@jutge.org/toolkit 4.4.5 → 4.4.7

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.
@@ -254,7 +254,7 @@ jtk verify <program> # Test a solution
254
254
  jtk upload # Upload to Jutge.org
255
255
  jtk submit -l <language> <solution> # Submit a solution to Jutge.org
256
256
  jtk clean # Clean temporary files
257
- jtk passcode # Manage problem passcode
257
+ jtk share # Update and show sharing settings (passcode, testcases, solutions)
258
258
 
259
259
  jtk doctor # Check system dependencies
260
260
  ```
@@ -169,7 +169,7 @@ The `\Link{...}` macro provides a hyperlink to another problem (without specifie
169
169
 
170
170
  ## The `problem.yml` file
171
171
 
172
- Once a problem is uploaded to Jutge.org, a `problem.yml` file is automatically created in the root of the problem folder. This file contains metadata about the problem that is used by the system. **The fields of this file should not be modified by hand**. In it, you will find fields such as the problem identifier (e.g., X12345), its passcode, the time of creation, and the time of the last modification. Importantly, the presence of this file indicates that the problem has already been uploaded to Jutge.org.
172
+ Once a problem is uploaded to Jutge.org, a `problem.yml` file is automatically created in the root of the problem folder. This file contains metadata about the problem that is used by the system. **The fields of this file should not be modified by hand**. In it, you will find fields such as the problem identifier (e.g., X12345), its sharing settings (passcode, shared testcases, shared solutions), the time of creation, and the time of the last modification. You can view and update these sharing settings with the `jtk share` command. Importantly, the presence of this file indicates that the problem has already been uploaded to Jutge.org.
173
173
 
174
174
  If you are creating a problem from a copy of an existing problem, be sure to delete the `problem.yml` file before uploading it to Jutge.org to avoid interfering with the existing problem.
175
175
 
@@ -178,6 +178,8 @@ Here is an example of a `problem.yml` file:
178
178
  ```yml
179
179
  problem_nm: X12345
180
180
  passcode: 16PbADb1qfDj
181
+ shared_testcases: false
182
+ shared_solutions: false
181
183
  created_at: 2016-01-13T11:33:16.187Z
182
184
  updated_at: 2026-01-13T12:47:12.884Z
183
185
  ```
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jutge.org/toolkit",
3
3
  "description": "Toolkit to prepare problems for Jutge.org",
4
- "version": "4.4.5",
4
+ "version": "4.4.7",
5
5
  "homepage": "https://jutge.org",
6
6
  "author": {
7
7
  "name": "Jutge.org",
package/toolkit/index.ts CHANGED
@@ -17,7 +17,7 @@ import { makeCmd } from './make'
17
17
  import { quizCmd } from './quiz'
18
18
  import { upgradeCmd } from './upgrade'
19
19
  import { uploadCmd } from './upload'
20
- import { cmdPasscode } from './passcode'
20
+ import { cmdShare } from './share'
21
21
  import { submitCmd } from './submit'
22
22
  import { askCmd } from './ask'
23
23
  import { convertCmd } from './convert'
@@ -34,7 +34,7 @@ program.addHelpText('after', '\nMore documentation:\n https://github.com/jutge-
34
34
 
35
35
  program.addCommand(makeCmd)
36
36
  program.addCommand(uploadCmd)
37
- program.addCommand(cmdPasscode)
37
+ program.addCommand(cmdShare)
38
38
  program.addCommand(cleanCmd)
39
39
  program.addCommand(cloneCmd)
40
40
  program.addCommand(generateCmd)
@@ -0,0 +1,49 @@
1
+ import { password } from '@inquirer/prompts'
2
+ import { Command } from '@commander-js/extra-typings'
3
+ import { updateSharingSettings } from '../lib/share'
4
+
5
+
6
+ export const cmdShare = new Command('share')
7
+ .summary('Update and show sharing settings')
8
+
9
+ .description(`Update and show sharing settings
10
+
11
+ First, this command updates the sharing settings in problem.yml file with the ones on Jutge.org to ensure they are consistent.
12
+
13
+ Then, it updates the sharing settings in Jutge.org with the requested changes. The following options are available:
14
+ --passcode [code] Set a passcode (prompted if omitted)
15
+ --no-passcode Clear the passcode
16
+ --testcases Share testcases
17
+ --no-testcases Stop sharing testcases
18
+ --solutions Share solutions
19
+ --no-solutions Stop sharing solutions
20
+
21
+ Finally, it updates problem.yml file with the current sharing settings and shows them.`)
22
+
23
+ .option('-d, --directory <directory>', 'problem directory', '.')
24
+ .option('--passcode [code]', 'Set a passcode (prompted if omitted)')
25
+ .option('--no-passcode', 'Clear the passcode')
26
+ .option('--testcases', 'Share testcases')
27
+ .option('--no-testcases', 'Stop sharing testcases')
28
+ .option('--solutions', 'Share solutions')
29
+ .option('--no-solutions', 'Stop sharing solutions')
30
+
31
+ .action(async function () {
32
+ const opts = this.opts()
33
+
34
+ let passcode: string | undefined | false
35
+ if (this.getOptionValueSource('passcode') === undefined) {
36
+ passcode = undefined
37
+ } else if (this.getOptionValueSource('passcode') === 'cli') {
38
+ if (opts.passcode === true) {
39
+ passcode = await password({ message: 'Passcode:' })
40
+ } else {
41
+ passcode = opts.passcode
42
+ }
43
+ }
44
+
45
+ const testcases = this.getOptionValueSource('testcases') !== 'default' ? opts.testcases : undefined
46
+ const solutions = this.getOptionValueSource('solutions') !== 'default' ? opts.solutions : undefined
47
+
48
+ await updateSharingSettings(opts.directory, { passcode, testcases, solutions })
49
+ })
package/toolkit/create.ts DELETED
@@ -1,36 +0,0 @@
1
- import { Command } from '@commander-js/extra-typings'
2
- import { createProblemWithJutgeAI } from '../lib/create-with-jutgeai'
3
- import { createProblemWithTemplate } from '../lib/create-with-template'
4
- import { settings } from '../lib/settings'
5
-
6
- export const createCmd = new Command('create')
7
- .description('Create a new problem')
8
-
9
- .action(() => {
10
- createCmd.help()
11
- })
12
-
13
- createCmd
14
- .command('with-template')
15
- .description('Create a problem with a template')
16
-
17
- .argument('[template]', 'template to use (empty to interactive selection)')
18
- .option('-d, --directory <path>', 'output directory', 'new-problem.pbm')
19
-
20
- .action(async (template, { directory }) => {
21
- await createProblemWithTemplate(directory, template)
22
- })
23
-
24
- createCmd
25
- .command('with-ai')
26
- .description('Create a problem with JutgeAI')
27
-
28
- .option('-d, --directory <path>', 'output directory', 'new-problem.pbm')
29
- .option('-i, --input <path>', 'input specification file')
30
- .option('-o, --output <path>', 'output specification file')
31
- .option('-n, --do-not-ask', 'do not ask interactively if --input given', false)
32
- .option('-m, --model <model>', 'AI model to use', settings.defaultModel)
33
-
34
- .action(async ({ input, output, directory, model, doNotAsk }) => {
35
- await createProblemWithJutgeAI(model, directory, input, output, doNotAsk)
36
- })
@@ -1,41 +0,0 @@
1
- import { Command } from '@commander-js/extra-typings'
2
- import { removePasscodeInDirectory, setPasscodeInDirectory, showPasscodeInDirectory } from '../lib/passcode'
3
-
4
- export const cmdPasscode = new Command('passcode')
5
- .summary('Show, set or remove problem passcode')
6
- .description(
7
- `Show, set or remove the passcode of a problem at Jutge.org.
8
-
9
- These operations require an existing problem.yml file in the problem directory.
10
- On success, problem.yml is updated with the new passcode (or empty for remove).`,
11
- )
12
-
13
-
14
- cmdPasscode
15
- .command('show')
16
- .description('Show the passcode of the problem')
17
- .option('-d, --directory <directory>', 'problem directory', '.')
18
-
19
- .action(async ({ directory }) => {
20
- await showPasscodeInDirectory(directory)
21
- })
22
-
23
- cmdPasscode
24
- .command('set')
25
- .description('Set or update the passcode of the problem')
26
-
27
- .option('-d, --directory <directory>', 'problem directory', '.')
28
- .option('-p, --passcode <passcode>', 'passcode (if omitted, will prompt)')
29
-
30
- .action(async ({ directory, passcode }) => {
31
- await setPasscodeInDirectory(directory, passcode)
32
- })
33
-
34
- cmdPasscode
35
- .command('remove')
36
- .description('Remove the passcode of the problem')
37
- .option('-d, --directory <directory>', 'problem directory', '.')
38
-
39
- .action(async ({ directory }) => {
40
- await removePasscodeInDirectory(directory)
41
- })