@agent-native/core 0.106.0 → 0.106.1

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 (67) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +6 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/application-state/index.ts +2 -0
  5. package/corpus/core/src/application-state/script-helpers.ts +12 -0
  6. package/corpus/core/src/application-state/store.ts +38 -0
  7. package/corpus/core/src/client/review/ReviewCommentComposer.tsx +10 -3
  8. package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +22 -0
  9. package/corpus/templates/design/AGENTS.md +16 -0
  10. package/corpus/templates/design/actions/cancel-node-rewrite-request.ts +54 -0
  11. package/corpus/templates/design/actions/propose-node-rewrite.ts +290 -0
  12. package/corpus/templates/design/actions/resolve-node-rewrite.ts +257 -0
  13. package/corpus/templates/design/actions/view-screen.ts +98 -2
  14. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +71 -1
  15. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +19 -0
  16. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +33 -0
  17. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +194 -0
  18. package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +21 -4
  19. package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +18 -0
  20. package/corpus/templates/design/app/components/design/multi-screen/types.ts +4 -0
  21. package/corpus/templates/design/app/components/visual-editor/NodeRewriteProposal.tsx +638 -0
  22. package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +535 -54
  23. package/corpus/templates/design/app/components/visual-editor/index.ts +5 -1
  24. package/corpus/templates/design/app/components/visual-editor/review-canvas-state.ts +21 -3
  25. package/corpus/templates/design/app/i18n/ar-SA.ts +35 -0
  26. package/corpus/templates/design/app/i18n/de-DE.ts +35 -0
  27. package/corpus/templates/design/app/i18n/es-ES.ts +35 -0
  28. package/corpus/templates/design/app/i18n/fr-FR.ts +35 -0
  29. package/corpus/templates/design/app/i18n/hi-IN.ts +35 -0
  30. package/corpus/templates/design/app/i18n/ja-JP.ts +35 -0
  31. package/corpus/templates/design/app/i18n/ko-KR.ts +35 -0
  32. package/corpus/templates/design/app/i18n/pt-BR.ts +35 -0
  33. package/corpus/templates/design/app/i18n/zh-CN.ts +35 -0
  34. package/corpus/templates/design/app/i18n/zh-TW.ts +32 -0
  35. package/corpus/templates/design/app/i18n-data.ts +32 -0
  36. package/corpus/templates/design/app/lib/node-reprompt.ts +110 -0
  37. package/corpus/templates/design/changelog/2026-07-16-design-editing-and-review-are-now-more-predictable.md +6 -0
  38. package/corpus/templates/design/server/lib/reprompt-action-guard.ts +107 -0
  39. package/corpus/templates/design/server/plugins/agent-chat.ts +9 -1
  40. package/corpus/templates/design/shared/code-layer.ts +15 -0
  41. package/corpus/templates/design/shared/node-rewrite.ts +213 -0
  42. package/corpus/templates/design/shared/review-anchor.ts +26 -3
  43. package/dist/application-state/index.d.ts +2 -2
  44. package/dist/application-state/index.d.ts.map +1 -1
  45. package/dist/application-state/index.js +2 -2
  46. package/dist/application-state/index.js.map +1 -1
  47. package/dist/application-state/script-helpers.d.ts +1 -0
  48. package/dist/application-state/script-helpers.d.ts.map +1 -1
  49. package/dist/application-state/script-helpers.js +7 -1
  50. package/dist/application-state/script-helpers.js.map +1 -1
  51. package/dist/application-state/store.d.ts +1 -0
  52. package/dist/application-state/store.d.ts.map +1 -1
  53. package/dist/application-state/store.js +28 -0
  54. package/dist/application-state/store.js.map +1 -1
  55. package/dist/client/review/ReviewCommentComposer.d.ts +4 -1
  56. package/dist/client/review/ReviewCommentComposer.d.ts.map +1 -1
  57. package/dist/client/review/ReviewCommentComposer.js +3 -3
  58. package/dist/client/review/ReviewCommentComposer.js.map +1 -1
  59. package/dist/collab/awareness.d.ts +2 -2
  60. package/dist/collab/awareness.d.ts.map +1 -1
  61. package/dist/collab/struct-routes.d.ts +1 -1
  62. package/dist/notifications/routes.d.ts +2 -2
  63. package/dist/observability/routes.d.ts +5 -5
  64. package/dist/resources/handlers.d.ts +1 -1
  65. package/dist/secrets/routes.d.ts +9 -9
  66. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  67. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/application-state/store.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,eAAe,EACf,iBAAiB,EACjB,UAAU,EACV,OAAO,GACR,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEtE,IAAI,YAAuC,CAAC;AAC5C,MAAM,gCAAgC,GAAG,IAAI,GAAG,IAAI,CAAC;AAErD,6EAA6E;AAC7E,+EAA+E;AAC/E,6EAA6E;AAC7E,qEAAqE;AACrE,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;AACrD,CAAC;AAED,KAAK,UAAU,WAAW;IACxB,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,CAAC,KAAK,IAAI,EAAE;YACzB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,SAAS,GAAG;;;;;uBAKD,OAAO,EAAE;;;OAGzB,CAAC;YAEF,IAAI,UAAU,EAAE,EAAE,CAAC;gBACjB,mEAAmE;gBACnE,kEAAkE;gBAClE,6DAA6D;gBAC7D,kEAAkE;gBAClE,uEAAuE;gBACvE,oEAAoE;gBACpE,uEAAuE;gBACvE,uEAAuE;gBACvE,wEAAwE;gBACxE,uEAAuE;gBACvE,8CAA8C;gBAC9C,MAAM,iBAAiB,CAAC,mBAAmB,EAAE,SAAS,CAAC,CAAC;gBACxD,0EAA0E;gBAC1E,0EAA0E;gBAC1E,mEAAmE;gBACnE,MAAM,uBAAuB,CAAC,mBAAmB,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;gBACnE,uEAAuE;gBACvE,gEAAgE;gBAChE,MAAM,iBAAiB,CACrB,0BAA0B,EAC1B,uFAAuF,CACxF,CAAC;gBACF,MAAM,iBAAiB,CACrB,2BAA2B,EAC3B,6FAA6F,CAC9F,CAAC;gBACF,OAAO;YACT,CAAC;YAED,qEAAqE;YACrE,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAChC,0EAA0E;YAC1E,0EAA0E;YAC1E,mEAAmE;YACnE,MAAM,uBAAuB,CAAC,mBAAmB,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC;YACnE,sCAAsC;YACtC,wEAAwE;YACxE,yEAAyE;YACzE,qEAAqE;YACrE,qEAAqE;YACrE,oDAAoD;YACpD,KAAK,MAAM,GAAG,IAAI;gBAChB,uFAAuF;gBACvF,6FAA6F;aAC9F,EAAE,CAAC;gBACF,IAAI,CAAC;oBACH,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC5B,CAAC;gBAAC,MAAM,CAAC;oBACP,4DAA4D;gBAC9D,CAAC;YACH,CAAC;QACH,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACjB,sDAAsD;YACtD,YAAY,GAAG,SAAS,CAAC;YACzB,MAAM,GAAG,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAiB,EACjB,GAAW;IAEX,IAAI,CAAC;QACH,MAAM,WAAW,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;YACpC,GAAG,EAAE,sEAAsE;YAC3E,IAAI,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,CAAC,CAAC;QACH,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAe,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,yEAAyE;QACzE,uEAAuE;QACvE,IAAI,iBAAiB,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACxC,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,SAAiB,EACjB,IAAuB;IAEvB,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC,MAAM,MAAM,GAAmD,EAAE,CAAC;IAClE,KAAK,MAAM,GAAG,IAAI,UAAU;QAAE,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IACjD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAE3C,IAAI,CAAC;QACH,MAAM,WAAW,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,YAAY,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1D,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;YACpC,GAAG,EAAE,6EAA6E,YAAY,GAAG;YACjG,IAAI,EAAE,CAAC,SAAS,EAAE,GAAG,UAAU,CAAC;SACjC,CAAC,CAAC;QACH,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,CAAC,GAAG,CAAC,GAAa,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAe,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,iBAAiB,CAAC,GAAG,CAAC;YAAE,OAAO,MAAM,CAAC;QAC1C,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAiB,EACjB,GAAW,EACX,KAA8B,EAC9B,OAA2B;IAE3B,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACzC,IACE,CAAC,eAAe,EAAE;QAClB,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,CAAC,GAAG,gCAAgC,EACxE,CAAC;QACD,MAAM,IAAI,KAAK,CACb,4BAA4B,GAAG,4HAA4H,CAC5J,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,CAAC,OAAO,CAAC;QACnB,GAAG,EAAE,UAAU,EAAE;YACf,CAAC,CAAC,yLAAyL;YAC3L,CAAC,CAAC,mGAAmG;QACvG,IAAI,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;KAC/C,CAAC,CAAC;IACH,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,SAAiB,EACjB,GAAW,EACX,OAA2B;IAE3B,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QAClC,GAAG,EAAE,gEAAgE;QACrE,IAAI,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC;KACvB,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,GAAG,CAAC,CAAC;IACxC,IAAI,OAAO;QAAE,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;IACxE,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,SAAiB,EACjB,SAAiB;IAEjB,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QACpC,GAAG,EAAE,yFAAyF;QAC9F,IAAI,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC;KAC/C,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACxB,GAAG,EAAE,GAAG,CAAC,GAAa;QACtB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAe,CAAC;KACvC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,SAAiB,EACjB,SAAiB,EACjB,OAA2B;IAE3B,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,uCAAuC;IACvC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QACpC,GAAG,EAAE,kFAAkF;QACvF,IAAI,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC;KAC/C,CAAC,CAAC;IAEH,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAEhC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QAClC,GAAG,EAAE,8EAA8E;QACnF,IAAI,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC;KAC/C,CAAC,CAAC;IAEH,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,kBAAkB,CAAC,GAAG,CAAC,GAAa,EAAE,OAAO,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO,MAAM,CAAC,YAAY,CAAC;AAC7B,CAAC","sourcesContent":["import {\n getDbExec,\n isLocalDatabase,\n isConnectionError,\n isPostgres,\n intType,\n} from \"../db/client.js\";\nimport { ensureIndexExists, ensureTableExists } from \"../db/ddl-guard.js\";\nimport { widenIntColumnsToBigInt } from \"../db/widen-columns.js\";\nimport type { StoreWriteOptions } from \"../settings/store.js\";\nimport { emitAppStateChange, emitAppStateDelete } from \"./emitter.js\";\n\nlet _initPromise: Promise<void> | undefined;\nconst MAX_HOSTED_APP_STATE_VALUE_BYTES = 1024 * 1024;\n\n// Escapes LIKE wildcards (`%`, `_`) and the escape char itself so a caller's\n// literal prefix is matched verbatim. Used with `ESCAPE '!'` in prefix queries\n// below; without this, a prefix such as `user_settings` would treat `_` as a\n// single-char wildcard and over-match (e.g. delete `userXsettings`).\nfunction escapeLike(s: string): string {\n return s.replace(/[!%_]/g, (match) => `!${match}`);\n}\n\nasync function ensureTable(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n const createSql = `\n CREATE TABLE IF NOT EXISTS application_state (\n session_id TEXT NOT NULL,\n key TEXT NOT NULL,\n value TEXT NOT NULL,\n updated_at ${intType()} NOT NULL,\n PRIMARY KEY (session_id, key)\n )\n `;\n\n if (isPostgres()) {\n // Hot path: the `application_state` table and its poll indexes are\n // virtually always already present in production. Issuing `CREATE\n // TABLE`/ `CREATE INDEX` still takes a lock that, in a fresh\n // background-worker process behind a concurrent connection on the\n // shared Neon DB, can block ~indefinitely (ACCESS EXCLUSIVE for CREATE\n // TABLE; a write-blocking SHARE lock for CREATE INDEX). The ensure*\n // wrappers probe `information_schema`/`pg_indexes` first (plain reads,\n // no lock) and run DDL ONLY for what is actually missing, bounded by a\n // transaction-scoped `lock_timeout`. If a swallowed lock-timeout leaves\n // the schema still missing they RE-PROBE and THROW rather than letting\n // init memoize success against absent schema.\n await ensureTableExists(\"application_state\", createSql);\n // Older deployments created `updated_at` as 32-bit `INTEGER`; on Postgres\n // the `Date.now()` written by appStatePut() on every turn overflows int4.\n // Widen it in place (no-op once done / on fresh BIGINT databases).\n await widenIntColumnsToBigInt(\"application_state\", [\"updated_at\"]);\n // Indexes for the two hot poll paths. Probe pg_indexes first (no lock)\n // and skip the SHARE-locking CREATE INDEX when already present.\n await ensureIndexExists(\n \"app_state_updated_at_idx\",\n `CREATE INDEX IF NOT EXISTS app_state_updated_at_idx ON application_state (updated_at)`,\n );\n await ensureIndexExists(\n \"app_state_key_updated_idx\",\n `CREATE INDEX IF NOT EXISTS app_state_key_updated_idx ON application_state (key, updated_at)`,\n );\n return;\n }\n\n // SQLite (local dev): no lock problem — keep the original behaviour.\n await client.execute(createSql);\n // Older deployments created `updated_at` as 32-bit `INTEGER`; on Postgres\n // the `Date.now()` written by appStatePut() on every turn overflows int4.\n // Widen it in place (no-op once done / on fresh BIGINT databases).\n await widenIntColumnsToBigInt(\"application_state\", [\"updated_at\"]);\n // Indexes for the two hot poll paths:\n // - `SELECT … WHERE updated_at > ?` (watermark scan, every poll cycle)\n // - `SELECT … WHERE key = ? … ORDER BY updated_at ASC` (marker lookups)\n // Both are dialect-agnostic (no DESC/partial/PG-only syntax) so they\n // apply identically on SQLite and Postgres. IF NOT EXISTS makes them\n // idempotent across restarts on existing databases.\n for (const ddl of [\n `CREATE INDEX IF NOT EXISTS app_state_updated_at_idx ON application_state (updated_at)`,\n `CREATE INDEX IF NOT EXISTS app_state_key_updated_idx ON application_state (key, updated_at)`,\n ]) {\n try {\n await client.execute(ddl);\n } catch {\n // Index already exists or the dialect rejected a duplicate.\n }\n }\n })().catch((err) => {\n // Retry init on the next call after a failed startup.\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\nexport async function appStateGet(\n sessionId: string,\n key: string,\n): Promise<Record<string, unknown> | null> {\n try {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT value FROM application_state WHERE session_id = ? AND key = ?`,\n args: [sessionId, key],\n });\n if (rows.length === 0) return null;\n return JSON.parse(rows[0].value as string);\n } catch (err) {\n // Transient WS / connection drops (Neon serverless) — caller polls every\n // 2s and will see the value on the next tick. Swallow rather than 500.\n if (isConnectionError(err)) return null;\n throw err;\n }\n}\n\n/**\n * Read several application-state keys for one session in a single SQL query.\n * Missing keys are returned as `null` so callers can preserve the requested\n * shape without issuing one fallback query per key.\n */\nexport async function appStateGetMany(\n sessionId: string,\n keys: readonly string[],\n): Promise<Record<string, Record<string, unknown> | null>> {\n const uniqueKeys = [...new Set(keys)];\n const values: Record<string, Record<string, unknown> | null> = {};\n for (const key of uniqueKeys) values[key] = null;\n if (uniqueKeys.length === 0) return values;\n\n try {\n await ensureTable();\n const client = getDbExec();\n const placeholders = uniqueKeys.map(() => \"?\").join(\", \");\n const { rows } = await client.execute({\n sql: `SELECT key, value FROM application_state WHERE session_id = ? AND key IN (${placeholders})`,\n args: [sessionId, ...uniqueKeys],\n });\n for (const row of rows) {\n values[row.key as string] = JSON.parse(row.value as string);\n }\n return values;\n } catch (err) {\n if (isConnectionError(err)) return values;\n throw err;\n }\n}\n\nexport async function appStatePut(\n sessionId: string,\n key: string,\n value: Record<string, unknown>,\n options?: StoreWriteOptions,\n): Promise<void> {\n await ensureTable();\n const client = getDbExec();\n const serialized = JSON.stringify(value);\n if (\n !isLocalDatabase() &&\n Buffer.byteLength(serialized, \"utf8\") > MAX_HOSTED_APP_STATE_VALUE_BYTES\n ) {\n throw new Error(\n `application_state value \"${key}\" is too large for hosted SQL storage. Store large files, base64, or blobs in file storage and write only a URL or handle.`,\n );\n }\n await client.execute({\n sql: isPostgres()\n ? `INSERT INTO application_state (session_id, key, value, updated_at) VALUES (?, ?, ?, ?) ON CONFLICT (session_id, key) DO UPDATE SET value=EXCLUDED.value, updated_at=EXCLUDED.updated_at`\n : `INSERT OR REPLACE INTO application_state (session_id, key, value, updated_at) VALUES (?, ?, ?, ?)`,\n args: [sessionId, key, serialized, Date.now()],\n });\n emitAppStateChange(key, options?.requestSource, sessionId);\n}\n\nexport async function appStateDelete(\n sessionId: string,\n key: string,\n options?: StoreWriteOptions,\n): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const result = await client.execute({\n sql: `DELETE FROM application_state WHERE session_id = ? AND key = ?`,\n args: [sessionId, key],\n });\n const deleted = result.rowsAffected > 0;\n if (deleted) emitAppStateDelete(key, options?.requestSource, sessionId);\n return deleted;\n}\n\nexport async function appStateList(\n sessionId: string,\n keyPrefix: string,\n): Promise<Array<{ key: string; value: Record<string, unknown> }>> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT key, value FROM application_state WHERE session_id = ? AND key LIKE ? ESCAPE '!'`,\n args: [sessionId, escapeLike(keyPrefix) + \"%\"],\n });\n return rows.map((row) => ({\n key: row.key as string,\n value: JSON.parse(row.value as string),\n }));\n}\n\nexport async function appStateDeleteByPrefix(\n sessionId: string,\n keyPrefix: string,\n options?: StoreWriteOptions,\n): Promise<number> {\n await ensureTable();\n const client = getDbExec();\n\n // Get keys first so we can emit events\n const { rows } = await client.execute({\n sql: `SELECT key FROM application_state WHERE session_id = ? AND key LIKE ? ESCAPE '!'`,\n args: [sessionId, escapeLike(keyPrefix) + \"%\"],\n });\n\n if (rows.length === 0) return 0;\n\n const result = await client.execute({\n sql: `DELETE FROM application_state WHERE session_id = ? AND key LIKE ? ESCAPE '!'`,\n args: [sessionId, escapeLike(keyPrefix) + \"%\"],\n });\n\n for (const row of rows) {\n emitAppStateDelete(row.key as string, options?.requestSource, sessionId);\n }\n\n return result.rowsAffected;\n}\n"]}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/application-state/store.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getDbExec,\n isLocalDatabase,\n isConnectionError,\n isPostgres,\n intType,\n} from \"../db/client.js\";\nimport { ensureIndexExists, ensureTableExists } from \"../db/ddl-guard.js\";\nimport { widenIntColumnsToBigInt } from \"../db/widen-columns.js\";\nimport type { StoreWriteOptions } from \"../settings/store.js\";\nimport { emitAppStateChange, emitAppStateDelete } from \"./emitter.js\";\n\nlet _initPromise: Promise<void> | undefined;\nconst MAX_HOSTED_APP_STATE_VALUE_BYTES = 1024 * 1024;\n\n// Escapes LIKE wildcards (`%`, `_`) and the escape char itself so a caller's\n// literal prefix is matched verbatim. Used with `ESCAPE '!'` in prefix queries\n// below; without this, a prefix such as `user_settings` would treat `_` as a\n// single-char wildcard and over-match (e.g. delete `userXsettings`).\nfunction escapeLike(s: string): string {\n return s.replace(/[!%_]/g, (match) => `!${match}`);\n}\n\nasync function ensureTable(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n const createSql = `\n CREATE TABLE IF NOT EXISTS application_state (\n session_id TEXT NOT NULL,\n key TEXT NOT NULL,\n value TEXT NOT NULL,\n updated_at ${intType()} NOT NULL,\n PRIMARY KEY (session_id, key)\n )\n `;\n\n if (isPostgres()) {\n // Hot path: the `application_state` table and its poll indexes are\n // virtually always already present in production. Issuing `CREATE\n // TABLE`/ `CREATE INDEX` still takes a lock that, in a fresh\n // background-worker process behind a concurrent connection on the\n // shared Neon DB, can block ~indefinitely (ACCESS EXCLUSIVE for CREATE\n // TABLE; a write-blocking SHARE lock for CREATE INDEX). The ensure*\n // wrappers probe `information_schema`/`pg_indexes` first (plain reads,\n // no lock) and run DDL ONLY for what is actually missing, bounded by a\n // transaction-scoped `lock_timeout`. If a swallowed lock-timeout leaves\n // the schema still missing they RE-PROBE and THROW rather than letting\n // init memoize success against absent schema.\n await ensureTableExists(\"application_state\", createSql);\n // Older deployments created `updated_at` as 32-bit `INTEGER`; on Postgres\n // the `Date.now()` written by appStatePut() on every turn overflows int4.\n // Widen it in place (no-op once done / on fresh BIGINT databases).\n await widenIntColumnsToBigInt(\"application_state\", [\"updated_at\"]);\n // Indexes for the two hot poll paths. Probe pg_indexes first (no lock)\n // and skip the SHARE-locking CREATE INDEX when already present.\n await ensureIndexExists(\n \"app_state_updated_at_idx\",\n `CREATE INDEX IF NOT EXISTS app_state_updated_at_idx ON application_state (updated_at)`,\n );\n await ensureIndexExists(\n \"app_state_key_updated_idx\",\n `CREATE INDEX IF NOT EXISTS app_state_key_updated_idx ON application_state (key, updated_at)`,\n );\n return;\n }\n\n // SQLite (local dev): no lock problem — keep the original behaviour.\n await client.execute(createSql);\n // Older deployments created `updated_at` as 32-bit `INTEGER`; on Postgres\n // the `Date.now()` written by appStatePut() on every turn overflows int4.\n // Widen it in place (no-op once done / on fresh BIGINT databases).\n await widenIntColumnsToBigInt(\"application_state\", [\"updated_at\"]);\n // Indexes for the two hot poll paths:\n // - `SELECT … WHERE updated_at > ?` (watermark scan, every poll cycle)\n // - `SELECT … WHERE key = ? … ORDER BY updated_at ASC` (marker lookups)\n // Both are dialect-agnostic (no DESC/partial/PG-only syntax) so they\n // apply identically on SQLite and Postgres. IF NOT EXISTS makes them\n // idempotent across restarts on existing databases.\n for (const ddl of [\n `CREATE INDEX IF NOT EXISTS app_state_updated_at_idx ON application_state (updated_at)`,\n `CREATE INDEX IF NOT EXISTS app_state_key_updated_idx ON application_state (key, updated_at)`,\n ]) {\n try {\n await client.execute(ddl);\n } catch {\n // Index already exists or the dialect rejected a duplicate.\n }\n }\n })().catch((err) => {\n // Retry init on the next call after a failed startup.\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\nexport async function appStateGet(\n sessionId: string,\n key: string,\n): Promise<Record<string, unknown> | null> {\n try {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT value FROM application_state WHERE session_id = ? AND key = ?`,\n args: [sessionId, key],\n });\n if (rows.length === 0) return null;\n return JSON.parse(rows[0].value as string);\n } catch (err) {\n // Transient WS / connection drops (Neon serverless) — caller polls every\n // 2s and will see the value on the next tick. Swallow rather than 500.\n if (isConnectionError(err)) return null;\n throw err;\n }\n}\n\n/**\n * Read several application-state keys for one session in a single SQL query.\n * Missing keys are returned as `null` so callers can preserve the requested\n * shape without issuing one fallback query per key.\n */\nexport async function appStateGetMany(\n sessionId: string,\n keys: readonly string[],\n): Promise<Record<string, Record<string, unknown> | null>> {\n const uniqueKeys = [...new Set(keys)];\n const values: Record<string, Record<string, unknown> | null> = {};\n for (const key of uniqueKeys) values[key] = null;\n if (uniqueKeys.length === 0) return values;\n\n try {\n await ensureTable();\n const client = getDbExec();\n const placeholders = uniqueKeys.map(() => \"?\").join(\", \");\n const { rows } = await client.execute({\n sql: `SELECT key, value FROM application_state WHERE session_id = ? AND key IN (${placeholders})`,\n args: [sessionId, ...uniqueKeys],\n });\n for (const row of rows) {\n values[row.key as string] = JSON.parse(row.value as string);\n }\n return values;\n } catch (err) {\n if (isConnectionError(err)) return values;\n throw err;\n }\n}\n\nexport async function appStatePut(\n sessionId: string,\n key: string,\n value: Record<string, unknown>,\n options?: StoreWriteOptions,\n): Promise<void> {\n await ensureTable();\n const client = getDbExec();\n const serialized = JSON.stringify(value);\n if (\n !isLocalDatabase() &&\n Buffer.byteLength(serialized, \"utf8\") > MAX_HOSTED_APP_STATE_VALUE_BYTES\n ) {\n throw new Error(\n `application_state value \"${key}\" is too large for hosted SQL storage. Store large files, base64, or blobs in file storage and write only a URL or handle.`,\n );\n }\n await client.execute({\n sql: isPostgres()\n ? `INSERT INTO application_state (session_id, key, value, updated_at) VALUES (?, ?, ?, ?) ON CONFLICT (session_id, key) DO UPDATE SET value=EXCLUDED.value, updated_at=EXCLUDED.updated_at`\n : `INSERT OR REPLACE INTO application_state (session_id, key, value, updated_at) VALUES (?, ?, ?, ?)`,\n args: [sessionId, key, serialized, Date.now()],\n });\n emitAppStateChange(key, options?.requestSource, sessionId);\n}\n\nexport async function appStateDelete(\n sessionId: string,\n key: string,\n options?: StoreWriteOptions,\n): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const result = await client.execute({\n sql: `DELETE FROM application_state WHERE session_id = ? AND key = ?`,\n args: [sessionId, key],\n });\n const deleted = result.rowsAffected > 0;\n if (deleted) emitAppStateDelete(key, options?.requestSource, sessionId);\n return deleted;\n}\n\nexport async function appStateCompareAndSet(\n sessionId: string,\n key: string,\n expectedValue: Record<string, unknown>,\n nextValue: Record<string, unknown> | null,\n options?: StoreWriteOptions,\n): Promise<boolean> {\n await ensureTable();\n const client = getDbExec();\n const expected = JSON.stringify(expectedValue);\n if (nextValue === null) {\n const result = await client.execute({\n sql: `DELETE FROM application_state WHERE session_id = ? AND key = ? AND value = ?`,\n args: [sessionId, key, expected],\n });\n const changed = result.rowsAffected > 0;\n if (changed) emitAppStateDelete(key, options?.requestSource, sessionId);\n return changed;\n }\n\n const next = JSON.stringify(nextValue);\n if (\n !isLocalDatabase() &&\n Buffer.byteLength(next, \"utf8\") > MAX_HOSTED_APP_STATE_VALUE_BYTES\n ) {\n throw new Error(\n `application_state value \"${key}\" is too large for hosted SQL storage. Store large files, base64, or blobs in file storage and write only a URL or handle.`,\n );\n }\n const result = await client.execute({\n sql: `UPDATE application_state SET value = ?, updated_at = ? WHERE session_id = ? AND key = ? AND value = ?`,\n args: [next, Date.now(), sessionId, key, expected],\n });\n const changed = result.rowsAffected > 0;\n if (changed) emitAppStateChange(key, options?.requestSource, sessionId);\n return changed;\n}\n\nexport async function appStateList(\n sessionId: string,\n keyPrefix: string,\n): Promise<Array<{ key: string; value: Record<string, unknown> }>> {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT key, value FROM application_state WHERE session_id = ? AND key LIKE ? ESCAPE '!'`,\n args: [sessionId, escapeLike(keyPrefix) + \"%\"],\n });\n return rows.map((row) => ({\n key: row.key as string,\n value: JSON.parse(row.value as string),\n }));\n}\n\nexport async function appStateDeleteByPrefix(\n sessionId: string,\n keyPrefix: string,\n options?: StoreWriteOptions,\n): Promise<number> {\n await ensureTable();\n const client = getDbExec();\n\n // Get keys first so we can emit events\n const { rows } = await client.execute({\n sql: `SELECT key FROM application_state WHERE session_id = ? AND key LIKE ? ESCAPE '!'`,\n args: [sessionId, escapeLike(keyPrefix) + \"%\"],\n });\n\n if (rows.length === 0) return 0;\n\n const result = await client.execute({\n sql: `DELETE FROM application_state WHERE session_id = ? AND key LIKE ? ESCAPE '!'`,\n args: [sessionId, escapeLike(keyPrefix) + \"%\"],\n });\n\n for (const row of rows) {\n emitAppStateDelete(row.key as string, options?.requestSource, sessionId);\n }\n\n return result.rowsAffected;\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import type { ReactNode } from "react";
