Add company skills library and agent skills UI

This commit is contained in:
Dotta 2026-03-14 10:55:04 -05:00
parent 2137c2f715
commit 0bf53bc513
22 changed files with 8050 additions and 131 deletions

View file

@ -0,0 +1,21 @@
CREATE TABLE "company_skills" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"company_id" uuid NOT NULL,
"slug" text NOT NULL,
"name" text NOT NULL,
"description" text,
"markdown" text NOT NULL,
"source_type" text DEFAULT 'local_path' NOT NULL,
"source_locator" text,
"source_ref" text,
"trust_level" text DEFAULT 'markdown_only' NOT NULL,
"compatibility" text DEFAULT 'compatible' NOT NULL,
"file_inventory" jsonb DEFAULT '[]'::jsonb NOT NULL,
"metadata" jsonb,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
ALTER TABLE "company_skills" ADD CONSTRAINT "company_skills_company_id_companies_id_fk" FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
CREATE UNIQUE INDEX "company_skills_company_slug_idx" ON "company_skills" USING btree ("company_id","slug");--> statement-breakpoint
CREATE INDEX "company_skills_company_name_idx" ON "company_skills" USING btree ("company_id","name");

File diff suppressed because it is too large Load diff

View file

@ -197,6 +197,13 @@
"when": 1773150731736,
"tag": "0027_tranquil_tenebrous",
"breakpoints": true
},
{
"idx": 28,
"version": "7",
"when": 1773503397855,
"tag": "0028_bent_eternals",
"breakpoints": true
}
]
}

View file

@ -0,0 +1,35 @@
import {
pgTable,
uuid,
text,
timestamp,
jsonb,
index,
uniqueIndex,
} from "drizzle-orm/pg-core";
import { companies } from "./companies.js";
export const companySkills = pgTable(
"company_skills",
{
id: uuid("id").primaryKey().defaultRandom(),
companyId: uuid("company_id").notNull().references(() => companies.id),
slug: text("slug").notNull(),
name: text("name").notNull(),
description: text("description"),
markdown: text("markdown").notNull(),
sourceType: text("source_type").notNull().default("local_path"),
sourceLocator: text("source_locator"),
sourceRef: text("source_ref"),
trustLevel: text("trust_level").notNull().default("markdown_only"),
compatibility: text("compatibility").notNull().default("compatible"),
fileInventory: jsonb("file_inventory").$type<Array<Record<string, unknown>>>().notNull().default([]),
metadata: jsonb("metadata").$type<Record<string, unknown>>(),
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
},
(table) => ({
companySlugUniqueIdx: uniqueIndex("company_skills_company_slug_idx").on(table.companyId, table.slug),
companyNameIdx: index("company_skills_company_name_idx").on(table.companyId, table.name),
}),
);

View file

@ -32,3 +32,4 @@ export { approvalComments } from "./approval_comments.js";
export { activityLog } from "./activity_log.js";
export { companySecrets } from "./company_secrets.js";
export { companySecretVersions } from "./company_secret_versions.js";
export { companySkills } from "./company_skills.js";

View file

