erdos-problems 0.1.13 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +117 -4
  2. package/docs/RESEARCH_LOOP.md +21 -2
  3. package/package.json +1 -1
  4. package/packs/number-theory/README.md +17 -0
  5. package/packs/number-theory/problems/1/CHECKPOINT_TEMPLATE.md +7 -0
  6. package/packs/number-theory/problems/1/CONTEXT.md +8 -0
  7. package/packs/number-theory/problems/1/FRONTIER_NOTE.md +8 -0
  8. package/packs/number-theory/problems/1/OPS_DETAILS.yaml +25 -0
  9. package/packs/number-theory/problems/1/REPORT_TEMPLATE.md +7 -0
  10. package/packs/number-theory/problems/1/ROUTE_HISTORY.md +5 -0
  11. package/packs/number-theory/problems/1/ROUTE_PACKET.yaml +13 -0
  12. package/packs/number-theory/problems/1/context.yaml +25 -0
  13. package/packs/number-theory/problems/2/CHECKPOINT_TEMPLATE.md +7 -0
  14. package/packs/number-theory/problems/2/CONTEXT.md +8 -0
  15. package/packs/number-theory/problems/2/FRONTIER_NOTE.md +8 -0
  16. package/packs/number-theory/problems/2/OPS_DETAILS.yaml +25 -0
  17. package/packs/number-theory/problems/2/REPORT_TEMPLATE.md +7 -0
  18. package/packs/number-theory/problems/2/ROUTE_HISTORY.md +5 -0
  19. package/packs/number-theory/problems/2/ROUTE_PACKET.yaml +13 -0
  20. package/packs/number-theory/problems/2/context.yaml +25 -0
  21. package/packs/sunflower/README.md +17 -4
  22. package/packs/sunflower/problems/20/CHECKPOINT_TEMPLATE.md +29 -0
  23. package/packs/sunflower/problems/20/FRONTIER_NOTE.md +13 -0
  24. package/packs/sunflower/problems/20/OPS_DETAILS.yaml +44 -0
  25. package/packs/sunflower/problems/20/REPORT_TEMPLATE.md +23 -0
  26. package/packs/sunflower/problems/20/ROUTE_HISTORY.md +18 -0
  27. package/packs/sunflower/problems/536/CHECKPOINT_TEMPLATE.md +7 -0
  28. package/packs/sunflower/problems/536/FRONTIER_NOTE.md +8 -0
  29. package/packs/sunflower/problems/536/OPS_DETAILS.yaml +39 -0
  30. package/packs/sunflower/problems/536/REPORT_TEMPLATE.md +7 -0
  31. package/packs/sunflower/problems/536/ROUTE_HISTORY.md +5 -0
  32. package/packs/sunflower/problems/856/CHECKPOINT_TEMPLATE.md +7 -0
  33. package/packs/sunflower/problems/856/FRONTIER_NOTE.md +8 -0
  34. package/packs/sunflower/problems/856/OPS_DETAILS.yaml +39 -0
  35. package/packs/sunflower/problems/856/REPORT_TEMPLATE.md +7 -0
  36. package/packs/sunflower/problems/856/ROUTE_HISTORY.md +5 -0
  37. package/packs/sunflower/problems/857/CHECKPOINT_TEMPLATE.md +32 -0
  38. package/packs/sunflower/problems/857/FRONTIER_NOTE.md +18 -0
  39. package/packs/sunflower/problems/857/OPS_DETAILS.yaml +65 -0
  40. package/packs/sunflower/problems/857/REPORT_TEMPLATE.md +26 -0
  41. package/packs/sunflower/problems/857/ROUTE_HISTORY.md +25 -0
  42. package/src/cli/index.js +22 -3
  43. package/src/commands/archive.js +46 -0
  44. package/src/commands/cluster.js +4 -0
  45. package/src/commands/maintainer.js +20 -2
  46. package/src/commands/number-theory.js +199 -0
  47. package/src/commands/problem.js +3 -0
  48. package/src/commands/pull.js +180 -5
  49. package/src/commands/sunflower.js +290 -12
  50. package/src/commands/upstream.js +129 -0
  51. package/src/commands/workspace.js +20 -0
  52. package/src/runtime/archive.js +87 -0
  53. package/src/runtime/checkpoints.js +27 -0
  54. package/src/runtime/maintainer-seed.js +70 -0
  55. package/src/runtime/number-theory.js +169 -0
  56. package/src/runtime/paths.js +16 -0
  57. package/src/runtime/state.js +63 -3
  58. package/src/runtime/sunflower.js +329 -2
  59. package/src/runtime/workspace.js +4 -0
  60. package/src/upstream/literature.js +83 -0
