@tiangong-ai/cli 0.0.35 → 0.0.37
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/AGENTS.md +16 -6
- package/README.md +128 -10
- package/dist/research/orchestration.js +334 -29
- package/dist/research/orchestration.js.map +1 -1
- package/dist/research/workspace/acquisition-routes.d.ts +14 -0
- package/dist/research/workspace/acquisition-routes.js +45 -0
- package/dist/research/workspace/acquisition-routes.js.map +1 -0
- package/dist/research/workspace/audit-bundle.d.ts +44 -0
- package/dist/research/workspace/audit-bundle.js +357 -0
- package/dist/research/workspace/audit-bundle.js.map +1 -0
- package/dist/research/workspace/broker.js +54 -10
- package/dist/research/workspace/broker.js.map +1 -1
- package/dist/research/workspace/downloads.d.ts +6 -0
- package/dist/research/workspace/downloads.js +32 -8
- package/dist/research/workspace/downloads.js.map +1 -1
- package/dist/research/workspace/evidence-exhaustion.d.ts +45 -0
- package/dist/research/workspace/evidence-exhaustion.js +365 -0
- package/dist/research/workspace/evidence-exhaustion.js.map +1 -0
- package/dist/research/workspace/native-activity.d.ts +6 -0
- package/dist/research/workspace/native-activity.js +24 -7
- package/dist/research/workspace/native-activity.js.map +1 -1
- package/dist/research/workspace/preflight.d.ts +34 -2
- package/dist/research/workspace/preflight.js +161 -1
- package/dist/research/workspace/preflight.js.map +1 -1
- package/dist/research/workspace/projects.d.ts +28 -4
- package/dist/research/workspace/projects.js +301 -12
- package/dist/research/workspace/projects.js.map +1 -1
- package/dist/research/workspace/publication-workflow.js +2 -0
- package/dist/research/workspace/publication-workflow.js.map +1 -1
- package/dist/research/workspace/runtime.d.ts +151 -3
- package/dist/research/workspace/runtime.js +180 -6
- package/dist/research/workspace/runtime.js.map +1 -1
- package/dist/research/workspace/sanitization.js +9 -3
- package/dist/research/workspace/sanitization.js.map +1 -1
- package/dist/research/workspace/scientific-design.d.ts +359 -0
- package/dist/research/workspace/scientific-design.js +2021 -0
- package/dist/research/workspace/scientific-design.js.map +1 -0
- package/dist/research/workspace/scientific-review.d.ts +101 -0
- package/dist/research/workspace/scientific-review.js +1167 -0
- package/dist/research/workspace/scientific-review.js.map +1 -0
- package/dist/research/workspace/setup-catalog.js +2 -2
- package/dist/research/workspace/setup.js +12 -3
- package/dist/research/workspace/setup.js.map +1 -1
- package/dist/research/workspace/types.d.ts +54 -0
- package/dist/research/workspace/workspace.js +25 -7
- package/dist/research/workspace/workspace.js.map +1 -1
- package/package.json +2 -1
|
@@ -11,8 +11,10 @@ import { configureExternalSkillProfile, doctorExternalCapabilities, EXTERNAL_SKI
|
|
|
11
11
|
import { appendJournalEvent } from "./workspace/journal.js";
|
|
12
12
|
import { fetchNativeCandidateSource } from "./workspace/broker.js";
|
|
13
13
|
import { registerEvidenceArtifact } from "./workspace/artifacts.js";
|
|
14
|
+
import { exportProjectAuditBundle, verifyProjectAuditBundle } from "./workspace/audit-bundle.js";
|
|
14
15
|
import { loadCurrentEvidenceSnapshot } from "./workspace/acquisition.js";
|
|
15
16
|
import { inspectDiscoveryProgress } from "./workspace/discovery-status.js";
|
|
17
|
+
import { inspectEvidenceAccessStatus } from "./workspace/evidence-exhaustion.js";
|
|
16
18
|
import { recordDiscoveryAssessmentBatch } from "./workspace/discovery.js";
|
|
17
19
|
import { bindEvidenceDownload } from "./workspace/downloads.js";
|
|
18
20
|
import { registerNativeDiscoveryCandidate } from "./workspace/evidence-ledger.js";
|
|
@@ -25,6 +27,8 @@ import { approveResearchPolicy, initializeResearchPolicy, inspectResearchPolicyC
|
|
|
25
27
|
import { resolveInstalledResearchPolicySource, runInteractiveResearchPolicyWizard, } from "./workspace/research-policy-wizard.js";
|
|
26
28
|
import { abortNativeResearchStage, inspectNativeResearchStage, prepareNativeResearchStage, requestResearchHandoff, resolveResearchHandoff, runResearchWorkspace, submitNativeResearchStage, } from "./workspace/runtime.js";
|
|
27
29
|
import { schemaForStage } from "./workspace/schemas.js";
|
|
30
|
+
import { readAndVerifyScientificDesign, scientificDesignSchema, } from "./workspace/scientific-design.js";
|
|
31
|
+
import { inspectScientificReviewStatus, prepareScientificReview, scientificGateAssessmentSchema, scientificReviewSchema, submitScientificReview, } from "./workspace/scientific-review.js";
|
|
28
32
|
import { pathExists, sha256Text, workspacePaths } from "./workspace/storage.js";
|
|
29
33
|
import { doctorResearchWorkspace, initializeResearchWorkspace, requireResearchWorkspace, withWorkspaceLock, } from "./workspace/workspace.js";
|
|
30
34
|
const COMMON_OPTIONS = { help: "boolean", json: "boolean" };
|
|
@@ -78,16 +82,22 @@ export function researchOrchestrationHelp() {
|
|
|
78
82
|
tiangong-ai research publication review submit <project-id> --role evidence|methods-reproducibility|domain-novelty|journal-editor --review <absolute-json> [--workspace <path>] [--json]
|
|
79
83
|
tiangong-ai research publication status <project-id> [--workspace <path>] [--json]
|
|
80
84
|
tiangong-ai research publication close <project-id> [--workspace <path>] [--json]
|
|
81
|
-
tiangong-ai research project init <project-id> --question <question> [--goal evidence-report|top-journal] [--requirements <absolute-json>] [--input-plan <absolute-json>] [--confirm-budget] [--workspace <path>] [--json]
|
|
82
|
-
tiangong-ai research project preflight --question <question> [--goal evidence-report|top-journal] [--policy-project <project-id>] [--requirements <absolute-json>] [--input-plan <absolute-json>] [--workspace <path>] [--json]
|
|
85
|
+
tiangong-ai research project init <project-id> --question <question> [--goal evidence-report|top-journal] [--design <absolute-json> --design-producer-agent codex|claude --design-producer-session <opaque-id>] [--requirements <absolute-json>] [--input-plan <absolute-json>] [--confirm-budget] [--workspace <path>] [--json]
|
|
86
|
+
tiangong-ai research project preflight --question <question> [--goal evidence-report|top-journal] [--policy-project <project-id> --design <absolute-json>] [--requirements <absolute-json>] [--input-plan <absolute-json>] [--workspace <path>] [--json]
|
|
83
87
|
tiangong-ai research project input add <project-id> --path <absolute-file> [--role primary|reference|replication] [--trust-status verified-owner-input|unverified-owner-input|reference-only|replication-candidate] [--independently-reproduced] [--workspace <path>] [--json]
|
|
84
88
|
tiangong-ai research project retry <project-id> [--package <package-id>] [--workspace <path>] [--json]
|
|
85
|
-
tiangong-ai research project fork <source-project-id> --to <target-project-id> [--resume-through discover|acquire|analyze|synthesize] [--workspace <path>] [--json]
|
|
86
|
-
tiangong-ai research project addendum <closed-project-id> --to <target-project-id> [--workspace <path>] [--json]
|
|
89
|
+
tiangong-ai research project fork <source-project-id> --to <target-project-id> [--resume-through discover|acquire|analyze|synthesize] [--design <absolute-json> --design-producer-agent codex|claude --design-producer-session <opaque-id>] [--workspace <path>] [--json]
|
|
90
|
+
tiangong-ai research project addendum <closed-project-id> --to <target-project-id> [--design <absolute-json> --design-producer-agent codex|claude --design-producer-session <opaque-id>] [--workspace <path>] [--json]
|
|
87
91
|
tiangong-ai research project archive <project-id> --reason <text> [--workspace <path>] [--json]
|
|
88
92
|
tiangong-ai research project abandon <project-id> --reason <text> [--workspace <path>] [--json]
|
|
89
93
|
tiangong-ai research project handoff request <project-id> --record <absolute-json> [--workspace <path>] [--json]
|
|
90
94
|
tiangong-ai research project handoff resolve <project-id> --note <text> [--workspace <path>] [--json]
|
|
95
|
+
tiangong-ai research project access status <project-id> [--workspace <path>] [--json]
|
|
96
|
+
tiangong-ai research project scientific review prepare <project-id> --role research-design|evidence-construct|pilot-methods --assessment <absolute-json> --reviewer-agent codex|claude --reviewer-session <opaque-id> [--workspace <path>] [--json]
|
|
97
|
+
tiangong-ai research project scientific review submit <project-id> --role research-design|evidence-construct|pilot-methods --review <absolute-json> [--workspace <path>] [--json]
|
|
98
|
+
tiangong-ai research project scientific status <project-id> [--workspace <path>] [--json]
|
|
99
|
+
tiangong-ai research project audit export <project-id> --output <absolute-new-directory> [--workspace <path>] [--json]
|
|
100
|
+
tiangong-ai research project audit verify --bundle <absolute-directory> [--json]
|
|
91
101
|
tiangong-ai research project stage prepare <project-id> --stage discover|acquire|analyze|synthesize --host-agent codex|claude [--workspace <path>] [--json]
|
|
92
102
|
tiangong-ai research project stage submit <project-id> --session <id> --output <absolute-json> [--confirm-model <id>] [--workspace <path>] [--json]
|
|
93
103
|
tiangong-ai research project stage abort <project-id> --session <id> [--workspace <path>] [--json]
|
|
@@ -97,7 +107,7 @@ export function researchOrchestrationHelp() {
|
|
|
97
107
|
tiangong-ai research project evidence assessment record <project-id> --record <absolute-json> [--workspace <path>] [--json]
|
|
98
108
|
tiangong-ai research project evidence download bind <project-id> --candidate <id> --record <absolute-json> [--workspace <path>] [--json]
|
|
99
109
|
tiangong-ai research project evidence artifact register <project-id> --candidate <id> --path <absolute-file> [--download-binding <id> | --derived-from-artifact <id>] [--media-type <type>] [--source-url <https-url>] [--license <declared-license>] [--license-url <https-url>] [--host-type <type>] [--article-version <version>] [--workspace <path>] [--json]
|
|
100
|
-
tiangong-ai research schema show <discover|acquire|analyze|synthesize|review|doctor|publication-assessment|publication-review-evidence|publication-review-methods-reproducibility|publication-review-domain-novelty|publication-review-journal-editor> [--json]
|
|
110
|
+
tiangong-ai research schema show <discover|acquire|analyze|synthesize|review|doctor|scientific-design|scientific-assessment-research-design|scientific-assessment-evidence-construct|scientific-assessment-pilot-methods|scientific-review-research-design|scientific-review-evidence-construct|scientific-review-pilot-methods|publication-assessment|publication-review-evidence|publication-review-methods-reproducibility|publication-review-domain-novelty|publication-review-journal-editor> [--compatibility claude-code] [--json]
|
|
101
111
|
tiangong-ai research status [--project <project-id>] [--all] [--workspace <absolute-path>] [--json]
|
|
102
112
|
tiangong-ai research run [--project <project-id>] [--max-parallel <1-8>] [--max-cycles <1-100>] [--dry-run] [--progress-jsonl] [--workspace <absolute-path>] [--json]
|
|
103
113
|
|
|
@@ -303,33 +313,74 @@ async function runSchema(argv, io) {
|
|
|
303
313
|
return writeHelp(io);
|
|
304
314
|
if (action !== "show")
|
|
305
315
|
throw unknownAction("research schema", action);
|
|
306
|
-
const args = parseStrictArgs(rest, COMMON_OPTIONS, "research schema show");
|
|
316
|
+
const args = parseStrictArgs(rest, { ...COMMON_OPTIONS, compatibility: "string" }, "research schema show");
|
|
307
317
|
if (strictBoolean(args, "help"))
|
|
308
318
|
return writeHelp(io);
|
|
309
319
|
const stage = onePositional(args.positionals, "research schema show");
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
320
|
+
let schema;
|
|
321
|
+
if (stage === "scientific-design") {
|
|
322
|
+
schema = scientificDesignSchema();
|
|
323
|
+
}
|
|
324
|
+
else if (stage.startsWith("scientific-assessment-")) {
|
|
325
|
+
const role = scientificReviewRole(stage.slice("scientific-assessment-".length));
|
|
326
|
+
schema = scientificGateAssessmentSchema(role);
|
|
327
|
+
}
|
|
328
|
+
else if (stage.startsWith("scientific-review-")) {
|
|
329
|
+
const role = scientificReviewRole(stage.slice("scientific-review-".length));
|
|
330
|
+
schema = scientificReviewSchema(role);
|
|
331
|
+
}
|
|
332
|
+
else if (stage === "publication-assessment") {
|
|
333
|
+
schema = publicationAssessmentSchema();
|
|
313
334
|
}
|
|
314
|
-
if (stage.startsWith("publication-review-")) {
|
|
335
|
+
else if (stage.startsWith("publication-review-")) {
|
|
315
336
|
const role = publicationReviewRole(stage.slice("publication-review-".length));
|
|
316
|
-
|
|
317
|
-
|
|
337
|
+
schema = publicationReviewSchema(role);
|
|
338
|
+
}
|
|
339
|
+
else if (stage === "discover" ||
|
|
340
|
+
stage === "acquire" ||
|
|
341
|
+
stage === "analyze" ||
|
|
342
|
+
stage === "synthesize" ||
|
|
343
|
+
stage === "review" ||
|
|
344
|
+
stage === "doctor") {
|
|
345
|
+
schema = schemaForStage(stage);
|
|
318
346
|
}
|
|
319
|
-
|
|
320
|
-
stage !== "acquire" &&
|
|
321
|
-
stage !== "analyze" &&
|
|
322
|
-
stage !== "synthesize" &&
|
|
323
|
-
stage !== "review" &&
|
|
324
|
-
stage !== "doctor") {
|
|
347
|
+
else {
|
|
325
348
|
throw new CliError(`Unsupported research schema stage: ${stage}`, {
|
|
326
349
|
code: "RESEARCH_SCHEMA_INVALID",
|
|
327
350
|
exitCode: 2,
|
|
328
351
|
});
|
|
329
352
|
}
|
|
330
|
-
writeJson(io,
|
|
353
|
+
writeJson(io, compatibleSchema(schema, strictString(args, "compatibility")), args);
|
|
331
354
|
return 0;
|
|
332
355
|
}
|
|
356
|
+
function compatibleSchema(schema, compatibility) {
|
|
357
|
+
if (!compatibility)
|
|
358
|
+
return schema;
|
|
359
|
+
if (compatibility !== "claude-code") {
|
|
360
|
+
throw new CliError(`Unsupported schema compatibility target: ${compatibility}`, {
|
|
361
|
+
code: "RESEARCH_SCHEMA_COMPATIBILITY_INVALID",
|
|
362
|
+
exitCode: 2,
|
|
363
|
+
details: { supported: ["claude-code"] },
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
const compatible = structuredClone(schema);
|
|
367
|
+
const stripMetadata = (value) => {
|
|
368
|
+
if (Array.isArray(value)) {
|
|
369
|
+
for (const item of value)
|
|
370
|
+
stripMetadata(item);
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
if (!value || typeof value !== "object")
|
|
374
|
+
return;
|
|
375
|
+
const record = value;
|
|
376
|
+
delete record.$schema;
|
|
377
|
+
delete record.$id;
|
|
378
|
+
for (const item of Object.values(record))
|
|
379
|
+
stripMetadata(item);
|
|
380
|
+
};
|
|
381
|
+
stripMetadata(compatible);
|
|
382
|
+
return compatible;
|
|
383
|
+
}
|
|
333
384
|
async function runContext(argv, io) {
|
|
334
385
|
const [action, ...rest] = argv;
|
|
335
386
|
if (!action || action === "--help" || action === "-h")
|
|
@@ -520,6 +571,54 @@ async function runProject(argv, io) {
|
|
|
520
571
|
const [action, ...rest] = argv;
|
|
521
572
|
if (!action || action === "--help" || action === "-h")
|
|
522
573
|
return writeHelp(io);
|
|
574
|
+
if (action === "audit") {
|
|
575
|
+
const [auditAction, ...auditRest] = rest;
|
|
576
|
+
if (auditAction === "export") {
|
|
577
|
+
const args = parseStrictArgs(auditRest, { ...WORKSPACE_OPTIONS, output: "string" }, "research project audit export");
|
|
578
|
+
if (strictBoolean(args, "help"))
|
|
579
|
+
return writeHelp(io);
|
|
580
|
+
const projectId = onePositional(args.positionals, "research project audit export");
|
|
581
|
+
const destination = strictString(args, "output");
|
|
582
|
+
if (!destination) {
|
|
583
|
+
throw new CliError("Audit export requires --output.", {
|
|
584
|
+
code: "RESEARCH_AUDIT_BUNDLE_PATH_INVALID",
|
|
585
|
+
exitCode: 2,
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
const root = await workspaceFromArgs(args);
|
|
589
|
+
writeJson(io, await exportProjectAuditBundle({ root, projectId, destination }), args);
|
|
590
|
+
return 0;
|
|
591
|
+
}
|
|
592
|
+
if (auditAction === "verify") {
|
|
593
|
+
const args = parseStrictArgs(auditRest, { ...COMMON_OPTIONS, bundle: "string" }, "research project audit verify");
|
|
594
|
+
if (strictBoolean(args, "help"))
|
|
595
|
+
return writeHelp(io);
|
|
596
|
+
rejectPositionals(args.positionals, "research project audit verify");
|
|
597
|
+
const bundlePath = strictString(args, "bundle");
|
|
598
|
+
if (!bundlePath) {
|
|
599
|
+
throw new CliError("Audit verification requires --bundle.", {
|
|
600
|
+
code: "RESEARCH_AUDIT_BUNDLE_PATH_INVALID",
|
|
601
|
+
exitCode: 2,
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
writeJson(io, await verifyProjectAuditBundle(bundlePath), args);
|
|
605
|
+
return 0;
|
|
606
|
+
}
|
|
607
|
+
throw unknownAction("research project audit", auditAction ?? "");
|
|
608
|
+
}
|
|
609
|
+
if (action === "access") {
|
|
610
|
+
const [accessAction, ...accessRest] = rest;
|
|
611
|
+
if (accessAction !== "status") {
|
|
612
|
+
throw unknownAction("research project access", accessAction ?? "");
|
|
613
|
+
}
|
|
614
|
+
const args = parseStrictArgs(accessRest, WORKSPACE_OPTIONS, "research project access status");
|
|
615
|
+
if (strictBoolean(args, "help"))
|
|
616
|
+
return writeHelp(io);
|
|
617
|
+
const projectId = onePositional(args.positionals, "research project access status");
|
|
618
|
+
const root = await workspaceFromArgs(args);
|
|
619
|
+
writeJson(io, await inspectEvidenceAccessStatus(root, projectId), args);
|
|
620
|
+
return 0;
|
|
621
|
+
}
|
|
523
622
|
if (action === "handoff") {
|
|
524
623
|
const [handoffAction, ...handoffRest] = rest;
|
|
525
624
|
if (handoffAction === "request") {
|
|
@@ -559,6 +658,71 @@ async function runProject(argv, io) {
|
|
|
559
658
|
}
|
|
560
659
|
throw unknownAction("research project handoff", handoffAction ?? "");
|
|
561
660
|
}
|
|
661
|
+
if (action === "scientific") {
|
|
662
|
+
const [scientificAction, ...scientificRest] = rest;
|
|
663
|
+
if (scientificAction === "status") {
|
|
664
|
+
const args = parseStrictArgs(scientificRest, WORKSPACE_OPTIONS, "research project scientific status");
|
|
665
|
+
if (strictBoolean(args, "help"))
|
|
666
|
+
return writeHelp(io);
|
|
667
|
+
const projectId = onePositional(args.positionals, "research project scientific status");
|
|
668
|
+
const root = await workspaceFromArgs(args);
|
|
669
|
+
writeJson(io, await inspectScientificReviewStatus(root, projectId), args);
|
|
670
|
+
return 0;
|
|
671
|
+
}
|
|
672
|
+
if (scientificAction !== "review") {
|
|
673
|
+
throw unknownAction("research project scientific", scientificAction ?? "");
|
|
674
|
+
}
|
|
675
|
+
const [reviewAction, ...reviewRest] = scientificRest;
|
|
676
|
+
if (reviewAction === "prepare") {
|
|
677
|
+
const args = parseStrictArgs(reviewRest, {
|
|
678
|
+
...WORKSPACE_OPTIONS,
|
|
679
|
+
role: "string",
|
|
680
|
+
assessment: "string",
|
|
681
|
+
"reviewer-agent": "string",
|
|
682
|
+
"reviewer-session": "string",
|
|
683
|
+
}, "research project scientific review prepare");
|
|
684
|
+
if (strictBoolean(args, "help"))
|
|
685
|
+
return writeHelp(io);
|
|
686
|
+
const projectId = onePositional(args.positionals, "research project scientific review prepare");
|
|
687
|
+
const assessmentPath = strictString(args, "assessment");
|
|
688
|
+
const reviewerSessionId = strictString(args, "reviewer-session");
|
|
689
|
+
if (!assessmentPath || !reviewerSessionId) {
|
|
690
|
+
throw new CliError("Scientific review prepare requires --assessment, --reviewer-agent, and --reviewer-session.", { code: "RESEARCH_SCIENTIFIC_REVIEW_ARGUMENT_REQUIRED", exitCode: 2 });
|
|
691
|
+
}
|
|
692
|
+
const root = await workspaceFromArgs(args);
|
|
693
|
+
writeJson(io, await prepareScientificReview({
|
|
694
|
+
root,
|
|
695
|
+
projectId,
|
|
696
|
+
role: scientificReviewRole(strictString(args, "role")),
|
|
697
|
+
assessmentPath,
|
|
698
|
+
reviewerAgent: publicationAgent(strictString(args, "reviewer-agent"), "reviewer"),
|
|
699
|
+
reviewerSessionId,
|
|
700
|
+
}), args);
|
|
701
|
+
return 0;
|
|
702
|
+
}
|
|
703
|
+
if (reviewAction === "submit") {
|
|
704
|
+
const args = parseStrictArgs(reviewRest, { ...WORKSPACE_OPTIONS, role: "string", review: "string" }, "research project scientific review submit");
|
|
705
|
+
if (strictBoolean(args, "help"))
|
|
706
|
+
return writeHelp(io);
|
|
707
|
+
const projectId = onePositional(args.positionals, "research project scientific review submit");
|
|
708
|
+
const reviewPath = strictString(args, "review");
|
|
709
|
+
if (!reviewPath) {
|
|
710
|
+
throw new CliError("Scientific review submit requires --review.", {
|
|
711
|
+
code: "RESEARCH_SCIENTIFIC_REVIEW_ARGUMENT_REQUIRED",
|
|
712
|
+
exitCode: 2,
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
const root = await workspaceFromArgs(args);
|
|
716
|
+
writeJson(io, await submitScientificReview({
|
|
717
|
+
root,
|
|
718
|
+
projectId,
|
|
719
|
+
role: scientificReviewRole(strictString(args, "role")),
|
|
720
|
+
reviewPath,
|
|
721
|
+
}), args);
|
|
722
|
+
return 0;
|
|
723
|
+
}
|
|
724
|
+
throw unknownAction("research project scientific review", reviewAction ?? "");
|
|
725
|
+
}
|
|
562
726
|
if (action === "stage") {
|
|
563
727
|
const [stageAction, ...stageRest] = rest;
|
|
564
728
|
if (stageAction === "prepare") {
|
|
@@ -800,6 +964,9 @@ async function runProject(argv, io) {
|
|
|
800
964
|
goal: "string",
|
|
801
965
|
requirements: "string",
|
|
802
966
|
"input-plan": "string",
|
|
967
|
+
design: "string",
|
|
968
|
+
"design-producer-agent": "string",
|
|
969
|
+
"design-producer-session": "string",
|
|
803
970
|
"confirm-budget": "boolean",
|
|
804
971
|
}, "research project init");
|
|
805
972
|
if (strictBoolean(args, "help"))
|
|
@@ -816,7 +983,26 @@ async function runProject(argv, io) {
|
|
|
816
983
|
const goal = researchGoal(strictString(args, "goal"));
|
|
817
984
|
const requirementsPath = strictString(args, "requirements");
|
|
818
985
|
const inputPlanPath = strictString(args, "input-plan");
|
|
819
|
-
const
|
|
986
|
+
const publicationPolicy = goal === "top-journal" ? await loadApprovedResearchPolicy(root, projectId) : undefined;
|
|
987
|
+
const designPath = strictString(args, "design");
|
|
988
|
+
const designProducerAgent = strictString(args, "design-producer-agent");
|
|
989
|
+
const designProducerSession = strictString(args, "design-producer-session");
|
|
990
|
+
if (goal === "top-journal" && (!designPath || !designProducerAgent || !designProducerSession)) {
|
|
991
|
+
throw new CliError("Top-journal init requires --design, --design-producer-agent, and --design-producer-session.", { code: "RESEARCH_SCIENTIFIC_DESIGN_REQUIRED", exitCode: 2 });
|
|
992
|
+
}
|
|
993
|
+
if (goal !== "top-journal" && (designPath || designProducerAgent || designProducerSession)) {
|
|
994
|
+
throw new CliError("Scientific design options are only valid with --goal top-journal.", {
|
|
995
|
+
code: "RESEARCH_SCIENTIFIC_DESIGN_POLICY_REQUIRED",
|
|
996
|
+
exitCode: 2,
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
const project = await initializeProject(root, projectId, question, requirementsPath ? await readEvidenceRequirements(requirementsPath) : undefined, strictBoolean(args, "confirm-budget"), inputPlanPath ? await readAndVerifyProjectInputPlan(inputPlanPath) : undefined, publicationPolicy, designPath && designProducerAgent && designProducerSession
|
|
1000
|
+
? {
|
|
1001
|
+
design: await readAndVerifyScientificDesign(designPath, projectId),
|
|
1002
|
+
producerAgent: publicationAgent(designProducerAgent, "design producer"),
|
|
1003
|
+
producerSessionId: designProducerSession,
|
|
1004
|
+
}
|
|
1005
|
+
: undefined);
|
|
820
1006
|
writeJson(io, project, args);
|
|
821
1007
|
return 0;
|
|
822
1008
|
}
|
|
@@ -828,6 +1014,7 @@ async function runProject(argv, io) {
|
|
|
828
1014
|
"policy-project": "string",
|
|
829
1015
|
requirements: "string",
|
|
830
1016
|
"input-plan": "string",
|
|
1017
|
+
design: "string",
|
|
831
1018
|
}, "research project preflight");
|
|
832
1019
|
if (strictBoolean(args, "help"))
|
|
833
1020
|
return writeHelp(io);
|
|
@@ -842,6 +1029,7 @@ async function runProject(argv, io) {
|
|
|
842
1029
|
const root = await workspaceFromArgs(args);
|
|
843
1030
|
const goal = researchGoal(strictString(args, "goal"));
|
|
844
1031
|
const policyProject = strictString(args, "policy-project");
|
|
1032
|
+
let publicationPolicy = null;
|
|
845
1033
|
if (goal === "top-journal") {
|
|
846
1034
|
if (!policyProject) {
|
|
847
1035
|
throw new CliError("Top-journal preflight requires --policy-project.", {
|
|
@@ -849,7 +1037,7 @@ async function runProject(argv, io) {
|
|
|
849
1037
|
exitCode: 2,
|
|
850
1038
|
});
|
|
851
1039
|
}
|
|
852
|
-
await loadApprovedResearchPolicy(root, policyProject);
|
|
1040
|
+
publicationPolicy = await loadApprovedResearchPolicy(root, policyProject);
|
|
853
1041
|
}
|
|
854
1042
|
else if (policyProject) {
|
|
855
1043
|
throw new CliError("--policy-project is only valid with --goal top-journal.", {
|
|
@@ -861,7 +1049,26 @@ async function runProject(argv, io) {
|
|
|
861
1049
|
const requirements = requirementsPath ? await readEvidenceRequirements(requirementsPath) : null;
|
|
862
1050
|
const inputPlanPath = strictString(args, "input-plan");
|
|
863
1051
|
const inputPlan = inputPlanPath ? await readAndVerifyProjectInputPlan(inputPlanPath) : null;
|
|
864
|
-
const
|
|
1052
|
+
const designPath = strictString(args, "design");
|
|
1053
|
+
if (goal === "top-journal" && !designPath) {
|
|
1054
|
+
throw new CliError("Top-journal preflight requires --design.", {
|
|
1055
|
+
code: "RESEARCH_SCIENTIFIC_DESIGN_REQUIRED",
|
|
1056
|
+
exitCode: 2,
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
if (goal !== "top-journal" && designPath) {
|
|
1060
|
+
throw new CliError("--design is only valid with --goal top-journal.", {
|
|
1061
|
+
code: "RESEARCH_SCIENTIFIC_DESIGN_POLICY_REQUIRED",
|
|
1062
|
+
exitCode: 2,
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
const scientificDesign = designPath
|
|
1066
|
+
? await readAndVerifyScientificDesign(designPath, policyProject)
|
|
1067
|
+
: null;
|
|
1068
|
+
const result = await evaluateProjectPreflight(root, question, requirements, inputPlan, {
|
|
1069
|
+
publicationPolicy,
|
|
1070
|
+
scientificDesign,
|
|
1071
|
+
});
|
|
865
1072
|
writeJson(io, result, args);
|
|
866
1073
|
return result.readyToInitialize ? 0 : 3;
|
|
867
1074
|
}
|
|
@@ -909,7 +1116,14 @@ async function runProject(argv, io) {
|
|
|
909
1116
|
return 0;
|
|
910
1117
|
}
|
|
911
1118
|
if (action === "fork") {
|
|
912
|
-
const args = parseStrictArgs(rest, {
|
|
1119
|
+
const args = parseStrictArgs(rest, {
|
|
1120
|
+
...WORKSPACE_OPTIONS,
|
|
1121
|
+
to: "string",
|
|
1122
|
+
"resume-through": "string",
|
|
1123
|
+
design: "string",
|
|
1124
|
+
"design-producer-agent": "string",
|
|
1125
|
+
"design-producer-session": "string",
|
|
1126
|
+
}, "research project fork");
|
|
913
1127
|
if (strictBoolean(args, "help"))
|
|
914
1128
|
return writeHelp(io);
|
|
915
1129
|
const sourceProjectId = onePositional(args.positionals, "research project fork");
|
|
@@ -921,12 +1135,41 @@ async function runProject(argv, io) {
|
|
|
921
1135
|
});
|
|
922
1136
|
}
|
|
923
1137
|
const root = await workspaceFromArgs(args);
|
|
924
|
-
const
|
|
1138
|
+
const source = await loadProject(root, sourceProjectId);
|
|
1139
|
+
const designPath = strictString(args, "design");
|
|
1140
|
+
const designProducerAgent = strictString(args, "design-producer-agent");
|
|
1141
|
+
const designProducerSession = strictString(args, "design-producer-session");
|
|
1142
|
+
if (source.publicationPolicy &&
|
|
1143
|
+
(!designPath || !designProducerAgent || !designProducerSession)) {
|
|
1144
|
+
throw new CliError("A top-journal fork requires a target-specific approved policy plus --design, --design-producer-agent, and --design-producer-session.", { code: "RESEARCH_SCIENTIFIC_DESIGN_REAPPROVAL_REQUIRED", exitCode: 3 });
|
|
1145
|
+
}
|
|
1146
|
+
if (!source.publicationPolicy && (designPath || designProducerAgent || designProducerSession)) {
|
|
1147
|
+
throw new CliError("Scientific reapproval options require a top-journal source project.", {
|
|
1148
|
+
code: "RESEARCH_SCIENTIFIC_DESIGN_REAPPROVAL_INVALID",
|
|
1149
|
+
exitCode: 2,
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
const project = await forkProject(root, sourceProjectId, targetProjectId, resumeStage(strictString(args, "resume-through")), designPath && designProducerAgent && designProducerSession
|
|
1153
|
+
? {
|
|
1154
|
+
publicationPolicy: await loadApprovedResearchPolicy(root, targetProjectId),
|
|
1155
|
+
scientificDesign: {
|
|
1156
|
+
design: await readAndVerifyScientificDesign(designPath, targetProjectId),
|
|
1157
|
+
producerAgent: publicationAgent(designProducerAgent, "design producer"),
|
|
1158
|
+
producerSessionId: designProducerSession,
|
|
1159
|
+
},
|
|
1160
|
+
}
|
|
1161
|
+
: undefined);
|
|
925
1162
|
writeJson(io, project, args);
|
|
926
1163
|
return 0;
|
|
927
1164
|
}
|
|
928
1165
|
if (action === "addendum") {
|
|
929
|
-
const args = parseStrictArgs(rest, {
|
|
1166
|
+
const args = parseStrictArgs(rest, {
|
|
1167
|
+
...WORKSPACE_OPTIONS,
|
|
1168
|
+
to: "string",
|
|
1169
|
+
design: "string",
|
|
1170
|
+
"design-producer-agent": "string",
|
|
1171
|
+
"design-producer-session": "string",
|
|
1172
|
+
}, "research project addendum");
|
|
930
1173
|
if (strictBoolean(args, "help"))
|
|
931
1174
|
return writeHelp(io);
|
|
932
1175
|
const sourceProjectId = onePositional(args.positionals, "research project addendum");
|
|
@@ -938,7 +1181,30 @@ async function runProject(argv, io) {
|
|
|
938
1181
|
});
|
|
939
1182
|
}
|
|
940
1183
|
const root = await workspaceFromArgs(args);
|
|
941
|
-
const
|
|
1184
|
+
const source = await loadProject(root, sourceProjectId);
|
|
1185
|
+
const designPath = strictString(args, "design");
|
|
1186
|
+
const designProducerAgent = strictString(args, "design-producer-agent");
|
|
1187
|
+
const designProducerSession = strictString(args, "design-producer-session");
|
|
1188
|
+
if (source.publicationPolicy &&
|
|
1189
|
+
(!designPath || !designProducerAgent || !designProducerSession)) {
|
|
1190
|
+
throw new CliError("A top-journal addendum requires a target-specific approved policy plus --design, --design-producer-agent, and --design-producer-session.", { code: "RESEARCH_SCIENTIFIC_DESIGN_REAPPROVAL_REQUIRED", exitCode: 3 });
|
|
1191
|
+
}
|
|
1192
|
+
if (!source.publicationPolicy && (designPath || designProducerAgent || designProducerSession)) {
|
|
1193
|
+
throw new CliError("Scientific reapproval options require a top-journal source project.", {
|
|
1194
|
+
code: "RESEARCH_SCIENTIFIC_DESIGN_REAPPROVAL_INVALID",
|
|
1195
|
+
exitCode: 2,
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
const project = await createProjectAddendum(root, sourceProjectId, targetProjectId, designPath && designProducerAgent && designProducerSession
|
|
1199
|
+
? {
|
|
1200
|
+
publicationPolicy: await loadApprovedResearchPolicy(root, targetProjectId),
|
|
1201
|
+
scientificDesign: {
|
|
1202
|
+
design: await readAndVerifyScientificDesign(designPath, targetProjectId),
|
|
1203
|
+
producerAgent: publicationAgent(designProducerAgent, "design producer"),
|
|
1204
|
+
producerSessionId: designProducerSession,
|
|
1205
|
+
},
|
|
1206
|
+
}
|
|
1207
|
+
: undefined);
|
|
942
1208
|
writeJson(io, project, args);
|
|
943
1209
|
return 0;
|
|
944
1210
|
}
|
|
@@ -996,6 +1262,10 @@ async function runStatus(argv, io) {
|
|
|
996
1262
|
const nativeStage = await inspectNativeResearchStage(root, current);
|
|
997
1263
|
const snapshot = await inspectSnapshotForStatus(root, current.id);
|
|
998
1264
|
const readyPackage = nextReadyPackage(current)?.id ?? null;
|
|
1265
|
+
const scientificReview = await inspectScientificReviewStatus(root, current.id);
|
|
1266
|
+
const evidenceAccess = current.scientificDesign
|
|
1267
|
+
? await inspectEvidenceAccessForStatus(root, current.id)
|
|
1268
|
+
: null;
|
|
999
1269
|
const publication = current.publicationPolicy
|
|
1000
1270
|
? await inspectPublicationForStatus(root, current.id)
|
|
1001
1271
|
: null;
|
|
@@ -1009,9 +1279,11 @@ async function runStatus(argv, io) {
|
|
|
1009
1279
|
evidenceState: current.evidenceState,
|
|
1010
1280
|
snapshot,
|
|
1011
1281
|
nativeStage,
|
|
1282
|
+
scientificReview,
|
|
1283
|
+
evidenceAccess,
|
|
1012
1284
|
publication,
|
|
1013
1285
|
readyPackage,
|
|
1014
|
-
recommendedAction: projectRecommendedAction(root, current, readyPackage, nativeStage, publication),
|
|
1286
|
+
recommendedAction: projectRecommendedAction(root, current, readyPackage, nativeStage, scientificReview, publication),
|
|
1015
1287
|
usage: current.usage,
|
|
1016
1288
|
inputs: current.inputs,
|
|
1017
1289
|
packages: current.packages,
|
|
@@ -1022,6 +1294,17 @@ async function runStatus(argv, io) {
|
|
|
1022
1294
|
writeJson(io, result, args);
|
|
1023
1295
|
return 0;
|
|
1024
1296
|
}
|
|
1297
|
+
async function inspectEvidenceAccessForStatus(root, projectId) {
|
|
1298
|
+
try {
|
|
1299
|
+
return await inspectEvidenceAccessStatus(root, projectId);
|
|
1300
|
+
}
|
|
1301
|
+
catch (error) {
|
|
1302
|
+
return {
|
|
1303
|
+
status: "invalid",
|
|
1304
|
+
code: error instanceof CliError ? error.code : "RESEARCH_EVIDENCE_ACCESS_PLAN_INVALID",
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1025
1308
|
function projectAuthority(project, projects) {
|
|
1026
1309
|
const byId = new Map(projects.map((candidate) => [candidate.id, candidate]));
|
|
1027
1310
|
const visited = new Set([project.id]);
|
|
@@ -1079,7 +1362,7 @@ async function inspectPublicationForStatus(root, projectId) {
|
|
|
1079
1362
|
};
|
|
1080
1363
|
}
|
|
1081
1364
|
}
|
|
1082
|
-
function projectRecommendedAction(root, project, readyPackage, nativeStage, publication) {
|
|
1365
|
+
function projectRecommendedAction(root, project, readyPackage, nativeStage, scientificReview, publication) {
|
|
1083
1366
|
if (project.lineage.supersededBy) {
|
|
1084
1367
|
return `Continue with superseding project ${project.lineage.supersededBy}.`;
|
|
1085
1368
|
}
|
|
@@ -1087,7 +1370,12 @@ function projectRecommendedAction(root, project, readyPackage, nativeStage, publ
|
|
|
1087
1370
|
return `Project is ${project.status}; inspect with research status --all and continue only from an authoritative project.`;
|
|
1088
1371
|
}
|
|
1089
1372
|
if (project.handoff.state === "user-action-required") {
|
|
1090
|
-
|
|
1373
|
+
const resources = project.handoff.accessRequests.map((request) => request.resourceName);
|
|
1374
|
+
const detail = resources.length ? ` Required resources: ${resources.join(", ")}.` : "";
|
|
1375
|
+
const stop = project.handoff.kind === "evidence-exhausted"
|
|
1376
|
+
? " Do not continue substitute searching; the plan-bound agent routes are frozen in the handoff."
|
|
1377
|
+
: "";
|
|
1378
|
+
return `User action required: ${project.handoff.summary ?? "review the requested action"}${detail}${stop} Resolve only after completion: tiangong-ai research project handoff resolve ${project.id} --note <resolution-note> --workspace ${root}`;
|
|
1091
1379
|
}
|
|
1092
1380
|
if (project.handoff.state === "external-response-required") {
|
|
1093
1381
|
return `Waiting for an external response: ${project.handoff.summary ?? "external evidence is pending"} Do not continue substitute searching; resolve after the response is registered.`;
|
|
@@ -1098,6 +1386,14 @@ function projectRecommendedAction(root, project, readyPackage, nativeStage, publ
|
|
|
1098
1386
|
if (nativeStage.status === "active") {
|
|
1099
1387
|
return nativeStage.recommendedAction ?? "Resume the active native stage.";
|
|
1100
1388
|
}
|
|
1389
|
+
if (scientificReview.nextGate) {
|
|
1390
|
+
const gate = scientificReview.nextGate;
|
|
1391
|
+
if (gate.status === "stopped") {
|
|
1392
|
+
return `Scientific ${gate.role} review stopped the project; inspect the frozen review and request user or external action instead of continuing.`;
|
|
1393
|
+
}
|
|
1394
|
+
const schema = `scientific-assessment-${gate.role}`;
|
|
1395
|
+
return `Use the native producer App to create a bounded ${gate.role} assessment from schema ${schema}, then prepare an independent review: tiangong-ai research project scientific review prepare ${project.id} --role ${gate.role} --assessment <absolute-json> --reviewer-agent <codex|claude> --reviewer-session <fresh-opaque-id> --workspace ${root}`;
|
|
1396
|
+
}
|
|
1101
1397
|
if (project.status === "complete") {
|
|
1102
1398
|
if (project.publicationPolicy) {
|
|
1103
1399
|
if (publication && "code" in publication) {
|
|
@@ -1349,6 +1645,15 @@ function publicationReviewRole(value) {
|
|
|
1349
1645
|
}
|
|
1350
1646
|
throw new CliError("--role must be evidence, methods-reproducibility, domain-novelty, or journal-editor.", { code: "RESEARCH_PUBLICATION_REVIEW_ROLE_INVALID", exitCode: 2 });
|
|
1351
1647
|
}
|
|
1648
|
+
function scientificReviewRole(value) {
|
|
1649
|
+
if (value === "research-design" || value === "evidence-construct" || value === "pilot-methods") {
|
|
1650
|
+
return value;
|
|
1651
|
+
}
|
|
1652
|
+
throw new CliError("--role must be research-design, evidence-construct, or pilot-methods.", {
|
|
1653
|
+
code: "RESEARCH_SCIENTIFIC_REVIEW_ROLE_INVALID",
|
|
1654
|
+
exitCode: 2,
|
|
1655
|
+
});
|
|
1656
|
+
}
|
|
1352
1657
|
function publicationAgent(value, label) {
|
|
1353
1658
|
if (value === "codex" || value === "claude")
|
|
1354
1659
|
return value;
|