skilluse 0.1.0 → 0.1.3

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/dist/index.js +7291 -12079
  2. package/package.json +5 -5
  3. package/dist/app.d.ts +0 -6
  4. package/dist/app.js +0 -6
  5. package/dist/cli.d.ts +0 -3
  6. package/dist/cli.js +0 -167
  7. package/dist/commands/demo.d.ts +0 -14
  8. package/dist/commands/demo.js +0 -46
  9. package/dist/commands/index.d.ts +0 -8
  10. package/dist/commands/index.js +0 -77
  11. package/dist/commands/list.d.ts +0 -14
  12. package/dist/commands/list.js +0 -54
  13. package/dist/commands/login.d.ts +0 -14
  14. package/dist/commands/login.js +0 -153
  15. package/dist/commands/logout.d.ts +0 -8
  16. package/dist/commands/logout.js +0 -47
  17. package/dist/commands/repo/add.d.ts +0 -22
  18. package/dist/commands/repo/add.js +0 -139
  19. package/dist/commands/repo/edit.d.ts +0 -19
  20. package/dist/commands/repo/edit.js +0 -117
  21. package/dist/commands/repo/index.d.ts +0 -8
  22. package/dist/commands/repo/index.js +0 -47
  23. package/dist/commands/repo/list.d.ts +0 -8
  24. package/dist/commands/repo/list.js +0 -47
  25. package/dist/commands/repo/remove.d.ts +0 -16
  26. package/dist/commands/repo/remove.js +0 -83
  27. package/dist/commands/repo/sync.d.ts +0 -10
  28. package/dist/commands/repo/sync.js +0 -78
  29. package/dist/commands/repo/use.d.ts +0 -10
  30. package/dist/commands/repo/use.js +0 -56
  31. package/dist/commands/repos.d.ts +0 -11
  32. package/dist/commands/repos.js +0 -50
  33. package/dist/commands/search.d.ts +0 -16
  34. package/dist/commands/search.js +0 -199
  35. package/dist/commands/skills.d.ts +0 -11
  36. package/dist/commands/skills.js +0 -43
  37. package/dist/commands/whoami.d.ts +0 -8
  38. package/dist/commands/whoami.js +0 -69
  39. package/dist/components/CLIError.d.ts +0 -27
  40. package/dist/components/CLIError.js +0 -24
  41. package/dist/components/ProgressBar.d.ts +0 -7
  42. package/dist/components/ProgressBar.js +0 -9
  43. package/dist/components/Select.d.ts +0 -11
  44. package/dist/components/Select.js +0 -6
  45. package/dist/components/Spinner.d.ts +0 -6
  46. package/dist/components/Spinner.js +0 -7
  47. package/dist/components/StatusMessage.d.ts +0 -9
  48. package/dist/components/StatusMessage.js +0 -13
  49. package/dist/components/Table.d.ts +0 -9
  50. package/dist/components/Table.js +0 -27
  51. package/dist/components/TextInput.d.ts +0 -9
  52. package/dist/components/TextInput.js +0 -6
  53. package/dist/components/index.d.ts +0 -8
  54. package/dist/components/index.js +0 -8
  55. package/dist/index.d.ts +0 -3
  56. package/dist/services/credentials.d.ts +0 -69
  57. package/dist/services/credentials.js +0 -216
  58. package/dist/services/index.d.ts +0 -6
  59. package/dist/services/index.js +0 -10
  60. package/dist/services/oauth.d.ts +0 -106
  61. package/dist/services/oauth.js +0 -208
  62. package/dist/services/paths.d.ts +0 -19
  63. package/dist/services/paths.js +0 -21
  64. package/dist/services/store.d.ts +0 -64
  65. package/dist/services/store.js +0 -107
  66. package/dist/services/update.d.ts +0 -20
  67. package/dist/services/update.js +0 -93