1
2
  import type { ReviewResolutionTarget } from "../../review/types.js";
2
3
  export interface ReviewCommentComposerProps {
3
4
  value: string;
@@ -6,14 +7,16 @@ export interface ReviewCommentComposerProps {
6
7
  submittingTarget?: ReviewResolutionTarget | null;
7
8
  disabled?: boolean;
8
9
  showAgentAction?: boolean;
10
+ agentAction?: ReactNode;
9
11
  placeholder?: string;
10
12
  commentLabel?: string;
11
13
  agentLabel?: string;
12
14
  contextLabel?: string;
13
15
  autoFocus?: boolean;
14
16
  submitOnEnter?: boolean;
17
+ enterSubmitTarget?: ReviewResolutionTarget;
15
18
  onEscape?: () => void;
16
19
  className?: string;
17
20
  }
18
- export declare function ReviewCommentComposer({ value, onChange, onSubmit, submittingTarget, disabled, showAgentAction, placeholder, commentLabel, agentLabel, contextLabel, autoFocus, submitOnEnter, onEscape, className, }: ReviewCommentComposerProps): import("react").JSX.Element;
21
+ export declare function ReviewCommentComposer({ value, onChange, onSubmit, submittingTarget, disabled, showAgentAction, agentAction, placeholder, commentLabel, agentLabel, contextLabel, autoFocus, submitOnEnter, enterSubmitTarget, onEscape, className, }: ReviewCommentComposerProps): import("react").JSX.Element;
19
22
  //# sourceMappingURL=ReviewCommentComposer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ReviewCommentComposer.d.ts","sourceRoot":"","sources":["../../../src/client/review/ReviewCommentComposer.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAGpE,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,CAAC,gBAAgB,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAC7D,gBAAgB,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,qBAAqB,CAAC,EACpC,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,gBAAuB,EACvB,QAAgB,EAChB,eAAuB,EACvB,WAAgC,EAChC,YAAwB,EACxB,UAA4B,EAC5B,YAAY,EACZ,SAAiB,EACjB,aAAqB,EACrB,QAAQ,EACR,SAAS,GACV,EAAE,0BAA0B,+BA2E5B"}
1
+ {"version":3,"file":"ReviewCommentComposer.d.ts","sourceRoot":"","sources":["../../../src/client/review/ReviewCommentComposer.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAGpE,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,CAAC,gBAAgB,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAC7D,gBAAgB,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IAC3C,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,qBAAqB,CAAC,EACpC,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,gBAAuB,EACvB,QAAgB,EAChB,eAAuB,EACvB,WAAW,EACX,WAAgC,EAChC,YAAwB,EACxB,UAA4B,EAC5B,YAAY,EACZ,SAAiB,EACjB,aAAqB,EACrB,iBAA2B,EAC3B,QAAQ,EACR,SAAS,GACV,EAAE,0BAA0B,+BA6E5B"}
@@ -4,7 +4,7 @@ import { Spinner } from "@agent-native/toolkit/ui/spinner";
4
4
  import { Textarea } from "@agent-native/toolkit/ui/textarea";
5
5
  import { IconFocus2, IconMessageCircle, IconSend } from "@tabler/icons-react";
6
6
  import { cn } from "../utils.js";
7
- export function ReviewCommentComposer({ value, onChange, onSubmit, submittingTarget = null, disabled = false, showAgentAction = false, placeholder = "Add a comment...", commentLabel = "Comment", agentLabel = "Send to agent", contextLabel, autoFocus = false, submitOnEnter = false, onEscape, className, }) {
7
+ export function ReviewCommentComposer({ value, onChange, onSubmit, submittingTarget = null, disabled = false, showAgentAction = false, agentAction, placeholder = "Add a comment...", commentLabel = "Comment", agentLabel = "Send to agent", contextLabel, autoFocus = false, submitOnEnter = false, enterSubmitTarget = "human", onEscape, className, }) {
8
8
  const canSubmit = Boolean(value.trim()) && !disabled;
9
9
  const submit = (resolutionTarget) => {
10
10
  if (!canSubmit)
@@ -23,8 +23,8 @@ export function ReviewCommentComposer({ value, onChange, onSubmit, submittingTar
23
23
  }
24
24
  if (submitOnEnter && event.key === "Enter" && !event.shiftKey) {
25
25
  event.preventDefault();
26
- submit("human");
26
+ submit(enterSubmitTarget);
27
27
  }
28
- } }), _jsxs("div", { className: "mt-2 flex flex-col items-stretch justify-end gap-2 @2xs/review:flex-row @2xs/review:items-center", children: [_jsxs(Button, { type: "submit", size: "sm", disabled: !canSubmit, className: "h-8 w-full min-w-0 gap-1.5 @2xs/review:w-auto", children: [submittingTarget === "human" ? (_jsx(Spinner, { className: "size-3.5" })) : (_jsx(IconMessageCircle, { className: "size-3.5" })), _jsx("span", { className: "truncate", children: commentLabel })] }), showAgentAction ? (_jsxs(Button, { type: "button", size: "sm", variant: "outline", disabled: !canSubmit, className: "h-8 w-full min-w-0 gap-1.5 @2xs/review:w-auto", onClick: () => submit("agent"), children: [submittingTarget === "agent" ? (_jsx(Spinner, { className: "size-3.5" })) : (_jsx(IconSend, { className: "size-3.5" })), _jsx("span", { className: "truncate", children: agentLabel })] })) : null] })] }));
28
+ } }), _jsxs("div", { className: "mt-2 flex flex-col items-stretch justify-end gap-2 @2xs/review:flex-row @2xs/review:items-center", children: [_jsxs(Button, { type: "submit", size: "sm", disabled: !canSubmit, className: "h-8 w-full gap-1.5 @2xs/review:w-auto @2xs/review:min-w-28 @2xs/review:shrink-0", children: [submittingTarget === "human" ? (_jsx(Spinner, { className: "size-3.5" })) : (_jsx(IconMessageCircle, { className: "size-3.5" })), _jsx("span", { className: "truncate", children: commentLabel })] }), showAgentAction && agentAction ? (agentAction) : showAgentAction ? (_jsxs(Button, { type: "button", size: "sm", variant: "outline", disabled: !canSubmit, className: "h-8 w-full min-w-0 gap-1.5 @2xs/review:w-auto", onClick: () => submit("agent"), children: [submittingTarget === "agent" ? (_jsx(Spinner, { className: "size-3.5" })) : (_jsx(IconSend, { className: "size-3.5" })), _jsx("span", { className: "truncate", children: agentLabel })] })) : null] })] }));
29
29
  }
