@agent-native/core 0.90.3 → 0.90.4
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/bin/agent-native.js +25 -3
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +9 -0
- package/corpus/core/bin/agent-native.js +25 -3
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/engine/index.ts +1 -0
- package/corpus/core/src/agent/engine/registry.ts +63 -2
- package/corpus/core/src/cli/create.ts +35 -0
- package/corpus/core/src/cli/design-connect.ts +248 -0
- package/corpus/core/src/cli/index.ts +84 -7
- package/corpus/core/src/cli/workspacify.ts +34 -0
- package/corpus/core/src/client/history/VersionHistoryPanel.tsx +77 -47
- package/corpus/core/src/client/history/index.ts +3 -0
- package/corpus/core/src/client/history/use-history.ts +28 -0
- package/corpus/core/src/client/index.ts +8 -0
- package/corpus/core/src/client/review/index.ts +5 -0
- package/corpus/core/src/client/review/use-review.ts +40 -2
- package/corpus/core/src/history/actions/create-resource-version.ts +11 -8
- package/corpus/core/src/history/index.ts +0 -1
- package/corpus/core/src/history/registry.ts +24 -12
- package/corpus/core/src/history/store.ts +84 -53
- package/corpus/core/src/review/actions/consume-review-feedback.ts +15 -5
- package/corpus/core/src/review/actions/delete-review-comment.ts +15 -3
- package/corpus/core/src/review/actions/resolve-review-thread.ts +12 -5
- package/corpus/core/src/review/index.ts +0 -5
- package/corpus/core/src/review/registry.ts +24 -12
- package/corpus/core/src/review/store.ts +10 -7
- package/corpus/core/src/server/agent-chat-plugin.ts +6 -0
- package/corpus/core/src/server/credential-provider.ts +13 -3
- package/corpus/templates/assets/actions/_preset-skeleton-validation.ts +11 -11
- package/corpus/templates/assets/actions/generate-image.ts +64 -28
- package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +1 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +91 -74
- package/corpus/templates/assets/server/lib/generation.ts +29 -4
- package/corpus/templates/assets/server/lib/image-processing.ts +131 -0
- package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +24 -2
- package/corpus/templates/calendar/AGENTS.md +3 -0
- package/corpus/templates/calendar/actions/create-event.ts +8 -34
- package/corpus/templates/calendar/actions/event-action-helpers.ts +52 -0
- package/corpus/templates/calendar/actions/manage-event-draft.ts +7 -34
- package/corpus/templates/calendar/actions/update-event.ts +10 -23
- package/corpus/templates/calendar/app/components/calendar/AttendeeAutocomplete.tsx +47 -0
- package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +23 -0
- package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +59 -2
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +40 -1
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +34 -1
- package/corpus/templates/calendar/app/hooks/use-events.ts +6 -0
- package/corpus/templates/calendar/app/i18n/zh-TW.ts +4 -0
- package/corpus/templates/calendar/app/i18n-data.ts +40 -0
- package/corpus/templates/calendar/changelog/2026-07-07-you-can-mark-event-guests-as-optional-while-inviting-them-or.md +6 -0
- package/corpus/templates/calendar/server/handlers/events.ts +1 -0
- package/corpus/templates/calendar/server/lib/google-calendar.ts +4 -0
- package/corpus/templates/calendar/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/calendar/shared/api.ts +2 -0
- package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +29 -3
- package/corpus/templates/clips/actions/generate-workflow.ts +19 -8
- package/corpus/templates/clips/actions/get-clips-ai-prefs.ts +36 -0
- package/corpus/templates/clips/actions/lib/clips-ai-prefs.ts +28 -0
- package/corpus/templates/clips/actions/regenerate-chapters.ts +21 -7
- package/corpus/templates/clips/actions/regenerate-summary.ts +26 -8
- package/corpus/templates/clips/actions/regenerate-title.ts +44 -7
- package/corpus/templates/clips/actions/update-clips-ai-prefs.ts +50 -0
- package/corpus/templates/clips/app/components/meetings/meeting-card.tsx +7 -2
- package/corpus/templates/clips/app/hooks/use-auto-title.ts +25 -10
- package/corpus/templates/clips/app/i18n/ar-SA.ts +28 -6
- package/corpus/templates/clips/app/i18n/de-DE.ts +28 -6
- package/corpus/templates/clips/app/i18n/en-US.ts +29 -6
- package/corpus/templates/clips/app/i18n/es-ES.ts +29 -6
- package/corpus/templates/clips/app/i18n/fr-FR.ts +30 -6
- package/corpus/templates/clips/app/i18n/hi-IN.ts +26 -6
- package/corpus/templates/clips/app/i18n/ja-JP.ts +27 -6
- package/corpus/templates/clips/app/i18n/ko-KR.ts +28 -6
- package/corpus/templates/clips/app/i18n/pt-BR.ts +28 -6
- package/corpus/templates/clips/app/i18n/zh-CN.ts +26 -6
- package/corpus/templates/clips/app/i18n/zh-TW.ts +25 -6
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +73 -0
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +1 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +70 -2
- package/corpus/templates/clips/changelog/2026-07-07-ai-tools-can-include-the-full-video-not-just-the-transcript-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-clips-desktop-now-surfaces-meetings-and-dictate-directly-in-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-meeting-notes-now-explain-exactly-how-to-start-granola-style.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-meeting-start-alerts-now-include-separate-start-notes-and-jo.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-recordings-start-more-predictably-and-newly-saved-clips-refr.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
- package/corpus/templates/clips/desktop/src/app.tsx +435 -105
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +27 -21
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +23 -22
- package/corpus/templates/clips/desktop/src/styles.css +167 -2
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +1 -1
- package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +3 -7
- package/corpus/templates/clips/desktop/src-tauri/src/tray_meetings.rs +5 -4
- package/corpus/templates/clips/server/routes/_agent-native/clips/user-prefs.put.ts +16 -8
- package/corpus/templates/clips/shared/clips-ai-prefs.ts +81 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +16 -1
- package/corpus/templates/design/actions/add-localhost-screens.ts +1 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +345 -11
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +89 -14
- package/corpus/templates/design/app/components/design/bridge-security.ts +7 -1
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +1 -1
- package/corpus/templates/design/app/i18n/zh-TW.ts +3 -0
- package/corpus/templates/design/app/i18n-data.ts +41 -0
- package/corpus/templates/design/changelog/2026-07-07-local-visual-edit-uses-live-app-iframes-for-click-to-edit-pr.md +6 -0
- package/dist/agent/engine/index.d.ts +1 -1
- package/dist/agent/engine/index.d.ts.map +1 -1
- package/dist/agent/engine/index.js +1 -1
- package/dist/agent/engine/index.js.map +1 -1
- package/dist/agent/engine/registry.d.ts +14 -0
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +56 -2
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +31 -0
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +186 -0
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/index.js +76 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/workspacify.d.ts.map +1 -1
- package/dist/cli/workspacify.js +30 -0
- package/dist/cli/workspacify.js.map +1 -1
- package/dist/client/history/VersionHistoryPanel.d.ts +1 -1
- package/dist/client/history/VersionHistoryPanel.d.ts.map +1 -1
- package/dist/client/history/VersionHistoryPanel.js +12 -5
- package/dist/client/history/VersionHistoryPanel.js.map +1 -1
- package/dist/client/history/index.d.ts +1 -1
- package/dist/client/history/index.d.ts.map +1 -1
- package/dist/client/history/index.js +1 -1
- package/dist/client/history/index.js.map +1 -1
- package/dist/client/history/use-history.d.ts +12 -0
- package/dist/client/history/use-history.d.ts.map +1 -1
- package/dist/client/history/use-history.js +6 -0
- package/dist/client/history/use-history.js.map +1 -1
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/review/index.d.ts +1 -1
- package/dist/client/review/index.d.ts.map +1 -1
- package/dist/client/review/index.js +1 -1
- package/dist/client/review/index.js.map +1 -1
- package/dist/client/review/use-review.d.ts +23 -0
- package/dist/client/review/use-review.d.ts.map +1 -1
- package/dist/client/review/use-review.js +8 -0
- package/dist/client/review/use-review.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/history/actions/create-resource-version.js +7 -4
- package/dist/history/actions/create-resource-version.js.map +1 -1
- package/dist/history/index.d.ts +1 -1
- package/dist/history/index.d.ts.map +1 -1
- package/dist/history/index.js +1 -1
- package/dist/history/index.js.map +1 -1
- package/dist/history/registry.d.ts.map +1 -1
- package/dist/history/registry.js +14 -12
- package/dist/history/registry.js.map +1 -1
- package/dist/history/store.d.ts.map +1 -1
- package/dist/history/store.js +74 -49
- package/dist/history/store.js.map +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/review/actions/consume-review-feedback.d.ts +1 -0
- package/dist/review/actions/consume-review-feedback.js +8 -2
- package/dist/review/actions/consume-review-feedback.js.map +1 -1
- package/dist/review/actions/delete-review-comment.d.ts +2 -1
- package/dist/review/actions/delete-review-comment.js +11 -3
- package/dist/review/actions/delete-review-comment.js.map +1 -1
- package/dist/review/actions/resolve-review-thread.d.ts +2 -1
- package/dist/review/actions/resolve-review-thread.js +5 -2
- package/dist/review/actions/resolve-review-thread.js.map +1 -1
- package/dist/review/index.d.ts +1 -1
- package/dist/review/index.d.ts.map +1 -1
- package/dist/review/index.js +1 -1
- package/dist/review/index.js.map +1 -1
- package/dist/review/registry.d.ts.map +1 -1
- package/dist/review/registry.js +14 -12
- package/dist/review/registry.js.map +1 -1
- package/dist/review/store.d.ts +3 -3
- package/dist/review/store.d.ts.map +1 -1
- package/dist/review/store.js +7 -4
- package/dist/review/store.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +5 -0
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +2 -0
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +13 -3
- package/dist/server/credential-provider.js.map +1 -1
- package/package.json +1 -1
|
@@ -24,6 +24,12 @@ import fs from "fs";
|
|
|
24
24
|
import path from "path";
|
|
25
25
|
|
|
26
26
|
const POSTGRES_DEPENDENCY_VERSION = "^3.4.9";
|
|
27
|
+
const REACT_ROUTER_BUILD_DEPENDENCIES = [
|
|
28
|
+
"@react-router/dev",
|
|
29
|
+
"@react-router/fs-routes",
|
|
30
|
+
"react-router",
|
|
31
|
+
"vite",
|
|
32
|
+
] as const;
|
|
27
33
|
|
|
28
34
|
export interface WorkspacifyOptions {
|
|
29
35
|
/** Target app directory (already populated with the copied template) */
|
|
@@ -87,6 +93,7 @@ export function workspacifyApp(opts: WorkspacifyOptions): void {
|
|
|
87
93
|
// Add the runtime package to workspace apps so production bundles do
|
|
88
94
|
// not fail only after a hosted Postgres database is configured.
|
|
89
95
|
pkg.dependencies.postgres ??= POSTGRES_DEPENDENCY_VERSION;
|
|
96
|
+
ensureReactRouterBuildDependencies(pkg);
|
|
90
97
|
// pnpm build-script approvals belong at the workspace root. Leaving the
|
|
91
98
|
// template's per-app setting in place makes pnpm warn on every install.
|
|
92
99
|
if (pkg.pnpm && typeof pkg.pnpm === "object") {
|
|
@@ -156,6 +163,33 @@ export function workspacifyApp(opts: WorkspacifyOptions): void {
|
|
|
156
163
|
}
|
|
157
164
|
}
|
|
158
165
|
|
|
166
|
+
function ensureReactRouterBuildDependencies(pkg: Record<string, any>): void {
|
|
167
|
+
const allDeps = {
|
|
168
|
+
...pkg.dependencies,
|
|
169
|
+
...pkg.devDependencies,
|
|
170
|
+
...pkg.peerDependencies,
|
|
171
|
+
};
|
|
172
|
+
if (
|
|
173
|
+
!allDeps["@react-router/dev"] &&
|
|
174
|
+
!allDeps["react-router"] &&
|
|
175
|
+
!allDeps["@react-router/fs-routes"]
|
|
176
|
+
) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
pkg.dependencies = pkg.dependencies ?? {};
|
|
181
|
+
for (const key of REACT_ROUTER_BUILD_DEPENDENCIES) {
|
|
182
|
+
const existing =
|
|
183
|
+
pkg.dependencies[key] ??
|
|
184
|
+
pkg.devDependencies?.[key] ??
|
|
185
|
+
pkg.peerDependencies?.[key];
|
|
186
|
+
if (!existing) continue;
|
|
187
|
+
pkg.dependencies[key] = existing;
|
|
188
|
+
delete pkg.devDependencies?.[key];
|
|
189
|
+
delete pkg.peerDependencies?.[key];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
159
193
|
function writeInheritedChatPlugin(
|
|
160
194
|
appDir: string,
|
|
161
195
|
workspaceCoreName: string,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IconClock, IconRestore, IconTimeline } from "@tabler/icons-react";
|
|
2
|
-
import type
|
|
2
|
+
import { useState, type ReactNode } from "react";
|
|
3
3
|
|
|
4
4
|
import type { ResourceVersion } from "../../history/types.js";
|
|
5
5
|
import { cn } from "../utils.js";
|
|
@@ -31,6 +31,7 @@ export function VersionHistoryPanel({
|
|
|
31
31
|
}: VersionHistoryPanelProps) {
|
|
32
32
|
const versions = useResourceVersions({ resourceType, resourceId, limit });
|
|
33
33
|
const restore = useRestoreResourceVersion();
|
|
34
|
+
const [confirmRestoreId, setConfirmRestoreId] = useState<string | null>(null);
|
|
34
35
|
|
|
35
36
|
return (
|
|
36
37
|
<section
|
|
@@ -49,52 +50,81 @@ export function VersionHistoryPanel({
|
|
|
49
50
|
Loading versions...
|
|
50
51
|
</div>
|
|
51
52
|
) : versions.data?.versions.length ? (
|
|
52
|
-
versions.data.versions.map((version) =>
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
className="
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
53
|
+
versions.data.versions.map((version) => {
|
|
54
|
+
const confirming = confirmRestoreId === version.id;
|
|
55
|
+
return (
|
|
56
|
+
<article key={version.id} className="flex gap-3 px-4 py-3">
|
|
57
|
+
<div className="mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-muted">
|
|
58
|
+
<IconClock className="h-4 w-4 text-muted-foreground" />
|
|
59
|
+
</div>
|
|
60
|
+
<div className="min-w-0 flex-1">
|
|
61
|
+
{renderVersion ? (
|
|
62
|
+
renderVersion(version)
|
|
63
|
+
) : (
|
|
64
|
+
<>
|
|
65
|
+
<div className="flex flex-wrap items-center gap-x-2 gap-y-1">
|
|
66
|
+
<h3 className="truncate text-sm font-medium">
|
|
67
|
+
{version.title ?? `Version ${version.versionNumber}`}
|
|
68
|
+
</h3>
|
|
69
|
+
<span className="text-xs text-muted-foreground">
|
|
70
|
+
{formatVersionDate(version.createdAt)}
|
|
71
|
+
</span>
|
|
72
|
+
</div>
|
|
73
|
+
{version.summary ? (
|
|
74
|
+
<p className="mt-1 text-sm text-muted-foreground">
|
|
75
|
+
{version.summary}
|
|
76
|
+
</p>
|
|
77
|
+
) : null}
|
|
78
|
+
</>
|
|
79
|
+
)}
|
|
80
|
+
</div>
|
|
81
|
+
<div className="flex shrink-0 items-center gap-2">
|
|
82
|
+
{confirming ? (
|
|
83
|
+
<>
|
|
84
|
+
<button
|
|
85
|
+
type="button"
|
|
86
|
+
className="inline-flex h-8 items-center rounded-md border border-input px-2.5 text-xs font-medium hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50"
|
|
87
|
+
disabled={restore.isPending}
|
|
88
|
+
onClick={() => setConfirmRestoreId(null)}
|
|
89
|
+
>
|
|
90
|
+
Cancel
|
|
91
|
+
</button>
|
|
92
|
+
<button
|
|
93
|
+
type="button"
|
|
94
|
+
className="inline-flex h-8 items-center gap-1.5 rounded-md border border-destructive bg-destructive px-2.5 text-xs font-medium text-destructive-foreground hover:bg-destructive/90 disabled:cursor-not-allowed disabled:opacity-50"
|
|
95
|
+
disabled={restore.isPending}
|
|
96
|
+
onClick={() =>
|
|
97
|
+
restore.mutate(
|
|
98
|
+
{ id: version.id },
|
|
99
|
+
{
|
|
100
|
+
onSuccess: (result) => {
|
|
101
|
+
setConfirmRestoreId(null);
|
|
102
|
+
onRestored?.(result.version, result.result);
|
|
103
|
+
},
|
|
104
|
+
onError: () => setConfirmRestoreId(null),
|
|
105
|
+
},
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
>
|
|
109
|
+
<IconRestore className="h-3.5 w-3.5" />
|
|
110
|
+
Confirm restore
|
|
111
|
+
</button>
|
|
112
|
+
</>
|
|
113
|
+
) : (
|
|
114
|
+
<button
|
|
115
|
+
type="button"
|
|
116
|
+
className="inline-flex h-8 items-center gap-1.5 rounded-md border border-input px-2.5 text-xs font-medium hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50"
|
|
117
|
+
disabled={restore.isPending}
|
|
118
|
+
onClick={() => setConfirmRestoreId(version.id)}
|
|
119
|
+
>
|
|
120
|
+
<IconRestore className="h-3.5 w-3.5" />
|
|
121
|
+
Restore
|
|
122
|
+
</button>
|
|
123
|
+
)}
|
|
124
|
+
</div>
|
|
125
|
+
</article>
|
|
126
|
+
);
|
|
127
|
+
})
|
|
98
128
|
) : (
|
|
99
129
|
<div className="px-4 py-6 text-sm text-muted-foreground">
|
|
100
130
|
{emptyState}
|
|
@@ -6,9 +6,12 @@ export {
|
|
|
6
6
|
export {
|
|
7
7
|
useCreateResourceVersion,
|
|
8
8
|
useResourceHistory,
|
|
9
|
+
useResourceVersion,
|
|
9
10
|
useResourceVersions,
|
|
10
11
|
useRestoreResourceVersion,
|
|
11
12
|
type CreateResourceVersionInput,
|
|
13
|
+
type GetResourceVersionInput,
|
|
14
|
+
type GetResourceVersionResult,
|
|
12
15
|
type ListResourceHistoryResult,
|
|
13
16
|
type ListResourceVersionsResult,
|
|
14
17
|
type ResourceHistoryParams,
|
|
@@ -30,6 +30,13 @@ export interface RestoreResourceVersionInput {
|
|
|
30
30
|
versionNumber?: number;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
export interface GetResourceVersionInput {
|
|
34
|
+
id?: string;
|
|
35
|
+
resourceType?: string;
|
|
36
|
+
resourceId?: string;
|
|
37
|
+
versionNumber?: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
33
40
|
export interface ListResourceVersionsResult {
|
|
34
41
|
versions: ResourceVersion[];
|
|
35
42
|
}
|
|
@@ -39,6 +46,10 @@ export interface ListResourceHistoryResult {
|
|
|
39
46
|
auditEvents: unknown[];
|
|
40
47
|
}
|
|
41
48
|
|
|
49
|
+
export interface GetResourceVersionResult {
|
|
50
|
+
version: ResourceVersion;
|
|
51
|
+
}
|
|
52
|
+
|
|
42
53
|
export interface RestoreResourceVersionResult {
|
|
43
54
|
version: ResourceVersion;
|
|
44
55
|
result: unknown;
|
|
@@ -72,6 +83,23 @@ export function useResourceHistory(
|
|
|
72
83
|
);
|
|
73
84
|
}
|
|
74
85
|
|
|
86
|
+
export function useResourceVersion(
|
|
87
|
+
params: GetResourceVersionInput,
|
|
88
|
+
options?: { enabled?: boolean },
|
|
89
|
+
) {
|
|
90
|
+
const enabled =
|
|
91
|
+
options?.enabled ??
|
|
92
|
+
Boolean(
|
|
93
|
+
params.id ||
|
|
94
|
+
(params.resourceType && params.resourceId && params.versionNumber),
|
|
95
|
+
);
|
|
96
|
+
return useActionQuery<GetResourceVersionResult>(
|
|
97
|
+
"get-resource-version",
|
|
98
|
+
params,
|
|
99
|
+
{ enabled },
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
75
103
|
export function useCreateResourceVersion() {
|
|
76
104
|
return useActionMutation<ResourceVersion, CreateResourceVersionInput>(
|
|
77
105
|
"create-resource-version",
|
|
@@ -791,9 +791,12 @@ export {
|
|
|
791
791
|
VersionHistoryPanel,
|
|
792
792
|
useCreateResourceVersion,
|
|
793
793
|
useResourceHistory,
|
|
794
|
+
useResourceVersion,
|
|
794
795
|
useResourceVersions,
|
|
795
796
|
useRestoreResourceVersion,
|
|
796
797
|
type CreateResourceVersionInput,
|
|
798
|
+
type GetResourceVersionInput,
|
|
799
|
+
type GetResourceVersionResult,
|
|
797
800
|
type ListResourceHistoryResult,
|
|
798
801
|
type ListResourceVersionsResult,
|
|
799
802
|
type ResourceHistoryParams,
|
|
@@ -806,14 +809,19 @@ export {
|
|
|
806
809
|
ReviewStatusBadge,
|
|
807
810
|
ReviewThreadPanel,
|
|
808
811
|
buildReviewThreads,
|
|
812
|
+
useConsumeReviewFeedback,
|
|
809
813
|
useCreateReviewComment,
|
|
810
814
|
useDeleteReviewComment,
|
|
811
815
|
useReplyReviewComment,
|
|
812
816
|
useResolveReviewThread,
|
|
813
817
|
useReviewComments,
|
|
818
|
+
useReviewFeedback,
|
|
814
819
|
useSetReviewStatus,
|
|
820
|
+
type ConsumeReviewFeedbackInput,
|
|
815
821
|
type CreateReviewCommentInput,
|
|
816
822
|
type DeleteReviewCommentInput,
|
|
823
|
+
type GetReviewFeedbackParams,
|
|
824
|
+
type GetReviewFeedbackResult,
|
|
817
825
|
type ListReviewCommentsParams,
|
|
818
826
|
type ListReviewCommentsResult,
|
|
819
827
|
type ReplyReviewCommentInput,
|
|
@@ -9,14 +9,19 @@ export {
|
|
|
9
9
|
type ReviewThreadPanelProps,
|
|
10
10
|
} from "./ReviewThreadPanel.js";
|
|
11
11
|
export {
|
|
12
|
+
useConsumeReviewFeedback,
|
|
12
13
|
useCreateReviewComment,
|
|
13
14
|
useDeleteReviewComment,
|
|
14
15
|
useReplyReviewComment,
|
|
15
16
|
useResolveReviewThread,
|
|
16
17
|
useReviewComments,
|
|
18
|
+
useReviewFeedback,
|
|
17
19
|
useSetReviewStatus,
|
|
20
|
+
type ConsumeReviewFeedbackInput,
|
|
18
21
|
type CreateReviewCommentInput,
|
|
19
22
|
type DeleteReviewCommentInput,
|
|
23
|
+
type GetReviewFeedbackParams,
|
|
24
|
+
type GetReviewFeedbackResult,
|
|
20
25
|
type ListReviewCommentsParams,
|
|
21
26
|
type ListReviewCommentsResult,
|
|
22
27
|
type ReplyReviewCommentInput,
|
|
@@ -22,6 +22,17 @@ export interface ListReviewCommentsResult {
|
|
|
22
22
|
reviewStatus: ReviewStatusEntry | null;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
export interface GetReviewFeedbackParams {
|
|
26
|
+
resourceType: string;
|
|
27
|
+
resourceId: string;
|
|
28
|
+
includeHumanTargeted?: boolean;
|
|
29
|
+
limit?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface GetReviewFeedbackResult {
|
|
33
|
+
comments: ReviewComment[];
|
|
34
|
+
}
|
|
35
|
+
|
|
25
36
|
export interface CreateReviewCommentInput {
|
|
26
37
|
resourceType: string;
|
|
27
38
|
resourceId: string;
|
|
@@ -59,6 +70,12 @@ export interface DeleteReviewCommentInput {
|
|
|
59
70
|
commentId: string;
|
|
60
71
|
}
|
|
61
72
|
|
|
73
|
+
export interface ConsumeReviewFeedbackInput {
|
|
74
|
+
resourceType: string;
|
|
75
|
+
resourceId: string;
|
|
76
|
+
commentIds: string[];
|
|
77
|
+
}
|
|
78
|
+
|
|
62
79
|
export interface SetReviewStatusInput {
|
|
63
80
|
resourceType: string;
|
|
64
81
|
resourceId: string;
|
|
@@ -81,6 +98,20 @@ export function useReviewComments(
|
|
|
81
98
|
);
|
|
82
99
|
}
|
|
83
100
|
|
|
101
|
+
export function useReviewFeedback(
|
|
102
|
+
params: GetReviewFeedbackParams,
|
|
103
|
+
options?: { enabled?: boolean },
|
|
104
|
+
) {
|
|
105
|
+
return useActionQuery<GetReviewFeedbackResult>(
|
|
106
|
+
"get-review-feedback",
|
|
107
|
+
params,
|
|
108
|
+
{
|
|
109
|
+
enabled:
|
|
110
|
+
options?.enabled ?? Boolean(params.resourceType && params.resourceId),
|
|
111
|
+
},
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
84
115
|
export function useCreateReviewComment() {
|
|
85
116
|
return useActionMutation<ReviewComment, CreateReviewCommentInput>(
|
|
86
117
|
"create-review-comment",
|
|
@@ -95,18 +126,25 @@ export function useReplyReviewComment() {
|
|
|
95
126
|
|
|
96
127
|
export function useResolveReviewThread() {
|
|
97
128
|
return useActionMutation<
|
|
98
|
-
{ threadId: string; resolved: true },
|
|
129
|
+
{ threadId: string; resolved: true; updatedCount: number },
|
|
99
130
|
ResolveReviewThreadInput
|
|
100
131
|
>("resolve-review-thread");
|
|
101
132
|
}
|
|
102
133
|
|
|
103
134
|
export function useDeleteReviewComment() {
|
|
104
135
|
return useActionMutation<
|
|
105
|
-
{ commentId: string; deleted: true },
|
|
136
|
+
{ commentId: string; deleted: true; updatedCount: number },
|
|
106
137
|
DeleteReviewCommentInput
|
|
107
138
|
>("delete-review-comment");
|
|
108
139
|
}
|
|
109
140
|
|
|
141
|
+
export function useConsumeReviewFeedback() {
|
|
142
|
+
return useActionMutation<
|
|
143
|
+
{ consumedCommentIds: string[]; updatedCount: number },
|
|
144
|
+
ConsumeReviewFeedbackInput
|
|
145
|
+
>("consume-review-feedback");
|
|
146
|
+
}
|
|
147
|
+
|
|
110
148
|
export function useSetReviewStatus() {
|
|
111
149
|
return useActionMutation<ReviewStatusEntry, SetReviewStatusInput>(
|
|
112
150
|
"set-review-status",
|
|
@@ -30,15 +30,18 @@ export default defineAction({
|
|
|
30
30
|
"editor",
|
|
31
31
|
);
|
|
32
32
|
const registration = getVersionedResource(args.resourceType);
|
|
33
|
+
// Prefer the registered server snapshot when available so editors/agents
|
|
34
|
+
// cannot plant arbitrary restore payloads for managed resource types.
|
|
35
|
+
const serverSnapshot = registration?.getSnapshot
|
|
36
|
+
? await registration.getSnapshot({
|
|
37
|
+
resourceType: args.resourceType,
|
|
38
|
+
resourceId: args.resourceId,
|
|
39
|
+
ctx: actionCtx,
|
|
40
|
+
access,
|
|
41
|
+
})
|
|
42
|
+
: undefined;
|
|
33
43
|
const snapshot =
|
|
34
|
-
|
|
35
|
-
? args.snapshot
|
|
36
|
-
: await registration?.getSnapshot?.({
|
|
37
|
-
resourceType: args.resourceType,
|
|
38
|
-
resourceId: args.resourceId,
|
|
39
|
-
ctx: actionCtx,
|
|
40
|
-
access,
|
|
41
|
-
});
|
|
44
|
+
serverSnapshot !== undefined ? serverSnapshot : args.snapshot;
|
|
42
45
|
|
|
43
46
|
if (snapshot === undefined) {
|
|
44
47
|
throw new Error(
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ForbiddenError,
|
|
3
|
+
resolveAccess,
|
|
4
|
+
type AccessContext,
|
|
5
|
+
} from "../sharing/access.js";
|
|
2
6
|
import { getShareableResource } from "../sharing/registry.js";
|
|
3
7
|
import { roleSatisfies, type Visibility } from "../sharing/schema.js";
|
|
4
8
|
import type {
|
|
@@ -31,6 +35,16 @@ export function listVersionedResources(): VersionedResourceRegistration[] {
|
|
|
31
35
|
return Array.from(registrations.values());
|
|
32
36
|
}
|
|
33
37
|
|
|
38
|
+
function accessContextFrom(
|
|
39
|
+
ctx?: VersionedResourceContext,
|
|
40
|
+
): AccessContext | undefined {
|
|
41
|
+
if (!ctx) return undefined;
|
|
42
|
+
return {
|
|
43
|
+
userEmail: ctx.userEmail ?? undefined,
|
|
44
|
+
orgId: ctx.orgId ?? undefined,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
34
48
|
export async function resolveVersionedResourceAccess(
|
|
35
49
|
resourceType: string,
|
|
36
50
|
resourceId: string,
|
|
@@ -42,7 +56,11 @@ export async function resolveVersionedResourceAccess(
|
|
|
42
56
|
}
|
|
43
57
|
|
|
44
58
|
if (getShareableResource(resourceType)) {
|
|
45
|
-
const access = await resolveAccess(
|
|
59
|
+
const access = await resolveAccess(
|
|
60
|
+
resourceType,
|
|
61
|
+
resourceId,
|
|
62
|
+
accessContextFrom(ctx),
|
|
63
|
+
);
|
|
46
64
|
if (!access) {
|
|
47
65
|
return null;
|
|
48
66
|
}
|
|
@@ -55,16 +73,10 @@ export async function resolveVersionedResourceAccess(
|
|
|
55
73
|
};
|
|
56
74
|
}
|
|
57
75
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
role: "owner",
|
|
64
|
-
ownerEmail: userEmail,
|
|
65
|
-
orgId: ctx?.orgId ?? null,
|
|
66
|
-
visibility: "private",
|
|
67
|
-
};
|
|
76
|
+
// Fail closed: unregistered types, and registered types without an access
|
|
77
|
+
// resolver that aren't shareable, never invent ownership. bypassScope on
|
|
78
|
+
// history queries is only safe after a real resource ACL.
|
|
79
|
+
return null;
|
|
68
80
|
}
|
|
69
81
|
|
|
70
82
|
export async function assertVersionedResourceAccess(
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
getDbExec,
|
|
3
|
+
intType,
|
|
4
|
+
isPostgres,
|
|
5
|
+
isUniqueViolation,
|
|
6
|
+
} from "../db/client.js";
|
|
2
7
|
import { ensureIndexExists, ensureTableExists } from "../db/ddl-guard.js";
|
|
3
8
|
import type { Visibility } from "../sharing/schema.js";
|
|
4
9
|
import type {
|
|
@@ -9,6 +14,8 @@ import type {
|
|
|
9
14
|
|
|
10
15
|
let historyTableInitPromise: Promise<void> | undefined;
|
|
11
16
|
|
|
17
|
+
const VERSION_INSERT_MAX_ATTEMPTS = 8;
|
|
18
|
+
|
|
12
19
|
export interface InsertResourceVersionInput {
|
|
13
20
|
resourceType: string;
|
|
14
21
|
resourceId: string;
|
|
@@ -53,7 +60,7 @@ export async function ensureResourceVersionsTable(): Promise<void> {
|
|
|
53
60
|
metadata_json TEXT
|
|
54
61
|
)`;
|
|
55
62
|
const indexes = [
|
|
56
|
-
`CREATE INDEX IF NOT EXISTS
|
|
63
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_resource_versions_resource_number
|
|
57
64
|
ON agent_resource_versions (resource_type, resource_id, version_number)`,
|
|
58
65
|
`CREATE INDEX IF NOT EXISTS idx_agent_resource_versions_owner
|
|
59
66
|
ON agent_resource_versions (owner_email, created_at)`,
|
|
@@ -64,7 +71,7 @@ export async function ensureResourceVersionsTable(): Promise<void> {
|
|
|
64
71
|
if (isPostgres()) {
|
|
65
72
|
await ensureTableExists("agent_resource_versions", createSql);
|
|
66
73
|
await ensureIndexExists(
|
|
67
|
-
"
|
|
74
|
+
"idx_agent_resource_versions_resource_number",
|
|
68
75
|
indexes[0],
|
|
69
76
|
);
|
|
70
77
|
await ensureIndexExists(
|
|
@@ -89,41 +96,55 @@ export async function insertResourceVersion(
|
|
|
89
96
|
): Promise<ResourceVersion> {
|
|
90
97
|
await ensureResourceVersionsTable();
|
|
91
98
|
const client = getDbExec();
|
|
92
|
-
const
|
|
93
|
-
|
|
99
|
+
const visibility =
|
|
100
|
+
input.visibility === "org" || input.visibility === "public"
|
|
101
|
+
? input.visibility
|
|
102
|
+
: "private";
|
|
103
|
+
const actorKind = input.actorKind ?? "human";
|
|
104
|
+
const createdBy = input.createdBy ?? null;
|
|
105
|
+
const ownerEmail = input.ownerEmail ?? input.createdBy ?? null;
|
|
106
|
+
const orgId = input.orgId ?? null;
|
|
107
|
+
const title = input.title ?? null;
|
|
108
|
+
const summary = input.summary ?? null;
|
|
109
|
+
const metadata = input.metadata ?? null;
|
|
110
|
+
const snapshotJson = JSON.stringify(input.snapshot);
|
|
111
|
+
const metadataJson = stringifyOptionalJson(metadata);
|
|
112
|
+
|
|
113
|
+
let lastError: unknown;
|
|
114
|
+
for (let attempt = 0; attempt < VERSION_INSERT_MAX_ATTEMPTS; attempt++) {
|
|
115
|
+
const maxRows = await client.execute({
|
|
116
|
+
sql: `SELECT MAX(version_number) as max_version
|
|
94
117
|
FROM agent_resource_versions
|
|
95
118
|
WHERE resource_type = ? AND resource_id = ?`,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
snapshot: input.snapshot,
|
|
122
|
-
metadata: input.metadata ?? null,
|
|
123
|
-
};
|
|
119
|
+
args: [input.resourceType, input.resourceId],
|
|
120
|
+
});
|
|
121
|
+
const versionNumber =
|
|
122
|
+
Number(
|
|
123
|
+
(maxRows.rows?.[0] as Record<string, unknown> | undefined)
|
|
124
|
+
?.max_version ?? 0,
|
|
125
|
+
) + 1;
|
|
126
|
+
const id = createVersionId();
|
|
127
|
+
const createdAt = new Date().toISOString();
|
|
128
|
+
const version: ResourceVersion = {
|
|
129
|
+
id,
|
|
130
|
+
resourceType: input.resourceType,
|
|
131
|
+
resourceId: input.resourceId,
|
|
132
|
+
versionNumber,
|
|
133
|
+
createdAt,
|
|
134
|
+
createdBy,
|
|
135
|
+
actorKind,
|
|
136
|
+
ownerEmail,
|
|
137
|
+
orgId,
|
|
138
|
+
visibility,
|
|
139
|
+
title,
|
|
140
|
+
summary,
|
|
141
|
+
snapshot: input.snapshot,
|
|
142
|
+
metadata,
|
|
143
|
+
};
|
|
124
144
|
|
|
125
|
-
|
|
126
|
-
|
|
145
|
+
try {
|
|
146
|
+
await client.execute({
|
|
147
|
+
sql: `INSERT INTO agent_resource_versions (
|
|
127
148
|
id,
|
|
128
149
|
resource_type,
|
|
129
150
|
resource_id,
|
|
@@ -139,25 +160,35 @@ export async function insertResourceVersion(
|
|
|
139
160
|
snapshot_json,
|
|
140
161
|
metadata_json
|
|
141
162
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
163
|
+
args: [
|
|
164
|
+
version.id,
|
|
165
|
+
version.resourceType,
|
|
166
|
+
version.resourceId,
|
|
167
|
+
version.versionNumber,
|
|
168
|
+
version.createdAt,
|
|
169
|
+
version.createdBy,
|
|
170
|
+
version.actorKind,
|
|
171
|
+
version.ownerEmail,
|
|
172
|
+
version.orgId,
|
|
173
|
+
version.visibility,
|
|
174
|
+
version.title,
|
|
175
|
+
version.summary,
|
|
176
|
+
snapshotJson,
|
|
177
|
+
metadataJson,
|
|
178
|
+
],
|
|
179
|
+
});
|
|
180
|
+
return version;
|
|
181
|
+
} catch (error) {
|
|
182
|
+
lastError = error;
|
|
183
|
+
if (!isUniqueViolation(error)) {
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
159
188
|
|
|
160
|
-
|
|
189
|
+
throw lastError instanceof Error
|
|
190
|
+
? lastError
|
|
191
|
+
: new Error("Failed to allocate a unique resource version number");
|
|
161
192
|
}
|
|
162
193
|
|
|
163
194
|
export async function queryResourceVersions(
|