@mearl/plugin-qoder 0.0.0-stage → 3.0.0-beta.10

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/dist/auth.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ export declare function qoderAuthenticationHint(platform?: NodeJS.Platform): string;
2
+ interface QoderTokenResolverOptions {
3
+ token?: string;
4
+ env?: NodeJS.ProcessEnv;
5
+ homeDirectory?: string;
6
+ platform?: NodeJS.Platform;
7
+ readFile?: (file: string) => string;
8
+ readKeychainToken?: () => string | undefined;
9
+ }
10
+ /** Resolve a PAT without putting it in a pairing URL, process argument, registry, or log. */
11
+ export declare function resolveQoderPersonalAccessToken(options?: QoderTokenResolverOptions): string | undefined;
12
+ export {};
package/dist/auth.js ADDED
@@ -0,0 +1,89 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { homedir, userInfo } from 'node:os';
3
+ import { resolve } from 'node:path';
4
+ import { spawnSync } from 'node:child_process';
5
+ const QODER_TOKEN_KEY = 'QODER_PERSONAL_ACCESS_TOKEN';
6
+ const QODER_KEYCHAIN_SERVICE = 'ai.mearl.qoder.pat';
7
+ export function qoderAuthenticationHint(platform = process.platform) {
8
+ const lines = [
9
+ 'Configure QODER_PERSONAL_ACCESS_TOKEN on the browser machine, then restart the connector.',
10
+ 'Lookup order: process environment > MEARL_ENV_FILE > ~/.mearl/.env' +
11
+ (platform === 'darwin' ? ` > macOS Keychain (${QODER_KEYCHAIN_SERVICE}).` : '.'),
12
+ ];
13
+ if (platform === 'darwin') {
14
+ lines.push(`Enter the PAT interactively in a local terminal: security add-generic-password -U -a "$USER" -s ${QODER_KEYCHAIN_SERVICE} -w`);
15
+ }
16
+ lines.push('Keep the PAT out of pairing URLs, chat messages and logs.');
17
+ return lines.join('\n');
18
+ }
19
+ function normalizeToken(value) {
20
+ const token = value?.trim();
21
+ if (!token || /[\r\n\0]/.test(token))
22
+ return undefined;
23
+ return token;
24
+ }
25
+ function envValue(text, key) {
26
+ for (const line of text.split(/\r?\n/)) {
27
+ const match = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)\s*$/.exec(line);
28
+ if (!match || match[1] !== key)
29
+ continue;
30
+ let value = (match[2] ?? '').trim();
31
+ if (value.length >= 2 &&
32
+ ((value.startsWith('"') && value.endsWith('"')) ||
33
+ (value.startsWith("'") && value.endsWith("'")))) {
34
+ value = value.slice(1, -1);
35
+ }
36
+ else {
37
+ value = value.replace(/\s+#.*$/, '').trim();
38
+ }
39
+ return normalizeToken(value);
40
+ }
41
+ return undefined;
42
+ }
43
+ function readMacKeychainToken() {
44
+ const securityPath = '/usr/bin/security';
45
+ if (!existsSync(securityPath))
46
+ return undefined;
47
+ try {
48
+ const account = userInfo().username;
49
+ const result = spawnSync(securityPath, ['find-generic-password', '-a', account, '-s', QODER_KEYCHAIN_SERVICE, '-w'], {
50
+ encoding: 'utf8',
51
+ stdio: ['ignore', 'pipe', 'ignore'],
52
+ timeout: 5_000,
53
+ windowsHide: true,
54
+ });
55
+ return result.status === 0 ? normalizeToken(result.stdout) : undefined;
56
+ }
57
+ catch {
58
+ return undefined;
59
+ }
60
+ }
61
+ /** Resolve a PAT without putting it in a pairing URL, process argument, registry, or log. */
62
+ export function resolveQoderPersonalAccessToken(options = {}) {
63
+ const direct = normalizeToken(options.token);
64
+ if (direct)
65
+ return direct;
66
+ const env = options.env ?? process.env;
67
+ const inherited = normalizeToken(env[QODER_TOKEN_KEY]);
68
+ if (inherited)
69
+ return inherited;
70
+ const homeDirectory = options.homeDirectory ?? homedir();
71
+ const envFiles = [
72
+ ...(env.MEARL_ENV_FILE?.trim() ? [resolve(env.MEARL_ENV_FILE)] : []),
73
+ resolve(homeDirectory, '.mearl', '.env'),
74
+ ];
75
+ const readFile = options.readFile ?? (file => readFileSync(file, 'utf8'));
76
+ for (const file of new Set(envFiles)) {
77
+ try {
78
+ const token = envValue(readFile(file), QODER_TOKEN_KEY);
79
+ if (token)
80
+ return token;
81
+ }
82
+ catch {
83
+ // Continue to the next credential source.
84
+ }
85
+ }
86
+ if ((options.platform ?? process.platform) !== 'darwin')
87
+ return undefined;
88
+ return normalizeToken((options.readKeychainToken ?? readMacKeychainToken)());
89
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "qoder",
4
+ "version": "1.0.0",
5
+ "requires": {
6
+ "mearlApi": "^1"
7
+ },
8
+ "resources": {
9
+ "runtime.cjs": {
10
+ "sha256": "1a603acc3c2e3f00922cb20f2b29cfe0a05a9a2a5d7f9388809e7a6cb52f6a14",
11
+ "byteLength": 1103931
12
+ }
13
+ },
14
+ "contributions": {
15
+ "appProfiles": [],
16
+ "nodeRuntimes": {
17
+ "native-host": {
18
+ "entry": "runtime.cjs",
19
+ "bindings": {
20
+ "agent.provider.qoder": "agent",
21
+ "cloud.connector.qoder": "connector",
22
+ "cloud.server.qoder": "server"
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "id": "qoder",
4
+ "version": "1.0.0",
5
+ "packages": {
6
+ "qoder": {
7
+ "source": "./bundle.json",
8
+ "version": "^1",
9
+ "targets": [
10
+ "node"
11
+ ]
12
+ }
13
+ }
14
+ }