30
30
  //# sourceMappingURL=ReviewCommentComposer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ReviewCommentComposer.js","sourceRoot":"","sources":["../../../src/client/review/ReviewCommentComposer.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Button } from \"@agent-native/toolkit/ui/button\";\nimport { Spinner } from \"@agent-native/toolkit/ui/spinner\";\nimport { Textarea } from \"@agent-native/toolkit/ui/textarea\";\nimport { IconFocus2, IconMessageCircle, IconSend } from \"@tabler/icons-react\";\n\nimport type { ReviewResolutionTarget } from \"../../review/types.js\";\nimport { cn } from \"../utils.js\";\n\nexport interface ReviewCommentComposerProps {\n value: string;\n onChange: (value: string) => void;\n onSubmit: (resolutionTarget: ReviewResolutionTarget) => void;\n submittingTarget?: ReviewResolutionTarget | null;\n disabled?: boolean;\n showAgentAction?: boolean;\n placeholder?: string;\n commentLabel?: string;\n agentLabel?: string;\n contextLabel?: string;\n autoFocus?: boolean;\n submitOnEnter?: boolean;\n onEscape?: () => void;\n className?: string;\n}\n\nexport function ReviewCommentComposer({\n value,\n onChange,\n onSubmit,\n submittingTarget = null,\n disabled = false,\n showAgentAction = false,\n placeholder = \"Add a comment...\",\n commentLabel = \"Comment\",\n agentLabel = \"Send to agent\",\n contextLabel,\n autoFocus = false,\n submitOnEnter = false,\n onEscape,\n className,\n}: ReviewCommentComposerProps) {\n const canSubmit = Boolean(value.trim()) && !disabled;\n const submit = (resolutionTarget: ReviewResolutionTarget) => {\n if (!canSubmit) return;\n onSubmit(resolutionTarget);\n };\n\n return (\n <form\n className={cn(\"@container/review\", className)}\n onSubmit={(event) => {\n event.preventDefault();\n submit(\"human\");\n }}\n >\n {contextLabel ? (\n <div className=\"mb-2 flex min-w-0 items-center gap-1.5 text-xs text-muted-foreground\">\n <IconFocus2 className=\"size-3.5 shrink-0\" />\n <span className=\"truncate\">{contextLabel}</span>\n </div>\n ) : null}\n <Textarea\n autoFocus={autoFocus}\n value={value}\n disabled={disabled}\n onChange={(event) => onChange(event.currentTarget.value)}\n placeholder={placeholder}\n className=\"min-h-16 resize-none text-sm\"\n onKeyDown={(event) => {\n if (event.key === \"Escape\" && onEscape) {\n event.stopPropagation();\n event.preventDefault();\n onEscape();\n return;\n }\n if (submitOnEnter && event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n submit(\"human\");\n }\n }}\n />\n <div className=\"mt-2 flex flex-col items-stretch justify-end gap-2 @2xs/review:flex-row @2xs/review:items-center\">\n <Button\n type=\"submit\"\n size=\"sm\"\n disabled={!canSubmit}\n className=\"h-8 w-full min-w-0 gap-1.5 @2xs/review:w-auto\"\n >\n {submittingTarget === \"human\" ? (\n <Spinner className=\"size-3.5\" />\n ) : (\n <IconMessageCircle className=\"size-3.5\" />\n )}\n <span className=\"truncate\">{commentLabel}</span>\n </Button>\n {showAgentAction ? (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={!canSubmit}\n className=\"h-8 w-full min-w-0 gap-1.5 @2xs/review:w-auto\"\n onClick={() => submit(\"agent\")}\n >\n {submittingTarget === \"agent\" ? (\n <Spinner className=\"size-3.5\" />\n ) : (\n <IconSend className=\"size-3.5\" />\n )}\n <span className=\"truncate\">{agentLabel}</span>\n </Button>\n ) : null}\n </div>\n </form>\n );\n}\n"]}