@ -65,6 +65,16 @@ export {
export type {
Company,
CompanySkillSourceType,
CompanySkillTrustLevel,
CompanySkillCompatibility,
CompanySkillFileInventoryEntry,
CompanySkill,
CompanySkillListItem,
CompanySkillUsageAgent,
CompanySkillDetail,
CompanySkillImportRequest,
CompanySkillImportResult,
AgentSkillSyncMode,
AgentSkillState,
AgentSkillEntry,
@ -238,6 +248,15 @@ export {
type ClaimJoinRequestApiKey,
type UpdateMemberPermissions,
type UpdateUserCompanyAccess,
companySkillSourceTypeSchema,
companySkillTrustLevelSchema,
companySkillCompatibilitySchema,
companySkillFileInventoryEntrySchema,
companySkillSchema,
companySkillListItemSchema,
companySkillUsageAgentSchema,
companySkillDetailSchema,
companySkillImportSchema,
portabilityIncludeSchema,
portabilityEnvInputSchema,
portabilityCompanyManifestEntrySchema,

View file

@ -0,0 +1,55 @@
export type CompanySkillSourceType = "local_path" | "github" | "url" | "catalog";
export type CompanySkillTrustLevel = "markdown_only" | "assets" | "scripts_executables";
export type CompanySkillCompatibility = "compatible" | "unknown" | "invalid";
export interface CompanySkillFileInventoryEntry {
path: string;
kind: "skill" | "markdown" | "reference" | "script" | "asset" | "other";
}
export interface CompanySkill {
id: string;
companyId: string;
slug: string;
name: string;
description: string | null;
markdown: string;
sourceType: CompanySkillSourceType;
sourceLocator: string | null;
sourceRef: string | null;
trustLevel: CompanySkillTrustLevel;
compatibility: CompanySkillCompatibility;
fileInventory: CompanySkillFileInventoryEntry[];
metadata: Record<string, unknown> | null;
createdAt: Date;
updatedAt: Date;
}
export interface CompanySkillListItem extends CompanySkill {
attachedAgentCount: number;
}
export interface CompanySkillUsageAgent {
id: string;
name: string;
urlKey: string;
adapterType: string;
desired: boolean;
actualState: string | null;
}
export interface CompanySkillDetail extends CompanySkill {
attachedAgentCount: number;
usedByAgents: CompanySkillUsageAgent[];
}
export interface CompanySkillImportRequest {
source: string;
}
export interface CompanySkillImportResult {
imported: CompanySkill[];
warnings: string[];
}

View file

@ -1,4 +1,16 @@
export type { Company } from "./company.js";
export type {
CompanySkillSourceType,
CompanySkillTrustLevel,
CompanySkillCompatibility,
CompanySkillFileInventoryEntry,
CompanySkill,
CompanySkillListItem,
CompanySkillUsageAgent,
CompanySkillDetail,
CompanySkillImportRequest,
CompanySkillImportResult,
} from "./company-skill.js";
export type {
AgentSkillSyncMode,
AgentSkillState,

View file

@ -0,0 +1,52 @@
import { z } from "zod";
export const companySkillSourceTypeSchema = z.enum(["local_path", "github", "url", "catalog"]);
export const companySkillTrustLevelSchema = z.enum(["markdown_only", "assets", "scripts_executables"]);
export const companySkillCompatibilitySchema = z.enum(["compatible", "unknown", "invalid"]);
export const companySkillFileInventoryEntrySchema = z.object({
path: z.string().min(1),
kind: z.enum(["skill", "markdown", "reference", "script", "asset", "other"]),
});
export const companySkillSchema = z.object({
id: z.string().uuid(),
companyId: z.string().uuid(),
slug: z.string().min(1),
name: z.string().min(1),
description: z.string().nullable(),
markdown: z.string(),
sourceType: companySkillSourceTypeSchema,
sourceLocator: z.string().nullable(),
sourceRef: z.string().nullable(),
trustLevel: companySkillTrustLevelSchema,
compatibility: companySkillCompatibilitySchema,
fileInventory: z.array(companySkillFileInventoryEntrySchema).default([]),
metadata: z.record(z.unknown()).nullable(),
createdAt: z.coerce.date(),
updatedAt: z.coerce.date(),
});
export const companySkillListItemSchema = companySkillSchema.extend({
attachedAgentCount: z.number().int().nonnegative(),
});
export const companySkillUsageAgentSchema = z.object({
id: z.string().uuid(),
name: z.string().min(1),
urlKey: z.string().min(1),
adapterType: z.string().min(1),
desired: z.boolean(),
actualState: z.string().nullable(),
});
export const companySkillDetailSchema = companySkillSchema.extend({
attachedAgentCount: z.number().int().nonnegative(),
usedByAgents: z.array(companySkillUsageAgentSchema).default([]),
});
export const companySkillImportSchema = z.object({
source: z.string().min(1),
});
export type CompanySkillImport = z.infer<typeof companySkillImportSchema>;

View file

@ -4,6 +4,18 @@ export {
type CreateCompany,
type UpdateCompany,
} from "./company.js";
export {
companySkillSourceTypeSchema,
companySkillTrustLevelSchema,
companySkillCompatibilitySchema,
companySkillFileInventoryEntrySchema,
companySkillSchema,
companySkillListItemSchema,
companySkillUsageAgentSchema,
companySkillDetailSchema,
companySkillImportSchema,
type CompanySkillImport,
} from "./company-skill.js";
export {
agentSkillStateSchema,
agentSkillSyncModeSchema,