@chengxianglibra/dsh-data-analysis 0.1.2 → 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.
- package/README.md +136 -99
- package/cordis.patch.yml +1 -1
- package/lib/bin/environment.js +8 -6
- package/lib/client/credentials/changes.js +74 -0
- package/lib/client/credentials/create-datasource.js +126 -22
- package/lib/client/credentials/credential-draft.js +42 -0
- package/lib/client/credentials/defaults.js +11 -0
- package/lib/client/credentials/descriptions.js +46 -0
- package/lib/client/credentials/install.js +209 -81
- package/lib/client/credentials/model.js +323 -51
- package/lib/client/credentials/report-publishing.js +96 -0
- package/lib/client/credentials/styles.js +13 -9
- package/lib/client/i18n/context.js +22 -0
- package/lib/client/i18n/copy.js +57 -0
- package/lib/client/i18n/credentials.js +475 -0
- package/lib/client/i18n/host.js +27 -0
- package/lib/client/i18n/navigation.js +41 -0
- package/lib/client/i18n/presentation.js +577 -0
- package/lib/client/i18n/python.js +36 -0
- package/lib/client/i18n/semantic.js +441 -0
- package/lib/client/input-context.js +21 -0
- package/lib/client/python-tool/card.js +35 -0
- package/lib/client/python-tool/execution-error.js +35 -0
- package/lib/client/python-tool/install.js +9 -0
- package/lib/client/python-tool/model.js +101 -0
- package/lib/client/right-tabs/install.js +535 -0
- package/lib/client/right-tabs/live-delivery.js +58 -0
- package/lib/client/right-tabs/navigation.js +47 -0
- package/lib/client/right-tabs/page.js +178 -0
- package/lib/client/right-tabs/styles.js +11 -0
- package/lib/client/rpc.js +5 -0
- package/lib/client/semantic-reference.js +10 -0
- package/lib/client/workspace-header-action.js +14 -1
- package/lib/client/workspace-shortcuts.js +26 -0
- package/lib/client.js +365 -242
- package/lib/compatibility.js +1 -1
- package/lib/datasource/authoring.js +43 -4
- package/lib/datasource/bridge-programs.js +23 -20
- package/lib/datasource/bridge.js +46 -3
- package/lib/datasource/changes-contract.js +41 -0
- package/lib/datasource/changes.js +49 -0
- package/lib/datasource/configure.js +39 -0
- package/lib/datasource/defaults.js +25 -0
- package/lib/datasource/index.js +2 -1
- package/lib/datasource/python-options.js +21 -0
- package/lib/datasource/python.js +116 -25
- package/lib/datasource/rpc.js +75 -13
- package/lib/datasource/service.js +286 -11
- package/lib/datasource/test.js +2 -1
- package/lib/disclosure/activation.js +19 -7
- package/lib/disclosure/execution-guidance.js +52 -0
- package/lib/disclosure/help.js +4 -1
- package/lib/environment/runtime.js +35 -34
- package/lib/environment/workspace.js +18 -1
- package/lib/lifecycle.js +33 -0
- package/lib/plugin-agents.js +154 -0
- package/lib/plugin.js +94 -172
- package/lib/presentation/asset.js +34 -0
- package/lib/presentation/assets/portable.js +14 -14
- package/lib/presentation/assets/static.js +344 -73
- package/lib/presentation/build/index.js +3 -2
- package/lib/presentation/commit.js +19 -12
- package/lib/presentation/contracts/asset-path.js +9 -0
- package/lib/presentation/contracts/catalog.js +62 -0
- package/lib/presentation/contracts/charts.js +0 -23
- package/lib/presentation/contracts/index.js +17 -5
- package/lib/presentation/contracts/types.js +1 -1
- package/lib/presentation/delivery.js +45 -30
- package/lib/presentation/export-html.js +214 -0
- package/lib/presentation/files.js +4 -5
- package/lib/presentation/projection/index.js +2 -1
- package/lib/presentation/projection/program.js +2 -9
- package/lib/presentation/projection/sql-code.js +13 -13
- package/lib/presentation/reports.js +114 -17
- package/lib/presentation/rpc.js +96 -58
- package/lib/presentation/tool.js +6 -10
- package/lib/report-publishing/adapters.js +111 -0
- package/lib/report-publishing/config.js +69 -0
- package/lib/report-publishing/service.js +180 -0
- package/lib/rpc.js +49 -0
- package/lib/semantic-browser/contracts.js +17 -0
- package/lib/semantic-browser/program.js +10 -0
- package/lib/semantic-browser/service.js +40 -6
- package/lib/semantic-reference/bridge.js +10 -1
- package/lib/semantic-reference/contracts.js +20 -6
- package/lib/semantic-reference/environment.js +56 -0
- package/lib/semantic-reference/labels.js +16 -0
- package/lib/semantic-reference/rpc.js +39 -18
- package/lib/semantic-reference/search.js +5 -4
- package/lib/semantic-reference/usage.js +12 -3
- package/lib/tool-lifecycle.js +22 -0
- package/lib/types/client/credentials/changes.d.ts +9 -0
- package/lib/types/client/credentials/create-datasource.d.ts +3 -1
- package/lib/types/client/credentials/credential-draft.d.ts +14 -0
- package/lib/types/client/credentials/defaults.d.ts +2 -0
- package/lib/types/client/credentials/descriptions.d.ts +1 -0
- package/lib/types/client/credentials/install.d.ts +19 -1
- package/lib/types/client/credentials/model.d.ts +31 -11
- package/lib/types/client/credentials/report-publishing.d.ts +5 -0
- package/lib/types/client/credentials/styles.d.ts +1 -1
- package/lib/types/client/i18n/context.d.ts +17 -0
- package/lib/types/client/i18n/copy.d.ts +806 -0
- package/lib/types/client/i18n/credentials.d.ts +475 -0
- package/lib/types/client/i18n/host.d.ts +16 -0
- package/lib/types/client/i18n/navigation.d.ts +41 -0
- package/lib/types/client/i18n/presentation.d.ts +577 -0
- package/lib/types/client/i18n/python.d.ts +19 -0
- package/lib/types/client/i18n/semantic.d.ts +441 -0
- package/lib/types/client/input-context.d.ts +19 -0
- package/lib/types/client/presentation/ask-dsh.d.ts +4 -8
- package/lib/types/client/presentation/catalog-model.d.ts +24 -0
- package/lib/types/client/presentation/catalog.d.ts +20 -0
- package/lib/types/client/presentation/chart-tooltip.d.ts +2 -2
- package/lib/types/client/presentation/context-reference.d.ts +12 -0
- package/lib/types/client/presentation/copy-context.d.ts +2 -2
- package/lib/types/client/presentation/delivery-model.d.ts +27 -6
- package/lib/types/client/presentation/delivery.d.ts +8 -7
- package/lib/types/client/presentation/download.d.ts +2 -0
- package/lib/types/client/presentation/export-menu.d.ts +26 -0
- package/lib/types/client/presentation/export-view.d.ts +63 -0
- package/lib/types/client/presentation/host-entry.d.ts +8 -2
- package/lib/types/client/presentation/icons.d.ts +1 -1
- package/lib/types/client/presentation/model.d.ts +14 -15
- package/lib/types/client/presentation/reader.d.ts +15 -2
- package/lib/types/client/presentation/reference-source.d.ts +9 -0
- package/lib/types/client/presentation/source-code-model.d.ts +2 -1
- package/lib/types/client/presentation/source-code.d.ts +0 -5
- package/lib/types/client/presentation/source-dialog.d.ts +1 -2
- package/lib/types/client/presentation/sources.d.ts +5 -5
- package/lib/types/client/presentation/styles.d.ts +1 -1
- package/lib/types/client/presentation/table.d.ts +5 -1
- package/lib/types/client/python-tool/card.d.ts +2 -0
- package/lib/types/client/python-tool/execution-error.d.ts +3 -0
- package/lib/types/client/python-tool/install.d.ts +2 -0
- package/lib/types/client/python-tool/model.d.ts +20 -0
- package/lib/types/client/right-tabs/install.d.ts +18 -0
- package/lib/types/client/right-tabs/live-delivery.d.ts +8 -0
- package/lib/types/client/right-tabs/navigation.d.ts +17 -0
- package/lib/types/client/right-tabs/page.d.ts +36 -0
- package/lib/types/client/right-tabs/styles.d.ts +2 -0
- package/lib/types/client/rpc.d.ts +3 -0
- package/lib/types/client/semantic-reference.d.ts +4 -0
- package/lib/types/client/workspace-header-action.d.ts +1 -1
- package/lib/types/client/workspace-shortcuts.d.ts +15 -0
- package/lib/types/client.d.ts +6 -3
- package/lib/types/compatibility.d.ts +1 -1
- package/lib/types/datasource/authoring.d.ts +10 -0
- package/lib/types/datasource/bridge.d.ts +23 -2
- package/lib/types/datasource/changes-contract.d.ts +18 -0
- package/lib/types/datasource/changes.d.ts +15 -0
- package/lib/types/datasource/configure.d.ts +7 -0
- package/lib/types/datasource/defaults.d.ts +7 -0
- package/lib/types/datasource/index.d.ts +6 -1
- package/lib/types/datasource/python-options.d.ts +9 -0
- package/lib/types/datasource/python.d.ts +17 -2
- package/lib/types/datasource/rpc.d.ts +2 -1
- package/lib/types/datasource/service.d.ts +48 -5
- package/lib/types/datasource/test.d.ts +1 -1
- package/lib/types/disclosure/activation.d.ts +2 -1
- package/lib/types/disclosure/execution-guidance.d.ts +6 -0
- package/lib/types/disclosure/help.d.ts +1 -1
- package/lib/types/environment/types.d.ts +2 -1
- package/lib/types/environment/workspace.d.ts +1 -0
- package/lib/types/lifecycle.d.ts +8 -0
- package/lib/types/plugin-agents.d.ts +27 -0
- package/lib/types/plugin.d.ts +12 -28
- package/lib/types/presentation/asset.d.ts +6 -0
- package/lib/types/presentation/build/index.d.ts +7 -2
- package/lib/types/presentation/commit.d.ts +1 -1
- package/lib/types/presentation/contracts/asset-path.d.ts +2 -0
- package/lib/types/presentation/contracts/catalog.d.ts +27 -0
- package/lib/types/presentation/contracts/charts.d.ts +0 -2
- package/lib/types/presentation/contracts/types.d.ts +7 -4
- package/lib/types/presentation/delivery.d.ts +1 -1
- package/lib/types/presentation/export-html.d.ts +13 -0
- package/lib/types/presentation/reports.d.ts +6 -1
- package/lib/types/presentation/rpc.d.ts +3 -2
- package/lib/types/presentation/tool.d.ts +2 -2
- package/lib/types/report-publishing/adapters.d.ts +6 -0
- package/lib/types/report-publishing/config.d.ts +22 -0
- package/lib/types/report-publishing/service.d.ts +68 -0
- package/lib/types/rpc.d.ts +3 -0
- package/lib/types/semantic-browser/contracts.d.ts +7 -0
- package/lib/types/semantic-browser/service.d.ts +7 -1
- package/lib/types/semantic-reference/bridge.d.ts +1 -0
- package/lib/types/semantic-reference/contracts.d.ts +5 -2
- package/lib/types/semantic-reference/environment.d.ts +22 -0
- package/lib/types/semantic-reference/labels.d.ts +16 -0
- package/lib/types/semantic-reference/rpc.d.ts +1 -1
- package/lib/types/semantic-reference/search.d.ts +1 -1
- package/lib/types/tool-lifecycle.d.ts +4 -0
- package/lib/types/workspace-identity.d.ts +6 -0
- package/lib/workspace-identity.js +9 -0
- package/package.json +83 -61
- package/python/presentation-kit/dist/dsh_data_analysis_presentation_kit-1.1.0-py3-none-any.whl +0 -0
- package/skills/dsh-data-analysis-files/SKILL.md +32 -0
- package/skills/dsh-data-analysis-files/references/examples.md +93 -0
- package/skills/dsh-data-analysis-presentation/SKILL.md +10 -6
- package/skills/dsh-data-analysis-presentation/references/examples/artifact.draft.json +13 -4
- package/skills/dsh-data-analysis-presentation/references/examples/charts.draft.json +3 -2
- package/skills/dsh-data-analysis-presentation/references/examples/comparison.draft.json +3 -2
- package/skills/dsh-data-analysis-presentation/references/examples/computed-sources.draft.json +12 -5
- package/skills/dsh-data-analysis-presentation/references/examples/computed.draft.json +3 -2
- package/skills/dsh-data-analysis-presentation/references/examples/interaction.draft.json +3 -2
- package/skills/dsh-data-analysis-presentation/references/examples/source-only.draft.json +12 -4
- package/skills/dsh-data-analysis-presentation/references/examples.md +3 -1
- package/skills/dsh-data-analysis-presentation/references/export-html.md +7 -0
- package/skills/dsh-data-analysis-presentation/references/interaction.md +1 -1
- package/skills/dsh-data-analysis-presentation/references/narrative.md +1 -1
- package/skills/dsh-data-analysis-presentation/references/publishing.md +3 -0
- package/skills/dsh-data-analysis-presentation/references/schema.md +25 -1
- package/lib/types/client/presentation/install.d.ts +0 -15
package/lib/plugin.js
CHANGED
|
@@ -1,28 +1,38 @@
|
|
|
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
13
|
import process from 'node:process';
|
|
3
14
|
import { fileURLToPath } from 'node:url';
|
|
4
15
|
import { apply as installSkillFilesystem } from '@deepseek-ai/dsh-skill-filesystem';
|
|
5
16
|
import { WorkspaceId } from '@deepseek-ai/dsh-workspace';
|
|
6
17
|
import z from '@deepseek-ai/schemastery';
|
|
7
|
-
import { createMarivoBridgeSet } from "./bridges.js";
|
|
8
18
|
import { MarivoDatasourceBridge } from "./datasource/bridge.js";
|
|
9
|
-
import {
|
|
10
|
-
import { registerMarivoPythonTool } from "./datasource/python.js";
|
|
19
|
+
import { DEFAULT_PYTHON_MAX_TIMEOUT_MS, DEFAULT_PYTHON_TIMEOUT_MS, resolvePythonOptions, } from "./datasource/python-options.js";
|
|
11
20
|
import { registerCredentialRpc } from "./datasource/rpc.js";
|
|
12
21
|
import { MarivoCredentialService } from "./datasource/service.js";
|
|
13
22
|
import { registerMarivoRuntimeShellEnvironment } from "./datasource/shell-env.js";
|
|
14
23
|
import { MarivoHelpBridge } from "./disclosure/bridge.js";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import { installMarivoPresentationCodeDelivery, MarivoPresentationFileService, registerMarivoPresentationRpc, registerMarivoPresentTool, } from "./presentation/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";
|
|
18
26
|
import { browserFailure, SemanticBrowserService } from "./semantic-browser/service.js";
|
|
19
27
|
import { registerSemanticReferenceRpc, SemanticReferenceService, SemanticReferenceUsage, } from "./semantic-reference/index.js";
|
|
28
|
+
export { MARIVO_DATASOURCE_CREDENTIAL_PROMPT } from "./disclosure/execution-guidance.js";
|
|
20
29
|
/** Cordis plugin name used by loader diagnostics and lifecycle logs. */
|
|
21
30
|
export const name = 'dsh-data-analysis';
|
|
22
31
|
/** Services that must exist before the plugin binds and watches Agent scopes. */
|
|
23
32
|
export const inject = [
|
|
24
33
|
'agents',
|
|
25
34
|
'connection',
|
|
35
|
+
'typert',
|
|
26
36
|
'storageDomain',
|
|
27
37
|
'workspaceRegistry',
|
|
28
38
|
'credentials',
|
|
@@ -31,28 +41,18 @@ export const inject = [
|
|
|
31
41
|
'systemPrompt',
|
|
32
42
|
'tools',
|
|
33
43
|
];
|
|
34
|
-
export const MARIVO_DATASOURCE_CREDENTIAL_PROMPT = [
|
|
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.',
|
|
47
|
-
].join(' ');
|
|
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.';
|
|
49
44
|
/** Cordis loader schema. Runtime defaults are resolved in {@link apply}. */
|
|
50
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
51
|
credentialInteraction: z.union(['web', 'none']).default('web'),
|
|
52
52
|
projectRoot: z.string(),
|
|
53
53
|
pythonExecutable: z.string(),
|
|
54
54
|
runtimeRoot: z.string(),
|
|
55
|
-
|
|
55
|
+
bootstrapPythonExecutable: z.string(),
|
|
56
56
|
installTimeoutMs: z.number().default(DEFAULT_SHARED_RUNTIME_INSTALL_TIMEOUT_MS),
|
|
57
57
|
});
|
|
58
58
|
function configuredProjectRoot(config, agent) {
|
|
@@ -62,124 +62,17 @@ function configuredProjectRoot(config, agent) {
|
|
|
62
62
|
process.env.DSH_CWD ??
|
|
63
63
|
process.cwd());
|
|
64
64
|
}
|
|
65
|
-
/**
|
|
66
|
-
* Install one already-bound environment into every live or subsequently published Agent scope.
|
|
67
|
-
* Installation is transactional for existing Agents and is disposed with the Cordis plugin.
|
|
68
|
-
*/
|
|
69
|
-
export function installMarivoPlugin(ctx, environmentOrResolver, options = {}) {
|
|
70
|
-
const installed = new Map();
|
|
71
|
-
const credentials = options.credentials ?? ctx.credentials;
|
|
72
|
-
if (credentials === undefined) {
|
|
73
|
-
throw new Error('dsh-data-analysis requires the DSH credentials service');
|
|
74
|
-
}
|
|
75
|
-
const credentialService = options.credentialService ??
|
|
76
|
-
new MarivoCredentialService(credentials, options.credentialInteraction);
|
|
77
|
-
const stopCredentialUpdates = ctx.on('credentials/reference-updated', (ref) => credentialService.invalidateStorageRef(ref));
|
|
78
|
-
const bridgeSets = new WeakMap();
|
|
79
|
-
const install = (agent) => {
|
|
80
|
-
if (installed.has(agent))
|
|
81
|
-
return;
|
|
82
|
-
const source = environmentOrResolver instanceof MarivoEnvironment
|
|
83
|
-
? environmentOrResolver
|
|
84
|
-
: () => Promise.resolve(environmentOrResolver(agent));
|
|
85
|
-
const resolveBridgeSet = async () => {
|
|
86
|
-
const environment = await resolveMarivoEnvironmentSource(source);
|
|
87
|
-
let bridges = bridgeSets.get(environment);
|
|
88
|
-
if (bridges === undefined) {
|
|
89
|
-
bridges = createMarivoBridgeSet(environment);
|
|
90
|
-
bridgeSets.set(environment, bridges);
|
|
91
|
-
}
|
|
92
|
-
return bridges;
|
|
93
|
-
};
|
|
94
|
-
const helpSource = options.helpBridgeSource ?? (async () => (await resolveBridgeSet()).help);
|
|
95
|
-
const datasourceSource = async () => (await resolveBridgeSet()).datasource;
|
|
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
|
-
};
|
|
106
|
-
const controller = installMarivoDisclosure(ctx, agent, helpSource, options);
|
|
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,
|
|
116
|
-
}));
|
|
117
|
-
controller.addDisposer(agent.ctx.systemPrompt.section({
|
|
118
|
-
name: 'marivo:datasource-credentials',
|
|
119
|
-
order: 170,
|
|
120
|
-
text: () => controller.activeSkills.some((skill) => ['marivo-analysis', 'marivo-semantic'].includes(skill))
|
|
121
|
-
? MARIVO_DATASOURCE_CREDENTIAL_PROMPT
|
|
122
|
-
: '',
|
|
123
|
-
}));
|
|
124
|
-
controller.addDisposer(agent.ctx.systemPrompt.section({
|
|
125
|
-
name: 'marivo:analysis-closeout',
|
|
126
|
-
order: 175,
|
|
127
|
-
text: () => controller.activeSkills.includes('marivo-analysis')
|
|
128
|
-
? MARIVO_ANALYSIS_CLOSEOUT_PROMPT
|
|
129
|
-
: '',
|
|
130
|
-
}));
|
|
131
|
-
installed.set(agent, controller);
|
|
132
|
-
};
|
|
133
|
-
try {
|
|
134
|
-
for (const agent of ctx.agents.list())
|
|
135
|
-
install(agent);
|
|
136
|
-
}
|
|
137
|
-
catch (error) {
|
|
138
|
-
for (const controller of installed.values())
|
|
139
|
-
controller.dispose();
|
|
140
|
-
stopCredentialUpdates();
|
|
141
|
-
void credentialService.close();
|
|
142
|
-
throw error;
|
|
143
|
-
}
|
|
144
|
-
const stopCreated = ctx.on('agent/created', ({ agent }) => {
|
|
145
|
-
install(agent);
|
|
146
|
-
});
|
|
147
|
-
const stopDisposed = ctx.on('agent/disposed', ({ agent }) => {
|
|
148
|
-
installed.get(agent)?.dispose();
|
|
149
|
-
installed.delete(agent);
|
|
150
|
-
});
|
|
151
|
-
let active = true;
|
|
152
|
-
return () => {
|
|
153
|
-
if (!active)
|
|
154
|
-
return;
|
|
155
|
-
active = false;
|
|
156
|
-
stopCreated();
|
|
157
|
-
stopDisposed();
|
|
158
|
-
stopCredentialUpdates();
|
|
159
|
-
for (const controller of installed.values())
|
|
160
|
-
controller.dispose();
|
|
161
|
-
installed.clear();
|
|
162
|
-
void credentialService.close();
|
|
163
|
-
};
|
|
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
|
-
}
|
|
174
65
|
/** Ensure the shared Runtime once, mount its skills, then bind each Workspace lazily. */
|
|
175
66
|
export async function apply(ctx, config = {}) {
|
|
67
|
+
const publishingConfig = resolvePublishingConfig(config.reportPublishing);
|
|
68
|
+
const pythonOptions = resolvePythonOptions(config);
|
|
176
69
|
const pythonExecutable = config.pythonExecutable ?? process.env.DSH_DATA_ANALYSIS_PYTHON;
|
|
177
70
|
const runtimeRoot = config.runtimeRoot ?? process.env.DSH_DATA_ANALYSIS_RUNTIME_ROOT;
|
|
178
|
-
const
|
|
71
|
+
const bootstrapPythonExecutable = config.bootstrapPythonExecutable ?? process.env.DSH_DATA_ANALYSIS_BOOTSTRAP_PYTHON;
|
|
179
72
|
const runtime = await ensureSharedMarivoRuntime({
|
|
180
73
|
...(pythonExecutable === undefined ? {} : { pythonExecutable }),
|
|
181
74
|
...(runtimeRoot === undefined ? {} : { runtimeRoot }),
|
|
182
|
-
...(
|
|
75
|
+
...(bootstrapPythonExecutable === undefined ? {} : { bootstrapPythonExecutable }),
|
|
183
76
|
...(config.installTimeoutMs === undefined ? {} : { installTimeoutMs: config.installTimeoutMs }),
|
|
184
77
|
});
|
|
185
78
|
const disposeRuntimeShellEnvironment = registerMarivoRuntimeShellEnvironment(ctx, runtime.pythonExecutable);
|
|
@@ -195,17 +88,51 @@ export async function apply(ctx, config = {}) {
|
|
|
195
88
|
return environment;
|
|
196
89
|
};
|
|
197
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;
|
|
198
98
|
let disposeCredentials;
|
|
199
99
|
let disposeReferences;
|
|
200
100
|
let disposePresentation;
|
|
201
101
|
let referenceService;
|
|
202
|
-
let
|
|
102
|
+
let agentInstallation;
|
|
103
|
+
let closing;
|
|
203
104
|
const browserService = new SemanticBrowserService({
|
|
204
105
|
getWorkspace: (id) => ctx.workspaceRegistry.get(WorkspaceId(id)),
|
|
205
106
|
projectRoot: (workspace) => config.projectRoot ?? process.env.DSH_DATA_ANALYSIS_PROJECT_ROOT ?? workspace.path,
|
|
206
107
|
resolve: (root) => manager.resolve(root),
|
|
207
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
|
+
};
|
|
208
134
|
try {
|
|
135
|
+
unregisterChanges = ctx.typert.register(credentialChangesHost);
|
|
209
136
|
installSkillFilesystem(ctx, {
|
|
210
137
|
providerName: 'dsh-data-analysis-marivo',
|
|
211
138
|
includeDefaultRoots: false,
|
|
@@ -219,10 +146,25 @@ export async function apply(ctx, config = {}) {
|
|
|
219
146
|
watch: false,
|
|
220
147
|
});
|
|
221
148
|
const helpBridge = new MarivoHelpBridge(createSharedMarivoRuntimeRunner(runtime));
|
|
222
|
-
|
|
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,
|
|
223
163
|
helpBridgeSource: helpBridge,
|
|
164
|
+
...(publishingConfig ? { reportPublishing } : {}),
|
|
224
165
|
credentialService,
|
|
225
166
|
});
|
|
167
|
+
agentInstallation.install();
|
|
226
168
|
disposeCredentials = registerCredentialRpc(ctx.connection, credentialService, async (id) => {
|
|
227
169
|
const workspace = ctx.workspaceRegistry.get(WorkspaceId(id));
|
|
228
170
|
if (!workspace)
|
|
@@ -232,11 +174,11 @@ export async function apply(ctx, config = {}) {
|
|
|
232
174
|
const current = ctx.workspaceRegistry.get(WorkspaceId(id));
|
|
233
175
|
if (!current ||
|
|
234
176
|
current.path !== workspace.path ||
|
|
235
|
-
(config.projectRoot ?? process.env.DSH_DATA_ANALYSIS_PROJECT_ROOT ?? current.path) !==
|
|
177
|
+
(config.projectRoot ?? process.env.DSH_DATA_ANALYSIS_PROJECT_ROOT ?? current.path) !==
|
|
178
|
+
root)
|
|
236
179
|
throw new Error('Workspace changed');
|
|
237
180
|
return new MarivoDatasourceBridge(environment);
|
|
238
|
-
});
|
|
239
|
-
disposePresentation = registerMarivoPresentationRpc(ctx.connection, new MarivoPresentationFileService(async (sessionId) => resolvePresentationWorkspace(ctx, sessionId)));
|
|
181
|
+
}, config.datasourceDefaults);
|
|
240
182
|
let lastDiagnostic = -Infinity;
|
|
241
183
|
const usage = new SemanticReferenceUsage(ctx.storageDomain, Date.now, () => {
|
|
242
184
|
if (Date.now() - lastDiagnostic >= 30_000) {
|
|
@@ -244,22 +186,13 @@ export async function apply(ctx, config = {}) {
|
|
|
244
186
|
console.warn('dsh-data-analysis semantic-reference usage unavailable');
|
|
245
187
|
}
|
|
246
188
|
});
|
|
247
|
-
referenceService = new SemanticReferenceService(
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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);
|
|
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);
|
|
263
196
|
disposeReferences = registerSemanticReferenceRpc(ctx.connection, referenceService, async (_endpoint, payload, signal) => {
|
|
264
197
|
try {
|
|
265
198
|
return { ok: true, value: await browserService.read(payload, signal) };
|
|
@@ -273,24 +206,13 @@ export async function apply(ctx, config = {}) {
|
|
|
273
206
|
});
|
|
274
207
|
}
|
|
275
208
|
catch (error) {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
manager.dispose();
|
|
283
|
-
disposeRuntimeShellEnvironment();
|
|
209
|
+
try {
|
|
210
|
+
await close();
|
|
211
|
+
}
|
|
212
|
+
catch (cleanupError) {
|
|
213
|
+
throw new AggregateError([error, cleanupError], 'Marivo installation and cleanup failed');
|
|
214
|
+
}
|
|
284
215
|
throw error;
|
|
285
216
|
}
|
|
286
|
-
return
|
|
287
|
-
browserService.dispose();
|
|
288
|
-
await disposePresentation?.();
|
|
289
|
-
await disposeCredentials?.();
|
|
290
|
-
await credentialService.close();
|
|
291
|
-
await disposeReferences?.();
|
|
292
|
-
disposePlugin?.();
|
|
293
|
-
manager.dispose();
|
|
294
|
-
disposeRuntimeShellEnvironment();
|
|
295
|
-
};
|
|
217
|
+
return close;
|
|
296
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
|
+
}
|