@chengxianglibra/dsh-data-analysis 0.1.1 → 0.1.2

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 (195) hide show
  1. package/README.md +83 -34
  2. package/lib/bin/environment.js +1 -1
  3. package/lib/bin/presentation-lint.js +21 -0
  4. package/lib/bridges.js +2 -2
  5. package/lib/client/credentials/create-datasource.js +67 -0
  6. package/lib/client/credentials/install.js +191 -0
  7. package/lib/client/credentials/model.js +494 -0
  8. package/lib/client/credentials/styles.js +17 -0
  9. package/lib/client/workspace-header-action.js +11 -0
  10. package/lib/client.js +1133 -736
  11. package/lib/compatibility.js +1 -1
  12. package/lib/datasource/authoring.js +70 -0
  13. package/lib/datasource/bridge-programs.js +30 -18
  14. package/lib/datasource/bridge.js +100 -8
  15. package/lib/datasource/index.js +3 -2
  16. package/lib/datasource/python.js +115 -0
  17. package/lib/datasource/resolver-program.js +112 -0
  18. package/lib/datasource/rpc.js +88 -0
  19. package/lib/datasource/service.js +687 -0
  20. package/lib/datasource/shell-env.js +2 -333
  21. package/lib/datasource/test.js +24 -51
  22. package/lib/environment/binding.js +54 -9
  23. package/lib/environment/runtime.js +89 -78
  24. package/lib/environment/subprocess.js +6 -1
  25. package/lib/environment/summary.js +3 -3
  26. package/lib/environment/workspace.js +5 -0
  27. package/lib/index.js +1 -1
  28. package/lib/plugin.js +168 -51
  29. package/lib/presentation/assets/portable.js +606 -0
  30. package/lib/presentation/assets/static.js +945 -0
  31. package/lib/presentation/build/index.js +71 -0
  32. package/lib/presentation/commit.js +156 -0
  33. package/lib/presentation/contracts/charts.js +476 -0
  34. package/lib/presentation/contracts/editing.js +58 -0
  35. package/lib/presentation/contracts/index.js +651 -0
  36. package/lib/presentation/contracts/interaction.js +62 -0
  37. package/lib/presentation/contracts/types.js +15 -0
  38. package/lib/presentation/contracts/values.js +28 -0
  39. package/lib/presentation/delivery.js +56 -0
  40. package/lib/presentation/files.js +83 -0
  41. package/lib/presentation/index.js +6 -0
  42. package/lib/presentation/lint.js +46 -0
  43. package/lib/presentation/projection/files.js +85 -0
  44. package/lib/presentation/projection/index.js +195 -0
  45. package/lib/presentation/projection/program.js +144 -0
  46. package/lib/presentation/projection/sql-code.js +79 -0
  47. package/lib/presentation/receipt.js +34 -0
  48. package/lib/presentation/reports.js +122 -0
  49. package/lib/presentation/rpc.js +148 -0
  50. package/lib/presentation/tool.js +122 -0
  51. package/lib/python-execution-contracts.js +1 -0
  52. package/lib/python-execution.js +232 -0
  53. package/lib/semantic-browser/contracts.js +80 -0
  54. package/lib/semantic-browser/definition.js +64 -0
  55. package/lib/semantic-browser/program.js +119 -0
  56. package/lib/semantic-browser/service.js +72 -0
  57. package/lib/semantic-reference/bridge.js +118 -0
  58. package/lib/semantic-reference/contracts.js +113 -0
  59. package/lib/semantic-reference/index.js +3 -0
  60. package/lib/semantic-reference/rpc.js +122 -0
  61. package/lib/semantic-reference/search.js +94 -0
  62. package/lib/semantic-reference/usage.js +143 -0
  63. package/lib/types/bridges.d.ts +2 -2
  64. package/lib/types/client/credentials/create-datasource.d.ts +5 -0
  65. package/lib/types/client/credentials/install.d.ts +1 -0
  66. package/lib/types/client/credentials/model.d.ts +59 -0
  67. package/lib/types/client/credentials/styles.d.ts +1 -0
  68. package/lib/types/client/presentation/ask-dsh.d.ts +9 -0
  69. package/lib/types/client/presentation/chart-explorer.d.ts +12 -0
  70. package/lib/types/client/presentation/chart-geometry.d.ts +30 -0
  71. package/lib/types/client/presentation/chart-renderer.d.ts +10 -0
  72. package/lib/types/client/presentation/chart-specials.d.ts +10 -0
  73. package/lib/types/client/presentation/chart-styles.d.ts +1 -0
  74. package/lib/types/client/presentation/chart-tooltip.d.ts +13 -0
  75. package/lib/types/client/presentation/chart-view.d.ts +23 -0
  76. package/lib/types/client/presentation/copy-context.d.ts +5 -0
  77. package/lib/types/client/presentation/delivery-model.d.ts +54 -0
  78. package/lib/types/client/presentation/delivery.d.ts +77 -0
  79. package/lib/types/client/presentation/editor-controls.d.ts +12 -0
  80. package/lib/types/client/presentation/global-filters.d.ts +6 -0
  81. package/lib/types/client/presentation/host-entry.d.ts +12 -0
  82. package/lib/types/client/presentation/icons.d.ts +4 -0
  83. package/lib/types/client/presentation/install.d.ts +15 -0
  84. package/lib/types/client/presentation/markdown.d.ts +5 -0
  85. package/lib/types/client/presentation/model.d.ts +62 -0
  86. package/lib/types/client/presentation/reader.d.ts +11 -0
  87. package/lib/types/client/presentation/source-code-model.d.ts +16 -0
  88. package/lib/types/client/presentation/source-code.d.ts +11 -0
  89. package/lib/types/client/presentation/source-dialog.d.ts +13 -0
  90. package/lib/types/client/presentation/source-facts.d.ts +20 -0
  91. package/lib/types/client/presentation/source-format.d.ts +5 -0
  92. package/lib/types/client/presentation/source-highlight.d.ts +7 -0
  93. package/lib/types/client/presentation/sources.d.ts +13 -0
  94. package/lib/types/client/presentation/styles.d.ts +1 -0
  95. package/lib/types/client/presentation/table.d.ts +12 -0
  96. package/lib/types/client/presentation/use-element-width.d.ts +5 -0
  97. package/lib/types/client/workspace-header-action.d.ts +7 -0
  98. package/lib/types/client.d.ts +4 -122
  99. package/lib/types/compatibility.d.ts +2 -2
  100. package/lib/types/datasource/authoring.d.ts +25 -0
  101. package/lib/types/datasource/bridge.d.ts +21 -3
  102. package/lib/types/datasource/index.d.ts +3 -5
  103. package/lib/types/datasource/python.d.ts +4 -0
  104. package/lib/types/datasource/resolver-program.d.ts +6 -0
  105. package/lib/types/datasource/rpc.d.ts +4 -0
  106. package/lib/types/datasource/service.d.ts +112 -0
  107. package/lib/types/datasource/shell-env.d.ts +0 -29
  108. package/lib/types/datasource/test.d.ts +6 -29
  109. package/lib/types/environment/binding.d.ts +5 -1
  110. package/lib/types/environment/errors.d.ts +1 -1
  111. package/lib/types/environment/runtime.d.ts +5 -5
  112. package/lib/types/environment/types.d.ts +13 -2
  113. package/lib/types/index.d.ts +1 -1
  114. package/lib/types/plugin.d.ts +11 -5
  115. package/lib/types/presentation/build/index.d.ts +11 -0
  116. package/lib/types/presentation/commit.d.ts +4 -0
  117. package/lib/types/presentation/contracts/charts.d.ts +13 -0
  118. package/lib/types/presentation/contracts/editing.d.ts +8 -0
  119. package/lib/types/presentation/contracts/index.d.ts +11 -0
  120. package/lib/types/presentation/contracts/interaction.d.ts +8 -0
  121. package/lib/types/presentation/contracts/types.d.ts +252 -0
  122. package/lib/types/presentation/contracts/values.d.ts +9 -0
  123. package/lib/types/presentation/delivery.d.ts +3 -0
  124. package/lib/types/presentation/files.d.ts +7 -0
  125. package/lib/types/presentation/index.d.ts +6 -0
  126. package/lib/types/presentation/lint.d.ts +13 -0
  127. package/lib/types/presentation/projection/files.d.ts +2 -0
  128. package/lib/types/presentation/projection/index.d.ts +20 -0
  129. package/lib/types/presentation/projection/program.d.ts +2 -0
  130. package/lib/types/presentation/projection/sql-code.d.ts +2 -0
  131. package/lib/types/presentation/receipt.d.ts +14 -0
  132. package/lib/types/presentation/reports.d.ts +5 -0
  133. package/lib/types/presentation/rpc.d.ts +24 -0
  134. package/lib/types/presentation/tool.d.ts +12 -0
  135. package/lib/types/python-execution-contracts.d.ts +10 -0
  136. package/lib/types/python-execution.d.ts +10 -0
  137. package/lib/types/semantic-browser/contracts.d.ts +40 -0
  138. package/lib/types/semantic-browser/definition.d.ts +20 -0
  139. package/lib/types/semantic-browser/program.d.ts +2 -0
  140. package/lib/types/semantic-browser/service.d.ts +20 -0
  141. package/lib/types/semantic-reference/bridge.d.ts +11 -0
  142. package/lib/types/semantic-reference/contracts.d.ts +51 -0
  143. package/lib/types/semantic-reference/index.d.ts +3 -0
  144. package/lib/types/semantic-reference/rpc.d.ts +15 -0
  145. package/lib/types/semantic-reference/search.d.ts +10 -0
  146. package/lib/types/semantic-reference/usage.d.ts +43 -0
  147. package/package.json +43 -19
  148. package/python/presentation-kit/dist/dsh_data_analysis_presentation_kit-1.1.0-py3-none-any.whl +0 -0
  149. package/skills/dsh-data-analysis-presentation/SKILL.md +24 -0
  150. package/skills/dsh-data-analysis-presentation/references/chart-examples.md +18 -0
  151. package/skills/dsh-data-analysis-presentation/references/charts.md +55 -0
  152. package/skills/dsh-data-analysis-presentation/references/examples/artifact.draft.json +27 -0
  153. package/skills/dsh-data-analysis-presentation/references/examples/charts-bins.dataset.json +33 -0
  154. package/skills/dsh-data-analysis-presentation/references/examples/charts-boxes.dataset.json +45 -0
  155. package/skills/dsh-data-analysis-presentation/references/examples/charts-composition.dataset.json +33 -0
  156. package/skills/dsh-data-analysis-presentation/references/examples/charts-funnel.dataset.json +27 -0
  157. package/skills/dsh-data-analysis-presentation/references/examples/charts-precision.dataset.json +21 -0
  158. package/skills/dsh-data-analysis-presentation/references/examples/charts-series.dataset.json +58 -0
  159. package/skills/dsh-data-analysis-presentation/references/examples/charts-shares.dataset.json +33 -0
  160. package/skills/dsh-data-analysis-presentation/references/examples/charts-waterfall.dataset.json +44 -0
  161. package/skills/dsh-data-analysis-presentation/references/examples/charts.draft.json +392 -0
  162. package/skills/dsh-data-analysis-presentation/references/examples/comparison-selected.dataset.json +24 -0
  163. package/skills/dsh-data-analysis-presentation/references/examples/comparison-summary.dataset.json +22 -0
  164. package/skills/dsh-data-analysis-presentation/references/examples/comparison.dataset.json +18 -0
  165. package/skills/dsh-data-analysis-presentation/references/examples/comparison.draft.json +79 -0
  166. package/skills/dsh-data-analysis-presentation/references/examples/computed-sources.draft.json +35 -0
  167. package/skills/dsh-data-analysis-presentation/references/examples/computed.dataset.json +12 -0
  168. package/skills/dsh-data-analysis-presentation/references/examples/computed.draft.json +57 -0
  169. package/skills/dsh-data-analysis-presentation/references/examples/interaction-detail.dataset.json +30 -0
  170. package/skills/dsh-data-analysis-presentation/references/examples/interaction-summary.dataset.json +22 -0
  171. package/skills/dsh-data-analysis-presentation/references/examples/interaction.draft.json +278 -0
  172. package/skills/dsh-data-analysis-presentation/references/examples/source-only.draft.json +19 -0
  173. package/skills/dsh-data-analysis-presentation/references/examples/write-charts.py +73 -0
  174. package/skills/dsh-data-analysis-presentation/references/examples/write-comparison.py +42 -0
  175. package/skills/dsh-data-analysis-presentation/references/examples/write-computed.py +21 -0
  176. package/skills/dsh-data-analysis-presentation/references/examples/write-interaction.py +33 -0
  177. package/skills/dsh-data-analysis-presentation/references/examples.md +42 -0
  178. package/skills/dsh-data-analysis-presentation/references/interaction.md +56 -0
  179. package/skills/dsh-data-analysis-presentation/references/narrative.md +37 -0
  180. package/skills/dsh-data-analysis-presentation/references/schema.md +138 -0
  181. package/lib/datasource/access.js +0 -60
  182. package/lib/datasource/credentials.js +0 -24
  183. package/lib/evidence/bridge-program.js +0 -153
  184. package/lib/evidence/bridge.js +0 -166
  185. package/lib/evidence/index.js +0 -2
  186. package/lib/evidence/sources.js +0 -263
  187. package/lib/types/datasource/access.d.ts +0 -27
  188. package/lib/types/evidence/bridge.d.ts +0 -40
  189. package/lib/types/evidence/index.d.ts +0 -4
  190. package/lib/types/evidence/sources.d.ts +0 -57
  191. package/python/report-kit/dist/dsh_data_analysis_report_kit-3.0.0-py3-none-any.whl +0 -0
  192. package/skills/dsh-data-analysis-report/SKILL.md +0 -57
  193. package/skills/dsh-data-analysis-report/assets/marivo-artifact.js +0 -113
  194. package/skills/dsh-data-analysis-report/assets/marivo-session-dag.js +0 -1201
  195. package/skills/dsh-data-analysis-report/assets/report-data.js +0 -449
