@world-engines/project-host 0.1.0-alpha.0

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 (218) hide show
  1. package/LICENSE +46 -0
  2. package/assets/gui/WELogo-title.svg +11 -0
  3. package/assets/gui/app.js +1326 -0
  4. package/assets/gui/index.html +118 -0
  5. package/assets/gui/local-preview-asset-urls.js +61 -0
  6. package/assets/gui/local-preview-bridge.js +393 -0
  7. package/assets/gui/spatial-template-panel.js +233 -0
  8. package/assets/gui/styles.css +115 -0
  9. package/assets/gui/terrain-render.js +120 -0
  10. package/assets/gui/workspace-status.css +17 -0
  11. package/assets/gui/workspace-status.js +255 -0
  12. package/assets/gui/world-map-globe.js +187 -0
  13. package/assets/gui/world-map-worker.js +62 -0
  14. package/assets/gui/world-map.css +30 -0
  15. package/assets/gui/world-map.js +2466 -0
  16. package/dist/account-model-proxy.d.ts +21 -0
  17. package/dist/account-model-proxy.js +470 -0
  18. package/dist/authoring-browser-runtime.d.ts +7 -0
  19. package/dist/authoring-browser-runtime.js +110 -0
  20. package/dist/authoring-ingestion.d.ts +38 -0
  21. package/dist/authoring-ingestion.js +410 -0
  22. package/dist/authoring-model-connection.d.ts +166 -0
  23. package/dist/authoring-model-connection.js +757 -0
  24. package/dist/chinese-lexical.d.ts +152 -0
  25. package/dist/chinese-lexical.js +555 -0
  26. package/dist/chromium-preview-browser-driver.d.ts +43 -0
  27. package/dist/chromium-preview-browser-driver.js +575 -0
  28. package/dist/cli/download.d.ts +12 -0
  29. package/dist/cli/download.js +50 -0
  30. package/dist/cli/dump.d.ts +32 -0
  31. package/dist/cli/dump.js +91 -0
  32. package/dist/cli/ingest.d.ts +49 -0
  33. package/dist/cli/ingest.js +225 -0
  34. package/dist/cli/review.d.ts +10 -0
  35. package/dist/cli/review.js +44 -0
  36. package/dist/cli/upload.d.ts +57 -0
  37. package/dist/cli/upload.js +112 -0
  38. package/dist/cli-command.d.ts +60 -0
  39. package/dist/cli-command.js +613 -0
  40. package/dist/cli.d.ts +2 -0
  41. package/dist/cli.js +182 -0
  42. package/dist/desktop-authoring-runtime.d.ts +88 -0
  43. package/dist/desktop-authoring-runtime.js +1602 -0
  44. package/dist/desktop-sidecar.d.ts +11 -0
  45. package/dist/desktop-sidecar.js +143 -0
  46. package/dist/document-dump.d.ts +113 -0
  47. package/dist/document-dump.js +431 -0
  48. package/dist/document-graph-extractor.d.ts +125 -0
  49. package/dist/document-graph-extractor.js +588 -0
  50. package/dist/document-ingestion-journal.d.ts +68 -0
  51. package/dist/document-ingestion-journal.js +471 -0
  52. package/dist/document-ingestion.d.ts +183 -0
  53. package/dist/document-ingestion.js +976 -0
  54. package/dist/document-query-path-proof.d.ts +30 -0
  55. package/dist/document-query-path-proof.js +34 -0
  56. package/dist/document-query-path-renderer.d.ts +50 -0
  57. package/dist/document-query-path-renderer.js +75 -0
  58. package/dist/document-query-proof-paths.d.ts +22 -0
  59. package/dist/document-query-proof-paths.js +71 -0
  60. package/dist/document-query.d.ts +97 -0
  61. package/dist/document-query.js +1106 -0
  62. package/dist/document-relation-role.d.ts +14 -0
  63. package/dist/document-relation-role.js +86 -0
  64. package/dist/document-source.d.ts +107 -0
  65. package/dist/document-source.js +255 -0
  66. package/dist/embedding-cache.d.ts +35 -0
  67. package/dist/embedding-cache.js +317 -0
  68. package/dist/frozen-review-local-pipeline.d.ts +88 -0
  69. package/dist/frozen-review-local-pipeline.js +609 -0
  70. package/dist/frozen-review-source-capture.d.ts +15 -0
  71. package/dist/frozen-review-source-capture.js +551 -0
  72. package/dist/frozen-review-wasm-encryptor.d.ts +16 -0
  73. package/dist/frozen-review-wasm-encryptor.js +72 -0
  74. package/dist/frozen-review.d.ts +131 -0
  75. package/dist/frozen-review.js +802 -0
  76. package/dist/graph-traversal.d.ts +23 -0
  77. package/dist/graph-traversal.js +100 -0
  78. package/dist/gui/graph-layout-worker.js +1 -0
  79. package/dist/gui/graph-layout.wasm +0 -0
  80. package/dist/gui/graph.css +1 -0
  81. package/dist/gui/graph.js +76 -0
  82. package/dist/gui/plane-generation.js +112 -0
  83. package/dist/gui/plane-generator.js +310 -0
  84. package/dist/gui/plane-generator_bg.wasm +0 -0
  85. package/dist/gui/procedural-city.js +595 -0
  86. package/dist/gui/road-generation.js +129 -0
  87. package/dist/gui/road-parcels.js +1584 -0
  88. package/dist/gui/score.css +1 -0
  89. package/dist/gui/score.js +54 -0
  90. package/dist/gui/spatial-runtime.js +1231 -0
  91. package/dist/gui/spatial-templates.js +200 -0
  92. package/dist/gui/trigger.css +1 -0
  93. package/dist/gui/trigger.js +142 -0
  94. package/dist/harness-callback-transport.d.ts +17 -0
  95. package/dist/harness-callback-transport.js +128 -0
  96. package/dist/harness-document-ingestion.d.ts +77 -0
  97. package/dist/harness-document-ingestion.js +343 -0
  98. package/dist/index.d.ts +43 -0
  99. package/dist/index.js +43 -0
  100. package/dist/ingestion-source-reconciliation.d.ts +88 -0
  101. package/dist/ingestion-source-reconciliation.js +253 -0
  102. package/dist/ladybug-runtime.d.ts +117 -0
  103. package/dist/ladybug-runtime.js +886 -0
  104. package/dist/local-account-embedding.d.ts +34 -0
  105. package/dist/local-account-embedding.js +294 -0
  106. package/dist/local-gallery.d.ts +35 -0
  107. package/dist/local-gallery.js +227 -0
  108. package/dist/local-gui-auth.d.ts +96 -0
  109. package/dist/local-gui-auth.js +703 -0
  110. package/dist/local-gui-contract.d.ts +53 -0
  111. package/dist/local-gui-contract.js +5 -0
  112. package/dist/local-gui-image-assets.d.ts +17 -0
  113. package/dist/local-gui-image-assets.js +96 -0
  114. package/dist/local-gui-preview-client.d.ts +3 -0
  115. package/dist/local-gui-preview-client.js +111 -0
  116. package/dist/local-gui-score.d.ts +72 -0
  117. package/dist/local-gui-score.js +184 -0
  118. package/dist/local-gui-server.d.ts +10 -0
  119. package/dist/local-gui-server.js +987 -0
  120. package/dist/local-gui-version.d.ts +17 -0
  121. package/dist/local-gui-version.js +147 -0
  122. package/dist/local-gui-workspace.d.ts +14 -0
  123. package/dist/local-gui-workspace.js +171 -0
  124. package/dist/local-model-settings.d.ts +28 -0
  125. package/dist/local-model-settings.js +124 -0
  126. package/dist/local-preview-assets.d.ts +28 -0
  127. package/dist/local-preview-assets.js +124 -0
  128. package/dist/local-preview-bound-resources.d.ts +12 -0
  129. package/dist/local-preview-bound-resources.js +80 -0
  130. package/dist/local-preview-message-store.d.ts +63 -0
  131. package/dist/local-preview-message-store.js +214 -0
  132. package/dist/local-preview-player-read-models.d.ts +47 -0
  133. package/dist/local-preview-player-read-models.js +90 -0
  134. package/dist/local-preview-projections.d.ts +61 -0
  135. package/dist/local-preview-projections.js +117 -0
  136. package/dist/local-preview-runtime.d.ts +105 -0
  137. package/dist/local-preview-runtime.js +553 -0
  138. package/dist/local-preview-session.d.ts +73 -0
  139. package/dist/local-preview-session.js +395 -0
  140. package/dist/local-preview-source.d.ts +40 -0
  141. package/dist/local-preview-source.js +192 -0
  142. package/dist/local-preview-view-events.d.ts +101 -0
  143. package/dist/local-preview-view-events.js +179 -0
  144. package/dist/local-preview-view-state-sqlite.d.ts +24 -0
  145. package/dist/local-preview-view-state-sqlite.js +263 -0
  146. package/dist/local-preview-view-state.d.ts +93 -0
  147. package/dist/local-preview-view-state.js +108 -0
  148. package/dist/local-preview-vite-config.d.ts +6 -0
  149. package/dist/local-preview-vite-config.js +122 -0
  150. package/dist/local-preview-world-effects.d.ts +9 -0
  151. package/dist/local-preview-world-effects.js +55 -0
  152. package/dist/local-preview-worldline-store.d.ts +47 -0
  153. package/dist/local-preview-worldline-store.js +282 -0
  154. package/dist/local-preview-worldlines.d.ts +95 -0
  155. package/dist/local-preview-worldlines.js +136 -0
  156. package/dist/mcp-async-dispatcher.d.ts +3 -0
  157. package/dist/mcp-async-dispatcher.js +129 -0
  158. package/dist/mcp-line-queue.d.ts +14 -0
  159. package/dist/mcp-line-queue.js +184 -0
  160. package/dist/mcp-pipe-internal.d.ts +6 -0
  161. package/dist/mcp-pipe-internal.js +151 -0
  162. package/dist/mcp-pipe-response.d.ts +14 -0
  163. package/dist/mcp-pipe-response.js +50 -0
  164. package/dist/mcp-stdio-response.d.ts +12 -0
  165. package/dist/mcp-stdio-response.js +27 -0
  166. package/dist/mcp.d.ts +27 -0
  167. package/dist/mcp.js +194 -0
  168. package/dist/prepared-embedding-cache.d.ts +38 -0
  169. package/dist/prepared-embedding-cache.js +238 -0
  170. package/dist/preview-browser-adapter.d.ts +53 -0
  171. package/dist/preview-browser-adapter.js +171 -0
  172. package/dist/preview-runtime.d.ts +67 -0
  173. package/dist/preview-runtime.js +460 -0
  174. package/dist/project-auth-transport.d.ts +27 -0
  175. package/dist/project-auth-transport.js +121 -0
  176. package/dist/project-auth.d.ts +51 -0
  177. package/dist/project-auth.js +108 -0
  178. package/dist/project-git-capture-recovery.d.ts +16 -0
  179. package/dist/project-git-capture-recovery.js +347 -0
  180. package/dist/project-git-cli.d.ts +5 -0
  181. package/dist/project-git-cli.js +40 -0
  182. package/dist/project-git-scenario-source.d.ts +10 -0
  183. package/dist/project-git-scenario-source.js +240 -0
  184. package/dist/project-git-view-source.d.ts +13 -0
  185. package/dist/project-git-view-source.js +134 -0
  186. package/dist/project-git.d.ts +97 -0
  187. package/dist/project-git.js +656 -0
  188. package/dist/project-host.d.ts +59 -0
  189. package/dist/project-host.js +471 -0
  190. package/dist/project-writer-lease.d.ts +18 -0
  191. package/dist/project-writer-lease.js +430 -0
  192. package/dist/public-error.d.ts +7 -0
  193. package/dist/public-error.js +61 -0
  194. package/dist/retrieval-benchmark.d.ts +46 -0
  195. package/dist/retrieval-benchmark.js +58 -0
  196. package/dist/safe-project-path.d.ts +8 -0
  197. package/dist/safe-project-path.js +93 -0
  198. package/dist/scenario-writer.d.ts +32 -0
  199. package/dist/scenario-writer.js +191 -0
  200. package/dist/transfer/download.d.ts +159 -0
  201. package/dist/transfer/download.js +598 -0
  202. package/dist/transfer/transport.d.ts +26 -0
  203. package/dist/transfer/transport.js +1 -0
  204. package/dist/transfer/upload.d.ts +162 -0
  205. package/dist/transfer/upload.js +354 -0
  206. package/dist/transfer-types.d.ts +95 -0
  207. package/dist/transfer-types.js +1 -0
  208. package/dist/transfer.d.ts +18 -0
  209. package/dist/transfer.js +273 -0
  210. package/dist/trigger-runtime.d.ts +121 -0
  211. package/dist/trigger-runtime.js +153 -0
  212. package/dist/vendor/wasm-core/asset-hashes.json +5 -0
  213. package/dist/vendor/wasm-core/wasm_core.d.ts +490 -0
  214. package/dist/vendor/wasm-core/wasm_core.js +1 -0
  215. package/dist/vendor/wasm-core/wasm_core_bg.wasm +0 -0
  216. package/dist/view-watcher.d.ts +9 -0
  217. package/dist/view-watcher.js +34 -0
  218. package/package.json +110 -0
