@myclaude-cli/cli 0.3.0-alpha

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 (93) hide show
  1. package/bin/dev.js +5 -0
  2. package/bin/myclaude.js +20 -0
  3. package/dist/commands/help.d.ts +11 -0
  4. package/dist/commands/help.js +221 -0
  5. package/dist/commands/help.js.map +1 -0
  6. package/dist/commands/info.d.ts +12 -0
  7. package/dist/commands/info.js +87 -0
  8. package/dist/commands/info.js.map +1 -0
  9. package/dist/commands/install.d.ts +14 -0
  10. package/dist/commands/install.js +113 -0
  11. package/dist/commands/install.js.map +1 -0
  12. package/dist/commands/list.d.ts +9 -0
  13. package/dist/commands/list.js +41 -0
  14. package/dist/commands/list.js.map +1 -0
  15. package/dist/commands/login.d.ts +9 -0
  16. package/dist/commands/login.js +83 -0
  17. package/dist/commands/login.js.map +1 -0
  18. package/dist/commands/logout.d.ts +9 -0
  19. package/dist/commands/logout.js +25 -0
  20. package/dist/commands/logout.js.map +1 -0
  21. package/dist/commands/publish.d.ts +10 -0
  22. package/dist/commands/publish.js +229 -0
  23. package/dist/commands/publish.js.map +1 -0
  24. package/dist/commands/search.d.ts +18 -0
  25. package/dist/commands/search.js +108 -0
  26. package/dist/commands/search.js.map +1 -0
  27. package/dist/commands/status.d.ts +8 -0
  28. package/dist/commands/status.js +84 -0
  29. package/dist/commands/status.js.map +1 -0
  30. package/dist/commands/uninstall.d.ts +14 -0
  31. package/dist/commands/uninstall.js +98 -0
  32. package/dist/commands/uninstall.js.map +1 -0
  33. package/dist/commands/validate.d.ts +9 -0
  34. package/dist/commands/validate.js +144 -0
  35. package/dist/commands/validate.js.map +1 -0
  36. package/dist/commands/whoami.d.ts +9 -0
  37. package/dist/commands/whoami.js +52 -0
  38. package/dist/commands/whoami.js.map +1 -0
  39. package/dist/constants.d.ts +9 -0
  40. package/dist/constants.js +10 -0
  41. package/dist/constants.js.map +1 -0
  42. package/dist/core/api.d.ts +18 -0
  43. package/dist/core/api.js +135 -0
  44. package/dist/core/api.js.map +1 -0
  45. package/dist/core/auth.d.ts +30 -0
  46. package/dist/core/auth.js +71 -0
  47. package/dist/core/auth.js.map +1 -0
  48. package/dist/core/browser-auth.d.ts +24 -0
  49. package/dist/core/browser-auth.js +155 -0
  50. package/dist/core/browser-auth.js.map +1 -0
  51. package/dist/core/install.d.ts +24 -0
  52. package/dist/core/install.js +191 -0
  53. package/dist/core/install.js.map +1 -0
  54. package/dist/core/lockfile.d.ts +18 -0
  55. package/dist/core/lockfile.js +41 -0
  56. package/dist/core/lockfile.js.map +1 -0
  57. package/dist/core/manifest.d.ts +41 -0
  58. package/dist/core/manifest.js +203 -0
  59. package/dist/core/manifest.js.map +1 -0
  60. package/dist/core/packer.d.ts +25 -0
  61. package/dist/core/packer.js +169 -0
  62. package/dist/core/packer.js.map +1 -0
  63. package/dist/core/paths.d.ts +2 -0
  64. package/dist/core/paths.js +50 -0
  65. package/dist/core/paths.js.map +1 -0
  66. package/dist/core/secret-scan.d.ts +17 -0
  67. package/dist/core/secret-scan.js +73 -0
  68. package/dist/core/secret-scan.js.map +1 -0
  69. package/dist/ui/exit-codes.d.ts +91 -0
  70. package/dist/ui/exit-codes.js +51 -0
  71. package/dist/ui/exit-codes.js.map +1 -0
  72. package/dist/ui/format.d.ts +12 -0
  73. package/dist/ui/format.js +44 -0
  74. package/dist/ui/format.js.map +1 -0
  75. package/dist/ui/index.d.ts +13 -0
  76. package/dist/ui/index.js +11 -0
  77. package/dist/ui/index.js.map +1 -0
  78. package/dist/ui/layout.d.ts +28 -0
  79. package/dist/ui/layout.js +161 -0
  80. package/dist/ui/layout.js.map +1 -0
  81. package/dist/ui/table.d.ts +10 -0
  82. package/dist/ui/table.js +42 -0
  83. package/dist/ui/table.js.map +1 -0
  84. package/dist/ui/theme.d.ts +46 -0
  85. package/dist/ui/theme.js +180 -0
  86. package/dist/ui/theme.js.map +1 -0
  87. package/dist/utils/config.d.ts +11 -0
  88. package/dist/utils/config.js +44 -0
  89. package/dist/utils/config.js.map +1 -0
  90. package/dist/utils/keychain.d.ts +3 -0
  91. package/dist/utils/keychain.js +53 -0
  92. package/dist/utils/keychain.js.map +1 -0
  93. package/package.json +63 -0
