@delta-infra/cli 1.1.17 → 1.1.18

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 (33) hide show
  1. package/README.md +513 -506
  2. package/checksums.txt +5 -5
  3. package/package.json +1 -1
  4. package/scripts/install-wizard.js +701 -701
  5. package/scripts/install.js +442 -442
  6. package/scripts/run.js +65 -65
  7. package/skills/delta-sandbox/SKILL.md +388 -388
  8. package/skills/delta-sandbox/agents/openai.yaml +4 -4
  9. package/skills/delta-sandbox/references/commands.md +58 -58
  10. package/skills/delta-sandbox/references/lifecycle.md +100 -100
  11. package/skills/delta-sandbox/references/recipes.md +138 -138
  12. package/skills/delta-science/AGENTS.md +47 -47
  13. package/skills/delta-science/SKILL.md +227 -185
  14. package/skills/delta-science/agents/openai.yaml +4 -4
  15. package/skills/delta-science/references/antbo.md +105 -100
  16. package/skills/delta-science/references/delta-bo.md +92 -89
  17. package/skills/delta-science/references/gsasii.md +118 -116
  18. package/skills/delta-science/references/lammps.md +68 -66
  19. package/skills/delta-science/references/ldm-bo.md +132 -129
  20. package/skills/delta-science/references/materials-design.md +130 -118
  21. package/skills/delta-science/references/pubchem.md +128 -126
  22. package/skills/delta-science/references/pymatgen.md +69 -68
  23. package/skills/delta-science/references/qe.md +134 -125
  24. package/skills/delta-science/references/rdkit.md +141 -138
  25. package/skills/delta-science/references/strbo.md +95 -87
  26. package/skills/delta-science/references/synbo.md +201 -198
  27. package/skills/delta-science/references/xrd.md +197 -186
  28. package/skills/delta-science/scripts/catalog.py +92 -92
  29. package/skills/delta-science/scripts/generated_catalog.py +69 -69
  30. package/skills/delta-science/scripts/invoke.py +346 -346
  31. package/skills/delta-shared/SKILL.md +113 -111
  32. package/skills/delta-shared/agents/openai.yaml +4 -4
  33. package/skills/manifest.json +19 -19
