solforge 0.2.3 → 0.2.5

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 (43) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +323 -364
  3. package/cli.cjs +126 -69
  4. package/package.json +1 -1
  5. package/scripts/install.sh +112 -0
  6. package/scripts/postinstall.cjs +66 -58
  7. package/server/methods/program/get-token-accounts-by-owner.ts +7 -2
  8. package/server/ws-server.ts +4 -1
  9. package/src/api-server-entry.ts +91 -91
  10. package/src/cli/commands/rpc-start.ts +4 -1
  11. package/src/cli/main.ts +39 -14
  12. package/src/cli/run-solforge.ts +20 -6
  13. package/src/commands/add-program.ts +324 -328
  14. package/src/commands/init.ts +106 -106
  15. package/src/commands/list.ts +125 -125
  16. package/src/commands/mint.ts +246 -246
  17. package/src/commands/start.ts +834 -831
  18. package/src/commands/status.ts +80 -80
  19. package/src/commands/stop.ts +381 -382
  20. package/src/config/manager.ts +149 -149
  21. package/src/gui/public/app.css +1556 -1
  22. package/src/gui/public/build/main.css +1569 -1
  23. package/src/gui/server.ts +20 -21
  24. package/src/gui/src/app.tsx +56 -37
  25. package/src/gui/src/components/airdrop-mint-form.tsx +17 -11
  26. package/src/gui/src/components/clone-program-modal.tsx +6 -6
  27. package/src/gui/src/components/clone-token-modal.tsx +7 -7
  28. package/src/gui/src/components/modal.tsx +13 -11
  29. package/src/gui/src/components/programs-panel.tsx +27 -15
  30. package/src/gui/src/components/status-panel.tsx +31 -17
  31. package/src/gui/src/components/tokens-panel.tsx +25 -19
  32. package/src/gui/src/index.css +491 -463
  33. package/src/index.ts +161 -146
  34. package/src/rpc/start.ts +1 -1
  35. package/src/services/api-server.ts +470 -473
  36. package/src/services/port-manager.ts +167 -167
  37. package/src/services/process-registry.ts +143 -143
  38. package/src/services/program-cloner.ts +312 -312
  39. package/src/services/token-cloner.ts +799 -797
  40. package/src/services/validator.ts +288 -288
  41. package/src/types/config.ts +71 -71
  42. package/src/utils/shell.ts +75 -75
  43. package/src/utils/token-loader.ts +77 -77
@@ -1,156 +1,156 @@
1
- import { readFileSync, writeFileSync, existsSync } from "fs";
1
+ import { existsSync, readFileSync, writeFileSync } from "fs";
2
2
  import { join, resolve } from "path";
3
- import { ConfigSchema } from "../types/config.js";
4
3
  import type { Config, ValidationResult } from "../types/config.js";
4
+ import { ConfigSchema } from "../types/config.js";
5
5
 