1
+ {"version":3,"file":"ReviewCommentComposer.js","sourceRoot":"","sources":["../../../src/client/review/ReviewCommentComposer.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Button } from \"@agent-native/toolkit/ui/button\";\nimport { Spinner } from \"@agent-native/toolkit/ui/spinner\";\nimport { Textarea } from \"@agent-native/toolkit/ui/textarea\";\nimport { IconFocus2, IconMessageCircle, IconSend } from \"@tabler/icons-react\";\nimport type { ReactNode } from \"react\";\n\nimport type { ReviewResolutionTarget } from \"../../review/types.js\";\nimport { cn } from \"../utils.js\";\n\nexport interface ReviewCommentComposerProps {\n value: string;\n onChange: (value: string) => void;\n onSubmit: (resolutionTarget: ReviewResolutionTarget) => void;\n submittingTarget?: ReviewResolutionTarget | null;\n disabled?: boolean;\n showAgentAction?: boolean;\n agentAction?: ReactNode;\n placeholder?: string;\n commentLabel?: string;\n agentLabel?: string;\n contextLabel?: string;\n autoFocus?: boolean;\n submitOnEnter?: boolean;\n enterSubmitTarget?: ReviewResolutionTarget;\n onEscape?: () => void;\n className?: string;\n}\n\nexport function ReviewCommentComposer({\n value,\n onChange,\n onSubmit,\n submittingTarget = null,\n disabled = false,\n showAgentAction = false,\n agentAction,\n placeholder = \"Add a comment...\",\n commentLabel = \"Comment\",\n agentLabel = \"Send to agent\",\n contextLabel,\n autoFocus = false,\n submitOnEnter = false,\n enterSubmitTarget = \"human\",\n onEscape,\n className,\n}: ReviewCommentComposerProps) {\n const canSubmit = Boolean(value.trim()) && !disabled;\n const submit = (resolutionTarget: ReviewResolutionTarget) => {\n if (!canSubmit) return;\n onSubmit(resolutionTarget);\n };\n\n return (\n <form\n className={cn(\"@container/review\", className)}\n onSubmit={(event) => {\n event.preventDefault();\n submit(\"human\");\n }}\n >\n {contextLabel ? (\n <div className=\"mb-2 flex min-w-0 items-center gap-1.5 text-xs text-muted-foreground\">\n <IconFocus2 className=\"size-3.5 shrink-0\" />\n <span className=\"truncate\">{contextLabel}</span>\n </div>\n ) : null}\n <Textarea\n autoFocus={autoFocus}\n value={value}\n disabled={disabled}\n onChange={(event) => onChange(event.currentTarget.value)}\n placeholder={placeholder}\n className=\"min-h-16 resize-none text-sm\"\n onKeyDown={(event) => {\n if (event.key === \"Escape\" && onEscape) {\n event.stopPropagation();\n event.preventDefault();\n onEscape();\n return;\n }\n if (submitOnEnter && event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n submit(enterSubmitTarget);\n }\n }}\n />\n <div className=\"mt-2 flex flex-col items-stretch justify-end gap-2 @2xs/review:flex-row @2xs/review:items-center\">\n <Button\n type=\"submit\"\n size=\"sm\"\n disabled={!canSubmit}\n className=\"h-8 w-full gap-1.5 @2xs/review:w-auto @2xs/review:min-w-28 @2xs/review:shrink-0\"\n >\n {submittingTarget === \"human\" ? (\n <Spinner className=\"size-3.5\" />\n ) : (\n <IconMessageCircle className=\"size-3.5\" />\n )}\n <span className=\"truncate\">{commentLabel}</span>\n </Button>\n {showAgentAction && agentAction ? (\n agentAction\n ) : showAgentAction ? (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n disabled={!canSubmit}\n className=\"h-8 w-full min-w-0 gap-1.5 @2xs/review:w-auto\"\n onClick={() => submit(\"agent\")}\n >\n {submittingTarget === \"agent\" ? (\n <Spinner className=\"size-3.5\" />\n ) : (\n <IconSend className=\"size-3.5\" />\n )}\n <span className=\"truncate\">{agentLabel}</span>\n </Button>\n ) : null}\n </div>\n </form>\n );\n}\n"]}
@@ -62,11 +62,11 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
62
62
  error: string;
