cognova 0.2.0 → 0.2.2

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 (45) hide show
  1. package/Claude/CLAUDE.md +9 -4
  2. package/Claude/skills/environment/SKILL.md +6 -0
  3. package/Claude/skills/memory/SKILL.md +6 -0
  4. package/Claude/skills/project/SKILL.md +6 -0
  5. package/Claude/skills/secret/SKILL.md +85 -0
  6. package/Claude/skills/secret/secret.py +146 -0
  7. package/Claude/skills/skill-creator/SKILL.md +30 -0
  8. package/Claude/skills/task/SKILL.md +6 -0
  9. package/app/components/skills/Card.vue +82 -0
  10. package/app/components/skills/CreateModal.vue +156 -0
  11. package/app/components/skills/Editor.vue +135 -0
  12. package/app/components/skills/FileTree.vue +336 -0
  13. package/app/components/skills/LibraryCard.vue +122 -0
  14. package/app/components/skills/RenameModal.vue +84 -0
  15. package/app/layouts/dashboard.vue +7 -0
  16. package/app/pages/skills/[name].vue +198 -0
  17. package/app/pages/skills/index.vue +157 -0
  18. package/app/pages/skills/library.vue +209 -0
  19. package/dist/cli/index.js +23 -23
  20. package/nuxt.config.ts +9 -0
  21. package/package.json +1 -1
  22. package/server/api/skills/[name]/files/create.post.ts +45 -0
  23. package/server/api/skills/[name]/files/delete.post.ts +45 -0
  24. package/server/api/skills/[name]/files/index.get.ts +28 -0
  25. package/server/api/skills/[name]/files/read.post.ts +41 -0
  26. package/server/api/skills/[name]/files/write.post.ts +42 -0
  27. package/server/api/skills/[name]/index.get.ts +54 -0
  28. package/server/api/skills/[name]/rename.post.ts +64 -0
  29. package/server/api/skills/[name]/toggle.post.ts +32 -0
  30. package/server/api/skills/create.post.ts +51 -0
  31. package/server/api/skills/generate.post.ts +126 -0
  32. package/server/api/skills/index.get.ts +57 -0
  33. package/server/api/skills/library/check-updates.get.ts +46 -0
  34. package/server/api/skills/library/index.get.ts +56 -0
  35. package/server/api/skills/library/install.post.ts +73 -0
  36. package/server/db/schema.ts +17 -0
  37. package/server/drizzle/migrations/0012_good_deadpool.sql +12 -0
  38. package/server/drizzle/migrations/0013_swift_snowbird.sql +1 -0
  39. package/server/drizzle/migrations/meta/0012_snapshot.json +1713 -0
  40. package/server/drizzle/migrations/meta/0013_snapshot.json +1720 -0
  41. package/server/drizzle/migrations/meta/_journal.json +14 -0
  42. package/server/middleware/auth.ts +0 -1
  43. package/server/plugins/05.skills-catalog.ts +105 -0
  44. package/server/utils/skills-path.ts +197 -0
  45. package/shared/types/index.ts +63 -0
@@ -0,0 +1,56 @@
1
+ import { readFile, stat } from 'fs/promises'
2
+ import { join } from 'path'
3
+ import { getDb } from '~~/server/db'
4
+ import { getSkillsDir, getInactiveSkillsDir, parseSkillFrontmatter } from '~~/server/utils/skills-path'
5
+
6
+ export default defineEventHandler(async () => {
7
+ const db = getDb()
8
+ const catalogItems = await db.query.skillsCatalog.findMany()
9
+
10
+ // Check which skills are already installed
11
+ const skillsDir = getSkillsDir()
12
+ const inactiveDir = getInactiveSkillsDir()
13
+
14
+ const items = await Promise.all(catalogItems.map(async (item) => {
15
+ const activePath = join(skillsDir, item.name, 'SKILL.md')
16
+ const inactivePath = join(inactiveDir, item.name, 'SKILL.md')
17
+
18
+ let installed = false
19
+ let installedVersion: string | undefined
20
+
21
+ // Check active skills
22
+ const activeStat = await stat(activePath).catch(() => null)
23
+ if (activeStat) {
24
+ installed = true
25
+ const content = await readFile(activePath, 'utf-8').catch(() => '')
26
+ const meta = parseSkillFrontmatter(content)
27
+ installedVersion = meta.version
28
+ } else {
29
+ // Check inactive skills
30
+ const inactiveStat = await stat(inactivePath).catch(() => null)
31
+ if (inactiveStat) {
32
+ installed = true
33
+ const content = await readFile(inactivePath, 'utf-8').catch(() => '')
34
+ const meta = parseSkillFrontmatter(content)
35
+ installedVersion = meta.version
36
+ }
37
+ }
38
+
39
+ return {
40
+ id: item.id,
41
+ name: item.name,
42
+ description: item.description,
43
+ version: item.version,
44
+ author: item.author,
45
+ tags: item.tags || [],
46
+ requiresSecrets: item.requiresSecrets || [],
47
+ files: item.files || [],
48
+ updatedAt: item.updatedAt.toISOString(),
49
+ installed,
50
+ installedVersion,
51
+ hasUpdate: installed && installedVersion ? installedVersion !== item.version : false
52
+ }
53
+ }))
54
+
55
+ return { data: items }
56
+ })
@@ -0,0 +1,73 @@
1
+ import { mkdir, writeFile, stat } from 'fs/promises'
2
+ import { join } from 'path'
3
+ import { eq } from 'drizzle-orm'
4
+ import { getDb } from '~~/server/db'
5
+ import * as schema from '~~/server/db/schema'
6
+ import { getSkillsDir } from '~~/server/utils/skills-path'
7
+
8
+ const REPO_RAW_BASE = 'https://raw.githubusercontent.com/Patrity/cognova-skills/main'
9
+
10
+ export default defineEventHandler(async (event) => {
11
+ const body = await readBody<{ name: string }>(event)
12
+ if (!body?.name)
13
+ throw createError({ statusCode: 400, message: 'Skill name is required' })
14
+
15
+ const db = getDb()
16
+ const catalogItem = await db.query.skillsCatalog.findFirst({
17
+ where: eq(schema.skillsCatalog.name, body.name)
18
+ })
19
+
20
+ if (!catalogItem)
21
+ throw createError({ statusCode: 404, message: `Skill '${body.name}' not found in library` })
22
+
23
+ const skillDir = join(getSkillsDir(), body.name)
24
+
25
+ // Check if already installed
26
+ const existing = await stat(skillDir).catch(() => null)
27
+ if (existing)
28
+ throw createError({ statusCode: 409, message: `Skill '${body.name}' is already installed` })
29
+
30
+ await mkdir(skillDir, { recursive: true })
31
+
32
+ const files = catalogItem.files || []
33
+ if (files.length === 0)
34
+ throw createError({ statusCode: 500, message: 'Skill has no files listed in registry' })
35
+
36
+ // Download each file from GitHub
37
+ for (const file of files) {
38
+ const url = `${REPO_RAW_BASE}/${body.name}/${file}`
39
+ const response = await fetch(url)
40
+ if (!response.ok) {
41
+ console.error(`[skills/library/install] Failed to fetch ${url}: ${response.status}`)
42
+ continue
43
+ }
44
+
45
+ let content = await response.text()
46
+
47
+ // Inject installed-from into SKILL.md frontmatter
48
+ if (file === 'SKILL.md' && content.startsWith('---')) {
49
+ content = content.replace(
50
+ /^---\n/,
51
+ '---\n installed-from: "cognova-skills"\n'
52
+ )
53
+ }
54
+
55
+ // Handle nested paths
56
+ const filePath = join(skillDir, file)
57
+ const fileDir = filePath.substring(0, filePath.lastIndexOf('/'))
58
+ if (fileDir !== skillDir) {
59
+ await mkdir(fileDir, { recursive: true })
60
+ }
61
+
62
+ await writeFile(filePath, content, 'utf-8')
63
+ }
64
+
65
+ return {
66
+ data: {
67
+ name: body.name,
68
+ installed: true,
69
+ version: catalogItem.version,
70
+ fileCount: files.length
71
+ }
72
+ }
73
+ })
@@ -360,6 +360,23 @@ export const userSettingsRelations = relations(userSettings, ({ one }) => ({
360
360
  user: one(user, { fields: [userSettings.userId], references: [user.id] })
361
361
  }))
362
362
 
363
+ // =============================================================================
364
+ // Skills Catalog - Cache of community skills registry
365
+ // =============================================================================
366
+
367
+ export const skillsCatalog = pgTable('skills_catalog', {
368
+ id: uuid('id').primaryKey().defaultRandom(),
369
+ name: text('name').notNull().unique(),
370
+ description: text('description').notNull(),
371
+ version: text('version').notNull(),
372
+ author: text('author').notNull(),
373
+ tags: text('tags').array().default([]),
374
+ requiresSecrets: text('requires_secrets').array().default([]),
375
+ files: text('files').array().default([]),
376
+ updatedAt: timestamp('updated_at', { withTimezone: true }).notNull(),
377
+ syncedAt: timestamp('synced_at', { withTimezone: true }).defaultNow().notNull()
378
+ })
379
+
363
380
  // =============================================================================
364
381
  // Token Usage - Unified AI cost & token tracking
365
382
  // =============================================================================
@@ -0,0 +1,12 @@
1
+ CREATE TABLE "skills_catalog" (
2
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
3
+ "name" text NOT NULL,
4
+ "description" text NOT NULL,
5
+ "version" text NOT NULL,
6
+ "author" text NOT NULL,
7
+ "requires_secrets" text[] DEFAULT '{}',
8
+ "files" text[] DEFAULT '{}',
9
+ "updated_at" timestamp with time zone NOT NULL,
10
+ "synced_at" timestamp with time zone DEFAULT now() NOT NULL,
11
+ CONSTRAINT "skills_catalog_name_unique" UNIQUE("name")
12
+ );
@@ -0,0 +1 @@
1
+ ALTER TABLE "skills_catalog" ADD COLUMN "tags" text[] DEFAULT '{}';