erdos-problems 0.1.6 → 0.1.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.
- package/README.md +21 -0
- package/docs/RESEARCH_LOOP.md +11 -0
- package/package.json +1 -1
- package/src/atlas/catalog.js +37 -29
- package/src/cli/index.js +4 -0
- package/src/commands/pull.js +41 -26
- package/src/commands/seed.js +264 -0
- package/src/commands/workspace.js +2 -0
- package/src/runtime/paths.js +8 -0
- package/src/runtime/workspace.js +4 -0
package/README.md
CHANGED
|
@@ -38,6 +38,14 @@ erdos sunflower status 857
|
|
|
38
38
|
erdos dossier show 857
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
For an unseeded problem, the one-step self-seeding flow is now:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
erdos seed problem 1 --include-site --cluster number-theory
|
|
45
|
+
erdos problem show 1
|
|
46
|
+
erdos workspace show
|
|
47
|
+
```
|
|
48
|
+
|
|
41
49
|
What `bootstrap` does:
|
|
42
50
|
- sets the active workspace problem
|
|
43
51
|
- scaffolds the canonical dossier files into `.erdos/scaffolds/<id>/`
|
|
@@ -45,6 +53,13 @@ What `bootstrap` does:
|
|
|
45
53
|
- copies pack-specific context and compute packets when the problem has them
|
|
46
54
|
- gives an agent a ready-to-read local artifact bundle immediately after install
|
|
47
55
|
|
|
56
|
+
What `seed` does:
|
|
57
|
+
- creates a pull bundle for any problem in the upstream snapshot
|
|
58
|
+
- promotes that bundle into `.erdos/seeded-problems/<id>/`
|
|
59
|
+
- auto-selects the problem in the workspace
|
|
60
|
+
- syncs the staged research loop state and checkpoint shelf
|
|
61
|
+
- makes the new dossier visible to the atlas commands immediately inside that workspace
|
|
62
|
+
|
|
48
63
|
## Pull lanes
|
|
49
64
|
|
|
50
65
|
For any problem number in the upstream snapshot, you can create a workspace bundle even if the problem is not yet seeded locally:
|
|
@@ -138,6 +153,7 @@ erdos upstream diff
|
|
|
138
153
|
erdos scaffold problem 857
|
|
139
154
|
erdos bootstrap problem 857
|
|
140
155
|
erdos bootstrap problem 857 --sync-upstream
|
|
156
|
+
erdos seed problem 1 --include-site --cluster number-theory
|
|
141
157
|
erdos pull problem 857
|
|
142
158
|
erdos pull artifacts 857
|
|
143
159
|
erdos pull literature 857
|
|
@@ -166,6 +182,7 @@ The CLI can surface these directly:
|
|
|
166
182
|
- `erdos problem artifacts <id> --json` emits machine-readable inventory
|
|
167
183
|
- `erdos scaffold problem <id>` copies the seeded dossier into the active workspace
|
|
168
184
|
- `erdos bootstrap problem <id>` selects the problem and creates the scaffold in one step
|
|
185
|
+
- `erdos seed problem <id>` self-seeds an unseeded problem into `.erdos/seeded-problems/` and syncs the loop
|
|
169
186
|
- `erdos pull problem <id>` creates a workspace bundle for any problem in the upstream snapshot
|
|
170
187
|
- `erdos maintainer seed problem <id>` promotes a pull bundle into a canonical local dossier
|
|
171
188
|
|
|
@@ -213,5 +230,9 @@ The public package uses the same status ladder we settled on in the lab:
|
|
|
213
230
|
- route breakthrough
|
|
214
231
|
- problem solved
|
|
215
232
|
|
|
233
|
+
That means a fresh install now supports two clean research starts:
|
|
234
|
+
- `erdos bootstrap problem <seeded-id>` for native packaged dossiers
|
|
235
|
+
- `erdos seed problem <unseeded-id>` for workspace-local self-seeding with the same loop
|
|
236
|
+
|
|
216
237
|
See also:
|
|
217
238
|
- `docs/RESEARCH_LOOP.md`
|
package/docs/RESEARCH_LOOP.md
CHANGED
|
@@ -36,6 +36,17 @@ erdos checkpoints sync
|
|
|
36
36
|
erdos workspace show
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
For problems that are not yet packaged as native dossiers, the loop can start with one-step self-seeding:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
erdos seed problem 1 --include-site --cluster number-theory
|
|
43
|
+
erdos preflight
|
|
44
|
+
erdos continuation use route
|
|
45
|
+
erdos checkpoints sync
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
That flow writes the local dossier into `.erdos/seeded-problems/<id>/`, makes it visible to the atlas inside the current workspace, and immediately syncs the same state/checkpoint machinery used by packaged dossiers.
|
|
49
|
+
|
|
39
50
|
## Status ladder
|
|
40
51
|
|
|
41
52
|
The public package uses the same ladder we converged on in the lab:
|
package/package.json
CHANGED
package/src/atlas/catalog.js
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { parse } from 'yaml';
|
|
4
|
-
import { getProblemDir, repoRoot } from '../runtime/paths.js';
|
|
4
|
+
import { getProblemDir, getWorkspaceRoot, getWorkspaceSeededProblemsDir, repoRoot } from '../runtime/paths.js';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
function readProblemRecord(problemId) {
|
|
9
|
-
const problemDir = getProblemDir(problemId);
|
|
6
|
+
function readProblemRecordFromDir(problemDir) {
|
|
10
7
|
const yamlPath = path.join(problemDir, 'problem.yaml');
|
|
11
8
|
const record = parse(fs.readFileSync(yamlPath, 'utf8'));
|
|
12
9
|
return { problemDir, record };
|
|
13
10
|
}
|
|
14
11
|
|
|
15
|
-
function toCatalogProblem(problemDir, record) {
|
|
12
|
+
function toCatalogProblem(problemDir, record, sourceKind) {
|
|
16
13
|
const statementRelative = record.statement?.normalized_md_path ?? 'STATEMENT.md';
|
|
17
14
|
const referencesRelative = record.references_path ?? 'REFERENCES.md';
|
|
18
15
|
const evidenceRelative = record.evidence_path ?? 'EVIDENCE.md';
|
|
@@ -47,47 +44,58 @@ function toCatalogProblem(problemDir, record) {
|
|
|
47
44
|
problemDir,
|
|
48
45
|
problemYamlPath: path.join(problemDir, 'problem.yaml'),
|
|
49
46
|
record,
|
|
47
|
+
sourceKind,
|
|
50
48
|
};
|
|
51
49
|
}
|
|
52
50
|
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
return
|
|
51
|
+
function listProblemDirectories(rootDir) {
|
|
52
|
+
if (!fs.existsSync(rootDir)) {
|
|
53
|
+
return [];
|
|
56
54
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
.readdirSync(problemsRoot, { withFileTypes: true })
|
|
55
|
+
return fs
|
|
56
|
+
.readdirSync(rootDir, { withFileTypes: true })
|
|
60
57
|
.filter((entry) => entry.isDirectory())
|
|
61
|
-
.map((entry) => entry.name)
|
|
62
|
-
|
|
58
|
+
.map((entry) => path.join(rootDir, entry.name));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function loadLocalProblems(workspaceRoot = getWorkspaceRoot()) {
|
|
62
|
+
const packageRoot = path.join(repoRoot, 'problems');
|
|
63
|
+
const workspaceRootDir = getWorkspaceSeededProblemsDir(workspaceRoot);
|
|
64
|
+
const merged = new Map();
|
|
65
|
+
|
|
66
|
+
for (const problemDir of listProblemDirectories(packageRoot)) {
|
|
67
|
+
const { record } = readProblemRecordFromDir(problemDir);
|
|
68
|
+
merged.set(String(record.problem_id), toCatalogProblem(problemDir, record, 'package'));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (const problemDir of listProblemDirectories(workspaceRootDir)) {
|
|
72
|
+
const { record } = readProblemRecordFromDir(problemDir);
|
|
73
|
+
merged.set(String(record.problem_id), toCatalogProblem(problemDir, record, 'workspace'));
|
|
74
|
+
}
|
|
63
75
|
|
|
64
|
-
|
|
65
|
-
const { problemDir, record } = readProblemRecord(problemId);
|
|
66
|
-
return toCatalogProblem(problemDir, record);
|
|
67
|
-
});
|
|
68
|
-
return cachedProblems;
|
|
76
|
+
return [...merged.values()].sort((left, right) => Number(left.problemId) - Number(right.problemId));
|
|
69
77
|
}
|
|
70
78
|
|
|
71
|
-
export function listProblems(filters = {}) {
|
|
79
|
+
export function listProblems(filters = {}, workspaceRoot = getWorkspaceRoot()) {
|
|
72
80
|
const cluster = filters.cluster ? String(filters.cluster).toLowerCase() : null;
|
|
73
81
|
const repoStatus = filters.repoStatus ? String(filters.repoStatus).toLowerCase() : null;
|
|
74
82
|
const harnessDepth = filters.harnessDepth ? String(filters.harnessDepth).toLowerCase() : null;
|
|
75
83
|
const siteStatus = filters.siteStatus ? String(filters.siteStatus).toLowerCase() : null;
|
|
76
84
|
|
|
77
|
-
return loadLocalProblems()
|
|
85
|
+
return loadLocalProblems(workspaceRoot)
|
|
78
86
|
.filter((entry) => (cluster ? entry.cluster === cluster : true))
|
|
79
87
|
.filter((entry) => (repoStatus ? entry.repoStatus === repoStatus : true))
|
|
80
88
|
.filter((entry) => (harnessDepth ? entry.harnessDepth === harnessDepth : true))
|
|
81
89
|
.filter((entry) => (siteStatus ? entry.siteStatus === siteStatus : true));
|
|
82
90
|
}
|
|
83
91
|
|
|
84
|
-
export function getProblem(problemId) {
|
|
85
|
-
return loadLocalProblems().find((entry) => entry.problemId === String(problemId));
|
|
92
|
+
export function getProblem(problemId, workspaceRoot = getWorkspaceRoot()) {
|
|
93
|
+
return loadLocalProblems(workspaceRoot).find((entry) => entry.problemId === String(problemId));
|
|
86
94
|
}
|
|
87
95
|
|
|
88
|
-
export function getCluster(clusterName) {
|
|
96
|
+
export function getCluster(clusterName, workspaceRoot = getWorkspaceRoot()) {
|
|
89
97
|
const name = String(clusterName).toLowerCase();
|
|
90
|
-
const problems = listProblems({ cluster: name });
|
|
98
|
+
const problems = listProblems({ cluster: name }, workspaceRoot);
|
|
91
99
|
if (problems.length === 0) {
|
|
92
100
|
return null;
|
|
93
101
|
}
|
|
@@ -99,11 +107,11 @@ export function getCluster(clusterName) {
|
|
|
99
107
|
};
|
|
100
108
|
}
|
|
101
109
|
|
|
102
|
-
export function listClusters() {
|
|
103
|
-
const names = [...new Set(loadLocalProblems().map((entry) => entry.cluster))].sort();
|
|
104
|
-
return names.map((name) => getCluster(name));
|
|
110
|
+
export function listClusters(workspaceRoot = getWorkspaceRoot()) {
|
|
111
|
+
const names = [...new Set(loadLocalProblems(workspaceRoot).map((entry) => entry.cluster))].sort();
|
|
112
|
+
return names.map((name) => getCluster(name, workspaceRoot));
|
|
105
113
|
}
|
|
106
114
|
|
|
107
115
|
export function clearCatalogCache() {
|
|
108
|
-
|
|
116
|
+
return null;
|
|
109
117
|
}
|
package/src/cli/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import { runPreflightCommand } from '../commands/preflight.js';
|
|
|
8
8
|
import { runProblemCommand } from '../commands/problem.js';
|
|
9
9
|
import { runPullCommand } from '../commands/pull.js';
|
|
10
10
|
import { runScaffoldCommand } from '../commands/scaffold.js';
|
|
11
|
+
import { runSeedCommand } from '../commands/seed.js';
|
|
11
12
|
import { runStateCommand } from '../commands/state.js';
|
|
12
13
|
import { runSunflowerCommand } from '../commands/sunflower.js';
|
|
13
14
|
import { runUpstreamCommand } from '../commands/upstream.js';
|
|
@@ -38,6 +39,7 @@ function printUsage() {
|
|
|
38
39
|
console.log(' erdos upstream diff [--write-package-report]');
|
|
39
40
|
console.log(' erdos scaffold problem <id> [--dest <path>]');
|
|
40
41
|
console.log(' erdos bootstrap problem <id> [--dest <path>] [--sync-upstream]');
|
|
42
|
+
console.log(' erdos seed problem <id> [--include-site] [--refresh-upstream] [--cluster <name>] [--repo-status <status>] [--harness-depth <depth>] [--title <title>] [--family-tag <tag>] [--related <id>] [--formalization-status <status>] [--active-route <route>] [--route-breakthrough] [--problem-solved] [--dest-root <path>] [--no-activate] [--no-loop-sync] [--force] [--json]');
|
|
41
43
|
console.log(' erdos pull problem <id> [--dest <path>] [--include-site] [--refresh-upstream]');
|
|
42
44
|
console.log(' erdos pull artifacts <id> [--dest <path>] [--refresh-upstream]');
|
|
43
45
|
console.log(' erdos pull literature <id> [--dest <path>] [--include-site] [--refresh-upstream]');
|
|
@@ -75,6 +77,8 @@ if (!command || command === 'help' || command === '--help') {
|
|
|
75
77
|
exitCode = runScaffoldCommand(rest);
|
|
76
78
|
} else if (command === 'bootstrap') {
|
|
77
79
|
exitCode = await runBootstrapCommand(rest);
|
|
80
|
+
} else if (command === 'seed') {
|
|
81
|
+
exitCode = await runSeedCommand(rest);
|
|
78
82
|
} else if (command === 'pull') {
|
|
79
83
|
exitCode = await runPullCommand(rest);
|
|
80
84
|
} else if (command === 'maintainer') {
|
package/src/commands/pull.js
CHANGED
|
@@ -257,22 +257,29 @@ function writeRootProblemBundle(rootDir, problemId, localProblem, upstreamRecord
|
|
|
257
257
|
return problemRecord;
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
-
export async function runPullCommand(args) {
|
|
260
|
+
export async function runPullCommand(args, options = {}) {
|
|
261
|
+
const silent = options.silent === true;
|
|
261
262
|
if (args.length === 0 || args[0] === 'help' || args[0] === '--help') {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
263
|
+
if (!silent) {
|
|
264
|
+
console.log('Usage:');
|
|
265
|
+
console.log(' erdos pull problem <id> [--dest <path>] [--include-site] [--refresh-upstream]');
|
|
266
|
+
console.log(' erdos pull artifacts <id> [--dest <path>] [--refresh-upstream]');
|
|
267
|
+
console.log(' erdos pull literature <id> [--dest <path>] [--include-site] [--refresh-upstream]');
|
|
268
|
+
}
|
|
266
269
|
return 0;
|
|
267
270
|
}
|
|
268
271
|
|
|
269
272
|
const parsed = parsePullArgs(args);
|
|
270
273
|
if (parsed.error) {
|
|
271
|
-
|
|
274
|
+
if (!silent) {
|
|
275
|
+
console.error(parsed.error);
|
|
276
|
+
}
|
|
272
277
|
return 1;
|
|
273
278
|
}
|
|
274
279
|
if (!parsed.problemId) {
|
|
275
|
-
|
|
280
|
+
if (!silent) {
|
|
281
|
+
console.error('Missing problem id.');
|
|
282
|
+
}
|
|
276
283
|
return 1;
|
|
277
284
|
}
|
|
278
285
|
|
|
@@ -285,7 +292,9 @@ export async function runPullCommand(args) {
|
|
|
285
292
|
const upstreamRecord = snapshot?.index?.by_number?.[String(parsed.problemId)] ?? null;
|
|
286
293
|
|
|
287
294
|
if (!localProblem && !upstreamRecord) {
|
|
288
|
-
|
|
295
|
+
if (!silent) {
|
|
296
|
+
console.error(`Problem ${parsed.problemId} is not present in the local dossier set or upstream snapshot.`);
|
|
297
|
+
}
|
|
289
298
|
return 1;
|
|
290
299
|
}
|
|
291
300
|
|
|
@@ -294,10 +303,12 @@ export async function runPullCommand(args) {
|
|
|
294
303
|
? path.resolve(parsed.destination)
|
|
295
304
|
: getWorkspaceProblemArtifactDir(parsed.problemId);
|
|
296
305
|
const result = writeArtifactsLane(String(parsed.problemId), destination, localProblem, upstreamRecord, snapshot);
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
306
|
+
if (!silent) {
|
|
307
|
+
console.log(`Artifact bundle created: ${destination}`);
|
|
308
|
+
console.log(`Local canonical dossier included: ${localProblem ? 'yes' : 'no'}`);
|
|
309
|
+
console.log(`Upstream record included: ${upstreamRecord ? 'yes' : 'no'}`);
|
|
310
|
+
console.log(`Artifacts copied: ${result.copiedArtifacts?.length ?? result.artifactsCopied ?? 0}`);
|
|
311
|
+
}
|
|
301
312
|
return 0;
|
|
302
313
|
}
|
|
303
314
|
|
|
@@ -306,12 +317,14 @@ export async function runPullCommand(args) {
|
|
|
306
317
|
? path.resolve(parsed.destination)
|
|
307
318
|
: getWorkspaceProblemLiteratureDir(parsed.problemId);
|
|
308
319
|
const result = await writeLiteratureLane(String(parsed.problemId), destination, localProblem, upstreamRecord, parsed.includeSite);
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
320
|
+
if (!silent) {
|
|
321
|
+
console.log(`Literature bundle created: ${destination}`);
|
|
322
|
+
console.log(`Local dossier context included: ${localProblem ? 'yes' : 'no'}`);
|
|
323
|
+
console.log(`Upstream record included: ${upstreamRecord ? 'yes' : 'no'}`);
|
|
324
|
+
console.log(`Live site snapshot included: ${result.siteStatus.included ? 'yes' : 'no'}`);
|
|
325
|
+
if (result.siteStatus.error) {
|
|
326
|
+
console.log(`Live site snapshot note: ${result.siteStatus.error}`);
|
|
327
|
+
}
|
|
315
328
|
}
|
|
316
329
|
return 0;
|
|
317
330
|
}
|
|
@@ -341,14 +354,16 @@ export async function runPullCommand(args) {
|
|
|
341
354
|
siteSnapshotError: literatureResult.siteStatus.error,
|
|
342
355
|
});
|
|
343
356
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
357
|
+
if (!silent) {
|
|
358
|
+
console.log(`Pull bundle created: ${rootDestination}`);
|
|
359
|
+
console.log(`Artifact lane: ${artifactDestination}`);
|
|
360
|
+
console.log(`Literature lane: ${literatureDestination}`);
|
|
361
|
+
console.log(`Local canonical dossier included: ${localProblem ? 'yes' : 'no'}`);
|
|
362
|
+
console.log(`Upstream record included: ${upstreamRecord ? 'yes' : 'no'}`);
|
|
363
|
+
console.log(`Live site snapshot included: ${literatureResult.siteStatus.included ? 'yes' : 'no'}`);
|
|
364
|
+
if (literatureResult.siteStatus.error) {
|
|
365
|
+
console.log(`Live site snapshot note: ${literatureResult.siteStatus.error}`);
|
|
366
|
+
}
|
|
352
367
|
}
|
|
353
368
|
return 0;
|
|
354
369
|
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { getProblem } from '../atlas/catalog.js';
|
|
3
|
+
import { syncCheckpoints } from '../runtime/checkpoints.js';
|
|
4
|
+
import { seedProblemFromPullBundle } from '../runtime/maintainer-seed.js';
|
|
5
|
+
import { getWorkspaceProblemPullDir, getWorkspaceRoot, getWorkspaceSeededProblemsDir } from '../runtime/paths.js';
|
|
6
|
+
import { syncState } from '../runtime/state.js';
|
|
7
|
+
import { readCurrentProblem, setCurrentProblem } from '../runtime/workspace.js';
|
|
8
|
+
import { runPullCommand } from './pull.js';
|
|
9
|
+
|
|
10
|
+
function parseSeedArgs(args) {
|
|
11
|
+
const [kind, value, ...rest] = args;
|
|
12
|
+
if (kind !== 'problem') {
|
|
13
|
+
return { error: 'Only `erdos seed problem <id>` is supported right now.' };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const parsed = {
|
|
17
|
+
problemId: value,
|
|
18
|
+
includeSite: false,
|
|
19
|
+
refreshUpstream: false,
|
|
20
|
+
cluster: null,
|
|
21
|
+
repoStatus: 'local_seeded',
|
|
22
|
+
harnessDepth: 'dossier',
|
|
23
|
+
title: null,
|
|
24
|
+
familyTags: [],
|
|
25
|
+
relatedProblems: [],
|
|
26
|
+
formalizationStatus: 'planned',
|
|
27
|
+
activeRoute: null,
|
|
28
|
+
routeBreakthrough: false,
|
|
29
|
+
problemSolved: false,
|
|
30
|
+
destRoot: null,
|
|
31
|
+
noActivate: false,
|
|
32
|
+
noLoopSync: false,
|
|
33
|
+
force: false,
|
|
34
|
+
asJson: false,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
for (let index = 0; index < rest.length; index += 1) {
|
|
38
|
+
const token = rest[index];
|
|
39
|
+
if (token === '--include-site') {
|
|
40
|
+
parsed.includeSite = true;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (token === '--refresh-upstream') {
|
|
44
|
+
parsed.refreshUpstream = true;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (token === '--cluster') {
|
|
48
|
+
parsed.cluster = rest[index + 1];
|
|
49
|
+
if (!parsed.cluster) {
|
|
50
|
+
return { error: 'Missing cluster value after --cluster.' };
|
|
51
|
+
}
|
|
52
|
+
index += 1;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (token === '--repo-status') {
|
|
56
|
+
parsed.repoStatus = rest[index + 1];
|
|
57
|
+
if (!parsed.repoStatus) {
|
|
58
|
+
return { error: 'Missing repo status after --repo-status.' };
|
|
59
|
+
}
|
|
60
|
+
index += 1;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (token === '--harness-depth') {
|
|
64
|
+
parsed.harnessDepth = rest[index + 1];
|
|
65
|
+
if (!parsed.harnessDepth) {
|
|
66
|
+
return { error: 'Missing harness depth after --harness-depth.' };
|
|
67
|
+
}
|
|
68
|
+
index += 1;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (token === '--title') {
|
|
72
|
+
parsed.title = rest[index + 1];
|
|
73
|
+
if (!parsed.title) {
|
|
74
|
+
return { error: 'Missing title after --title.' };
|
|
75
|
+
}
|
|
76
|
+
index += 1;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (token === '--family-tag') {
|
|
80
|
+
const tag = rest[index + 1];
|
|
81
|
+
if (!tag) {
|
|
82
|
+
return { error: 'Missing tag after --family-tag.' };
|
|
83
|
+
}
|
|
84
|
+
parsed.familyTags.push(tag);
|
|
85
|
+
index += 1;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (token === '--related') {
|
|
89
|
+
const related = rest[index + 1];
|
|
90
|
+
if (!related) {
|
|
91
|
+
return { error: 'Missing problem id after --related.' };
|
|
92
|
+
}
|
|
93
|
+
parsed.relatedProblems.push(related);
|
|
94
|
+
index += 1;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (token === '--formalization-status') {
|
|
98
|
+
parsed.formalizationStatus = rest[index + 1];
|
|
99
|
+
if (!parsed.formalizationStatus) {
|
|
100
|
+
return { error: 'Missing value after --formalization-status.' };
|
|
101
|
+
}
|
|
102
|
+
index += 1;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (token === '--active-route') {
|
|
106
|
+
parsed.activeRoute = rest[index + 1];
|
|
107
|
+
if (!parsed.activeRoute) {
|
|
108
|
+
return { error: 'Missing value after --active-route.' };
|
|
109
|
+
}
|
|
110
|
+
index += 1;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (token === '--route-breakthrough') {
|
|
114
|
+
parsed.routeBreakthrough = true;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (token === '--problem-solved') {
|
|
118
|
+
parsed.problemSolved = true;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (token === '--dest-root') {
|
|
122
|
+
parsed.destRoot = rest[index + 1];
|
|
123
|
+
if (!parsed.destRoot) {
|
|
124
|
+
return { error: 'Missing path after --dest-root.' };
|
|
125
|
+
}
|
|
126
|
+
index += 1;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (token === '--no-activate') {
|
|
130
|
+
parsed.noActivate = true;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (token === '--no-loop-sync') {
|
|
134
|
+
parsed.noLoopSync = true;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (token === '--force') {
|
|
138
|
+
parsed.force = true;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (token === '--json') {
|
|
142
|
+
parsed.asJson = true;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
return { error: `Unknown seed option: ${token}` };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return parsed;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export async function runSeedCommand(args) {
|
|
152
|
+
if (args.length === 0 || args[0] === 'help' || args[0] === '--help') {
|
|
153
|
+
console.log('Usage:');
|
|
154
|
+
console.log(' erdos seed problem <id> [--include-site] [--refresh-upstream] [--cluster <name>] [--repo-status <status>] [--harness-depth <depth>] [--title <title>] [--family-tag <tag>] [--related <id>] [--formalization-status <status>] [--active-route <route>] [--route-breakthrough] [--problem-solved] [--dest-root <path>] [--no-activate] [--no-loop-sync] [--force] [--json]');
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const parsed = parseSeedArgs(args);
|
|
159
|
+
if (parsed.error) {
|
|
160
|
+
console.error(parsed.error);
|
|
161
|
+
return 1;
|
|
162
|
+
}
|
|
163
|
+
if (!parsed.problemId) {
|
|
164
|
+
console.error('Missing problem id.');
|
|
165
|
+
return 1;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const workspaceRoot = getWorkspaceRoot();
|
|
169
|
+
const pullDir = getWorkspaceProblemPullDir(parsed.problemId, workspaceRoot);
|
|
170
|
+
const defaultSeedRoot = getWorkspaceSeededProblemsDir(workspaceRoot);
|
|
171
|
+
const destinationRoot = parsed.destRoot
|
|
172
|
+
? path.resolve(parsed.destRoot)
|
|
173
|
+
: defaultSeedRoot;
|
|
174
|
+
const seedsIntoWorkspaceOverlay = destinationRoot === defaultSeedRoot;
|
|
175
|
+
|
|
176
|
+
const pullArgs = ['problem', String(parsed.problemId), '--dest', pullDir];
|
|
177
|
+
if (parsed.includeSite) {
|
|
178
|
+
pullArgs.push('--include-site');
|
|
179
|
+
}
|
|
180
|
+
if (parsed.refreshUpstream) {
|
|
181
|
+
pullArgs.push('--refresh-upstream');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const pullExit = await runPullCommand(pullArgs, { silent: parsed.asJson });
|
|
185
|
+
if (pullExit !== 0) {
|
|
186
|
+
return pullExit;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const packageProblem = getProblem(parsed.problemId, workspaceRoot);
|
|
190
|
+
const result = seedProblemFromPullBundle(parsed.problemId, {
|
|
191
|
+
fromPullDir: pullDir,
|
|
192
|
+
destRoot: destinationRoot,
|
|
193
|
+
cluster: parsed.cluster ?? packageProblem?.cluster ?? 'uncategorized',
|
|
194
|
+
repoStatus: parsed.repoStatus,
|
|
195
|
+
harnessDepth: parsed.harnessDepth,
|
|
196
|
+
title: parsed.title,
|
|
197
|
+
familyTags: parsed.familyTags,
|
|
198
|
+
relatedProblems: parsed.relatedProblems,
|
|
199
|
+
formalizationStatus: parsed.formalizationStatus,
|
|
200
|
+
activeRoute: parsed.activeRoute ?? (parsed.problemSolved ? null : 'seed_route_pending'),
|
|
201
|
+
routeBreakthrough: parsed.routeBreakthrough,
|
|
202
|
+
problemSolved: parsed.problemSolved,
|
|
203
|
+
force: parsed.force,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const activated = !parsed.noActivate && seedsIntoWorkspaceOverlay;
|
|
207
|
+
const loopSynced = !parsed.noLoopSync && activated;
|
|
208
|
+
|
|
209
|
+
let state = null;
|
|
210
|
+
let checkpoints = null;
|
|
211
|
+
if (activated) {
|
|
212
|
+
setCurrentProblem(parsed.problemId, workspaceRoot);
|
|
213
|
+
}
|
|
214
|
+
if (loopSynced) {
|
|
215
|
+
state = syncState(workspaceRoot);
|
|
216
|
+
checkpoints = syncCheckpoints(workspaceRoot);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const payload = {
|
|
220
|
+
problemId: String(parsed.problemId),
|
|
221
|
+
pullDir,
|
|
222
|
+
destinationDir: result.destinationDir,
|
|
223
|
+
cluster: result.record.cluster,
|
|
224
|
+
harnessDepth: result.record.harness.depth,
|
|
225
|
+
title: result.record.title,
|
|
226
|
+
activated,
|
|
227
|
+
loopSynced,
|
|
228
|
+
activeProblem: activated ? readCurrentProblem(workspaceRoot) : null,
|
|
229
|
+
activeRoute: state?.activeRoute ?? null,
|
|
230
|
+
nextHonestMove: state?.nextHonestMove ?? null,
|
|
231
|
+
checkpointShelf: checkpoints?.indexPath ?? null,
|
|
232
|
+
usedUpstreamRecord: result.usedUpstreamRecord,
|
|
233
|
+
usedSiteSnapshot: result.usedSiteSnapshot,
|
|
234
|
+
workspaceOverlayVisible: seedsIntoWorkspaceOverlay,
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
if (parsed.asJson) {
|
|
238
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
239
|
+
return 0;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
console.log(`Seeded local dossier for problem ${parsed.problemId}`);
|
|
243
|
+
console.log(`Pull bundle: ${pullDir}`);
|
|
244
|
+
console.log(`Destination: ${result.destinationDir}`);
|
|
245
|
+
console.log(`Title: ${result.record.title}`);
|
|
246
|
+
console.log(`Cluster: ${result.record.cluster}`);
|
|
247
|
+
console.log(`Harness depth: ${result.record.harness.depth}`);
|
|
248
|
+
console.log(`Upstream record used: ${result.usedUpstreamRecord ? 'yes' : 'no'}`);
|
|
249
|
+
console.log(`Site snapshot used: ${result.usedSiteSnapshot ? 'yes' : 'no'}`);
|
|
250
|
+
console.log(`Workspace overlay visible: ${seedsIntoWorkspaceOverlay ? 'yes' : 'no'}`);
|
|
251
|
+
console.log(`Activated: ${activated ? 'yes' : 'no'}`);
|
|
252
|
+
console.log(`Loop synced: ${loopSynced ? 'yes' : 'no'}`);
|
|
253
|
+
if (!seedsIntoWorkspaceOverlay && (!parsed.noActivate || !parsed.noLoopSync)) {
|
|
254
|
+
console.log('Note: activation and loop sync were skipped because --dest-root points outside .erdos/seeded-problems.');
|
|
255
|
+
}
|
|
256
|
+
if (state) {
|
|
257
|
+
console.log(`Active route: ${state.activeRoute ?? '(none)'}`);
|
|
258
|
+
console.log(`Next honest move: ${state.nextHonestMove}`);
|
|
259
|
+
}
|
|
260
|
+
if (checkpoints) {
|
|
261
|
+
console.log(`Checkpoint shelf: ${checkpoints.indexPath}`);
|
|
262
|
+
}
|
|
263
|
+
return 0;
|
|
264
|
+
}
|
|
@@ -29,10 +29,12 @@ export function runWorkspaceCommand(args) {
|
|
|
29
29
|
console.log(`Question ledger: ${summary.questionLedgerPath}`);
|
|
30
30
|
console.log(`Checkpoint shelf: ${summary.checkpointIndexPath}`);
|
|
31
31
|
console.log(`Workspace upstream dir: ${summary.upstreamDir}`);
|
|
32
|
+
console.log(`Workspace seeded-problems dir: ${summary.seededProblemsDir}`);
|
|
32
33
|
console.log(`Workspace scaffold dir: ${summary.scaffoldDir}`);
|
|
33
34
|
console.log(`Workspace pull dir: ${summary.pullDir}`);
|
|
34
35
|
console.log(`Workspace artifact dir: ${summary.artifactDir}`);
|
|
35
36
|
console.log(`Workspace literature dir: ${summary.literatureDir}`);
|
|
37
|
+
console.log(`Active seeded dossier dir: ${summary.seededProblemDir}`);
|
|
36
38
|
console.log(`Preferred agent: ${config.preferredAgent}`);
|
|
37
39
|
console.log(`Continuation mode: ${summary.continuationMode ?? config.continuation}`);
|
|
38
40
|
console.log(`Active route: ${summary.activeRoute ?? '(none)'}`);
|
package/src/runtime/paths.js
CHANGED
|
@@ -92,6 +92,14 @@ export function getWorkspaceProblemLiteratureDir(problemId, workspaceRoot = getW
|
|
|
92
92
|
return path.join(getWorkspaceProblemPullDir(problemId, workspaceRoot), 'literature');
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
export function getWorkspaceSeededProblemsDir(workspaceRoot = getWorkspaceRoot()) {
|
|
96
|
+
return path.join(getWorkspaceDir(workspaceRoot), 'seeded-problems');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function getWorkspaceSeededProblemDir(problemId, workspaceRoot = getWorkspaceRoot()) {
|
|
100
|
+
return path.join(getWorkspaceSeededProblemsDir(workspaceRoot), String(problemId));
|
|
101
|
+
}
|
|
102
|
+
|
|
95
103
|
export function getWorkspaceCheckpointsDir(workspaceRoot = getWorkspaceRoot()) {
|
|
96
104
|
return path.join(getWorkspaceDir(workspaceRoot), 'checkpoints');
|
|
97
105
|
}
|
package/src/runtime/workspace.js
CHANGED
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
getWorkspaceProblemScaffoldDir,
|
|
11
11
|
getWorkspaceQuestionLedgerPath,
|
|
12
12
|
getWorkspaceRoot,
|
|
13
|
+
getWorkspaceSeededProblemDir,
|
|
14
|
+
getWorkspaceSeededProblemsDir,
|
|
13
15
|
getWorkspaceStateMarkdownPath,
|
|
14
16
|
getWorkspaceStatePath,
|
|
15
17
|
getWorkspaceUpstreamDir,
|
|
@@ -77,10 +79,12 @@ export function getWorkspaceSummary(workspaceRoot = getWorkspaceRoot()) {
|
|
|
77
79
|
questionLedgerPath: getWorkspaceQuestionLedgerPath(workspaceRoot),
|
|
78
80
|
checkpointIndexPath: getWorkspaceCheckpointIndexPath(workspaceRoot),
|
|
79
81
|
upstreamDir: getWorkspaceUpstreamDir(workspaceRoot),
|
|
82
|
+
seededProblemsDir: getWorkspaceSeededProblemsDir(workspaceRoot),
|
|
80
83
|
scaffoldDir: activeProblem ? getWorkspaceProblemScaffoldDir(activeProblem, workspaceRoot) : getWorkspaceProblemScaffoldDir('<problem-id>', workspaceRoot),
|
|
81
84
|
pullDir: activeProblem ? getWorkspaceProblemPullDir(activeProblem, workspaceRoot) : getWorkspaceProblemPullDir('<problem-id>', workspaceRoot),
|
|
82
85
|
artifactDir: activeProblem ? getWorkspaceProblemArtifactDir(activeProblem, workspaceRoot) : getWorkspaceProblemArtifactDir('<problem-id>', workspaceRoot),
|
|
83
86
|
literatureDir: activeProblem ? getWorkspaceProblemLiteratureDir(activeProblem, workspaceRoot) : getWorkspaceProblemLiteratureDir('<problem-id>', workspaceRoot),
|
|
87
|
+
seededProblemDir: activeProblem ? getWorkspaceSeededProblemDir(activeProblem, workspaceRoot) : getWorkspaceSeededProblemDir('<problem-id>', workspaceRoot),
|
|
84
88
|
updatedAt: state?.updatedAt ?? null,
|
|
85
89
|
continuationMode: state?.continuation?.mode ?? null,
|
|
86
90
|
activeRoute: state?.activeRoute ?? null,
|