@ttsc/graph 0.30.4 → 0.31.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 (292) hide show
  1. package/README.md +122 -30
  2. package/lib/CapturedProcessOutput.d.ts +47 -0
  3. package/lib/CapturedProcessOutput.js +3 -0
  4. package/lib/CapturedProcessOutput.js.map +1 -0
  5. package/lib/ILauncherOption.d.ts +22 -0
  6. package/lib/ILauncherOption.js +3 -0
  7. package/lib/ILauncherOption.js.map +1 -0
  8. package/lib/IProjectOptions.d.ts +18 -0
  9. package/lib/IProjectOptions.js +3 -0
  10. package/lib/IProjectOptions.js.map +1 -0
  11. package/lib/ParsedLauncherOptions.d.ts +13 -0
  12. package/lib/ParsedLauncherOptions.js +3 -0
  13. package/lib/ParsedLauncherOptions.js.map +1 -0
  14. package/lib/TtscGraphApplication.d.ts +38 -1
  15. package/lib/TtscGraphApplication.js +26 -1
  16. package/lib/TtscGraphApplication.js.map +1 -1
  17. package/lib/TtscGraphLauncherArguments.d.ts +115 -0
  18. package/lib/TtscGraphLauncherArguments.js +181 -0
  19. package/lib/TtscGraphLauncherArguments.js.map +1 -0
  20. package/lib/TtscGraphViewSnapshot.d.ts +35 -0
  21. package/lib/TtscGraphViewSnapshot.js +48 -0
  22. package/lib/TtscGraphViewSnapshot.js.map +1 -0
  23. package/lib/index.d.ts +9 -24
  24. package/lib/index.js +6 -128
  25. package/lib/index.js.map +1 -1
  26. package/lib/internal/GraphProcessTrace.d.ts +1 -0
  27. package/lib/internal/GraphProcessTrace.js +235 -0
  28. package/lib/internal/GraphProcessTrace.js.map +1 -0
  29. package/lib/launcherArgs.d.ts +75 -16
  30. package/lib/launcherArgs.js +77 -8
  31. package/lib/launcherArgs.js.map +1 -1
  32. package/lib/model/IArtifactDirectory.d.ts +26 -0
  33. package/lib/model/IArtifactDirectory.js +3 -0
  34. package/lib/model/IArtifactDirectory.js.map +1 -0
  35. package/lib/model/IArtifactInputs.d.ts +19 -0
  36. package/lib/model/IArtifactInputs.js +3 -0
  37. package/lib/model/IArtifactInputs.js.map +1 -0
  38. package/lib/model/IPublishedArtifacts.d.ts +76 -0
  39. package/lib/model/IPublishedArtifacts.js +3 -0
  40. package/lib/model/IPublishedArtifacts.js.map +1 -0
  41. package/lib/model/IPublishedArtifactsResident.d.ts +19 -0
  42. package/lib/model/IPublishedArtifactsResident.js +3 -0
  43. package/lib/model/IPublishedArtifactsResident.js.map +1 -0
  44. package/lib/model/ITtscLintDaemonTarget.d.ts +20 -0
  45. package/lib/model/ITtscLintDaemonTarget.js +3 -0
  46. package/lib/model/ITtscLintDaemonTarget.js.map +1 -0
  47. package/lib/model/TtscGraphLinePeer.d.ts +146 -0
  48. package/lib/model/TtscGraphLinePeer.js +213 -0
  49. package/lib/model/TtscGraphLinePeer.js.map +1 -0
  50. package/lib/model/TtscGraphMemory.d.ts +156 -16
  51. package/lib/model/TtscGraphMemory.js +228 -222
  52. package/lib/model/TtscGraphMemory.js.map +1 -1
  53. package/lib/model/TtscGraphNativeArguments.d.ts +40 -0
  54. package/lib/model/TtscGraphNativeArguments.js +64 -0
  55. package/lib/model/TtscGraphNativeArguments.js.map +1 -0
  56. package/lib/model/TtscGraphNodeId.d.ts +55 -3
  57. package/lib/model/TtscGraphNodeId.js +40 -2
  58. package/lib/model/TtscGraphNodeId.js.map +1 -1
  59. package/lib/model/TtscGraphProjection.d.ts +156 -0
  60. package/lib/model/TtscGraphProjection.js +390 -0
  61. package/lib/model/TtscGraphProjection.js.map +1 -0
  62. package/lib/model/TtscGraphProtocol.d.ts +28 -0
  63. package/lib/model/TtscGraphProtocol.js +928 -0
  64. package/lib/model/TtscGraphProtocol.js.map +1 -0
  65. package/lib/model/TtscGraphReadonly.d.ts +15 -0
  66. package/lib/model/TtscGraphReadonly.js +3 -0
  67. package/lib/model/TtscGraphReadonly.js.map +1 -0
  68. package/lib/model/TtscGraphRequestOptions.d.ts +16 -0
  69. package/lib/model/TtscGraphRequestOptions.js +3 -0
  70. package/lib/model/TtscGraphRequestOptions.js.map +1 -0
  71. package/lib/model/TtscGraphSession.d.ts +82 -36
  72. package/lib/model/TtscGraphSession.js +164 -1238
  73. package/lib/model/TtscGraphSession.js.map +1 -1
  74. package/lib/model/TtscGraphSessionOptions.d.ts +20 -0
  75. package/lib/model/TtscGraphSessionOptions.js +3 -0
  76. package/lib/model/TtscGraphSessionOptions.js.map +1 -0
  77. package/lib/model/TtscGraphSessionState.d.ts +187 -0
  78. package/lib/model/TtscGraphSessionState.js +417 -0
  79. package/lib/model/TtscGraphSessionState.js.map +1 -0
  80. package/lib/model/TtscGraphShardStore.d.ts +64 -3
  81. package/lib/model/TtscGraphShardStore.js +85 -15
  82. package/lib/model/TtscGraphShardStore.js.map +1 -1
  83. package/lib/model/TtscGraphSourceReader.d.ts +31 -8
  84. package/lib/model/TtscGraphSourceReader.js +37 -13
  85. package/lib/model/TtscGraphSourceReader.js.map +1 -1
  86. package/lib/model/TtscLintDaemon.d.ts +35 -17
  87. package/lib/model/TtscLintDaemon.js +39 -117
  88. package/lib/model/TtscLintDaemon.js.map +1 -1
  89. package/lib/model/TtscLintDaemonState.d.ts +69 -0
  90. package/lib/model/TtscLintDaemonState.js +166 -0
  91. package/lib/model/TtscLintDaemonState.js.map +1 -0
  92. package/lib/model/copyGraphRecords.d.ts +14 -0
  93. package/lib/model/copyGraphRecords.js +19 -0
  94. package/lib/model/copyGraphRecords.js.map +1 -0
  95. package/lib/model/copyGraphSnapshot.d.ts +17 -0
  96. package/lib/model/copyGraphSnapshot.js +33 -0
  97. package/lib/model/copyGraphSnapshot.js.map +1 -0
  98. package/lib/model/loadGraph.d.ts +19 -10
  99. package/lib/model/loadGraph.js +21 -12
  100. package/lib/model/loadGraph.js.map +1 -1
  101. package/lib/model/publishedArtifacts.d.ts +78 -97
  102. package/lib/model/publishedArtifacts.js +271 -85
  103. package/lib/model/publishedArtifacts.js.map +1 -1
  104. package/lib/nativeExecutable.d.ts +19 -8
  105. package/lib/nativeExecutable.js +75 -15
  106. package/lib/nativeExecutable.js.map +1 -1
  107. package/lib/reduce.d.ts +19 -45
  108. package/lib/reduce.js +19 -3
  109. package/lib/reduce.js.map +1 -1
  110. package/lib/resolveGraphBinary.d.ts +9 -0
  111. package/lib/resolveGraphBinary.js +11 -3
  112. package/lib/resolveGraphBinary.js.map +1 -1
  113. package/lib/runGraph.d.ts +21 -0
  114. package/lib/runGraph.js +83 -0
  115. package/lib/runGraph.js.map +1 -0
  116. package/lib/server/IResolvedGraphHandle.d.ts +22 -0
  117. package/lib/server/IResolvedGraphHandle.js +3 -0
  118. package/lib/server/IResolvedGraphHandle.js.map +1 -0
  119. package/lib/server/createServer.d.ts +14 -10
  120. package/lib/server/createServer.js +42 -39
  121. package/lib/server/createServer.js.map +1 -1
  122. package/lib/server/exportSurface.d.ts +23 -1
  123. package/lib/server/exportSurface.js +23 -1
  124. package/lib/server/exportSurface.js.map +1 -1
  125. package/lib/server/formatGraphFailure.d.ts +20 -0
  126. package/lib/server/formatGraphFailure.js +35 -0
  127. package/lib/server/formatGraphFailure.js.map +1 -0
  128. package/lib/server/pathPolicy.d.ts +70 -5
  129. package/lib/server/pathPolicy.js +66 -4
  130. package/lib/server/pathPolicy.js.map +1 -1
  131. package/lib/server/resolveHandle.d.ts +10 -5
  132. package/lib/server/resolveHandle.js +39 -7
  133. package/lib/server/resolveHandle.js.map +1 -1
  134. package/lib/server/resultAudit.d.ts +17 -14
  135. package/lib/server/resultAudit.js +56 -27
  136. package/lib/server/resultAudit.js.map +1 -1
  137. package/lib/server/resultNext.d.ts +26 -1
  138. package/lib/server/resultNext.js +14 -0
  139. package/lib/server/resultNext.js.map +1 -1
  140. package/lib/server/runDetails.d.ts +72 -15
  141. package/lib/server/runDetails.js +104 -69
  142. package/lib/server/runDetails.js.map +1 -1
  143. package/lib/server/runEntrypoints.d.ts +9 -0
  144. package/lib/server/runEntrypoints.js +9 -0
  145. package/lib/server/runEntrypoints.js.map +1 -1
  146. package/lib/server/runLookup.d.ts +13 -3
  147. package/lib/server/runLookup.js +19 -6
  148. package/lib/server/runLookup.js.map +1 -1
  149. package/lib/server/runOverview.d.ts +13 -4
  150. package/lib/server/runOverview.js +13 -4
  151. package/lib/server/runOverview.js.map +1 -1
  152. package/lib/server/runTour.d.ts +9 -0
  153. package/lib/server/runTour.js +33 -65
  154. package/lib/server/runTour.js.map +1 -1
  155. package/lib/server/runTrace.d.ts +25 -1
  156. package/lib/server/runTrace.js +133 -88
  157. package/lib/server/runTrace.js.map +1 -1
  158. package/lib/server/startServer.d.ts +16 -0
  159. package/lib/server/startServer.js +24 -1
  160. package/lib/server/startServer.js.map +1 -1
  161. package/lib/structures/ITtscGraphApplication.d.ts +95 -41
  162. package/lib/structures/ITtscGraphDecorator.d.ts +18 -0
  163. package/lib/structures/ITtscGraphDetails.d.ts +81 -6
  164. package/lib/structures/ITtscGraphDocTag.d.ts +17 -8
  165. package/lib/structures/ITtscGraphDump.d.ts +106 -8
  166. package/lib/structures/ITtscGraphEdge.d.ts +14 -2
  167. package/lib/structures/ITtscGraphEntrypoints.d.ts +81 -6
  168. package/lib/structures/ITtscGraphEscape.d.ts +24 -2
  169. package/lib/structures/ITtscGraphEvidence.d.ts +9 -0
  170. package/lib/structures/ITtscGraphLookup.d.ts +42 -9
  171. package/lib/structures/ITtscGraphNext.d.ts +12 -1
  172. package/lib/structures/ITtscGraphNode.d.ts +38 -11
  173. package/lib/structures/ITtscGraphOverview.d.ts +81 -6
  174. package/lib/structures/ITtscGraphSnapshot.d.ts +97 -2
  175. package/lib/structures/ITtscGraphSpan.d.ts +9 -0
  176. package/lib/structures/ITtscGraphTour.d.ts +83 -9
  177. package/lib/structures/ITtscGraphTrace.d.ts +99 -14
  178. package/lib/structures/RawDump.d.ts +22 -0
  179. package/lib/structures/RawDump.js +3 -0
  180. package/lib/structures/RawDump.js.map +1 -0
  181. package/lib/structures/RawEdge.d.ts +20 -0
  182. package/lib/structures/RawEdge.js +3 -0
  183. package/lib/structures/RawEdge.js.map +1 -0
  184. package/lib/structures/RawNode.d.ts +26 -0
  185. package/lib/structures/RawNode.js +3 -0
  186. package/lib/structures/RawNode.js.map +1 -0
  187. package/lib/structures/TtscGraphArtifactNodeKind.d.ts +9 -0
  188. package/lib/structures/TtscGraphArtifactNodeKind.js +9 -0
  189. package/lib/structures/TtscGraphArtifactNodeKind.js.map +1 -1
  190. package/lib/structures/TtscGraphDumpEdgeKind.d.ts +15 -1
  191. package/lib/structures/TtscGraphDumpNodeKind.d.ts +9 -0
  192. package/lib/structures/TtscGraphEdgeKind.d.ts +13 -4
  193. package/lib/structures/TtscGraphNodeKind.d.ts +9 -0
  194. package/lib/structures/TtscGraphNodeModifier.d.ts +9 -0
  195. package/lib/structures/ViewerLink.d.ts +20 -0
  196. package/lib/structures/ViewerLink.js +3 -0
  197. package/lib/structures/ViewerLink.js.map +1 -0
  198. package/lib/structures/ViewerNode.d.ts +24 -0
  199. package/lib/structures/ViewerNode.js +3 -0
  200. package/lib/structures/ViewerNode.js.map +1 -0
  201. package/lib/structures/ViewerPayload.d.ts +42 -0
  202. package/lib/structures/ViewerPayload.js +3 -0
  203. package/lib/structures/ViewerPayload.js.map +1 -0
  204. package/lib/view.d.ts +9 -0
  205. package/lib/view.js +203 -91
  206. package/lib/view.js.map +1 -1
  207. package/lib/viewer/viewer.js +1 -1
  208. package/package.json +8 -6
  209. package/src/CapturedProcessOutput.ts +50 -0
  210. package/src/ILauncherOption.ts +24 -0
  211. package/src/IProjectOptions.ts +19 -0
  212. package/src/ParsedLauncherOptions.ts +13 -0
  213. package/src/TtscGraphApplication.ts +38 -1
  214. package/src/TtscGraphLauncherArguments.ts +207 -0
  215. package/src/TtscGraphViewSnapshot.ts +46 -0
  216. package/src/index.ts +9 -160
  217. package/src/internal/GraphProcessTrace.ts +242 -0
  218. package/src/launcherArgs.ts +89 -23
  219. package/src/model/IArtifactDirectory.ts +27 -0
  220. package/src/model/IArtifactInputs.ts +21 -0
  221. package/src/model/IPublishedArtifacts.ts +81 -0
  222. package/src/model/IPublishedArtifactsResident.ts +24 -0
  223. package/src/model/ITtscLintDaemonTarget.ts +22 -0
  224. package/src/model/TtscGraphLinePeer.ts +318 -0
  225. package/src/model/TtscGraphMemory.ts +284 -246
  226. package/src/model/TtscGraphNativeArguments.ts +67 -0
  227. package/src/model/TtscGraphNodeId.ts +57 -3
  228. package/src/model/TtscGraphProjection.ts +473 -0
  229. package/src/model/TtscGraphProtocol.ts +90 -0
  230. package/src/model/TtscGraphReadonly.ts +17 -0
  231. package/src/model/TtscGraphRequestOptions.ts +16 -0
  232. package/src/model/TtscGraphSession.ts +196 -475
  233. package/src/model/TtscGraphSessionOptions.ts +22 -0
  234. package/src/model/TtscGraphSessionState.ts +558 -0
  235. package/src/model/TtscGraphShardStore.ts +99 -23
  236. package/src/model/TtscGraphSourceReader.ts +37 -15
  237. package/src/model/TtscLintDaemon.ts +55 -136
  238. package/src/model/TtscLintDaemonState.ts +174 -0
  239. package/src/model/copyGraphRecords.ts +17 -0
  240. package/src/model/copyGraphSnapshot.ts +30 -0
  241. package/src/model/loadGraph.ts +23 -12
  242. package/src/model/publishedArtifacts.ts +361 -182
  243. package/src/nativeExecutable.ts +93 -26
  244. package/src/reduce.ts +24 -51
  245. package/src/resolveGraphBinary.ts +13 -3
  246. package/src/runGraph.ts +90 -0
  247. package/src/server/IResolvedGraphHandle.ts +24 -0
  248. package/src/server/createServer.ts +16 -22
  249. package/src/server/exportSurface.ts +23 -1
  250. package/src/server/formatGraphFailure.ts +32 -0
  251. package/src/server/pathPolicy.ts +70 -5
  252. package/src/server/resolveHandle.ts +45 -14
  253. package/src/server/resultAudit.ts +58 -27
  254. package/src/server/resultNext.ts +26 -1
  255. package/src/server/runDetails.ts +138 -73
  256. package/src/server/runEntrypoints.ts +13 -1
  257. package/src/server/runLookup.ts +23 -7
  258. package/src/server/runOverview.ts +17 -5
  259. package/src/server/runTour.ts +44 -82
  260. package/src/server/runTrace.ts +175 -102
  261. package/src/server/startServer.ts +29 -1
  262. package/src/structures/ITtscGraphApplication.ts +95 -41
  263. package/src/structures/ITtscGraphDecorator.ts +18 -0
  264. package/src/structures/ITtscGraphDetails.ts +81 -6
  265. package/src/structures/ITtscGraphDocTag.ts +17 -8
  266. package/src/structures/ITtscGraphDump.ts +106 -8
  267. package/src/structures/ITtscGraphEdge.ts +14 -2
  268. package/src/structures/ITtscGraphEntrypoints.ts +81 -6
  269. package/src/structures/ITtscGraphEscape.ts +24 -2
  270. package/src/structures/ITtscGraphEvidence.ts +9 -0
  271. package/src/structures/ITtscGraphLookup.ts +42 -9
  272. package/src/structures/ITtscGraphNext.ts +12 -1
  273. package/src/structures/ITtscGraphNode.ts +38 -11
  274. package/src/structures/ITtscGraphOverview.ts +88 -6
  275. package/src/structures/ITtscGraphSnapshot.ts +117 -2
  276. package/src/structures/ITtscGraphSpan.ts +9 -0
  277. package/src/structures/ITtscGraphTour.ts +83 -9
  278. package/src/structures/ITtscGraphTrace.ts +100 -14
  279. package/src/structures/RawDump.ts +25 -0
  280. package/src/structures/RawEdge.ts +22 -0
  281. package/src/structures/RawNode.ts +31 -0
  282. package/src/structures/TtscGraphArtifactNodeKind.ts +9 -0
  283. package/src/structures/TtscGraphDumpEdgeKind.ts +15 -1
  284. package/src/structures/TtscGraphDumpNodeKind.ts +9 -0
  285. package/src/structures/TtscGraphEdgeKind.ts +13 -4
  286. package/src/structures/TtscGraphNodeKind.ts +9 -0
  287. package/src/structures/TtscGraphNodeModifier.ts +9 -0
  288. package/src/structures/ViewerLink.ts +22 -0
  289. package/src/structures/ViewerNode.ts +28 -0
  290. package/src/structures/ViewerPayload.ts +52 -0
  291. package/src/view.ts +208 -110
  292. package/src/viewer/legend.ts +119 -27
