erdos-problems 0.1.1 → 0.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.
- package/README.md +50 -2
- package/data/upstream/erdosproblems/PROBLEMS_INDEX.json +44420 -0
- package/data/upstream/erdosproblems/SYNC_MANIFEST.json +9 -0
- package/data/upstream/erdosproblems/problems.yaml +13077 -0
- package/docs/ERDOS_PROBLEMS_PROBLEM_SCHEMA.md +104 -119
- package/package.json +5 -1
- package/problems/1008/problem.yaml +30 -9
- package/problems/18/problem.yaml +31 -10
- package/problems/20/problem.yaml +30 -8
- package/problems/536/problem.yaml +30 -8
- package/problems/542/problem.yaml +30 -9
- package/problems/856/problem.yaml +30 -8
- package/problems/857/problem.yaml +31 -9
- package/problems/89/problem.yaml +30 -9
- package/src/atlas/catalog.js +78 -140
- package/src/cli/index.js +16 -1
- package/src/commands/bootstrap.js +81 -0
- package/src/commands/dossier.js +19 -11
- package/src/commands/problem.js +94 -5
- package/src/commands/scaffold.js +60 -0
- package/src/commands/upstream.js +60 -0
- package/src/commands/workspace.js +2 -0
- package/src/runtime/files.js +37 -0
- package/src/runtime/paths.js +64 -0
- package/src/runtime/problem-artifacts.js +150 -0
- package/src/runtime/workspace.js +7 -7
- package/src/upstream/sync.js +272 -0
package/problems/89/problem.yaml
CHANGED
|
@@ -1,16 +1,37 @@
|
|
|
1
1
|
problem_id: "89"
|
|
2
2
|
display_name: "Erdos Problem #89"
|
|
3
|
-
title:
|
|
3
|
+
title: Distinct Distances Lower Bound
|
|
4
4
|
source:
|
|
5
|
-
site:
|
|
6
|
-
url:
|
|
5
|
+
site: erdosproblems.com
|
|
6
|
+
url: https://www.erdosproblems.com/89
|
|
7
7
|
external_id: "89"
|
|
8
|
+
upstream:
|
|
9
|
+
repo: https://github.com/teorth/erdosproblems
|
|
10
|
+
data_file: data/problems.yaml
|
|
11
|
+
number: "89"
|
|
8
12
|
status:
|
|
9
|
-
site_status:
|
|
10
|
-
site_badge:
|
|
11
|
-
repo_status:
|
|
12
|
-
|
|
13
|
+
site_status: open
|
|
14
|
+
site_badge: OPEN
|
|
15
|
+
repo_status: cataloged
|
|
16
|
+
upstream_status: open
|
|
17
|
+
upstream_last_update: 2025-08-31
|
|
18
|
+
cluster: geometry
|
|
19
|
+
prize:
|
|
20
|
+
display: $500
|
|
13
21
|
related_problems: []
|
|
14
22
|
family_tags:
|
|
15
|
-
-
|
|
16
|
-
-
|
|
23
|
+
- geometry
|
|
24
|
+
- distances
|
|
25
|
+
harness:
|
|
26
|
+
depth: dossier
|
|
27
|
+
statement:
|
|
28
|
+
short: Ask whether every n-point set in the plane determines at least a constant
|
|
29
|
+
multiple of n/sqrt(log n) distinct distances.
|
|
30
|
+
normalized_md_path: STATEMENT.md
|
|
31
|
+
references_path: REFERENCES.md
|
|
32
|
+
evidence_path: EVIDENCE.md
|
|
33
|
+
formalization_path: FORMALIZATION.md
|
|
34
|
+
formalization:
|
|
35
|
+
status: statement-formalized
|
|
36
|
+
upstream_state: yes
|
|
37
|
+
upstream_last_update: 2025-10-24
|
package/src/atlas/catalog.js
CHANGED
|
@@ -1,154 +1,88 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
siteStatus: 'solved',
|
|
71
|
-
siteBadge: 'SOLVED',
|
|
72
|
-
repoStatus: 'historical',
|
|
73
|
-
cluster: 'number-theory',
|
|
74
|
-
familyTags: ['number-theory', 'least-common-multiple'],
|
|
75
|
-
relatedProblems: ['784'],
|
|
76
|
-
sourceUrl: 'https://www.erdosproblems.com/542',
|
|
77
|
-
shortStatement:
|
|
78
|
-
'Control reciprocal sums of sets with all pairwise least common multiples above n, a problem resolved by Schinzel and Szekeres.',
|
|
79
|
-
harnessDepth: 'dossier',
|
|
80
|
-
formalizationStatus: 'unstarted',
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
problemId: '856',
|
|
84
|
-
displayName: 'Erdos Problem #856',
|
|
85
|
-
title: 'Harmonic LCM Sunflower Analogue',
|
|
86
|
-
siteStatus: 'open',
|
|
87
|
-
siteBadge: 'OPEN',
|
|
88
|
-
repoStatus: 'cataloged',
|
|
89
|
-
cluster: 'sunflower',
|
|
90
|
-
familyTags: ['sunflower-analogue', 'number-theory'],
|
|
91
|
-
relatedProblems: ['857'],
|
|
92
|
-
sourceUrl: 'https://www.erdosproblems.com/856',
|
|
93
|
-
shortStatement:
|
|
94
|
-
'A harmonic or density-shaped LCM analogue whose exponents are explicitly linked to progress on the weak sunflower problem.',
|
|
95
|
-
harnessDepth: 'dossier',
|
|
96
|
-
formalizationStatus: 'planned',
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
problemId: '857',
|
|
100
|
-
displayName: 'Erdos Problem #857',
|
|
101
|
-
title: 'Sunflower Conjecture',
|
|
102
|
-
siteStatus: 'open',
|
|
103
|
-
siteBadge: 'OPEN',
|
|
104
|
-
repoStatus: 'active',
|
|
105
|
-
cluster: 'sunflower',
|
|
106
|
-
familyTags: ['sunflower', 'extremal-set-theory'],
|
|
107
|
-
relatedProblems: ['20', '536', '856'],
|
|
108
|
-
sourceUrl: 'https://www.erdosproblems.com/857',
|
|
109
|
-
shortStatement:
|
|
110
|
-
'Bound the weak sunflower number m(n,k) by C(k)^n and sharpen the current active route toward asymptotic closure.',
|
|
111
|
-
harnessDepth: 'deep',
|
|
112
|
-
formalizationStatus: 'active',
|
|
113
|
-
researchState: {
|
|
114
|
-
openProblem: true,
|
|
115
|
-
activeRoute: 'anchored_selector_linearization',
|
|
116
|
-
routeBreakthrough: true,
|
|
117
|
-
problemSolved: false,
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
problemId: '1008',
|
|
122
|
-
displayName: 'Erdos Problem #1008',
|
|
123
|
-
title: 'C4-Free Subgraph Density Problem',
|
|
124
|
-
siteStatus: 'solved',
|
|
125
|
-
siteBadge: 'PROVED (LEAN)',
|
|
126
|
-
repoStatus: 'historical',
|
|
127
|
-
cluster: 'graph-theory',
|
|
128
|
-
familyTags: ['graph-theory', 'cycles'],
|
|
129
|
-
relatedProblems: [],
|
|
130
|
-
sourceUrl: 'https://www.erdosproblems.com/1008',
|
|
131
|
-
shortStatement:
|
|
132
|
-
'Determine whether every graph with m edges contains a C4-free subgraph with a constant multiple of m^(2/3) edges.',
|
|
133
|
-
harnessDepth: 'dossier',
|
|
134
|
-
formalizationStatus: 'site-proved-lean',
|
|
135
|
-
},
|
|
136
|
-
];
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { parse } from 'yaml';
|
|
4
|
+
import { getProblemDir, repoRoot } from '../runtime/paths.js';
|
|
5
|
+
|
|
6
|
+
let cachedProblems = null;
|
|
7
|
+
|
|
8
|
+
function readProblemRecord(problemId) {
|
|
9
|
+
const problemDir = getProblemDir(problemId);
|
|
10
|
+
const yamlPath = path.join(problemDir, 'problem.yaml');
|
|
11
|
+
const record = parse(fs.readFileSync(yamlPath, 'utf8'));
|
|
12
|
+
return { problemDir, record };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function toCatalogProblem(problemDir, record) {
|
|
16
|
+
const statementRelative = record.statement?.normalized_md_path ?? 'STATEMENT.md';
|
|
17
|
+
const referencesRelative = record.references_path ?? 'REFERENCES.md';
|
|
18
|
+
const evidenceRelative = record.evidence_path ?? 'EVIDENCE.md';
|
|
19
|
+
const formalizationRelative = record.formalization_path ?? 'FORMALIZATION.md';
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
problemId: String(record.problem_id),
|
|
23
|
+
displayName: record.display_name,
|
|
24
|
+
title: record.title,
|
|
25
|
+
sourceUrl: record.source?.url,
|
|
26
|
+
sourceSite: record.source?.site,
|
|
27
|
+
siteStatus: record.status?.site_status ?? 'unknown',
|
|
28
|
+
siteBadge: record.status?.site_badge ?? String(record.status?.site_status ?? 'unknown').toUpperCase(),
|
|
29
|
+
repoStatus: record.status?.repo_status ?? 'cataloged',
|
|
30
|
+
upstreamStatus: record.status?.upstream_status ?? null,
|
|
31
|
+
upstreamLastUpdate: record.status?.upstream_last_update ?? null,
|
|
32
|
+
cluster: record.cluster ?? 'uncategorized',
|
|
33
|
+
prize: record.prize?.display ?? null,
|
|
34
|
+
familyTags: record.family_tags ?? [],
|
|
35
|
+
relatedProblems: record.related_problems ?? [],
|
|
36
|
+
harnessDepth: record.harness?.depth ?? 'dossier',
|
|
37
|
+
shortStatement: record.statement?.short ?? '',
|
|
38
|
+
formalizationStatus: record.formalization?.status ?? 'unstarted',
|
|
39
|
+
upstreamFormalizedState: record.formalization?.upstream_state ?? null,
|
|
40
|
+
upstreamFormalizedLastUpdate: record.formalization?.upstream_last_update ?? null,
|
|
41
|
+
researchState: record.research_state ?? null,
|
|
42
|
+
upstream: record.upstream ?? null,
|
|
43
|
+
statementPath: path.join(problemDir, statementRelative),
|
|
44
|
+
referencesPath: path.join(problemDir, referencesRelative),
|
|
45
|
+
evidencePath: path.join(problemDir, evidenceRelative),
|
|
46
|
+
formalizationPath: path.join(problemDir, formalizationRelative),
|
|
47
|
+
problemDir,
|
|
48
|
+
problemYamlPath: path.join(problemDir, 'problem.yaml'),
|
|
49
|
+
record,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function loadLocalProblems() {
|
|
54
|
+
if (cachedProblems) {
|
|
55
|
+
return cachedProblems;
|
|
56
|
+
}
|
|
57
|
+
const problemsRoot = path.join(repoRoot, 'problems');
|
|
58
|
+
const directories = fs
|
|
59
|
+
.readdirSync(problemsRoot, { withFileTypes: true })
|
|
60
|
+
.filter((entry) => entry.isDirectory())
|
|
61
|
+
.map((entry) => entry.name)
|
|
62
|
+
.sort((a, b) => Number(a) - Number(b));
|
|
63
|
+
|
|
64
|
+
cachedProblems = directories.map((problemId) => {
|
|
65
|
+
const { problemDir, record } = readProblemRecord(problemId);
|
|
66
|
+
return toCatalogProblem(problemDir, record);
|
|
67
|
+
});
|
|
68
|
+
return cachedProblems;
|
|
69
|
+
}
|
|
137
70
|
|
|
138
71
|
export function listProblems(filters = {}) {
|
|
139
72
|
const cluster = filters.cluster ? String(filters.cluster).toLowerCase() : null;
|
|
140
73
|
const repoStatus = filters.repoStatus ? String(filters.repoStatus).toLowerCase() : null;
|
|
141
74
|
const harnessDepth = filters.harnessDepth ? String(filters.harnessDepth).toLowerCase() : null;
|
|
75
|
+
const siteStatus = filters.siteStatus ? String(filters.siteStatus).toLowerCase() : null;
|
|
142
76
|
|
|
143
|
-
return
|
|
77
|
+
return loadLocalProblems()
|
|
144
78
|
.filter((entry) => (cluster ? entry.cluster === cluster : true))
|
|
145
79
|
.filter((entry) => (repoStatus ? entry.repoStatus === repoStatus : true))
|
|
146
80
|
.filter((entry) => (harnessDepth ? entry.harnessDepth === harnessDepth : true))
|
|
147
|
-
.
|
|
81
|
+
.filter((entry) => (siteStatus ? entry.siteStatus === siteStatus : true));
|
|
148
82
|
}
|
|
149
83
|
|
|
150
84
|
export function getProblem(problemId) {
|
|
151
|
-
return
|
|
85
|
+
return loadLocalProblems().find((entry) => entry.problemId === String(problemId));
|
|
152
86
|
}
|
|
153
87
|
|
|
154
88
|
export function getCluster(clusterName) {
|
|
@@ -166,6 +100,10 @@ export function getCluster(clusterName) {
|
|
|
166
100
|
}
|
|
167
101
|
|
|
168
102
|
export function listClusters() {
|
|
169
|
-
const names = [...new Set(
|
|
103
|
+
const names = [...new Set(loadLocalProblems().map((entry) => entry.cluster))].sort();
|
|
170
104
|
return names.map((name) => getCluster(name));
|
|
171
105
|
}
|
|
106
|
+
|
|
107
|
+
export function clearCatalogCache() {
|
|
108
|
+
cachedProblems = null;
|
|
109
|
+
}
|
package/src/cli/index.js
CHANGED
|
@@ -1,20 +1,29 @@
|
|
|
1
|
+
import { runBootstrapCommand } from '../commands/bootstrap.js';
|
|
1
2
|
import { runClusterCommand } from '../commands/cluster.js';
|
|
2
3
|
import { runDossierCommand } from '../commands/dossier.js';
|
|
3
4
|
import { runProblemCommand } from '../commands/problem.js';
|
|
5
|
+
import { runScaffoldCommand } from '../commands/scaffold.js';
|
|
6
|
+
import { runUpstreamCommand } from '../commands/upstream.js';
|
|
4
7
|
import { runWorkspaceCommand } from '../commands/workspace.js';
|
|
5
8
|
|
|
6
9
|
function printUsage() {
|
|
7
10
|
console.log('erdos-problems CLI');
|
|
8
11
|
console.log('');
|
|
9
12
|
console.log('Usage:');
|
|
10
|
-
console.log(' erdos problem list [--cluster <name>]');
|
|
13
|
+
console.log(' erdos problem list [--cluster <name>] [--repo-status <status>] [--harness-depth <depth>] [--site-status <status>]');
|
|
11
14
|
console.log(' erdos problem show <id>');
|
|
12
15
|
console.log(' erdos problem use <id>');
|
|
13
16
|
console.log(' erdos problem current');
|
|
17
|
+
console.log(' erdos problem artifacts [<id>] [--json]');
|
|
14
18
|
console.log(' erdos cluster list');
|
|
15
19
|
console.log(' erdos cluster show <name>');
|
|
16
20
|
console.log(' erdos workspace show');
|
|
17
21
|
console.log(' erdos dossier show <id>');
|
|
22
|
+
console.log(' erdos upstream show');
|
|
23
|
+
console.log(' erdos upstream sync [--write-package-snapshot]');
|
|
24
|
+
console.log(' erdos upstream diff [--write-package-report]');
|
|
25
|
+
console.log(' erdos scaffold problem <id> [--dest <path>]');
|
|
26
|
+
console.log(' erdos bootstrap problem <id> [--dest <path>] [--sync-upstream]');
|
|
18
27
|
}
|
|
19
28
|
|
|
20
29
|
const args = process.argv.slice(2);
|
|
@@ -32,6 +41,12 @@ if (!command || command === 'help' || command === '--help') {
|
|
|
32
41
|
exitCode = runWorkspaceCommand(rest);
|
|
33
42
|
} else if (command === 'dossier') {
|
|
34
43
|
exitCode = runDossierCommand(rest);
|
|
44
|
+
} else if (command === 'upstream') {
|
|
45
|
+
exitCode = await runUpstreamCommand(rest);
|
|
46
|
+
} else if (command === 'scaffold') {
|
|
47
|
+
exitCode = runScaffoldCommand(rest);
|
|
48
|
+
} else if (command === 'bootstrap') {
|
|
49
|
+
exitCode = await runBootstrapCommand(rest);
|
|
35
50
|
} else {
|
|
36
51
|
console.error(`Unknown command: ${command}`);
|
|
37
52
|
printUsage();
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { getProblem } from '../atlas/catalog.js';
|
|
3
|
+
import { scaffoldProblem } from '../runtime/problem-artifacts.js';
|
|
4
|
+
import { getWorkspaceProblemScaffoldDir } from '../runtime/paths.js';
|
|
5
|
+
import { setCurrentProblem } from '../runtime/workspace.js';
|
|
6
|
+
import { syncUpstream } from '../upstream/sync.js';
|
|
7
|
+
|
|
8
|
+
function parseBootstrapArgs(args) {
|
|
9
|
+
const [kind, value, ...rest] = args;
|
|
10
|
+
if (kind !== 'problem') {
|
|
11
|
+
return { error: 'Only `erdos bootstrap problem <id>` is supported right now.' };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let destination = null;
|
|
15
|
+
let syncUpstreamSnapshot = false;
|
|
16
|
+
|
|
17
|
+
for (let index = 0; index < rest.length; index += 1) {
|
|
18
|
+
const token = rest[index];
|
|
19
|
+
if (token === '--dest') {
|
|
20
|
+
destination = rest[index + 1];
|
|
21
|
+
if (!destination) {
|
|
22
|
+
return { error: 'Missing destination path after --dest.' };
|
|
23
|
+
}
|
|
24
|
+
index += 1;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (token === '--sync-upstream') {
|
|
28
|
+
syncUpstreamSnapshot = true;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
return { error: `Unknown bootstrap option: ${token}` };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
problemId: value,
|
|
36
|
+
destination,
|
|
37
|
+
syncUpstreamSnapshot,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function runBootstrapCommand(args) {
|
|
42
|
+
if (args.length === 0 || args[0] === 'help' || args[0] === '--help') {
|
|
43
|
+
console.log('Usage:');
|
|
44
|
+
console.log(' erdos bootstrap problem <id> [--dest <path>] [--sync-upstream]');
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const parsed = parseBootstrapArgs(args);
|
|
49
|
+
if (parsed.error) {
|
|
50
|
+
console.error(parsed.error);
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
if (!parsed.problemId) {
|
|
54
|
+
console.error('Missing problem id.');
|
|
55
|
+
return 1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const problem = getProblem(parsed.problemId);
|
|
59
|
+
if (!problem) {
|
|
60
|
+
console.error(`Unknown problem: ${parsed.problemId}`);
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (parsed.syncUpstreamSnapshot) {
|
|
65
|
+
const syncResult = await syncUpstream();
|
|
66
|
+
console.log(`Workspace upstream snapshot refreshed: ${syncResult.workspacePaths.manifestPath}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
setCurrentProblem(problem.problemId);
|
|
70
|
+
const destination = parsed.destination
|
|
71
|
+
? path.resolve(parsed.destination)
|
|
72
|
+
: getWorkspaceProblemScaffoldDir(problem.problemId);
|
|
73
|
+
const result = scaffoldProblem(problem, destination);
|
|
74
|
+
|
|
75
|
+
console.log(`Bootstrapped problem ${problem.problemId} (${problem.title})`);
|
|
76
|
+
console.log(`Active problem: ${problem.problemId}`);
|
|
77
|
+
console.log(`Scaffold dir: ${result.destination}`);
|
|
78
|
+
console.log(`Artifacts copied: ${result.copiedArtifacts.length}`);
|
|
79
|
+
console.log(`Upstream record included: ${result.inventory.upstreamRecordIncluded ? 'yes' : 'no'}`);
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
package/src/commands/dossier.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
2
|
import { getProblem } from '../atlas/catalog.js';
|
|
4
|
-
import { getProblemDir } from '../runtime/paths.js';
|
|
5
3
|
import { readCurrentProblem } from '../runtime/workspace.js';
|
|
6
4
|
|
|
7
|
-
const sections = [
|
|
5
|
+
const sections = [
|
|
6
|
+
['problem.yaml', 'problemYamlPath'],
|
|
7
|
+
['STATEMENT.md', 'statementPath'],
|
|
8
|
+
['REFERENCES.md', 'referencesPath'],
|
|
9
|
+
['EVIDENCE.md', 'evidencePath'],
|
|
10
|
+
['FORMALIZATION.md', 'formalizationPath'],
|
|
11
|
+
];
|
|
8
12
|
|
|
9
13
|
export function runDossierCommand(args) {
|
|
10
14
|
const [subcommand, value] = args;
|
|
@@ -32,20 +36,24 @@ export function runDossierCommand(args) {
|
|
|
32
36
|
return 1;
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
const problemDir = getProblemDir(problem.problemId);
|
|
36
39
|
console.log(`${problem.displayName} dossier`);
|
|
37
|
-
console.log(`Directory: ${problemDir}`);
|
|
40
|
+
console.log(`Directory: ${problem.problemDir}`);
|
|
38
41
|
console.log('Sections:');
|
|
39
|
-
for (const
|
|
40
|
-
const filePath =
|
|
42
|
+
for (const [label, key] of sections) {
|
|
43
|
+
const filePath = problem[key];
|
|
41
44
|
const exists = fs.existsSync(filePath);
|
|
42
|
-
console.log(`- ${
|
|
45
|
+
console.log(`- ${label}: ${exists ? 'present' : 'missing'}`);
|
|
43
46
|
}
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
console.log('');
|
|
48
|
+
console.log('Canonical metadata:');
|
|
49
|
+
console.log(`- cluster: ${problem.cluster}`);
|
|
50
|
+
console.log(`- repo status: ${problem.repoStatus}`);
|
|
51
|
+
console.log(`- harness depth: ${problem.harnessDepth}`);
|
|
52
|
+
console.log(`- upstream number: ${problem.upstream?.number ?? '(unset)'}`);
|
|
53
|
+
if (fs.existsSync(problem.statementPath)) {
|
|
46
54
|
console.log('');
|
|
47
55
|
console.log('Statement preview:');
|
|
48
|
-
console.log(fs.readFileSync(statementPath, 'utf8').trim());
|
|
56
|
+
console.log(fs.readFileSync(problem.statementPath, 'utf8').trim());
|
|
49
57
|
}
|
|
50
58
|
return 0;
|
|
51
59
|
}
|
package/src/commands/problem.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getProblem, listProblems } from '../atlas/catalog.js';
|
|
2
|
+
import { getProblemArtifactInventory } from '../runtime/problem-artifacts.js';
|
|
2
3
|
import { readCurrentProblem, setCurrentProblem } from '../runtime/workspace.js';
|
|
3
4
|
|
|
4
5
|
function parseListFilters(args) {
|
|
@@ -32,11 +33,42 @@ function parseListFilters(args) {
|
|
|
32
33
|
index += 1;
|
|
33
34
|
continue;
|
|
34
35
|
}
|
|
36
|
+
if (token === '--site-status') {
|
|
37
|
+
const siteStatus = args[index + 1];
|
|
38
|
+
if (!siteStatus) {
|
|
39
|
+
return { error: 'Missing site status after --site-status.' };
|
|
40
|
+
}
|
|
41
|
+
filters.siteStatus = siteStatus;
|
|
42
|
+
index += 1;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
35
45
|
return { error: `Unknown list option: ${token}` };
|
|
36
46
|
}
|
|
37
47
|
return { filters };
|
|
38
48
|
}
|
|
39
49
|
|
|
50
|
+
function parseArtifactArgs(args) {
|
|
51
|
+
const parsed = {
|
|
52
|
+
problemId: null,
|
|
53
|
+
asJson: false,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
57
|
+
const token = args[index];
|
|
58
|
+
if (token === '--json') {
|
|
59
|
+
parsed.asJson = true;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (!parsed.problemId) {
|
|
63
|
+
parsed.problemId = token;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
return { error: `Unknown artifact option: ${token}` };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return parsed;
|
|
70
|
+
}
|
|
71
|
+
|
|
40
72
|
function printProblemTable(rows, activeProblem) {
|
|
41
73
|
console.log('ID Site Repo Cluster Depth Active Title');
|
|
42
74
|
for (const row of rows) {
|
|
@@ -59,28 +91,64 @@ function printProblem(problem) {
|
|
|
59
91
|
console.log(`Repo status: ${problem.repoStatus}`);
|
|
60
92
|
console.log(`Cluster: ${problem.cluster}`);
|
|
61
93
|
console.log(`Harness depth: ${problem.harnessDepth}`);
|
|
94
|
+
console.log(`Prize: ${problem.prize ?? '(none)'}`);
|
|
62
95
|
console.log(`Formalization: ${problem.formalizationStatus}`);
|
|
96
|
+
console.log(`Upstream formalized: ${problem.upstreamFormalizedState ?? '(unknown)'}`);
|
|
97
|
+
console.log(`Upstream last update: ${problem.upstreamLastUpdate ?? '(unknown)'}`);
|
|
63
98
|
console.log(`Related: ${problem.relatedProblems.join(', ') || '(none)'}`);
|
|
64
99
|
console.log(`Tags: ${problem.familyTags.join(', ') || '(none)'}`);
|
|
65
100
|
console.log(`Statement: ${problem.shortStatement}`);
|
|
66
101
|
if (problem.researchState) {
|
|
67
102
|
console.log('Research state:');
|
|
68
|
-
console.log(` open problem: ${problem.researchState.
|
|
69
|
-
console.log(` active route: ${problem.researchState.
|
|
70
|
-
console.log(` route breakthrough: ${problem.researchState.
|
|
71
|
-
console.log(` problem solved: ${problem.researchState.
|
|
103
|
+
console.log(` open problem: ${problem.researchState.open_problem ? 'yes' : 'no'}`);
|
|
104
|
+
console.log(` active route: ${problem.researchState.active_route}`);
|
|
105
|
+
console.log(` route breakthrough: ${problem.researchState.route_breakthrough ? 'yes' : 'no'}`);
|
|
106
|
+
console.log(` problem solved: ${problem.researchState.problem_solved ? 'yes' : 'no'}`);
|
|
107
|
+
}
|
|
108
|
+
if (problem.upstream) {
|
|
109
|
+
console.log('Upstream provenance:');
|
|
110
|
+
console.log(` repo: ${problem.upstream.repo}`);
|
|
111
|
+
console.log(` data file: ${problem.upstream.data_file}`);
|
|
112
|
+
console.log(` number: ${problem.upstream.number}`);
|
|
72
113
|
}
|
|
73
114
|
}
|
|
74
115
|
|
|
116
|
+
function printArtifactInventory(problem, inventory, asJson) {
|
|
117
|
+
if (asJson) {
|
|
118
|
+
console.log(JSON.stringify(inventory, null, 2));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log(`${problem.displayName} canonical artifacts`);
|
|
123
|
+
console.log(`Problem directory: ${inventory.problemDir}`);
|
|
124
|
+
console.log(`Source: ${inventory.sourceUrl}`);
|
|
125
|
+
console.log('Canonical files:');
|
|
126
|
+
for (const artifact of inventory.canonicalArtifacts) {
|
|
127
|
+
console.log(`- ${artifact.label}: ${artifact.exists ? 'present' : 'missing'} (${artifact.path})`);
|
|
128
|
+
}
|
|
129
|
+
if (inventory.packContext) {
|
|
130
|
+
console.log(`- ${inventory.packContext.label}: ${inventory.packContext.exists ? 'present' : 'missing'} (${inventory.packContext.path})`);
|
|
131
|
+
}
|
|
132
|
+
if (inventory.upstreamSnapshot) {
|
|
133
|
+
console.log('Upstream snapshot:');
|
|
134
|
+
console.log(`- kind: ${inventory.upstreamSnapshot.kind}`);
|
|
135
|
+
console.log(`- manifest: ${inventory.upstreamSnapshot.manifestPath}`);
|
|
136
|
+
console.log(`- index: ${inventory.upstreamSnapshot.indexPath}`);
|
|
137
|
+
console.log(`- commit: ${inventory.upstreamSnapshot.upstreamCommit ?? '(unknown)'}`);
|
|
138
|
+
}
|
|
139
|
+
console.log(`Upstream record available: ${inventory.upstreamRecordIncluded ? 'yes' : 'no'}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
75
142
|
export function runProblemCommand(args) {
|
|
76
143
|
const [subcommand, value, ...rest] = args;
|
|
77
144
|
|
|
78
145
|
if (!subcommand || subcommand === 'help' || subcommand === '--help') {
|
|
79
146
|
console.log('Usage:');
|
|
80
|
-
console.log(' erdos problem list [--cluster <name>] [--repo-status <status>] [--harness-depth <depth>]');
|
|
147
|
+
console.log(' erdos problem list [--cluster <name>] [--repo-status <status>] [--harness-depth <depth>] [--site-status <status>]');
|
|
81
148
|
console.log(' erdos problem show <id>');
|
|
82
149
|
console.log(' erdos problem use <id>');
|
|
83
150
|
console.log(' erdos problem current');
|
|
151
|
+
console.log(' erdos problem artifacts [<id>] [--json]');
|
|
84
152
|
return 0;
|
|
85
153
|
}
|
|
86
154
|
|
|
@@ -139,6 +207,27 @@ export function runProblemCommand(args) {
|
|
|
139
207
|
return 0;
|
|
140
208
|
}
|
|
141
209
|
|
|
210
|
+
if (subcommand === 'artifacts') {
|
|
211
|
+
const parsed = parseArtifactArgs([value, ...rest].filter(Boolean));
|
|
212
|
+
if (parsed.error) {
|
|
213
|
+
console.error(parsed.error);
|
|
214
|
+
return 1;
|
|
215
|
+
}
|
|
216
|
+
const problemId = parsed.problemId ?? readCurrentProblem();
|
|
217
|
+
if (!problemId) {
|
|
218
|
+
console.error('Missing problem id and no active problem is selected.');
|
|
219
|
+
return 1;
|
|
220
|
+
}
|
|
221
|
+
const problem = getProblem(problemId);
|
|
222
|
+
if (!problem) {
|
|
223
|
+
console.error(`Unknown problem: ${problemId}`);
|
|
224
|
+
return 1;
|
|
225
|
+
}
|
|
226
|
+
const inventory = getProblemArtifactInventory(problem);
|
|
227
|
+
printArtifactInventory(problem, inventory, parsed.asJson);
|
|
228
|
+
return 0;
|
|
229
|
+
}
|
|
230
|
+
|
|
142
231
|
console.error(`Unknown problem subcommand: ${subcommand}`);
|
|
143
232
|
return 1;
|
|
144
233
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { getProblem } from '../atlas/catalog.js';
|
|
3
|
+
import { scaffoldProblem } from '../runtime/problem-artifacts.js';
|
|
4
|
+
import { getWorkspaceProblemScaffoldDir } from '../runtime/paths.js';
|
|
5
|
+
import { readCurrentProblem } from '../runtime/workspace.js';
|
|
6
|
+
|
|
7
|
+
export function parseScaffoldArgs(args) {
|
|
8
|
+
const [kind, value, ...rest] = args;
|
|
9
|
+
if (kind !== 'problem') {
|
|
10
|
+
return { error: 'Only `erdos scaffold problem <id>` is supported right now.' };
|
|
11
|
+
}
|
|
12
|
+
let destination = null;
|
|
13
|
+
for (let index = 0; index < rest.length; index += 1) {
|
|
14
|
+
const token = rest[index];
|
|
15
|
+
if (token === '--dest') {
|
|
16
|
+
destination = rest[index + 1];
|
|
17
|
+
if (!destination) {
|
|
18
|
+
return { error: 'Missing destination path after --dest.' };
|
|
19
|
+
}
|
|
20
|
+
index += 1;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
return { error: `Unknown scaffold option: ${token}` };
|
|
24
|
+
}
|
|
25
|
+
return { problemId: value ?? readCurrentProblem(), destination };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function runScaffoldCommand(args) {
|
|
29
|
+
if (args.length === 0 || args[0] === 'help' || args[0] === '--help') {
|
|
30
|
+
console.log('Usage:');
|
|
31
|
+
console.log(' erdos scaffold problem <id> [--dest <path>]');
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const parsed = parseScaffoldArgs(args);
|
|
36
|
+
if (parsed.error) {
|
|
37
|
+
console.error(parsed.error);
|
|
38
|
+
return 1;
|
|
39
|
+
}
|
|
40
|
+
if (!parsed.problemId) {
|
|
41
|
+
console.error('Missing problem id and no active problem is selected.');
|
|
42
|
+
return 1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const problem = getProblem(parsed.problemId);
|
|
46
|
+
if (!problem) {
|
|
47
|
+
console.error(`Unknown problem: ${parsed.problemId}`);
|
|
48
|
+
return 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const destination = parsed.destination
|
|
52
|
+
? path.resolve(parsed.destination)
|
|
53
|
+
: getWorkspaceProblemScaffoldDir(problem.problemId);
|
|
54
|
+
|
|
55
|
+
const result = scaffoldProblem(problem, destination);
|
|
56
|
+
console.log(`Scaffold created: ${result.destination}`);
|
|
57
|
+
console.log(`Artifacts copied: ${result.copiedArtifacts.length}`);
|
|
58
|
+
console.log(`Upstream record included: ${result.inventory.upstreamRecordIncluded ? 'yes' : 'no'}`);
|
|
59
|
+
return 0;
|
|
60
|
+
}
|