63
63
  states?: undefined;
64
64
  } | {
65
- error?: undefined;
66
65
  states: {
67
66
  clientId: number;
68
67
  state: string;
69
68
  }[];
69
+ error?: undefined;
70
70
  }>>;
71
71
  /**
72
72
  * GET /_agent-native/collab/:docId/users
@@ -77,10 +77,10 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
77
77
  error: string;
78
78
  users?: undefined;
79
79
  } | {
80
- error?: undefined;
81
80
  users: {
82
81
  clientId: number;
83
82
  lastSeen: number;
84
83
  }[];
84
+ error?: undefined;
85
85
  }>>;
86
86
  //# sourceMappingURL=awareness.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"awareness.d.ts","sourceRoot":"","sources":["../../src/collab/awareness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAgB3C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAOD,eAAO,MAAM,sBAAsB,EAAG,kBAA2B,CAAC;AAElE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,MAAM,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAOD,wBAAgB,mBAAmB,IAAI,YAAY,CAElD;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,cAAc,GAAG,SAAS,GAChC,IAAI,CAON;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAClD,KAAK,CAAC,EAAE,cAAc,GACrB,IAAI,CAgBN;AAoBD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,MAAmB,GAC7B,IAAI,CAON;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE1E;AAiBD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAO1E;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,IAAI,CAOnE;AAkCD;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa;;;;;;kBAwDa,MAAM;eAAS,MAAM;;GAoB1D,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,cAAc;;;;;;kBAYM,MAAM;kBAAY,MAAM;;GAMvD,CAAC"}
1
+ {"version":3,"file":"awareness.d.ts","sourceRoot":"","sources":["../../src/collab/awareness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAgB3C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAOD,eAAO,MAAM,sBAAsB,EAAG,kBAA2B,CAAC;AAElE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,MAAM,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAOD,wBAAgB,mBAAmB,IAAI,YAAY,CAElD;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,cAAc,GAAG,SAAS,GAChC,IAAI,CAON;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,EAClD,KAAK,CAAC,EAAE,cAAc,GACrB,IAAI,CAgBN;AAoBD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,MAAmB,GAC7B,IAAI,CAON;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAE1E;AAiBD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAO1E;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,IAAI,CAOnE;AAkCD;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa;;;;;kBAwDa,MAAM;eAAS,MAAM;;;GAoB1D,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,cAAc;;;;;kBAYM,MAAM;kBAAY,MAAM;;;GAMvD,CAAC"}
@@ -13,8 +13,8 @@
13
13
  * Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
14
14
  */
