@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
@@ -1,5 +1,6 @@
1
1
  import { realpath, stat } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
+ import { finishCleanup, PendingTasks } from "../lifecycle.js";
3
4
  import { bindMarivoEnvironment } from "./binding.js";
4
5
  import { MarivoEnvironmentError } from "./errors.js";
5
6
  async function assertDirectory(target, label) {
@@ -26,24 +27,45 @@ async function canonicalWorkspaceRoot(projectRoot) {
26
27
  }
27
28
  /** Cache one zero-init Workspace binding while retaining project-specific doctor state. */
28
29
  export class MarivoWorkspaceEnvironmentManager {
30
+ #tasks = new PendingTasks();
31
+ #disposed = false;
32
+ #closing;
29
33
  runtime;
30
34
  #bindings = new Map();
31
35
  constructor(runtime) {
32
36
  this.runtime = runtime;
33
37
  }
34
- async resolve(projectRoot) {
38
+ resolve(projectRoot) {
39
+ return this.#tasks.track(this.#resolve(projectRoot));
40
+ }
41
+ async #resolve(projectRoot) {
42
+ if (this.#disposed)
43
+ throw new Error('Marivo Workspace manager disposed');
35
44
  const canonicalRoot = await canonicalWorkspaceRoot(projectRoot);
45
+ if (this.#disposed)
46
+ throw new Error('Marivo Workspace manager disposed');
36
47
  let binding = this.#bindings.get(canonicalRoot);
37
48
  if (binding === undefined) {
38
49
  binding = bindMarivoEnvironment({
39
50
  projectRoot: canonicalRoot,
40
51
  pythonExecutable: this.runtime.pythonExecutable,
52
+ }, {
53
+ presentationKit: {
54
+ version: this.runtime.presentationKitVersion,
55
+ packagePath: this.runtime.presentationKitPackagePath,
56
+ },
41
57
  });
42
58
  this.#bindings.set(canonicalRoot, binding);
43
59
  }
44
60
  return binding;
45
61
  }
62
+ close() {
63
+ this.dispose();
64
+ this.#closing ??= finishCleanup([() => this.#tasks.drain()]);
65
+ return this.#closing;
66
+ }
46
67
  dispose() {
68
+ this.#disposed = true;
47
69
  this.#bindings.clear();
48
70
  }
49
71
  }
package/lib/index.js CHANGED
@@ -3,5 +3,5 @@ export * from "./compatibility.js";
3
3
  export * from "./datasource/index.js";
4
4
  export * from "./disclosure/index.js";
5
5
  export * from "./environment/index.js";
6
- export * from "./evidence/index.js";
7
6
  export { apply, Config, inject, installMarivoPlugin, name } from "./plugin.js";
7
+ export * from "./presentation/index.js";
@@ -0,0 +1,33 @@
1
+ /** Tracks owned work, including work whose caller stopped waiting after cancellation. */
2
+ export class PendingTasks {
3
+ #tasks = new Set();
4
+ track(task) {
5
+ const settled = task.then(() => { }, () => { });
6
+ this.#tasks.add(settled);
7
+ void settled.then(() => this.#tasks.delete(settled));
8
+ return task;
9
+ }
10
+ async drain() {
11
+ while (this.#tasks.size)
12
+ await Promise.all([...this.#tasks]);
13
+ }
14
+ }
15
+ /** Start every stop synchronously, then await every cleanup even if another one fails. */
16
+ export function finishCleanup(actions) {
17
+ const pending = actions.map((action) => {
18
+ try {
19
+ return Promise.resolve(action());
20
+ }
21
+ catch (error) {
22
+ return Promise.reject(error);
23
+ }
24
+ });
25
+ const completion = Promise.allSettled(pending).then((results) => {
26
+ const failures = results.flatMap((result) => result.status === 'rejected' ? [result.reason] : []);
27
+ if (failures.length)
28
+ throw new AggregateError(failures, 'Marivo cleanup failed');
29
+ });
30
+ // Legacy synchronous callers may ignore completion; awaiting it still reports failures.
31
+ void completion.catch(() => { });
32
+ return completion;
33
+ }
@@ -0,0 +1,154 @@
1
+ import { createMarivoBridgeSet } from "./bridges.js";
2
+ import { registerMarivoDatasourceConfigureTool } from "./datasource/configure.js";
3
+ import { registerMarivoPythonTool } from "./datasource/python.js";
4
+ import { resolvePythonOptions } from "./datasource/python-options.js";
5
+ import { MarivoCredentialService } from "./datasource/service.js";
6
+ import { registerMarivoDatasourceTestTool } from "./datasource/test.js";
7
+ import { installMarivoExecutionGuidance, MARIVO_ANALYSIS_CLOSEOUT_PROMPT, MARIVO_DATASOURCE_CREDENTIAL_PROMPT, } from "./disclosure/execution-guidance.js";
8
+ import { installMarivoDisclosure, } from "./disclosure/index.js";
9
+ import { MarivoEnvironment, resolveMarivoEnvironmentSource, } from "./environment/index.js";
10
+ import { finishCleanup, PendingTasks } from "./lifecycle.js";
11
+ import { registerMarivoExportHtmlTool } from "./presentation/export-html.js";
12
+ import { installMarivoPresentationCodeDelivery, registerMarivoPresentTool, } from "./presentation/index.js";
13
+ import { registerReportPublishTool } from "./report-publishing/adapters.js";
14
+ import { resolvePresentationWorkspace } from "./workspace-identity.js";
15
+ const PRESENTATION_PROMPT = 'Answer ordinary factual questions in text. For analysis of provided data files, load dsh-data-analysis-files; local pandas or native DuckDB work needs no Marivo semantic setup. For charts, tables, reports, dashboards or a readable source presentation, load dsh-data-analysis-presentation and deliver through marivo_present. When the user requests an offline HTML file, export the saved report with marivo_export_html, then call native present with the returned path before the final response. Use the Runtime skills and live Help when the task needs Marivo analysis or semantic authoring; existing data can be presented directly.';
16
+ /**
17
+ * Install one already-bound environment into every live or subsequently published Agent scope.
18
+ * Installation is transactional for existing Agents and is disposed with the Cordis plugin.
19
+ */
20
+ export function createMarivoAgentInstallation(ctx, environmentOrResolver, options = {}) {
21
+ const pythonOptions = resolvePythonOptions(options);
22
+ const installed = new Map();
23
+ const credentials = options.credentials ?? ctx.credentials;
24
+ if (credentials === undefined) {
25
+ throw new Error('dsh-data-analysis requires the DSH credentials service');
26
+ }
27
+ const credentialService = options.credentialService ??
28
+ new MarivoCredentialService(credentials, options.credentialInteraction);
29
+ const ownsCredentials = options.credentialService === undefined;
30
+ const retiring = new PendingTasks();
31
+ const failures = [];
32
+ const stops = [];
33
+ let active = true;
34
+ let closing;
35
+ const retire = (controller) => {
36
+ retiring.track(controller.close().catch((error) => {
37
+ failures.push(error);
38
+ }));
39
+ };
40
+ const close = () => {
41
+ if (closing)
42
+ return closing;
43
+ active = false;
44
+ closing = finishCleanup([
45
+ ...stops.reverse(),
46
+ ...[...installed.values()].map((controller) => () => retire(controller)),
47
+ ...(ownsCredentials ? [() => credentialService.close()] : []),
48
+ async () => {
49
+ await retiring.drain();
50
+ if (failures.length)
51
+ throw new AggregateError(failures, 'Marivo Agent cleanup failed');
52
+ },
53
+ ]);
54
+ installed.clear();
55
+ return closing;
56
+ };
57
+ const bridgeSets = new WeakMap();
58
+ const install = (agent) => {
59
+ if (!active || installed.has(agent))
60
+ return;
61
+ const source = environmentOrResolver instanceof MarivoEnvironment
62
+ ? environmentOrResolver
63
+ : () => Promise.resolve(environmentOrResolver(agent));
64
+ const resolveBridgeSet = async () => {
65
+ const environment = await resolveMarivoEnvironmentSource(source);
66
+ let bridges = bridgeSets.get(environment);
67
+ if (bridges === undefined) {
68
+ bridges = createMarivoBridgeSet(environment);
69
+ bridgeSets.set(environment, bridges);
70
+ }
71
+ return bridges;
72
+ };
73
+ const helpSource = options.helpBridgeSource ?? (async () => (await resolveBridgeSet()).help);
74
+ const datasourceSource = async () => (await resolveBridgeSet()).datasource;
75
+ const presentationSource = async () => {
76
+ const workspace = resolvePresentationWorkspace(ctx, String(agent.session.id));
77
+ const projection = (await resolveBridgeSet()).presentation;
78
+ const current = resolvePresentationWorkspace(ctx, String(agent.session.id));
79
+ if (workspace.id !== current.id ||
80
+ workspace.path !== current.path ||
81
+ projection.binding.projectRoot !== current.path)
82
+ throw new Error('Presentation Workspace changed or does not match the bound Runtime');
83
+ return { workspaceId: current.id, projection };
84
+ };
85
+ const controller = installMarivoDisclosure(ctx, agent, helpSource, options);
86
+ try {
87
+ controller.addDisposer(installMarivoExecutionGuidance(agent, controller));
88
+ controller.addDisposer(registerMarivoDatasourceTestTool(agent.ctx, datasourceSource, credentialService));
89
+ controller.addDisposer(registerMarivoDatasourceConfigureTool(agent.ctx, datasourceSource, credentialService));
90
+ controller.addDisposer(registerMarivoPythonTool(agent.ctx, datasourceSource, credentialService, pythonOptions));
91
+ controller.addDisposer(() => credentialService.disposeAgent(agent));
92
+ controller.addDisposer(registerMarivoPresentTool(agent.ctx, presentationSource, agent.session));
93
+ controller.addDisposer(registerMarivoExportHtmlTool(agent.ctx, () => resolvePresentationWorkspace(ctx, String(agent.session.id)), agent.session));
94
+ if (options.reportPublishing)
95
+ controller.addDisposer(registerReportPublishTool(agent.ctx, options.reportPublishing, agent.session.id));
96
+ controller.addDisposer(installMarivoPresentationCodeDelivery(agent.ctx));
97
+ controller.addDisposer(agent.ctx.systemPrompt.section({
98
+ name: 'marivo:presentation',
99
+ order: 180,
100
+ text: PRESENTATION_PROMPT,
101
+ }));
102
+ controller.addDisposer(agent.ctx.systemPrompt.section({
103
+ name: 'marivo:datasource-credentials',
104
+ order: 170,
105
+ text: () => controller.activeSkills.some((skill) => ['marivo-analysis', 'marivo-semantic'].includes(skill))
106
+ ? MARIVO_DATASOURCE_CREDENTIAL_PROMPT
107
+ : '',
108
+ }));
109
+ controller.addDisposer(agent.ctx.systemPrompt.section({
110
+ name: 'marivo:analysis-closeout',
111
+ order: 175,
112
+ text: () => controller.activeSkills.includes('marivo-analysis')
113
+ ? MARIVO_ANALYSIS_CLOSEOUT_PROMPT
114
+ : '',
115
+ }));
116
+ installed.set(agent, controller);
117
+ }
118
+ catch (error) {
119
+ retire(controller);
120
+ throw error;
121
+ }
122
+ };
123
+ return {
124
+ install() {
125
+ if (!active)
126
+ throw new Error('Marivo Agent installation disposed');
127
+ try {
128
+ stops.push(ctx.on('credentials/reference-updated', (ref) => credentialService.invalidateStorageRef(ref)));
129
+ for (const agent of ctx.agents.list())
130
+ install(agent);
131
+ stops.push(ctx.on('agent/created', ({ agent }) => {
132
+ install(agent);
133
+ }));
134
+ stops.push(ctx.on('agent/disposed', ({ agent }) => {
135
+ const controller = installed.get(agent);
136
+ if (controller)
137
+ retire(controller);
138
+ installed.delete(agent);
139
+ }));
140
+ }
141
+ catch (error) {
142
+ void close();
143
+ throw error;
144
+ }
145
+ },
146
+ close,
147
+ };
148
+ }
149
+ /** Stops synchronously; the returned Promise also waits for all owned work. */
150
+ export function installMarivoPlugin(...args) {
151
+ const installation = createMarivoAgentInstallation(...args);
152
+ installation.install();
153
+ return installation.close;
154
+ }
package/lib/plugin.js CHANGED
@@ -1,48 +1,58 @@
1
+ import { CredentialChangesService } from "./datasource/changes.js";
2
+ import { credentialChangesHost } from "./datasource/changes-contract.js";
3
+ import { finishCleanup } from "./lifecycle.js";
4
+ import { createMarivoAgentInstallation } from "./plugin-agents.js";
5
+ import { registerPublishingCredentials } from "./report-publishing/adapters.js";
6
+ import { resolvePublishingConfig } from "./report-publishing/config.js";
7
+ import { ReportPublishingService } from "./report-publishing/service.js";
8
+ import { resolvePresentationWorkspace } from "./workspace-identity.js";
9
+ export { installMarivoPlugin } from "./plugin-agents.js";
10
+ export { resolvePresentationWorkspace } from "./workspace-identity.js";
11
+ import { referenceEnvironmentResolver } from "./semantic-reference/environment.js";
1
12
  /** Cordis lifecycle adapter for the Web-profile shared Marivo Runtime. */
2
- import path from 'node:path';
3
13
  import process from 'node:process';
4
14
  import { fileURLToPath } from 'node:url';
5
15
  import { apply as installSkillFilesystem } from '@deepseek-ai/dsh-skill-filesystem';
16
+ import { WorkspaceId } from '@deepseek-ai/dsh-workspace';
6
17
  import z from '@deepseek-ai/schemastery';
7
- import { createMarivoBridgeSet } from "./bridges.js";
8
- import { registerMarivoDatasourceAccessTool, registerMarivoDatasourceTestTool, } from "./datasource/index.js";
9
- import { MarivoShellCredentialLeases, registerMarivoRuntimeShellEnvironment, } from "./datasource/shell-env.js";
18
+ import { MarivoDatasourceBridge } from "./datasource/bridge.js";
19
+ import { DEFAULT_PYTHON_MAX_TIMEOUT_MS, DEFAULT_PYTHON_TIMEOUT_MS, resolvePythonOptions, } from "./datasource/python-options.js";
20
+ import { registerCredentialRpc } from "./datasource/rpc.js";
21
+ import { MarivoCredentialService } from "./datasource/service.js";
22
+ import { registerMarivoRuntimeShellEnvironment } from "./datasource/shell-env.js";
10
23
  import { MarivoHelpBridge } from "./disclosure/bridge.js";
11
- import { installMarivoDisclosure, } from "./disclosure/index.js";
12
- import { createSharedMarivoRuntimeRunner, DEFAULT_SHARED_RUNTIME_INSTALL_TIMEOUT_MS, ensureSharedMarivoRuntime, MarivoEnvironment, MarivoWorkspaceEnvironmentManager, resolveMarivoEnvironmentSource, } from "./environment/index.js";
13
- import { installMarivoEvidenceSourcesCodeDelivery, registerMarivoEvidenceSourcesTool, } from "./evidence/index.js";
24
+ import { createSharedMarivoRuntimeRunner, DEFAULT_SHARED_RUNTIME_INSTALL_TIMEOUT_MS, ensureSharedMarivoRuntime, MarivoWorkspaceEnvironmentManager, } from "./environment/index.js";
25
+ import { MarivoPresentationFileService, registerMarivoPresentationRpc, } from "./presentation/index.js";
26
+ import { browserFailure, SemanticBrowserService } from "./semantic-browser/service.js";
27
+ import { registerSemanticReferenceRpc, SemanticReferenceService, SemanticReferenceUsage, } from "./semantic-reference/index.js";
28
+ export { MARIVO_DATASOURCE_CREDENTIAL_PROMPT } from "./disclosure/execution-guidance.js";
14
29
  /** Cordis plugin name used by loader diagnostics and lifecycle logs. */
15
30
  export const name = 'dsh-data-analysis';
16
31
  /** Services that must exist before the plugin binds and watches Agent scopes. */
17
- export const inject = ['agents', 'credentials', 'shellEnv', 'skills', 'systemPrompt', 'tools'];
18
- export const MARIVO_DATASOURCE_CREDENTIAL_PROMPT = [
19
- 'When marivo-semantic is active, every Marivo datasource *_env field must reference a valid POSIX environment name outside the reserved MARIVO_* and DSH_DATA_ANALYSIS_* namespaces and Host-owned DSH shell facts.',
20
- 'Never ask the user to provide credential values in chat, and never place credential values in commands or project files.',
21
- 'Immediately after md.register(...) or a manual datasource-file change, call marivo_datasource_test with that datasource name.',
22
- 'If marivo_datasource_test returns needs-credentials, wait for the user to save the Web credential form, then retry marivo_datasource_test before continuing.',
23
- 'Before datasource-backed analysis, call marivo_datasource_access once and reuse its exact bash_prelude or pwsh_prelude before each foreground analysis command until the bounded lease expires or is exhausted. The first # dsh-marivo-credential-lease: line is a required control marker; never remove or move it.',
24
- 'Do not call marivo_datasource_test before each analysis script. Renew access with marivo_datasource_access; run another connection test only after datasource changes, credential rotation, a connection failure, or an explicit user request.',
25
- 'Never use a lease with background or persistent Shell execution. Each admitted Shell consumes one use even if later credential resolution fails.',
26
- 'If a datasource credential environment variable is missing, reacquire access and retry with the exact prelude in a foreground Shell. Never inspect or read DSH credential files, credential backups, or ~/.marivo/secrets.toml.',
27
- ].join(' ');
28
- export const MARIVO_EVIDENCE_SOURCES_PROMPT = [
29
- 'Call marivo_evidence_sources only when the user explicitly requests sources, citations, provenance, or audit details.',
30
- 'Request only exact persisted Findings by Marivo Session, Artifact, and Finding identity.',
31
- 'Treat source existence as identity and availability evidence, not as proof that the whole conclusion, calculation, or business judgment is entailed or correct.',
32
- 'If no exact Finding exists or its source cannot be recovered, say so instead of inventing or approximating a source.',
33
- ].join(' ');
34
- export const MARIVO_REPORT_PROMPT = [
35
- 'Use dsh-data-analysis-report only when the user explicitly requests HTML/web or a durable report file, accepts an Agent proposal to create one, or asks to revise an existing Workspace report bundle.',
36
- 'Answer ordinary analysis in the conversation even when it is long or contains multiple charts or tables.',
37
- 'For existing analysis, recover and revalidate persisted Artifacts; never rerun observe only to create the report or fill DAG details.',
38
- ].join(' ');
39
- const integrationSkillsRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'skills');
32
+ export const inject = [
33
+ 'agents',
34
+ 'connection',
35
+ 'typert',
36
+ 'storageDomain',
37
+ 'workspaceRegistry',
38
+ 'credentials',
39
+ 'shellEnv',
40
+ 'skills',
41
+ 'systemPrompt',
42
+ 'tools',
43
+ ];
40
44
  /** Cordis loader schema. Runtime defaults are resolved in {@link apply}. */
41
45
  export const Config = z.object({
46
+ // Defer validation to authoring so loader errors cannot echo configured values.
47
+ datasourceDefaults: z.any(),
48
+ reportPublishing: z.any(),
49
+ pythonTimeoutMs: z.number().default(DEFAULT_PYTHON_TIMEOUT_MS),
50
+ pythonMaxTimeoutMs: z.number().default(DEFAULT_PYTHON_MAX_TIMEOUT_MS),
51
+ credentialInteraction: z.union(['web', 'none']).default('web'),
42
52
  projectRoot: z.string(),
43
53
  pythonExecutable: z.string(),
44
54
  runtimeRoot: z.string(),
45
- uvExecutable: z.string(),
55
+ bootstrapPythonExecutable: z.string(),
46
56
  installTimeoutMs: z.number().default(DEFAULT_SHARED_RUNTIME_INSTALL_TIMEOUT_MS),
47
57
  });
48
58
  function configuredProjectRoot(config, agent) {
@@ -52,128 +62,157 @@ function configuredProjectRoot(config, agent) {
52
62
  process.env.DSH_CWD ??
53
63
  process.cwd());
54
64
  }
55
- /**
56
- * Install one already-bound environment into every live or subsequently published Agent scope.
57
- * Installation is transactional for existing Agents and is disposed with the Cordis plugin.
58
- */
59
- export function installMarivoPlugin(ctx, environmentOrResolver, options = {}) {
60
- const installed = new Map();
61
- const credentials = options.credentials ?? ctx.credentials;
62
- if (credentials === undefined) {
63
- throw new Error('dsh-data-analysis requires the DSH credentials service');
64
- }
65
- const shellCredentials = new MarivoShellCredentialLeases(ctx, credentials);
66
- const bridgeSets = new WeakMap();
67
- const install = (agent) => {
68
- if (installed.has(agent))
69
- return;
70
- const source = environmentOrResolver instanceof MarivoEnvironment
71
- ? environmentOrResolver
72
- : () => Promise.resolve(environmentOrResolver(agent));
73
- const resolveBridgeSet = async () => {
74
- const environment = await resolveMarivoEnvironmentSource(source);
75
- let bridges = bridgeSets.get(environment);
76
- if (bridges === undefined) {
77
- bridges = createMarivoBridgeSet(environment);
78
- bridgeSets.set(environment, bridges);
79
- }
80
- return bridges;
81
- };
82
- const helpSource = options.helpBridgeSource ?? (async () => (await resolveBridgeSet()).help);
83
- const datasourceSource = async () => (await resolveBridgeSet()).datasource;
84
- const evidenceSource = async () => (await resolveBridgeSet()).evidence;
85
- const controller = installMarivoDisclosure(ctx, agent, helpSource, options);
86
- controller.addDisposer(shellCredentials.installAgent(agent, datasourceSource));
87
- controller.addDisposer(registerMarivoDatasourceTestTool(agent.ctx, datasourceSource, credentials, {
88
- revokeShellLease: (bridge, datasourceName) => shellCredentials.revokeLease(agent, bridge, datasourceName),
89
- }));
90
- controller.addDisposer(registerMarivoDatasourceAccessTool(agent.ctx, datasourceSource, credentials, {
91
- revokeShellLease: (bridge, datasourceName) => shellCredentials.revokeLease(agent, bridge, datasourceName),
92
- issueShellLease: (bridge, datasourceName, refs) => shellCredentials.issueLease(agent, bridge, datasourceName, refs),
93
- }));
94
- controller.addDisposer(registerMarivoEvidenceSourcesTool(agent.ctx, evidenceSource, agent.session));
95
- controller.addDisposer(installMarivoEvidenceSourcesCodeDelivery(agent.ctx));
96
- controller.addDisposer(agent.ctx.systemPrompt.section({
97
- name: 'marivo:datasource-credentials',
98
- order: 170,
99
- text: () => controller.activeSkills.includes('marivo-semantic')
100
- ? MARIVO_DATASOURCE_CREDENTIAL_PROMPT
101
- : '',
102
- }));
103
- controller.addDisposer(agent.ctx.systemPrompt.section({
104
- name: 'marivo:evidence-sources',
105
- order: 180,
106
- text: () => controller.activeSkills.includes('marivo-analysis') ? MARIVO_EVIDENCE_SOURCES_PROMPT : '',
107
- }));
108
- controller.addDisposer(agent.ctx.systemPrompt.section({
109
- name: 'marivo:report',
110
- order: 185,
111
- text: () => controller.activeSkills.includes('marivo-analysis') ? MARIVO_REPORT_PROMPT : '',
112
- }));
113
- installed.set(agent, controller);
114
- };
115
- try {
116
- for (const agent of ctx.agents.list())
117
- install(agent);
118
- }
119
- catch (error) {
120
- for (const controller of installed.values())
121
- controller.dispose();
122
- shellCredentials.dispose();
123
- throw error;
124
- }
125
- const stopCreated = ctx.on('agent/created', ({ agent }) => {
126
- install(agent);
127
- });
128
- const stopDisposed = ctx.on('agent/disposed', ({ agent }) => {
129
- installed.get(agent)?.dispose();
130
- installed.delete(agent);
131
- });
132
- let active = true;
133
- return () => {
134
- if (!active)
135
- return;
136
- active = false;
137
- stopCreated();
138
- stopDisposed();
139
- for (const controller of installed.values())
140
- controller.dispose();
141
- installed.clear();
142
- shellCredentials.dispose();
143
- };
144
- }
145
65
  /** Ensure the shared Runtime once, mount its skills, then bind each Workspace lazily. */
146
66
  export async function apply(ctx, config = {}) {
67
+ const publishingConfig = resolvePublishingConfig(config.reportPublishing);
68
+ const pythonOptions = resolvePythonOptions(config);
147
69
  const pythonExecutable = config.pythonExecutable ?? process.env.DSH_DATA_ANALYSIS_PYTHON;
148
70
  const runtimeRoot = config.runtimeRoot ?? process.env.DSH_DATA_ANALYSIS_RUNTIME_ROOT;
149
- const uvExecutable = config.uvExecutable ?? process.env.DSH_DATA_ANALYSIS_UV;
71
+ const bootstrapPythonExecutable = config.bootstrapPythonExecutable ?? process.env.DSH_DATA_ANALYSIS_BOOTSTRAP_PYTHON;
150
72
  const runtime = await ensureSharedMarivoRuntime({
151
73
  ...(pythonExecutable === undefined ? {} : { pythonExecutable }),
152
74
  ...(runtimeRoot === undefined ? {} : { runtimeRoot }),
153
- ...(uvExecutable === undefined ? {} : { uvExecutable }),
75
+ ...(bootstrapPythonExecutable === undefined ? {} : { bootstrapPythonExecutable }),
154
76
  ...(config.installTimeoutMs === undefined ? {} : { installTimeoutMs: config.installTimeoutMs }),
155
77
  });
156
78
  const disposeRuntimeShellEnvironment = registerMarivoRuntimeShellEnvironment(ctx, runtime.pythonExecutable);
157
79
  const manager = new MarivoWorkspaceEnvironmentManager(runtime);
158
- let disposePlugin;
80
+ const bindings = new WeakMap();
81
+ const resolveEnvironment = (agent) => {
82
+ const root = configuredProjectRoot(config, agent);
83
+ const existing = bindings.get(agent);
84
+ if (existing?.root === root)
85
+ return existing.environment;
86
+ const environment = manager.resolve(root);
87
+ bindings.set(agent, { root, environment });
88
+ return environment;
89
+ };
90
+ const credentialService = new MarivoCredentialService(ctx.credentials, config.credentialInteraction);
91
+ const credentialNotifications = new CredentialChangesService(ctx, credentialService);
92
+ let unregisterChanges;
93
+ const disposeChanges = async () => {
94
+ await credentialNotifications.close();
95
+ await unregisterChanges?.();
96
+ };
97
+ let disposePublishing;
98
+ let disposeCredentials;
99
+ let disposeReferences;
100
+ let disposePresentation;
101
+ let referenceService;
102
+ let agentInstallation;
103
+ let closing;
104
+ const browserService = new SemanticBrowserService({
105
+ getWorkspace: (id) => ctx.workspaceRegistry.get(WorkspaceId(id)),
106
+ projectRoot: (workspace) => config.projectRoot ?? process.env.DSH_DATA_ANALYSIS_PROJECT_ROOT ?? workspace.path,
107
+ resolve: (root) => manager.resolve(root),
108
+ });
109
+ const close = () => {
110
+ if (closing)
111
+ return closing;
112
+ closing = finishCleanup([
113
+ () => agentInstallation?.close(),
114
+ () => disposeCredentials?.(),
115
+ disposeChanges,
116
+ () => disposePublishing?.(),
117
+ () => disposePresentation?.(),
118
+ () => disposeReferences?.(),
119
+ () => browserService.close(),
120
+ () => credentialService.close(),
121
+ () => referenceService?.close(),
122
+ ]).then(() => finishCleanup([() => manager.close(), disposeRuntimeShellEnvironment]), async (error) => {
123
+ await finishCleanup([
124
+ () => manager.close(),
125
+ disposeRuntimeShellEnvironment,
126
+ () => {
127
+ throw error;
128
+ },
129
+ ]);
130
+ });
131
+ void closing.catch(() => { });
132
+ return closing;
133
+ };
159
134
  try {
135
+ unregisterChanges = ctx.typert.register(credentialChangesHost);
160
136
  installSkillFilesystem(ctx, {
161
137
  providerName: 'dsh-data-analysis-marivo',
162
138
  includeDefaultRoots: false,
163
- customSkillDirs: [runtime.skillsRoot, integrationSkillsRoot],
139
+ customSkillDirs: [runtime.skillsRoot],
140
+ watch: false,
141
+ });
142
+ installSkillFilesystem(ctx, {
143
+ providerName: 'dsh-data-analysis-presentation',
144
+ includeDefaultRoots: false,
145
+ customSkillDirs: [fileURLToPath(new URL('../skills/', import.meta.url))],
164
146
  watch: false,
165
147
  });
166
148
  const helpBridge = new MarivoHelpBridge(createSharedMarivoRuntimeRunner(runtime));
167
- disposePlugin = installMarivoPlugin(ctx, (agent) => manager.resolve(configuredProjectRoot(config, agent)), { helpBridgeSource: helpBridge });
149
+ const presentationFiles = new MarivoPresentationFileService(async (sessionId) => resolvePresentationWorkspace(ctx, sessionId), async (id) => {
150
+ const workspace = ctx.workspaceRegistry.get(WorkspaceId(id));
151
+ return workspace ? { id: String(workspace.id), path: workspace.path } : undefined;
152
+ });
153
+ disposePresentation = registerMarivoPresentationRpc(ctx.connection, presentationFiles);
154
+ const reportPublishing = new ReportPublishingService(publishingConfig, ctx.credentials, presentationFiles, undefined, (id) => {
155
+ const workspace = ctx.workspaceRegistry.get(WorkspaceId(id));
156
+ if (!workspace)
157
+ throw new Error('workspace-unavailable');
158
+ return workspace.title;
159
+ });
160
+ disposePublishing = registerPublishingCredentials(ctx.connection, reportPublishing, (id) => Boolean(ctx.workspaceRegistry.get(WorkspaceId(id))));
161
+ agentInstallation = createMarivoAgentInstallation(ctx, resolveEnvironment, {
162
+ ...pythonOptions,
163
+ helpBridgeSource: helpBridge,
164
+ ...(publishingConfig ? { reportPublishing } : {}),
165
+ credentialService,
166
+ });
167
+ agentInstallation.install();
168
+ disposeCredentials = registerCredentialRpc(ctx.connection, credentialService, async (id) => {
169
+ const workspace = ctx.workspaceRegistry.get(WorkspaceId(id));
170
+ if (!workspace)
171
+ throw new Error('Workspace unavailable');
172
+ const root = config.projectRoot ?? process.env.DSH_DATA_ANALYSIS_PROJECT_ROOT ?? workspace.path;
173
+ const environment = await manager.resolve(root);
174
+ const current = ctx.workspaceRegistry.get(WorkspaceId(id));
175
+ if (!current ||
176
+ current.path !== workspace.path ||
177
+ (config.projectRoot ?? process.env.DSH_DATA_ANALYSIS_PROJECT_ROOT ?? current.path) !==
178
+ root)
179
+ throw new Error('Workspace changed');
180
+ return new MarivoDatasourceBridge(environment);
181
+ }, config.datasourceDefaults);
182
+ let lastDiagnostic = -Infinity;
183
+ const usage = new SemanticReferenceUsage(ctx.storageDomain, Date.now, () => {
184
+ if (Date.now() - lastDiagnostic >= 30_000) {
185
+ lastDiagnostic = Date.now();
186
+ console.warn('dsh-data-analysis semantic-reference usage unavailable');
187
+ }
188
+ });
189
+ referenceService = new SemanticReferenceService(referenceEnvironmentResolver({
190
+ agent: (sessionId) => ctx.agents.list().find((item) => item.session.id === sessionId),
191
+ binding: (agent) => bindings.get(agent),
192
+ projectRoot: (agent) => configuredProjectRoot(config, agent),
193
+ resolve: resolveEnvironment,
194
+ workspace: (sessionId) => resolvePresentationWorkspace(ctx, sessionId),
195
+ }), usage);
196
+ disposeReferences = registerSemanticReferenceRpc(ctx.connection, referenceService, async (_endpoint, payload, signal) => {
197
+ try {
198
+ return { ok: true, value: await browserService.read(payload, signal) };
199
+ }
200
+ catch (error) {
201
+ return {
202
+ ok: false,
203
+ error: { code: 'internal', message: browserFailure(error), details: {} },
204
+ };
205
+ }
206
+ });
168
207
  }
169
208
  catch (error) {
170
- manager.dispose();
171
- disposeRuntimeShellEnvironment();
209
+ try {
210
+ await close();
211
+ }
212
+ catch (cleanupError) {
213
+ throw new AggregateError([error, cleanupError], 'Marivo installation and cleanup failed');
214
+ }
172
215
  throw error;
173
216
  }
174
- return () => {
175
- disposePlugin();
176
- manager.dispose();
177
- disposeRuntimeShellEnvironment();
178
- };
217
+ return close;
179
218
  }
@@ -0,0 +1,34 @@
1
+ import { buildPresentation } from "./build/index.js";
2
+ import { parsePresentationDocument, } from "./contracts/index.js";
3
+ import { presentationAssetPath, presentationSha256, readPresentationAsset } from "./files.js";
4
+ /** Read a fixed, receipt-verified snapshot; never access analysis or current. */
5
+ export async function readReceiptAsset(root, workspaceId, receipt, asset, signal) {
6
+ signal.throwIfAborted();
7
+ if (receipt.workspaceId !== workspaceId)
8
+ throw new Error('asset-owner-mismatch');
9
+ for (const file of Object.values(receipt.files))
10
+ if (file.path !== presentationAssetPath(root, receipt.reportId, receipt.buildId, file.asset))
11
+ throw new Error('asset-path-mismatch');
12
+ const documentBytes = await readPresentationAsset(root, receipt.reportId, receipt.buildId, 'presentation.json', signal);
13
+ if (documentBytes.length !== receipt.files.document.bytes ||
14
+ presentationSha256(documentBytes) !== receipt.files.document.sha256)
15
+ throw new Error('asset-digest-mismatch');
16
+ const document = parsePresentationDocument(JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(documentBytes)));
17
+ if (document.workspaceId !== workspaceId ||
18
+ document.reportId !== receipt.reportId ||
19
+ document.buildId !== receipt.buildId ||
20
+ document.title !== receipt.title)
21
+ throw new Error('asset-owner-mismatch');
22
+ const bytes = asset === 'presentation.json'
23
+ ? documentBytes
24
+ : receipt.files.html
25
+ ? await readPresentationAsset(root, receipt.reportId, receipt.buildId, asset, signal)
26
+ : (await buildPresentation(document)).htmlBytes;
27
+ const file = asset === 'presentation.json'
28
+ ? receipt.files.document
29
+ : (receipt.files.html ?? { bytes: bytes.length, sha256: presentationSha256(bytes) });
30
+ if (bytes.length !== file.bytes || presentationSha256(bytes) !== file.sha256)
31
+ throw new Error('asset-digest-mismatch');
32
+ signal.throwIfAborted();
33
+ return { bytes, sha256: file.sha256 };
34
+ }