@agent-native/dispatch 0.2.10 → 0.2.12
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/dist/actions/create-workspace-resource.js +4 -4
- package/dist/actions/create-workspace-resource.js.map +1 -1
- package/dist/actions/grant-workspace-resources-to-app.d.ts +3 -0
- package/dist/actions/grant-workspace-resources-to-app.d.ts.map +1 -0
- package/dist/actions/grant-workspace-resources-to-app.js +15 -0
- package/dist/actions/grant-workspace-resources-to-app.js.map +1 -0
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +4 -0
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/list-workspace-resource-options.d.ts +3 -0
- package/dist/actions/list-workspace-resource-options.d.ts.map +1 -0
- package/dist/actions/list-workspace-resource-options.js +15 -0
- package/dist/actions/list-workspace-resource-options.js.map +1 -0
- package/dist/actions/list-workspace-resources.js +2 -2
- package/dist/actions/list-workspace-resources.js.map +1 -1
- package/dist/actions/start-workspace-app-creation.d.ts.map +1 -1
- package/dist/actions/start-workspace-app-creation.js +5 -0
- package/dist/actions/start-workspace-app-creation.js.map +1 -1
- package/dist/actions/view-screen.d.ts.map +1 -1
- package/dist/actions/view-screen.js +4 -0
- package/dist/actions/view-screen.js.map +1 -1
- package/dist/components/create-app-popover.d.ts +1 -1
- package/dist/components/create-app-popover.d.ts.map +1 -1
- package/dist/components/create-app-popover.js +63 -20
- package/dist/components/create-app-popover.js.map +1 -1
- package/dist/db/schema.js +2 -2
- package/dist/db/schema.js.map +1 -1
- package/dist/routes/pages/overview.d.ts.map +1 -1
- package/dist/routes/pages/overview.js +6 -6
- package/dist/routes/pages/overview.js.map +1 -1
- package/dist/routes/pages/workspace.d.ts.map +1 -1
- package/dist/routes/pages/workspace.js +17 -6
- package/dist/routes/pages/workspace.js.map +1 -1
- package/dist/server/lib/app-creation-store.d.ts +1 -0
- package/dist/server/lib/app-creation-store.d.ts.map +1 -1
- package/dist/server/lib/app-creation-store.js +33 -0
- package/dist/server/lib/app-creation-store.js.map +1 -1
- package/dist/server/lib/workspace-resources-store.d.ts +29 -1
- package/dist/server/lib/workspace-resources-store.d.ts.map +1 -1
- package/dist/server/lib/workspace-resources-store.js +46 -0
- package/dist/server/lib/workspace-resources-store.js.map +1 -1
- package/package.json +2 -3
- package/src/actions/create-workspace-resource.ts +4 -4
- package/src/actions/grant-workspace-resources-to-app.ts +16 -0
- package/src/actions/index.ts +4 -0
- package/src/actions/list-workspace-resource-options.ts +16 -0
- package/src/actions/list-workspace-resources.ts +2 -2
- package/src/actions/start-workspace-app-creation.ts +7 -0
- package/src/actions/view-screen.ts +4 -0
- package/src/components/create-app-popover.tsx +152 -21
- package/src/db/schema.ts +2 -2
- package/src/routes/pages/overview.tsx +21 -19
- package/src/routes/pages/workspace.tsx +31 -5
- package/src/server/lib/app-creation-store.ts +49 -0
- package/src/server/lib/workspace-resources-store.ts +75 -1
|
@@ -20,6 +20,11 @@ import {
|
|
|
20
20
|
} from "./dispatch-store.js";
|
|
21
21
|
import { identityKeyForIncoming } from "./dispatch-integrations.js";
|
|
22
22
|
import { createRequest, listSecrets } from "./vault-store.js";
|
|
23
|
+
import {
|
|
24
|
+
grantWorkspaceResourcesToApp,
|
|
25
|
+
listWorkspaceResourceOptions,
|
|
26
|
+
type WorkspaceResourceOption,
|
|
27
|
+
} from "./workspace-resources-store.js";
|
|
23
28
|
|
|
24
29
|
const SETTINGS_KEY = "dispatch-app-creation-settings";
|
|
25
30
|
const WORKSPACE_APPS_ENV_KEY = "AGENT_NATIVE_WORKSPACE_APPS_JSON";
|
|
@@ -827,6 +832,7 @@ function buildWorkspaceAppPrompt(input: {
|
|
|
827
832
|
appId?: string | null;
|
|
828
833
|
template?: string | null;
|
|
829
834
|
selectedKeys?: string[];
|
|
835
|
+
selectedResources?: WorkspaceResourceOption[];
|
|
830
836
|
}): { appId: string; prompt: string } {
|
|
831
837
|
const appId =
|
|
832
838
|
slugify(input.appId || "") ||
|
|
@@ -835,6 +841,15 @@ function buildWorkspaceAppPrompt(input: {
|
|
|
835
841
|
) ||
|
|
836
842
|
"new-app";
|
|
837
843
|
const selectedKeys = input.selectedKeys || [];
|
|
844
|
+
const selectedResources = input.selectedResources || [];
|
|
845
|
+
const resourceList = selectedResources.length
|
|
846
|
+
? selectedResources
|
|
847
|
+
.map(
|
|
848
|
+
(resource) =>
|
|
849
|
+
`- ${resource.name} (${resource.kind}, ${resource.path})`,
|
|
850
|
+
)
|
|
851
|
+
.join("\n")
|
|
852
|
+
: "none";
|
|
838
853
|
return {
|
|
839
854
|
appId,
|
|
840
855
|
prompt: [
|
|
@@ -846,11 +861,15 @@ function buildWorkspaceAppPrompt(input: {
|
|
|
846
861
|
selectedKeys.length
|
|
847
862
|
? `Dispatch vault keys selected for this app: ${selectedKeys.join(", ")}`
|
|
848
863
|
: "Dispatch vault keys selected for this app: none",
|
|
864
|
+
`Dispatch workspace resources selected for this app:\n${resourceList}`,
|
|
849
865
|
"",
|
|
850
866
|
`Use the workspace app layout: create it under apps/${appId}, mount it at /${appId}, keep it on the shared workspace database/hosting model, and avoid table-name collisions by namespacing any new domain tables to the app.`,
|
|
851
867
|
selectedKeys.length
|
|
852
868
|
? `Dispatch will create pending vault requests for the selected keys for appId "${appId}" after this app creation request is accepted. Do not grant or sync vault keys directly from the app-creation branch.`
|
|
853
869
|
: "Do not grant or request any Dispatch vault keys unless the user asks later.",
|
|
870
|
+
selectedResources.length
|
|
871
|
+
? `Dispatch will create workspace resource grants for the selected resources for appId "${appId}". After the app exists, sync workspace resources so the app receives those shared resources. Add a short note to apps/${appId}/AGENTS.md telling the app agent to read relevant shared resources under context/ or the selected resource paths before doing GTM/domain work.`
|
|
872
|
+
: "Do not grant any Dispatch workspace resources unless the user asks later.",
|
|
854
873
|
"",
|
|
855
874
|
"Agent-native rules (these are the framework's contract — not optional):",
|
|
856
875
|
`- Persist ALL data in SQL via Drizzle. Add tables to apps/${appId}/server/db/schema.ts and migrations to apps/${appId}/server/plugins/db.ts. NEVER use localStorage, sessionStorage, IndexedDB, or in-memory state for anything the user expects to persist — agent and UI must read the same source of truth.`,
|
|
@@ -890,11 +909,29 @@ async function requestSelectedVaultKeys(input: {
|
|
|
890
909
|
);
|
|
891
910
|
}
|
|
892
911
|
|
|
912
|
+
async function selectedWorkspaceResourcesForIds(
|
|
913
|
+
resourceIds: string[] | undefined,
|
|
914
|
+
): Promise<WorkspaceResourceOption[]> {
|
|
915
|
+
if (!resourceIds?.length) return [];
|
|
916
|
+
const requested = new Set(resourceIds);
|
|
917
|
+
const resources = await listWorkspaceResourceOptions();
|
|
918
|
+
return resources.filter((resource) => requested.has(resource.id));
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
async function grantSelectedWorkspaceResources(input: {
|
|
922
|
+
appId: string;
|
|
923
|
+
resourceIds: string[];
|
|
924
|
+
}) {
|
|
925
|
+
if (input.resourceIds.length === 0) return;
|
|
926
|
+
await grantWorkspaceResourcesToApp(input);
|
|
927
|
+
}
|
|
928
|
+
|
|
893
929
|
export async function startWorkspaceAppCreation(input: {
|
|
894
930
|
prompt: string;
|
|
895
931
|
appId?: string | null;
|
|
896
932
|
template?: string | null;
|
|
897
933
|
secretIds?: string[];
|
|
934
|
+
resourceIds?: string[];
|
|
898
935
|
}) {
|
|
899
936
|
const initial = buildWorkspaceAppPrompt({
|
|
900
937
|
prompt: input.prompt,
|
|
@@ -920,11 +957,15 @@ export async function startWorkspaceAppCreation(input: {
|
|
|
920
957
|
.filter((secret) => input.secretIds?.includes(secret.id))
|
|
921
958
|
.map((secret) => secret.credentialKey)
|
|
922
959
|
: [];
|
|
960
|
+
const selectedResources = await selectedWorkspaceResourcesForIds(
|
|
961
|
+
input.resourceIds,
|
|
962
|
+
);
|
|
923
963
|
const built = buildWorkspaceAppPrompt({
|
|
924
964
|
prompt: input.prompt,
|
|
925
965
|
appId: input.appId,
|
|
926
966
|
template: input.template,
|
|
927
967
|
selectedKeys,
|
|
968
|
+
selectedResources,
|
|
928
969
|
});
|
|
929
970
|
const prompt = built.prompt;
|
|
930
971
|
|
|
@@ -933,6 +974,10 @@ export async function startWorkspaceAppCreation(input: {
|
|
|
933
974
|
appId: built.appId,
|
|
934
975
|
selectedKeys,
|
|
935
976
|
});
|
|
977
|
+
await grantSelectedWorkspaceResources({
|
|
978
|
+
appId: built.appId,
|
|
979
|
+
resourceIds: selectedResources.map((resource) => resource.id),
|
|
980
|
+
});
|
|
936
981
|
return {
|
|
937
982
|
mode: "local-agent",
|
|
938
983
|
appId: built.appId,
|
|
@@ -997,6 +1042,10 @@ export async function startWorkspaceAppCreation(input: {
|
|
|
997
1042
|
appId: built.appId,
|
|
998
1043
|
selectedKeys,
|
|
999
1044
|
});
|
|
1045
|
+
await grantSelectedWorkspaceResources({
|
|
1046
|
+
appId: built.appId,
|
|
1047
|
+
resourceIds: selectedResources.map((resource) => resource.id),
|
|
1048
|
+
});
|
|
1000
1049
|
|
|
1001
1050
|
return {
|
|
1002
1051
|
mode: "builder",
|
|
@@ -54,7 +54,11 @@ function orgFilter<T extends { ownerEmail: any; orgId: any }>(table: T) {
|
|
|
54
54
|
|
|
55
55
|
// ─── Workspace Resources CRUD ──────────────────────────────────
|
|
56
56
|
|
|
57
|
-
export type WorkspaceResourceKind =
|
|
57
|
+
export type WorkspaceResourceKind =
|
|
58
|
+
| "skill"
|
|
59
|
+
| "instruction"
|
|
60
|
+
| "agent"
|
|
61
|
+
| "knowledge";
|
|
58
62
|
export type WorkspaceResourceScope = "all" | "selected";
|
|
59
63
|
|
|
60
64
|
export interface WorkspaceResourceInput {
|
|
@@ -66,6 +70,16 @@ export interface WorkspaceResourceInput {
|
|
|
66
70
|
scope: WorkspaceResourceScope;
|
|
67
71
|
}
|
|
68
72
|
|
|
73
|
+
export interface WorkspaceResourceOption {
|
|
74
|
+
id: string;
|
|
75
|
+
kind: WorkspaceResourceKind;
|
|
76
|
+
name: string;
|
|
77
|
+
description: string | null;
|
|
78
|
+
path: string;
|
|
79
|
+
scope: WorkspaceResourceScope;
|
|
80
|
+
updatedAt: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
69
83
|
export async function listWorkspaceResources(filter?: { kind?: string }) {
|
|
70
84
|
const db = getDb();
|
|
71
85
|
const conditions = [orgFilter(schema.workspaceResources)];
|
|
@@ -79,6 +93,21 @@ export async function listWorkspaceResources(filter?: { kind?: string }) {
|
|
|
79
93
|
.orderBy(desc(schema.workspaceResources.updatedAt));
|
|
80
94
|
}
|
|
81
95
|
|
|
96
|
+
export async function listWorkspaceResourceOptions(filter?: {
|
|
97
|
+
kind?: string;
|
|
98
|
+
}): Promise<WorkspaceResourceOption[]> {
|
|
99
|
+
const resources = await listWorkspaceResources(filter);
|
|
100
|
+
return resources.map((resource) => ({
|
|
101
|
+
id: resource.id,
|
|
102
|
+
kind: resource.kind as WorkspaceResourceKind,
|
|
103
|
+
name: resource.name,
|
|
104
|
+
description: resource.description,
|
|
105
|
+
path: resource.path,
|
|
106
|
+
scope: resource.scope as WorkspaceResourceScope,
|
|
107
|
+
updatedAt: resource.updatedAt,
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
|
|
82
111
|
export async function getWorkspaceResource(
|
|
83
112
|
resourceId: string,
|
|
84
113
|
ctx: WorkspaceResourceCtx = requireWorkspaceResourceCtx(),
|
|
@@ -248,6 +277,13 @@ export async function createResourceGrant(resourceId: string, appId: string) {
|
|
|
248
277
|
const resource = await getWorkspaceResource(resourceId, ctx);
|
|
249
278
|
if (!resource) throw new Error("Workspace resource not found");
|
|
250
279
|
|
|
280
|
+
const activeExisting = (await listResourceGrants({ resourceId, appId })).find(
|
|
281
|
+
(grant) => grant.status === "active",
|
|
282
|
+
);
|
|
283
|
+
if (activeExisting) {
|
|
284
|
+
return activeExisting;
|
|
285
|
+
}
|
|
286
|
+
|
|
251
287
|
const timestamp = now();
|
|
252
288
|
const grantId = id();
|
|
253
289
|
const actor = currentOwnerEmail();
|
|
@@ -274,6 +310,42 @@ export async function createResourceGrant(resourceId: string, appId: string) {
|
|
|
274
310
|
return getResourceGrant(grantId);
|
|
275
311
|
}
|
|
276
312
|
|
|
313
|
+
export async function grantWorkspaceResourcesToApp(input: {
|
|
314
|
+
appId: string;
|
|
315
|
+
resourceIds: string[];
|
|
316
|
+
}) {
|
|
317
|
+
const uniqueResourceIds = [...new Set(input.resourceIds.filter(Boolean))];
|
|
318
|
+
if (uniqueResourceIds.length === 0) {
|
|
319
|
+
return { appId: input.appId, granted: [], skipped: [] };
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const granted: Array<{ id: string; resourceId: string; appId: string }> = [];
|
|
323
|
+
const skipped: Array<{ resourceId: string; reason: string }> = [];
|
|
324
|
+
|
|
325
|
+
for (const resourceId of uniqueResourceIds) {
|
|
326
|
+
const resource = await getWorkspaceResource(resourceId).catch(() => null);
|
|
327
|
+
if (!resource) {
|
|
328
|
+
skipped.push({ resourceId, reason: "not-found" });
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
if (resource.scope === "all") {
|
|
332
|
+
skipped.push({ resourceId, reason: "already-all-apps" });
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const grant = await createResourceGrant(resourceId, input.appId);
|
|
337
|
+
if (grant) {
|
|
338
|
+
granted.push({
|
|
339
|
+
id: grant.id,
|
|
340
|
+
resourceId: grant.resourceId,
|
|
341
|
+
appId: grant.appId,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return { appId: input.appId, granted, skipped };
|
|
347
|
+
}
|
|
348
|
+
|
|
277
349
|
export async function revokeResourceGrant(
|
|
278
350
|
grantId: string,
|
|
279
351
|
ctx: WorkspaceResourceCtx = requireWorkspaceResourceCtx(),
|
|
@@ -433,12 +505,14 @@ export async function listWorkspaceResourcesOverview() {
|
|
|
433
505
|
const skills = resources.filter((r) => r.kind === "skill");
|
|
434
506
|
const instructions = resources.filter((r) => r.kind === "instruction");
|
|
435
507
|
const agents = resources.filter((r) => r.kind === "agent");
|
|
508
|
+
const knowledge = resources.filter((r) => r.kind === "knowledge");
|
|
436
509
|
const activeGrants = grants.filter((g) => g.status === "active");
|
|
437
510
|
|
|
438
511
|
return {
|
|
439
512
|
skillCount: skills.length,
|
|
440
513
|
instructionCount: instructions.length,
|
|
441
514
|
agentCount: agents.length,
|
|
515
|
+
knowledgeCount: knowledge.length,
|
|
442
516
|
totalResources: resources.length,
|
|
443
517
|
activeGrantCount: activeGrants.length,
|
|
444
518
|
};
|