@@ -1,27 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box, Text } from "ink";
3
- export function Table({ data, columns, }) {
4
- if (data.length === 0) {
5
- return _jsx(Text, { dimColor: true, children: "No data" });
6
- }
7
- // Get columns from data keys if not specified
8
- const cols = columns || Object.keys(data[0]);
9
- // Calculate column widths
10
- const widths = cols.map((col) => {
11
- const headerWidth = String(col).length;
12
- const maxDataWidth = data.reduce((max, row) => {
13
- const value = row[col];
14
- const width = value == null ? 0 : String(value).length;
15
- return Math.max(max, width);
16
- }, 0);
17
- return Math.max(headerWidth, maxDataWidth);
18
- });
19
- const renderCell = (value, width, isHeader = false) => {
20
- const str = value == null ? "" : String(value);
21
- const padded = str.padEnd(width);
22
- return isHeader ? (_jsx(Text, { bold: true, children: padded })) : (_jsx(Text, { children: padded }));
23
- };
24
- const separator = (_jsx(Box, { children: _jsx(Text, { children: widths.map((w, i) => "─".repeat(w) + (i < widths.length - 1 ? "─┼─" : "")).join("") }) }));
25
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { children: cols.map((col, i) => (_jsxs(Box, { children: [renderCell(String(col), widths[i], true), i < cols.length - 1 && _jsx(Text, { children: " \u2502 " })] }, String(col)))) }), separator, data.map((row, rowIndex) => (_jsx(Box, { children: cols.map((col, i) => (_jsxs(Box, { children: [renderCell(row[col], widths[i]), i < cols.length - 1 && _jsx(Text, { children: " \u2502 " })] }, String(col)))) }, rowIndex)))] }));
26
- }
27
- //# sourceMappingURL=Table.js.map
@@ -1,9 +0,0 @@
1
- interface TextInputProps {
2
- value: string;
3
- onChange: (value: string) => void;
4
- placeholder?: string;
5
- onSubmit?: (value: string) => void;
6
- }
7
- export declare function TextInput({ value, onChange, placeholder, onSubmit, }: TextInputProps): import("react/jsx-runtime").JSX.Element;
8
- export {};
9
- //# sourceMappingURL=TextInput.d.ts.map
@@ -1,6 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import InkTextInput from "ink-text-input";
3
- export function TextInput({ value, onChange, placeholder, onSubmit, }) {
4
- return (_jsx(InkTextInput, { value: value, onChange: onChange, placeholder: placeholder, onSubmit: onSubmit }));
5
- }
6
- //# sourceMappingURL=TextInput.js.map
@@ -1,8 +0,0 @@
1
- export { Spinner } from "./Spinner.js";
2
- export { Select } from "./Select.js";
3
- export { Table } from "./Table.js";
4
- export { ProgressBar } from "./ProgressBar.js";
5
- export { StatusMessage } from "./StatusMessage.js";
6
- export { TextInput } from "./TextInput.js";
7
- export { CLIError, type CLIErrorProps } from "./CLIError.js";
8
- //# sourceMappingURL=index.d.ts.map
@@ -1,8 +0,0 @@
1
- export { Spinner } from "./Spinner.js";
2
- export { Select } from "./Select.js";
3
- export { Table } from "./Table.js";
4
- export { ProgressBar } from "./ProgressBar.js";
5
- export { StatusMessage } from "./StatusMessage.js";
6
- export { TextInput } from "./TextInput.js";
7
- export { CLIError } from "./CLIError.js";
8
- //# sourceMappingURL=index.js.map
package/dist/index.d.ts DELETED
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
3
- //# sourceMappingURL=index.d.ts.map
@@ -1,69 +0,0 @@
1
- /**
2
- * Secure credential storage service.
3
- *
4
- * Stores OAuth tokens securely using:
5
- * 1. System keychain (preferred) - macOS Keychain, Windows Credential Manager, Linux libsecret
6
- * 2. Encrypted file fallback - when keychain is unavailable
7
- *
8
- * Storage strategy:
9
- * - User token → Keychain/encrypted file (sensitive)
10
- * - Installation list → Config file JSON via store.ts (metadata)
11
- * - Installation token → Memory cache (short-lived, 1 hour)
12
- */
13
- /** @deprecated Use UserCredentials instead */
14
- export interface Credentials {
15
- token: string;
16
- user: string;
17
- }
18
- export interface UserCredentials {
19
- token: string;
20
- userName: string;
21
- }
22
- export interface InstallationTokenCache {
23
- installationId: number;
24
- token: string;
25
- expiresAt: Date;
26
- }
27
- /**
28
- * Check if the system keychain is available and working.
29
- */
30
- export declare function isKeychainAvailable(): Promise<boolean>;
31
- /**
32
- * Get stored credentials from keychain or encrypted file.
33
- */
34
- export declare function getCredentials(): Promise<Credentials | null>;
35
- /**
36
- * Store credentials in keychain or encrypted file.
37
- */
38
- export declare function setCredentials(token: string, user: string): Promise<void>;
39
- /**
40
- * Clear stored credentials from both keychain and encrypted file.
41
- */
42
- export declare function clearCredentials(): Promise<void>;
43
- /**
44
- * Store user credentials (token and username) securely.
45
- */
46
- export declare function setUserCredentials(token: string, userName: string): Promise<void>;
47
- /**
48
- * Get user credentials from secure storage.
49
- */
50
- export declare function getUserCredentials(): Promise<UserCredentials | null>;
51
- /**
52
- * Get cached installation token if it exists and is not expired.
53
- * Returns null if no valid token is cached.
54
- */
55
- export declare function getCachedInstallationToken(installationId: number): InstallationTokenCache | null;
56
- /**
57
- * Cache an installation token.
58
- */
59
- export declare function setCachedInstallationToken(cache: InstallationTokenCache): void;
60
- /**
61
- * Clear all cached installation tokens.
62
- */
63
- export declare function clearInstallationTokenCache(): void;
64
- /**
65
- * Clear all credentials: user token, and installation token cache.
66
- * Note: Installation list and default installation are cleared via store.ts
67
- */
68
- export declare function clearAllCredentials(): Promise<void>;
69
- //# sourceMappingURL=credentials.d.ts.map
@@ -1,216 +0,0 @@
1
- /**
2
- * Secure credential storage service.
3
- *
4
- * Stores OAuth tokens securely using:
5
- * 1. System keychain (preferred) - macOS Keychain, Windows Credential Manager, Linux libsecret
6
- * 2. Encrypted file fallback - when keychain is unavailable
7
- *
8
- * Storage strategy:
9
- * - User token → Keychain/encrypted file (sensitive)
10
- * - Installation list → Config file JSON via store.ts (metadata)
11
- * - Installation token → Memory cache (short-lived, 1 hour)
12
- */
13
- import crypto from "crypto";
14
- import fs from "fs/promises";
15
- import os from "os";
16
- import path from "path";
17
- import keytar from "keytar";
18
- import { dataPath } from "./paths.js";
19
- const SERVICE_NAME = "skilluse";
20
- const CREDENTIALS_FILE = "credentials.enc";
21
- // In-memory cache for short-lived installation tokens
22
- const installationTokenCache = new Map();
23
- // Cache keychain availability to avoid repeated checks
24
- let keychainAvailable = null;
25
- /**
26
- * Check if the system keychain is available and working.
27
- */
28
- export async function isKeychainAvailable() {
29
- if (keychainAvailable !== null) {
30
- return keychainAvailable;
31
- }
32
- try {
33
- // Try a test operation to see if keychain is working
34
- const testKey = "__keychain_test__";
35
- await keytar.setPassword(SERVICE_NAME, testKey, "test");
36
- await keytar.deletePassword(SERVICE_NAME, testKey);
37
- keychainAvailable = true;
38
- }
39
- catch {
40
- keychainAvailable = false;
41
- }
42
- return keychainAvailable;
43
- }
44
- /**
45
- * Get stored credentials from keychain or encrypted file.
46
- */
47
- export async function getCredentials() {
48
- if (await isKeychainAvailable()) {
49
- return getCredentialsFromKeychain();
50
- }
51
- return getCredentialsFromFile();
52
- }
53
- /**
54
- * Store credentials in keychain or encrypted file.
55
- */
56
- export async function setCredentials(token, user) {
57
- if (await isKeychainAvailable()) {
58
- await setCredentialsToKeychain(token, user);
59
- }
60
- else {
61
- await setCredentialsToFile(token, user);
62
- }
63
- }
64
- /**
65
- * Clear stored credentials from both keychain and encrypted file.
66
- */
67
- export async function clearCredentials() {
68
- // Clear from keychain
69
- try {
70
- await keytar.deletePassword(SERVICE_NAME, "github-token");
71
- await keytar.deletePassword(SERVICE_NAME, "github-user");
72
- }
73
- catch {
74
- // Ignore keychain errors
75
- }
76
- // Clear encrypted file
77
- try {
78
- const filePath = path.join(dataPath, CREDENTIALS_FILE);
79
- await fs.unlink(filePath);
80
- }
81
- catch {
82
- // Ignore file errors (file may not exist)
83
- }
84
- }
85
- // --- Keychain operations ---
86
- async function getCredentialsFromKeychain() {
87
- try {
88
- const token = await keytar.getPassword(SERVICE_NAME, "github-token");
89
- const user = await keytar.getPassword(SERVICE_NAME, "github-user");
90
- if (token && user) {
91
- return { token, user };
92
- }
93
- return null;
94
- }
95
- catch {
96
- return null;
97
- }
98
- }
99
- async function setCredentialsToKeychain(token, user) {
100
- await keytar.setPassword(SERVICE_NAME, "github-token", token);
101
- await keytar.setPassword(SERVICE_NAME, "github-user", user);
102
- }
103
- // --- Encrypted file operations ---
104
- /**
105
- * Derive an encryption key from machine-specific information.
106
- * This provides basic protection against copying the file to another machine.
107
- */
108
- function deriveKey() {
109
- const machineInfo = `${os.hostname()}:${os.userInfo().username}:${SERVICE_NAME}`;
110
- return crypto.scryptSync(machineInfo, "skilluse-salt", 32);
111
- }
112
- function encrypt(data) {
113
- const key = deriveKey();
114
- const iv = crypto.randomBytes(16);
115
- const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
116
- let encrypted = cipher.update(data, "utf8", "hex");
117
- encrypted += cipher.final("hex");
118
- const authTag = cipher.getAuthTag();
119
- // Format: iv:authTag:encryptedData
120
- return `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted}`;
121
- }
122
- function decrypt(encryptedData) {
123
- const [ivHex, authTagHex, encrypted] = encryptedData.split(":");
124
- const key = deriveKey();
125
- const iv = Buffer.from(ivHex, "hex");
126
- const authTag = Buffer.from(authTagHex, "hex");
127
- const decipher = crypto.createDecipheriv("aes-256-gcm", key, iv);
128
- decipher.setAuthTag(authTag);
129
- let decrypted = decipher.update(encrypted, "hex", "utf8");
130
- decrypted += decipher.final("utf8");
131
- return decrypted;
132
- }
133
- async function getCredentialsFromFile() {
134
- try {
135
- const filePath = path.join(dataPath, CREDENTIALS_FILE);
136
- const encryptedData = await fs.readFile(filePath, "utf8");
137
- const decrypted = decrypt(encryptedData);
138
- return JSON.parse(decrypted);
139
- }
140
- catch {
141
- return null;
142
- }
143
- }
144
- async function setCredentialsToFile(token, user) {
145
- const credentials = { token, user };
146
- const encrypted = encrypt(JSON.stringify(credentials));
147
- // Ensure data directory exists
148
- await fs.mkdir(dataPath, { recursive: true });
149
- const filePath = path.join(dataPath, CREDENTIALS_FILE);
150
- await fs.writeFile(filePath, encrypted, { mode: 0o600 }); // Owner read/write only
151
- }
152
- // ============================================================================
153
- // New GitHub App Credential Functions
154
- // ============================================================================
155
- /**
156
- * Store user credentials (token and username) securely.
157
- */
158
- export async function setUserCredentials(token, userName) {
159
- // Reuse existing implementation with new interface
160
- await setCredentials(token, userName);
161
- }
162
- /**
163
- * Get user credentials from secure storage.
164
- */
165
- export async function getUserCredentials() {
166
- const creds = await getCredentials();
167
- if (!creds)
168
- return null;
169
- return {
170
- token: creds.token,
171
- userName: creds.user,
172
- };
173
- }
174
- // ============================================================================
175
- // Installation Token Cache (in-memory, short-lived)
176
- // ============================================================================
177
- /**
178
- * Get cached installation token if it exists and is not expired.
179
- * Returns null if no valid token is cached.
180
- */
181
- export function getCachedInstallationToken(installationId) {
182
- const cached = installationTokenCache.get(installationId);
183
- if (!cached)
184
- return null;
185
- // Check if token is expired (with 5 minute buffer for safety)
186
- const bufferMs = 5 * 60 * 1000;
187
- if (new Date(cached.expiresAt).getTime() - bufferMs < Date.now()) {
188
- // Token is expired or about to expire, remove it
189
- installationTokenCache.delete(installationId);
190
- return null;
191
- }
192
- return cached;
193
- }
194
- /**
195
- * Cache an installation token.
196
- */
197
- export function setCachedInstallationToken(cache) {
198
- installationTokenCache.set(cache.installationId, cache);
199
- }
200
- /**
201
- * Clear all cached installation tokens.
202
- */
203
- export function clearInstallationTokenCache() {
204
- installationTokenCache.clear();
205
- }
206
- /**
207
- * Clear all credentials: user token, and installation token cache.
208
- * Note: Installation list and default installation are cleared via store.ts
209
- */
210
- export async function clearAllCredentials() {
211
- // Clear user credentials
212
- await clearCredentials();
213
- // Clear installation token cache
214
- clearInstallationTokenCache();
215
- }
216
- //# sourceMappingURL=credentials.js.map
@@ -1,6 +0,0 @@
1
- export { requestDeviceCode, pollForAccessToken, pollUntilComplete, openBrowser, sleep, getUserInstallations, getInstallationRepositories, getInstallationToken, type DeviceCodeResponse, type AccessTokenResponse, type OAuthError, type PollResult, type Installation, type Repository, type InstallationToken, } from "./oauth.js";
2
- export { getConfig, addRepo, removeRepo, setDefaultRepo, addInstalledSkill, removeInstalledSkill, setInstallations, getInstallations, setDefaultInstallation, getDefaultInstallation, clearInstallations, isFirstRun, type Config, type RepoConfig, type InstalledSkill, type StoredInstallation, } from "./store.js";
3
- export { configPath, dataPath, cachePath, logPath, tempPath, } from "./paths.js";
4
- export { getCredentials, setCredentials, clearCredentials, isKeychainAvailable, type Credentials, setUserCredentials, getUserCredentials, getCachedInstallationToken, setCachedInstallationToken, clearInstallationTokenCache, clearAllCredentials, type UserCredentials, type InstallationTokenCache, } from "./credentials.js";
5
- export { checkForUpdate, getCurrentVersion, type UpdateInfo, } from "./update.js";
6
- //# sourceMappingURL=index.d.ts.map
@@ -1,10 +0,0 @@
1
- export { requestDeviceCode, pollForAccessToken, pollUntilComplete, openBrowser, sleep, getUserInstallations, getInstallationRepositories, getInstallationToken, } from "./oauth.js";
2
- export { getConfig, addRepo, removeRepo, setDefaultRepo, addInstalledSkill, removeInstalledSkill, setInstallations, getInstallations, setDefaultInstallation, getDefaultInstallation, clearInstallations, isFirstRun, } from "./store.js";
3
- export { configPath, dataPath, cachePath, logPath, tempPath, } from "./paths.js";
4
- export {
5
- // Legacy (deprecated)
6
- getCredentials, setCredentials, clearCredentials, isKeychainAvailable,
7
- // New GitHub App credential functions
8
- setUserCredentials, getUserCredentials, getCachedInstallationToken, setCachedInstallationToken, clearInstallationTokenCache, clearAllCredentials, } from "./credentials.js";
9
- export { checkForUpdate, getCurrentVersion, } from "./update.js";
10
- //# sourceMappingURL=index.js.map
@@ -1,106 +0,0 @@
1
- /**
2
- * GitHub OAuth Device Flow implementation
3
- * Reference: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#device-flow
4
- */
5
- export interface Installation {
6
- id: number;
7
- account: {
8
- login: string;
9
- type: "User" | "Organization";
10
- };
11
- repository_selection: "all" | "selected";
12
- permissions: Record<string, string>;
13
- }
14
- export interface Repository {
15
- id: number;
16
- name: string;
17
- full_name: string;
18
- private: boolean;
19
- }
20
- export interface InstallationToken {
21
- token: string;
22
- expires_at: string;
23
- permissions: Record<string, string>;
24
- repositories?: Repository[];
25
- }
26
- export interface DeviceCodeResponse {
27
- device_code: string;
28
- user_code: string;
29
- verification_uri: string;
30
- expires_in: number;
31
- interval: number;
32
- }
33
- export interface AccessTokenResponse {
34
- access_token: string;
35
- token_type: string;
36
- scope: string;
37
- }
38
- export interface OAuthError {
39
- error: string;
40
- error_description?: string;
41
- }
42
- export type PollResult = {
43
- status: "success";
44
- token: AccessTokenResponse;
45
- } | {
46
- status: "pending";
47
- } | {
48
- status: "slow_down";
49
- newInterval: number;
50
- } | {
51
- status: "expired";
52
- } | {
53
- status: "access_denied";
54
- } | {
55
- status: "error";
56
- message: string;
57
- };
58
- /**
59
- * Request a device code from GitHub
60
- * This is the first step in the device flow
61
- */
62
- export declare function requestDeviceCode(clientId: string, scope?: string): Promise<DeviceCodeResponse>;
63
- /**
64
- * Poll GitHub for the access token
65
- * Returns the poll result which can be:
66
- * - success: user authorized, token received
67
- * - pending: user hasn't authorized yet
68
- * - slow_down: polling too fast, increase interval
69
- * - expired: device code expired
70
- * - access_denied: user denied authorization
71
- * - error: other error occurred
72
- */
73
- export declare function pollForAccessToken(clientId: string, deviceCode: string): Promise<PollResult>;
74
- /**
75
- * Helper to sleep for a given number of milliseconds
76
- */
77
- export declare function sleep(ms: number): Promise<void>;
78
- /**
79
- * Poll for access token with automatic retry
80
- * This handles the full polling loop until success, timeout, or error
81
- */
82
- export declare function pollUntilComplete(clientId: string, deviceCode: string, expiresIn: number, initialInterval: number, onPoll?: (attempt: number) => void): Promise<{
83
- success: true;
84
- token: AccessTokenResponse;
85
- } | {
86
- success: false;
87
- reason: "expired" | "denied" | "error";
88
- message?: string;
89
- }>;
90
- /**
91
- * Open URL in the default browser
92
- */
93
- export declare function openBrowser(url: string): Promise<void>;
94
- /**
95
- * Get all GitHub App installations for the authenticated user
96
- */
97
- export declare function getUserInstallations(userToken: string): Promise<Installation[]>;
98
- /**
99
- * Get repositories accessible by a specific installation
100
- */
101
- export declare function getInstallationRepositories(userToken: string, installationId: number): Promise<Repository[]>;
102
- /**
103
- * Get an installation access token for API operations
104
- */
105
- export declare function getInstallationToken(userToken: string, installationId: number): Promise<InstallationToken>;
106
- //# sourceMappingURL=oauth.d.ts.map