skedyul 0.2.137 → 0.2.139

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 (40) hide show
  1. package/README.md +335 -0
  2. package/dist/.build-stamp +1 -1
  3. package/dist/cli/commands/auth/index.d.ts +1 -0
  4. package/dist/cli/commands/auth/index.js +83 -0
  5. package/dist/cli/commands/auth/login.d.ts +1 -0
  6. package/dist/cli/commands/auth/login.js +65 -0
  7. package/dist/cli/commands/auth/logout.d.ts +1 -0
  8. package/dist/cli/commands/auth/logout.js +33 -0
  9. package/dist/cli/commands/auth/status.d.ts +1 -0
  10. package/dist/cli/commands/auth/status.js +118 -0
  11. package/dist/cli/commands/config.d.ts +12 -0
  12. package/dist/cli/commands/config.js +129 -0
  13. package/dist/cli/commands/install.d.ts +1 -0
  14. package/dist/cli/commands/install.js +122 -0
  15. package/dist/cli/commands/invoke.js +128 -31
  16. package/dist/cli/commands/link.d.ts +1 -0
  17. package/dist/cli/commands/link.js +118 -0
  18. package/dist/cli/commands/serve.js +550 -33
  19. package/dist/cli/commands/unlink.d.ts +1 -0
  20. package/dist/cli/commands/unlink.js +52 -0
  21. package/dist/cli/index.js +150 -31
  22. package/dist/cli/utils/auth.d.ts +55 -0
  23. package/dist/cli/utils/auth.js +342 -0
  24. package/dist/cli/utils/config.d.ts +31 -0
  25. package/dist/cli/utils/config.js +347 -0
  26. package/dist/cli/utils/index.d.ts +6 -0
  27. package/dist/cli/utils/index.js +37 -0
  28. package/dist/cli/utils/link.d.ts +19 -0
  29. package/dist/cli/utils/link.js +179 -0
  30. package/dist/cli/utils/prompt.d.ts +32 -0
  31. package/dist/cli/utils/prompt.js +142 -0
  32. package/dist/cli/utils/tunnel.d.ts +22 -0
  33. package/dist/cli/utils/tunnel.js +120 -0
  34. package/dist/cli/utils.js +53 -5
  35. package/dist/index.d.ts +1 -0
  36. package/dist/index.js +3 -1
  37. package/dist/server.js +12 -1
  38. package/dist/types.d.ts +18 -3
  39. package/dist/types.js +17 -0
  40. package/package.json +4 -1
package/README.md CHANGED
@@ -240,6 +240,341 @@ Both adapters expose `getHealthStatus()`, returning:
240
240
  - `runtime`: string label (`dedicated` or `serverless`).
241
241
  - `tools`: list of registered tool names.
242
242
 
