@agent-native/dispatch 0.7.0 → 0.8.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/README.md +37 -0
- package/dist/actions/apply-dream-proposal.d.ts +3 -0
- package/dist/actions/apply-dream-proposal.d.ts.map +1 -0
- package/dist/actions/apply-dream-proposal.js +11 -0
- package/dist/actions/apply-dream-proposal.js.map +1 -0
- package/dist/actions/create-dream-report.d.ts +3 -0
- package/dist/actions/create-dream-report.d.ts.map +1 -0
- package/dist/actions/create-dream-report.js +67 -0
- package/dist/actions/create-dream-report.js.map +1 -0
- package/dist/actions/create-workspace-resource.js +3 -3
- package/dist/actions/create-workspace-resource.js.map +1 -1
- package/dist/actions/delete-workspace-resource.js +1 -1
- package/dist/actions/delete-workspace-resource.js.map +1 -1
- package/dist/actions/ensure-dream-job.d.ts +3 -0
- package/dist/actions/ensure-dream-job.d.ts.map +1 -0
- package/dist/actions/ensure-dream-job.js +73 -0
- package/dist/actions/ensure-dream-job.js.map +1 -0
- package/dist/actions/get-dream-settings.d.ts +3 -0
- package/dist/actions/get-dream-settings.d.ts.map +1 -0
- package/dist/actions/get-dream-settings.js +11 -0
- package/dist/actions/get-dream-settings.js.map +1 -0
- package/dist/actions/get-dream.d.ts +3 -0
- package/dist/actions/get-dream.d.ts.map +1 -0
- package/dist/actions/get-dream.js +13 -0
- package/dist/actions/get-dream.js.map +1 -0
- package/dist/actions/get-workspace-resource-effective-context.d.ts +3 -0
- package/dist/actions/get-workspace-resource-effective-context.d.ts.map +1 -0
- package/dist/actions/get-workspace-resource-effective-context.js +27 -0
- package/dist/actions/get-workspace-resource-effective-context.js.map +1 -0
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +30 -4
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/list-dream-candidates.d.ts +3 -0
- package/dist/actions/list-dream-candidates.d.ts.map +1 -0
- package/dist/actions/list-dream-candidates.js +68 -0
- package/dist/actions/list-dream-candidates.js.map +1 -0
- package/dist/actions/list-dreams.d.ts +3 -0
- package/dist/actions/list-dreams.d.ts.map +1 -0
- package/dist/actions/list-dreams.js +17 -0
- package/dist/actions/list-dreams.js.map +1 -0
- package/dist/actions/list-workspace-resources-for-app.d.ts +3 -0
- package/dist/actions/list-workspace-resources-for-app.d.ts.map +1 -0
- package/dist/actions/list-workspace-resources-for-app.js +12 -0
- package/dist/actions/list-workspace-resources-for-app.js.map +1 -0
- package/dist/actions/list-workspace-resources.js +1 -1
- package/dist/actions/list-workspace-resources.js.map +1 -1
- package/dist/actions/navigate.d.ts +1 -0
- package/dist/actions/navigate.d.ts.map +1 -1
- package/dist/actions/navigate.js +2 -1
- package/dist/actions/navigate.js.map +1 -1
- package/dist/actions/preview-dream-proposal.d.ts +3 -0
- package/dist/actions/preview-dream-proposal.d.ts.map +1 -0
- package/dist/actions/preview-dream-proposal.js +13 -0
- package/dist/actions/preview-dream-proposal.js.map +1 -0
- package/dist/actions/preview-workspace-resource-change.d.ts +3 -0
- package/dist/actions/preview-workspace-resource-change.d.ts.map +1 -0
- package/dist/actions/preview-workspace-resource-change.js +24 -0
- package/dist/actions/preview-workspace-resource-change.js.map +1 -0
- package/dist/actions/reject-dream-proposal.d.ts +3 -0
- package/dist/actions/reject-dream-proposal.d.ts.map +1 -0
- package/dist/actions/reject-dream-proposal.js +12 -0
- package/dist/actions/reject-dream-proposal.js.map +1 -0
- package/dist/actions/restore-starter-workspace-resources.d.ts +3 -0
- package/dist/actions/restore-starter-workspace-resources.d.ts.map +1 -0
- package/dist/actions/restore-starter-workspace-resources.js +14 -0
- package/dist/actions/restore-starter-workspace-resources.js.map +1 -0
- package/dist/actions/send-code-agent-remote-command.d.ts +3 -0
- package/dist/actions/send-code-agent-remote-command.d.ts.map +1 -0
- package/dist/actions/send-code-agent-remote-command.js +53 -0
- package/dist/actions/send-code-agent-remote-command.js.map +1 -0
- package/dist/actions/set-dream-settings.d.ts +3 -0
- package/dist/actions/set-dream-settings.d.ts.map +1 -0
- package/dist/actions/set-dream-settings.js +41 -0
- package/dist/actions/set-dream-settings.js.map +1 -0
- package/dist/actions/update-workspace-resource.js +1 -1
- package/dist/actions/update-workspace-resource.js.map +1 -1
- package/dist/actions/view-screen.d.ts.map +1 -1
- package/dist/actions/view-screen.js +73 -2
- package/dist/actions/view-screen.js.map +1 -1
- package/dist/components/approval-value-block.d.ts +7 -0
- package/dist/components/approval-value-block.d.ts.map +1 -0
- package/dist/components/approval-value-block.js +22 -0
- package/dist/components/approval-value-block.js.map +1 -0
- package/dist/components/create-app-popover.d.ts.map +1 -1
- package/dist/components/create-app-popover.js +3 -2
- package/dist/components/create-app-popover.js.map +1 -1
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +8 -1
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/ui/chart.d.ts +1 -1
- package/dist/components/workspace-app-card.d.ts.map +1 -1
- package/dist/components/workspace-app-card.js +25 -4
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/components/workspace-resource-effective-stack.d.ts +11 -0
- package/dist/components/workspace-resource-effective-stack.d.ts.map +1 -0
- package/dist/components/workspace-resource-effective-stack.js +59 -0
- package/dist/components/workspace-resource-effective-stack.js.map +1 -0
- package/dist/components/workspace-resource-impact-preview.d.ts +9 -0
- package/dist/components/workspace-resource-impact-preview.d.ts.map +1 -0
- package/dist/components/workspace-resource-impact-preview.js +39 -0
- package/dist/components/workspace-resource-impact-preview.js.map +1 -0
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +59 -0
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/schema.d.ts +714 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +44 -2
- package/dist/db/schema.js.map +1 -1
- package/dist/hooks/use-navigation-state.d.ts +3 -0
- package/dist/hooks/use-navigation-state.d.ts.map +1 -1
- package/dist/hooks/use-navigation-state.js +23 -3
- package/dist/hooks/use-navigation-state.js.map +1 -1
- package/dist/lib/utils.d.ts +2 -1
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +5 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +1 -0
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/pages/approval.d.ts.map +1 -1
- package/dist/routes/pages/approval.js +4 -1
- package/dist/routes/pages/approval.js.map +1 -1
- package/dist/routes/pages/approvals.js +1 -1
- package/dist/routes/pages/approvals.js.map +1 -1
- package/dist/routes/pages/dream-settings.d.ts +34 -0
- package/dist/routes/pages/dream-settings.d.ts.map +1 -0
- package/dist/routes/pages/dream-settings.js +68 -0
- package/dist/routes/pages/dream-settings.js.map +1 -0
- package/dist/routes/pages/dreams.d.ts +5 -0
- package/dist/routes/pages/dreams.d.ts.map +1 -0
- package/dist/routes/pages/dreams.js +435 -0
- package/dist/routes/pages/dreams.js.map +1 -0
- package/dist/routes/pages/workspace.d.ts.map +1 -1
- package/dist/routes/pages/workspace.js +187 -35
- package/dist/routes/pages/workspace.js.map +1 -1
- package/dist/server/lib/app-creation-store.d.ts.map +1 -1
- package/dist/server/lib/app-creation-store.js +3 -2
- package/dist/server/lib/app-creation-store.js.map +1 -1
- package/dist/server/lib/dispatch-integrations.d.ts +1 -1
- package/dist/server/lib/dispatch-integrations.d.ts.map +1 -1
- package/dist/server/lib/dispatch-integrations.js +9 -4
- package/dist/server/lib/dispatch-integrations.js.map +1 -1
- package/dist/server/lib/dispatch-remote-commands.d.ts +83 -0
- package/dist/server/lib/dispatch-remote-commands.d.ts.map +1 -0
- package/dist/server/lib/dispatch-remote-commands.js +256 -0
- package/dist/server/lib/dispatch-remote-commands.js.map +1 -0
- package/dist/server/lib/dispatch-store.d.ts +26 -0
- package/dist/server/lib/dispatch-store.d.ts.map +1 -1
- package/dist/server/lib/dispatch-store.js +17 -1
- package/dist/server/lib/dispatch-store.js.map +1 -1
- package/dist/server/lib/dreams-store.d.ts +398 -0
- package/dist/server/lib/dreams-store.d.ts.map +1 -0
- package/dist/server/lib/dreams-store.js +2330 -0
- package/dist/server/lib/dreams-store.js.map +1 -0
- package/dist/server/lib/thread-debug-store.d.ts +2 -2
- package/dist/server/lib/vault-store.d.ts +1 -1
- package/dist/server/lib/workspace-resources-store.d.ts +181 -17
- package/dist/server/lib/workspace-resources-store.d.ts.map +1 -1
- package/dist/server/lib/workspace-resources-store.js +737 -108
- package/dist/server/lib/workspace-resources-store.js.map +1 -1
- package/package.json +4 -2
- package/src/actions/apply-dream-proposal.ts +12 -0
- package/src/actions/create-dream-report.ts +76 -0
- package/src/actions/create-workspace-resource.ts +3 -3
- package/src/actions/delete-workspace-resource.ts +1 -1
- package/src/actions/ensure-dream-job.ts +76 -0
- package/src/actions/get-dream-settings.ts +12 -0
- package/src/actions/get-dream.ts +14 -0
- package/src/actions/get-workspace-resource-effective-context.ts +34 -0
- package/src/actions/index.spec.ts +26 -0
- package/src/actions/index.ts +31 -4
- package/src/actions/list-dream-candidates.ts +77 -0
- package/src/actions/list-dreams.ts +17 -0
- package/src/actions/list-workspace-resources-for-app.ts +13 -0
- package/src/actions/list-workspace-resources.ts +1 -1
- package/src/actions/navigate.ts +2 -1
- package/src/actions/preview-dream-proposal.ts +14 -0
- package/src/actions/preview-workspace-resource-change.ts +25 -0
- package/src/actions/reject-dream-proposal.ts +12 -0
- package/src/actions/restore-starter-workspace-resources.ts +17 -0
- package/src/actions/send-code-agent-remote-command.ts +59 -0
- package/src/actions/set-dream-settings.spec.ts +81 -0
- package/src/actions/set-dream-settings.ts +44 -0
- package/src/actions/update-workspace-resource.ts +1 -1
- package/src/actions/view-screen.ts +90 -2
- package/src/components/approval-value-block.spec.tsx +59 -0
- package/src/components/approval-value-block.tsx +33 -0
- package/src/components/create-app-popover.tsx +3 -2
- package/src/components/layout/Layout.tsx +8 -0
- package/src/components/workspace-app-card.tsx +166 -1
- package/src/components/workspace-resource-effective-stack.spec.tsx +125 -0
- package/src/components/workspace-resource-effective-stack.tsx +141 -0
- package/src/components/workspace-resource-impact-preview.spec.tsx +147 -0
- package/src/components/workspace-resource-impact-preview.tsx +116 -0
- package/src/db/migrations.ts +59 -0
- package/src/db/schema.ts +46 -2
- package/src/hooks/use-navigation-state.ts +24 -5
- package/src/lib/utils.ts +6 -1
- package/src/routes/index.ts +1 -0
- package/src/routes/pages/approval.tsx +14 -1
- package/src/routes/pages/approvals.tsx +1 -1
- package/src/routes/pages/dream-settings.spec.ts +130 -0
- package/src/routes/pages/dream-settings.ts +103 -0
- package/src/routes/pages/dreams.tsx +1828 -0
- package/src/routes/pages/workspace.tsx +577 -97
- package/src/server/lib/app-creation-store.ts +3 -2
- package/src/server/lib/dispatch-integrations.ts +10 -3
- package/src/server/lib/dispatch-remote-commands.spec.ts +167 -0
- package/src/server/lib/dispatch-remote-commands.ts +375 -0
- package/src/server/lib/dispatch-store.ts +37 -1
- package/src/server/lib/dreams-store.spec.ts +1492 -0
- package/src/server/lib/dreams-store.ts +3168 -0
- package/src/server/lib/workspace-resource-approval-lifecycle.spec.ts +236 -0
- package/src/server/lib/workspace-resources-store.spec.ts +1106 -0
- package/src/server/lib/workspace-resources-store.ts +1001 -134
- package/dist/actions/sync-workspace-resources-to-all.d.ts +0 -3
- package/dist/actions/sync-workspace-resources-to-all.d.ts.map +0 -1
- package/dist/actions/sync-workspace-resources-to-all.js +0 -9
- package/dist/actions/sync-workspace-resources-to-all.js.map +0 -1
- package/dist/actions/sync-workspace-resources-to-app.d.ts +0 -3
- package/dist/actions/sync-workspace-resources-to-app.d.ts.map +0 -1
- package/dist/actions/sync-workspace-resources-to-app.js +0 -11
- package/dist/actions/sync-workspace-resources-to-app.js.map +0 -1
- package/src/actions/sync-workspace-resources-to-all.ts +0 -10
- package/src/actions/sync-workspace-resources-to-app.ts +0 -12
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from "react";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
3
|
import { useActionMutation, useActionQuery } from "@agent-native/core/client";
|
|
4
4
|
import { toast } from "sonner";
|
|
5
|
-
import { IconBook, IconChevronDown, IconChevronRight, IconCode, IconFileText, IconPlus,
|
|
5
|
+
import { IconAlertCircle, IconBook, IconChevronDown, IconChevronRight, IconCircleCheck, IconCode, IconEdit, IconFileText, IconPlus, IconTrash, IconUser, IconX, } from "@tabler/icons-react";
|
|
6
6
|
import { DispatchShell } from "../../components/dispatch-shell.js";
|
|
7
|
+
import { ImpactPreview, workspaceResourceMutationMessage, } from "../../components/workspace-resource-impact-preview.js";
|
|
7
8
|
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "../../components/ui/alert-dialog.js";
|
|
8
9
|
import { Badge } from "../../components/ui/badge.js";
|
|
9
10
|
import { Button } from "../../components/ui/button.js";
|
|
@@ -22,27 +23,150 @@ const KIND_CONFIG = {
|
|
|
22
23
|
label: "Skill",
|
|
23
24
|
icon: IconCode,
|
|
24
25
|
pathPrefix: "skills/",
|
|
25
|
-
description: "Agent skills
|
|
26
|
+
description: "Agent skills - on-demand guidance available across workspace apps",
|
|
26
27
|
},
|
|
27
28
|
instruction: {
|
|
28
29
|
label: "Instruction",
|
|
29
30
|
icon: IconBook,
|
|
30
|
-
pathPrefix: "",
|
|
31
|
-
description: "
|
|
31
|
+
pathPrefix: "instructions/",
|
|
32
|
+
description: "Global instructions - guardrails loaded by every app agent",
|
|
32
33
|
},
|
|
33
34
|
agent: {
|
|
34
35
|
label: "Agent",
|
|
35
36
|
icon: IconUser,
|
|
36
37
|
pathPrefix: "agents/",
|
|
37
|
-
description: "Reusable agent profiles
|
|
38
|
+
description: "Reusable agent profiles - specialist agents shared across apps",
|
|
38
39
|
},
|
|
39
40
|
knowledge: {
|
|
40
41
|
label: "Knowledge",
|
|
41
42
|
icon: IconFileText,
|
|
42
43
|
pathPrefix: "context/",
|
|
43
|
-
description: "
|
|
44
|
+
description: "Reference resources - brand, positioning, persona, and domain context",
|
|
44
45
|
},
|
|
45
46
|
};
|
|
47
|
+
const STARTER_GLOBAL_CONTEXT = [
|
|
48
|
+
{
|
|
49
|
+
path: "context/company.md",
|
|
50
|
+
label: "Company",
|
|
51
|
+
kind: "knowledge",
|
|
52
|
+
description: "Company facts, ICP, products, and canonical links",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
path: "context/brand.md",
|
|
56
|
+
label: "Brand",
|
|
57
|
+
kind: "knowledge",
|
|
58
|
+
description: "Voice, visual identity, naming, and style rules",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
path: "context/messaging.md",
|
|
62
|
+
label: "Messaging",
|
|
63
|
+
kind: "knowledge",
|
|
64
|
+
description: "Positioning, value props, proof points, and objections",
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
path: "instructions/guardrails.md",
|
|
68
|
+
label: "Guardrails",
|
|
69
|
+
kind: "instruction",
|
|
70
|
+
description: "Always-on rules loaded by every app agent",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
path: "skills/company-voice/SKILL.md",
|
|
74
|
+
label: "Company Voice",
|
|
75
|
+
kind: "skill",
|
|
76
|
+
description: "On-demand guidance for customer-facing writing",
|
|
77
|
+
},
|
|
78
|
+
];
|
|
79
|
+
function resourceSlug(value) {
|
|
80
|
+
return value
|
|
81
|
+
.toLowerCase()
|
|
82
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
83
|
+
.replace(/^-+|-+$/g, "");
|
|
84
|
+
}
|
|
85
|
+
function defaultResourcePath(kind, name) {
|
|
86
|
+
const slug = resourceSlug(name) || "example";
|
|
87
|
+
if (kind === "skill")
|
|
88
|
+
return `skills/${slug}/SKILL.md`;
|
|
89
|
+
if (kind === "instruction")
|
|
90
|
+
return `instructions/${slug}.md`;
|
|
91
|
+
if (kind === "agent")
|
|
92
|
+
return `agents/${slug}.md`;
|
|
93
|
+
if (kind === "knowledge")
|
|
94
|
+
return `context/${slug}.md`;
|
|
95
|
+
return `${slug}.md`;
|
|
96
|
+
}
|
|
97
|
+
function isAutoLoadedInstruction(resource) {
|
|
98
|
+
return (resource.kind === "instruction" &&
|
|
99
|
+
(resource.path === "AGENTS.md" ||
|
|
100
|
+
String(resource.path).startsWith("instructions/")));
|
|
101
|
+
}
|
|
102
|
+
function formatTimestamp(value) {
|
|
103
|
+
if (!value)
|
|
104
|
+
return "Not present";
|
|
105
|
+
return new Date(value).toLocaleString();
|
|
106
|
+
}
|
|
107
|
+
function availabilityLabel(value) {
|
|
108
|
+
switch (value) {
|
|
109
|
+
case "all-apps":
|
|
110
|
+
return "Inherited by all apps";
|
|
111
|
+
case "selected-granted":
|
|
112
|
+
return "Granted to selected app";
|
|
113
|
+
case "selected-not-granted":
|
|
114
|
+
return "Not granted to this app";
|
|
115
|
+
case "selected-no-app":
|
|
116
|
+
return "Select an app to check grant";
|
|
117
|
+
case "path-not-managed":
|
|
118
|
+
return "Path is not a Dispatch resource";
|
|
119
|
+
default:
|
|
120
|
+
return "Checking availability";
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function layerState(layer) {
|
|
124
|
+
if (layer.effective) {
|
|
125
|
+
return {
|
|
126
|
+
label: "Active",
|
|
127
|
+
className: "border-green-500/30 bg-green-500/10 text-green-700",
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (layer.overridden) {
|
|
131
|
+
return {
|
|
132
|
+
label: "Overridden",
|
|
133
|
+
className: "border-amber-500/30 bg-amber-500/10 text-amber-700",
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
label: "Missing",
|
|
138
|
+
className: "text-muted-foreground",
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function EditResourceDialog({ resource, trigger, }) {
|
|
142
|
+
const [open, setOpen] = useState(false);
|
|
143
|
+
const [name, setName] = useState(resource.name || "");
|
|
144
|
+
const [description, setDescription] = useState(resource.description || "");
|
|
145
|
+
const [content, setContent] = useState(resource.content || "");
|
|
146
|
+
const [scope, setScope] = useState(resource.scope || "all");
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
if (!open)
|
|
149
|
+
return;
|
|
150
|
+
setName(resource.name || "");
|
|
151
|
+
setDescription(resource.description || "");
|
|
152
|
+
setContent(resource.content || "");
|
|
153
|
+
setScope(resource.scope || "all");
|
|
154
|
+
}, [open, resource]);
|
|
155
|
+
const update = useActionMutation("update-workspace-resource", {
|
|
156
|
+
onSuccess: (result) => {
|
|
157
|
+
toast.success(workspaceResourceMutationMessage(result, "Resource updated"));
|
|
158
|
+
setOpen(false);
|
|
159
|
+
},
|
|
160
|
+
onError: (err) => toast.error(String(err)),
|
|
161
|
+
});
|
|
162
|
+
return (_jsxs(Dialog, { open: open, onOpenChange: setOpen, children: [_jsx(DialogTrigger, { asChild: true, children: trigger || (_jsxs(Button, { variant: "outline", size: "sm", children: [_jsx(IconEdit, { size: 14, className: "mr-1.5" }), "Edit"] })) }), _jsxs(DialogContent, { className: "max-w-2xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Edit workspace resource" }), _jsx(DialogDescription, { children: "Updates apply immediately anywhere this workspace resource is inherited. App shared or personal resources can override it locally." })] }), _jsxs("div", { className: "space-y-4 py-2", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Name" }), _jsx(Input, { value: name, onChange: (e) => setName(e.target.value) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Scope" }), _jsxs(Select, { value: scope, onValueChange: setScope, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: "All apps" }), _jsx(SelectItem, { value: "selected", children: "Selected apps only" })] })] })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Path" }), _jsx(Input, { value: resource.path, disabled: true, className: "font-mono text-sm" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Description" }), _jsx(Input, { value: description, onChange: (e) => setDescription(e.target.value) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Content" }), _jsx(Textarea, { value: content, onChange: (e) => setContent(e.target.value), rows: 14, className: "font-mono text-sm" })] }), _jsx(ImpactPreview, { operation: "update", resourceId: resource.id, scope: scope, enabled: open })] }), _jsx(DialogFooter, { children: _jsx(Button, { onClick: () => update.mutate({
|
|
163
|
+
id: resource.id,
|
|
164
|
+
name,
|
|
165
|
+
description,
|
|
166
|
+
content,
|
|
167
|
+
scope: scope,
|
|
168
|
+
}), disabled: !name.trim() || update.isPending, children: update.isPending ? "Saving..." : "Save changes" }) })] })] }));
|
|
169
|
+
}
|
|
46
170
|
function AddResourceDialog() {
|
|
47
171
|
const [open, setOpen] = useState(false);
|
|
48
172
|
const [kind, setKind] = useState("skill");
|
|
@@ -52,8 +176,8 @@ function AddResourceDialog() {
|
|
|
52
176
|
const [content, setContent] = useState("");
|
|
53
177
|
const [scope, setScope] = useState("all");
|
|
54
178
|
const create = useActionMutation("create-workspace-resource", {
|
|
55
|
-
onSuccess: () => {
|
|
56
|
-
toast.success("Resource created");
|
|
179
|
+
onSuccess: (result) => {
|
|
180
|
+
toast.success(workspaceResourceMutationMessage(result, "Resource created"));
|
|
57
181
|
setOpen(false);
|
|
58
182
|
setKind("skill");
|
|
59
183
|
setName("");
|
|
@@ -64,25 +188,23 @@ function AddResourceDialog() {
|
|
|
64
188
|
},
|
|
65
189
|
onError: (err) => toast.error(String(err)),
|
|
66
190
|
});
|
|
67
|
-
|
|
68
|
-
return (_jsxs(Dialog, { open: open, onOpenChange: setOpen, children: [_jsx(DialogTrigger, { asChild: true, children: _jsxs(Button, { children: [_jsx(IconPlus, { size: 16, className: "mr-1.5" }), "Add resource"] }) }), _jsxs(DialogContent, { className: "max-w-2xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Add workspace resource" }), _jsx(DialogDescription, { children: "Create a skill, instruction, or agent profile that can be shared across workspace apps." })] }), _jsxs("div", { className: "space-y-4 py-2", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Kind" }), _jsxs(Select, { value: kind, onValueChange: setKind, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "skill", children: "Skill" }), _jsx(SelectItem, { value: "instruction", children: "Instruction" }), _jsx(SelectItem, { value: "agent", children: "Agent" }), _jsx(SelectItem, { value: "knowledge", children: "Knowledge pack" })] })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Scope" }), _jsxs(Select, { value: scope, onValueChange: setScope, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: "All apps" }), _jsx(SelectItem, { value: "selected", children: "Selected apps only" })] })] })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Name" }), _jsx(Input, { placeholder: kind === "skill"
|
|
191
|
+
return (_jsxs(Dialog, { open: open, onOpenChange: setOpen, children: [_jsx(DialogTrigger, { asChild: true, children: _jsxs(Button, { children: [_jsx(IconPlus, { size: 16, className: "mr-1.5" }), "Add resource"] }) }), _jsxs(DialogContent, { className: "max-w-2xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Add workspace resource" }), _jsx(DialogDescription, { children: "Create a skill, instruction, agent profile, or reference resource that can be shared across workspace apps." })] }), _jsxs("div", { className: "space-y-4 py-2", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Kind" }), _jsxs(Select, { value: kind, onValueChange: setKind, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "skill", children: "Skill" }), _jsx(SelectItem, { value: "instruction", children: "Instruction" }), _jsx(SelectItem, { value: "agent", children: "Agent" }), _jsx(SelectItem, { value: "knowledge", children: "Knowledge pack" })] })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Scope" }), _jsxs(Select, { value: scope, onValueChange: setScope, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: "All apps" }), _jsx(SelectItem, { value: "selected", children: "Selected apps only" })] })] })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Name" }), _jsx(Input, { placeholder: kind === "skill"
|
|
69
192
|
? "Frontend Designer"
|
|
70
193
|
: kind === "agent"
|
|
71
194
|
? "Research Specialist"
|
|
72
195
|
: kind === "knowledge"
|
|
73
196
|
? "Core GTM Messaging"
|
|
74
|
-
: "Code Style Guide", value: name, onChange: (e) => setName(e.target.value) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Path" }), _jsx(Input, { placeholder:
|
|
197
|
+
: "Code Style Guide", value: name, onChange: (e) => setName(e.target.value) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Path" }), _jsx(Input, { placeholder: defaultResourcePath(kind, name), value: path, onChange: (e) => setPath(e.target.value), className: "font-mono text-sm" }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Skills use skills/name/SKILL.md. Guardrails in AGENTS.md or instructions/ auto-load in app chat. Reference resources in context/ are indexed so agents can read them when relevant." })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Description (optional)" }), _jsx(Input, { placeholder: "Short description of what this resource does", value: description, onChange: (e) => setDescription(e.target.value) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Content" }), _jsx(Textarea, { placeholder: kind === "skill"
|
|
75
198
|
? "---\nname: my-skill\ndescription: What this skill teaches\n---\n\n# My Skill\n\n..."
|
|
76
199
|
: kind === "agent"
|
|
77
200
|
? "---\nname: Research Specialist\ndescription: Handles research tasks\n---\n\n# Instructions\n\n..."
|
|
78
201
|
: kind === "knowledge"
|
|
79
202
|
? "# Core GTM Messaging\n\n## Positioning\n\n## ICP\n\n## Proof points\n\n## Source\n\n"
|
|
80
|
-
: "# Instructions\n\
|
|
203
|
+
: "# Instructions\n\nAlways-on guardrails for agents across apps...", value: content, onChange: (e) => setContent(e.target.value), rows: 12, className: "font-mono text-sm" })] }), _jsx(ImpactPreview, { operation: "create", path: path || defaultResourcePath(kind, name), scope: scope, enabled: open && Boolean(name.trim()) })] }), _jsx(DialogFooter, { children: _jsx(Button, { onClick: () => create.mutate({
|
|
81
204
|
kind: kind,
|
|
82
205
|
name,
|
|
83
206
|
description: description || undefined,
|
|
84
|
-
path: path ||
|
|
85
|
-
`${kindInfo?.pathPrefix || ""}${name.toLowerCase().replace(/\s+/g, "-")}.md`,
|
|
207
|
+
path: path || defaultResourcePath(kind, name),
|
|
86
208
|
content,
|
|
87
209
|
scope: scope,
|
|
88
210
|
}), disabled: !name || !content || create.isPending, children: create.isPending ? "Creating..." : "Create resource" }) })] })] }));
|
|
@@ -105,39 +227,69 @@ function GrantDialog({ resourceId, resourceName, }) {
|
|
|
105
227
|
}));
|
|
106
228
|
return (_jsxs(Dialog, { open: open, onOpenChange: setOpen, children: [_jsx(DialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", children: [_jsx(IconPlus, { size: 14, className: "mr-1" }), "Grant"] }) }), _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsxs(DialogTitle, { children: ["Grant \"", resourceName, "\" to an app"] }), _jsx(DialogDescription, { children: "Choose which app should receive this resource." })] }), _jsx("div", { className: "py-2", children: _jsxs(Select, { value: appId, onValueChange: setAppId, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Select an app..." }) }), _jsx(SelectContent, { children: apps.map((app) => (_jsx(SelectItem, { value: app.id, children: app.name }, app.id))) })] }) }), _jsx(DialogFooter, { children: _jsx(Button, { onClick: () => grant.mutate({ resourceId, appId }), disabled: !appId || grant.isPending, children: grant.isPending ? "Granting..." : "Grant access" }) })] })] }));
|
|
107
229
|
}
|
|
230
|
+
function EffectiveContextPreview({ resource }) {
|
|
231
|
+
const [appId, setAppId] = useState("__any__");
|
|
232
|
+
const [userEmail, setUserEmail] = useState("");
|
|
233
|
+
const selectedAppId = appId === "__any__" ? undefined : appId;
|
|
234
|
+
const normalizedUserEmail = userEmail.trim() || undefined;
|
|
235
|
+
const { data: apps } = useActionQuery("list-workspace-apps", {
|
|
236
|
+
includeAgentCards: false,
|
|
237
|
+
});
|
|
238
|
+
const { data: context, isLoading } = useActionQuery("get-workspace-resource-effective-context", {
|
|
239
|
+
resourceId: resource.id,
|
|
240
|
+
appId: selectedAppId,
|
|
241
|
+
userEmail: normalizedUserEmail,
|
|
242
|
+
});
|
|
243
|
+
const visibleApps = (apps || []).filter((app) => !app.isDispatch && app.status !== "pending");
|
|
244
|
+
const layers = (context?.layers || []);
|
|
245
|
+
const active = context?.effectiveResource;
|
|
246
|
+
const availability = context?.availability;
|
|
247
|
+
return (_jsxs("div", { className: "rounded-lg border bg-background p-3", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("h4", { className: "text-xs font-semibold uppercase text-muted-foreground", children: "Effective in app" }), _jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: "Preview the runtime stack for this path: workspace default, organization/app override, then personal override." })] }), _jsx(Badge, { variant: "outline", children: availabilityLabel(availability) })] }), _jsxs("div", { className: "mt-3 grid gap-3 md:grid-cols-2", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: `resource-app-${resource.id}`, children: "App" }), _jsxs(Select, { value: appId, onValueChange: setAppId, children: [_jsx(SelectTrigger, { id: `resource-app-${resource.id}`, children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "__any__", children: "Any app" }), visibleApps.map((app) => (_jsx(SelectItem, { value: app.id, children: app.name }, app.id)))] })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: `resource-user-${resource.id}`, children: "User email" }), _jsx(Input, { id: `resource-user-${resource.id}`, value: userEmail, onChange: (event) => setUserEmail(event.target.value), placeholder: "Current Dispatch user" })] })] }), resource.scope === "selected" ? (_jsx("div", { className: "mt-3 rounded-md border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-xs leading-relaxed text-amber-800 dark:text-amber-200", children: "Selected resources are app-specific exceptions. Use All apps for company-wide context that should be inherited everywhere without copy or sync." })) : null, isLoading ? (_jsx("div", { className: "mt-3 grid gap-2 md:grid-cols-3", children: Array.from({ length: 3 }).map((_, index) => (_jsx(Skeleton, { className: "h-28 rounded-lg" }, index))) })) : (_jsx("div", { className: "mt-3 grid gap-2 md:grid-cols-3", children: layers.map((layer) => {
|
|
248
|
+
const state = layerState(layer);
|
|
249
|
+
return (_jsxs("div", { className: "rounded-lg border p-3", children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsx("span", { className: "text-sm font-medium text-foreground", children: layer.label }), _jsx(Badge, { variant: "outline", className: state.className, children: state.label })] }), _jsx("div", { className: "mt-2 truncate font-mono text-[11px] text-muted-foreground", children: layer.owner }), layer.resource ? (_jsxs("div", { className: "mt-2 space-y-1 text-xs text-muted-foreground", children: [_jsx("div", { className: "truncate font-mono", children: layer.resource.path }), _jsx("div", { children: formatTimestamp(layer.resource.updatedAt) })] })) : (_jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: "No resource exists at this layer." }))] }, layer.scope));
|
|
250
|
+
}) })), _jsx("div", { className: "mt-3 rounded-md bg-muted/40 px-3 py-2 text-xs text-muted-foreground", children: active ? (_jsxs(_Fragment, { children: ["Active file:", " ", _jsxs("span", { className: "font-mono text-foreground", children: [active.owner, "/", active.path] })] })) : ("No active resource exists for this path yet.") })] }));
|
|
251
|
+
}
|
|
108
252
|
function ResourceRow({ resource, grants }) {
|
|
109
253
|
const [expanded, setExpanded] = useState(false);
|
|
110
254
|
const deleteResource = useActionMutation("delete-workspace-resource", {
|
|
111
|
-
onSuccess: () => toast.success("Resource deleted"),
|
|
255
|
+
onSuccess: (result) => toast.success(workspaceResourceMutationMessage(result, "Resource deleted")),
|
|
112
256
|
onError: (err) => toast.error(String(err)),
|
|
113
257
|
});
|
|
114
258
|
const revokeGrant = useActionMutation("revoke-workspace-resource-grant", {
|
|
115
259
|
onSuccess: () => toast.success("Grant revoked"),
|
|
116
260
|
onError: (err) => toast.error(String(err)),
|
|
117
261
|
});
|
|
118
|
-
const syncToApp = useActionMutation("sync-workspace-resources-to-app", {
|
|
119
|
-
onSuccess: (data) => toast.success(`Synced ${data.synced} resource(s) to ${data.appId}`),
|
|
120
|
-
onError: (err) => toast.error(String(err)),
|
|
121
|
-
});
|
|
122
262
|
const kindInfo = KIND_CONFIG[resource.kind];
|
|
123
263
|
const KindIcon = kindInfo?.icon || IconCode;
|
|
124
264
|
const activeGrants = grants.filter((g) => g.status === "active");
|
|
125
|
-
return (_jsxs("div", { className: "rounded-
|
|
265
|
+
return (_jsxs("div", { className: "rounded-lg border bg-card", children: [_jsxs("button", { type: "button", className: "flex w-full items-center gap-3 px-4 py-3 text-left cursor-pointer", onClick: () => setExpanded(!expanded), children: [expanded ? (_jsx(IconChevronDown, { size: 16, className: "text-muted-foreground" })) : (_jsx(IconChevronRight, { size: 16, className: "text-muted-foreground" })), _jsx(KindIcon, { size: 16, className: "text-muted-foreground" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm font-medium text-foreground", children: resource.name }), _jsx(Badge, { variant: "secondary", className: "text-xs", children: kindInfo?.label || resource.kind }), _jsx(Badge, { variant: "outline", className: resource.scope === "all"
|
|
126
266
|
? "text-xs bg-green-500/10 text-green-700 dark:text-green-400"
|
|
127
|
-
: "text-xs", children: resource.scope === "all" ? "All apps" : "Selected" })] }), _jsx("div", { className: "mt-0.5 font-mono text-xs text-muted-foreground", children: resource.path })] }), _jsx("div", { className: "flex items-center gap-2", children: resource.scope === "selected" && (_jsxs(Badge, { variant: "outline", className: "text-xs", children: [activeGrants.length, " grant", activeGrants.length !== 1 ? "s" : ""] })) })] }), expanded && (_jsxs("div", { className: "border-t px-4 py-3 space-y-3", children: [resource.description && (_jsx("p", { className: "text-sm text-muted-foreground", children: resource.description })), _jsx("div", { className: "rounded-lg border bg-muted/30 p-3", children: _jsx("pre", { className: "whitespace-pre-wrap text-xs font-mono text-foreground max-h-64 overflow-y-auto", children: resource.content }) }), resource.scope === "selected" && (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-xs font-medium text-foreground", children: "Grants" }), _jsx(GrantDialog, { resourceId: resource.id, resourceName: resource.name })] }), activeGrants.length > 0 ? (_jsx("div", { className: "space-y-1.5", children: activeGrants.map((grant) => (_jsxs("div", { className: "flex items-center justify-between rounded-lg border px-3 py-2", children: [_jsxs("div", { children: [_jsx("span", { className: "text-sm font-medium text-foreground", children: grant.appId }), _jsx("span", { className: "ml-2 text-xs text-muted-foreground", children: grant.
|
|
128
|
-
? `synced ${new Date(grant.syncedAt).toLocaleString()}`
|
|
129
|
-
: "not synced" })] }), _jsxs("div", { className: "flex gap-1.5", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: () => syncToApp.mutate({ appId: grant.appId }), disabled: syncToApp.isPending, children: _jsx(IconRefresh, { size: 14 }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => revokeGrant.mutate({ grantId: grant.id }), disabled: revokeGrant.isPending, children: _jsx(IconX, { size: 14 }) })] })] }, grant.id))) })) : (_jsx("div", { className: "rounded-lg border border-dashed px-3 py-4 text-center text-xs text-muted-foreground", children: "No grants yet. Grant this resource to specific apps." }))] })), _jsxs("div", { className: "flex justify-between border-t pt-3", children: [_jsxs("div", { className: "text-xs text-muted-foreground", children: ["Created by ", resource.createdBy, " \u00B7", " ", new Date(resource.createdAt).toLocaleString()] }), _jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "destructive", size: "sm", disabled: deleteResource.isPending, children: [_jsx(IconTrash, { size: 14, className: "mr-1" }), "Delete"] }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Delete this resource?" }), _jsxs(AlertDialogDescription, { children: ["Removing \"", resource.name, "\" revokes all of its grants. Apps that depended on this resource will lose access on the next sync. This cannot be undone."] })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Cancel" }), _jsx(AlertDialogAction, { onClick: () => deleteResource.mutate({ id: resource.id }), children: "Delete resource" })] })] })] })] })] }))] }));
|
|
267
|
+
: "text-xs", children: resource.scope === "all" ? "All apps" : "Selected" }), isAutoLoadedInstruction(resource) && (_jsx(Badge, { variant: "outline", className: "text-xs", children: "Auto-loaded" }))] }), _jsx("div", { className: "mt-0.5 font-mono text-xs text-muted-foreground", children: resource.path })] }), _jsx("div", { className: "flex items-center gap-2", children: resource.scope === "selected" && (_jsxs(Badge, { variant: "outline", className: "text-xs", children: [activeGrants.length, " grant", activeGrants.length !== 1 ? "s" : ""] })) })] }), expanded && (_jsxs("div", { className: "border-t px-4 py-3 space-y-3", children: [resource.description && (_jsx("p", { className: "text-sm text-muted-foreground", children: resource.description })), _jsx("div", { className: "rounded-lg border bg-muted/30 p-3", children: _jsx("pre", { className: "whitespace-pre-wrap text-xs font-mono text-foreground max-h-64 overflow-y-auto", children: resource.content }) }), _jsx(EffectiveContextPreview, { resource: resource }), resource.scope === "selected" && (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-xs font-medium text-foreground", children: "Grants" }), _jsx(GrantDialog, { resourceId: resource.id, resourceName: resource.name })] }), activeGrants.length > 0 ? (_jsx("div", { className: "space-y-1.5", children: activeGrants.map((grant) => (_jsxs("div", { className: "flex items-center justify-between rounded-lg border px-3 py-2", children: [_jsxs("div", { children: [_jsx("span", { className: "text-sm font-medium text-foreground", children: grant.appId }), _jsx("span", { className: "ml-2 text-xs text-muted-foreground", children: "selected grant" })] }), _jsx("div", { className: "flex gap-1.5", children: _jsx(Button, { variant: "ghost", size: "sm", onClick: () => revokeGrant.mutate({ grantId: grant.id }), disabled: revokeGrant.isPending, children: _jsx(IconX, { size: 14 }) }) })] }, grant.id))) })) : (_jsx("div", { className: "rounded-lg border border-dashed px-3 py-4 text-center text-xs text-muted-foreground", children: "No grants yet. Grant this resource to specific apps." }))] })), _jsxs("div", { className: "flex justify-between border-t pt-3", children: [_jsxs("div", { className: "text-xs text-muted-foreground", children: ["Created by ", resource.createdBy, " \u00B7", " ", new Date(resource.createdAt).toLocaleString()] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(EditResourceDialog, { resource: resource }), _jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "destructive", size: "sm", disabled: deleteResource.isPending, children: [_jsx(IconTrash, { size: 14, className: "mr-1" }), "Delete"] }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Delete this resource?" }), _jsxs(AlertDialogDescription, { children: ["Removing \"", resource.name, "\" revokes all of its grants and removes inherited workspace access immediately. This cannot be undone."] })] }), _jsx(ImpactPreview, { operation: "delete", resourceId: resource.id, enabled: true }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Cancel" }), _jsx(AlertDialogAction, { onClick: () => deleteResource.mutate({ id: resource.id }), children: "Delete resource" })] })] })] })] })] })] }))] }));
|
|
130
268
|
}
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
const
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
269
|
+
function GlobalContextSection({ resources }) {
|
|
270
|
+
const byPath = new Map(resources.map((resource) => [resource.path, resource]));
|
|
271
|
+
const missingPaths = STARTER_GLOBAL_CONTEXT.filter((item) => !byPath.has(item.path)).map((item) => item.path);
|
|
272
|
+
const presentCount = STARTER_GLOBAL_CONTEXT.length - missingPaths.length;
|
|
273
|
+
const restoreStarter = useActionMutation("restore-starter-workspace-resources", {
|
|
274
|
+
onSuccess: (result) => {
|
|
275
|
+
const restored = result?.restored?.length ?? 0;
|
|
276
|
+
const existing = result?.existing?.length ?? 0;
|
|
277
|
+
toast.success(restored > 0
|
|
278
|
+
? `Restored ${restored} starter resource${restored === 1 ? "" : "s"}`
|
|
279
|
+
: `Starter resources already present (${existing})`);
|
|
138
280
|
},
|
|
139
281
|
onError: (err) => toast.error(String(err)),
|
|
140
282
|
});
|
|
283
|
+
return (_jsxs("section", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-sm font-semibold text-foreground", children: "Global context" }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Starter resources every workspace can use for company facts, brand, messaging, guardrails, and voice." }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "All-app resources live once at workspace scope and are inherited by every app agent at runtime." })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [missingPaths.length > 0 ? (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => restoreStarter.mutate({ paths: missingPaths }), disabled: restoreStarter.isPending, children: [_jsx(IconPlus, { size: 14, className: "mr-1.5" }), restoreStarter.isPending ? "Restoring..." : "Restore missing"] })) : null, _jsxs(Badge, { variant: "outline", children: [presentCount, "/", STARTER_GLOBAL_CONTEXT.length, " ready"] })] })] }), _jsx("div", { className: "grid gap-3 md:grid-cols-2 xl:grid-cols-5", children: STARTER_GLOBAL_CONTEXT.map((item) => {
|
|
284
|
+
const resource = byPath.get(item.path);
|
|
285
|
+
const exists = !!resource;
|
|
286
|
+
const global = resource?.scope === "all";
|
|
287
|
+
return (_jsxs("div", { className: "rounded-lg border bg-card p-4", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2", children: [exists ? (_jsx(IconCircleCheck, { size: 15, className: "shrink-0 text-green-600 dark:text-green-400" })) : (_jsx(IconAlertCircle, { size: 15, className: "shrink-0 text-amber-600 dark:text-amber-400" })), _jsx("h3", { className: "truncate text-sm font-medium text-foreground", children: item.label })] }), _jsx("p", { className: "mt-1 line-clamp-2 text-xs text-muted-foreground", children: item.description })] }), resource ? (_jsx(EditResourceDialog, { resource: resource, trigger: _jsxs(Button, { variant: "ghost", size: "sm", className: "h-7 px-2", children: [_jsxs("span", { className: "sr-only", children: ["Edit ", item.label] }), _jsx(IconEdit, { size: 14 })] }) })) : (_jsx(Button, { variant: "ghost", size: "sm", className: "h-7 px-2", onClick: () => restoreStarter.mutate({ paths: [item.path] }), disabled: restoreStarter.isPending, "aria-label": `Restore ${item.label}`, children: _jsx(IconPlus, { size: 14 }) }))] }), _jsxs("div", { className: "mt-3 space-y-2", children: [_jsx("div", { className: "truncate font-mono text-[11px] text-muted-foreground", children: item.path }), _jsxs("div", { className: "flex flex-wrap gap-1.5", children: [_jsx(Badge, { variant: exists ? "secondary" : "outline", children: exists ? "Present" : "Missing" }), exists ? (_jsx(Badge, { variant: "outline", children: global ? "All apps" : "Selected" })) : null, resource && isAutoLoadedInstruction(resource) ? (_jsx(Badge, { variant: "outline", children: "Auto-loaded" })) : null] })] })] }, item.path));
|
|
288
|
+
}) })] }));
|
|
289
|
+
}
|
|
290
|
+
export default function WorkspaceRoute() {
|
|
291
|
+
const { data: resources, isLoading } = useActionQuery("list-workspace-resources", {});
|
|
292
|
+
const { data: grants } = useActionQuery("list-workspace-resource-grants", {});
|
|
141
293
|
const grantsByResource = (grants || []).reduce((acc, g) => {
|
|
142
294
|
if (!acc[g.resourceId])
|
|
143
295
|
acc[g.resourceId] = [];
|
|
@@ -150,13 +302,13 @@ export default function WorkspaceRoute() {
|
|
|
150
302
|
const knowledge = (resources || []).filter((r) => r.kind === "knowledge");
|
|
151
303
|
function ResourceList({ items, emptyText, }) {
|
|
152
304
|
if (isLoading && (resources ?? []).length === 0) {
|
|
153
|
-
return (_jsx("div", { className: "space-y-3", children: Array.from({ length: 3 }).map((_, index) => (_jsxs("div", { className: "rounded-
|
|
305
|
+
return (_jsx("div", { className: "space-y-3", children: Array.from({ length: 3 }).map((_, index) => (_jsxs("div", { className: "rounded-lg border bg-card px-5 py-4 space-y-2", children: [_jsx(Skeleton, { className: "h-4 w-1/3" }), _jsx(Skeleton, { className: "h-3 w-2/3" })] }, index))) }));
|
|
154
306
|
}
|
|
155
307
|
if (items.length === 0) {
|
|
156
|
-
return (_jsx("div", { className: "rounded-
|
|
308
|
+
return (_jsx("div", { className: "rounded-lg border border-dashed px-6 py-12 text-center text-sm text-muted-foreground", children: emptyText }));
|
|
157
309
|
}
|
|
158
310
|
return (_jsx("div", { className: "space-y-3", children: items.map((resource) => (_jsx(ResourceRow, { resource: resource, grants: grantsByResource[resource.id] || [] }, resource.id))) }));
|
|
159
311
|
}
|
|
160
|
-
return (_jsxs(DispatchShell, { title: "Workspace Resources", description: "
|
|
312
|
+
return (_jsxs(DispatchShell, { title: "Workspace Resources", description: "Manage inherited workspace skills, guardrail instructions, agent profiles, and reference resources. All-app resources are available to every app without syncing.", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { className: "text-sm text-muted-foreground", children: isLoading ? (_jsx(Skeleton, { className: "h-4 w-24" })) : (`${resources?.length || 0} resource${(resources?.length || 0) !== 1 ? "s" : ""}`) }), _jsx("div", { className: "flex gap-2", children: _jsx(AddResourceDialog, {}) })] }), _jsx(GlobalContextSection, { resources: resources || [] }), _jsxs(Tabs, { defaultValue: "skills", children: [_jsxs(TabsList, { children: [_jsxs(TabsTrigger, { value: "skills", children: ["Skills ", skills.length > 0 && `(${skills.length})`] }), _jsxs(TabsTrigger, { value: "instructions", children: ["Instructions ", instructions.length > 0 && `(${instructions.length})`] }), _jsxs(TabsTrigger, { value: "agents", children: ["Agents ", agents.length > 0 && `(${agents.length})`] }), _jsxs(TabsTrigger, { value: "knowledge", children: ["Knowledge ", knowledge.length > 0 && `(${knowledge.length})`] })] }), _jsx(TabsContent, { value: "skills", className: "mt-4", children: _jsx(ResourceList, { items: skills, emptyText: "No workspace skills yet. Add a skill to share agent guidance across apps." }) }), _jsx(TabsContent, { value: "instructions", className: "mt-4", children: _jsx(ResourceList, { items: instructions, emptyText: "No workspace instructions yet. Add instructions to set behavioral rules across apps." }) }), _jsx(TabsContent, { value: "agents", className: "mt-4", children: _jsx(ResourceList, { items: agents, emptyText: "No workspace agents yet. Add a reusable agent profile to share specialist agents across apps." }) }), _jsx(TabsContent, { value: "knowledge", className: "mt-4", children: _jsx(ResourceList, { items: knowledge, emptyText: "No knowledge packs yet. Add GTM, product, or domain context that apps can reuse." }) })] })] }));
|
|
161
313
|
}
|
|
162
314
|
//# sourceMappingURL=workspace.js.map
|