@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.
- package/assets/prompts/creators/create-solution.tpl.txt +10 -0
- package/assets/prompts/creators/create-statement.tpl.txt +21 -0
- package/assets/prompts/creators/create-translation.tpl.txt +5 -0
- package/assets/prompts/creators/private-test-cases.txt +6 -0
- package/assets/prompts/creators/sample-test-cases.txt +6 -0
- package/assets/prompts/creators/system-prompt.txt +2 -0
- package/assets/prompts/examples/statement-coda.tex +7 -0
- package/assets/prompts/examples/statement.tex +19 -0
- package/assets/prompts/generators/efficiency.md +41 -0
- package/assets/prompts/generators/hard.md +47 -0
- package/assets/prompts/generators/random.md +39 -0
- package/assets/prompts/proglangs/cc.md +3 -0
- package/assets/prompts/proglangs/py.md +40 -0
- package/package.json +48 -11
- package/toolkit/index.ts +32 -21
- package/lib/ai.ts +0 -144
- package/lib/cleaner.ts +0 -66
- package/lib/compilers/base.ts +0 -103
- package/lib/compilers/clojure.ts +0 -76
- package/lib/compilers/gcc.ts +0 -68
- package/lib/compilers/ghc.ts +0 -75
- package/lib/compilers/gxx.ts +0 -68
- package/lib/compilers/index.ts +0 -72
- package/lib/compilers/python3.ts +0 -105
- package/lib/compilers/run-haskell.ts +0 -113
- package/lib/compilers/run-python.ts +0 -109
- package/lib/data.ts +0 -19
- package/lib/doctor.ts +0 -158
- package/lib/generate.ts +0 -329
- package/lib/maker.ts +0 -700
- package/lib/settings.ts +0 -42
- package/lib/tui.ts +0 -142
- package/lib/types.ts +0 -20
- package/lib/utils.ts +0 -133
- package/toolkit/ai.ts +0 -30
- package/toolkit/clean.ts +0 -37
- package/toolkit/compilers.ts +0 -29
- package/toolkit/create-jutge-ai.ts +0 -101
- package/toolkit/create-template.ts +0 -55
- package/toolkit/create-wizard.ts +0 -6
- package/toolkit/create.ts +0 -65
- package/toolkit/doctor.ts +0 -18
- package/toolkit/generate.ts +0 -116
- package/toolkit/init.ts +0 -56
- package/toolkit/make.ts +0 -118
- package/toolkit/verify.ts +0 -19
package/toolkit/generate.ts
DELETED
|
@@ -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
|
-
})
|