@@ -0,0 +1,14 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Uninstall extends Command {
3
+ static args: {
4
+ slug: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ };
12
+ run(): Promise<void>;
13
+ private confirm;
14
+ }
@@ -0,0 +1,98 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { createInterface } from 'node:readline';
3
+ import { existsSync, rmSync } from 'node:fs';
4
+ import { resolve } from 'node:path';
5
+ import { homedir } from 'node:os';
6
+ import { isInstalled, removeEntry } from '../core/lockfile.js';
7
+ import { EXIT, color, icon } from '../ui/index.js';
8
+ /** Verify uninstall path is within expected roots before rmSync */
9
+ function isSafePath(location) {
10
+ const resolved = resolve(location);
11
+ const cwd = resolve('.');
12
+ const home = homedir();
13
+ const safePrefixes = [
14
+ resolve(cwd, '.claude'),
15
+ resolve(cwd, 'myclaude-products'),
16
+ resolve(home, '.claude'),
17
+ resolve(home, 'myclaude-products'),
18
+ ];
19
+ return safePrefixes.some((prefix) => resolved.startsWith(prefix));
20
+ }
21
+ export default class Uninstall extends Command {
22
+ static args = {
23
+ slug: Args.string({ description: 'Product slug to uninstall', required: true }),
24
+ };
25
+ static description = 'Remove an installed product';
26
+ static examples = [
27
+ '<%= config.bin %> uninstall auth-guard-skill',
28
+ ];
29
+ static flags = {
30
+ json: Flags.boolean({ description: 'Output as JSON' }),
31
+ yes: Flags.boolean({ char: 'y', default: false, description: 'Skip confirmation' }),
32
+ };
33
+ async run() {
34
+ const { args, flags } = await this.parse(Uninstall);
35
+ const entry = isInstalled(args.slug);
36
+ if (!entry) {
37
+ if (flags.json) {
38
+ this.log(JSON.stringify({ error: 'Not installed', uninstalled: false }));
39
+ }
40
+ else {
41
+ this.log(` ${icon.info} ${args.slug} is not installed`);
42
+ }
43
+ return;
44
+ }
45
+ if (!flags.yes && !flags.json) {
46
+ const confirmed = await this.confirm(`Remove ${args.slug} from ${entry.location}?`);
47
+ if (!confirmed) {
48
+ this.log('Aborted.');
49
+ return;
50
+ }
51
+ }
52
+ // Security: validate path before deletion
53
+ if (!isSafePath(entry.location)) {
54
+ const msg = `Refusing to delete unsafe path: ${entry.location}`;
55
+ if (flags.json) {
56
+ this.log(JSON.stringify({ error: msg, uninstalled: false }));
57
+ this.exit(EXIT.ERROR);
58
+ }
59
+ else {
60
+ this.error(msg);
61
+ }
62
+ return;
63
+ }
64
+ try {
65
+ if (existsSync(entry.location)) {
66
+ rmSync(entry.location, { force: true, recursive: true });
67
+ }
68
+ }
69
+ catch (error) {
70
+ const msg = error.message;
71
+ if (flags.json) {
72
+ this.log(JSON.stringify({ error: `Failed to remove files: ${msg}`, uninstalled: false }));
73
+ this.exit(EXIT.ERROR);
74
+ }
75
+ else {
76
+ this.error(`Failed to remove files: ${msg}`);
77
+ }
78
+ return;
79
+ }
80
+ removeEntry(args.slug);
81
+ if (flags.json) {
82
+ this.log(JSON.stringify({ slug: args.slug, uninstalled: true }));
83
+ }
84
+ else {
85
+ this.log(` ${icon.success} ${color.success(args.slug)} uninstalled`);
86
+ }
87
+ }
88
+ async confirm(question) {
89
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
90
+ return new Promise((resolve) => {
91
+ rl.question(` ${question} (y/N) `, (answer) => {
92
+ rl.close();
93
+ resolve(answer.trim().toLowerCase() === 'y');
94
+ });
95
+ });
96
+ }
97
+ }
98
+ //# sourceMappingURL=uninstall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uninstall.js","sourceRoot":"","sources":["../../src/commands/uninstall.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Validate extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,144 @@
1
+ import { readFileSync, statSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { Command, Flags } from '@oclif/core';
4
+ import { readManifest } from '../core/manifest.js';
5
+ import { collectFiles, formatBytes } from '../core/packer.js';
6
+ import { isEnvFile, scanForSecrets } from '../core/secret-scan.js';
7
+ import { EXIT, color, icon } from '../ui/index.js';
8
+ export default class Validate extends Command {
9
+ static description = 'Validate a product before publishing';
10
+ static examples = [
11
+ '<%= config.bin %> validate',
12
+ '<%= config.bin %> validate --json',
13
+ ];
14
+ static flags = {
15
+ json: Flags.boolean({ description: 'Output as JSON' }),
16
+ };
17
+ async run() {
18
+ const { flags } = await this.parse(Validate);
19
+ const results = [];
20
+ let hasBlocker = false;
21
+ // 1. Parse vault.yaml
22
+ const { manifest, issues: manifestIssues } = readManifest();
23
+ if (!manifest) {
24
+ for (const issue of manifestIssues) {
25
+ results.push({ check: issue.field, message: issue.message, pass: false });
26
+ }
27
+ hasBlocker = true;
28
+ }
29
+ else {
30
+ results.push({ check: 'vault.yaml', message: 'valid', pass: true });
31
+ // Add non-blocker warnings from manifest
32
+ for (const issue of manifestIssues) {
33
+ results.push({ check: issue.field, message: issue.message, pass: !issue.blocker });
34
+ if (issue.blocker)
35
+ hasBlocker = true;
36
+ }
37
+ // 2. Collect files
38
+ const { files, issues: packIssues } = collectFiles(process.cwd());
39
+ for (const issue of packIssues) {
40
+ results.push({ check: 'file size', message: `${issue.file}: ${issue.message}`, pass: false });
41
+ if (issue.blocker)
42
+ hasBlocker = true;
43
+ }
44
+ // Check for .env files in file list
45
+ const envFiles = files.filter(f => isEnvFile(f));
46
+ if (envFiles.length > 0) {
47
+ results.push({ check: '.env files', message: `Found ${envFiles.length} .env file(s) — excluded by default`, pass: true });
48
+ }
49
+ // Total size
50
+ let totalSize = 0;
51
+ for (const f of files) {
52
+ try {
53
+ totalSize += statSync(f).size;
54
+ }
55
+ catch { /* skip */ }
56
+ }
57
+ results.push({ check: 'files', message: `${files.length} files (${formatBytes(totalSize)})`, pass: true });
58
+ // 3. Secret scan
59
+ const findings = scanForSecrets(files, process.cwd());
60
+ if (findings.length > 0) {
61
+ hasBlocker = true;
62
+ for (const f of findings) {
63
+ results.push({
64
+ check: 'secret scan',
65
+ message: `${f.pattern} in ${f.file}:${f.line}`,
66
+ pass: false,
67
+ });
68
+ }
69
+ }
70
+ else {
71
+ results.push({ check: 'secret scan', message: 'no secrets detected', pass: true });
72
+ }
73
+ // 4. License
74
+ const KNOWN_SPDX = [
75
+ 'MIT', 'Apache-2.0', 'GPL-3.0', 'GPL-2.0', 'BSD-3-Clause', 'BSD-2-Clause',
76
+ 'ISC', 'CC-BY-4.0', 'CC-BY-SA-4.0', 'CC0-1.0', 'MPL-2.0', 'LGPL-3.0',
77
+ 'AGPL-3.0', 'Unlicense', 'Proprietary', 'Custom',
78
+ ];
79
+ if (KNOWN_SPDX.includes(manifest.license)) {
80
+ results.push({ check: 'license', message: `${manifest.license} (valid)`, pass: true });
81
+ }
82
+ else {
83
+ results.push({ check: 'license', message: `${manifest.license} (unknown SPDX identifier)`, pass: true }); // warning, not blocker
84
+ }
85
+ // 5. Entry file type-specific checks
86
+ if (['skill', 'agent', 'squad'].includes(manifest.type)) {
87
+ const entryContent = await readEntryFile(manifest.entry);
88
+ if (entryContent && !entryContent.includes('---')) {
89
+ results.push({ check: 'frontmatter', message: `${manifest.entry} missing YAML frontmatter (---)`, pass: false });
90
+ hasBlocker = true;
91
+ }
92
+ else if (entryContent) {
93
+ results.push({ check: 'frontmatter', message: `${manifest.entry} has valid frontmatter`, pass: true });
94
+ }
95
+ }
96
+ }
97
+ // Output
98
+ if (flags.json) {
99
+ this.log(JSON.stringify({
100
+ checks: results,
101
+ manifest: manifest ? {
102
+ category: manifest.category,
103
+ description: manifest.description,
104
+ license: manifest.license,
105
+ name: manifest.name,
106
+ price: manifest.price,
107
+ tags: manifest.tags,
108
+ type: manifest.type,
109
+ version: manifest.version,
110
+ } : null,
111
+ valid: !hasBlocker,
112
+ }));
113
+ }
114
+ else {
115
+ const title = manifest?.name ?? 'unknown';
116
+ this.log(`\n Validating ${color.bold(title)}...\n`);
117
+ for (const r of results) {
118
+ const mark = r.pass ? icon.success : icon.error;
119
+ const msg = r.pass ? color.muted(r.message) : color.error(r.message);
120
+ this.log(` ${mark} ${color.muted(r.check + ':')} ${msg}`);
121
+ }
122
+ this.log('');
123
+ if (hasBlocker) {
124
+ this.log(` ${icon.error} ${color.error('Validation failed. Fix blockers above.')}`);
125
+ this.exit(EXIT.VALIDATION);
126
+ }
127
+ else {
128
+ this.log(` ${icon.success} ${color.success('All checks passed.')} Run: ${color.bold('myclaude publish')}`);
129
+ }
130
+ }
131
+ if (hasBlocker) {
132
+ this.exit(EXIT.VALIDATION);
133
+ }
134
+ }
135
+ }
136
+ function readEntryFile(entry) {
137
+ try {
138
+ return readFileSync(resolve(process.cwd(), entry), 'utf-8');
139
+ }
140
+ catch {
141
+ return null;
142
+ }
143
+ }
144
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Whoami extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,52 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { getValidToken } from '../core/auth.js';
3
+ import { readConfig } from '../utils/config.js';
4
+ import { action, color, icon } from '../ui/index.js';
5
+ export default class Whoami extends Command {
6
+ static description = 'Show current authenticated user';
7
+ static examples = [
8
+ '<%= config.bin %> whoami',
9
+ '<%= config.bin %> whoami --json',
10
+ ];
11
+ static flags = {
12
+ json: Flags.boolean({ description: 'Output as JSON' }),
13
+ };
14
+ async run() {
15
+ const { flags } = await this.parse(Whoami);
16
+ const config = readConfig();
17
+ if (!config) {
18
+ if (flags.json) {
19
+ this.log(JSON.stringify({ loggedIn: false }));
20
+ }
21
+ else {
22
+ this.log(` ${icon.warning} not logged in`);
23
+ this.log(action('myclaude login'));
24
+ }
25
+ return;
26
+ }
27
+ const token = await getValidToken(config.email);
28
+ if (!token) {
29
+ if (flags.json) {
30
+ this.log(JSON.stringify({ expired: true, loggedIn: false }));
31
+ }
32
+ else {
33
+ this.log(` ${icon.warning} session expired`);
34
+ this.log(action('myclaude login'));
35
+ }
36
+ return;
37
+ }
38
+ if (flags.json) {
39
+ this.log(JSON.stringify({
40
+ displayName: config.displayName,
41
+ email: config.email,
42
+ loggedIn: true,
43
+ uid: config.uid,
44
+ username: config.username,
45
+ }));
46
+ }
47
+ else {
48
+ this.log(` ${color.primary('@' + config.username)} ${color.muted(`(${config.email})`)}`);
49
+ }
50
+ }
51
+ }
52
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAE,KAAK,EAAC,MAAM,aAAa,CAAA;AAE1C,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAC,MAAM,gBAAgB,CAAA;AAElD,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,OAAO;IACzC,MAAM,CAAU,WAAW,GAAG,iCAAiC,CAAA;IAE/D,MAAM,CAAU,QAAQ,GAAG;QACzB,0BAA0B;QAC1B,iCAAiC;KAClC,CAAA;IAED,MAAM,CAAU,KAAK,GAAG;QACtB,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,EAAC,WAAW,EAAE,gBAAgB,EAAC,CAAC;KACrD,CAAA;IAED,KAAK,CAAC,GAAG;QACP,MAAM,EAAC,KAAK,EAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;QAExC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;QAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;gBACf,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAC,QAAQ,EAAE,KAAK,EAAC,CAAC,CAAC,CAAA;YAC7C,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,OAAO,gBAAgB,CAAC,CAAA;gBAC3C,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAA;YACpC,CAAC;YAED,OAAM;QACR,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC/C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;gBACf,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAC,CAAC,CAAC,CAAA;YAC5D,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,OAAO,kBAAkB,CAAC,CAAA;gBAC7C,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAA;YACpC,CAAC;YAED,OAAM;QACR,CAAC;QAED,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YACf,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC;gBACtB,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,QAAQ,EAAE,IAAI;gBACd,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,QAAQ,EAAE,MAAM,CAAC,QAAQ;aAC1B,CAAC,CAAC,CAAA;QACL,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,OAAO,CAAC,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,CAAA;QAC3F,CAAC;IACH,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Production constants for MyClaude CLI.
3
+ *
4
+ * The CLI talks ONLY to myclaude.sh — no Firebase API keys,
5
+ * no Google endpoints. All auth is proxied through the backend.
6
+ */
7
+ export declare const MYCLAUDE_API_URL: string;
8
+ /** CLI version — injected from package.json at build time */
9
+ export declare const CLI_VERSION = "0.3.0-alpha";
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Production constants for MyClaude CLI.
3
+ *
4
+ * The CLI talks ONLY to myclaude.sh — no Firebase API keys,
5
+ * no Google endpoints. All auth is proxied through the backend.
6
+ */
7
+ export const MYCLAUDE_API_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://myclaude.sh';
8
+ /** CLI version — injected from package.json at build time */
9
+ export const CLI_VERSION = '0.3.0-alpha';
10
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,qBAAqB,CAAA;AAExF,6DAA6D;AAC7D,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAA"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * HTTP client for myClaude API routes.
3
+ * Auto-attaches auth token when available.
4
+ * Uses native fetch (Node.js >= 20) with timeout and safe error handling.
5
+ */
6
+ declare const DEFAULT_TIMEOUT_MS = 15000;
7
+ declare const MAX_TIMEOUT_MS = 60000;
8
+ export declare function getBaseUrl(): string;
9
+ export declare function apiGet(path: string, params?: Record<string, string>, options?: {
10
+ auth?: boolean;
11
+ timeout?: number;
12
+ }): Promise<Response>;
13
+ export declare function apiPost(path: string, body?: Record<string, unknown>, options?: {
14
+ auth?: boolean;
15
+ timeout?: number;
16
+ }): Promise<Response>;
17
+ export declare function requireAuth(): Promise<string>;
18
+ export { DEFAULT_TIMEOUT_MS, MAX_TIMEOUT_MS };
@@ -0,0 +1,135 @@
1
+ import { MYCLAUDE_API_URL } from '../constants.js';
2
+ import { readConfig } from '../utils/config.js';
3
+ import { getValidToken } from './auth.js';
4
+ /**
5
+ * HTTP client for myClaude API routes.
6
+ * Auto-attaches auth token when available.
7
+ * Uses native fetch (Node.js >= 20) with timeout and safe error handling.
8
+ */
9
+ const DEFAULT_TIMEOUT_MS = 15_000; // 15 seconds
10
+ const MAX_TIMEOUT_MS = 60_000; // 60 seconds for downloads
11
+ let httpsWarningShown = false;
12
+ export function getBaseUrl() {
13
+ const url = MYCLAUDE_API_URL;
14
+ if (!httpsWarningShown && !url.startsWith('https://') && !url.includes('localhost') && !url.includes('127.0.0.1')) {
15
+ httpsWarningShown = true;
16
+ process.stderr.write(`\x1b[33mWarning: API URL is not HTTPS: ${url}. Auth tokens may be exposed.\x1b[0m\n`);
17
+ }
18
+ return url;
19
+ }
20
+ /** Build a safe URL — validates base URL to prevent SSRF */
21
+ function buildUrl(path, params) {
22
+ const base = getBaseUrl();
23
+ const url = new URL(path, base);
24
+ // Ensure we're not being redirected to an unexpected host
25
+ const baseHost = new URL(base).host;
26
+ if (url.host !== baseHost) {
27
+ throw new Error('API URL host mismatch — possible redirect attack');
28
+ }
29
+ if (params) {
30
+ for (const [key, value] of Object.entries(params)) {
31
+ if (value !== undefined && value !== '') {
32
+ url.searchParams.set(key, value);
33
+ }
34
+ }
35
+ }
36
+ return url;
37
+ }
38
+ export async function apiGet(path, params, options) {
39
+ const url = buildUrl(path, params);
40
+ const timeout = options?.timeout ?? DEFAULT_TIMEOUT_MS;
41
+ const controller = new AbortController();
42
+ const timer = setTimeout(() => controller.abort(), timeout);
43
+ const headers = {
44
+ 'Accept': 'application/json',
45
+ 'X-Source': 'cli',
46
+ };
47
+ if (options?.auth !== false) {
48
+ const token = await getAuthToken();
49
+ if (token)
50
+ headers['Authorization'] = `Bearer ${token}`;
51
+ }
52
+ try {
53
+ const res = await fetch(url.toString(), {
54
+ headers,
55
+ signal: controller.signal,
56
+ });
57
+ return res;
58
+ }
59
+ catch (error) {
60
+ if (error.name === 'AbortError') {
61
+ throw new Error(`Request timed out after ${timeout / 1000}s — check your connection`);
62
+ }
63
+ throw wrapNetworkError(error);
64
+ }
65
+ finally {
66
+ clearTimeout(timer);
67
+ }
68
+ }
69
+ export async function apiPost(path, body, options) {
70
+ const url = buildUrl(path);
71
+ const timeout = options?.timeout ?? DEFAULT_TIMEOUT_MS;
72
+ const controller = new AbortController();
73
+ const timer = setTimeout(() => controller.abort(), timeout);
74
+ const headers = {
75
+ 'Accept': 'application/json',
76
+ 'Content-Type': 'application/json',
77
+ 'X-Source': 'cli',
78
+ };
79
+ if (options?.auth !== false) {
80
+ const token = await getAuthToken();
81
+ if (token) {
82
+ headers['Authorization'] = `Bearer ${token}`;
83
+ }
84
+ else if (options?.auth === true) {
85
+ throw new Error('Authentication required. Run: myclaude login');
86
+ }
87
+ }
88
+ try {
89
+ const res = await fetch(url.toString(), {
90
+ body: body ? JSON.stringify(body) : undefined,
91
+ headers,
92
+ method: 'POST',
93
+ signal: controller.signal,
94
+ });
95
+ return res;
96
+ }
97
+ catch (error) {
98
+ if (error.name === 'AbortError') {
99
+ throw new Error(`Request timed out after ${timeout / 1000}s — check your connection`);
100
+ }
101
+ throw wrapNetworkError(error);
102
+ }
103
+ finally {
104
+ clearTimeout(timer);
105
+ }
106
+ }
107
+ /** Convert raw network errors into human-readable messages */
108
+ function wrapNetworkError(error) {
109
+ const msg = error.message || '';
110
+ if (msg.includes('ECONNREFUSED')) {
111
+ return new Error('Cannot reach myClaude API — is the server running?');
112
+ }
113
+ if (msg.includes('ENOTFOUND') || msg.includes('getaddrinfo')) {
114
+ return new Error('DNS resolution failed — check your internet connection');
115
+ }
116
+ if (msg.includes('CERT') || msg.includes('SSL')) {
117
+ return new Error('SSL/TLS error — certificate verification failed');
118
+ }
119
+ return new Error(`Network error: ${msg}`);
120
+ }
121
+ async function getAuthToken() {
122
+ const config = readConfig();
123
+ if (!config?.email)
124
+ return null;
125
+ return getValidToken(config.email);
126
+ }
127
+ export async function requireAuth() {
128
+ const token = await getAuthToken();
129
+ if (!token) {
130
+ throw new Error('Authentication required. Run: myclaude login');
131
+ }
132
+ return token;
133
+ }
134
+ export { DEFAULT_TIMEOUT_MS, MAX_TIMEOUT_MS };
135
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/core/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * CLI authentication via myClaude backend.
3
+ *
4
+ * Token refresh goes through myclaude.sh/api/cli/auth/refresh
5
+ * so the Firebase API key NEVER leaves the server.
6
+ *
7
+ * The idToken is NEVER stored on disk (DC20) — only the
8
+ * refreshToken is persisted in the keychain/credentials file.
9
+ */
10
+ export interface AuthResult {
11
+ idToken: string;
12
+ refreshToken: string;
13
+ uid: string;
14
+ email: string;
15
+ }
16
+ export interface TokenRefreshResult {
17
+ idToken: string;
18
+ refreshToken: string;
19
+ }
20
+ export declare function refreshToken(refreshTkn: string): Promise<TokenRefreshResult>;
21
+ /**
22
+ * Get a valid idToken for API calls.
23
+ * Uses in-memory cache first, then refreshes from keychain.
24
+ * Returns null if not logged in.
25
+ */
26
+ export declare function getValidToken(email: string): Promise<string | null>;
27
+ export declare function logout(): Promise<void>;
28
+ export declare class AuthError extends Error {
29
+ constructor(message: string);
30
+ }
@@ -0,0 +1,71 @@
1
+ import { deleteToken, getToken, storeToken } from '../utils/keychain.js';
2
+ import { getBaseUrl } from './api.js';
3
+ // FIX H1: In-memory token cache to avoid multiple refreshes per process
4
+ let cachedIdToken = null;
5
+ let cachedTokenExpiry = 0;
6
+ export async function refreshToken(refreshTkn) {
7
+ const baseUrl = getBaseUrl();
8
+ let response;
9
+ try {
10
+ response = await fetch(`${baseUrl}/api/cli/auth/refresh`, {
11
+ body: JSON.stringify({ refreshToken: refreshTkn }),
12
+ headers: {
13
+ 'Content-Type': 'application/json',
14
+ 'X-Source': 'cli',
15
+ },
16
+ method: 'POST',
17
+ });
18
+ }
19
+ catch {
20
+ // FIX M3: distinguish network errors from auth errors
21
+ throw new AuthError('Cannot reach myClaude servers. Check your internet connection.');
22
+ }
23
+ if (!response.ok) {
24
+ throw new AuthError('Session expired. Run: myclaude login');
25
+ }
26
+ const data = await response.json();
27
+ return {
28
+ idToken: data.idToken,
29
+ refreshToken: data.refreshToken,
30
+ };
31
+ }
32
+ /**
33
+ * Get a valid idToken for API calls.
34
+ * Uses in-memory cache first, then refreshes from keychain.
35
+ * Returns null if not logged in.
36
+ */
37
+ export async function getValidToken(email) {
38
+ // FIX H1: return cached token if still valid
39
+ if (cachedIdToken && Date.now() < cachedTokenExpiry) {
40
+ return cachedIdToken;
41
+ }
42
+ const stored = await getToken(email);
43
+ if (!stored)
44
+ return null;
45
+ try {
46
+ const result = await refreshToken(stored);
47
+ // Update the stored refresh token (rotation)
48
+ await storeToken(email, result.refreshToken);
49
+ // Cache the new token
50
+ cachedIdToken = result.idToken;
51
+ cachedTokenExpiry = Date.now() + 55 * 60 * 1000;
52
+ return result.idToken;
53
+ }
54
+ catch {
55
+ cachedIdToken = null;
56
+ cachedTokenExpiry = 0;
57
+ return null;
58
+ }
59
+ }
60
+ export async function logout() {
61
+ cachedIdToken = null;
62
+ cachedTokenExpiry = 0;
63
+ await deleteToken();
64
+ }
65
+ export class AuthError extends Error {
66
+ constructor(message) {
67
+ super(message);
68
+ this.name = 'AuthError';
69
+ }
70
+ }
71
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/core/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAC,MAAM,sBAAsB,CAAA;AACtE,OAAO,EAAC,UAAU,EAAC,MAAM,UAAU,CAAA;AAwBnC,wEAAwE;AACxE,IAAI,aAAa,GAAkB,IAAI,CAAA;AACvC,IAAI,iBAAiB,GAAG,CAAC,CAAA;AAEzB,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAkB;IACnD,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAE5B,IAAI,QAAkB,CAAA;IACtB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,uBAAuB,EAAE;YACxD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAC,YAAY,EAAE,UAAU,EAAC,CAAC;YAChD,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,UAAU,EAAE,KAAK;aAClB;YACD,MAAM,EAAE,MAAM;SACf,CAAC,CAAA;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,sDAAsD;QACtD,MAAM,IAAI,SAAS,CACjB,gEAAgE,CACjE,CAAA;IACH,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,SAAS,CAAC,sCAAsC,CAAC,CAAA;IAC7D,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA4B,CAAA;IAC5D,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,YAAY,EAAE,IAAI,CAAC,YAAY;KAChC,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAa;IAC/C,6CAA6C;IAC7C,IAAI,aAAa,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,iBAAiB,EAAE,CAAC;QACpD,OAAO,aAAa,CAAA;IACtB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAA;IACpC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IAExB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAA;QACzC,6CAA6C;QAC7C,MAAM,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,YAAY,CAAC,CAAA;QAC5C,sBAAsB;QACtB,aAAa,GAAG,MAAM,CAAC,OAAO,CAAA;QAC9B,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;QAC/C,OAAO,MAAM,CAAC,OAAO,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,aAAa,GAAG,IAAI,CAAA;QACpB,iBAAiB,GAAG,CAAC,CAAA;QACrB,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM;IAC1B,aAAa,GAAG,IAAI,CAAA;IACpB,iBAAiB,GAAG,CAAC,CAAA;IACrB,MAAM,WAAW,EAAE,CAAA;AACrB,CAAC;AAED,MAAM,OAAO,SAAU,SAAQ,KAAK;IAClC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,WAAW,CAAA;IACzB,CAAC;CACF"}