243
+ ---
244
+
245
+ # Skedyul CLI
246
+
247
+ The Skedyul CLI (`skedyul`) is a powerful command-line interface for developing, testing, and debugging Skedyul integration apps locally.
248
+
249
+ ## Quick Start
250
+
251
+ ```bash
252
+ # 1. Authenticate with Skedyul
253
+ skedyul auth login
254
+
255
+ # 2. Navigate to your app directory
256
+ cd packages/skedyul-integrations/integrations/my-app
257
+
258
+ # 3. Link to a workplace
259
+ skedyul dev link --workplace my-clinic
260
+
261
+ # 4. Start the local development server
262
+ skedyul dev serve --workplace my-clinic
263
+ ```
264
+
265
+ That's it! The CLI will:
266
+ - Prompt for any missing environment variables (API keys, credentials)
267
+ - Start an ngrok tunnel automatically
268
+ - Register your local machine with Skedyul
269
+ - Route tool calls from Skedyul to your local server
270
+
271
+ ## Installation
272
+
273
+ The CLI is included with the `skedyul` package:
274
+
275
+ ```bash
276
+ npm install skedyul
277
+ # or
278
+ pnpm add skedyul
279
+ ```
280
+
281
+ Run commands with `npx skedyul` or install globally:
282
+
283
+ ```bash
284
+ npm link # In the skedyul-node package directory
285
+ skedyul --help
286
+ ```
287
+
288
+ ## Commands
289
+
290
+ ### Authentication
291
+
292
+ ```bash
293
+ # Log in via browser OAuth
294
+ skedyul auth login
295
+
296
+ # Check authentication status
297
+ skedyul auth status
298
+
299
+ # Log out
300
+ skedyul auth logout
301
+ ```
302
+
303
+ ### Configuration
304
+
305
+ ```bash
306
+ # Set global configuration
307
+ skedyul config set <key> <value>
308
+
309
+ # Get a config value
310
+ skedyul config get <key>
311
+
312
+ # List all configuration
313
+ skedyul config list
314
+ ```
315
+
316
+ **Available config keys:**
317
+
318
+ | Key | Description | Default |
319
+ |-----|-------------|---------|
320
+ | `defaultServer` | Skedyul server URL | `https://admin.skedyul.it` |
321
+ | `ngrokAuthtoken` | Your ngrok authtoken for tunneling | - |
322
+
323
+ ### Development Commands
324
+
325
+ #### `skedyul dev link`
326
+
327
+ Links your local app to a Skedyul workplace. This creates a personal `local-{username}` AppVersion for testing.
328
+
329
+ ```bash
330
+ skedyul dev link --workplace <subdomain>
331
+
332
+ # Example
333
+ skedyul dev link --workplace demo-clinic
334
+ ```
335
+
336
+ **What it does:**
337
+ - Creates (or finds) a `local-{username}` AppVersion in the target workplace
338
+ - Creates an AppInstallation for your app in that workplace
339
+ - Saves link configuration to `.skedyul/links/{subdomain}.json`
340
+
341
+ #### `skedyul dev unlink`
342
+
343
+ Removes a workplace link.
344
+
345
+ ```bash
346
+ skedyul dev unlink --workplace <subdomain>
347
+ ```
348
+
349
+ #### `skedyul dev serve`
350
+
351
+ Starts a local MCP server for testing your tools.
352
+
353
+ ```bash
354
+ # Standalone mode (no Skedyul connection)
355
+ skedyul dev serve
356
+
357
+ # Connected to Skedyul (sidecar mode)
358
+ skedyul dev serve --workplace <subdomain>
359
+ ```
360
+
361
+ **Options:**
362
+
363
+ | Flag | Description |
364
+ |------|-------------|
365
+ | `--workplace, -w` | Workplace subdomain (enables sidecar mode) |
366
+ | `--port, -p` | Port to listen on (default: 60000, auto-increments if busy) |
367
+ | `--registry, -r` | Path to registry file (auto-detected) |
368
+ | `--no-tunnel` | Don't start ngrok tunnel |
369
+ | `--tunnel-url` | Use existing tunnel URL |
370
+ | `--env, -e` | Set environment variable (e.g., `--env KEY=VALUE`) |
371
+ | `--env-file` | Load env vars from file |
372
+
373
+ **Sidecar Mode:**
374
+
375
+ When you specify `--workplace`, the CLI:
376
+ 1. Loads your link configuration
377
+ 2. Prompts for any missing required environment variables
378
+ 3. Starts an ngrok tunnel (or uses `--tunnel-url`)
379
+ 4. Registers the tunnel URL with Skedyul
380
+ 5. Sends heartbeats to keep the connection alive
381
+ 6. Routes incoming tool calls to your local server
382
+
383
+ ```bash
384
+ # Full example with custom port
385
+ skedyul dev serve --workplace demo-clinic --port 8080
386
+
387
+ # Use existing ngrok tunnel
388
+ skedyul dev serve --workplace demo-clinic --tunnel-url https://abc123.ngrok.io
389
+ ```
390
+
391
+ #### `skedyul dev invoke`
392
+
393
+ Invoke a single tool for quick testing.
394
+
395
+ ```bash
396
+ skedyul dev invoke <tool-name> [options]
397
+
398
+ # Examples
399
+ skedyul dev invoke appointment_types_list
400
+ skedyul dev invoke clients_search --args '{"phone": "+1234567890"}'
401
+
402
+ # With linked credentials
403
+ skedyul dev invoke appointment_types_list --workplace demo-clinic
404
+ ```
405
+
406
+ #### `skedyul dev tools`
407
+
408
+ List all tools in your registry.
409
+
410
+ ```bash
411
+ skedyul dev tools
412
+ skedyul dev tools --registry ./dist/registry.js
413
+ ```
414
+
415
+ #### `skedyul dev validate`
416
+
417
+ Validate your `skedyul.config.ts` file.
418
+
419
+ ```bash
420
+ skedyul dev validate
421
+ ```
422
+
423
+ #### `skedyul dev diff`
424
+
425
+ Preview what would change on deploy.
426
+
427
+ ```bash
428
+ skedyul dev diff
429
+ ```
430
+
431
+ ## Configuration Files
432
+
433
+ The CLI uses several configuration files:
434
+
435
+ | File | Purpose |
436
+ |------|---------|
437
+ | `~/.skedyul/credentials.json` | Authentication tokens |
438
+ | `~/.skedyul/config.json` | Global configuration (server URL, ngrok token) |
439
+ | `.skedyul.local.json` | Local project overrides (e.g., local server URL) |
440
+ | `.skedyul/links/{workplace}.json` | Per-workplace link configuration |
441
+ | `.skedyul/env/{workplace}.env` | Per-workplace environment variables |
442
+
443
+ ### Local Development Override
444
+
445
+ To use a local Skedyul server during development, create `.skedyul.local.json` in your project root:
446
+
447
+ ```json
448
+ {
449
+ "serverUrl": "http://localhost:3000"
450
+ }
451
+ ```
452
+
453
+ ## Environment Variables
454
+
455
+ ### Install Configuration
456
+
457
+ Define required environment variables in your app's `config/install.config.ts`:
458
+
459
+ ```typescript
460
+ import type { InstallConfig } from 'skedyul'
461
+
462
+ const config: InstallConfig = {
463
+ env: {
464
+ API_KEY: {
465
+ label: 'API Key',
466
+ required: true,
467
+ visibility: 'encrypted',
468
+ description: 'Your API key for authentication',
469
+ },
470
+ BASE_URL: {
471
+ label: 'Server URL',
472
+ required: true,
473
+ visibility: 'visible',
474
+ placeholder: 'https://api.example.com',
475
+ description: 'Base URL for the API',
476
+ },
477
+ },
478
+ }
479
+
480
+ export default config
481
+ ```
482
+
483
+ The CLI will automatically prompt for these when you run `skedyul dev serve --workplace <name>` if they're not already configured.
484
+
485
+ ### Visibility Options
486
+
487
+ | Visibility | Behavior |
488
+ |------------|----------|
489
+ | `visible` | Shown in plain text |
490
+ | `encrypted` | Hidden during input, masked in output |
491
+
492
+ ## Ngrok Integration
493
+
494
+ The CLI uses ngrok to create public tunnels to your local server, allowing Skedyul to route requests to your machine.
495
+
496
+ ### Setup
497
+
498
+ 1. Get a free authtoken at [ngrok.com](https://dashboard.ngrok.com/get-started/your-authtoken)
499
+ 2. The CLI will prompt for it on first use, or set it manually:
500
+
501
+ ```bash
502
+ skedyul config set ngrokAuthtoken <your-token>
503
+ ```
504
+
505
+ ### Session Limits
506
+
507
+ ngrok's free tier allows 1 simultaneous session. If you see an error:
508
+
509
+ ```
510
+ ngrok free tier only allows 1 simultaneous session.
511
+ ```
512
+
513
+ **Solutions:**
514
+ 1. Kill other ngrok sessions: `pkill -f ngrok`
515
+ 2. Use an existing tunnel: `skedyul dev serve --workplace demo --tunnel-url https://existing.ngrok.io`
516
+ 3. Upgrade to a paid ngrok plan
517
+
518
+ ## Workflow Example
519
+
520
+ ### Setting Up a New Integration
521
+
522
+ ```bash
523
+ # 1. Navigate to your app
524
+ cd integrations/my-app
525
+
526
+ # 2. Authenticate
527
+ skedyul auth login
528
+
529
+ # 3. Link to your test workplace
530
+ skedyul dev link --workplace staging-clinic
531
+
532
+ # 4. Start development server (will prompt for env vars)
533
+ skedyul dev serve --workplace staging-clinic
534
+
535
+ # Server starts...
536
+ # ✓ Loaded 12 tools from registry
537
+ # ✓ Tunnel active: https://abc123.ngrok.io
538
+ # ✓ Registered with Skedyul
539
+ # Listening on http://localhost:60000
540
+ ```
541
+
542
+ ### Testing Individual Tools
543
+
544
+ ```bash
545
+ # Quick test without full server
546
+ skedyul dev invoke appointment_types_list --workplace staging-clinic
547
+
548
+ # With arguments
549
+ skedyul dev invoke calendar_slots_availability_list \
550
+ --workplace staging-clinic \
551
+ --args '{"calendar_names": ["Room 1"], "dates": ["2024-01-15"]}'
552
+ ```
553
+
554
+ ## Troubleshooting
555
+
556
+ ### "Not linked to {workplace}"
557
+
558
+ Run `skedyul dev link --workplace {workplace}` first.
559
+
560
+ ### "Authentication required"
561
+
562
+ Run `skedyul auth login` to authenticate.
563
+
564
+ ### Port already in use
565
+
566
+ The CLI auto-increments from port 60000 if busy. Or specify: `--port 8080`
567
+
568
+ ### ngrok authentication failed
569
+
570
+ Set your authtoken: `skedyul config set ngrokAuthtoken <token>`
571
+
572
+ ### Environment variables not loading
573
+
574
+ Check that your `config/install.config.ts` exports the env configuration properly. Use `--debug` flag for verbose output.
575
+
576
+ ---
577
+
243
578
  ## Development
244
579
 
245
580
  - `npm run build` compiles the TypeScript sources into `dist/`.
package/dist/.build-stamp CHANGED
@@ -1 +1 @@
1
- 1770183335160
1
+ 1770350396098
@@ -0,0 +1 @@
1
+ export declare function authCommand(args: string[]): Promise<void>;
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.authCommand = authCommand;
4
+ const login_1 = require("./login");
5
+ const logout_1 = require("./logout");
6
+ const status_1 = require("./status");
7
+ function printUsage() {
8
+ console.log(`
9
+ SKEDYUL AUTH - Authentication Commands
10
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
11
+
12
+ Manage your Skedyul CLI authentication.
13
+
14
+ USAGE
15
+ $ skedyul auth <command> [options]
16
+
17
+ COMMANDS
18
+ login Authenticate with Skedyul via browser OAuth
19
+ logout Clear stored credentials
20
+ status Show current authentication status and linked workplaces
21
+
22
+ HOW AUTHENTICATION WORKS
23
+ 1. Run 'skedyul auth login'
24
+ 2. Browser opens to Skedyul login page
25
+ 3. After login, you're redirected back to CLI
26
+ 4. Credentials saved to ~/.skedyul/credentials.json
27
+
28
+ Your CLI token is used for:
29
+ • Linking projects to workplaces
30
+ • Getting scoped API tokens for tool testing
31
+ • Managing local development environments
32
+
33
+ EXAMPLES
34
+ # Login to production Skedyul
35
+ $ skedyul auth login
36
+
37
+ # Login to a specific server
38
+ $ skedyul auth login --server http://localhost:3000
39
+
40
+ # Check authentication status
41
+ $ skedyul auth status
42
+
43
+ # Logout and clear credentials
44
+ $ skedyul auth logout
45
+
46
+ SERVER CONFIGURATION
47
+ Default server: https://admin.skedyul.it
48
+
49
+ Override with:
50
+ • --server flag on any command
51
+ • .skedyul.local.json in project root:
52
+ { "serverUrl": "http://localhost:3000" }
53
+
54
+ CREDENTIAL STORAGE
55
+ Credentials: ~/.skedyul/credentials.json
56
+ Config: ~/.skedyul/config.json
57
+
58
+ Credentials are stored with restrictive permissions (600).
59
+ `);
60
+ }
61
+ async function authCommand(args) {
62
+ const subCommand = args[0];
63
+ if (!subCommand || subCommand === '--help' || subCommand === '-h') {
64
+ printUsage();
65
+ return;
66
+ }
67
+ const subArgs = args.slice(1);
68
+ switch (subCommand) {
69
+ case 'login':
70
+ await (0, login_1.loginCommand)(subArgs);
71
+ break;
72
+ case 'logout':
73
+ await (0, logout_1.logoutCommand)(subArgs);
74
+ break;
75
+ case 'status':
76
+ await (0, status_1.statusCommand)(subArgs);
77
+ break;
78
+ default:
79
+ console.error(`Unknown auth command: ${subCommand}`);
80
+ console.error(`Run 'skedyul auth --help' for usage information.`);
81
+ process.exit(1);
82
+ }
83
+ }
@@ -0,0 +1 @@
1
+ export declare function loginCommand(args: string[]): Promise<void>;
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loginCommand = loginCommand;
4
+ const utils_1 = require("../../utils");
5
+ const auth_1 = require("../../utils/auth");
6
+ function printHelp() {
7
+ console.log(`
8
+ skedyul auth login - Authenticate with Skedyul
9
+
10
+ Usage:
11
+ skedyul auth login [options]
12
+
13
+ Options:
14
+ --server, -s Skedyul server URL (default: https://app.skedyul.com)
15
+ --help, -h Show this help message
16
+
17
+ Examples:
18
+ # Login to production Skedyul
19
+ skedyul auth login
20
+
21
+ # Login to a local Skedyul instance
22
+ skedyul auth login --server http://localhost:3000
23
+ `);
24
+ }
25
+ async function loginCommand(args) {
26
+ const { flags } = (0, utils_1.parseArgs)(args);
27
+ if (flags.help || flags.h) {
28
+ printHelp();
29
+ return;
30
+ }
31
+ // Check if already logged in
32
+ const existingCredentials = (0, auth_1.getCredentials)();
33
+ if (existingCredentials) {
34
+ console.log(`Already logged in as ${existingCredentials.email}`);
35
+ console.log(`Server: ${existingCredentials.serverUrl}`);
36
+ console.log(`\nRun 'skedyul auth logout' to log out first.`);
37
+ return;
38
+ }
39
+ // Get server URL
40
+ const serverUrl = (0, auth_1.getServerUrl)((flags.server || flags.s));
41
+ console.log(`Authenticating with ${serverUrl}...\n`);
42
+ try {
43
+ const result = await (0, auth_1.startOAuthCallback)(serverUrl);
44
+ // Save credentials
45
+ (0, auth_1.saveCredentials)({
46
+ token: result.token,
47
+ userId: result.userId,
48
+ username: result.username,
49
+ email: result.email,
50
+ serverUrl,
51
+ expiresAt: result.expiresAt,
52
+ createdAt: new Date().toISOString(),
53
+ });
54
+ // Save server as default
55
+ (0, auth_1.saveConfig)({ defaultServer: serverUrl });
56
+ console.log(`\n✓ Logged in as ${result.email}`);
57
+ console.log(` Username: ${result.username}`);
58
+ console.log(` Server: ${serverUrl}`);
59
+ console.log(` Credentials saved to ~/.skedyul/credentials.json`);
60
+ }
61
+ catch (error) {
62
+ console.error(`\nAuthentication failed: ${error instanceof Error ? error.message : String(error)}`);
63
+ process.exit(1);
64
+ }
65
+ }
@@ -0,0 +1 @@
1
+ export declare function logoutCommand(args: string[]): Promise<void>;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logoutCommand = logoutCommand;
4
+ const utils_1 = require("../../utils");
5
+ const auth_1 = require("../../utils/auth");
6
+ function printHelp() {
7
+ console.log(`
8
+ skedyul auth logout - Log out from Skedyul
9
+
10
+ Usage:
11
+ skedyul auth logout [options]
12
+
13
+ Options:
14
+ --help, -h Show this help message
15
+
16
+ This command clears your stored credentials from ~/.skedyul/credentials.json
17
+ `);
18
+ }
19
+ async function logoutCommand(args) {
20
+ const { flags } = (0, utils_1.parseArgs)(args);
21
+ if (flags.help || flags.h) {
22
+ printHelp();
23
+ return;
24
+ }
25
+ const credentials = (0, auth_1.getCredentials)();
26
+ if (!credentials) {
27
+ console.log('Not logged in.');
28
+ return;
29
+ }
30
+ (0, auth_1.clearCredentials)();
31
+ console.log(`✓ Logged out from ${credentials.email}`);
32
+ console.log(` Credentials removed from ~/.skedyul/credentials.json`);
33
+ }
@@ -0,0 +1 @@
1
+ export declare function statusCommand(args: string[]): Promise<void>;
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.statusCommand = statusCommand;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const utils_1 = require("../../utils");
40
+ const auth_1 = require("../../utils/auth");
41
+ function printHelp() {
42
+ console.log(`
43
+ skedyul auth status - Show authentication status
44
+
45
+ Usage:
46
+ skedyul auth status [options]
47
+
48
+ Options:
49
+ --help, -h Show this help message
50
+
51
+ Shows:
52
+ - Current logged in user
53
+ - Server URL
54
+ - Token expiration
55
+ - Linked workplaces (from .skedyul/links/)
56
+ `);
57
+ }
58
+ async function statusCommand(args) {
59
+ const { flags } = (0, utils_1.parseArgs)(args);
60
+ if (flags.help || flags.h) {
61
+ printHelp();
62
+ return;
63
+ }
64
+ const credentials = (0, auth_1.getCredentials)();
65
+ console.log('Skedyul CLI Status');
66
+ console.log('─'.repeat(40));
67
+ if (!credentials) {
68
+ console.log('\nAuthentication: Not logged in');
69
+ console.log(`\nRun 'skedyul auth login' to authenticate.`);
70
+ return;
71
+ }
72
+ console.log('\nAuthentication:');
73
+ console.log(` Email: ${credentials.email}`);
74
+ console.log(` Username: ${credentials.username}`);
75
+ console.log(` Server: ${credentials.serverUrl}`);
76
+ if (credentials.expiresAt) {
77
+ const expiresAt = new Date(credentials.expiresAt);
78
+ const now = new Date();
79
+ if (expiresAt < now) {
80
+ console.log(` Token: Expired`);
81
+ }
82
+ else {
83
+ const diffMs = expiresAt.getTime() - now.getTime();
84
+ const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
85
+ const diffHours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
86
+ console.log(` Token: Valid (expires in ${diffDays}d ${diffHours}h)`);
87
+ }
88
+ }
89
+ else {
90
+ console.log(` Token: Valid (no expiration)`);
91
+ }
92
+ // Check for linked workplaces in current project
93
+ const linksDir = path.join(process.cwd(), '.skedyul', 'links');
94
+ if (fs.existsSync(linksDir)) {
95
+ const linkFiles = fs.readdirSync(linksDir).filter((f) => f.endsWith('.json'));
96
+ if (linkFiles.length > 0) {
97
+ console.log('\nLinked Workplaces (this project):');
98
+ for (const file of linkFiles) {
99
+ const subdomain = file.replace('.json', '');
100
+ try {
101
+ const content = fs.readFileSync(path.join(linksDir, file), 'utf-8');
102
+ const link = JSON.parse(content);
103
+ console.log(` - ${subdomain} (${link.appHandle})`);
104
+ }
105
+ catch {
106
+ console.log(` - ${subdomain} (error reading link file)`);
107
+ }
108
+ }
109
+ }
110
+ else {
111
+ console.log('\nNo workplaces linked in this project.');
112
+ }
113
+ }
114
+ else {
115
+ console.log('\nNo workplaces linked in this project.');
116
+ }
117
+ console.log(`\nRun 'skedyul dev link --workplace <subdomain>' to link a workplace.`);
118
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * skedyul config command
3
+ *
4
+ * Manage global CLI configuration.
5
+ *
6
+ * Usage:
7
+ * skedyul config set <key> <value> - Set a config value
8
+ * skedyul config get <key> - Get a config value
9
+ * skedyul config list - List all config values
10
+ */
11
+ export declare function configCommand(args: string[]): Promise<void>;
12
+ export { configCommand as config };