@chengxianglibra/dsh-data-analysis 0.1.1 → 0.2.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 (303) hide show
  1. package/README.md +139 -53
  2. package/cordis.patch.yml +1 -1
  3. package/lib/bin/environment.js +9 -7
  4. package/lib/bin/presentation-lint.js +21 -0
  5. package/lib/bridges.js +2 -2
  6. package/lib/client/credentials/changes.js +74 -0
  7. package/lib/client/credentials/create-datasource.js +171 -0
  8. package/lib/client/credentials/credential-draft.js +42 -0
  9. package/lib/client/credentials/defaults.js +11 -0
  10. package/lib/client/credentials/descriptions.js +46 -0
  11. package/lib/client/credentials/install.js +319 -0
  12. package/lib/client/credentials/model.js +766 -0
  13. package/lib/client/credentials/report-publishing.js +96 -0
  14. package/lib/client/credentials/styles.js +21 -0
  15. package/lib/client/i18n/context.js +22 -0
  16. package/lib/client/i18n/copy.js +57 -0
  17. package/lib/client/i18n/credentials.js +475 -0
  18. package/lib/client/i18n/host.js +27 -0
  19. package/lib/client/i18n/navigation.js +41 -0
  20. package/lib/client/i18n/presentation.js +577 -0
  21. package/lib/client/i18n/python.js +36 -0
  22. package/lib/client/i18n/semantic.js +441 -0
  23. package/lib/client/input-context.js +21 -0
  24. package/lib/client/python-tool/card.js +35 -0
  25. package/lib/client/python-tool/execution-error.js +35 -0
  26. package/lib/client/python-tool/install.js +9 -0
  27. package/lib/client/python-tool/model.js +101 -0
  28. package/lib/client/right-tabs/install.js +535 -0
  29. package/lib/client/right-tabs/live-delivery.js +58 -0
  30. package/lib/client/right-tabs/navigation.js +47 -0
  31. package/lib/client/right-tabs/page.js +178 -0
  32. package/lib/client/right-tabs/styles.js +11 -0
  33. package/lib/client/rpc.js +5 -0
  34. package/lib/client/semantic-reference.js +10 -0
  35. package/lib/client/workspace-header-action.js +24 -0
  36. package/lib/client/workspace-shortcuts.js +26 -0
  37. package/lib/client.js +1250 -730
  38. package/lib/compatibility.js +2 -2
  39. package/lib/datasource/authoring.js +109 -0
  40. package/lib/datasource/bridge-programs.js +42 -27
  41. package/lib/datasource/bridge.js +144 -9
  42. package/lib/datasource/changes-contract.js +41 -0
  43. package/lib/datasource/changes.js +49 -0
  44. package/lib/datasource/configure.js +39 -0
  45. package/lib/datasource/defaults.js +25 -0
  46. package/lib/datasource/index.js +4 -2
  47. package/lib/datasource/python-options.js +21 -0
  48. package/lib/datasource/python.js +206 -0
  49. package/lib/datasource/resolver-program.js +112 -0
  50. package/lib/datasource/rpc.js +150 -0
  51. package/lib/datasource/service.js +962 -0
  52. package/lib/datasource/shell-env.js +2 -333
  53. package/lib/datasource/test.js +25 -51
  54. package/lib/disclosure/activation.js +19 -7
  55. package/lib/disclosure/execution-guidance.js +52 -0
  56. package/lib/disclosure/help.js +4 -1
  57. package/lib/environment/binding.js +54 -9
  58. package/lib/environment/runtime.js +120 -108
  59. package/lib/environment/subprocess.js +6 -1
  60. package/lib/environment/summary.js +3 -3
  61. package/lib/environment/workspace.js +23 -1
  62. package/lib/index.js +1 -1
  63. package/lib/lifecycle.js +33 -0
  64. package/lib/plugin-agents.js +154 -0
  65. package/lib/plugin.js +172 -133
  66. package/lib/presentation/asset.js +34 -0
  67. package/lib/presentation/assets/portable.js +606 -0
  68. package/lib/presentation/assets/static.js +1216 -0
  69. package/lib/presentation/build/index.js +72 -0
  70. package/lib/presentation/commit.js +163 -0
  71. package/lib/presentation/contracts/asset-path.js +9 -0
  72. package/lib/presentation/contracts/catalog.js +62 -0
  73. package/lib/presentation/contracts/charts.js +453 -0
  74. package/lib/presentation/contracts/editing.js +58 -0
  75. package/lib/presentation/contracts/index.js +663 -0
  76. package/lib/presentation/contracts/interaction.js +62 -0
  77. package/lib/presentation/contracts/types.js +15 -0
  78. package/lib/presentation/contracts/values.js +28 -0
  79. package/lib/presentation/delivery.js +71 -0
  80. package/lib/presentation/export-html.js +214 -0
  81. package/lib/presentation/files.js +82 -0
  82. package/lib/presentation/index.js +6 -0
  83. package/lib/presentation/lint.js +46 -0
  84. package/lib/presentation/projection/files.js +85 -0
  85. package/lib/presentation/projection/index.js +196 -0
  86. package/lib/presentation/projection/program.js +137 -0
  87. package/lib/presentation/projection/sql-code.js +79 -0
  88. package/lib/presentation/receipt.js +34 -0
  89. package/lib/presentation/reports.js +219 -0
  90. package/lib/presentation/rpc.js +186 -0
  91. package/lib/presentation/tool.js +118 -0
  92. package/lib/python-execution-contracts.js +1 -0
  93. package/lib/python-execution.js +232 -0
  94. package/lib/report-publishing/adapters.js +111 -0
  95. package/lib/report-publishing/config.js +69 -0
  96. package/lib/report-publishing/service.js +180 -0
  97. package/lib/rpc.js +49 -0
  98. package/lib/semantic-browser/contracts.js +97 -0
  99. package/lib/semantic-browser/definition.js +64 -0
  100. package/lib/semantic-browser/program.js +129 -0
  101. package/lib/semantic-browser/service.js +106 -0
  102. package/lib/semantic-reference/bridge.js +127 -0
  103. package/lib/semantic-reference/contracts.js +127 -0
  104. package/lib/semantic-reference/environment.js +56 -0
  105. package/lib/semantic-reference/index.js +3 -0
  106. package/lib/semantic-reference/labels.js +16 -0
  107. package/lib/semantic-reference/rpc.js +143 -0
  108. package/lib/semantic-reference/search.js +95 -0
  109. package/lib/semantic-reference/usage.js +152 -0
  110. package/lib/tool-lifecycle.js +22 -0
  111. package/lib/types/bridges.d.ts +2 -2
  112. package/lib/types/client/credentials/changes.d.ts +9 -0
  113. package/lib/types/client/credentials/create-datasource.d.ts +7 -0
  114. package/lib/types/client/credentials/credential-draft.d.ts +14 -0
  115. package/lib/types/client/credentials/defaults.d.ts +2 -0
  116. package/lib/types/client/credentials/descriptions.d.ts +1 -0
  117. package/lib/types/client/credentials/install.d.ts +19 -0
  118. package/lib/types/client/credentials/model.d.ts +79 -0
  119. package/lib/types/client/credentials/report-publishing.d.ts +5 -0
  120. package/lib/types/client/credentials/styles.d.ts +1 -0
  121. package/lib/types/client/i18n/context.d.ts +17 -0
  122. package/lib/types/client/i18n/copy.d.ts +806 -0
  123. package/lib/types/client/i18n/credentials.d.ts +475 -0
  124. package/lib/types/client/i18n/host.d.ts +16 -0
  125. package/lib/types/client/i18n/navigation.d.ts +41 -0
  126. package/lib/types/client/i18n/presentation.d.ts +577 -0
  127. package/lib/types/client/i18n/python.d.ts +19 -0
  128. package/lib/types/client/i18n/semantic.d.ts +441 -0
  129. package/lib/types/client/input-context.d.ts +19 -0
  130. package/lib/types/client/presentation/ask-dsh.d.ts +5 -0
  131. package/lib/types/client/presentation/catalog-model.d.ts +24 -0
  132. package/lib/types/client/presentation/catalog.d.ts +20 -0
  133. package/lib/types/client/presentation/chart-explorer.d.ts +12 -0
  134. package/lib/types/client/presentation/chart-geometry.d.ts +30 -0
  135. package/lib/types/client/presentation/chart-renderer.d.ts +10 -0
  136. package/lib/types/client/presentation/chart-specials.d.ts +10 -0
  137. package/lib/types/client/presentation/chart-styles.d.ts +1 -0
  138. package/lib/types/client/presentation/chart-tooltip.d.ts +13 -0
  139. package/lib/types/client/presentation/chart-view.d.ts +23 -0
  140. package/lib/types/client/presentation/context-reference.d.ts +12 -0
  141. package/lib/types/client/presentation/copy-context.d.ts +5 -0
  142. package/lib/types/client/presentation/delivery-model.d.ts +75 -0
  143. package/lib/types/client/presentation/delivery.d.ts +78 -0
  144. package/lib/types/client/presentation/download.d.ts +2 -0
  145. package/lib/types/client/presentation/editor-controls.d.ts +12 -0
  146. package/lib/types/client/presentation/export-menu.d.ts +26 -0
  147. package/lib/types/client/presentation/export-view.d.ts +63 -0
  148. package/lib/types/client/presentation/global-filters.d.ts +6 -0
  149. package/lib/types/client/presentation/host-entry.d.ts +18 -0
  150. package/lib/types/client/presentation/icons.d.ts +4 -0
  151. package/lib/types/client/presentation/markdown.d.ts +5 -0
  152. package/lib/types/client/presentation/model.d.ts +61 -0
  153. package/lib/types/client/presentation/reader.d.ts +24 -0
  154. package/lib/types/client/presentation/reference-source.d.ts +9 -0
  155. package/lib/types/client/presentation/source-code-model.d.ts +17 -0
  156. package/lib/types/client/presentation/source-code.d.ts +6 -0
  157. package/lib/types/client/presentation/source-dialog.d.ts +12 -0
  158. package/lib/types/client/presentation/source-facts.d.ts +20 -0
  159. package/lib/types/client/presentation/source-format.d.ts +5 -0
  160. package/lib/types/client/presentation/source-highlight.d.ts +7 -0
  161. package/lib/types/client/presentation/sources.d.ts +13 -0
  162. package/lib/types/client/presentation/styles.d.ts +1 -0
  163. package/lib/types/client/presentation/table.d.ts +16 -0
  164. package/lib/types/client/presentation/use-element-width.d.ts +5 -0
  165. package/lib/types/client/python-tool/card.d.ts +2 -0
  166. package/lib/types/client/python-tool/execution-error.d.ts +3 -0
  167. package/lib/types/client/python-tool/install.d.ts +2 -0
  168. package/lib/types/client/python-tool/model.d.ts +20 -0
  169. package/lib/types/client/right-tabs/install.d.ts +18 -0
  170. package/lib/types/client/right-tabs/live-delivery.d.ts +8 -0
  171. package/lib/types/client/right-tabs/navigation.d.ts +17 -0
  172. package/lib/types/client/right-tabs/page.d.ts +36 -0
  173. package/lib/types/client/right-tabs/styles.d.ts +2 -0
  174. package/lib/types/client/rpc.d.ts +3 -0
  175. package/lib/types/client/semantic-reference.d.ts +4 -0
  176. package/lib/types/client/workspace-header-action.d.ts +7 -0
  177. package/lib/types/client/workspace-shortcuts.d.ts +15 -0
  178. package/lib/types/client.d.ts +9 -124
  179. package/lib/types/compatibility.d.ts +3 -3
  180. package/lib/types/datasource/authoring.d.ts +35 -0
  181. package/lib/types/datasource/bridge.d.ts +43 -4
  182. package/lib/types/datasource/changes-contract.d.ts +18 -0
  183. package/lib/types/datasource/changes.d.ts +15 -0
  184. package/lib/types/datasource/configure.d.ts +7 -0
  185. package/lib/types/datasource/defaults.d.ts +7 -0
  186. package/lib/types/datasource/index.d.ts +8 -5
  187. package/lib/types/datasource/python-options.d.ts +9 -0
  188. package/lib/types/datasource/python.d.ts +19 -0
  189. package/lib/types/datasource/resolver-program.d.ts +6 -0
  190. package/lib/types/datasource/rpc.d.ts +5 -0
  191. package/lib/types/datasource/service.d.ts +155 -0
  192. package/lib/types/datasource/shell-env.d.ts +0 -29
  193. package/lib/types/datasource/test.d.ts +6 -29
  194. package/lib/types/disclosure/activation.d.ts +2 -1
  195. package/lib/types/disclosure/execution-guidance.d.ts +6 -0
  196. package/lib/types/disclosure/help.d.ts +1 -1
  197. package/lib/types/environment/binding.d.ts +5 -1
  198. package/lib/types/environment/errors.d.ts +1 -1
  199. package/lib/types/environment/runtime.d.ts +5 -5
  200. package/lib/types/environment/types.d.ts +15 -3
  201. package/lib/types/environment/workspace.d.ts +1 -0
  202. package/lib/types/index.d.ts +1 -1
  203. package/lib/types/lifecycle.d.ts +8 -0
  204. package/lib/types/plugin-agents.d.ts +27 -0
  205. package/lib/types/plugin.d.ts +14 -24
  206. package/lib/types/presentation/asset.d.ts +6 -0
  207. package/lib/types/presentation/build/index.d.ts +16 -0
  208. package/lib/types/presentation/commit.d.ts +4 -0
  209. package/lib/types/presentation/contracts/asset-path.d.ts +2 -0
  210. package/lib/types/presentation/contracts/catalog.d.ts +27 -0
  211. package/lib/types/presentation/contracts/charts.d.ts +11 -0
  212. package/lib/types/presentation/contracts/editing.d.ts +8 -0
  213. package/lib/types/presentation/contracts/index.d.ts +11 -0
  214. package/lib/types/presentation/contracts/interaction.d.ts +8 -0
  215. package/lib/types/presentation/contracts/types.d.ts +255 -0
  216. package/lib/types/presentation/contracts/values.d.ts +9 -0
  217. package/lib/types/presentation/delivery.d.ts +3 -0
  218. package/lib/types/presentation/export-html.d.ts +13 -0
  219. package/lib/types/presentation/files.d.ts +7 -0
  220. package/lib/types/presentation/index.d.ts +6 -0
  221. package/lib/types/presentation/lint.d.ts +13 -0
  222. package/lib/types/presentation/projection/files.d.ts +2 -0
  223. package/lib/types/presentation/projection/index.d.ts +20 -0
  224. package/lib/types/presentation/projection/program.d.ts +2 -0
  225. package/lib/types/presentation/projection/sql-code.d.ts +2 -0
  226. package/lib/types/presentation/receipt.d.ts +14 -0
  227. package/lib/types/presentation/reports.d.ts +10 -0
  228. package/lib/types/presentation/rpc.d.ts +25 -0
  229. package/lib/types/presentation/tool.d.ts +12 -0
  230. package/lib/types/python-execution-contracts.d.ts +10 -0
  231. package/lib/types/python-execution.d.ts +10 -0
  232. package/lib/types/report-publishing/adapters.d.ts +6 -0
  233. package/lib/types/report-publishing/config.d.ts +22 -0
  234. package/lib/types/report-publishing/service.d.ts +68 -0
  235. package/lib/types/rpc.d.ts +3 -0
  236. package/lib/types/semantic-browser/contracts.d.ts +47 -0
  237. package/lib/types/semantic-browser/definition.d.ts +20 -0
  238. package/lib/types/semantic-browser/program.d.ts +2 -0
  239. package/lib/types/semantic-browser/service.d.ts +26 -0
  240. package/lib/types/semantic-reference/bridge.d.ts +12 -0
  241. package/lib/types/semantic-reference/contracts.d.ts +54 -0
  242. package/lib/types/semantic-reference/environment.d.ts +22 -0
  243. package/lib/types/semantic-reference/index.d.ts +3 -0
  244. package/lib/types/semantic-reference/labels.d.ts +16 -0
  245. package/lib/types/semantic-reference/rpc.d.ts +15 -0
  246. package/lib/types/semantic-reference/search.d.ts +10 -0
  247. package/lib/types/semantic-reference/usage.d.ts +43 -0
  248. package/lib/types/tool-lifecycle.d.ts +4 -0
  249. package/lib/types/workspace-identity.d.ts +6 -0
  250. package/lib/workspace-identity.js +9 -0
  251. package/package.json +99 -53
  252. package/python/presentation-kit/dist/dsh_data_analysis_presentation_kit-1.1.0-py3-none-any.whl +0 -0
  253. package/skills/dsh-data-analysis-files/SKILL.md +32 -0
  254. package/skills/dsh-data-analysis-files/references/examples.md +93 -0
  255. package/skills/dsh-data-analysis-presentation/SKILL.md +28 -0
  256. package/skills/dsh-data-analysis-presentation/references/chart-examples.md +18 -0
  257. package/skills/dsh-data-analysis-presentation/references/charts.md +55 -0
  258. package/skills/dsh-data-analysis-presentation/references/examples/artifact.draft.json +36 -0
  259. package/skills/dsh-data-analysis-presentation/references/examples/charts-bins.dataset.json +33 -0
  260. package/skills/dsh-data-analysis-presentation/references/examples/charts-boxes.dataset.json +45 -0
  261. package/skills/dsh-data-analysis-presentation/references/examples/charts-composition.dataset.json +33 -0
  262. package/skills/dsh-data-analysis-presentation/references/examples/charts-funnel.dataset.json +27 -0
  263. package/skills/dsh-data-analysis-presentation/references/examples/charts-precision.dataset.json +21 -0
  264. package/skills/dsh-data-analysis-presentation/references/examples/charts-series.dataset.json +58 -0
  265. package/skills/dsh-data-analysis-presentation/references/examples/charts-shares.dataset.json +33 -0
  266. package/skills/dsh-data-analysis-presentation/references/examples/charts-waterfall.dataset.json +44 -0
  267. package/skills/dsh-data-analysis-presentation/references/examples/charts.draft.json +393 -0
  268. package/skills/dsh-data-analysis-presentation/references/examples/comparison-selected.dataset.json +24 -0
  269. package/skills/dsh-data-analysis-presentation/references/examples/comparison-summary.dataset.json +22 -0
  270. package/skills/dsh-data-analysis-presentation/references/examples/comparison.dataset.json +18 -0
  271. package/skills/dsh-data-analysis-presentation/references/examples/comparison.draft.json +80 -0
  272. package/skills/dsh-data-analysis-presentation/references/examples/computed-sources.draft.json +42 -0
  273. package/skills/dsh-data-analysis-presentation/references/examples/computed.dataset.json +12 -0
  274. package/skills/dsh-data-analysis-presentation/references/examples/computed.draft.json +58 -0
  275. package/skills/dsh-data-analysis-presentation/references/examples/interaction-detail.dataset.json +30 -0
  276. package/skills/dsh-data-analysis-presentation/references/examples/interaction-summary.dataset.json +22 -0
  277. package/skills/dsh-data-analysis-presentation/references/examples/interaction.draft.json +279 -0
  278. package/skills/dsh-data-analysis-presentation/references/examples/source-only.draft.json +27 -0
  279. package/skills/dsh-data-analysis-presentation/references/examples/write-charts.py +73 -0
  280. package/skills/dsh-data-analysis-presentation/references/examples/write-comparison.py +42 -0
  281. package/skills/dsh-data-analysis-presentation/references/examples/write-computed.py +21 -0
  282. package/skills/dsh-data-analysis-presentation/references/examples/write-interaction.py +33 -0
  283. package/skills/dsh-data-analysis-presentation/references/examples.md +44 -0
  284. package/skills/dsh-data-analysis-presentation/references/export-html.md +7 -0
  285. package/skills/dsh-data-analysis-presentation/references/interaction.md +56 -0
  286. package/skills/dsh-data-analysis-presentation/references/narrative.md +37 -0
  287. package/skills/dsh-data-analysis-presentation/references/publishing.md +3 -0
  288. package/skills/dsh-data-analysis-presentation/references/schema.md +162 -0
  289. package/lib/datasource/access.js +0 -60
  290. package/lib/datasource/credentials.js +0 -24
  291. package/lib/evidence/bridge-program.js +0 -153
  292. package/lib/evidence/bridge.js +0 -166
  293. package/lib/evidence/index.js +0 -2
  294. package/lib/evidence/sources.js +0 -263
  295. package/lib/types/datasource/access.d.ts +0 -27
  296. package/lib/types/evidence/bridge.d.ts +0 -40
  297. package/lib/types/evidence/index.d.ts +0 -4
  298. package/lib/types/evidence/sources.d.ts +0 -57
  299. package/python/report-kit/dist/dsh_data_analysis_report_kit-3.0.0-py3-none-any.whl +0 -0
  300. package/skills/dsh-data-analysis-report/SKILL.md +0 -57
  301. package/skills/dsh-data-analysis-report/assets/marivo-artifact.js +0 -113
  302. package/skills/dsh-data-analysis-report/assets/marivo-session-dag.js +0 -1201
  303. package/skills/dsh-data-analysis-report/assets/report-data.js +0 -449
