@agent-native/core-corpus 0.216.0 → 0.217.0
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/analytics/.agents/skills/session-replay/SKILL.md +61 -1
- package/corpus/templates/analytics/AGENTS.md +1 -1
- package/corpus/templates/analytics/CHANGELOG.md +1 -0
- package/corpus/templates/analytics/actions/get-session-replay-summary.ts +9 -65
- package/corpus/templates/analytics/actions/list-event-catalog.ts +1 -1
- package/corpus/templates/analytics/actions/list-session-outputs.ts +40 -0
- package/corpus/templates/analytics/actions/list-session-recordings.ts +17 -4
- package/corpus/templates/analytics/actions/view-screen.ts +29 -3
- package/corpus/templates/analytics/app/i18n/en-US.ts +27 -0
- package/corpus/templates/analytics/app/pages/sessions/EventCatalogPage.tsx +18 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +3 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionOutputs.tsx +197 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionsTriagePage.tsx +114 -4
- package/corpus/templates/analytics/changelog/2026-10-15-sessions-can-find-people-who-made-a-slides-deck-but-didn-t-p.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-16-the-activation-funnel-counts-visitors-who-decline-analytics-.md +6 -0
- package/corpus/templates/analytics/server/db/schema.ts +67 -0
- package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +9 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +28 -22
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +36 -1
- package/corpus/templates/analytics/server/lib/output-outcomes.ts +712 -0
- package/corpus/templates/analytics/server/lib/replay-origins.ts +33 -0
- package/corpus/templates/analytics/server/lib/session-event-index.ts +20 -0
- package/corpus/templates/analytics/server/lib/session-performance.ts +6 -40
- package/corpus/templates/analytics/server/lib/session-recording-associations.ts +30 -1
- package/corpus/templates/analytics/server/lib/session-replay-triage.ts +99 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +45 -31
- package/corpus/templates/analytics/server/lib/sessions-triage-lab.ts +8 -2
- package/corpus/templates/analytics/server/plugins/db.ts +46 -0
- package/corpus/templates/analytics/shared/output-use.ts +205 -0
- package/corpus/templates/analytics/shared/session-events.ts +6 -0
- package/corpus/templates/calendar/CHANGELOG.md +6 -0
- package/corpus/templates/calendar/actions/create-event.ts +2 -4
- package/corpus/templates/calendar/actions/update-event.ts +35 -6
- package/corpus/templates/calendar/changelog/2026-10-21-solo-events-avoid-notification-approval.md +6 -0
- package/corpus/templates/community/qr/package.json +1 -1
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +6 -3
- package/corpus/templates/content/CHANGELOG.md +8 -0
- package/corpus/templates/content/actions/_browser-document-save-attempt.ts +23 -1
- package/corpus/templates/content/actions/_builder-cms-blob-custody.ts +467 -0
- package/corpus/templates/content/actions/_builder-cms-execution-lease.ts +17 -0
- package/corpus/templates/content/actions/_builder-cms-intent-lookup.ts +5 -0
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +881 -21
- package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +28 -2
- package/corpus/templates/content/actions/_builder-cms-write-client.ts +109 -11
- package/corpus/templates/content/actions/_builder-docs-client.ts +1 -0
- package/corpus/templates/content/actions/_builder-private-blob.test-fixture.ts +90 -0
- package/corpus/templates/content/actions/_builder-source-execution-guard.ts +48 -0
- package/corpus/templates/content/actions/_content-save-outcomes.ts +5 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +290 -8
- package/corpus/templates/content/actions/_database-utils.ts +93 -7
- package/corpus/templates/content/actions/_database-view-setup.ts +21 -2
- package/corpus/templates/content/actions/_delete-content-space.ts +8 -1
- package/corpus/templates/content/actions/_github-source-freshness.ts +30 -4
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +23 -6
- package/corpus/templates/content/actions/cancel-prepared-builder-source-update.ts +110 -26
- package/corpus/templates/content/actions/change-content-database-source-role.ts +51 -7
- package/corpus/templates/content/actions/delete-document.ts +41 -3
- package/corpus/templates/content/actions/disconnect-content-database-source.ts +68 -2
- package/corpus/templates/content/actions/disconnect-local-folder-source.ts +33 -2
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +900 -140
- package/corpus/templates/content/actions/get-document.ts +2 -0
- package/corpus/templates/content/actions/permanently-delete-document.ts +6 -0
- package/corpus/templates/content/actions/prepare-builder-source-execution.ts +155 -13
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +299 -73
- package/corpus/templates/content/actions/set-live-body-switch.ts +45 -0
- package/corpus/templates/content/actions/update-document.ts +139 -20
- package/corpus/templates/content/actions/validate-builder-source-execution.ts +135 -26
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +23 -0
- package/corpus/templates/content/app/components/editor/database/GitHubSourceStatusLine.tsx +27 -2
- package/corpus/templates/content/app/components/editor/database/ListItemLayout.tsx +32 -8
- package/corpus/templates/content/app/components/editor/database/ListItemRow.tsx +27 -2
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +1 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +40 -2
- package/corpus/templates/content/app/hooks/use-documents.ts +14 -0
- package/corpus/templates/content/app/i18n-data.ts +1 -0
- package/corpus/templates/content/changelog/2026-10-17-builder-content-avoids-retrying-a-write-when-builder-accepte.md +6 -0
- package/corpus/templates/content/changelog/2026-10-18-link-a-new-collection-to-a-github-folder-from-its-sources.md +1 -1
- package/corpus/templates/content/changelog/2026-10-20-builder-content-sync-keeps-read-and-write-status-accurate-wh.md +6 -0
- package/corpus/templates/content/changelog/2026-10-21-list-rows-can-show-each-pages-first-lines.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-a-collection-linked-to-a-big-github-folder-fills-faster-and-p.md +6 -0
- package/corpus/templates/content/docs/product/capabilities/content.source.adapters.md +29 -0
- package/corpus/templates/content/parity/matrix.md +42 -42
- package/corpus/templates/content/parity/matrix.ts +3 -1
- package/corpus/templates/content/server/db/schema.ts +20 -0
- package/corpus/templates/content/server/lib/content-trash-purge.ts +15 -1
- package/corpus/templates/content/server/lib/live-body-writer.ts +138 -26
- package/corpus/templates/content/server/live-copy/binding.ts +31 -0
- package/corpus/templates/content/server/live-copy/bounded-task.d.ts +6 -0
- package/corpus/templates/content/server/live-copy/exec-db.ts +1 -0
- package/corpus/templates/content/server/live-copy/holds.ts +59 -0
- package/corpus/templates/content/server/live-copy/persist.ts +656 -0
- package/corpus/templates/content/server/live-copy/switch.ts +136 -0
- package/corpus/templates/content/server/live-copy/task-names.ts +4 -0
- package/corpus/templates/content/server/live-copy/tasks.ts +183 -0
- package/corpus/templates/content/server/live-copy/write-cause.ts +85 -0
- package/corpus/templates/content/server/live-copy/write.ts +85 -0
- package/corpus/templates/content/server/plugins/builder-private-payload-cleanup.ts +22 -0
- package/corpus/templates/content/server/plugins/collab.ts +3 -0
- package/corpus/templates/content/server/plugins/db.ts +28 -0
- package/corpus/templates/content/shared/api.ts +30 -1
- package/corpus/templates/content/shared/database-item-layout.ts +54 -22
- package/corpus/templates/content/shared/document-intent-merge.ts +16 -9
- package/corpus/templates/content/shared/og-description.ts +258 -36
- package/corpus/templates/design/.agents/skills/design-templates/SKILL.md +5 -1
- package/corpus/templates/design/.generated/bridge/shader-runtime.generated.ts +25 -4
- package/corpus/templates/design/CHANGELOG.md +2 -0
- package/corpus/templates/design/actions/get-getting-started.ts +53 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +10 -0
- package/corpus/templates/design/app/components/design/bridge/native-shader-runtime.bridge.ts +132 -79
- package/corpus/templates/design/app/components/design/bridge/native-source-provider.ts +268 -130
- package/corpus/templates/design/app/components/design/bridge/native-worker-scene-host.ts +122 -42
- package/corpus/templates/design/app/components/design/bridge/shader-runtime.bridge.ts +41 -4
- package/corpus/templates/design/app/components/design/design-canvas/text-content-change-result.ts +46 -12
- package/corpus/templates/design/app/components/home/DesignHomeLibrary.tsx +15 -8
- package/corpus/templates/design/app/components/layout/GettingStarted.tsx +50 -0
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +3 -0
- package/corpus/templates/design/app/components/templates/DesignTemplateGrid.tsx +163 -0
- package/corpus/templates/design/app/components/templates/DesignTemplateLibrary.tsx +65 -78
- package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +6 -2
- package/corpus/templates/design/app/global.css +6 -0
- package/corpus/templates/design/app/i18n/en-US.ts +17 -0
- package/corpus/templates/design/app/lib/canvas-load-outcome.ts +147 -0
- package/corpus/templates/design/app/lib/canvas-outcome-tracking.ts +531 -0
- package/corpus/templates/design/app/lib/canvas-style-kind.ts +50 -0
- package/corpus/templates/design/app/pages/Index.tsx +10 -3
- package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +86 -29
- package/corpus/templates/design/app/pages/design-editor/commands/save-file-content.ts +38 -3
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-core.ts +9 -0
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-files-and-saving.ts +2 -0
- package/corpus/templates/design/changelog/2026-10-21-a-getting-started-checklist-at-the-bottom-of-the-sidebar-tra.md +6 -0
- package/corpus/templates/design/changelog/2026-10-21-templates-now-open-a-read-only-preview-from-the-card-and-the.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-collapsed-shader-layers-no-longer-interrupt-other-shaders-on.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-shader-fills-keep-rendering-when-other-screen-content-cannot.md +6 -0
- package/corpus/templates/design/scripts/design-export-validation/export-baseline.json +24 -0
- package/corpus/templates/design/server/lib/getting-started.ts +267 -0
- package/corpus/templates/design/server/plugins/getting-started.ts +5 -0
- package/corpus/templates/design/shared/design-template-presets/analytics-dashboard.ts +127 -0
- package/corpus/templates/design/shared/design-template-presets/design-studio.ts +98 -0
- package/corpus/templates/design/shared/design-template-presets/messaging-app.ts +101 -0
- package/corpus/templates/design/shared/design-template-presets/project-tasks.ts +120 -0
- package/corpus/templates/design/shared/design-template-presets.ts +8 -0
- package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/slides/CHANGELOG.md +6 -0
- package/corpus/templates/slides/actions/delete-deck.ts +7 -0
- package/corpus/templates/slides/changelog/2026-10-21-connected-deck-deletion-requires-approval.md +6 -0
- package/corpus/templates/slides/scripts/edit-fidelity/client-action.ts +61 -0
- package/corpus/templates/slides/scripts/edit-fidelity/run.ts +10 -0
- package/package.json +1 -1
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Made it, didn't use it": per app, the output a person makes, the events
|
|
3
|
+
* that say they made one, and the events that say they used it. Opening an
|
|
4
|
+
* output never counts as using it; a use shows the output to people or takes
|
|
5
|
+
* it out of the app.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** A use counts only within this many days of the output being made. */
|
|
9
|
+
export const OUTPUT_USE_WINDOW_DAYS = 7;
|
|
10
|
+
export const OUTPUT_USE_WINDOW_MS = OUTPUT_USE_WINDOW_DAYS * 24 * 60 * 60_000;
|
|
11
|
+
/** A presentation shorter than this was a look, not a talk. */
|
|
12
|
+
export const MIN_PRESENTATION_MS = 30_000;
|
|
13
|
+
/** The most outputs one recording lists; the rest are counted, not listed. */
|
|
14
|
+
export const MAX_OUTPUTS_PER_RECORDING = 10;
|
|
15
|
+
/** Output ids are skipped past this length, never cut, like session ids. */
|
|
16
|
+
export const MAX_OUTPUT_ID_LENGTH = 256;
|
|
17
|
+
/** The Sessions URL param naming the app whose unused outputs to find. */
|
|
18
|
+
export const UNUSED_OUTPUT_PARAM = "unused";
|
|
19
|
+
/** Every generator sends this when it makes an output, so it marks an app that makes them. */
|
|
20
|
+
export const OUTPUT_MADE_EVENT = "generation_completed";
|
|
21
|
+
|
|
22
|
+
type EventProperties = Readonly<Record<string, unknown>>;
|
|
23
|
+
|
|
24
|
+
export interface OutputUseEvent {
|
|
25
|
+
eventName: string;
|
|
26
|
+
qualifies: (properties: EventProperties) => boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface OutputUseRule {
|
|
30
|
+
outputType: string;
|
|
31
|
+
madeEvents: readonly string[];
|
|
32
|
+
usedEvents: readonly OutputUseEvent[];
|
|
33
|
+
/** The output's page, relative to its app's origin. */
|
|
34
|
+
outputPath: (outputId: string) => string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** A missing or non-numeric property never proves a use. */
|
|
38
|
+
function atLeast(value: unknown, minimum: number): boolean {
|
|
39
|
+
return (
|
|
40
|
+
typeof value === "number" && Number.isFinite(value) && value >= minimum
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const OUTPUT_USE_RULES = {
|
|
45
|
+
slides: {
|
|
46
|
+
outputType: "deck",
|
|
47
|
+
madeEvents: [OUTPUT_MADE_EVENT],
|
|
48
|
+
usedEvents: [
|
|
49
|
+
{
|
|
50
|
+
// Moving forward at least once means two or more slides were shown,
|
|
51
|
+
// even when the presentation started mid-deck.
|
|
52
|
+
eventName: "presentation_ended",
|
|
53
|
+
qualifies: (properties) =>
|
|
54
|
+
atLeast(properties.slides_advanced, 1) &&
|
|
55
|
+
atLeast(properties.duration_ms, MIN_PRESENTATION_MS),
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
// `slide_export_started` fires before the export runs, so only a
|
|
59
|
+
// finished export of a deck with slides counts.
|
|
60
|
+
eventName: "deck_exported",
|
|
61
|
+
qualifies: (properties) =>
|
|
62
|
+
properties.status === "completed" &&
|
|
63
|
+
atLeast(properties.slide_count, 1),
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
outputPath: (outputId) => `/deck/${encodeURIComponent(outputId)}`,
|
|
67
|
+
},
|
|
68
|
+
} as const satisfies Record<string, OutputUseRule>;
|
|
69
|
+
|
|
70
|
+
export type OutputUseApp = keyof typeof OUTPUT_USE_RULES;
|
|
71
|
+
|
|
72
|
+
export const OUTPUT_USE_APPS = Object.keys(OUTPUT_USE_RULES) as [
|
|
73
|
+
OutputUseApp,
|
|
74
|
+
...OutputUseApp[],
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
export function isOutputUseApp(value: unknown): value is OutputUseApp {
|
|
78
|
+
return (
|
|
79
|
+
typeof value === "string" &&
|
|
80
|
+
Object.prototype.hasOwnProperty.call(OUTPUT_USE_RULES, value)
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function outputUseRule(
|
|
85
|
+
app: string | null | undefined,
|
|
86
|
+
): OutputUseRule | null {
|
|
87
|
+
return isOutputUseApp(app) ? OUTPUT_USE_RULES[app] : null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Every event name any rule reads, for the catalog and for ingest. */
|
|
91
|
+
export const OUTPUT_USE_EVENT_NAMES: ReadonlySet<string> = new Set(
|
|
92
|
+
Object.values(OUTPUT_USE_RULES).flatMap((rule: OutputUseRule) => [
|
|
93
|
+
...rule.madeEvents,
|
|
94
|
+
...rule.usedEvents.map((used) => used.eventName),
|
|
95
|
+
]),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
export function outputIdOf(properties: EventProperties): string | null {
|
|
99
|
+
const value = properties.output_id;
|
|
100
|
+
if (typeof value !== "string") return null;
|
|
101
|
+
const outputId = value.trim();
|
|
102
|
+
return outputId && outputId.length <= MAX_OUTPUT_ID_LENGTH ? outputId : null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Where a recording's session ran, as far as the recording shows. */
|
|
106
|
+
export interface OutputRecordingPages {
|
|
107
|
+
firstUrl: string | null;
|
|
108
|
+
lastUrl: string | null;
|
|
109
|
+
/**
|
|
110
|
+
* Origins the recording's replay key lists. An empty list accepts uploads
|
|
111
|
+
* from anywhere, so it vouches for no origin and yields no link.
|
|
112
|
+
*/
|
|
113
|
+
allowedOrigins: readonly string[];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function recordedPage(value: string | null): URL | null {
|
|
117
|
+
if (!value) return null;
|
|
118
|
+
try {
|
|
119
|
+
const url = new URL(value);
|
|
120
|
+
return url.origin === "null" ? null : url;
|
|
121
|
+
// coercion-ok: a recording without a parseable URL has no app to link to; the output id still shows.
|
|
122
|
+
} catch {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Where a session's output opens: the app origin the session was recorded on,
|
|
129
|
+
* its mount path, and the output's page. The app checks access when it opens.
|
|
130
|
+
* A recording's URLs are whatever its uploader sent, so only an origin the
|
|
131
|
+
* replay key's owner allowed becomes a link; otherwise this is null.
|
|
132
|
+
*/
|
|
133
|
+
export function outputUrl(
|
|
134
|
+
app: string,
|
|
135
|
+
outputId: string,
|
|
136
|
+
recording: OutputRecordingPages,
|
|
137
|
+
): string | null {
|
|
138
|
+
const rule = outputUseRule(app);
|
|
139
|
+
if (!rule) return null;
|
|
140
|
+
const pages = [recording.firstUrl, recording.lastUrl].flatMap((value) => {
|
|
141
|
+
const page = recordedPage(value);
|
|
142
|
+
return page ? [page] : [];
|
|
143
|
+
});
|
|
144
|
+
// A recording's id lives in its tab's sessionStorage, which is per origin,
|
|
145
|
+
// so a real recording never spans origins; pages on two came from a forged
|
|
146
|
+
// upload, and neither can be trusted.
|
|
147
|
+
const origin = pages[0]?.origin;
|
|
148
|
+
if (
|
|
149
|
+
!origin ||
|
|
150
|
+
pages.some((page) => page.origin !== origin) ||
|
|
151
|
+
!recording.allowedOrigins.includes(origin)
|
|
152
|
+
) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
// A workspace deploy mounts each app at `/<app id>` on one origin, and a
|
|
156
|
+
// tab's recording follows it from app to app, so either page may show the
|
|
157
|
+
// mount. Reading that prefix as the mount assumes the app has no route of
|
|
158
|
+
// its own there (Slides has none). The recording's app label can't decide
|
|
159
|
+
// it: without a declared app it is the hostname's first label.
|
|
160
|
+
const mount = `/${app}`;
|
|
161
|
+
const mounted = pages.some(
|
|
162
|
+
(page) => page.pathname === mount || page.pathname.startsWith(`${mount}/`),
|
|
163
|
+
);
|
|
164
|
+
return `${origin}${mounted ? mount : ""}${rule.outputPath(outputId)}`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* What became of one output made in a session. `open` means the use window
|
|
169
|
+
* has not closed yet; `unmeasured` means a failed write may have dropped a
|
|
170
|
+
* use, so it cannot be called unused.
|
|
171
|
+
*/
|
|
172
|
+
export type SessionOutputStatus = "used" | "unused" | "open" | "unmeasured";
|
|
173
|
+
|
|
174
|
+
export interface SessionOutput {
|
|
175
|
+
app: OutputUseApp;
|
|
176
|
+
outputType: string;
|
|
177
|
+
outputId: string;
|
|
178
|
+
madeAt: string;
|
|
179
|
+
useBy: string;
|
|
180
|
+
status: SessionOutputStatus;
|
|
181
|
+
/** The first qualifying use's event name, when it was used in time. */
|
|
182
|
+
usedEvent: string | null;
|
|
183
|
+
usedAt: string | null;
|
|
184
|
+
url: string | null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface SessionRecordingOutputs {
|
|
188
|
+
/**
|
|
189
|
+
* By recording id, for each requested recording the viewer can read: its
|
|
190
|
+
* outputs, [] when it made none since coverage began, or null when they
|
|
191
|
+
* are unknown: it was shared from another tenant, whose events a share does
|
|
192
|
+
* not grant, its tenant has not started output tracking, or a batch lost in
|
|
193
|
+
* ingest overlapped it and may have held an output it made. Ids the viewer
|
|
194
|
+
* cannot read are absent.
|
|
195
|
+
*/
|
|
196
|
+
outputs: Record<string, SessionOutput[] | null>;
|
|
197
|
+
/**
|
|
198
|
+
* How many more outputs a recording made than `outputs` lists, by
|
|
199
|
+
* recording id; absent when none were left out. Unused outputs are listed
|
|
200
|
+
* first.
|
|
201
|
+
*/
|
|
202
|
+
omittedOutputs: Record<string, number>;
|
|
203
|
+
/** When the viewer's output tracking began, or null before it has. */
|
|
204
|
+
coverageStartedAt: string | null;
|
|
205
|
+
}
|
|
@@ -54,6 +54,8 @@ export interface EventCatalogEntry {
|
|
|
54
54
|
description: string | null;
|
|
55
55
|
automatic: boolean;
|
|
56
56
|
stoppedFiring: boolean;
|
|
57
|
+
/** Whether "made it, didn't use it" reads this event as making or using its app's output. */
|
|
58
|
+
outputRole: "made" | "used" | null;
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
export interface EventCatalogApp {
|
|
@@ -61,6 +63,10 @@ export interface EventCatalogApp {
|
|
|
61
63
|
eventCount: number;
|
|
62
64
|
volume: number;
|
|
63
65
|
onlyAutomaticEvents: boolean;
|
|
66
|
+
/** The app sent `generation_completed` in range, so it makes outputs. */
|
|
67
|
+
makesOutputs: boolean;
|
|
68
|
+
/** Events that count as using this app's output; empty for an app that makes outputs is a catalog gap. */
|
|
69
|
+
usedItEvents: string[];
|
|
64
70
|
}
|
|
65
71
|
|
|
66
72
|
export interface EventCatalogResult {
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Calendar are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-10-21
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- Calendar skips notification approval for solo events while preserving it for guest invitations and cancellations.
|
|
11
|
+
|
|
6
12
|
## 2026-10-19
|
|
7
13
|
|
|
8
14
|
### Changed
|
|
@@ -338,10 +338,8 @@ export default defineAction({
|
|
|
338
338
|
),
|
|
339
339
|
}),
|
|
340
340
|
needsApproval: ({ sendUpdates, attendees, eventType, autoDeclineMode }) =>
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
(sendUpdates === undefined &&
|
|
344
|
-
(normalizeAttendees(attendees)?.length ?? 0) > 0) ||
|
|
341
|
+
((normalizeAttendees(attendees)?.length ?? 0) > 0 &&
|
|
342
|
+
sendUpdates !== "none") ||
|
|
345
343
|
(eventType === "outOfOffice" && autoDeclineMode !== "declineNone"),
|
|
346
344
|
run: async (args, actionContext?: ActionRunContext) => {
|
|
347
345
|
const email = getRequestUserEmail();
|
|
@@ -224,16 +224,45 @@ export default defineAction({
|
|
|
224
224
|
),
|
|
225
225
|
}),
|
|
226
226
|
toolCallable: false,
|
|
227
|
-
needsApproval: ({
|
|
227
|
+
needsApproval: async ({
|
|
228
|
+
id,
|
|
229
|
+
accountEmail: requestedAccountEmail,
|
|
230
|
+
scope,
|
|
228
231
|
sendUpdates,
|
|
229
232
|
notificationMessage,
|
|
230
233
|
targetAccountEmail,
|
|
234
|
+
attendees,
|
|
231
235
|
addAttendees,
|
|
232
|
-
}) =>
|
|
233
|
-
targetAccountEmail !== undefined ||
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
(sendUpdates ===
|
|
236
|
+
}) => {
|
|
237
|
+
if (targetAccountEmail !== undefined || !!notificationMessage?.trim()) {
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
if (sendUpdates === "none") return false;
|
|
241
|
+
if (sendUpdates === undefined) return namesGuests(addAttendees);
|
|
242
|
+
|
|
243
|
+
if (namesGuests(attendees) || namesGuests(addAttendees)) return true;
|
|
244
|
+
|
|
245
|
+
// An empty replacement can still send cancellation notices to removed guests.
|
|
246
|
+
const ownerEmail = requireActionUserEmail();
|
|
247
|
+
const accountEmail = await resolveOwnedAccountEmail(
|
|
248
|
+
resolveGoogleEventAccountEmail(id, requestedAccountEmail),
|
|
249
|
+
ownerEmail,
|
|
250
|
+
);
|
|
251
|
+
let event = await googleCalendar.getEvent(
|
|
252
|
+
normalizeWritableGoogleEventId(id),
|
|
253
|
+
{
|
|
254
|
+
ownerEmail,
|
|
255
|
+
accountEmail,
|
|
256
|
+
},
|
|
257
|
+
);
|
|
258
|
+
if (scope === "all" && event.recurringEventId) {
|
|
259
|
+
event = await googleCalendar.getEvent(event.recurringEventId, {
|
|
260
|
+
ownerEmail,
|
|
261
|
+
accountEmail,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
return (event.attendees?.length ?? 0) > 0;
|
|
265
|
+
},
|
|
237
266
|
run: async (args, actionContext?: ActionRunContext) => {
|
|
238
267
|
const ownerEmail = requireActionUserEmail();
|
|
239
268
|
if (args.addGoogleMeet && args.addZoom) {
|
|
@@ -244,9 +244,12 @@ supports searching property types by label or machine name.
|
|
|
244
244
|
List views can save an item layout (`itemLayout`) that decides what each row
|
|
245
245
|
shows: a start slot (page icon, a checkbox property, a status property, or
|
|
246
246
|
nothing), the title weight, line 2 (a text, URL, or non-body Blocks property,
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
247
|
+
or with `source: "page"` the first lines of each row's page, clamped to 1-3
|
|
248
|
+
lines), and ordered property IDs for line 3 and the end of the row; end values
|
|
249
|
+
move under the title on narrow screens and empty values take no space. While
|
|
250
|
+
any list view shows page text, collection reads give each item an `excerpt`
|
|
251
|
+
with the start of its page as plain text; other collections leave page bodies
|
|
252
|
+
out of row reads. Ticking a row's checkbox writes the property through
|
|
250
253
|
`set-document-property` and strikes the title through without moving the row.
|
|
251
254
|
A view without `itemLayout` keeps the default rows. Agents update it with an
|
|
252
255
|
`update-content-database-view` `update` patch on the list view: pass
|
|
@@ -7,6 +7,7 @@ time from the command menu (Cmd+K → "What's new").
|
|
|
7
7
|
|
|
8
8
|
### Improved
|
|
9
9
|
|
|
10
|
+
- A collection linked to a big GitHub folder fills faster, and pushes to other linked collections aren't held up while it does
|
|
10
11
|
- Accept remaining and Reject remaining show the result for every suggested edit at once
|
|
11
12
|
- Accepting a group of suggested edits saves faster and adds one page version
|
|
12
13
|
|
|
@@ -18,6 +19,10 @@ time from the command menu (Cmd+K → "What's new").
|
|
|
18
19
|
|
|
19
20
|
## 2026-10-21
|
|
20
21
|
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- List rows can show the first lines of each page under its title: pick **Page text** for Line 2
|
|
25
|
+
|
|
21
26
|
### Improved
|
|
22
27
|
|
|
23
28
|
- Suggested edits show an agent's whole reason: open a group to read past the first two lines, and lone edits show the reason above the change
|
|
@@ -37,6 +42,7 @@ time from the command menu (Cmd+K → "What's new").
|
|
|
37
42
|
|
|
38
43
|
### Fixed
|
|
39
44
|
|
|
45
|
+
- Builder content sync keeps read and write status accurate when API responses fail.
|
|
40
46
|
- HTML table cells preserve a trailing backslash when opening Markdown.
|
|
41
47
|
- Preserve empty paragraph colors and refuse unsupported inline image and oversized math formatting before content is stored.
|
|
42
48
|
|
|
@@ -67,6 +73,7 @@ time from the command menu (Cmd+K → "What's new").
|
|
|
67
73
|
|
|
68
74
|
### Added
|
|
69
75
|
|
|
76
|
+
- Fill a collection from a GitHub folder through its Sources settings, which an empty collection links to from under its title and which say up front when GitHub can't link and what to do instead. A short preview comes before linking, the collection shows where its pages come from and when they last updated, with a link back to its folder in Sources, and unlinking asks first
|
|
70
77
|
- Connected AI assistants can make a collection from a GitHub folder, or link an empty one: each Markdown file becomes a view-only page, and a sync brings in the latest pushes
|
|
71
78
|
- Make a collection from a GitHub folder in the sidebar's New menu, or fill an empty one from its Sources settings, which say up front when GitHub can't link and what to do instead. A short preview comes before linking, the collection shows where its pages come from and when they last updated, and unlinking asks first
|
|
72
79
|
- Connected AI assistants can link a new collection to a GitHub folder: each Markdown file becomes a view-only page, and a sync brings in the latest pushes
|
|
@@ -91,6 +98,7 @@ time from the command menu (Cmd+K → "What's new").
|
|
|
91
98
|
|
|
92
99
|
### Fixed
|
|
93
100
|
|
|
101
|
+
- Builder Content avoids retrying a write when Builder accepted it but the response could not be saved.
|
|
94
102
|
- Agents reading a page you have open no longer wait or fail when your edits are already saved
|
|
95
103
|
|
|
96
104
|
## 2026-10-16
|
|
@@ -4,13 +4,15 @@ import { ActionContractError } from "@agent-native/core";
|
|
|
4
4
|
import { and, eq } from "drizzle-orm";
|
|
5
5
|
|
|
6
6
|
import { getDb, schema } from "../server/db/index.js";
|
|
7
|
+
import type { LiveCopyBodySave } from "../shared/api.js";
|
|
7
8
|
|
|
8
9
|
export interface BrowserSaveAttemptConfirmation {
|
|
9
10
|
attemptId: string;
|
|
10
|
-
result: "applied" | "replayed";
|
|
11
|
+
result: "applied" | "replayed" | "live_copy";
|
|
11
12
|
revision: string;
|
|
12
13
|
updatedAt: string;
|
|
13
14
|
softDeletedDatabaseIds?: string[];
|
|
15
|
+
bodySave?: LiveCopyBodySave;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export interface BrowserSaveAttemptPreservation {
|
|
@@ -72,6 +74,7 @@ export function readBrowserSaveAttempt(
|
|
|
72
74
|
reason?: unknown;
|
|
73
75
|
checkpointId?: unknown;
|
|
74
76
|
softDeletedDatabaseIds?: unknown;
|
|
77
|
+
bodySave?: unknown;
|
|
75
78
|
};
|
|
76
79
|
if (
|
|
77
80
|
typeof result.revision !== "string" ||
|
|
@@ -119,6 +122,12 @@ export function readBrowserSaveAttempt(
|
|
|
119
122
|
{ errorCode: "BROWSER_SAVE_RECEIPT_INVALID", statusCode: 500 },
|
|
120
123
|
);
|
|
121
124
|
}
|
|
125
|
+
if (result.bodySave !== undefined && !isLiveCopyBodySave(result.bodySave)) {
|
|
126
|
+
throw new ActionContractError(
|
|
127
|
+
"The stored browser save receipt has an invalid live-copy body save.",
|
|
128
|
+
{ errorCode: "BROWSER_SAVE_RECEIPT_INVALID", statusCode: 500 },
|
|
129
|
+
);
|
|
130
|
+
}
|
|
122
131
|
return {
|
|
123
132
|
attemptId: stored.attemptId,
|
|
124
133
|
result: "replayed",
|
|
@@ -127,5 +136,18 @@ export function readBrowserSaveAttempt(
|
|
|
127
136
|
softDeletedDatabaseIds: result.softDeletedDatabaseIds as
|
|
128
137
|
| string[]
|
|
129
138
|
| undefined,
|
|
139
|
+
...(result.bodySave ? { bodySave: result.bodySave } : {}),
|
|
130
140
|
};
|
|
131
141
|
}
|
|
142
|
+
|
|
143
|
+
function isLiveCopyBodySave(value: unknown): value is LiveCopyBodySave {
|
|
144
|
+
const save = value as Partial<LiveCopyBodySave> | null;
|
|
145
|
+
return (
|
|
146
|
+
typeof save === "object" &&
|
|
147
|
+
save !== null &&
|
|
148
|
+
save.status === "live_copy" &&
|
|
149
|
+
typeof save.matchesLiveCopy === "boolean" &&
|
|
150
|
+
Number.isSafeInteger(save.bodyRevision) &&
|
|
151
|
+
Number.isSafeInteger(save.collabVersion)
|
|
152
|
+
);
|
|
153
|
+
}
|