@citeark/agent 0.3.20

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 (347) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +128 -0
  3. package/data/dataset-source-registry.v1.json +300 -0
  4. package/dist/arkgraph/boot.js +6 -0
  5. package/dist/arkgraph/index.html +1 -0
  6. package/dist/arkgraph/viewer.css +1 -0
  7. package/dist/arkgraph/viewer.en.css +1 -0
  8. package/dist/arkgraph/viewer.en.js +49 -0
  9. package/dist/arkgraph/viewer.en.js.LEGAL.txt +56 -0
  10. package/dist/arkgraph/viewer.js +49 -0
  11. package/dist/arkgraph/viewer.js.LEGAL.txt +56 -0
  12. package/docker/claude-code/Dockerfile +97 -0
  13. package/docker/claude-code/codex-pro-relay.mjs +466 -0
  14. package/docker/claude-code/runtime-contract-check.mjs +79 -0
  15. package/docs/arkgraph-reading.md +79 -0
  16. package/docs/configuration.md +100 -0
  17. package/docs/integration.md +92 -0
  18. package/docs/maturity-plan.md +27 -0
  19. package/docs/npm-release.md +44 -0
  20. package/docs/paper-reading.md +40 -0
  21. package/docs/research-plan-granularity.md +27 -0
  22. package/docs/terminal.md +49 -0
  23. package/examples/toy-evaluation/compile-task.json +27 -0
  24. package/examples/toy-evaluation/paper.md +5 -0
  25. package/examples/toy-evaluation/repository/README.md +9 -0
  26. package/examples/toy-evaluation/repository/checkpoint.json +4 -0
  27. package/examples/toy-evaluation/repository/evaluate.py +17 -0
  28. package/examples/toy-evaluation/task.json +81 -0
  29. package/package.json +59 -0
  30. package/prompts/compile-research.md +58 -0
  31. package/prompts/execute-contract.md +72 -0
  32. package/prompts/execute-workspace-simple.md +51 -0
  33. package/prompts/execute-workspace.md +34 -0
  34. package/prompts/prepare-reproduction.md +82 -0
  35. package/prompts/repair-research.md +45 -0
  36. package/protocol/CAP.md +129 -0
  37. package/protocol/LICENSE +12 -0
  38. package/protocol/MAPPINGS.md +72 -0
  39. package/protocol/README.md +38 -0
  40. package/protocol/conformance-v2.0-alpha.1.json +36 -0
  41. package/protocol/examples/arkgraph/checkpoint-evaluation.json +309 -0
  42. package/protocol/examples/arkgraph/fixtures.mjs +49 -0
  43. package/protocol/examples/arkgraph/paper-free.json +291 -0
  44. package/protocol/examples/arkgraph/partial-failure.json +344 -0
  45. package/protocol/examples/arkgraph/training-evaluation.json +443 -0
  46. package/protocol/profiles/agent-trace.md +16 -0
  47. package/protocol/profiles/computational-run.md +16 -0
  48. package/protocol/profiles/core.md +15 -0
  49. package/protocol/profiles/public-bundle.md +18 -0
  50. package/protocol/profiles/reproduction.md +29 -0
  51. package/protocol/profiles/research-compilation.md +44 -0
  52. package/protocol/profiles/research-plan.md +39 -0
  53. package/protocol/profiles/restricted-evidence.md +15 -0
  54. package/runtime/bootstrap-autodl-runtime.sh +314 -0
  55. package/runtime/create-runtime-venv.sh +41 -0
  56. package/runtime/install-local-cpu-runtime.sh +23 -0
  57. package/runtime/install-scientific-runtime.sh +153 -0
  58. package/runtime/mineru/parse.py +62 -0
  59. package/runtime/mineru/requirements.txt +4 -0
  60. package/runtime/requirements-baseline.txt +38 -0
  61. package/schemas/cap/v2/activity.schema.json +47 -0
  62. package/schemas/cap/v2/agent.schema.json +32 -0
  63. package/schemas/cap/v2/assertion.schema.json +110 -0
  64. package/schemas/cap/v2/descriptor.schema.json +243 -0
  65. package/schemas/cap/v2/entity.schema.json +64 -0
  66. package/schemas/cap/v2/manifest.schema.json +67 -0
  67. package/schemas/cap/v2/relation.schema.json +82 -0
  68. package/schemas/compute-catalog.schema.json +63 -0
  69. package/schemas/compute-decision.schema.json +27 -0
  70. package/schemas/execution-contract.schema.json +1024 -0
  71. package/schemas/research-card.schema.json +30 -0
  72. package/schemas/research-inventory-draft.schema.json +366 -0
  73. package/schemas/research.schema.json +1044 -0
  74. package/schemas/result.schema.json +173 -0
  75. package/schemas/verification-policy.schema.json +47 -0
  76. package/schemas/verified-conclusion.schema.json +58 -0
  77. package/schemas/workspace-summary.schema.json +24 -0
  78. package/scripts/build-arkgraph-view.mjs +12 -0
  79. package/scripts/check-execution-feasibility.mjs +24 -0
  80. package/scripts/check-syntax.mjs +15 -0
  81. package/scripts/deterministic-asset-preparation.py +438 -0
  82. package/scripts/package-cap.mjs +23 -0
  83. package/scripts/package-local-agent.mjs +23 -0
  84. package/scripts/preview-arkgraph.mjs +25 -0
  85. package/scripts/replay-research-compiler-candidate.mjs +134 -0
  86. package/scripts/review-compiler-sources.mjs +44 -0
  87. package/scripts/run-asset-preparation.sh +17 -0
  88. package/scripts/run-research-plan.mjs +98 -0
  89. package/scripts/validate-asset-preparation.py +290 -0
  90. package/scripts/verify-local-runtime.mjs +57 -0
  91. package/scripts/verify-npm-package.mjs +57 -0
  92. package/src/adapters/paper2agent.mjs +107 -0
  93. package/src/assets/cache.mjs +159 -0
  94. package/src/assets/compute.mjs +98 -0
  95. package/src/assets/executor.mjs +145 -0
  96. package/src/assets/lifecycle.mjs +213 -0
  97. package/src/assets/manifest.mjs +242 -0
  98. package/src/assets/opportunistic-preparation.mjs +81 -0
  99. package/src/assets/plan.mjs +411 -0
  100. package/src/assets/prompts.mjs +29 -0
  101. package/src/assets/public-asset-probe.mjs +525 -0
  102. package/src/assets/qualification.mjs +119 -0
  103. package/src/assets/readiness.mjs +130 -0
  104. package/src/assets/reproduction-admission.mjs +355 -0
  105. package/src/assets/requirements.mjs +152 -0
  106. package/src/assets/source-grounding.mjs +341 -0
  107. package/src/assets/source-policy.mjs +118 -0
  108. package/src/autodl/client.mjs +260 -0
  109. package/src/autodl/ssh.mjs +380 -0
  110. package/src/autodl/tools.mjs +129 -0
  111. package/src/cap/redaction.mjs +38 -0
  112. package/src/cap/v2/archive.mjs +152 -0
  113. package/src/cap/v2/attestation.mjs +204 -0
  114. package/src/cap/v2/canonical-json.mjs +114 -0
  115. package/src/cap/v2/compilation-artifact.mjs +240 -0
  116. package/src/cap/v2/core.mjs +282 -0
  117. package/src/cap/v2/measurement-assessment-records.mjs +23 -0
  118. package/src/cap/v2/pipeline-artifact.mjs +922 -0
  119. package/src/cap/v2/read.mjs +41 -0
  120. package/src/cap/v2/reassessment-artifact.mjs +383 -0
  121. package/src/cap/v2/research-artifact.mjs +231 -0
  122. package/src/cap/v2/research-map-records.mjs +46 -0
  123. package/src/cap/v2/research-object-records.mjs +163 -0
  124. package/src/cap/v2/research-records.mjs +187 -0
  125. package/src/cap/v2/verify.mjs +642 -0
  126. package/src/cli.mjs +1146 -0
  127. package/src/compute/autodl-pro-compiler.mjs +347 -0
  128. package/src/compute/autodl-pro-executor.mjs +459 -0
  129. package/src/compute/autodl-pro-job.mjs +843 -0
  130. package/src/compute/autodl-pro-network.mjs +295 -0
  131. package/src/compute/autodl-pro-remote.mjs +810 -0
  132. package/src/compute/autodl-pro-staging.mjs +117 -0
  133. package/src/compute/campaign.mjs +110 -0
  134. package/src/compute/catalog.mjs +123 -0
  135. package/src/compute/checkpoint-protocol.mjs +154 -0
  136. package/src/compute/codex-account-lock.mjs +111 -0
  137. package/src/compute/codex-account-session.mjs +107 -0
  138. package/src/compute/compiler-profile.mjs +38 -0
  139. package/src/compute/compiler-router.mjs +23 -0
  140. package/src/compute/coordinator-recovery.mjs +210 -0
  141. package/src/compute/executor-router.mjs +29 -0
  142. package/src/compute/gcp-batch-compiler.mjs +685 -0
  143. package/src/compute/gcp-batch-executor.mjs +1215 -0
  144. package/src/compute/gcp-batch-failure.mjs +92 -0
  145. package/src/compute/gcp-batch-job.mjs +527 -0
  146. package/src/compute/gcp-batch-lifecycle.mjs +81 -0
  147. package/src/compute/gcp-checkpoint-worker.mjs +1633 -0
  148. package/src/compute/local-codex-compiler.mjs +52 -0
  149. package/src/compute/measurement-hardware.mjs +128 -0
  150. package/src/compute/remote-attempt.mjs +226 -0
  151. package/src/compute/requirements.mjs +124 -0
  152. package/src/compute/research-phases.mjs +48 -0
  153. package/src/compute/scheduler.mjs +452 -0
  154. package/src/compute/shared-workloads.mjs +26 -0
  155. package/src/compute/stage-archive.mjs +79 -0
  156. package/src/contracts/campaign-contract.mjs +52 -0
  157. package/src/contracts/execution-contract.mjs +819 -0
  158. package/src/contracts/execution-mode.mjs +19 -0
  159. package/src/contracts/execution-timeouts.mjs +45 -0
  160. package/src/contracts/execution-workload.mjs +68 -0
  161. package/src/contracts/preflight-schema.mjs +25 -0
  162. package/src/contracts/public-contract.mjs +63 -0
  163. package/src/contracts/subject-tags.mjs +31 -0
  164. package/src/dashboard/data.mjs +898 -0
  165. package/src/dashboard/server.mjs +79 -0
  166. package/src/dashboard/static/dashboard.css +366 -0
  167. package/src/dashboard/static/dashboard.js +560 -0
  168. package/src/dashboard/static/index.html +85 -0
  169. package/src/deployment/community-policy.mjs +9 -0
  170. package/src/deployment/environment.mjs +112 -0
  171. package/src/deployment/guided.mjs +98 -0
  172. package/src/deployment/handoff.mjs +102 -0
  173. package/src/deployment/local-contract.mjs +31 -0
  174. package/src/deployment/local.mjs +100 -0
  175. package/src/deployment/prepare.mjs +46 -0
  176. package/src/deployment/recipe.mjs +108 -0
  177. package/src/deployment/supplement.mjs +51 -0
  178. package/src/deployment/terminal.mjs +43 -0
  179. package/src/diagnosis/renderer.mjs +75 -0
  180. package/src/diagnosis/target-failure.mjs +46 -0
  181. package/src/evidence/parser-registry.mjs +54 -0
  182. package/src/evidence/parsers/fasttext-classification.mjs +82 -0
  183. package/src/evidence/parsers/json-scalar.mjs +96 -0
  184. package/src/evidence/parsers/simcse-senteval.mjs +104 -0
  185. package/src/evidence/parsers/starspace-classification.mjs +78 -0
  186. package/src/evidence/registry.mjs +147 -0
  187. package/src/execution/runner-audit.mjs +473 -0
  188. package/src/gcp/auth.mjs +106 -0
  189. package/src/gcp/batch-client.mjs +120 -0
  190. package/src/gcp/resource-discovery.mjs +177 -0
  191. package/src/gcp/rest.mjs +82 -0
  192. package/src/gcp/secret-manager.mjs +34 -0
  193. package/src/gcp/signed-url.mjs +133 -0
  194. package/src/gcp/storage.mjs +220 -0
  195. package/src/graph/command.mjs +41 -0
  196. package/src/graph/execution.mjs +97 -0
  197. package/src/graph/model.mjs +37 -0
  198. package/src/graph/presentation.mjs +110 -0
  199. package/src/graph/query.mjs +159 -0
  200. package/src/graph/research-relations.mjs +69 -0
  201. package/src/graph/source-page.mjs +12 -0
  202. package/src/graph/source-preview.mjs +34 -0
  203. package/src/graph/validate.mjs +76 -0
  204. package/src/job.mjs +496 -0
  205. package/src/network/autodl-routing-proxy.mjs +462 -0
  206. package/src/network/egress-proxy.mjs +158 -0
  207. package/src/observability/event-contract.mjs +230 -0
  208. package/src/observability/pipeline-monitor.mjs +166 -0
  209. package/src/pipeline/orchestrator.mjs +1281 -0
  210. package/src/pipeline/recovery-error.mjs +11 -0
  211. package/src/pipeline/replay.mjs +304 -0
  212. package/src/pipeline/shared-execution.mjs +115 -0
  213. package/src/pipeline/stage-checkpoint.mjs +86 -0
  214. package/src/pipeline/stage-recovery.mjs +101 -0
  215. package/src/pipeline/targets.mjs +110 -0
  216. package/src/process.mjs +143 -0
  217. package/src/protocol.mjs +312 -0
  218. package/src/provider/codex-account.mjs +44 -0
  219. package/src/provider/codex-completion.mjs +49 -0
  220. package/src/provider/completion.mjs +292 -0
  221. package/src/provider/model-client.mjs +44 -0
  222. package/src/provider/model-route.mjs +29 -0
  223. package/src/provider/openrouter-readiness.mjs +189 -0
  224. package/src/provider/reader-bridge.mjs +35 -0
  225. package/src/provider/relay.mjs +263 -0
  226. package/src/provider/runtime-auth.mjs +40 -0
  227. package/src/public/cap.d.mts +90 -0
  228. package/src/public/cap.mjs +12 -0
  229. package/src/public/contracts.d.mts +2 -0
  230. package/src/public/host.mjs +171 -0
  231. package/src/public/operations.d.mts +11 -0
  232. package/src/public/presentation.d.mts +4 -0
  233. package/src/records/views.mjs +26 -0
  234. package/src/remote/command.mjs +178 -0
  235. package/src/remote/ssh.mjs +59 -0
  236. package/src/repository-origin.mjs +81 -0
  237. package/src/reproduction/evidence-feedback.mjs +96 -0
  238. package/src/reproduction/incomplete-initialization.mjs +25 -0
  239. package/src/reproduction/lifecycle.mjs +253 -0
  240. package/src/reproduction/plan.mjs +132 -0
  241. package/src/reproduction/prompts.mjs +70 -0
  242. package/src/reproduction/runner.mjs +188 -0
  243. package/src/reproduction/summary.mjs +130 -0
  244. package/src/reproduction/workspace-mode.mjs +7 -0
  245. package/src/research/automatic-admission.mjs +156 -0
  246. package/src/research/compiler-coverage.mjs +85 -0
  247. package/src/research/compiler-failure.mjs +24 -0
  248. package/src/research/compiler-normalization-guards.mjs +112 -0
  249. package/src/research/compiler-repair.mjs +3 -0
  250. package/src/research/compiler.mjs +853 -0
  251. package/src/research/continuation-selection.mjs +26 -0
  252. package/src/research/execution-graph-context.mjs +43 -0
  253. package/src/research/experiment-importance.mjs +15 -0
  254. package/src/research/inventory-handoff.mjs +104 -0
  255. package/src/research/inventory-revisions.mjs +32 -0
  256. package/src/research/mineru-local.mjs +73 -0
  257. package/src/research/paper-command.mjs +19 -0
  258. package/src/research/paper-markdown.mjs +180 -0
  259. package/src/research/paper-source-map.mjs +69 -0
  260. package/src/research/planning-policy.mjs +88 -0
  261. package/src/research/reference-materials.mjs +11 -0
  262. package/src/research/reproduction-scope.mjs +30 -0
  263. package/src/research/research-map.mjs +94 -0
  264. package/src/research/research-objects.mjs +88 -0
  265. package/src/research/source-discovery.mjs +646 -0
  266. package/src/research/source-observations.mjs +75 -0
  267. package/src/research/source-review-cli-mcp.mjs +26 -0
  268. package/src/research/source-review-input.mjs +209 -0
  269. package/src/research/source-review-local-codex.mjs +36 -0
  270. package/src/research/source-review-model.mjs +70 -0
  271. package/src/research/source-review.mjs +173 -0
  272. package/src/research/structure.mjs +3163 -0
  273. package/src/research-card/renderer.mjs +277 -0
  274. package/src/research-card/verified-conclusion.mjs +143 -0
  275. package/src/results/output-registry.mjs +183 -0
  276. package/src/runtime/claude-code.mjs +52 -0
  277. package/src/runtime/codex-capacity-retry.mjs +87 -0
  278. package/src/runtime/codex.mjs +64 -0
  279. package/src/runtime/config.mjs +157 -0
  280. package/src/runtime/final-output.mjs +40 -0
  281. package/src/runtime/index.mjs +21 -0
  282. package/src/runtime/local-codex.mjs +74 -0
  283. package/src/runtime/opencode.mjs +95 -0
  284. package/src/runtime/prompt.mjs +13 -0
  285. package/src/sandbox/docker.mjs +363 -0
  286. package/src/settings/command.mjs +297 -0
  287. package/src/settings/store.mjs +119 -0
  288. package/src/telemetry/pricing.mjs +68 -0
  289. package/src/telemetry/usage.mjs +265 -0
  290. package/src/terminal/events.mjs +97 -0
  291. package/src/terminal/input.mjs +40 -0
  292. package/src/terminal/plain.mjs +40 -0
  293. package/src/terminal/remote-stream.mjs +22 -0
  294. package/src/terminal/screen.mjs +214 -0
  295. package/src/terminal/transcript.mjs +69 -0
  296. package/src/util.mjs +107 -0
  297. package/src/verification/ai-assessor.mjs +534 -0
  298. package/src/verification/claim-evaluator.mjs +242 -0
  299. package/src/verification/evidence-context.mjs +165 -0
  300. package/src/verification/evidence-reader.mjs +95 -0
  301. package/src/verification/integrity.mjs +570 -0
  302. package/src/verification/tolerance.mjs +32 -0
  303. package/src/workloads/cpu-research-preparation.mjs +56 -0
  304. package/src/workloads/definition.mjs +74 -0
  305. package/src/workloads/phase-aware-reproduction.mjs +46 -0
  306. package/src/workloads/reproduction.mjs +85 -0
  307. package/src/workspace/command.mjs +242 -0
  308. package/src/workspace/control.mjs +49 -0
  309. package/src/workspace/entry.mjs +28 -0
  310. package/src/workspace/input.mjs +93 -0
  311. package/src/workspace/interactive.mjs +94 -0
  312. package/src/workspace/jobs.mjs +418 -0
  313. package/src/workspace/session.mjs +97 -0
  314. package/src/workspace/worker.mjs +137 -0
  315. package/ui/arkgraph/ambient-motion.mjs +10 -0
  316. package/ui/arkgraph/app.jsx +153 -0
  317. package/ui/arkgraph/boot.js +6 -0
  318. package/ui/arkgraph/camera-motion.mjs +20 -0
  319. package/ui/arkgraph/context-reveal.mjs +39 -0
  320. package/ui/arkgraph/details.css +3 -0
  321. package/ui/arkgraph/entry.jsx +28 -0
  322. package/ui/arkgraph/experiment-curves.mjs +17 -0
  323. package/ui/arkgraph/experiment-selection.mjs +15 -0
  324. package/ui/arkgraph/experiment-style.css +26 -0
  325. package/ui/arkgraph/experiment-ui.jsx +32 -0
  326. package/ui/arkgraph/frame.html +1 -0
  327. package/ui/arkgraph/graph-gestures.mjs +62 -0
  328. package/ui/arkgraph/label-layout.mjs +57 -0
  329. package/ui/arkgraph/locales/en.json +229 -0
  330. package/ui/arkgraph/locales/source-types.json +15 -0
  331. package/ui/arkgraph/localization-build.mjs +27 -0
  332. package/ui/arkgraph/material-build.mjs +23 -0
  333. package/ui/arkgraph/material-colors.mjs +39 -0
  334. package/ui/arkgraph/material-style.css +15 -0
  335. package/ui/arkgraph/open-graph.jsx +326 -0
  336. package/ui/arkgraph/outline.jsx +49 -0
  337. package/ui/arkgraph/package-lock.json +888 -0
  338. package/ui/arkgraph/package.json +17 -0
  339. package/ui/arkgraph/reading-layout.mjs +130 -0
  340. package/ui/arkgraph/reading-presentation.mjs +73 -0
  341. package/ui/arkgraph/record-detail.css +51 -0
  342. package/ui/arkgraph/record-details.jsx +29 -0
  343. package/ui/arkgraph/research-types.mjs +31 -0
  344. package/ui/arkgraph/selection-mark.jsx +6 -0
  345. package/ui/arkgraph/soft-spine.mjs +26 -0
  346. package/ui/arkgraph/steering-style.css +187 -0
  347. package/ui/arkgraph/style.css +272 -0