@@ -39,10 +39,36 @@ _dsh_sys.argv = [_dsh_sys.argv[0], *_dsh_sys.argv[4:]]
39
39
  const IMPORT_IDENTITY_PROGRAM = String.raw `
40
40
  print(_dsh_json.dumps(_dsh_actual, sort_keys=True))
41
41
  `.trim();
42
- function redactSubprocessOutput(result, environmentOverlay) {
43
- if (environmentOverlay === undefined)
42
+ const PRESENTATION_IDENTITY_PRELUDE = String.raw `
43
+ try:
44
+ import dsh_data_analysis_presentation as _dsh_presentation
45
+ from importlib.metadata import distribution as _dsh_distribution
46
+ _dsh_presentation_distribution = _dsh_distribution("dsh-data-analysis-presentation-kit")
47
+ _dsh_presentation_path = _dsh_os.path.realpath(_dsh_presentation.__file__ or "")
48
+ if (
49
+ _dsh_presentation.__version__ != _dsh_expected_presentation["version"]
50
+ or _dsh_presentation_distribution.version != _dsh_expected_presentation["version"]
51
+ or _dsh_presentation_path != _dsh_os.path.realpath(_dsh_expected_presentation["packagePath"])
52
+ or _dsh_presentation_path != _dsh_os.path.realpath(_dsh_presentation_distribution.locate_file("dsh_data_analysis_presentation/__init__.py"))
53
+ or not callable(_dsh_presentation.write_dataset)
54
+ ):
55
+ raise ValueError("presentation helper identity mismatch")
56
+ except Exception:
57
+ print(_dsh_json.dumps({"kind": "presentation-identity-mismatch"}), file=_dsh_sys.stderr)
58
+ raise SystemExit(78)
59
+ `.trim();
60
+ function redactSubprocessOutput(result, environmentOverlay, secretValues = []) {
61
+ if (environmentOverlay === undefined && secretValues.length === 0)
44
62
  return result;
45
- const secrets = Object.values(environmentOverlay).filter((value) => value !== undefined && value !== '');
63
+ // These exact process controls carry no credential material. Redacting '1' would
64
+ // corrupt public schema IDs such as marivo.semantic_ref/v1.
65
+ const secrets = Object.entries(environmentOverlay ?? {})
66
+ .filter(([key, value]) => !((key === 'MARIVO_TELEMETRY' && value === 'off') ||
67
+ (key === 'PYTHONDONTWRITEBYTECODE' && value === '1')))
68
+ .map(([, value]) => value)
69
+ .filter((value) => value !== undefined && value !== '');
70
+ secrets.push(...secretValues.filter(Boolean));
71
+ secrets.sort((a, b) => b.length - a.length);
46
72
  const redactText = (source) => {
47
73
  let text = source;
48
74
  for (const secret of secrets)
@@ -116,6 +142,9 @@ function fingerprint(binding) {
116
142
  binding.marivoVersion,
117
143
  binding.packagePath,
118
144
  binding.subprocessPolicyId,
145
+ ...(binding.presentationKit === undefined
146
+ ? []
147
+ : [binding.presentationKit.version, binding.presentationKit.packagePath]),
119
148
  ];
120
149
  return createHash('sha256').update(JSON.stringify(payload)).digest('hex');
121
150
  }
@@ -142,7 +171,14 @@ export class MarivoEnvironment {
142
171
  subprocessPolicy;
143
172
  #failed = false;
144
173
  constructor(binding, subprocessPolicy) {
145
- this.binding = Object.freeze({ ...binding });
174
+ this.binding = Object.freeze({
175
+ ...binding,
176
+ ...(binding.presentationKit === undefined
177
+ ? {}
178
+ : {
179
+ presentationKit: Object.freeze({ ...binding.presentationKit }),
180
+ }),
181
+ });
146
182
  this.subprocessPolicy = subprocessPolicy;
147
183
  }
148
184
  get status() {
@@ -158,11 +194,14 @@ export class MarivoEnvironment {
158
194
  }
159
195
  if (request.program.trim() === '')
160
196
  throw new TypeError('checked Python program must not be empty');
197
+ const presentationPrelude = this.binding.presentationKit === undefined
198
+ ? ''
199
+ : `_dsh_expected_presentation = ${JSON.stringify(this.binding.presentationKit)}\n${PRESENTATION_IDENTITY_PRELUDE}\n`;
161
200
  const rawResult = await this.subprocessPolicy.run({
162
201
  executable: this.binding.pythonExecutable,
163
202
  args: [
164
203
  '-c',
165
- `${CHECKED_IDENTITY_PRELUDE}\n${request.program}`,
204
+ `${CHECKED_IDENTITY_PRELUDE}\n${presentationPrelude}${request.program}`,
166
205
  this.binding.pythonExecutable,
167
206
  this.binding.marivoVersion,
168
207
  this.binding.packagePath,
@@ -171,13 +210,14 @@ export class MarivoEnvironment {
171
210
  ...(request.environmentOverlay === undefined
172
211
  ? {}
173
212
  : { environmentOverlay: request.environmentOverlay }),
213
+ ...(request.stdin === undefined ? {} : { stdin: request.stdin }),
174
214
  ...(request.limits === undefined ? {} : { limits: request.limits }),
175
215
  ...(request.signal === undefined ? {} : { signal: request.signal }),
176
216
  });
177
- const result = redactSubprocessOutput(rawResult, request.environmentOverlay);
217
+ const result = redactSubprocessOutput(rawResult, request.environmentOverlay, request.secretValues);
178
218
  if (result.exitCode === 78) {
179
219
  this.#failed = true;
180
- throw new MarivoEnvironmentError('binding-identity-mismatch', 'Marivo import identity changed; explicit rebind is required', {
220
+ throw new MarivoEnvironmentError('binding-identity-mismatch', 'Bound Runtime import identity changed; explicit rebind is required', {
181
221
  fingerprint: this.binding.fingerprint,
182
222
  exitCode: result.exitCode,
183
223
  stderr: result.stderr.toString('utf8').slice(0, 2_000),
@@ -194,7 +234,7 @@ export class MarivoEnvironment {
194
234
  });
195
235
  if (result.exitCode !== 0) {
196
236
  this.#failed = true;
197
- throw new MarivoEnvironmentError('binding-identity-mismatch', 'Marivo import identity changed; explicit rebind is required', {
237
+ throw new MarivoEnvironmentError('binding-identity-mismatch', 'Bound Runtime import identity changed; explicit rebind is required', {
198
238
  fingerprint: this.binding.fingerprint,
199
239
  exitCode: result.exitCode,
200
240
  stderr: result.stderr.toString('utf8').slice(0, 2_000),
@@ -213,7 +253,7 @@ export class MarivoEnvironment {
213
253
  this.#failed = true;
214
254
  if (cause instanceof MarivoEnvironmentError)
215
255
  throw cause;
216
- throw new MarivoEnvironmentError('binding-identity-mismatch', 'Marivo import identity changed; explicit rebind is required', { fingerprint: this.binding.fingerprint }, { cause });
256
+ throw new MarivoEnvironmentError('binding-identity-mismatch', 'Bound Runtime import identity changed; explicit rebind is required', { fingerprint: this.binding.fingerprint }, { cause });
217
257
  }
218
258
  }
219
259
  }
@@ -225,6 +265,10 @@ export function createSharedMarivoRuntimeRunner(runtime, options = {}) {
225
265
  pythonExecutable: runtime.pythonExecutable,
226
266
  marivoVersion: runtime.marivoVersion,
227
267
  packagePath: runtime.packagePath,
268
+ presentationKit: {
269
+ version: runtime.presentationKitVersion,
270
+ packagePath: runtime.presentationKitPackagePath,
271
+ },
228
272
  subprocessPolicyId: subprocessPolicy.id,
229
273
  };
230
274
  return new MarivoEnvironment({ ...partialBinding, fingerprint: fingerprint(partialBinding) }, subprocessPolicy);
@@ -263,6 +307,7 @@ export async function bindMarivoEnvironment(config, options = {}) {
263
307
  pythonExecutable,
264
308
  marivoVersion: report.marivo.version,
265
309
  packagePath: normalizeAbsolute(report.marivo.package_path),
310
+ ...(options.presentationKit === undefined ? {} : { presentationKit: options.presentationKit }),
266
311
  subprocessPolicyId: subprocessPolicy.id,
267
312
  };
268
313
  const binding = {
@@ -11,38 +11,42 @@ import { FixedSubprocessPolicy } from "./subprocess.js";
11
11
  export const SHARED_PYTHON_SPEC = '3.10';
12
12
  const PINNED_MARIVO_VERSION = MARIVO_VERSION;
13
13
  export const SHARED_MARIVO_PACKAGE_SPEC = MARIVO_PACKAGE_SPEC;
14
- export const REPORT_KIT_DISTRIBUTION = 'dsh-data-analysis-report-kit';
15
- export const REPORT_KIT_VERSION = '3.0.0';
16
- export const REPORT_KIT_PANDAS_RANGE = '>=2.2.0,<3.0.0';
17
- export const REPORT_KIT_WHEEL_FILENAME = 'dsh_data_analysis_report_kit-3.0.0-py3-none-any.whl';
14
+ export const PRESENTATION_KIT_DISTRIBUTION = 'dsh-data-analysis-presentation-kit';
15
+ export const PRESENTATION_KIT_VERSION = '1.1.0';
16
+ export const PRESENTATION_KIT_PANDAS_RANGE = '>=2.2.0,<3.0.0';
17
+ export const PRESENTATION_KIT_WHEEL_FILENAME = 'dsh_data_analysis_presentation_kit-1.1.0-py3-none-any.whl';
18
18
  export const DEFAULT_SHARED_RUNTIME_INSTALL_TIMEOUT_MS = 600_000;
19
19
  const INSTALLATION_SCHEMA = RUNTIME_INSTALLATION_VERSION;
20
20
  const INSTALLATION_FILENAME = 'installation.json';
21
21
  const SKILL_NAMES = ['marivo-analysis', 'marivo-semantic'];
22
- const REPORT_ADAPTER_KIND = 'dsh-data-analysis-report-transport-adapter';
23
22
  const PROBE_SCRIPT = String.raw `
24
23
  import json
25
24
  import os
26
25
  import sys
26
+ from importlib.metadata import distribution
27
27
  import marivo
28
+ import ibis.backends.duckdb
29
+ from marivo.semantic.definition import SemanticDefinition
28
30
  import pandas
29
- import dsh_data_analysis_report
31
+ import dsh_data_analysis_presentation
30
32
  from packaging.specifiers import SpecifierSet
31
33
  from packaging.version import Version
32
34
 
35
+ presentation_distribution = distribution("dsh-data-analysis-presentation-kit")
36
+
33
37
  print(json.dumps({
34
38
  "python_executable": os.path.abspath(sys.executable),
35
39
  "marivo_version": marivo.__version__,
36
40
  "package_path": os.path.abspath(marivo.__file__ or ""),
37
41
  "pandas_version": pandas.__version__,
38
42
  "pandas_supported": Version(pandas.__version__) in SpecifierSet(">=2.2.0,<3.0.0"),
39
- "report_kit_version": dsh_data_analysis_report.__version__,
40
- "report_kit_package_path": os.path.abspath(dsh_data_analysis_report.__file__ or ""),
41
- "report_kit_public_imports": all(callable(value) for value in (
42
- dsh_data_analysis_report.emit_computed,
43
- dsh_data_analysis_report.emit_dataset,
44
- dsh_data_analysis_report.emit_session_trace,
45
- )),
43
+ "presentation_kit_version": dsh_data_analysis_presentation.__version__,
44
+ "presentation_kit_distribution_version": presentation_distribution.version,
45
+ "presentation_kit_package_path": os.path.abspath(dsh_data_analysis_presentation.__file__ or ""),
46
+ "presentation_kit_import_identity": os.path.realpath(dsh_data_analysis_presentation.__file__ or "") == os.path.realpath(
47
+ presentation_distribution.locate_file("dsh_data_analysis_presentation/__init__.py")
48
+ ),
49
+ "presentation_kit_public_imports": callable(dsh_data_analysis_presentation.write_dataset),
46
50
  }, sort_keys=True))
47
51
  `.trim();
48
52
  const PYTHON_VERSION_SCRIPT = String.raw `
@@ -56,8 +60,8 @@ print(json.dumps({
56
60
  "prefix": os.path.abspath(sys.prefix),
57
61
  }, sort_keys=True))
58
62
  `.trim();
59
- function administratorRepair(executable, reportKitWheel) {
60
- const dependencies = [SHARED_MARIVO_PACKAGE_SPEC, `pandas${REPORT_KIT_PANDAS_RANGE}`];
63
+ function administratorRepair(executable, presentationKitWheel) {
64
+ const dependencies = [SHARED_MARIVO_PACKAGE_SPEC, `pandas${PRESENTATION_KIT_PANDAS_RANGE}`];
61
65
  const commands = [
62
66
  {
63
67
  executable,
@@ -65,7 +69,7 @@ function administratorRepair(executable, reportKitWheel) {
65
69
  },
66
70
  {
67
71
  executable,
68
- args: ['-m', 'pip', 'install', '--no-deps', reportKitWheel],
72
+ args: ['-m', 'pip', 'install', '--no-deps', presentationKitWheel],
69
73
  },
70
74
  ];
71
75
  const commandText = (command) => [command.executable, ...command.args].map((value) => JSON.stringify(value)).join(' ');
@@ -90,22 +94,22 @@ function normalizeAbsolute(name, value) {
90
94
  function defaultRuntimeRoot() {
91
95
  return path.join(resolveDshHome(), 'dsh-data-analysis', 'runtimes', 'marivo');
92
96
  }
93
- function bundledReportKitWheel() {
94
- return fileURLToPath(new URL(`../../python/report-kit/dist/${REPORT_KIT_WHEEL_FILENAME}`, import.meta.url));
97
+ function bundledPresentationKitWheel() {
98
+ return fileURLToPath(new URL(`../../python/presentation-kit/dist/${PRESENTATION_KIT_WHEEL_FILENAME}`, import.meta.url));
95
99
  }
96
- async function assertReportKitWheel(filename) {
100
+ async function assertPresentationKitWheel(filename) {
97
101
  const selected = path.normalize(path.resolve(filename));
98
- if (path.basename(selected) !== REPORT_KIT_WHEEL_FILENAME) {
99
- throw new MarivoEnvironmentError('shared-runtime-report-kit-wheel-invalid', `Bundled report-kit wheel must be named ${REPORT_KIT_WHEEL_FILENAME}`, { expectedWheel: REPORT_KIT_WHEEL_FILENAME, actualWheel: path.basename(selected) });
102
+ if (path.basename(selected) !== PRESENTATION_KIT_WHEEL_FILENAME) {
103
+ throw new MarivoEnvironmentError('shared-runtime-presentation-kit-wheel-invalid', `Bundled presentation-kit wheel must be named ${PRESENTATION_KIT_WHEEL_FILENAME}`, { expectedWheel: PRESENTATION_KIT_WHEEL_FILENAME, actualWheel: path.basename(selected) });
100
104
  }
101
105
  try {
102
106
  if (!(await stat(selected)).isFile())
103
107
  throw new Error('not a file');
104
108
  }
105
109
  catch (cause) {
106
- throw new MarivoEnvironmentError('shared-runtime-report-kit-wheel-unavailable', `Bundled report-kit wheel is unavailable: ${selected}`, {
107
- distribution: REPORT_KIT_DISTRIBUTION,
108
- version: REPORT_KIT_VERSION,
110
+ throw new MarivoEnvironmentError('shared-runtime-presentation-kit-wheel-unavailable', `Bundled presentation-kit wheel is unavailable: ${selected}`, {
111
+ distribution: PRESENTATION_KIT_DISTRIBUTION,
112
+ version: PRESENTATION_KIT_VERSION,
109
113
  wheel: selected,
110
114
  }, { cause });
111
115
  }
@@ -153,7 +157,7 @@ function parseJsonObject(stage, result) {
153
157
  throw new MarivoEnvironmentError('shared-runtime-install-failed', `Shared Marivo runtime stage returned invalid JSON: ${stage}`, { stage, stdout: boundedText(result.stdout), stderr: boundedText(result.stderr) }, { cause });
154
158
  }
155
159
  }
156
- async function probeRuntime(runtimeRoot, executable, environment, timeoutMs, reportKitWheel, administrator, expectedMarivoVersion) {
160
+ async function probeRuntime(runtimeRoot, executable, environment, timeoutMs, presentationKitWheel, administrator, expectedMarivoVersion) {
157
161
  const canonical = await assertExecutable(executable);
158
162
  const policy = new FixedSubprocessPolicy(runtimeRoot, environment);
159
163
  const result = await policy.run({
@@ -161,15 +165,15 @@ async function probeRuntime(runtimeRoot, executable, environment, timeoutMs, rep
161
165
  args: ['-c', PROBE_SCRIPT],
162
166
  limits: { timeoutMs, stdoutMaxBytes: 16_384, stderrMaxBytes: 16_384 },
163
167
  });
164
- const repair = administrator ? administratorRepair(canonical, reportKitWheel) : undefined;
168
+ const repair = administrator ? administratorRepair(canonical, presentationKitWheel) : undefined;
165
169
  if (administrator && result.exitCode !== 0) {
166
- throw new MarivoEnvironmentError('shared-runtime-package-unavailable', `Administrator Python must provide Marivo ${PINNED_MARIVO_VERSION}, pandas ${REPORT_KIT_PANDAS_RANGE}, and ${REPORT_KIT_DISTRIBUTION} ${REPORT_KIT_VERSION}. ${repair.message}`, {
170
+ throw new MarivoEnvironmentError('shared-runtime-package-unavailable', `Administrator Python must provide Marivo ${PINNED_MARIVO_VERSION} with the duckdb extra, pandas ${PRESENTATION_KIT_PANDAS_RANGE}, and ${PRESENTATION_KIT_DISTRIBUTION} ${PRESENTATION_KIT_VERSION}. ${repair.message}`, {
167
171
  pythonExecutable: canonical,
168
172
  marivoVersion: PINNED_MARIVO_VERSION,
169
- pandasRange: REPORT_KIT_PANDAS_RANGE,
170
- reportKitDistribution: REPORT_KIT_DISTRIBUTION,
171
- reportKitVersion: REPORT_KIT_VERSION,
172
- reportKitWheel: reportKitWheel,
173
+ pandasRange: PRESENTATION_KIT_PANDAS_RANGE,
174
+ presentationKitDistribution: PRESENTATION_KIT_DISTRIBUTION,
175
+ presentationKitVersion: PRESENTATION_KIT_VERSION,
176
+ presentationKitWheel: presentationKitWheel,
173
177
  exitCode: result.exitCode,
174
178
  stderr: boundedText(result.stderr),
175
179
  repairCommands: repair.commands,
@@ -184,12 +188,15 @@ async function probeRuntime(runtimeRoot, executable, environment, timeoutMs, rep
184
188
  typeof probe.pandas_version !== 'string' ||
185
189
  probe.pandas_version.length === 0 ||
186
190
  typeof probe.pandas_supported !== 'boolean' ||
187
- typeof probe.report_kit_version !== 'string' ||
188
- probe.report_kit_version.length === 0 ||
189
- typeof probe.report_kit_package_path !== 'string' ||
190
- probe.report_kit_package_path.length === 0 ||
191
- probe.report_kit_public_imports !== true) {
192
- throw new MarivoEnvironmentError('shared-runtime-identity-mismatch', 'Shared Runtime returned an incomplete package identity', { probe });
191
+ typeof probe.presentation_kit_version !== 'string' ||
192
+ probe.presentation_kit_version.length === 0 ||
193
+ typeof probe.presentation_kit_distribution_version !== 'string' ||
194
+ probe.presentation_kit_distribution_version.length === 0 ||
195
+ typeof probe.presentation_kit_package_path !== 'string' ||
196
+ probe.presentation_kit_package_path.length === 0 ||
197
+ probe.presentation_kit_import_identity !== true ||
198
+ probe.presentation_kit_public_imports !== true) {
199
+ throw new MarivoEnvironmentError('shared-runtime-identity-mismatch', 'Shared Runtime returned an incomplete or mismatched package identity', { probe, ...(repair === undefined ? {} : { repairCommands: repair.commands }) });
193
200
  }
194
201
  const actualPython = await realpath(path.resolve(probe.python_executable));
195
202
  const selectedPython = await realpath(canonical);
@@ -202,18 +209,20 @@ async function probeRuntime(runtimeRoot, executable, environment, timeoutMs, rep
202
209
  });
203
210
  }
204
211
  if (!probe.pandas_supported) {
205
- throw new MarivoEnvironmentError('shared-runtime-pandas-unsupported', `Shared Runtime pandas ${probe.pandas_version} is unsupported; install ${REPORT_KIT_PANDAS_RANGE}.${repair === undefined ? '' : ` ${repair.message}`}`, {
206
- supportedPandasRange: REPORT_KIT_PANDAS_RANGE,
212
+ throw new MarivoEnvironmentError('shared-runtime-pandas-unsupported', `Shared Runtime pandas ${probe.pandas_version} is unsupported; install ${PRESENTATION_KIT_PANDAS_RANGE}.${repair === undefined ? '' : ` ${repair.message}`}`, {
213
+ supportedPandasRange: PRESENTATION_KIT_PANDAS_RANGE,
207
214
  actualPandasVersion: probe.pandas_version,
208
215
  ...(repair === undefined ? {} : { repairCommands: repair.commands }),
209
216
  });
210
217
  }
211
- if (probe.report_kit_version !== REPORT_KIT_VERSION) {
212
- throw new MarivoEnvironmentError('shared-runtime-report-kit-unsupported', `Shared Runtime report kit ${probe.report_kit_version} is unsupported; install ${REPORT_KIT_VERSION} from ${reportKitWheel}.${repair === undefined ? '' : ` ${repair.message}`}`, {
213
- supportedReportKitVersion: REPORT_KIT_VERSION,
214
- actualReportKitVersion: probe.report_kit_version,
215
- reportKitPackagePath: probe.report_kit_package_path,
216
- reportKitWheel,
218
+ if (probe.presentation_kit_version !== PRESENTATION_KIT_VERSION ||
219
+ probe.presentation_kit_distribution_version !== PRESENTATION_KIT_VERSION) {
220
+ throw new MarivoEnvironmentError('shared-runtime-presentation-kit-unsupported', `Shared Runtime presentation kit module ${probe.presentation_kit_version} and distribution ${probe.presentation_kit_distribution_version} must both be ${PRESENTATION_KIT_VERSION}; install from ${presentationKitWheel}.${repair === undefined ? '' : ` ${repair.message}`}`, {
221
+ supportedPresentationKitVersion: PRESENTATION_KIT_VERSION,
222
+ actualPresentationKitVersion: probe.presentation_kit_version,
223
+ actualPresentationKitDistributionVersion: probe.presentation_kit_distribution_version,
224
+ presentationKitPackagePath: probe.presentation_kit_package_path,
225
+ presentationKitWheel,
217
226
  ...(repair === undefined ? {} : { repairCommands: repair.commands }),
218
227
  });
219
228
  }
@@ -230,9 +239,11 @@ async function probeRuntime(runtimeRoot, executable, environment, timeoutMs, rep
230
239
  package_path: path.resolve(probe.package_path),
231
240
  pandas_version: probe.pandas_version,
232
241
  pandas_supported: probe.pandas_supported,
233
- report_kit_version: probe.report_kit_version,
234
- report_kit_package_path: path.resolve(probe.report_kit_package_path),
235
- report_kit_public_imports: true,
242
+ presentation_kit_version: probe.presentation_kit_version,
243
+ presentation_kit_distribution_version: probe.presentation_kit_distribution_version,
244
+ presentation_kit_package_path: path.resolve(probe.presentation_kit_package_path),
245
+ presentation_kit_import_identity: true,
246
+ presentation_kit_public_imports: true,
236
247
  };
237
248
  }
238
249
  async function validateSkills(skillsRoot) {
@@ -308,12 +319,12 @@ async function readInstallation(runtimeRoot) {
308
319
  'marivoVersion',
309
320
  'packagePath',
310
321
  'pythonExecutable',
311
- 'reportAdapterKind',
312
- 'reportKitPackagePath',
313
- 'reportKitVersion',
322
+ 'presentationKitDistribution',
323
+ 'presentationKitPackagePath',
324
+ 'presentationKitVersion',
314
325
  'schema',
315
326
  'skillsRoot',
316
- ];
327
+ ].sort();
317
328
  if (fields.length !== expectedFields.length ||
318
329
  fields.some((field, index) => field !== expectedFields[index]) ||
319
330
  record.schema !== INSTALLATION_SCHEMA ||
@@ -323,11 +334,11 @@ async function readInstallation(runtimeRoot) {
323
334
  record.pythonExecutable.length === 0 ||
324
335
  typeof record.packagePath !== 'string' ||
325
336
  record.packagePath.length === 0 ||
326
- record.reportAdapterKind !== REPORT_ADAPTER_KIND ||
327
- typeof record.reportKitVersion !== 'string' ||
328
- record.reportKitVersion.length === 0 ||
329
- typeof record.reportKitPackagePath !== 'string' ||
330
- record.reportKitPackagePath.length === 0 ||
337
+ record.presentationKitDistribution !== PRESENTATION_KIT_DISTRIBUTION ||
338
+ typeof record.presentationKitVersion !== 'string' ||
339
+ record.presentationKitVersion.length === 0 ||
340
+ typeof record.presentationKitPackagePath !== 'string' ||
341
+ record.presentationKitPackagePath.length === 0 ||
331
342
  typeof record.skillsRoot !== 'string' ||
332
343
  record.skillsRoot.length === 0)
333
344
  return undefined;
@@ -349,13 +360,13 @@ async function writeInstallation(runtimeRoot, record) {
349
360
  await rename(temporary, installationPath);
350
361
  return installationPath;
351
362
  }
352
- async function validatedExisting(runtimeRoot, configuredPython, environment, timeoutMs, reportKitWheel) {
363
+ async function validatedExisting(runtimeRoot, configuredPython, environment, timeoutMs, presentationKitWheel) {
353
364
  const record = await readInstallation(runtimeRoot);
354
365
  if (record === undefined)
355
366
  return undefined;
356
367
  if (record.marivoVersion !== PINNED_MARIVO_VERSION)
357
368
  return undefined;
358
- if (record.reportKitVersion !== REPORT_KIT_VERSION)
369
+ if (record.presentationKitVersion !== PRESENTATION_KIT_VERSION)
359
370
  return undefined;
360
371
  const expectedPython = configuredPython ?? venvPython(runtimeRoot);
361
372
  const expectedSkillsRoot = path.join(runtimeRoot, 'skills');
@@ -365,10 +376,11 @@ async function validatedExisting(runtimeRoot, configuredPython, environment, tim
365
376
  const selectedPython = await assertExecutable(expectedPython);
366
377
  if (path.normalize(record.pythonExecutable) !== selectedPython)
367
378
  return undefined;
368
- const probe = await probeRuntime(runtimeRoot, selectedPython, environment, timeoutMs, reportKitWheel, configuredPython !== undefined, record.marivoVersion);
379
+ const probe = await probeRuntime(runtimeRoot, selectedPython, environment, timeoutMs, presentationKitWheel, configuredPython !== undefined, record.marivoVersion);
369
380
  if (path.normalize(probe.package_path) !== path.normalize(record.packagePath))
370
381
  return undefined;
371
- if (path.normalize(probe.report_kit_package_path) !== path.normalize(record.reportKitPackagePath))
382
+ if (path.normalize(probe.presentation_kit_package_path) !==
383
+ path.normalize(record.presentationKitPackagePath))
372
384
  return undefined;
373
385
  await validateSkills(record.skillsRoot);
374
386
  return {
@@ -376,8 +388,8 @@ async function validatedExisting(runtimeRoot, configuredPython, environment, tim
376
388
  pythonExecutable: probe.python_executable,
377
389
  marivoVersion: probe.marivo_version,
378
390
  packagePath: probe.package_path,
379
- reportKitVersion: probe.report_kit_version,
380
- reportKitPackagePath: probe.report_kit_package_path,
391
+ presentationKitVersion: probe.presentation_kit_version,
392
+ presentationKitPackagePath: probe.presentation_kit_package_path,
381
393
  skillsRoot: record.skillsRoot,
382
394
  installationPath: path.join(runtimeRoot, INSTALLATION_FILENAME),
383
395
  };
@@ -451,53 +463,51 @@ async function backupInvalidRuntime(runtimeRoot) {
451
463
  }
452
464
  await rename(runtimeRoot, `${runtimeRoot}.invalid-${Date.now()}-${randomUUID()}`);
453
465
  }
454
- async function installManagedRuntime(runtimeRoot, uvExecutable, reportKitWheel, environment, timeoutMs) {
466
+ async function installManagedRuntime(runtimeRoot, bootstrapPythonExecutable, presentationKitWheel, environment, timeoutMs) {
455
467
  const policy = new FixedSubprocessPolicy(runtimeRoot, environment);
456
468
  const limits = { timeoutMs, stdoutMaxBytes: 1_048_576, stderrMaxBytes: 1_048_576 };
457
- requireSuccess('install managed Python', await policy.run({
458
- executable: uvExecutable,
459
- args: ['python', 'install', SHARED_PYTHON_SPEC],
460
- limits,
461
- }));
462
- const found = requireSuccess('resolve managed Python', await policy.run({
463
- executable: uvExecutable,
464
- args: ['python', 'find', '--managed-python', SHARED_PYTHON_SPEC],
465
- limits,
466
- }));
467
- const managedPython = found.stdout.toString('utf8').trim();
468
- if (!path.isAbsolute(managedPython)) {
469
- throw new MarivoEnvironmentError('shared-runtime-install-failed', 'uv returned a non-absolute managed Python path', { managedPython });
470
- }
471
- const canonicalManagedPython = await assertExecutable(managedPython);
472
- const version = parseJsonObject('validate managed Python', await policy.run({
473
- executable: canonicalManagedPython,
474
- args: ['-c', PYTHON_VERSION_SCRIPT],
475
- limits,
476
- }));
469
+ let version;
470
+ try {
471
+ version = parseJsonObject('validate local Python', await policy.run({
472
+ executable: bootstrapPythonExecutable,
473
+ args: ['-c', PYTHON_VERSION_SCRIPT],
474
+ limits,
475
+ }));
476
+ }
477
+ catch (error) {
478
+ if (!(error instanceof MarivoEnvironmentError))
479
+ throw error;
480
+ throw new MarivoEnvironmentError('shared-runtime-install-failed', 'Could not validate local Python. Install Python 3.10+ with venv/ensurepip, or set bootstrapPythonExecutable to its absolute path.', { pythonExecutable: bootstrapPythonExecutable, causeCode: error.code });
481
+ }
477
482
  if (!Array.isArray(version.version) ||
478
483
  typeof version.version[0] !== 'number' ||
479
484
  typeof version.version[1] !== 'number' ||
480
485
  version.version[0] < 3 ||
481
486
  (version.version[0] === 3 && version.version[1] < 10)) {
482
- throw new MarivoEnvironmentError('shared-runtime-install-failed', 'uv managed Python does not satisfy Marivo >=3.10', { version: version.version, pythonExecutable: canonicalManagedPython });
487
+ throw new MarivoEnvironmentError('shared-runtime-install-failed', `Local Python does not satisfy Marivo >=${SHARED_PYTHON_SPEC}; detected ${Array.isArray(version.version) ? version.version.join('.') : 'unknown'}`, { version: version.version, pythonExecutable: bootstrapPythonExecutable });
488
+ }
489
+ if (typeof version.python_executable !== 'string' ||
490
+ !path.isAbsolute(version.python_executable)) {
491
+ throw new MarivoEnvironmentError('shared-runtime-install-failed', 'Local Python returned a non-absolute interpreter path');
483
492
  }
484
- requireSuccess('create shared virtual environment', await policy.run({
485
- executable: uvExecutable,
486
- args: ['venv', '--python', canonicalManagedPython, '--seed', path.join(runtimeRoot, '.venv')],
493
+ const canonicalPython = await assertExecutable(version.python_executable);
494
+ requireSuccess('create shared virtual environment (requires Python venv/ensurepip; install python3-venv on Debian/Ubuntu)', await policy.run({
495
+ executable: canonicalPython,
496
+ args: ['-m', 'venv', path.join(runtimeRoot, '.venv')],
487
497
  limits,
488
498
  }));
489
499
  const executable = venvPython(runtimeRoot);
490
500
  requireSuccess(`install Marivo ${PINNED_MARIVO_VERSION}`, await policy.run({
491
- executable: uvExecutable,
492
- args: ['pip', 'install', '--python', executable, '--upgrade', SHARED_MARIVO_PACKAGE_SPEC],
501
+ executable,
502
+ args: ['-m', 'pip', 'install', '--upgrade', SHARED_MARIVO_PACKAGE_SPEC],
493
503
  limits,
494
504
  }));
495
- requireSuccess(`install report kit ${REPORT_KIT_VERSION}`, await policy.run({
496
- executable: uvExecutable,
497
- args: ['pip', 'install', '--python', executable, '--no-deps', reportKitWheel],
505
+ requireSuccess(`install presentation kit ${PRESENTATION_KIT_VERSION}`, await policy.run({
506
+ executable,
507
+ args: ['-m', 'pip', 'install', '--no-deps', presentationKitWheel],
498
508
  limits,
499
509
  }));
500
- return probeRuntime(runtimeRoot, executable, environment, timeoutMs, reportKitWheel, false, PINNED_MARIVO_VERSION);
510
+ return probeRuntime(runtimeRoot, executable, environment, timeoutMs, presentationKitWheel, false, PINNED_MARIVO_VERSION);
501
511
  }
502
512
  /** Ensure and validate the one DSH-home-owned Marivo installation. */
503
513
  export async function ensureSharedMarivoRuntime(config = {}, options = {}) {
@@ -507,37 +517,39 @@ export async function ensureSharedMarivoRuntime(config = {}, options = {}) {
507
517
  const configuredPython = config.pythonExecutable === undefined
508
518
  ? undefined
509
519
  : normalizeAbsolute('pythonExecutable', config.pythonExecutable);
510
- const uvExecutable = config.uvExecutable === undefined
511
- ? 'uv'
512
- : normalizeAbsolute('uvExecutable', config.uvExecutable);
520
+ const bootstrapPythonExecutable = config.bootstrapPythonExecutable === undefined
521
+ ? process.platform === 'win32'
522
+ ? 'python'
523
+ : 'python3'
524
+ : normalizeAbsolute('bootstrapPythonExecutable', config.bootstrapPythonExecutable);
513
525
  const timeoutMs = positiveTimeout(config.installTimeoutMs);
514
- const reportKitWheel = path.normalize(path.resolve(options.reportKitWheelPath ?? bundledReportKitWheel()));
515
- const existing = await validatedExisting(runtimeRoot, configuredPython, options.environment, timeoutMs, reportKitWheel);
526
+ const presentationKitWheel = path.normalize(path.resolve(options.presentationKitWheelPath ?? bundledPresentationKitWheel()));
527
+ const existing = await validatedExisting(runtimeRoot, configuredPython, options.environment, timeoutMs, presentationKitWheel);
516
528
  if (existing !== undefined)
517
529
  return existing;
518
530
  await mkdir(path.dirname(runtimeRoot), { recursive: true });
519
531
  const lockPath = `${runtimeRoot}.install-lock`;
520
532
  const release = await acquireLock(lockPath, timeoutMs, options.waitIntervalMs ?? 100);
521
533
  try {
522
- const afterLock = await validatedExisting(runtimeRoot, configuredPython, options.environment, timeoutMs, reportKitWheel);
534
+ const afterLock = await validatedExisting(runtimeRoot, configuredPython, options.environment, timeoutMs, presentationKitWheel);
523
535
  if (afterLock !== undefined)
524
536
  return afterLock;
525
537
  if (configuredPython === undefined)
526
- await assertReportKitWheel(reportKitWheel);
538
+ await assertPresentationKitWheel(presentationKitWheel);
527
539
  await backupInvalidRuntime(runtimeRoot);
528
540
  await mkdir(runtimeRoot, { recursive: true });
529
541
  const probe = configuredPython === undefined
530
- ? await installManagedRuntime(runtimeRoot, uvExecutable, reportKitWheel, options.environment, timeoutMs)
531
- : await probeRuntime(runtimeRoot, configuredPython, options.environment, timeoutMs, reportKitWheel, true, PINNED_MARIVO_VERSION);
542
+ ? await installManagedRuntime(runtimeRoot, bootstrapPythonExecutable, presentationKitWheel, options.environment, timeoutMs)
543
+ : await probeRuntime(runtimeRoot, configuredPython, options.environment, timeoutMs, presentationKitWheel, true, PINNED_MARIVO_VERSION);
532
544
  const skillsRoot = await syncSkills(runtimeRoot, probe.package_path);
533
545
  const record = {
534
546
  schema: INSTALLATION_SCHEMA,
535
547
  marivoVersion: probe.marivo_version,
536
548
  pythonExecutable: probe.python_executable,
537
549
  packagePath: probe.package_path,
538
- reportAdapterKind: REPORT_ADAPTER_KIND,
539
- reportKitVersion: probe.report_kit_version,
540
- reportKitPackagePath: probe.report_kit_package_path,
550
+ presentationKitDistribution: PRESENTATION_KIT_DISTRIBUTION,
551
+ presentationKitVersion: probe.presentation_kit_version,
552
+ presentationKitPackagePath: probe.presentation_kit_package_path,
541
553
  skillsRoot,
542
554
  };
543
555
  const installationPath = await writeInstallation(runtimeRoot, record);
@@ -546,8 +558,8 @@ export async function ensureSharedMarivoRuntime(config = {}, options = {}) {
546
558
  pythonExecutable: probe.python_executable,
547
559
  marivoVersion: probe.marivo_version,
548
560
  packagePath: probe.package_path,
549
- reportKitVersion: probe.report_kit_version,
550
- reportKitPackagePath: probe.report_kit_package_path,
561
+ presentationKitVersion: probe.presentation_kit_version,
562
+ presentationKitPackagePath: probe.presentation_kit_package_path,
551
563
  skillsRoot,
552
564
  installationPath,
553
565
  };
@@ -71,7 +71,7 @@ export class FixedSubprocessPolicy {
71
71
  shell: false,
72
72
  windowsHide: true,
73
73
  detached: process.platform !== 'win32',
74
- stdio: ['ignore', 'pipe', 'pipe'],
74
+ stdio: ['pipe', 'pipe', 'pipe'],
75
75
  });
76
76
  let child;
77
77
  try {
@@ -84,6 +84,9 @@ export class FixedSubprocessPolicy {
84
84
  }));
85
85
  return;
86
86
  }
87
+ // A child may reject its input before all bytes are written. Do not log payloads.
88
+ child.stdin.on('error', () => { });
89
+ child.stdin.end(request.stdin);
87
90
  const stdout = [];
88
91
  const stderr = [];
89
92
  let stdoutBytes = 0;
@@ -127,6 +130,8 @@ export class FixedSubprocessPolicy {
127
130
  timeout.unref();
128
131
  const onAbort = () => terminate(new MarivoEnvironmentError('subprocess-cancelled', 'Marivo subprocess was cancelled'));
129
132
  request.signal?.addEventListener('abort', onAbort, { once: true });
133
+ if (request.signal?.aborted)
134
+ onAbort();
130
135
  child.stdout.on('data', (chunk) => {
131
136
  stdoutBytes += chunk.byteLength;
132
137
  if (stdoutBytes > limits.stdoutMaxBytes) {
@@ -10,9 +10,9 @@ export function environmentPayload(runtime, environment) {
10
10
  version: environment.binding.marivoVersion,
11
11
  packagePath: environment.binding.packagePath,
12
12
  },
13
- reportKit: {
14
- version: runtime.reportKitVersion,
15
- packagePath: runtime.reportKitPackagePath,
13
+ presentationKit: {
14
+ version: runtime.presentationKitVersion,
15
+ packagePath: runtime.presentationKitPackagePath,
16
16
  },
17
17
  fingerprint: environment.binding.fingerprint,
18
18
  };