package/lib/plugin.js CHANGED
@@ -1,44 +1,54 @@
1
1
  /** Cordis lifecycle adapter for the Web-profile shared Marivo Runtime. */
2
- import path from 'node:path';
3
2
  import process from 'node:process';
4
3
  import { fileURLToPath } from 'node:url';
5
4
  import { apply as installSkillFilesystem } from '@deepseek-ai/dsh-skill-filesystem';
5
+ import { WorkspaceId } from '@deepseek-ai/dsh-workspace';
6
6
  import z from '@deepseek-ai/schemastery';
7
7
  import { createMarivoBridgeSet } from "./bridges.js";
8
- import { registerMarivoDatasourceAccessTool, registerMarivoDatasourceTestTool, } from "./datasource/index.js";
9
- import { MarivoShellCredentialLeases, registerMarivoRuntimeShellEnvironment, } from "./datasource/shell-env.js";
8
+ import { MarivoDatasourceBridge } from "./datasource/bridge.js";
9
+ import { registerMarivoDatasourceTestTool } from "./datasource/index.js";
10
+ import { registerMarivoPythonTool } from "./datasource/python.js";
11
+ import { registerCredentialRpc } from "./datasource/rpc.js";
12
+ import { MarivoCredentialService } from "./datasource/service.js";
13
+ import { registerMarivoRuntimeShellEnvironment } from "./datasource/shell-env.js";
10
14
  import { MarivoHelpBridge } from "./disclosure/bridge.js";
