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 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
- # Login to the registry
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
- * Token-only login: requires a pre-generated token from Web UI.
5
- * Logs in to the registry and stores the token in ~/.reskillrc
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;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyFpC,eAAO,MAAM,YAAY,SAOH,CAAC;AAEvB,eAAe,YAAY,CAAC"}
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
- * Token-only login: requires a pre-generated token from Web UI.
6903
- * Logs in to the registry and stores the token in ~/.reskillrc
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
- // Token is required (no email/password login)
6911
- if (!options.token) {
6912
- logger_logger.error('Token is required');
6913
- logger_logger.newline();
6914
- logger_logger.log('To get a token:');
6915
- logger_logger.log(' 1. Visit the Registry Web UI');
6916
- logger_logger.log(' 2. Login and generate an API token');
6917
- logger_logger.log(' 3. Run: reskill login --registry <url> --token <token>');
6918
- process.exit(1);
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(options.token, registry, authManager);
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 (required)').action(loginAction);
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
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reskill",
3
- "version": "1.11.2",
3
+ "version": "1.12.0",
4
4
  "description": "AI Skills Package Manager - Git-based skills management for AI agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",