15
15
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- ok?: undefined;
17
16
  error: string;
17
+ ok?: undefined;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
@@ -13,13 +13,13 @@
13
13
  export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
14
14
  count: number;
15
15
  updated?: undefined;
16
- ok?: undefined;
17
16
  error?: undefined;
17
+ ok?: undefined;
18
18
  } | {
19
19
  count?: undefined;
20
20
  updated: number;
21
- ok?: undefined;
22
21
  error?: undefined;
22
+ ok?: undefined;
23
23
  } | {
24
24
  count?: undefined;
25
25
  updated?: undefined;
@@ -41,28 +41,28 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
- error?: undefined;
45
- ok?: undefined;
46
44
  summary: import("./types.js").TraceSummary;
47
45
  spans: import("./types.js").TraceSpan[];
48
46
  id?: undefined;
49
- } | {
50
47
  error?: undefined;
51
48
  ok?: undefined;
49
+ } | {
52
50
  summary?: undefined;
53
51
  spans?: undefined;
54
52
  id: string;
55
- } | {
53
+ error?: undefined;
56
54
  ok?: undefined;
55
+ } | {
57
56
  summary?: undefined;
58
57
  spans?: undefined;
59
58
  id?: undefined;
60
59
  error: any;
60
+ ok?: undefined;
61
61
  } | {
62
- error?: undefined;
63
62
  summary?: undefined;
64
63
  spans?: undefined;
65
64
  id?: undefined;
65
+ error?: undefined;
66
66
  ok: boolean;
67
67
  }>>;
