@agent-native/core 0.71.0 → 0.72.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 (165) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +60 -0
  3. package/corpus/core/docs/content/actions.md +23 -0
  4. package/corpus/core/docs/content/audit-log.md +111 -0
  5. package/corpus/core/package.json +2 -1
  6. package/corpus/core/src/action.ts +80 -1
  7. package/corpus/core/src/agent/production-agent.ts +27 -0
  8. package/corpus/core/src/agent/run-store.ts +18 -1
  9. package/corpus/core/src/application-state/store.ts +5 -0
  10. package/corpus/core/src/audit/actions/get-audit-event.ts +23 -0
  11. package/corpus/core/src/audit/actions/list-audit-events.ts +65 -0
  12. package/corpus/core/src/audit/cleanup-job.ts +100 -0
  13. package/corpus/core/src/audit/config.ts +91 -0
  14. package/corpus/core/src/audit/index.ts +43 -0
  15. package/corpus/core/src/audit/record.ts +143 -0
  16. package/corpus/core/src/audit/redact.ts +109 -0
  17. package/corpus/core/src/audit/store.ts +244 -0
  18. package/corpus/core/src/audit/types.ts +125 -0
  19. package/corpus/core/src/chat-threads/store.ts +10 -0
  20. package/corpus/core/src/client/AssistantChat.tsx +6 -0
  21. package/corpus/core/src/client/chat/repo-helpers.ts +38 -0
  22. package/corpus/core/src/db/client.ts +4 -0
  23. package/corpus/core/src/db/widen-columns.ts +75 -0
  24. package/corpus/core/src/mcp/build-server.ts +1 -0
  25. package/corpus/core/src/oauth-tokens/store.ts +6 -0
  26. package/corpus/core/src/provider-api/custom-registry.ts +8 -0
  27. package/corpus/core/src/resources/store.ts +10 -0
  28. package/corpus/core/src/scripts/runner.ts +6 -3
  29. package/corpus/core/src/server/action-discovery.ts +6 -0
  30. package/corpus/core/src/server/action-routes.ts +1 -0
  31. package/corpus/core/src/server/auth.ts +5 -0
  32. package/corpus/core/src/server/core-routes-plugin.ts +14 -0
  33. package/corpus/core/src/server/security-headers.ts +9 -6
  34. package/corpus/core/src/settings/store.ts +6 -0
  35. package/corpus/core/src/templates/workspace-core/.agents/skills/audit-log/SKILL.md +93 -0
  36. package/corpus/core/src/usage/store.ts +6 -0
  37. package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +60 -6
  38. package/corpus/templates/calendar/changelog/2026-06-23-added-a-heads-up-explaining-google-s-app-not-verified-screen.md +6 -0
  39. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +20 -43
  40. package/corpus/templates/clips/app/components/recorder/recording-toolbar.tsx +5 -1
  41. package/corpus/templates/clips/app/lib/countdown-audio-cue.ts +3 -51
  42. package/corpus/templates/clips/changelog/2026-06-23-public-clips-now-play-inline-in-slack-connect-a-workspac.md +6 -0
  43. package/corpus/templates/clips/chrome-extension/PERMISSIONS.md +72 -0
  44. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -10
  45. package/corpus/templates/clips/chrome-extension/src/background.ts +34 -1
  46. package/corpus/templates/clips/chrome-extension/src/content-script.ts +138 -11
  47. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +50 -33
  48. package/corpus/templates/clips/chrome-extension/src/overlay.css +11 -27
  49. package/corpus/templates/clips/chrome-extension/src/overlay.html +7 -1
  50. package/corpus/templates/clips/chrome-extension/src/overlay.ts +33 -38
  51. package/corpus/templates/clips/chrome-extension/src/popup.ts +6 -24
  52. package/corpus/templates/clips/chrome-extension/vite.config.ts +5 -0
  53. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +43 -3
  54. package/corpus/templates/clips/server/lib/media-permissions.ts +5 -1
  55. package/corpus/templates/clips/shared/recording-audio.ts +62 -0
  56. package/corpus/templates/clips/shared/recording-core.ts +94 -0
  57. package/dist/action.d.ts +31 -0
  58. package/dist/action.d.ts.map +1 -1
  59. package/dist/action.js +45 -1
  60. package/dist/action.js.map +1 -1
  61. package/dist/agent/context-xray/schema.d.ts +1 -1
  62. package/dist/agent/observational-memory/schema.d.ts +1 -1
  63. package/dist/agent/production-agent.d.ts.map +1 -1
  64. package/dist/agent/production-agent.js +28 -0
  65. package/dist/agent/production-agent.js.map +1 -1
  66. package/dist/agent/run-store.d.ts.map +1 -1
  67. package/dist/agent/run-store.js +18 -1
  68. package/dist/agent/run-store.js.map +1 -1
  69. package/dist/application-state/store.d.ts.map +1 -1
  70. package/dist/application-state/store.js +5 -0
  71. package/dist/application-state/store.js.map +1 -1
  72. package/dist/audit/actions/get-audit-event.d.ts +11 -0
  73. package/dist/audit/actions/get-audit-event.d.ts.map +1 -0
  74. package/dist/audit/actions/get-audit-event.js +22 -0
  75. package/dist/audit/actions/get-audit-event.js.map +1 -0
  76. package/dist/audit/actions/list-audit-events.d.ts +22 -0
  77. package/dist/audit/actions/list-audit-events.d.ts.map +1 -0
  78. package/dist/audit/actions/list-audit-events.js +61 -0
  79. package/dist/audit/actions/list-audit-events.js.map +1 -0
  80. package/dist/audit/cleanup-job.d.ts +12 -0
  81. package/dist/audit/cleanup-job.d.ts.map +1 -0
  82. package/dist/audit/cleanup-job.js +93 -0
  83. package/dist/audit/cleanup-job.js.map +1 -0
  84. package/dist/audit/config.d.ts +30 -0
  85. package/dist/audit/config.d.ts.map +1 -0
  86. package/dist/audit/config.js +65 -0
  87. package/dist/audit/config.js.map +1 -0
  88. package/dist/audit/index.d.ts +13 -0
  89. package/dist/audit/index.d.ts.map +1 -0
  90. package/dist/audit/index.js +6 -0
  91. package/dist/audit/index.js.map +1 -0
  92. package/dist/audit/record.d.ts +24 -0
  93. package/dist/audit/record.d.ts.map +1 -0
  94. package/dist/audit/record.js +106 -0
  95. package/dist/audit/record.js.map +1 -0
  96. package/dist/audit/redact.d.ts +28 -0
  97. package/dist/audit/redact.d.ts.map +1 -0
  98. package/dist/audit/redact.js +109 -0
  99. package/dist/audit/redact.js.map +1 -0
  100. package/dist/audit/store.d.ts +14 -0
  101. package/dist/audit/store.d.ts.map +1 -0
  102. package/dist/audit/store.js +219 -0
  103. package/dist/audit/store.js.map +1 -0
  104. package/dist/audit/types.d.ts +114 -0
  105. package/dist/audit/types.d.ts.map +1 -0
  106. package/dist/audit/types.js +15 -0
  107. package/dist/audit/types.js.map +1 -0
  108. package/dist/chat-threads/store.d.ts.map +1 -1
  109. package/dist/chat-threads/store.js +10 -0
  110. package/dist/chat-threads/store.js.map +1 -1
  111. package/dist/client/AssistantChat.d.ts.map +1 -1
  112. package/dist/client/AssistantChat.js +6 -1
  113. package/dist/client/AssistantChat.js.map +1 -1
  114. package/dist/client/chat/repo-helpers.d.ts +16 -0
  115. package/dist/client/chat/repo-helpers.d.ts.map +1 -1
  116. package/dist/client/chat/repo-helpers.js +40 -0
  117. package/dist/client/chat/repo-helpers.js.map +1 -1
  118. package/dist/db/client.d.ts.map +1 -1
  119. package/dist/db/client.js +3 -0
  120. package/dist/db/client.js.map +1 -1
  121. package/dist/db/widen-columns.d.ts +39 -0
  122. package/dist/db/widen-columns.d.ts.map +1 -0
  123. package/dist/db/widen-columns.js +73 -0
  124. package/dist/db/widen-columns.js.map +1 -0
  125. package/dist/mcp/build-server.d.ts.map +1 -1
  126. package/dist/mcp/build-server.js +1 -0
  127. package/dist/mcp/build-server.js.map +1 -1
  128. package/dist/oauth-tokens/store.d.ts.map +1 -1
  129. package/dist/oauth-tokens/store.js +6 -0
  130. package/dist/oauth-tokens/store.js.map +1 -1
  131. package/dist/provider-api/custom-registry.d.ts.map +1 -1
  132. package/dist/provider-api/custom-registry.js +8 -0
  133. package/dist/provider-api/custom-registry.js.map +1 -1
  134. package/dist/resources/store.d.ts.map +1 -1
  135. package/dist/resources/store.js +9 -0
  136. package/dist/resources/store.js.map +1 -1
  137. package/dist/scripts/runner.js +4 -3
  138. package/dist/scripts/runner.js.map +1 -1
  139. package/dist/server/action-discovery.d.ts.map +1 -1
  140. package/dist/server/action-discovery.js +6 -0
  141. package/dist/server/action-discovery.js.map +1 -1
  142. package/dist/server/action-routes.d.ts.map +1 -1
  143. package/dist/server/action-routes.js +1 -0
  144. package/dist/server/action-routes.js.map +1 -1
  145. package/dist/server/auth.d.ts.map +1 -1
  146. package/dist/server/auth.js +5 -0
  147. package/dist/server/auth.js.map +1 -1
  148. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  149. package/dist/server/core-routes-plugin.js +13 -0
  150. package/dist/server/core-routes-plugin.js.map +1 -1
  151. package/dist/server/security-headers.d.ts +8 -5
  152. package/dist/server/security-headers.d.ts.map +1 -1
  153. package/dist/server/security-headers.js +9 -6
  154. package/dist/server/security-headers.js.map +1 -1
  155. package/dist/settings/store.d.ts.map +1 -1
  156. package/dist/settings/store.js +6 -0
  157. package/dist/settings/store.js.map +1 -1
  158. package/dist/templates/workspace-core/.agents/skills/audit-log/SKILL.md +93 -0
  159. package/dist/usage/store.d.ts.map +1 -1
  160. package/dist/usage/store.js +5 -0
  161. package/dist/usage/store.js.map +1 -1
  162. package/docs/content/actions.md +23 -0
  163. package/docs/content/audit-log.md +111 -0
  164. package/package.json +2 -1
  165. package/src/templates/workspace-core/.agents/skills/audit-log/SKILL.md +93 -0
@@ -0,0 +1,219 @@
1
+ /**
2
+ * SQL persistence for the framework audit log.
3
+ *
4
+ * Follows the same raw-SQL, provider-agnostic pattern as observability/store.ts
5
+ * and usage/store.ts — framework tables use `getDbExec()` + `intType()` rather
6
+ * than Drizzle ORM (which is for template-level schemas). One append-only table
7
+ * `agent_audit_log`; reads are scoped to the caller's identity in SQL (no
8
+ * shares table — audit rows are never individually shared).
9
+ */
10
+ import { getDbExec, intType, retryOnDdlRace } from "../db/client.js";
11
+ let _initPromise;
12
+ export async function ensureAuditTables() {
13
+ if (!_initPromise) {
14
+ _initPromise = (async () => {
15
+ const client = getDbExec();
16
+ await retryOnDdlRace(() => client.execute(`
17
+ CREATE TABLE IF NOT EXISTS agent_audit_log (
18
+ id TEXT PRIMARY KEY,
19
+ created_at ${intType()} NOT NULL,
20
+ action TEXT NOT NULL,
21
+ caller TEXT NOT NULL,
22
+ actor_kind TEXT NOT NULL,
23
+ actor_email TEXT,
24
+ org_id TEXT,
25
+ thread_id TEXT,
26
+ turn_id TEXT,
27
+ target_type TEXT,
28
+ target_id TEXT,
29
+ status TEXT NOT NULL DEFAULT 'success',
30
+ summary TEXT,
31
+ input TEXT,
32
+ error_code TEXT,
33
+ owner_email TEXT,
34
+ visibility TEXT NOT NULL DEFAULT 'private'
35
+ )
36
+ `));
37
+ const indexes = [
38
+ `CREATE INDEX IF NOT EXISTS idx_audit_owner ON agent_audit_log (owner_email, created_at)`,
39
+ `CREATE INDEX IF NOT EXISTS idx_audit_org ON agent_audit_log (org_id, created_at)`,
40
+ `CREATE INDEX IF NOT EXISTS idx_audit_target ON agent_audit_log (target_type, target_id, created_at)`,
41
+ `CREATE INDEX IF NOT EXISTS idx_audit_turn ON agent_audit_log (turn_id)`,
42
+ `CREATE INDEX IF NOT EXISTS idx_audit_actor ON agent_audit_log (actor_email, created_at)`,
43
+ `CREATE INDEX IF NOT EXISTS idx_audit_created ON agent_audit_log (created_at)`,
44
+ ];
45
+ for (const sql of indexes) {
46
+ try {
47
+ await client.execute(sql);
48
+ }
49
+ catch {
50
+ // Index creation is best-effort; a racing boot may have created it.
51
+ }
52
+ }
53
+ })().catch((err) => {
54
+ // Allow a later call to retry if the first init failed.
55
+ _initPromise = undefined;
56
+ throw err;
57
+ });
58
+ }
59
+ return _initPromise;
60
+ }
61
+ export async function insertAuditEvent(event) {
62
+ await ensureAuditTables();
63
+ const client = getDbExec();
64
+ await client.execute({
65
+ sql: `INSERT INTO agent_audit_log
66
+ (id, created_at, action, caller, actor_kind, actor_email, org_id,
67
+ thread_id, turn_id, target_type, target_id, status, summary, input,
68
+ error_code, owner_email, visibility)
69
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
70
+ args: [
71
+ event.id,
72
+ event.createdAt,
73
+ event.action,
74
+ event.caller,
75
+ event.actorKind,
76
+ event.actorEmail,
77
+ event.orgId,
78
+ event.threadId,
79
+ event.turnId,
80
+ event.targetType,
81
+ event.targetId,
82
+ event.status,
83
+ event.summary,
84
+ event.input,
85
+ event.errorCode,
86
+ event.ownerEmail,
87
+ event.visibility,
88
+ ],
89
+ });
90
+ }
91
+ function mapRow(row) {
92
+ return {
93
+ id: String(row.id),
94
+ createdAt: Number(row.created_at),
95
+ action: String(row.action),
96
+ caller: String(row.caller),
97
+ actorKind: row.actor_kind,
98
+ actorEmail: row.actor_email ?? null,
99
+ orgId: row.org_id ?? null,
100
+ threadId: row.thread_id ?? null,
101
+ turnId: row.turn_id ?? null,
102
+ targetType: row.target_type ?? null,
103
+ targetId: row.target_id ?? null,
104
+ status: row.status,
105
+ summary: row.summary ?? null,
106
+ input: row.input ?? null,
107
+ errorCode: row.error_code ?? null,
108
+ ownerEmail: row.owner_email ?? null,
109
+ visibility: (row.visibility ?? "private"),
110
+ };
111
+ }
112
+ /**
113
+ * Build the access-scoping WHERE fragment + args. A caller sees audit rows they
114
+ * own, plus org-visible rows in their org. With no identity, nothing matches —
115
+ * the audit log never leaks cross-tenant. Mirrors the core ownership clause of
116
+ * `accessFilter` (minus shares, which audit rows don't have).
117
+ */
118
+ function scopeClause(scope) {
119
+ const clauses = [];
120
+ const args = [];
121
+ if (scope.userEmail) {
122
+ if (scope.orgId) {
123
+ // Constrain the owner's rows to the active org — plus legacy/solo rows
124
+ // that predate org-scoping (org_id IS NULL) — mirroring sharing's
125
+ // `ownerScopeFilter`, so switching orgs doesn't surface another org's
126
+ // trail.
127
+ clauses.push("(owner_email = ? AND (org_id = ? OR org_id IS NULL))");
128
+ args.push(scope.userEmail, scope.orgId);
129
+ }
130
+ else {
131
+ clauses.push("owner_email = ?");
132
+ args.push(scope.userEmail);
133
+ }
134
+ }
135
+ if (scope.orgId) {
136
+ clauses.push("(visibility = 'org' AND org_id = ?)");
137
+ args.push(scope.orgId);
138
+ }
139
+ if (clauses.length === 0)
140
+ return { sql: "1=0", args };
141
+ return { sql: `(${clauses.join(" OR ")})`, args };
142
+ }
143
+ const MAX_LIMIT = 500;
144
+ const DEFAULT_LIMIT = 100;
145
+ // Columns returned by the list surface — deliberately EXCLUDES `input` so a
146
+ // timeline query never streams every event's (redacted) request body in bulk.
147
+ // Fetch the full payload one event at a time via `getAuditEventById`.
148
+ const LIST_COLUMNS = "id, created_at, action, caller, actor_kind, actor_email, org_id, " +
149
+ "thread_id, turn_id, target_type, target_id, status, summary, " +
150
+ "error_code, owner_email, visibility";
151
+ export async function queryAuditEvents(scope, filters = {}) {
152
+ await ensureAuditTables();
153
+ if (!scope.userEmail && !scope.orgId)
154
+ return [];
155
+ const client = getDbExec();
156
+ const scoped = scopeClause(scope);
157
+ const where = [scoped.sql];
158
+ const args = [...scoped.args];
159
+ const push = (clause, value) => {
160
+ where.push(clause);
161
+ args.push(value);
162
+ };
163
+ if (filters.targetType)
164
+ push("target_type = ?", filters.targetType);
165
+ if (filters.targetId)
166
+ push("target_id = ?", filters.targetId);
167
+ if (filters.actorKind)
168
+ push("actor_kind = ?", filters.actorKind);
169
+ if (filters.actorEmail)
170
+ push("actor_email = ?", filters.actorEmail);
171
+ if (filters.status)
172
+ push("status = ?", filters.status);
173
+ if (filters.threadId)
174
+ push("thread_id = ?", filters.threadId);
175
+ if (filters.turnId)
176
+ push("turn_id = ?", filters.turnId);
177
+ if (filters.action)
178
+ push("action = ?", filters.action);
179
+ if (typeof filters.sinceMs === "number") {
180
+ push("created_at >= ?", Math.floor(filters.sinceMs));
181
+ }
182
+ const limit = Math.min(Math.max(1, Math.floor(filters.limit ?? DEFAULT_LIMIT)), MAX_LIMIT);
183
+ const result = await client.execute({
184
+ sql: `SELECT ${LIST_COLUMNS} FROM agent_audit_log
185
+ WHERE ${where.join(" AND ")}
186
+ ORDER BY created_at DESC
187
+ LIMIT ?`,
188
+ args: [...args, limit],
189
+ });
190
+ return (result.rows ?? []).map(mapRow);
191
+ }
192
+ export async function getAuditEventById(id, scope) {
193
+ await ensureAuditTables();
194
+ if (!scope.userEmail && !scope.orgId)
195
+ return null;
196
+ const client = getDbExec();
197
+ const scoped = scopeClause(scope);
198
+ const result = await client.execute({
199
+ sql: `SELECT * FROM agent_audit_log WHERE id = ? AND ${scoped.sql} LIMIT 1`,
200
+ args: [id, ...scoped.args],
201
+ });
202
+ const row = (result.rows ?? [])[0];
203
+ return row ? mapRow(row) : null;
204
+ }
205
+ /** Purge audit rows older than `cutoffMs`. Returns the deleted row count. */
206
+ export async function deleteOldAuditEvents(cutoffMs) {
207
+ await ensureAuditTables();
208
+ const client = getDbExec();
209
+ const result = await client.execute({
210
+ sql: `DELETE FROM agent_audit_log WHERE created_at < ?`,
211
+ args: [Math.floor(cutoffMs)],
212
+ });
213
+ return Number(result.rowsAffected ?? 0);
214
+ }
215
+ /** Test-only: reset the cached init promise so a fresh DB re-creates tables. */
216
+ export function __resetAuditInitForTests() {
217
+ _initPromise = undefined;
218
+ }
219
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/audit/store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SQL persistence for the framework audit log.\n *\n * Follows the same raw-SQL, provider-agnostic pattern as observability/store.ts\n * and usage/store.ts — framework tables use `getDbExec()` + `intType()` rather\n * than Drizzle ORM (which is for template-level schemas). One append-only table\n * `agent_audit_log`; reads are scoped to the caller's identity in SQL (no\n * shares table — audit rows are never individually shared).\n */\nimport { getDbExec, intType, retryOnDdlRace } from \"../db/client.js\";\nimport type {\n AuditEvent,\n AuditQueryFilters,\n AuditVisibility,\n} from \"./types.js\";\n\nlet _initPromise: Promise<void> | undefined;\n\nexport async function ensureAuditTables(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n\n await retryOnDdlRace(() =>\n client.execute(`\n CREATE TABLE IF NOT EXISTS agent_audit_log (\n id TEXT PRIMARY KEY,\n created_at ${intType()} NOT NULL,\n action TEXT NOT NULL,\n caller TEXT NOT NULL,\n actor_kind TEXT NOT NULL,\n actor_email TEXT,\n org_id TEXT,\n thread_id TEXT,\n turn_id TEXT,\n target_type TEXT,\n target_id TEXT,\n status TEXT NOT NULL DEFAULT 'success',\n summary TEXT,\n input TEXT,\n error_code TEXT,\n owner_email TEXT,\n visibility TEXT NOT NULL DEFAULT 'private'\n )\n `),\n );\n\n const indexes = [\n `CREATE INDEX IF NOT EXISTS idx_audit_owner ON agent_audit_log (owner_email, created_at)`,\n `CREATE INDEX IF NOT EXISTS idx_audit_org ON agent_audit_log (org_id, created_at)`,\n `CREATE INDEX IF NOT EXISTS idx_audit_target ON agent_audit_log (target_type, target_id, created_at)`,\n `CREATE INDEX IF NOT EXISTS idx_audit_turn ON agent_audit_log (turn_id)`,\n `CREATE INDEX IF NOT EXISTS idx_audit_actor ON agent_audit_log (actor_email, created_at)`,\n `CREATE INDEX IF NOT EXISTS idx_audit_created ON agent_audit_log (created_at)`,\n ];\n for (const sql of indexes) {\n try {\n await client.execute(sql);\n } catch {\n // Index creation is best-effort; a racing boot may have created it.\n }\n }\n })().catch((err) => {\n // Allow a later call to retry if the first init failed.\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\nexport async function insertAuditEvent(event: AuditEvent): Promise<void> {\n await ensureAuditTables();\n const client = getDbExec();\n await client.execute({\n sql: `INSERT INTO agent_audit_log\n (id, created_at, action, caller, actor_kind, actor_email, org_id,\n thread_id, turn_id, target_type, target_id, status, summary, input,\n error_code, owner_email, visibility)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n args: [\n event.id,\n event.createdAt,\n event.action,\n event.caller,\n event.actorKind,\n event.actorEmail,\n event.orgId,\n event.threadId,\n event.turnId,\n event.targetType,\n event.targetId,\n event.status,\n event.summary,\n event.input,\n event.errorCode,\n event.ownerEmail,\n event.visibility,\n ],\n });\n}\n\nfunction mapRow(row: any): AuditEvent {\n return {\n id: String(row.id),\n createdAt: Number(row.created_at),\n action: String(row.action),\n caller: String(row.caller),\n actorKind: row.actor_kind,\n actorEmail: row.actor_email ?? null,\n orgId: row.org_id ?? null,\n threadId: row.thread_id ?? null,\n turnId: row.turn_id ?? null,\n targetType: row.target_type ?? null,\n targetId: row.target_id ?? null,\n status: row.status,\n summary: row.summary ?? null,\n input: row.input ?? null,\n errorCode: row.error_code ?? null,\n ownerEmail: row.owner_email ?? null,\n visibility: (row.visibility ?? \"private\") as AuditVisibility,\n };\n}\n\nexport interface AuditReadScope {\n userEmail?: string;\n orgId?: string | null;\n}\n\n/**\n * Build the access-scoping WHERE fragment + args. A caller sees audit rows they\n * own, plus org-visible rows in their org. With no identity, nothing matches —\n * the audit log never leaks cross-tenant. Mirrors the core ownership clause of\n * `accessFilter` (minus shares, which audit rows don't have).\n */\nfunction scopeClause(scope: AuditReadScope): { sql: string; args: any[] } {\n const clauses: string[] = [];\n const args: any[] = [];\n if (scope.userEmail) {\n if (scope.orgId) {\n // Constrain the owner's rows to the active org — plus legacy/solo rows\n // that predate org-scoping (org_id IS NULL) — mirroring sharing's\n // `ownerScopeFilter`, so switching orgs doesn't surface another org's\n // trail.\n clauses.push(\"(owner_email = ? AND (org_id = ? OR org_id IS NULL))\");\n args.push(scope.userEmail, scope.orgId);\n } else {\n clauses.push(\"owner_email = ?\");\n args.push(scope.userEmail);\n }\n }\n if (scope.orgId) {\n clauses.push(\"(visibility = 'org' AND org_id = ?)\");\n args.push(scope.orgId);\n }\n if (clauses.length === 0) return { sql: \"1=0\", args };\n return { sql: `(${clauses.join(\" OR \")})`, args };\n}\n\nconst MAX_LIMIT = 500;\nconst DEFAULT_LIMIT = 100;\n\n// Columns returned by the list surface — deliberately EXCLUDES `input` so a\n// timeline query never streams every event's (redacted) request body in bulk.\n// Fetch the full payload one event at a time via `getAuditEventById`.\nconst LIST_COLUMNS =\n \"id, created_at, action, caller, actor_kind, actor_email, org_id, \" +\n \"thread_id, turn_id, target_type, target_id, status, summary, \" +\n \"error_code, owner_email, visibility\";\n\nexport async function queryAuditEvents(\n scope: AuditReadScope,\n filters: AuditQueryFilters = {},\n): Promise<AuditEvent[]> {\n await ensureAuditTables();\n if (!scope.userEmail && !scope.orgId) return [];\n const client = getDbExec();\n\n const scoped = scopeClause(scope);\n const where: string[] = [scoped.sql];\n const args: any[] = [...scoped.args];\n\n const push = (clause: string, value: any) => {\n where.push(clause);\n args.push(value);\n };\n if (filters.targetType) push(\"target_type = ?\", filters.targetType);\n if (filters.targetId) push(\"target_id = ?\", filters.targetId);\n if (filters.actorKind) push(\"actor_kind = ?\", filters.actorKind);\n if (filters.actorEmail) push(\"actor_email = ?\", filters.actorEmail);\n if (filters.status) push(\"status = ?\", filters.status);\n if (filters.threadId) push(\"thread_id = ?\", filters.threadId);\n if (filters.turnId) push(\"turn_id = ?\", filters.turnId);\n if (filters.action) push(\"action = ?\", filters.action);\n if (typeof filters.sinceMs === \"number\") {\n push(\"created_at >= ?\", Math.floor(filters.sinceMs));\n }\n\n const limit = Math.min(\n Math.max(1, Math.floor(filters.limit ?? DEFAULT_LIMIT)),\n MAX_LIMIT,\n );\n\n const result = await client.execute({\n sql: `SELECT ${LIST_COLUMNS} FROM agent_audit_log\n WHERE ${where.join(\" AND \")}\n ORDER BY created_at DESC\n LIMIT ?`,\n args: [...args, limit],\n });\n return (result.rows ?? []).map(mapRow);\n}\n\nexport async function getAuditEventById(\n id: string,\n scope: AuditReadScope,\n): Promise<AuditEvent | null> {\n await ensureAuditTables();\n if (!scope.userEmail && !scope.orgId) return null;\n const client = getDbExec();\n const scoped = scopeClause(scope);\n const result = await client.execute({\n sql: `SELECT * FROM agent_audit_log WHERE id = ? AND ${scoped.sql} LIMIT 1`,\n args: [id, ...scoped.args],\n });\n const row = (result.rows ?? [])[0];\n return row ? mapRow(row) : null;\n}\n\n/** Purge audit rows older than `cutoffMs`. Returns the deleted row count. */\nexport async function deleteOldAuditEvents(cutoffMs: number): Promise<number> {\n await ensureAuditTables();\n const client = getDbExec();\n const result = await client.execute({\n sql: `DELETE FROM agent_audit_log WHERE created_at < ?`,\n args: [Math.floor(cutoffMs)],\n });\n return Number(result.rowsAffected ?? 0);\n}\n\n/** Test-only: reset the cached init promise so a fresh DB re-creates tables. */\nexport function __resetAuditInitForTests(): void {\n _initPromise = undefined;\n}\n"]}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Types for the framework audit log.
3
+ *
4
+ * The audit log is a durable, complete, access-scoped, append-only record of
5
+ * *who mutated what app data, when, from where, and — when it was the agent —
6
+ * in which run*. It is deliberately distinct from observability (sampled
7
+ * agent-run telemetry) and tracking (fire-and-forget product analytics): audit
8
+ * rows are complete, locally queryable, and scoped to the data they describe.
9
+ *
10
+ * Capture happens automatically at the action-execution seam (`defineAction`):
11
+ * every mutating action records an audit event after it runs. Read-only (GET /
12
+ * `readOnly`) actions are skipped unless they opt in via `audit.onRead`.
13
+ */
14
+ /** Outcome of an audited action call. */
15
+ export type AuditStatus = "success" | "error" | "denied";
16
+ /**
17
+ * Who performed the mutation.
18
+ * - `agent` — the in-app assistant / sub-agents / A2A (caller `"tool"`).
19
+ * - `human` — a person via the UI, HTTP, CLI, or an external MCP client.
20
+ * - `system` — no resolved identity (background jobs, schedules).
21
+ */
22
+ export type AuditActorKind = "agent" | "human" | "system";
23
+ export type AuditVisibility = "private" | "org" | "public";
24
+ /**
25
+ * The resource an action mutated, plus the ownership used to scope who can
26
+ * read the resulting audit event. Returned by an action's `audit.target`.
27
+ *
28
+ * `ownerEmail` / `orgId` / `visibility` default to the actor's identity when
29
+ * omitted, which is correct for the common case where a user mutates their own
30
+ * data. Provide them explicitly when a user edits a resource owned by someone
31
+ * else so the *owner* sees the change in their audit trail.
32
+ */
33
+ export interface AuditTarget {
34
+ type?: string;
35
+ id?: string;
36
+ ownerEmail?: string | null;
37
+ orgId?: string | null;
38
+ visibility?: AuditVisibility;
39
+ }
40
+ /** Metadata about the call, passed to `audit.target` / `audit.summary`. */
41
+ export interface AuditCallMeta {
42
+ status: AuditStatus;
43
+ caller: string;
44
+ userEmail?: string;
45
+ orgId?: string | null;
46
+ }
47
+ /**
48
+ * Per-action audit configuration, set on `defineAction({ audit })`.
49
+ *
50
+ * Audit is **default-on for mutating actions** — you only need this object to
51
+ * *tune* capture (declare the target, customize the summary) or to opt a
52
+ * read-only action in / a noisy action out.
53
+ */
54
+ export interface ActionAuditConfig {
55
+ /**
56
+ * Force audit on (`true`) or off (`false`). Overrides every default,
57
+ * including the read-only skip and the high-frequency denylist. When
58
+ * omitted, mutating actions are audited and read-only actions are not.
59
+ */
60
+ enabled?: boolean;
61
+ /**
62
+ * Audit this action even though it is read-only (GET). Use for sensitive
63
+ * reads worth recording — secret access, bulk export. Ignored when
64
+ * `enabled` is set explicitly.
65
+ */
66
+ onRead?: boolean;
67
+ /** Capture the (redacted) call arguments. Default `true`. */
68
+ recordInputs?: boolean;
69
+ /** Resolve the mutated resource + its ownership for scoped reads. */
70
+ target?: (args: any, result: unknown, meta: AuditCallMeta) => AuditTarget | null | undefined;
71
+ /** Build a short human-readable summary line for the event. */
72
+ summary?: (args: any, result: unknown, meta: AuditCallMeta) => string;
73
+ }
74
+ /** A persisted audit event. */
75
+ export interface AuditEvent {
76
+ id: string;
77
+ createdAt: number;
78
+ /** Action name (the registry key, e.g. `delete-recording`). */
79
+ action: string;
80
+ /** Invocation surface: tool | frontend | http | cli | mcp | a2a. */
81
+ caller: string;
82
+ actorKind: AuditActorKind;
83
+ /** Human on whose behalf it ran — populated even for agent calls. */
84
+ actorEmail: string | null;
85
+ orgId: string | null;
86
+ /** Agent conversation thread, when caller is the agent loop. */
87
+ threadId: string | null;
88
+ /** Agent turn that produced the mutation — the unit of one agent response. */
89
+ turnId: string | null;
90
+ targetType: string | null;
91
+ targetId: string | null;
92
+ status: AuditStatus;
93
+ summary: string | null;
94
+ /** Redacted JSON of the call arguments, or null. */
95
+ input: string | null;
96
+ errorCode: string | null;
97
+ /** Denormalized owner used to scope reads (defaults to the actor). */
98
+ ownerEmail: string | null;
99
+ visibility: AuditVisibility;
100
+ }
101
+ /** Filters for `queryAuditEvents`. */
102
+ export interface AuditQueryFilters {
103
+ targetType?: string;
104
+ targetId?: string;
105
+ actorKind?: AuditActorKind;
106
+ actorEmail?: string;
107
+ status?: AuditStatus;
108
+ threadId?: string;
109
+ turnId?: string;
110
+ action?: string;
111
+ sinceMs?: number;
112
+ limit?: number;
113
+ }
114
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/audit/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Types for the framework audit log.
3
+ *
4
+ * The audit log is a durable, complete, access-scoped, append-only record of
5
+ * *who mutated what app data, when, from where, and — when it was the agent —
6
+ * in which run*. It is deliberately distinct from observability (sampled
7
+ * agent-run telemetry) and tracking (fire-and-forget product analytics): audit
8
+ * rows are complete, locally queryable, and scoped to the data they describe.
9
+ *
10
+ * Capture happens automatically at the action-execution seam (`defineAction`):
11
+ * every mutating action records an audit event after it runs. Read-only (GET /
12
+ * `readOnly`) actions are skipped unless they opt in via `audit.onRead`.
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/audit/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG","sourcesContent":["/**\n * Types for the framework audit log.\n *\n * The audit log is a durable, complete, access-scoped, append-only record of\n * *who mutated what app data, when, from where, and — when it was the agent —\n * in which run*. It is deliberately distinct from observability (sampled\n * agent-run telemetry) and tracking (fire-and-forget product analytics): audit\n * rows are complete, locally queryable, and scoped to the data they describe.\n *\n * Capture happens automatically at the action-execution seam (`defineAction`):\n * every mutating action records an audit event after it runs. Read-only (GET /\n * `readOnly`) actions are skipped unless they opt in via `audit.onRead`.\n */\n\n/** Outcome of an audited action call. */\nexport type AuditStatus = \"success\" | \"error\" | \"denied\";\n\n/**\n * Who performed the mutation.\n * - `agent` — the in-app assistant / sub-agents / A2A (caller `\"tool\"`).\n * - `human` — a person via the UI, HTTP, CLI, or an external MCP client.\n * - `system` — no resolved identity (background jobs, schedules).\n */\nexport type AuditActorKind = \"agent\" | \"human\" | \"system\";\n\nexport type AuditVisibility = \"private\" | \"org\" | \"public\";\n\n/**\n * The resource an action mutated, plus the ownership used to scope who can\n * read the resulting audit event. Returned by an action's `audit.target`.\n *\n * `ownerEmail` / `orgId` / `visibility` default to the actor's identity when\n * omitted, which is correct for the common case where a user mutates their own\n * data. Provide them explicitly when a user edits a resource owned by someone\n * else so the *owner* sees the change in their audit trail.\n */\nexport interface AuditTarget {\n type?: string;\n id?: string;\n ownerEmail?: string | null;\n orgId?: string | null;\n visibility?: AuditVisibility;\n}\n\n/** Metadata about the call, passed to `audit.target` / `audit.summary`. */\nexport interface AuditCallMeta {\n status: AuditStatus;\n caller: string;\n userEmail?: string;\n orgId?: string | null;\n}\n\n/**\n * Per-action audit configuration, set on `defineAction({ audit })`.\n *\n * Audit is **default-on for mutating actions** — you only need this object to\n * *tune* capture (declare the target, customize the summary) or to opt a\n * read-only action in / a noisy action out.\n */\nexport interface ActionAuditConfig {\n /**\n * Force audit on (`true`) or off (`false`). Overrides every default,\n * including the read-only skip and the high-frequency denylist. When\n * omitted, mutating actions are audited and read-only actions are not.\n */\n enabled?: boolean;\n /**\n * Audit this action even though it is read-only (GET). Use for sensitive\n * reads worth recording — secret access, bulk export. Ignored when\n * `enabled` is set explicitly.\n */\n onRead?: boolean;\n /** Capture the (redacted) call arguments. Default `true`. */\n recordInputs?: boolean;\n /** Resolve the mutated resource + its ownership for scoped reads. */\n target?: (\n args: any,\n result: unknown,\n meta: AuditCallMeta,\n ) => AuditTarget | null | undefined;\n /** Build a short human-readable summary line for the event. */\n summary?: (args: any, result: unknown, meta: AuditCallMeta) => string;\n}\n\n/** A persisted audit event. */\nexport interface AuditEvent {\n id: string;\n createdAt: number;\n /** Action name (the registry key, e.g. `delete-recording`). */\n action: string;\n /** Invocation surface: tool | frontend | http | cli | mcp | a2a. */\n caller: string;\n actorKind: AuditActorKind;\n /** Human on whose behalf it ran — populated even for agent calls. */\n actorEmail: string | null;\n orgId: string | null;\n /** Agent conversation thread, when caller is the agent loop. */\n threadId: string | null;\n /** Agent turn that produced the mutation — the unit of one agent response. */\n turnId: string | null;\n targetType: string | null;\n targetId: string | null;\n status: AuditStatus;\n summary: string | null;\n /** Redacted JSON of the call arguments, or null. */\n input: string | null;\n errorCode: string | null;\n /** Denormalized owner used to scope reads (defaults to the actor). */\n ownerEmail: string | null;\n visibility: AuditVisibility;\n}\n\n/** Filters for `queryAuditEvents`. */\nexport interface AuditQueryFilters {\n targetType?: string;\n targetId?: string;\n actorKind?: AuditActorKind;\n actorEmail?: string;\n status?: AuditStatus;\n threadId?: string;\n turnId?: string;\n action?: string;\n sinceMs?: number;\n limit?: number;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/chat-threads/store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/chat-threads/store.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import crypto from "node:crypto";
2
2
  import { getDbExec, intType } from "../db/client.js";
3
+ import { widenIntColumnsToBigInt } from "../db/widen-columns.js";
3
4
  import { mergeThreadDataForClientSave, normalizeThreadRepository, normalizeThreadTitle, } from "../agent/thread-data-builder.js";
4
5
  import { emitChatThreadChange } from "./emitter.js";
5
6
  let _initPromise;
@@ -75,6 +76,15 @@ async function ensureTable() {
75
76
  // Column already exists.
76
77
  }
77
78
  }
79
+ // Widen millisecond-timestamp columns that older deployments created as
80
+ // 32-bit `INTEGER`; on Postgres the `Date.now()` written on every turn
81
+ // overflows int4. No-op once widened / on fresh BIGINT databases.
82
+ await widenIntColumnsToBigInt("chat_threads", [
83
+ "created_at",
84
+ "updated_at",
85
+ "pinned_at",
86
+ "archived_at",
87
+ ]);
78
88
  // Indexes for the hot read paths. Both the sidebar list and the
79
89
  // scoped/per-resource list filter on owner_email (and optionally
80
90
  // scope) and sort by updated_at. Keep these dialect-agnostic (no