11
15
  import { installMarivoDisclosure, } from "./disclosure/index.js";
12
16
  import { createSharedMarivoRuntimeRunner, DEFAULT_SHARED_RUNTIME_INSTALL_TIMEOUT_MS, ensureSharedMarivoRuntime, MarivoEnvironment, MarivoWorkspaceEnvironmentManager, resolveMarivoEnvironmentSource, } from "./environment/index.js";
13
- import { installMarivoEvidenceSourcesCodeDelivery, registerMarivoEvidenceSourcesTool, } from "./evidence/index.js";
17
+ import { installMarivoPresentationCodeDelivery, MarivoPresentationFileService, registerMarivoPresentationRpc, registerMarivoPresentTool, } from "./presentation/index.js";
18
+ import { browserFailure, SemanticBrowserService } from "./semantic-browser/service.js";
19
+ import { registerSemanticReferenceRpc, SemanticReferenceService, SemanticReferenceUsage, } from "./semantic-reference/index.js";
14
20
  /** Cordis plugin name used by loader diagnostics and lifecycle logs. */
15
21
  export const name = 'dsh-data-analysis';
16
22
  /** Services that must exist before the plugin binds and watches Agent scopes. */
17
- export const inject = ['agents', 'credentials', 'shellEnv', 'skills', 'systemPrompt', 'tools'];
23
+ export const inject = [
24
+ 'agents',
25
+ 'connection',
26
+ 'storageDomain',
27
+ 'workspaceRegistry',
28
+ 'credentials',
29
+ 'shellEnv',
30
+ 'skills',
31
+ 'systemPrompt',
32
+ 'tools',
33
+ ];
18
34
  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.',
