@agent-native/dispatch 0.6.1 → 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 +38 -1
- 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-pylon-ticket.d.ts +3 -0
- package/dist/actions/create-pylon-ticket.d.ts.map +1 -0
- package/dist/actions/create-pylon-ticket.js +94 -0
- package/dist/actions/create-pylon-ticket.js.map +1 -0
- package/dist/actions/create-vault-grant.js +1 -1
- package/dist/actions/create-vault-grant.js.map +1 -1
- package/dist/actions/create-vault-secret.d.ts.map +1 -1
- package/dist/actions/create-vault-secret.js +4 -3
- package/dist/actions/create-vault-secret.js.map +1 -1
- 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-vault-access-settings.d.ts +3 -0
- package/dist/actions/get-vault-access-settings.d.ts.map +1 -0
- package/dist/actions/get-vault-access-settings.js +10 -0
- package/dist/actions/get-vault-access-settings.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/grant-vault-secrets-to-app.js +1 -1
- package/dist/actions/grant-vault-secrets-to-app.js.map +1 -1
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +38 -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-integrations-catalog.js +1 -1
- package/dist/actions/list-integrations-catalog.js.map +1 -1
- package/dist/actions/list-vault-grants.js +1 -1
- package/dist/actions/list-vault-grants.js.map +1 -1
- package/dist/actions/list-workspace-apps.d.ts.map +1 -1
- package/dist/actions/list-workspace-apps.js +5 -1
- package/dist/actions/list-workspace-apps.js.map +1 -1
- 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/set-vault-access-settings.d.ts +3 -0
- package/dist/actions/set-vault-access-settings.d.ts.map +1 -0
- package/dist/actions/set-vault-access-settings.js +13 -0
- package/dist/actions/set-vault-access-settings.js.map +1 -0
- package/dist/actions/start-workspace-app-creation.d.ts.map +1 -1
- package/dist/actions/start-workspace-app-creation.js +6 -0
- package/dist/actions/start-workspace-app-creation.js.map +1 -1
- package/dist/actions/sync-vault-to-app.js +1 -1
- package/dist/actions/sync-vault-to-app.js.map +1 -1
- package/dist/actions/update-workspace-app-metadata.d.ts +3 -0
- package/dist/actions/update-workspace-app-metadata.d.ts.map +1 -0
- package/dist/actions/update-workspace-app-metadata.js +30 -0
- package/dist/actions/update-workspace-app-metadata.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 +77 -4
- package/dist/actions/view-screen.js.map +1 -1
- package/dist/components/app-keys-popover.js +16 -5
- package/dist/components/app-keys-popover.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 +41 -16
- package/dist/components/create-app-popover.js.map +1 -1
- package/dist/components/dispatch-shell.d.ts +4 -4
- package/dist/components/dispatch-shell.d.ts.map +1 -1
- package/dist/components/dispatch-shell.js +6 -6
- package/dist/components/dispatch-shell.js.map +1 -1
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +18 -4
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/messaging-setup-panel.d.ts.map +1 -1
- package/dist/components/messaging-setup-panel.js +2 -2
- package/dist/components/messaging-setup-panel.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 +63 -3
- 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 +35 -8
- package/dist/hooks/use-navigation-state.js.map +1 -1
- package/dist/lib/catch-all-target.d.ts +2 -0
- package/dist/lib/catch-all-target.d.ts.map +1 -0
- package/dist/lib/catch-all-target.js +95 -0
- package/dist/lib/catch-all-target.js.map +1 -0
- 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/lib/workspace-apps.d.ts +9 -0
- package/dist/lib/workspace-apps.d.ts.map +1 -1
- package/dist/lib/workspace-apps.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/$appId.d.ts +2 -2
- package/dist/routes/pages/$appId.d.ts.map +1 -1
- package/dist/routes/pages/$appId.js +17 -8
- package/dist/routes/pages/$appId.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/integrations.d.ts.map +1 -1
- package/dist/routes/pages/integrations.js +20 -15
- package/dist/routes/pages/integrations.js.map +1 -1
- package/dist/routes/pages/new-app.js +1 -1
- package/dist/routes/pages/new-app.js.map +1 -1
- package/dist/routes/pages/overview.d.ts.map +1 -1
- package/dist/routes/pages/overview.js +5 -1
- package/dist/routes/pages/overview.js.map +1 -1
- package/dist/routes/pages/vault.d.ts.map +1 -1
- package/dist/routes/pages/vault.js +23 -5
- package/dist/routes/pages/vault.js.map +1 -1
- 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 +13 -0
- package/dist/server/lib/app-creation-store.d.ts.map +1 -1
- package/dist/server/lib/app-creation-store.js +298 -11
- 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/env-config.d.ts.map +1 -1
- package/dist/server/lib/env-config.js +5 -0
- package/dist/server/lib/env-config.js.map +1 -1
- package/dist/server/lib/onboarding-steps.d.ts +12 -0
- package/dist/server/lib/onboarding-steps.d.ts.map +1 -0
- package/dist/server/lib/onboarding-steps.js +47 -0
- package/dist/server/lib/onboarding-steps.js.map +1 -0
- package/dist/server/lib/thread-debug-store.d.ts +2 -2
- package/dist/server/lib/vault-store.d.ts +55 -0
- package/dist/server/lib/vault-store.d.ts.map +1 -1
- package/dist/server/lib/vault-store.js +210 -41
- package/dist/server/lib/vault-store.js.map +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/dist/server/plugins/agent-chat.d.ts.map +1 -1
- package/dist/server/plugins/agent-chat.js +2 -1
- package/dist/server/plugins/agent-chat.js.map +1 -1
- package/dist/server/plugins/core-routes.d.ts.map +1 -1
- package/dist/server/plugins/core-routes.js +4 -0
- package/dist/server/plugins/core-routes.js.map +1 -1
- package/dist/server/plugins/integrations.js +2 -2
- package/dist/server/plugins/integrations.js.map +1 -1
- package/package.json +15 -11
- package/src/actions/apply-dream-proposal.ts +12 -0
- package/src/actions/create-dream-report.ts +76 -0
- package/src/actions/create-pylon-ticket.ts +109 -0
- package/src/actions/create-vault-grant.ts +1 -1
- package/src/actions/create-vault-secret.ts +4 -3
- 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-vault-access-settings.ts +11 -0
- package/src/actions/get-workspace-resource-effective-context.ts +34 -0
- package/src/actions/grant-vault-secrets-to-app.ts +1 -1
- package/src/actions/index.spec.ts +26 -0
- package/src/actions/index.ts +39 -4
- package/src/actions/list-dream-candidates.ts +77 -0
- package/src/actions/list-dreams.ts +17 -0
- package/src/actions/list-integrations-catalog.ts +1 -1
- package/src/actions/list-vault-grants.ts +1 -1
- package/src/actions/list-workspace-apps.ts +5 -1
- 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/set-vault-access-settings.ts +16 -0
- package/src/actions/start-workspace-app-creation.ts +8 -0
- package/src/actions/sync-vault-to-app.ts +1 -1
- package/src/actions/update-workspace-app-metadata.ts +32 -0
- package/src/actions/update-workspace-resource.ts +1 -1
- package/src/actions/view-screen.ts +94 -3
- package/src/components/app-keys-popover.tsx +23 -7
- 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 +50 -16
- package/src/components/dispatch-shell.tsx +16 -15
- package/src/components/layout/Layout.tsx +19 -5
- package/src/components/messaging-setup-panel.tsx +54 -39
- package/src/components/workspace-app-card.tsx +268 -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 +34 -9
- package/src/lib/catch-all-target.spec.ts +218 -0
- package/src/lib/catch-all-target.ts +99 -0
- package/src/lib/utils.ts +6 -1
- package/src/lib/workspace-apps.ts +9 -0
- package/src/routes/index.ts +1 -0
- package/src/routes/pages/$appId.tsx +21 -8
- 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/integrations.tsx +57 -18
- package/src/routes/pages/new-app.tsx +1 -1
- package/src/routes/pages/overview.tsx +11 -3
- package/src/routes/pages/vault.tsx +76 -9
- package/src/routes/pages/workspace.tsx +577 -97
- package/src/server/lib/app-creation-store.spec.ts +61 -2
- package/src/server/lib/app-creation-store.ts +389 -13
- 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/env-config.ts +5 -0
- package/src/server/lib/onboarding-steps.ts +49 -0
- package/src/server/lib/vault-store.spec.ts +69 -0
- package/src/server/lib/vault-store.ts +266 -49
- 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/src/server/plugins/agent-chat.ts +2 -1
- package/src/server/plugins/core-routes.ts +5 -0
- package/src/server/plugins/integrations.ts +2 -2
- 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,19 +1,25 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
1
|
+
import { useEffect, useState, type ReactNode } from "react";
|
|
2
2
|
import { useActionMutation, useActionQuery } from "@agent-native/core/client";
|
|
3
3
|
import { toast } from "sonner";
|
|
4
4
|
import {
|
|
5
|
+
IconAlertCircle,
|
|
5
6
|
IconBook,
|
|
6
7
|
IconChevronDown,
|
|
7
8
|
IconChevronRight,
|
|
9
|
+
IconCircleCheck,
|
|
8
10
|
IconCode,
|
|
11
|
+
IconEdit,
|
|
9
12
|
IconFileText,
|
|
10
13
|
IconPlus,
|
|
11
|
-
IconRefresh,
|
|
12
14
|
IconTrash,
|
|
13
15
|
IconUser,
|
|
14
16
|
IconX,
|
|
15
17
|
} from "@tabler/icons-react";
|
|
16
18
|
import { DispatchShell } from "@/components/dispatch-shell";
|
|
19
|
+
import {
|
|
20
|
+
ImpactPreview,
|
|
21
|
+
workspaceResourceMutationMessage,
|
|
22
|
+
} from "@/components/workspace-resource-impact-preview";
|
|
17
23
|
import {
|
|
18
24
|
AlertDialog,
|
|
19
25
|
AlertDialogAction,
|
|
@@ -58,31 +64,252 @@ const KIND_CONFIG = {
|
|
|
58
64
|
label: "Skill",
|
|
59
65
|
icon: IconCode,
|
|
60
66
|
pathPrefix: "skills/",
|
|
61
|
-
description:
|
|
67
|
+
description:
|
|
68
|
+
"Agent skills - on-demand guidance available across workspace apps",
|
|
62
69
|
},
|
|
63
70
|
instruction: {
|
|
64
71
|
label: "Instruction",
|
|
65
72
|
icon: IconBook,
|
|
66
|
-
pathPrefix: "",
|
|
67
|
-
description:
|
|
68
|
-
"Agent instructions — operational rules and behavioral guidance",
|
|
73
|
+
pathPrefix: "instructions/",
|
|
74
|
+
description: "Global instructions - guardrails loaded by every app agent",
|
|
69
75
|
},
|
|
70
76
|
agent: {
|
|
71
77
|
label: "Agent",
|
|
72
78
|
icon: IconUser,
|
|
73
79
|
pathPrefix: "agents/",
|
|
74
80
|
description:
|
|
75
|
-
"Reusable agent profiles
|
|
81
|
+
"Reusable agent profiles - specialist agents shared across apps",
|
|
76
82
|
},
|
|
77
83
|
knowledge: {
|
|
78
84
|
label: "Knowledge",
|
|
79
85
|
icon: IconFileText,
|
|
80
86
|
pathPrefix: "context/",
|
|
81
87
|
description:
|
|
82
|
-
"
|
|
88
|
+
"Reference resources - brand, positioning, persona, and domain context",
|
|
83
89
|
},
|
|
84
90
|
} as const;
|
|
85
91
|
|
|
92
|
+
const STARTER_GLOBAL_CONTEXT = [
|
|
93
|
+
{
|
|
94
|
+
path: "context/company.md",
|
|
95
|
+
label: "Company",
|
|
96
|
+
kind: "knowledge",
|
|
97
|
+
description: "Company facts, ICP, products, and canonical links",
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
path: "context/brand.md",
|
|
101
|
+
label: "Brand",
|
|
102
|
+
kind: "knowledge",
|
|
103
|
+
description: "Voice, visual identity, naming, and style rules",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
path: "context/messaging.md",
|
|
107
|
+
label: "Messaging",
|
|
108
|
+
kind: "knowledge",
|
|
109
|
+
description: "Positioning, value props, proof points, and objections",
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
path: "instructions/guardrails.md",
|
|
113
|
+
label: "Guardrails",
|
|
114
|
+
kind: "instruction",
|
|
115
|
+
description: "Always-on rules loaded by every app agent",
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
path: "skills/company-voice/SKILL.md",
|
|
119
|
+
label: "Company Voice",
|
|
120
|
+
kind: "skill",
|
|
121
|
+
description: "On-demand guidance for customer-facing writing",
|
|
122
|
+
},
|
|
123
|
+
] as const;
|
|
124
|
+
|
|
125
|
+
function resourceSlug(value: string): string {
|
|
126
|
+
return value
|
|
127
|
+
.toLowerCase()
|
|
128
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
129
|
+
.replace(/^-+|-+$/g, "");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function defaultResourcePath(kind: string, name: string): string {
|
|
133
|
+
const slug = resourceSlug(name) || "example";
|
|
134
|
+
if (kind === "skill") return `skills/${slug}/SKILL.md`;
|
|
135
|
+
if (kind === "instruction") return `instructions/${slug}.md`;
|
|
136
|
+
if (kind === "agent") return `agents/${slug}.md`;
|
|
137
|
+
if (kind === "knowledge") return `context/${slug}.md`;
|
|
138
|
+
return `${slug}.md`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function isAutoLoadedInstruction(resource: any): boolean {
|
|
142
|
+
return (
|
|
143
|
+
resource.kind === "instruction" &&
|
|
144
|
+
(resource.path === "AGENTS.md" ||
|
|
145
|
+
String(resource.path).startsWith("instructions/"))
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function formatTimestamp(value?: number | null): string {
|
|
150
|
+
if (!value) return "Not present";
|
|
151
|
+
return new Date(value).toLocaleString();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function availabilityLabel(value?: string): string {
|
|
155
|
+
switch (value) {
|
|
156
|
+
case "all-apps":
|
|
157
|
+
return "Inherited by all apps";
|
|
158
|
+
case "selected-granted":
|
|
159
|
+
return "Granted to selected app";
|
|
160
|
+
case "selected-not-granted":
|
|
161
|
+
return "Not granted to this app";
|
|
162
|
+
case "selected-no-app":
|
|
163
|
+
return "Select an app to check grant";
|
|
164
|
+
case "path-not-managed":
|
|
165
|
+
return "Path is not a Dispatch resource";
|
|
166
|
+
default:
|
|
167
|
+
return "Checking availability";
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function layerState(layer: any): {
|
|
172
|
+
label: string;
|
|
173
|
+
className: string;
|
|
174
|
+
} {
|
|
175
|
+
if (layer.effective) {
|
|
176
|
+
return {
|
|
177
|
+
label: "Active",
|
|
178
|
+
className: "border-green-500/30 bg-green-500/10 text-green-700",
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
if (layer.overridden) {
|
|
182
|
+
return {
|
|
183
|
+
label: "Overridden",
|
|
184
|
+
className: "border-amber-500/30 bg-amber-500/10 text-amber-700",
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
label: "Missing",
|
|
189
|
+
className: "text-muted-foreground",
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function EditResourceDialog({
|
|
194
|
+
resource,
|
|
195
|
+
trigger,
|
|
196
|
+
}: {
|
|
197
|
+
resource: any;
|
|
198
|
+
trigger?: ReactNode;
|
|
199
|
+
}) {
|
|
200
|
+
const [open, setOpen] = useState(false);
|
|
201
|
+
const [name, setName] = useState(resource.name || "");
|
|
202
|
+
const [description, setDescription] = useState(resource.description || "");
|
|
203
|
+
const [content, setContent] = useState(resource.content || "");
|
|
204
|
+
const [scope, setScope] = useState(resource.scope || "all");
|
|
205
|
+
|
|
206
|
+
useEffect(() => {
|
|
207
|
+
if (!open) return;
|
|
208
|
+
setName(resource.name || "");
|
|
209
|
+
setDescription(resource.description || "");
|
|
210
|
+
setContent(resource.content || "");
|
|
211
|
+
setScope(resource.scope || "all");
|
|
212
|
+
}, [open, resource]);
|
|
213
|
+
|
|
214
|
+
const update = useActionMutation("update-workspace-resource", {
|
|
215
|
+
onSuccess: (result: any) => {
|
|
216
|
+
toast.success(
|
|
217
|
+
workspaceResourceMutationMessage(result, "Resource updated"),
|
|
218
|
+
);
|
|
219
|
+
setOpen(false);
|
|
220
|
+
},
|
|
221
|
+
onError: (err) => toast.error(String(err)),
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
return (
|
|
225
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
226
|
+
<DialogTrigger asChild>
|
|
227
|
+
{trigger || (
|
|
228
|
+
<Button variant="outline" size="sm">
|
|
229
|
+
<IconEdit size={14} className="mr-1.5" />
|
|
230
|
+
Edit
|
|
231
|
+
</Button>
|
|
232
|
+
)}
|
|
233
|
+
</DialogTrigger>
|
|
234
|
+
<DialogContent className="max-w-2xl">
|
|
235
|
+
<DialogHeader>
|
|
236
|
+
<DialogTitle>Edit workspace resource</DialogTitle>
|
|
237
|
+
<DialogDescription>
|
|
238
|
+
Updates apply immediately anywhere this workspace resource is
|
|
239
|
+
inherited. App shared or personal resources can override it locally.
|
|
240
|
+
</DialogDescription>
|
|
241
|
+
</DialogHeader>
|
|
242
|
+
<div className="space-y-4 py-2">
|
|
243
|
+
<div className="grid grid-cols-2 gap-4">
|
|
244
|
+
<div className="space-y-2">
|
|
245
|
+
<Label>Name</Label>
|
|
246
|
+
<Input value={name} onChange={(e) => setName(e.target.value)} />
|
|
247
|
+
</div>
|
|
248
|
+
<div className="space-y-2">
|
|
249
|
+
<Label>Scope</Label>
|
|
250
|
+
<Select value={scope} onValueChange={setScope}>
|
|
251
|
+
<SelectTrigger>
|
|
252
|
+
<SelectValue />
|
|
253
|
+
</SelectTrigger>
|
|
254
|
+
<SelectContent>
|
|
255
|
+
<SelectItem value="all">All apps</SelectItem>
|
|
256
|
+
<SelectItem value="selected">Selected apps only</SelectItem>
|
|
257
|
+
</SelectContent>
|
|
258
|
+
</Select>
|
|
259
|
+
</div>
|
|
260
|
+
</div>
|
|
261
|
+
<div className="space-y-2">
|
|
262
|
+
<Label>Path</Label>
|
|
263
|
+
<Input
|
|
264
|
+
value={resource.path}
|
|
265
|
+
disabled
|
|
266
|
+
className="font-mono text-sm"
|
|
267
|
+
/>
|
|
268
|
+
</div>
|
|
269
|
+
<div className="space-y-2">
|
|
270
|
+
<Label>Description</Label>
|
|
271
|
+
<Input
|
|
272
|
+
value={description}
|
|
273
|
+
onChange={(e) => setDescription(e.target.value)}
|
|
274
|
+
/>
|
|
275
|
+
</div>
|
|
276
|
+
<div className="space-y-2">
|
|
277
|
+
<Label>Content</Label>
|
|
278
|
+
<Textarea
|
|
279
|
+
value={content}
|
|
280
|
+
onChange={(e) => setContent(e.target.value)}
|
|
281
|
+
rows={14}
|
|
282
|
+
className="font-mono text-sm"
|
|
283
|
+
/>
|
|
284
|
+
</div>
|
|
285
|
+
<ImpactPreview
|
|
286
|
+
operation="update"
|
|
287
|
+
resourceId={resource.id}
|
|
288
|
+
scope={scope as "all" | "selected"}
|
|
289
|
+
enabled={open}
|
|
290
|
+
/>
|
|
291
|
+
</div>
|
|
292
|
+
<DialogFooter>
|
|
293
|
+
<Button
|
|
294
|
+
onClick={() =>
|
|
295
|
+
update.mutate({
|
|
296
|
+
id: resource.id,
|
|
297
|
+
name,
|
|
298
|
+
description,
|
|
299
|
+
content,
|
|
300
|
+
scope: scope as "all" | "selected",
|
|
301
|
+
})
|
|
302
|
+
}
|
|
303
|
+
disabled={!name.trim() || update.isPending}
|
|
304
|
+
>
|
|
305
|
+
{update.isPending ? "Saving..." : "Save changes"}
|
|
306
|
+
</Button>
|
|
307
|
+
</DialogFooter>
|
|
308
|
+
</DialogContent>
|
|
309
|
+
</Dialog>
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
86
313
|
function AddResourceDialog() {
|
|
87
314
|
const [open, setOpen] = useState(false);
|
|
88
315
|
const [kind, setKind] = useState<string>("skill");
|
|
@@ -93,8 +320,10 @@ function AddResourceDialog() {
|
|
|
93
320
|
const [scope, setScope] = useState<string>("all");
|
|
94
321
|
|
|
95
322
|
const create = useActionMutation("create-workspace-resource", {
|
|
96
|
-
onSuccess: () => {
|
|
97
|
-
toast.success(
|
|
323
|
+
onSuccess: (result: any) => {
|
|
324
|
+
toast.success(
|
|
325
|
+
workspaceResourceMutationMessage(result, "Resource created"),
|
|
326
|
+
);
|
|
98
327
|
setOpen(false);
|
|
99
328
|
setKind("skill");
|
|
100
329
|
setName("");
|
|
@@ -106,8 +335,6 @@ function AddResourceDialog() {
|
|
|
106
335
|
onError: (err) => toast.error(String(err)),
|
|
107
336
|
});
|
|
108
337
|
|
|
109
|
-
const kindInfo = KIND_CONFIG[kind as keyof typeof KIND_CONFIG];
|
|
110
|
-
|
|
111
338
|
return (
|
|
112
339
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
113
340
|
<DialogTrigger asChild>
|
|
@@ -120,8 +347,8 @@ function AddResourceDialog() {
|
|
|
120
347
|
<DialogHeader>
|
|
121
348
|
<DialogTitle>Add workspace resource</DialogTitle>
|
|
122
349
|
<DialogDescription>
|
|
123
|
-
Create a skill, instruction,
|
|
124
|
-
across workspace apps.
|
|
350
|
+
Create a skill, instruction, agent profile, or reference resource
|
|
351
|
+
that can be shared across workspace apps.
|
|
125
352
|
</DialogDescription>
|
|
126
353
|
</DialogHeader>
|
|
127
354
|
<div className="space-y-4 py-2">
|
|
@@ -172,14 +399,15 @@ function AddResourceDialog() {
|
|
|
172
399
|
<div className="space-y-2">
|
|
173
400
|
<Label>Path</Label>
|
|
174
401
|
<Input
|
|
175
|
-
placeholder={
|
|
402
|
+
placeholder={defaultResourcePath(kind, name)}
|
|
176
403
|
value={path}
|
|
177
404
|
onChange={(e) => setPath(e.target.value)}
|
|
178
405
|
className="font-mono text-sm"
|
|
179
406
|
/>
|
|
180
407
|
<p className="text-xs text-muted-foreground">
|
|
181
|
-
|
|
182
|
-
|
|
408
|
+
Skills use skills/name/SKILL.md. Guardrails in AGENTS.md or
|
|
409
|
+
instructions/ auto-load in app chat. Reference resources in
|
|
410
|
+
context/ are indexed so agents can read them when relevant.
|
|
183
411
|
</p>
|
|
184
412
|
</div>
|
|
185
413
|
<div className="space-y-2">
|
|
@@ -200,7 +428,7 @@ function AddResourceDialog() {
|
|
|
200
428
|
? "---\nname: Research Specialist\ndescription: Handles research tasks\n---\n\n# Instructions\n\n..."
|
|
201
429
|
: kind === "knowledge"
|
|
202
430
|
? "# Core GTM Messaging\n\n## Positioning\n\n## ICP\n\n## Proof points\n\n## Source\n\n"
|
|
203
|
-
: "# Instructions\n\
|
|
431
|
+
: "# Instructions\n\nAlways-on guardrails for agents across apps..."
|
|
204
432
|
}
|
|
205
433
|
value={content}
|
|
206
434
|
onChange={(e) => setContent(e.target.value)}
|
|
@@ -208,6 +436,12 @@ function AddResourceDialog() {
|
|
|
208
436
|
className="font-mono text-sm"
|
|
209
437
|
/>
|
|
210
438
|
</div>
|
|
439
|
+
<ImpactPreview
|
|
440
|
+
operation="create"
|
|
441
|
+
path={path || defaultResourcePath(kind, name)}
|
|
442
|
+
scope={scope as "all" | "selected"}
|
|
443
|
+
enabled={open && Boolean(name.trim())}
|
|
444
|
+
/>
|
|
211
445
|
</div>
|
|
212
446
|
<DialogFooter>
|
|
213
447
|
<Button
|
|
@@ -216,9 +450,7 @@ function AddResourceDialog() {
|
|
|
216
450
|
kind: kind as "skill" | "instruction" | "agent" | "knowledge",
|
|
217
451
|
name,
|
|
218
452
|
description: description || undefined,
|
|
219
|
-
path:
|
|
220
|
-
path ||
|
|
221
|
-
`${kindInfo?.pathPrefix || ""}${name.toLowerCase().replace(/\s+/g, "-")}.md`,
|
|
453
|
+
path: path || defaultResourcePath(kind, name),
|
|
222
454
|
content,
|
|
223
455
|
scope: scope as "all" | "selected",
|
|
224
456
|
})
|
|
@@ -300,29 +532,159 @@ function GrantDialog({
|
|
|
300
532
|
);
|
|
301
533
|
}
|
|
302
534
|
|
|
535
|
+
function EffectiveContextPreview({ resource }: { resource: any }) {
|
|
536
|
+
const [appId, setAppId] = useState("__any__");
|
|
537
|
+
const [userEmail, setUserEmail] = useState("");
|
|
538
|
+
const selectedAppId = appId === "__any__" ? undefined : appId;
|
|
539
|
+
const normalizedUserEmail = userEmail.trim() || undefined;
|
|
540
|
+
const { data: apps } = useActionQuery("list-workspace-apps", {
|
|
541
|
+
includeAgentCards: false,
|
|
542
|
+
});
|
|
543
|
+
const { data: context, isLoading } = useActionQuery(
|
|
544
|
+
"get-workspace-resource-effective-context",
|
|
545
|
+
{
|
|
546
|
+
resourceId: resource.id,
|
|
547
|
+
appId: selectedAppId,
|
|
548
|
+
userEmail: normalizedUserEmail,
|
|
549
|
+
},
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
const visibleApps = ((apps || []) as any[]).filter(
|
|
553
|
+
(app) => !app.isDispatch && app.status !== "pending",
|
|
554
|
+
);
|
|
555
|
+
const layers = ((context as any)?.layers || []) as any[];
|
|
556
|
+
const active = (context as any)?.effectiveResource;
|
|
557
|
+
const availability = (context as any)?.availability;
|
|
558
|
+
|
|
559
|
+
return (
|
|
560
|
+
<div className="rounded-lg border bg-background p-3">
|
|
561
|
+
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
562
|
+
<div className="min-w-0">
|
|
563
|
+
<h4 className="text-xs font-semibold uppercase text-muted-foreground">
|
|
564
|
+
Effective in app
|
|
565
|
+
</h4>
|
|
566
|
+
<p className="mt-1 text-xs leading-relaxed text-muted-foreground">
|
|
567
|
+
Preview the runtime stack for this path: workspace default,
|
|
568
|
+
organization/app override, then personal override.
|
|
569
|
+
</p>
|
|
570
|
+
</div>
|
|
571
|
+
<Badge variant="outline">{availabilityLabel(availability)}</Badge>
|
|
572
|
+
</div>
|
|
573
|
+
|
|
574
|
+
<div className="mt-3 grid gap-3 md:grid-cols-2">
|
|
575
|
+
<div className="space-y-2">
|
|
576
|
+
<Label htmlFor={`resource-app-${resource.id}`}>App</Label>
|
|
577
|
+
<Select value={appId} onValueChange={setAppId}>
|
|
578
|
+
<SelectTrigger id={`resource-app-${resource.id}`}>
|
|
579
|
+
<SelectValue />
|
|
580
|
+
</SelectTrigger>
|
|
581
|
+
<SelectContent>
|
|
582
|
+
<SelectItem value="__any__">Any app</SelectItem>
|
|
583
|
+
{visibleApps.map((app) => (
|
|
584
|
+
<SelectItem key={app.id} value={app.id}>
|
|
585
|
+
{app.name}
|
|
586
|
+
</SelectItem>
|
|
587
|
+
))}
|
|
588
|
+
</SelectContent>
|
|
589
|
+
</Select>
|
|
590
|
+
</div>
|
|
591
|
+
<div className="space-y-2">
|
|
592
|
+
<Label htmlFor={`resource-user-${resource.id}`}>User email</Label>
|
|
593
|
+
<Input
|
|
594
|
+
id={`resource-user-${resource.id}`}
|
|
595
|
+
value={userEmail}
|
|
596
|
+
onChange={(event) => setUserEmail(event.target.value)}
|
|
597
|
+
placeholder="Current Dispatch user"
|
|
598
|
+
/>
|
|
599
|
+
</div>
|
|
600
|
+
</div>
|
|
601
|
+
|
|
602
|
+
{resource.scope === "selected" ? (
|
|
603
|
+
<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">
|
|
604
|
+
Selected resources are app-specific exceptions. Use All apps for
|
|
605
|
+
company-wide context that should be inherited everywhere without copy
|
|
606
|
+
or sync.
|
|
607
|
+
</div>
|
|
608
|
+
) : null}
|
|
609
|
+
|
|
610
|
+
{isLoading ? (
|
|
611
|
+
<div className="mt-3 grid gap-2 md:grid-cols-3">
|
|
612
|
+
{Array.from({ length: 3 }).map((_, index) => (
|
|
613
|
+
<Skeleton key={index} className="h-28 rounded-lg" />
|
|
614
|
+
))}
|
|
615
|
+
</div>
|
|
616
|
+
) : (
|
|
617
|
+
<div className="mt-3 grid gap-2 md:grid-cols-3">
|
|
618
|
+
{layers.map((layer) => {
|
|
619
|
+
const state = layerState(layer);
|
|
620
|
+
return (
|
|
621
|
+
<div key={layer.scope} className="rounded-lg border p-3">
|
|
622
|
+
<div className="flex items-start justify-between gap-2">
|
|
623
|
+
<span className="text-sm font-medium text-foreground">
|
|
624
|
+
{layer.label}
|
|
625
|
+
</span>
|
|
626
|
+
<Badge variant="outline" className={state.className}>
|
|
627
|
+
{state.label}
|
|
628
|
+
</Badge>
|
|
629
|
+
</div>
|
|
630
|
+
<div className="mt-2 truncate font-mono text-[11px] text-muted-foreground">
|
|
631
|
+
{layer.owner}
|
|
632
|
+
</div>
|
|
633
|
+
{layer.resource ? (
|
|
634
|
+
<div className="mt-2 space-y-1 text-xs text-muted-foreground">
|
|
635
|
+
<div className="truncate font-mono">
|
|
636
|
+
{layer.resource.path}
|
|
637
|
+
</div>
|
|
638
|
+
<div>{formatTimestamp(layer.resource.updatedAt)}</div>
|
|
639
|
+
</div>
|
|
640
|
+
) : (
|
|
641
|
+
<p className="mt-2 text-xs text-muted-foreground">
|
|
642
|
+
No resource exists at this layer.
|
|
643
|
+
</p>
|
|
644
|
+
)}
|
|
645
|
+
</div>
|
|
646
|
+
);
|
|
647
|
+
})}
|
|
648
|
+
</div>
|
|
649
|
+
)}
|
|
650
|
+
|
|
651
|
+
<div className="mt-3 rounded-md bg-muted/40 px-3 py-2 text-xs text-muted-foreground">
|
|
652
|
+
{active ? (
|
|
653
|
+
<>
|
|
654
|
+
Active file:{" "}
|
|
655
|
+
<span className="font-mono text-foreground">
|
|
656
|
+
{active.owner}/{active.path}
|
|
657
|
+
</span>
|
|
658
|
+
</>
|
|
659
|
+
) : (
|
|
660
|
+
"No active resource exists for this path yet."
|
|
661
|
+
)}
|
|
662
|
+
</div>
|
|
663
|
+
</div>
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
|
|
303
667
|
function ResourceRow({ resource, grants }: { resource: any; grants: any[] }) {
|
|
304
668
|
const [expanded, setExpanded] = useState(false);
|
|
305
669
|
|
|
306
670
|
const deleteResource = useActionMutation("delete-workspace-resource", {
|
|
307
|
-
onSuccess: () =>
|
|
671
|
+
onSuccess: (result: any) =>
|
|
672
|
+
toast.success(
|
|
673
|
+
workspaceResourceMutationMessage(result, "Resource deleted"),
|
|
674
|
+
),
|
|
308
675
|
onError: (err) => toast.error(String(err)),
|
|
309
676
|
});
|
|
310
677
|
const revokeGrant = useActionMutation("revoke-workspace-resource-grant", {
|
|
311
678
|
onSuccess: () => toast.success("Grant revoked"),
|
|
312
679
|
onError: (err) => toast.error(String(err)),
|
|
313
680
|
});
|
|
314
|
-
const syncToApp = useActionMutation("sync-workspace-resources-to-app", {
|
|
315
|
-
onSuccess: (data: any) =>
|
|
316
|
-
toast.success(`Synced ${data.synced} resource(s) to ${data.appId}`),
|
|
317
|
-
onError: (err) => toast.error(String(err)),
|
|
318
|
-
});
|
|
319
681
|
|
|
320
682
|
const kindInfo = KIND_CONFIG[resource.kind as keyof typeof KIND_CONFIG];
|
|
321
683
|
const KindIcon = kindInfo?.icon || IconCode;
|
|
322
684
|
const activeGrants = grants.filter((g) => g.status === "active");
|
|
323
685
|
|
|
324
686
|
return (
|
|
325
|
-
<div className="rounded-
|
|
687
|
+
<div className="rounded-lg border bg-card">
|
|
326
688
|
<button
|
|
327
689
|
type="button"
|
|
328
690
|
className="flex w-full items-center gap-3 px-4 py-3 text-left cursor-pointer"
|
|
@@ -352,6 +714,11 @@ function ResourceRow({ resource, grants }: { resource: any; grants: any[] }) {
|
|
|
352
714
|
>
|
|
353
715
|
{resource.scope === "all" ? "All apps" : "Selected"}
|
|
354
716
|
</Badge>
|
|
717
|
+
{isAutoLoadedInstruction(resource) && (
|
|
718
|
+
<Badge variant="outline" className="text-xs">
|
|
719
|
+
Auto-loaded
|
|
720
|
+
</Badge>
|
|
721
|
+
)}
|
|
355
722
|
</div>
|
|
356
723
|
<div className="mt-0.5 font-mono text-xs text-muted-foreground">
|
|
357
724
|
{resource.path}
|
|
@@ -381,6 +748,8 @@ function ResourceRow({ resource, grants }: { resource: any; grants: any[] }) {
|
|
|
381
748
|
</pre>
|
|
382
749
|
</div>
|
|
383
750
|
|
|
751
|
+
<EffectiveContextPreview resource={resource} />
|
|
752
|
+
|
|
384
753
|
{resource.scope === "selected" && (
|
|
385
754
|
<div className="space-y-2">
|
|
386
755
|
<div className="flex items-center justify-between">
|
|
@@ -404,22 +773,10 @@ function ResourceRow({ resource, grants }: { resource: any; grants: any[] }) {
|
|
|
404
773
|
{grant.appId}
|
|
405
774
|
</span>
|
|
406
775
|
<span className="ml-2 text-xs text-muted-foreground">
|
|
407
|
-
|
|
408
|
-
? `synced ${new Date(grant.syncedAt).toLocaleString()}`
|
|
409
|
-
: "not synced"}
|
|
776
|
+
selected grant
|
|
410
777
|
</span>
|
|
411
778
|
</div>
|
|
412
779
|
<div className="flex gap-1.5">
|
|
413
|
-
<Button
|
|
414
|
-
variant="ghost"
|
|
415
|
-
size="sm"
|
|
416
|
-
onClick={() =>
|
|
417
|
-
syncToApp.mutate({ appId: grant.appId })
|
|
418
|
-
}
|
|
419
|
-
disabled={syncToApp.isPending}
|
|
420
|
-
>
|
|
421
|
-
<IconRefresh size={14} />
|
|
422
|
-
</Button>
|
|
423
780
|
<Button
|
|
424
781
|
variant="ghost"
|
|
425
782
|
size="sm"
|
|
@@ -447,36 +804,44 @@ function ResourceRow({ resource, grants }: { resource: any; grants: any[] }) {
|
|
|
447
804
|
Created by {resource.createdBy} ·{" "}
|
|
448
805
|
{new Date(resource.createdAt).toLocaleString()}
|
|
449
806
|
</div>
|
|
450
|
-
<
|
|
451
|
-
<
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
Delete
|
|
459
|
-
</Button>
|
|
460
|
-
</AlertDialogTrigger>
|
|
461
|
-
<AlertDialogContent>
|
|
462
|
-
<AlertDialogHeader>
|
|
463
|
-
<AlertDialogTitle>Delete this resource?</AlertDialogTitle>
|
|
464
|
-
<AlertDialogDescription>
|
|
465
|
-
Removing "{resource.name}" revokes all of its grants. Apps
|
|
466
|
-
that depended on this resource will lose access on the next
|
|
467
|
-
sync. This cannot be undone.
|
|
468
|
-
</AlertDialogDescription>
|
|
469
|
-
</AlertDialogHeader>
|
|
470
|
-
<AlertDialogFooter>
|
|
471
|
-
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
472
|
-
<AlertDialogAction
|
|
473
|
-
onClick={() => deleteResource.mutate({ id: resource.id })}
|
|
807
|
+
<div className="flex gap-2">
|
|
808
|
+
<EditResourceDialog resource={resource} />
|
|
809
|
+
<AlertDialog>
|
|
810
|
+
<AlertDialogTrigger asChild>
|
|
811
|
+
<Button
|
|
812
|
+
variant="destructive"
|
|
813
|
+
size="sm"
|
|
814
|
+
disabled={deleteResource.isPending}
|
|
474
815
|
>
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
816
|
+
<IconTrash size={14} className="mr-1" />
|
|
817
|
+
Delete
|
|
818
|
+
</Button>
|
|
819
|
+
</AlertDialogTrigger>
|
|
820
|
+
<AlertDialogContent>
|
|
821
|
+
<AlertDialogHeader>
|
|
822
|
+
<AlertDialogTitle>Delete this resource?</AlertDialogTitle>
|
|
823
|
+
<AlertDialogDescription>
|
|
824
|
+
Removing "{resource.name}" revokes all of its grants and
|
|
825
|
+
removes inherited workspace access immediately. This
|
|
826
|
+
cannot be undone.
|
|
827
|
+
</AlertDialogDescription>
|
|
828
|
+
</AlertDialogHeader>
|
|
829
|
+
<ImpactPreview
|
|
830
|
+
operation="delete"
|
|
831
|
+
resourceId={resource.id}
|
|
832
|
+
enabled
|
|
833
|
+
/>
|
|
834
|
+
<AlertDialogFooter>
|
|
835
|
+
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
836
|
+
<AlertDialogAction
|
|
837
|
+
onClick={() => deleteResource.mutate({ id: resource.id })}
|
|
838
|
+
>
|
|
839
|
+
Delete resource
|
|
840
|
+
</AlertDialogAction>
|
|
841
|
+
</AlertDialogFooter>
|
|
842
|
+
</AlertDialogContent>
|
|
843
|
+
</AlertDialog>
|
|
844
|
+
</div>
|
|
480
845
|
</div>
|
|
481
846
|
</div>
|
|
482
847
|
)}
|
|
@@ -484,6 +849,143 @@ function ResourceRow({ resource, grants }: { resource: any; grants: any[] }) {
|
|
|
484
849
|
);
|
|
485
850
|
}
|
|
486
851
|
|
|
852
|
+
function GlobalContextSection({ resources }: { resources: any[] }) {
|
|
853
|
+
const byPath = new Map(
|
|
854
|
+
resources.map((resource) => [resource.path, resource]),
|
|
855
|
+
);
|
|
856
|
+
const missingPaths = STARTER_GLOBAL_CONTEXT.filter(
|
|
857
|
+
(item) => !byPath.has(item.path),
|
|
858
|
+
).map((item) => item.path);
|
|
859
|
+
const presentCount = STARTER_GLOBAL_CONTEXT.length - missingPaths.length;
|
|
860
|
+
const restoreStarter = useActionMutation(
|
|
861
|
+
"restore-starter-workspace-resources",
|
|
862
|
+
{
|
|
863
|
+
onSuccess: (result: any) => {
|
|
864
|
+
const restored = result?.restored?.length ?? 0;
|
|
865
|
+
const existing = result?.existing?.length ?? 0;
|
|
866
|
+
toast.success(
|
|
867
|
+
restored > 0
|
|
868
|
+
? `Restored ${restored} starter resource${restored === 1 ? "" : "s"}`
|
|
869
|
+
: `Starter resources already present (${existing})`,
|
|
870
|
+
);
|
|
871
|
+
},
|
|
872
|
+
onError: (err) => toast.error(String(err)),
|
|
873
|
+
},
|
|
874
|
+
);
|
|
875
|
+
|
|
876
|
+
return (
|
|
877
|
+
<section className="space-y-3">
|
|
878
|
+
<div className="flex items-center justify-between gap-3">
|
|
879
|
+
<div>
|
|
880
|
+
<h2 className="text-sm font-semibold text-foreground">
|
|
881
|
+
Global context
|
|
882
|
+
</h2>
|
|
883
|
+
<p className="mt-1 text-xs text-muted-foreground">
|
|
884
|
+
Starter resources every workspace can use for company facts, brand,
|
|
885
|
+
messaging, guardrails, and voice.
|
|
886
|
+
</p>
|
|
887
|
+
<p className="mt-1 text-xs text-muted-foreground">
|
|
888
|
+
All-app resources live once at workspace scope and are inherited by
|
|
889
|
+
every app agent at runtime.
|
|
890
|
+
</p>
|
|
891
|
+
</div>
|
|
892
|
+
<div className="flex shrink-0 items-center gap-2">
|
|
893
|
+
{missingPaths.length > 0 ? (
|
|
894
|
+
<Button
|
|
895
|
+
size="sm"
|
|
896
|
+
variant="outline"
|
|
897
|
+
onClick={() => restoreStarter.mutate({ paths: missingPaths })}
|
|
898
|
+
disabled={restoreStarter.isPending}
|
|
899
|
+
>
|
|
900
|
+
<IconPlus size={14} className="mr-1.5" />
|
|
901
|
+
{restoreStarter.isPending ? "Restoring..." : "Restore missing"}
|
|
902
|
+
</Button>
|
|
903
|
+
) : null}
|
|
904
|
+
<Badge variant="outline">
|
|
905
|
+
{presentCount}/{STARTER_GLOBAL_CONTEXT.length} ready
|
|
906
|
+
</Badge>
|
|
907
|
+
</div>
|
|
908
|
+
</div>
|
|
909
|
+
<div className="grid gap-3 md:grid-cols-2 xl:grid-cols-5">
|
|
910
|
+
{STARTER_GLOBAL_CONTEXT.map((item) => {
|
|
911
|
+
const resource = byPath.get(item.path);
|
|
912
|
+
const exists = !!resource;
|
|
913
|
+
const global = resource?.scope === "all";
|
|
914
|
+
return (
|
|
915
|
+
<div key={item.path} className="rounded-lg border bg-card p-4">
|
|
916
|
+
<div className="flex items-start justify-between gap-3">
|
|
917
|
+
<div className="min-w-0">
|
|
918
|
+
<div className="flex items-center gap-2">
|
|
919
|
+
{exists ? (
|
|
920
|
+
<IconCircleCheck
|
|
921
|
+
size={15}
|
|
922
|
+
className="shrink-0 text-green-600 dark:text-green-400"
|
|
923
|
+
/>
|
|
924
|
+
) : (
|
|
925
|
+
<IconAlertCircle
|
|
926
|
+
size={15}
|
|
927
|
+
className="shrink-0 text-amber-600 dark:text-amber-400"
|
|
928
|
+
/>
|
|
929
|
+
)}
|
|
930
|
+
<h3 className="truncate text-sm font-medium text-foreground">
|
|
931
|
+
{item.label}
|
|
932
|
+
</h3>
|
|
933
|
+
</div>
|
|
934
|
+
<p className="mt-1 line-clamp-2 text-xs text-muted-foreground">
|
|
935
|
+
{item.description}
|
|
936
|
+
</p>
|
|
937
|
+
</div>
|
|
938
|
+
{resource ? (
|
|
939
|
+
<EditResourceDialog
|
|
940
|
+
resource={resource}
|
|
941
|
+
trigger={
|
|
942
|
+
<Button variant="ghost" size="sm" className="h-7 px-2">
|
|
943
|
+
<span className="sr-only">Edit {item.label}</span>
|
|
944
|
+
<IconEdit size={14} />
|
|
945
|
+
</Button>
|
|
946
|
+
}
|
|
947
|
+
/>
|
|
948
|
+
) : (
|
|
949
|
+
<Button
|
|
950
|
+
variant="ghost"
|
|
951
|
+
size="sm"
|
|
952
|
+
className="h-7 px-2"
|
|
953
|
+
onClick={() =>
|
|
954
|
+
restoreStarter.mutate({ paths: [item.path] })
|
|
955
|
+
}
|
|
956
|
+
disabled={restoreStarter.isPending}
|
|
957
|
+
aria-label={`Restore ${item.label}`}
|
|
958
|
+
>
|
|
959
|
+
<IconPlus size={14} />
|
|
960
|
+
</Button>
|
|
961
|
+
)}
|
|
962
|
+
</div>
|
|
963
|
+
<div className="mt-3 space-y-2">
|
|
964
|
+
<div className="truncate font-mono text-[11px] text-muted-foreground">
|
|
965
|
+
{item.path}
|
|
966
|
+
</div>
|
|
967
|
+
<div className="flex flex-wrap gap-1.5">
|
|
968
|
+
<Badge variant={exists ? "secondary" : "outline"}>
|
|
969
|
+
{exists ? "Present" : "Missing"}
|
|
970
|
+
</Badge>
|
|
971
|
+
{exists ? (
|
|
972
|
+
<Badge variant="outline">
|
|
973
|
+
{global ? "All apps" : "Selected"}
|
|
974
|
+
</Badge>
|
|
975
|
+
) : null}
|
|
976
|
+
{resource && isAutoLoadedInstruction(resource) ? (
|
|
977
|
+
<Badge variant="outline">Auto-loaded</Badge>
|
|
978
|
+
) : null}
|
|
979
|
+
</div>
|
|
980
|
+
</div>
|
|
981
|
+
</div>
|
|
982
|
+
);
|
|
983
|
+
})}
|
|
984
|
+
</div>
|
|
985
|
+
</section>
|
|
986
|
+
);
|
|
987
|
+
}
|
|
988
|
+
|
|
487
989
|
export default function WorkspaceRoute() {
|
|
488
990
|
const { data: resources, isLoading } = useActionQuery(
|
|
489
991
|
"list-workspace-resources",
|
|
@@ -491,19 +993,6 @@ export default function WorkspaceRoute() {
|
|
|
491
993
|
);
|
|
492
994
|
const { data: grants } = useActionQuery("list-workspace-resource-grants", {});
|
|
493
995
|
|
|
494
|
-
const syncAll = useActionMutation("sync-workspace-resources-to-all", {
|
|
495
|
-
onSuccess: (data: any) => {
|
|
496
|
-
const total = (data || []).reduce(
|
|
497
|
-
(sum: number, r: any) => sum + r.synced,
|
|
498
|
-
0,
|
|
499
|
-
);
|
|
500
|
-
toast.success(
|
|
501
|
-
`Synced resources to ${data?.length || 0} apps (${total} total pushes)`,
|
|
502
|
-
);
|
|
503
|
-
},
|
|
504
|
-
onError: (err) => toast.error(String(err)),
|
|
505
|
-
});
|
|
506
|
-
|
|
507
996
|
const grantsByResource = (grants || []).reduce(
|
|
508
997
|
(acc: Record<string, any[]>, g: any) => {
|
|
509
998
|
if (!acc[g.resourceId]) acc[g.resourceId] = [];
|
|
@@ -535,7 +1024,7 @@ export default function WorkspaceRoute() {
|
|
|
535
1024
|
{Array.from({ length: 3 }).map((_, index) => (
|
|
536
1025
|
<div
|
|
537
1026
|
key={index}
|
|
538
|
-
className="rounded-
|
|
1027
|
+
className="rounded-lg border bg-card px-5 py-4 space-y-2"
|
|
539
1028
|
>
|
|
540
1029
|
<Skeleton className="h-4 w-1/3" />
|
|
541
1030
|
<Skeleton className="h-3 w-2/3" />
|
|
@@ -546,7 +1035,7 @@ export default function WorkspaceRoute() {
|
|
|
546
1035
|
}
|
|
547
1036
|
if (items.length === 0) {
|
|
548
1037
|
return (
|
|
549
|
-
<div className="rounded-
|
|
1038
|
+
<div className="rounded-lg border border-dashed px-6 py-12 text-center text-sm text-muted-foreground">
|
|
550
1039
|
{emptyText}
|
|
551
1040
|
</div>
|
|
552
1041
|
);
|
|
@@ -567,7 +1056,7 @@ export default function WorkspaceRoute() {
|
|
|
567
1056
|
return (
|
|
568
1057
|
<DispatchShell
|
|
569
1058
|
title="Workspace Resources"
|
|
570
|
-
description="
|
|
1059
|
+
description="Manage inherited workspace skills, guardrail instructions, agent profiles, and reference resources. All-app resources are available to every app without syncing."
|
|
571
1060
|
>
|
|
572
1061
|
<div className="flex items-center justify-between">
|
|
573
1062
|
<div className="text-sm text-muted-foreground">
|
|
@@ -578,21 +1067,12 @@ export default function WorkspaceRoute() {
|
|
|
578
1067
|
)}
|
|
579
1068
|
</div>
|
|
580
1069
|
<div className="flex gap-2">
|
|
581
|
-
<Button
|
|
582
|
-
variant="outline"
|
|
583
|
-
onClick={() => syncAll.mutate({})}
|
|
584
|
-
disabled={syncAll.isPending || (resources?.length || 0) === 0}
|
|
585
|
-
>
|
|
586
|
-
<IconRefresh
|
|
587
|
-
size={16}
|
|
588
|
-
className={syncAll.isPending ? "mr-1.5 animate-spin" : "mr-1.5"}
|
|
589
|
-
/>
|
|
590
|
-
Sync all
|
|
591
|
-
</Button>
|
|
592
1070
|
<AddResourceDialog />
|
|
593
1071
|
</div>
|
|
594
1072
|
</div>
|
|
595
1073
|
|
|
1074
|
+
<GlobalContextSection resources={resources || []} />
|
|
1075
|
+
|
|
596
1076
|
<Tabs defaultValue="skills">
|
|
597
1077
|
<TabsList>
|
|
598
1078
|
<TabsTrigger value="skills">
|