@agent-native/core 0.0.0-beta-20260819204836 → 0.0.0-beta-20260819215811
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/templates/content/app/components/sidebar/DocumentSidebar.tsx +37 -5
- package/corpus/templates/content/app/hooks/use-create-page.ts +26 -4
- package/corpus/templates/content/app/hooks/use-documents.ts +83 -0
- package/corpus/templates/content/docs/solutions/2026-08-18-content-navigation-coherence-shape.md +482 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +6 -6
- package/dist/server/auth.js +13 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
package/corpus/README.md
CHANGED
|
@@ -127,6 +127,8 @@ import {
|
|
|
127
127
|
buildDocumentTree,
|
|
128
128
|
filterDocumentTreeDocuments,
|
|
129
129
|
documentQueryFilter,
|
|
130
|
+
rollbackOptimisticCreatedDocument,
|
|
131
|
+
restoreDeletedDocumentSnapshots,
|
|
130
132
|
} from "@/hooks/use-documents";
|
|
131
133
|
import { useLocalStorage } from "@/hooks/use-local-storage";
|
|
132
134
|
import {
|
|
@@ -1153,12 +1155,16 @@ export function DocumentSidebar({
|
|
|
1153
1155
|
createdAt: now,
|
|
1154
1156
|
updatedAt: now,
|
|
1155
1157
|
});
|
|
1158
|
+
const previousDocuments = queryClient.getQueryData(
|
|
1159
|
+
LIST_DOCUMENTS_QUERY_KEY,
|
|
1160
|
+
);
|
|
1161
|
+
const previousPath = `${location.pathname}${location.search}${location.hash}`;
|
|
1156
1162
|
|
|
1157
1163
|
// Optimistically inject into caches so UI updates immediately
|
|
1158
1164
|
queryClient.setQueryData(LIST_DOCUMENTS_QUERY_KEY, (old: any) => {
|
|
1159
1165
|
const docs: Document[] =
|
|
1160
1166
|
old?.documents ?? (Array.isArray(old) ? old : []);
|
|
1161
|
-
return
|
|
1167
|
+
return withDocumentsCacheShape(old, [...docs, tempDoc]);
|
|
1162
1168
|
});
|
|
1163
1169
|
queryClient.setQueryData(["action", "get-document", { id }], tempDoc);
|
|
1164
1170
|
if (rootFilesDatabaseId) {
|
|
@@ -1207,7 +1213,11 @@ export function DocumentSidebar({
|
|
|
1207
1213
|
});
|
|
1208
1214
|
}
|
|
1209
1215
|
} catch (err) {
|
|
1210
|
-
|
|
1216
|
+
rollbackOptimisticCreatedDocument(
|
|
1217
|
+
queryClient,
|
|
1218
|
+
id,
|
|
1219
|
+
previousDocuments !== undefined,
|
|
1220
|
+
);
|
|
1211
1221
|
queryClient.invalidateQueries({
|
|
1212
1222
|
queryKey: ["action", "list-documents"],
|
|
1213
1223
|
});
|
|
@@ -1218,7 +1228,10 @@ export function DocumentSidebar({
|
|
|
1218
1228
|
(current) => removeOptimisticItemFromContentDatabase(current, id),
|
|
1219
1229
|
);
|
|
1220
1230
|
}
|
|
1221
|
-
navigate(
|
|
1231
|
+
navigate(previousPath, {
|
|
1232
|
+
replace: true,
|
|
1233
|
+
flushSync: true,
|
|
1234
|
+
});
|
|
1222
1235
|
toast.error(t("sidebar.failedCreatePage"), {
|
|
1223
1236
|
description:
|
|
1224
1237
|
err instanceof Error ? err.message : t("empty.genericError"),
|
|
@@ -1228,6 +1241,9 @@ export function DocumentSidebar({
|
|
|
1228
1241
|
[
|
|
1229
1242
|
createDocument,
|
|
1230
1243
|
localFileMode,
|
|
1244
|
+
location.hash,
|
|
1245
|
+
location.pathname,
|
|
1246
|
+
location.search,
|
|
1231
1247
|
navigate,
|
|
1232
1248
|
navigateToDocument,
|
|
1233
1249
|
onNavigate,
|
|
@@ -1284,6 +1300,13 @@ export function DocumentSidebar({
|
|
|
1284
1300
|
navigationCandidates.find((doc) => doc.isFavorite) ??
|
|
1285
1301
|
[...navigationCandidates].sort(compareDocumentsByPosition)[0] ??
|
|
1286
1302
|
null;
|
|
1303
|
+
const previousDocuments = queryClient.getQueryData(
|
|
1304
|
+
LIST_DOCUMENTS_QUERY_KEY,
|
|
1305
|
+
);
|
|
1306
|
+
const previousDocumentQueries = [...deletedIds].flatMap((deletedId) =>
|
|
1307
|
+
queryClient.getQueriesData(documentQueryFilter(deletedId)),
|
|
1308
|
+
);
|
|
1309
|
+
const previousPath = `${location.pathname}${location.search}${location.hash}`;
|
|
1287
1310
|
|
|
1288
1311
|
queryClient.setQueryData(LIST_DOCUMENTS_QUERY_KEY, (old: unknown) => {
|
|
1289
1312
|
const cachedDocs: Document[] =
|
|
@@ -1317,11 +1340,17 @@ export function DocumentSidebar({
|
|
|
1317
1340
|
queryKey: ["action", "list-documents"],
|
|
1318
1341
|
});
|
|
1319
1342
|
} catch (err) {
|
|
1343
|
+
restoreDeletedDocumentSnapshots(
|
|
1344
|
+
queryClient,
|
|
1345
|
+
previousDocuments,
|
|
1346
|
+
previousDocumentQueries,
|
|
1347
|
+
deletedIds,
|
|
1348
|
+
);
|
|
1320
1349
|
queryClient.invalidateQueries({
|
|
1321
1350
|
queryKey: ["action", "list-documents"],
|
|
1322
1351
|
});
|
|
1323
|
-
if (activeDeleted
|
|
1324
|
-
navigate(
|
|
1352
|
+
if (activeDeleted) {
|
|
1353
|
+
navigate(previousPath, {
|
|
1325
1354
|
replace: true,
|
|
1326
1355
|
flushSync: true,
|
|
1327
1356
|
});
|
|
@@ -1338,6 +1367,9 @@ export function DocumentSidebar({
|
|
|
1338
1367
|
deleteDocument,
|
|
1339
1368
|
documents,
|
|
1340
1369
|
localFileMode,
|
|
1370
|
+
location.hash,
|
|
1371
|
+
location.pathname,
|
|
1372
|
+
location.search,
|
|
1341
1373
|
navigate,
|
|
1342
1374
|
queryClient,
|
|
1343
1375
|
],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Document } from "@shared/api";
|
|
2
2
|
import { useQueryClient } from "@tanstack/react-query";
|
|
3
3
|
import { useCallback } from "react";
|
|
4
|
-
import { useNavigate } from "react-router";
|
|
4
|
+
import { useLocation, useNavigate } from "react-router";
|
|
5
5
|
import { toast } from "sonner";
|
|
6
6
|
|
|
7
7
|
import {
|
|
@@ -10,7 +10,10 @@ import {
|
|
|
10
10
|
SELECTED_CONTENT_SPACE_STORAGE_KEY,
|
|
11
11
|
} from "@/components/sidebar/select-content-space";
|
|
12
12
|
import { useContentSpaces } from "@/hooks/use-content-spaces";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
rollbackOptimisticCreatedDocument,
|
|
15
|
+
useCreateDocument,
|
|
16
|
+
} from "@/hooks/use-documents";
|
|
14
17
|
import { useLocalStorage } from "@/hooks/use-local-storage";
|
|
15
18
|
import { documentQueryFilter } from "@/lib/document-query";
|
|
16
19
|
import { markDocumentCreationPending } from "@/lib/optimistic-document";
|
|
@@ -34,6 +37,7 @@ export function useCreatePage(opts?: {
|
|
|
34
37
|
awaitPersist?: boolean;
|
|
35
38
|
}) {
|
|
36
39
|
const navigate = useNavigate();
|
|
40
|
+
const location = useLocation();
|
|
37
41
|
const queryClient = useQueryClient();
|
|
38
42
|
const createDocument = useCreateDocument();
|
|
39
43
|
const contentSpacesQuery = useContentSpaces();
|
|
@@ -78,11 +82,19 @@ export function useCreatePage(opts?: {
|
|
|
78
82
|
createdAt: now,
|
|
79
83
|
updatedAt: now,
|
|
80
84
|
});
|
|
85
|
+
const previousDocuments = queryClient.getQueryData(
|
|
86
|
+
LIST_DOCUMENTS_QUERY_KEY,
|
|
87
|
+
);
|
|
88
|
+
const previousPath = `${location.pathname}${location.search}${location.hash}`;
|
|
81
89
|
|
|
82
90
|
queryClient.setQueryData(LIST_DOCUMENTS_QUERY_KEY, (old: any) => {
|
|
83
91
|
const docs: Document[] =
|
|
84
92
|
old?.documents ?? (Array.isArray(old) ? old : []);
|
|
85
|
-
|
|
93
|
+
if (Array.isArray(old)) return [...docs, tempDoc];
|
|
94
|
+
return {
|
|
95
|
+
...(old && typeof old === "object" ? old : {}),
|
|
96
|
+
documents: [...docs, tempDoc],
|
|
97
|
+
};
|
|
86
98
|
});
|
|
87
99
|
queryClient.setQueryData(["action", "get-document", { id }], tempDoc);
|
|
88
100
|
|
|
@@ -111,11 +123,18 @@ export function useCreatePage(opts?: {
|
|
|
111
123
|
};
|
|
112
124
|
|
|
113
125
|
const onPersistError = (err: unknown) => {
|
|
126
|
+
rollbackOptimisticCreatedDocument(
|
|
127
|
+
queryClient,
|
|
128
|
+
id,
|
|
129
|
+
previousDocuments !== undefined,
|
|
130
|
+
);
|
|
114
131
|
queryClient.invalidateQueries({
|
|
115
132
|
queryKey: ["action", "list-documents"],
|
|
116
133
|
});
|
|
117
134
|
queryClient.removeQueries(documentQueryFilter(id));
|
|
118
|
-
if (shouldNavigate)
|
|
135
|
+
if (shouldNavigate) {
|
|
136
|
+
navigate(previousPath, { replace: true, flushSync: true });
|
|
137
|
+
}
|
|
119
138
|
toast.error("Failed to create page", {
|
|
120
139
|
description:
|
|
121
140
|
err instanceof Error ? err.message : "Something went wrong",
|
|
@@ -137,6 +156,9 @@ export function useCreatePage(opts?: {
|
|
|
137
156
|
},
|
|
138
157
|
[
|
|
139
158
|
createDocument,
|
|
159
|
+
location.hash,
|
|
160
|
+
location.pathname,
|
|
161
|
+
location.search,
|
|
140
162
|
navigate,
|
|
141
163
|
onAfterNavigate,
|
|
142
164
|
queryClient,
|
|
@@ -66,6 +66,89 @@ export const LIST_DOCUMENTS_QUERY_KEY = [
|
|
|
66
66
|
undefined,
|
|
67
67
|
] as const;
|
|
68
68
|
|
|
69
|
+
export function restoreListDocumentsSnapshot(
|
|
70
|
+
queryClient: Pick<QueryClient, "removeQueries" | "setQueryData">,
|
|
71
|
+
snapshot: unknown,
|
|
72
|
+
) {
|
|
73
|
+
if (snapshot === undefined) {
|
|
74
|
+
queryClient.removeQueries({ queryKey: LIST_DOCUMENTS_QUERY_KEY });
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
queryClient.setQueryData(LIST_DOCUMENTS_QUERY_KEY, snapshot);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function rollbackOptimisticCreatedDocument(
|
|
81
|
+
queryClient: Pick<
|
|
82
|
+
QueryClient,
|
|
83
|
+
"getQueryData" | "removeQueries" | "setQueryData"
|
|
84
|
+
>,
|
|
85
|
+
documentId: string,
|
|
86
|
+
hadListSnapshot: boolean,
|
|
87
|
+
) {
|
|
88
|
+
const current = queryClient.getQueryData(LIST_DOCUMENTS_QUERY_KEY);
|
|
89
|
+
const documents: Document[] = Array.isArray(current)
|
|
90
|
+
? current
|
|
91
|
+
: ((current as DocumentListResponse | undefined)?.documents ?? []);
|
|
92
|
+
const remaining = documents.filter((document) => document.id !== documentId);
|
|
93
|
+
|
|
94
|
+
if (!hadListSnapshot && remaining.length === 0) {
|
|
95
|
+
queryClient.removeQueries({ queryKey: LIST_DOCUMENTS_QUERY_KEY });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (Array.isArray(current)) {
|
|
100
|
+
queryClient.setQueryData(LIST_DOCUMENTS_QUERY_KEY, remaining);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
queryClient.setQueryData(LIST_DOCUMENTS_QUERY_KEY, {
|
|
105
|
+
...(current && typeof current === "object" ? current : {}),
|
|
106
|
+
documents: remaining,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function restoreDeletedDocumentSnapshots(
|
|
111
|
+
queryClient: Pick<QueryClient, "getQueryData" | "setQueryData">,
|
|
112
|
+
listSnapshot: unknown,
|
|
113
|
+
documentSnapshots: Array<[readonly unknown[], unknown]>,
|
|
114
|
+
deletedDocumentIds: Iterable<string>,
|
|
115
|
+
) {
|
|
116
|
+
const deletedIds = new Set(deletedDocumentIds);
|
|
117
|
+
const snapshotDocuments: Document[] = Array.isArray(listSnapshot)
|
|
118
|
+
? listSnapshot
|
|
119
|
+
: ((listSnapshot as DocumentListResponse | undefined)?.documents ?? []);
|
|
120
|
+
const current = queryClient.getQueryData(LIST_DOCUMENTS_QUERY_KEY);
|
|
121
|
+
const currentDocuments: Document[] = Array.isArray(current)
|
|
122
|
+
? current
|
|
123
|
+
: ((current as DocumentListResponse | undefined)?.documents ?? []);
|
|
124
|
+
const currentDocumentIds = new Set(
|
|
125
|
+
currentDocuments.map((document) => document.id),
|
|
126
|
+
);
|
|
127
|
+
const restoredDocuments = snapshotDocuments.filter(
|
|
128
|
+
(document) =>
|
|
129
|
+
deletedIds.has(document.id) && !currentDocumentIds.has(document.id),
|
|
130
|
+
);
|
|
131
|
+
const documents = [...currentDocuments, ...restoredDocuments];
|
|
132
|
+
|
|
133
|
+
if (Array.isArray(current)) {
|
|
134
|
+
queryClient.setQueryData(LIST_DOCUMENTS_QUERY_KEY, documents);
|
|
135
|
+
} else {
|
|
136
|
+
queryClient.setQueryData(LIST_DOCUMENTS_QUERY_KEY, {
|
|
137
|
+
...(current && typeof current === "object"
|
|
138
|
+
? current
|
|
139
|
+
: listSnapshot && typeof listSnapshot === "object"
|
|
140
|
+
? listSnapshot
|
|
141
|
+
: {}),
|
|
142
|
+
documents,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
for (const [queryKey, data] of documentSnapshots) {
|
|
146
|
+
if (queryClient.getQueryData(queryKey) === undefined) {
|
|
147
|
+
queryClient.setQueryData(queryKey, data);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
69
152
|
const DOCUMENT_LIST_PAGE_SIZE = 200;
|
|
70
153
|
|
|
71
154
|
export async function fetchCompleteDocumentList(
|
package/corpus/templates/content/docs/solutions/2026-08-18-content-navigation-coherence-shape.md
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
# Content navigation coherence: ordered cache-boundary repairs
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
Four durable reports describe navigation that temporarily disagrees with
|
|
6
|
+
committed Content state: the tree blanks after page creation, an MCP-created
|
|
7
|
+
file does not appear without reload, a deleted page remains briefly, and a new
|
|
8
|
+
pin takes seconds to appear. They are related as user experience, but current
|
|
9
|
+
repository evidence does **not** support one four-symptom implementation lane.
|
|
10
|
+
|
|
11
|
+
Creation, deletion, and cross-surface MCP creation all converge on the complete
|
|
12
|
+
`list-documents` action query that supplies the document tree. Pinning does not:
|
|
13
|
+
the visible Pinned section is rendered from the Favorites system database's
|
|
14
|
+
`get-content-database` query. The current code already contains partial or
|
|
15
|
+
complete-looking repairs for each path, so historical reports cannot establish
|
|
16
|
+
that any particular failure still reproduces on current head.
|
|
17
|
+
|
|
18
|
+
The smallest compatible first slice is therefore one document-list coherence
|
|
19
|
+
lane, beginning with a current-head successful-user-story reproduction matrix.
|
|
20
|
+
It may repair only the first demonstrated failure at the existing query/cache
|
|
21
|
+
ownership boundary. Pinning stays a separately ordered repair after that lane;
|
|
22
|
+
it must not be folded into a generic navigation store or broad invalidation
|
|
23
|
+
helper.
|
|
24
|
+
|
|
25
|
+
## Durable task cluster
|
|
26
|
+
|
|
27
|
+
- `ab8d5f7f-2fc7-438a-8c63-74a5e1b42b55` — **Fix Content navigation tree
|
|
28
|
+
flicker after page creation**. Two reporter flows and Clips show the entire
|
|
29
|
+
tree disappearing temporarily after creation.
|
|
30
|
+
- `7438346b-c717-4e2f-b581-a90cb2c91ab8` — **Refresh Content navigation after
|
|
31
|
+
MCP-created files**. A reporter says supported MCP creation remains absent
|
|
32
|
+
until reload.
|
|
33
|
+
- `50c4a2d7-2525-4fa3-8260-6ae3e4beb6f7` — **Remove stale Content navigation
|
|
34
|
+
after page deletion**. A reporter Clip shows confirmed deletion leaving a
|
|
35
|
+
stale entry briefly.
|
|
36
|
+
- `a185e193-28fb-4d0d-a014-e79d4ddcb6c3` — **Make Content pinning update the
|
|
37
|
+
sidebar immediately**. The report says pinning takes about three seconds
|
|
38
|
+
while unpinning is nearly immediate.
|
|
39
|
+
|
|
40
|
+
These are historical reporter observations. This Shape did not replay the
|
|
41
|
+
Clips or mutate a live Content runtime, and it does not claim a fresh
|
|
42
|
+
reproduction.
|
|
43
|
+
|
|
44
|
+
## Product context
|
|
45
|
+
|
|
46
|
+
- Feature: `content.feature.find-your-place-again` (partially implemented).
|
|
47
|
+
- Capability: `content.navigation.sidebar` (approved shape).
|
|
48
|
+
- User workflow: while Content is open, create, externally create, delete, pin,
|
|
49
|
+
or unpin a Page and continue navigating without the sidebar blanking, lagging,
|
|
50
|
+
or presenting stale success.
|
|
51
|
+
- Product contract preserved: the sidebar is a personal navigation projection,
|
|
52
|
+
not object parentage or a second source of truth. Personal pins must not
|
|
53
|
+
reparent Pages or alter Database membership beyond the Favorites reference.
|
|
54
|
+
- Change classification: contract repair if a current-head reproduction fails;
|
|
55
|
+
verification-only closure for any historical symptom that current evidence
|
|
56
|
+
proves already repaired.
|
|
57
|
+
|
|
58
|
+
## Current architecture and demonstrated callers
|
|
59
|
+
|
|
60
|
+
### Document-tree projection
|
|
61
|
+
|
|
62
|
+
`DocumentSidebar` calls `useDocuments()`. That hook owns the stable
|
|
63
|
+
`["action", "list-documents", undefined]` query and refuses to return a clipped
|
|
64
|
+
paginated list as complete. The sidebar derives local-file and database trees
|
|
65
|
+
from that one complete document list.
|
|
66
|
+
|
|
67
|
+
Demonstrated callers entering this projection:
|
|
68
|
+
|
|
69
|
+
1. **Sidebar page creation.** `handleCreatePage` calls the shared
|
|
70
|
+
`create-document` Action. Ordinary SQL creation and local-file creation
|
|
71
|
+
backed by a Files database insert a temporary document into
|
|
72
|
+
`LIST_DOCUMENTS_QUERY_KEY`; direct local-file creation without that
|
|
73
|
+
database waits for write-back before navigation.
|
|
74
|
+
2. **Sidebar deletion.** `handleDelete` computes the deleted subtree, removes
|
|
75
|
+
those rows from `LIST_DOCUMENTS_QUERY_KEY`, removes per-document queries,
|
|
76
|
+
and chooses a safe remaining route before calling `delete-document` or
|
|
77
|
+
`delete-content-database`. Success and failure both refetch the list; failure
|
|
78
|
+
does not restore a captured list snapshot directly.
|
|
79
|
+
3. **MCP/tool creation.** Mutating Action execution emits a durable
|
|
80
|
+
action-change marker. Root `useDbSync()` receives action events and the core
|
|
81
|
+
sync hook invalidates active `["action"]` queries, including
|
|
82
|
+
`list-documents`, while preserving a trailing refresh when an older read is
|
|
83
|
+
already in flight. The framework already intends this to be the cross-tab,
|
|
84
|
+
agent, script, and MCP convergence seam.
|
|
85
|
+
|
|
86
|
+
### Pinned projection
|
|
87
|
+
|
|
88
|
+
`DocumentSidebar` obtains `favoritesDatabaseId` from `list-content-spaces`,
|
|
89
|
+
reads the Pinned section through `useContentDatabaseById(favoritesDatabaseId)`,
|
|
90
|
+
and renders its `ContentDatabaseItem` rows. Pin/unpin calls `update-document`
|
|
91
|
+
with `isFavorite`.
|
|
92
|
+
|
|
93
|
+
`useUpdateDocument` optimistically patches per-document, `list-documents`, and
|
|
94
|
+
every cached `get-content-database` response and restores captured snapshots on
|
|
95
|
+
error. For a Favorites database, setting `isFavorite: false` removes an
|
|
96
|
+
existing row immediately. Setting it to `true` can only patch an item already
|
|
97
|
+
present; it cannot synthesize the missing Favorites membership row. This
|
|
98
|
+
directly predicts the reported asymmetry—unpin is immediate while pin waits for
|
|
99
|
+
the database query to refetch—but remains an inference until reproduced on
|
|
100
|
+
current head.
|
|
101
|
+
|
|
102
|
+
### Navigation and application state
|
|
103
|
+
|
|
104
|
+
Route selection (`activeDocumentId`, React Router navigation, selected Content
|
|
105
|
+
space, expanded nodes, and persisted sidebar expansion) controls which existing
|
|
106
|
+
projection is open. It does not own document-list membership or Favorites
|
|
107
|
+
membership. No evidence supports moving these four repairs into application
|
|
108
|
+
state or creating a new navigation store.
|
|
109
|
+
|
|
110
|
+
## Architecture grounding and fit
|
|
111
|
+
|
|
112
|
+
### Direct evidence
|
|
113
|
+
|
|
114
|
+
- `templates/content/app/components/sidebar/DocumentSidebar.tsx` renders the
|
|
115
|
+
tree from `useDocuments`, optimistically removes deleted subtrees, and renders
|
|
116
|
+
Pinned from the Favorites `get-content-database` response.
|
|
117
|
+
- `templates/content/app/hooks/use-documents.ts` owns the complete-list query,
|
|
118
|
+
document cache patches, optimistic favorite updates, rollback snapshots, and
|
|
119
|
+
explicit document/list/database invalidation.
|
|
120
|
+
- `templates/content/app/hooks/use-content-database.ts` owns database response
|
|
121
|
+
caches and existing optimistic database-item movement.
|
|
122
|
+
- `templates/content/app/hooks/use-db-sync.ts` installs the Content root's core
|
|
123
|
+
database/action synchronization.
|
|
124
|
+
- `packages/core/src/client/use-db-sync.ts`, action routes, CLI runner, and
|
|
125
|
+
production-agent paths establish action-change events as the intended
|
|
126
|
+
cross-surface invalidation seam.
|
|
127
|
+
- The four Bowerbird notes preserve the reporter observations, distinct outcome
|
|
128
|
+
boundaries, and done conditions.
|
|
129
|
+
|
|
130
|
+
### Inferences to test
|
|
131
|
+
|
|
132
|
+
- The creation report may arise from a loading-state transition or list-cache
|
|
133
|
+
replacement around ordinary SQL creation, but invalidation alone does not
|
|
134
|
+
prove that cause.
|
|
135
|
+
- The deletion report may reflect an older implementation, a refetch race, a
|
|
136
|
+
content-database deletion path, or rollback behavior; current optimistic
|
|
137
|
+
removal means the historical Clip is not current-head proof.
|
|
138
|
+
- MCP visibility should converge through action-change invalidation; if it does
|
|
139
|
+
not, the first missing boundary may be marker publication, delivery/cursor
|
|
140
|
+
replay, event scoping, or the list refetch—not necessarily React Query.
|
|
141
|
+
- Pin latency is likely the absent optimistic Favorites membership row, not the
|
|
142
|
+
document-list query or navigation state.
|
|
143
|
+
|
|
144
|
+
### Ownership boundaries
|
|
145
|
+
|
|
146
|
+
- Actions and SQL own committed Page and Favorites membership state.
|
|
147
|
+
- `useDocuments` and `LIST_DOCUMENTS_QUERY_KEY` own the complete document-list
|
|
148
|
+
client projection.
|
|
149
|
+
- `get-content-database` caches own Favorites rows and order.
|
|
150
|
+
- Core `useDbSync` plus action-change markers own cross-surface freshness
|
|
151
|
+
signaling; Content may configure or narrowly consume that seam but must not
|
|
152
|
+
add an MCP-only refresh channel.
|
|
153
|
+
- React Router and Content sidebar state own route, selection, and expansion,
|
|
154
|
+
not object membership.
|
|
155
|
+
|
|
156
|
+
### Legacy contracts that must remain unchanged
|
|
157
|
+
|
|
158
|
+
- `list-documents` exhaustion remains explicit; absent, unreadable, clipped,
|
|
159
|
+
and successfully empty results stay distinguishable.
|
|
160
|
+
- The dedicated `get-document` response remains authoritative for editable
|
|
161
|
+
bodies; list/database snapshots must not seed a body as fresh.
|
|
162
|
+
- Local-file optimistic creation and write-back behavior remain intact.
|
|
163
|
+
- Deletes navigate safely, remove the full subtree, and roll back visibly on
|
|
164
|
+
failure.
|
|
165
|
+
- Pinning remains personal and access-scoped, with truthful persistence,
|
|
166
|
+
rollback, and no Page reparenting.
|
|
167
|
+
- Action-change sync remains generic across browser, MCP, agent, CLI, and other
|
|
168
|
+
supported Action callers; no provider- or MCP-specific twin path is added.
|
|
169
|
+
- Broad bare-action invalidation is not added to high-volume paths that already
|
|
170
|
+
own narrow invalidation.
|
|
171
|
+
|
|
172
|
+
### Smallest compatible delta
|
|
173
|
+
|
|
174
|
+
First, characterize all three document-list flows against one mounted sidebar
|
|
175
|
+
and the real supported interfaces. If a document-list symptom fails, fix only
|
|
176
|
+
the earliest demonstrated break in the existing Action -> action-change or
|
|
177
|
+
mutation lifecycle -> `LIST_DOCUMENTS_QUERY_KEY` -> derived tree chain. Preserve
|
|
178
|
+
the previous successful list while a replacement read is pending and use exact
|
|
179
|
+
optimistic patch/rollback only where the failing flow requires it.
|
|
180
|
+
|
|
181
|
+
Do not design a generic `navigation-coherence` cache, an application-state copy,
|
|
182
|
+
or a new subscription. Existing ownership is already specific enough.
|
|
183
|
+
|
|
184
|
+
### Deferred capabilities
|
|
185
|
+
|
|
186
|
+
- Optimistic construction of a new Favorites `ContentDatabaseItem` and its
|
|
187
|
+
exact rollback/reconciliation strategy.
|
|
188
|
+
- Dynamic Recent/Shared sections, generalized personal References, and the
|
|
189
|
+
complete `content.navigation.sidebar` Capability.
|
|
190
|
+
- Session restoration, view-instance state, local-folder watch behavior, and
|
|
191
|
+
provider-source hydration.
|
|
192
|
+
- Refactoring every mutation to a generalized normalized entity cache.
|
|
193
|
+
|
|
194
|
+
### Reversibility
|
|
195
|
+
|
|
196
|
+
The first slice is restricted to current query keys, mutation callbacks, sync
|
|
197
|
+
configuration, and focused regression coverage. It adds no schema, route,
|
|
198
|
+
protocol, source-of-truth, or product vocabulary and can be reverted without
|
|
199
|
+
data migration.
|
|
200
|
+
|
|
201
|
+
### Unresolved owner questions
|
|
202
|
+
|
|
203
|
+
None. Current code and product records settle the public boundaries; the
|
|
204
|
+
remaining uncertainty is empirical current-head behavior for Work to establish.
|
|
205
|
+
|
|
206
|
+
## Implementation-lane decision
|
|
207
|
+
|
|
208
|
+
Use **two separately ordered repair lanes**, not one four-symptom lane:
|
|
209
|
+
|
|
210
|
+
1. **Document-list coherence lane (first).** Treat creation, deletion, and MCP
|
|
211
|
+
creation as one investigation/proof lane because they share the same rendered
|
|
212
|
+
query boundary. Within it, repair only symptoms that reproduce, in this
|
|
213
|
+
order: creation flicker, deletion success/rollback, then MCP cross-surface
|
|
214
|
+
convergence. One fix may close siblings only when the complete acceptance
|
|
215
|
+
matrix proves that exact shared delta.
|
|
216
|
+
2. **Favorites membership lane (second).** Shape/implement immediate pin and
|
|
217
|
+
unpin behavior at the Favorites database cache boundary. It may reuse
|
|
218
|
+
existing database-cache helpers, but it is not coupled to the first lane's
|
|
219
|
+
document-list or sync repair and should not delay it.
|
|
220
|
+
|
|
221
|
+
This ordering puts the highest-confidence shared boundary first while avoiding
|
|
222
|
+
a four-task PR whose mechanism and proof surface would be ambiguous.
|
|
223
|
+
|
|
224
|
+
## Explicit exclusions
|
|
225
|
+
|
|
226
|
+
- No shipping-code edit, dependency, schema, migration, branch operation,
|
|
227
|
+
commit, push, pull request, deployment, feature-flag change, merge, or
|
|
228
|
+
Bowerbird status mutation is authorized by this Shape.
|
|
229
|
+
- No new navigation store, event bus, subscription, raw REST endpoint, or MCP-
|
|
230
|
+
specific refresh action.
|
|
231
|
+
- No redesign of the sidebar, hierarchy, Content spaces, Home, Recent, Shared,
|
|
232
|
+
session restore, or database Views.
|
|
233
|
+
- No claim that historical reports reproduce on current head.
|
|
234
|
+
- No automatic consolidation or completion of the four Bowerbird tasks; Work
|
|
235
|
+
must reconcile each only from exact current proof.
|
|
236
|
+
|
|
237
|
+
## Successful-user-story acceptance plan
|
|
238
|
+
|
|
239
|
+
Story `content-navigation-document-list-coherence-v1`:
|
|
240
|
+
|
|
241
|
+
> With an existing populated Content sidebar open, a person can create and
|
|
242
|
+
> delete a Page while a supported Content MCP caller can create another Page;
|
|
243
|
+
> throughout those changes the existing tree never blanks, committed additions
|
|
244
|
+
> appear without reload, confirmed deletions disappear immediately with safe
|
|
245
|
+
> navigation, failed deletion restores the prior truthful state, and incomplete
|
|
246
|
+
> reads never masquerade as an empty workspace.
|
|
247
|
+
|
|
248
|
+
Required assertions:
|
|
249
|
+
|
|
250
|
+
1. Starting from at least two visible Pages, ordinary UI page creation keeps the
|
|
251
|
+
pre-existing rows visible continuously and adds/navigates to exactly one new
|
|
252
|
+
Page after success.
|
|
253
|
+
2. Failed UI creation restores the exact prior tree and route with an explicit
|
|
254
|
+
error; it leaves no optimistic row or stale page query.
|
|
255
|
+
3. Supported MCP creation in the same workspace appears in the already-open
|
|
256
|
+
sidebar without manual reload and without duplicate rows.
|
|
257
|
+
4. A confirmed UI deletion removes the Page and descendants immediately and
|
|
258
|
+
selects a deterministic safe remaining destination.
|
|
259
|
+
5. A failed deletion restores the exact prior tree and active route and exposes
|
|
260
|
+
the failure instead of presenting deletion success.
|
|
261
|
+
6. During slow/in-flight replacement reads, the last complete successful list
|
|
262
|
+
stays visible; unavailable, unauthorized, inconsistent-pagination, and
|
|
263
|
+
successfully empty results remain distinct.
|
|
264
|
+
7. The same flows do not regress local-file creation, per-document body
|
|
265
|
+
authority, access scoping, or full-list pagination.
|
|
266
|
+
|
|
267
|
+
Acceptance policy:
|
|
268
|
+
|
|
269
|
+
- Modality: `real-interface` joined with focused automated regression coverage.
|
|
270
|
+
- Independence: `preferred`.
|
|
271
|
+
- Custody: `same-context-allowed`.
|
|
272
|
+
- Interface: the real Content UI for UI create/delete plus the supported
|
|
273
|
+
Content MCP Action surface for cross-surface creation, against an isolated
|
|
274
|
+
local or branch-preview workspace with task-owned disposable Pages.
|
|
275
|
+
- Rationale: the defect is interaction timing across two real callers, so unit
|
|
276
|
+
tests alone are insufficient. Alice did not require tester-owned independent
|
|
277
|
+
custody; same-context evidence is proportionate, with technical review and
|
|
278
|
+
automated failure/rollback coverage.
|
|
279
|
+
|
|
280
|
+
Work must declare exact disposable Page IDs and baseline tree state before
|
|
281
|
+
mutation, delete every created Page, and prove independent absence before
|
|
282
|
+
acceptance can be satisfied.
|
|
283
|
+
|
|
284
|
+
The second Favorites lane retains its own acceptance story from Bowerbird:
|
|
285
|
+
pin and unpin update immediately, success reconciles to persisted Favorites
|
|
286
|
+
membership, failure restores the prior state with an explicit error, and
|
|
287
|
+
focused plus real-interface coverage exercises both directions. That story is
|
|
288
|
+
not part of the first Work grant.
|
|
289
|
+
|
|
290
|
+
## Architecture fingerprint — frozen five
|
|
291
|
+
|
|
292
|
+
```yaml
|
|
293
|
+
authoritySchemaVersion: 3
|
|
294
|
+
stage: shape
|
|
295
|
+
authority-source: >-
|
|
296
|
+
Delegated request from Codex thread 01a00f83-f02d-7b42-9a31-ff18c5a5eded:
|
|
297
|
+
shape the four named Content navigation tasks only; implementation is not
|
|
298
|
+
authorized.
|
|
299
|
+
authorized-scope:
|
|
300
|
+
repositories:
|
|
301
|
+
- /Users/alicemoore/.codex/worktrees/e19d/agent-native
|
|
302
|
+
product-surfaces:
|
|
303
|
+
- Content document-tree navigation
|
|
304
|
+
outcome: >-
|
|
305
|
+
Prove and repair current-head coherence for UI-created, UI-deleted, and
|
|
306
|
+
MCP-created Pages at the existing complete document-list boundary without
|
|
307
|
+
coupling the separate Favorites membership repair.
|
|
308
|
+
allowed-mutations:
|
|
309
|
+
- artifact-write
|
|
310
|
+
write-targets:
|
|
311
|
+
artifacts:
|
|
312
|
+
- templates/content/docs/solutions/2026-08-18-content-navigation-coherence-shape.md
|
|
313
|
+
governing-artifact:
|
|
314
|
+
path: templates/content/docs/solutions/2026-08-18-content-navigation-coherence-shape.md
|
|
315
|
+
revision: shape-v1-2026-08-18
|
|
316
|
+
architecture-fingerprint:
|
|
317
|
+
outcome: >-
|
|
318
|
+
Existing Content navigation remains truthful and continuously usable while
|
|
319
|
+
UI and MCP Page mutations converge through the document-list projection.
|
|
320
|
+
shipping-surfaces:
|
|
321
|
+
- id: content-document-list-navigation
|
|
322
|
+
repository: builderio/agent-native
|
|
323
|
+
product-surface: templates/content document-tree sidebar and Action sync
|
|
324
|
+
constituency: authorized Content users using UI and supported MCP callers
|
|
325
|
+
durable-destination: agent-native origin/main Content template
|
|
326
|
+
integration-action: merge
|
|
327
|
+
governing-architecture: >-
|
|
328
|
+
Actions and SQL remain authoritative; UI-local mutation lifecycles and the
|
|
329
|
+
existing core action-change sync seam converge the complete
|
|
330
|
+
LIST_DOCUMENTS_QUERY_KEY projection, while route/application state owns
|
|
331
|
+
selection only and Favorites remains a separate database projection.
|
|
332
|
+
acceptance-story:
|
|
333
|
+
id: content-navigation-document-list-coherence-v1
|
|
334
|
+
summary: >-
|
|
335
|
+
A populated open sidebar stays visible and converges without reload across
|
|
336
|
+
UI create, UI delete success and rollback, and supported MCP creation.
|
|
337
|
+
required-assertions:
|
|
338
|
+
- UI creation preserves existing rows and adds exactly one committed Page.
|
|
339
|
+
- Creation failure restores the exact prior tree and route.
|
|
340
|
+
- Supported MCP creation appears without reload or duplication.
|
|
341
|
+
- Deletion removes the subtree and selects a safe destination immediately.
|
|
342
|
+
- Deletion failure restores the exact prior tree and active route.
|
|
343
|
+
- Slow, failed, unreadable, clipped, and empty reads remain distinguishable.
|
|
344
|
+
- Local-file behavior, body authority, access scope, and pagination remain intact.
|
|
345
|
+
acceptance-policy:
|
|
346
|
+
modality: real-interface
|
|
347
|
+
independence: preferred
|
|
348
|
+
custody: same-context-allowed
|
|
349
|
+
interface: >-
|
|
350
|
+
Real Content UI plus supported Content MCP Actions in an isolated local
|
|
351
|
+
or branch-preview workspace with declared disposable Pages.
|
|
352
|
+
rationale: >-
|
|
353
|
+
Timing and cross-caller convergence require real interfaces; Alice did
|
|
354
|
+
not make independent tester custody part of the story.
|
|
355
|
+
risk-strategy:
|
|
356
|
+
kind: system-ready
|
|
357
|
+
production-validation-after-merge: false
|
|
358
|
+
architecture-grounding:
|
|
359
|
+
applicability: required
|
|
360
|
+
reason: >-
|
|
361
|
+
The lane crosses Content mutation hooks and the shared framework
|
|
362
|
+
action-change synchronization seam.
|
|
363
|
+
status: grounded
|
|
364
|
+
demonstrated-callers:
|
|
365
|
+
- DocumentSidebar UI create through create-document.
|
|
366
|
+
- DocumentSidebar UI delete through delete-document or delete-content-database.
|
|
367
|
+
- Supported Content MCP/tool create through the same mutating Action surface.
|
|
368
|
+
existing-primitives:
|
|
369
|
+
- useDocuments and LIST_DOCUMENTS_QUERY_KEY complete-list cache.
|
|
370
|
+
- DocumentSidebar optimistic local-file create and subtree delete patches.
|
|
371
|
+
- useUpdateDocument cache snapshots and rollback.
|
|
372
|
+
- core useDbSync action-change invalidation with trailing refresh.
|
|
373
|
+
ownership-boundaries:
|
|
374
|
+
- SQL and Actions own committed objects and memberships.
|
|
375
|
+
- list-documents owns the complete tree projection.
|
|
376
|
+
- get-content-database owns Favorites membership rows.
|
|
377
|
+
- action-change sync owns cross-surface freshness delivery.
|
|
378
|
+
- Router and sidebar state own selection and expansion only.
|
|
379
|
+
legacy-contracts:
|
|
380
|
+
- Complete-list pagination fails loudly rather than returning a clipped success.
|
|
381
|
+
- get-document remains authoritative for editable bodies.
|
|
382
|
+
- Local-file optimistic creation and write-back remain intact.
|
|
383
|
+
- Delete success, rollback, and safe navigation remain truthful.
|
|
384
|
+
- Action-change stays caller-generic and access-scoped.
|
|
385
|
+
shared-vocabulary:
|
|
386
|
+
- document-list projection
|
|
387
|
+
- Favorites membership projection
|
|
388
|
+
- action-change sync seam
|
|
389
|
+
smallest-compatible-delta: >-
|
|
390
|
+
Reproduce the three document-list flows on current head, then repair only
|
|
391
|
+
the earliest demonstrated break inside the existing mutation/action-change
|
|
392
|
+
to LIST_DOCUMENTS_QUERY_KEY chain, preserving the last complete list and
|
|
393
|
+
adding exact rollback where the failed story requires it.
|
|
394
|
+
deferred-capabilities:
|
|
395
|
+
- Immediate optimistic Favorites membership creation and rollback.
|
|
396
|
+
- Full personal References and dynamic sidebar sections.
|
|
397
|
+
- Session restoration, Home, Recent, Shared, and provider/local-source sync.
|
|
398
|
+
reversibility: >-
|
|
399
|
+
No schema or public contract changes; the slice stays within existing query
|
|
400
|
+
keys, mutation callbacks, sync configuration, and regression coverage.
|
|
401
|
+
direct-evidence:
|
|
402
|
+
- templates/content/app/components/sidebar/DocumentSidebar.tsx
|
|
403
|
+
- templates/content/app/hooks/use-documents.ts
|
|
404
|
+
- templates/content/app/hooks/use-content-database.ts
|
|
405
|
+
- templates/content/app/hooks/use-db-sync.ts
|
|
406
|
+
- packages/core/src/client/use-db-sync.ts
|
|
407
|
+
- templates/content/docs/product/capabilities/content.navigation.sidebar.md
|
|
408
|
+
- the four named Bowerbird task notes
|
|
409
|
+
inferences:
|
|
410
|
+
- Pin asymmetry likely comes from inability to add an absent optimistic Favorites row.
|
|
411
|
+
- Historical creation, deletion, and MCP failures may have changed on current head.
|
|
412
|
+
unresolved-owner-questions: []
|
|
413
|
+
delegation-ceiling: []
|
|
414
|
+
product-boundary-gates:
|
|
415
|
+
agent-native-public-constituency: >-
|
|
416
|
+
Content is a public template surface for authorized end users and supported
|
|
417
|
+
MCP callers; the repository evidence names both callers and one shared Action contract.
|
|
418
|
+
bowerbird-product-boundary: >-
|
|
419
|
+
Four existing tasks remain separate durable outcomes; this artifact orders
|
|
420
|
+
their repair and does not mutate or collapse their status.
|
|
421
|
+
acceptance-state:
|
|
422
|
+
status: satisfied
|
|
423
|
+
summary: >-
|
|
424
|
+
Work preserves the complete list-cache shape during optimistic creation,
|
|
425
|
+
removes only the failed creation's temporary Page, and restores exact list
|
|
426
|
+
and document snapshots on failed deletion. Sixty-two focused tests,
|
|
427
|
+
typecheck, all 55 guards, a
|
|
428
|
+
production build, real UI creation/deletion, and open-UI Action refresh are
|
|
429
|
+
green. Every declared disposable Page is independently absent after cleanup.
|
|
430
|
+
blockers: []
|
|
431
|
+
last-land-packet: null
|
|
432
|
+
ledger-revision: content-navigation-coherence-work-v1
|
|
433
|
+
status: review-ready
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
## Work evidence — 2026-08-18
|
|
437
|
+
|
|
438
|
+
- Exact branch: `codex/content-navigation-coherence` from
|
|
439
|
+
`origin/main@39383b558b881269a1387d7cfcc94eba8826250b`.
|
|
440
|
+
- Smallest delta: preserve the existing list-cache envelope during optimistic
|
|
441
|
+
creation; remove only the failed creation's temporary Page so concurrent
|
|
442
|
+
creates survive; restore deletion list/per-document snapshots and the exact
|
|
443
|
+
prior URL synchronously on mutation failure; remove the optimistic list query
|
|
444
|
+
when no prior snapshot existed.
|
|
445
|
+
- Cross-surface result: two Action-created Pages appeared in the already-open
|
|
446
|
+
real sidebar without reload or duplication, so no new MCP channel or core
|
|
447
|
+
sync change was necessary.
|
|
448
|
+
- Real UI result: with `nav-baseline-a` and `nav-baseline-b` visible, creating
|
|
449
|
+
`nav-ui-create` kept both baseline rows visible and navigated to exactly one
|
|
450
|
+
new Page. Confirmed deletion removed it immediately and navigated to the
|
|
451
|
+
surviving `Dev's workspace` surface while both baseline rows remained.
|
|
452
|
+
- Automated result: 62 focused Content tests pass, including concurrent and
|
|
453
|
+
absent-list creation rollback, exact prior-URL restoration, complete-list
|
|
454
|
+
pagination, and deleted list/per-document snapshot restoration. The 44
|
|
455
|
+
focused core sync tests also pass.
|
|
456
|
+
- Repository result: Content typecheck, `git diff --check`, all 55 guards, and
|
|
457
|
+
the Content production build pass. The build reports pre-existing doctor and
|
|
458
|
+
local-production-configuration warnings but completes successfully.
|
|
459
|
+
- Review result: an independent read-only review found two rollback holes
|
|
460
|
+
(prior-route restoration and absent-snapshot semantics) plus weak deletion
|
|
461
|
+
coverage; all three were corrected and covered before acceptance.
|
|
462
|
+
- Cleanup receipt: `nav-baseline-a`, `nav-baseline-b`, and
|
|
463
|
+
`thmKsbqMzOAJ` (`nav-ui-create`) were permanently deleted. The open sidebar
|
|
464
|
+
reported zero matching rows, SQLite reported zero matching records, port
|
|
465
|
+
`8086` had no listener after shutdown, and
|
|
466
|
+
`/tmp/content-nav-coherence.CFh4Jg` was moved to Trash.
|
|
467
|
+
- Compute receipt: framework remote preflight could not run because Tailscale
|
|
468
|
+
was stopped, so the supported Mac fallback was used; no remote workload or
|
|
469
|
+
manifest was created.
|
|
470
|
+
|
|
471
|
+
## Precise Work handoff
|
|
472
|
+
|
|
473
|
+
Invoke:
|
|
474
|
+
|
|
475
|
+
`/work templates/content/docs/solutions/2026-08-18-content-navigation-coherence-shape.md`
|
|
476
|
+
|
|
477
|
+
Work is authorized only after that explicit invocation. It should begin with
|
|
478
|
+
the document-list acceptance matrix, preserve the exact frozen fingerprint,
|
|
479
|
+
and stop rather than absorbing the deferred Favorites lane. When the first lane
|
|
480
|
+
is proven and review-ready, reconcile each of the three document-list Bowerbird
|
|
481
|
+
tasks independently from its evidence; leave the pinning task open for its
|
|
482
|
+
separate ordered repair.
|
|
@@ -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;
|
|
65
66
|
states: {
|
|
66
67
|
clientId: number;
|
|
67
68
|
state: string;
|
|
68
69
|
}[];
|
|
69
|
-
error?: undefined;
|
|
70
70
|
}>>;
|
|
71
71
|
/**
|
|
72
72
|
* GET /_agent-native/collab/:docId/users
|
|
@@ -77,9 +77,9 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
|
|
|
77
77
|
error: string;
|
|
78
78
|
users?: undefined;
|
|
79
79
|
} | {
|
|
80
|
+
error?: undefined;
|
|
80
81
|
users: {
|
|
81
82
|
clientId: number;
|
|
82
83
|
lastSeen: number;
|
|
83
84
|
}[];
|
|
84
|
-
error?: undefined;
|
|
85
85
|
}>>;
|
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
* DELETE /_agent-native/notifications/:id — delete
|
|
12
12
|
*/
|
|
13
13
|
export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
|
|
14
|
+
error?: undefined;
|
|
14
15
|
count: number;
|
|
15
16
|
updated?: undefined;
|
|
16
|
-
error?: undefined;
|
|
17
17
|
ok?: undefined;
|
|
18
18
|
} | {
|
|
19
|
+
error?: undefined;
|
|
19
20
|
count?: undefined;
|
|
20
21
|
updated: number;
|
|
21
|
-
error?: undefined;
|
|
22
22
|
ok?: undefined;
|
|
23
23
|
} | {
|
|
24
24
|
count?: undefined;
|
|
@@ -26,8 +26,8 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
|
|
|
26
26
|
error: string;
|
|
27
27
|
ok?: undefined;
|
|
28
28
|
} | {
|
|
29
|
+
error?: undefined;
|
|
29
30
|
count?: undefined;
|
|
30
31
|
updated?: undefined;
|
|
31
|
-
error?: undefined;
|
|
32
32
|
ok: boolean;
|
|
33
33
|
}>>;
|
|
@@ -41,27 +41,27 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
41
41
|
thumbsUpRate: number;
|
|
42
42
|
avgEvalScore: number;
|
|
43
43
|
} | {
|
|
44
|
+
ok?: undefined;
|
|
45
|
+
error?: undefined;
|
|
44
46
|
summary: import("./types.js").TraceSummary;
|
|
45
47
|
spans: import("./types.js").TraceSpan[];
|
|
46
48
|
id?: undefined;
|
|
47
|
-
error?: undefined;
|
|
48
|
-
ok?: undefined;
|
|
49
49
|
} | {
|
|
50
|
+
ok?: undefined;
|
|
51
|
+
error?: undefined;
|
|
50
52
|
summary?: undefined;
|
|
51
53
|
spans?: undefined;
|
|
52
54
|
id: string;
|
|
53
|
-
error?: undefined;
|
|
54
|
-
ok?: undefined;
|
|
55
55
|
} | {
|
|
56
|
+
ok?: undefined;
|
|
56
57
|
summary?: undefined;
|
|
57
58
|
spans?: undefined;
|
|
58
59
|
id?: undefined;
|
|
59
60
|
error: any;
|
|
60
|
-
ok?: undefined;
|
|
61
61
|
} | {
|
|
62
|
+
error?: undefined;
|
|
62
63
|
summary?: undefined;
|
|
63
64
|
spans?: undefined;
|
|
64
65
|
id?: undefined;
|
|
65
|
-
error?: undefined;
|
|
66
66
|
ok: boolean;
|
|
67
67
|
}>>;
|
package/dist/server/auth.js
CHANGED
|
@@ -1242,7 +1242,7 @@ export function prepareDesktopOAuthBrowserBinding(event) {
|
|
|
1242
1242
|
if (!binding || !/^[A-Za-z0-9_-]{43}$/.test(binding)) {
|
|
1243
1243
|
binding = crypto.randomBytes(32).toString("base64url");
|
|
1244
1244
|
setCookie(event, DESKTOP_OAUTH_BROWSER_BINDING_COOKIE, binding, {
|
|
1245
|
-
...
|
|
1245
|
+
...desktopOAuthBrowserBindingCookieAttrs(event),
|
|
1246
1246
|
httpOnly: true,
|
|
1247
1247
|
path: "/",
|
|
1248
1248
|
maxAge: Math.floor(DESKTOP_EXCHANGE_TTL_MS / 1_000),
|
|
@@ -2810,6 +2810,18 @@ function crossSiteCookieAttrs(event) {
|
|
|
2810
2810
|
? { sameSite: "none", secure: true, partitioned: true }
|
|
2811
2811
|
: { sameSite: "lax", secure: false };
|
|
2812
2812
|
}
|
|
2813
|
+
/**
|
|
2814
|
+
* The binding cookie is set before navigating to Google and read after the
|
|
2815
|
+
* provider redirects back. A partitioned cookie uses the top-level site from
|
|
2816
|
+
* the bootstrap request, so it is unavailable when the callback starts from
|
|
2817
|
+
* Google's top-level site. Keep this host-scoped cookie unpartitioned while
|
|
2818
|
+
* retaining the cross-site and transport protections required by the flow.
|
|
2819
|
+
*/
|
|
2820
|
+
function desktopOAuthBrowserBindingCookieAttrs(event) {
|
|
2821
|
+
return isHttpsRequest(event)
|
|
2822
|
+
? { sameSite: "none", secure: true }
|
|
2823
|
+
: { sameSite: "lax", secure: false };
|
|
2824
|
+
}
|
|
2813
2825
|
function setFirstRunOnboardingCookie(event) {
|
|
2814
2826
|
setCookie(event, FIRST_RUN_ONBOARDING_COOKIE, "1", {
|
|
2815
2827
|
...crossSiteCookieAttrs(event),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.0.0-beta-
|
|
3
|
+
"version": "0.0.0-beta-20260819215811",
|
|
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": {
|