clawdhub 0.0.1

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 (79) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +57 -0
  3. package/bin/clawdhub.js +2 -0
  4. package/dist/browserAuth.d.ts +20 -0
  5. package/dist/browserAuth.js +156 -0
  6. package/dist/browserAuth.js.map +1 -0
  7. package/dist/browserAuth.test.d.ts +1 -0
  8. package/dist/browserAuth.test.js +39 -0
  9. package/dist/browserAuth.test.js.map +1 -0
  10. package/dist/cli/buildInfo.d.ts +3 -0
  11. package/dist/cli/buildInfo.js +103 -0
  12. package/dist/cli/buildInfo.js.map +1 -0
  13. package/dist/cli/commands/auth.d.ts +9 -0
  14. package/dist/cli/commands/auth.js +75 -0
  15. package/dist/cli/commands/auth.js.map +1 -0
  16. package/dist/cli/commands/publish.d.ts +8 -0
  17. package/dist/cli/commands/publish.js +91 -0
  18. package/dist/cli/commands/publish.js.map +1 -0
  19. package/dist/cli/commands/publish.test.d.ts +1 -0
  20. package/dist/cli/commands/publish.test.js +120 -0
  21. package/dist/cli/commands/publish.test.js.map +1 -0
  22. package/dist/cli/commands/skills.d.ts +9 -0
  23. package/dist/cli/commands/skills.js +195 -0
  24. package/dist/cli/commands/skills.js.map +1 -0
  25. package/dist/cli/commands/sync.d.ts +11 -0
  26. package/dist/cli/commands/sync.js +273 -0
  27. package/dist/cli/commands/sync.js.map +1 -0
  28. package/dist/cli/commands/sync.test.d.ts +1 -0
  29. package/dist/cli/commands/sync.test.js +106 -0
  30. package/dist/cli/commands/sync.test.js.map +1 -0
  31. package/dist/cli/helpStyle.d.ts +13 -0
  32. package/dist/cli/helpStyle.js +38 -0
  33. package/dist/cli/helpStyle.js.map +1 -0
  34. package/dist/cli/registry.d.ts +7 -0
  35. package/dist/cli/registry.js +27 -0
  36. package/dist/cli/registry.js.map +1 -0
  37. package/dist/cli/scanSkills.d.ts +7 -0
  38. package/dist/cli/scanSkills.js +75 -0
  39. package/dist/cli/scanSkills.js.map +1 -0
  40. package/dist/cli/scanSkills.test.d.ts +1 -0
  41. package/dist/cli/scanSkills.test.js +47 -0
  42. package/dist/cli/scanSkills.test.js.map +1 -0
  43. package/dist/cli/slug.d.ts +2 -0
  44. package/dist/cli/slug.js +16 -0
  45. package/dist/cli/slug.js.map +1 -0
  46. package/dist/cli/types.d.ts +14 -0
  47. package/dist/cli/types.js +2 -0
  48. package/dist/cli/types.js.map +1 -0
  49. package/dist/cli/ui.d.ts +7 -0
  50. package/dist/cli/ui.js +72 -0
  51. package/dist/cli/ui.js.map +1 -0
  52. package/dist/cli.d.ts +2 -0
  53. package/dist/cli.js +179 -0
  54. package/dist/cli.js.map +1 -0
  55. package/dist/config.d.ts +4 -0
  56. package/dist/config.js +38 -0
  57. package/dist/config.js.map +1 -0
  58. package/dist/discovery.d.ts +5 -0
  59. package/dist/discovery.js +21 -0
  60. package/dist/discovery.js.map +1 -0
  61. package/dist/discovery.test.d.ts +1 -0
  62. package/dist/discovery.test.js +24 -0
  63. package/dist/discovery.test.js.map +1 -0
  64. package/dist/http.d.ts +19 -0
  65. package/dist/http.js +46 -0
  66. package/dist/http.js.map +1 -0
  67. package/dist/http.test.d.ts +1 -0
  68. package/dist/http.test.js +70 -0
  69. package/dist/http.test.js.map +1 -0
  70. package/dist/skills.d.ts +34 -0
  71. package/dist/skills.js +135 -0
  72. package/dist/skills.js.map +1 -0
  73. package/dist/skills.test.d.ts +1 -0
  74. package/dist/skills.test.js +83 -0
  75. package/dist/skills.test.js.map +1 -0
  76. package/dist/types.d.ts +7 -0
  77. package/dist/types.js +2 -0
  78. package/dist/types.js.map +1 -0
  79. package/package.json +39 -0
