@jpetit/toolkit 3.0.23 → 3.1.2

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 (61) hide show
  1. package/assets/prompts/creators/create-solution.tpl.txt +10 -0
  2. package/assets/prompts/creators/create-statement.tpl.txt +21 -0
  3. package/assets/prompts/creators/create-translation.tpl.txt +5 -0
  4. package/assets/prompts/creators/private-test-cases.txt +6 -0
  5. package/assets/prompts/creators/sample-test-cases.txt +6 -0
  6. package/assets/prompts/creators/system-prompt.txt +2 -0
  7. package/assets/prompts/examples/statement-coda.tex +7 -0
  8. package/assets/prompts/examples/statement.tex +19 -0
  9. package/assets/prompts/generators/efficiency.md +41 -0
  10. package/assets/prompts/generators/hard.md +47 -0
  11. package/assets/prompts/generators/random.md +39 -0
  12. package/assets/prompts/proglangs/cc.md +3 -0
  13. package/assets/prompts/proglangs/py.md +40 -0
  14. package/lib/ai.ts +60 -4
  15. package/lib/cleaner.ts +24 -13
  16. package/lib/compilers/base.ts +70 -14
  17. package/lib/compilers/clojure.ts +21 -10
  18. package/lib/compilers/gcc.ts +4 -33
  19. package/lib/compilers/ghc.ts +4 -40
  20. package/lib/compilers/gxx.ts +4 -33
  21. package/lib/compilers/index.ts +9 -0
  22. package/lib/compilers/java.ts +105 -0
  23. package/lib/compilers/python3.ts +44 -37
  24. package/lib/compilers/run-clojure.ts +101 -0
  25. package/lib/compilers/run-haskell.ts +26 -22
  26. package/lib/compilers/run-python.ts +29 -35
  27. package/lib/compilers/rust.ts +39 -0
  28. package/lib/create-with-jutgeai.ts +407 -0
  29. package/lib/create-with-template.ts +55 -0
  30. package/lib/data.ts +6 -0
  31. package/lib/doctor.ts +86 -6
  32. package/lib/generate.ts +132 -290
  33. package/lib/helpers.ts +48 -0
  34. package/lib/inspector.ts +253 -0
  35. package/lib/jutge_api_client.ts +4631 -0
  36. package/lib/maker.ts +202 -289
  37. package/lib/settings.ts +26 -17
  38. package/lib/tui.ts +25 -15
  39. package/lib/types.ts +40 -5
  40. package/lib/upload.ts +216 -0
  41. package/lib/utils.ts +82 -14
  42. package/lib/versions.ts +46 -0
  43. package/package.json +50 -11
  44. package/toolkit/about.ts +43 -0
  45. package/toolkit/ai.ts +44 -18
  46. package/toolkit/check.ts +16 -0
  47. package/toolkit/clean.ts +16 -26
  48. package/toolkit/compilers.ts +4 -4
  49. package/toolkit/config.ts +91 -0
  50. package/toolkit/create.ts +30 -58
  51. package/toolkit/doctor.ts +15 -11
  52. package/toolkit/generate.ts +195 -98
  53. package/toolkit/index.ts +32 -21
  54. package/toolkit/make.ts +12 -48
  55. package/toolkit/upgrade.ts +9 -0
  56. package/toolkit/upload.ts +19 -0
  57. package/toolkit/create-jutge-ai.ts +0 -101
  58. package/toolkit/create-template.ts +0 -55
  59. package/toolkit/create-wizard.ts +0 -6
  60. package/toolkit/init.ts +0 -56
  61. package/toolkit/verify.ts +0 -19
package/package.json CHANGED
@@ -1,27 +1,52 @@
1
1
  {
2
2
  "name": "@jpetit/toolkit",
3
3
  "description": "Toolkit to prepare problems for Jutge.org",
4
- "version": "3.0.23",
4
+ "version": "3.1.2",
5
+ "homepage": "https://jutge.org",
6
+ "author": {
7
+ "name": "Jutge.org",
8
+ "email": "info@jutge.org",
9
+ "url": "https://jutge.org"
10
+ },
11
+ "contributors": [
12
+ {
13
+ "name": "Jordi Petit",
14
+ "url": "https://github.com/jordi-petit"
15
+ },
16
+ {
17
+ "name": "Pau Fernández",
18
+ "url": "https://github.com/pauek"
19
+ }
20
+ ],
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/jutge-org/jutge-toolkit.git"
24
+ },
5
25
  "publishConfig": {
6
26
  "access": "public"
7
27
  },
