@secondlayer/cli 0.1.0 → 0.2.0

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.
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Configuration types for @secondlayer/cli
3
+ */
4
+ type NetworkName = "mainnet" | "testnet" | "devnet";
5
+ interface ContractSource {
6
+ /**
7
+ * Contract identifier (address.name) for deployed contracts
8
+ */
9
+ address?: string | Partial<Record<NetworkName, string>>;
10
+ /**
11
+ * Path to local Clarity file
12
+ */
13
+ source?: string;
14
+ /**
15
+ * Optional name to use in generated code
16
+ */
17
+ name?: string;
18
+ }
19
+ interface StacksConfig {
20
+ /**
21
+ * Contracts to generate interfaces for (optional - plugins can provide these)
22
+ */
23
+ contracts?: ContractSource[];
24
+ /**
25
+ * Output file path
26
+ */
27
+ out: string;
28
+ /**
29
+ * Plugins to use for generation
30
+ */
31
+ plugins?: any[];
32
+ /**
33
+ * Network to use for fetching contracts
34
+ */
35
+ network?: NetworkName;
36
+ /**
37
+ * API key for Stacks API (if required)
38
+ */
39
+ apiKey?: string;
40
+ /**
41
+ * Base URL for Stacks API (optional override)
42
+ */
43
+ apiUrl?: string;
44
+ }
45
+ interface ResolvedContract {
46
+ name: string;
47
+ address: string;
48
+ contractName: string;
49
+ abi: any;
50
+ source: "api" | "local";
51
+ }
52
+ /**
53
+ * Core plugin interface that all plugins must implement
54
+ */
55
+ interface StacksCodegenPlugin {
56
+ /** Plugin name (should be unique) */
57
+ name: string;
58
+ /** Plugin version */
59
+ version: string;
60
+ /** Called after config is resolved but before generation starts */
61
+ configResolved?: (config: ResolvedConfig) => void | Promise<void>;
62
+ /** Called before generation starts */
63
+ beforeGenerate?: (context: GenerateContext) => void | Promise<void>;
64
+ /** Called during generation phase - plugins can add their own outputs */
65
+ generate?: (context: GenerateContext) => void | Promise<void>;
66
+ /** Called after all generation is complete */
67
+ afterGenerate?: (context: GenerateContext) => void | Promise<void>;
68
+ /** Transform user config before resolution */
69
+ transformConfig?: (config: UserConfig) => UserConfig | Promise<UserConfig>;
70
+ /** Transform individual contracts during processing */
71
+ transformContract?: (contract: ContractConfig) => ContractConfig | Promise<ContractConfig>;
72
+ /** Transform generated output before writing to disk */
73
+ transformOutput?: (output: string, type: OutputType) => string | Promise<string>;
74
+ }
75
+ /**
76
+ * User configuration (before plugin transformations)
77
+ */
78
+ type UserConfig = StacksConfig;
79
+ /**
80
+ * Resolved configuration (after plugin transformations)
81
+ */
82
+ interface ResolvedConfig extends StacksConfig {
83
+ /** Resolved plugins array */
84
+ plugins: StacksCodegenPlugin[];
85
+ }
86
+ /**
87
+ * Contract configuration that can be transformed by plugins
88
+ */
89
+ interface ContractConfig {
90
+ name?: string;
91
+ address?: string | Partial<Record<NetworkName, string>>;
92
+ source?: string;
93
+ abi?: any;
94
+ metadata?: Record<string, any>;
95
+ }
96
+ /**
97
+ * Processed contract with resolved ABI and metadata
98
+ */
99
+ interface ProcessedContract extends ResolvedContract {
100
+ /** Additional metadata added by plugins */
101
+ metadata?: Record<string, any>;
102
+ }
103
+ /**
104
+ * Generated output from plugins
105
+ */
106
+ interface GeneratedOutput {
107
+ /** File path where output should be written */
108
+ path: string;
109
+ /** Generated content */
110
+ content: string;
111
+ /** Output type for transformation hooks */
112
+ type?: OutputType;
113
+ /** Whether this output should overwrite existing files */
114
+ overwrite?: boolean;
115
+ }
116
+ /**
117
+ * Types of outputs that can be generated
118
+ */
119
+ type OutputType = "contracts" | "hooks" | "actions" | "types" | "utils" | "config" | "other";
120
+ /**
121
+ * Base context available to all plugin hooks
122
+ */
123
+ interface PluginContext {
124
+ /** Resolved configuration */
125
+ config: ResolvedConfig;
126
+ /** Logger for plugin output */
127
+ logger: Logger;
128
+ /** Utility functions for plugins */
129
+ utils: PluginUtils;
130
+ }
131
+ /**
132
+ * Context available during generation phase
133
+ */
134
+ interface GenerateContext extends PluginContext {
135
+ /** Processed contracts ready for generation */
136
+ contracts: ProcessedContract[];
137
+ /** Map of output keys to generated content */
138
+ outputs: Map<string, GeneratedOutput>;
139
+ /** Function to augment existing outputs */
140
+ augment: (outputKey: string, contractName: string, content: any) => void;
141
+ /** Function to add new outputs */
142
+ addOutput: (key: string, output: GeneratedOutput) => void;
143
+ }
144
+ /**
145
+ * Logger interface for plugin output
146
+ */
147
+ interface Logger {
148
+ info: (message: string) => void;
149
+ warn: (message: string) => void;
150
+ error: (message: string) => void;
151
+ debug: (message: string) => void;
152
+ success: (message: string) => void;
153
+ }
154
+ /**
155
+ * Utility functions available to plugins
156
+ */
157
+ interface PluginUtils {
158
+ /** Convert kebab-case to camelCase */
159
+ toCamelCase: (str: string) => string;
160
+ /** Convert camelCase to kebab-case */
161
+ toKebabCase: (str: string) => string;
162
+ /** Validate Stacks address format */
163
+ validateAddress: (address: string) => boolean;
164
+ /** Parse contract identifier (address.contract-name) */
165
+ parseContractId: (contractId: string) => {
166
+ address: string
167
+ contractName: string
168
+ };
169
+ /** Format TypeScript code using prettier */
170
+ formatCode: (code: string) => Promise<string>;
171
+ /** Resolve file path relative to project root */
172
+ resolvePath: (relativePath: string) => string;
173
+ /** Check if file exists */
174
+ fileExists: (path: string) => Promise<boolean>;
175
+ /** Read file content */
176
+ readFile: (path: string) => Promise<string>;
177
+ /** Write file content */
178
+ writeFile: (path: string, content: string) => Promise<void>;
179
+ /** Create directory recursively */
180
+ ensureDir: (path: string) => Promise<void>;
181
+ }
182
+ /**
183
+ * Hook execution result
184
+ */
185
+ interface HookResult<T = any> {
186
+ /** Whether the hook was successful */
187
+ success: boolean;
188
+ /** Result data from the hook */
189
+ data?: T;
190
+ /** Error if hook failed */
191
+ error?: Error;
192
+ /** Plugin that executed the hook */
193
+ plugin: string;
194
+ }
195
+ /**
196
+ * Core plugin manager that orchestrates plugin execution
197
+ */
198
+ declare class PluginManager {
199
+ private plugins;
200
+ private logger;
201
+ private utils;
202
+ private executionContext;
203
+ constructor();
204
+ /**
205
+ * Register a plugin
206
+ */
207
+ register(plugin: StacksCodegenPlugin): void;
208
+ /**
209
+ * Get all registered plugins
210
+ */
211
+ getPlugins(): StacksCodegenPlugin[];
212
+ /**
213
+ * Transform user config through all plugins
214
+ */
215
+ transformConfig(config: UserConfig): Promise<ResolvedConfig>;
216
+ /**
217
+ * Transform contracts through all plugins
218
+ */
219
+ transformContracts(contracts: ContractConfig[], _config: ResolvedConfig): Promise<ProcessedContract[]>;
220
+ /**
221
+ * Execute lifecycle hooks
222
+ */
223
+ executeHook(hookName: keyof StacksCodegenPlugin, context: any): Promise<void>;
224
+ /**
225
+ * Execute generation phase with full context
226
+ */
227
+ executeGeneration(contracts: ProcessedContract[], config: ResolvedConfig): Promise<Map<string, GeneratedOutput>>;
228
+ /**
229
+ * Transform outputs through plugins
230
+ */
231
+ transformOutputs(outputs: Map<string, GeneratedOutput>): Promise<Map<string, GeneratedOutput>>;
232
+ /**
233
+ * Write outputs to disk
234
+ */
235
+ writeOutputs(outputs: Map<string, GeneratedOutput>): Promise<void>;
236
+ /**
237
+ * Get execution results for debugging
238
+ */
239
+ getExecutionResults(): Map<string, HookResult[]>;
240
+ /**
241
+ * Augment existing output with additional content
242
+ */
243
+ private augmentOutput;
244
+ /**
245
+ * Record hook execution result
246
+ */
247
+ private recordHookResult;
248
+ /**
249
+ * Create logger instance
250
+ */
251
+ private createLogger;
252
+ /**
253
+ * Create utils instance
254
+ */
255
+ private createUtils;
256
+ }
257
+ export { PluginManager };
@@ -1,44 +1,38 @@
1
+ // @bun
1
2
  // src/core/plugin-manager.ts