35
+ 'DSH Credentials owns Marivo datasource secrets. Never request values in chat, read credential files or ~/.marivo/secrets.toml, or write secrets to scripts, arguments, environment variables, reports or logs.',
36
+ 'Use marivo_datasource_test after datasource changes, credential rotation, connection failures, or explicit user requests. Missing credentials wait for the Web form only while the original call remains alive.',
37
+ 'Execute analysis, metadata inspection and semantic data reads through marivo_python. Declare all exact datasource names this execution may access, including datasources without passwords. Use datasources: [] only when no datasource will be accessed.',
38
+ 'marivo_python waits for all missing credentials and validates the bound Workspace and datasource identities before taking one fresh snapshot and starting user code once. Configured credentials need no extra connection test. Ordinary Shell receives no datasource secret.',
39
+ 'marivo_python installs credential_scope before user code. Create or resume Session/reader objects inside that execution, and close Sessions in finally. Do not replace the resolver, read SecretValue contents, or bypass Host scope with environment/cache configuration.',
40
+ "Each marivo_python call uses a separate process. Closing releases that process's Session resources; it does not end the analytical question or delete durable Artifacts. Continue the same persistent Session identity across calls.",
41
+ 'Configured credentials do not imply a valid connection or query permissions. Preserve real failures; never automatically replay a script with possible side effects.',
42
+ 'Session lifetime pattern inside one marivo_python call (create/resume using current Runtime Help):\nsession = ...\ntry:\n ... # analysis using this Session\nfinally:\n session.close()',
43
+ ].join('\n');
44
+ const MARIVO_ANALYSIS_CLOSEOUT_PROMPT = [
45
+ 'Analysis semantics and execution contracts come from the activated Runtime Skill and current Help.',
46
+ 'Before completing any analysis, including a text-only answer, check each user question and each requested comparison scope against its evidence. Keep incomplete branches explicit; preserve comparison sides, direction and denominator. Match conclusion strength to evidence, and reflect limitations in the claims themselves.',
27
47
  ].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');