8
28
  "module": "index.ts",
9
29
  "type": "module",
10
- "bin": "toolkit/index.ts",
30
+ "bin": {
31
+ "jutge-toolkit": "toolkit/index.ts",
32
+ "jtk": "toolkit/index.ts"
33
+ },
11
34
  "scripts": {
12
35
  "lint": "eslint .",
13
36
  "format": "bun prettier --write .",
14
- "depcheck": "bunx depcheck"
37
+ "depcheck": "bunx depcheck",
38
+ "update-jutge-client": "(cd lib ; rm -f jutge_api_client.ts ; https --download https://api.jutge.org/clients/download/typescript)"
15
39
  },
16
40
  "files": [
41
+ "assets",
17
42
  "lib",
18
- "toolkit",
19
- "assets"
43
+ "toolkit"
20
44
  ],
21
45
  "dependencies": {
22
46
  "@commander-js/extra-typings": "^14.0.0",
23
47
  "@eslint/js": "^9.39.2",
24
48
  "@inquirer/prompts": "^8.1.0",
49
+ "archiver": "^7.0.1",
25
50
  "boxen": "^8.0.1",
26
51
  "bun-types": "^1.3.5",
27
52
  "chalk": "^5.6.2",
@@ -30,35 +55,49 @@
30
55
  "eslint": "^9.39.2",
31
56
  "execa": "^9.6.1",
32
57
  "gpt-tokenizer": "^3.4.0",
58
+ "handlebars": "^4.7.8",
33
59
  "human-id": "^4.1.3",
34
60
  "image-size": "^2.0.2",
35
- "install": "^0.13.0",
36
- "jdenticon": "^3.3.0",
61
+ "inquirer-checkbox-plus-plus": "^1.1.1",
37
62
  "marked": "^17.0.1",
38
63
  "marked-terminal": "^7.3.0",
39
64
  "multi-llm-ts": "^4.6.2",
40
65
  "nanoid": "^5.1.6",
66
+ "openai": "^6.15.0",
41
67
  "ora": "^9.0.0",
42
68
  "prettier": "^3.7.4",
43
69
  "pretty-bytes": "^7.1.0",
44
70
  "pretty-ms": "^9.3.0",
45
71
  "radash": "^12.1.1",
46
- "slug": "^11.0.1",
72
+ "semver": "^7.7.3",
73
+ "sharp": "^0.34.5",
47
74
  "terminal-image": "^4.1.0",
48
75
  "terminal-link": "^5.0.0",
49
- "typescript-eslint": "^8.50.0",
76
+ "typescript-eslint": "^8.51.0",
50
77
  "yaml": "^2.8.2",
51
- "zod": "^4.2.1"
78
+ "zod": "^4.3.4",
79
+ "zod-package-json": "^2.1.0",
80
+ "zod-validation-error": "^5.0.0"
52
81
  },
53
82
  "devDependencies": {
83
+ "@types/archiver": "^7.0.0",
54
84
  "@types/image-size": "^0.8.0",
55
85
  "@types/marked": "^6.0.0",
56
86
  "@types/marked-terminal": "^6.1.1",
57
87
  "@types/node": "^25.0.3",
58
88
  "@types/ora": "^3.2.0",
59
- "@types/slug": "^5.0.9"
89
+ "@types/semver": "^7.7.1"
60
90
  },
61
91
  "peerDependencies": {
62
92
  "typescript": "^5.9.3"
93
+ },
94
+ "prettier": {
95
+ "semi": false,
96
+ "singleQuote": true,
97
+ "trailingComma": "all",
98
+ "tabWidth": 4,
99
+ "useTabs": false,
100
+ "arrowParens": "always",
101
+ "printWidth": 120
63
102
  }
64
103
  }