@@ -2,6 +2,8 @@ import fs from "node:fs";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
 
5
+ import type { CapturedProcessOutput } from "./CapturedProcessOutput";
6
+
5
7
  /**
6
8
  * Ensure a resolved native binary can be executed on POSIX installs.
7
9
  *
@@ -9,6 +11,15 @@ import path from "node:path";
9
11
  * package binaries without executable bits. The ttsc launcher already repairs
10
12
  * its native helper before spawning; @ttsc/graph has its own ttscgraph spawn
11
13
  * paths, so it must apply the same first-run repair here.
14
+ *
15
+ * @evidence contracts/common.md#principled-implementation POSIX executable access is checked before preserving existing permission bits and adding the required execution permissions.
16
+ * @evidence contracts/common.md#clear-and-simple-design This helper owns the native permission boundary for all graph spawn lanes.
17
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Permission repair addresses supported package installation differences; failures still reach the original spawn path.
18
+ * @evidence contracts/common.md#meaningful-documentation Native paragraphs explain the package-manager condition and why graph must apply its own spawn-boundary repair.
19
+ * @evidence contracts/performance.md#efficient-algorithms Permission repair uses constant-count access/stat/chmod operations without reading binary contents or scanning directories.
20
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work Permission is an effectful spawn precondition, not a completed producer result shared across requests.
21
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources This precondition retains no handle, task or historical entry after synchronous filesystem calls.
22
+ * @evidence contracts/portability.md#os-neutral-implementation Windows has no POSIX executable-bit requirement; other hosts use filesystem access and mode APIs rather than path spelling assumptions.
12
23
  */
