@agent-native/core-corpus 0.212.1 → 0.213.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/onboarding-journeys/SKILL.md +29 -14
  3. package/corpus/templates/analytics/CHANGELOG.md +11 -0
  4. package/corpus/templates/analytics/actions/estimate-onboarding-journey-cost.ts +23 -6
  5. package/corpus/templates/analytics/actions/get-onboarding-journey.ts +20 -5
  6. package/corpus/templates/analytics/actions/provider-api-register.ts +2 -7
  7. package/corpus/templates/analytics/changelog/2026-10-21-analytics-recognizes-questions-about-connected-data-product-.md +6 -0
  8. package/corpus/templates/analytics/changelog/2026-10-21-onboarding-journeys-now-honor-larger-event-row-budgets.md +6 -0
  9. package/corpus/templates/analytics/changelog/2026-10-21-preserve-unknown-replay-availability-in-partial-journeys.md +6 -0
  10. package/corpus/templates/analytics/package.json +6 -0
  11. package/corpus/templates/analytics/scripts/journey-capture-plan.ts +18 -7
  12. package/corpus/templates/analytics/scripts/journey-capture.ts +3 -1
  13. package/corpus/templates/analytics/server/lib/db-admin-connections.ts +19 -12
  14. package/corpus/templates/analytics/server/lib/journey-tree.ts +24 -9
  15. package/corpus/templates/analytics/server/lib/onboarding-journey-cost.ts +163 -94
  16. package/corpus/templates/analytics/server/lib/onboarding-journey.ts +162 -74
  17. package/corpus/templates/assets/server/lib/org-admin.ts +20 -16
  18. package/corpus/templates/brain/server/lib/zoom-governance.ts +11 -6
  19. package/corpus/templates/clips/CHANGELOG.md +1 -0
  20. package/corpus/templates/clips/changelog/2026-10-16-rewind-status-says-when-it-remembers-audio.md +6 -0
  21. package/corpus/templates/clips/desktop/src/app.tsx +7 -4
  22. package/corpus/templates/clips/desktop/src/components/RewindCaptureStatus.tsx +25 -0
  23. package/corpus/templates/clips/desktop/src/lib/rewind-status.ts +6 -1
  24. package/corpus/templates/clips/desktop/src/shared/config.ts +3 -0
  25. package/corpus/templates/clips/desktop/src-tauri/src/screen_memory.rs +2 -0
  26. package/corpus/templates/clips/server/lib/recordings.ts +4 -19
  27. package/corpus/templates/community/qr/package.json +1 -1
  28. package/corpus/templates/content/CHANGELOG.md +8 -0
  29. package/corpus/templates/content/actions/_content-space-access.ts +95 -6
  30. package/corpus/templates/content/actions/_database-utils.ts +20 -16
  31. package/corpus/templates/content/actions/_github-source-freshness.ts +72 -17
  32. package/corpus/templates/content/actions/_github-source-metadata.ts +63 -17
  33. package/corpus/templates/content/actions/_github-source.ts +141 -77
  34. package/corpus/templates/content/actions/check-github-connection.ts +15 -0
  35. package/corpus/templates/content/actions/create-github-collection.ts +180 -0
  36. package/corpus/templates/content/actions/disconnect-content-database-source.ts +5 -0
  37. package/corpus/templates/content/actions/link-github-folder.ts +104 -36
  38. package/corpus/templates/content/actions/refresh-content-database-source.ts +37 -4
  39. package/corpus/templates/content/actions/sync-github-folder.ts +23 -5
  40. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +172 -19
  41. package/corpus/templates/content/app/components/editor/database/GitHubLinkDialog.tsx +938 -0
  42. package/corpus/templates/content/app/components/editor/database/GitHubSourcePanel.tsx +228 -0
  43. package/corpus/templates/content/app/components/editor/database/GitHubSourceStatusLine.tsx +561 -0
  44. package/corpus/templates/content/app/components/editor/database/GitHubUnlinkDialog.tsx +96 -0
  45. package/corpus/templates/content/app/components/editor/database/github-availability.ts +147 -0
  46. package/corpus/templates/content/app/components/editor/database/github-source-text.ts +280 -0
  47. package/corpus/templates/content/app/components/layout/Layout.tsx +2 -0
  48. package/corpus/templates/content/app/hooks/content-action-refresh.ts +6 -0
  49. package/corpus/templates/content/app/hooks/use-content-database.ts +3 -1
  50. package/corpus/templates/content/app/hooks/use-github-folder.ts +199 -0
  51. package/corpus/templates/content/app/i18n-data.ts +154 -1
  52. package/corpus/templates/content/app/lib/github-link-dialog.ts +86 -0
  53. package/corpus/templates/content/changelog/2026-10-18-connected-ai-assistants-can-link-a-new-collection-to-a-github.md +1 -1
  54. package/corpus/templates/content/changelog/2026-10-18-link-a-new-collection-to-a-github-folder-from-its-sources.md +6 -0
  55. package/corpus/templates/content/changelog/2026-10-21-organization-favorites-include-documents-shared-with-the-cur.md +6 -0
  56. package/corpus/templates/content/docs/product/capabilities/content.source.sync-policy.md +32 -7
  57. package/corpus/templates/content/docs/product/encyclopedia.md +3 -3
  58. package/corpus/templates/content/docs/product/features/content.feature.trust-your-connected-sources.md +2 -2
  59. package/corpus/templates/content/docs/product/roadmap.md +1 -1
  60. package/corpus/templates/content/parity/matrix.md +42 -42
  61. package/corpus/templates/content/parity/matrix.ts +14 -0
  62. package/corpus/templates/content/server/lib/github-source-client.ts +50 -1
  63. package/corpus/templates/content/shared/api.ts +3 -0
  64. package/corpus/templates/content/shared/github-source.ts +68 -0
  65. package/corpus/templates/design/CHANGELOG.md +1 -0
  66. package/corpus/templates/design/actions/connect-assets-mcp.ts +5 -9
  67. package/corpus/templates/design/changelog/2026-10-21-journey-canvases-accept-partial-analytics-samples-when-repla.md +6 -0
  68. package/corpus/templates/design/shared/journey-canvas.ts +6 -4
  69. package/corpus/templates/dispatch/.agents/skills/a2a-protocol/SKILL.md +16 -13
  70. package/corpus/templates/dispatch/CHANGELOG.md +4 -0
  71. package/corpus/templates/dispatch/changelog/2026-10-21-customer-ai-credit-questions-route-to-account-health-instead.md +6 -0
  72. package/corpus/templates/factory/server/lib/require-workspace-member.ts +5 -17
  73. package/corpus/templates/mail/server/lib/queued-drafts.ts +9 -4
  74. package/corpus/templates/slides/server/workspace-defaults.ts +12 -15
  75. package/package.json +1 -1