6
6
  export class ConfigManager {
7
- private config: Config | null = null;
8
- private configPath: string | null = null;
9
-
10
- /**
11
- * Load configuration from a file path
12
- */
13
- async load(configPath: string): Promise<Config> {
14
- try {
15
- const fullPath = resolve(configPath);
16
-
17
- if (!existsSync(fullPath)) {
18
- throw new Error(`Configuration file not found: ${fullPath}`);
19
- }
20
-
21
- const configContent = readFileSync(fullPath, "utf-8");
22
- const rawConfig = JSON.parse(configContent);
23
-
24
- // Validate and parse with Zod
25
- const result = ConfigSchema.safeParse(rawConfig);
26
-
27
- if (!result.success) {
28
- const errors = result.error.issues.map((issue) => ({
29
- path: issue.path.join("."),
30
- message: issue.message,
31
- }));
32
- throw new Error(
33
- `Configuration validation failed:\n${errors
34
- .map((e) => ` - ${e.path}: ${e.message}`)
35
- .join("\n")}`
36
- );
37
- }
38
-
39
- this.config = result.data;
40
- this.configPath = fullPath;
41
-
42
- return this.config;
43
- } catch (error) {
44
- if (error instanceof SyntaxError) {
45
- throw new Error(`Invalid JSON in configuration file: ${error.message}`);
46
- }
47
- throw error;
48
- }
49
- }
50
-
51
- /**
52
- * Save current configuration to file
53
- */
54
- async save(configPath?: string): Promise<void> {
55
- if (!this.config) {
56
- throw new Error("No configuration loaded");
57
- }
58
-
59
- const targetPath = configPath || this.configPath;
60
- if (!targetPath) {
61
- throw new Error("No configuration path specified");
62
- }
63
-
64
- try {
65
- const configContent = JSON.stringify(this.config, null, 2);
66
- writeFileSync(targetPath, configContent, "utf-8");
67
- this.configPath = targetPath;
68
- } catch (error) {
69
- throw new Error(
70
- `Failed to save configuration: ${
71
- error instanceof Error ? error.message : String(error)
72
- }`
73
- );
74
- }
75
- }
76
-
77
- /**
78
- * Validate a configuration object
79
- */
80
- validate(config: any): ValidationResult {
81
- const result = ConfigSchema.safeParse(config);
82
-
83
- if (result.success) {
84
- return { valid: true, errors: [] };
85
- }
86
-
87
- const errors = result.error.issues.map((issue) => ({
88
- path: issue.path.join("."),
89
- message: issue.message,
90
- }));
91
-
92
- return { valid: false, errors };
93
- }
94
-
95
- /**
96
- * Create a default configuration
97
- */
98
- createDefault(): Config {
99
- const defaultConfig = ConfigSchema.parse({});
100
- this.config = defaultConfig;
101
- return defaultConfig;
102
- }
103
-
104
- /**
105
- * Get current configuration
106
- */
107
- getConfig(): Config {
108
- if (!this.config) {
109
- throw new Error("No configuration loaded. Call load() first.");
110
- }
111
- return this.config;
112
- }
113
-
114
- /**
115
- * Update configuration
116
- */
117
- updateConfig(updates: Partial<Config>): Config {
118
- if (!this.config) {
119
- throw new Error("No configuration loaded. Call load() first.");
120
- }
121
-
122
- const updated = { ...this.config, ...updates };
123
- const result = ConfigSchema.safeParse(updated);
124
-
125
- if (!result.success) {
126
- const errors = result.error.issues.map((issue) => ({
127
- path: issue.path.join("."),
128
- message: issue.message,
129
- }));
130
- throw new Error(
131
- `Configuration update validation failed:\n${errors
132
- .map((e) => ` - ${e.path}: ${e.message}`)
133
- .join("\n")}`
134
- );
135
- }
136
-
137
- this.config = result.data;
138
- return this.config;
139
- }
140
-
141
- /**
142
- * Get configuration file path
143
- */
144
- getConfigPath(): string | null {
145
- return this.configPath;
146
- }
147
-
148
- /**
149
- * Check if configuration is loaded
150
- */
151
- isLoaded(): boolean {
152
- return this.config !== null;
153
- }
7
+ private config: Config | null = null;
8
+ private configPath: string | null = null;
9
+
10
+ /**
11
+ * Load configuration from a file path
12
+ */
13
+ async load(configPath: string): Promise<Config> {
14
+ try {
15
+ const fullPath = resolve(configPath);
16
+
17
+ if (!existsSync(fullPath)) {
18
+ throw new Error(`Configuration file not found: ${fullPath}`);
19
+ }
20
+
21
+ const configContent = readFileSync(fullPath, "utf-8");
22
+ const rawConfig = JSON.parse(configContent);
23
+
24
+ // Validate and parse with Zod
25
+ const result = ConfigSchema.safeParse(rawConfig);
26
+
27
+ if (!result.success) {
28
+ const errors = result.error.issues.map((issue) => ({
29
+ path: issue.path.join("."),
30
+ message: issue.message,
31
+ }));
32
+ throw new Error(
33
+ `Configuration validation failed:\n${errors
34
+ .map((e) => ` - ${e.path}: ${e.message}`)
35
+ .join("\n")}`,
36
+ );
37
+ }
38
+
39
+ this.config = result.data;
40
+ this.configPath = fullPath;
41
+
42
+ return this.config;
43
+ } catch (error) {
44
+ if (error instanceof SyntaxError) {
45
+ throw new Error(`Invalid JSON in configuration file: ${error.message}`);
46
+ }
47
+ throw error;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Save current configuration to file
53
+ */
54
+ async save(configPath?: string): Promise<void> {
55
+ if (!this.config) {
56
+ throw new Error("No configuration loaded");
57
+ }
58
+
59
+ const targetPath = configPath || this.configPath;
60
+ if (!targetPath) {
61
+ throw new Error("No configuration path specified");
62
+ }
63
+
64
+ try {
65
+ const configContent = JSON.stringify(this.config, null, 2);
66
+ writeFileSync(targetPath, configContent, "utf-8");
67
+ this.configPath = targetPath;
68
+ } catch (error) {
69
+ throw new Error(
70
+ `Failed to save configuration: ${
71
+ error instanceof Error ? error.message : String(error)
72
+ }`,
73
+ );
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Validate a configuration object
79
+ */
80
+ validate(config: any): ValidationResult {
81
+ const result = ConfigSchema.safeParse(config);
82
+
83
+ if (result.success) {
84
+ return { valid: true, errors: [] };
85
+ }
86
+
87
+ const errors = result.error.issues.map((issue) => ({
88
+ path: issue.path.join("."),
89
+ message: issue.message,
90
+ }));
91
+
92
+ return { valid: false, errors };
93
+ }
94
+
95
+ /**
96
+ * Create a default configuration
97
+ */
98
+ createDefault(): Config {
99
+ const defaultConfig = ConfigSchema.parse({});
100
+ this.config = defaultConfig;
101
+ return defaultConfig;
102
+ }
103
+
104
+ /**
105
+ * Get current configuration
106
+ */
107
+ getConfig(): Config {
108
+ if (!this.config) {
109
+ throw new Error("No configuration loaded. Call load() first.");
110
+ }
111
+ return this.config;
112
+ }
113
+
114
+ /**
115
+ * Update configuration
116
+ */
117
+ updateConfig(updates: Partial<Config>): Config {
118
+ if (!this.config) {
119
+ throw new Error("No configuration loaded. Call load() first.");
120
+ }
121
+
122
+ const updated = { ...this.config, ...updates };
123
+ const result = ConfigSchema.safeParse(updated);
124
+
125
+ if (!result.success) {
126
+ const errors = result.error.issues.map((issue) => ({
127
+ path: issue.path.join("."),
128
+ message: issue.message,
129
+ }));
130
+ throw new Error(
131
+ `Configuration update validation failed:\n${errors
132
+ .map((e) => ` - ${e.path}: ${e.message}`)
133
+ .join("\n")}`,
134
+ );
135
+ }
136
+
137
+ this.config = result.data;
138
+ return this.config;
139
+ }
140
+
141
+ /**
142
+ * Get configuration file path
143
+ */
144
+ getConfigPath(): string | null {
145
+ return this.configPath;
146
+ }
147
+
148
+ /**
149
+ * Check if configuration is loaded
150
+ */
151
+ isLoaded(): boolean {
152
+ return this.config !== null;
153
+ }
154
154
  }
155
155
 
156
156
  // Singleton instance