68
68
  //# sourceMappingURL=routes.d.ts.map
@@ -49,8 +49,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
49
49
  }>;
50
50
  /** DELETE /_agent-native/resources/:id — delete a resource */
51
51
  export declare function handleDeleteResource(event: any): Promise<{
52
- ok?: undefined;
53
52
  error: string;
53
+ ok?: undefined;
54
54
  } | {
55
55
  error?: undefined;
56
56
  ok: boolean;
@@ -34,37 +34,37 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
34
34
  /** POST /_agent-native/secrets/:key — write a secret. */
35
35
  export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
36
36
  error: string;
37
- ok?: undefined;
38
37
  status?: undefined;
38
+ ok?: undefined;
39
39
  } | {
40
- error?: undefined;
41
40
  ok: boolean;
42
41
  status: string;
42
+ error?: undefined;
43
43
  } | {
44
- ok?: undefined;
45
44
  error: string;
46
45
  removed?: undefined;
46
+ ok?: undefined;
47
47
  } | {
48
- error?: undefined;
49
48
  ok: boolean;
50
49
  removed: boolean;
50
+ error?: undefined;
51
51
  }>>;
52
52
  /**
53
53
  * POST /_agent-native/secrets/:key/test — re-run the validator against the
54
54
  * current stored value without changing anything. Useful for the "Test" button.
55
55
  */