2
3
  import { format } from "prettier";
3
4
  import { promises as fs } from "fs";
4
5
  import path from "path";
5
6
  import { validateStacksAddress } from "@stacks/transactions";
6
- var PluginManager = class {
7
+
8
+ class PluginManager {
9
+ plugins = [];
10
+ logger;
11
+ utils;
12
+ executionContext;
7
13
  constructor() {
8
- this.plugins = [];
9
14
  this.logger = this.createLogger();
10
15
  this.utils = this.createUtils();
11
16
  this.executionContext = {
12
17
  phase: "config",
13
18
  startTime: Date.now(),
14
- results: /* @__PURE__ */ new Map()
19
+ results: new Map
15
20
  };
16
21
  }
17
- /**
18
- * Register a plugin
19
- */
20
22
  register(plugin) {
21
23
  if (!plugin.name || !plugin.version) {
22
24
  throw new Error("Plugin must have a name and version");
23
25
  }
24
26
  const existing = this.plugins.find((p) => p.name === plugin.name);
25
27
  if (existing) {
26
- throw new Error(
27
- `Plugin "${plugin.name}" is already registered (version ${existing.version})`
28
- );
28
+ throw new Error(`Plugin "${plugin.name}" is already registered (version ${existing.version})`);
29
29
  }
30
30
  this.plugins.push(plugin);
31
31
  this.logger.debug(`Registered plugin: ${plugin.name}@${plugin.version}`);
32
32
  }
33
- /**
34
- * Get all registered plugins
35
- */
36
33
  getPlugins() {
37
34
  return [...this.plugins];
38
35
  }
39
- /**
40
- * Transform user config through all plugins
41
- */
42
36
  async transformConfig(config) {
43
37
  this.executionContext.phase = "config";
44
38
  let transformedConfig = { ...config };
@@ -57,9 +51,7 @@ var PluginManager = class {
57
51
  success: false,
58
52
  error: err
59
53
  });
60
- throw new Error(
61
- `Plugin "${plugin.name}" failed during config transformation: ${err.message}`
62
- );
54
+ throw new Error(`Plugin "${plugin.name}" failed during config transformation: ${err.message}`);
63
55
  }
64
56
  }
65
57
  }
@@ -69,9 +61,6 @@ var PluginManager = class {
69
61
  };
70
62
  return resolvedConfig;
71
63
  }
72
- /**
73
- * Transform contracts through all plugins
74
- */
75
64
  async transformContracts(contracts, _config) {
76
65
  const processedContracts = [];
77
66
  for (let contract of contracts) {
@@ -89,6 +78,20 @@ var PluginManager = class {
89
78
  processedContracts.push(processed);
90
79
  continue;
91
80
  }
81
+ if (contract._directFile && contract.abi) {
82
+ const address = typeof contract.address === "string" ? contract.address : "";
83
+ const [contractAddress, contractName] = address.split(".");
84
+ const processed = {
85
+ name: contract.name || contractName,
86
+ address: contractAddress,
87
+ contractName,
88
+ abi: contract.abi,
89
+ source: "local",
90
+ metadata: { source: "direct" }
91
+ };
92
+ processedContracts.push(processed);
93
+ continue;
94
+ }
92
95
  for (const plugin of this.plugins) {
93
96
  if (plugin.transformContract) {
94
97
  this.executionContext.currentPlugin = plugin;
@@ -103,9 +106,7 @@ var PluginManager = class {
103
106
  success: false,
104
107
  error: err
105
108
  });
106
- this.logger.warn(
107
- `Plugin "${plugin.name}" failed to transform contract: ${err.message}`
108
- );
109
+ this.logger.warn(`Plugin "${plugin.name}" failed to transform contract: ${err.message}`);
109
110
  }
110
111
  }
111
112
  }
@@ -116,7 +117,6 @@ var PluginManager = class {
116
117
  contractName: contract.name || "unknown",
117
118
  abi: contract.abi,
118
119
  source: "api",
119
- // Use "api" as default for plugin-processed contracts
120
120
  metadata: contract.metadata
121
121
  };
122
122
  processedContracts.push(processed);
@@ -124,9 +124,6 @@ var PluginManager = class {
124
124
  }
125
125
  return processedContracts;
126
126
  }
127
- /**
128
- * Execute lifecycle hooks
129
- */
130
127
  async executeHook(hookName, context) {
131
128
  for (const plugin of this.plugins) {
132
129
  const hook = plugin[hookName];
@@ -143,19 +140,14 @@ var PluginManager = class {
143
140
  success: false,
144
141
  error: err
145
142
  });
146
- this.logger.error(
147
- `Plugin "${plugin.name}" failed during ${hookName}: ${err.message}`
148
- );
143
+ this.logger.error(`Plugin "${plugin.name}" failed during ${hookName}: ${err.message}`);
149
144
  }
150
145
  }
151
146
  }
152
147
  }
153
- /**
154
- * Execute generation phase with full context
155
- */
156
148
  async executeGeneration(contracts, config) {
157
149
  this.executionContext.phase = "generate";
158
- const outputs = /* @__PURE__ */ new Map();
150
+ const outputs = new Map;
159
151
  const context = {
160
152
  config,
161
153
  logger: this.logger,
@@ -174,22 +166,16 @@ var PluginManager = class {
174
166
  await this.executeHook("afterGenerate", context);
175
167
  return outputs;
176
168
  }
177
- /**
178
- * Transform outputs through plugins
179
- */
180
169
  async transformOutputs(outputs) {
181
170
  this.executionContext.phase = "output";
182
- const transformedOutputs = /* @__PURE__ */ new Map();
171
+ const transformedOutputs = new Map;
183
172
  for (const [key, output] of outputs) {
184
173
  let transformedContent = output.content;
185
174
  for (const plugin of this.plugins) {
186
175
  if (plugin.transformOutput) {
187
176
  this.executionContext.currentPlugin = plugin;
188
177
  try {
189
- transformedContent = await plugin.transformOutput(
190
- transformedContent,
191
- output.type || "other"
192
- );
178
+ transformedContent = await plugin.transformOutput(transformedContent, output.type || "other");
193
179
  this.recordHookResult(plugin.name, "transformOutput", {
194
180
  success: true
195
181
  });
@@ -199,9 +185,7 @@ var PluginManager = class {
199
185
  success: false,
200
186
  error: err
201
187
  });
202
- this.logger.warn(
203
- `Plugin "${plugin.name}" failed to transform output: ${err.message}`
204
- );
188
+ this.logger.warn(`Plugin "${plugin.name}" failed to transform output: ${err.message}`);
205
189
  }
206
190
  }
207
191
  }
@@ -212,9 +196,6 @@ var PluginManager = class {
212
196
  }
213
197
  return transformedOutputs;
214
198
  }
215
- /**
216
- * Write outputs to disk
217
- */
218
199
  async writeOutputs(outputs) {
219
200
  for (const [, output] of outputs) {
220
201
  try {
@@ -228,15 +209,9 @@ var PluginManager = class {
228
209
  }
229
210
  }
230
211
  }
231
- /**
232
- * Get execution results for debugging
233
- */
234
212
  getExecutionResults() {
235
213
  return new Map(this.executionContext.results);
236
214
  }
237
- /**
238
- * Augment existing output with additional content
239
- */
240
215
  augmentOutput(outputs, outputKey, contractName, content) {
241
216
  const existing = outputs.get(outputKey);
242
217
  if (!existing) {
@@ -252,18 +227,12 @@ ${JSON.stringify(content, null, 2)}`;
252
227
  content: augmentedContent
253
228
  });
254
229
  }
255
- /**
256
- * Record hook execution result
257
- */
258
230
  recordHookResult(pluginName, hookName, result) {
259
231
  const key = `${pluginName}:${hookName}`;
260
232
  const existing = this.executionContext.results.get(key) || [];
261
233
  existing.push({ ...result, plugin: pluginName });
262
234
  this.executionContext.results.set(key, existing);
263
235
  }
264
- /**
265
- * Create logger instance
266
- */
267
236
  createLogger() {
268
237
  return {
269
238
  info: (message) => console.log(`\u2139\uFE0F ${message}`),
@@ -271,15 +240,12 @@ ${JSON.stringify(content, null, 2)}`;
271
240
  error: (message) => console.error(`\u274C ${message}`),
272
241
  debug: (message) => {
273
242
  if (process.env.DEBUG) {
274
- console.log(`\u{1F41B} ${message}`);
243
+ console.log(`\uD83D\uDC1B ${message}`);
275
244
  }
276
245
  },
277
246
  success: (message) => console.log(`\u2705 ${message}`)
278
247
  };
279
248
  }
280
- /**
281
- * Create utils instance
282
- */
283
249
  createUtils() {
284
250
  return {
285
251
  toCamelCase: (str) => {
@@ -326,8 +292,10 @@ ${JSON.stringify(content, null, 2)}`;
326
292
  }
327
293
  };
328
294
  }
329
- };
295
+ }
330
296
  export {
331
297
  PluginManager
332
298
  };
333
- //# sourceMappingURL=plugin-manager.js.map
299
+
300
+ //# debugId=5975310D6EA97DB264756E2164756E21
301
+ //# sourceMappingURL=plugin-manager.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/core/plugin-manager.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Plugin Manager for @secondlayer/cli\n * Handles plugin registration, lifecycle execution, and output management\n */\n\nimport { format } from \"prettier\";\nimport { promises as fs } from \"fs\";\nimport path from \"path\";\nimport { validateStacksAddress } from \"@stacks/transactions\";\nimport type {\n StacksCodegenPlugin,\n UserConfig,\n ResolvedConfig,\n GenerateContext,\n Logger,\n PluginUtils,\n GeneratedOutput,\n ProcessedContract,\n ContractConfig,\n HookResult,\n PluginExecutionContext,\n} from \"../types/plugin\";\n\n/**\n * Core plugin manager that orchestrates plugin execution\n */\nexport class PluginManager {\n private plugins: StacksCodegenPlugin[] = [];\n private logger: Logger;\n private utils: PluginUtils;\n private executionContext: PluginExecutionContext;\n\n constructor() {\n this.logger = this.createLogger();\n this.utils = this.createUtils();\n this.executionContext = {\n phase: \"config\",\n startTime: Date.now(),\n results: new Map(),\n };\n }\n\n /**\n * Register a plugin\n */\n register(plugin: StacksCodegenPlugin): void {\n // Validate plugin\n if (!plugin.name || !plugin.version) {\n throw new Error(\"Plugin must have a name and version\");\n }\n\n // Check for duplicate plugin names\n const existing = this.plugins.find((p) => p.name === plugin.name);\n if (existing) {\n throw new Error(\n `Plugin \"${plugin.name}\" is already registered (version ${existing.version})`\n );\n }\n\n this.plugins.push(plugin);\n this.logger.debug(`Registered plugin: ${plugin.name}@${plugin.version}`);\n }\n\n /**\n * Get all registered plugins\n */\n getPlugins(): StacksCodegenPlugin[] {\n return [...this.plugins];\n }\n\n /**\n * Transform user config through all plugins\n */\n async transformConfig(config: UserConfig): Promise<ResolvedConfig> {\n this.executionContext.phase = \"config\";\n let transformedConfig = { ...config };\n\n for (const plugin of this.plugins) {\n if (plugin.transformConfig) {\n this.executionContext.currentPlugin = plugin;\n try {\n const result = await plugin.transformConfig(transformedConfig);\n transformedConfig = result;\n this.recordHookResult(plugin.name, \"transformConfig\", {\n success: true,\n });\n } catch (error) {\n const err = error as Error;\n this.recordHookResult(plugin.name, \"transformConfig\", {\n success: false,\n error: err,\n });\n throw new Error(\n `Plugin \"${plugin.name}\" failed during config transformation: ${err.message}`\n );\n }\n }\n }\n\n // Add plugins array to resolved config\n const resolvedConfig: ResolvedConfig = {\n ...transformedConfig,\n plugins: this.plugins,\n };\n\n return resolvedConfig;\n }\n\n /**\n * Transform contracts through all plugins\n */\n async transformContracts(\n contracts: ContractConfig[],\n _config: ResolvedConfig\n ): Promise<ProcessedContract[]> {\n const processedContracts: ProcessedContract[] = [];\n\n for (let contract of contracts) {\n // Handle special case for Clarinet plugin contracts\n if ((contract as any)._clarinetSource && contract.abi) {\n // Convert Clarinet contracts directly to ProcessedContract format\n const address =\n typeof contract.address === \"string\" ? contract.address : \"\";\n const [contractAddress, contractName] = address.split(\".\");\n const processed: ProcessedContract = {\n name: contract.name || contractName,\n address: contractAddress,\n contractName: contractName,\n abi: contract.abi,\n source: \"local\" as const,\n metadata: { source: \"clarinet\" },\n };\n processedContracts.push(processed);\n continue;\n }\n\n // Handle direct file mode contracts (already have ABIs parsed)\n if ((contract as any)._directFile && contract.abi) {\n const address =\n typeof contract.address === \"string\" ? contract.address : \"\";\n const [contractAddress, contractName] = address.split(\".\");\n const processed: ProcessedContract = {\n name: contract.name || contractName,\n address: contractAddress,\n contractName: contractName,\n abi: contract.abi,\n source: \"local\" as const,\n metadata: { source: \"direct\" },\n };\n processedContracts.push(processed);\n continue;\n }\n\n // Transform through each plugin\n for (const plugin of this.plugins) {\n if (plugin.transformContract) {\n this.executionContext.currentPlugin = plugin;\n try {\n contract = await plugin.transformContract(contract);\n this.recordHookResult(plugin.name, \"transformContract\", {\n success: true,\n });\n } catch (error) {\n const err = error as Error;\n this.recordHookResult(plugin.name, \"transformContract\", {\n success: false,\n error: err,\n });\n this.logger.warn(\n `Plugin \"${plugin.name}\" failed to transform contract: ${err.message}`\n );\n }\n }\n }\n\n // Convert to ProcessedContract\n if (contract.abi) {\n const processed: ProcessedContract = {\n name: contract.name || \"unknown\",\n address:\n typeof contract.address === \"string\"\n ? contract.address.split(\".\")[0]\n : \"unknown\",\n contractName: contract.name || \"unknown\",\n abi: contract.abi,\n source: \"api\" as const, // Use \"api\" as default for plugin-processed contracts\n metadata: contract.metadata,\n };\n processedContracts.push(processed);\n }\n }\n\n return processedContracts;\n }\n\n /**\n * Execute lifecycle hooks\n */\n async executeHook(\n hookName: keyof StacksCodegenPlugin,\n context: any\n ): Promise<void> {\n for (const plugin of this.plugins) {\n const hook = plugin[hookName];\n if (typeof hook === \"function\") {\n this.executionContext.currentPlugin = plugin;\n try {\n await (hook as any).call(plugin, context);\n this.recordHookResult(plugin.name, hookName as string, {\n success: true,\n });\n } catch (error) {\n const err = error as Error;\n this.recordHookResult(plugin.name, hookName as string, {\n success: false,\n error: err,\n });\n this.logger.error(\n `Plugin \"${plugin.name}\" failed during ${hookName as string}: ${err.message}`\n );\n // Don't throw - allow other plugins to continue\n }\n }\n }\n }\n\n /**\n * Execute generation phase with full context\n */\n async executeGeneration(\n contracts: ProcessedContract[],\n config: ResolvedConfig\n ): Promise<Map<string, GeneratedOutput>> {\n this.executionContext.phase = \"generate\";\n const outputs = new Map<string, GeneratedOutput>();\n\n // Create generation context\n const context: GenerateContext = {\n config,\n logger: this.logger,\n utils: this.utils,\n contracts,\n outputs,\n augment: (outputKey: string, contractName: string, content: any) => {\n this.augmentOutput(outputs, outputKey, contractName, content);\n },\n addOutput: (key: string, output: GeneratedOutput) => {\n outputs.set(key, output);\n },\n };\n\n // Execute beforeGenerate hooks\n await this.executeHook(\"beforeGenerate\", context);\n\n // Execute generate hooks\n await this.executeHook(\"generate\", context);\n\n // Execute afterGenerate hooks\n await this.executeHook(\"afterGenerate\", context);\n\n return outputs;\n }\n\n /**\n * Transform outputs through plugins\n */\n async transformOutputs(\n outputs: Map<string, GeneratedOutput>\n ): Promise<Map<string, GeneratedOutput>> {\n this.executionContext.phase = \"output\";\n const transformedOutputs = new Map<string, GeneratedOutput>();\n\n for (const [key, output] of outputs) {\n let transformedContent = output.content;\n\n for (const plugin of this.plugins) {\n if (plugin.transformOutput) {\n this.executionContext.currentPlugin = plugin;\n try {\n transformedContent = await plugin.transformOutput(\n transformedContent,\n output.type || \"other\"\n );\n this.recordHookResult(plugin.name, \"transformOutput\", {\n success: true,\n });\n } catch (error) {\n const err = error as Error;\n this.recordHookResult(plugin.name, \"transformOutput\", {\n success: false,\n error: err,\n });\n this.logger.warn(\n `Plugin \"${plugin.name}\" failed to transform output: ${err.message}`\n );\n }\n }\n }\n\n transformedOutputs.set(key, {\n ...output,\n content: transformedContent,\n });\n }\n\n return transformedOutputs;\n }\n\n /**\n * Write outputs to disk\n */\n async writeOutputs(outputs: Map<string, GeneratedOutput>): Promise<void> {\n for (const [, output] of outputs) {\n try {\n const resolvedPath = path.resolve(process.cwd(), output.path);\n await this.utils.ensureDir(path.dirname(resolvedPath));\n await this.utils.writeFile(resolvedPath, output.content);\n // Don't log here - let the main command handle success messaging\n } catch (error) {\n const err = error as Error;\n this.logger.error(`Failed to write ${output.path}: ${err.message}`);\n throw err;\n }\n }\n }\n\n /**\n * Get execution results for debugging\n */\n getExecutionResults(): Map<string, HookResult[]> {\n return new Map(this.executionContext.results);\n }\n\n /**\n * Augment existing output with additional content\n */\n private augmentOutput(\n outputs: Map<string, GeneratedOutput>,\n outputKey: string,\n contractName: string,\n content: any\n ): void {\n const existing = outputs.get(outputKey);\n if (!existing) {\n this.logger.warn(`Cannot augment non-existent output: ${outputKey}`);\n return;\n }\n\n // Simple augmentation - append content\n // In a real implementation, this would be more sophisticated\n const augmentedContent = `${existing.content}\\n\\n// Augmented by plugin for ${contractName}\\n${JSON.stringify(content, null, 2)}`;\n\n outputs.set(outputKey, {\n ...existing,\n content: augmentedContent,\n });\n }\n\n /**\n * Record hook execution result\n */\n private recordHookResult(\n pluginName: string,\n hookName: string,\n result: Omit<HookResult, \"plugin\">\n ): void {\n const key = `${pluginName}:${hookName}`;\n const existing = this.executionContext.results.get(key) || [];\n existing.push({ ...result, plugin: pluginName });\n this.executionContext.results.set(key, existing);\n }\n\n /**\n * Create logger instance\n */\n private createLogger(): Logger {\n return {\n info: (message: string) => console.log(`ℹ️ ${message}`),\n warn: (message: string) => console.warn(`⚠️ ${message}`),\n error: (message: string) => console.error(`❌ ${message}`),\n debug: (message: string) => {\n if (process.env.DEBUG) {\n console.log(`🐛 ${message}`);\n }\n },\n success: (message: string) => console.log(`✅ ${message}`),\n };\n }\n\n /**\n * Create utils instance\n */\n private createUtils(): PluginUtils {\n return {\n toCamelCase: (str: string) => {\n return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());\n },\n\n toKebabCase: (str: string) => {\n return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n },\n\n validateAddress: (address: string) => {\n return validateStacksAddress(address.split(\".\")[0]);\n },\n\n parseContractId: (contractId: string) => {\n const [address, contractName] = contractId.split(\".\");\n return { address, contractName };\n },\n\n formatCode: async (code: string) => {\n return format(code, {\n parser: \"typescript\",\n singleQuote: true,\n semi: true,\n printWidth: 100,\n trailingComma: \"es5\",\n });\n },\n\n resolvePath: (relativePath: string) => {\n return path.resolve(process.cwd(), relativePath);\n },\n\n fileExists: async (filePath: string) => {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n },\n\n readFile: async (filePath: string) => {\n return fs.readFile(filePath, \"utf-8\");\n },\n\n writeFile: async (filePath: string, content: string) => {\n await fs.writeFile(filePath, content, \"utf-8\");\n },\n\n ensureDir: async (dirPath: string) => {\n await fs.mkdir(dirPath, { recursive: true });\n },\n };\n }\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "5975310D6EA97DB264756E2164756E21",
9
+ "names": []
10
+ }
package/package.json CHANGED
@@ -1,24 +1,21 @@
1
1
  {
2
2
  "name": "@secondlayer/cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "CLI for generating type-safe contract interfaces for the Stacks blockchain",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "secondlayer": "./dist/cli.js"
8
8
  },
9
- "main": "./dist/index.cjs",
10
- "module": "./dist/index.js",
9
+ "main": "./dist/index.js",
11
10
  "types": "./dist/index.d.ts",
12
11
  "exports": {
13
12
  ".": {
14
13
  "types": "./dist/index.d.ts",
15
- "import": "./dist/index.js",
16
- "require": "./dist/index.cjs"
14
+ "import": "./dist/index.js"
17
15
  },
18
16
  "./plugins": {
19
17
  "types": "./dist/plugins/index.d.ts",
20
- "import": "./dist/plugins/index.js",
21
- "require": "./dist/plugins/index.cjs"
18
+ "import": "./dist/plugins/index.js"
22
19
  }
23
20
  },
24
21
  "files": [
@@ -26,8 +23,8 @@
26
23
  "templates"
27
24
  ],
28
25
  "scripts": {
29
- "build": "tsup",
30
- "dev": "tsup --watch",
26
+ "build": "bunup",
27
+ "dev": "bunup --watch",
31
28
  "test": "vitest",
32
29
  "typecheck": "tsc --noEmit",
33
30
  "prepublishOnly": "bun run build"
@@ -37,15 +34,14 @@
37
34
  "clarity",
38
35
  "blockchain",
39
36
  "smart-contracts",
40
- "cli",
41
- "codegen"
37
+ "cli"
42
38
  ],
43
39
  "author": "",
44
40
  "license": "MIT",
45
41
  "dependencies": {
46
42
  "@antfu/ni": "^24.4.0",
47
43
  "@hirosystems/clarinet-sdk": "^3.0.2",
48
- "@secondlayer/clarity-types": "^0.1.0",
44
+ "@secondlayer/clarity-types": "workspace:*",
49
45
  "@stacks/connect": "^8.1.9",
50
46
  "@stacks/transactions": "7.0.6",
51
47
  "@tanstack/react-query": "^5.77.0",
@@ -59,11 +55,8 @@
59
55
  "react": "^19.1.0"
60
56
  },
61
57
  "devDependencies": {
62
- "@types/node": "^20.11.0",
63
- "@types/react": "^19.1.5",
64
- "tsup": "^8.0.1",
65
- "typescript": "^5.3.3",
66
- "vitest": "^1.2.1"
58
+ "@types/bun": "^1.1.14",
59
+ "@types/react": "^19.1.5"
67
60
  },
68
61
  "engines": {
69
62
  "node": ">=18"
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Ryan Waits
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the “Software”), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.