@agent-native/core 0.84.0 → 0.84.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +13 -0
- package/corpus/core/docs/content/evals.mdx +34 -12
- package/corpus/core/docs/content/locales/ar-SA/evals.mdx +7 -0
- package/corpus/core/docs/content/locales/de-DE/evals.mdx +8 -0
- package/corpus/core/docs/content/locales/es-ES/evals.mdx +8 -0
- package/corpus/core/docs/content/locales/fr-FR/evals.mdx +8 -0
- package/corpus/core/docs/content/locales/hi-IN/evals.mdx +8 -0
- package/corpus/core/docs/content/locales/ja-JP/evals.mdx +7 -0
- package/corpus/core/docs/content/locales/ko-KR/evals.mdx +7 -0
- package/corpus/core/docs/content/locales/pt-BR/evals.mdx +8 -0
- package/corpus/core/docs/content/locales/zh-CN/evals.mdx +7 -0
- package/corpus/core/docs/content/locales/zh-TW/evals.mdx +7 -0
- package/corpus/core/docs/design/durable-agent-runs.md +34 -35
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/engine/builder-engine.ts +81 -9
- package/corpus/core/src/agent/run-manager.ts +8 -7
- package/corpus/core/src/cli/design-connect.ts +175 -0
- package/corpus/core/src/cli/skills.ts +5 -7
- package/corpus/core/src/client/AgentPanel.tsx +8 -0
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +4 -1
- package/corpus/core/src/client/agent-chat-adapter.ts +45 -15
- package/corpus/core/src/client/sse-event-processor.ts +31 -4
- package/corpus/core/src/eval/define-eval.ts +4 -1
- package/corpus/core/src/eval/report.ts +23 -8
- package/corpus/core/src/eval/runner.ts +41 -6
- package/corpus/core/src/eval/types.ts +11 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +15 -17
- package/corpus/templates/content/AGENTS.md +9 -2
- package/corpus/templates/content/actions/_database-row-batch.ts +230 -0
- package/corpus/templates/content/actions/_database-utils.ts +17 -9
- package/corpus/templates/content/actions/_notion-action-utils.ts +26 -0
- package/corpus/templates/content/actions/connect-notion-status.ts +13 -4
- package/corpus/templates/content/actions/create-and-link-notion-page.ts +23 -0
- package/corpus/templates/content/actions/delete-database-items.ts +55 -0
- package/corpus/templates/content/actions/delete-document.ts +4 -4
- package/corpus/templates/content/actions/disconnect-notion.ts +16 -0
- package/corpus/templates/content/actions/duplicate-database-item.ts +1 -1
- package/corpus/templates/content/actions/duplicate-database-items.ts +191 -0
- package/corpus/templates/content/actions/link-notion-page.ts +10 -7
- package/corpus/templates/content/actions/list-notion-links.ts +3 -4
- package/corpus/templates/content/actions/pull-notion-page.ts +7 -9
- package/corpus/templates/content/actions/push-notion-page.ts +7 -9
- package/corpus/templates/content/actions/refresh-notion-sync-status.ts +24 -0
- package/corpus/templates/content/actions/resolve-notion-sync-conflict.ts +23 -0
- package/corpus/templates/content/actions/search-notion-pages.ts +67 -0
- package/corpus/templates/content/actions/unlink-notion-page.ts +23 -0
- package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +27 -34
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +16 -13
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +10 -10
- package/corpus/templates/content/app/components/editor/NotionConflictBanner.tsx +1 -1
- package/corpus/templates/content/app/components/editor/NotionSyncBar.tsx +18 -9
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +27 -34
- package/corpus/templates/content/app/components/editor/database/navigation-state.ts +10 -4
- package/corpus/templates/content/app/components/sidebar/NotionButton.tsx +32 -17
- package/corpus/templates/content/app/hooks/use-content-database.ts +35 -0
- package/corpus/templates/content/app/hooks/use-notion.ts +108 -99
- package/corpus/templates/content/package.json +3 -0
- package/corpus/templates/content/parity/README.md +69 -0
- package/corpus/templates/content/parity/eval-scenarios.ts +118 -0
- package/corpus/templates/content/parity/exceptions.allowlist.ts +17 -0
- package/corpus/templates/content/parity/matrix.md +28 -0
- package/corpus/templates/content/parity/matrix.ts +606 -0
- package/corpus/templates/content/parity/matrix.types.ts +42 -0
- package/corpus/templates/content/parity/parity-evals.eval.ts +4 -0
- package/corpus/templates/content/parity/render-matrix.ts +90 -0
- package/corpus/templates/content/parity/scenario-to-eval.ts +57 -0
- package/corpus/templates/content/shared/api.ts +11 -0
- package/corpus/templates/design/actions/apply-motion-edit.ts +50 -18
- package/corpus/templates/design/actions/get-motion-timeline.ts +4 -14
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +156 -12
- package/corpus/templates/design/app/components/design/MotionDock.tsx +2 -3
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +217 -75
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +39 -39
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +558 -37
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +75 -3
- package/corpus/templates/design/app/components/design/types.ts +13 -0
- package/corpus/templates/design/app/components/layout/Layout.tsx +1 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +17 -0
- package/corpus/templates/design/app/i18n-data.ts +245 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +762 -153
- package/corpus/templates/design/changelog/2026-06-30-copying-or-dragging-screen-elements-onto-the-infinite-canvas.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-design-questions-now-use-tighter-editor-typography-and-contr.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-element-drags-can-be-cancelled-with-escape-before-they-commi.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-pending-visual-style-edits-now-warn-before-you-leave-the-edi.md +6 -0
- package/corpus/templates/design/changelog/2026-06-30-visual-style-drags-stay-live-while-pending-edits-can-be-appl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-01-design-chat-no-longer-shows-a-redundant-context-tab-above-the-composer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-01-motion-track-creation-no-longer-fails-in-local-editors.md +6 -0
- package/corpus/templates/design/server/plugins/db.ts +10 -0
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +61 -10
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/agent/run-manager.d.ts +8 -7
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +8 -7
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/cli/design-connect.d.ts +2 -0
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +140 -0
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +5 -7
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +5 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +4 -4
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts +3 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +2 -2
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +37 -14
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +14 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +21 -5
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/eval/define-eval.d.ts.map +1 -1
- package/dist/eval/define-eval.js +2 -1
- package/dist/eval/define-eval.js.map +1 -1
- package/dist/eval/report.d.ts.map +1 -1
- package/dist/eval/report.js +19 -4
- package/dist/eval/report.js.map +1 -1
- package/dist/eval/runner.d.ts.map +1 -1
- package/dist/eval/runner.js +38 -6
- package/dist/eval/runner.js.map +1 -1
- package/dist/eval/types.d.ts +11 -0
- package/dist/eval/types.d.ts.map +1 -1
- package/dist/eval/types.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/observability/routes.d.ts +2 -2
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +15 -17
- package/docs/content/evals.mdx +34 -12
- package/docs/content/locales/ar-SA/evals.mdx +7 -0
- package/docs/content/locales/de-DE/evals.mdx +8 -0
- package/docs/content/locales/es-ES/evals.mdx +8 -0
- package/docs/content/locales/fr-FR/evals.mdx +8 -0
- package/docs/content/locales/hi-IN/evals.mdx +8 -0
- package/docs/content/locales/ja-JP/evals.mdx +7 -0
- package/docs/content/locales/ko-KR/evals.mdx +7 -0
- package/docs/content/locales/pt-BR/evals.mdx +8 -0
- package/docs/content/locales/zh-CN/evals.mdx +7 -0
- package/docs/content/locales/zh-TW/evals.mdx +7 -0
- package/docs/design/durable-agent-runs.md +34 -35
- package/package.json +1 -1
- package/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +15 -17
- package/corpus/templates/content/server/routes/api/notion/disconnect.post.ts +0 -12
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
appApiPath,
|
|
3
|
+
callAction,
|
|
4
|
+
useActionMutation,
|
|
5
|
+
useActionQuery,
|
|
6
|
+
} from "@agent-native/core/client";
|
|
2
7
|
import type {
|
|
3
8
|
CreateNotionPageRequest,
|
|
4
9
|
Document,
|
|
@@ -8,18 +13,20 @@ import type {
|
|
|
8
13
|
NotionSearchResponse,
|
|
9
14
|
ResolveDocumentSyncConflictRequest,
|
|
10
15
|
} from "@shared/api";
|
|
11
|
-
import {
|
|
16
|
+
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
12
17
|
import { useEffect, useRef } from "react";
|
|
13
18
|
|
|
14
|
-
async function
|
|
15
|
-
const res = await fetch(appApiPath(url)
|
|
19
|
+
async function fetchNotionAuthUrl(): Promise<string> {
|
|
20
|
+
const res = await fetch(appApiPath("/api/notion/auth-url"));
|
|
16
21
|
if (!res.ok) {
|
|
17
22
|
const body = await res.json().catch(() => null);
|
|
18
23
|
throw new Error(
|
|
19
24
|
body?.error || body?.message || `${res.status} ${res.statusText}`,
|
|
20
25
|
);
|
|
21
26
|
}
|
|
22
|
-
|
|
27
|
+
const body = (await res.json()) as { url?: string };
|
|
28
|
+
if (!body.url) throw new Error("Notion OAuth URL is unavailable");
|
|
29
|
+
return body.url;
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
function invalidateDocumentQueries(
|
|
@@ -27,34 +34,65 @@ function invalidateDocumentQueries(
|
|
|
27
34
|
documentId: string,
|
|
28
35
|
) {
|
|
29
36
|
queryClient.invalidateQueries({ queryKey: ["action"] });
|
|
30
|
-
queryClient.invalidateQueries({
|
|
37
|
+
queryClient.invalidateQueries({
|
|
38
|
+
queryKey: documentSyncStatusQueryKey(documentId),
|
|
39
|
+
});
|
|
40
|
+
queryClient.invalidateQueries({
|
|
41
|
+
queryKey: documentSyncStatusQueryKey(documentId, { autoSync: true }),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function documentSyncStatusQueryKey(
|
|
46
|
+
documentId: string,
|
|
47
|
+
options?: { autoSync?: boolean },
|
|
48
|
+
) {
|
|
49
|
+
return [
|
|
50
|
+
"action",
|
|
51
|
+
"refresh-notion-sync-status",
|
|
52
|
+
{ documentId, autoSync: !!options?.autoSync },
|
|
53
|
+
] as const;
|
|
31
54
|
}
|
|
32
55
|
|
|
33
56
|
export function useNotionConnection() {
|
|
57
|
+
return useActionQuery<NotionConnectionStatus>(
|
|
58
|
+
"connect-notion-status",
|
|
59
|
+
undefined,
|
|
60
|
+
{
|
|
61
|
+
staleTime: 30_000,
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function useNotionAuthUrl(enabled: boolean) {
|
|
34
67
|
return useQuery({
|
|
35
|
-
queryKey: ["notion-
|
|
36
|
-
queryFn:
|
|
68
|
+
queryKey: ["notion-auth-url"],
|
|
69
|
+
queryFn: fetchNotionAuthUrl,
|
|
70
|
+
enabled,
|
|
37
71
|
staleTime: 30_000,
|
|
38
72
|
});
|
|
39
73
|
}
|
|
40
74
|
|
|
75
|
+
export async function openNotionOAuthUrl() {
|
|
76
|
+
return fetchNotionAuthUrl();
|
|
77
|
+
}
|
|
78
|
+
|
|
41
79
|
export function useDocumentSyncStatus(
|
|
42
80
|
documentId: string | null,
|
|
43
81
|
options?: { autoSync?: boolean },
|
|
44
82
|
) {
|
|
45
83
|
const queryClient = useQueryClient();
|
|
46
84
|
const lastObservedSyncedAtRef = useRef<string | null>(null);
|
|
47
|
-
const query = useQuery({
|
|
48
|
-
queryKey:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
85
|
+
const query = useQuery<DocumentSyncStatus>({
|
|
86
|
+
queryKey: documentId
|
|
87
|
+
? documentSyncStatusQueryKey(documentId, options)
|
|
88
|
+
: ["action", "refresh-notion-sync-status", null],
|
|
89
|
+
queryFn: () => {
|
|
90
|
+
if (!documentId) throw new Error("documentId is required");
|
|
91
|
+
return callAction<DocumentSyncStatus>("refresh-notion-sync-status", {
|
|
92
|
+
documentId,
|
|
93
|
+
autoSync: !!options?.autoSync,
|
|
94
|
+
});
|
|
95
|
+
},
|
|
58
96
|
enabled: !!documentId,
|
|
59
97
|
// Poll Notion aggressively when auto-sync is on so remote changes appear
|
|
60
98
|
// within ~2s. Server throttles match (see REFRESH_THROTTLE_AUTO_SYNC_MS in
|
|
@@ -97,118 +135,89 @@ export function useDocumentSyncStatus(
|
|
|
97
135
|
|
|
98
136
|
export function useDisconnectNotion() {
|
|
99
137
|
const queryClient = useQueryClient();
|
|
100
|
-
return
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
138
|
+
return useActionMutation<{ success: boolean; deleted: number }>(
|
|
139
|
+
"disconnect-notion",
|
|
140
|
+
{
|
|
141
|
+
onSuccess: () => {
|
|
142
|
+
queryClient.invalidateQueries({
|
|
143
|
+
queryKey: ["action", "connect-notion-status"],
|
|
144
|
+
});
|
|
145
|
+
queryClient.invalidateQueries({
|
|
146
|
+
queryKey: ["action", "refresh-notion-sync-status"],
|
|
147
|
+
});
|
|
148
|
+
},
|
|
108
149
|
},
|
|
109
|
-
|
|
150
|
+
);
|
|
110
151
|
}
|
|
111
152
|
|
|
112
153
|
export function useLinkDocumentToNotion(documentId: string) {
|
|
113
154
|
const queryClient = useQueryClient();
|
|
114
|
-
return
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
{
|
|
119
|
-
method: "POST",
|
|
120
|
-
headers: { "Content-Type": "application/json" },
|
|
121
|
-
body: JSON.stringify(data),
|
|
122
|
-
},
|
|
123
|
-
),
|
|
155
|
+
return useActionMutation<
|
|
156
|
+
DocumentSyncStatus,
|
|
157
|
+
LinkNotionPageRequest & { documentId: string }
|
|
158
|
+
>("link-notion-page", {
|
|
124
159
|
onSuccess: () => invalidateDocumentQueries(queryClient, documentId),
|
|
125
160
|
});
|
|
126
161
|
}
|
|
127
162
|
|
|
128
163
|
export function useUnlinkDocumentFromNotion(documentId: string) {
|
|
129
164
|
const queryClient = useQueryClient();
|
|
130
|
-
return
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
),
|
|
138
|
-
onSuccess: () => invalidateDocumentQueries(queryClient, documentId),
|
|
139
|
-
});
|
|
165
|
+
return useActionMutation<{ success: boolean }, { documentId: string }>(
|
|
166
|
+
"unlink-notion-page",
|
|
167
|
+
{
|
|
168
|
+
method: "DELETE",
|
|
169
|
+
onSuccess: () => invalidateDocumentQueries(queryClient, documentId),
|
|
170
|
+
},
|
|
171
|
+
);
|
|
140
172
|
}
|
|
141
173
|
|
|
142
174
|
export function usePullDocumentFromNotion(documentId: string) {
|
|
143
175
|
const queryClient = useQueryClient();
|
|
144
|
-
return
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
},
|
|
151
|
-
),
|
|
152
|
-
onSuccess: () => invalidateDocumentQueries(queryClient, documentId),
|
|
153
|
-
});
|
|
176
|
+
return useActionMutation<DocumentSyncStatus, { documentId: string }>(
|
|
177
|
+
"pull-notion-page",
|
|
178
|
+
{
|
|
179
|
+
onSuccess: () => invalidateDocumentQueries(queryClient, documentId),
|
|
180
|
+
},
|
|
181
|
+
);
|
|
154
182
|
}
|
|
155
183
|
|
|
156
184
|
export function usePushDocumentToNotion(documentId: string) {
|
|
157
185
|
const queryClient = useQueryClient();
|
|
158
|
-
return
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
},
|
|
165
|
-
),
|
|
166
|
-
onSuccess: () => invalidateDocumentQueries(queryClient, documentId),
|
|
167
|
-
});
|
|
186
|
+
return useActionMutation<DocumentSyncStatus, { documentId: string }>(
|
|
187
|
+
"push-notion-page",
|
|
188
|
+
{
|
|
189
|
+
onSuccess: () => invalidateDocumentQueries(queryClient, documentId),
|
|
190
|
+
},
|
|
191
|
+
);
|
|
168
192
|
}
|
|
169
193
|
|
|
170
194
|
export function useResolveDocumentSyncConflict(documentId: string) {
|
|
171
195
|
const queryClient = useQueryClient();
|
|
172
|
-
return
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
{
|
|
177
|
-
method: "POST",
|
|
178
|
-
headers: { "Content-Type": "application/json" },
|
|
179
|
-
body: JSON.stringify(data),
|
|
180
|
-
},
|
|
181
|
-
),
|
|
196
|
+
return useActionMutation<
|
|
197
|
+
DocumentSyncStatus,
|
|
198
|
+
ResolveDocumentSyncConflictRequest & { documentId: string }
|
|
199
|
+
>("resolve-notion-sync-conflict", {
|
|
182
200
|
onSuccess: () => invalidateDocumentQueries(queryClient, documentId),
|
|
183
201
|
});
|
|
184
202
|
}
|
|
185
203
|
|
|
186
204
|
export function useCreateAndLinkNotionPage(documentId: string) {
|
|
187
205
|
const queryClient = useQueryClient();
|
|
188
|
-
return
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
{
|
|
193
|
-
method: "POST",
|
|
194
|
-
headers: { "Content-Type": "application/json" },
|
|
195
|
-
body: JSON.stringify(data ?? {}),
|
|
196
|
-
},
|
|
197
|
-
),
|
|
206
|
+
return useActionMutation<
|
|
207
|
+
DocumentSyncStatus,
|
|
208
|
+
CreateNotionPageRequest & { documentId: string }
|
|
209
|
+
>("create-and-link-notion-page", {
|
|
198
210
|
onSuccess: () => invalidateDocumentQueries(queryClient, documentId),
|
|
199
211
|
});
|
|
200
212
|
}
|
|
201
213
|
|
|
202
214
|
export function useSearchNotionPages(query: string, enabled: boolean) {
|
|
203
|
-
return
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
enabled,
|
|
212
|
-
staleTime: 10_000,
|
|
213
|
-
});
|
|
215
|
+
return useActionQuery<NotionSearchResponse>(
|
|
216
|
+
"search-notion-pages",
|
|
217
|
+
{ query },
|
|
218
|
+
{
|
|
219
|
+
enabled,
|
|
220
|
+
staleTime: 10_000,
|
|
221
|
+
},
|
|
222
|
+
);
|
|
214
223
|
}
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
"build": "agent-native build",
|
|
10
10
|
"start": "agent-native start",
|
|
11
11
|
"test": "vitest --run",
|
|
12
|
+
"test:parity": "vitest --run parity",
|
|
13
|
+
"test:parity-capabilities": "vitest --run parity actions/content-database-lifecycle.db.test.ts actions/bind-content-database-source-field.db.test.ts actions/_local-file-documents.test.ts actions/builder-source-review-gates.db.test.ts",
|
|
14
|
+
"eval:parity": "agent-native eval parity",
|
|
12
15
|
"format.fix": "oxfmt --write .",
|
|
13
16
|
"typecheck": "agent-native typecheck",
|
|
14
17
|
"action": "agent-native action",
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Content Parity Harness
|
|
2
|
+
|
|
3
|
+
This folder is the living audit for Content's agent/UI action parity. The
|
|
4
|
+
matrix records which visible workflows are action-backed, which have explicit
|
|
5
|
+
exceptions, and which gaps need follow-up.
|
|
6
|
+
|
|
7
|
+
PR 2.2 adds two executable tiers:
|
|
8
|
+
|
|
9
|
+
- Deterministic parity tests run in normal CI. They use fixture data and
|
|
10
|
+
existing action tests, make no model calls, and require no private provider
|
|
11
|
+
credentials.
|
|
12
|
+
- Gated agent evals run through `agent-native eval parity`. They are opt-in via
|
|
13
|
+
`CONTENT_PARITY_EVALS=1`, capped to four initial scenarios, and should be
|
|
14
|
+
reserved for manual or nightly checks.
|
|
15
|
+
|
|
16
|
+
## Deterministic Checks
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
cd templates/content
|
|
20
|
+
./node_modules/.bin/vitest --run parity
|
|
21
|
+
./node_modules/.bin/vitest --run actions/content-database-lifecycle.db.test.ts actions/bind-content-database-source-field.db.test.ts actions/_local-file-documents.test.ts actions/builder-source-review-gates.db.test.ts
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The matrix rows use `coverageRefs` to point at deterministic files that prove a
|
|
25
|
+
capability. The meta-tests fail with the row id when a priority capability loses
|
|
26
|
+
coverage, so reviewers do not have to map a random test name back to the audit.
|
|
27
|
+
|
|
28
|
+
## Gated Agent Evals
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
cd templates/content
|
|
32
|
+
./node_modules/.bin/agent-native eval parity --json
|
|
33
|
+
CONTENT_PARITY_EVALS=1 ANTHROPIC_API_KEY=... ./node_modules/.bin/agent-native eval parity
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
With `CONTENT_PARITY_EVALS` unset, parity evals return skipped rows and do not
|
|
37
|
+
call the agent runner. The CLI still exits `0`, but both readable and JSON
|
|
38
|
+
reports mark each row with `status: "skipped"` and a `skipReason` such as
|
|
39
|
+
`Skipped because CONTENT_PARITY_EVALS is unset`.
|
|
40
|
+
|
|
41
|
+
With the gate set, the eval files run the four PR 2.2 scenarios:
|
|
42
|
+
|
|
43
|
+
- `database-source-scope`
|
|
44
|
+
- `document-search-edit`
|
|
45
|
+
- `local-file-source-truth`
|
|
46
|
+
- `builder-source-review-readonly`
|
|
47
|
+
|
|
48
|
+
The scenarios use fake or fixture data only. They must not require private
|
|
49
|
+
Builder, Notion, customer, or workspace credentials. The Builder scenario is
|
|
50
|
+
readonly/mocked by default and must not execute a live write.
|
|
51
|
+
|
|
52
|
+
## CI Posture
|
|
53
|
+
|
|
54
|
+
Normal PR CI runs deterministic parity checks through `pnpm test:content-parity`.
|
|
55
|
+
Live or LLM-backed parity evals are reserved for the gated eval workflow, which
|
|
56
|
+
can be triggered manually or by the nightly schedule. Missing provider secrets
|
|
57
|
+
should show as skipped in that workflow summary, not as a scored pass.
|
|
58
|
+
|
|
59
|
+
## Updating The Matrix
|
|
60
|
+
|
|
61
|
+
Edit `matrix.ts`, then regenerate:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
cd templates/content
|
|
65
|
+
./node_modules/.bin/tsx parity/render-matrix.ts --write
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`parity/__tests__/matrix-render-fresh.test.ts` keeps `matrix.md` synced with
|
|
69
|
+
the typed source.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
export interface ParityEvalScenario {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
capabilityIds: string[];
|
|
5
|
+
gateEnv: string;
|
|
6
|
+
defaultState: "skipped";
|
|
7
|
+
requiresPrivateCredentials: false;
|
|
8
|
+
prompt: string;
|
|
9
|
+
successSignals: string[];
|
|
10
|
+
expectedTools?: string[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const parityEvalScenarios: ParityEvalScenario[] = [
|
|
14
|
+
{
|
|
15
|
+
id: "database-bulk-row-reliability",
|
|
16
|
+
title: "Bulk database row reliability",
|
|
17
|
+
capabilityIds: ["database.rows"],
|
|
18
|
+
gateEnv: "CONTENT_PARITY_EVALS",
|
|
19
|
+
defaultState: "skipped",
|
|
20
|
+
requiresPrivateCredentials: false,
|
|
21
|
+
prompt:
|
|
22
|
+
"Using fixture Content database rows only, duplicate multiple selected rows and delete multiple selected rows through the action surface. Report the ordered duplicated item/document IDs, deleted IDs, and the verified remaining row count. Do not loop single-row duplicate or document delete actions for the multi-row operations.",
|
|
23
|
+
successSignals: [
|
|
24
|
+
"Uses duplicate-database-items once for the multi-row duplicate.",
|
|
25
|
+
"Uses delete-database-items once for the multi-row delete.",
|
|
26
|
+
"Reports ordered duplicated item and document IDs.",
|
|
27
|
+
"Reports deleted IDs and verified remaining row count.",
|
|
28
|
+
"Does not use private provider credentials.",
|
|
29
|
+
],
|
|
30
|
+
expectedTools: ["duplicate-database-items", "delete-database-items"],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "database-source-scope",
|
|
34
|
+
title: "Source-backed database scope",
|
|
35
|
+
capabilityIds: [
|
|
36
|
+
"database.lifecycle-and-trash",
|
|
37
|
+
"source-sync.database-source-bindings",
|
|
38
|
+
],
|
|
39
|
+
gateEnv: "CONTENT_PARITY_EVALS",
|
|
40
|
+
defaultState: "skipped",
|
|
41
|
+
requiresPrivateCredentials: false,
|
|
42
|
+
prompt:
|
|
43
|
+
"Using only fake or fixture source data, inspect or create a source-backed Content database, attach a safe source, map at least one unmapped field, change a view/filter/grouping, and report visible source scope plus whether any live external write occurred.",
|
|
44
|
+
successSignals: [
|
|
45
|
+
"Uses action-backed database/source operations instead of raw SQL.",
|
|
46
|
+
"Reports source scope and provenance explicitly.",
|
|
47
|
+
"Does not require private Builder credentials.",
|
|
48
|
+
"States that no live external write occurred unless a gated write action was explicitly run.",
|
|
49
|
+
],
|
|
50
|
+
expectedTools: [
|
|
51
|
+
"create-content-database",
|
|
52
|
+
"attach-content-database-source",
|
|
53
|
+
"bind-content-database-source-field",
|
|
54
|
+
"get-content-database-source",
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "document-search-edit",
|
|
59
|
+
title: "Document search and edit through actions",
|
|
60
|
+
capabilityIds: [
|
|
61
|
+
"sidebar.document-tree-crud",
|
|
62
|
+
"editor.document-body-and-title",
|
|
63
|
+
],
|
|
64
|
+
gateEnv: "CONTENT_PARITY_EVALS",
|
|
65
|
+
defaultState: "skipped",
|
|
66
|
+
requiresPrivateCredentials: false,
|
|
67
|
+
prompt:
|
|
68
|
+
"Using fixture Content documents only, search for a document by a unique title or body phrase, inspect it, make one small title or body edit through an action-backed document operation, and report the changed title/body plus the action path used.",
|
|
69
|
+
successSignals: [
|
|
70
|
+
"Uses search/open/edit document actions instead of direct SQL.",
|
|
71
|
+
"Reports which fixture document was changed.",
|
|
72
|
+
"Shows the edited title or body text.",
|
|
73
|
+
"Does not require private provider credentials.",
|
|
74
|
+
],
|
|
75
|
+
expectedTools: ["search-documents", "get-document", "edit-document"],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
id: "local-file-source-truth",
|
|
79
|
+
title: "Local file source-truth edit",
|
|
80
|
+
capabilityIds: [
|
|
81
|
+
"local-files.import-export-mounted-folder",
|
|
82
|
+
"sharing.document-discoverability-and-export",
|
|
83
|
+
],
|
|
84
|
+
gateEnv: "CONTENT_PARITY_EVALS",
|
|
85
|
+
defaultState: "skipped",
|
|
86
|
+
requiresPrivateCredentials: false,
|
|
87
|
+
prompt:
|
|
88
|
+
"Using only a temporary local-file Content fixture, find a local MDX document, edit a small phrase through the Content action surface, pull or export the document, and report that the mounted local file remains the source of truth. Do not invoke OS reveal.",
|
|
89
|
+
successSignals: [
|
|
90
|
+
"Uses local-file-aware document actions rather than raw filesystem writes.",
|
|
91
|
+
"Reports the local file source-truth relationship.",
|
|
92
|
+
"Does not call OS reveal as an agent tool.",
|
|
93
|
+
"Does not require private provider credentials.",
|
|
94
|
+
],
|
|
95
|
+
expectedTools: ["search-documents", "edit-document", "pull-document"],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
id: "builder-source-review-readonly",
|
|
99
|
+
title: "Builder source review without live write",
|
|
100
|
+
capabilityIds: ["source-sync.builder-cms-review-and-write-gates"],
|
|
101
|
+
gateEnv: "CONTENT_PARITY_EVALS",
|
|
102
|
+
defaultState: "skipped",
|
|
103
|
+
requiresPrivateCredentials: false,
|
|
104
|
+
prompt:
|
|
105
|
+
"Using mocked Builder CMS fixture data only, prepare or review a Builder source change set, summarize the staged changes and write gates, and explicitly state that no live Builder write was executed.",
|
|
106
|
+
successSignals: [
|
|
107
|
+
"Uses Builder source review or validation actions.",
|
|
108
|
+
"Reports staged changes or gate state.",
|
|
109
|
+
"States that no live Builder write occurred.",
|
|
110
|
+
"Does not require private Builder credentials.",
|
|
111
|
+
],
|
|
112
|
+
expectedTools: [
|
|
113
|
+
"prepare-builder-source-review",
|
|
114
|
+
"review-content-database-source-change-set",
|
|
115
|
+
"validate-builder-source-execution",
|
|
116
|
+
],
|
|
117
|
+
},
|
|
118
|
+
];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface ParityActionAllowlistEntry {
|
|
2
|
+
action: string;
|
|
3
|
+
reason: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export const parityActionAllowlist: ParityActionAllowlistEntry[] = [
|
|
7
|
+
{
|
|
8
|
+
action: "refresh-list",
|
|
9
|
+
reason:
|
|
10
|
+
"Agent/UI bridge helper that only nudges application-state refresh; not a user-visible Content operation.",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
action: "run",
|
|
14
|
+
reason:
|
|
15
|
+
"Template bootstrap/support action rather than a Content user workflow.",
|
|
16
|
+
},
|
|
17
|
+
];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Content Agent/UI Action Parity Matrix
|
|
2
|
+
|
|
3
|
+
This generated matrix tracks whether high-value Content UI operations use the same action surface agents can call, or have an explicit exception. Edit `matrix.ts`, then regenerate this file.
|
|
4
|
+
|
|
5
|
+
| ID | Surface | User-visible action | Status | Actions | UI entrypoints | Durable effect | Exception / gap | Reliability risk | Spine priority | Test coverage | Coverage refs | Eval scenarios | Follow-up |
|
|
6
|
+
| ---------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------- | -------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------ |
|
|
7
|
+
| comments.threads | comments | List, add, reply, resolve, reopen, and delete comment threads | action-backed | `add-comment`, `delete-comment`, `list-comments`, `update-comment` | `app/components/editor/CommentsSidebar.tsx`, `app/hooks/use-comments.ts` | Comment threads, replies, anchors, mentions, resolution state, and deletion are stored through comment actions. | - | - | P0 | seeded | - | - | - |
|
|
8
|
+
| database.lifecycle-and-trash | database | Create, soft-delete, restore, list, and inspect content databases | action-backed | `create-content-database`, `create-inline-content-database`, `delete-content-database`, `get-content-database`, `list-content-databases`, `list-trashed-content-databases`, `restore-content-database` | `app/components/editor/SlashCommandMenu.tsx`, `app/hooks/use-content-database.ts`, `app/hooks/use-documents.ts` | Database pages and database records are created, read, soft-deleted, restored, and listed. | - | - | P0 | covered | `actions/content-database-lifecycle.db.test.ts` | `database-source-scope` | - |
|
|
9
|
+
| database.properties-and-view-config | database | Configure properties, values, ordering, and saved views | action-backed | `configure-document-property`, `delete-document-property`, `duplicate-document-property`, `list-document-properties`, `reorder-document-property`, `set-document-property`, `update-content-database-view` | `app/components/editor/DocumentProperties.tsx`, `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-document-properties.ts` | Property schemas, property values, property order, filters, sorts, grouping, hidden columns, view type, and view settings are stored. | - | - | P0 | covered | `actions/bind-content-database-source-field.db.test.ts`, `actions/content-database-source-actions.test.ts`, `actions/resync-content-database-source.db.test.ts` | `database-source-scope` | - |
|
|
10
|
+
| database.rows | database | Add, duplicate, move, open, and delete database rows | action-backed | `add-database-item`, `delete-database-items`, `delete-document`, `duplicate-database-items`, `duplicate-database-item`, `move-database-item`, `set-document-property` | `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/database/DatabaseView.tsx` | Database row backing documents and row ordering are created, duplicated, moved, edited, and deleted. | - | - | P0 | covered | `actions/database-row-batch-actions.db.test.ts`, `parity/__tests__/database-row-batch-reliability.test.ts` | `database-bulk-row-reliability` | - |
|
|
11
|
+
| editor.agent-assist-prompts | editor | Ask AI from slash generation or comment context | client-assist | - | `app/components/editor/SlashCommandMenu.tsx`, `app/components/editor/CommentsSidebar.tsx` | No direct durable mutation; the prompt asks the agent to use document actions when it decides to write. | - | - | P1 | none | - | - | - |
|
|
12
|
+
| editor.client-formatting-and-insertions | editor | Rich text formatting, selection state, slash block insertion, and copy actions | client-only-ephemeral | - | `app/components/editor/BubbleToolbar.tsx`, `app/components/editor/SlashCommandMenu.tsx`, `app/components/editor/DocumentToolbar.tsx` | - | - | - | P1 | none | - | - | - |
|
|
13
|
+
| editor.document-body-and-title | editor | Edit document title, body, icon, image alt text, and precise text | action-backed | `edit-document`, `pull-document`, `set-image-alt-text`, `transcribe-media`, `update-document` | `app/components/editor/DocumentEditor.tsx`, `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/extensions/ImageBlock.tsx`, `app/components/editor/SlashCommandMenu.tsx` | Document content, title, icon, image metadata, and text replacements are saved to the same document source. | - | - | P0 | covered | `actions/content-database-lifecycle.db.test.ts`, `actions/_local-file-documents.test.ts` | `document-search-edit` | - |
|
|
14
|
+
| local-files.components-workspace | local-files | Register, list, and write local MDX component workspaces | host-only | `list-local-component-files`, `register-local-component-workspace`, `write-local-component-file` | `app/routes/_app.local-files.tsx`, `actions/register-local-component-workspace.ts`, `actions/list-local-component-files.ts`, `actions/write-local-component-file.ts` | Trusted local component workspace registration and component file reads/writes support local MDX previews. | Workspace registration depends on a trusted Desktop folder path and is intentionally hidden with agentTool: false. | - | P1 | seeded | - | - | Local folder exception/docs PR |
|
|
15
|
+
| local-files.host-folder-handles | local-files | Choose, persist, remove, and write trusted local folder handles | host-only | - | `app/routes/_app.local-files.tsx` | Host directory handles and browser/Desktop write permissions are managed outside SQL action state. | Mounted local folders require browser/Desktop host handles that agents cannot safely or portably hold as normal tools. | - | P0 | none | - | - | Local folder exception/docs PR |
|
|
16
|
+
| local-files.import-export-mounted-folder | local-files | Import, check, export, and push local folder source files | action-backed | `export-content-source`, `import-content-source` | `app/routes/_app.local-files.tsx`, `actions/import-content-source.ts`, `actions/export-content-source.ts` | Local Markdown/MDX source files are imported into Content documents, and editable Content documents are exported back to source-friendly files. | - | - | P0 | covered | `actions/_local-file-documents.test.ts` | `local-file-source-truth` | - |
|
|
17
|
+
| notion.route-backed-document-sync | source-sync | Notion document sync status, link, unlink, pull, push, resolve, create, search, and disconnect | action-backed | `connect-notion-status`, `create-and-link-notion-page`, `disconnect-notion`, `link-notion-page`, `list-notion-links`, `pull-notion-page`, `push-notion-page`, `refresh-notion-sync-status`, `resolve-notion-sync-conflict`, `search-notion-pages`, `sync-notion-comments`, `unlink-notion-page` | `app/hooks/use-notion.ts`, `app/components/editor/DocumentToolbar.tsx`, `app/components/editor/NotionSyncBar.tsx`, `app/components/editor/DocumentEditor.tsx` | Notion connection state, page search, link metadata, and local/remote document body sync state are read or mutated through Content actions. | Notion OAuth auth-url and callback routes remain route-shaped because they initiate and receive browser redirects rather than normal app data mutations. | - | P0 | covered | `parity/__tests__/matrix-route-gap-classify.test.ts` | - | - |
|
|
18
|
+
| sharing.document-discoverability-and-export | sharing | Share, hide from search, export, and reveal documents | action-backed | `export-document`, `reveal-local-source-file`, `set-document-discoverability`, `share-local-file-document` | `app/components/editor/DocumentToolbar.tsx`, `app/hooks/use-documents.ts` | Search discoverability, shareable copies, exports, and OS reveal requests are managed through Content actions. | - | - | P0 | covered | `actions/_local-file-documents.test.ts` | `local-file-source-truth` | - |
|
|
19
|
+
| sharing.os-reveal-local-source | sharing | Reveal a local source file in the system file manager | host-only | `reveal-local-source-file` | `app/components/editor/DocumentToolbar.tsx`, `actions/reveal-local-source-file.ts` | - | OS reveal depends on trusted local host capabilities and should not spend agent tool surface or imply portable hosted behavior. | - | P2 | seeded | - | - | Local folder exception/docs PR |
|
|
20
|
+
| sidebar.chrome-state | sidebar | Collapse sections and resize the sidebar | client-only-ephemeral | - | `app/components/sidebar/DocumentSidebar.tsx`, `app/components/layout/Layout.tsx` | - | - | - | P2 | none | - | - | - |
|
|
21
|
+
| sidebar.document-tree-crud | sidebar | Create, delete, move, favorite, list, search, and open pages | action-backed | `create-document`, `delete-document`, `get-document`, `list-documents`, `move-document`, `search-documents`, `update-document` | `app/components/sidebar/DocumentSidebar.tsx`, `app/components/sidebar/DocumentTreeItem.tsx`, `app/hooks/use-documents.ts` | Document tree rows and document metadata are created, updated, deleted, moved, searched, or read. | - | - | P0 | covered | `actions/content-database-lifecycle.db.test.ts`, `actions/_local-file-documents.test.ts` | `document-search-edit` | - |
|
|
22
|
+
| sidebar.navigation-and-screen-context | sidebar | Navigate between documents and expose current screen context | action-equivalent | `navigate`, `view-screen` | `app/components/sidebar/DocumentSidebar.tsx`, `actions/navigate.ts`, `actions/view-screen.ts` | Application navigation state is updated or read so the agent can reason about the user's current page/view. | Human navigation is router-local, while agent navigation/screen inspection uses application-state actions to produce the same workspace orientation effect. | - | P1 | seeded | - | - | - |
|
|
23
|
+
| source-sync.builder-body-hydration-worker | source-sync | Process queued Builder CMS body hydration work | action-backed | `process-builder-body-hydration` | `app/components/editor/DocumentEditor.tsx`, `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-content-database.ts` | Queued Builder body hydration entries are processed into readable Content document/database body state. | This action is intentionally hidden from the model with agentTool: false because it is an internal bounded queue worker; agents should use source refresh, review, and execution actions rather than manually driving hydration internals. | - | P0 | covered | `actions/_database-source-utils.test.ts` | - | - |
|
|
24
|
+
| source-sync.builder-cms-review-and-write-gates | source-sync | Review, stage, validate, and execute Builder CMS source writes | action-backed | `execute-builder-source-batch`, `execute-builder-source-execution`, `prepare-builder-source-execution`, `prepare-builder-source-review`, `review-content-database-source-change-set`, `set-content-database-source-write-mode`, `stage-builder-revision`, `validate-builder-source-execution` | `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/database/DatabaseView.tsx`, `app/components/editor/database-sources/BuilderSourceReviewDialog.tsx` | Builder source write mode, staged reviews, validation records, and bounded execution records are created through guarded actions. | - | - | P0 | covered | `actions/builder-source-review-gates.db.test.ts`, `actions/execute-builder-source-execution.test.ts` | `builder-source-review-readonly` | - |
|
|
25
|
+
| source-sync.builder-documents | source-sync | List, pull, check, and push Builder docs/blog MDX documents | action-backed | `check-builder-doc`, `list-builder-docs`, `pull-builder-doc`, `push-builder-doc` | `actions/list-builder-docs.ts`, `actions/pull-builder-doc.ts`, `actions/check-builder-doc.ts`, `actions/push-builder-doc.ts` | Builder docs/blog entries can be read into Content, checked locally, and pushed through guarded Builder document actions. | - | - | P1 | seeded | - | - | - |
|
|
26
|
+
| source-sync.database-source-bindings | source-sync | Attach, inspect, refresh, disconnect, join, and bind database sources | action-backed | `add-content-database-source-field-property`, `attach-content-database-source`, `bind-content-database-source-field`, `change-content-database-source-role`, `disconnect-content-database-source`, `get-content-database-source`, `list-builder-cms-models`, `refresh-content-database-source`, `suggest-source-join-key` | `app/components/editor/DocumentDatabase.tsx`, `app/components/editor/DocumentProperties.tsx`, `app/components/editor/database/DatabaseView.tsx`, `app/hooks/use-content-database.ts` | Mounted database source metadata, fields, source role, join keys, and source-field/property bindings are stored and refreshed. | - | - | P0 | covered | `actions/bind-content-database-source-field.db.test.ts`, `actions/content-database-source-actions.test.ts`, `actions/resync-content-database-source.db.test.ts` | `database-source-scope` | - |
|
|
27
|
+
| source-sync.provider-api-and-staged-datasets | source-sync | Inspect provider APIs and stage/query/delete large provider datasets | action-backed | `delete-staged-dataset`, `list-staged-datasets`, `provider-api-catalog`, `provider-api-docs`, `provider-api-request`, `query-staged-dataset` | `actions/provider-api-catalog.ts`, `actions/provider-api-docs.ts`, `actions/provider-api-request.ts`, `actions/query-staged-dataset.ts` | Provider API metadata and staged dataset scratch storage support scoped agent/source analysis. | - | - | P1 | seeded | - | - | - |
|
|
28
|
+
| versions.history-and-restore | versions | Open version history and restore a previous document version | action-backed | `list-document-versions`, `restore-document-version` | `app/components/editor/VersionHistoryPanel.tsx`, `app/hooks/use-document-versions.ts` | Document versions are listed and selected versions can restore the document while snapshotting current state. | - | - | P0 | seeded | - | - | - |
|