@trikhub/cli 0.2.0

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 (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +389 -0
  3. package/dist/cli.d.ts +8 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +105 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/info.d.ts +11 -0
  8. package/dist/commands/info.d.ts.map +1 -0
  9. package/dist/commands/info.js +101 -0
  10. package/dist/commands/info.js.map +1 -0
  11. package/dist/commands/install.d.ts +17 -0
  12. package/dist/commands/install.d.ts.map +1 -0
  13. package/dist/commands/install.js +358 -0
  14. package/dist/commands/install.js.map +1 -0
  15. package/dist/commands/list.d.ts +11 -0
  16. package/dist/commands/list.d.ts.map +1 -0
  17. package/dist/commands/list.js +96 -0
  18. package/dist/commands/list.js.map +1 -0
  19. package/dist/commands/login.d.ts +19 -0
  20. package/dist/commands/login.d.ts.map +1 -0
  21. package/dist/commands/login.js +154 -0
  22. package/dist/commands/login.js.map +1 -0
  23. package/dist/commands/publish.d.ts +13 -0
  24. package/dist/commands/publish.d.ts.map +1 -0
  25. package/dist/commands/publish.js +285 -0
  26. package/dist/commands/publish.js.map +1 -0
  27. package/dist/commands/search.d.ts +12 -0
  28. package/dist/commands/search.d.ts.map +1 -0
  29. package/dist/commands/search.js +60 -0
  30. package/dist/commands/search.js.map +1 -0
  31. package/dist/commands/sync.d.ts +19 -0
  32. package/dist/commands/sync.d.ts.map +1 -0
  33. package/dist/commands/sync.js +193 -0
  34. package/dist/commands/sync.js.map +1 -0
  35. package/dist/commands/uninstall.d.ts +11 -0
  36. package/dist/commands/uninstall.d.ts.map +1 -0
  37. package/dist/commands/uninstall.js +153 -0
  38. package/dist/commands/uninstall.js.map +1 -0
  39. package/dist/commands/upgrade.d.ts +15 -0
  40. package/dist/commands/upgrade.d.ts.map +1 -0
  41. package/dist/commands/upgrade.js +144 -0
  42. package/dist/commands/upgrade.js.map +1 -0
  43. package/dist/index.d.ts +10 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +14 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/lib/config.d.ts +79 -0
  48. package/dist/lib/config.d.ts.map +1 -0
  49. package/dist/lib/config.js +202 -0
  50. package/dist/lib/config.js.map +1 -0
  51. package/dist/lib/registry.d.ts +90 -0
  52. package/dist/lib/registry.d.ts.map +1 -0
  53. package/dist/lib/registry.js +294 -0
  54. package/dist/lib/registry.js.map +1 -0
  55. package/dist/lib/storage.d.ts +82 -0
  56. package/dist/lib/storage.d.ts.map +1 -0
  57. package/dist/lib/storage.js +177 -0
  58. package/dist/lib/storage.js.map +1 -0
  59. package/dist/lib/validator.d.ts +24 -0
  60. package/dist/lib/validator.d.ts.map +1 -0
  61. package/dist/lib/validator.js +181 -0
  62. package/dist/lib/validator.js.map +1 -0
  63. package/dist/types.d.ts +187 -0
  64. package/dist/types.d.ts.map +1 -0
  65. package/dist/types.js +36 -0
  66. package/dist/types.js.map +1 -0
  67. package/package.json +66 -0
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Configuration resolution for TrikHub CLI
3
+ *
4
+ * Supports both local (project-level) and global configurations.
5
+ *
6
+ * Resolution order:
7
+ * 1. Local: .trikhub/config.json in current directory
8
+ * 2. Global: ~/.trikhub/config.json in home directory
9
+ *
10
+ * If neither exists, user is prompted to choose where to set up.
11
+ */
12
+ import { TrikConfig } from '../types.js';
13
+ /**
14
+ * Configuration scope - where the config lives
15
+ */
16
+ export type ConfigScope = 'local' | 'global';
17
+ /**
18
+ * Resolved configuration context
19
+ */
20
+ export interface ConfigContext {
21
+ /** The scope of this config (local or global) */
22
+ scope: ConfigScope;
23
+ /** Base directory where .trikhub folder lives */
24
+ baseDir: string;
25
+ /** Full path to the .trikhub directory */
26
+ trikhubDir: string;
27
+ /** Full path to config.json */
28
+ configPath: string;
29
+ /** Full path to triks.lock */
30
+ lockfilePath: string;
31
+ /** Full path to triks/ directory */
32
+ triksDir: string;
33
+ /** The loaded configuration */
34
+ config: TrikConfig;
35
+ }
36
+ /**
37
+ * Get the local trikhub directory path (in current working directory)
38
+ */
39
+ export declare function getLocalTrikhubDir(): string;
40
+ /**
41
+ * Get the global trikhub directory path (in home directory)
42
+ */
43
+ export declare function getGlobalTrikhubDir(): string;
44
+ /**
45
+ * Check if a local config exists in the current directory
46
+ */
47
+ export declare function hasLocalConfig(): boolean;
48
+ /**
49
+ * Check if a global config exists in the home directory
50
+ */
51
+ export declare function hasGlobalConfig(): boolean;
52
+ /**
53
+ * Initialize a new configuration at the specified location
54
+ */
55
+ export declare function initializeConfig(scope: ConfigScope): ConfigContext;
56
+ /**
57
+ * Resolve configuration - find the appropriate config to use
58
+ *
59
+ * This is the main entry point for config resolution.
60
+ * It checks local first, then global, then prompts if neither exists.
61
+ *
62
+ * @param options - Resolution options
63
+ * @param options.interactive - If false, don't prompt user (use global by default)
64
+ */
65
+ export declare function resolveConfig(options?: {
66
+ interactive?: boolean;
67
+ }): Promise<ConfigContext>;
68
+ /**
69
+ * Get the current config context without prompting
70
+ *
71
+ * Returns local if it exists, otherwise global.
72
+ * Creates global if neither exists (for backwards compatibility).
73
+ */
74
+ export declare function getConfigContext(): ConfigContext;
75
+ /**
76
+ * Save configuration to the context's config path
77
+ */
78
+ export declare function saveConfig(ctx: ConfigContext, config: TrikConfig): void;
79
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAE,UAAU,EAAkB,MAAM,aAAa,CAAC;AAIzD;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,iDAAiD;IACjD,KAAK,EAAE,WAAW,CAAC;IAEnB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAEhB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;IAEnB,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;IAEnB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IAErB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IAEjB,+BAA+B;IAC/B,MAAM,EAAE,UAAU,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAGxC;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAGzC;AAmDD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,aAAa,CAuBlE;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,OAAO,CAAC,EAAE;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAAC,aAAa,CAAC,CA6DzB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAWhD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAOvE"}
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Configuration resolution for TrikHub CLI
3
+ *
4
+ * Supports both local (project-level) and global configurations.
5
+ *
6
+ * Resolution order:
7
+ * 1. Local: .trikhub/config.json in current directory
8
+ * 2. Global: ~/.trikhub/config.json in home directory
9
+ *
10
+ * If neither exists, user is prompted to choose where to set up.
11
+ */
12
+ import { homedir } from 'node:os';
13
+ import { join } from 'node:path';
14
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
15
+ import { DEFAULT_CONFIG } from '../types.js';
16
+ import chalk from 'chalk';
17
+ import { select, confirm } from '@inquirer/prompts';
18
+ /**
19
+ * Get the local trikhub directory path (in current working directory)
20
+ */
21
+ export function getLocalTrikhubDir() {
22
+ return join(process.cwd(), '.trikhub');
23
+ }
24
+ /**
25
+ * Get the global trikhub directory path (in home directory)
26
+ */
27
+ export function getGlobalTrikhubDir() {
28
+ return join(homedir(), '.trikhub');
29
+ }
30
+ /**
31
+ * Check if a local config exists in the current directory
32
+ */
33
+ export function hasLocalConfig() {
34
+ const localConfigPath = join(getLocalTrikhubDir(), 'config.json');
35
+ return existsSync(localConfigPath);
36
+ }
37
+ /**
38
+ * Check if a global config exists in the home directory
39
+ */
40
+ export function hasGlobalConfig() {
41
+ const globalConfigPath = join(getGlobalTrikhubDir(), 'config.json');
42
+ return existsSync(globalConfigPath);
43
+ }
44
+ /**
45
+ * Load a config file from a path, merging with defaults
46
+ */
47
+ function loadConfigFromPath(configPath) {
48
+ if (!existsSync(configPath)) {
49
+ return { ...DEFAULT_CONFIG };
50
+ }
51
+ try {
52
+ const content = readFileSync(configPath, 'utf-8');
53
+ const config = JSON.parse(content);
54
+ return { ...DEFAULT_CONFIG, ...config };
55
+ }
56
+ catch {
57
+ return { ...DEFAULT_CONFIG };
58
+ }
59
+ }
60
+ /**
61
+ * Create a ConfigContext from a base directory
62
+ */
63
+ function createContext(baseDir, scope) {
64
+ const trikhubDir = join(baseDir, '.trikhub');
65
+ const configPath = join(trikhubDir, 'config.json');
66
+ const config = loadConfigFromPath(configPath);
67
+ // For local configs, triksDirectory is relative to the .trikhub folder
68
+ // For global configs, it uses the config value (which may be absolute)
69
+ let triksDir;
70
+ if (scope === 'local') {
71
+ // Local triks are stored in .trikhub/triks/
72
+ triksDir = join(trikhubDir, 'triks');
73
+ }
74
+ else {
75
+ // Global uses the configured path (default: ~/.trikhub/triks)
76
+ triksDir = config.triksDirectory.startsWith('~')
77
+ ? config.triksDirectory.replace('~', homedir())
78
+ : config.triksDirectory;
79
+ }
80
+ return {
81
+ scope,
82
+ baseDir,
83
+ trikhubDir,
84
+ configPath,
85
+ lockfilePath: join(trikhubDir, 'triks.lock'),
86
+ triksDir,
87
+ config,
88
+ };
89
+ }
90
+ /**
91
+ * Initialize a new configuration at the specified location
92
+ */
93
+ export function initializeConfig(scope) {
94
+ const baseDir = scope === 'local' ? process.cwd() : homedir();
95
+ const trikhubDir = join(baseDir, '.trikhub');
96
+ const triksDir = join(trikhubDir, 'triks');
97
+ const configPath = join(trikhubDir, 'config.json');
98
+ // Create directories
99
+ if (!existsSync(trikhubDir)) {
100
+ mkdirSync(trikhubDir, { recursive: true });
101
+ }
102
+ if (!existsSync(triksDir)) {
103
+ mkdirSync(triksDir, { recursive: true });
104
+ }
105
+ // Create config file with defaults
106
+ const config = {
107
+ ...DEFAULT_CONFIG,
108
+ // For local configs, use relative path
109
+ triksDirectory: scope === 'local' ? '.trikhub/triks' : DEFAULT_CONFIG.triksDirectory,
110
+ };
111
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
112
+ return createContext(baseDir, scope);
113
+ }
114
+ /**
115
+ * Resolve configuration - find the appropriate config to use
116
+ *
117
+ * This is the main entry point for config resolution.
118
+ * It checks local first, then global, then prompts if neither exists.
119
+ *
120
+ * @param options - Resolution options
121
+ * @param options.interactive - If false, don't prompt user (use global by default)
122
+ */
123
+ export async function resolveConfig(options) {
124
+ const interactive = options?.interactive ?? true;
125
+ // 1. Check for local config first
126
+ if (hasLocalConfig()) {
127
+ return createContext(process.cwd(), 'local');
128
+ }
129
+ // 2. Check for global config
130
+ if (hasGlobalConfig()) {
131
+ if (!interactive) {
132
+ // Non-interactive mode: just use global
133
+ return createContext(homedir(), 'global');
134
+ }
135
+ // Interactive mode: ask user if they want to use global
136
+ console.log(chalk.cyan('\nNo local .trikhub configuration found.'));
137
+ console.log(chalk.dim(`Global configuration exists at ${getGlobalTrikhubDir()}\n`));
138
+ const useGlobal = await confirm({
139
+ message: 'Use global configuration?',
140
+ default: true,
141
+ });
142
+ if (useGlobal) {
143
+ return createContext(homedir(), 'global');
144
+ }
145
+ // User wants local - create it
146
+ console.log(chalk.dim('\nInitializing local configuration...'));
147
+ return initializeConfig('local');
148
+ }
149
+ // 3. No config exists anywhere - prompt user to set up
150
+ if (!interactive) {
151
+ // Non-interactive mode: create global by default
152
+ return initializeConfig('global');
153
+ }
154
+ console.log(chalk.cyan('\nNo TrikHub configuration found.'));
155
+ console.log(chalk.dim('Triks need a place to be installed.\n'));
156
+ const scope = await select({
157
+ message: 'Where would you like to set up TrikHub?',
158
+ choices: [
159
+ {
160
+ value: 'global',
161
+ name: `Global (${chalk.dim('~/.trikhub')})`,
162
+ description: 'Install triks in your home directory. Available to all projects.',
163
+ },
164
+ {
165
+ value: 'local',
166
+ name: `Local (${chalk.dim('./.trikhub')})`,
167
+ description: 'Install triks in this project directory. Project-specific configuration.',
168
+ },
169
+ ],
170
+ default: 'global',
171
+ });
172
+ console.log(chalk.dim(`\nInitializing ${scope} configuration...`));
173
+ return initializeConfig(scope);
174
+ }
175
+ /**
176
+ * Get the current config context without prompting
177
+ *
178
+ * Returns local if it exists, otherwise global.
179
+ * Creates global if neither exists (for backwards compatibility).
180
+ */
181
+ export function getConfigContext() {
182
+ if (hasLocalConfig()) {
183
+ return createContext(process.cwd(), 'local');
184
+ }
185
+ if (hasGlobalConfig()) {
186
+ return createContext(homedir(), 'global');
187
+ }
188
+ // Fallback: create global config for backwards compatibility
189
+ return initializeConfig('global');
190
+ }
191
+ /**
192
+ * Save configuration to the context's config path
193
+ */
194
+ export function saveConfig(ctx, config) {
195
+ // Ensure directory exists
196
+ if (!existsSync(ctx.trikhubDir)) {
197
+ mkdirSync(ctx.trikhubDir, { recursive: true });
198
+ }
199
+ writeFileSync(ctx.configPath, JSON.stringify(config, null, 2));
200
+ ctx.config = config;
201
+ }
202
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Registry client for TrikHub
3
+ *
4
+ * Connects to the TrikHub registry API to search and fetch triks.
5
+ */
6
+ import { TrikInfo, TrikVersion, SearchResult, DeviceAuthResponse, AuthResult, Publisher } from '../types.js';
7
+ /**
8
+ * Registry client class
9
+ */
10
+ export declare class RegistryClient {
11
+ private baseUrl;
12
+ private authToken?;
13
+ constructor(baseUrl?: string, authToken?: string);
14
+ /**
15
+ * Make an API request
16
+ */
17
+ private fetch;
18
+ /**
19
+ * Search for triks in the registry
20
+ */
21
+ search(query: string, options?: {
22
+ page?: number;
23
+ perPage?: number;
24
+ }): Promise<SearchResult>;
25
+ /**
26
+ * Get detailed information about a specific trik
27
+ */
28
+ getTrik(fullName: string): Promise<TrikInfo | null>;
29
+ /**
30
+ * Get a specific version of a trik
31
+ */
32
+ getTrikVersion(fullName: string, version: string): Promise<TrikVersion | null>;
33
+ /**
34
+ * Get the latest version of a trik
35
+ */
36
+ getLatestVersion(fullName: string): Promise<TrikVersion | null>;
37
+ /**
38
+ * List all available triks (paginated)
39
+ */
40
+ listTriks(options?: {
41
+ page?: number;
42
+ perPage?: number;
43
+ }): Promise<SearchResult>;
44
+ /**
45
+ * Report a download (for analytics)
46
+ */
47
+ reportDownload(fullName: string, version: string): Promise<void>;
48
+ /**
49
+ * Start device authorization flow
50
+ * Returns device_code for polling and user_code for user to enter
51
+ */
52
+ startDeviceAuth(): Promise<DeviceAuthResponse>;
53
+ /**
54
+ * Poll for device authorization completion
55
+ * Returns null if still pending, AuthResult when complete
56
+ */
57
+ pollDeviceAuth(deviceCode: string): Promise<AuthResult | null>;
58
+ /**
59
+ * Get the current authenticated user
60
+ */
61
+ getCurrentUser(): Promise<Publisher>;
62
+ /**
63
+ * Logout (invalidate session)
64
+ */
65
+ logout(): Promise<void>;
66
+ /**
67
+ * Register a new trik in the registry
68
+ */
69
+ registerTrik(data: {
70
+ githubRepo: string;
71
+ name?: string;
72
+ description?: string;
73
+ categories?: string[];
74
+ keywords?: string[];
75
+ }): Promise<TrikInfo>;
76
+ /**
77
+ * Publish a new version of a trik
78
+ */
79
+ publishVersion(fullName: string, data: {
80
+ version: string;
81
+ tarballUrl: string;
82
+ sha256?: string;
83
+ manifest: Record<string, unknown>;
84
+ }): Promise<TrikVersion>;
85
+ }
86
+ /**
87
+ * Default registry client instance
88
+ */
89
+ export declare const registry: RegistryClient;
90
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/lib/registry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,kBAAkB,EAClB,UAAU,EACV,SAAS,EACV,MAAM,aAAa,CAAC;AA2FrB;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAC,CAAS;gBAEf,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;IAOhD;;OAEG;YACW,KAAK;IAkCnB;;OAEG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,YAAY,CAAC;IAmBrG;;OAEG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAezD;;OAEG;IACG,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAOpF;;OAEG;IACG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAOrE;;OAEG;IACG,SAAS,CAAC,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,YAAY,CAAC;IAkBzF;;OAEG;IACG,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBtE;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAmBpD;;;OAGG;IACG,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IA2BpE;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,SAAS,CAAC;IAO1C;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAW7B;;OAEG;IACG,YAAY,CAAC,IAAI,EAAE;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAWrB;;OAEG;IACG,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACnC,GACA,OAAO,CAAC,WAAW,CAAC;CAiBxB;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ,gBAAuB,CAAC"}
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Registry client for TrikHub
3
+ *
4
+ * Connects to the TrikHub registry API to search and fetch triks.
5
+ */
6
+ import { loadConfig } from './storage.js';
7
+ /**
8
+ * Convert API response to CLI TrikInfo type
9
+ */
10
+ function apiToTrikInfo(api, versions = []) {
11
+ return {
12
+ fullName: api.name,
13
+ scope: api.scope,
14
+ name: api.shortName,
15
+ githubRepo: api.githubRepo,
16
+ latestVersion: api.latestVersion,
17
+ description: api.description,
18
+ categories: api.categories,
19
+ keywords: api.keywords,
20
+ downloads: api.totalDownloads,
21
+ stars: api.githubStars,
22
+ verified: api.verified,
23
+ discussionsUrl: `https://github.com/${api.githubRepo}/discussions`,
24
+ versions,
25
+ createdAt: api.createdAt,
26
+ updatedAt: api.updatedAt,
27
+ };
28
+ }
29
+ /**
30
+ * Convert API version to CLI TrikVersion type
31
+ */
32
+ function apiToTrikVersion(api, githubRepo) {
33
+ return {
34
+ version: api.version,
35
+ releaseUrl: `https://github.com/${githubRepo}/releases/tag/v${api.version}`,
36
+ tarballUrl: api.tarballUrl,
37
+ sha256: api.sha256,
38
+ publishedAt: api.publishedAt,
39
+ downloads: api.downloads,
40
+ };
41
+ }
42
+ /**
43
+ * Build a trik path from full name (e.g., "@Muffles/article-search" -> "@Muffles/article-search")
44
+ * Used to construct API paths with scope and name as separate segments
45
+ */
46
+ function trikPath(fullName) {
47
+ // fullName format: @scope/name
48
+ // We need to return: @scope/name (scope and name as path segments)
49
+ // The URL will be: /api/v1/triks/@scope/name
50
+ return fullName;
51
+ }
52
+ /**
53
+ * Registry client class
54
+ */
55
+ export class RegistryClient {
56
+ baseUrl;
57
+ authToken;
58
+ constructor(baseUrl, authToken) {
59
+ const config = loadConfig();
60
+ // Priority: explicit param > env var > config file
61
+ this.baseUrl = baseUrl ?? process.env.TRIKHUB_REGISTRY ?? config.registry;
62
+ this.authToken = authToken ?? config.authToken;
63
+ }
64
+ /**
65
+ * Make an API request
66
+ */
67
+ async fetch(path, options = {}) {
68
+ const url = `${this.baseUrl}${path}`;
69
+ const headers = {
70
+ 'Content-Type': 'application/json',
71
+ ...options.headers,
72
+ };
73
+ if (this.authToken) {
74
+ headers['Authorization'] = `Bearer ${this.authToken}`;
75
+ }
76
+ const response = await fetch(url, { ...options, headers });
77
+ if (!response.ok) {
78
+ if (response.status === 401) {
79
+ throw new Error('Authentication failed. Please run `trik login`');
80
+ }
81
+ if (response.status === 404) {
82
+ throw new Error(`Not found: ${path}`);
83
+ }
84
+ const body = await response.text();
85
+ let message = `Registry API error: ${response.status} ${response.statusText}`;
86
+ try {
87
+ const json = JSON.parse(body);
88
+ if (json.error)
89
+ message = json.error;
90
+ }
91
+ catch {
92
+ // Use default message
93
+ }
94
+ throw new Error(message);
95
+ }
96
+ return response.json();
97
+ }
98
+ /**
99
+ * Search for triks in the registry
100
+ */
101
+ async search(query, options = {}) {
102
+ const { page = 1, perPage = 10 } = options;
103
+ const params = new URLSearchParams({
104
+ q: query,
105
+ page: String(page),
106
+ pageSize: String(perPage),
107
+ });
108
+ const result = await this.fetch(`/api/v1/triks?${params}`);
109
+ return {
110
+ total: result.total,
111
+ page: result.page,
112
+ perPage: result.pageSize,
113
+ results: result.triks.map((t) => apiToTrikInfo(t)),
114
+ };
115
+ }
116
+ /**
117
+ * Get detailed information about a specific trik
118
+ */
119
+ async getTrik(fullName) {
120
+ try {
121
+ // Use path directly - routes expect /api/v1/triks/:scope/:trikName
122
+ const result = await this.fetch(`/api/v1/triks/${trikPath(fullName)}`);
123
+ const versions = result.versions.map((v) => apiToTrikVersion(v, result.githubRepo));
124
+ return apiToTrikInfo(result, versions);
125
+ }
126
+ catch (error) {
127
+ if (error instanceof Error && error.message.includes('Not found')) {
128
+ return null;
129
+ }
130
+ throw error;
131
+ }
132
+ }
133
+ /**
134
+ * Get a specific version of a trik
135
+ */
136
+ async getTrikVersion(fullName, version) {
137
+ const trik = await this.getTrik(fullName);
138
+ if (!trik)
139
+ return null;
140
+ return trik.versions.find((v) => v.version === version) ?? null;
141
+ }
142
+ /**
143
+ * Get the latest version of a trik
144
+ */
145
+ async getLatestVersion(fullName) {
146
+ const trik = await this.getTrik(fullName);
147
+ if (!trik)
148
+ return null;
149
+ return trik.versions[0] ?? null;
150
+ }
151
+ /**
152
+ * List all available triks (paginated)
153
+ */
154
+ async listTriks(options = {}) {
155
+ const { page = 1, perPage = 10 } = options;
156
+ const params = new URLSearchParams({
157
+ page: String(page),
158
+ pageSize: String(perPage),
159
+ });
160
+ const result = await this.fetch(`/api/v1/triks?${params}`);
161
+ return {
162
+ total: result.total,
163
+ page: result.page,
164
+ perPage: result.pageSize,
165
+ results: result.triks.map((t) => apiToTrikInfo(t)),
166
+ };
167
+ }
168
+ /**
169
+ * Report a download (for analytics)
170
+ */
171
+ async reportDownload(fullName, version) {
172
+ try {
173
+ // Use path directly - routes expect /api/v1/triks/:scope/:trikName/download
174
+ await fetch(`${this.baseUrl}/api/v1/triks/${trikPath(fullName)}/download`, {
175
+ method: 'POST',
176
+ headers: { 'Content-Type': 'application/json' },
177
+ body: JSON.stringify({ version }),
178
+ });
179
+ }
180
+ catch {
181
+ // Silently fail analytics - don't break the install
182
+ }
183
+ }
184
+ // ============================================
185
+ // Authentication Methods
186
+ // ============================================
187
+ /**
188
+ * Start device authorization flow
189
+ * Returns device_code for polling and user_code for user to enter
190
+ */
191
+ async startDeviceAuth() {
192
+ const response = await fetch(`${this.baseUrl}/auth/device`);
193
+ if (!response.ok) {
194
+ const body = await response.text();
195
+ let message = `Failed to start authentication: ${response.status}`;
196
+ try {
197
+ const json = JSON.parse(body);
198
+ if (json.error)
199
+ message = json.error;
200
+ if (json.message)
201
+ message = json.message;
202
+ }
203
+ catch {
204
+ // Use default message
205
+ }
206
+ throw new Error(message);
207
+ }
208
+ return response.json();
209
+ }
210
+ /**
211
+ * Poll for device authorization completion
212
+ * Returns null if still pending, AuthResult when complete
213
+ */
214
+ async pollDeviceAuth(deviceCode) {
215
+ const response = await fetch(`${this.baseUrl}/auth/device/poll`, {
216
+ method: 'POST',
217
+ headers: { 'Content-Type': 'application/json' },
218
+ body: JSON.stringify({ deviceCode }),
219
+ });
220
+ if (response.status === 202) {
221
+ // Still pending
222
+ return null;
223
+ }
224
+ if (!response.ok) {
225
+ const body = await response.text();
226
+ let message = `Authentication failed: ${response.status}`;
227
+ try {
228
+ const json = JSON.parse(body);
229
+ if (json.error)
230
+ message = json.error;
231
+ }
232
+ catch {
233
+ // Use default message
234
+ }
235
+ throw new Error(message);
236
+ }
237
+ return response.json();
238
+ }
239
+ /**
240
+ * Get the current authenticated user
241
+ */
242
+ async getCurrentUser() {
243
+ if (!this.authToken) {
244
+ throw new Error('Not authenticated. Please run `trik login`');
245
+ }
246
+ return this.fetch('/auth/me');
247
+ }
248
+ /**
249
+ * Logout (invalidate session)
250
+ */
251
+ async logout() {
252
+ if (!this.authToken) {
253
+ return;
254
+ }
255
+ await this.fetch('/auth/logout', { method: 'POST' });
256
+ }
257
+ // ============================================
258
+ // Publishing Methods
259
+ // ============================================
260
+ /**
261
+ * Register a new trik in the registry
262
+ */
263
+ async registerTrik(data) {
264
+ if (!this.authToken) {
265
+ throw new Error('Not authenticated. Please run `trik login`');
266
+ }
267
+ return this.fetch('/api/v1/triks', {
268
+ method: 'POST',
269
+ body: JSON.stringify(data),
270
+ });
271
+ }
272
+ /**
273
+ * Publish a new version of a trik
274
+ */
275
+ async publishVersion(fullName, data) {
276
+ if (!this.authToken) {
277
+ throw new Error('Not authenticated. Please run `trik login`');
278
+ }
279
+ // Use path directly - routes expect /api/v1/triks/:scope/:trikName/versions
280
+ const result = await this.fetch(`/api/v1/triks/${trikPath(fullName)}/versions`, {
281
+ method: 'POST',
282
+ body: JSON.stringify(data),
283
+ });
284
+ // Get the github repo for the release URL
285
+ const trik = await this.getTrik(fullName);
286
+ const githubRepo = trik?.githubRepo ?? '';
287
+ return apiToTrikVersion(result, githubRepo);
288
+ }
289
+ }
290
+ /**
291
+ * Default registry client instance
292
+ */
293
+ export const registry = new RegistryClient();
294
+ //# sourceMappingURL=registry.js.map