13
24
  export function ensureExecutable(binary: string): void {
14
25
  if (process.platform === "win32") return;
@@ -25,15 +36,6 @@ export function ensureExecutable(binary: string): void {
25
36
  }
26
37
  }
27
38
 
28
- export interface CapturedProcessOutput {
29
- /** Close the descriptors and remove the backing files. */
30
- dispose(): void;
31
- /** Read one stream's text. */
32
- read(stream: "stdout" | "stderr"): string;
33
- stderrFd: number;
34
- stdoutFd: number;
35
- }
36
-
37
39
  /**
38
40
  * A pair of temporary files standing in for a child process's pipes.
39
41
  *
@@ -46,12 +48,27 @@ export interface CapturedProcessOutput {
46
48
  * the same answer everywhere. Reading the result back still materializes a
47
49
  * string, so V8's own maximum string length remains the outer bound — a
48
50
  * property of the runtime rather than a budget chosen here.
51
+ *
52
+ * @evidence contracts/common.md#principled-implementation Passing file descriptors avoids spawnSync's pipe-buffer limit while later UTF-8 reads preserve each output channel.
53
+ * @evidence contracts/common.md#clear-and-simple-design One factory transfers descriptor and directory ownership through a read/dispose handle; private helpers isolate cleanup.
54
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The capture uses supported spawn descriptors rather than patching child_process or imposing repository-sized output limits.
55
+ * @evidence contracts/common.md#meaningful-documentation Native paragraphs explain file capture, heap materialization and the runtime string-length boundary; the handle documents caller disposal.
56
+ * @evidence contracts/portability.md#os-neutral-implementation Native fs descriptors and path.join operate on every host; storage is created beneath the resolved physical system-temp directory.
57
+ * @evidence contracts/performance.md#efficient-algorithms Capturing writes directly to files; reading costs linear output bytes and materializes one stream string, with no pipe-buffer copy in this heap.
58
+ * @evidence contracts/performance.md#reuse-equivalent-work Stdout and stderr are distinct effectful streams from one child invocation; reruns require new storage and cannot reuse a prior result.
59
+ * @evidence contracts/performance.md#bound-retention-and-release-resources The returned owner disposes two descriptors and one directory; acquisition failure unwinds acquired storage and removal is best effort when foreign handles remain open.
49
60
  */
50
61
  export function captureProcessOutput(): CapturedProcessOutput {
51
62
  const directory = createCanonicalTempDirectory("ttscgraph-spawn-");
52
63
  const stdoutPath = path.join(directory, "stdout");
53
64
  const stderrPath = path.join(directory, "stderr");
54
- const stdoutFd = fs.openSync(stdoutPath, "w+");
65
+ let stdoutFd: number;
66
+ try {
67
+ stdoutFd = fs.openSync(stdoutPath, "w+");
68
+ } catch (error) {
69
+ removeQuietly(directory);
70
+ throw error;
71
+ }
55
72
  let stderrFd: number;
56
73
  try {
57
74
  stderrFd = fs.openSync(stderrPath, "w+");
@@ -62,20 +79,18 @@ export function captureProcessOutput(): CapturedProcessOutput {
62
79
  removeQuietly(directory);
63
80
  throw error;
64
81
  }
82
+ let disposed = false;
65
83
  return {
66
84
  dispose(): void {
85
+ if (disposed) return;
86
+ disposed = true;
67
87
  closeQuietly(stdoutFd);
68
88
  closeQuietly(stderrFd);
69
89
  removeQuietly(directory);
70
90
  },
71
91
  read(stream): string {
72
92
  const location = stream === "stdout" ? stdoutPath : stderrPath;
73
- try {
74
- return fs.readFileSync(location, "utf8");
75
- } catch {
76
- // A spawn that never launched leaves nothing behind.
77
- return "";
78
- }
93
+ return fs.readFileSync(location, "utf8");
79
94
  },
80
95
  stderrFd,
81
96
  stdoutFd,
@@ -85,24 +100,76 @@ export function captureProcessOutput(): CapturedProcessOutput {
85
100
  /** Create capture storage beneath the frozen physical system-temp parent. */
86
101
  function createCanonicalTempDirectory(prefix: string): string {
87
102
  const physicalParent = fs.realpathSync.native(os.tmpdir());
88
- if (!fs.lstatSync(physicalParent).isDirectory()) {
103
+ const parentIdentity = fs.lstatSync(physicalParent);
104
+ if (!parentIdentity.isDirectory()) {
89
105
  throw new Error(
90
106
  `@ttsc/graph: temporary directory parent is not a directory: ${physicalParent}`,
91
107
  );
92
108
  }
93
109
  const directory = fs.mkdtempSync(path.join(physicalParent, prefix));
94
- if (!fs.lstatSync(directory).isDirectory()) {
95
- throw new Error(
96
- `@ttsc/graph: temporary directory postflight is not a directory: ${directory}`,
110
+ let childIdentity: fs.Stats | undefined;
111
+ try {
112
+ childIdentity = fs.lstatSync(directory);
113
+ if (!childIdentity.isDirectory() || childIdentity.isSymbolicLink()) {
114
+ throw new Error(
115
+ `@ttsc/graph: temporary directory postflight is not a directory: ${directory}`,
116
+ );
117
+ }
118
+ const physicalDirectory = fs.realpathSync.native(directory);
119
+ if (path.dirname(physicalDirectory) !== physicalParent) {
120
+ throw new Error(
121
+ `@ttsc/graph: temporary directory escaped its physical parent: ${physicalDirectory}`,
122
+ );
123
+ }
124
+ return physicalDirectory;
125
+ } catch (error) {
126
+ removeUnchangedTempDirectory(
127
+ directory,
128
+ physicalParent,
129
+ prefix,
130
+ parentIdentity,
131
+ childIdentity,
97
132
  );
133
+ throw error;
98
134
  }
99
- const physicalDirectory = fs.realpathSync.native(directory);
100
- if (path.dirname(physicalDirectory) !== physicalParent) {
101
- throw new Error(
102
- `@ttsc/graph: temporary directory escaped its physical parent: ${physicalDirectory}`,
103
- );
135
+ }
136
+
137
+ /** Roll back only an unchanged direct child whose native ownership was seen. */
138
+ function removeUnchangedTempDirectory(
139
+ directory: string,
140
+ parent: string,
141
+ prefix: string,
142
+ parentIdentity: fs.Stats,
143
+ childIdentity: fs.Stats | undefined,
144
+ ): void {
145
+ if (
146
+ childIdentity === undefined ||
147
+ !childIdentity.isDirectory() ||
148
+ childIdentity.isSymbolicLink() ||
149
+ path.dirname(directory) !== parent ||
150
+ !path.basename(directory).startsWith(prefix)
151
+ )
152
+ return;
153
+ try {
154
+ const currentParent = fs.lstatSync(parent);
155
+ const currentChild = fs.lstatSync(directory);
156
+ if (
157
+ fs.realpathSync.native(parent) !== parent ||
158
+ !currentParent.isDirectory() ||
159
+ currentParent.isSymbolicLink() ||
160
+ currentParent.dev !== parentIdentity.dev ||
161
+ currentParent.ino !== parentIdentity.ino ||
162
+ !currentChild.isDirectory() ||
163
+ currentChild.isSymbolicLink() ||
164
+ currentChild.dev !== childIdentity.dev ||
165
+ currentChild.ino !== childIdentity.ino
166
+ )
167
+ return;
168
+ removeQuietly(directory);
169
+ } catch {
170
+ // Failed ownership checks leave storage untouched rather than delete a
171
+ // replacement or an unrelated canonical target.
104
172
  }
105
- return physicalDirectory;
106
173
  }
107
174
 
108
175
  /** Close a descriptor, ignoring one that is already closed. */
package/src/reduce.ts CHANGED
@@ -1,3 +1,10 @@
1
+ import type { RawDump } from "./structures/RawDump";
2
+ import type { RawEdge } from "./structures/RawEdge";
3
+ import type { RawNode } from "./structures/RawNode";
4
+ import type { ViewerLink } from "./structures/ViewerLink";
5
+ import type { ViewerNode } from "./structures/ViewerNode";
6
+ import type { ViewerPayload } from "./structures/ViewerPayload";
7
+
1
8
  // Reduce a raw `ttscgraph dump` to the payload the bundled 3D viewer renders.
2
9
  // The same pure transform is copied in
3
10
  // website/src/components/graph/TtscWebsiteGraphReduce.ts and
@@ -8,56 +15,6 @@
8
15
  // before serving, so the browser viewer only ever renders a ready
9
16
  // `{ nodes, links }`.
10
17
 
11
- export interface RawNode {
12
- id: string;
13
- name: string;
14
- kind: string;
15
- file: string;
16
- external?: boolean;
17
- ignored?: boolean;
18
- }
19
-
20
- export interface RawEdge {
21
- from: string;
22
- to: string;
23
- kind: string;
24
- }
25
-
26
- export interface RawDump {
27
- project?: string;
28
- nodes: RawNode[];
29
- edges: RawEdge[];
30
- }
31
-
32
- export interface ViewerNode {
33
- id: string;
34
- name: string;
35
- kind: string;
36
- file: string;
37
- degree: number;
38
- }
39
-
40
- export interface ViewerLink {
41
- source: string;
42
- target: string;
43
- kind: string;
44
- }
45
-
46
- export interface ViewerPayload {
47
- project: string;
48
- counts: {
49
- rawNodes: number;
50
- rawEdges: number;
51
- nodes: number;
52
- links: number;
53
- droppedExternal: number;
54
- droppedIgnored: number;
55
- droppedByCap: number;
56
- };
57
- nodes: ViewerNode[];
58
- links: ViewerLink[];
59
- }
60
-
61
18
  function posix(p: string): string {
62
19
  return p.replace(/\\/g, "/");
63
20
  }
@@ -233,9 +190,25 @@ const DISPLAY_KIND: Record<string, string> = {
233
190
  };
234
191
 
235
192
  function displayKind(kind: string): string {
236
- return DISPLAY_KIND[kind] ?? kind;
193
+ return Object.hasOwn(DISPLAY_KIND, kind) ? DISPLAY_KIND[kind]! : kind;
237
194
  }
238
195
 
196
+ /**
197
+ * Project a dump into a connected viewer graph, retaining high-degree nodes.
198
+ *
199
+ * Current portable coordinates retain their spelling. Legacy absolute paths are
200
+ * rerooted together, and node ids and edge endpoints use the same rewrite.
201
+ * Boundary and cap counters explain selection; isolated nodes are not drawn.
202
+ *
203
+ * @evidence contracts/common.md#principled-implementation Boundary selection precedes induced-edge filtering and degree ranking; final edge membership and matching identity rewrites preserve the displayed subgraph.
204
+ * @evidence contracts/common.md#clear-and-simple-design Pure projection separates path/identity codec, degree calculation and display-family mapping through private helpers.
205
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Paths outside the common root keep identity rather than collapse to basename; filters use producer flags and general kinds without fixture lists.
206
+ * @evidence contracts/common.md#meaningful-documentation Native prose explains legacy/current coordinates and selection losses; DTO members document identity, degree and each counter.
207
+ * @evidence contracts/performance.md#efficient-algorithms Node/edge scans and degree maps cost O(N+E); degree selection sorts at most N nodes, adding O(N log N), with temporary maps/arrays proportional to the input.
208
+ * @evidence contracts/performance.md#reuse-equivalent-work Within one projection, indexed live/kept id sets and degree maps serve multiple filters; callers share the resulting payload across render requests rather than repeat reduction.
209
+ * @evidence contracts/performance.md#bound-retention-and-release-resources Temporary arrays and indexes become unreachable after return; the caller owns only selected DTO arrays and counts, with selected populations bounded by maxNodes and induced edges.
210
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation rewrites path strings as text (separators and common root); it never opens, stats or resolves them.
211
+ */
239
212
  export function reduce(
240
213
  raw: RawDump,
241
214
  {
@@ -25,6 +25,15 @@ import path from "node:path";
25
25
  * or an API `cwd` option), defaulting to `process.cwd()` when no project was
26
26
  * named. A launcher started from an unrelated directory still resolves the
27
27
  * `ttsc` installed under the target project it was asked to graph.
28
+ *
29
+ * @evidence contracts/common.md#principled-implementation Project-anchored module resolution locates the peer ttsc and then its platform binary; an explicit absolute override has precedence.
30
+ * @evidence contracts/common.md#clear-and-simple-design One resolver owns override and peer-package lookup for all graph launchers.
31
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Resolution uses installed package contracts rather than guessing binary paths from repository layouts.
32
+ * @evidence contracts/common.md#meaningful-documentation Native paragraphs and the ordered list explain peer placement, override precedence and target-project anchoring.
33
+ * @evidence contracts/portability.md#os-neutral-implementation Native path checks and module resolution select the platform/architecture package; only Windows's required executable suffix differs explicitly.
34
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources returns a path string and opens no handle.
35
+ * @evidenceExclude contracts/performance.md#efficient-algorithms performs a constant number of module resolutions (ttsc, then its platform package).
36
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work resolves on every call and caches nothing, so a reinstall between calls is honored.
28
37
  */
29
38
  export function resolveGraphBinary(
30
39
  env: NodeJS.ProcessEnv = process.env,
@@ -37,9 +46,10 @@ export function resolveGraphBinary(
37
46
  try {
38
47
  // Anchor package lookup at the absolute project root so a relative `--cwd`
39
48
  // resolves the same way the native process interprets it.
40
- const ttscPackageJson = require.resolve("ttsc/package.json", {
41
- paths: [path.resolve(cwd)],
42
- });
49
+ const fromProject = createRequire(
50
+ path.join(path.resolve(cwd), "package.json"),
51
+ );
52
+ const ttscPackageJson = fromProject.resolve("ttsc/package.json");
43
53
  const fromTtsc = createRequire(ttscPackageJson);
44
54
  return fromTtsc.resolve(
45
55
  `@ttsc/${process.platform}-${process.arch}/bin/${exe}`,
@@ -0,0 +1,90 @@
1
+ import { TtscGraphLauncherArguments } from "./TtscGraphLauncherArguments";
2
+ import { GraphProcessTrace } from "./internal/GraphProcessTrace";
3
+ import { publishArtifacts } from "./model/publishedArtifacts";
4
+ import { ensureExecutable } from "./nativeExecutable";
5
+ import { resolveGraphBinary } from "./resolveGraphBinary";
6
+ import { startServer } from "./server/startServer";
7
+ import { runView } from "./view";
8
+
9
+ // The server version reported in the MCP handshake; read from this package.
10
+ const VERSION: string = (require("../package.json") as { version: string })
11
+ .version;
12
+
13
+ /**
14
+ * Run the `@ttsc/graph` launcher.
15
+ *
16
+ * - `view`: JS-orchestrated 3D viewer (dump -> reduce -> serve -> open).
17
+ * - `dump`: pass through to the native `ttscgraph dump`, which prints the whole
18
+ * graph as JSON for piping or the viewer.
19
+ * - Default: serve the MCP graph over stdio. The TypeScript server keeps a native
20
+ * incremental compiler session resident, checks the disk snapshot before each
21
+ * graph operation, and reuses the in-memory graph when unchanged; the agent's
22
+ * MCP client speaks JSON-RPC over this process's stdin/stdout.
23
+ *
24
+ * @evidence contracts/common.md#principled-implementation The first command token selects view, native dump or stdio MCP; shared project parsing supplies the producer coordinates consistently.
25
+ * @evidence contracts/common.md#clear-and-simple-design The launcher owns lane dispatch while viewer, server and native dump helpers own their respective execution boundaries.
26
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts A missing dump binary exposes only an explicitly qualified help summary; execution failures retain nonzero outcomes instead of fake graph answers.
27
+ * @evidence contracts/common.md#meaningful-documentation Native lane bullets explain observable CLI behavior and resident refresh ownership with a blank line before tags.
28
+ * @evidence contracts/portability.md#os-neutral-implementation Native lanes resolve the selected project's platform package and pass argv directly; stdio MCP uses Node transport APIs without shell path construction.
29
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources starts the stdio server (owned by startServer), runs a synchronous dump child to completion or hands over to runView, and keeps no handle itself.
30
+ * @evidenceExclude contracts/performance.md#efficient-algorithms dispatches on the first argv token to one lane and the lanes own the work.
31
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work runs one launcher lane per process invocation, so there is nothing to share.
32
+ */
33
+ export function runGraph(
34
+ argv: readonly string[] = process.argv.slice(2),
35
+ ): number | void {
36
+ if (argv[0] === "view") return runView(argv.slice(1));
37
+ if (argv[0] === "dump") return runDump(argv.slice(1));
38
+
39
+ const { cwd, tsconfig } = TtscGraphLauncherArguments.project(argv);
40
+ void startServer({ cwd, tsconfig, version: VERSION }).catch(
41
+ (error: unknown) => {
42
+ process.stderr.write(
43
+ `@ttsc/graph: ${error instanceof Error ? error.message : String(error)}\n`,
44
+ );
45
+ process.exit(1);
46
+ },
47
+ );
48
+ }
49
+
50
+ /**
51
+ * Pass `dump` through to the native binary, inheriting stdio so the JSON lands
52
+ * on this process's stdout. Returns the child's exit code.
53
+ */
54
+ function runDump(argv: readonly string[]): number {
55
+ // Resolve the native binary from the target project the caller named with
56
+ // `--cwd`, not from wherever the launcher process happened to start.
57
+ const { cwd, tsconfig, artifactsSpecified } =
58
+ TtscGraphLauncherArguments.dump(argv);
59
+ const binary = resolveGraphBinary(process.env, cwd);
60
+ if (binary === null) {
61
+ // `ttscgraph` owns the flag contract, so a resolvable binary always answers
62
+ // `--help` itself and stays the single source of truth. It cannot answer
63
+ // when it is absent, and that is exactly when a caller is most likely to be
64
+ // asking what the command needs — so fall back to a summary that names the
65
+ // authority rather than making usage unreachable behind an install error.
66
+ const fallback = TtscGraphLauncherArguments.missingDump(argv);
67
+ if (fallback.stdout !== undefined) process.stdout.write(fallback.stdout);
68
+ if (fallback.stderr !== undefined) process.stderr.write(fallback.stderr);
69
+ return fallback.code;
70
+ }
71
+ ensureExecutable(binary);
72
+ // The same artifacts `loadGraph` and the resident session ask for, so the
73
+ // three ways to reach a dump answer a citation the same way. A caller that
74
+ // named `--artifacts` itself owns the answer and is not overridden.
75
+ const published = artifactsSpecified
76
+ ? null
77
+ : publishArtifacts({ cwd, tsconfig });
78
+ const result = GraphProcessTrace.spawnSync(
79
+ binary,
80
+ TtscGraphLauncherArguments.dumpVector(argv, published?.file ?? null),
81
+ {
82
+ stdio: "inherit",
83
+ windowsHide: true,
84
+ },
85
+ );
86
+ const completion = TtscGraphLauncherArguments.dumpCompletion(result);
87
+ if (completion.diagnostic !== undefined)
88
+ process.stderr.write(completion.diagnostic);
89
+ return completion.code;
90
+ }
@@ -0,0 +1,24 @@
1
+ import { TtscGraphReadonly } from "../model/TtscGraphReadonly";
2
+ import { ITtscGraphNode as NodeShape } from "../structures/ITtscGraphNode";
3
+
4
+ type ITtscGraphNode = TtscGraphReadonly<NodeShape>;
5
+
6
+ /**
7
+ * Exact resolved node, ambiguous candidates or an empty unknown outcome.
8
+ *
9
+ * @evidence contracts/common.md#principled-implementation Optional node and candidates preserve the resolver's unique, ambiguous and absent states without fabricating identity.
10
+ * @evidence contracts/common.md#clear-and-simple-design One compact outcome is shared by direct-id, name and file-qualified resolution paths.
11
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Ranked candidates remain unresolved choices rather than a guessed definitive node.
12
+ * @evidence contracts/common.md#meaningful-documentation Native member comments distinguish uniquely resolved identity from ranked ambiguity.
13
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources data shape only: it holds no handle, task or retained state.
14
+ * @evidenceExclude contracts/performance.md#efficient-algorithms data shape only: it contains no loop or algorithm.
15
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work data shape only: it computes nothing another request could share.
16
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation data shape only: it touches no file, path or process.
17
+ */
18
+ export interface IResolvedGraphHandle {
19
+ /** Present when the handle identifies exactly one node. */
20
+ node?: ITtscGraphNode;
21
+
22
+ /** Ranked remaining choices when more than one identity matches. */
23
+ candidates?: ITtscGraphNode[];
24
+ }
@@ -12,37 +12,31 @@ import { ITtscGraphApplication } from "../structures/ITtscGraphApplication";
12
12
  * input and output schemas and its argument validator, with no hand-written
13
13
  * schema: the interface's JSDoc becomes the handshake instructions, the
14
14
  * method's becomes the tool description, and every property's becomes the
15
- * description of that field — including `audit`, whose JSDoc is how a caller
16
- * learns what the server checked before it answered.
15
+ * description of that field — including `audit`, whose JSDoc explains fact
16
+ * provenance and coverage without claiming a second compiler check.
17
17
  *
18
- * The registration was hand-written here for a while, because a tool that
19
- * declares an output schema must answer with `structuredContent` and the helper
20
- * also serialized the same JSON into a text block: the payload crossed the wire
21
- * twice, a client counted both copies against its tool-result cap, and a 30 KB
22
- * tour arrived as 60 KB, blew the cap, and was spilled to a file the model then
23
- * shelled out to read back. `@typia/mcp` 13.1.0 ships the structured result
24
- * once (samchon/typia#2020), so the hand-written server had nothing left to fix
25
- * and the library owns the registration again.
18
+ * The library owns registration and sends structured results once by default.
19
+ * Its version option identifies this graph server in the handshake without
20
+ * changing SDK internals after construction.
21
+ *
22
+ * @evidence contracts/common.md#principled-implementation The typed controller supplies reflected schemas and executor dispatch; the supported version option sets the MCP implementation identity at construction.
23
+ * @evidence contracts/common.md#clear-and-simple-design The integration delegates registration and result serialization to the library instead of maintaining another transport implementation.
24
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Handshake version uses the public createMcpServer option; no SDK private field or foreign method is patched.
25
+ * @evidence contracts/common.md#meaningful-documentation Native paragraphs explain schema/JSDoc reflection, structured-result ownership and public version configuration.
26
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources returns a server whose transport lifetime startServer owns.
27
+ * @evidenceExclude contracts/performance.md#efficient-algorithms builds the MCP server once from the typia controller, with no loop of its own.
28
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work called once per process; the schema reflection happens at compile time.
29
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation creates an in-memory MCP server object; startServer attaches the stdio transport.
26
30
  */
27
31
  export function createServer(
28
32
  graph: TtscGraphSource,
29
33
  version: string,
30
34
  ): McpServer {
31
- const server = createMcpServer(
35
+ return createMcpServer(
32
36
  typia.llm.controller<ITtscGraphApplication>(
33
37
  "ttsc-graph",
34
38
  new TtscGraphApplication(graph),
35
39
  ),
40
+ { version },
36
41
  );
37
- // @typia/mcp 13.1.0 exposes no class-controller version option. The MCP SDK
38
- // keeps the initialize implementation on its public inner Server, so update
39
- // that already-constructed implementation before any transport connects.
40
- const inner = server.server as unknown as {
41
- _serverInfo?: { version: string };
42
- };
43
- if (inner._serverInfo === undefined) {
44
- throw new Error("@ttsc/graph: MCP SDK omitted the server implementation");
45
- }
46
- inner._serverInfo.version = version;
47
- return server;
48
42
  }
@@ -21,6 +21,15 @@ import { TtscGraphMemory } from "../model/TtscGraphMemory";
21
21
  *
22
22
  * The count is a fact the compiler resolved. It reads no package.json, guesses
23
23
  * from no filename, and holds for a project that has neither.
24
+ *
25
+ * @evidence contracts/common.md#principled-implementation Counting incoming exports edges reports modules whose checker-resolved export tables publish this exact node.
26
+ * @evidence contracts/common.md#clear-and-simple-design One predicate supplies the graph-derived public-surface signal to handle and tour ranking.
27
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts No package.json, file-name front-door guess or named project's expected score substitutes for export relationships.
28
+ * @evidence contracts/common.md#meaningful-documentation Native paragraphs explain barrel/re-export propagation and distinguish edge count from declaring-file exported status.
29
+ * @evidence contracts/performance.md#efficient-algorithms The incoming index restricts counting to this node's degree instead of scanning every graph edge.
30
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work This count is a primitive over an already shared generation index; caller-owned rank computation decides any broader reuse.
31
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources Counting borrows indexed edges and retains only a scalar local accumulator.
32
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation counts edges in an in-memory index.
24
33
  */
25
34
  export function exportFanIn(graph: TtscGraphMemory, id: string): number {
26
35
  let count = 0;
@@ -28,7 +37,20 @@ export function exportFanIn(graph: TtscGraphMemory, id: string): number {
28
37
  return count;
29
38
  }
30
39
 
31
- /** True when the dump carries an export surface at all. */
40
+ /**
41
+ * True when the graph carries an exports edge at all.
42
+ *
43
+ * The answer is cached by immutable graph generation, including false.
44
+ *
45
+ * @evidence contracts/common.md#principled-implementation Existence of an exports edge establishes collection of at least one module surface without guessing from local declaration flags.
46
+ * @evidence contracts/common.md#clear-and-simple-design A WeakMap holds the generation-wide predicate result for all rankers.
47
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts A false cached answer is retained as a real result rather than mistaken for a cache miss.
48
+ * @evidence contracts/common.md#meaningful-documentation Native prose states the edge criterion and generation-scoped caching.
49
+ * @evidence contracts/performance.md#efficient-algorithms The first check scans edges until a match; later lookups are map accesses.
50
+ * @evidence contracts/performance.md#reuse-equivalent-work The model's owned frozen facts make graph identity a stable generation key; a new generation is a different key and does not inherit the result.
51
+ * @evidence contracts/performance.md#bound-retention-and-release-resources WeakMap entries follow graph reachability and do not retain historical graph generations.
52
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation scans in-memory edges and caches the answer per graph object.
53
+ */
32
54
  export function hasExportSurface(graph: TtscGraphMemory): boolean {
33
55
  const known = cache.get(graph);
34
56
  if (known !== undefined) return known;
@@ -0,0 +1,32 @@
1
+ import { inspect } from "node:util";
2
+ import { serializeCompilerError } from "ttsc";
3
+
4
+ /**
5
+ * Render a terminal graph failure with its nested causes and aggregate members.
6
+ *
7
+ * The SDK's descriptor-based failure description preserves causes and shared
8
+ * references without evaluating getters. Node then displays that passive data
9
+ * without invoking custom inspectors. Proxy reflection retains the serializer's
10
+ * documented inspection limits.
11
+ *
12
+ * It is stderr text, not a serialization format or a retirement certificate.
13
+ *
14
+ * @evidence contracts/common.md#principled-implementation The SDK failure serializer preserves nested causes and aggregate members as passive data; Node inspection renders that finite description rather than projecting the outer message.
15
+ * @evidence contracts/common.md#clear-and-simple-design One renderer owns shutdown diagnostic text; the server continues to own its failing exit status.
16
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Diagnostic formatting changes no cleanup result, admission state or original lifetime proof.
17
+ * @evidence contracts/common.md#meaningful-documentation Native prose defines nested diagnostics, disabled user hooks and the absence of transport or retirement authority.
18
+ * @evidenceExclude contracts/portability.md#os-neutral-implementation This renderer observes JavaScript values and selects no OS path or process primitive.
19
+ * @evidence contracts/performance.md#efficient-algorithms Delegated serialization visits distinct observed objects and owned fields; unlimited diagnostic inspection then renders that finite description. Structural work and returned text grow with the observed diagnostic graph, excluding arbitrary Proxy reflection.
20
+ * @evidenceExclude contracts/performance.md#reuse-equivalent-work Each failure is rendered when reported; there is no reusable computation population.
21
+ * @evidenceExclude contracts/performance.md#bound-retention-and-release-resources The returned diagnostic string is caller-owned; no handle or retained cache is acquired.
22
+ */
23
+ export function formatGraphFailure(error: unknown): string {
24
+ return inspect(serializeCompilerError(error), {
25
+ depth: null,
26
+ customInspect: false,
27
+ getters: false,
28
+ colors: false,
29
+ maxArrayLength: null,
30
+ maxStringLength: null,
31
+ });
32
+ }