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.
- package/Claude/CLAUDE.md +9 -4
- package/Claude/skills/environment/SKILL.md +6 -0
- package/Claude/skills/memory/SKILL.md +6 -0
- package/Claude/skills/project/SKILL.md +6 -0
- package/Claude/skills/secret/SKILL.md +85 -0
- package/Claude/skills/secret/secret.py +146 -0
- package/Claude/skills/skill-creator/SKILL.md +30 -0
- package/Claude/skills/task/SKILL.md +6 -0
- package/app/components/skills/Card.vue +82 -0
- package/app/components/skills/CreateModal.vue +156 -0
- package/app/components/skills/Editor.vue +135 -0
- package/app/components/skills/FileTree.vue +336 -0
- package/app/components/skills/LibraryCard.vue +122 -0
- package/app/components/skills/RenameModal.vue +84 -0
- package/app/layouts/dashboard.vue +7 -0
- package/app/pages/skills/[name].vue +198 -0
- package/app/pages/skills/index.vue +157 -0
- package/app/pages/skills/library.vue +209 -0
- package/dist/cli/index.js +23 -23
- package/nuxt.config.ts +9 -0
- package/package.json +1 -1
- package/server/api/skills/[name]/files/create.post.ts +45 -0
- package/server/api/skills/[name]/files/delete.post.ts +45 -0
- package/server/api/skills/[name]/files/index.get.ts +28 -0
- package/server/api/skills/[name]/files/read.post.ts +41 -0
- package/server/api/skills/[name]/files/write.post.ts +42 -0
- package/server/api/skills/[name]/index.get.ts +54 -0
- package/server/api/skills/[name]/rename.post.ts +64 -0
- package/server/api/skills/[name]/toggle.post.ts +32 -0
- package/server/api/skills/create.post.ts +51 -0
- package/server/api/skills/generate.post.ts +126 -0
- package/server/api/skills/index.get.ts +57 -0
- package/server/api/skills/library/check-updates.get.ts +46 -0
- package/server/api/skills/library/index.get.ts +56 -0
- package/server/api/skills/library/install.post.ts +73 -0
- package/server/db/schema.ts +17 -0
- package/server/drizzle/migrations/0012_good_deadpool.sql +12 -0
- package/server/drizzle/migrations/0013_swift_snowbird.sql +1 -0
- package/server/drizzle/migrations/meta/0012_snapshot.json +1713 -0
- package/server/drizzle/migrations/meta/0013_snapshot.json +1720 -0
- package/server/drizzle/migrations/meta/_journal.json +14 -0
- package/server/middleware/auth.ts +0 -1
- package/server/plugins/05.skills-catalog.ts +105 -0
- package/server/utils/skills-path.ts +197 -0
- 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
|
+
})
|
package/server/db/schema.ts
CHANGED
|
@@ -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 '{}';
|