48
+ const PRESENTATION_PROMPT = 'Answer ordinary factual questions in text. For charts, tables, reports, dashboards or a readable source presentation, load the dsh-data-analysis-presentation skill and deliver through marivo_present. Existing data needs no prior Marivo skill activation; load the Runtime skills and live Help when new analysis or semantic authoring is needed.';
40
49
  /** Cordis loader schema. Runtime defaults are resolved in {@link apply}. */
41
50
  export const Config = z.object({
51
+ credentialInteraction: z.union(['web', 'none']).default('web'),
42
52
  projectRoot: z.string(),
43
53
  pythonExecutable: z.string(),
44
54
  runtimeRoot: z.string(),
@@ -62,7 +72,9 @@ export function installMarivoPlugin(ctx, environmentOrResolver, options = {}) {
62
72
  if (credentials === undefined) {
63
73
  throw new Error('dsh-data-analysis requires the DSH credentials service');
64
74
  }
65
- const shellCredentials = new MarivoShellCredentialLeases(ctx, credentials);
75
+ const credentialService = options.credentialService ??
76
+ new MarivoCredentialService(credentials, options.credentialInteraction);
77
+ const stopCredentialUpdates = ctx.on('credentials/reference-updated', (ref) => credentialService.invalidateStorageRef(ref));
66
78
  const bridgeSets = new WeakMap();
67
79
  const install = (agent) => {
68
80
  if (installed.has(agent))
@@ -81,34 +93,40 @@ export function installMarivoPlugin(ctx, environmentOrResolver, options = {}) {
81
93
  };
82
94
  const helpSource = options.helpBridgeSource ?? (async () => (await resolveBridgeSet()).help);
83
95
  const datasourceSource = async () => (await resolveBridgeSet()).datasource;
84
- const evidenceSource = async () => (await resolveBridgeSet()).evidence;
96
+ const presentationSource = async () => {
97
+ const workspace = resolvePresentationWorkspace(ctx, String(agent.session.id));
98
+ const projection = (await resolveBridgeSet()).presentation;
99
+ const current = resolvePresentationWorkspace(ctx, String(agent.session.id));
100
+ if (workspace.id !== current.id ||
101
+ workspace.path !== current.path ||
102
+ projection.binding.projectRoot !== current.path)
103
+ throw new Error('Presentation Workspace changed or does not match the bound Runtime');
104
+ return { workspaceId: current.id, projection };
105
+ };
85
106
  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),
107
+ controller.addDisposer(registerMarivoDatasourceTestTool(agent.ctx, datasourceSource, credentialService));
108
+ controller.addDisposer(registerMarivoPythonTool(agent.ctx, datasourceSource, credentialService));
109
+ controller.addDisposer(() => credentialService.disposeAgent(agent));
110
+ controller.addDisposer(registerMarivoPresentTool(agent.ctx, presentationSource, agent.session));
111
+ controller.addDisposer(installMarivoPresentationCodeDelivery(agent.ctx));
112
+ controller.addDisposer(agent.ctx.systemPrompt.section({
113
+ name: 'marivo:presentation',
114
+ order: 180,
115
+ text: PRESENTATION_PROMPT,
93
116
  }));
94
- controller.addDisposer(registerMarivoEvidenceSourcesTool(agent.ctx, evidenceSource, agent.session));
95
- controller.addDisposer(installMarivoEvidenceSourcesCodeDelivery(agent.ctx));
96
117
  controller.addDisposer(agent.ctx.systemPrompt.section({
97
118
  name: 'marivo:datasource-credentials',
98
119
  order: 170,
99
- text: () => controller.activeSkills.includes('marivo-semantic')
120
+ text: () => controller.activeSkills.some((skill) => ['marivo-analysis', 'marivo-semantic'].includes(skill))
100
121
  ? MARIVO_DATASOURCE_CREDENTIAL_PROMPT
101
122
  : '',
102
123
  }));
103
124
  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 : '',
125
+ name: 'marivo:analysis-closeout',
126
+ order: 175,
127
+ text: () => controller.activeSkills.includes('marivo-analysis')
128
+ ? MARIVO_ANALYSIS_CLOSEOUT_PROMPT
129
+ : '',
112
130
  }));