package/dist/cli.js ADDED
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env node
2
+ import { resolve } from 'node:path';
3
+ import { Command } from 'commander';
4
+ import { getCliBuildLabel, getCliVersion } from './cli/buildInfo.js';
5
+ import { cmdLoginFlow, cmdLogout, cmdWhoami } from './cli/commands/auth.js';
6
+ import { cmdPublish } from './cli/commands/publish.js';
7
+ import { cmdInstall, cmdList, cmdSearch, cmdUpdate } from './cli/commands/skills.js';
8
+ import { cmdSync } from './cli/commands/sync.js';
9
+ import { configureCommanderHelp, styleEnvBlock, styleTitle } from './cli/helpStyle.js';
10
+ import { DEFAULT_REGISTRY, DEFAULT_SITE } from './cli/registry.js';
11
+ import { fail } from './cli/ui.js';
12
+ import { readGlobalConfig } from './config.js';
13
+ const program = new Command()
14
+ .name('clawdhub')
15
+ .description(`${styleTitle(`ClawdHub CLI ${getCliBuildLabel()}`)}\n${styleEnvBlock('install, update, search, and publish agent skills.')}`)
16
+ .version(getCliVersion(), '-V, --version', 'Show version')
17
+ .option('--workdir <dir>', 'Working directory (default: cwd)')
18
+ .option('--dir <dir>', 'Skills directory (relative to workdir, default: skills)')
19
+ .option('--site <url>', 'Site base URL (for browser login)')
20
+ .option('--registry <url>', 'Registry API base URL')
21
+ .option('--no-input', 'Disable prompts')
22
+ .showHelpAfterError()
23
+ .showSuggestionAfterError()
24
+ .addHelpText('after', styleEnvBlock('\nEnv:\n CLAWDHUB_SITE\n CLAWDHUB_REGISTRY\n'));
25
+ configureCommanderHelp(program);
26
+ function resolveGlobalOpts() {
27
+ const raw = program.opts();
28
+ const workdir = resolve(raw.workdir ?? process.cwd());
29
+ const dir = resolve(workdir, raw.dir ?? 'skills');
30
+ const site = raw.site ?? process.env.CLAWDHUB_SITE ?? DEFAULT_SITE;
31
+ const registry = raw.registry ?? process.env.CLAWDHUB_REGISTRY ?? DEFAULT_REGISTRY;
32
+ return { workdir, dir, site, registry };
33
+ }
34
+ function isInputAllowed() {
35
+ const globalFlags = program.opts();
36
+ return globalFlags.input !== false;
37
+ }
38
+ program
39
+ .command('login')
40
+ .description('Log in (opens browser or stores token)')
41
+ .option('--token <token>', 'API token')
42
+ .option('--label <label>', 'Token label (browser flow only)', 'CLI token')
43
+ .option('--no-browser', 'Do not open browser (requires --token)')
44
+ .action(async (options) => {
45
+ const opts = resolveGlobalOpts();
46
+ await cmdLoginFlow(opts, options, isInputAllowed());
47
+ });
48
+ program
49
+ .command('logout')
50
+ .description('Remove stored token')
51
+ .action(async () => {
52
+ const opts = resolveGlobalOpts();
53
+ await cmdLogout(opts);
54
+ });
55
+ program
56
+ .command('whoami')
57
+ .description('Validate token')
58
+ .action(async () => {
59
+ const opts = resolveGlobalOpts();
60
+ await cmdWhoami(opts);
61
+ });
62
+ const auth = program
63
+ .command('auth')
64
+ .description('Authentication commands')
65
+ .showHelpAfterError()
66
+ .showSuggestionAfterError();
67
+ auth
68
+ .command('login')
69
+ .description('Log in (opens browser or stores token)')
70
+ .option('--token <token>', 'API token')
71
+ .option('--label <label>', 'Token label (browser flow only)', 'CLI token')
72
+ .option('--no-browser', 'Do not open browser (requires --token)')
73
+ .action(async (options) => {
74
+ const opts = resolveGlobalOpts();
75
+ await cmdLoginFlow(opts, options, isInputAllowed());
76
+ });
77
+ auth
78
+ .command('logout')
79
+ .description('Remove stored token')
80
+ .action(async () => {
81
+ const opts = resolveGlobalOpts();
82
+ await cmdLogout(opts);
83
+ });
84
+ auth
85
+ .command('whoami')
86
+ .description('Validate token')
87
+ .action(async () => {
88
+ const opts = resolveGlobalOpts();
89
+ await cmdWhoami(opts);
90
+ });
91
+ program
92
+ .command('search')
93
+ .description('Vector search skills')
94
+ .argument('<query...>', 'Query string')
95
+ .option('--limit <n>', 'Max results', (value) => Number.parseInt(value, 10))
96
+ .action(async (queryParts, options) => {
97
+ const opts = resolveGlobalOpts();
98
+ const query = queryParts.join(' ').trim();
99
+ await cmdSearch(opts, query, options.limit);
100
+ });
101
+ program
102
+ .command('install')
103
+ .description('Install into <dir>/<slug>')
104
+ .argument('<slug>', 'Skill slug')
105
+ .option('--version <version>', 'Version to install')
106
+ .option('--force', 'Overwrite existing folder')
107
+ .action(async (slug, options) => {
108
+ const opts = resolveGlobalOpts();
109
+ await cmdInstall(opts, slug, options.version, options.force);
110
+ });
111
+ program
112
+ .command('update')
113
+ .description('Update installed skills')
114
+ .argument('[slug]', 'Skill slug')
115
+ .option('--all', 'Update all installed skills')
116
+ .option('--version <version>', 'Update to specific version (single slug only)')
117
+ .option('--force', 'Overwrite when local files do not match any version')
118
+ .action(async (slug, options) => {
119
+ const opts = resolveGlobalOpts();
120
+ await cmdUpdate(opts, slug, options, isInputAllowed());
121
+ });
122
+ program
123
+ .command('list')
124
+ .description('List installed skills (from lockfile)')
125
+ .action(async () => {
126
+ const opts = resolveGlobalOpts();
127
+ await cmdList(opts);
128
+ });
129
+ program
130
+ .command('publish')
131
+ .description('Publish skill from folder')
132
+ .argument('<path>', 'Skill folder path')
133
+ .option('--slug <slug>', 'Skill slug')
134
+ .option('--name <name>', 'Display name')
135
+ .option('--version <version>', 'Version (semver)')
136
+ .option('--changelog <text>', 'Changelog text')
137
+ .option('--tags <tags>', 'Comma-separated tags', 'latest')
138
+ .action(async (folder, options) => {
139
+ const opts = resolveGlobalOpts();
140
+ await cmdPublish(opts, folder, options);
141
+ });
142
+ program
143
+ .command('sync')
144
+ .description('Scan local skills and publish new/updated ones')
145
+ .option('--root <dir...>', 'Extra scan roots (one or more)')
146
+ .option('--all', 'Upload all new/updated skills without prompting')
147
+ .option('--dry-run', 'Show what would be uploaded')
148
+ .option('--bump <type>', 'Version bump for updates (patch|minor|major)', 'patch')
149
+ .option('--changelog <text>', 'Changelog to use for updates (non-interactive)')
150
+ .option('--tags <tags>', 'Comma-separated tags', 'latest')
151
+ .action(async (options) => {
152
+ const opts = resolveGlobalOpts();
153
+ const bump = String(options.bump ?? 'patch');
154
+ if (!['patch', 'minor', 'major'].includes(bump))
155
+ fail('--bump must be patch|minor|major');
156
+ await cmdSync(opts, {
157
+ root: options.root,
158
+ all: options.all,
159
+ dryRun: options.dryRun,
160
+ bump,
161
+ changelog: options.changelog,
162
+ tags: options.tags,
163
+ }, isInputAllowed());
164
+ });
165
+ program.action(async () => {
166
+ const opts = resolveGlobalOpts();
167
+ const cfg = await readGlobalConfig();
168
+ if (cfg?.token) {
169
+ await cmdSync(opts, {}, isInputAllowed());
170
+ return;
171
+ }
172
+ program.outputHelp();
173
+ process.exitCode = 0;
174
+ });
175
+ void program.parseAsync(process.argv).catch((error) => {
176
+ const message = error instanceof Error ? error.message : String(error);
177
+ fail(message);
178
+ });
179
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type GlobalConfig } from 'clawdhub-schema';
2
+ export declare function getGlobalConfigPath(): string;
3
+ export declare function readGlobalConfig(): Promise<GlobalConfig | null>;
4
+ export declare function writeGlobalConfig(config: GlobalConfig): Promise<void>;
package/dist/config.js ADDED
@@ -0,0 +1,38 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { homedir } from 'node:os';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { GlobalConfigSchema, parseArk } from 'clawdhub-schema';
5
+ export function getGlobalConfigPath() {
6
+ const override = process.env.CLAWDHUB_CONFIG_PATH?.trim();
7
+ if (override)
8
+ return resolve(override);
9
+ const home = homedir();
10
+ if (process.platform === 'darwin') {
11
+ return join(home, 'Library', 'Application Support', 'clawdhub', 'config.json');
12
+ }
13
+ const xdg = process.env.XDG_CONFIG_HOME;
14
+ if (xdg)
15
+ return join(xdg, 'clawdhub', 'config.json');
16
+ if (process.platform === 'win32') {
17
+ const appData = process.env.APPDATA;
18
+ if (appData)
19
+ return join(appData, 'clawdhub', 'config.json');
20
+ }
21
+ return join(home, '.config', 'clawdhub', 'config.json');
22
+ }
23
+ export async function readGlobalConfig() {
24
+ try {
25
+ const raw = await readFile(getGlobalConfigPath(), 'utf8');
26
+ const parsed = JSON.parse(raw);
27
+ return parseArk(GlobalConfigSchema, parsed, 'Global config');
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ export async function writeGlobalConfig(config) {
34
+ const path = getGlobalConfigPath();
35
+ await mkdir(dirname(path), { recursive: true });
36
+ await writeFile(path, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
37
+ }
38
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAqB,kBAAkB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAEjF,MAAM,UAAU,mBAAmB;IACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,IAAI,EAAE,CAAA;IACzD,IAAI,QAAQ;QAAE,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAA;IACtC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAA;IACtB,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,UAAU,EAAE,aAAa,CAAC,CAAA;IAChF,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAA;IACvC,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,aAAa,CAAC,CAAA;IACpD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAA;QACnC,IAAI,OAAO;YAAE,OAAO,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,aAAa,CAAC,CAAA;IAC9D,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,CAAC,CAAA;AACzD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,mBAAmB,EAAE,EAAE,MAAM,CAAC,CAAA;QACzD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAA;QACzC,OAAO,QAAQ,CAAC,kBAAkB,EAAE,MAAM,EAAE,eAAe,CAAC,CAAA;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAoB;IAC1D,MAAM,IAAI,GAAG,mBAAmB,EAAE,CAAA;IAClC,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/C,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;AACvE,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function discoverRegistryFromSite(siteUrl: string): Promise<{
2
+ apiBase: string;
3
+ authBase: string | undefined;
4
+ minCliVersion: string | undefined;
5
+ } | null>;
@@ -0,0 +1,21 @@
1
+ import { parseArk, WellKnownConfigSchema } from 'clawdhub-schema';
2
+ export async function discoverRegistryFromSite(siteUrl) {
3
+ const url = new URL('/.well-known/clawdhub.json', siteUrl);
4
+ const response = await fetch(url.toString(), {
5
+ method: 'GET',
6
+ headers: { Accept: 'application/json' },
7
+ });
8
+ if (!response.ok)
9
+ return null;
10
+ const raw = (await response.json());
11
+ const parsed = parseArk(WellKnownConfigSchema, raw, 'WellKnown config');
12
+ const apiBase = 'apiBase' in parsed ? parsed.apiBase : parsed.registry;
13
+ if (!apiBase)
14
+ return null;
15
+ return {
16
+ apiBase,
17
+ authBase: parsed.authBase,
18
+ minCliVersion: parsed.minCliVersion,
19
+ };
20
+ }
21
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAEjE,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,OAAe;IAC5D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,4BAA4B,EAAE,OAAO,CAAC,CAAA;IAC1D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;QAC3C,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;KACxC,CAAC,CAAA;IACF,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,OAAO,IAAI,CAAA;IAC7B,MAAM,GAAG,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAY,CAAA;IAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE,kBAAkB,CAAC,CAAA;IACvE,MAAM,OAAO,GAAG,SAAS,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAA;IACtE,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAA;IACzB,OAAO;QACL,OAAO;QACP,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,aAAa,EAAE,MAAM,CAAC,aAAa;KACpC,CAAA;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ /* @vitest-environment node */
2
+ import { afterEach, describe, expect, it, vi } from 'vitest';
3
+ import { discoverRegistryFromSite } from './discovery';
4
+ describe('discovery', () => {
5
+ afterEach(() => {
6
+ vi.unstubAllGlobals();
7
+ });
8
+ it('returns null on non-ok response', async () => {
9
+ vi.stubGlobal('fetch', vi.fn(async () => new Response('nope', { status: 404 })));
10
+ await expect(discoverRegistryFromSite('https://example.com')).resolves.toBeNull();
11
+ });
12
+ it('parses registry config', async () => {
13
+ vi.stubGlobal('fetch', vi.fn(async () => new Response(JSON.stringify({ registry: 'https://example.convex.site' }), {
14
+ status: 200,
15
+ headers: { 'Content-Type': 'application/json' },
16
+ })));
17
+ await expect(discoverRegistryFromSite('https://example.com')).resolves.toEqual({
18
+ apiBase: 'https://example.convex.site',
19
+ authBase: undefined,
20
+ minCliVersion: undefined,
21
+ });
22
+ });
23
+ });
24
+ //# sourceMappingURL=discovery.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.test.js","sourceRoot":"","sources":["../src/discovery.test.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAE9B,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC5D,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAA;AAEtD,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,gBAAgB,EAAE,CAAA;IACvB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,EAAE,CAAC,UAAU,CACX,OAAO,EACP,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAA4B,CACpF,CAAA;QACD,MAAM,MAAM,CAAC,wBAAwB,CAAC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAA;IACnF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;QACtC,EAAE,CAAC,UAAU,CACX,OAAO,EACP,EAAE,CAAC,EAAE,CACH,KAAK,IAAI,EAAE,CACT,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,6BAA6B,EAAE,CAAC,EAAE;YACxE,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;SAChD,CAAC,CACsB,CAC7B,CAAA;QACD,MAAM,MAAM,CAAC,wBAAwB,CAAC,qBAAqB,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;YAC7E,OAAO,EAAE,6BAA6B;YACtC,QAAQ,EAAE,SAAS;YACnB,aAAa,EAAE,SAAS;SACzB,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import type { ArkValidator } from 'clawdhub-schema';
2
+ type RequestArgs = {
3
+ method: 'GET' | 'POST';
4
+ path: string;
5
+ token?: string;
6
+ body?: unknown;
7
+ } | {
8
+ method: 'GET' | 'POST';
9
+ url: string;
10
+ token?: string;
11
+ body?: unknown;
12
+ };
13
+ export declare function apiRequest<T>(registry: string, args: RequestArgs): Promise<T>;
14
+ export declare function apiRequest<T>(registry: string, args: RequestArgs, schema: ArkValidator<T>): Promise<T>;
15
+ export declare function downloadZip(registry: string, args: {
16
+ slug: string;
17
+ version?: string;
18
+ }): Promise<Uint8Array<ArrayBuffer>>;
19
+ export {};
package/dist/http.js ADDED
@@ -0,0 +1,46 @@
1
+ import { ApiRoutes, parseArk } from 'clawdhub-schema';
2
+ import pRetry, { AbortError } from 'p-retry';
3
+ export async function apiRequest(registry, args, schema) {
4
+ const url = 'url' in args ? args.url : new URL(args.path, registry).toString();
5
+ const json = await pRetry(async () => {
6
+ const headers = { Accept: 'application/json' };
7
+ if (args.token)
8
+ headers.Authorization = `Bearer ${args.token}`;
9
+ let body;
10
+ if (args.method === 'POST') {
11
+ headers['Content-Type'] = 'application/json';
12
+ body = JSON.stringify(args.body ?? {});
13
+ }
14
+ const response = await fetch(url, { method: args.method, headers, body });
15
+ if (!response.ok) {
16
+ const text = await response.text().catch(() => '');
17
+ const message = text || `HTTP ${response.status}`;
18
+ if (response.status === 429 || response.status >= 500) {
19
+ throw new Error(message);
20
+ }
21
+ throw new AbortError(message);
22
+ }
23
+ return (await response.json());
24
+ }, { retries: 2 });
25
+ if (schema)
26
+ return parseArk(schema, json, 'API response');
27
+ return json;
28
+ }
29
+ export async function downloadZip(registry, args) {
30
+ const url = new URL(ApiRoutes.download, registry);
31
+ url.searchParams.set('slug', args.slug);
32
+ if (args.version)
33
+ url.searchParams.set('version', args.version);
34
+ return pRetry(async () => {
35
+ const response = await fetch(url.toString(), { method: 'GET' });
36
+ if (!response.ok) {
37
+ const message = (await response.text().catch(() => '')) || `HTTP ${response.status}`;
38
+ if (response.status === 429 || response.status >= 500) {
39
+ throw new Error(message);
40
+ }
41
+ throw new AbortError(message);
42
+ }
43
+ return new Uint8Array(await response.arrayBuffer());
44
+ }, { retries: 2 });
45
+ }
46
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,70 @@
1
+ /* @vitest-environment node */
2
+ import { ApiCliWhoamiResponseSchema } from 'clawdhub-schema';
3
+ import { describe, expect, it, vi } from 'vitest';
4
+ import { apiRequest, downloadZip } from './http';
5
+ describe('apiRequest', () => {
6
+ it('adds bearer token and parses json', async () => {
7
+ const fetchMock = vi.fn().mockResolvedValue({
8
+ ok: true,
9
+ json: async () => ({ user: { handle: null } }),
10
+ });
11
+ vi.stubGlobal('fetch', fetchMock);
12
+ const result = await apiRequest('https://example.com', { method: 'GET', path: '/x', token: 'clh_token' }, ApiCliWhoamiResponseSchema);
13
+ expect(result.user.handle).toBeNull();
14
+ expect(fetchMock).toHaveBeenCalledTimes(1);
15
+ const [, init] = fetchMock.mock.calls[0];
16
+ expect(init.headers.Authorization).toBe('Bearer clh_token');
17
+ vi.unstubAllGlobals();
18
+ });
19
+ it('posts json body', async () => {
20
+ const fetchMock = vi.fn().mockResolvedValue({
21
+ ok: true,
22
+ json: async () => ({ ok: true }),
23
+ });
24
+ vi.stubGlobal('fetch', fetchMock);
25
+ await apiRequest('https://example.com', {
26
+ method: 'POST',
27
+ path: '/x',
28
+ body: { a: 1 },
29
+ });
30
+ const [url, init] = fetchMock.mock.calls[0];
31
+ expect(url).toBe('https://example.com/x');
32
+ expect(init.body).toBe(JSON.stringify({ a: 1 }));
33
+ expect(init.headers['Content-Type']).toBe('application/json');
34
+ vi.unstubAllGlobals();
35
+ });
36
+ it('throws text body on non-200', async () => {
37
+ const fetchMock = vi.fn().mockResolvedValue({
38
+ ok: false,
39
+ status: 400,
40
+ text: async () => 'bad',
41
+ });
42
+ vi.stubGlobal('fetch', fetchMock);
43
+ await expect(apiRequest('https://example.com', { method: 'GET', path: '/x' })).rejects.toThrow('bad');
44
+ vi.unstubAllGlobals();
45
+ });
46
+ it('falls back to HTTP status when body is empty', async () => {
47
+ const fetchMock = vi.fn().mockResolvedValue({
48
+ ok: false,
49
+ status: 500,
50
+ text: async () => '',
51
+ });
52
+ vi.stubGlobal('fetch', fetchMock);
53
+ await expect(apiRequest('https://example.com', { method: 'GET', url: 'https://example.com/x' })).rejects.toThrow('HTTP 500');
54
+ vi.unstubAllGlobals();
55
+ });
56
+ it('downloads zip bytes', async () => {
57
+ const fetchMock = vi.fn().mockResolvedValue({
58
+ ok: true,
59
+ arrayBuffer: async () => new Uint8Array([1, 2, 3]).buffer,
60
+ });
61
+ vi.stubGlobal('fetch', fetchMock);
62
+ const bytes = await downloadZip('https://example.com', { slug: 'demo', version: '1.0.0' });
63
+ expect(Array.from(bytes)).toEqual([1, 2, 3]);
64
+ const [url] = fetchMock.mock.calls[0];
65
+ expect(url).toContain('slug=demo');
66
+ expect(url).toContain('version=1.0.0');
67
+ vi.unstubAllGlobals();
68
+ });
69
+ });
70
+ //# sourceMappingURL=http.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.test.js","sourceRoot":"","sources":["../src/http.test.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAE9B,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAA;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AAEhD,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;YAC1C,EAAE,EAAE,IAAI;YACR,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;SAC/C,CAAC,CAAA;QACF,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QACjC,MAAM,MAAM,GAAG,MAAM,UAAU,CAC7B,qBAAqB,EACrB,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,EACjD,0BAA0B,CAC3B,CAAA;QACD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAA;QACrC,MAAM,CAAC,SAAS,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAA;QAC1C,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAA0B,CAAA;QACjE,MAAM,CAAE,IAAI,CAAC,OAAkC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;QACvF,EAAE,CAAC,gBAAgB,EAAE,CAAA;IACvB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iBAAiB,EAAE,KAAK,IAAI,EAAE;QAC/B,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;YAC1C,EAAE,EAAE,IAAI;YACR,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;SACjC,CAAC,CAAA;QACF,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QACjC,MAAM,UAAU,CAAC,qBAAqB,EAAE;YACtC,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI;YACV,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE;SACf,CAAC,CAAA;QACF,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAA0B,CAAA;QACpE,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAA;QACzC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QAChD,MAAM,CAAE,IAAI,CAAC,OAAkC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;QACzF,EAAE,CAAC,gBAAgB,EAAE,CAAA;IACvB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;YAC1C,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,KAAK;SACxB,CAAC,CAAA;QACF,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QACjC,MAAM,MAAM,CAAC,UAAU,CAAC,qBAAqB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC5F,KAAK,CACN,CAAA;QACD,EAAE,CAAC,gBAAgB,EAAE,CAAA;IACvB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;YAC1C,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,EAAE;SACrB,CAAC,CAAA;QACF,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QACjC,MAAM,MAAM,CACV,UAAU,CAAC,qBAAqB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,uBAAuB,EAAE,CAAC,CACnF,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;QAC7B,EAAE,CAAC,gBAAgB,EAAE,CAAA;IACvB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;YAC1C,EAAE,EAAE,IAAI;YACR,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM;SAC1D,CAAC,CAAA;QACF,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAA;QACjC,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,qBAAqB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;QAC1F,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAC5C,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAa,CAAA;QACjD,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;QAClC,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAA;QACtC,EAAE,CAAC,gBAAgB,EAAE,CAAA;IACvB,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,34 @@
1
+ import { type Lockfile } from 'clawdhub-schema';
2
+ export declare function extractZipToDir(zipBytes: Uint8Array, targetDir: string): Promise<void>;
3
+ export declare function listTextFiles(root: string): Promise<{
4
+ relPath: string;
5
+ bytes: Uint8Array;
6
+ contentType?: string;
7
+ }[]>;
8
+ export type SkillFileHash = {
9
+ path: string;
10
+ sha256: string;
11
+ size: number;
12
+ };
13
+ export declare function sha256Hex(bytes: Uint8Array): string;
14
+ export declare function buildSkillFingerprint(files: Array<{
15
+ path: string;
16
+ sha256: string;
17
+ }>): string;
18
+ export declare function hashSkillFiles(files: Array<{
19
+ relPath: string;
20
+ bytes: Uint8Array;
21
+ }>): {
22
+ files: {
23
+ path: string;
24
+ sha256: string;
25
+ size: number;
26
+ }[];
27
+ fingerprint: string;
28
+ };
29
+ export declare function hashSkillZip(zipBytes: Uint8Array): {
30
+ files: SkillFileHash[];
31
+ fingerprint: string;
32
+ };
33
+ export declare function readLockfile(workdir: string): Promise<Lockfile>;
34
+ export declare function writeLockfile(workdir: string, lock: Lockfile): Promise<void>;
package/dist/skills.js ADDED
@@ -0,0 +1,135 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
3
+ import { dirname, join, relative, resolve, sep } from 'node:path';
4
+ import { LockfileSchema, parseArk, TEXT_FILE_EXTENSION_SET } from 'clawdhub-schema';
5
+ import { unzipSync } from 'fflate';
6
+ import ignore from 'ignore';
7
+ import mime from 'mime';
8
+ export async function extractZipToDir(zipBytes, targetDir) {
9
+ const entries = unzipSync(zipBytes);
10
+ await mkdir(targetDir, { recursive: true });
11
+ for (const [rawPath, data] of Object.entries(entries)) {
12
+ const safePath = sanitizeRelPath(rawPath);
13
+ if (!safePath)
14
+ continue;
15
+ const outPath = join(targetDir, safePath);
16
+ await mkdir(dirname(outPath), { recursive: true });
17
+ await writeFile(outPath, data);
18
+ }
19
+ }
20
+ export async function listTextFiles(root) {
21
+ const files = [];
22
+ const absRoot = resolve(root);
23
+ const ig = ignore();
24
+ ig.add(['.git/', 'node_modules/', '.clawdhub/']);
25
+ await addIgnoreFile(ig, join(absRoot, '.gitignore'));
26
+ await addIgnoreFile(ig, join(absRoot, '.clawdhubignore'));
27
+ await walk(absRoot, async (absPath) => {
28
+ const relPath = normalizePath(relative(absRoot, absPath));
29
+ if (!relPath)
30
+ return;
31
+ if (ig.ignores(relPath))
32
+ return;
33
+ const ext = relPath.split('.').at(-1)?.toLowerCase() ?? '';
34
+ if (!ext || !TEXT_FILE_EXTENSION_SET.has(ext))
35
+ return;
36
+ const buffer = await readFile(absPath);
37
+ const contentType = mime.getType(relPath) ?? 'text/plain';
38
+ files.push({ relPath, bytes: new Uint8Array(buffer), contentType });
39
+ });
40
+ return files;
41
+ }
42
+ export function sha256Hex(bytes) {
43
+ return createHash('sha256').update(bytes).digest('hex');
44
+ }
45
+ export function buildSkillFingerprint(files) {
46
+ const normalized = files
47
+ .filter((file) => Boolean(file.path) && Boolean(file.sha256))
48
+ .map((file) => ({ path: file.path, sha256: file.sha256 }))
49
+ .sort((a, b) => a.path.localeCompare(b.path));
50
+ const payload = normalized.map((file) => `${file.path}:${file.sha256}`).join('\n');
51
+ return createHash('sha256').update(payload).digest('hex');
52
+ }
53
+ export function hashSkillFiles(files) {
54
+ const hashed = files.map((file) => ({
55
+ path: file.relPath,
56
+ sha256: sha256Hex(file.bytes),
57
+ size: file.bytes.byteLength,
58
+ }));
59
+ return { files: hashed, fingerprint: buildSkillFingerprint(hashed) };
60
+ }
61
+ export function hashSkillZip(zipBytes) {
62
+ const entries = unzipSync(zipBytes);
63
+ const hashed = Object.entries(entries)
64
+ .map(([rawPath, bytes]) => {
65
+ const safePath = sanitizeZipPath(rawPath);
66
+ if (!safePath)
67
+ return null;
68
+ const ext = safePath.split('.').at(-1)?.toLowerCase() ?? '';
69
+ if (!ext || !TEXT_FILE_EXTENSION_SET.has(ext))
70
+ return null;
71
+ return { path: safePath, sha256: sha256Hex(bytes), size: bytes.byteLength };
72
+ })
73
+ .filter(Boolean);
74
+ return { files: hashed, fingerprint: buildSkillFingerprint(hashed) };
75
+ }
76
+ export async function readLockfile(workdir) {
77
+ const path = join(workdir, '.clawdhub', 'lock.json');
78
+ try {
79
+ const raw = await readFile(path, 'utf8');
80
+ const parsed = JSON.parse(raw);
81
+ return parseArk(LockfileSchema, parsed, 'Lockfile');
82
+ }
83
+ catch {
84
+ return { version: 1, skills: {} };
85
+ }
86
+ }
87
+ export async function writeLockfile(workdir, lock) {
88
+ const path = join(workdir, '.clawdhub', 'lock.json');
89
+ await mkdir(dirname(path), { recursive: true });
90
+ await writeFile(path, `${JSON.stringify(lock, null, 2)}\n`, 'utf8');
91
+ }
92
+ function normalizePath(path) {
93
+ return path
94
+ .split(sep)
95
+ .join('/')
96
+ .replace(/^\.\/+/, '');
97
+ }
98
+ function sanitizeRelPath(path) {
99
+ const normalized = path.replace(/^\.\/+/, '').replace(/^\/+/, '');
100
+ if (!normalized || normalized.endsWith('/'))
101
+ return null;
102
+ if (normalized.includes('..') || normalized.includes('\\'))
103
+ return null;
104
+ return normalized;
105
+ }
106
+ function sanitizeZipPath(path) {
107
+ return sanitizeRelPath(path);
108
+ }
109
+ async function walk(dir, onFile) {
110
+ const entries = await readdir(dir, { withFileTypes: true });
111
+ for (const entry of entries) {
112
+ if (entry.name.startsWith('.'))
113
+ continue;
114
+ if (entry.name === 'node_modules')
115
+ continue;
116
+ const full = join(dir, entry.name);
117
+ if (entry.isDirectory()) {
118
+ await walk(full, onFile);
119
+ continue;
120
+ }
121
+ if (!entry.isFile())
122
+ continue;
123
+ await onFile(full);
124
+ }
125
+ }
126
+ async function addIgnoreFile(ig, path) {
127
+ try {
128
+ const raw = await readFile(path, 'utf8');
129
+ ig.add(raw.split(/\r?\n/));
130
+ }
131
+ catch {
132
+ // optional
133
+ }
134
+ }
135
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"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"}