@jpetit/toolkit 3.0.22 → 3.1.1

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 (46) 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/package.json +48 -11
  15. package/toolkit/index.ts +32 -21
  16. package/lib/ai.ts +0 -144
  17. package/lib/cleaner.ts +0 -66
  18. package/lib/compilers/base.ts +0 -103
  19. package/lib/compilers/clojure.ts +0 -76
  20. package/lib/compilers/gcc.ts +0 -68
  21. package/lib/compilers/ghc.ts +0 -75
  22. package/lib/compilers/gxx.ts +0 -68
  23. package/lib/compilers/index.ts +0 -72
  24. package/lib/compilers/python3.ts +0 -105
  25. package/lib/compilers/run-haskell.ts +0 -113
  26. package/lib/compilers/run-python.ts +0 -109
  27. package/lib/data.ts +0 -19
  28. package/lib/doctor.ts +0 -158
  29. package/lib/generate.ts +0 -329
  30. package/lib/maker.ts +0 -700
  31. package/lib/settings.ts +0 -42
  32. package/lib/tui.ts +0 -142
  33. package/lib/types.ts +0 -20
  34. package/lib/utils.ts +0 -133
  35. package/toolkit/ai.ts +0 -30
  36. package/toolkit/clean.ts +0 -37
  37. package/toolkit/compilers.ts +0 -29
  38. package/toolkit/create-jutge-ai.ts +0 -101
  39. package/toolkit/create-template.ts +0 -55
  40. package/toolkit/create-wizard.ts +0 -6
  41. package/toolkit/create.ts +0 -65
  42. package/toolkit/doctor.ts +0 -18
  43. package/toolkit/generate.ts +0 -116
  44. package/toolkit/init.ts +0 -56
  45. package/toolkit/make.ts +0 -118
  46. package/toolkit/verify.ts +0 -19
@@ -1,116 +0,0 @@
1
- import tui from '../lib/tui'
2
- import { Maker, newMaker, type MakerOptions } from '../lib/maker'
3
- import { guessUserEmail, guessUserName, nothing, readText, writeText, writeYaml } from '../lib/utils'
4
- import { Command } from '@commander-js/extra-typings'
5
- import { languageNames } from '../lib/data'
6
- import { join } from 'path'
7
- import { cleanMardownCodeString, complete } from '../lib/ai'
8
- import { getTitleFromStatement } from '../lib/generate'
9
- import { writeFile } from 'fs/promises'
10
- import * as jdenticon from 'jdenticon'
11
-
12
- type Options = {
13
- directory: string
14
- verbose: boolean
15
- model: string
16
- }
17
-
18
- export const generate = new Command('generate')
19
- .description('Generate additional components')
20
- // Add common options here
21
- .option('-d, --directory <path>', 'problem directory', process.cwd()) // TODO: use '.' when bun fixes it
22
- .option('-v, --verbose', 'verbose output (TODO)')
23
- .option(
24
- '-m, --model <model>',
25
- 'the AI model to use (eg: openai/gpt-5, google/gemini-2.5-pro, ...)',
26
- 'google/gemini-2.5-flash-lite',
27
- )
28
-
29
- generate
30
- .command('translations')
31
- .description('Generate statement translations')
32
- .argument('<languages...>', 'languages to generate')
33
-
34
- .action(async (languages, options, command) => {
35
- const parentOptions = (command.parent?.opts() || {}) as any as Options
36
- const maker = await newMaker(parentOptions)
37
-
38
- await tui.section('Generating translations', async () => {
39
- for (const language of languages) {
40
- await generateTranslation(parentOptions.model, maker, language)
41
- }
42
- })
43
- })
44
-
45
- generate
46
- .command('award')
47
- .description('Generate random award')
48
-
49
- .action(async (options, command) => {
50
- const parentOptions = (command.parent?.opts() || {}) as any as Options
51
- const maker = await newMaker(parentOptions)
52
-
53
- await tui.section('Generating award', async () => {
54
- const png = jdenticon.toPng(maker.directory, 200)
55
- await writeFile(join(maker.directory, 'award.png'), png)
56
- await writeText(join(maker.directory, 'award.html'), '<b>Well done!</b>\n')
57
- tui.success(
58
- 'Award generated: ' +
59
- tui.hyperlink(maker.directory, 'award.png') +
60
- ' and ' +
61
- tui.hyperlink(maker.directory, 'award.html'),
62
- )
63
- await tui.image(join(maker.directory, 'award.png'), 6, 3)
64
- })
65
- })
66
-
67
- generate
68
- .command('solutions')
69
- .description('Generate solutions TODO')
70
- .argument('<proglangs...>', 'programming languages to generate')
71
-
72
- .action(async (proglangs, options, command) => {
73
- await nothing()
74
- throw new Error('Not implemented yet')
75
- })
76
-
77
- async function generateTranslation(model: string, maker: Maker, language: string) {
78
- const original = maker.originalLanguage
79
- if (!original) {
80
- throw new Error('Original language not set, cannot generate translations')
81
- }
82
- if (language === original) {
83
- throw new Error(`Language ${language} is the original language`)
84
- }
85
- if (maker.languages.includes(language)) {
86
- throw new Error(`Language ${language} already exists`)
87
- }
88
-
89
- const statememt = await readText(join(maker.directory, `problem.${original}.tex`))
90
-
91
- await tui.section(`Translating from ${languageNames[original]} to ${languageNames[language]}`, async () => {
92
- const prompt = `
93
- Translate the given problem statement to ${languageNames[language]}.
94
-
95
- The translation must be accurate and use proper technical terminology.
96
- Maintain the LaTeX formatting and macros.
97
- The texts that the program must read and write should not be translated.
98
- `
99
-
100
- tui.action(`Generating translation with ${model}`)
101
-
102
- const answer = cleanMardownCodeString(await complete(model, prompt, statememt))
103
-
104
- const info = {
105
- title: getTitleFromStatement(answer) || 'Error translating title',
106
- translator: (await guessUserName()) || 'Unknown',
107
- translator_email: (await guessUserEmail()) || 'unknown',
108
- model,
109
- }
110
- await writeText(join(maker.directory, `problem.${language}.tex`), answer)
111
- await writeYaml(join(maker.directory, `problem.${language}.yml`), info)
112
-
113
- tui.success(`Translation completed: files problem.${language}.tex and problem.${language}.yml created`)
114
- tui.warning(`Please review the generated translation`)
115
- })
116
- }
package/toolkit/init.ts DELETED
@@ -1,56 +0,0 @@
1
- import { initializePaths, loadSettings, paths, saveSettings, settingsExist } from '../lib/settings'
2
- import tui from '../lib/tui'
3
- import { guessUserEmail, guessUserName, nothing } from '../lib/utils'
4
- import { Command } from '@commander-js/extra-typings'
5
- import { confirm, input } from '@inquirer/prompts'
6
- import chalk from 'chalk'
7
-
8
- async function initialize() {
9
- await tui.section('Initialize', async () => {
10
- let name = (await guessUserName()) || 'John Doe'
11
- let email = (await guessUserEmail()) || 'john.doe@example.com'
12
-
13
- name = await input({ message: 'What is your name?', default: name })
14
- email = await input({ message: 'What is your email?', default: email })
15
- const notifications = await confirm({ message: 'Enable notifications?', default: true })
16
-
17
- await initializePaths()
18
- await saveSettings({ name, email, notifications })
19
-
20
- tui.success('Settings created')
21
- })
22
- }
23
-
24
- async function configure() {
25
- await tui.section('Configure', async () => {
26
- const settings = await loadSettings()
27
-
28
- const name = await input({ message: 'What is your name?', default: settings.name })
29
- const email = await input({ message: 'What is your email?', default: settings.email })
30
- const notifications = await confirm({ message: 'Enable notifications?', default: settings.notifications })
31
-
32
- await saveSettings({ name, email, notifications })
33
-
34
- tui.success('Settings updated')
35
- })
36
- }
37
-
38
- export const init = new Command('init')
39
- .description('Initialize/configure the toolkit')
40
-
41
- .action(async () => {
42
- if (await settingsExist()) {
43
- await configure()
44
- } else {
45
- await initialize()
46
- }
47
-
48
- await tui.section('Directories', async () => {
49
- await nothing()
50
- console.log('config:', chalk.magenta(paths.config))
51
- console.log('data: ', chalk.magenta(paths.data))
52
- console.log('cache: ', chalk.magenta(paths.cache))
53
- console.log('log: ', chalk.magenta(paths.log))
54
- console.log('temp: ', chalk.magenta(paths.temp))
55
- })
56
- })
package/toolkit/make.ts DELETED
@@ -1,118 +0,0 @@
1
- import tui from '../lib/tui'
2
- import { newMaker, type MakerOptions } from '../lib/maker'
3
- import { nothing, projectDir } from '../lib/utils'
4
- import { Command } from '@commander-js/extra-typings'
5
- import { join, normalize, resolve } from 'path'
6
- import { languageNames } from '../lib/data'
7
- import { exists } from 'fs/promises'
8
-
9
- /*
10
- Find real problem directories from a list of directories. A real problem directory is one that contains a handler.yml file.
11
- If a directory does not contain a handler.yml file, check if it contains subdirectories for each language that contain a handler.yml file.
12
- If so, add those subdirectories to the list of real problem directories.
13
- */
14
- async function findRealDirectories(directories: string[]): Promise<string[]> {
15
- const realDirectories: string[] = []
16
- for (let dir of directories) {
17
- if (dir === '.') {
18
- dir = normalize(resolve(process.cwd()))
19
- }
20
- if (await exists(join(dir, 'handler.yml'))) {
21
- realDirectories.push(dir)
22
- } else {
23
- for (const language of Object.keys(languageNames).sort()) {
24
- const child = join(dir, language, 'handler.yml')
25
- if (await exists(child)) {
26
- realDirectories.push(resolve(dir, language))
27
- }
28
- }
29
- }
30
- }
31
- return realDirectories
32
- }
33
-
34
- type TaskType = 'all' | 'inspection' | 'executables' | 'corrects' | 'pdf' | 'text'
35
-
36
- interface MakeOptions extends MakerOptions {
37
- directories: string[]
38
- tasks: TaskType[]
39
- ignoreErrors: boolean
40
- onlyErrors: boolean
41
- verbose?: boolean
42
- }
43
-
44
- export const make = new Command('make')
45
- .description('Make problem components')
46
- .argument('[directories...]', 'problem directories', ['.'])
47
- .option('-i, --ignore-errors', 'ignore errors on a directory and continue processing', false)
48
- .option('-e, --only-errors', 'only show errors at the final summary', false)
49
- .option('-t, --tasks <tasks...>', 'tasks to run: all, inspection, executables, corrects, pdf, text', ['all'])
50
- .option('-v, --verbose', 'verbose output (TODO)', false)
51
-
52
- .action(async (directories, options) => {
53
- console.log()
54
- await tui.image(join(projectDir(), 'assets', 'images', 'jutge-toolkit.png'), 8, 4)
55
-
56
- const { tasks, ignoreErrors, ...makerOptions } = options as MakeOptions
57
- const errors: Record<string, string> = {} // directory -> error message
58
-
59
- const realDirectories = await findRealDirectories(directories)
60
- // console.log(realDirectories)
61
-
62
- for (const directory of realDirectories) {
63
- try {
64
- tui.title(`Making problem in directory ${tui.hyperlink(directory, resolve(directory))}`)
65
-
66
- const maker = await newMaker({ ...makerOptions, directory })
67
-
68
- // If tasks include 'all', run makeProblem
69
- if (tasks.includes('all')) {
70
- await maker.makeProblem()
71
- } else {
72
- // Run specific tasks
73
- if (tasks.includes('inspection')) {
74
- // already done in maker initialization
75
- }
76
- if (tasks.includes('executables')) {
77
- await maker.makeExecutables()
78
- }
79
- if (tasks.includes('corrects')) {
80
- await maker.makeCorrects()
81
- }
82
- if (tasks.includes('pdf')) {
83
- await maker.makePdfs()
84
- }
85
- if (tasks.includes('text')) {
86
- await maker.makeTexts()
87
- }
88
- }
89
- } catch (error) {
90
- const errorMessage = error instanceof Error ? error.message : String(error)
91
-
92
- if (ignoreErrors) {
93
- errors[directory] = errorMessage
94
- tui.error(`Error: ${errorMessage}`)
95
- } else {
96
- throw error
97
- }
98
- }
99
- console.log()
100
- }
101
-
102
- tui.title('Summary')
103
- await tui.section('', async () => {
104
- await nothing()
105
- if (realDirectories.length === 0) {
106
- tui.warning('No problem directories found')
107
- }
108
- for (const directory of realDirectories) {
109
- if (errors[directory]) {
110
- tui.directory(directory)
111
- tui.error(` ${errors[directory]}`)
112
- } else if (!options.onlyErrors) {
113
- tui.directory(directory)
114
- tui.success(` No errors found`)
115
- }
116
- }
117
- })
118
- })
package/toolkit/verify.ts DELETED
@@ -1,19 +0,0 @@
1
- import { newMaker } from '../lib/maker'
2
- import { Command } from '@commander-js/extra-typings'
3
- import { normalize } from 'path'
4
-
5
- export const verify = new Command('verify')
6
- .description('Verify candidate programs')
7
- // Add common options here
8
-
9
- .argument('<programs...>', 'source programs to verify')
10
- .option('-d, --directory <path>', 'problem directory', process.cwd()) // TODO: use '.' when bun fixes it
11
- .option('-v, --verbose', 'verbose output (TODO)')
12
-
13
- .action(async (programs, { directory, verbose }) => {
14
- directory = normalize(directory)
15
- const maker = await newMaker({ verbose, directory })
16
- for (const program of programs) {
17
- await maker.verifyCandidate(program)
18
- }
19
- })