reskill 1.11.2 → 1.12.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.
- package/README.md +4 -1
- package/dist/cli/commands/login.d.ts +15 -2
- package/dist/cli/commands/login.d.ts.map +1 -1
- package/dist/cli/index.js +128 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -208,9 +208,12 @@ Skills are installed to `.skills/` by default and can be integrated with any age
|
|
|
208
208
|
Publish your skills to the registry for others to use:
|
|
209
209
|
|
|
210
210
|
```bash
|
|
211
|
-
#
|
|
211
|
+
# Interactive login (recommended for humans — guides you through token setup)
|
|
212
212
|
reskill login
|
|
213
213
|
|
|
214
|
+
# Non-interactive login (for CI/CD — pass token directly)
|
|
215
|
+
reskill login --token <your-token>
|
|
216
|
+
|
|
214
217
|
# Validate without publishing (dry run)
|
|
215
218
|
reskill publish --dry-run
|
|
216
219
|
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* login command - Authenticate with a reskill registry
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Supports two modes:
|
|
5
|
+
* 1. Interactive: prompts user to paste token (default when no --token flag)
|
|
6
|
+
* 2. Non-interactive: uses --token flag directly (for CI/CD)
|
|
7
|
+
*
|
|
8
|
+
* Tokens are stored in ~/.reskillrc per registry.
|
|
6
9
|
*/
|
|
7
10
|
import { Command } from 'commander';
|
|
11
|
+
/**
|
|
12
|
+
* Build the token settings page URL for a registry
|
|
13
|
+
*/
|
|
14
|
+
export declare function getTokenPageUrl(registry: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Prompt user to paste their access token interactively.
|
|
17
|
+
* Shows a fixed-length mask on input for visual feedback without revealing token length.
|
|
18
|
+
* Retries on empty input, returns null only on explicit cancel (Ctrl+C).
|
|
19
|
+
*/
|
|
20
|
+
export declare function promptForToken(registry: string): Promise<string | null>;
|
|
8
21
|
export declare const loginCommand: Command;
|
|
9
22
|
export default loginCommand;
|
|
10
23
|
//# sourceMappingURL=login.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/login.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/login.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGxD;AAiGD;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA6B7E;AA4ED,eAAO,MAAM,YAAY,SAOH,CAAC;AAEvB,eAAe,YAAY,CAAC"}
|
package/dist/cli/index.js
CHANGED
|
@@ -6899,32 +6899,146 @@ class AuthManager {
|
|
|
6899
6899
|
/**
|
|
6900
6900
|
* login command - Authenticate with a reskill registry
|
|
6901
6901
|
*
|
|
6902
|
-
*
|
|
6903
|
-
*
|
|
6902
|
+
* Supports two modes:
|
|
6903
|
+
* 1. Interactive: prompts user to paste token (default when no --token flag)
|
|
6904
|
+
* 2. Non-interactive: uses --token flag directly (for CI/CD)
|
|
6905
|
+
*
|
|
6906
|
+
* Tokens are stored in ~/.reskillrc per registry.
|
|
6904
6907
|
*/ // ============================================================================
|
|
6908
|
+
// Helpers
|
|
6909
|
+
// ============================================================================
|
|
6910
|
+
/**
|
|
6911
|
+
* Build the token settings page URL for a registry
|
|
6912
|
+
*/ function getTokenPageUrl(registry) {
|
|
6913
|
+
const base = registry.endsWith('/') ? registry.slice(0, -1) : registry;
|
|
6914
|
+
return `${base}/skills/tokens`;
|
|
6915
|
+
}
|
|
6916
|
+
const MASK = '••••••••';
|
|
6917
|
+
const CANCELLED = Symbol('cancelled');
|
|
6918
|
+
/**
|
|
6919
|
+
* Erase N characters behind the cursor and clear to end of line.
|
|
6920
|
+
*/ function eraseChars(count) {
|
|
6921
|
+
process.stdout.write(`\x1b[${count}D\x1b[0K`);
|
|
6922
|
+
}
|
|
6923
|
+
/**
|
|
6924
|
+
* Read a line from piped stdin (non-TTY).
|
|
6925
|
+
*/ function readFromPipe() {
|
|
6926
|
+
return new Promise((resolve, reject)=>{
|
|
6927
|
+
const chunks = [];
|
|
6928
|
+
const onData = (chunk)=>chunks.push(chunk);
|
|
6929
|
+
const onEnd = ()=>{
|
|
6930
|
+
cleanup();
|
|
6931
|
+
const value = Buffer.concat(chunks).toString().trim();
|
|
6932
|
+
resolve(value || null);
|
|
6933
|
+
};
|
|
6934
|
+
const onError = (err)=>{
|
|
6935
|
+
cleanup();
|
|
6936
|
+
reject(err);
|
|
6937
|
+
};
|
|
6938
|
+
const cleanup = ()=>{
|
|
6939
|
+
process.stdin.removeListener('data', onData);
|
|
6940
|
+
process.stdin.removeListener('end', onEnd);
|
|
6941
|
+
process.stdin.removeListener('error', onError);
|
|
6942
|
+
};
|
|
6943
|
+
process.stdin.on('data', onData);
|
|
6944
|
+
process.stdin.on('end', onEnd);
|
|
6945
|
+
process.stdin.on('error', onError);
|
|
6946
|
+
process.stdin.resume();
|
|
6947
|
+
});
|
|
6948
|
+
}
|
|
6949
|
+
/**
|
|
6950
|
+
* Read token from TTY stdin in raw mode with fixed-length mask feedback.
|
|
6951
|
+
*
|
|
6952
|
+
* Returns:
|
|
6953
|
+
* - token string on valid input + Enter
|
|
6954
|
+
* - empty string on empty Enter (no input)
|
|
6955
|
+
* - CANCELLED symbol on Ctrl+C
|
|
6956
|
+
*/ function readFromTTY() {
|
|
6957
|
+
return new Promise((resolve)=>{
|
|
6958
|
+
let input = '';
|
|
6959
|
+
let masked = false;
|
|
6960
|
+
process.stdin.setRawMode(true);
|
|
6961
|
+
process.stdin.resume();
|
|
6962
|
+
process.stdin.setEncoding('utf8');
|
|
6963
|
+
const finish = (value)=>{
|
|
6964
|
+
process.stdin.setRawMode(false);
|
|
6965
|
+
process.stdin.pause();
|
|
6966
|
+
process.stdin.removeAllListeners('data');
|
|
6967
|
+
process.stdout.write('\n');
|
|
6968
|
+
resolve(value);
|
|
6969
|
+
};
|
|
6970
|
+
process.stdin.on('data', (data)=>{
|
|
6971
|
+
for (const ch of data){
|
|
6972
|
+
if ('\r' === ch || '\n' === ch) return finish(input.trim());
|
|
6973
|
+
if ('\x03' === ch) return finish(CANCELLED);
|
|
6974
|
+
if ('\x7f' === ch || '\b' === ch) {
|
|
6975
|
+
// Fixed-length mask can't represent per-char deletion — clear all to let user retry
|
|
6976
|
+
if (input.length > 0) {
|
|
6977
|
+
input = '';
|
|
6978
|
+
if (masked) {
|
|
6979
|
+
eraseChars(MASK.length);
|
|
6980
|
+
masked = false;
|
|
6981
|
+
}
|
|
6982
|
+
}
|
|
6983
|
+
continue;
|
|
6984
|
+
}
|
|
6985
|
+
if (ch >= ' ') {
|
|
6986
|
+
input += ch;
|
|
6987
|
+
if (!masked) {
|
|
6988
|
+
process.stdout.write(MASK);
|
|
6989
|
+
masked = true;
|
|
6990
|
+
}
|
|
6991
|
+
}
|
|
6992
|
+
}
|
|
6993
|
+
});
|
|
6994
|
+
});
|
|
6995
|
+
}
|
|
6996
|
+
/**
|
|
6997
|
+
* Prompt user to paste their access token interactively.
|
|
6998
|
+
* Shows a fixed-length mask on input for visual feedback without revealing token length.
|
|
6999
|
+
* Retries on empty input, returns null only on explicit cancel (Ctrl+C).
|
|
7000
|
+
*/ async function promptForToken(registry) {
|
|
7001
|
+
const tokenPageUrl = getTokenPageUrl(registry);
|
|
7002
|
+
logger_logger.newline();
|
|
7003
|
+
logger_logger.log(` Registry: ${registry}`);
|
|
7004
|
+
logger_logger.newline();
|
|
7005
|
+
logger_logger.log(' To get your access token:');
|
|
7006
|
+
logger_logger.log(` 1. Open ${tokenPageUrl}`);
|
|
7007
|
+
logger_logger.log(' 2. Login and generate an API token');
|
|
7008
|
+
logger_logger.log(' 3. Copy the token and paste it below');
|
|
7009
|
+
logger_logger.newline();
|
|
7010
|
+
if (!process.stdin.isTTY) return readFromPipe();
|
|
7011
|
+
while(true){
|
|
7012
|
+
process.stdout.write(' Paste your access token: ');
|
|
7013
|
+
const result = await readFromTTY();
|
|
7014
|
+
if (result === CANCELLED) return null;
|
|
7015
|
+
if (result.length > 0) return result;
|
|
7016
|
+
logger_logger.warn(' Token cannot be empty. Please try again.');
|
|
7017
|
+
}
|
|
7018
|
+
}
|
|
7019
|
+
// ============================================================================
|
|
6905
7020
|
// Main Action
|
|
6906
7021
|
// ============================================================================
|
|
6907
7022
|
async function loginAction(options) {
|
|
6908
7023
|
const registry = resolveRegistry(options.registry);
|
|
6909
7024
|
const authManager = new AuthManager();
|
|
6910
|
-
|
|
6911
|
-
if (
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
7025
|
+
let token;
|
|
7026
|
+
if (options.token) token = options.token;
|
|
7027
|
+
else {
|
|
7028
|
+
const prompted = await promptForToken(registry);
|
|
7029
|
+
if (!prompted) {
|
|
7030
|
+
logger_logger.warn('Login cancelled');
|
|
7031
|
+
process.exit(0);
|
|
7032
|
+
}
|
|
7033
|
+
token = prompted;
|
|
6919
7034
|
}
|
|
6920
|
-
await loginWithToken(
|
|
7035
|
+
await loginWithToken(token, registry, authManager);
|
|
6921
7036
|
}
|
|
6922
7037
|
/**
|
|
6923
7038
|
* Login with a pre-generated token from Web UI
|
|
6924
7039
|
*/ async function loginWithToken(token, registry, authManager) {
|
|
6925
7040
|
logger_logger.log(`Verifying token with ${registry}...`);
|
|
6926
7041
|
logger_logger.newline();
|
|
6927
|
-
// Verify token by calling login-cli endpoint
|
|
6928
7042
|
const client = new RegistryClient({
|
|
6929
7043
|
registry,
|
|
6930
7044
|
token
|
|
@@ -6935,7 +7049,6 @@ async function loginAction(options) {
|
|
|
6935
7049
|
logger_logger.error(response.error || 'Token verification failed');
|
|
6936
7050
|
process.exit(1);
|
|
6937
7051
|
}
|
|
6938
|
-
// Save token with handle and email
|
|
6939
7052
|
authManager.setToken(token, registry, response.user.email, response.user.handle);
|
|
6940
7053
|
logger_logger.log('✓ Token verified and saved!');
|
|
6941
7054
|
logger_logger.newline();
|
|
@@ -6956,7 +7069,7 @@ async function loginAction(options) {
|
|
|
6956
7069
|
// ============================================================================
|
|
6957
7070
|
// Command Definition
|
|
6958
7071
|
// ============================================================================
|
|
6959
|
-
const loginCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('login').description('Authenticate with a reskill registry').option('-r, --registry <url>', 'Registry URL (or set RESKILL_REGISTRY env var, or defaults.publishRegistry in skills.json)').option('-t, --token <token>', 'API token from Web UI (
|
|
7072
|
+
const loginCommand = new __WEBPACK_EXTERNAL_MODULE_commander__.Command('login').description('Authenticate with a reskill registry').option('-r, --registry <url>', 'Registry URL (or set RESKILL_REGISTRY env var, or defaults.publishRegistry in skills.json)').option('-t, --token <token>', 'API token from Web UI (skips interactive prompt)').action(loginAction);
|
|
6960
7073
|
/**
|
|
6961
7074
|
* logout command - Log out from a reskill registry
|
|
6962
7075
|
*
|