@reminix/cli 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.
- package/README.md +1 -1
- package/dist/commands/login.d.ts +6 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +65 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +6 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +15 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/version.d.ts +1 -1
- package/dist/commands/version.js +1 -1
- package/dist/commands/whoami.d.ts +6 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +21 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/auth-server.d.ts +21 -0
- package/dist/lib/auth-server.d.ts.map +1 -0
- package/dist/lib/auth-server.js +234 -0
- package/dist/lib/auth-server.js.map +1 -0
- package/dist/lib/credentials.d.ts +32 -0
- package/dist/lib/credentials.d.ts.map +1 -0
- package/dist/lib/credentials.js +86 -0
- package/dist/lib/credentials.js.map +1 -0
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBpC;;GAEG;AACH,eAAO,MAAM,YAAY,SAmDrB,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import open from 'open';
|
|
3
|
+
import { createAuthServer, generateState } from '../lib/auth-server.js';
|
|
4
|
+
import { saveCredentials, loadCredentials } from '../lib/credentials.js';
|
|
5
|
+
/**
|
|
6
|
+
* Default web app URL - can be overridden with REMINIX_WEB_URL env var
|
|
7
|
+
*/
|
|
8
|
+
const DEFAULT_WEB_URL = 'https://reminix.com';
|
|
9
|
+
/**
|
|
10
|
+
* Get the web app URL from environment or use default
|
|
11
|
+
*/
|
|
12
|
+
function getWebUrl() {
|
|
13
|
+
return process.env.REMINIX_WEB_URL || DEFAULT_WEB_URL;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Login command - authenticates user via browser
|
|
17
|
+
*/
|
|
18
|
+
export const loginCommand = new Command('login')
|
|
19
|
+
.description('Authenticate with Reminix')
|
|
20
|
+
.option('--no-browser', "Don't open browser automatically")
|
|
21
|
+
.action(async (options) => {
|
|
22
|
+
try {
|
|
23
|
+
// Check if already logged in
|
|
24
|
+
const existing = loadCredentials();
|
|
25
|
+
if (existing) {
|
|
26
|
+
console.log(`Already logged in as ${existing.email}`);
|
|
27
|
+
console.log('Run "reminix logout" first to switch accounts.');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// Generate state for CSRF protection
|
|
31
|
+
const state = generateState();
|
|
32
|
+
// Start local auth server
|
|
33
|
+
console.log('Starting authentication...');
|
|
34
|
+
const { port, waitForCallback } = await createAuthServer(state);
|
|
35
|
+
// Build auth URL
|
|
36
|
+
const webUrl = getWebUrl();
|
|
37
|
+
const authUrl = `${webUrl}/cli/authorize?port=${port}&state=${state}`;
|
|
38
|
+
// Open browser or show URL
|
|
39
|
+
if (options.browser) {
|
|
40
|
+
console.log('Opening browser to log in...\n');
|
|
41
|
+
await open(authUrl);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
console.log('Open this URL in your browser to log in:\n');
|
|
45
|
+
console.log(` ${authUrl}\n`);
|
|
46
|
+
}
|
|
47
|
+
console.log('Waiting for authentication...');
|
|
48
|
+
// Wait for callback
|
|
49
|
+
const result = await waitForCallback();
|
|
50
|
+
// Save credentials
|
|
51
|
+
saveCredentials(result.token, result.email);
|
|
52
|
+
console.log(`\n✓ Successfully logged in as ${result.email}!`);
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error instanceof Error) {
|
|
57
|
+
console.error(`\n✗ Login failed: ${error.message}`);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
console.error('\n✗ Login failed: Unknown error');
|
|
61
|
+
}
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEzE;;GAEG;AACH,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAE9C;;GAEG;AACH,SAAS,SAAS;IAChB,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,eAAe,CAAC;AACxD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,2BAA2B,CAAC;KACxC,MAAM,CAAC,cAAc,EAAE,kCAAkC,CAAC;KAC1D,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,6BAA6B;QAC7B,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;QACnC,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CAAC,wBAAwB,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;YACtD,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;QAED,qCAAqC;QACrC,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;QAE9B,0BAA0B;QAC1B,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAC1C,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAEhE,iBAAiB;QACjB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,GAAG,MAAM,uBAAuB,IAAI,UAAU,KAAK,EAAE,CAAC;QAEtE,2BAA2B;QAC3B,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;YAC9C,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;YAC1D,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,IAAI,CAAC,CAAC;QAChC,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;QAE7C,oBAAoB;QACpB,MAAM,MAAM,GAAG,MAAM,eAAe,EAAE,CAAC;QAEvC,mBAAmB;QACnB,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAE5C,OAAO,CAAC,GAAG,CAAC,iCAAiC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,qBAAqB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACtD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACnD,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC;;GAEG;AACH,eAAO,MAAM,aAAa,SAUxB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { clearCredentials, loadCredentials } from '../lib/credentials.js';
|
|
3
|
+
/**
|
|
4
|
+
* Logout command - clears stored credentials
|
|
5
|
+
*/
|
|
6
|
+
export const logoutCommand = new Command('logout').description('Log out of Reminix').action(() => {
|
|
7
|
+
const credentials = loadCredentials();
|
|
8
|
+
if (!credentials) {
|
|
9
|
+
console.log('Not logged in.');
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
clearCredentials();
|
|
13
|
+
console.log(`✓ Logged out of ${credentials.email}`);
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=logout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE1E;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,oBAAoB,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE;IAC/F,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IAEtC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAC9B,OAAO;IACT,CAAC;IAED,gBAAgB,EAAE,CAAC;IACnB,OAAO,CAAC,GAAG,CAAC,mBAAmB,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC;AACtD,CAAC,CAAC,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "0.1.
|
|
1
|
+
export declare const version = "0.1.3";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/commands/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const version = '0.1.
|
|
1
|
+
export const version = '0.1.3';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC;;GAEG;AACH,eAAO,MAAM,aAAa,SAiBtB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { loadCredentials, getCredentialsDirPath } from '../lib/credentials.js';
|
|
3
|
+
/**
|
|
4
|
+
* Whoami command - shows current logged-in user
|
|
5
|
+
*/
|
|
6
|
+
export const whoamiCommand = new Command('whoami')
|
|
7
|
+
.description('Show the currently logged-in user')
|
|
8
|
+
.option('--verbose', 'Show additional details')
|
|
9
|
+
.action((options) => {
|
|
10
|
+
const credentials = loadCredentials();
|
|
11
|
+
if (!credentials) {
|
|
12
|
+
console.log("Not logged in. Run 'reminix login' to authenticate.");
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
console.log(credentials.email);
|
|
16
|
+
if (options.verbose) {
|
|
17
|
+
console.log(`\nToken created: ${credentials.createdAt}`);
|
|
18
|
+
console.log(`Credentials stored in: ${getCredentialsDirPath()}`);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=whoami.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE/E;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,mCAAmC,CAAC;KAChD,MAAM,CAAC,WAAW,EAAE,yBAAyB,CAAC;KAC9C,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;IAClB,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IAEtC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAE/B,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,oBAAoB,WAAW,CAAC,SAAS,EAAE,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,0BAA0B,qBAAqB,EAAE,EAAE,CAAC,CAAC;IACnE,CAAC;AACH,CAAC,CAAC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { version } from './commands/version.js';
|
|
4
|
+
import { loginCommand } from './commands/login.js';
|
|
5
|
+
import { logoutCommand } from './commands/logout.js';
|
|
6
|
+
import { whoamiCommand } from './commands/whoami.js';
|
|
4
7
|
const program = new Command();
|
|
5
8
|
program
|
|
6
9
|
.name('reminix')
|
|
7
10
|
.description('Reminix CLI - Command-line interface for Reminix')
|
|
8
|
-
.version(version, '-v, --version', 'display version number')
|
|
11
|
+
.version(version, '-v, --version', 'display version number')
|
|
12
|
+
.showHelpAfterError()
|
|
13
|
+
.action(() => {
|
|
14
|
+
program.help();
|
|
15
|
+
});
|
|
16
|
+
// Add commands
|
|
17
|
+
program.addCommand(loginCommand);
|
|
18
|
+
program.addCommand(logoutCommand);
|
|
19
|
+
program.addCommand(whoamiCommand);
|
|
9
20
|
program.parse();
|
|
10
21
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,kDAAkD,CAAC;KAC/D,OAAO,CAAC,OAAO,EAAE,eAAe,EAAE,wBAAwB,CAAC;KAC3D,kBAAkB,EAAE;KACpB,MAAM,CAAC,GAAG,EAAE;IACX,OAAO,CAAC,IAAI,EAAE,CAAC;AACjB,CAAC,CAAC,CAAC;AAEL,eAAe;AACf,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAElC,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result from the auth callback
|
|
3
|
+
*/
|
|
4
|
+
export interface AuthCallbackResult {
|
|
5
|
+
token: string;
|
|
6
|
+
state: string;
|
|
7
|
+
email: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Start the auth server and return both the port and the result promise
|
|
11
|
+
* This allows the caller to get the port immediately and wait for the result separately
|
|
12
|
+
*/
|
|
13
|
+
export declare function createAuthServer(expectedState: string, timeoutMs?: number): Promise<{
|
|
14
|
+
port: number;
|
|
15
|
+
waitForCallback: () => Promise<AuthCallbackResult>;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Generate a random state string for CSRF protection
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateState(): string;
|
|
21
|
+
//# sourceMappingURL=auth-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-server.d.ts","sourceRoot":"","sources":["../../src/lib/auth-server.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AA+ID;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,aAAa,EAAE,MAAM,EACrB,SAAS,GAAE,MAAsB,GAChC,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAA;CAAE,CAAC,CA0F/E;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAItC"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import * as http from 'node:http';
|
|
2
|
+
/**
|
|
3
|
+
* HTML page shown after successful authentication
|
|
4
|
+
*/
|
|
5
|
+
const SUCCESS_HTML = `
|
|
6
|
+
<!DOCTYPE html>
|
|
7
|
+
<html lang="en">
|
|
8
|
+
<head>
|
|
9
|
+
<meta charset="UTF-8">
|
|
10
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
11
|
+
<title>Reminix CLI - Authenticated</title>
|
|
12
|
+
<style>
|
|
13
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
14
|
+
body {
|
|
15
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
16
|
+
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
|
17
|
+
min-height: 100vh;
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
color: #fff;
|
|
22
|
+
}
|
|
23
|
+
.container {
|
|
24
|
+
text-align: center;
|
|
25
|
+
padding: 2rem;
|
|
26
|
+
}
|
|
27
|
+
.checkmark {
|
|
28
|
+
width: 80px;
|
|
29
|
+
height: 80px;
|
|
30
|
+
margin: 0 auto 1.5rem;
|
|
31
|
+
background: #10b981;
|
|
32
|
+
border-radius: 50%;
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
animation: pop 0.3s ease-out;
|
|
37
|
+
}
|
|
38
|
+
.checkmark svg {
|
|
39
|
+
width: 40px;
|
|
40
|
+
height: 40px;
|
|
41
|
+
stroke: white;
|
|
42
|
+
stroke-width: 3;
|
|
43
|
+
fill: none;
|
|
44
|
+
}
|
|
45
|
+
h1 {
|
|
46
|
+
font-size: 1.5rem;
|
|
47
|
+
font-weight: 600;
|
|
48
|
+
margin-bottom: 0.5rem;
|
|
49
|
+
}
|
|
50
|
+
p {
|
|
51
|
+
color: #94a3b8;
|
|
52
|
+
font-size: 1rem;
|
|
53
|
+
}
|
|
54
|
+
@keyframes pop {
|
|
55
|
+
0% { transform: scale(0); }
|
|
56
|
+
80% { transform: scale(1.1); }
|
|
57
|
+
100% { transform: scale(1); }
|
|
58
|
+
}
|
|
59
|
+
</style>
|
|
60
|
+
</head>
|
|
61
|
+
<body>
|
|
62
|
+
<div class="container">
|
|
63
|
+
<div class="checkmark">
|
|
64
|
+
<svg viewBox="0 0 24 24">
|
|
65
|
+
<polyline points="20 6 9 17 4 12"></polyline>
|
|
66
|
+
</svg>
|
|
67
|
+
</div>
|
|
68
|
+
<h1>Authentication successful!</h1>
|
|
69
|
+
<p>You can close this tab and return to your terminal.</p>
|
|
70
|
+
</div>
|
|
71
|
+
</body>
|
|
72
|
+
</html>
|
|
73
|
+
`;
|
|
74
|
+
/**
|
|
75
|
+
* HTML page shown when there's an error
|
|
76
|
+
*/
|
|
77
|
+
const ERROR_HTML = `
|
|
78
|
+
<!DOCTYPE html>
|
|
79
|
+
<html lang="en">
|
|
80
|
+
<head>
|
|
81
|
+
<meta charset="UTF-8">
|
|
82
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
83
|
+
<title>Reminix CLI - Error</title>
|
|
84
|
+
<style>
|
|
85
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
86
|
+
body {
|
|
87
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
88
|
+
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
|
89
|
+
min-height: 100vh;
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
justify-content: center;
|
|
93
|
+
color: #fff;
|
|
94
|
+
}
|
|
95
|
+
.container {
|
|
96
|
+
text-align: center;
|
|
97
|
+
padding: 2rem;
|
|
98
|
+
}
|
|
99
|
+
.error-icon {
|
|
100
|
+
width: 80px;
|
|
101
|
+
height: 80px;
|
|
102
|
+
margin: 0 auto 1.5rem;
|
|
103
|
+
background: #ef4444;
|
|
104
|
+
border-radius: 50%;
|
|
105
|
+
display: flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
justify-content: center;
|
|
108
|
+
}
|
|
109
|
+
.error-icon svg {
|
|
110
|
+
width: 40px;
|
|
111
|
+
height: 40px;
|
|
112
|
+
stroke: white;
|
|
113
|
+
stroke-width: 3;
|
|
114
|
+
fill: none;
|
|
115
|
+
}
|
|
116
|
+
h1 {
|
|
117
|
+
font-size: 1.5rem;
|
|
118
|
+
font-weight: 600;
|
|
119
|
+
margin-bottom: 0.5rem;
|
|
120
|
+
}
|
|
121
|
+
p {
|
|
122
|
+
color: #94a3b8;
|
|
123
|
+
font-size: 1rem;
|
|
124
|
+
}
|
|
125
|
+
</style>
|
|
126
|
+
</head>
|
|
127
|
+
<body>
|
|
128
|
+
<div class="container">
|
|
129
|
+
<div class="error-icon">
|
|
130
|
+
<svg viewBox="0 0 24 24">
|
|
131
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
132
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
133
|
+
</svg>
|
|
134
|
+
</div>
|
|
135
|
+
<h1>Authentication failed</h1>
|
|
136
|
+
<p>Please try again from your terminal.</p>
|
|
137
|
+
</div>
|
|
138
|
+
</body>
|
|
139
|
+
</html>
|
|
140
|
+
`;
|
|
141
|
+
/**
|
|
142
|
+
* Start the auth server and return both the port and the result promise
|
|
143
|
+
* This allows the caller to get the port immediately and wait for the result separately
|
|
144
|
+
*/
|
|
145
|
+
export function createAuthServer(expectedState, timeoutMs = 5 * 60 * 1000) {
|
|
146
|
+
return new Promise((resolve, reject) => {
|
|
147
|
+
let callbackResolve;
|
|
148
|
+
let callbackReject;
|
|
149
|
+
const callbackPromise = new Promise((res, rej) => {
|
|
150
|
+
callbackResolve = res;
|
|
151
|
+
callbackReject = rej;
|
|
152
|
+
});
|
|
153
|
+
const server = http.createServer((req, res) => {
|
|
154
|
+
// Only handle GET requests to /callback
|
|
155
|
+
if (!req.url?.startsWith('/callback')) {
|
|
156
|
+
res.writeHead(404);
|
|
157
|
+
res.end('Not found');
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// Parse query parameters using WHATWG URL API
|
|
161
|
+
const parsedUrl = new URL(req.url, `http://localhost`);
|
|
162
|
+
const token = parsedUrl.searchParams.get('token') ?? undefined;
|
|
163
|
+
const state = parsedUrl.searchParams.get('state') ?? undefined;
|
|
164
|
+
const email = parsedUrl.searchParams.get('email') ?? undefined;
|
|
165
|
+
const error = parsedUrl.searchParams.get('error') ?? undefined;
|
|
166
|
+
// Handle error from web app
|
|
167
|
+
if (error) {
|
|
168
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
169
|
+
res.end(ERROR_HTML);
|
|
170
|
+
cleanup();
|
|
171
|
+
callbackReject(new Error(`Authentication failed: ${error}`));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
// Validate required parameters
|
|
175
|
+
if (!token || !state || !email) {
|
|
176
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
177
|
+
res.end(ERROR_HTML);
|
|
178
|
+
cleanup();
|
|
179
|
+
callbackReject(new Error('Missing token, state, or email in callback'));
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
// Verify state matches (CSRF protection)
|
|
183
|
+
if (state !== expectedState) {
|
|
184
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
185
|
+
res.end(ERROR_HTML);
|
|
186
|
+
cleanup();
|
|
187
|
+
callbackReject(new Error('State mismatch - possible CSRF attack'));
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
// Success!
|
|
191
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
192
|
+
res.end(SUCCESS_HTML);
|
|
193
|
+
cleanup();
|
|
194
|
+
callbackResolve({ token, state, email });
|
|
195
|
+
});
|
|
196
|
+
// Handle server errors
|
|
197
|
+
server.on('error', (err) => {
|
|
198
|
+
cleanup();
|
|
199
|
+
reject(err);
|
|
200
|
+
});
|
|
201
|
+
// Set up timeout
|
|
202
|
+
const timeoutId = setTimeout(() => {
|
|
203
|
+
cleanup();
|
|
204
|
+
callbackReject(new Error('Authentication timed out. Please try again.'));
|
|
205
|
+
}, timeoutMs);
|
|
206
|
+
// Cleanup function
|
|
207
|
+
function cleanup() {
|
|
208
|
+
clearTimeout(timeoutId);
|
|
209
|
+
server.close();
|
|
210
|
+
}
|
|
211
|
+
// Start server on random available port (port 0)
|
|
212
|
+
server.listen(0, '127.0.0.1', () => {
|
|
213
|
+
const address = server.address();
|
|
214
|
+
if (typeof address === 'object' && address) {
|
|
215
|
+
resolve({
|
|
216
|
+
port: address.port,
|
|
217
|
+
waitForCallback: () => callbackPromise,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
reject(new Error('Failed to start auth server'));
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Generate a random state string for CSRF protection
|
|
228
|
+
*/
|
|
229
|
+
export function generateState() {
|
|
230
|
+
const array = new Uint8Array(32);
|
|
231
|
+
crypto.getRandomValues(array);
|
|
232
|
+
return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=auth-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-server.js","sourceRoot":"","sources":["../../src/lib/auth-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAWlC;;GAEG;AACH,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoEpB,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+DlB,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,aAAqB,EACrB,YAAoB,CAAC,GAAG,EAAE,GAAG,IAAI;IAEjC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,eAAqD,CAAC;QAC1D,IAAI,cAAsC,CAAC;QAE3C,MAAM,eAAe,GAAG,IAAI,OAAO,CAAqB,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YACnE,eAAe,GAAG,GAAG,CAAC;YACtB,cAAc,GAAG,GAAG,CAAC;QACvB,CAAC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC5C,wCAAwC;YACxC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;gBACtC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBACnB,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;gBACrB,OAAO;YACT,CAAC;YAED,8CAA8C;YAC9C,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;YACvD,MAAM,KAAK,GAAG,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC;YAC/D,MAAM,KAAK,GAAG,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC;YAC/D,MAAM,KAAK,GAAG,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC;YAC/D,MAAM,KAAK,GAAG,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC;YAE/D,4BAA4B;YAC5B,IAAI,KAAK,EAAE,CAAC;gBACV,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;gBACpD,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBACpB,OAAO,EAAE,CAAC;gBACV,cAAc,CAAC,IAAI,KAAK,CAAC,0BAA0B,KAAK,EAAE,CAAC,CAAC,CAAC;gBAC7D,OAAO;YACT,CAAC;YAED,+BAA+B;YAC/B,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC/B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;gBACpD,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBACpB,OAAO,EAAE,CAAC;gBACV,cAAc,CAAC,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC,CAAC;gBACxE,OAAO;YACT,CAAC;YAED,yCAAyC;YACzC,IAAI,KAAK,KAAK,aAAa,EAAE,CAAC;gBAC5B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;gBACpD,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBACpB,OAAO,EAAE,CAAC;gBACV,cAAc,CAAC,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC,CAAC;gBACnE,OAAO;YACT,CAAC;YAED,WAAW;YACX,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;YACpD,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;YACtB,OAAO,EAAE,CAAC;YACV,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,uBAAuB;QACvB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACzB,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;QAEH,iBAAiB;QACjB,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAChC,OAAO,EAAE,CAAC;YACV,cAAc,CAAC,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC,CAAC;QAC3E,CAAC,EAAE,SAAS,CAAC,CAAC;QAEd,mBAAmB;QACnB,SAAS,OAAO;YACd,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,CAAC;QAED,iDAAiD;QACjD,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;YACjC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YACjC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,EAAE,CAAC;gBAC3C,OAAO,CAAC;oBACN,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,eAAe,EAAE,GAAG,EAAE,CAAC,eAAe;iBACvC,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;YACnD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACjC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAC9B,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAClF,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credentials stored locally for CLI authentication
|
|
3
|
+
*/
|
|
4
|
+
export interface Credentials {
|
|
5
|
+
token: string;
|
|
6
|
+
email: string;
|
|
7
|
+
createdAt: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Save credentials to the local filesystem
|
|
11
|
+
* Creates the config directory if it doesn't exist
|
|
12
|
+
*/
|
|
13
|
+
export declare function saveCredentials(token: string, email: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Load credentials from the local filesystem
|
|
16
|
+
* Returns null if no credentials exist or file is invalid
|
|
17
|
+
*/
|
|
18
|
+
export declare function loadCredentials(): Credentials | null;
|
|
19
|
+
/**
|
|
20
|
+
* Clear stored credentials
|
|
21
|
+
* Removes the credentials file if it exists
|
|
22
|
+
*/
|
|
23
|
+
export declare function clearCredentials(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Check if user is logged in (has valid credentials)
|
|
26
|
+
*/
|
|
27
|
+
export declare function isLoggedIn(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Get the credentials directory path (for display purposes)
|
|
30
|
+
*/
|
|
31
|
+
export declare function getCredentialsDirPath(): string;
|
|
32
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/lib/credentials.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAqBD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAmBlE;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,WAAW,GAAG,IAAI,CAoBpD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAMvC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
/**
|
|
5
|
+
* Get the path to the credentials directory
|
|
6
|
+
* Uses XDG_CONFIG_HOME if set, otherwise ~/.config/reminix
|
|
7
|
+
*/
|
|
8
|
+
function getCredentialsDir() {
|
|
9
|
+
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
10
|
+
if (xdgConfigHome) {
|
|
11
|
+
return path.join(xdgConfigHome, 'reminix');
|
|
12
|
+
}
|
|
13
|
+
return path.join(os.homedir(), '.config', 'reminix');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get the path to the credentials file
|
|
17
|
+
*/
|
|
18
|
+
function getCredentialsPath() {
|
|
19
|
+
return path.join(getCredentialsDir(), 'credentials.json');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Save credentials to the local filesystem
|
|
23
|
+
* Creates the config directory if it doesn't exist
|
|
24
|
+
*/
|
|
25
|
+
export function saveCredentials(token, email) {
|
|
26
|
+
const dir = getCredentialsDir();
|
|
27
|
+
const filePath = getCredentialsPath();
|
|
28
|
+
// Create directory if it doesn't exist
|
|
29
|
+
if (!fs.existsSync(dir)) {
|
|
30
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 }); // Only owner can access
|
|
31
|
+
}
|
|
32
|
+
const credentials = {
|
|
33
|
+
token,
|
|
34
|
+
email,
|
|
35
|
+
createdAt: new Date().toISOString(),
|
|
36
|
+
};
|
|
37
|
+
// Write credentials file with restricted permissions
|
|
38
|
+
fs.writeFileSync(filePath, JSON.stringify(credentials, null, 2), {
|
|
39
|
+
mode: 0o600, // Only owner can read/write
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Load credentials from the local filesystem
|
|
44
|
+
* Returns null if no credentials exist or file is invalid
|
|
45
|
+
*/
|
|
46
|
+
export function loadCredentials() {
|
|
47
|
+
const filePath = getCredentialsPath();
|
|
48
|
+
if (!fs.existsSync(filePath)) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
53
|
+
const credentials = JSON.parse(content);
|
|
54
|
+
// Basic validation
|
|
55
|
+
if (!credentials.token || !credentials.email) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return credentials;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Clear stored credentials
|
|
66
|
+
* Removes the credentials file if it exists
|
|
67
|
+
*/
|
|
68
|
+
export function clearCredentials() {
|
|
69
|
+
const filePath = getCredentialsPath();
|
|
70
|
+
if (fs.existsSync(filePath)) {
|
|
71
|
+
fs.unlinkSync(filePath);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Check if user is logged in (has valid credentials)
|
|
76
|
+
*/
|
|
77
|
+
export function isLoggedIn() {
|
|
78
|
+
return loadCredentials() !== null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Get the credentials directory path (for display purposes)
|
|
82
|
+
*/
|
|
83
|
+
export function getCredentialsDirPath() {
|
|
84
|
+
return getCredentialsDir();
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/lib/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAW9B;;;GAGG;AACH,SAAS,iBAAiB;IACxB,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAClD,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;AACvD,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB;IACzB,OAAO,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,kBAAkB,CAAC,CAAC;AAC5D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa,EAAE,KAAa;IAC1D,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;IAChC,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAC;IAEtC,uCAAuC;IACvC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,wBAAwB;IAC/E,CAAC;IAED,MAAM,WAAW,GAAgB;QAC/B,KAAK;QACL,KAAK;QACL,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IAEF,qDAAqD;IACrD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QAC/D,IAAI,EAAE,KAAK,EAAE,4BAA4B;KAC1C,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAC;IAEtC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAC;QAEvD,mBAAmB;QACnB,IAAI,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;YAC7C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAC;IAEtC,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO,eAAe,EAAE,KAAK,IAAI,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,iBAAiB,EAAE,CAAC;AAC7B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reminix/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Reminix CLI - Command-line interface for Reminix",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": {
|
|
@@ -18,11 +18,11 @@
|
|
|
18
18
|
"homepage": "https://reminix.com",
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|
|
21
|
-
"url": "git+https://github.com/reminix-ai/
|
|
21
|
+
"url": "git+https://github.com/reminix-ai/cli.git",
|
|
22
22
|
"directory": "packages/cli"
|
|
23
23
|
},
|
|
24
24
|
"bugs": {
|
|
25
|
-
"url": "https://github.com/reminix-ai/
|
|
25
|
+
"url": "https://github.com/reminix-ai/cli/issues"
|
|
26
26
|
},
|
|
27
27
|
"engines": {
|
|
28
28
|
"node": ">=20"
|
|
@@ -48,13 +48,14 @@
|
|
|
48
48
|
"LICENSE"
|
|
49
49
|
],
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"commander": "^
|
|
51
|
+
"commander": "^14.0.2",
|
|
52
|
+
"open": "^11.0.0"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
54
|
-
"@types/node": "^
|
|
55
|
+
"@types/node": "^25.0.9",
|
|
55
56
|
"tsx": "^4.21.0",
|
|
56
57
|
"typescript": "^5.9.3",
|
|
57
|
-
"vitest": "^
|
|
58
|
+
"vitest": "^4.0.17"
|
|
58
59
|
},
|
|
59
60
|
"scripts": {
|
|
60
61
|
"build": "tsc",
|