@agent-native/core 0.164.12 → 0.164.15

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 (43) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/content/actions/_database-source-utils.ts +25 -2
  3. package/corpus/templates/content/actions/_database-utils.ts +2 -0
  4. package/corpus/templates/content/actions/_local-folder-source.ts +186 -2
  5. package/corpus/templates/content/actions/connect-local-folder-source.ts +23 -8
  6. package/corpus/templates/content/actions/disconnect-local-folder-source.ts +3 -3
  7. package/corpus/templates/content/actions/resolve-local-folder-conflict.ts +2 -2
  8. package/corpus/templates/content/actions/sync-local-folder-source.ts +130 -12
  9. package/corpus/templates/content/app/components/LocalFolderLiveSync.tsx +77 -0
  10. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +354 -8
  11. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +23 -1
  12. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +78 -1
  13. package/corpus/templates/content/app/components/editor/database/sidebar.tsx +36 -0
  14. package/corpus/templates/content/app/components/editor/local-source-write-state.ts +52 -0
  15. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +244 -6
  16. package/corpus/templates/content/app/components/sidebar/local-source-hierarchy.ts +189 -0
  17. package/corpus/templates/content/app/hooks/use-create-page.ts +26 -4
  18. package/corpus/templates/content/app/hooks/use-documents.ts +83 -0
  19. package/corpus/templates/content/app/i18n-data.ts +79 -0
  20. package/corpus/templates/content/app/lib/desktop-content-files.ts +57 -1
  21. package/corpus/templates/content/app/lib/local-content-source-files.ts +210 -34
  22. package/corpus/templates/content/app/lib/local-folder-live-sync.ts +191 -0
  23. package/corpus/templates/content/app/root.tsx +2 -1
  24. package/corpus/templates/content/app/routes/_app.local-files.tsx +103 -38
  25. package/corpus/templates/content/docs/product/capabilities/content.source.file-folder.md +2 -2
  26. package/corpus/templates/content/docs/product/features/content.feature.bring-your-local-work.md +3 -3
  27. package/corpus/templates/content/docs/product/roadmap.md +2 -2
  28. package/corpus/templates/content/docs/solutions/2026-08-18-content-navigation-coherence-shape.md +482 -0
  29. package/corpus/templates/content/shared/api.ts +25 -0
  30. package/dist/app-config/auth.d.ts +4 -0
  31. package/dist/app-config/auth.js +7 -0
  32. package/dist/app-config/schema.d.ts +3 -0
  33. package/dist/app-config/schema.js +2 -0
  34. package/dist/cli/code-agent-executor.js +6 -1
  35. package/dist/cli/code-agent-mcp-config.d.ts +2 -2
  36. package/dist/cli/code-agent-mcp-config.js +34 -9
  37. package/dist/client/org/OrgSwitcher.js +8 -4
  38. package/dist/collab/routes.d.ts +1 -1
  39. package/dist/mcp-client/config.d.ts +11 -0
  40. package/dist/mcp-client/config.js +33 -26
  41. package/dist/resources/handlers.d.ts +2 -2
  42. package/dist/server/auth.js +15 -1
  43. package/package.json +1 -1
@@ -45,6 +45,12 @@ import {
45
45
  syncLocalControlResources,
46
46
  type LocalControlResourceFiles,
47
47
  } from "@/lib/local-control-resources";
48
+ import {
49
+ connectTemporaryLocalFolder,
50
+ rememberLiveLocalFolderSource,
51
+ requestLiveLocalFolderActivation,
52
+ syncLiveLocalFolder,
53
+ } from "@/lib/local-folder-live-sync";
48
54
  import {
49
55
  hasInterruptedNativeFolderPickerAttempt,
50
56
  runNativeFolderPickerWithCrashSentinel,
@@ -149,18 +155,6 @@ interface ManifestFolderSyncResult extends ImportContentSourceResult {
149
155
  requestedDocumentId: string | null;
150
156
  }
151
157
 
152
- interface RegisterLocalComponentWorkspaceResult {
153
- ok: true;
154
- workspace: {
155
- id: string;
156
- workspacePath: string;
157
- componentPaths: string[];
158
- };
159
- componentDirs: string[];
160
- componentCount: number;
161
- reloadRequired: boolean;
162
- }
163
-
164
158
  interface RemoveLocalFileSourceResult {
165
159
  success: boolean;
166
160
  deleted: number;
@@ -269,7 +263,7 @@ function desktopDirectoryFromFolder(
269
263
  folder: DesktopContentFilesFolder,
270
264
  directories: SelectedDirectory[] = [],
271
265
  ): SelectedDirectory {
272
- const id = folder.id ?? opaqueDesktopDirectoryId(folder.path ?? folder.name);
266
+ const id = folder.id ?? opaqueDesktopDirectoryId(folder.name);
273
267
  return {
274
268
  id,
275
269
  kind: "desktop",
@@ -755,6 +749,7 @@ export default function LocalFilesRoute() {
755
749
  const targetDatabaseId = searchParams.get("databaseId") || undefined;
756
750
  const manifestConnectionId = searchParams.get("connectionId") || undefined;
757
751
  const manifestFile = searchParams.get("file") || undefined;
752
+ const workingCopyId = searchParams.get("workingCopyId") || undefined;
758
753
  const workspacePropertyValues = (
759
754
  location.state as {
760
755
  workspacePropertyValues?: Record<string, unknown>;
@@ -767,6 +762,7 @@ export default function LocalFilesRoute() {
767
762
  const [restoringDirectory, setRestoringDirectory] = useState(false);
768
763
  const supported = useMemo(supportsLocalFolderSync, []);
769
764
  const manifestBootstrapRef = useRef<string | null>(null);
765
+ const workingCopyBootstrapRef = useRef<string | null>(null);
770
766
  const documentSourceDirectories = useMemo(
771
767
  () =>
772
768
  directories.length === 0
@@ -850,6 +846,59 @@ export default function LocalFilesRoute() {
850
846
  targetSpaceId,
851
847
  ]);
852
848
 
849
+ useEffect(() => {
850
+ if (!workingCopyId) return;
851
+ if (workingCopyBootstrapRef.current === workingCopyId) return;
852
+ workingCopyBootstrapRef.current = workingCopyId;
853
+ const desktopFiles = getDesktopContentFiles();
854
+ if (!desktopFiles) return;
855
+ setBusy("choose");
856
+ void desktopFiles
857
+ .getFolder({ folderId: workingCopyId })
858
+ .then(async (folderResult) => {
859
+ if (!folderResult.ok || folderResult.folder.kind !== "temporary") {
860
+ throw new Error(
861
+ folderResult.ok
862
+ ? t("localFiles.chooseAnotherFolder")
863
+ : folderResult.error,
864
+ );
865
+ }
866
+ const sourceId = await connectTemporaryLocalFolder(folderResult.folder);
867
+ if (!sourceId) throw new Error(t("localFiles.chooseAnotherFolder"));
868
+ const outcome = await syncLiveLocalFolder(workingCopyId);
869
+ if (!outcome.synced) {
870
+ throw new Error(t("localFiles.chooseAnotherFolder"));
871
+ }
872
+ const result = outcome.result as ImportContentSourceResult;
873
+ const firstDocument = [
874
+ ...result.created,
875
+ ...result.updated,
876
+ ...result.unchanged,
877
+ ][0];
878
+ if (!firstDocument)
879
+ throw new Error(t("localFiles.chooseAnotherFolder"));
880
+ requestLiveLocalFolderActivation(workingCopyId);
881
+ await Promise.all([
882
+ queryClient.invalidateQueries({
883
+ queryKey: ["action", "list-documents"],
884
+ }),
885
+ queryClient.invalidateQueries({
886
+ queryKey: ["action", "get-content-database"],
887
+ }),
888
+ ]);
889
+ navigate(`/page/${firstDocument.id}`, { replace: true });
890
+ })
891
+ .catch((err) => {
892
+ workingCopyBootstrapRef.current = null;
893
+ setStatus({
894
+ kind: "error",
895
+ title: t("localFiles.pullFailed"),
896
+ detail: err instanceof Error ? err.message : t("localFiles.tryAgain"),
897
+ });
898
+ })
899
+ .finally(() => setBusy(null));
900
+ }, [navigate, queryClient, t, workingCopyId]);
901
+
853
902
  useEffect(() => {
854
903
  if (!supported) return;
855
904
  let cancelled = false;
@@ -937,6 +986,24 @@ export default function LocalFilesRoute() {
937
986
  createSourceBackedSpace: !targetSpaceId && !targetDatabaseId,
938
987
  propertyValues: workspacePropertyValues,
939
988
  truthPolicy: "source_primary",
989
+ connectionMetadata:
990
+ directory.kind === "desktop"
991
+ ? {
992
+ liveBridgeEnabled: true,
993
+ repository: directory.folder.repository
994
+ ? { localId: directory.folder.repository.localId }
995
+ : undefined,
996
+ workingCopy: {
997
+ id: directory.id,
998
+ repositoryId: directory.folder.repository?.localId,
999
+ kind: directory.folder.kind ?? "persistent",
1000
+ name: directory.folder.name,
1001
+ branch: directory.folder.repository?.branch,
1002
+ commit: directory.folder.repository?.commit,
1003
+ deviceId: "agent-native-desktop",
1004
+ },
1005
+ }
1006
+ : undefined,
940
1007
  dryRun,
941
1008
  } as never,
942
1009
  );
@@ -1012,6 +1079,16 @@ export default function LocalFilesRoute() {
1012
1079
  if (!connection.sourceId) {
1013
1080
  throw new Error("The local folder connection was not created");
1014
1081
  }
1082
+ if (!dryRun && refreshedDirectory.kind === "desktop") {
1083
+ await rememberLiveLocalFolderSource(
1084
+ refreshedDirectory.folder,
1085
+ connection.sourceId,
1086
+ connection.filesDatabaseId,
1087
+ );
1088
+ await getDesktopContentFiles()?.subscribeChanges?.({
1089
+ folderId: refreshedDirectory.id,
1090
+ });
1091
+ }
1015
1092
  const result = await callAction<ImportContentSourceResult>(
1016
1093
  "sync-local-folder-source" as never,
1017
1094
  {
@@ -1038,29 +1115,6 @@ export default function LocalFilesRoute() {
1038
1115
  ) {
1039
1116
  for (const directory of selectedDirectories) {
1040
1117
  if (directory.kind === "desktop") {
1041
- const workspacePath = directory.folder.path;
1042
- if (!workspacePath) continue;
1043
- try {
1044
- const result =
1045
- await callAction<RegisterLocalComponentWorkspaceResult>(
1046
- "register-local-component-workspace" as never,
1047
- { workspacePath } as never,
1048
- );
1049
- if (result.componentCount > 0 && showToast) {
1050
- toast.success(t("localFiles.localComponentsConnected"), {
1051
- description: t("localFiles.localComponentsConnectedDescription"),
1052
- });
1053
- }
1054
- } catch (error) {
1055
- if (showToast) {
1056
- toast.info(t("localFiles.localFilesLinked"), {
1057
- description:
1058
- error instanceof Error
1059
- ? error.message
1060
- : t("localFiles.componentPreviewsNeedBridge"),
1061
- });
1062
- }
1063
- }
1064
1118
  continue;
1065
1119
  }
1066
1120
 
@@ -1139,9 +1193,21 @@ export default function LocalFilesRoute() {
1139
1193
  if (!desktopFiles) {
1140
1194
  throw new Error(t("localFiles.desktopFolderUnavailable"));
1141
1195
  }
1196
+ const observed = await desktopFiles.readFiles({
1197
+ folderId: directory.id,
1198
+ });
1199
+ if (!observed.ok) throw new Error(observed.error);
1200
+ const expectedRevisions: Record<string, string | null> = {
1201
+ ...(observed.revisions ?? {}),
1202
+ };
1203
+ for (const filePath of Object.keys(files)) {
1204
+ if (!(filePath in expectedRevisions))
1205
+ expectedRevisions[filePath] = null;
1206
+ }
1142
1207
  const result = await desktopFiles.writeFiles({
1143
1208
  folderId: directory.id,
1144
1209
  files,
1210
+ expectedRevisions,
1145
1211
  });
1146
1212
  if (!result.ok) throw new Error(result.error);
1147
1213
  setDirectories((current) =>
@@ -1478,8 +1544,7 @@ export default function LocalFilesRoute() {
1478
1544
  ? (directory.sourceRootPath ??
1479
1545
  t("localFiles.importedSource"))
1480
1546
  : directory.kind === "desktop"
1481
- ? (directory.folder.path ??
1482
- t("localFiles.desktopFolder"))
1547
+ ? t("localFiles.desktopFolder")
1483
1548
  : t("localFiles.browserFolder")}
1484
1549
  </div>
1485
1550
  </div>
@@ -22,7 +22,7 @@ proof_requirements:
22
22
  ]
23
23
  evidence: []
24
24
  superseded_by: null
25
- last_reviewed: "2026-07-29"
25
+ last_reviewed: "2026-08-17"
26
26
  ---
27
27
 
28
28
  # Files and folders as Sources
@@ -58,7 +58,7 @@ Given a browser without bridge authority, when it opens a materialized folder it
58
58
 
59
59
  ## Current evidence
60
60
 
61
- Donor evidence: `actions/connect-local-folder-source.ts`, `actions/sync-local-folder-source.ts`, `actions/local-folder-source.db.test.ts`, and sidebar source handling establish local-folder substrate. The common heterogeneous folder contract and complete authority/recovery proof remain exploratory.
61
+ Current implementation adds opaque Desktop grants, recursive Markdown materialization, watched reconciliation with a bounded fallback, atomic revision-guarded writes, and local working-copy identity. Focused tests cover the substrate, but packaged real-interface authority, recovery, redaction, and cleanup proof is still pending, and heterogeneous file families remain exploratory. This Capability therefore remains `exploring`.
62
62
 
63
63
  ## Proof plan
64
64
 
@@ -8,8 +8,8 @@ order: 12
8
8
  roadmap_status: "partially_implemented"
9
9
  summary: "Open a folder or repository through the same Source model while keeping device authority and browser limitations honest."
10
10
  example_workflow: "A developer opens a local documentation folder in Content Desktop, edits the files through Content, sees external file changes synchronize back, and later reads the last synchronized representation from Safari without exposing the folder path."
11
- works_today: "Local File Mode, manifest-declared workspaces, connected-folder Sources, source-backed Pages, conflict records, and a trusted local bridge already establish substantial foundations."
12
- remains: "Opening a folder must become effortless, Desktop needs dependable background sync and caching, browser clients need graceful read and queued-write behavior, and the portable vault workflow needs full product polish."
11
+ works_today: "Local File Mode, connected-folder Sources, source-backed Pages, Desktop folder grants, watched reconciliation, revision-guarded writes, and named local working-copy identity establish the first end-to-end local Markdown path behind its release flag."
12
+ remains: "The packaged Desktop story still needs independent H1-H10 acceptance before release; broader file families, queued remote writes, and provider-bound GitHub review remain later increments."
13
13
  required_capabilities:
14
14
  [
15
15
  "content.source.local-bridge",
@@ -22,7 +22,7 @@ enhancing_capabilities:
22
22
  increments: []
23
23
  feature_proof: null
24
24
  publicness: "public"
25
- last_reviewed: "2026-07-29"
25
+ last_reviewed: "2026-08-17"
26
26
  ---
27
27
 
28
28
  # Feature 12: Bring your local work
@@ -336,9 +336,9 @@ Open a folder or repository through the same Source model while keeping device a
336
336
 
337
337
  **Example workflow:** A developer opens a local documentation folder in Content Desktop, edits the files through Content, sees external file changes synchronize back, and later reads the last synchronized representation from Safari without exposing the folder path.
338
338
 
339
- **What works today:** Local File Mode, manifest-declared workspaces, connected-folder Sources, source-backed Pages, conflict records, and a trusted local bridge already establish substantial foundations.
339
+ **What works today:** Local File Mode, connected-folder Sources, source-backed Pages, Desktop folder grants, watched reconciliation, revision-guarded writes, and named local working-copy identity establish the first end-to-end local Markdown path behind its release flag.
340
340
 
341
- **What remains:** Opening a folder must become effortless, Desktop needs dependable background sync and caching, browser clients need graceful read and queued-write behavior, and the portable vault workflow needs full product polish.
341
+ **What remains:** The packaged Desktop story still needs independent H1-H10 acceptance before release; broader file families, queued remote writes, and provider-bound GitHub review remain later increments.
342
342
 
343
343
  **What this Feature includes:**
344
344