56
56
  export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
57
- ok?: undefined;
58
57
  error: string;
59
58
  note?: undefined;
59
+ ok?: undefined;
60
60
  } | {
61
- error?: undefined;
62
61
  ok: boolean;
63
62
  note?: undefined;
64
- } | {
65
63
  error?: undefined;
64
+ } | {
66
65
  ok: boolean;
67
66
  note: string;
67
+ error?: undefined;
68
68
  } | {
69
69
  note?: undefined;
70
70
  ok: boolean;
@@ -95,12 +95,12 @@ export interface AdHocSecretPayload {
95
95
  export declare function createAdHocSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<AdHocSecretPayload[] | {
96
96
  error: string;
97
97
  } | {
98
- error?: undefined;
99
98
  ok: boolean;
100
99
  key: string;
101
- } | {
102
100
  error?: undefined;
101
+ } | {
103
102
  ok: boolean;
104
103
  removed: boolean;
104
+ error?: undefined;
105
105
  }>>;
106
106
  //# sourceMappingURL=routes.d.ts.map
@@ -27,11 +27,11 @@ export declare function resolveAgentEngineApiKeyWriteTarget(event: H3Event, scop
27
27
  export declare function createAgentEngineApiKeyHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
28
28
  error: any;
29
29
  } | {
30
- error?: undefined;
31
30
  ok: boolean;
32
31
  key: string;
33
32
  baseUrlKey?: string;
34
33
  scope: AgentEngineApiKeyScope;
34
+ error?: undefined;
35
35
  }>>;
36
36
  export {};
37
37
  //# sourceMappingURL=agent-engine-api-key-route.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.106.0",
3
+ "version": "0.106.1",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {