@agent-native/dispatch 0.2.11 → 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.
Files changed (51) hide show
  1. package/dist/actions/create-workspace-resource.js +4 -4
  2. package/dist/actions/create-workspace-resource.js.map +1 -1
  3. package/dist/actions/grant-workspace-resources-to-app.d.ts +3 -0
  4. package/dist/actions/grant-workspace-resources-to-app.d.ts.map +1 -0
  5. package/dist/actions/grant-workspace-resources-to-app.js +15 -0
  6. package/dist/actions/grant-workspace-resources-to-app.js.map +1 -0
  7. package/dist/actions/index.d.ts.map +1 -1
  8. package/dist/actions/index.js +4 -0
  9. package/dist/actions/index.js.map +1 -1
  10. package/dist/actions/list-workspace-resource-options.d.ts +3 -0
  11. package/dist/actions/list-workspace-resource-options.d.ts.map +1 -0
  12. package/dist/actions/list-workspace-resource-options.js +15 -0
  13. package/dist/actions/list-workspace-resource-options.js.map +1 -0
  14. package/dist/actions/list-workspace-resources.js +2 -2
  15. package/dist/actions/list-workspace-resources.js.map +1 -1
  16. package/dist/actions/start-workspace-app-creation.d.ts.map +1 -1
  17. package/dist/actions/start-workspace-app-creation.js +5 -0
  18. package/dist/actions/start-workspace-app-creation.js.map +1 -1
  19. package/dist/actions/view-screen.d.ts.map +1 -1
  20. package/dist/actions/view-screen.js +4 -0
  21. package/dist/actions/view-screen.js.map +1 -1
  22. package/dist/components/create-app-popover.d.ts +1 -1
  23. package/dist/components/create-app-popover.d.ts.map +1 -1
  24. package/dist/components/create-app-popover.js +63 -20
  25. package/dist/components/create-app-popover.js.map +1 -1
  26. package/dist/db/schema.js +2 -2
  27. package/dist/db/schema.js.map +1 -1
  28. package/dist/routes/pages/workspace.d.ts.map +1 -1
  29. package/dist/routes/pages/workspace.js +17 -6
  30. package/dist/routes/pages/workspace.js.map +1 -1
  31. package/dist/server/lib/app-creation-store.d.ts +1 -0
  32. package/dist/server/lib/app-creation-store.d.ts.map +1 -1
  33. package/dist/server/lib/app-creation-store.js +33 -0
  34. package/dist/server/lib/app-creation-store.js.map +1 -1
  35. package/dist/server/lib/workspace-resources-store.d.ts +29 -1
  36. package/dist/server/lib/workspace-resources-store.d.ts.map +1 -1
  37. package/dist/server/lib/workspace-resources-store.js +46 -0
  38. package/dist/server/lib/workspace-resources-store.js.map +1 -1
  39. package/package.json +2 -2
  40. package/src/actions/create-workspace-resource.ts +4 -4
  41. package/src/actions/grant-workspace-resources-to-app.ts +16 -0
  42. package/src/actions/index.ts +4 -0
  43. package/src/actions/list-workspace-resource-options.ts +16 -0
  44. package/src/actions/list-workspace-resources.ts +2 -2
  45. package/src/actions/start-workspace-app-creation.ts +7 -0
  46. package/src/actions/view-screen.ts +4 -0
  47. package/src/components/create-app-popover.tsx +152 -21
  48. package/src/db/schema.ts +2 -2
  49. package/src/routes/pages/workspace.tsx +31 -5
  50. package/src/server/lib/app-creation-store.ts +49 -0
  51. package/src/server/lib/workspace-resources-store.ts +75 -1
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-resources-store.js","sourceRoot":"","sources":["../../../src/server/lib/workspace-resources-store.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"node:crypto\";\nimport { and, desc, eq, isNull, or } from \"drizzle-orm\";\nimport { discoverAgents } from \"@agent-native/core/server/agent-discovery\";\nimport { getDb, schema } from \"../../db/index.js\";\nimport {\n currentOwnerEmail,\n currentOrgId,\n recordAudit,\n} from \"./dispatch-store.js\";\nimport { recordVaultAudit } from \"./vault-store.js\";\n\n/**\n * Caller-supplied access context for workspace-resource operations.\n * Same shape and semantics as VaultCtx — looking up a row by id alone is\n * unsafe because UUIDs are not authorization. A row matches the ctx if\n * either the caller owns it or it lives in the caller's active org.\n */\nexport interface WorkspaceResourceCtx {\n ownerEmail: string;\n orgId: string | null;\n}\n\nexport function requireWorkspaceResourceCtx(): WorkspaceResourceCtx {\n const ownerEmail = currentOwnerEmail();\n return { ownerEmail, orgId: currentOrgId() };\n}\n\n/** WHERE clause that limits a workspace-resource row to the caller's scope. */\nfunction ctxScope<T extends { ownerEmail: any; orgId: any }>(\n table: T,\n ctx: WorkspaceResourceCtx,\n) {\n if (!ctx.orgId) {\n return and(eq(table.ownerEmail, ctx.ownerEmail), isNull(table.orgId));\n }\n return or(eq(table.ownerEmail, ctx.ownerEmail), eq(table.orgId, ctx.orgId));\n}\n\nfunction id() {\n return crypto.randomUUID();\n}\n\nfunction now() {\n return Date.now();\n}\n\nfunction orgFilter<T extends { ownerEmail: any; orgId: any }>(table: T) {\n const orgId = currentOrgId();\n return and(\n eq(table.ownerEmail, currentOwnerEmail()),\n orgId ? eq(table.orgId, orgId) : isNull(table.orgId),\n );\n}\n\n// ─── Workspace Resources CRUD ──────────────────────────────────\n\nexport type WorkspaceResourceKind = \"skill\" | \"instruction\" | \"agent\";\nexport type WorkspaceResourceScope = \"all\" | \"selected\";\n\nexport interface WorkspaceResourceInput {\n kind: WorkspaceResourceKind;\n name: string;\n description?: string | null;\n path: string;\n content: string;\n scope: WorkspaceResourceScope;\n}\n\nexport async function listWorkspaceResources(filter?: { kind?: string }) {\n const db = getDb();\n const conditions = [orgFilter(schema.workspaceResources)];\n if (filter?.kind) {\n conditions.push(eq(schema.workspaceResources.kind, filter.kind) as any);\n }\n return db\n .select()\n .from(schema.workspaceResources)\n .where(and(...conditions))\n .orderBy(desc(schema.workspaceResources.updatedAt));\n}\n\nexport async function getWorkspaceResource(\n resourceId: string,\n ctx: WorkspaceResourceCtx = requireWorkspaceResourceCtx(),\n) {\n const db = getDb();\n const [row] = await db\n .select()\n .from(schema.workspaceResources)\n .where(\n and(\n eq(schema.workspaceResources.id, resourceId),\n ctxScope(schema.workspaceResources, ctx),\n ),\n )\n .limit(1);\n return row ?? null;\n}\n\nexport async function createWorkspaceResource(input: WorkspaceResourceInput) {\n const db = getDb();\n const timestamp = now();\n const resourceId = id();\n const actor = currentOwnerEmail();\n\n await db.insert(schema.workspaceResources).values({\n id: resourceId,\n ownerEmail: actor,\n orgId: currentOrgId(),\n kind: input.kind,\n name: input.name,\n description: input.description || null,\n path: input.path,\n content: input.content,\n scope: input.scope,\n createdBy: actor,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n\n await recordAudit({\n action: `workspace.${input.kind}.created`,\n targetType: `workspace-${input.kind}`,\n targetId: resourceId,\n summary: `Created workspace ${input.kind} \"${input.name}\" (${input.path})`,\n });\n\n return getWorkspaceResource(resourceId);\n}\n\nexport async function updateWorkspaceResource(\n resourceId: string,\n input: Partial<\n Pick<WorkspaceResourceInput, \"name\" | \"description\" | \"content\" | \"scope\">\n >,\n) {\n const db = getDb();\n const ctx = requireWorkspaceResourceCtx();\n const existing = await getWorkspaceResource(resourceId, ctx);\n if (!existing) throw new Error(\"Workspace resource not found\");\n\n const updates: Record<string, unknown> = { updatedAt: now() };\n if (input.name !== undefined) updates.name = input.name;\n if (input.description !== undefined)\n updates.description = input.description || null;\n if (input.content !== undefined) updates.content = input.content;\n if (input.scope !== undefined) updates.scope = input.scope;\n\n await db\n .update(schema.workspaceResources)\n .set(updates)\n .where(\n and(\n eq(schema.workspaceResources.id, resourceId),\n ctxScope(schema.workspaceResources, ctx),\n ),\n );\n\n await recordAudit({\n action: `workspace.${existing.kind}.updated`,\n targetType: `workspace-${existing.kind}`,\n targetId: resourceId,\n summary: `Updated workspace ${existing.kind} \"${input.name || existing.name}\"`,\n });\n\n return getWorkspaceResource(resourceId, ctx);\n}\n\nexport async function deleteWorkspaceResource(resourceId: string) {\n const db = getDb();\n const ctx = requireWorkspaceResourceCtx();\n const existing = await getWorkspaceResource(resourceId, ctx);\n if (!existing) throw new Error(\"Workspace resource not found\");\n\n // Revoke all grants\n const grants = await listResourceGrants({ resourceId });\n for (const grant of grants) {\n if (grant.status === \"active\") {\n await revokeResourceGrant(grant.id);\n }\n }\n\n await db\n .delete(schema.workspaceResources)\n .where(\n and(\n eq(schema.workspaceResources.id, resourceId),\n ctxScope(schema.workspaceResources, ctx),\n ),\n );\n\n await recordAudit({\n action: `workspace.${existing.kind}.deleted`,\n targetType: `workspace-${existing.kind}`,\n targetId: resourceId,\n summary: `Deleted workspace ${existing.kind} \"${existing.name}\" (${existing.path})`,\n });\n\n return existing;\n}\n\n// ─── Grants ──────────────────────────────────────────────────────\n\nexport async function listResourceGrants(filter?: {\n resourceId?: string;\n appId?: string;\n}) {\n const db = getDb();\n const conditions = [orgFilter(schema.workspaceResourceGrants)];\n if (filter?.resourceId) {\n conditions.push(\n eq(schema.workspaceResourceGrants.resourceId, filter.resourceId) as any,\n );\n }\n if (filter?.appId) {\n conditions.push(\n eq(schema.workspaceResourceGrants.appId, filter.appId) as any,\n );\n }\n return db\n .select()\n .from(schema.workspaceResourceGrants)\n .where(and(...conditions))\n .orderBy(desc(schema.workspaceResourceGrants.updatedAt));\n}\n\nexport async function getResourceGrant(\n grantId: string,\n ctx: WorkspaceResourceCtx = requireWorkspaceResourceCtx(),\n) {\n const db = getDb();\n const [row] = await db\n .select()\n .from(schema.workspaceResourceGrants)\n .where(\n and(\n eq(schema.workspaceResourceGrants.id, grantId),\n ctxScope(schema.workspaceResourceGrants, ctx),\n ),\n )\n .limit(1);\n return row ?? null;\n}\n\nexport async function createResourceGrant(resourceId: string, appId: string) {\n const db = getDb();\n const ctx = requireWorkspaceResourceCtx();\n const resource = await getWorkspaceResource(resourceId, ctx);\n if (!resource) throw new Error(\"Workspace resource not found\");\n\n const timestamp = now();\n const grantId = id();\n const actor = currentOwnerEmail();\n\n await db.insert(schema.workspaceResourceGrants).values({\n id: grantId,\n ownerEmail: actor,\n orgId: currentOrgId(),\n resourceId,\n appId,\n status: \"active\",\n syncedAt: null,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n\n await recordAudit({\n action: `workspace.${resource.kind}.granted`,\n targetType: `workspace-${resource.kind}-grant`,\n targetId: grantId,\n summary: `Granted workspace ${resource.kind} \"${resource.name}\" to ${appId}`,\n });\n\n return getResourceGrant(grantId);\n}\n\nexport async function revokeResourceGrant(\n grantId: string,\n ctx: WorkspaceResourceCtx = requireWorkspaceResourceCtx(),\n) {\n const db = getDb();\n const grant = await getResourceGrant(grantId, ctx);\n if (!grant) throw new Error(\"Grant not found\");\n\n const resource = await getWorkspaceResource(grant.resourceId);\n\n await db\n .update(schema.workspaceResourceGrants)\n .set({ status: \"revoked\", updatedAt: now() })\n .where(\n and(\n eq(schema.workspaceResourceGrants.id, grantId),\n ctxScope(schema.workspaceResourceGrants, ctx),\n ),\n );\n\n await recordAudit({\n action: `workspace.${resource?.kind || \"resource\"}.grant-revoked`,\n targetType: \"workspace-resource-grant\",\n targetId: grantId,\n summary: `Revoked workspace ${resource?.kind || \"resource\"} \"${resource?.name || grant.resourceId}\" from ${grant.appId}`,\n });\n\n return getResourceGrant(grantId, ctx);\n}\n\n// ─── Sync ──────────────────────────────────────────────────────\n\n/**\n * Push workspace resources to an app via its /_agent-native/resources endpoint.\n * Resources with scope=\"all\" are always pushed. Resources with scope=\"selected\"\n * are only pushed if there's an active grant for that app.\n */\nexport async function syncResourcesToApp(appId: string) {\n const agents = await discoverAgents(\"dispatch\");\n const agent = agents.find((a) => a.id === appId);\n if (!agent) throw new Error(`App \"${appId}\" not found in agent registry`);\n\n const allResources = await listWorkspaceResources();\n const grants = await listResourceGrants({ appId });\n const activeGrantResourceIds = new Set(\n grants.filter((g) => g.status === \"active\").map((g) => g.resourceId),\n );\n\n // Determine which resources to push\n const toPush = allResources.filter(\n (r) =>\n r.scope === \"all\" ||\n (r.scope === \"selected\" && activeGrantResourceIds.has(r.id)),\n );\n\n if (toPush.length === 0) {\n return { appId, synced: 0, resources: [] };\n }\n\n const syncedPaths: string[] = [];\n const db = getDb();\n const timestamp = now();\n\n for (const resource of toPush) {\n try {\n // Push via the resources API — create as shared resource\n const res = await fetch(`${agent.url}/_agent-native/resources`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n path: resource.path,\n content: resource.content,\n shared: true,\n mimeType: \"text/markdown\",\n }),\n });\n\n if (res.ok || res.status === 409) {\n // 409 = already exists, try updating\n if (res.status === 409) {\n // Fetch existing to get ID, then update\n const listRes = await fetch(\n `${agent.url}/_agent-native/resources?scope=shared&path=${encodeURIComponent(resource.path)}`,\n );\n if (listRes.ok) {\n const items = await listRes.json();\n const existing = Array.isArray(items)\n ? items.find((i: any) => i.path === resource.path)\n : null;\n if (existing) {\n await fetch(\n `${agent.url}/_agent-native/resources/${existing.id}`,\n {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ content: resource.content }),\n },\n );\n }\n }\n }\n syncedPaths.push(resource.path);\n\n // Update grant syncedAt if applicable\n const grant = grants.find(\n (g) => g.resourceId === resource.id && g.status === \"active\",\n );\n if (grant) {\n await db\n .update(schema.workspaceResourceGrants)\n .set({ syncedAt: timestamp, updatedAt: timestamp })\n .where(eq(schema.workspaceResourceGrants.id, grant.id));\n }\n }\n } catch {\n // Skip unreachable — don't fail the whole sync\n }\n }\n\n await recordAudit({\n action: \"workspace.resources.synced\",\n targetType: \"workspace-resource-sync\",\n targetId: appId,\n summary: `Synced ${syncedPaths.length} workspace resource(s) to ${appId}: ${syncedPaths.join(\", \")}`,\n });\n\n return { appId, synced: syncedPaths.length, resources: syncedPaths };\n}\n\n/**\n * Sync all workspace resources to all apps that have grants or scope=\"all\" resources.\n */\nexport async function syncResourcesToAllApps() {\n const agents = await discoverAgents(\"dispatch\");\n const results: Array<{ appId: string; synced: number }> = [];\n\n for (const agent of agents) {\n try {\n const result = await syncResourcesToApp(agent.id);\n results.push({ appId: result.appId, synced: result.synced });\n } catch {\n results.push({ appId: agent.id, synced: 0 });\n }\n }\n\n return results;\n}\n\n// ─── Overview ──────────────────────────────────────────────────────\n\nexport async function listWorkspaceResourcesOverview() {\n const [resources, grants] = await Promise.all([\n listWorkspaceResources(),\n listResourceGrants(),\n ]);\n\n const skills = resources.filter((r) => r.kind === \"skill\");\n const instructions = resources.filter((r) => r.kind === \"instruction\");\n const agents = resources.filter((r) => r.kind === \"agent\");\n const activeGrants = grants.filter((g) => g.status === \"active\");\n\n return {\n skillCount: skills.length,\n instructionCount: instructions.length,\n agentCount: agents.length,\n totalResources: resources.length,\n activeGrantCount: activeGrants.length,\n };\n}\n"]}
1
+ {"version":3,"file":"workspace-resources-store.js","sourceRoot":"","sources":["../../../src/server/lib/workspace-resources-store.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"node:crypto\";\nimport { and, desc, eq, isNull, or } from \"drizzle-orm\";\nimport { discoverAgents } from \"@agent-native/core/server/agent-discovery\";\nimport { getDb, schema } from \"../../db/index.js\";\nimport {\n currentOwnerEmail,\n currentOrgId,\n recordAudit,\n} from \"./dispatch-store.js\";\nimport { recordVaultAudit } from \"./vault-store.js\";\n\n/**\n * Caller-supplied access context for workspace-resource operations.\n * Same shape and semantics as VaultCtx — looking up a row by id alone is\n * unsafe because UUIDs are not authorization. A row matches the ctx if\n * either the caller owns it or it lives in the caller's active org.\n */\nexport interface WorkspaceResourceCtx {\n ownerEmail: string;\n orgId: string | null;\n}\n\nexport function requireWorkspaceResourceCtx(): WorkspaceResourceCtx {\n const ownerEmail = currentOwnerEmail();\n return { ownerEmail, orgId: currentOrgId() };\n}\n\n/** WHERE clause that limits a workspace-resource row to the caller's scope. */\nfunction ctxScope<T extends { ownerEmail: any; orgId: any }>(\n table: T,\n ctx: WorkspaceResourceCtx,\n) {\n if (!ctx.orgId) {\n return and(eq(table.ownerEmail, ctx.ownerEmail), isNull(table.orgId));\n }\n return or(eq(table.ownerEmail, ctx.ownerEmail), eq(table.orgId, ctx.orgId));\n}\n\nfunction id() {\n return crypto.randomUUID();\n}\n\nfunction now() {\n return Date.now();\n}\n\nfunction orgFilter<T extends { ownerEmail: any; orgId: any }>(table: T) {\n const orgId = currentOrgId();\n return and(\n eq(table.ownerEmail, currentOwnerEmail()),\n orgId ? eq(table.orgId, orgId) : isNull(table.orgId),\n );\n}\n\n// ─── Workspace Resources CRUD ──────────────────────────────────\n\nexport type WorkspaceResourceKind =\n | \"skill\"\n | \"instruction\"\n | \"agent\"\n | \"knowledge\";\nexport type WorkspaceResourceScope = \"all\" | \"selected\";\n\nexport interface WorkspaceResourceInput {\n kind: WorkspaceResourceKind;\n name: string;\n description?: string | null;\n path: string;\n content: string;\n scope: WorkspaceResourceScope;\n}\n\nexport interface WorkspaceResourceOption {\n id: string;\n kind: WorkspaceResourceKind;\n name: string;\n description: string | null;\n path: string;\n scope: WorkspaceResourceScope;\n updatedAt: number;\n}\n\nexport async function listWorkspaceResources(filter?: { kind?: string }) {\n const db = getDb();\n const conditions = [orgFilter(schema.workspaceResources)];\n if (filter?.kind) {\n conditions.push(eq(schema.workspaceResources.kind, filter.kind) as any);\n }\n return db\n .select()\n .from(schema.workspaceResources)\n .where(and(...conditions))\n .orderBy(desc(schema.workspaceResources.updatedAt));\n}\n\nexport async function listWorkspaceResourceOptions(filter?: {\n kind?: string;\n}): Promise<WorkspaceResourceOption[]> {\n const resources = await listWorkspaceResources(filter);\n return resources.map((resource) => ({\n id: resource.id,\n kind: resource.kind as WorkspaceResourceKind,\n name: resource.name,\n description: resource.description,\n path: resource.path,\n scope: resource.scope as WorkspaceResourceScope,\n updatedAt: resource.updatedAt,\n }));\n}\n\nexport async function getWorkspaceResource(\n resourceId: string,\n ctx: WorkspaceResourceCtx = requireWorkspaceResourceCtx(),\n) {\n const db = getDb();\n const [row] = await db\n .select()\n .from(schema.workspaceResources)\n .where(\n and(\n eq(schema.workspaceResources.id, resourceId),\n ctxScope(schema.workspaceResources, ctx),\n ),\n )\n .limit(1);\n return row ?? null;\n}\n\nexport async function createWorkspaceResource(input: WorkspaceResourceInput) {\n const db = getDb();\n const timestamp = now();\n const resourceId = id();\n const actor = currentOwnerEmail();\n\n await db.insert(schema.workspaceResources).values({\n id: resourceId,\n ownerEmail: actor,\n orgId: currentOrgId(),\n kind: input.kind,\n name: input.name,\n description: input.description || null,\n path: input.path,\n content: input.content,\n scope: input.scope,\n createdBy: actor,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n\n await recordAudit({\n action: `workspace.${input.kind}.created`,\n targetType: `workspace-${input.kind}`,\n targetId: resourceId,\n summary: `Created workspace ${input.kind} \"${input.name}\" (${input.path})`,\n });\n\n return getWorkspaceResource(resourceId);\n}\n\nexport async function updateWorkspaceResource(\n resourceId: string,\n input: Partial<\n Pick<WorkspaceResourceInput, \"name\" | \"description\" | \"content\" | \"scope\">\n >,\n) {\n const db = getDb();\n const ctx = requireWorkspaceResourceCtx();\n const existing = await getWorkspaceResource(resourceId, ctx);\n if (!existing) throw new Error(\"Workspace resource not found\");\n\n const updates: Record<string, unknown> = { updatedAt: now() };\n if (input.name !== undefined) updates.name = input.name;\n if (input.description !== undefined)\n updates.description = input.description || null;\n if (input.content !== undefined) updates.content = input.content;\n if (input.scope !== undefined) updates.scope = input.scope;\n\n await db\n .update(schema.workspaceResources)\n .set(updates)\n .where(\n and(\n eq(schema.workspaceResources.id, resourceId),\n ctxScope(schema.workspaceResources, ctx),\n ),\n );\n\n await recordAudit({\n action: `workspace.${existing.kind}.updated`,\n targetType: `workspace-${existing.kind}`,\n targetId: resourceId,\n summary: `Updated workspace ${existing.kind} \"${input.name || existing.name}\"`,\n });\n\n return getWorkspaceResource(resourceId, ctx);\n}\n\nexport async function deleteWorkspaceResource(resourceId: string) {\n const db = getDb();\n const ctx = requireWorkspaceResourceCtx();\n const existing = await getWorkspaceResource(resourceId, ctx);\n if (!existing) throw new Error(\"Workspace resource not found\");\n\n // Revoke all grants\n const grants = await listResourceGrants({ resourceId });\n for (const grant of grants) {\n if (grant.status === \"active\") {\n await revokeResourceGrant(grant.id);\n }\n }\n\n await db\n .delete(schema.workspaceResources)\n .where(\n and(\n eq(schema.workspaceResources.id, resourceId),\n ctxScope(schema.workspaceResources, ctx),\n ),\n );\n\n await recordAudit({\n action: `workspace.${existing.kind}.deleted`,\n targetType: `workspace-${existing.kind}`,\n targetId: resourceId,\n summary: `Deleted workspace ${existing.kind} \"${existing.name}\" (${existing.path})`,\n });\n\n return existing;\n}\n\n// ─── Grants ──────────────────────────────────────────────────────\n\nexport async function listResourceGrants(filter?: {\n resourceId?: string;\n appId?: string;\n}) {\n const db = getDb();\n const conditions = [orgFilter(schema.workspaceResourceGrants)];\n if (filter?.resourceId) {\n conditions.push(\n eq(schema.workspaceResourceGrants.resourceId, filter.resourceId) as any,\n );\n }\n if (filter?.appId) {\n conditions.push(\n eq(schema.workspaceResourceGrants.appId, filter.appId) as any,\n );\n }\n return db\n .select()\n .from(schema.workspaceResourceGrants)\n .where(and(...conditions))\n .orderBy(desc(schema.workspaceResourceGrants.updatedAt));\n}\n\nexport async function getResourceGrant(\n grantId: string,\n ctx: WorkspaceResourceCtx = requireWorkspaceResourceCtx(),\n) {\n const db = getDb();\n const [row] = await db\n .select()\n .from(schema.workspaceResourceGrants)\n .where(\n and(\n eq(schema.workspaceResourceGrants.id, grantId),\n ctxScope(schema.workspaceResourceGrants, ctx),\n ),\n )\n .limit(1);\n return row ?? null;\n}\n\nexport async function createResourceGrant(resourceId: string, appId: string) {\n const db = getDb();\n const ctx = requireWorkspaceResourceCtx();\n const resource = await getWorkspaceResource(resourceId, ctx);\n if (!resource) throw new Error(\"Workspace resource not found\");\n\n const activeExisting = (await listResourceGrants({ resourceId, appId })).find(\n (grant) => grant.status === \"active\",\n );\n if (activeExisting) {\n return activeExisting;\n }\n\n const timestamp = now();\n const grantId = id();\n const actor = currentOwnerEmail();\n\n await db.insert(schema.workspaceResourceGrants).values({\n id: grantId,\n ownerEmail: actor,\n orgId: currentOrgId(),\n resourceId,\n appId,\n status: \"active\",\n syncedAt: null,\n createdAt: timestamp,\n updatedAt: timestamp,\n });\n\n await recordAudit({\n action: `workspace.${resource.kind}.granted`,\n targetType: `workspace-${resource.kind}-grant`,\n targetId: grantId,\n summary: `Granted workspace ${resource.kind} \"${resource.name}\" to ${appId}`,\n });\n\n return getResourceGrant(grantId);\n}\n\nexport async function grantWorkspaceResourcesToApp(input: {\n appId: string;\n resourceIds: string[];\n}) {\n const uniqueResourceIds = [...new Set(input.resourceIds.filter(Boolean))];\n if (uniqueResourceIds.length === 0) {\n return { appId: input.appId, granted: [], skipped: [] };\n }\n\n const granted: Array<{ id: string; resourceId: string; appId: string }> = [];\n const skipped: Array<{ resourceId: string; reason: string }> = [];\n\n for (const resourceId of uniqueResourceIds) {\n const resource = await getWorkspaceResource(resourceId).catch(() => null);\n if (!resource) {\n skipped.push({ resourceId, reason: \"not-found\" });\n continue;\n }\n if (resource.scope === \"all\") {\n skipped.push({ resourceId, reason: \"already-all-apps\" });\n continue;\n }\n\n const grant = await createResourceGrant(resourceId, input.appId);\n if (grant) {\n granted.push({\n id: grant.id,\n resourceId: grant.resourceId,\n appId: grant.appId,\n });\n }\n }\n\n return { appId: input.appId, granted, skipped };\n}\n\nexport async function revokeResourceGrant(\n grantId: string,\n ctx: WorkspaceResourceCtx = requireWorkspaceResourceCtx(),\n) {\n const db = getDb();\n const grant = await getResourceGrant(grantId, ctx);\n if (!grant) throw new Error(\"Grant not found\");\n\n const resource = await getWorkspaceResource(grant.resourceId);\n\n await db\n .update(schema.workspaceResourceGrants)\n .set({ status: \"revoked\", updatedAt: now() })\n .where(\n and(\n eq(schema.workspaceResourceGrants.id, grantId),\n ctxScope(schema.workspaceResourceGrants, ctx),\n ),\n );\n\n await recordAudit({\n action: `workspace.${resource?.kind || \"resource\"}.grant-revoked`,\n targetType: \"workspace-resource-grant\",\n targetId: grantId,\n summary: `Revoked workspace ${resource?.kind || \"resource\"} \"${resource?.name || grant.resourceId}\" from ${grant.appId}`,\n });\n\n return getResourceGrant(grantId, ctx);\n}\n\n// ─── Sync ──────────────────────────────────────────────────────\n\n/**\n * Push workspace resources to an app via its /_agent-native/resources endpoint.\n * Resources with scope=\"all\" are always pushed. Resources with scope=\"selected\"\n * are only pushed if there's an active grant for that app.\n */\nexport async function syncResourcesToApp(appId: string) {\n const agents = await discoverAgents(\"dispatch\");\n const agent = agents.find((a) => a.id === appId);\n if (!agent) throw new Error(`App \"${appId}\" not found in agent registry`);\n\n const allResources = await listWorkspaceResources();\n const grants = await listResourceGrants({ appId });\n const activeGrantResourceIds = new Set(\n grants.filter((g) => g.status === \"active\").map((g) => g.resourceId),\n );\n\n // Determine which resources to push\n const toPush = allResources.filter(\n (r) =>\n r.scope === \"all\" ||\n (r.scope === \"selected\" && activeGrantResourceIds.has(r.id)),\n );\n\n if (toPush.length === 0) {\n return { appId, synced: 0, resources: [] };\n }\n\n const syncedPaths: string[] = [];\n const db = getDb();\n const timestamp = now();\n\n for (const resource of toPush) {\n try {\n // Push via the resources API — create as shared resource\n const res = await fetch(`${agent.url}/_agent-native/resources`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n path: resource.path,\n content: resource.content,\n shared: true,\n mimeType: \"text/markdown\",\n }),\n });\n\n if (res.ok || res.status === 409) {\n // 409 = already exists, try updating\n if (res.status === 409) {\n // Fetch existing to get ID, then update\n const listRes = await fetch(\n `${agent.url}/_agent-native/resources?scope=shared&path=${encodeURIComponent(resource.path)}`,\n );\n if (listRes.ok) {\n const items = await listRes.json();\n const existing = Array.isArray(items)\n ? items.find((i: any) => i.path === resource.path)\n : null;\n if (existing) {\n await fetch(\n `${agent.url}/_agent-native/resources/${existing.id}`,\n {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ content: resource.content }),\n },\n );\n }\n }\n }\n syncedPaths.push(resource.path);\n\n // Update grant syncedAt if applicable\n const grant = grants.find(\n (g) => g.resourceId === resource.id && g.status === \"active\",\n );\n if (grant) {\n await db\n .update(schema.workspaceResourceGrants)\n .set({ syncedAt: timestamp, updatedAt: timestamp })\n .where(eq(schema.workspaceResourceGrants.id, grant.id));\n }\n }\n } catch {\n // Skip unreachable — don't fail the whole sync\n }\n }\n\n await recordAudit({\n action: \"workspace.resources.synced\",\n targetType: \"workspace-resource-sync\",\n targetId: appId,\n summary: `Synced ${syncedPaths.length} workspace resource(s) to ${appId}: ${syncedPaths.join(\", \")}`,\n });\n\n return { appId, synced: syncedPaths.length, resources: syncedPaths };\n}\n\n/**\n * Sync all workspace resources to all apps that have grants or scope=\"all\" resources.\n */\nexport async function syncResourcesToAllApps() {\n const agents = await discoverAgents(\"dispatch\");\n const results: Array<{ appId: string; synced: number }> = [];\n\n for (const agent of agents) {\n try {\n const result = await syncResourcesToApp(agent.id);\n results.push({ appId: result.appId, synced: result.synced });\n } catch {\n results.push({ appId: agent.id, synced: 0 });\n }\n }\n\n return results;\n}\n\n// ─── Overview ──────────────────────────────────────────────────────\n\nexport async function listWorkspaceResourcesOverview() {\n const [resources, grants] = await Promise.all([\n listWorkspaceResources(),\n listResourceGrants(),\n ]);\n\n const skills = resources.filter((r) => r.kind === \"skill\");\n const instructions = resources.filter((r) => r.kind === \"instruction\");\n const agents = resources.filter((r) => r.kind === \"agent\");\n const knowledge = resources.filter((r) => r.kind === \"knowledge\");\n const activeGrants = grants.filter((g) => g.status === \"active\");\n\n return {\n skillCount: skills.length,\n instructionCount: instructions.length,\n agentCount: agents.length,\n knowledgeCount: knowledge.length,\n totalResources: resources.length,\n activeGrantCount: activeGrants.length,\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/dispatch",
3
- "version": "0.2.11",
3
+ "version": "0.2.12",
4
4
  "type": "module",
5
5
  "description": "Dispatch — workspace control plane for agent-native apps. Vault, integrations, destinations, scheduled jobs, and cross-app delegation, shipped as a single drop-in package.",
6
6
  "license": "MIT",
@@ -96,7 +96,7 @@
96
96
  "typescript": "^6.0.3",
97
97
  "vite": "8.0.3",
98
98
  "vitest": "^4.1.5",
99
- "@agent-native/core": "0.12.12"
99
+ "@agent-native/core": "0.12.14"
100
100
  },
101
101
  "scripts": {
102
102
  "build": "tsc && tsc-alias --resolve-full-paths",
@@ -4,17 +4,17 @@ import { createWorkspaceResource } from "../server/lib/workspace-resources-store
4
4
 
5
5
  export default defineAction({
6
6
  description:
7
- 'Create a workspace-wide skill, instruction, or agent profile. Set scope to "all" to push to every app, or "selected" to grant per-app.',
7
+ 'Create a workspace-wide skill, instruction, agent profile, or knowledge pack. Set scope to "all" to push to every app, or "selected" to grant per-app.',
8
8
  schema: z.object({
9
9
  kind: z
10
- .enum(["skill", "instruction", "agent"])
11
- .describe("Resource kind: skill, instruction, or agent"),
10
+ .enum(["skill", "instruction", "agent", "knowledge"])
11
+ .describe("Resource kind: skill, instruction, agent, or knowledge"),
12
12
  name: z.string().describe("Human-readable name"),
13
13
  description: z.string().optional().describe("Short description"),
14
14
  path: z
15
15
  .string()
16
16
  .describe(
17
- 'Resource path, e.g. "skills/designer.md", "agents/researcher.md", or "remote-agents/researcher.json"',
17
+ 'Resource path, e.g. "skills/designer.md", "agents/researcher.md", "context/gtm-messaging.md", or "remote-agents/researcher.json"',
18
18
  ),
19
19
  content: z
20
20
  .string()
@@ -0,0 +1,16 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { z } from "zod";
3
+ import { grantWorkspaceResourcesToApp } from "../server/lib/workspace-resources-store.js";
4
+
5
+ export default defineAction({
6
+ description:
7
+ "Grant several selected workspace resources or knowledge packs to an app, skipping existing active grants.",
8
+ schema: z.object({
9
+ appId: z.string().describe("App ID receiving the resources"),
10
+ resourceIds: z
11
+ .array(z.string())
12
+ .max(100)
13
+ .describe("Workspace resource IDs to grant"),
14
+ }),
15
+ run: async (args) => grantWorkspaceResourcesToApp(args),
16
+ });
@@ -13,6 +13,7 @@ import denyVaultRequest from "./deny-vault-request.js";
13
13
  import getAppCreationSettings from "./get-app-creation-settings.js";
14
14
  import getDispatchSettings from "./get-dispatch-settings.js";
15
15
  import getWorkspaceInfo from "./get-workspace-info.js";
16
+ import grantWorkspaceResourcesToApp from "./grant-workspace-resources-to-app.js";
16
17
  import grantVaultSecretsToApp from "./grant-vault-secrets-to-app.js";
17
18
  import listConnectedAgents from "./list-connected-agents.js";
18
19
  import listDestinations from "./list-destinations.js";
@@ -28,6 +29,7 @@ import listVaultRequests from "./list-vault-requests.js";
28
29
  import listVaultSecretOptions from "./list-vault-secret-options.js";
29
30
  import listVaultSecrets from "./list-vault-secrets.js";
30
31
  import listWorkspaceApps from "./list-workspace-apps.js";
32
+ import listWorkspaceResourceOptions from "./list-workspace-resource-options.js";
31
33
  import listWorkspaceResourceGrants from "./list-workspace-resource-grants.js";
32
34
  import listWorkspaceResources from "./list-workspace-resources.js";
33
35
  import navigate from "./navigate.js";
@@ -68,6 +70,7 @@ export const dispatchActions: Record<string, ActionEntry> = {
68
70
  "get-app-creation-settings": getAppCreationSettings,
69
71
  "get-dispatch-settings": getDispatchSettings,
70
72
  "get-workspace-info": getWorkspaceInfo,
73
+ "grant-workspace-resources-to-app": grantWorkspaceResourcesToApp,
71
74
  "grant-vault-secrets-to-app": grantVaultSecretsToApp,
72
75
  "list-connected-agents": listConnectedAgents,
73
76
  "list-destinations": listDestinations,
@@ -83,6 +86,7 @@ export const dispatchActions: Record<string, ActionEntry> = {
83
86
  "list-vault-secret-options": listVaultSecretOptions,
84
87
  "list-vault-secrets": listVaultSecrets,
85
88
  "list-workspace-apps": listWorkspaceApps,
89
+ "list-workspace-resource-options": listWorkspaceResourceOptions,
86
90
  "list-workspace-resource-grants": listWorkspaceResourceGrants,
87
91
  "list-workspace-resources": listWorkspaceResources,
88
92
  navigate: navigate,
@@ -0,0 +1,16 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { z } from "zod";
3
+ import { listWorkspaceResourceOptions } from "../server/lib/workspace-resources-store.js";
4
+
5
+ export default defineAction({
6
+ description:
7
+ "List lightweight workspace resource options for selectors, without returning full content.",
8
+ schema: z.object({
9
+ kind: z
10
+ .enum(["skill", "instruction", "agent", "knowledge"])
11
+ .optional()
12
+ .describe("Filter by resource kind"),
13
+ }),
14
+ http: { method: "GET" },
15
+ run: async (args) => listWorkspaceResourceOptions(args),
16
+ });
@@ -4,10 +4,10 @@ import { listWorkspaceResources } from "../server/lib/workspace-resources-store.
4
4
 
5
5
  export default defineAction({
6
6
  description:
7
- "List all workspace-wide resources (skills, instructions, agents) that can be shared across apps.",
7
+ "List all workspace-wide resources (skills, instructions, agents, and knowledge packs) that can be shared across apps.",
8
8
  schema: z.object({
9
9
  kind: z
10
- .enum(["skill", "instruction", "agent"])
10
+ .enum(["skill", "instruction", "agent", "knowledge"])
11
11
  .optional()
12
12
  .describe("Filter by resource kind"),
13
13
  }),
@@ -28,6 +28,13 @@ export default defineAction({
28
28
  .max(100)
29
29
  .optional()
30
30
  .describe("Dispatch vault secret IDs to grant to the app"),
31
+ resourceIds: z
32
+ .array(z.string())
33
+ .max(100)
34
+ .optional()
35
+ .describe(
36
+ "Dispatch workspace resource IDs or knowledge packs to grant to the app",
37
+ ),
31
38
  }),
32
39
  run: async (args) => startWorkspaceAppCreation(args),
33
40
  });
@@ -19,6 +19,7 @@ import {
19
19
  } from "../server/lib/vault-store.js";
20
20
  import { listWorkspaceApps } from "../server/lib/app-creation-store.js";
21
21
  import { listDispatchUsageMetrics } from "../server/lib/usage-metrics-store.js";
22
+ import { listWorkspaceResourceOptions } from "../server/lib/workspace-resources-store.js";
22
23
 
23
24
  export default defineAction({
24
25
  description:
@@ -88,6 +89,9 @@ export default defineAction({
88
89
  .map((g) => ({ secretId: g.secretId, appId: g.appId }));
89
90
  screen.vaultPendingRequests = requests;
90
91
  }
92
+ if (navigation?.view === "workspace" || navigation?.view === "new-app") {
93
+ screen.workspaceResources = await listWorkspaceResourceOptions();
94
+ }
91
95
 
92
96
  if (Object.keys(screen).length === 0) {
93
97
  return "No application state found. Is the app running?";
@@ -11,8 +11,10 @@ import { getWorkspaceAppIdValidationError } from "@agent-native/core/shared";
11
11
  import {
12
12
  IconArrowLeft,
13
13
  IconArrowUpRight,
14
+ IconBook,
14
15
  IconCheck,
15
16
  IconChevronDown,
17
+ IconFileText,
16
18
  IconKey,
17
19
  IconLoader2,
18
20
  IconPlus,
@@ -32,6 +34,16 @@ interface VaultSecretOption {
32
34
  description?: string | null;
33
35
  }
34
36
 
37
+ interface WorkspaceResourceOption {
38
+ id: string;
39
+ kind: "skill" | "instruction" | "agent" | "knowledge";
40
+ name: string;
41
+ description?: string | null;
42
+ path: string;
43
+ scope: "all" | "selected";
44
+ updatedAt?: number;
45
+ }
46
+
35
47
  interface CreateAppPopoverProps {
36
48
  /**
37
49
  * Custom trigger element. Defaults to a dashed-border tile that matches the
@@ -65,11 +77,20 @@ function buildAppCreationPrompt(input: {
65
77
  appId: string;
66
78
  prompt: string;
67
79
  selectedKeys: string[];
80
+ selectedResources: WorkspaceResourceOption[];
68
81
  }): string {
69
82
  const keyList = input.selectedKeys.join(", ");
70
83
  const grantRequest = keyList
71
84
  ? `Requested Dispatch vault key grants for this app: ${keyList}`
72
85
  : `Requested Dispatch vault key grants for this app: none`;
86
+ const resourceList = input.selectedResources.length
87
+ ? input.selectedResources
88
+ .map(
89
+ (resource) =>
90
+ `- ${resource.name} (${resource.kind}, ${resource.path})`,
91
+ )
92
+ .join("\n")
93
+ : "none";
73
94
 
74
95
  return [
75
96
  `Create a new agent-native app in this workspace.`,
@@ -78,6 +99,7 @@ function buildAppCreationPrompt(input: {
78
99
  `Suggested app name: ${input.appId} (you may adjust the slug if it conflicts)`,
79
100
  `User prompt: ${input.prompt.trim()}`,
80
101
  grantRequest,
102
+ `Requested Dispatch workspace resources for this app:\n${resourceList}`,
81
103
  ``,
82
104
  `Pick a starter template that fits the user's prompt — analytics, calendar, content, design, dispatch, forms, mail, slides, clips, or starter when none of the others fit.`,
83
105
  `Use the workspace app layout: create it under apps/${input.appId}, mount it at /${input.appId}, keep it on the shared workspace database/hosting model, and avoid table-name collisions by namespacing any new domain tables to the app.`,
@@ -88,6 +110,9 @@ function buildAppCreationPrompt(input: {
88
110
  keyList
89
111
  ? `After the app exists, grant the selected Dispatch vault keys to appId "${input.appId}" and sync them once the app server is available. Treat these as requested grants, not active grants before creation succeeds.`
90
112
  : `Do not grant any Dispatch vault keys unless the user asks later.`,
113
+ input.selectedResources.length
114
+ ? `After the app exists, grant the selected Dispatch workspace resources to appId "${input.appId}" and sync them once the app server is available. Add a short note to apps/${input.appId}/AGENTS.md telling the app agent to read relevant shared resources under context/ or the selected resource paths before doing GTM/domain work.`
115
+ : `Do not grant any Dispatch workspace resources unless the user asks later.`,
91
116
  ``,
92
117
  `App readiness requirements before handing off:`,
93
118
  `- Ensure apps/${input.appId}/package.json exists; Dispatch discovers workspace apps from apps/<app-id>/package.json, not a separate app registry.`,
@@ -123,7 +148,7 @@ function actionUrl(basePath: string | null, action: string): string {
123
148
  }
124
149
 
125
150
  /**
126
- * Inline two-step app-creation flow: prompt → optional key picker → submit.
151
+ * Inline two-step app-creation flow: prompt → optional access picker → submit.
127
152
  * Used both in the popover form and in the dedicated `/new-app` page so the
128
153
  * same UX shows up everywhere a teammate kicks off a new workspace app.
129
154
  */
@@ -134,11 +159,14 @@ export function CreateAppFlow({
134
159
  onClose?: () => void;
135
160
  className?: string;
136
161
  }) {
137
- const [step, setStep] = useState<"prompt" | "keys">("prompt");
162
+ const [step, setStep] = useState<"prompt" | "access">("prompt");
138
163
  const [prompt, setPrompt] = useState("");
139
164
  const [selectedSecretIds, setSelectedSecretIds] = useState<string[]>([]);
165
+ const [selectedResourceIds, setSelectedResourceIds] = useState<string[]>([]);
140
166
  const [secrets, setSecrets] = useState<VaultSecretOption[]>([]);
167
+ const [resources, setResources] = useState<WorkspaceResourceOption[]>([]);
141
168
  const [secretsError, setSecretsError] = useState<string | null>(null);
169
+ const [resourcesError, setResourcesError] = useState<string | null>(null);
142
170
  const [statusMessage, setStatusMessage] = useState<string | null>(null);
143
171
  const [branchUrl, setBranchUrl] = useState<string | null>(null);
144
172
  const [isSubmitting, setIsSubmitting] = useState(false);
@@ -146,8 +174,7 @@ export function CreateAppFlow({
146
174
 
147
175
  const basePath = useMemo(() => defaultDispatchBasePath(), []);
148
176
 
149
- // Fetch the vault keys eagerly so step 2 has them ready the moment the user
150
- // taps "Choose keys" — no spinner, no pause between steps.
177
+ // Fetch access options eagerly so step 2 has them ready immediately.
151
178
  useEffect(() => {
152
179
  let cancelled = false;
153
180
  fetchJson(actionUrl(basePath, "list-vault-secret-options"))
@@ -161,6 +188,17 @@ export function CreateAppFlow({
161
188
  setSecrets([]);
162
189
  setSecretsError(err?.message || "Could not load Dispatch keys");
163
190
  });
191
+ fetchJson(actionUrl(basePath, "list-workspace-resource-options"))
192
+ .then((data) => {
193
+ if (cancelled) return;
194
+ setResources(Array.isArray(data) ? data : []);
195
+ setResourcesError(null);
196
+ })
197
+ .catch((err) => {
198
+ if (cancelled) return;
199
+ setResources([]);
200
+ setResourcesError(err?.message || "Could not load Dispatch resources");
201
+ });
164
202
  return () => {
165
203
  cancelled = true;
166
204
  };
@@ -170,10 +208,21 @@ export function CreateAppFlow({
170
208
  () => secrets.filter((s) => selectedSecretIds.includes(s.id)),
171
209
  [secrets, selectedSecretIds],
172
210
  );
211
+ const selectedResources = useMemo(
212
+ () => resources.filter((r) => selectedResourceIds.includes(r.id)),
213
+ [resources, selectedResourceIds],
214
+ );
173
215
  const selectedSecretLabel =
174
216
  selectedSecretIds.length === 0
175
217
  ? "no keys"
176
218
  : `${selectedSecretIds.length} key${selectedSecretIds.length === 1 ? "" : "s"}`;
219
+ const selectedResourceLabel =
220
+ selectedResourceIds.length === 0
221
+ ? "no resources"
222
+ : `${selectedResourceIds.length} resource${selectedResourceIds.length === 1 ? "" : "s"}`;
223
+ const selectedAccessLabel = [selectedSecretLabel, selectedResourceLabel].join(
224
+ " · ",
225
+ );
177
226
 
178
227
  function toggleSecret(id: string) {
179
228
  setSelectedSecretIds((cur) =>
@@ -181,7 +230,13 @@ export function CreateAppFlow({
181
230
  );
182
231
  }
183
232
 
184
- async function submit(rawPrompt: string, selectedKeys: string[]) {
233
+ function toggleResource(id: string) {
234
+ setSelectedResourceIds((cur) =>
235
+ cur.includes(id) ? cur.filter((x) => x !== id) : [...cur, id],
236
+ );
237
+ }
238
+
239
+ async function submit(rawPrompt: string) {
185
240
  const trimmed = rawPrompt.trim();
186
241
  if (!trimmed || isSubmitting) return;
187
242
  const appId = titleFromPrompt(trimmed);
@@ -194,7 +249,8 @@ export function CreateAppFlow({
194
249
  const message = buildAppCreationPrompt({
195
250
  appId,
196
251
  prompt: trimmed,
197
- selectedKeys,
252
+ selectedKeys: selectedSecrets.map((s) => s.credentialKey),
253
+ selectedResources,
198
254
  });
199
255
  setIsSubmitting(true);
200
256
  setStatusMessage(null);
@@ -218,7 +274,9 @@ export function CreateAppFlow({
218
274
  body: JSON.stringify({
219
275
  prompt: trimmed,
220
276
  appId,
221
- secretIds: selectedKeys.length > 0 ? selectedSecretIds : [],
277
+ secretIds: selectedSecretIds.length > 0 ? selectedSecretIds : [],
278
+ resourceIds:
279
+ selectedResourceIds.length > 0 ? selectedResourceIds : [],
222
280
  }),
223
281
  },
224
282
  );
@@ -239,11 +297,7 @@ export function CreateAppFlow({
239
297
  }
240
298
  }
241
299
 
242
- const submitWithSelectedKeys = () =>
243
- submit(
244
- prompt,
245
- selectedSecrets.map((s) => s.credentialKey),
246
- );
300
+ const submitWithSelectedAccess = () => submit(prompt);
247
301
 
248
302
  return (
249
303
  <div className={`flex flex-col gap-3 ${className}`}>
@@ -253,11 +307,11 @@ export function CreateAppFlow({
253
307
  <p className="text-sm font-semibold text-foreground">Create app</p>
254
308
  <button
255
309
  type="button"
256
- onClick={() => setStep("keys")}
310
+ onClick={() => setStep("access")}
257
311
  className="inline-flex cursor-pointer items-center gap-1 rounded-md border border-border bg-background/40 px-2 py-1 text-[11px] text-muted-foreground hover:text-foreground hover:bg-accent/50"
258
312
  >
259
313
  <IconKey size={11} />
260
- {selectedSecretLabel}
314
+ {selectedAccessLabel}
261
315
  </button>
262
316
  </div>
263
317
  <PromptComposer
@@ -267,10 +321,7 @@ export function CreateAppFlow({
267
321
  draftScope="dispatch:create-app"
268
322
  onSubmit={(text) => {
269
323
  setPrompt(text);
270
- submit(
271
- text,
272
- selectedSecrets.map((s) => s.credentialKey),
273
- );
324
+ submit(text);
274
325
  }}
275
326
  />
276
327
  </>
@@ -286,10 +337,14 @@ export function CreateAppFlow({
286
337
  Back
287
338
  </button>
288
339
  <span className="text-[11px] text-muted-foreground/70">
289
- {selectedSecretLabel} selected
340
+ {selectedAccessLabel}
290
341
  </span>
291
342
  </div>
292
- <div className="max-h-[340px] space-y-2 overflow-y-auto rounded-md border border-border bg-card p-2">
343
+ <div className="max-h-[180px] space-y-2 overflow-y-auto rounded-md border border-border bg-card p-2">
344
+ <div className="flex items-center gap-1.5 px-1 pb-1 text-[11px] font-medium text-muted-foreground">
345
+ <IconKey size={12} />
346
+ Dispatch keys
347
+ </div>
293
348
  {secretsError ? (
294
349
  <p className="rounded-md border border-dashed border-border px-3 py-3 text-xs text-muted-foreground">
295
350
  {secretsError}
@@ -355,11 +410,87 @@ export function CreateAppFlow({
355
410
  })
356
411
  )}
357
412
  </div>
413
+ <div className="max-h-[180px] space-y-2 overflow-y-auto rounded-md border border-border bg-card p-2">
414
+ <div className="flex items-center gap-1.5 px-1 pb-1 text-[11px] font-medium text-muted-foreground">
415
+ <IconBook size={12} />
416
+ Resource packs
417
+ </div>
418
+ {resourcesError ? (
419
+ <p className="rounded-md border border-dashed border-border px-3 py-3 text-xs text-muted-foreground">
420
+ {resourcesError}
421
+ </p>
422
+ ) : resources.length === 0 ? (
423
+ <p className="rounded-md border border-dashed border-border px-3 py-3 text-xs text-muted-foreground">
424
+ No Dispatch resource packs found yet.
425
+ </p>
426
+ ) : (
427
+ resources.map((resource) => {
428
+ const selected = selectedResourceIds.includes(resource.id);
429
+ return (
430
+ <div
431
+ key={resource.id}
432
+ className={`group rounded-md border text-sm ${
433
+ selected
434
+ ? "border-primary/45 bg-primary/5"
435
+ : "border-border hover:border-muted-foreground/40 hover:bg-accent/35"
436
+ }`}
437
+ >
438
+ <button
439
+ type="button"
440
+ aria-pressed={selected}
441
+ onClick={() => toggleResource(resource.id)}
442
+ className="flex w-full cursor-pointer items-start gap-3 rounded-md px-3 py-2 text-left"
443
+ >
444
+ <span
445
+ className={`mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border ${
446
+ selected
447
+ ? "border-primary/60 bg-primary/10 text-primary"
448
+ : "border-muted-foreground/35 text-transparent"
449
+ }`}
450
+ >
451
+ {selected ? <IconCheck className="h-3 w-3" /> : null}
452
+ </span>
453
+ <span className="min-w-0 flex-1">
454
+ <span className="flex min-w-0 items-center gap-1.5">
455
+ <IconFileText className="h-3.5 w-3.5 shrink-0 text-muted-foreground/70" />
456
+ <span className="block truncate font-medium">
457
+ {resource.name}
458
+ </span>
459
+ </span>
460
+ <span className="block truncate text-xs text-muted-foreground/70">
461
+ {resource.kind} · {resource.path}
462
+ </span>
463
+ </span>
464
+ </button>
465
+ <details className="group/details border-t border-border/60 px-3 py-1.5 text-xs text-muted-foreground/75">
466
+ <summary className="flex cursor-pointer list-none items-center gap-1.5 text-[11px] hover:text-muted-foreground [&::-webkit-details-marker]:hidden">
467
+ <IconChevronDown className="h-3 w-3 transition-transform group-open/details:rotate-180" />
468
+ Details
469
+ </summary>
470
+ <div className="mt-1.5 space-y-1 pb-0.5 pl-4">
471
+ <div className="truncate">
472
+ Scope:{" "}
473
+ {resource.scope === "all"
474
+ ? "All apps"
475
+ : "Selected apps"}
476
+ </div>
477
+ {resource.description ? (
478
+ <div className="line-clamp-2">
479
+ {resource.description}
480
+ </div>
481
+ ) : null}
482
+ </div>
483
+ </details>
484
+ </div>
485
+ );
486
+ })
487
+ )}
488
+ </div>
358
489
  <div className="flex items-center justify-end gap-2">
359
490
  <Button
360
491
  type="button"
361
492
  size="sm"
362
- onClick={submitWithSelectedKeys}
493
+ onClick={submitWithSelectedAccess}
363
494
  disabled={!prompt.trim() || isSubmitting}
364
495
  >
365
496
  {isSubmitting ? (
package/src/db/schema.ts CHANGED
@@ -130,13 +130,13 @@ export const vaultAuditLog = table("vault_audit_log", {
130
130
  createdAt: integer("created_at").notNull(),
131
131
  });
132
132
 
133
- // ─── Workspace Resources: shared skills, instructions, agents ──────
133
+ // ─── Workspace Resources: shared skills, instructions, agents, knowledge ──────
134
134
 
135
135
  export const workspaceResources = table("workspace_resources", {
136
136
  id: text("id").primaryKey(),
137
137
  ownerEmail: text("owner_email").notNull(),
138
138
  orgId: text("org_id"),
139
- kind: text("kind").notNull(), // "skill" | "instruction" | "agent"
139
+ kind: text("kind").notNull(), // "skill" | "instruction" | "agent" | "knowledge"
140
140
  name: text("name").notNull(),
141
141
  description: text("description"),
142
142
  path: text("path").notNull(), // resource path, e.g. "skills/designer.md"