@@ -0,0 +1,17 @@
1
+ import type { DesktopAuthoringCapabilities } from "./desktop-authoring-runtime.js";
2
+ export interface HarnessCallbackEnvironment {
3
+ readonly WORLDENGINE_HARNESS_CALLBACK_PIPE?: string;
4
+ readonly WORLDENGINE_HARNESS_CALLBACK_CHALLENGE_ID?: string;
5
+ readonly WORLDENGINE_HARNESS_CALLBACK_CHALLENGE?: string;
6
+ readonly WORLDENGINE_HARNESS_CALLBACK_EXPIRES_AT_MS?: string;
7
+ }
8
+ export interface HarnessCallbackTransportDependencies {
9
+ readonly now?: () => number;
10
+ readonly currentWindowsSid?: () => Promise<string>;
11
+ readonly request?: (pipeName: string, payload: string) => Promise<unknown>;
12
+ }
13
+ /**
14
+ * Desktop 启动器可注入短期、project-bound named-pipe capability。没有 broker 时返回空能力,
15
+ * ProjectHost/MCP 会把三个 callback 标记为 unavailable,绝不伪造 GUI 或用户回答。
16
+ */
17
+ export declare function createHarnessCallbackCapabilities(projectId: string, environment?: HarnessCallbackEnvironment, dependencies?: HarnessCallbackTransportDependencies): Promise<DesktopAuthoringCapabilities>;
@@ -0,0 +1,128 @@
1
+ import { execFile } from "node:child_process";
2
+ import { createConnection } from "node:net";
3
+ import { promisify } from "node:util";
4
+ import { AuthoringBridgeError } from "@world-engines/authoring-bridge";
5
+ const execFileAsync = promisify(execFile);
6
+ const CALLBACK_PIPE_PATTERN = /^\\\\\.\\pipe\\worldengine-harness-callback-[a-f0-9]{64}$/i;
7
+ const CALLBACK_RESPONSE_LIMIT = 4 * 1024 * 1024;
8
+ const CALLBACK_TIMEOUT_MS = 5 * 60_000;
9
+ function unavailable(toolName, reason) {
10
+ throw new AuthoringBridgeError("E_VALIDATION_FAILED", `E_CAPABILITY_UNAVAILABLE: ${toolName} ${reason}`, {
11
+ failure: "E_CAPABILITY_UNAVAILABLE",
12
+ tool_name: toolName,
13
+ });
14
+ }
15
+ function capabilityFromEnvironment(environment, now) {
16
+ const values = [
17
+ environment.WORLDENGINE_HARNESS_CALLBACK_PIPE,
18
+ environment.WORLDENGINE_HARNESS_CALLBACK_CHALLENGE_ID,
19
+ environment.WORLDENGINE_HARNESS_CALLBACK_CHALLENGE,
20
+ environment.WORLDENGINE_HARNESS_CALLBACK_EXPIRES_AT_MS,
21
+ ];
22
+ if (values.every((value) => value === undefined))
23
+ return undefined;
24
+ const [pipeName, challengeId, challenge, expires] = values;
25
+ const expiresAtMs = Number(expires);
26
+ if (pipeName === undefined || !CALLBACK_PIPE_PATTERN.test(pipeName)
27
+ || challengeId === undefined || !/^[0-9a-f-]{36}$/i.test(challengeId)
28
+ || challenge === undefined || challenge.length < 32 || challenge.length > 256
29
+ || !Number.isSafeInteger(expiresAtMs) || expiresAtMs <= now) {
30
+ throw new AuthoringBridgeError("E_AUTH_REQUIRED", "Harness callback capability 无效或已过期");
31
+ }
32
+ return { pipeName, challengeId, challenge, expiresAtMs };
33
+ }
34
+ async function currentWindowsSid() {
35
+ if (process.platform !== "win32")
36
+ throw new AuthoringBridgeError("E_AUTH_REQUIRED", "Harness callback broker 仅支持 Windows");
37
+ const { stdout } = await execFileAsync("whoami", ["/user", "/fo", "csv", "/nh"], { windowsHide: true });
38
+ const sid = stdout.split(",").map((value) => value.trim().replace(/^"|"$/g, ""))
39
+ .find((value) => /^S-1-[0-9-]+$/i.test(value));
40
+ if (sid === undefined)
41
+ throw new AuthoringBridgeError("E_AUTH_REQUIRED", "Harness callback Windows identity 不可用");
42
+ return sid;
43
+ }
44
+ async function pipeRequest(pipeName, payload) {
45
+ return new Promise((resolvePromise, rejectPromise) => {
46
+ const socket = createConnection(pipeName);
47
+ const chunks = [];
48
+ let total = 0;
49
+ const fail = () => {
50
+ socket.destroy();
51
+ rejectPromise(new AuthoringBridgeError("E_VALIDATION_FAILED", "Harness callback broker 不可用", {
52
+ failure: "E_CAPABILITY_UNAVAILABLE",
53
+ }));
54
+ };
55
+ socket.setTimeout(CALLBACK_TIMEOUT_MS, fail);
56
+ socket.once("connect", () => socket.write(`${payload}\n`));
57
+ socket.on("data", (chunk) => {
58
+ total += chunk.byteLength;
59
+ if (!Number.isSafeInteger(total) || total > CALLBACK_RESPONSE_LIMIT)
60
+ fail();
61
+ else
62
+ chunks.push(chunk);
63
+ });
64
+ socket.once("error", fail);
65
+ socket.once("end", () => {
66
+ try {
67
+ resolvePromise(JSON.parse(Buffer.concat(chunks).toString("utf8")));
68
+ }
69
+ catch {
70
+ fail();
71
+ }
72
+ });
73
+ });
74
+ }
75
+ function callbackResult(toolName, response) {
76
+ if (typeof response !== "object" || response === null || Array.isArray(response))
77
+ unavailable(toolName, "响应无效");
78
+ const record = response;
79
+ if (record.ok === true && Object.hasOwn(record, "result"))
80
+ return record.result;
81
+ if (record.ok === false && record.error === "E_PREVIEW_NOT_RUNNING") {
82
+ throw new AuthoringBridgeError("E_PREVIEW_NOT_RUNNING", "Preview 尚未运行");
83
+ }
84
+ unavailable(toolName, "被 UI broker 拒绝");
85
+ }
86
+ /**
87
+ * Desktop 启动器可注入短期、project-bound named-pipe capability。没有 broker 时返回空能力,
88
+ * ProjectHost/MCP 会把三个 callback 标记为 unavailable,绝不伪造 GUI 或用户回答。
89
+ */
90
+ export async function createHarnessCallbackCapabilities(projectId, environment = process.env, dependencies = {}) {
91
+ if (!/^[A-Za-z0-9_-]{1,256}$/.test(projectId))
92
+ throw new AuthoringBridgeError("E_SCHEMA_INVALID", "project_id 无效");
93
+ const now = dependencies.now ?? Date.now;
94
+ const capability = capabilityFromEnvironment(environment, now());
95
+ if (capability === undefined)
96
+ return Object.freeze({});
97
+ const windowsSid = await (dependencies.currentWindowsSid ?? currentWindowsSid)();
98
+ const request = dependencies.request ?? pipeRequest;
99
+ const call = async (toolName, input) => {
100
+ if (capability.expiresAtMs <= now())
101
+ unavailable(toolName, "capability 已过期");
102
+ const payload = JSON.stringify({
103
+ namespace: "worldengine.harness_callbacks.v1",
104
+ project_id: projectId,
105
+ windows_sid: windowsSid,
106
+ challenge_id: capability.challengeId,
107
+ challenge: capability.challenge,
108
+ tool_name: toolName,
109
+ input,
110
+ });
111
+ if (Buffer.byteLength(payload, "utf8") > CALLBACK_RESPONSE_LIMIT) {
112
+ throw new AuthoringBridgeError("E_SCHEMA_INVALID", "Harness callback 请求过大");
113
+ }
114
+ try {
115
+ return callbackResult(toolName, await request(capability.pipeName, payload));
116
+ }
117
+ catch (error) {
118
+ if (error instanceof AuthoringBridgeError)
119
+ throw error;
120
+ unavailable(toolName, "transport 不可用");
121
+ }
122
+ };
123
+ return Object.freeze({
124
+ ask_user: (input) => call("ask_user", input),
125
+ preview_inspect: (input) => call("preview_inspect", input),
126
+ preview_interact: (input) => call("preview_interact", input),
127
+ });
128
+ }
@@ -0,0 +1,77 @@
1
+ import { type PreparedDocumentGraphWindowRequest } from "./document-graph-extractor.js";
2
+ import { type LosslessDocumentIngestionHost, type LosslessDocumentIngestionReceipt, type LosslessDocumentInput } from "./document-ingestion.js";
3
+ import { type DocumentSourceOptions } from "./document-source.js";
4
+ export type HarnessDocumentIngestionRequest = Readonly<{
5
+ schemaVersion: 1;
6
+ operationId: string;
7
+ requestId: string;
8
+ windowId: string;
9
+ attempt: number;
10
+ maximumAttempts: number;
11
+ rawByteSha256: string;
12
+ planSha256: string;
13
+ methodSha256: string;
14
+ evidenceUnits: readonly Readonly<{
15
+ id: string;
16
+ kind: string;
17
+ text: string;
18
+ core: boolean;
19
+ startOffset: number;
20
+ endOffset: number;
21
+ }>[];
22
+ structuredRequest: PreparedDocumentGraphWindowRequest;
23
+ }>;
24
+ export type HarnessDocumentIngestionNext = Readonly<{
25
+ schemaVersion: 1;
26
+ state: "request";
27
+ processedWindows: number;
28
+ totalWindows: number;
29
+ sourcePath?: string;
30
+ sourceStoragePath?: string;
31
+ request: HarnessDocumentIngestionRequest;
32
+ }> | Readonly<{
33
+ schemaVersion: 1;
34
+ state: "ready_to_commit" | "committed";
35
+ processedWindows: number;
36
+ totalWindows: number;
37
+ sourcePath?: string;
38
+ sourceStoragePath?: string;
39
+ }> | Readonly<{
40
+ schemaVersion: 1;
41
+ state: "repair_exhausted";
42
+ processedWindows: number;
43
+ totalWindows: number;
44
+ sourcePath?: string;
45
+ sourceStoragePath?: string;
46
+ windowId: string;
47
+ attempts: number;
48
+ reasons: readonly string[];
49
+ }>;
50
+ export type HarnessDocumentIngestionAcceptance = Readonly<{
51
+ schemaVersion: 1;
52
+ operationId: string;
53
+ requestId: string;
54
+ windowId: string;
55
+ attempt: number;
56
+ accepted: boolean;
57
+ graphStatus: "complete" | "partial";
58
+ next: HarnessDocumentIngestionNext;
59
+ }>;
60
+ /** 只保存用户选定的最终成书原文字节;不接收或记录 harness 对话。 */
61
+ export declare function prepareHarnessDocumentIngestion(host: LosslessDocumentIngestionHost, input: LosslessDocumentInput, options: Readonly<{
62
+ projectRoot: string;
63
+ sourceOptions?: DocumentSourceOptions;
64
+ }>): Promise<Readonly<{
65
+ receipt: LosslessDocumentIngestionReceipt;
66
+ next: HarnessDocumentIngestionNext;
67
+ }>>;
68
+ /** 跨 CLI/MCP 调用可重复计算的下一请求;函数只读,不持久化 prompt 或聊天日志。 */
69
+ export declare function nextHarnessDocumentIngestion(projectRoot: string, operationId: string): Promise<HarnessDocumentIngestionNext>;
70
+ /** requestId 是对 source/method/checkpoint/prompt 的 CAS;只把校验后的 GraphSegment 写入 journal。 */
71
+ export declare function acceptHarnessDocumentIngestion(projectRoot: string, operationId: string, requestId: string, candidate: unknown,
72
+ /** 仅用于模块测试模拟 ledger 与 checkpoint 之间的进程中断;产品调用必须省略。 */
73
+ dependencies?: Readonly<{
74
+ afterAcceptanceLedgerPersist?(): void | Promise<void>;
75
+ }>): Promise<HarnessDocumentIngestionAcceptance>;
76
+ /** 所有窗口 complete 后复用 losslessDocument 的唯一 assemble + world_apply CAS commit。 */
77
+ export declare function commitHarnessDocumentIngestion(host: LosslessDocumentIngestionHost, projectRoot: string, operationId: string): Promise<LosslessDocumentIngestionReceipt>;
@@ -0,0 +1,343 @@
1
+ import { createHash } from "node:crypto";
2
+ import { AuthoringBridgeError } from "@world-engines/authoring-bridge";
3
+ import { prepareDocumentGraphWindowRequest, validateDocumentGraphWindowCandidate, } from "./document-graph-extractor.js";
4
+ import { DOCUMENT_INGESTION_CHECKPOINT_IDS, graphSegment, ingestHarnessDocument, knownDocumentGraphEntities, readDocumentIngestionCheckpoint, readStagedDocumentInput, resumeHarnessDocument, } from "./document-ingestion.js";
5
+ import { openDocumentIngestionJournal, readDocumentIngestionJournalStatus } from "./document-ingestion-journal.js";
6
+ import { buildDocumentSource } from "./document-source.js";
7
+ const HARNESS_MODEL_ID = "external-project-harness-v1";
8
+ function sha256(value) {
9
+ return createHash("sha256").update(value).digest("hex");
10
+ }
11
+ function stableJson(value) {
12
+ if (value === null || typeof value !== "object")
13
+ return JSON.stringify(value);
14
+ if (Array.isArray(value))
15
+ return `[${value.map(stableJson).join(",")}]`;
16
+ const record = value;
17
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`).join(",")}}`;
18
+ }
19
+ function asJson(value) {
20
+ return JSON.parse(JSON.stringify(value));
21
+ }
22
+ function fail(code, message, failure, details = {}) {
23
+ throw new AuthoringBridgeError(code, message, Object.freeze({ failure, ...details }));
24
+ }
25
+ function normalizedCandidate(value) {
26
+ let encoded;
27
+ try {
28
+ encoded = JSON.stringify(value);
29
+ }
30
+ catch {
31
+ fail("E_SCHEMA_INVALID", "harness response 不是可序列化 JSON", "HARNESS_RESPONSE_SCHEMA_INVALID");
32
+ }
33
+ if (encoded === undefined || encoded.length > 16 * 1024 * 1024) {
34
+ fail("E_SCHEMA_INVALID", "harness response 不是有效 JSON 或超过大小上限", "HARNESS_RESPONSE_SCHEMA_INVALID");
35
+ }
36
+ const parsed = JSON.parse(encoded);
37
+ return Object.freeze({ value: parsed, sha256: sha256(stableJson(parsed)) });
38
+ }
39
+ function acceptanceCheckpointId(requestId) {
40
+ return `${DOCUMENT_INGESTION_CHECKPOINT_IDS.harnessAcceptancePrefix}${sha256(requestId)}`;
41
+ }
42
+ function parseAcceptanceLedger(value) {
43
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
44
+ fail("E_OPERATION_ID_CONFLICT", "harness acceptance ledger 已损坏", "HARNESS_ACCEPTANCE_LEDGER_CORRUPT");
45
+ }
46
+ const input = value;
47
+ if (input.schema_version !== 1 || typeof input.operation_id !== "string" || typeof input.request_id !== "string"
48
+ || typeof input.candidate_sha256 !== "string" || !/^[0-9a-f]{64}$/u.test(input.candidate_sha256)
49
+ || typeof input.segment_sha256 !== "string" || !/^[0-9a-f]{64}$/u.test(input.segment_sha256)
50
+ || typeof input.window_id !== "string" || !Number.isSafeInteger(input.attempt) || input.attempt < 1
51
+ || typeof input.accepted !== "boolean" || (input.graph_status !== "complete" && input.graph_status !== "partial")
52
+ || typeof input.checkpoint_id !== "string" || input.accepted !== (input.graph_status === "complete")) {
53
+ fail("E_OPERATION_ID_CONFLICT", "harness acceptance ledger 已损坏", "HARNESS_ACCEPTANCE_LEDGER_CORRUPT");
54
+ }
55
+ return Object.freeze({ schemaVersion: 1, operationId: input.operation_id, requestId: input.request_id,
56
+ candidateSha256: input.candidate_sha256, segmentSha256: input.segment_sha256, windowId: input.window_id,
57
+ attempt: input.attempt, accepted: input.accepted, graphStatus: input.graph_status,
58
+ checkpointId: input.checkpoint_id });
59
+ }
60
+ async function readAcceptanceLedger(projectRoot, operationId, requestId) {
61
+ try {
62
+ const ledger = parseAcceptanceLedger(await readDocumentIngestionCheckpoint(projectRoot, operationId, acceptanceCheckpointId(requestId)));
63
+ if (ledger.operationId !== operationId || ledger.requestId !== requestId) {
64
+ fail("E_OPERATION_ID_CONFLICT", "harness acceptance ledger identity 不匹配", "HARNESS_ACCEPTANCE_LEDGER_CONFLICT");
65
+ }
66
+ return ledger;
67
+ }
68
+ catch (error) {
69
+ if (error.code === "ENOENT")
70
+ return null;
71
+ throw error;
72
+ }
73
+ }
74
+ function unavailableModelCall() {
75
+ return Promise.reject(new AuthoringBridgeError("E_VALIDATION_FAILED", "harness workflow 没有也不会调用 provider model port", {
76
+ failure: "E_CAPABILITY_UNAVAILABLE",
77
+ }));
78
+ }
79
+ function unavailableModelConnection() {
80
+ return Object.freeze({
81
+ embedding: Object.freeze({ providerId: "none", modelId: HARNESS_MODEL_ID, dimensions: 0,
82
+ embed: unavailableModelCall }),
83
+ structuredJson: Object.freeze({ providerId: "project-harness", modelId: HARNESS_MODEL_ID,
84
+ generate: unavailableModelCall }),
85
+ usage: () => Object.freeze({ inputTokens: 0, outputTokens: 0, totalTokens: 0, requests: 0 }),
86
+ });
87
+ }
88
+ async function loadState(projectRoot, operationId) {
89
+ const descriptor = await readStagedDocumentInput(projectRoot, operationId);
90
+ if (descriptor.method.version !== "harness-v1") {
91
+ fail("E_VALIDATION_FAILED", "该 operation 不是 harness ingestion;需要对应 legacy provider capability", "E_CAPABILITY_UNAVAILABLE", { method_version: descriptor.method.version });
92
+ }
93
+ const status = await readDocumentIngestionJournalStatus(projectRoot, operationId);
94
+ if (status.modelId !== HARNESS_MODEL_ID || status.sourceByteSha256 !== sha256(descriptor.input.bytes)
95
+ || status.planSha256 !== descriptor.planSha256 || status.method?.sha256 !== descriptor.method.sha256) {
96
+ fail("E_OPERATION_ID_CONFLICT", "harness operation descriptor 与 journal identity 不匹配", "HARNESS_OPERATION_IDENTITY_CONFLICT");
97
+ }
98
+ const source = buildDocumentSource({ bytes: descriptor.input.bytes, sourceId: descriptor.input.sourceId,
99
+ sourceRevision: descriptor.input.sourceRevision, scopeId: descriptor.input.scopeId,
100
+ ...(descriptor.sourceOptions === undefined ? {} : { options: descriptor.sourceOptions }) });
101
+ const completed = new Map();
102
+ for (const window of source.windows) {
103
+ const retryId = `${DOCUMENT_INGESTION_CHECKPOINT_IDS.retryCompletePrefix}${window.id}`;
104
+ const checkpointId = status.completedSegmentIds.includes(retryId) ? retryId
105
+ : status.completedSegmentIds.includes(window.id) ? window.id : undefined;
106
+ if (checkpointId === undefined)
107
+ continue;
108
+ const segment = graphSegment(await readDocumentIngestionCheckpoint(projectRoot, operationId, checkpointId), window.id);
109
+ if (segment.status === "complete")
110
+ completed.set(window.id, segment);
111
+ }
112
+ return Object.freeze({ source, descriptor, status, completed });
113
+ }
114
+ function partialIds(status, windowId) {
115
+ const prefix = `${DOCUMENT_INGESTION_CHECKPOINT_IDS.partialAttemptPrefix}${windowId}:`;
116
+ return Object.freeze(status.completedSegmentIds.filter((id) => id.startsWith(prefix))
117
+ .sort((left, right) => Number(left.slice(prefix.length)) - Number(right.slice(prefix.length))));
118
+ }
119
+ function diagnosticFingerprint(methodSha256, segment) {
120
+ return sha256(stableJson({ methodSha256, windowId: segment.windowId,
121
+ reasons: Object.keys(segment.diagnostics.rejectionReasons).sort(),
122
+ segmentationIssues: segment.diagnostics.segmentationIssues ?? [] }));
123
+ }
124
+ async function previousAttempt(projectRoot, state, window, ids) {
125
+ const latestId = ids.at(-1);
126
+ if (latestId === undefined)
127
+ return undefined;
128
+ const latest = graphSegment(await readDocumentIngestionCheckpoint(projectRoot, state.descriptor.operationId, latestId), window.id);
129
+ const previousId = ids.at(-2);
130
+ const previous = previousId === undefined ? undefined
131
+ : graphSegment(await readDocumentIngestionCheckpoint(projectRoot, state.descriptor.operationId, previousId), window.id);
132
+ const fingerprint = diagnosticFingerprint(state.descriptor.method.sha256, latest);
133
+ return Object.freeze({
134
+ attempt: ids.length,
135
+ diagnosticFingerprint: fingerprint,
136
+ repeatedDiagnosticFingerprint: previous !== undefined
137
+ && diagnosticFingerprint(state.descriptor.method.sha256, previous) === fingerprint,
138
+ reasons: Object.freeze(Object.keys(latest.diagnostics.rejectionReasons).sort()),
139
+ validLocalNodeIds: Object.freeze(latest.nodes.map((node) => node.localId).sort()),
140
+ allowedEvidenceUnitIds: Object.freeze([...window.contextUnitIds, ...window.coreUnitIds]),
141
+ ...(latest.diagnostics.segmentationIssues === undefined ? {}
142
+ : { segmentationIssues: Object.freeze(latest.diagnostics.segmentationIssues.map((issue) => Object.freeze({ ...issue }))) }),
143
+ });
144
+ }
145
+ async function requestFor(projectRoot, state, window, ids) {
146
+ const adaptiveRepair = await previousAttempt(projectRoot, state, window, ids);
147
+ const structuredRequest = prepareDocumentGraphWindowRequest({ window, source: state.source,
148
+ knownEntities: knownDocumentGraphEntities(state.source, [...state.completed.values()]), methodVersion: "harness-v1",
149
+ ...(adaptiveRepair === undefined ? {} : { adaptiveRepair }) });
150
+ const attempt = ids.length + 1;
151
+ const requestId = `document-harness-request:${sha256(stableJson({ operationId: state.descriptor.operationId,
152
+ windowId: window.id, attempt, sourceSha256: state.source.sourceSha256, planSha256: state.descriptor.planSha256,
153
+ methodSha256: state.descriptor.method.sha256, structuredRequest }))}`;
154
+ const core = new Set(window.coreUnitIds);
155
+ const allowed = new Set([...window.contextUnitIds, ...window.coreUnitIds]);
156
+ const evidenceUnits = state.source.units.filter((unit) => allowed.has(unit.id)).map((unit) => Object.freeze({
157
+ id: unit.id, kind: unit.kind, text: unit.text, core: core.has(unit.id), startOffset: unit.startOffset, endOffset: unit.endOffset,
158
+ }));
159
+ return Object.freeze({ schemaVersion: 1, operationId: state.descriptor.operationId, requestId, windowId: window.id,
160
+ attempt, maximumAttempts: DOCUMENT_INGESTION_CHECKPOINT_IDS.maxPartialAttempts, rawByteSha256: state.source.sourceSha256,
161
+ planSha256: state.descriptor.planSha256, methodSha256: state.descriptor.method.sha256,
162
+ evidenceUnits: Object.freeze(evidenceUnits), structuredRequest });
163
+ }
164
+ async function nextFromState(projectRoot, state) {
165
+ const summary = { schemaVersion: 1, processedWindows: state.completed.size, totalWindows: state.source.windows.length,
166
+ ...(state.descriptor.input.sourcePath === undefined ? {} : { sourcePath: state.descriptor.input.sourcePath }),
167
+ ...(state.descriptor.input.sourceStoragePath === undefined ? {} : { sourceStoragePath: state.descriptor.input.sourceStoragePath }) };
168
+ if (state.status.phase === "committed")
169
+ return Object.freeze({ ...summary, state: "committed" });
170
+ for (const window of state.source.windows) {
171
+ if (state.completed.has(window.id))
172
+ continue;
173
+ const ids = partialIds(state.status, window.id);
174
+ if (ids.length >= DOCUMENT_INGESTION_CHECKPOINT_IDS.maxPartialAttempts) {
175
+ const last = graphSegment(await readDocumentIngestionCheckpoint(projectRoot, state.descriptor.operationId, ids.at(-1)), window.id);
176
+ return Object.freeze({ ...summary, state: "repair_exhausted", windowId: window.id, attempts: ids.length,
177
+ reasons: Object.freeze(Object.keys(last.diagnostics.rejectionReasons).sort()) });
178
+ }
179
+ return Object.freeze({ ...summary, state: "request", request: await requestFor(projectRoot, state, window, ids) });
180
+ }
181
+ return Object.freeze({ ...summary, state: "ready_to_commit" });
182
+ }
183
+ /** 只保存用户选定的最终成书原文字节;不接收或记录 harness 对话。 */
184
+ export async function prepareHarnessDocumentIngestion(host, input, options) {
185
+ const abort = new AbortController();
186
+ abort.abort();
187
+ const receipt = await ingestHarnessDocument(host, input, { projectRoot: options.projectRoot,
188
+ modelConnection: unavailableModelConnection(), signal: abort.signal, concurrency: 1,
189
+ ...(options.sourceOptions === undefined ? {} : { sourceOptions: options.sourceOptions }) });
190
+ return Object.freeze({ receipt, next: await nextHarnessDocumentIngestion(options.projectRoot, receipt.operationId) });
191
+ }
192
+ /** 跨 CLI/MCP 调用可重复计算的下一请求;函数只读,不持久化 prompt 或聊天日志。 */
193
+ export async function nextHarnessDocumentIngestion(projectRoot, operationId) {
194
+ return nextFromState(projectRoot, await loadState(projectRoot, operationId));
195
+ }
196
+ async function validateCandidateForRequest(projectRoot, state, request, candidate) {
197
+ const window = state.source.windows.find((item) => item.id === request.windowId);
198
+ if (window === undefined)
199
+ fail("E_REFERENCE_MISSING", "harness request window 不存在", "HARNESS_WINDOW_MISSING");
200
+ const ids = partialIds(state.status, window.id).slice(0, request.attempt - 1);
201
+ const adaptiveRepair = await previousAttempt(projectRoot, state, window, ids);
202
+ try {
203
+ return validateDocumentGraphWindowCandidate({ window, source: state.source,
204
+ knownEntities: knownDocumentGraphEntities(state.source, [...state.completed.values()]), methodVersion: "harness-v1",
205
+ ...(adaptiveRepair === undefined ? {} : { adaptiveRepair }) }, candidate);
206
+ }
207
+ catch (error) {
208
+ if (error instanceof AuthoringBridgeError)
209
+ throw error;
210
+ fail("E_OPERATION_ID_CONFLICT", "harness request validation context 已损坏", "HARNESS_VALIDATION_CONTEXT_CONFLICT");
211
+ }
212
+ }
213
+ function ledgerPayload(ledger) {
214
+ return asJson({ schema_version: 1, operation_id: ledger.operationId, request_id: ledger.requestId,
215
+ candidate_sha256: ledger.candidateSha256, segment_sha256: ledger.segmentSha256, window_id: ledger.windowId,
216
+ attempt: ledger.attempt, accepted: ledger.accepted, graph_status: ledger.graphStatus, checkpoint_id: ledger.checkpointId });
217
+ }
218
+ async function acceptanceResult(projectRoot, ledger) {
219
+ return Object.freeze({ schemaVersion: 1, operationId: ledger.operationId, requestId: ledger.requestId,
220
+ windowId: ledger.windowId, attempt: ledger.attempt, accepted: ledger.accepted, graphStatus: ledger.graphStatus,
221
+ next: await nextHarnessDocumentIngestion(projectRoot, ledger.operationId) });
222
+ }
223
+ async function replayAcceptance(projectRoot, ledger, candidate) {
224
+ if (ledger.candidateSha256 !== candidate.sha256) {
225
+ fail("E_OPERATION_ID_CONFLICT", "同一 harness request_id 已绑定不同 response", "HARNESS_RESPONSE_DIGEST_CONFLICT", { request_id: ledger.requestId });
226
+ }
227
+ const state = await loadState(projectRoot, ledger.operationId);
228
+ let checkpoint;
229
+ try {
230
+ checkpoint = graphSegment(await readDocumentIngestionCheckpoint(projectRoot, ledger.operationId, ledger.checkpointId), ledger.windowId);
231
+ }
232
+ catch (error) {
233
+ if (error.code !== "ENOENT")
234
+ throw error;
235
+ }
236
+ if (checkpoint !== undefined) {
237
+ if (sha256(stableJson(asJson(checkpoint))) !== ledger.segmentSha256 || checkpoint.status !== ledger.graphStatus) {
238
+ fail("E_OPERATION_ID_CONFLICT", "harness acceptance checkpoint 与 ledger 不匹配", "HARNESS_ACCEPTANCE_LEDGER_CONFLICT");
239
+ }
240
+ return acceptanceResult(projectRoot, ledger);
241
+ }
242
+ if (state.status.phase !== "extracting") {
243
+ fail("E_OPERATION_ID_CONFLICT", "harness acceptance ledger 缺少对应 checkpoint", "HARNESS_ACCEPTANCE_LEDGER_CORRUPT");
244
+ }
245
+ const requestState = await nextFromState(projectRoot, state);
246
+ if (requestState.state !== "request" || requestState.request.requestId !== ledger.requestId) {
247
+ fail("E_OPERATION_ID_CONFLICT", "harness acceptance 恢复点已变化", "HARNESS_REQUEST_STALE");
248
+ }
249
+ const segment = await validateCandidateForRequest(projectRoot, state, requestState.request, candidate.value);
250
+ if (sha256(stableJson(asJson(segment))) !== ledger.segmentSha256 || segment.status !== ledger.graphStatus) {
251
+ fail("E_OPERATION_ID_CONFLICT", "harness response 无法重建 ledger 中的校验结果", "HARNESS_ACCEPTANCE_LEDGER_CONFLICT");
252
+ }
253
+ const journal = await openDocumentIngestionJournal({ projectRoot, operationId: ledger.operationId,
254
+ sourceByteSha256: state.status.sourceByteSha256, planSha256: state.status.planSha256,
255
+ modelId: state.status.modelId, expectedProjectRevision: state.status.expectedProjectRevision,
256
+ ...(state.status.method === undefined ? {} : { method: state.status.method }) });
257
+ try {
258
+ if (await journal.readSegment(ledger.checkpointId) === null) {
259
+ await journal.writeSegment(ledger.checkpointId, asJson(segment));
260
+ if (segment.status === "partial") {
261
+ await journal.recordSegmentFailure(ledger.windowId, { code: ledger.attempt >= DOCUMENT_INGESTION_CHECKPOINT_IDS.maxPartialAttempts
262
+ ? "document_graph_partial_retry_exhausted" : "document_graph_partial",
263
+ retryable: ledger.attempt < DOCUMENT_INGESTION_CHECKPOINT_IDS.maxPartialAttempts, attempts: ledger.attempt });
264
+ }
265
+ else
266
+ await journal.clearSegmentFailure(ledger.windowId);
267
+ }
268
+ }
269
+ finally {
270
+ await journal.close();
271
+ }
272
+ return acceptanceResult(projectRoot, ledger);
273
+ }
274
+ /** requestId 是对 source/method/checkpoint/prompt 的 CAS;只把校验后的 GraphSegment 写入 journal。 */
275
+ export async function acceptHarnessDocumentIngestion(projectRoot, operationId, requestId, candidate,
276
+ /** 仅用于模块测试模拟 ledger 与 checkpoint 之间的进程中断;产品调用必须省略。 */
277
+ dependencies = {}) {
278
+ const normalized = normalizedCandidate(candidate);
279
+ const existing = await readAcceptanceLedger(projectRoot, operationId, requestId);
280
+ if (existing !== null)
281
+ return replayAcceptance(projectRoot, existing, normalized);
282
+ const state = await loadState(projectRoot, operationId);
283
+ const next = await nextFromState(projectRoot, state);
284
+ if (next.state !== "request" || next.request.requestId !== requestId || next.request.operationId !== operationId) {
285
+ fail("E_OPERATION_ID_CONFLICT", "harness request_id 已过期或不属于该 operation", "HARNESS_REQUEST_STALE", { operation_id: operationId });
286
+ }
287
+ const request = next.request;
288
+ const window = state.source.windows.find((item) => item.id === request.windowId);
289
+ const ids = partialIds(state.status, window.id);
290
+ const segment = await validateCandidateForRequest(projectRoot, state, request, normalized.value);
291
+ const checkpointId = segment.status === "partial"
292
+ ? `${DOCUMENT_INGESTION_CHECKPOINT_IDS.partialAttemptPrefix}${window.id}:${request.attempt}`
293
+ : request.attempt === 1 ? window.id : `${DOCUMENT_INGESTION_CHECKPOINT_IDS.retryCompletePrefix}${window.id}`;
294
+ const ledger = Object.freeze({ schemaVersion: 1, operationId, requestId,
295
+ candidateSha256: normalized.sha256, segmentSha256: sha256(stableJson(asJson(segment))), windowId: window.id,
296
+ attempt: request.attempt, accepted: segment.status === "complete", graphStatus: segment.status, checkpointId });
297
+ const journal = await openDocumentIngestionJournal({ projectRoot, operationId,
298
+ sourceByteSha256: state.status.sourceByteSha256, planSha256: state.status.planSha256,
299
+ modelId: state.status.modelId, expectedProjectRevision: state.status.expectedProjectRevision,
300
+ ...(state.status.method === undefined ? {} : { method: state.status.method }) });
301
+ let concurrentLedger;
302
+ try {
303
+ const current = await journal.getStatus();
304
+ const currentIds = partialIds(current, window.id);
305
+ const retryId = `${DOCUMENT_INGESTION_CHECKPOINT_IDS.retryCompletePrefix}${window.id}`;
306
+ const ledgerValue = await journal.readSegment(acceptanceCheckpointId(requestId));
307
+ if (ledgerValue !== null) {
308
+ concurrentLedger = parseAcceptanceLedger(ledgerValue);
309
+ if (concurrentLedger.candidateSha256 !== normalized.sha256) {
310
+ fail("E_OPERATION_ID_CONFLICT", "同一 harness request_id 已绑定不同 response", "HARNESS_RESPONSE_DIGEST_CONFLICT", { request_id: requestId });
311
+ }
312
+ }
313
+ else {
314
+ if (current.phase !== "extracting" || currentIds.length !== ids.length
315
+ || current.completedSegmentIds.includes(window.id) || current.completedSegmentIds.includes(retryId)) {
316
+ fail("E_OPERATION_ID_CONFLICT", "harness request_id 已过期", "HARNESS_REQUEST_STALE", { request_id: requestId });
317
+ }
318
+ // 先持久化不含原始 response 的 digest ledger;进程若在下一写入前退出,重复 accept 可安全补齐 checkpoint。
319
+ await journal.writeSegment(acceptanceCheckpointId(requestId), ledgerPayload(ledger));
320
+ await dependencies.afterAcceptanceLedgerPersist?.();
321
+ await journal.writeSegment(checkpointId, asJson(segment));
322
+ if (segment.status === "partial") {
323
+ await journal.recordSegmentFailure(window.id, { code: request.attempt >= request.maximumAttempts
324
+ ? "document_graph_partial_retry_exhausted" : "document_graph_partial", retryable: request.attempt < request.maximumAttempts,
325
+ attempts: request.attempt });
326
+ }
327
+ else
328
+ await journal.clearSegmentFailure(window.id);
329
+ }
330
+ }
331
+ finally {
332
+ await journal.close();
333
+ }
334
+ return concurrentLedger === undefined ? acceptanceResult(projectRoot, ledger) : replayAcceptance(projectRoot, concurrentLedger, normalized);
335
+ }
336
+ /** 所有窗口 complete 后复用 losslessDocument 的唯一 assemble + world_apply CAS commit。 */
337
+ export async function commitHarnessDocumentIngestion(host, projectRoot, operationId) {
338
+ const next = await nextHarnessDocumentIngestion(projectRoot, operationId);
339
+ if (next.state !== "ready_to_commit" && next.state !== "committed") {
340
+ fail("E_VALIDATION_FAILED", "harness ingestion 尚未完成全部窗口校验", "HARNESS_INGESTION_NOT_READY", { state: next.state });
341
+ }
342
+ return resumeHarnessDocument(host, operationId, { projectRoot, modelConnection: unavailableModelConnection(), concurrency: 1 });
343
+ }
@@ -0,0 +1,43 @@
1
+ export * from "./cli-command.js";
2
+ export * from "./mcp.js";
3
+ export * from "./public-error.js";
4
+ export * from "./project-host.js";
5
+ export * from "./scenario-writer.js";
6
+ export * from "./desktop-authoring-runtime.js";
7
+ export * from "./ladybug-runtime.js";
8
+ export * from "./trigger-runtime.js";
9
+ export * from "./authoring-model-connection.js";
10
+ export * from "./account-model-proxy.js";
11
+ export * from "./local-account-embedding.js";
12
+ export * from "./authoring-ingestion.js";
13
+ export * from "./document-source.js";
14
+ export * from "./document-graph-extractor.js";
15
+ export * from "./document-ingestion-journal.js";
16
+ export * from "./document-ingestion.js";
17
+ export * from "./harness-document-ingestion.js";
18
+ export * from "./document-query.js";
19
+ export * from "./graph-traversal.js";
20
+ export * from "./retrieval-benchmark.js";
21
+ export * from "./document-dump.js";
22
+ export * from "./embedding-cache.js";
23
+ export * from "./prepared-embedding-cache.js";
24
+ export * from "./preview-browser-adapter.js";
25
+ export * from "./chromium-preview-browser-driver.js";
26
+ export * from "./prepared-embedding-cache.js";
27
+ export * from "./desktop-sidecar.js";
28
+ export * from "./local-gui-contract.js";
29
+ export * from "./local-gui-auth.js";
30
+ export * from "./local-gui-server.js";
31
+ export * from "./local-gui-workspace.js";
32
+ export * from "./project-auth.js";
33
+ export * from "./project-auth-transport.js";
34
+ export * from "./project-git.js";
35
+ export * from "./project-git-cli.js";
36
+ export * from "./preview-runtime.js";
37
+ export * from "./preview-browser-adapter.js";
38
+ export * from "./frozen-review.js";
39
+ export * from "./frozen-review-local-pipeline.js";
40
+ export * from "./cli/review.js";
41
+ export * from "./transfer-types.js";
42
+ export * from "./transfer.js";
43
+ export * from "./view-watcher.js";
package/dist/index.js ADDED
@@ -0,0 +1,43 @@
1
+ export * from "./cli-command.js";
2
+ export * from "./mcp.js";
3
+ export * from "./public-error.js";
4
+ export * from "./project-host.js";
5
+ export * from "./scenario-writer.js";
6
+ export * from "./desktop-authoring-runtime.js";
7
+ export * from "./ladybug-runtime.js";
8
+ export * from "./trigger-runtime.js";
9
+ export * from "./authoring-model-connection.js";
10
+ export * from "./account-model-proxy.js";
11
+ export * from "./local-account-embedding.js";
12
+ export * from "./authoring-ingestion.js";
13
+ export * from "./document-source.js";
14
+ export * from "./document-graph-extractor.js";
15
+ export * from "./document-ingestion-journal.js";
16
+ export * from "./document-ingestion.js";
17
+ export * from "./harness-document-ingestion.js";
18
+ export * from "./document-query.js";
19
+ export * from "./graph-traversal.js";
20
+ export * from "./retrieval-benchmark.js";
21
+ export * from "./document-dump.js";
22
+ export * from "./embedding-cache.js";
23
+ export * from "./prepared-embedding-cache.js";
24
+ export * from "./preview-browser-adapter.js";
25
+ export * from "./chromium-preview-browser-driver.js";
26
+ export * from "./prepared-embedding-cache.js";
27
+ export * from "./desktop-sidecar.js";
28
+ export * from "./local-gui-contract.js";
29
+ export * from "./local-gui-auth.js";
30
+ export * from "./local-gui-server.js";
31
+ export * from "./local-gui-workspace.js";
32
+ export * from "./project-auth.js";
33
+ export * from "./project-auth-transport.js";
34
+ export * from "./project-git.js";
35
+ export * from "./project-git-cli.js";
36
+ export * from "./preview-runtime.js";
37
+ export * from "./preview-browser-adapter.js";
38
+ export * from "./frozen-review.js";
39
+ export * from "./frozen-review-local-pipeline.js";
40
+ export * from "./cli/review.js";
41
+ export * from "./transfer-types.js";
42
+ export * from "./transfer.js";
43
+ export * from "./view-watcher.js";