package/src/job.mjs ADDED
@@ -0,0 +1,496 @@
1
+ import { appendFile } from "node:fs/promises";
2
+ import { DELIVERY_INSTRUCTIONS } from "./deployment/handoff.mjs";
3
+ import { hasResearchWorkspace, usesWorkspaceSummary } from "./reproduction/workspace-mode.mjs";
4
+ import { createHash } from "node:crypto";
5
+ import { fileURLToPath } from "node:url";
6
+ import {
7
+ cp,
8
+ lstat,
9
+ mkdir,
10
+ readFile,
11
+ realpath,
12
+ readdir,
13
+ readlink,
14
+ writeFile,
15
+ } from "node:fs/promises";
16
+ import path from "node:path";
17
+
18
+ import { listEvidenceParsers } from "./evidence/registry.mjs";
19
+ import { initializeResearchPlan, stageResearchPlanTools } from "./reproduction/plan.mjs";
20
+ import { captureProcess } from "./process.mjs";
21
+ import {
22
+ isCiteArkReconstructionRepository,
23
+ prepareReconstructionRepository,
24
+ } from "./repository-origin.mjs";
25
+ import {
26
+ CiteArkError,
27
+ createRunId,
28
+ createSessionId,
29
+ pathExists,
30
+ sha256File,
31
+ sha256Value,
32
+ writeJson,
33
+ } from "./util.mjs";
34
+
35
+ const SOURCE_ROOT = path.dirname(fileURLToPath(import.meta.url));
36
+ const PACKAGE_ROOT = path.resolve(SOURCE_ROOT, "..");
37
+ const SNAPSHOT_EXCLUDED_DIRECTORIES = new Set([
38
+ ".git",
39
+ ".cache",
40
+ ".mypy_cache",
41
+ ".pytest_cache",
42
+ ".venv",
43
+ "__pycache__",
44
+ "node_modules",
45
+ ]);
46
+
47
+ export async function prepareRunBundle({
48
+ task,
49
+ taskDirectory,
50
+ runsDirectory,
51
+ runId = createRunId(),
52
+ imageOverride,
53
+ repositoryOverride,
54
+ paperOverride,
55
+ }) {
56
+ const runDirectory = path.resolve(runsDirectory, runId);
57
+ if (await pathExists(runDirectory)) {
58
+ throw new CiteArkError(`运行目录已经存在:${runDirectory}`);
59
+ }
60
+
61
+ const directories = {
62
+ run: runDirectory,
63
+ input: path.join(runDirectory, "input"),
64
+ workspace: path.join(runDirectory, "workspace"),
65
+ repository: path.join(runDirectory, "workspace", "repository"),
66
+ output: path.join(runDirectory, "output"),
67
+ runtimeHome: path.join(runDirectory, "runtime-home"),
68
+ execution: path.join(runDirectory, "execution"),
69
+ };
70
+ await Promise.all(
71
+ Object.values(directories)
72
+ .filter(
73
+ (directory) =>
74
+ directory !== directories.run && directory !== directories.repository,
75
+ )
76
+ .map((directory) => mkdir(directory, { recursive: true })),
77
+ );
78
+ // Codex refuses to start when CODEX_HOME points at a path that has not been
79
+ // created yet. Keep every runtime's mutable state inside the mounted,
80
+ // per-run home so retries can resume without touching the host user profile.
81
+ await mkdir(path.join(directories.runtimeHome, "codex"), { recursive: true });
82
+
83
+ const runtimeTask = structuredClone(task);
84
+ if (imageOverride) runtimeTask.environment.image = imageOverride;
85
+ if (paperOverride?.path) runtimeTask.paper.path = path.resolve(paperOverride.path);
86
+ if (paperOverride?.preparedReading) runtimeTask.paper.preparedReading = paperOverride.preparedReading;
87
+
88
+ await writeJson(path.join(directories.input, "submitted-task.json"), task);
89
+ if (paperOverride?.digest) {
90
+ if (!(await pathExists(runtimeTask.paper.path))) {
91
+ throw new CiteArkError(`流水线论文快照不存在:${runtimeTask.paper.path}`);
92
+ }
93
+ const observedPaperDigest = `sha256:${await sha256File(runtimeTask.paper.path)}`;
94
+ if (observedPaperDigest !== paperOverride.digest) {
95
+ throw new CiteArkError(
96
+ `流水线论文快照摘要不一致:expected=${paperOverride.digest}, observed=${observedPaperDigest}`,
97
+ );
98
+ }
99
+ }
100
+ await copyPaper(runtimeTask, taskDirectory, directories.input);
101
+ await copyAssets(runtimeTask, taskDirectory, directories.input);
102
+ const contractRepository = structuredClone(runtimeTask.repository);
103
+ const repositoryTask = repositoryOverride
104
+ ? {
105
+ ...runtimeTask,
106
+ repository: { path: path.resolve(repositoryOverride.path) },
107
+ }
108
+ : runtimeTask;
109
+ let repositoryProvenance = await prepareRepository(
110
+ repositoryTask,
111
+ taskDirectory,
112
+ directories.repository,
113
+ );
114
+ if (repositoryOverride) {
115
+ const copiedSnapshot = await snapshotDirectory(directories.repository);
116
+ const copiedDigest = snapshotDigest(copiedSnapshot);
117
+ if (
118
+ repositoryOverride.digest &&
119
+ repositoryOverride.digest !== copiedDigest
120
+ ) {
121
+ throw new CiteArkError(
122
+ `流水线仓库快照摘要不一致:expected=${repositoryOverride.digest}, observed=${copiedDigest}`,
123
+ );
124
+ }
125
+ repositoryProvenance = {
126
+ sourceType: "pipeline-snapshot",
127
+ contractUrl: contractRepository.url,
128
+ commit: contractRepository.commit,
129
+ dirty: false,
130
+ snapshotDigest: copiedDigest,
131
+ };
132
+ }
133
+
134
+ runtimeTask.run = {
135
+ id: runId,
136
+ repositoryPath: "/job/workspace/repository",
137
+ outputPath: "/job/output",
138
+ };
139
+ runtimeTask.repository.path = "/job/workspace/repository";
140
+ delete runtimeTask.repository.url;
141
+
142
+ await writeJson(path.join(directories.input, "task.json"), runtimeTask);
143
+ await initializeResearchPlan(runtimeTask, directories.output);
144
+ if (hasResearchWorkspace(runtimeTask)) {
145
+ await stageResearchPlanTools(directories.input);
146
+ }
147
+ await cp(
148
+ path.join(PACKAGE_ROOT, "schemas", usesWorkspaceSummary(runtimeTask) ? "workspace-summary.schema.json" : "result.schema.json"),
149
+ path.join(directories.input, "result.schema.json"),
150
+ );
151
+ await cp(
152
+ path.join(PACKAGE_ROOT, "prompts", usesWorkspaceSummary(runtimeTask) ? "execute-workspace-simple.md" : hasResearchWorkspace(runtimeTask) ? "execute-workspace.md" : "execute-contract.md"),
153
+ path.join(directories.input, "agent-instructions.md"),
154
+ );
155
+ await cp(
156
+ path.join(PACKAGE_ROOT, "data", "dataset-source-registry.v1.json"),
157
+ path.join(directories.input, "dataset-source-registry.json"),
158
+ );
159
+ await writeJson(
160
+ path.join(directories.input, "parser-catalog.json"),
161
+ listEvidenceParsers(),
162
+ );
163
+
164
+ await appendFile(path.join(directories.input, "agent-instructions.md"), DELIVERY_INSTRUCTIONS);
165
+ const beforeSnapshot = await snapshotDirectory(directories.repository);
166
+ await writeJson(
167
+ path.join(directories.execution, "workspace-before.json"),
168
+ beforeSnapshot,
169
+ );
170
+
171
+ const sessionId = createSessionId();
172
+ const state = {
173
+ schemaVersion: "0.1",
174
+ runId,
175
+ sessionId,
176
+ status: "prepared",
177
+ createdAt: new Date().toISOString(),
178
+ updatedAt: new Date().toISOString(),
179
+ taskName: task.name,
180
+ runtime: task.agent.runtime,
181
+ sandbox: "docker",
182
+ image: runtimeTask.environment.image,
183
+ repository: repositoryProvenance,
184
+ };
185
+ await writeJson(path.join(directories.run, "run.json"), state);
186
+
187
+ return {
188
+ runId,
189
+ sessionId,
190
+ task,
191
+ runtimeTask,
192
+ directories,
193
+ state,
194
+ beforeSnapshot,
195
+ repositoryProvenance,
196
+ };
197
+ }
198
+
199
+ export async function copyPaper(runtimeTask, taskDirectory, inputDirectory) {
200
+ if (runtimeTask.paper.path) {
201
+ const source = path.resolve(taskDirectory, runtimeTask.paper.path);
202
+ if (!(await pathExists(source))) {
203
+ throw new CiteArkError(`论文文件不存在:${source}`);
204
+ }
205
+ const paperDirectory = path.join(inputDirectory, "paper");
206
+ await mkdir(paperDirectory, { recursive: true });
207
+ const destination = path.join(paperDirectory, path.basename(source));
208
+ await cp(source, destination, { recursive: true, verbatimSymlinks: true });
209
+ runtimeTask.paper.path = `/job/input/paper/${path.basename(source)}`;
210
+ const reading = runtimeTask.paper.preparedReading;
211
+ if (reading?.status === "ready") {
212
+ if (createHash("sha256").update(await readFile(source)).digest("hex") !== reading.sourceDigest) throw new CiteArkError("论文阅读副本与原 PDF 身份不一致");
213
+ for (const file of reading.files) {
214
+ if (typeof file.path !== "string" || file.path.startsWith("/") || file.path.includes("\\") || file.path.split("/").some((part) => !part || part === "." || part === "..") || (!["paper.md", "source-map.json"].includes(file.path) && !file.path.startsWith("images/"))) throw new CiteArkError("论文阅读副本路径无效");
215
+ const content = await readFile(path.join(reading.directory, file.path));
216
+ if (content.length !== file.size || createHash("sha256").update(content).digest("hex") !== file.digest) throw new CiteArkError("论文阅读副本摘要不一致");
217
+ const target = path.join(inputDirectory, "paper-reading", file.path);
218
+ await mkdir(path.dirname(target), { recursive: true });
219
+ await writeFile(target, content);
220
+ }
221
+ runtimeTask.paper.markdownPath = "/job/input/paper-reading/paper.md";
222
+ runtimeTask.paper.sourceMapPath = "/job/input/paper-reading/source-map.json";
223
+ delete runtimeTask.paper.preparedReading;
224
+ }
225
+ }
226
+ }
227
+
228
+ export async function copyAssets(runtimeTask, taskDirectory, inputDirectory) {
229
+ const assetsDirectory = path.join(inputDirectory, "assets");
230
+ const copiedAssets = [];
231
+ for (const asset of runtimeTask.assets) {
232
+ const source = path.resolve(taskDirectory, asset.path);
233
+ if (!(await pathExists(source))) {
234
+ throw new CiteArkError(`任务资产不存在:${source}`);
235
+ }
236
+ const name = asset.name ?? path.basename(source);
237
+ if (name.includes("/") || name.includes("\\") || name === "." || name === "..") {
238
+ throw new CiteArkError(`资产 name 只能是单个文件名:${name}`);
239
+ }
240
+ await mkdir(assetsDirectory, { recursive: true });
241
+ await cp(source, path.join(assetsDirectory, name), {
242
+ recursive: true,
243
+ verbatimSymlinks: true,
244
+ });
245
+ copiedAssets.push({
246
+ ...asset,
247
+ path: `/job/input/assets/${name}`,
248
+ name,
249
+ });
250
+ }
251
+ runtimeTask.assets = copiedAssets;
252
+ }
253
+
254
+ export async function prepareRepository(runtimeTask, taskDirectory, destination) {
255
+ if (isCiteArkReconstructionRepository(runtimeTask.repository)) {
256
+ const commit = await prepareReconstructionRepository(destination);
257
+ return {
258
+ sourceType: "citeark-reconstruction",
259
+ submittedSource: runtimeTask.repository.url,
260
+ commit,
261
+ dirty: false,
262
+ };
263
+ }
264
+ if (runtimeTask.repository.path) {
265
+ const source = path.resolve(taskDirectory, runtimeTask.repository.path);
266
+ if (!(await pathExists(source))) {
267
+ throw new CiteArkError(`仓库目录不存在:${source}`);
268
+ }
269
+ await cp(source, destination, {
270
+ recursive: true,
271
+ force: true,
272
+ verbatimSymlinks: true,
273
+ });
274
+ const git = await inspectGitRepository(destination);
275
+ if (
276
+ runtimeTask.repository.commit &&
277
+ git.commit &&
278
+ !git.commit.startsWith(runtimeTask.repository.commit)
279
+ ) {
280
+ throw new CiteArkError(
281
+ `本地仓库 HEAD (${git.commit}) 与任务指定 commit (${runtimeTask.repository.commit}) 不一致`,
282
+ );
283
+ }
284
+ return {
285
+ sourceType: "path",
286
+ submittedSource: runtimeTask.repository.path,
287
+ commit: git.commit ?? runtimeTask.repository.commit ?? null,
288
+ dirty: git.dirty,
289
+ };
290
+ }
291
+
292
+ const clone = await captureProcess(
293
+ "git",
294
+ ["clone", "--config", "core.autocrlf=false", "--filter=blob:none", runtimeTask.repository.url, destination],
295
+ { cwd: taskDirectory },
296
+ );
297
+ if (clone.code !== 0) {
298
+ throw new CiteArkError(`克隆仓库失败:\n${clone.stderr.trim()}`);
299
+ }
300
+ if (runtimeTask.repository.commit) {
301
+ const checkout = await captureProcess(
302
+ "git",
303
+ ["checkout", "--detach", runtimeTask.repository.commit],
304
+ { cwd: destination },
305
+ );
306
+ if (checkout.code !== 0) {
307
+ throw new CiteArkError(`检出 commit 失败:\n${checkout.stderr.trim()}`);
308
+ }
309
+ }
310
+ const git = await inspectGitRepository(destination);
311
+ return {
312
+ sourceType: "url",
313
+ submittedSource: runtimeTask.repository.url,
314
+ commit: git.commit,
315
+ dirty: git.dirty,
316
+ };
317
+ }
318
+
319
+ export async function inspectGitRepository(repositoryDirectory) {
320
+ const result = await captureProcess(
321
+ "git",
322
+ ["rev-parse", "--is-inside-work-tree"],
323
+ { cwd: repositoryDirectory },
324
+ );
325
+ if (result.code !== 0 || result.stdout.trim() !== "true") {
326
+ return { commit: null, dirty: null };
327
+ }
328
+ const topLevel = await captureProcess(
329
+ "git",
330
+ ["rev-parse", "--show-toplevel"],
331
+ { cwd: repositoryDirectory },
332
+ );
333
+ const [actualRoot, requestedRoot] = await Promise.all([
334
+ topLevel.code === 0 ? realpath(topLevel.stdout.trim()).catch(() => null) : null,
335
+ realpath(repositoryDirectory).catch(() => null),
336
+ ]);
337
+ if (!actualRoot || !requestedRoot || actualRoot !== requestedRoot) {
338
+ return { commit: null, dirty: null };
339
+ }
340
+ const [commit, status] = await Promise.all([
341
+ captureProcess("git", ["rev-parse", "HEAD"], { cwd: repositoryDirectory }),
342
+ captureProcess("git", ["status", "--porcelain=v1"], {
343
+ cwd: repositoryDirectory,
344
+ }),
345
+ ]);
346
+ return {
347
+ commit: commit.code === 0 ? commit.stdout.trim() : null,
348
+ dirty: status.code === 0 ? status.stdout.trim() !== "" : null,
349
+ };
350
+ }
351
+
352
+ export async function snapshotDirectory(root) {
353
+ const entries = [];
354
+ await walk(root, "", entries);
355
+ entries.sort((left, right) => left.path.localeCompare(right.path));
356
+ return {
357
+ generatedAt: new Date().toISOString(),
358
+ excludedDirectories: [...SNAPSHOT_EXCLUDED_DIRECTORIES].sort(),
359
+ entries,
360
+ };
361
+
362
+ async function walk(directory, relativeDirectory, output) {
363
+ const children = await readdir(directory, { withFileTypes: true });
364
+ children.sort((left, right) => left.name.localeCompare(right.name));
365
+ for (const child of children) {
366
+ const relative = path.posix.join(
367
+ relativeDirectory.split(path.sep).join(path.posix.sep),
368
+ child.name,
369
+ );
370
+ const absolute = path.join(directory, child.name);
371
+ if (child.isDirectory()) {
372
+ if (SNAPSHOT_EXCLUDED_DIRECTORIES.has(child.name)) continue;
373
+ await walk(absolute, relative, output);
374
+ } else if (child.isSymbolicLink()) {
375
+ output.push({
376
+ path: relative,
377
+ type: "symlink",
378
+ target: await readlink(absolute),
379
+ });
380
+ } else if (child.isFile()) {
381
+ const stat = await lstat(absolute);
382
+ output.push({
383
+ path: relative,
384
+ type: "file",
385
+ size: stat.size,
386
+ sha256: await sha256File(absolute),
387
+ });
388
+ }
389
+ }
390
+ }
391
+ }
392
+
393
+ export function snapshotDigest(snapshot) {
394
+ return `sha256:${sha256Value({
395
+ excludedDirectories: snapshot.excludedDirectories,
396
+ entries: snapshot.entries,
397
+ })}`;
398
+ }
399
+
400
+ export function diffSnapshots(before, after) {
401
+ const beforeByPath = new Map(before.entries.map((entry) => [entry.path, entry]));
402
+ const afterByPath = new Map(after.entries.map((entry) => [entry.path, entry]));
403
+ const added = [];
404
+ const modified = [];
405
+ const deleted = [];
406
+
407
+ for (const [entryPath, current] of afterByPath) {
408
+ const previous = beforeByPath.get(entryPath);
409
+ if (!previous) {
410
+ added.push(current);
411
+ } else if (hashEntry(previous) !== hashEntry(current)) {
412
+ modified.push({ path: entryPath, before: previous, after: current });
413
+ }
414
+ }
415
+ for (const [entryPath, previous] of beforeByPath) {
416
+ if (!afterByPath.has(entryPath)) deleted.push(previous);
417
+ }
418
+ return { added, modified, deleted };
419
+ }
420
+
421
+ function hashEntry(entry) {
422
+ return createHash("sha256").update(JSON.stringify(entry)).digest("hex");
423
+ }
424
+
425
+ export async function captureFinalWorkspace(bundle) {
426
+ const after = await snapshotDirectory(bundle.directories.repository);
427
+ const changes = diffSnapshots(bundle.beforeSnapshot, after);
428
+ await writeJson(
429
+ path.join(bundle.directories.execution, "workspace-after.json"),
430
+ after,
431
+ );
432
+ await writeJson(
433
+ path.join(bundle.directories.execution, "workspace-changes.json"),
434
+ changes,
435
+ );
436
+ await captureGitDiff(bundle.directories.repository, bundle.directories.execution);
437
+ return { after, changes };
438
+ }
439
+
440
+ export async function ensureFinalWorkspaceCapture(bundle) {
441
+ // Local execution can change files between validation attempts. Only remote
442
+ // captures are authoritative over the coordinator's repository copy.
443
+ if ((bundle.sandboxProvider ?? bundle.state?.sandbox) === "docker") {
444
+ return await captureFinalWorkspace(bundle);
445
+ }
446
+ const required = [
447
+ "workspace-after.json",
448
+ "workspace-changes.json",
449
+ "repository.patch",
450
+ "untracked-files.txt",
451
+ ].map((filename) => path.join(bundle.directories.execution, filename));
452
+ if ((await Promise.all(required.map(pathExists))).every(Boolean)) {
453
+ return { preservedRemoteAudit: true };
454
+ }
455
+ return await captureFinalWorkspace(bundle);
456
+ }
457
+
458
+ async function captureGitDiff(repositoryDirectory, executionDirectory) {
459
+ const git = await inspectGitRepository(repositoryDirectory);
460
+ if (!git.commit) {
461
+ await writeFile(path.join(executionDirectory, "repository.patch"), "");
462
+ return;
463
+ }
464
+ const diff = await captureProcess(
465
+ "git",
466
+ ["diff", "--binary", "--no-ext-diff", "HEAD"],
467
+ { cwd: repositoryDirectory },
468
+ );
469
+ if (diff.code === 0) {
470
+ await writeFile(path.join(executionDirectory, "repository.patch"), diff.stdout);
471
+ }
472
+ const untracked = await captureProcess(
473
+ "git",
474
+ ["ls-files", "--others", "--exclude-standard"],
475
+ { cwd: repositoryDirectory },
476
+ );
477
+ if (untracked.code === 0) {
478
+ await writeFile(
479
+ path.join(executionDirectory, "untracked-files.txt"),
480
+ untracked.stdout,
481
+ );
482
+ }
483
+ }
484
+
485
+ export async function updateRunState(bundle, patch) {
486
+ bundle.state = {
487
+ ...bundle.state,
488
+ ...patch,
489
+ updatedAt: new Date().toISOString(),
490
+ };
491
+ await writeJson(path.join(bundle.directories.run, "run.json"), bundle.state);
492
+ }
493
+
494
+ export async function readAgentInstructions(task) {
495
+ return (await readFile(path.join(PACKAGE_ROOT, "prompts", usesWorkspaceSummary(task) ? "execute-workspace-simple.md" : hasResearchWorkspace(task) ? "execute-workspace.md" : "execute-contract.md"), "utf8")) + DELIVERY_INSTRUCTIONS;
496
+ }