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 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`
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "erdos-problems",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "CLI atlas and staged research harness for Paul Erdos problems.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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
- let cachedProblems = null;
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
- export function loadLocalProblems() {
54
- if (cachedProblems) {
55
- return cachedProblems;
51
+ function listProblemDirectories(rootDir) {
52
+ if (!fs.existsSync(rootDir)) {
53
+ return [];
56
54
  }
57
- const problemsRoot = path.join(repoRoot, 'problems');
58
- const directories = fs
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
- .sort((a, b) => Number(a) - Number(b));
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
- cachedProblems = directories.map((problemId) => {
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
- cachedProblems = null;
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') {
@@ -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
- console.log('Usage:');
263
- console.log(' erdos pull problem <id> [--dest <path>] [--include-site] [--refresh-upstream]');
264
- console.log(' erdos pull artifacts <id> [--dest <path>] [--refresh-upstream]');
265
- console.log(' erdos pull literature <id> [--dest <path>] [--include-site] [--refresh-upstream]');
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
- console.error(parsed.error);
274
+ if (!silent) {
275
+ console.error(parsed.error);
276
+ }
272
277
  return 1;
273
278
  }
274
279
  if (!parsed.problemId) {
275
- console.error('Missing problem id.');
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
- console.error(`Problem ${parsed.problemId} is not present in the local dossier set or upstream snapshot.`);
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
- console.log(`Artifact bundle created: ${destination}`);
298
- console.log(`Local canonical dossier included: ${localProblem ? 'yes' : 'no'}`);
299
- console.log(`Upstream record included: ${upstreamRecord ? 'yes' : 'no'}`);
300
- console.log(`Artifacts copied: ${result.copiedArtifacts?.length ?? result.artifactsCopied ?? 0}`);
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
- console.log(`Literature bundle created: ${destination}`);
310
- console.log(`Local dossier context included: ${localProblem ? 'yes' : 'no'}`);
311
- console.log(`Upstream record included: ${upstreamRecord ? 'yes' : 'no'}`);
312
- console.log(`Live site snapshot included: ${result.siteStatus.included ? 'yes' : 'no'}`);
313
- if (result.siteStatus.error) {
314
- console.log(`Live site snapshot note: ${result.siteStatus.error}`);
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
- console.log(`Pull bundle created: ${rootDestination}`);
345
- console.log(`Artifact lane: ${artifactDestination}`);
346
- console.log(`Literature lane: ${literatureDestination}`);
347
- console.log(`Local canonical dossier included: ${localProblem ? 'yes' : 'no'}`);
348
- console.log(`Upstream record included: ${upstreamRecord ? 'yes' : 'no'}`);
349
- console.log(`Live site snapshot included: ${literatureResult.siteStatus.included ? 'yes' : 'no'}`);
350
- if (literatureResult.siteStatus.error) {
351
- console.log(`Live site snapshot note: ${literatureResult.siteStatus.error}`);
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)'}`);
@@ -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
  }
@@ -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,