@@ -0,0 +1,199 @@
1
+ import { getProblem } from '../atlas/catalog.js';
2
+ import { buildNumberTheoryStatusSnapshot } from '../runtime/number-theory.js';
3
+ import { readCurrentProblem } from '../runtime/workspace.js';
4
+
5
+ function resolveNumberTheoryProblem(problemId) {
6
+ const resolvedId = problemId ?? readCurrentProblem();
7
+ if (!resolvedId) {
8
+ return { error: 'Missing problem id and no active problem is selected.' };
9
+ }
10
+
11
+ const problem = getProblem(resolvedId);
12
+ if (!problem) {
13
+ return { error: `Unknown problem: ${resolvedId}` };
14
+ }
15
+
16
+ if (problem.cluster !== 'number-theory') {
17
+ return { error: `Problem ${resolvedId} is not in the number-theory pack.` };
18
+ }
19
+
20
+ return { problem };
21
+ }
22
+
23
+ function parseArgs(args) {
24
+ const parsed = {
25
+ problemId: null,
26
+ asJson: false,
27
+ };
28
+
29
+ for (const token of args) {
30
+ if (token === '--json') {
31
+ parsed.asJson = true;
32
+ continue;
33
+ }
34
+ if (!parsed.problemId) {
35
+ parsed.problemId = token;
36
+ continue;
37
+ }
38
+ return { error: `Unknown number-theory option: ${token}` };
39
+ }
40
+
41
+ return parsed;
42
+ }
43
+
44
+ function printStatus(snapshot) {
45
+ console.log(`${snapshot.displayName} number-theory harness`);
46
+ console.log(`Family role: ${snapshot.familyRole}`);
47
+ console.log(`Harness profile: ${snapshot.harnessProfile}`);
48
+ console.log(`Site status: ${snapshot.siteStatus}`);
49
+ console.log(`Archive mode: ${snapshot.archiveMode ?? '(none)'}`);
50
+ console.log(`Active route: ${snapshot.activeRoute ?? '(none)'}`);
51
+ console.log(`Route breakthrough: ${snapshot.routeBreakthrough ? 'yes' : 'no'}`);
52
+ console.log(`Open problem: ${snapshot.openProblem ? 'yes' : 'no'}`);
53
+ console.log(`Problem solved: ${snapshot.problemSolved ? 'yes' : 'no'}`);
54
+ console.log(`Frontier label: ${snapshot.frontierLabel}`);
55
+ console.log(`Frontier detail: ${snapshot.frontierDetail}`);
56
+ console.log(`Checkpoint focus: ${snapshot.checkpointFocus ?? '(none)'}`);
57
+ console.log(`Next honest move: ${snapshot.nextHonestMove}`);
58
+ console.log(`Route packet present: ${snapshot.routePacketPresent ? 'yes' : 'no'}`);
59
+ if (snapshot.routePacket?.route_packet_id) {
60
+ console.log(`Route packet id: ${snapshot.routePacket.route_packet_id}`);
61
+ }
62
+ console.log(`Frontier note: ${snapshot.frontierNotePresent ? snapshot.frontierNotePath : '(missing)'}`);
63
+ console.log(`Route history: ${snapshot.routeHistoryPresent ? snapshot.routeHistoryPath : '(missing)'}`);
64
+ console.log(`Checkpoint template: ${snapshot.checkpointTemplatePresent ? snapshot.checkpointTemplatePath : '(missing)'}`);
65
+ console.log(`Report template: ${snapshot.reportTemplatePresent ? snapshot.reportTemplatePath : '(missing)'}`);
66
+ console.log(`Ops details present: ${snapshot.opsDetailsPresent ? 'yes' : 'no'}`);
67
+ console.log(`Active ticket: ${snapshot.activeTicketDetail?.ticket_id ?? '(none)'}`);
68
+ console.log(`Ready atoms: ${snapshot.readyAtomCount}`);
69
+ if (snapshot.firstReadyAtom) {
70
+ console.log(`First ready atom: ${snapshot.firstReadyAtom.atom_id} — ${snapshot.firstReadyAtom.title}`);
71
+ }
72
+ }
73
+
74
+ function printFrontier(snapshot) {
75
+ console.log(`${snapshot.displayName} number-theory frontier`);
76
+ console.log(`Active route: ${snapshot.activeRoute ?? '(none)'}`);
77
+ console.log(`Frontier label: ${snapshot.frontierLabel}`);
78
+ console.log(`Frontier detail: ${snapshot.frontierDetail}`);
79
+ console.log(`Checkpoint focus: ${snapshot.checkpointFocus ?? '(none)'}`);
80
+ console.log(`Next honest move: ${snapshot.nextHonestMove}`);
81
+ console.log(`Open problem: ${snapshot.openProblem ? 'yes' : 'no'}`);
82
+ console.log(`Archive mode: ${snapshot.archiveMode ?? '(none)'}`);
83
+ console.log(`Frontier note: ${snapshot.frontierNotePresent ? snapshot.frontierNotePath : '(missing)'}`);
84
+ console.log(`Route history: ${snapshot.routeHistoryPresent ? snapshot.routeHistoryPath : '(missing)'}`);
85
+ }
86
+
87
+ function printRoutes(snapshot) {
88
+ console.log(`${snapshot.displayName} number-theory routes`);
89
+ console.log(`Active route: ${snapshot.activeRoute ?? '(none)'}`);
90
+ if (!snapshot.opsDetails?.routes?.length) {
91
+ console.log('Routes: none recorded.');
92
+ return;
93
+ }
94
+ for (const route of snapshot.opsDetails.routes) {
95
+ const flags = [];
96
+ if (route.route_id === snapshot.activeRoute) {
97
+ flags.push('active');
98
+ }
99
+ if (route.status) {
100
+ flags.push(route.status);
101
+ }
102
+ console.log(`- ${route.route_id}${flags.length > 0 ? ` [${flags.join(', ')}]` : ''}`);
103
+ if (route.title) {
104
+ console.log(` title: ${route.title}`);
105
+ }
106
+ if (route.summary) {
107
+ console.log(` summary: ${route.summary}`);
108
+ }
109
+ if (route.why_now) {
110
+ console.log(` why now: ${route.why_now}`);
111
+ }
112
+ if (route.next_move) {
113
+ console.log(` next move: ${route.next_move}`);
114
+ }
115
+ }
116
+ }
117
+
118
+ function printTickets(snapshot) {
119
+ console.log(`${snapshot.displayName} number-theory tickets`);
120
+ if (!snapshot.opsDetails?.tickets?.length) {
121
+ console.log('Tickets: none recorded.');
122
+ return;
123
+ }
124
+ console.log(`Active ticket: ${snapshot.activeTicketDetail?.ticket_id ?? '(none)'}`);
125
+ for (const ticket of snapshot.opsDetails.tickets) {
126
+ const flags = [];
127
+ if (ticket.ticket_id === snapshot.activeTicketDetail?.ticket_id) {
128
+ flags.push('active');
129
+ }
130
+ if (ticket.status) {
131
+ flags.push(ticket.status);
132
+ }
133
+ console.log(`- ${ticket.ticket_id}${flags.length > 0 ? ` [${flags.join(', ')}]` : ''}`);
134
+ if (ticket.title) {
135
+ console.log(` title: ${ticket.title}`);
136
+ }
137
+ if (ticket.summary) {
138
+ console.log(` summary: ${ticket.summary}`);
139
+ }
140
+ if (ticket.current_blocker) {
141
+ console.log(` blocker: ${ticket.current_blocker}`);
142
+ }
143
+ if (ticket.next_move) {
144
+ console.log(` next move: ${ticket.next_move}`);
145
+ }
146
+ }
147
+ }
148
+
149
+ export function runNumberTheoryCommand(args) {
150
+ const [subcommand, ...rest] = args;
151
+
152
+ if (!subcommand || subcommand === 'help' || subcommand === '--help') {
153
+ console.log('Usage:');
154
+ console.log(' erdos number-theory status [<id>] [--json]');
155
+ console.log(' erdos number-theory frontier [<id>] [--json]');
156
+ console.log(' erdos number-theory routes [<id>] [--json]');
157
+ console.log(' erdos number-theory tickets [<id>] [--json]');
158
+ return 0;
159
+ }
160
+
161
+ if (!['status', 'frontier', 'routes', 'tickets'].includes(subcommand)) {
162
+ console.error(`Unknown number-theory subcommand: ${subcommand}`);
163
+ return 1;
164
+ }
165
+
166
+ const parsed = parseArgs(rest);
167
+ if (parsed.error) {
168
+ console.error(parsed.error);
169
+ return 1;
170
+ }
171
+
172
+ const { problem, error } = resolveNumberTheoryProblem(parsed.problemId);
173
+ if (error) {
174
+ console.error(error);
175
+ return 1;
176
+ }
177
+
178
+ const snapshot = buildNumberTheoryStatusSnapshot(problem);
179
+ if (parsed.asJson) {
180
+ console.log(JSON.stringify(snapshot, null, 2));
181
+ return 0;
182
+ }
183
+
184
+ if (subcommand === 'frontier') {
185
+ printFrontier(snapshot);
186
+ return 0;
187
+ }
188
+ if (subcommand === 'routes') {
189
+ printRoutes(snapshot);
190
+ return 0;
191
+ }
192
+ if (subcommand === 'tickets') {
193
+ printTickets(snapshot);
194
+ return 0;
195
+ }
196
+
197
+ printStatus(snapshot);
198
+ return 0;
199
+ }
@@ -94,6 +94,9 @@ function printProblem(problem) {
94
94
  console.log(`Repo status: ${problem.repoStatus}`);
95
95
  console.log(`Cluster: ${problem.cluster}`);
96
96
  console.log(`Harness depth: ${problem.harnessDepth}`);
97
+ if (String(problem.siteStatus).toLowerCase() === 'solved') {
98
+ console.log('Archive mode: method_exemplar');
99
+ }
97
100
  console.log(`Prize: ${problem.prize ?? '(none)'}`);
98
101
  console.log(`Formalization: ${problem.formalizationStatus}`);
99
102
  console.log(`Upstream formalized: ${problem.upstreamFormalizedState ?? '(unknown)'}`);
@@ -10,6 +10,7 @@ import { getProblemArtifactInventory, scaffoldProblem } from '../runtime/problem
10
10
  import { loadActiveUpstreamSnapshot, syncUpstream } from '../upstream/sync.js';
11
11
  import { fetchProblemSiteSnapshot } from '../upstream/site.js';
12
12
  import { buildProblemSearchQueries, fetchProblemPublicSearchReview } from '../upstream/public-search.js';
13
+ import { fetchCrossrefLiterature, fetchOpenAlexLiterature } from '../upstream/literature.js';
13
14
 
14
15
  function normalizeClusterLabel(rawTag) {
15
16
  return String(rawTag ?? '')
@@ -44,13 +45,16 @@ function inferClusterFromUpstream(upstreamRecord) {
44
45
  function parsePullArgs(args) {
45
46
  const [kind, value, ...rest] = args;
46
47
  if (!['problem', 'artifacts', 'literature'].includes(kind)) {
47
- return { error: 'Usage: erdos pull problem|artifacts|literature <id> [--dest <path>] [--include-site] [--refresh-upstream]' };
48
+ return { error: 'Usage: erdos pull problem|artifacts|literature <id> [--dest <path>] [--include-site] [--include-public-search] [--include-crossref] [--include-openalex] [--refresh-upstream] [--json]' };
48
49
  }
49
50
 
50
51
  let destination = null;
51
52
  let includeSite = false;
52
53
  let includePublicSearch = false;
54
+ let includeCrossref = false;
55
+ let includeOpenAlex = false;
53
56
  let refreshUpstream = false;
57
+ let asJson = false;
54
58
 
55
59
  for (let index = 0; index < rest.length; index += 1) {
56
60
  const token = rest[index];
@@ -70,10 +74,22 @@ function parsePullArgs(args) {
70
74
  includePublicSearch = true;
71
75
  continue;
72
76
  }
77
+ if (token === '--include-crossref') {
78
+ includeCrossref = true;
79
+ continue;
80
+ }
81
+ if (token === '--include-openalex') {
82
+ includeOpenAlex = true;
83
+ continue;
84
+ }
73
85
  if (token === '--refresh-upstream') {
74
86
  refreshUpstream = true;
75
87
  continue;
76
88
  }
89
+ if (token === '--json') {
90
+ asJson = true;
91
+ continue;
92
+ }
77
93
  return { error: `Unknown pull option: ${token}` };
78
94
  }
79
95
 
@@ -83,7 +99,10 @@ function parsePullArgs(args) {
83
99
  destination,
84
100
  includeSite,
85
101
  includePublicSearch,
102
+ includeCrossref,
103
+ includeOpenAlex,
86
104
  refreshUpstream,
105
+ asJson,
87
106
  };
88
107
  }
89
108
 
@@ -318,7 +337,66 @@ async function maybeWritePublicSearchBundle(problemId, title, destination, inclu
318
337
  }
319
338
  }
320
339
 
321
- async function writeLiteratureLane(problemId, destination, localProblem, upstreamRecord, includeSite, includePublicSearch) {
340
+ async function maybeWriteLiteratureAdapter(problemId, title, destination, includeAdapter, label, fetcher) {
341
+ if (!includeAdapter) {
342
+ return {
343
+ attempted: false,
344
+ included: false,
345
+ error: null,
346
+ resultCount: 0,
347
+ filePrefix: label.toUpperCase(),
348
+ };
349
+ }
350
+
351
+ const filePrefix = label.toUpperCase();
352
+
353
+ try {
354
+ const payload = await fetcher(problemId, title);
355
+ writeJson(path.join(destination, `${filePrefix}_RESULTS.json`), payload);
356
+ writeText(
357
+ path.join(destination, `${filePrefix}_RESULTS.md`),
358
+ [
359
+ `# ${label} Results`,
360
+ '',
361
+ `Fetched at: ${payload.fetchedAt}`,
362
+ `Query: ${payload.query}`,
363
+ '',
364
+ ...(payload.results.length > 0
365
+ ? payload.results.map((result) => `- [${result.title || '(untitled)'}](${result.url || '#'})`)
366
+ : ['- *(no results captured)*']),
367
+ '',
368
+ ].join('\n'),
369
+ );
370
+ return {
371
+ attempted: true,
372
+ included: true,
373
+ error: null,
374
+ resultCount: payload.results.length,
375
+ filePrefix,
376
+ };
377
+ } catch (error) {
378
+ const message = String(error?.message ?? error);
379
+ writeText(path.join(destination, `${filePrefix}_ERROR.txt`), message);
380
+ return {
381
+ attempted: true,
382
+ included: false,
383
+ error: message,
384
+ resultCount: 0,
385
+ filePrefix,
386
+ };
387
+ }
388
+ }
389
+
390
+ async function writeLiteratureLane(
391
+ problemId,
392
+ destination,
393
+ localProblem,
394
+ upstreamRecord,
395
+ includeSite,
396
+ includePublicSearch,
397
+ includeCrossref,
398
+ includeOpenAlex,
399
+ ) {
322
400
  ensureDir(destination);
323
401
 
324
402
  const includedFiles = [];
@@ -355,6 +433,23 @@ async function writeLiteratureLane(problemId, destination, localProblem, upstrea
355
433
  destination,
356
434
  includePublicSearch,
357
435
  );
436
+ const literatureTitle = localProblem?.title ?? upstreamRecord?.title ?? `Erdos Problem #${problemId}`;
437
+ const crossref = await maybeWriteLiteratureAdapter(
438
+ problemId,
439
+ literatureTitle,
440
+ destination,
441
+ includeCrossref,
442
+ 'Crossref',
443
+ fetchCrossrefLiterature,
444
+ );
445
+ const openalex = await maybeWriteLiteratureAdapter(
446
+ problemId,
447
+ literatureTitle,
448
+ destination,
449
+ includeOpenAlex,
450
+ 'OpenAlex',
451
+ fetchOpenAlexLiterature,
452
+ );
358
453
  const problemRecord = buildProblemRecord(problemId, localProblem, upstreamRecord);
359
454
  writeJson(path.join(destination, 'PROBLEM.json'), problemRecord);
360
455
  writeJson(path.join(destination, 'LITERATURE_INDEX.json'), {
@@ -368,6 +463,10 @@ async function writeLiteratureLane(problemId, destination, localProblem, upstrea
368
463
  includedPublicSearch: publicSearch.included,
369
464
  publicSearchError: publicSearch.error,
370
465
  publicSearchQueries: publicSearch.queries,
466
+ includedCrossref: crossref.included,
467
+ crossrefError: crossref.error,
468
+ includedOpenAlex: openalex.included,
469
+ openAlexError: openalex.error,
371
470
  });
372
471
  writeText(
373
472
  path.join(destination, 'README.md'),
@@ -380,6 +479,8 @@ async function writeLiteratureLane(problemId, destination, localProblem, upstrea
380
479
  `- Upstream record included: ${upstreamRecord ? 'yes' : 'no'}`,
381
480
  `- Live site snapshot included: ${siteStatus.included ? 'yes' : 'no'}`,
382
481
  `- Public search review included: ${publicSearch.included ? 'yes' : 'no'}`,
482
+ `- Crossref adapter included: ${crossref.included ? 'yes' : 'no'}`,
483
+ `- OpenAlex adapter included: ${openalex.included ? 'yes' : 'no'}`,
383
484
  '',
384
485
  ].join('\n'),
385
486
  );
@@ -389,6 +490,8 @@ async function writeLiteratureLane(problemId, destination, localProblem, upstrea
389
490
  includedFiles,
390
491
  siteStatus,
391
492
  publicSearch,
493
+ crossref,
494
+ openalex,
392
495
  };
393
496
  }
394
497
 
@@ -433,9 +536,9 @@ export async function runPullCommand(args, options = {}) {
433
536
  if (args.length === 0 || args[0] === 'help' || args[0] === '--help') {
434
537
  if (!silent) {
435
538
  console.log('Usage:');
436
- console.log(' erdos pull problem <id> [--dest <path>] [--include-site] [--include-public-search] [--refresh-upstream]');
437
- console.log(' erdos pull artifacts <id> [--dest <path>] [--refresh-upstream]');
438
- console.log(' erdos pull literature <id> [--dest <path>] [--include-site] [--include-public-search] [--refresh-upstream]');
539
+ console.log(' erdos pull problem <id> [--dest <path>] [--include-site] [--include-public-search] [--include-crossref] [--include-openalex] [--refresh-upstream] [--json]');
540
+ console.log(' erdos pull artifacts <id> [--dest <path>] [--refresh-upstream] [--json]');
541
+ console.log(' erdos pull literature <id> [--dest <path>] [--include-site] [--include-public-search] [--include-crossref] [--include-openalex] [--refresh-upstream] [--json]');
439
542
  }
440
543
  return 0;
441
544
  }
@@ -474,6 +577,17 @@ export async function runPullCommand(args, options = {}) {
474
577
  ? path.resolve(parsed.destination)
475
578
  : getWorkspaceProblemArtifactDir(parsed.problemId);
476
579
  const result = writeArtifactsLane(String(parsed.problemId), destination, localProblem, upstreamRecord, snapshot);
580
+ if (parsed.asJson) {
581
+ console.log(JSON.stringify({
582
+ kind: 'artifacts',
583
+ problemId: String(parsed.problemId),
584
+ destination,
585
+ localProblemIncluded: Boolean(localProblem),
586
+ upstreamRecordIncluded: Boolean(upstreamRecord),
587
+ artifactsCopied: result.copiedArtifacts?.length ?? result.artifactsCopied ?? 0,
588
+ }, null, 2));
589
+ return 0;
590
+ }
477
591
  if (!silent) {
478
592
  console.log(`Artifact bundle created: ${destination}`);
479
593
  console.log(`Local canonical dossier included: ${localProblem ? 'yes' : 'no'}`);
@@ -494,19 +608,47 @@ export async function runPullCommand(args, options = {}) {
494
608
  upstreamRecord,
495
609
  parsed.includeSite,
496
610
  parsed.includePublicSearch,
611
+ parsed.includeCrossref,
612
+ parsed.includeOpenAlex,
497
613
  );
614
+ if (parsed.asJson) {
615
+ console.log(JSON.stringify({
616
+ kind: 'literature',
617
+ problemId: String(parsed.problemId),
618
+ destination,
619
+ localProblemIncluded: Boolean(localProblem),
620
+ upstreamRecordIncluded: Boolean(upstreamRecord),
621
+ includedSiteSnapshot: result.siteStatus.included,
622
+ siteStatusError: result.siteStatus.error,
623
+ includedPublicSearch: result.publicSearch.included,
624
+ publicSearchError: result.publicSearch.error,
625
+ includedCrossref: result.crossref.included,
626
+ crossrefError: result.crossref.error,
627
+ includedOpenAlex: result.openalex.included,
628
+ openAlexError: result.openalex.error,
629
+ }, null, 2));
630
+ return 0;
631
+ }
498
632
  if (!silent) {
499
633
  console.log(`Literature bundle created: ${destination}`);
500
634
  console.log(`Local dossier context included: ${localProblem ? 'yes' : 'no'}`);
501
635
  console.log(`Upstream record included: ${upstreamRecord ? 'yes' : 'no'}`);
502
636
  console.log(`Live site snapshot included: ${result.siteStatus.included ? 'yes' : 'no'}`);
503
637
  console.log(`Public search review included: ${result.publicSearch.included ? 'yes' : 'no'}`);
638
+ console.log(`Crossref adapter included: ${result.crossref.included ? 'yes' : 'no'}`);
639
+ console.log(`OpenAlex adapter included: ${result.openalex.included ? 'yes' : 'no'}`);
504
640
  if (result.siteStatus.error) {
505
641
  console.log(`Live site snapshot note: ${result.siteStatus.error}`);
506
642
  }
507
643
  if (result.publicSearch.error) {
508
644
  console.log(`Public search note: ${result.publicSearch.error}`);
509
645
  }
646
+ if (result.crossref.error) {
647
+ console.log(`Crossref note: ${result.crossref.error}`);
648
+ }
649
+ if (result.openalex.error) {
650
+ console.log(`OpenAlex note: ${result.openalex.error}`);
651
+ }
510
652
  }
511
653
  return 0;
512
654
  }
@@ -526,6 +668,8 @@ export async function runPullCommand(args, options = {}) {
526
668
  upstreamRecord,
527
669
  parsed.includeSite,
528
670
  parsed.includePublicSearch,
671
+ parsed.includeCrossref,
672
+ parsed.includeOpenAlex,
529
673
  );
530
674
 
531
675
  writeJson(path.join(rootDestination, 'PULL_STATUS.json'), {
@@ -545,8 +689,31 @@ export async function runPullCommand(args, options = {}) {
545
689
  publicSearchAttempted: literatureResult.publicSearch.attempted,
546
690
  publicSearchIncluded: literatureResult.publicSearch.included,
547
691
  publicSearchError: literatureResult.publicSearch.error,
692
+ crossrefAttempted: literatureResult.crossref.attempted,
693
+ crossrefIncluded: literatureResult.crossref.included,
694
+ crossrefError: literatureResult.crossref.error,
695
+ openAlexAttempted: literatureResult.openalex.attempted,
696
+ openAlexIncluded: literatureResult.openalex.included,
697
+ openAlexError: literatureResult.openalex.error,
548
698
  });
549
699
 
700
+ if (parsed.asJson) {
701
+ console.log(JSON.stringify({
702
+ kind: 'problem',
703
+ problemId: String(parsed.problemId),
704
+ destination: rootDestination,
705
+ artifactsDir: artifactDestination,
706
+ literatureDir: literatureDestination,
707
+ localProblemIncluded: Boolean(localProblem),
708
+ upstreamRecordIncluded: Boolean(upstreamRecord),
709
+ includedSiteSnapshot: literatureResult.siteStatus.included,
710
+ includedPublicSearch: literatureResult.publicSearch.included,
711
+ includedCrossref: literatureResult.crossref.included,
712
+ includedOpenAlex: literatureResult.openalex.included,
713
+ }, null, 2));
714
+ return 0;
715
+ }
716
+
550
717
  if (!silent) {
551
718
  console.log(`Pull bundle created: ${rootDestination}`);
552
719
  console.log(`Artifact lane: ${artifactDestination}`);
@@ -555,12 +722,20 @@ export async function runPullCommand(args, options = {}) {
555
722
  console.log(`Upstream record included: ${upstreamRecord ? 'yes' : 'no'}`);
556
723
  console.log(`Live site snapshot included: ${literatureResult.siteStatus.included ? 'yes' : 'no'}`);
557
724
  console.log(`Public search review included: ${literatureResult.publicSearch.included ? 'yes' : 'no'}`);
725
+ console.log(`Crossref adapter included: ${literatureResult.crossref.included ? 'yes' : 'no'}`);
726
+ console.log(`OpenAlex adapter included: ${literatureResult.openalex.included ? 'yes' : 'no'}`);
558
727
  if (literatureResult.siteStatus.error) {
559
728
  console.log(`Live site snapshot note: ${literatureResult.siteStatus.error}`);
560
729
  }
561
730
  if (literatureResult.publicSearch.error) {
562
731
  console.log(`Public search note: ${literatureResult.publicSearch.error}`);
563
732
  }
733
+ if (literatureResult.crossref.error) {
734
+ console.log(`Crossref note: ${literatureResult.crossref.error}`);
735
+ }
736
+ if (literatureResult.openalex.error) {
737
+ console.log(`OpenAlex note: ${literatureResult.openalex.error}`);
738
+ }
564
739
  }
565
740
  return 0;
566
741
  }