@@ -1,186 +1,197 @@
1
- # XRD Cloud Compute 详细规则
2
-
3
- `xrd` 是通过 Science 工具代理访问 XRD cloud compute 的真实工具。所有调用必须经由
4
- `delta-cli`,禁止使用 broker URL、`curl`、`requests`、`httpx`、浏览器或本地 XRD
5
- 科学库绕过 CLI。本文是 `delta-science` 的工具 reference,不是第二套 HTTP 客户端。
6
-
7
- ## 工具与 endpoint
8
-
9
- 执行前使用实时目录确认当前环境中的 canonical 名称和启用状态:
10
-
11
- ```text
12
- delta-cli science list
13
- delta-cli science endpoints list xrd
14
- ```
15
-
16
- `xrd` endpoint 名称必须逐字取自第二条命令的结果。当前 reference 覆盖以下稳定契约:
17
-
18
- | endpoint | 方法/用途 | 请求类型 |
19
- | --- | --- | --- |
20
- | `healthz`、`readyz`、`capabilities`、`xmatcher-status` | 就绪、能力和数据库状态 | 只读 JSON |
21
- | `xmatcher-artifacts` | 上传观测曲线、模型输入、CIF 或仪器参数 | `invoke --file` |
22
- | `xmatcher-artifact`、`xmatcher-artifact-content` | 查询/读取 artifact | `invoke --path-params` |
23
- | `xqueryer-predictions` | XQueryer 单相候选预测 | JSON |
24
- | `xmatcher-detect-peaks`、`xmatcher-match` | 峰检测和单相匹配 | JSON |
25
- | `xmatcher-multiphase-match`、`xdecomposer-predictions` | 多相匹配和相分解 | JSON |
26
- | `xmatcher-cif-xrd`、`xmatcher-pdf-peaks-xlsx` | CIF 模拟及 PDF 峰表导出 | JSON/二进制 |
27
- | `xmatcher-refinement-patterns` | 生成精修输入和 provenance manifest | JSON |
28
- | `refinement-fullprof`、`refinement-gsasii`、`refinement-wpem` | 提交对应后端精修作业 | JSON + header |
29
- | `refinement-job`、`refinement-job-events`、`refinement-job-artifacts` | 查询精修作业 | `invoke --path-params` |
30
- | `refinement-job-cancel` | 请求取消精修作业 | `invoke --path-params` |
31
- | `mp500-cif-exports` | MP500 结构导出为 CIF | JSON |
32
-
33
- 目录是最终权威。若 endpoint 不在实时目录中,停止并报告配置问题,不改名重试。
34
-
35
- ## CLI 参数映射
36
-
37
- ```text
38
- --data 上游 JSON body
39
- --params 上游 URL query 参数
40
- --path-params 替换 endpoint path 中的 {artifact_id}/{job_id}
41
- --headers 额外上游请求头,例如 Idempotency-Key
42
- --file 将本地文件通过 file_base64 传给工具代理
43
- --content-type file 的原始 MIME 类型
44
- ```
45
-
46
- `--params` 不能替代 `--path-params`。不要把本地路径、base64、路径参数或幂等键塞进
47
- 普通业务 `--data`。`science file` 是 QE/Materials Design 等独立文件接口;XRD 的
48
- `xmatcher-artifacts` 属于工具代理 endpoint,应使用 `science invoke --file`。
49
-
50
- ## 调用顺序
51
-
52
- 1. 用户明确要求诊断或执行时,先读取 `healthz`;需要选择后端时再读取
53
- `capabilities`。
54
- 2. 通过 `xmatcher-artifacts` 上传真实文件,保存返回的 `artifact_id` 和 `sha256`。
55
- 3. 观测数据使用 `xmatcher-match`、`xmatcher-multiphase-match` 或
56
- `xdecomposer-predictions`;XQueryer 使用 `model_input_pattern`。
57
- 4. CIF 模拟使用 `xmatcher-cif-xrd`;精修先调用 `xmatcher-refinement-patterns`,再选择
58
- 与 `data.backends` 一致的 refinement endpoint。
59
- 5. 精修提交后用 `refinement-job`、`refinement-job-events` 和
60
- `refinement-job-artifacts` 读取状态和产物。
61
-
62
- 不要把服务返回的 queued、scheduler completed 或 backend success 直接描述成科学结论。
63
- 精修至少分开报告传输/作业终态、后端执行状态和科学接受状态。
64
-
65
- ## 就绪检查
66
-
67
- ```text
68
- delta-cli science invoke --tool xrd --endpoint healthz
69
- delta-cli science invoke --tool xrd --endpoint capabilities
70
- ```
71
-
72
- 只有需要诊断或用户明确要求时才额外调用 readiness/status。能力结果中的每个所需组件
73
- 都必须满足 `available`;生产任务还应检查 `asset_release_approved`、checksum 字段和
74
- warnings。`auto` 不代表实际使用 GPU,只有结果明确返回 GPU backend 才能这样报告。
75
-
76
- ## Artifact 上传与身份
77
-
78
- 上传观测曲线:
79
-
80
- ```text
81
- delta-cli science invoke --tool xrd --endpoint xmatcher-artifacts `
82
- --file observed.csv `
83
- --params '{"filename":"observed.csv","kind":"observed_pattern","media_type":"text/csv"}' `
84
- --content-type application/octet-stream
85
- ```
86
-
87
- 允许的 `kind` 为:`observed_pattern`、`model_input_pattern`、`cif`、
88
- `instrument_parameters`。成功响应中的 `artifact_id` 和 `sha256` 必须成对保存并原样
89
- 传给下游。模式文件会在服务端标准化,返回的 digest 是标准化 artifact 的 digest,
90
- 不是一定等于本地上传字节的 digest。
91
-
92
- 查询 artifact 时使用路径参数:
93
-
94
- ```text
95
- delta-cli science invoke --tool xrd --endpoint xmatcher-artifact `
96
- --path-params '{"artifact_id":"art_<returned-id>"}'
97
- ```
98
-
99
- 二进制内容响应可能返回 `data._binary=true`、`content_base64`、`media_type` 和
100
- `content_length`。只有用户要求保存或工作流需要时才解码,并按服务返回的 SHA-256
101
- 校验;不要凭文件名猜测格式。
102
-
103
- ## 相识别与匹配
104
-
105
- XQueryer 的 `model_input_pattern` 必须正好包含 3500 个样本,覆盖 10 到 90 度 2theta,
106
- 强度不超过服务能力限制:
107
-
108
- ```text
109
- delta-cli science invoke --tool xrd --endpoint xqueryer-predictions `
110
- --data '{"schema_version":1,"pattern":{"artifact_id":"art_<model>","sha256":"<sha>"},"top_k":10,"radiation_profile":"CuKa"}'
111
- ```
112
-
113
- XMatcher 观测曲线:
114
-
115
- ```text
116
- delta-cli science invoke --tool xrd --endpoint xmatcher-match `
117
- --data '{"schema_version":1,"pattern":{"artifact_id":"art_<observed>","sha256":"<sha>"},"top_n":10,"element_filter_mode":"contains"}'
118
- ```
119
-
120
- 多相匹配:
121
-
122
- ```text
123
- delta-cli science invoke --tool xrd --endpoint xmatcher-multiphase-match `
124
- --data '{"schema_version":1,"pattern":{"artifact_id":"art_<observed>","sha256":"<sha>"},"max_phases":3,"candidate_pool":8}'
125
- ```
126
-
127
- `xqueryer-predictions` 的 `score` 是 softmax probability;XMatcher 的 `score` 是
128
- `raw_score / 100`。两者不可直接平均或当作同一校准概率。
129
-
130
- ## CIF 模拟与峰表
131
-
132
- `cifs` 中的每个 artifact 都必须同时提供 `artifact_id` 和 `sha256`:
133
-
134
- ```text
135
- delta-cli science invoke --tool xrd --endpoint xmatcher-cif-xrd `
136
- --data '{"schema_version":1,"cifs":[{"artifact":{"artifact_id":"art_<cif>","sha256":"<sha>"},"name":"phase"}],"two_theta_range":[5.0,90.0],"wavelength":"CuKa"}'
137
- ```
138
-
139
- `xmatcher-pdf-peaks-xlsx` 返回二进制 XLSX;只有用户要求导出时才读取和保存它。
140
-
141
- ## 精修作业
142
-
143
- 先生成校正曲线和 provenance manifest:
144
-
145
- ```text
146
- delta-cli science invoke --tool xrd --endpoint xmatcher-refinement-patterns `
147
- --data '{"schema_version":1,"source_pattern":{"artifact_id":"art_<observed>","sha256":"<sha>"}}'
148
- ```
149
-
150
- 然后使用与 `data.backends` 匹配的 endpoint。示例结构如下,所有 artifact 身份必须来自
151
- 当前调用链:
152
-
153
- ```text
154
- delta-cli science invoke --tool xrd --endpoint refinement-gsasii `
155
- --data '{"schema_version":1,"radiation_profile":"CuKa","refinement_pattern":{"observed_pattern":{"artifact_id":"art_<obs>","sha256":"<sha>"},"corrected_pattern":{"artifact_id":"art_<corrected>","sha256":"<sha>"},"provenance_manifest":{"artifact_id":"art_<manifest>","sha256":"<sha>"}},"phases":[{"phase_index":0,"name":"phase","cif":{"artifact_id":"art_<cif>","sha256":"<sha>"}}],"wavelengths_angstrom":[1.540593,1.544414],"backends":["gsasii"]}' `
156
- --headers '{"Idempotency-Key":"<stable-unique-key>"}'
157
- ```
158
-
159
- `refinement-fullprof`、`refinement-gsasii`、`refinement-wpem` 选择计费/后端入口;不要
160
- 因为它们映射到同一路径就互换 endpoint 名或 `backends`。提交、取消、重试和审核是
161
- 远端变更,必须得到用户明确授权;超时或连接中断时不要盲目重试,先查询是否已经创建
162
- 作业。
163
-
164
- 查询作业时:
165
-
166
- ```text
167
- delta-cli science invoke --tool xrd --endpoint refinement-job `
168
- --path-params '{"job_id":"refjob_<returned-id>"}'
169
-
170
- delta-cli science invoke --tool xrd --endpoint refinement-job-events `
171
- --path-params '{"job_id":"refjob_<returned-id>"}'
172
- ```
173
-
174
- ## 结果与错误
175
-
176
- - 只有 CLI 退出码为 0 且顶层 JSON `ok` 为 `true` 才算调用成功。
177
- - 原样保留服务返回的 `data`、warnings、错误 detail 和稳定错误码。
178
- - `202`、`queued` 或 `running` 只代表作业接收/执行状态,不代表 solver 收敛或科学接受。
179
- - `TIER_CONCURRENCY_EXCEEDED`、`Endpoint is disabled`、`ARTIFACT_MISSING`、
180
- `MP500_IDENTITY_MISMATCH` 等错误应停止当前调用链并报告原始 detail;不要换 endpoint、
181
- 改名、猜参数或用本地算法替代。
182
- - 付费 endpoint 的价格和可用状态以实时目录为准;执行前确认用户确实要求该业务调用。
183
-
184
- 证据边界:仅限当前 Delta CLI `data` 中的业务结果。
185
- 调用链:`delta-cli`。
186
- 禁止补充未返回内容:是。
1
+ # XRD Cloud Compute reference
2
+
3
+ `xrd` is a real tool for accessing XRD cloud compute through the Science tool proxy. Route every
4
+ call through `delta-cli`; do not bypass the CLI with broker URLs, `curl`, `requests`, `httpx`, a
5
+ browser or local XRD libraries. This is a tool reference for `delta-science`, not a second HTTP
6
+ client.
7
+
8
+ ## Tool and endpoints
9
+
10
+ Before execution, use the live catalogue to confirm the canonical names and enabled status in the
11
+ current environment:
12
+
13
+ ```text
14
+ delta-cli science list
15
+ delta-cli science endpoints list xrd
16
+ ```
17
+
18
+ Copy `xrd` endpoint names exactly from the output of the second command. This reference covers
19
+ the following stable contracts:
20
+
21
+ | endpoint | Method/purpose | Request type |
22
+ | --- | --- | --- |
23
+ | `healthz`, `readyz`, `capabilities`, `xmatcher-status` | Readiness, capabilities and database status | Read-only JSON |
24
+ | `xmatcher-artifacts` | Upload an observed pattern, model input, CIF or instrument parameters | `invoke --file` |
25
+ | `xmatcher-artifact`, `xmatcher-artifact-content` | Query/read an artifact | `invoke --path-params` |
26
+ | `xqueryer-predictions` | XQueryer single-phase candidate prediction | JSON |
27
+ | `xmatcher-detect-peaks`, `xmatcher-match` | Peak detection and single-phase matching | JSON |
28
+ | `xmatcher-multiphase-match`, `xdecomposer-predictions` | Multiphase matching and phase decomposition | JSON |
29
+ | `xmatcher-cif-xrd`, `xmatcher-pdf-peaks-xlsx` | CIF simulation and PDF peak-table export | JSON/binary |
30
+ | `xmatcher-refinement-patterns` | Generate refinement inputs and a provenance manifest | JSON |
31
+ | `refinement-fullprof`, `refinement-gsasii`, `refinement-wpem` | Submit a refinement job to the corresponding backend | JSON + header |
32
+ | `refinement-job`, `refinement-job-events`, `refinement-job-artifacts` | Query a refinement job | `invoke --path-params` |
33
+ | `refinement-job-cancel` | Request refinement-job cancellation | `invoke --path-params` |
34
+ | `mp500-cif-exports` | Export an MP500 structure as CIF | JSON |
35
+
36
+ The live catalogue is authoritative. If an endpoint is absent from it, stop and report a
37
+ configuration issue; do not retry under a different name.
38
+
39
+ ## CLI argument mapping
40
+
41
+ ```text
42
+ --data Upstream JSON body
43
+ --params Upstream URL query parameters
44
+ --path-params Replace {artifact_id}/{job_id} in the endpoint path
45
+ --headers Additional upstream headers, such as Idempotency-Key
46
+ --file Send a local file to the tool proxy via file_base64
47
+ --content-type The file's original MIME type
48
+ ```
49
+
50
+ `--params` cannot replace `--path-params`. Do not put local paths, base64, path parameters or
51
+ idempotency keys in ordinary business `--data`. `science file` is a separate file interface for
52
+ tools such as QE and Materials Design. XRD's `xmatcher-artifacts` is a tool-proxy endpoint; use
53
+ `science invoke --file` for it.
54
+
55
+ ## Call sequence
56
+
57
+ 1. When the user explicitly asks for a diagnosis or execution, read `healthz` first; read
58
+ `capabilities` only when you need to select a backend.
59
+ 2. Upload real files through `xmatcher-artifacts` and save the returned `artifact_id` and `sha256`.
60
+ 3. Use `xmatcher-match`, `xmatcher-multiphase-match` or `xdecomposer-predictions` for observed
61
+ data; XQueryer uses `model_input_pattern`.
62
+ 4. Use `xmatcher-cif-xrd` for CIF simulation. For refinement, call
63
+ `xmatcher-refinement-patterns` first, then choose a refinement endpoint matching
64
+ `data.backends`.
65
+ 5. After submitting a refinement job, read its status and artifacts with `refinement-job`,
66
+ `refinement-job-events` and `refinement-job-artifacts`.
67
+
68
+ Do not present a returned `queued` state, scheduler completion or backend success as a scientific
69
+ conclusion. For refinement, report the transport/job final state, backend execution state and
70
+ scientific acceptance state separately.
71
+
72
+ ## Readiness checks
73
+
74
+ ```text
75
+ delta-cli science invoke --tool xrd --endpoint healthz
76
+ delta-cli science invoke --tool xrd --endpoint capabilities
77
+ ```
78
+
79
+ Call readiness/status additionally only when diagnosis requires it or the user explicitly asks.
80
+ Every required component in the capabilities result must have `available` status. For production
81
+ jobs, also check `asset_release_approved`, checksum fields and warnings. `auto` does not prove GPU
82
+ use; report GPU use only when the result explicitly returns a GPU backend.
83
+
84
+ ## Artifact upload and identity
85
+
86
+ Upload an observed pattern:
87
+
88
+ ```text
89
+ delta-cli science invoke --tool xrd --endpoint xmatcher-artifacts `
90
+ --file observed.csv `
91
+ --params '{"filename":"observed.csv","kind":"observed_pattern","media_type":"text/csv"}' `
92
+ --content-type application/octet-stream
93
+ ```
94
+
95
+ Allowed `kind` values are `observed_pattern`, `model_input_pattern`, `cif` and
96
+ `instrument_parameters`. Save the successful response's `artifact_id` and `sha256` together and
97
+ pass them to downstream calls unchanged. Pattern files are normalised by the server, so the
98
+ returned digest identifies the normalised artifact and may differ from the digest of the local
99
+ upload bytes.
100
+
101
+ Use path parameters to query an artifact:
102
+
103
+ ```text
104
+ delta-cli science invoke --tool xrd --endpoint xmatcher-artifact `
105
+ --path-params '{"artifact_id":"art_<returned-id>"}'
106
+ ```
107
+
108
+ Binary-content responses may return `data._binary=true`, `content_base64`, `media_type` and
109
+ `content_length`. Decode only when the user asks to save the content or the workflow requires it,
110
+ and verify it against the SHA-256 returned by the service. Do not infer the format from the filename.
111
+
112
+ ## Phase identification and matching
113
+
114
+ XQueryer's `model_input_pattern` must contain exactly 3,500 samples over 10 to 90 degrees 2theta,
115
+ with intensities within the service's capability limits:
116
+
117
+ ```text
118
+ delta-cli science invoke --tool xrd --endpoint xqueryer-predictions `
119
+ --data '{"schema_version":1,"pattern":{"artifact_id":"art_<model>","sha256":"<sha>"},"top_k":10,"radiation_profile":"CuKa"}'
120
+ ```
121
+
122
+ XMatcher observed pattern:
123
+
124
+ ```text
125
+ delta-cli science invoke --tool xrd --endpoint xmatcher-match `
126
+ --data '{"schema_version":1,"pattern":{"artifact_id":"art_<observed>","sha256":"<sha>"},"top_n":10,"element_filter_mode":"contains"}'
127
+ ```
128
+
129
+ Multiphase matching:
130
+
131
+ ```text
132
+ delta-cli science invoke --tool xrd --endpoint xmatcher-multiphase-match `
133
+ --data '{"schema_version":1,"pattern":{"artifact_id":"art_<observed>","sha256":"<sha>"},"max_phases":3,"candidate_pool":8}'
134
+ ```
135
+
136
+ The `score` from `xqueryer-predictions` is a softmax probability; the XMatcher `score` is
137
+ `raw_score / 100`. Do not average them directly or treat them as the same calibrated probability.
138
+
139
+ ## CIF simulation and peak tables
140
+
141
+ Each artifact in `cifs` must provide both `artifact_id` and `sha256`:
142
+
143
+ ```text
144
+ delta-cli science invoke --tool xrd --endpoint xmatcher-cif-xrd `
145
+ --data '{"schema_version":1,"cifs":[{"artifact":{"artifact_id":"art_<cif>","sha256":"<sha>"},"name":"phase"}],"two_theta_range":[5.0,90.0],"wavelength":"CuKa"}'
146
+ ```
147
+
148
+ `xmatcher-pdf-peaks-xlsx` returns a binary XLSX file; read and save it only when the user asks for an export.
149
+
150
+ ## Refinement jobs
151
+
152
+ First generate the corrected pattern and provenance manifest:
153
+
154
+ ```text
155
+ delta-cli science invoke --tool xrd --endpoint xmatcher-refinement-patterns `
156
+ --data '{"schema_version":1,"source_pattern":{"artifact_id":"art_<observed>","sha256":"<sha>"}}'
157
+ ```
158
+
159
+ Then use the endpoint matching `data.backends`. The example below shows the structure; every
160
+ artifact identity must come from the current call chain:
161
+
162
+ ```text
163
+ delta-cli science invoke --tool xrd --endpoint refinement-gsasii `
164
+ --data '{"schema_version":1,"radiation_profile":"CuKa","refinement_pattern":{"observed_pattern":{"artifact_id":"art_<obs>","sha256":"<sha>"},"corrected_pattern":{"artifact_id":"art_<corrected>","sha256":"<sha>"},"provenance_manifest":{"artifact_id":"art_<manifest>","sha256":"<sha>"}},"phases":[{"phase_index":0,"name":"phase","cif":{"artifact_id":"art_<cif>","sha256":"<sha>"}}],"wavelengths_angstrom":[1.540593,1.544414],"backends":["gsasii"]}' `
165
+ --headers '{"Idempotency-Key":"<stable-unique-key>"}'
166
+ ```
167
+
168
+ `refinement-fullprof`, `refinement-gsasii` and `refinement-wpem` select the billing/backend
169
+ entry point. Do not interchange endpoint names or `backends` merely because they map to the same
170
+ path. Submission, cancellation, retry and review are remote mutations and require the user's
171
+ explicit authorisation. After a timeout or disconnection, do not retry blindly; first check
172
+ whether a job has already been created.
173
+
174
+ To query a job:
175
+
176
+ ```text
177
+ delta-cli science invoke --tool xrd --endpoint refinement-job `
178
+ --path-params '{"job_id":"refjob_<returned-id>"}'
179
+
180
+ delta-cli science invoke --tool xrd --endpoint refinement-job-events `
181
+ --path-params '{"job_id":"refjob_<returned-id>"}'
182
+ ```
183
+
184
+ ## Results and errors
185
+
186
+ - A call succeeds only when the CLI exits with code 0 and the top-level JSON `ok` is `true`.
187
+ - Preserve the returned `data`, warnings, error detail and stable error codes exactly as returned.
188
+ - `202`, `queued` and `running` describe job acceptance/execution state only; they do not mean the solver converged or the result was scientifically accepted.
189
+ - `TIER_CONCURRENCY_EXCEEDED`, `Endpoint is disabled`, `ARTIFACT_MISSING`,
190
+ `MP500_IDENTITY_MISMATCH` and similar errors should stop the current call chain; report the
191
+ original detail and do not switch endpoints, rename them, guess parameters or substitute a
192
+ local algorithm.
193
+ - Use the live catalogue as the authority for paid endpoint prices and availability; before execution, confirm that the user actually requested the business call.
194
+
195
+ Evidence boundary: business results in the current Delta CLI `data` only.
196
+ Call chain: `delta-cli`.
197
+ Do not add information absent from the response: yes.
@@ -1,92 +1,92 @@
1
- #!/usr/bin/env python3
2
- """Read the authoritative Delta Science catalog through delta-cli."""
3
-
4
- from __future__ import annotations
5
-
6
- import argparse
7
- import json
8
- import os
9
- import subprocess
10
- import sys
11
- import time
12
-
13
- from invoke import _parse_cli_error, _resolve_cli, _runtime_config
14
-
15
-
16
- def _parser() -> argparse.ArgumentParser:
17
- parser = argparse.ArgumentParser(description=__doc__)
18
- action = parser.add_mutually_exclusive_group(required=True)
19
- action.add_argument("--tools", action="store_true")
20
- action.add_argument("--endpoints", metavar="TOOL")
21
- parser.add_argument("--cli")
22
- parser.add_argument("--science-base-url")
23
- parser.add_argument("--timeout", type=float, default=30.0)
24
- return parser
25
-
26
-
27
- def main() -> int:
28
- args = _parser().parse_args()
29
- started = time.perf_counter()
30
- kind = "tools" if args.tools else "endpoints"
31
- try:
32
- runtime = _runtime_config()
33
- cli = _resolve_cli(args.cli, runtime)
34
- env = os.environ.copy()
35
- base_url = args.science_base_url or runtime.get("science_base_url")
36
- if base_url:
37
- env["DELTA_INFRA_SCIENCE_BASE_URL"] = str(base_url)
38
-
39
- command = [cli, "science", "list"]
40
- if args.endpoints:
41
- command = [cli, "science", "endpoints", "list", args.endpoints]
42
- completed = subprocess.run(
43
- command,
44
- capture_output=True,
45
- text=True,
46
- encoding="utf-8",
47
- errors="replace",
48
- env=env,
49
- timeout=args.timeout,
50
- check=False,
51
- )
52
- if completed.returncode != 0:
53
- error_type, detail = _parse_cli_error(completed)
54
- raise RuntimeError(f"{error_type}: {detail}")
55
- root = json.loads(completed.stdout)
56
- if not isinstance(root, dict) or root.get("ok") is not True:
57
- raise RuntimeError(json.dumps(root, ensure_ascii=False))
58
- if "data" not in root:
59
- raise RuntimeError("CLI success envelope is missing data")
60
- print(json.dumps({
61
- "ok": True,
62
- "transport": "delta-cli",
63
- "catalog": kind,
64
- "tool": args.endpoints,
65
- "elapsed_seconds": round(time.perf_counter() - started, 3),
66
- "native": root["data"],
67
- }, ensure_ascii=False))
68
- return 0
69
- except subprocess.TimeoutExpired:
70
- error_type = "timeout"
71
- error = f"timeout after {args.timeout}s"
72
- except (OSError, ValueError, json.JSONDecodeError) as exc:
73
- error_type = "catalog"
74
- error = str(exc)
75
- except RuntimeError as exc:
76
- error_type = "cli"
77
- error = str(exc)
78
-
79
- print(json.dumps({
80
- "ok": False,
81
- "transport": "delta-cli",
82
- "catalog": kind,
83
- "tool": args.endpoints,
84
- "error_type": error_type,
85
- "elapsed_seconds": round(time.perf_counter() - started, 3),
86
- "error": error[:2000],
87
- }, ensure_ascii=False))
88
- return 1
89
-
90
-
91
- if __name__ == "__main__":
92
- sys.exit(main())
1
+ #!/usr/bin/env python3
2
+ """Read the authoritative Delta Science catalog through delta-cli."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ import os
9
+ import subprocess
10
+ import sys
11
+ import time
12
+
13
+ from invoke import _parse_cli_error, _resolve_cli, _runtime_config
14
+
15
+
16
+ def _parser() -> argparse.ArgumentParser:
17
+ parser = argparse.ArgumentParser(description=__doc__)
18
+ action = parser.add_mutually_exclusive_group(required=True)
19
+ action.add_argument("--tools", action="store_true")
20
+ action.add_argument("--endpoints", metavar="TOOL")
21
+ parser.add_argument("--cli")
22
+ parser.add_argument("--science-base-url")
23
+ parser.add_argument("--timeout", type=float, default=30.0)
24
+ return parser
25
+
26
+
27
+ def main() -> int:
28
+ args = _parser().parse_args()
29
+ started = time.perf_counter()
30
+ kind = "tools" if args.tools else "endpoints"
31
+ try:
32
+ runtime = _runtime_config()
33
+ cli = _resolve_cli(args.cli, runtime)
34
+ env = os.environ.copy()
35
+ base_url = args.science_base_url or runtime.get("science_base_url")
36
+ if base_url:
37
+ env["DELTA_INFRA_SCIENCE_BASE_URL"] = str(base_url)
38
+
39
+ command = [cli, "science", "list"]
40
+ if args.endpoints:
41
+ command = [cli, "science", "endpoints", "list", args.endpoints]
42
+ completed = subprocess.run(
43
+ command,
44
+ capture_output=True,
45
+ text=True,
46
+ encoding="utf-8",
47
+ errors="replace",
48
+ env=env,
49
+ timeout=args.timeout,
50
+ check=False,
51
+ )
52
+ if completed.returncode != 0:
53
+ error_type, detail = _parse_cli_error(completed)
54
+ raise RuntimeError(f"{error_type}: {detail}")
55
+ root = json.loads(completed.stdout)
56
+ if not isinstance(root, dict) or root.get("ok") is not True:
57
+ raise RuntimeError(json.dumps(root, ensure_ascii=False))
58
+ if "data" not in root:
59
+ raise RuntimeError("CLI success envelope is missing data")
60
+ print(json.dumps({
61
+ "ok": True,
62
+ "transport": "delta-cli",
63
+ "catalog": kind,
64
+ "tool": args.endpoints,
65
+ "elapsed_seconds": round(time.perf_counter() - started, 3),
66
+ "native": root["data"],
67
+ }, ensure_ascii=False))
68
+ return 0
69
+ except subprocess.TimeoutExpired:
70
+ error_type = "timeout"
71
+ error = f"timeout after {args.timeout}s"
72
+ except (OSError, ValueError, json.JSONDecodeError) as exc:
73
+ error_type = "catalog"
74
+ error = str(exc)
75
+ except RuntimeError as exc:
76
+ error_type = "cli"
77
+ error = str(exc)
78
+
79
+ print(json.dumps({
80
+ "ok": False,
81
+ "transport": "delta-cli",
82
+ "catalog": kind,
83
+ "tool": args.endpoints,
84
+ "error_type": error_type,
85
+ "elapsed_seconds": round(time.perf_counter() - started, 3),
86
+ "error": error[:2000],
87
+ }, ensure_ascii=False))
88
+ return 1
89
+
90
+
91
+ if __name__ == "__main__":
92
+ sys.exit(main())