@@ -7,6 +7,7 @@ import { z } from "zod";
7
7
 
8
8
  import { getDb, schema } from "../server/db/index.js";
9
9
  import { documentChangeResource } from "../server/lib/document-change-resource.js";
10
+ import type { GitHubLinkBlockedReason } from "../shared/github-source.js";
10
11
  import {
11
12
  getContentDatabaseSourceSnapshot,
12
13
  resolveDatabaseForSourceMutation,
@@ -18,6 +19,8 @@ import {
18
19
  previewGitHubFolder,
19
20
  resolveGitHubFolder,
20
21
  syncGitHubSource,
22
+ unexpectedSyncFailure,
23
+ type GitHubSyncResult,
21
24
  } from "./_github-source.js";
22
25
  import { serializeDatabase } from "./_property-utils.js";
23
26
 
@@ -62,15 +65,10 @@ const linkGitHubFolderSchema = z
62
65
  "Provide exactly one databaseId or documentId",
63
66
  );
64
67
 
65
- type LinkBlocked =
66
- | "collection-has-rows"
67
- | "already-linked"
68
- | "system-collection";
69
-
70
68
  async function linkBlockedReason(
71
69
  database: { id: string; systemRole: string | null },
72
70
  db: ReturnType<typeof getDb> = getDb(),
73
- ): Promise<LinkBlocked | null> {
71
+ ): Promise<GitHubLinkBlockedReason | null> {
74
72
  if (database.systemRole) return "system-collection";
75
73
  const [source] = await db
76
74
  .select({ id: schema.contentDatabaseSources.id })
@@ -95,14 +93,14 @@ async function linkBlockedReason(
95
93
  return row ? "collection-has-rows" : null;
96
94
  }
97
95
 
98
- const BLOCKED_MESSAGES: Record<LinkBlocked, string> = {
96
+ const BLOCKED_MESSAGES: Record<GitHubLinkBlockedReason, string> = {
99
97
  "collection-has-rows":
100
98
  "This collection already has rows. Link a GitHub folder from a new, empty collection.",
101
99
  "already-linked": "This collection is already linked to a source.",
102
100
  "system-collection": "This collection can't be linked to a GitHub folder.",
103
101
  };
104
102
 
105
- function blockedError(blocked: LinkBlocked) {
103
+ function blockedError(blocked: GitHubLinkBlockedReason) {
106
104
  return new ActionContractError(BLOCKED_MESSAGES[blocked], {
107
105
  errorCode:
108
106
  blocked === "collection-has-rows"
@@ -114,6 +112,96 @@ function blockedError(blocked: LinkBlocked) {
114
112
  });
115
113
  }
116
114
 
115
+ /**
116
+ * Links a collection to a folder already read and previewed, then brings in
117
+ * the first files. The link is saved before the sync, so a sync that fails is
118
+ * reported on the link rather than thrown.
119
+ */
120
+ export async function linkPreviewedGitHubFolder({
121
+ database,
122
+ resolved,
123
+ preview,
124
+ connectionId,
125
+ userEmail,
126
+ }: {
127
+ database: Parameters<typeof createGitHubSourceLink>[0]["database"];
128
+ resolved: Awaited<ReturnType<typeof resolveGitHubFolder>>;
129
+ preview: Awaited<ReturnType<typeof previewGitHubFolder>>;
130
+ connectionId: string | null;
131
+ userEmail: string;
132
+ }) {
133
+ const sourceId = await createGitHubSourceLink({
134
+ database,
135
+ resolved,
136
+ preview,
137
+ connectionId,
138
+ userEmail,
139
+ // Reading GitHub takes seconds, so someone may have added a row since
140
+ // the check above; this runs again under the collection's lock.
141
+ assertLinkable: async (tx) => {
142
+ const blockedNow = await linkBlockedReason(database, tx);
143
+ if (blockedNow) throw blockedError(blockedNow);
144
+ },
145
+ });
146
+ return bringInGitHubLink({ database, preview, sourceId });
147
+ }
148
+
149
+ /**
150
+ * Brings in a saved link's first files, or the rest of them on a retry, and
151
+ * says how far it got.
152
+ */
153
+ export async function bringInGitHubLink({
154
+ database,
155
+ preview,
156
+ sourceId,
157
+ }: {
158
+ database: Parameters<typeof createGitHubSourceLink>[0]["database"];
159
+ preview: Awaited<ReturnType<typeof previewGitHubFolder>>;
160
+ sourceId: string;
161
+ }) {
162
+ // The link is saved by now, so anything that fails from here is reported
163
+ // on it rather than thrown, which would leave the caller thinking it failed.
164
+ // A contract error is the exception: the link or its collection went away
165
+ // during the sync, so there's nothing left to report on.
166
+ let sync: GitHubSyncResult;
167
+ try {
168
+ sync = await syncGitHubSource({
169
+ sourceId,
170
+ budgetMs: FIRST_SYNC_BUDGET_MS,
171
+ });
172
+ } catch (error) {
173
+ if (error instanceof ActionContractError) throw error;
174
+ console.warn(
175
+ "[github-source] first sync failed:",
176
+ error instanceof Error ? error.message : String(error),
177
+ );
178
+ sync = unexpectedSyncFailure(new Date().toISOString());
179
+ }
180
+ await writeAppState("refresh-signal", { ts: Date.now() }).catch(
181
+ (error: unknown) => {
182
+ // The change event below still reaches open pages.
183
+ console.warn(
184
+ "[github-source] refresh signal failed:",
185
+ error instanceof Error ? error.message : String(error),
186
+ );
187
+ },
188
+ );
189
+ // coercion-ok: the status line reads the link on its own; this is a courtesy copy.
190
+ const source = await getContentDatabaseSourceSnapshot(database).catch(
191
+ () => null,
192
+ );
193
+ return {
194
+ sync,
195
+ source,
196
+ summary:
197
+ sync.state === "partial"
198
+ ? `Linked ${preview.label}. ${sync.created} of ${preview.markdownFiles} rows are in; the rest follow within about a minute.`
199
+ : sync.state === "error"
200
+ ? `Linked ${preview.label}, but the first sync failed: ${sync.problem?.message ?? "GitHub sync failed."}`
201
+ : `Linked ${preview.label}: ${sync.created} rows from commit ${sync.commitSha?.slice(0, 7) ?? "unknown"}.${sync.problem ? ` ${sync.problem.message}` : ""}`,
202
+ };
203
+ }
204
+
117
205
  export default defineAction({
118
206
  description:
119
207
  "Link an empty content collection to a GitHub folder, view only: each Markdown file becomes a row, frontmatter becomes read-only columns, and pushes to the branch arrive on their own. Run with dryRun first to see the file count, skipped files with reasons, and the columns and types the frontmatter becomes.",
@@ -163,44 +251,24 @@ export default defineAction({
163
251
  preview,
164
252
  canLink: blocked === null,
165
253
  blocked: blocked ? BLOCKED_MESSAGES[blocked] : null,
254
+ blockedReason: blocked,
166
255
  summary: blocked
167
256
  ? BLOCKED_MESSAGES[blocked]
168
257
  : `${githubPreviewSummary(preview)} Run again without dryRun to link it.`,
169
258
  };
170
259
  }
171
260
 
172
- const sourceId = await createGitHubSourceLink({
173
- database,
174
- resolved,
175
- preview,
176
- connectionId,
177
- userEmail,
178
- // Reading GitHub takes seconds, so someone may have added a row since
179
- // the check above; this runs again under the collection's lock.
180
- assertLinkable: async (tx) => {
181
- const blockedNow = await linkBlockedReason(database, tx);
182
- if (blockedNow) throw blockedError(blockedNow);
183
- },
184
- });
185
- const sync = await syncGitHubSource({
186
- sourceId,
187
- budgetMs: FIRST_SYNC_BUDGET_MS,
188
- throwConnectionErrors: true,
189
- });
190
- await writeAppState("refresh-signal", { ts: Date.now() });
191
- const source = await getContentDatabaseSourceSnapshot(database);
192
261
  return {
193
262
  dryRun: false,
194
263
  database: serializeDatabase(database),
195
264
  preview,
196
- sync,
197
- source,
198
- summary:
199
- sync.state === "partial"
200
- ? `Linked ${preview.label}. ${sync.created} of ${preview.markdownFiles} rows are in; sync again to load the rest.`
201
- : sync.state === "error"
202
- ? `Linked ${preview.label}, but the first sync failed: ${sync.problem?.message ?? "GitHub sync failed."}`
203
- : `Linked ${preview.label}: ${sync.created} rows from commit ${sync.commitSha?.slice(0, 7) ?? "unknown"}.${sync.problem ? ` ${sync.problem.message}` : ""}`,
265
+ ...(await linkPreviewedGitHubFolder({
266
+ database,
267
+ resolved,
268
+ preview,
269
+ connectionId,
270
+ userEmail,
271
+ })),
204
272
  };
205
273
  },
206
274
  // Everyone reading the collection gets its new rows, not just the caller.
@@ -1,4 +1,5 @@
1
1
  import { defineAction } from "@agent-native/core/action";
2
+ import { getRequestUserEmail } from "@agent-native/core/server/request-context";
2
3
  import { assertAccess } from "@agent-native/core/sharing";
3
4
  import { z } from "zod";
4
5
 
@@ -18,7 +19,11 @@ import {
18
19
  storeSecondarySourceRows,
19
20
  updateReadOnlySourceMetadata,
20
21
  } from "./_database-source-utils.js";
21
- import { githubSyncChangedRows } from "./_github-source-freshness.js";
22
+ import {
23
+ announceGitHubSyncChange,
24
+ githubSyncChangedRows,
25
+ readGitHubStatusShown,
26
+ } from "./_github-source-freshness.js";
22
27
  import { githubSyncSummary, syncGitHubSource } from "./_github-source.js";
23
28
  import { serializeDatabase } from "./_property-utils.js";
24
29
 
@@ -80,13 +85,41 @@ export default defineAction({
80
85
  let githubSummary: string | null = null;
81
86
  let githubChanged = false;
82
87
  if (source.sourceType === "github") {
88
+ const shownBefore = await readGitHubStatusShown(source.id);
83
89
  const result = await syncGitHubSource({
84
90
  sourceId: source.id,
85
91
  budgetMs: args.fullRefresh === true ? 25_000 : 6_000,
86
92
  throwConnectionErrors: true,
93
+ throwUnexpectedErrors: true,
94
+ }).catch((error: unknown) => {
95
+ // A sync that fails may have written rows first, and it stores the
96
+ // problem on the link, so readers hear about it either way.
97
+ try {
98
+ announceGitHubSyncChange(
99
+ database.documentId,
100
+ getRequestUserEmail() ?? null,
101
+ );
102
+ } catch (announceError) {
103
+ // The caller still gets the sync's error; other tabs catch up on their next read.
104
+ console.warn(
105
+ "[github-source] change event failed:",
106
+ announceError instanceof Error
107
+ ? announceError.message
108
+ : String(announceError),
109
+ );
110
+ }
111
+ throw error;
87
112
  });
88
113
  githubSummary = githubSyncSummary(source.sourceName, result);
89
- githubChanged = githubSyncChangedRows(result);
114
+ // The rows are written by now, so a status that can't be read back
115
+ // counts as changed rather than failing the refresh.
116
+ // coercion-ok: null differs from every reading, so readers look again.
117
+ const shownAfter = await readGitHubStatusShown(source.id).catch(
118
+ () => null,
119
+ );
120
+ githubChanged =
121
+ githubSyncChangedRows(result) ||
122
+ (result.state !== "busy" && shownAfter !== shownBefore);
90
123
  } else if (source.sourceType === "mock-local") {
91
124
  await resyncMockSourceSnapshot({ database, source, now });
92
125
  } else if (source.sourceType === "builder-cms") {
@@ -182,8 +215,8 @@ export default defineAction({
182
215
  ...(source.sourceType === "github" ? { githubChanged } : {}),
183
216
  };
184
217
  },
185
- // A GitHub sync that changed rows changed them for everyone reading the
186
- // collection, as with Sync now.
218
+ // A GitHub sync that changed rows or the status line changed them for
219
+ // everyone reading the collection, as with Sync now.
187
220
  changeResource: (_input, result) =>
188
221
  result.githubChanged
189
222
  ? documentChangeResource(result.database.documentId)
@@ -8,7 +8,10 @@ import {
8
8
  getContentDatabaseSourceSnapshot,
9
9
  resolveDatabaseForSourceMutation,
10
10
  } from "./_database-source-utils.js";
11
- import { githubSyncChangedRows } from "./_github-source-freshness.js";
11
+ import {
12
+ githubSyncChangedRows,
13
+ readGitHubStatusShown,
14
+ } from "./_github-source-freshness.js";
12
15
  import {
13
16
  githubSyncSummary,
14
17
  readLinkedGitHubSource,
@@ -64,12 +67,23 @@ export default defineAction({
64
67
  { errorCode: "NOT_GITHUB_LINKED", statusCode: 409 },
65
68
  );
66
69
  }
70
+ const shownBefore = await readGitHubStatusShown(linked.id);
67
71
  const sync = await syncGitHubSource({
68
72
  sourceId: linked.id,
69
73
  budgetMs: SYNC_BUDGET_MS,
70
74
  });
71
75
  const failed: SyncFollowUp[] = [];
72
- if (sync.state !== "unchanged" && sync.state !== "busy") {
76
+ // A busy sync changed nothing; the run already going reports for itself.
77
+ // A status that can't be read back counts as changed, so readers check.
78
+ const statusChanged =
79
+ sync.state !== "busy" &&
80
+ (await afterSync("status_read", failed, () =>
81
+ readGitHubStatusShown(linked.id),
82
+ )) !== shownBefore;
83
+ if (
84
+ statusChanged ||
85
+ (sync.state !== "unchanged" && sync.state !== "busy")
86
+ ) {
73
87
  await afterSync("refresh_signal", failed, () =>
74
88
  writeAppState("refresh-signal", { ts: Date.now() }),
75
89
  );
@@ -80,6 +94,7 @@ export default defineAction({
80
94
  return {
81
95
  database: serializeDatabase(database),
82
96
  sync,
97
+ statusChanged,
83
98
  source,
84
99
  followUpFailed: failed,
85
100
  summary: [
@@ -88,16 +103,19 @@ export default defineAction({
88
103
  ].join(" "),
89
104
  };
90
105
  },
91
- // Everyone reading the collection gets the synced rows, not just the caller.
106
+ // Everyone reading the collection gets the synced rows and status, not just
107
+ // the caller.
92
108
  changeResource: (_input, result) =>
93
- githubSyncChangedRows(result.sync)
109
+ githubSyncChangedRows(result.sync) || result.statusChanged
94
110
  ? documentChangeResource(result.database.documentId)
95
111
  : null,
96
112
  });
97
113
 
98
- type SyncFollowUp = "refresh_signal" | "source_read";
114
+ type SyncFollowUp = "status_read" | "refresh_signal" | "source_read";
99
115
 
100
116
  const FOLLOW_UP_FAILED: Record<SyncFollowUp, string> = {
117
+ status_read:
118
+ "Whether the link's status changed couldn't be read, so readers were told to check it again.",
101
119
  refresh_signal:
102
120
  "Other open tabs couldn't be told about the changes; they show them once they reload.",
103
121
  source_read: