refactor: extract @clawdhub/schema package
- Move ArkType schemas into packages/schema - Wire app/convex/cli imports to workspace dep - Add workspaces + update lint/coverage - Build schema dist (tracked)
This commit is contained in:
parent
586a08ed4d
commit
5c28a2a252
36
bun.lock
36
bun.lock
@ -6,6 +6,7 @@
|
||||
"name": "clawdhub",
|
||||
"dependencies": {
|
||||
"@auth/core": "^0.41.1",
|
||||
"@clawdhub/schema": "workspace:*",
|
||||
"@convex-dev/auth": "^0.0.90",
|
||||
"@fontsource/bricolage-grotesque": "^5.2.10",
|
||||
"@fontsource/ibm-plex-mono": "^5.2.7",
|
||||
@ -20,7 +21,6 @@
|
||||
"@tanstack/react-router-ssr-query": "^1.144.0",
|
||||
"@tanstack/react-start": "^1.145.3",
|
||||
"@tanstack/router-plugin": "^1.145.2",
|
||||
"arktype": "^2.1.29",
|
||||
"clsx": "^2.1.1",
|
||||
"convex": "^1.31.2",
|
||||
"fflate": "^0.8.2",
|
||||
@ -46,9 +46,7 @@
|
||||
"@types/semver": "^7.7.1",
|
||||
"@vitejs/plugin-react": "^5.1.2",
|
||||
"@vitest/coverage-v8": "^4.0.16",
|
||||
"commander": "^14.0.2",
|
||||
"jsdom": "^27.4.0",
|
||||
"ora": "^9.0.0",
|
||||
"oxlint": "^1.36.0",
|
||||
"oxlint-tsgolint": "^0.10.1",
|
||||
"typescript": "^5.9.3",
|
||||
@ -57,6 +55,34 @@
|
||||
"web-vitals": "^5.1.0",
|
||||
},
|
||||
},
|
||||
"packages/clawdhub": {
|
||||
"name": "clawdhub",
|
||||
"version": "0.1.0",
|
||||
"bin": {
|
||||
"clawdhub": "./bin/clawdhub.js",
|
||||
},
|
||||
"dependencies": {
|
||||
"@clawdhub/schema": "workspace:*",
|
||||
"commander": "^14.0.2",
|
||||
"fflate": "^0.8.2",
|
||||
"ora": "^9.0.0",
|
||||
"semver": "^7.7.3",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.0.3",
|
||||
"typescript": "^5.9.3",
|
||||
},
|
||||
},
|
||||
"packages/schema": {
|
||||
"name": "@clawdhub/schema",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"arktype": "^2.1.29",
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.9.3",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@acemir/cssom": ["@acemir/cssom@0.9.30", "", {}, "sha512-9CnlMCI0LmCIq0olalQqdWrJHPzm0/tw3gzOA9zJSgvFX7Xau3D24mAGa4BtwxwY69nsuJW6kQqqCzf/mEcQgg=="],
|
||||
@ -137,6 +163,8 @@
|
||||
|
||||
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.11", "", { "os": "win32", "cpu": "x64" }, "sha512-43VrG813EW+b5+YbDbz31uUsheX+qFKCpXeY9kfdAx+ww3naKxeVkTD9zLIWxUPfJquANMHrmW3wbe/037G0Qg=="],
|
||||
|
||||
"@clawdhub/schema": ["@clawdhub/schema@workspace:packages/schema"],
|
||||
|
||||
"@convex-dev/auth": ["@convex-dev/auth@0.0.90", "", { "dependencies": { "@oslojs/crypto": "^1.0.1", "@oslojs/encoding": "^1.1.0", "cookie": "^1.0.1", "is-network-error": "^1.1.0", "jose": "^5.2.2", "jwt-decode": "^4.0.0", "lucia": "^3.2.0", "oauth4webapi": "^3.1.2", "path-to-regexp": "^6.3.0", "server-only": "^0.0.1" }, "peerDependencies": { "@auth/core": "^0.37.0", "convex": "^1.17.0", "react": "^18.2.0 || ^19.0.0-0" }, "optionalPeers": ["react"], "bin": { "auth": "dist/bin.cjs" } }, "sha512-aqw88EB042HvnaF4wcf/f/wTocmT2Bus2VDQRuV79cM0+8kORM0ICK/ByZ6XsHgQ9qr6TmidNbXm6QAgndrdpQ=="],
|
||||
|
||||
"@csstools/color-helpers": ["@csstools/color-helpers@5.1.0", "", {}, "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA=="],
|
||||
@ -677,6 +705,8 @@
|
||||
|
||||
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
||||
|
||||
"clawdhub": ["clawdhub@workspace:packages/clawdhub"],
|
||||
|
||||
"cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],
|
||||
|
||||
"cli-spinners": ["cli-spinners@3.3.0", "", {}, "sha512-/+40ljC3ONVnYIttjMWrlL51nItDAbBrq2upN8BPyvGU/2n5Oxw3tbNwORCaNuNqLJnxGqOfjUuhsv7l5Q4IsQ=="],
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { parseArk } from '../packages/clawdhub/src/shared/ark.js'
|
||||
import { CliPublishRequestSchema } from '../packages/clawdhub/src/shared/schemas.js'
|
||||
import { CliPublishRequestSchema, parseArk } from '@clawdhub/schema'
|
||||
import { api, internal } from './_generated/api'
|
||||
import type { Id } from './_generated/dataModel'
|
||||
import { httpAction } from './_generated/server'
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { parseArk } from '../../packages/clawdhub/src/shared/ark.js'
|
||||
import {
|
||||
type ClawdisSkillMetadata,
|
||||
ClawdisSkillMetadataSchema,
|
||||
parseArk,
|
||||
type SkillInstallSpec,
|
||||
} from '../../packages/clawdhub/src/shared/schemas.js'
|
||||
} from '@clawdhub/schema'
|
||||
|
||||
export type ParsedSkillFrontmatter = Record<string, string>
|
||||
export type { ClawdisSkillMetadata, SkillInstallSpec }
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
"name": "clawdhub",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "bun --bun vite dev --port 3000",
|
||||
"build": "bun --bun vite build",
|
||||
@ -12,10 +15,11 @@
|
||||
"convex:deploy": "bunx convex deploy --typecheck=disable --yes",
|
||||
"lint": "bun run lint:biome && bun run lint:oxlint",
|
||||
"lint:biome": "biome check .",
|
||||
"lint:oxlint": "oxlint --type-aware --tsconfig ./tsconfig.oxlint.json ./src ./convex ./packages/clawdhub/src",
|
||||
"lint:oxlint": "oxlint --type-aware --tsconfig ./tsconfig.oxlint.json ./src ./convex ./packages/clawdhub/src ./packages/schema/src",
|
||||
"format": "biome format --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@clawdhub/schema": "workspace:*",
|
||||
"@auth/core": "^0.41.1",
|
||||
"@convex-dev/auth": "^0.0.90",
|
||||
"@fontsource/bricolage-grotesque": "^5.2.10",
|
||||
@ -31,7 +35,6 @@
|
||||
"@tanstack/react-router-ssr-query": "^1.144.0",
|
||||
"@tanstack/react-start": "^1.145.3",
|
||||
"@tanstack/router-plugin": "^1.145.2",
|
||||
"arktype": "^2.1.29",
|
||||
"clsx": "^2.1.1",
|
||||
"convex": "^1.31.2",
|
||||
"fflate": "^0.8.2",
|
||||
@ -57,9 +60,7 @@
|
||||
"@types/semver": "^7.7.1",
|
||||
"@vitejs/plugin-react": "^5.1.2",
|
||||
"@vitest/coverage-v8": "^4.0.16",
|
||||
"commander": "^14.0.2",
|
||||
"jsdom": "^27.4.0",
|
||||
"ora": "^9.0.0",
|
||||
"oxlint": "^1.36.0",
|
||||
"oxlint-tsgolint": "^0.10.1",
|
||||
"typescript": "^5.9.3",
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"arktype": "^2.1.29",
|
||||
"@clawdhub/schema": "workspace:*",
|
||||
"commander": "^14.0.2",
|
||||
"fflate": "^0.8.2",
|
||||
"ora": "^9.0.0",
|
||||
|
||||
@ -3,12 +3,6 @@ import { mkdir, rm, stat } from 'node:fs/promises'
|
||||
import { basename, join, resolve } from 'node:path'
|
||||
import { stdin } from 'node:process'
|
||||
import { createInterface } from 'node:readline/promises'
|
||||
import { Command } from 'commander'
|
||||
import ora from 'ora'
|
||||
import semver from 'semver'
|
||||
import { getGlobalConfigPath, readGlobalConfig, writeGlobalConfig } from './config.js'
|
||||
import { apiRequest, downloadZip } from './http.js'
|
||||
import { parseArk } from './shared/ark.js'
|
||||
import {
|
||||
ApiCliPublishResponseSchema,
|
||||
ApiCliUploadUrlResponseSchema,
|
||||
@ -18,7 +12,13 @@ import {
|
||||
ApiSkillResolveResponseSchema,
|
||||
ApiUploadFileResponseSchema,
|
||||
CliPublishRequestSchema,
|
||||
} from './shared/schemas.js'
|
||||
parseArk,
|
||||
} from '@clawdhub/schema'
|
||||
import { Command } from 'commander'
|
||||
import ora from 'ora'
|
||||
import semver from 'semver'
|
||||
import { getGlobalConfigPath, readGlobalConfig, writeGlobalConfig } from './config.js'
|
||||
import { apiRequest, downloadZip } from './http.js'
|
||||
import {
|
||||
extractZipToDir,
|
||||
hashSkillFiles,
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
||||
import { homedir } from 'node:os'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { parseArk } from './shared/ark.js'
|
||||
import { type GlobalConfig, GlobalConfigSchema } from './shared/schemas.js'
|
||||
import { type GlobalConfig, GlobalConfigSchema, parseArk } from '@clawdhub/schema'
|
||||
|
||||
export function getGlobalConfigPath() {
|
||||
const home = homedir()
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* @vitest-environment node */
|
||||
|
||||
import { type } from 'arktype'
|
||||
import { ApiCliWhoamiResponseSchema } from '@clawdhub/schema'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { apiRequest, downloadZip } from './http'
|
||||
|
||||
@ -8,15 +8,15 @@ describe('apiRequest', () => {
|
||||
it('adds bearer token and parses json', async () => {
|
||||
const fetchMock = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ ok: true }),
|
||||
json: async () => ({ user: { handle: null } }),
|
||||
})
|
||||
vi.stubGlobal('fetch', fetchMock)
|
||||
const result = await apiRequest(
|
||||
'https://example.com',
|
||||
{ method: 'GET', path: '/x', token: 'clh_token' },
|
||||
type({ ok: 'boolean' }),
|
||||
ApiCliWhoamiResponseSchema,
|
||||
)
|
||||
expect(result.ok).toBe(true)
|
||||
expect(result.user.handle).toBeNull()
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1)
|
||||
const [, init] = fetchMock.mock.calls[0] as [string, RequestInit]
|
||||
expect((init.headers as Record<string, string>).Authorization).toBe('Bearer clh_token')
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { ArkValidator } from './shared/ark.js'
|
||||
import { parseArk } from './shared/ark.js'
|
||||
import type { ArkValidator } from '@clawdhub/schema'
|
||||
import { parseArk } from '@clawdhub/schema'
|
||||
|
||||
type RequestArgs =
|
||||
| { method: 'GET' | 'POST'; path: string; token?: string; body?: unknown }
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
import { createHash } from 'node:crypto'
|
||||
import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises'
|
||||
import { dirname, join, relative, resolve, sep } from 'node:path'
|
||||
import { type Lockfile, LockfileSchema, parseArk } from '@clawdhub/schema'
|
||||
import { unzipSync } from 'fflate'
|
||||
import { parseArk } from './shared/ark.js'
|
||||
import { type Lockfile, LockfileSchema } from './shared/schemas.js'
|
||||
|
||||
const TEXT_EXTENSIONS = new Set([
|
||||
'md',
|
||||
|
||||
4
packages/schema/README.md
Normal file
4
packages/schema/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# @clawdhub/schema
|
||||
|
||||
Shared runtime schemas (ArkType) for ClawdHub.
|
||||
|
||||
4
packages/schema/dist/ark.d.ts
vendored
Normal file
4
packages/schema/dist/ark.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
import { ArkErrors } from 'arktype';
|
||||
export type ArkValidator<T> = (data: unknown) => T | ArkErrors;
|
||||
export declare function parseArk<T>(schema: ArkValidator<T>, data: unknown, label: string): T;
|
||||
export declare function formatArkErrors(errors: ArkErrors): string;
|
||||
26
packages/schema/dist/ark.js
vendored
Normal file
26
packages/schema/dist/ark.js
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
import { ArkErrors } from 'arktype';
|
||||
export function parseArk(schema, data, label) {
|
||||
const result = schema(data);
|
||||
if (result instanceof ArkErrors) {
|
||||
throw new Error(`${label}: ${formatArkErrors(result)}`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
export function formatArkErrors(errors) {
|
||||
const parts = [];
|
||||
for (const error of errors) {
|
||||
if (parts.length >= 3)
|
||||
break;
|
||||
const path = Array.isArray(error.path) ? error.path.join('.') : '';
|
||||
const location = path ? `${path}: ` : '';
|
||||
const description = typeof error.description === 'string'
|
||||
? error.description
|
||||
: 'invalid value';
|
||||
parts.push(`${location}${description}`);
|
||||
}
|
||||
if (errors.count > parts.length) {
|
||||
parts.push(`+${errors.count - parts.length} more`);
|
||||
}
|
||||
return parts.join('; ');
|
||||
}
|
||||
//# sourceMappingURL=ark.js.map
|
||||
1
packages/schema/dist/ark.js.map
vendored
Normal file
1
packages/schema/dist/ark.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"ark.js","sourceRoot":"","sources":["../src/ark.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAInC,MAAM,UAAU,QAAQ,CAAI,MAAuB,EAAE,IAAa,EAAE,KAAa;IAC/E,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;IAC3B,IAAI,MAAM,YAAY,SAAS,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IACzD,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;YAAE,MAAK;QAC5B,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAClE,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;QACxC,MAAM,WAAW,GACf,OAAQ,KAAmC,CAAC,WAAW,KAAK,QAAQ;YAClE,CAAC,CAAG,KAAiC,CAAC,WAAsB;YAC5D,CAAC,CAAC,eAAe,CAAA;QACrB,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,GAAG,WAAW,EAAE,CAAC,CAAA;IACzC,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,OAAO,CAAC,CAAA;IACpD,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC"}
|
||||
3
packages/schema/dist/index.d.ts
vendored
Normal file
3
packages/schema/dist/index.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
export type { ArkValidator } from './ark.js';
|
||||
export { formatArkErrors, parseArk } from './ark.js';
|
||||
export * from './schemas.js';
|
||||
3
packages/schema/dist/index.js
vendored
Normal file
3
packages/schema/dist/index.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
export { formatArkErrors, parseArk } from './ark.js';
|
||||
export * from './schemas.js';
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
packages/schema/dist/index.js.map
vendored
Normal file
1
packages/schema/dist/index.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACpD,cAAc,cAAc,CAAA"}
|
||||
120
packages/schema/dist/schemas.d.ts
vendored
Normal file
120
packages/schema/dist/schemas.d.ts
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
import { type inferred } from 'arktype';
|
||||
export declare const GlobalConfigSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
||||
registry: string;
|
||||
token: string;
|
||||
}, {}>;
|
||||
export type GlobalConfig = (typeof GlobalConfigSchema)[inferred];
|
||||
export declare const LockfileSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
||||
version: 1;
|
||||
skills: {
|
||||
[x: string]: {
|
||||
version: string | null;
|
||||
installedAt: number;
|
||||
};
|
||||
};
|
||||
}, {}>;
|
||||
export type Lockfile = (typeof LockfileSchema)[inferred];
|
||||
export declare const ApiCliWhoamiResponseSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
||||
user: {
|
||||
handle: string | null;
|
||||
};
|
||||
}, {}>;
|
||||
export declare const ApiSearchResponseSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
||||
results: [{
|
||||
score: number;
|
||||
slug?: string | undefined;
|
||||
displayName?: string | undefined;
|
||||
version?: string | null | undefined;
|
||||
}];
|
||||
}, {}>;
|
||||
export declare const ApiSkillMetaResponseSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
||||
latestVersion?: {
|
||||
version: string;
|
||||
} | undefined;
|
||||
skill?: unknown;
|
||||
}, {}>;
|
||||
export declare const ApiCliUploadUrlResponseSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
||||
uploadUrl: string;
|
||||
}, {}>;
|
||||
export declare const ApiUploadFileResponseSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
||||
storageId: string;
|
||||
}, {}>;
|
||||
export declare const CliPublishFileSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
||||
path: string;
|
||||
size: number;
|
||||
storageId: string;
|
||||
sha256: string;
|
||||
contentType?: string | undefined;
|
||||
}, {}>;
|
||||
export type CliPublishFile = (typeof CliPublishFileSchema)[inferred];
|
||||
export declare const CliPublishRequestSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
||||
slug: string;
|
||||
displayName: string;
|
||||
version: string;
|
||||
changelog: string;
|
||||
files: {
|
||||
path: string;
|
||||
size: number;
|
||||
storageId: string;
|
||||
sha256: string;
|
||||
contentType?: string | undefined;
|
||||
}[];
|
||||
tags?: string[] | undefined;
|
||||
}, {}>;
|
||||
export type CliPublishRequest = (typeof CliPublishRequestSchema)[inferred];
|
||||
export declare const ApiCliPublishResponseSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
||||
ok: true;
|
||||
skillId: string;
|
||||
versionId: string;
|
||||
}, {}>;
|
||||
export declare const ApiSkillResolveResponseSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
||||
match: {
|
||||
version: string;
|
||||
} | null;
|
||||
latestVersion: {
|
||||
version: string;
|
||||
} | null;
|
||||
}, {}>;
|
||||
export declare const SkillInstallSpecSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
||||
kind: "brew" | "node" | "go" | "uv";
|
||||
id?: string | undefined;
|
||||
label?: string | undefined;
|
||||
bins?: string[] | undefined;
|
||||
formula?: string | undefined;
|
||||
tap?: string | undefined;
|
||||
package?: string | undefined;
|
||||
module?: string | undefined;
|
||||
}, {}>;
|
||||
export type SkillInstallSpec = (typeof SkillInstallSpecSchema)[inferred];
|
||||
export declare const ClawdisRequiresSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
||||
bins?: string[] | undefined;
|
||||
anyBins?: string[] | undefined;
|
||||
env?: string[] | undefined;
|
||||
config?: string[] | undefined;
|
||||
}, {}>;
|
||||
export type ClawdisRequires = (typeof ClawdisRequiresSchema)[inferred];
|
||||
export declare const ClawdisSkillMetadataSchema: import("arktype/internal/variants/object.ts").ObjectType<{
|
||||
always?: boolean | undefined;
|
||||
skillKey?: string | undefined;
|
||||
primaryEnv?: string | undefined;
|
||||
emoji?: string | undefined;
|
||||
homepage?: string | undefined;
|
||||
os?: string[] | undefined;
|
||||
requires?: {
|
||||
bins?: string[] | undefined;
|
||||
anyBins?: string[] | undefined;
|
||||
env?: string[] | undefined;
|
||||
config?: string[] | undefined;
|
||||
} | undefined;
|
||||
install?: {
|
||||
kind: "brew" | "node" | "go" | "uv";
|
||||
id?: string | undefined;
|
||||
label?: string | undefined;
|
||||
bins?: string[] | undefined;
|
||||
formula?: string | undefined;
|
||||
tap?: string | undefined;
|
||||
package?: string | undefined;
|
||||
module?: string | undefined;
|
||||
}[] | undefined;
|
||||
}, {}>;
|
||||
export type ClawdisSkillMetadata = (typeof ClawdisSkillMetadataSchema)[inferred];
|
||||
92
packages/schema/dist/schemas.js
vendored
Normal file
92
packages/schema/dist/schemas.js
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
import { type } from 'arktype';
|
||||
export const GlobalConfigSchema = type({
|
||||
registry: 'string',
|
||||
token: 'string',
|
||||
});
|
||||
export const LockfileSchema = type({
|
||||
version: '1',
|
||||
skills: {
|
||||
'[string]': {
|
||||
version: 'string|null',
|
||||
installedAt: 'number',
|
||||
},
|
||||
},
|
||||
});
|
||||
export const ApiCliWhoamiResponseSchema = type({
|
||||
user: {
|
||||
handle: 'string|null',
|
||||
},
|
||||
});
|
||||
export const ApiSearchResponseSchema = type({
|
||||
results: [
|
||||
{
|
||||
slug: 'string?',
|
||||
displayName: 'string?',
|
||||
version: 'string|null?',
|
||||
score: 'number',
|
||||
},
|
||||
],
|
||||
});
|
||||
export const ApiSkillMetaResponseSchema = type({
|
||||
latestVersion: type({
|
||||
version: 'string',
|
||||
}).optional(),
|
||||
skill: 'unknown|null?',
|
||||
});
|
||||
export const ApiCliUploadUrlResponseSchema = type({
|
||||
uploadUrl: 'string',
|
||||
});
|
||||
export const ApiUploadFileResponseSchema = type({
|
||||
storageId: 'string',
|
||||
});
|
||||
export const CliPublishFileSchema = type({
|
||||
path: 'string',
|
||||
size: 'number',
|
||||
storageId: 'string',
|
||||
sha256: 'string',
|
||||
contentType: 'string?',
|
||||
});
|
||||
export const CliPublishRequestSchema = type({
|
||||
slug: 'string',
|
||||
displayName: 'string',
|
||||
version: 'string',
|
||||
changelog: 'string',
|
||||
tags: 'string[]?',
|
||||
files: CliPublishFileSchema.array(),
|
||||
});
|
||||
export const ApiCliPublishResponseSchema = type({
|
||||
ok: 'true',
|
||||
skillId: 'string',
|
||||
versionId: 'string',
|
||||
});
|
||||
export const ApiSkillResolveResponseSchema = type({
|
||||
match: type({ version: 'string' }).or('null'),
|
||||
latestVersion: type({ version: 'string' }).or('null'),
|
||||
});
|
||||
export const SkillInstallSpecSchema = type({
|
||||
id: 'string?',
|
||||
kind: '"brew"|"node"|"go"|"uv"',
|
||||
label: 'string?',
|
||||
bins: 'string[]?',
|
||||
formula: 'string?',
|
||||
tap: 'string?',
|
||||
package: 'string?',
|
||||
module: 'string?',
|
||||
});
|
||||
export const ClawdisRequiresSchema = type({
|
||||
bins: 'string[]?',
|
||||
anyBins: 'string[]?',
|
||||
env: 'string[]?',
|
||||
config: 'string[]?',
|
||||
});
|
||||
export const ClawdisSkillMetadataSchema = type({
|
||||
always: 'boolean?',
|
||||
skillKey: 'string?',
|
||||
primaryEnv: 'string?',
|
||||
emoji: 'string?',
|
||||
homepage: 'string?',
|
||||
os: 'string[]?',
|
||||
requires: ClawdisRequiresSchema.optional(),
|
||||
install: SkillInstallSpecSchema.array().optional(),
|
||||
});
|
||||
//# sourceMappingURL=schemas.js.map
|
||||
1
packages/schema/dist/schemas.js.map
vendored
Normal file
1
packages/schema/dist/schemas.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,IAAI,EAAE,MAAM,SAAS,CAAA;AAE7C,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;IACrC,QAAQ,EAAE,QAAQ;IAClB,KAAK,EAAE,QAAQ;CAChB,CAAC,CAAA;AAGF,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,GAAG;IACZ,MAAM,EAAE;QACN,UAAU,EAAE;YACV,OAAO,EAAE,aAAa;YACtB,WAAW,EAAE,QAAQ;SACtB;KACF;CACF,CAAC,CAAA;AAGF,MAAM,CAAC,MAAM,0BAA0B,GAAG,IAAI,CAAC;IAC7C,IAAI,EAAE;QACJ,MAAM,EAAE,aAAa;KACtB;CACF,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE;QACP;YACE,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,SAAS;YACtB,OAAO,EAAE,cAAc;YACvB,KAAK,EAAE,QAAQ;SAChB;KACF;CACF,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,0BAA0B,GAAG,IAAI,CAAC;IAC7C,aAAa,EAAE,IAAI,CAAC;QAClB,OAAO,EAAE,QAAQ;KAClB,CAAC,CAAC,QAAQ,EAAE;IACb,KAAK,EAAE,eAAe;CACvB,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,6BAA6B,GAAG,IAAI,CAAC;IAChD,SAAS,EAAE,QAAQ;CACpB,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,2BAA2B,GAAG,IAAI,CAAC;IAC9C,SAAS,EAAE,QAAQ;CACpB,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC;IACvC,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,QAAQ;IACd,SAAS,EAAE,QAAQ;IACnB,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE,SAAS;CACvB,CAAC,CAAA;AAGF,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC;IAC1C,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,QAAQ;IACrB,OAAO,EAAE,QAAQ;IACjB,SAAS,EAAE,QAAQ;IACnB,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,oBAAoB,CAAC,KAAK,EAAE;CACpC,CAAC,CAAA;AAGF,MAAM,CAAC,MAAM,2BAA2B,GAAG,IAAI,CAAC;IAC9C,EAAE,EAAE,MAAM;IACV,OAAO,EAAE,QAAQ;IACjB,SAAS,EAAE,QAAQ;CACpB,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,6BAA6B,GAAG,IAAI,CAAC;IAChD,KAAK,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC;IAC7C,aAAa,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC;CACtD,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC;IACzC,EAAE,EAAE,SAAS;IACb,IAAI,EAAE,yBAAyB;IAC/B,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,SAAS;IAClB,GAAG,EAAE,SAAS;IACd,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,SAAS;CAClB,CAAC,CAAA;AAGF,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC;IACxC,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,WAAW;IACpB,GAAG,EAAE,WAAW;IAChB,MAAM,EAAE,WAAW;CACpB,CAAC,CAAA;AAGF,MAAM,CAAC,MAAM,0BAA0B,GAAG,IAAI,CAAC;IAC7C,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,SAAS;IACnB,UAAU,EAAE,SAAS;IACrB,KAAK,EAAE,SAAS;IAChB,QAAQ,EAAE,SAAS;IACnB,EAAE,EAAE,WAAW;IACf,QAAQ,EAAE,qBAAqB,CAAC,QAAQ,EAAE;IAC1C,OAAO,EAAE,sBAAsB,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;CACnD,CAAC,CAAA"}
|
||||
25
packages/schema/package.json
Normal file
25
packages/schema/package.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "@clawdhub/schema",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"arktype": "^2.1.29"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
3
packages/schema/src/index.ts
Normal file
3
packages/schema/src/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export type { ArkValidator } from './ark.js'
|
||||
export { formatArkErrors, parseArk } from './ark.js'
|
||||
export * from './schemas.js'
|
||||
@ -1,9 +1,10 @@
|
||||
/* @vitest-environment node */
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { parseArk } from './ark'
|
||||
import { CliPublishRequestSchema, LockfileSchema } from './schemas'
|
||||
|
||||
describe('shared schemas', () => {
|
||||
describe('@clawdhub/schema', () => {
|
||||
it('parses lockfile records', () => {
|
||||
const lock = parseArk(
|
||||
LockfileSchema,
|
||||
@ -29,7 +30,7 @@ describe('shared schemas', () => {
|
||||
expect(payload.files[0]?.path).toBe('SKILL.md')
|
||||
})
|
||||
|
||||
it('formats parse errors with label', () => {
|
||||
it('throws labeled errors', () => {
|
||||
expect(() => parseArk(LockfileSchema, null, 'Lockfile')).toThrow(/Lockfile:/)
|
||||
})
|
||||
})
|
||||
15
packages/schema/tsconfig.json
Normal file
15
packages/schema/tsconfig.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"moduleResolution": "Bundler",
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"strict": true,
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["src/**/*.test.ts"]
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
import type { ClawdisSkillMetadata, SkillInstallSpec } from '@clawdhub/schema'
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { useAction, useConvexAuth, useMutation, useQuery } from 'convex/react'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
@ -5,7 +6,6 @@ import ReactMarkdown from 'react-markdown'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import { api } from '../../../convex/_generated/api'
|
||||
import type { Doc, Id } from '../../../convex/_generated/dataModel'
|
||||
import type { ClawdisSkillMetadata, SkillInstallSpec } from '../../../convex/lib/skills'
|
||||
|
||||
export const Route = createFileRoute('/skills/$slug')({
|
||||
component: SkillDetail,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"include": ["src", "convex", "packages/clawdhub/src"],
|
||||
"include": ["src", "convex", "packages/clawdhub/src", "packages/schema/src"],
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"jsx": "react-jsx",
|
||||
|
||||
@ -5,6 +5,12 @@ export default defineConfig({
|
||||
environment: 'jsdom',
|
||||
globals: true,
|
||||
setupFiles: ['./vitest.setup.ts'],
|
||||
exclude: [
|
||||
'**/node_modules/**',
|
||||
'**/dist/**',
|
||||
'**/coverage/**',
|
||||
'**/convex/_generated/**',
|
||||
],
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
reporter: ['text', 'html', 'lcov'],
|
||||
@ -20,6 +26,7 @@ export default defineConfig({
|
||||
'convex/lib/tokens.ts',
|
||||
'convex/httpApi.ts',
|
||||
'packages/clawdhub/src/**/*.ts',
|
||||
'packages/schema/src/**/*.ts',
|
||||
],
|
||||
exclude: [
|
||||
'node_modules/',
|
||||
@ -29,6 +36,7 @@ export default defineConfig({
|
||||
'packages/clawdhub/src/cli.ts',
|
||||
'packages/clawdhub/src/config.ts',
|
||||
'packages/clawdhub/src/types.ts',
|
||||
'packages/schema/dist/',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user