@@ -0,0 +1,43 @@
1
+ import { Command } from '@commander-js/extra-typings'
2
+ import chalk from 'chalk'
3
+ import { nothing, projectDir, readJson } from '../lib/utils.ts'
4
+ import { join } from 'path'
5
+ import { PackageJson } from 'zod-package-json'
6
+ import tui from '../lib/tui.ts'
7
+
8
+ const packageJson = PackageJson.parse(await readJson(join(projectDir(), 'package.json')))
9
+
10
+ export const aboutCmd = new Command('about')
11
+ .description('Get information about jutge-toolkit')
12
+
13
+ .action(async () => {
14
+ await nothing()
15
+ tui.print(chalk.bold(`jutge-toolkit ${packageJson.version}`))
16
+ tui.print(packageJson.description!)
17
+ tui.print('')
18
+ tui.url(packageJson.homepage!)
19
+ tui.print('')
20
+ tui.print('Author:')
21
+ showperson(packageJson.author!)
22
+ tui.print('')
23
+ tui.print('Contributors:')
24
+ for (const contributor of packageJson.contributors!) {
25
+ showperson(contributor)
26
+ }
27
+ })
28
+
29
+ function showperson(person: string | { name: string; email?: string; url?: string }) {
30
+ let line = ' - '
31
+ if (typeof person === 'string') {
32
+ line += person
33
+ } else {
34
+ line += person.name
35
+ if (person.email) {
36
+ line += ` <${tui.link('mailto://' + person.email, person.email)}>`
37
+ }
38
+ if (person.url) {
39
+ line += ` (${tui.link(person.url)})`
40
+ }
41
+ }
42
+ tui.print(line)
43
+ }
package/toolkit/ai.ts CHANGED
@@ -1,30 +1,56 @@
1
1
  import { Command } from '@commander-js/extra-typings'
2
- import { complete, listModels } from '../lib/ai.ts'
2
+ import sharp from 'sharp'
3
+ import z from 'zod'
4
+ import { complete, generateImage, listModels } from '../lib/ai.ts'
5
+ import { settings } from '../lib/settings.ts'
6
+ import tui from '../lib/tui.ts'
7
+ import { convertStringToItsType } from '../lib/utils.ts'
3
8
 
4
- export const ai = new Command('ai').description('Query AI models')
9
+ export const aiCmd = new Command('ai')
10
+ .description('Query AI models')
5
11
 
6
- ai.command('complete')
12
+ .action(() => {
13
+ aiCmd.help()
14
+ })
15
+
16
+ aiCmd
17
+ .command('models')
18
+ .description('Show available AI models')
19
+
20
+ .action(async () => {
21
+ const models = await listModels()
22
+ tui.yaml(models)
23
+ })
24
+
25
+ aiCmd
26
+ .command('complete')
7
27
  .description('Complete a prompt using an AI model')
8
28
 
9
- .argument('prompt', 'the user prompt to complete')
29
+ .argument('<prompt>', 'the user prompt to complete')
10
30
  .option('-s, --system-prompt <system>', 'the system prompt to use', 'You are a helpful assistant.')
11
- .option(
12
- '-m, --model <model>',
13
- 'the AI model to use (eg: openai/gpt-5, google/gemini-2.5-pro, ...)',
14
- 'google/gemini-2.5-flash-lite',
15
- )
31
+ .option('-m, --model <model>', 'the AI model to use', settings.defaultModel)
16
32
 
17
33
  .action(async (prompt, { model, systemPrompt }) => {
18
- if (!prompt) prompt = 'Who are you?'
19
- if (!systemPrompt) systemPrompt = 'You are a helpful assistant.'
20
-
34
+ prompt = prompt.trim()
35
+ systemPrompt = systemPrompt.trim()
21
36
  const answer = await complete(model, systemPrompt, prompt)
22
- console.log(answer)
37
+ tui.print(answer)
23
38
  })
24
39
 
25
- ai.command('models')
26
- .description('Show available AI models')
27
- .action(async () => {
28
- const models = await listModels()
29
- console.dir(models, { depth: null })
40
+ // TODO: generate with different aspect ratios
41
+ aiCmd
42
+ .command('image')
43
+ .description('Generate a square image using an AI model')
44
+
45
+ .argument('<prompt>', 'description of the image to generate')
46
+ .option('-m, --model <model>', 'the graphic AI model to use', 'openai/dall-e-3')
47
+ .option('-s, --size <size>', 'the size of the image (in pixels)', '1024')
48
+ .option('-o, --output <path>', 'the output image path', 'image.png')
49
+
50
+ .action(async (prompt, { model, size, output }) => {
51
+ const sizeInt = z.int().min(16).max(2048).parse(convertStringToItsType(size))
52
+ const image = await generateImage(model, prompt)
53
+ await sharp(image).resize(sizeInt, sizeInt).toFile(output)
54
+ tui.success(`Generated image saved to ${output}`)
55
+ await tui.image(output, 20, 10)
30
56
  })
@@ -0,0 +1,16 @@
1
+ import { Command } from '@commander-js/extra-typings'
2
+ import { newMaker } from '../lib/maker'
3
+
4
+ export const checkCmd = new Command('check')
5
+ .alias('verify')
6
+ .description('Check candidate programs')
7
+
8
+ .argument('<programs...>', 'source programs to check')
9
+ .option('-d, --directory <path>', 'problem directory', '.')
10
+
11
+ .action(async (programs, { directory }) => {
12
+ const maker = await newMaker(directory)
13
+ for (const program of programs) {
14
+ await maker.checkCandidate(program)
15
+ }
16
+ })
package/toolkit/clean.ts CHANGED
@@ -1,37 +1,27 @@
1
- import { cleanFiles } from '../lib/cleaner'
2
- import tui from '../lib/tui'
3
1
  import { Command, Option } from '@commander-js/extra-typings'
4
- import { resolve } from 'path'
2
+ import { cleanDirectory } from '../lib/cleaner'
3
+ import tui from '../lib/tui'
4
+ import { findRealDirectories } from '../lib/helpers'
5
+
6
+ // TODO: usefindRealDirectories from lib/helpers.ts
5
7
 
6
- export const clean = new Command('clean')
8
+ export const cleanCmd = new Command('clean')
7
9
  .description('Clean generated files')
8
10
 
9
- .argument('[directories...]', 'problem directories', ['.'])
10
- .option('-i, --ignore-errors', 'ignore errors on a directory and continue processing', false)
11
+ .option('-d, --directories <directories...>', 'problem directories', ['.'])
12
+ .option('-a, --all', 'clean all generated files (including generated statement and correct files', false)
11
13
  .addOption(new Option('-f, --force', 'force removal').conflicts('dryRun'))
12
14
  .addOption(new Option('-n, --dry-run', 'show but do not remove files').conflicts('force'))
13
15
 
14
- .action(async (directories, { ignoreErrors, force }) => {
15
- // Default to dry-run if neither option is specified
16
- const isForce = force || false
17
- await tui.section('Cleaning generated files', async () => {
18
- for (const directory of directories) {
19
- try {
20
- await tui.section(
21
- `Cleaning directory ${tui.hyperlink(directory, resolve(directory))}`,
22
- async () => {
23
- await cleanFiles(isForce, directory)
24
- },
25
- )
26
- } catch (error) {
27
- const errorMessage = error instanceof Error ? error.message : String(error)
16
+ .action(async ({ directories, all, force, dryRun }) => {
17
+ const isForce = force || false // default to dry-run if neither option is specified
28
18
 
29
- if (ignoreErrors) {
30
- tui.error(`Error: ${errorMessage}`)
31
- } else {
32
- throw error
33
- }
34
- }
19
+ await tui.section(`Cleaning generated files`, async () => {
20
+ const realDirectories = await findRealDirectories(directories)
21
+ for (const directory of realDirectories) {
22
+ await tui.section(`Cleaning directory ${tui.hyperlink(directory)}`, async () => {
23
+ await cleanDirectory(isForce, all, directory)
24
+ })
35
25
  }
36
26
  })
37
27
  })
@@ -1,16 +1,16 @@
1
1
  import { getAvailableCompilers, getCompilersInfo, getDefinedCompilerIds } from '../lib/compilers'
2
2
  import { Command } from '@commander-js/extra-typings'
3
3
 
4
- export const compilers = new Command('compilers')
4
+ export const compilersCmd = new Command('compilers')
5
5
  .description('Query compiler information')
6
- // default action is to list all compilers
6
+ // default action is to list all compilers because of older compatibility
7
7
 
8
8
  .action(async () => {
9
9
  const info = await getCompilersInfo()
10
10
  console.dir(info)
11
11
  })
12
12
 
13
- compilers
13
+ compilersCmd
14
14
  .command('list-defined')
15
15
  .description('List all defined compiler names')
16
16
 
@@ -19,7 +19,7 @@ compilers
19
19
  console.dir(items)
20
20
  })
21
21
 
22
- compilers
22
+ compilersCmd
23
23
  .command('list-available')
24
24
  .description('List all available compiler names')
25
25
 
@@ -0,0 +1,91 @@
1
+ import { Command } from '@commander-js/extra-typings'
2
+ import { confirm } from '@inquirer/prompts'
3
+ import { editor } from '@inquirer/prompts'
4
+ import YAML from 'yaml'
5
+ import { ZodError } from 'zod'
6
+ import { fromError } from 'zod-validation-error'
7
+ import { configPath, loadSettings, saveSettings, settings } from '../lib/settings'
8
+ import { Settings } from '../lib/types.ts'
9
+ import tui from '../lib/tui.ts'
10
+ import { convertStringToItsType } from '../lib/utils.ts'
11
+
12
+ export const configCmd = new Command('config')
13
+ .summary('Manage configuration')
14
+ .description(
15
+ `Manage configuration
16
+
17
+ The actual configuration file is stored at ${configPath()}`,
18
+ )
19
+
20
+ .action(() => {
21
+ configCmd.help()
22
+ })
23
+
24
+ configCmd
25
+ .command('show')
26
+ .alias('list')
27
+ .description('Show configuration options')
28
+
29
+ .action(async () => {
30
+ const settings = await loadSettings()
31
+ tui.yaml(settings)
32
+ })
33
+
34
+ configCmd
35
+ .command('get <key>')
36
+ .description('Get the value of a configuration option')
37
+
38
+ .action((key: string) => {
39
+ if (!(key in settings)) {
40
+ throw new Error(`Configuration key ${key} does not exist`)
41
+ }
42
+ console.log((settings as any)[key])
43
+ })
44
+
45
+ configCmd
46
+ .command('set <key> <value>')
47
+ .description('Set the value of a configuration option')
48
+
49
+ .action(async (key: string, value: string) => {
50
+ if (!(key in settings)) {
51
+ throw new Error(`Configuration key ${key} does not exist`)
52
+ }
53
+ const convertedValue = convertStringToItsType(value)
54
+ const newSettings = Settings.parse({ ...settings, [key]: convertedValue })
55
+ await saveSettings(newSettings)
56
+ tui.success(`Configuration key ${key} updated successfully`)
57
+ })
58
+
59
+ configCmd
60
+ .command('edit')
61
+ .description('Open an editor (uses $EDITOR or $VISUAL) to modify the configuration options')
62
+
63
+ .action(async () => {
64
+ let data = YAML.stringify(settings, null, 4)
65
+ while (true) {
66
+ const newData = await editor({
67
+ message: 'Edit configuration',
68
+ default: data,
69
+ postfix: '.yml',
70
+ waitForUserInput: false,
71
+ })
72
+ try {
73
+ const newSettings = Settings.parse(YAML.parse(newData))
74
+ await saveSettings(newSettings)
75
+ tui.success('Configuration options updated successfully')
76
+ return
77
+ } catch (error) {
78
+ if (error instanceof ZodError) {
79
+ console.error(fromError(error).toString())
80
+ } else {
81
+ console.error(error)
82
+ }
83
+ const again = await confirm({ message: 'Edit again?', default: true })
84
+ if (!again) {
85
+ tui.warning('No changes made to the configuration options')
86
+ return
87
+ }
88
+ data = newData
89
+ }
90
+ }
91
+ })
package/toolkit/create.ts CHANGED
@@ -1,65 +1,37 @@
1
- import tui from '../lib/tui'
2
1
  import { Command } from '@commander-js/extra-typings'
3
- import { confirm, input, select } from '@inquirer/prompts'
4
- import { exists, mkdir, rm } from 'fs/promises'
5
- import { normalize } from 'path'
6
- import { createProblemWithJutgeAI } from './create-jutge-ai'
7
- import { createProblemWithTemplate } from './create-template'
8
- import { createProblemWithWizard } from './create-wizard'
2
+ import { createProblemWithJutgeAI } from '../lib/create-with-jutgeai'
3
+ import { createProblemWithTemplate } from '../lib/create-with-template'
4
+ import { settings } from '../lib/settings'
9
5
 
10
- async function selectMethod(): Promise<'template' | 'wizard' | 'jutgeAI'> {
11
- return await select({
12
- message: 'Method to create a new problem:',
13
- choices: [
14
- { name: 'Use a template', value: 'template' },
15
- { name: 'Use the wizard', value: 'wizard' },
16
- { name: 'Use JutgeAI', value: 'jutgeAI' },
17
- ],
6
+ export const createCmd = new Command('create')
7
+ .alias('new')
8
+ .description('Create a new problem')
9
+
10
+ .action(() => {
11
+ createCmd.help()
18
12
  })
19
- }
20
13
 
21
- async function selectOutputDir(): Promise<string> {
22
- let dir = 'my-new-problem.pbm'
23
- while (true) {
24
- dir = await input({
25
- message: 'Output directory for the new problem:',
26
- default: dir,
27
- })
28
- dir = normalize(dir)
29
- if (await exists(dir)) {
30
- tui.error(`Directory ${dir} already exists.`)
31
- const remove = await confirm({
32
- message: 'Remove it?',
33
- default: false,
34
- })
35
- if (!remove) continue
36
- tui.action(`Removing directory ${dir}`)
37
- await rm(dir, { recursive: true, force: true })
38
- tui.success(`Removed directory ${dir}`)
39
- }
40
- if (!dir.endsWith('.pbm')) {
41
- tui.warning("The output directory must end with the '.pbm' extension. Please try again.")
42
- dir += '.pbm'
43
- continue
44
- }
45
- await mkdir(dir, { recursive: true })
46
- tui.success(`Created directory ${dir}`)
47
- return dir
48
- }
49
- }
14
+ createCmd
15
+ .command('with-template')
16
+ .description('Create a problem with a template')
50
17
 
51
- export const create = new Command('create')
52
- .description('Create a new problem')
18
+ .argument('[template]', 'template to use (empty to interactive selection)')
19
+ .option('-d, --directory <path>', 'output directory', 'new-problem.pbm')
20
+
21
+ .action(async (template, { directory }) => {
22
+ await createProblemWithTemplate(directory, template)
23
+ })
24
+
25
+ createCmd
26
+ .command('with-ai')
27
+ .description('Create a problem with JutgeAI')
28
+
29
+ .option('-d, --directory <path>', 'output directory', 'new-problem.pbm')
30
+ .option('-i, --input <path>', 'input specification file')
31
+ .option('-o, --output <path>', 'output specification file')
32
+ .option('-n, --do-not-ask', 'do not ask interactively if --input given', false)
33
+ .option('-m, --model <model>', 'AI model to use', settings.defaultModel)
53
34
 
54
- .action(async () => {
55
- tui.title('Create new problem')
56
- const outputDir = await selectOutputDir()
57
- const method = await selectMethod()
58
- if (method === 'template') {
59
- await createProblemWithTemplate(outputDir)
60
- } else if (method === 'wizard') {
61
- await createProblemWithWizard(outputDir)
62
- } else if (method === 'jutgeAI') {
63
- await createProblemWithJutgeAI(outputDir)
64
- }
35
+ .action(async ({ input, output, directory, model, doNotAsk }) => {
36
+ await createProblemWithJutgeAI(model, directory, input, output, doNotAsk)
65
37
  })
package/toolkit/doctor.ts CHANGED
@@ -2,17 +2,21 @@ import * as doc from '../lib/doctor'
2
2
  import { Command } from '@commander-js/extra-typings'
3
3
  import tui from '../lib/tui'
4
4
 
5
- export const doctor = new Command('doctor')
6
- .description('Diagnose and fix common issues with the project setup')
5
+ export const doctorCmd = new Command('doctor')
6
+ .description('Diagnose status of the environment')
7
7
 
8
8
  .action(async () => {
9
- tui.title('Doctor')
10
-
11
- await tui.section('Checking Python3 installation', doc.checkPython3)
12
- await tui.section('Checking C/C++ installation', doc.checkGCC)
13
- await tui.section('Checking XeLaTeX installation', doc.checkXeLaTeX)
14
- await tui.section('Checking Pandoc installation', doc.checkPandoc)
15
- await tui.section('Checking ImageMagick installation', doc.checkImageMagick)
16
- await tui.section('Checking AI models', doc.checkEnvVars)
17
- await tui.section('Checking terminal', doc.checkTerminal)
9
+ await tui.section('Perform checks', async () => {
10
+ await tui.section('Checking Python3 installation', doc.checkPython3)
11
+ await tui.section('Checking C/C++ installation', doc.checkGCC)
12
+ await tui.section('Checking Haskell installation', doc.checkHaskell)
13
+ await tui.section('Checking Clojure installation', doc.checkClojure)
14
+ await tui.section('Checking Java installation', doc.checkJava)
15
+ await tui.section('Checking Rust installation', doc.checkRust)
16
+ await tui.section('Checking XeLaTeX installation', doc.checkXeLaTeX)
17
+ await tui.section('Checking Pandoc installation', doc.checkPandoc)
18
+ await tui.section('Checking ImageMagick installation', doc.checkImageMagick)
19
+ await tui.section('Checking AI models', doc.checkAIEnvVars)
20
+ await tui.section('Checking terminal', doc.checkTerminal)
21
+ })
18
22
  })