113
131
  installed.set(agent, controller);
114
132
  };
@@ -119,7 +137,8 @@ export function installMarivoPlugin(ctx, environmentOrResolver, options = {}) {
119
137
  catch (error) {
120
138
  for (const controller of installed.values())
121
139
  controller.dispose();
122
- shellCredentials.dispose();
140
+ stopCredentialUpdates();
141
+ void credentialService.close();
123
142
  throw error;
124
143
  }
125
144
  const stopCreated = ctx.on('agent/created', ({ agent }) => {
@@ -136,12 +155,22 @@ export function installMarivoPlugin(ctx, environmentOrResolver, options = {}) {
136
155
  active = false;
137
156
  stopCreated();
138
157
  stopDisposed();
158
+ stopCredentialUpdates();
139
159
  for (const controller of installed.values())
140
160
  controller.dispose();
141
161
  installed.clear();
142
- shellCredentials.dispose();
162
+ void credentialService.close();
143
163
  };
144
164
  }
165
+ /** Resolve only Harness-owned, header-validated Workspace membership; never infer it from a path. */
166
+ export function resolvePresentationWorkspace(ctx, sessionId) {
167
+ const matches = ctx.workspaceRegistry
168
+ .list()
169
+ .filter((workspace) => workspace.sessionIds.some((id) => String(id) === sessionId));
170
+ if (matches.length !== 1)
171
+ throw new Error('Presentation requires one current Session Workspace');
172
+ return { id: String(matches[0].id), path: matches[0].path };
173
+ }
145
174
  /** Ensure the shared Runtime once, mount its skills, then bind each Workspace lazily. */
146
175
  export async function apply(ctx, config = {}) {
147
176
  const pythonExecutable = config.pythonExecutable ?? process.env.DSH_DATA_ANALYSIS_PYTHON;
@@ -155,24 +184,112 @@ export async function apply(ctx, config = {}) {
155
184
  });
156
185
  const disposeRuntimeShellEnvironment = registerMarivoRuntimeShellEnvironment(ctx, runtime.pythonExecutable);
157
186
  const manager = new MarivoWorkspaceEnvironmentManager(runtime);
187
+ const bindings = new WeakMap();
188
+ const resolveEnvironment = (agent) => {
189
+ const root = configuredProjectRoot(config, agent);
190
+ const existing = bindings.get(agent);
191
+ if (existing?.root === root)
192
+ return existing.environment;
193
+ const environment = manager.resolve(root);
194
+ bindings.set(agent, { root, environment });
195
+ return environment;
196
+ };
197
+ const credentialService = new MarivoCredentialService(ctx.credentials, config.credentialInteraction);
198
+ let disposeCredentials;
199
+ let disposeReferences;
200
+ let disposePresentation;
201
+ let referenceService;
158
202
  let disposePlugin;
203
+ const browserService = new SemanticBrowserService({
204
+ getWorkspace: (id) => ctx.workspaceRegistry.get(WorkspaceId(id)),
205
+ projectRoot: (workspace) => config.projectRoot ?? process.env.DSH_DATA_ANALYSIS_PROJECT_ROOT ?? workspace.path,
206
+ resolve: (root) => manager.resolve(root),
207
+ });
159
208
  try {
160
209
  installSkillFilesystem(ctx, {
161
210
  providerName: 'dsh-data-analysis-marivo',
162
211
  includeDefaultRoots: false,
163
- customSkillDirs: [runtime.skillsRoot, integrationSkillsRoot],
212
+ customSkillDirs: [runtime.skillsRoot],
213
+ watch: false,
214
+ });
215
+ installSkillFilesystem(ctx, {
216
+ providerName: 'dsh-data-analysis-presentation',
217
+ includeDefaultRoots: false,
218
+ customSkillDirs: [fileURLToPath(new URL('../skills/', import.meta.url))],
164
219
  watch: false,
165
220
  });
166
221
  const helpBridge = new MarivoHelpBridge(createSharedMarivoRuntimeRunner(runtime));
167
- disposePlugin = installMarivoPlugin(ctx, (agent) => manager.resolve(configuredProjectRoot(config, agent)), { helpBridgeSource: helpBridge });
222
+ disposePlugin = installMarivoPlugin(ctx, resolveEnvironment, {
223
+ helpBridgeSource: helpBridge,
224
+ credentialService,
225
+ });
226
+ disposeCredentials = registerCredentialRpc(ctx.connection, credentialService, async (id) => {
227
+ const workspace = ctx.workspaceRegistry.get(WorkspaceId(id));
228
+ if (!workspace)
229
+ throw new Error('Workspace unavailable');
230
+ const root = config.projectRoot ?? process.env.DSH_DATA_ANALYSIS_PROJECT_ROOT ?? workspace.path;
231
+ const environment = await manager.resolve(root);
232
+ const current = ctx.workspaceRegistry.get(WorkspaceId(id));
233
+ if (!current ||
234
+ current.path !== workspace.path ||
235
+ (config.projectRoot ?? process.env.DSH_DATA_ANALYSIS_PROJECT_ROOT ?? current.path) !== root)
236
+ throw new Error('Workspace changed');
237
+ return new MarivoDatasourceBridge(environment);
238
+ });
239
+ disposePresentation = registerMarivoPresentationRpc(ctx.connection, new MarivoPresentationFileService(async (sessionId) => resolvePresentationWorkspace(ctx, sessionId)));
240
+ let lastDiagnostic = -Infinity;
241
+ const usage = new SemanticReferenceUsage(ctx.storageDomain, Date.now, () => {
242
+ if (Date.now() - lastDiagnostic >= 30_000) {
243
+ lastDiagnostic = Date.now();
244
+ console.warn('dsh-data-analysis semantic-reference usage unavailable');
245
+ }
246
+ });
247
+ referenceService = new SemanticReferenceService(async (sessionId, purpose) => {
248
+ const agent = ctx.agents.list().find((item) => item.session.id === sessionId);
249
+ if (!agent)
250
+ throw new Error('unknown-session');
251
+ const bound = bindings.get(agent);
252
+ if (purpose === 'reference' &&
253
+ (!bound || bound.root !== configuredProjectRoot(config, agent)))
254
+ throw new Error('environment-unbound');
255
+ const environment = await (purpose === 'reference'
256
+ ? bound.environment
257
+ : resolveEnvironment(agent));
258
+ if (!ctx.agents.list().includes(agent) ||
259
+ bindings.get(agent)?.root !== configuredProjectRoot(config, agent))
260
+ throw new Error('environment-changed');
261
+ return environment;
262
+ }, usage);
263
+ disposeReferences = registerSemanticReferenceRpc(ctx.connection, referenceService, async (_endpoint, payload, signal) => {
264
+ try {
265
+ return { ok: true, value: await browserService.read(payload, signal) };
266
+ }
267
+ catch (error) {
268
+ return {
269
+ ok: false,
270
+ error: { code: 'internal', message: browserFailure(error), details: {} },
271
+ };
272
+ }
273
+ });
168
274
  }
169
275
  catch (error) {
276
+ browserService.dispose();
277
+ await disposePresentation?.();
278
+ await disposeCredentials?.();
279
+ await credentialService.close();
280
+ await referenceService?.close();
281
+ disposePlugin?.();
170
282
  manager.dispose();
171
283
  disposeRuntimeShellEnvironment();
172
284
  throw error;
173
285
  }
174
- return () => {
175
- disposePlugin();
286
+ return async () => {
287
+ browserService.dispose();
288
+ await disposePresentation?.();
289
+ await disposeCredentials?.();
290
+ await credentialService.close();
291
+ await disposeReferences?.();
292
+ disposePlugin?.();
176
293
  manager.dispose();
177
294
  disposeRuntimeShellEnvironment();
178
295
  };