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.
- package/LICENSE +22 -0
- package/README.md +57 -0
- package/bin/clawdhub.js +2 -0
- package/dist/browserAuth.d.ts +20 -0
- package/dist/browserAuth.js +156 -0
- package/dist/browserAuth.js.map +1 -0
- package/dist/browserAuth.test.d.ts +1 -0
- package/dist/browserAuth.test.js +39 -0
- package/dist/browserAuth.test.js.map +1 -0
- package/dist/cli/buildInfo.d.ts +3 -0
- package/dist/cli/buildInfo.js +103 -0
- package/dist/cli/buildInfo.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +9 -0
- package/dist/cli/commands/auth.js +75 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/publish.d.ts +8 -0
- package/dist/cli/commands/publish.js +91 -0
- package/dist/cli/commands/publish.js.map +1 -0
- package/dist/cli/commands/publish.test.d.ts +1 -0
- package/dist/cli/commands/publish.test.js +120 -0
- package/dist/cli/commands/publish.test.js.map +1 -0
- package/dist/cli/commands/skills.d.ts +9 -0
- package/dist/cli/commands/skills.js +195 -0
- package/dist/cli/commands/skills.js.map +1 -0
- package/dist/cli/commands/sync.d.ts +11 -0
- package/dist/cli/commands/sync.js +273 -0
- package/dist/cli/commands/sync.js.map +1 -0
- package/dist/cli/commands/sync.test.d.ts +1 -0
- package/dist/cli/commands/sync.test.js +106 -0
- package/dist/cli/commands/sync.test.js.map +1 -0
- package/dist/cli/helpStyle.d.ts +13 -0
- package/dist/cli/helpStyle.js +38 -0
- package/dist/cli/helpStyle.js.map +1 -0
- package/dist/cli/registry.d.ts +7 -0
- package/dist/cli/registry.js +27 -0
- package/dist/cli/registry.js.map +1 -0
- package/dist/cli/scanSkills.d.ts +7 -0
- package/dist/cli/scanSkills.js +75 -0
- package/dist/cli/scanSkills.js.map +1 -0
- package/dist/cli/scanSkills.test.d.ts +1 -0
- package/dist/cli/scanSkills.test.js +47 -0
- package/dist/cli/scanSkills.test.js.map +1 -0
- package/dist/cli/slug.d.ts +2 -0
- package/dist/cli/slug.js +16 -0
- package/dist/cli/slug.js.map +1 -0
- package/dist/cli/types.d.ts +14 -0
- package/dist/cli/types.js +2 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/ui.d.ts +7 -0
- package/dist/cli/ui.js +72 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +179 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.js +38 -0
- package/dist/config.js.map +1 -0
- package/dist/discovery.d.ts +5 -0
- package/dist/discovery.js +21 -0
- package/dist/discovery.js.map +1 -0
- package/dist/discovery.test.d.ts +1 -0
- package/dist/discovery.test.js +24 -0
- package/dist/discovery.test.js.map +1 -0
- package/dist/http.d.ts +19 -0
- package/dist/http.js +46 -0
- package/dist/http.js.map +1 -0
- package/dist/http.test.d.ts +1 -0
- package/dist/http.test.js +70 -0
- package/dist/http.test.js.map +1 -0
- package/dist/skills.d.ts +34 -0
- package/dist/skills.js +135 -0
- package/dist/skills.js.map +1 -0
- package/dist/skills.test.d.ts +1 -0
- package/dist/skills.test.js +83 -0
- package/dist/skills.test.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/* @vitest-environment node */
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
const mockIntro = vi.fn();
|
|
4
|
+
const mockOutro = vi.fn();
|
|
5
|
+
const mockNote = vi.fn();
|
|
6
|
+
vi.mock('@clack/prompts', () => ({
|
|
7
|
+
intro: (value) => mockIntro(value),
|
|
8
|
+
outro: (value) => mockOutro(value),
|
|
9
|
+
note: (message, body) => mockNote(message, body),
|
|
10
|
+
multiselect: vi.fn(async () => []),
|
|
11
|
+
text: vi.fn(async () => ''),
|
|
12
|
+
isCancel: () => false,
|
|
13
|
+
}));
|
|
14
|
+
vi.mock('../../config.js', () => ({
|
|
15
|
+
readGlobalConfig: vi.fn(async () => ({ registry: 'https://clawdhub.com', token: 'tkn' })),
|
|
16
|
+
}));
|
|
17
|
+
const mockGetRegistry = vi.fn(async () => 'https://clawdhub.com');
|
|
18
|
+
vi.mock('../registry.js', () => ({
|
|
19
|
+
getRegistry: () => mockGetRegistry(),
|
|
20
|
+
}));
|
|
21
|
+
const mockApiRequest = vi.fn();
|
|
22
|
+
vi.mock('../../http.js', () => ({
|
|
23
|
+
apiRequest: (registry, args, schema) => mockApiRequest(registry, args, schema),
|
|
24
|
+
}));
|
|
25
|
+
const mockFail = vi.fn((message) => {
|
|
26
|
+
throw new Error(message);
|
|
27
|
+
});
|
|
28
|
+
const mockSpinner = { succeed: vi.fn(), fail: vi.fn(), stop: vi.fn() };
|
|
29
|
+
vi.mock('../ui.js', () => ({
|
|
30
|
+
createSpinner: vi.fn(() => mockSpinner),
|
|
31
|
+
fail: (message) => mockFail(message),
|
|
32
|
+
formatError: (error) => (error instanceof Error ? error.message : String(error)),
|
|
33
|
+
isInteractive: () => false,
|
|
34
|
+
}));
|
|
35
|
+
vi.mock('../scanSkills.js', () => ({
|
|
36
|
+
findSkillFolders: vi.fn(async (root) => {
|
|
37
|
+
if (!root.endsWith('/scan'))
|
|
38
|
+
return [];
|
|
39
|
+
return [
|
|
40
|
+
{ folder: '/scan/new-skill', slug: 'new-skill', displayName: 'New Skill' },
|
|
41
|
+
{ folder: '/scan/synced-skill', slug: 'synced-skill', displayName: 'Synced Skill' },
|
|
42
|
+
{ folder: '/scan/update-skill', slug: 'update-skill', displayName: 'Update Skill' },
|
|
43
|
+
];
|
|
44
|
+
}),
|
|
45
|
+
getFallbackSkillRoots: vi.fn(() => []),
|
|
46
|
+
}));
|
|
47
|
+
vi.mock('../../skills.js', async () => {
|
|
48
|
+
const actual = await vi.importActual('../../skills.js');
|
|
49
|
+
return {
|
|
50
|
+
...actual,
|
|
51
|
+
listTextFiles: vi.fn(async (folder) => [
|
|
52
|
+
{ relPath: 'SKILL.md', bytes: new TextEncoder().encode(folder) },
|
|
53
|
+
]),
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
const mockCmdPublish = vi.fn();
|
|
57
|
+
vi.mock('./publish.js', () => ({
|
|
58
|
+
cmdPublish: (...args) => mockCmdPublish(...args),
|
|
59
|
+
}));
|
|
60
|
+
const { cmdSync } = await import('./sync');
|
|
61
|
+
function makeOpts() {
|
|
62
|
+
return {
|
|
63
|
+
workdir: '/work',
|
|
64
|
+
dir: '/work/skills',
|
|
65
|
+
site: 'https://clawdhub.com',
|
|
66
|
+
registry: 'https://clawdhub.com',
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
afterEach(() => {
|
|
70
|
+
vi.clearAllMocks();
|
|
71
|
+
});
|
|
72
|
+
describe('cmdSync', () => {
|
|
73
|
+
it('classifies skills as new/update/synced (dry-run, mocked HTTP)', async () => {
|
|
74
|
+
mockApiRequest.mockImplementation(async (_registry, args) => {
|
|
75
|
+
if (args.path === '/api/cli/whoami')
|
|
76
|
+
return { user: { handle: 'steipete' } };
|
|
77
|
+
if (args.path.startsWith('/api/skill?slug=')) {
|
|
78
|
+
const slug = new URL(`https://x.test${args.path}`).searchParams.get('slug');
|
|
79
|
+
if (slug === 'new-skill')
|
|
80
|
+
return { latestVersion: undefined, skill: null };
|
|
81
|
+
if (slug === 'synced-skill')
|
|
82
|
+
return { latestVersion: { version: '1.2.3' }, skill: {} };
|
|
83
|
+
if (slug === 'update-skill')
|
|
84
|
+
return { latestVersion: { version: '1.0.0' }, skill: {} };
|
|
85
|
+
}
|
|
86
|
+
if (args.path.startsWith('/api/skill/resolve?')) {
|
|
87
|
+
const u = new URL(`https://x.test${args.path}`);
|
|
88
|
+
const slug = u.searchParams.get('slug');
|
|
89
|
+
if (slug === 'synced-skill') {
|
|
90
|
+
return { match: { version: '1.2.3' }, latestVersion: { version: '1.2.3' } };
|
|
91
|
+
}
|
|
92
|
+
if (slug === 'update-skill') {
|
|
93
|
+
return { match: null, latestVersion: { version: '1.0.0' } };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
throw new Error(`Unexpected apiRequest: ${args.path}`);
|
|
97
|
+
});
|
|
98
|
+
await cmdSync(makeOpts(), { root: ['/scan'], all: true, dryRun: true }, true);
|
|
99
|
+
expect(mockCmdPublish).not.toHaveBeenCalled();
|
|
100
|
+
const alreadySyncedNote = mockNote.mock.calls.find((call) => call[0] === 'Already synced');
|
|
101
|
+
expect(alreadySyncedNote?.[1]).toMatch(/synced-skill/);
|
|
102
|
+
const dryRunOutro = mockOutro.mock.calls.at(-1)?.[0];
|
|
103
|
+
expect(String(dryRunOutro)).toMatch(/Dry run: would upload 2 skill/);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
//# sourceMappingURL=sync.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.test.js","sourceRoot":"","sources":["../../../src/cli/commands/sync.test.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAE9B,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAG5D,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;AACzB,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;AACzB,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;AAExB,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/B,KAAK,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC;IAC1C,KAAK,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC;IAC1C,IAAI,EAAE,CAAC,OAAe,EAAE,IAAa,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACjE,WAAW,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;IAClC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;IAC3B,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK;CACtB,CAAC,CAAC,CAAA;AAEH,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,CAAC;IAChC,gBAAgB,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,sBAAsB,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;CAC1F,CAAC,CAAC,CAAA;AAEH,MAAM,eAAe,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,sBAAsB,CAAC,CAAA;AACjE,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/B,WAAW,EAAE,GAAG,EAAE,CAAC,eAAe,EAAE;CACrC,CAAC,CAAC,CAAA;AAEH,MAAM,cAAc,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;AAC9B,EAAE,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC;IAC9B,UAAU,EAAE,CAAC,QAAiB,EAAE,IAAa,EAAE,MAAgB,EAAE,EAAE,CACjE,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC;CACzC,CAAC,CAAC,CAAA;AAEH,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,OAAe,EAAE,EAAE;IACzC,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAA;AAC1B,CAAC,CAAC,CAAA;AACF,MAAM,WAAW,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAA;AACtE,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC;IACzB,aAAa,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC;IACvC,IAAI,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;IAC5C,WAAW,EAAE,CAAC,KAAc,EAAE,EAAE,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACzF,aAAa,EAAE,GAAG,EAAE,CAAC,KAAK;CAC3B,CAAC,CAAC,CAAA;AAEH,EAAE,CAAC,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC;IACjC,gBAAgB,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QAC7C,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,OAAO,EAAE,CAAA;QACtC,OAAO;YACL,EAAE,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE;YAC1E,EAAE,MAAM,EAAE,oBAAoB,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE;YACnF,EAAE,MAAM,EAAE,oBAAoB,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE;SACpF,CAAA;IACH,CAAC,CAAC;IACF,qBAAqB,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;CACvC,CAAC,CAAC,CAAA;AAEH,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,IAAI,EAAE;IACpC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,YAAY,CAAmC,iBAAiB,CAAC,CAAA;IACzF,OAAO;QACL,GAAG,MAAM;QACT,aAAa,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,MAAc,EAAE,EAAE,CAAC;YAC7C,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;SACjE,CAAC;KACH,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,MAAM,cAAc,GAAG,EAAE,CAAC,EAAE,EAAE,CAAA;AAC9B,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;IAC7B,UAAU,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC;CAC5D,CAAC,CAAC,CAAA;AAEH,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;AAE1C,SAAS,QAAQ;IACf,OAAO;QACL,OAAO,EAAE,OAAO;QAChB,GAAG,EAAE,cAAc;QACnB,IAAI,EAAE,sBAAsB;QAC5B,QAAQ,EAAE,sBAAsB;KACjC,CAAA;AACH,CAAC;AAED,SAAS,CAAC,GAAG,EAAE;IACb,EAAE,CAAC,aAAa,EAAE,CAAA;AACpB,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;IACvB,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,cAAc,CAAC,kBAAkB,CAAC,KAAK,EAAE,SAAiB,EAAE,IAAsB,EAAE,EAAE;YACpF,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB;gBAAE,OAAO,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAA;YAC5E,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBAC7C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,iBAAiB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;gBAC3E,IAAI,IAAI,KAAK,WAAW;oBAAE,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;gBAC1E,IAAI,IAAI,KAAK,cAAc;oBAAE,OAAO,EAAE,aAAa,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;gBACtF,IAAI,IAAI,KAAK,cAAc;oBAAE,OAAO,EAAE,aAAa,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;YACxF,CAAC;YACD,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,qBAAqB,CAAC,EAAE,CAAC;gBAChD,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,iBAAiB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;gBAC/C,MAAM,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;gBACvC,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;oBAC5B,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAA;gBAC7E,CAAC;gBACD,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;oBAC5B,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAA;gBAC7D,CAAC;YACH,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;QACxD,CAAC,CAAC,CAAA;QAEF,MAAM,OAAO,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAA;QAE7E,MAAM,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAA;QAE7C,MAAM,iBAAiB,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,gBAAgB,CAAC,CAAA;QAC1F,MAAM,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;QAEtD,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QACpD,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,+BAA+B,CAAC,CAAA;IACtE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare function styleTitle(value: string): string;
|
|
2
|
+
export declare function configureCommanderHelp(program: {
|
|
3
|
+
configureHelp: (config: {
|
|
4
|
+
sectionTitle?: (title: string) => string;
|
|
5
|
+
optionTerm?: (option: {
|
|
6
|
+
flags: string;
|
|
7
|
+
}) => string;
|
|
8
|
+
commandTerm?: (cmd: {
|
|
9
|
+
name: () => string;
|
|
10
|
+
}) => string;
|
|
11
|
+
}) => unknown;
|
|
12
|
+
}): void;
|
|
13
|
+
export declare function styleEnvBlock(value: string): string;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
function wrap(start, end = '\x1b[0m') {
|
|
2
|
+
return (value) => `${start}${value}${end}`;
|
|
3
|
+
}
|
|
4
|
+
const ansi = {
|
|
5
|
+
reset: '\x1b[0m',
|
|
6
|
+
bold: wrap('\x1b[1m'),
|
|
7
|
+
dim: wrap('\x1b[2m'),
|
|
8
|
+
cyan: wrap('\x1b[36m'),
|
|
9
|
+
green: wrap('\x1b[32m'),
|
|
10
|
+
yellow: wrap('\x1b[33m'),
|
|
11
|
+
};
|
|
12
|
+
function isColorEnabled() {
|
|
13
|
+
if (!process.stdout.isTTY)
|
|
14
|
+
return false;
|
|
15
|
+
if (process.env.NO_COLOR)
|
|
16
|
+
return false;
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
export function styleTitle(value) {
|
|
20
|
+
if (!isColorEnabled())
|
|
21
|
+
return value;
|
|
22
|
+
return `${ansi.bold(ansi.cyan(value))}${ansi.reset}`;
|
|
23
|
+
}
|
|
24
|
+
export function configureCommanderHelp(program) {
|
|
25
|
+
if (!isColorEnabled())
|
|
26
|
+
return;
|
|
27
|
+
program.configureHelp({
|
|
28
|
+
sectionTitle: (title) => ansi.bold(ansi.cyan(title)),
|
|
29
|
+
optionTerm: (option) => ansi.yellow(option.flags),
|
|
30
|
+
commandTerm: (cmd) => ansi.green(cmd.name()),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export function styleEnvBlock(value) {
|
|
34
|
+
if (!isColorEnabled())
|
|
35
|
+
return value;
|
|
36
|
+
return `${ansi.dim(value)}${ansi.reset}`;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=helpStyle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpStyle.js","sourceRoot":"","sources":["../../src/cli/helpStyle.ts"],"names":[],"mappings":"AAEA,SAAS,IAAI,CAAC,KAAa,EAAE,GAAG,GAAG,SAAS;IAC1C,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG,KAAK,GAAG,GAAG,EAAE,CAAA;AAC5C,CAAC;AAED,MAAM,IAAI,GAAG;IACX,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;IACrB,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC;IACpB,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC;IACtB,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC;IACvB,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC;CACzB,CAAA;AAED,SAAS,cAAc;IACrB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO,KAAK,CAAA;IACvC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAA;IACtC,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAI,CAAC,cAAc,EAAE;QAAE,OAAO,KAAK,CAAA;IACnC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAA;AACtD,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,OAMtC;IACC,IAAI,CAAC,cAAc,EAAE;QAAE,OAAM;IAC7B,OAAO,CAAC,aAAa,CAAC;QACpB,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpD,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;QACjD,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;KAC7C,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,IAAI,CAAC,cAAc,EAAE;QAAE,OAAO,KAAK,CAAA;IACnC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAA;AAC1C,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { GlobalOpts } from './types.js';
|
|
2
|
+
export declare const DEFAULT_SITE = "https://clawdhub.com";
|
|
3
|
+
export declare const DEFAULT_REGISTRY = "https://clawdhub.com";
|
|
4
|
+
export declare function resolveRegistry(opts: GlobalOpts): Promise<string>;
|
|
5
|
+
export declare function getRegistry(opts: GlobalOpts, params?: {
|
|
6
|
+
cache?: boolean;
|
|
7
|
+
}): Promise<string>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { readGlobalConfig, writeGlobalConfig } from '../config.js';
|
|
2
|
+
import { discoverRegistryFromSite } from '../discovery.js';
|
|
3
|
+
export const DEFAULT_SITE = 'https://clawdhub.com';
|
|
4
|
+
export const DEFAULT_REGISTRY = 'https://clawdhub.com';
|
|
5
|
+
export async function resolveRegistry(opts) {
|
|
6
|
+
const cfg = await readGlobalConfig();
|
|
7
|
+
if (cfg?.registry && cfg.registry !== DEFAULT_REGISTRY)
|
|
8
|
+
return cfg.registry;
|
|
9
|
+
const explicit = opts.registry.trim();
|
|
10
|
+
if (explicit && explicit !== DEFAULT_REGISTRY)
|
|
11
|
+
return explicit;
|
|
12
|
+
const discovery = await discoverRegistryFromSite(opts.site).catch(() => null);
|
|
13
|
+
const discovered = discovery?.apiBase?.trim();
|
|
14
|
+
return discovered || explicit || DEFAULT_REGISTRY;
|
|
15
|
+
}
|
|
16
|
+
export async function getRegistry(opts, params) {
|
|
17
|
+
const cache = params?.cache !== false;
|
|
18
|
+
const registry = await resolveRegistry(opts);
|
|
19
|
+
if (!cache)
|
|
20
|
+
return registry;
|
|
21
|
+
const cfg = await readGlobalConfig();
|
|
22
|
+
if (!cfg || !cfg.registry || cfg.registry === DEFAULT_REGISTRY) {
|
|
23
|
+
await writeGlobalConfig({ registry, token: cfg?.token });
|
|
24
|
+
}
|
|
25
|
+
return registry;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/cli/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAA;AAG1D,MAAM,CAAC,MAAM,YAAY,GAAG,sBAAsB,CAAA;AAClD,MAAM,CAAC,MAAM,gBAAgB,GAAG,sBAAsB,CAAA;AAEtD,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAgB;IACpD,MAAM,GAAG,GAAG,MAAM,gBAAgB,EAAE,CAAA;IACpC,IAAI,GAAG,EAAE,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,gBAAgB;QAAE,OAAO,GAAG,CAAC,QAAQ,CAAA;IAE3E,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAA;IACrC,IAAI,QAAQ,IAAI,QAAQ,KAAK,gBAAgB;QAAE,OAAO,QAAQ,CAAA;IAE9D,MAAM,SAAS,GAAG,MAAM,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;IAC7E,MAAM,UAAU,GAAG,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IAC7C,OAAO,UAAU,IAAI,QAAQ,IAAI,gBAAgB,CAAA;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAgB,EAAE,MAA4B;IAC9E,MAAM,KAAK,GAAG,MAAM,EAAE,KAAK,KAAK,KAAK,CAAA;IACrC,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAA;IAC5C,IAAI,CAAC,KAAK;QAAE,OAAO,QAAQ,CAAA;IAC3B,MAAM,GAAG,GAAG,MAAM,gBAAgB,EAAE,CAAA;IACpC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,gBAAgB,EAAE,CAAC;QAC/D,MAAM,iBAAiB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAA;IAC1D,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { readdir, stat } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { basename, join, resolve } from 'node:path';
|
|
4
|
+
import { sanitizeSlug, titleCase } from './slug.js';
|
|
5
|
+
export async function findSkillFolders(root) {
|
|
6
|
+
const absRoot = resolve(root);
|
|
7
|
+
const rootStat = await stat(absRoot).catch(() => null);
|
|
8
|
+
if (!rootStat || !rootStat.isDirectory())
|
|
9
|
+
return [];
|
|
10
|
+
const direct = await isSkillFolder(absRoot);
|
|
11
|
+
if (direct)
|
|
12
|
+
return [direct];
|
|
13
|
+
const entries = await readdir(absRoot, { withFileTypes: true }).catch(() => []);
|
|
14
|
+
const folders = entries
|
|
15
|
+
.filter((entry) => entry.isDirectory())
|
|
16
|
+
.map((entry) => join(absRoot, entry.name));
|
|
17
|
+
const results = [];
|
|
18
|
+
for (const folder of folders) {
|
|
19
|
+
const found = await isSkillFolder(folder);
|
|
20
|
+
if (found)
|
|
21
|
+
results.push(found);
|
|
22
|
+
}
|
|
23
|
+
return results.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
24
|
+
}
|
|
25
|
+
export function getFallbackSkillRoots(workdir) {
|
|
26
|
+
const home = homedir();
|
|
27
|
+
const roots = [
|
|
28
|
+
// adjacent repo installs
|
|
29
|
+
resolve(workdir, '..', 'clawdis', 'skills'),
|
|
30
|
+
resolve(workdir, '..', 'clawdis', 'Skills'),
|
|
31
|
+
resolve(workdir, '..', 'clawdbot', 'skills'),
|
|
32
|
+
resolve(workdir, '..', 'clawdbot', 'Skills'),
|
|
33
|
+
// legacy locations
|
|
34
|
+
resolve(home, 'clawd', 'skills'),
|
|
35
|
+
resolve(home, 'clawd', 'Skills'),
|
|
36
|
+
resolve(home, '.clawd', 'skills'),
|
|
37
|
+
resolve(home, '.clawd', 'Skills'),
|
|
38
|
+
resolve(home, 'clawdbot', 'skills'),
|
|
39
|
+
resolve(home, 'clawdbot', 'Skills'),
|
|
40
|
+
resolve(home, '.clawdbot', 'skills'),
|
|
41
|
+
resolve(home, '.clawdbot', 'Skills'),
|
|
42
|
+
resolve(home, 'clawdis', 'skills'),
|
|
43
|
+
resolve(home, 'clawdis', 'Skills'),
|
|
44
|
+
resolve(home, '.clawdis', 'skills'),
|
|
45
|
+
resolve(home, '.clawdis', 'Skills'),
|
|
46
|
+
// macOS App Support legacy
|
|
47
|
+
resolve(home, 'Library', 'Application Support', 'clawdbot', 'skills'),
|
|
48
|
+
resolve(home, 'Library', 'Application Support', 'clawdbot', 'Skills'),
|
|
49
|
+
resolve(home, 'Library', 'Application Support', 'clawdis', 'skills'),
|
|
50
|
+
resolve(home, 'Library', 'Application Support', 'clawdis', 'Skills'),
|
|
51
|
+
];
|
|
52
|
+
return Array.from(new Set(roots));
|
|
53
|
+
}
|
|
54
|
+
async function isSkillFolder(folder) {
|
|
55
|
+
const marker = await findSkillMarker(folder);
|
|
56
|
+
if (!marker)
|
|
57
|
+
return null;
|
|
58
|
+
const base = basename(folder);
|
|
59
|
+
const slug = sanitizeSlug(base);
|
|
60
|
+
if (!slug)
|
|
61
|
+
return null;
|
|
62
|
+
const displayName = titleCase(base);
|
|
63
|
+
return { folder, slug, displayName };
|
|
64
|
+
}
|
|
65
|
+
async function findSkillMarker(folder) {
|
|
66
|
+
const candidates = ['SKILL.md', 'skill.md', 'Skills.md', 'skills.md'];
|
|
67
|
+
for (const name of candidates) {
|
|
68
|
+
const path = join(folder, name);
|
|
69
|
+
const st = await stat(path).catch(() => null);
|
|
70
|
+
if (st?.isFile())
|
|
71
|
+
return path;
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=scanSkills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanSkills.js","sourceRoot":"","sources":["../../src/cli/scanSkills.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/* @vitest-environment node */
|
|
2
|
+
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
|
+
import { describe, expect, it } from 'vitest';
|
|
6
|
+
import { findSkillFolders, getFallbackSkillRoots } from './scanSkills';
|
|
7
|
+
async function makeTmpDir() {
|
|
8
|
+
return mkdtemp(join(tmpdir(), 'clawdhub-scan-'));
|
|
9
|
+
}
|
|
10
|
+
describe('scanSkills', () => {
|
|
11
|
+
it('detects a single skill folder (root contains SKILL.md)', async () => {
|
|
12
|
+
const root = await makeTmpDir();
|
|
13
|
+
try {
|
|
14
|
+
await writeFile(join(root, 'SKILL.md'), '# Skill\n', 'utf8');
|
|
15
|
+
const found = await findSkillFolders(root);
|
|
16
|
+
expect(found).toHaveLength(1);
|
|
17
|
+
expect(found[0]?.folder).toBe(resolve(root));
|
|
18
|
+
expect(found[0]?.slug).toBeTruthy();
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
await rm(root, { recursive: true, force: true });
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
it('detects skills in a skills directory (subfolders)', async () => {
|
|
25
|
+
const root = await makeTmpDir();
|
|
26
|
+
try {
|
|
27
|
+
const skillsDir = join(root, 'skills');
|
|
28
|
+
const folder = join(skillsDir, 'cool-skill');
|
|
29
|
+
await mkdir(folder, { recursive: true });
|
|
30
|
+
await writeFile(join(folder, 'SKILL.md'), '# Skill\n', 'utf8');
|
|
31
|
+
const found = await findSkillFolders(skillsDir);
|
|
32
|
+
expect(found).toHaveLength(1);
|
|
33
|
+
expect(found[0]?.slug).toBe('cool-skill');
|
|
34
|
+
expect(found[0]?.folder).toBe(resolve(folder));
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
await rm(root, { recursive: true, force: true });
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
it('includes known legacy roots', () => {
|
|
41
|
+
const roots = getFallbackSkillRoots('/tmp/anywhere');
|
|
42
|
+
expect(roots.some((p) => p.endsWith('/clawdis/skills'))).toBe(true);
|
|
43
|
+
expect(roots.some((p) => p.endsWith('/clawd/skills'))).toBe(true);
|
|
44
|
+
expect(roots.some((p) => p.endsWith('/clawdbot/skills'))).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=scanSkills.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanSkills.test.js","sourceRoot":"","sources":["../../src/cli/scanSkills.test.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/slug.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function sanitizeSlug(value) {
|
|
2
|
+
const raw = value
|
|
3
|
+
.trim()
|
|
4
|
+
.toLowerCase()
|
|
5
|
+
.replace(/[^a-z0-9-]+/g, '-');
|
|
6
|
+
const cleaned = raw.replace(/^-+/, '').replace(/-+$/, '').replace(/--+/g, '-');
|
|
7
|
+
return cleaned;
|
|
8
|
+
}
|
|
9
|
+
export function titleCase(value) {
|
|
10
|
+
return value
|
|
11
|
+
.trim()
|
|
12
|
+
.replace(/[-_]+/g, ' ')
|
|
13
|
+
.replace(/\s+/g, ' ')
|
|
14
|
+
.replace(/\b\w/g, (char) => char.toUpperCase());
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=slug.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slug.js","sourceRoot":"","sources":["../../src/cli/slug.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,GAAG,GAAG,KAAK;SACd,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAA;IAC/B,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC9E,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,KAAK;SACT,IAAI,EAAE;SACN,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;AACnD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":""}
|
package/dist/cli/ui.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function promptHidden(prompt: string): Promise<string>;
|
|
2
|
+
export declare function promptConfirm(prompt: string): Promise<boolean>;
|
|
3
|
+
export declare function openInBrowser(url: string): void;
|
|
4
|
+
export declare function isInteractive(): boolean;
|
|
5
|
+
export declare function createSpinner(text: string): import("ora").Ora;
|
|
6
|
+
export declare function formatError(error: unknown): string;
|
|
7
|
+
export declare function fail(message: string): never;
|
package/dist/cli/ui.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { stdin } from 'node:process';
|
|
3
|
+
import { confirm, isCancel } from '@clack/prompts';
|
|
4
|
+
import ora from 'ora';
|
|
5
|
+
export async function promptHidden(prompt) {
|
|
6
|
+
if (!stdin.isTTY)
|
|
7
|
+
return '';
|
|
8
|
+
process.stdout.write(prompt);
|
|
9
|
+
const chunks = [];
|
|
10
|
+
stdin.setRawMode(true);
|
|
11
|
+
stdin.resume();
|
|
12
|
+
return new Promise((resolvePromise) => {
|
|
13
|
+
function onData(data) {
|
|
14
|
+
const text = data.toString('utf8');
|
|
15
|
+
if (text === '\r' || text === '\n') {
|
|
16
|
+
stdin.setRawMode(false);
|
|
17
|
+
stdin.pause();
|
|
18
|
+
stdin.off('data', onData);
|
|
19
|
+
process.stdout.write('\n');
|
|
20
|
+
resolvePromise(Buffer.concat(chunks).toString('utf8').trim());
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (text === '\u0003') {
|
|
24
|
+
stdin.setRawMode(false);
|
|
25
|
+
stdin.pause();
|
|
26
|
+
stdin.off('data', onData);
|
|
27
|
+
process.stdout.write('\n');
|
|
28
|
+
fail('Canceled');
|
|
29
|
+
}
|
|
30
|
+
if (text === '\u007f') {
|
|
31
|
+
chunks.pop();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
chunks.push(data);
|
|
35
|
+
}
|
|
36
|
+
stdin.on('data', onData);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
export async function promptConfirm(prompt) {
|
|
40
|
+
const answer = await confirm({ message: prompt });
|
|
41
|
+
if (isCancel(answer))
|
|
42
|
+
return false;
|
|
43
|
+
return Boolean(answer);
|
|
44
|
+
}
|
|
45
|
+
export function openInBrowser(url) {
|
|
46
|
+
const args = process.platform === 'darwin'
|
|
47
|
+
? ['open', url]
|
|
48
|
+
: process.platform === 'win32'
|
|
49
|
+
? ['cmd', '/c', 'start', '', url]
|
|
50
|
+
: ['xdg-open', url];
|
|
51
|
+
const [command, ...commandArgs] = args;
|
|
52
|
+
if (!command)
|
|
53
|
+
return;
|
|
54
|
+
const child = spawn(command, commandArgs, { stdio: 'ignore', detached: true });
|
|
55
|
+
child.unref();
|
|
56
|
+
}
|
|
57
|
+
export function isInteractive() {
|
|
58
|
+
return Boolean(process.stdout.isTTY && stdin.isTTY);
|
|
59
|
+
}
|
|
60
|
+
export function createSpinner(text) {
|
|
61
|
+
return ora({ text, spinner: 'dots', isEnabled: isInteractive() }).start();
|
|
62
|
+
}
|
|
63
|
+
export function formatError(error) {
|
|
64
|
+
if (error instanceof Error)
|
|
65
|
+
return error.message;
|
|
66
|
+
return String(error);
|
|
67
|
+
}
|
|
68
|
+
export function fail(message) {
|
|
69
|
+
console.error(`Error: ${message}`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=ui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/cli/ui.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED