@5ive-tech/cli 1.0.4

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 (139) hide show
  1. package/README.md +226 -0
  2. package/dist/assets/vm/five_vm_wasm.d.ts +762 -0
  3. package/dist/assets/vm/five_vm_wasm.js +3754 -0
  4. package/dist/assets/vm/five_vm_wasm_bg.wasm +0 -0
  5. package/dist/assets/vm/five_vm_wasm_bg.wasm.d.ts +247 -0
  6. package/dist/assets/vm/package.json +11 -0
  7. package/dist/cli.d.ts +47 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +343 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/commands/analyze.d.ts +3 -0
  12. package/dist/commands/analyze.d.ts.map +1 -0
  13. package/dist/commands/analyze.js +435 -0
  14. package/dist/commands/analyze.js.map +1 -0
  15. package/dist/commands/build.d.ts +3 -0
  16. package/dist/commands/build.d.ts.map +1 -0
  17. package/dist/commands/build.js +66 -0
  18. package/dist/commands/build.js.map +1 -0
  19. package/dist/commands/compile.d.ts +3 -0
  20. package/dist/commands/compile.d.ts.map +1 -0
  21. package/dist/commands/compile.js +872 -0
  22. package/dist/commands/compile.js.map +1 -0
  23. package/dist/commands/config.d.ts +3 -0
  24. package/dist/commands/config.d.ts.map +1 -0
  25. package/dist/commands/config.js +431 -0
  26. package/dist/commands/config.js.map +1 -0
  27. package/dist/commands/deploy-and-execute.d.ts +3 -0
  28. package/dist/commands/deploy-and-execute.d.ts.map +1 -0
  29. package/dist/commands/deploy-and-execute.js +317 -0
  30. package/dist/commands/deploy-and-execute.js.map +1 -0
  31. package/dist/commands/deploy.d.ts +21 -0
  32. package/dist/commands/deploy.d.ts.map +1 -0
  33. package/dist/commands/deploy.js +806 -0
  34. package/dist/commands/deploy.js.map +1 -0
  35. package/dist/commands/donate.d.ts +4 -0
  36. package/dist/commands/donate.d.ts.map +1 -0
  37. package/dist/commands/donate.js +104 -0
  38. package/dist/commands/donate.js.map +1 -0
  39. package/dist/commands/execute.d.ts +6 -0
  40. package/dist/commands/execute.d.ts.map +1 -0
  41. package/dist/commands/execute.js +749 -0
  42. package/dist/commands/execute.js.map +1 -0
  43. package/dist/commands/fmt.d.ts +3 -0
  44. package/dist/commands/fmt.d.ts.map +1 -0
  45. package/dist/commands/fmt.js +327 -0
  46. package/dist/commands/fmt.js.map +1 -0
  47. package/dist/commands/help.d.ts +6 -0
  48. package/dist/commands/help.d.ts.map +1 -0
  49. package/dist/commands/help.js +224 -0
  50. package/dist/commands/help.js.map +1 -0
  51. package/dist/commands/index.d.ts +45 -0
  52. package/dist/commands/index.d.ts.map +1 -0
  53. package/dist/commands/index.js +119 -0
  54. package/dist/commands/index.js.map +1 -0
  55. package/dist/commands/init.d.ts +3 -0
  56. package/dist/commands/init.d.ts.map +1 -0
  57. package/dist/commands/init.js +887 -0
  58. package/dist/commands/init.js.map +1 -0
  59. package/dist/commands/local.d.ts +3 -0
  60. package/dist/commands/local.d.ts.map +1 -0
  61. package/dist/commands/local.js +703 -0
  62. package/dist/commands/local.js.map +1 -0
  63. package/dist/commands/namespace.d.ts +3 -0
  64. package/dist/commands/namespace.d.ts.map +1 -0
  65. package/dist/commands/namespace.js +328 -0
  66. package/dist/commands/namespace.js.map +1 -0
  67. package/dist/commands/template.d.ts +4 -0
  68. package/dist/commands/template.d.ts.map +1 -0
  69. package/dist/commands/template.js +486 -0
  70. package/dist/commands/template.js.map +1 -0
  71. package/dist/commands/test.d.ts +6 -0
  72. package/dist/commands/test.d.ts.map +1 -0
  73. package/dist/commands/test.js +890 -0
  74. package/dist/commands/test.js.map +1 -0
  75. package/dist/commands/version.d.ts +6 -0
  76. package/dist/commands/version.d.ts.map +1 -0
  77. package/dist/commands/version.js +339 -0
  78. package/dist/commands/version.js.map +1 -0
  79. package/dist/config/ConfigManager.d.ts +69 -0
  80. package/dist/config/ConfigManager.d.ts.map +1 -0
  81. package/dist/config/ConfigManager.js +261 -0
  82. package/dist/config/ConfigManager.js.map +1 -0
  83. package/dist/config/index.d.ts +10 -0
  84. package/dist/config/index.d.ts.map +1 -0
  85. package/dist/config/index.js +21 -0
  86. package/dist/config/index.js.map +1 -0
  87. package/dist/config/types.d.ts +35 -0
  88. package/dist/config/types.d.ts.map +1 -0
  89. package/dist/config/types.js +105 -0
  90. package/dist/config/types.js.map +1 -0
  91. package/dist/index.d.ts +3 -0
  92. package/dist/index.d.ts.map +1 -0
  93. package/dist/index.js +29 -0
  94. package/dist/index.js.map +1 -0
  95. package/dist/project/ProjectLoader.d.ts +12 -0
  96. package/dist/project/ProjectLoader.d.ts.map +1 -0
  97. package/dist/project/ProjectLoader.js +115 -0
  98. package/dist/project/ProjectLoader.js.map +1 -0
  99. package/dist/types.d.ts +334 -0
  100. package/dist/types.d.ts.map +1 -0
  101. package/dist/types.js +2 -0
  102. package/dist/types.js.map +1 -0
  103. package/dist/utils/AccountFixtureGenerator.d.ts +48 -0
  104. package/dist/utils/AccountFixtureGenerator.d.ts.map +1 -0
  105. package/dist/utils/AccountFixtureGenerator.js +265 -0
  106. package/dist/utils/AccountFixtureGenerator.js.map +1 -0
  107. package/dist/utils/FiveFileManager.d.ts +96 -0
  108. package/dist/utils/FiveFileManager.d.ts.map +1 -0
  109. package/dist/utils/FiveFileManager.js +329 -0
  110. package/dist/utils/FiveFileManager.js.map +1 -0
  111. package/dist/utils/ascii-art.d.ts +72 -0
  112. package/dist/utils/ascii-art.d.ts.map +1 -0
  113. package/dist/utils/ascii-art.js +314 -0
  114. package/dist/utils/ascii-art.js.map +1 -0
  115. package/dist/utils/cli-ui.d.ts +39 -0
  116. package/dist/utils/cli-ui.d.ts.map +1 -0
  117. package/dist/utils/cli-ui.js +75 -0
  118. package/dist/utils/cli-ui.js.map +1 -0
  119. package/dist/utils/fileUtils.d.ts +25 -0
  120. package/dist/utils/fileUtils.d.ts.map +1 -0
  121. package/dist/utils/fileUtils.js +50 -0
  122. package/dist/utils/fileUtils.js.map +1 -0
  123. package/dist/utils/logger.d.ts +53 -0
  124. package/dist/utils/logger.d.ts.map +1 -0
  125. package/dist/utils/logger.js +287 -0
  126. package/dist/utils/logger.js.map +1 -0
  127. package/dist/wasm/compiler.d.ts +101 -0
  128. package/dist/wasm/compiler.d.ts.map +1 -0
  129. package/dist/wasm/compiler.js +906 -0
  130. package/dist/wasm/compiler.js.map +1 -0
  131. package/dist/wasm/loader.d.ts +2 -0
  132. package/dist/wasm/loader.d.ts.map +1 -0
  133. package/dist/wasm/loader.js +90 -0
  134. package/dist/wasm/loader.js.map +1 -0
  135. package/dist/wasm/vm.d.ts +32 -0
  136. package/dist/wasm/vm.d.ts.map +1 -0
  137. package/dist/wasm/vm.js +440 -0
  138. package/dist/wasm/vm.js.map +1 -0
  139. package/package.json +100 -0
@@ -0,0 +1,887 @@
1
+ // Init command.
2
+ import { writeFile, mkdir, access } from 'fs/promises';
3
+ import { join } from 'path';
4
+ import chalk from 'chalk';
5
+ import ora from 'ora';
6
+ import { success as uiSuccess, warning as uiWarning, uiColors } from '../utils/cli-ui.js';
7
+ export const initCommand = {
8
+ name: 'init',
9
+ description: 'Initialize new project',
10
+ aliases: ['new', 'create'],
11
+ options: [
12
+ {
13
+ flags: '-t, --template <template>',
14
+ description: 'Project template',
15
+ choices: ['basic', 'defi', 'nft', 'game', 'dao'],
16
+ defaultValue: 'basic'
17
+ },
18
+ {
19
+ flags: '--target <target>',
20
+ description: 'Default compilation target',
21
+ choices: ['vm', 'solana', 'debug', 'test'],
22
+ defaultValue: 'vm'
23
+ },
24
+ {
25
+ flags: '--name <name>',
26
+ description: 'Project name (default: directory name)',
27
+ required: false
28
+ },
29
+ {
30
+ flags: '--description <desc>',
31
+ description: 'Project description',
32
+ required: false
33
+ },
34
+ {
35
+ flags: '--author <author>',
36
+ description: 'Project author',
37
+ required: false
38
+ },
39
+ {
40
+ flags: '--license <license>',
41
+ description: 'Project license',
42
+ defaultValue: 'MIT'
43
+ },
44
+ {
45
+ flags: '--no-git',
46
+ description: 'Skip git repository initialization',
47
+ defaultValue: false
48
+ },
49
+ {
50
+ flags: '--no-examples',
51
+ description: 'Skip example files',
52
+ defaultValue: false
53
+ }
54
+ ],
55
+ arguments: [
56
+ {
57
+ name: 'directory',
58
+ description: 'Project directory (default: current directory)',
59
+ required: false
60
+ }
61
+ ],
62
+ examples: [
63
+ {
64
+ command: 'five init',
65
+ description: 'Initialize project in current directory'
66
+ },
67
+ {
68
+ command: 'five init my-project',
69
+ description: 'Create new project in my-project directory'
70
+ },
71
+ {
72
+ command: 'five init my-defi --template defi --target solana',
73
+ description: 'Create DeFi project targeting Solana'
74
+ },
75
+ {
76
+ command: 'five init game --template game --no-git',
77
+ description: 'Create game project without git initialization'
78
+ }
79
+ ],
80
+ handler: async (args, options, context) => {
81
+ const { logger } = context;
82
+ try {
83
+ // Determine project directory
84
+ const projectDir = args[0] || process.cwd();
85
+ const projectName = options.name || (args[0] ? args[0] : 'five-project');
86
+ logger.info(`Initializing Five VM project: ${projectName}`);
87
+ // Check if directory exists and is empty
88
+ await checkProjectDirectory(projectDir, logger);
89
+ // Create project structure
90
+ const spinner = ora('Creating project structure...').start();
91
+ await createProjectStructure(projectDir, options.template);
92
+ spinner.succeed('Project structure created');
93
+ // Generate project configuration
94
+ spinner.start('Generating configuration files...');
95
+ await generateProjectConfig(projectDir, projectName, options);
96
+ await generatePackageJson(projectDir, projectName, options);
97
+ spinner.succeed('Configuration files generated');
98
+ // Generate source files
99
+ if (!options.noExamples) {
100
+ spinner.start('Generating example files...');
101
+ await generateExampleFiles(projectDir, options.template);
102
+ spinner.succeed('Example files generated');
103
+ }
104
+ // Initialize git repository
105
+ if (!options.noGit) {
106
+ spinner.start('Initializing git repository...');
107
+ await initializeGitRepository(projectDir);
108
+ spinner.succeed('Git repository initialized');
109
+ }
110
+ // Display success message
111
+ displaySuccessMessage(projectDir, projectName, options);
112
+ }
113
+ catch (error) {
114
+ logger.error('Project initialization failed:', error);
115
+ throw error;
116
+ }
117
+ }
118
+ };
119
+ async function checkProjectDirectory(projectDir, logger) {
120
+ try {
121
+ await access(projectDir);
122
+ // Directory exists, check if it's empty
123
+ const { readdir } = await import('fs/promises');
124
+ const files = await readdir(projectDir);
125
+ if (files.length > 0) {
126
+ logger.warn(`Directory ${projectDir} is not empty`);
127
+ // Check for existing Five project
128
+ const hasConfig = files.includes('five.toml') || files.includes('package.json');
129
+ if (hasConfig) {
130
+ throw new Error('Directory already contains a project configuration');
131
+ }
132
+ }
133
+ }
134
+ catch (error) {
135
+ if (error.code === 'ENOENT') {
136
+ // Directory doesn't exist, create it
137
+ await mkdir(projectDir, { recursive: true });
138
+ }
139
+ else {
140
+ throw error;
141
+ }
142
+ }
143
+ }
144
+ async function createProjectStructure(projectDir, template) {
145
+ const dirs = [
146
+ 'src',
147
+ 'tests',
148
+ 'examples',
149
+ 'build',
150
+ 'docs',
151
+ '.five'
152
+ ];
153
+ // Add template-specific directories
154
+ switch (template) {
155
+ case 'defi':
156
+ dirs.push('src/protocols', 'src/tokens', 'src/pools');
157
+ break;
158
+ case 'nft':
159
+ dirs.push('src/collections', 'src/metadata', 'assets');
160
+ break;
161
+ case 'game':
162
+ dirs.push('src/entities', 'src/systems', 'src/components', 'assets');
163
+ break;
164
+ case 'dao':
165
+ dirs.push('src/governance', 'src/treasury', 'src/proposals');
166
+ break;
167
+ }
168
+ for (const dir of dirs) {
169
+ await mkdir(join(projectDir, dir), { recursive: true });
170
+ }
171
+ }
172
+ async function generateProjectConfig(projectDir, projectName, options) {
173
+ const config = {
174
+ name: projectName,
175
+ version: '0.1.0',
176
+ description: options.description || `A Five VM project`,
177
+ sourceDir: 'src',
178
+ buildDir: 'build',
179
+ target: options.target,
180
+ optimizations: {
181
+ enableCompression: true,
182
+ enableConstraintOptimization: true,
183
+ optimizationLevel: 'production'
184
+ },
185
+ dependencies: []
186
+ };
187
+ const configContent = generateTomlConfig(config);
188
+ await writeFile(join(projectDir, 'five.toml'), configContent);
189
+ }
190
+ async function generatePackageJson(projectDir, projectName, options) {
191
+ const packageJson = {
192
+ name: projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-'),
193
+ version: '0.1.0',
194
+ description: options.description || 'A Five VM project',
195
+ author: options.author || '',
196
+ license: options.license,
197
+ scripts: {
198
+ build: 'five compile src/**/*.v',
199
+ test: 'five test',
200
+ deploy: 'five deploy',
201
+ 'build:release': 'five compile src/**/*.v -O 3',
202
+ 'build:debug': 'five compile src/**/*.v --debug',
203
+ 'watch': 'five compile src/**/*.v --watch'
204
+ },
205
+ devDependencies: {
206
+ 'five-cli': '^1.0.0'
207
+ },
208
+ keywords: [
209
+ 'five-vm',
210
+ 'blockchain',
211
+ 'solana',
212
+ 'smart-contracts'
213
+ ]
214
+ };
215
+ await writeFile(join(projectDir, 'package.json'), JSON.stringify(packageJson, null, 2));
216
+ }
217
+ async function generateExampleFiles(projectDir, template) {
218
+ // Generate main source file
219
+ const mainFile = getTemplateMainFile(template);
220
+ await writeFile(join(projectDir, 'src/main.v'), mainFile);
221
+ // Generate test file
222
+ const testFile = getTemplateTestFile(template);
223
+ await writeFile(join(projectDir, 'tests/main.test.v'), testFile);
224
+ // Generate README
225
+ const readme = generateReadme(template);
226
+ await writeFile(join(projectDir, 'README.md'), readme);
227
+ // Generate .gitignore
228
+ const gitignore = generateGitignore();
229
+ await writeFile(join(projectDir, '.gitignore'), gitignore);
230
+ }
231
+ async function initializeGitRepository(projectDir) {
232
+ const { execSync } = await import('child_process');
233
+ try {
234
+ execSync('git init', { cwd: projectDir, stdio: 'ignore' });
235
+ execSync('git add .', { cwd: projectDir, stdio: 'ignore' });
236
+ execSync('git commit -m "Initial commit"', { cwd: projectDir, stdio: 'ignore' });
237
+ }
238
+ catch (error) {
239
+ // Git initialization is optional, don't fail the entire process
240
+ console.warn(uiWarning('Git initialization failed'));
241
+ }
242
+ }
243
+ function generateTomlConfig(config) {
244
+ return `# Five VM Project Configuration
245
+ [project]
246
+ name = "${config.name}"
247
+ version = "${config.version}"
248
+ description = "${config.description}"
249
+ source_dir = "${config.sourceDir}"
250
+ build_dir = "${config.buildDir}"
251
+ target = "${config.target}"
252
+
253
+ [optimizations]
254
+ enable_compression = ${config.optimizations.enableCompression}
255
+ enable_constraint_optimization = ${config.optimizations.enableConstraintOptimization}
256
+ optimization_level = "${config.optimizations.optimizationLevel}"
257
+
258
+ [dependencies]
259
+ # Add project dependencies here
260
+ # example = { path = "../example" }
261
+
262
+ [build]
263
+ # Custom build settings
264
+ max_bytecode_size = 1048576 # 1MB
265
+ target_compute_units = 200000
266
+
267
+ [deploy]
268
+ # Deployment settings
269
+ network = "devnet"
270
+ # program_id = "your-program-id"
271
+ `;
272
+ }
273
+ function getTemplateMainFile(template) {
274
+ const templates = {
275
+ basic: `// Basic Five VM Program
276
+ script BasicProgram {
277
+ // Program initialization
278
+ init() {
279
+ log("BasicProgram initialized");
280
+ }
281
+
282
+ // Main program constraints
283
+ constraints {
284
+ // Add your business logic here
285
+ require(true, "Always passes");
286
+ }
287
+ }
288
+
289
+ // Main entry point
290
+ instruction main() {
291
+ log("Hello, Five VM!");
292
+ 42 // Return value
293
+ }
294
+
295
+ // Example function with parameters
296
+ instruction add(a: u64, b: u64) -> u64 {
297
+ a + b
298
+ }
299
+
300
+ #[test]
301
+ instruction test_add() {
302
+ let result = add(2, 3);
303
+ assert_eq(result, 5, "Addition should work");
304
+ }
305
+ `,
306
+ defi: `// DeFi Protocol on Five VM
307
+ script DefiProtocol {
308
+ init() {
309
+ log("DeFi Protocol initialized");
310
+ }
311
+
312
+ constraints {
313
+ // Ensure minimum liquidity
314
+ require(get_balance() >= 1000, "Insufficient liquidity");
315
+
316
+ // Validate price oracle
317
+ let price = get_price_oracle();
318
+ require(price > 0, "Invalid price");
319
+ }
320
+ }
321
+
322
+ account LiquidityPool {
323
+ token_a_amount: u64,
324
+ token_b_amount: u64,
325
+ total_shares: u64,
326
+ fee_rate: u64
327
+ }
328
+
329
+ instruction swap(amount_in: u64, token_in: string) -> u64 {
330
+ let pool = load_account<LiquidityPool>(0);
331
+
332
+ if token_in == "A" {
333
+ let amount_out = (amount_in * pool.token_b_amount) / (pool.token_a_amount + amount_in);
334
+ pool.token_a_amount += amount_in;
335
+ pool.token_b_amount -= amount_out;
336
+ amount_out
337
+ } else {
338
+ let amount_out = (amount_in * pool.token_a_amount) / (pool.token_b_amount + amount_in);
339
+ pool.token_b_amount += amount_in;
340
+ pool.token_a_amount -= amount_out;
341
+ amount_out
342
+ }
343
+ }
344
+
345
+ instruction add_liquidity(amount_a: u64, amount_b: u64) -> u64 {
346
+ let pool = load_account<LiquidityPool>(0);
347
+
348
+ let shares = if pool.total_shares == 0 {
349
+ (amount_a * amount_b).sqrt()
350
+ } else {
351
+ min(
352
+ (amount_a * pool.total_shares) / pool.token_a_amount,
353
+ (amount_b * pool.total_shares) / pool.token_b_amount
354
+ )
355
+ };
356
+
357
+ pool.token_a_amount += amount_a;
358
+ pool.token_b_amount += amount_b;
359
+ pool.total_shares += shares;
360
+
361
+ shares
362
+ }
363
+ `,
364
+ nft: `// NFT Collection on Five VM
365
+ script NFTCollection {
366
+ init() {
367
+ log("NFT Collection initialized");
368
+ }
369
+
370
+ constraints {
371
+ // Ensure valid mint authority
372
+ require(is_mint_authority(), "Invalid mint authority");
373
+
374
+ // Check collection size limits
375
+ let current_supply = get_current_supply();
376
+ require(current_supply < 10000, "Max supply reached");
377
+ }
378
+ }
379
+
380
+ account NFTMetadata {
381
+ name: string,
382
+ symbol: string,
383
+ uri: string,
384
+ creator: pubkey,
385
+ collection: pubkey,
386
+ is_mutable: bool
387
+ }
388
+
389
+ instruction mint_nft(to: pubkey, metadata_uri: string) -> pubkey {
390
+ let nft_id = derive_pda("nft", [to, get_clock().slot]);
391
+
392
+ let metadata = NFTMetadata {
393
+ name: "Five VM NFT",
394
+ symbol: "FVM",
395
+ uri: metadata_uri,
396
+ creator: get_signer(),
397
+ collection: get_program_id(),
398
+ is_mutable: true
399
+ };
400
+
401
+ create_account(nft_id, metadata);
402
+ log("NFT minted successfully");
403
+
404
+ nft_id
405
+ }
406
+
407
+ instruction transfer_nft(nft_id: pubkey, from: pubkey, to: pubkey) {
408
+ require(is_signer(from), "Invalid signature");
409
+
410
+ let metadata = load_account<NFTMetadata>(nft_id);
411
+ require(metadata.creator == from, "Not owner");
412
+
413
+ // Update ownership (simplified)
414
+ metadata.creator = to;
415
+ save_account(nft_id, metadata);
416
+
417
+ emit TransferEvent { from, to, nft_id };
418
+ }
419
+
420
+ event TransferEvent {
421
+ from: pubkey,
422
+ to: pubkey,
423
+ nft_id: pubkey
424
+ }
425
+ `,
426
+ game: `// Game Logic on Five VM
427
+ script GameEngine {
428
+ init() {
429
+ log("Game Engine initialized");
430
+ }
431
+
432
+ constraints {
433
+ // Validate player actions
434
+ let player = get_player();
435
+ require(player.is_active, "Player not active");
436
+
437
+ // Check game state
438
+ let game_state = get_game_state();
439
+ require(game_state == "active", "Game not active");
440
+ }
441
+ }
442
+
443
+ account Player {
444
+ id: pubkey,
445
+ level: u64,
446
+ experience: u64,
447
+ health: u64,
448
+ position_x: u64,
449
+ position_y: u64,
450
+ inventory: [u64; 10],
451
+ is_active: bool
452
+ }
453
+
454
+ account GameWorld {
455
+ width: u64,
456
+ height: u64,
457
+ players_count: u64,
458
+ started_at: u64
459
+ }
460
+
461
+ instruction move_player(direction: string, distance: u64) {
462
+ let player = load_account<Player>(get_signer());
463
+
464
+ match direction {
465
+ "north" => player.position_y += distance,
466
+ "south" => player.position_y -= distance,
467
+ "east" => player.position_x += distance,
468
+ "west" => player.position_x -= distance,
469
+ _ => require(false, "Invalid direction")
470
+ }
471
+
472
+ // Validate bounds
473
+ let world = load_account<GameWorld>(0);
474
+ require(player.position_x < world.width, "Out of bounds");
475
+ require(player.position_y < world.height, "Out of bounds");
476
+
477
+ save_account(get_signer(), player);
478
+ emit PlayerMoved { player: get_signer(), x: player.position_x, y: player.position_y };
479
+ }
480
+
481
+ instruction level_up() {
482
+ let player = load_account<Player>(get_signer());
483
+
484
+ let required_exp = player.level * 100;
485
+ require(player.experience >= required_exp, "Insufficient experience");
486
+
487
+ player.level += 1;
488
+ player.experience -= required_exp;
489
+ player.health = 100; // Full heal on level up
490
+
491
+ save_account(get_signer(), player);
492
+ emit LevelUp { player: get_signer(), new_level: player.level };
493
+ }
494
+
495
+ event PlayerMoved {
496
+ player: pubkey,
497
+ x: u64,
498
+ y: u64
499
+ }
500
+
501
+ event LevelUp {
502
+ player: pubkey,
503
+ new_level: u64
504
+ }
505
+ `,
506
+ dao: `// DAO Governance on Five VM
507
+ script DAOGovernance {
508
+ init() {
509
+ log("DAO Governance initialized");
510
+ }
511
+
512
+ constraints {
513
+ // Validate governance token
514
+ let token_balance = get_token_balance();
515
+ require(token_balance > 0, "No governance tokens");
516
+
517
+ // Check proposal validity
518
+ let proposal_id = get_current_proposal();
519
+ if proposal_id > 0 {
520
+ let proposal = get_proposal(proposal_id);
521
+ require(proposal.is_active, "Proposal not active");
522
+ }
523
+ }
524
+ }
525
+
526
+ account Proposal {
527
+ id: u64,
528
+ title: string,
529
+ description: string,
530
+ proposer: pubkey,
531
+ votes_for: u64,
532
+ votes_against: u64,
533
+ start_time: u64,
534
+ end_time: u64,
535
+ is_active: bool,
536
+ is_executed: bool
537
+ }
538
+
539
+ account Vote {
540
+ proposal_id: u64,
541
+ voter: pubkey,
542
+ amount: u64,
543
+ is_for: bool
544
+ }
545
+
546
+ instruction create_proposal(title: string, description: string, duration: u64) -> u64 {
547
+ let proposer_balance = get_token_balance();
548
+ require(proposer_balance >= 1000, "Insufficient tokens to propose");
549
+
550
+ let proposal_id = get_next_proposal_id();
551
+ let current_time = get_clock().unix_timestamp;
552
+
553
+ let proposal = Proposal {
554
+ id: proposal_id,
555
+ title,
556
+ description,
557
+ proposer: get_signer(),
558
+ votes_for: 0,
559
+ votes_against: 0,
560
+ start_time: current_time,
561
+ end_time: current_time + duration,
562
+ is_active: true,
563
+ is_executed: false
564
+ };
565
+
566
+ create_account(derive_pda("proposal", [proposal_id]), proposal);
567
+ emit ProposalCreated { id: proposal_id, proposer: get_signer() };
568
+
569
+ proposal_id
570
+ }
571
+
572
+ instruction vote(proposal_id: u64, amount: u64, is_for: bool) {
573
+ let voter_balance = get_token_balance();
574
+ require(voter_balance >= amount, "Insufficient token balance");
575
+
576
+ let proposal = load_account<Proposal>(derive_pda("proposal", [proposal_id]));
577
+ require(proposal.is_active, "Proposal not active");
578
+ require(get_clock().unix_timestamp <= proposal.end_time, "Voting period ended");
579
+
580
+ // Check if already voted
581
+ let vote_account = derive_pda("vote", [proposal_id, get_signer()]);
582
+ require(!account_exists(vote_account), "Already voted");
583
+
584
+ // Record vote
585
+ let vote = Vote {
586
+ proposal_id,
587
+ voter: get_signer(),
588
+ amount,
589
+ is_for
590
+ };
591
+
592
+ create_account(vote_account, vote);
593
+
594
+ // Update proposal vote counts
595
+ if is_for {
596
+ proposal.votes_for += amount;
597
+ } else {
598
+ proposal.votes_against += amount;
599
+ }
600
+
601
+ save_account(derive_pda("proposal", [proposal_id]), proposal);
602
+ emit VoteCast { proposal_id, voter: get_signer(), amount, is_for };
603
+ }
604
+
605
+ event ProposalCreated {
606
+ id: u64,
607
+ proposer: pubkey
608
+ }
609
+
610
+ event VoteCast {
611
+ proposal_id: u64,
612
+ voter: pubkey,
613
+ amount: u64,
614
+ is_for: bool
615
+ }
616
+ `
617
+ };
618
+ return templates[template] || templates.basic;
619
+ }
620
+ /**
621
+ * Get template test file content
622
+ */
623
+ function getTemplateTestFile(template) {
624
+ // Generate template-specific test functions
625
+ const templates = {
626
+ basic: `// Tests for ${template} template
627
+ // Use @test-params to specify function parameters for testing
628
+ // Format: @test-params <param1> <param2> ... <expected_result>
629
+
630
+ // @test-params 10 20 30
631
+ pub test_add(a: u64, b: u64) -> u64 {
632
+ return a + b;
633
+ }
634
+
635
+ // @test-params 5 2 10
636
+ pub test_multiply(a: u64, b: u64) -> u64 {
637
+ return a * b;
638
+ }
639
+
640
+ // @test-params
641
+ pub test_initialization() {
642
+ log("Initialization test passed");
643
+ }
644
+ `,
645
+ defi: `// Tests for ${template} template
646
+ // Test DeFi protocol functionality
647
+
648
+ // @test-params 1000 2000 3000
649
+ pub test_deposit(amount: u64) -> u64 {
650
+ // Simulate deposit logic
651
+ let fee = (amount * 1) / 100; // 1% fee
652
+ return amount - fee;
653
+ }
654
+
655
+ // @test-params 100 50 50
656
+ pub test_swap_calculation(pool_a: u64, amount: u64) -> u64 {
657
+ // Swap calculation
658
+ let result = (amount * pool_a) / (pool_a + amount);
659
+ return result;
660
+ }
661
+ `,
662
+ nft: `// Tests for ${template} template
663
+ // Test NFT functionality
664
+
665
+ // @test-params
666
+ pub test_mint_nft() -> bool {
667
+ // Test NFT minting
668
+ log("NFT mint test passed");
669
+ return true;
670
+ }
671
+
672
+ // @test-params
673
+ pub test_transfer_nft() -> bool {
674
+ // Test NFT transfer
675
+ log("NFT transfer test passed");
676
+ return true;
677
+ }
678
+ `,
679
+ game: `// Tests for ${template} template
680
+ // Test game logic
681
+
682
+ // @test-params 5 3 true
683
+ pub test_move_validation(x: u64, y: u64) -> bool {
684
+ // Validate game world bounds
685
+ let max_x = 100u64;
686
+ let max_y = 100u64;
687
+ return x < max_x && y < max_y;
688
+ }
689
+
690
+ // @test-params 1 100 101
691
+ pub test_level_up(level: u64, experience: u64) -> u64 {
692
+ // Calculate experience needed for next level
693
+ let required_exp = level * 100;
694
+ if experience >= required_exp {
695
+ return level + 1;
696
+ }
697
+ return level;
698
+ }
699
+ `,
700
+ dao: `// Tests for ${template} template
701
+ // Test DAO governance
702
+
703
+ // @test-params 1000 50 true
704
+ pub test_vote_power(tokens: u64, vote_amount: u64) -> bool {
705
+ // Test vote power calculation
706
+ return vote_amount <= tokens;
707
+ }
708
+
709
+ // @test-params 1000 600 true
710
+ pub test_proposal_threshold(token_balance: u64, threshold: u64) -> bool {
711
+ // Test if balance meets proposal threshold
712
+ return token_balance >= threshold;
713
+ }
714
+ `
715
+ };
716
+ return templates[template] || templates.basic;
717
+ }
718
+ /**
719
+ * Generate README content
720
+ */
721
+ function generateReadme(template) {
722
+ return `# Five VM Project
723
+
724
+ A ${template} project built with Five VM.
725
+
726
+ ## Getting Started
727
+
728
+ ### Prerequisites
729
+
730
+ - Node.js 18+
731
+ - Five CLI: \`npm install -g five-cli\`
732
+
733
+ ### Building
734
+
735
+ \`\`\`bash
736
+ # Compile the project
737
+ npm run build
738
+
739
+ # Compile with optimizations
740
+ npm run build:release
741
+
742
+ # Compile with debug information
743
+ npm run build:debug
744
+ \`\`\`
745
+
746
+ ### Testing
747
+
748
+ #### Discover and Run Tests
749
+
750
+ Five CLI automatically discovers test functions from your \`.v\` files:
751
+
752
+ \`\`\`bash
753
+ # Run all tests
754
+ npm test
755
+
756
+ # Run with watch mode for continuous testing
757
+ five test --watch
758
+
759
+ # Run specific tests by filter
760
+ five test --filter "test_add"
761
+
762
+ # Run with verbose output
763
+ five test --verbose
764
+
765
+ # Run with JSON output for CI/CD
766
+ five test --format json
767
+ \`\`\`
768
+
769
+ #### Writing Tests
770
+
771
+ Test functions in your \`.v\` files use the \`pub test_*\` naming convention and include \`@test-params\` comments:
772
+
773
+ \`\`\`v
774
+ // @test-params 10 20 30
775
+ pub test_add(a: u64, b: u64) -> u64 {
776
+ return a + b;
777
+ }
778
+
779
+ // @test-params 5 2 10
780
+ pub test_multiply(a: u64, b: u64) -> u64 {
781
+ return a * b;
782
+ }
783
+ \`\`\`
784
+
785
+ The \`@test-params\` comment specifies the parameters to pass and expected result. The test runner will:
786
+ 1. Discover test functions automatically
787
+ 2. Compile the source file
788
+ 3. Execute with the specified parameters
789
+ 4. Validate the result matches
790
+
791
+ ### Development
792
+
793
+ \`\`\`bash
794
+ # Watch for changes and auto-compile
795
+ npm run watch
796
+ \`\`\`
797
+
798
+ ### Deployment
799
+
800
+ \`\`\`bash
801
+ # Deploy to devnet
802
+ npm run deploy
803
+ \`\`\`
804
+
805
+ ## Project Structure
806
+
807
+ - \`src/\` - Five VM source files (.v)
808
+ - \`tests/\` - Test files (.v files with test_* functions)
809
+ - \`build/\` - Compiled bytecode
810
+ - \`docs/\` - Documentation
811
+ - \`five.toml\` - Project configuration
812
+
813
+ ## Multi-File Projects
814
+
815
+ If your project uses multiple modules with \`use\` or \`import\` statements, Five CLI automatically handles:
816
+
817
+ \`\`\`bash
818
+ # Automatic discovery of imported modules
819
+ five compile src/main.v --auto-discover
820
+
821
+ # Or use the build command which respects five.toml configuration
822
+ five build
823
+ \`\`\`
824
+
825
+ ## Learn More
826
+
827
+ - [Five VM Documentation](https://five-vm.dev)
828
+ - [Five VM GitHub](https://github.com/five-vm)
829
+ - [Multi-File Compilation Guide](./docs/multi-file.md)
830
+ - [Examples](./examples)
831
+
832
+ ## License
833
+
834
+ MIT
835
+ `;
836
+ }
837
+ /**
838
+ * Generate .gitignore content
839
+ */
840
+ function generateGitignore() {
841
+ return `# Build outputs
842
+ build/
843
+ *.bin
844
+ *.so
845
+ *.wasm
846
+
847
+ # Node.js
848
+ node_modules/
849
+ npm-debug.log*
850
+ yarn-debug.log*
851
+ yarn-error.log*
852
+
853
+ # Environment variables
854
+ .env
855
+ .env.local
856
+
857
+ # IDE
858
+ .vscode/
859
+ .idea/
860
+ *.swp
861
+ *.swo
862
+
863
+ # OS
864
+ .DS_Store
865
+ Thumbs.db
866
+
867
+ # Five VM
868
+ .five/cache/
869
+ *.debug.bin
870
+ `;
871
+ }
872
+ /**
873
+ * Display success message
874
+ */
875
+ function displaySuccessMessage(projectDir, projectName, options) {
876
+ console.log('\n' + uiSuccess('Project initialized'));
877
+ console.log('\n' + chalk.bold('Next steps:'));
878
+ if (projectDir !== process.cwd()) {
879
+ console.log(` ${uiColors.info('cd')} ${projectDir}`);
880
+ }
881
+ console.log(` ${uiColors.info('npm install')} - Install dependencies`);
882
+ console.log(` ${uiColors.info('npm run build')} - Compile the project`);
883
+ console.log(` ${uiColors.info('npm test')} - Run tests`);
884
+ console.log(` ${uiColors.info('npm run watch')} - Start development mode`);
885
+ console.log('\n' + uiColors.muted('Happy coding with Five VM.'));
886
+ }
887
+ //# sourceMappingURL=init.js.map