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