@foggy-projects/deepseek-harness-plugin 0.4.2-rc.3 → 0.4.2-rc.5
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 +21 -9
- package/docs/RELEASE-CANDIDATE-0.4.2-DSH-0.1.7-RC.4.md +32 -0
- package/docs/RELEASE-CANDIDATE-0.4.2-DSH-0.1.7-RC.5.md +27 -0
- package/docs/WINDOWS-BETA-ACCEPTANCE.md +4 -4
- package/experience/linux/prepare.sh +1 -1
- package/lib/client.js +149 -24
- package/lib/query-tool.js +44 -17
- package/lib/viewer-preview.js +1 -1
- package/package.json +10 -3
- package/skills/foggy-deepseek-onboarding/assets/versions.json +15 -15
- package/skills/foggy-deepseek-onboarding/scripts/onboarding.py +36 -20
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ are downloaded only when the user selects **Initialize and start** (or the
|
|
|
7
7
|
equivalent component action). Existing installations are not silently changed
|
|
8
8
|
when the plugin package is upgraded.
|
|
9
9
|
|
|
10
|
-
The `0.4.2-rc.
|
|
10
|
+
The `0.4.2-rc.5` compatibility candidate targets DeepSeek Harness `0.1.7-rc.2`
|
|
11
11
|
and requires a system Node.js `>=24.0.0`. Foggy's Java Launcher uses a system
|
|
12
12
|
Java 17+. Foggy manages its own pinned Python 3.12 runtime
|
|
13
13
|
inside the per-user component directory; it does not require a system Python,
|
|
@@ -17,7 +17,7 @@ modify `PATH`, or register Python globally. Advanced users may explicitly set
|
|
|
17
17
|
## Local release-candidate installation
|
|
18
18
|
|
|
19
19
|
```powershell
|
|
20
|
-
dsh plugin --profile web add --workspace-root ./foggy-projects-deepseek-harness-plugin-0.4.2-rc.
|
|
20
|
+
dsh plugin --profile web add --workspace-root ./foggy-projects-deepseek-harness-plugin-0.4.2-rc.5.tgz
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
Restart `dsh web`, use the browser it opens (or the complete printed URL,
|
|
@@ -28,11 +28,11 @@ Install the exact DSH 0.1.7-rc.2 compatibility candidate
|
|
|
28
28
|
so the stable `beta` channel is not changed:
|
|
29
29
|
|
|
30
30
|
```powershell
|
|
31
|
-
dsh plugin --profile web add --workspace-root @foggy-projects/deepseek-harness-plugin@0.4.2-rc.
|
|
31
|
+
dsh plugin --profile web add --workspace-root @foggy-projects/deepseek-harness-plugin@0.4.2-rc.5
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
The `dsh017` npm dist-tag points to the most recently published DSH 0.1.7
|
|
35
|
-
candidate (`0.4.2-rc.
|
|
35
|
+
candidate (`0.4.2-rc.5` at this release). Check the resolved version before
|
|
36
36
|
using this moving tag:
|
|
37
37
|
|
|
38
38
|
```powershell
|
|
@@ -131,13 +131,25 @@ port proxy produces an immediate, high-visibility error instead of a readiness t
|
|
|
131
131
|
The CLI and Skills resolve the resulting stable Runtime URL from managed state.
|
|
132
132
|
|
|
133
133
|
For a successful standard QueryModel DSL call made through the native
|
|
134
|
-
`foggy_query` tool, Harness shows a
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
`foggy_query` tool, Harness shows a compact result card below the completed
|
|
135
|
+
reply, outside the folded tool trace. A visible "Generated by Foggy plugin"
|
|
136
|
+
label distinguishes this programmatic record of executed results from the AI
|
|
137
|
+
reply. The card shows the model, namespace, row count, an optional five-row
|
|
138
|
+
result preview with DSL/SQL details, and **View data**. If a turn has more than six
|
|
139
|
+
successful queries, the first six are shown until the user expands the list.
|
|
140
|
+
The detailed DSL and execution record remains in the tool trace. Clicking
|
|
141
|
+
**View data** creates a fresh local preview URL each time; the historical card
|
|
142
|
+
remains usable after an earlier URL expires, as long as the Harness transcript
|
|
143
|
+
and the Runtime/model are still available. Individual URLs are not permanent.
|
|
137
144
|
The preview re-executes the DSL against the current model and data rather than
|
|
138
145
|
freezing the original rows. In the lite Runtime the preview cache is bounded,
|
|
139
146
|
process-local, and lost on restart. CTE calls are not included in this first
|
|
140
|
-
DataViewer integration.
|
|
147
|
+
DataViewer integration. DataViewer currently displays model-backed fields and
|
|
148
|
+
may omit ad-hoc aggregate columns from a query; the Harness card retains the
|
|
149
|
+
complete executed result and makes this limitation explicit.
|
|
150
|
+
The DataViewer page can export the current filtered and sorted model-backed
|
|
151
|
+
result to CSV (up to 10,000 rows). It refuses larger exports rather than
|
|
152
|
+
silently truncating them.
|
|
141
153
|
|
|
142
154
|
This beta remains a local dev/test integration. It does not automatically extend
|
|
143
155
|
local credentials or approvals into a formal environment. Production model
|
|
@@ -148,7 +160,7 @@ rollback plan.
|
|
|
148
160
|
See [`docs/PUBLIC-BETA-READINESS.md`](./docs/PUBLIC-BETA-READINESS.md) for the
|
|
149
161
|
tested public Beta scope, release gates, and stable-release blockers.
|
|
150
162
|
The DSH 0.1.7-rc.2 compatibility candidate is documented in
|
|
151
|
-
[`docs/RELEASE-CANDIDATE-0.4.2-DSH-0.1.7-RC.
|
|
163
|
+
[`docs/RELEASE-CANDIDATE-0.4.2-DSH-0.1.7-RC.4.md`](./docs/RELEASE-CANDIDATE-0.4.2-DSH-0.1.7-RC.4.md).
|
|
152
164
|
The previous DSH 0.1.7-rc.2 candidate is documented in
|
|
153
165
|
[`docs/RELEASE-CANDIDATE-0.4.2-DSH-0.1.7-RC.2.md`](./docs/RELEASE-CANDIDATE-0.4.2-DSH-0.1.7-RC.2.md).
|
|
154
166
|
The earlier DSH 0.1.5-rc.2 candidate is documented in
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Foggy DeepSeek Harness plugin 0.4.2-rc.4
|
|
2
|
+
|
|
3
|
+
This pre-release targets DeepSeek Harness `0.1.7-rc.2` and remains on the
|
|
4
|
+
`dsh017` npm channel. The `beta`, `rc`, `dsh015`, and `latest` channels are
|
|
5
|
+
unchanged.
|
|
6
|
+
|
|
7
|
+
## Fixes since 0.4.2-rc.3
|
|
8
|
+
|
|
9
|
+
- Register `foggy_query` with Harness's existing tool runtime instead of
|
|
10
|
+
installing a second private `@deepseek-ai/dsh-tools` copy. The duplicate
|
|
11
|
+
runtime caused `Cannot read properties of undefined (reading 'prepare')`
|
|
12
|
+
before the DSL query reached Foggy Runtime.
|
|
13
|
+
- Allow a normal Launcher upgrade to replace a same-named asset only when the
|
|
14
|
+
existing file still matches the SHA-256 recorded for the previous installed
|
|
15
|
+
version. The previous file is backed up; unexpected file changes remain
|
|
16
|
+
fail-closed. Downloads are verified before replacing the existing file.
|
|
17
|
+
- Convert Query DSL `groupBy` and `orderBy` string shorthand into equivalent
|
|
18
|
+
object entries when creating a DataViewer preview. A valid, executed query
|
|
19
|
+
is no longer incorrectly labeled as ineligible for preview.
|
|
20
|
+
- Warn that the current DataViewer table can omit ad-hoc aggregate columns
|
|
21
|
+
even though the query card contains the complete result. This is an engine
|
|
22
|
+
display limitation, not a failed Query DSL execution.
|
|
23
|
+
|
|
24
|
+
The DSL-only DataViewer behavior from rc.3 is unchanged: a preview URL is
|
|
25
|
+
created only when the user clicks the successful query card's button. CTE
|
|
26
|
+
preview is not included.
|
|
27
|
+
|
|
28
|
+
Install the exact version with:
|
|
29
|
+
|
|
30
|
+
```powershell
|
|
31
|
+
dsh plugin --profile web add --workspace-root @foggy-projects/deepseek-harness-plugin@0.4.2-rc.4
|
|
32
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Foggy DeepSeek Harness plugin 0.4.2-rc.5
|
|
2
|
+
|
|
3
|
+
This pre-release targets DeepSeek Harness `0.1.7-rc.2` and stays on the
|
|
4
|
+
dedicated `dsh017` npm channel. The `beta`, `rc`, `dsh015`, and `latest`
|
|
5
|
+
channels remain unchanged.
|
|
6
|
+
|
|
7
|
+
## Changes since 0.4.2-rc.4
|
|
8
|
+
|
|
9
|
+
- Pin Runtime Launcher `0.1.23`, which includes the lite-profile DataViewer
|
|
10
|
+
preview page without requiring the Analytics Console or MongoDB.
|
|
11
|
+
- The DataViewer page puts readable query details and the executed DSL side by
|
|
12
|
+
side, supports copying DSL, and places refresh and CSV export below the
|
|
13
|
+
details. Query links are created on demand from successful DSL result cards.
|
|
14
|
+
- The table supports local filtering and exports the current filtered result.
|
|
15
|
+
CTE preview is not included. Preview links are process-local development
|
|
16
|
+
aids, not durable production shares.
|
|
17
|
+
|
|
18
|
+
The plugin keeps the current Harness `0.1.7-rc.2` tool integration. The
|
|
19
|
+
Runtime is updated only when the user selects **Update components** or
|
|
20
|
+
**Update and start** in Foggy settings; package installation does not restart
|
|
21
|
+
an existing Runtime.
|
|
22
|
+
|
|
23
|
+
Install the exact version with:
|
|
24
|
+
|
|
25
|
+
```powershell
|
|
26
|
+
dsh plugin --profile web add --workspace-root @foggy-projects/deepseek-harness-plugin@0.4.2-rc.5
|
|
27
|
+
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Native Windows Beta acceptance
|
|
2
2
|
|
|
3
3
|
This runbook validates DeepSeek Harness `0.1.7-rc.2` with Foggy plugin
|
|
4
|
-
`0.4.2-rc.
|
|
4
|
+
`0.4.2-rc.5` on a clean 64-bit Windows 10 or Windows 11 machine. Use a local
|
|
5
5
|
directory that is not synchronized by OneDrive.
|
|
6
6
|
|
|
7
7
|
## Prerequisites
|
|
@@ -29,7 +29,7 @@ Set-Location C:\FoggyAcceptance
|
|
|
29
29
|
|
|
30
30
|
npx --yes --package=@deepseek-ai/dsh@0.1.7-rc.2 --package=pnpm@11.7.0 `
|
|
31
31
|
dsh plugin --profile web add --workspace-root `
|
|
32
|
-
"@foggy-projects/deepseek-harness-plugin@0.4.2-rc.
|
|
32
|
+
"@foggy-projects/deepseek-harness-plugin@0.4.2-rc.5"
|
|
33
33
|
|
|
34
34
|
npx --yes --package=@deepseek-ai/dsh@0.1.7-rc.2 --package=pnpm@11.7.0 dsh web
|
|
35
35
|
```
|
|
@@ -66,9 +66,9 @@ Expected component state:
|
|
|
66
66
|
|
|
67
67
|
- Python 3.12.13, source `Foggy private`;
|
|
68
68
|
- CLI 0.1.23;
|
|
69
|
-
- Launcher 0.1.
|
|
69
|
+
- Launcher 0.1.23;
|
|
70
70
|
- analysis/query Skills 0.1.18;
|
|
71
|
-
- onboarding Skill 0.4.2-rc.
|
|
71
|
+
- onboarding Skill 0.4.2-rc.5;
|
|
72
72
|
- Java 17+ available;
|
|
73
73
|
- native DSH Skill registration available.
|
|
74
74
|
|
package/lib/client.js
CHANGED
|
@@ -173,10 +173,22 @@ window.__ModuleLoader__.load({
|
|
|
173
173
|
queryCardFailed: '查询失败;可展开查看错误',
|
|
174
174
|
queryCardRows: '返回行数',
|
|
175
175
|
queryCardDetails: '查看 DSL 与执行结果',
|
|
176
|
-
queryCardOpen: '
|
|
176
|
+
queryCardOpen: '查看数据',
|
|
177
177
|
queryCardOpening: '正在生成预览链接…',
|
|
178
|
-
queryCardPreviewHint: '
|
|
178
|
+
queryCardPreviewHint: '每次点击都会生成新的预览链接。',
|
|
179
|
+
queryCardComputedHint: 'DataViewer 可能不显示临时聚合列;请以本次执行结果为准。',
|
|
179
180
|
queryCardUnsupported: '当前查询不支持 DataViewer 预览,可继续查看查询结果。',
|
|
181
|
+
queryCardResults: 'Foggy 查询结果',
|
|
182
|
+
queryCardProvenance: 'Foggy 插件生成',
|
|
183
|
+
queryCardSource: '来自实际执行结果,非 AI 撰写',
|
|
184
|
+
queryCardShowAll: '显示全部 {count} 条查询',
|
|
185
|
+
queryCardShowLess: '收起至前 6 条',
|
|
186
|
+
queryCardShowResult: '查看结果',
|
|
187
|
+
queryCardHideResult: '收起结果',
|
|
188
|
+
queryCardRowUnit: '行',
|
|
189
|
+
queryCardDsl: 'DSL / SQL',
|
|
190
|
+
queryCardNoRows: '没有返回数据',
|
|
191
|
+
queryCardTableMore: '仅预览前 {count} 行',
|
|
180
192
|
stepPlanned: '规划',
|
|
181
193
|
stepDatasourceConfigured: '数据库连接',
|
|
182
194
|
stepDatasourceVerified: '连接验证',
|
|
@@ -308,10 +320,22 @@ window.__ModuleLoader__.load({
|
|
|
308
320
|
queryCardFailed: 'Query failed; expand for details',
|
|
309
321
|
queryCardRows: 'Rows',
|
|
310
322
|
queryCardDetails: 'Show DSL and execution result',
|
|
311
|
-
queryCardOpen: '
|
|
323
|
+
queryCardOpen: 'View data',
|
|
312
324
|
queryCardOpening: 'Creating preview link…',
|
|
313
|
-
queryCardPreviewHint: '
|
|
325
|
+
queryCardPreviewHint: 'A fresh preview link is created on every click.',
|
|
326
|
+
queryCardComputedHint: 'DataViewer may omit ad-hoc aggregate columns; use this execution result as the source of truth.',
|
|
314
327
|
queryCardUnsupported: 'DataViewer preview is unavailable for this query; the query result remains available.',
|
|
328
|
+
queryCardResults: 'Foggy query results',
|
|
329
|
+
queryCardProvenance: 'Generated by Foggy plugin',
|
|
330
|
+
queryCardSource: 'From executed queries, not AI-written',
|
|
331
|
+
queryCardShowAll: 'Show all {count} queries',
|
|
332
|
+
queryCardShowLess: 'Show first 6',
|
|
333
|
+
queryCardShowResult: 'View result',
|
|
334
|
+
queryCardHideResult: 'Hide result',
|
|
335
|
+
queryCardRowUnit: 'rows',
|
|
336
|
+
queryCardDsl: 'DSL / SQL',
|
|
337
|
+
queryCardNoRows: 'No rows returned',
|
|
338
|
+
queryCardTableMore: 'Previewing first {count} rows',
|
|
315
339
|
stepPlanned: 'Plan',
|
|
316
340
|
stepDatasourceConfigured: 'Database connection',
|
|
317
341
|
stepDatasourceVerified: 'Connection test',
|
|
@@ -355,6 +379,8 @@ window.__ModuleLoader__.load({
|
|
|
355
379
|
.foggy-resources{border-top:1px solid var(--dsw-alias-border-l2);padding-top:14px}.foggy-resources h4{margin:0 0 9px;font-size:13px}.foggy-resource-links{display:flex;gap:8px;flex-wrap:wrap}.foggy-resource-link{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:7px 10px;color:var(--dsw-alias-label-secondary);font-size:12px;text-decoration:none}.foggy-resource-link:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.foggy-resource-link:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}
|
|
356
380
|
.foggy-error-panel{border:2px solid var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,var(--dsw-alias-bg-layer-3));border-radius:10px;padding:13px 14px;box-shadow:0 6px 18px color-mix(in srgb,var(--dsw-alias-state-error-primary) 13%,transparent)}.foggy-error-panel-head{display:flex;align-items:center;gap:8px;color:var(--dsw-alias-state-error-primary);font-size:14px;font-weight:700}.foggy-error-icon{display:grid;place-items:center;width:22px;height:22px;border-radius:50%;background:var(--dsw-alias-state-error-primary);color:white;font-size:14px}.foggy-error-panel p{margin:7px 0 0;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;overflow-wrap:anywhere}.foggy-error-help{color:var(--dsw-alias-state-error-primary)!important;font-weight:600}
|
|
357
381
|
.foggy-message{margin:0;font-size:13px;line-height:20px;color:var(--dsw-alias-label-secondary)}.foggy-message[data-error=true]{color:var(--dsw-alias-state-error-primary)}.foggy-paths,.foggy-next,.foggy-section{border-top:1px solid var(--dsw-alias-border-l2);padding-top:14px}.foggy-paths h4,.foggy-next h4,.foggy-section h4{margin:0 0 8px;font-size:13px}.foggy-paths dl{display:grid;grid-template-columns:100px minmax(0,1fr);gap:6px 10px;margin:0}.foggy-paths dt{color:var(--dsw-alias-label-tertiary);font-size:12px}.foggy-paths dd{margin:0;min-width:0;overflow-wrap:anywhere;font-family:var(--ds-font-family-code);font-size:11px}.foggy-next p,.foggy-section p{margin:0;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px}.foggy-section-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}.foggy-onboarding-head{display:flex;justify-content:space-between;gap:12px;align-items:start}.foggy-onboarding-head code{font-size:11px;color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere}.foggy-step-list{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:7px;margin-top:10px}.foggy-step{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:8px;font-size:11px;color:var(--dsw-alias-label-tertiary)}.foggy-step[data-state=completed]{border-color:color-mix(in srgb,var(--dsw-alias-state-success-primary) 45%,var(--dsw-alias-border-l2));color:var(--dsw-alias-state-success-primary)}.foggy-step[data-state=failed],.foggy-step[data-state=invalid]{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.foggy-warning{border:1px solid color-mix(in srgb,var(--dsw-alias-state-warning-primary) 55%,var(--dsw-alias-border-l2));background:color-mix(in srgb,var(--dsw-alias-state-warning-primary) 8%,transparent);border-radius:10px;padding:12px}.foggy-query-warning{margin-top:10px}.foggy-query-warning p+p{margin-top:5px}.foggy-query-warning code{overflow-wrap:anywhere}
|
|
382
|
+
.foggy-turn-results{margin:10px 0 14px;max-width:100%;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-3);overflow:hidden;color:var(--dsw-alias-label-primary)}.foggy-turn-results-head{display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid var(--dsw-alias-border-l2);font-size:13px;font-weight:600;flex-wrap:wrap}.foggy-turn-results-provenance{padding:2px 7px;border-radius:999px;background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary);font-size:11px;font-weight:600}.foggy-turn-results-source{color:var(--dsw-alias-label-secondary);font-size:11px;font-weight:400}.foggy-turn-results-count{font-weight:400;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums}.foggy-turn-result{padding:9px 12px}.foggy-turn-result+.foggy-turn-result{border-top:1px solid var(--dsw-alias-border-l2)}.foggy-turn-result-head{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap}.foggy-turn-result-name{min-width:0;overflow-wrap:anywhere;font-size:12px;font-weight:600}.foggy-turn-result-meta{margin-left:8px;color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:400}.foggy-turn-result-actions{display:flex;align-items:center;gap:8px}.foggy-turn-result-actions button,.foggy-turn-results-toggle{border:0;background:none;color:var(--dsw-alias-state-business-primary);font:inherit;font-size:12px;cursor:pointer;padding:3px 0}.foggy-turn-result-actions button:disabled{opacity:.55;cursor:not-allowed}.foggy-turn-result-actions button:focus-visible,.foggy-turn-results-toggle:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.foggy-turn-result-detail{margin-top:9px;overflow:auto;max-height:300px}.foggy-turn-result-detail table{border-collapse:collapse;width:100%;min-width:max-content;font-size:11px}.foggy-turn-result-detail th,.foggy-turn-result-detail td{border:1px solid var(--dsw-alias-border-l2);padding:5px 7px;text-align:left;max-width:240px;overflow-wrap:anywhere}.foggy-turn-result-detail th{background:var(--dsw-alias-bg-layer-2);font-weight:600}.foggy-turn-result-note{margin:6px 0 0;color:var(--dsw-alias-label-tertiary);font-size:11px}.foggy-turn-result-error{margin:6px 0 0;color:var(--dsw-alias-state-error-primary);font-size:11px}.foggy-turn-results-toggle{display:block;width:100%;padding:9px 12px;border-top:1px solid var(--dsw-alias-border-l2);text-align:left}
|
|
383
|
+
.foggy-turn-result-code{margin-top:9px;font-size:11px}.foggy-turn-result-code summary{cursor:pointer;color:var(--dsw-alias-label-secondary)}.foggy-turn-result-code pre{max-height:220px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;margin:7px 0;padding:8px;border-radius:6px;background:var(--dsw-alias-bg-layer-2)}
|
|
358
384
|
@media (width<=680px){.foggy-grid{grid-template-columns:minmax(0,1fr)}.foggy-runtime-settings-row{grid-template-columns:minmax(0,1fr)}.foggy-runtime-settings-row .foggy-button{width:100%}.foggy-toolbar-main{width:100%}.foggy-toolbar-main .foggy-button{flex:1}.foggy-resource-link{min-height:36px}}
|
|
359
385
|
`
|
|
360
386
|
|
|
@@ -817,8 +843,104 @@ window.__ModuleLoader__.load({
|
|
|
817
843
|
] })
|
|
818
844
|
}
|
|
819
845
|
|
|
846
|
+
function queryPreviewSupported(args, result) {
|
|
847
|
+
const payload = args?.payload
|
|
848
|
+
return Boolean(result?.execution?.success) && payload && Array.isArray(payload.columns) && payload.columns.length > 0
|
|
849
|
+
&& !('executable_plan' in payload) && !('executablePlan' in payload) && payload.route !== 'DSL_CTE'
|
|
850
|
+
&& Object.keys(payload).every((key) => ['columns', 'slice', 'groupBy', 'orderBy', 'calculatedFields', 'extData', 'start', 'limit', 'returnTotal'].includes(key))
|
|
851
|
+
&& ['slice', 'calculatedFields'].every((key) => !payload[key] || Array.isArray(payload[key]) && payload[key].every((item) => item && typeof item === 'object' && !Array.isArray(item)))
|
|
852
|
+
&& ['groupBy', 'orderBy'].every((key) => !payload[key] || Array.isArray(payload[key]) && payload[key].every((item) => typeof item === 'string' && item.trim() || item && typeof item === 'object' && !Array.isArray(item)))
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
function useViewerPreview(api) {
|
|
856
|
+
const [preview, setPreview] = useState({ loading: false, error: '' })
|
|
857
|
+
async function openViewer(args) {
|
|
858
|
+
const pendingTab = window.open('about:blank', '_blank')
|
|
859
|
+
setPreview({ loading: true, error: '' })
|
|
860
|
+
try {
|
|
861
|
+
const value = unwrap(await api.createViewerPreview({ model: args.model, namespace: args.namespace, payload: args.payload }), 'createViewerPreview')
|
|
862
|
+
if (pendingTab) pendingTab.location.replace(value.url)
|
|
863
|
+
else throw new Error('Browser blocked the DataViewer tab')
|
|
864
|
+
setPreview({ loading: false, error: '' })
|
|
865
|
+
} catch (error) {
|
|
866
|
+
if (pendingTab) pendingTab.close()
|
|
867
|
+
setPreview({ loading: false, error: String(error?.message || error) })
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
return { preview, openViewer }
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
function readSuccessfulQuery(block) {
|
|
874
|
+
if (block?.kind !== 'tool-result' || block.isError || block.call?.name !== 'foggy_query') return null
|
|
875
|
+
try {
|
|
876
|
+
const args = JSON.parse(block.call.argsRaw)
|
|
877
|
+
const text = block.content?.find((item) => item.type === 'text')?.text
|
|
878
|
+
const result = JSON.parse(text)
|
|
879
|
+
if (!result?.execution?.success || !args?.model || !args?.namespace || !Array.isArray(result.execution.data?.items)) return null
|
|
880
|
+
return { callId: block.callId, args, result }
|
|
881
|
+
} catch { return null }
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
function cellText(value) {
|
|
885
|
+
const raw = value === null || value === undefined ? '—' : typeof value === 'object' ? JSON.stringify(value) : String(value)
|
|
886
|
+
return raw.length > 160 ? `${raw.slice(0, 157)}…` : raw
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
function FoggyTurnQuery({ query, api, t }) {
|
|
890
|
+
const [expanded, setExpanded] = useState(false)
|
|
891
|
+
const { preview, openViewer } = useViewerPreview(api)
|
|
892
|
+
const rows = query.result.execution.data.items
|
|
893
|
+
const fields = rows.length && rows[0] && typeof rows[0] === 'object' ? Object.keys(rows[0]) : []
|
|
894
|
+
return jsxs('div', { className: 'foggy-turn-result', children: [
|
|
895
|
+
jsxs('div', { className: 'foggy-turn-result-head', children: [
|
|
896
|
+
jsxs('div', { className: 'foggy-turn-result-name', children: [
|
|
897
|
+
query.args.model,
|
|
898
|
+
jsx('span', { className: 'foggy-turn-result-meta', children: `${query.args.namespace} · ${rows.length} ${t('queryCardRowUnit')}` }),
|
|
899
|
+
] }),
|
|
900
|
+
jsxs('div', { className: 'foggy-turn-result-actions', children: [
|
|
901
|
+
jsx('button', { type: 'button', 'aria-expanded': expanded, onClick: () => setExpanded((current) => !current), children: t(expanded ? 'queryCardHideResult' : 'queryCardShowResult') }),
|
|
902
|
+
queryPreviewSupported(query.args, query.result) ? jsx('button', { type: 'button', disabled: preview.loading, onClick: () => openViewer(query.args), children: preview.loading ? t('queryCardOpening') : t('queryCardOpen') }) : null,
|
|
903
|
+
] }),
|
|
904
|
+
] }),
|
|
905
|
+
expanded ? jsxs('div', { className: 'foggy-turn-result-detail', children: [
|
|
906
|
+
rows.length && fields.length ? jsxs('table', { children: [
|
|
907
|
+
jsx('thead', { children: jsx('tr', { children: fields.map((field) => jsx('th', { scope: 'col', children: field }, field)) }) }),
|
|
908
|
+
jsx('tbody', { children: rows.slice(0, 5).map((row, index) => jsx('tr', { children: fields.map((field) => jsx('td', { children: cellText(row[field]) }, field)) }, index)) }),
|
|
909
|
+
] }) : jsx('p', { className: 'foggy-turn-result-note', children: t('queryCardNoRows') }),
|
|
910
|
+
rows.length > 5 ? jsx('p', { className: 'foggy-turn-result-note', children: t('queryCardTableMore', { count: 5 }) }) : null,
|
|
911
|
+
jsxs('details', { className: 'foggy-turn-result-code', children: [
|
|
912
|
+
jsx('summary', { children: t('queryCardDsl') }),
|
|
913
|
+
jsx('pre', { children: JSON.stringify(query.args.payload, null, 2) }),
|
|
914
|
+
query.result.execution.data.debug?.extra?.sql ? jsx('pre', { children: query.result.execution.data.debug.extra.sql }) : null,
|
|
915
|
+
] }),
|
|
916
|
+
] }) : null,
|
|
917
|
+
preview.error ? jsx('p', { className: 'foggy-turn-result-error', role: 'alert', children: preview.error }) : null,
|
|
918
|
+
] })
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
function FoggyTurnResults({ turn, useQueryCalls, api, t }) {
|
|
922
|
+
const [showAll, setShowAll] = useState(false)
|
|
923
|
+
const calls = useQueryCalls(String(turn.turn)) || []
|
|
924
|
+
const queries = calls.map((item) => readSuccessfulQuery(item.root)).filter(Boolean)
|
|
925
|
+
if (!queries.length) return null
|
|
926
|
+
const visible = showAll ? queries : queries.slice(0, 6)
|
|
927
|
+
return jsxs('section', { className: 'foggy-turn-results', 'aria-label': t('queryCardResults'), children: [
|
|
928
|
+
jsxs('div', { className: 'foggy-turn-results-head', children: [
|
|
929
|
+
t('queryCardResults'), jsx('span', { className: 'foggy-turn-results-count', children: queries.length }),
|
|
930
|
+
jsx('span', { className: 'foggy-turn-results-provenance', children: t('queryCardProvenance') }),
|
|
931
|
+
jsx('span', { className: 'foggy-turn-results-source', children: t('queryCardSource') }),
|
|
932
|
+
] }),
|
|
933
|
+
...visible.map((query) => jsx(FoggyTurnQuery, { query, api, t }, query.callId)),
|
|
934
|
+
queries.length > 6 ? jsx('button', {
|
|
935
|
+
className: 'foggy-turn-results-toggle', type: 'button', 'aria-expanded': showAll,
|
|
936
|
+
onClick: () => setShowAll((current) => !current),
|
|
937
|
+
children: showAll ? t('queryCardShowLess') : t('queryCardShowAll', { count: queries.length }),
|
|
938
|
+
}) : null,
|
|
939
|
+
] })
|
|
940
|
+
}
|
|
941
|
+
|
|
820
942
|
function FoggyQueryCard({ phase, block, api, t }) {
|
|
821
|
-
const
|
|
943
|
+
const { preview, openViewer } = useViewerPreview(api)
|
|
822
944
|
let args = null
|
|
823
945
|
let result = null
|
|
824
946
|
let outputText = ''
|
|
@@ -834,22 +956,8 @@ window.__ModuleLoader__.load({
|
|
|
834
956
|
const rows = result?.execution?.data?.items?.length
|
|
835
957
|
const sql = result?.execution?.data?.debug?.extra?.sql
|
|
836
958
|
const payload = args?.payload
|
|
837
|
-
const
|
|
838
|
-
|
|
839
|
-
&& Object.keys(payload).every((key) => ['columns', 'slice', 'groupBy', 'orderBy', 'calculatedFields', 'extData', 'start', 'limit', 'returnTotal'].includes(key))
|
|
840
|
-
&& ['slice', 'groupBy', 'orderBy', 'calculatedFields'].every((key) => !payload[key] || Array.isArray(payload[key]) && payload[key].every((item) => item && typeof item === 'object' && !Array.isArray(item)))
|
|
841
|
-
async function openViewer() {
|
|
842
|
-
const pendingTab = window.open('about:blank', '_blank')
|
|
843
|
-
setPreview({ loading: true, url: '', expiresAt: 0, error: '' })
|
|
844
|
-
try {
|
|
845
|
-
const value = unwrap(await api.createViewerPreview({ model: args.model, namespace: args.namespace, payload }), 'createViewerPreview')
|
|
846
|
-
setPreview({ loading: false, url: value.url, expiresAt: Date.now() + value.expiresInMinutes * 60_000, error: '' })
|
|
847
|
-
if (pendingTab) pendingTab.location.replace(value.url)
|
|
848
|
-
} catch (error) {
|
|
849
|
-
if (pendingTab) pendingTab.close()
|
|
850
|
-
setPreview({ loading: false, url: '', expiresAt: 0, error: String(error?.message || error) })
|
|
851
|
-
}
|
|
852
|
-
}
|
|
959
|
+
const hasAdHocColumns = payload?.columns?.some((column) => typeof column === 'string' && /\bas\b|\(/i.test(column))
|
|
960
|
+
const supported = success && queryPreviewSupported(args, result)
|
|
853
961
|
const box = { border: '1px solid var(--dsw-alias-border-l2)', borderRadius: 10, padding: 12, margin: '8px 0', fontSize: 13 }
|
|
854
962
|
return jsxs('section', { style: box, children: [
|
|
855
963
|
jsx('strong', { children: `${t('queryCardTitle')}${args?.model ? ` · ${args.model}` : ''}` }),
|
|
@@ -865,15 +973,15 @@ window.__ModuleLoader__.load({
|
|
|
865
973
|
jsx('pre', { style: { maxHeight: 260, overflow: 'auto', whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' }, children: (outputText || JSON.stringify(block)).slice(0, 6000) }),
|
|
866
974
|
] }) : null,
|
|
867
975
|
supported ? jsxs('div', { style: { marginTop: 10 }, children: [
|
|
868
|
-
jsx('button', { type: 'button', disabled: preview.loading, onClick: openViewer, children: preview.loading ? t('queryCardOpening') : t('queryCardOpen') }),
|
|
976
|
+
jsx('button', { type: 'button', disabled: preview.loading, onClick: () => openViewer(args), children: preview.loading ? t('queryCardOpening') : t('queryCardOpen') }),
|
|
869
977
|
jsx('p', { style: { margin: '5px 0', color: 'var(--dsw-alias-label-tertiary)', fontSize: 11 }, children: t('queryCardPreviewHint') }),
|
|
870
|
-
|
|
978
|
+
hasAdHocColumns ? jsx('p', { style: { margin: '5px 0', color: 'var(--dsw-alias-state-warning-primary)', fontSize: 11 }, children: t('queryCardComputedHint') }) : null,
|
|
871
979
|
preview.error ? jsx('p', { role: 'alert', style: { color: 'var(--dsw-alias-state-error-primary)' }, children: preview.error }) : null,
|
|
872
980
|
] }) : success ? jsx('p', { style: { margin: '8px 0 0', color: 'var(--dsw-alias-label-tertiary)' }, children: t('queryCardUnsupported') }) : null,
|
|
873
981
|
] })
|
|
874
982
|
}
|
|
875
983
|
|
|
876
|
-
const inject = ['slots', 'locale', 'remote']
|
|
984
|
+
const inject = ['slots', 'locale', 'remote', 'sessions', 'uiConversation']
|
|
877
985
|
|
|
878
986
|
async function apply(ctx) {
|
|
879
987
|
const disposeRemote = await ctx.remote.$mount(TYPERT_REMOTE)
|
|
@@ -887,6 +995,23 @@ window.__ModuleLoader__.load({
|
|
|
887
995
|
key: 'foggy_query',
|
|
888
996
|
inject: () => ({ api, t }),
|
|
889
997
|
}, FoggyQueryCard))
|
|
998
|
+
remoteCtx.slots.inject('conversation.chat.turnTail', () => remoteCtx.slots.register({
|
|
999
|
+
name: 'conversation.chat.turnTail',
|
|
1000
|
+
id: 'foggy-query-results',
|
|
1001
|
+
inject: (sessionId) => {
|
|
1002
|
+
const binding = remoteCtx.sessions.binding(sessionId)
|
|
1003
|
+
if (!binding) throw new Error(`Foggy: unknown session ${sessionId}`)
|
|
1004
|
+
const chat = remoteCtx.uiConversation.binding(binding).target('chat')
|
|
1005
|
+
return {
|
|
1006
|
+
api, t,
|
|
1007
|
+
keyedHooks: { queryCalls: (turn) => {
|
|
1008
|
+
const snapshot = chat.getSnapshot()
|
|
1009
|
+
if (!snapshot) throw new Error('Foggy: chat target is unavailable')
|
|
1010
|
+
return snapshot.nodes.turnDataSource(Number(turn), 'tool-call')
|
|
1011
|
+
} },
|
|
1012
|
+
}
|
|
1013
|
+
},
|
|
1014
|
+
}, FoggyTurnResults))
|
|
890
1015
|
remoteCtx.slots.inject('settings.plugins.tab', () => remoteCtx.slots.register({
|
|
891
1016
|
name: 'settings.plugins.tab',
|
|
892
1017
|
id: 'foggy',
|
package/lib/query-tool.js
CHANGED
|
@@ -3,7 +3,6 @@ import { mkdtemp, readFile, rmdir, unlink, writeFile } from 'node:fs/promises'
|
|
|
3
3
|
import { tmpdir } from 'node:os'
|
|
4
4
|
import { join } from 'node:path'
|
|
5
5
|
import { promisify } from 'node:util'
|
|
6
|
-
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
7
6
|
|
|
8
7
|
const execFileAsync = promisify(execFile)
|
|
9
8
|
const identifier = /^[A-Za-z0-9_.-]{1,128}$/
|
|
@@ -23,12 +22,30 @@ export function previewPayload(payload) {
|
|
|
23
22
|
const supported = new Set(['columns', 'slice', 'groupBy', 'orderBy', 'calculatedFields', 'extData'])
|
|
24
23
|
const unsupported = Object.keys(payload).filter((key) => !supported.has(key) && !['start', 'limit', 'returnTotal'].includes(key))
|
|
25
24
|
if (unsupported.length) throw new Error(`DataViewer preview does not support: ${unsupported.join(', ')}`)
|
|
26
|
-
for (const key of ['slice', '
|
|
25
|
+
for (const key of ['slice', 'calculatedFields']) {
|
|
27
26
|
if (payload[key] !== undefined && (!Array.isArray(payload[key]) || payload[key].some((item) => !item || typeof item !== 'object' || Array.isArray(item)))) {
|
|
28
27
|
throw new Error(`DataViewer preview requires object-form ${key} entries`)
|
|
29
28
|
}
|
|
30
29
|
}
|
|
31
|
-
|
|
30
|
+
const result = Object.fromEntries([...supported].filter((key) => payload[key] !== undefined).map((key) => [key, payload[key]]))
|
|
31
|
+
if (payload.groupBy !== undefined) {
|
|
32
|
+
if (!Array.isArray(payload.groupBy) || payload.groupBy.some((item) => typeof item !== 'string' && (!item || typeof item !== 'object' || Array.isArray(item)))) {
|
|
33
|
+
throw new Error('DataViewer preview requires field names or object-form groupBy entries')
|
|
34
|
+
}
|
|
35
|
+
result.groupBy = payload.groupBy.map((item) => typeof item === 'string' ? { field: item } : item)
|
|
36
|
+
}
|
|
37
|
+
if (payload.orderBy !== undefined) {
|
|
38
|
+
if (!Array.isArray(payload.orderBy) || payload.orderBy.some((item) => typeof item !== 'string' && (!item || typeof item !== 'object' || Array.isArray(item)))) {
|
|
39
|
+
throw new Error('DataViewer preview requires field names or object-form orderBy entries')
|
|
40
|
+
}
|
|
41
|
+
result.orderBy = payload.orderBy.map((item) => {
|
|
42
|
+
if (typeof item !== 'string') return item
|
|
43
|
+
const shorthand = item.trim().match(/^(-)?(.+?)(?:\s+(asc|desc))?$/i)
|
|
44
|
+
if (!shorthand || !shorthand[2].trim()) throw new Error('DataViewer preview requires a valid orderBy field')
|
|
45
|
+
return { field: shorthand[2].trim(), dir: shorthand[1] ? 'desc' : (shorthand[3] || 'asc').toLowerCase() }
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
return result
|
|
32
49
|
}
|
|
33
50
|
|
|
34
51
|
export function safeRuntimeUrl(value) {
|
|
@@ -60,25 +77,35 @@ async function cliJson(cli, runtimeUrl, namespace, command, signal) {
|
|
|
60
77
|
}
|
|
61
78
|
|
|
62
79
|
export function createFoggyQueryTool(roots) {
|
|
63
|
-
return
|
|
80
|
+
return {
|
|
64
81
|
name: 'foggy_query',
|
|
65
82
|
description: 'Validate and execute a bounded, read-only standard Foggy QueryModel DSL query against the managed local Runtime. On success Harness shows a query card; its DataViewer preview link is created only if the user clicks Open DataViewer. CTE is not supported here.',
|
|
66
83
|
parameters: {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
84
|
+
type: 'object',
|
|
85
|
+
properties: {
|
|
86
|
+
model: { type: 'string', description: 'Published Foggy QueryModel name' },
|
|
87
|
+
namespace: { type: 'string', description: 'Foggy namespace' },
|
|
88
|
+
payload: { type: 'object', additionalProperties: true, description: 'Standard QueryModel DSL, including explicit columns and bounded limit' },
|
|
89
|
+
},
|
|
90
|
+
required: ['model', 'namespace', 'payload'],
|
|
70
91
|
},
|
|
71
92
|
output: {
|
|
72
|
-
schema: {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
93
|
+
schema: {
|
|
94
|
+
type: 'object',
|
|
95
|
+
additionalProperties: false,
|
|
96
|
+
properties: {
|
|
97
|
+
model: { type: 'string' },
|
|
98
|
+
namespace: { type: 'string' },
|
|
99
|
+
validation: {},
|
|
100
|
+
execution: {},
|
|
101
|
+
},
|
|
102
|
+
required: ['model', 'namespace', 'validation', 'execution'],
|
|
103
|
+
},
|
|
78
104
|
render: (_args, value) => [{ type: 'text', text: JSON.stringify(value) }],
|
|
79
105
|
},
|
|
80
106
|
timeoutMs: 150_000,
|
|
81
|
-
async execute(
|
|
107
|
+
async execute(args, exec) {
|
|
108
|
+
const { model, namespace, payload } = args || {}
|
|
82
109
|
if (!identifier.test(model) || !identifier.test(namespace)) throw new Error('Invalid model or namespace')
|
|
83
110
|
assertStandardDsl(payload)
|
|
84
111
|
if (!Number.isInteger(payload.limit) || payload.limit < 1 || payload.limit > 100) {
|
|
@@ -89,8 +116,8 @@ export function createFoggyQueryTool(roots) {
|
|
|
89
116
|
const payloadPath = join(directory, 'query.json')
|
|
90
117
|
try {
|
|
91
118
|
await writeFile(payloadPath, JSON.stringify(payload), { encoding: 'utf8', flag: 'wx' })
|
|
92
|
-
const validation = await cliJson(cli, runtimeUrl, namespace, ['query', 'validate', model, '--payload', payloadPath], exec
|
|
93
|
-
const execution = await cliJson(cli, runtimeUrl, namespace, ['query', 'execute', model, '--payload', payloadPath], exec
|
|
119
|
+
const validation = await cliJson(cli, runtimeUrl, namespace, ['query', 'validate', model, '--payload', payloadPath], exec?.signal)
|
|
120
|
+
const execution = await cliJson(cli, runtimeUrl, namespace, ['query', 'execute', model, '--payload', payloadPath], exec?.signal)
|
|
94
121
|
return { model, namespace, validation, execution }
|
|
95
122
|
} finally {
|
|
96
123
|
await unlink(payloadPath).catch(() => {})
|
|
@@ -100,5 +127,5 @@ export function createFoggyQueryTool(roots) {
|
|
|
100
127
|
presentCall({ model }) {
|
|
101
128
|
return { card: 'generic', title: `Foggy DSL · ${model}`, kind: 'read' }
|
|
102
129
|
},
|
|
103
|
-
}
|
|
130
|
+
}
|
|
104
131
|
}
|
package/lib/viewer-preview.js
CHANGED
|
@@ -23,5 +23,5 @@ export async function createViewerPreview({ model, namespace, payload }, runtime
|
|
|
23
23
|
|| url.username || url.password || url.search || url.hash) {
|
|
24
24
|
throw new Error('DataViewer returned an unexpected preview URL')
|
|
25
25
|
}
|
|
26
|
-
return { success: true, url: url.href, queryId: result.queryId
|
|
26
|
+
return { success: true, url: url.href, queryId: result.queryId }
|
|
27
27
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foggy-projects/deepseek-harness-plugin",
|
|
3
|
-
"version": "0.4.2-rc.
|
|
3
|
+
"version": "0.4.2-rc.5",
|
|
4
4
|
"description": "Foggy Java data analysis engine integration for DeepSeek Harness",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
@@ -42,6 +42,8 @@
|
|
|
42
42
|
"docs/RELEASE-CANDIDATE-0.4.1-DSH-0.1.5-RC.1.md",
|
|
43
43
|
"docs/RELEASE-CANDIDATE-0.4.2-DSH-0.1.7-RC.2.md",
|
|
44
44
|
"docs/RELEASE-CANDIDATE-0.4.2-DSH-0.1.7-RC.3.md",
|
|
45
|
+
"docs/RELEASE-CANDIDATE-0.4.2-DSH-0.1.7-RC.4.md",
|
|
46
|
+
"docs/RELEASE-CANDIDATE-0.4.2-DSH-0.1.7-RC.5.md",
|
|
45
47
|
"docs/RELEASE-CANDIDATE-0.4.2-DSH-0.1.7-RC.1.md",
|
|
46
48
|
"docs/COMMUNITY-MARKETPLACES.md",
|
|
47
49
|
"docs/WINDOWS-BETA-ACCEPTANCE.md",
|
|
@@ -63,12 +65,14 @@
|
|
|
63
65
|
"@deepseek-ai/dsh-client-locale",
|
|
64
66
|
"@deepseek-ai/dsh-client-ui-settings",
|
|
65
67
|
"@deepseek-ai/dsh-client-ui-settings-plugins",
|
|
66
|
-
"@deepseek-ai/dsh-client-ui-tool"
|
|
68
|
+
"@deepseek-ai/dsh-client-ui-tool",
|
|
69
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
70
|
+
"@deepseek-ai/dsh-client-ui-chat",
|
|
71
|
+
"@deepseek-ai/dsh-api-session-controller"
|
|
67
72
|
]
|
|
68
73
|
}
|
|
69
74
|
},
|
|
70
75
|
"dependencies": {
|
|
71
|
-
"@deepseek-ai/dsh-tools": "0.1.7-rc.2",
|
|
72
76
|
"zod": "^4.4.3"
|
|
73
77
|
},
|
|
74
78
|
"peerDependencies": {
|
|
@@ -78,6 +82,9 @@
|
|
|
78
82
|
"@deepseek-ai/dsh-client-ui-settings": "^0.1.7-rc.2",
|
|
79
83
|
"@deepseek-ai/dsh-client-ui-settings-plugins": "^0.1.7-rc.2",
|
|
80
84
|
"@deepseek-ai/dsh-client-ui-tool": "^0.1.7-rc.2",
|
|
85
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.7-rc.2",
|
|
86
|
+
"@deepseek-ai/dsh-client-ui-chat": "^0.1.7-rc.2",
|
|
87
|
+
"@deepseek-ai/dsh-api-session-controller": "^0.1.7-rc.2",
|
|
81
88
|
"@deepseek-ai/dsh-skill": "^0.1.7-rc.2",
|
|
82
89
|
"@deepseek-ai/dsh-typert-protocol": "^0.1.7-rc.2"
|
|
83
90
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "foggy-deepseek-onboarding-versions/v1",
|
|
3
|
-
"packageVersion": "0.4.2-rc.
|
|
3
|
+
"packageVersion": "0.4.2-rc.5",
|
|
4
4
|
"validatedAt": "2026-09-28",
|
|
5
5
|
"components": {
|
|
6
6
|
"deepseekHarness": {
|
|
@@ -66,39 +66,39 @@
|
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
68
|
"launcher": {
|
|
69
|
-
"version": "0.1.
|
|
69
|
+
"version": "0.1.23",
|
|
70
70
|
"minimumJavaVersion": "17.0.0",
|
|
71
71
|
"runtimeApiContract": "foggy-runtime-api/v1",
|
|
72
72
|
"assets": [
|
|
73
73
|
{
|
|
74
|
-
"file": "foggy-runtime-launcher-0.1.
|
|
75
|
-
"url": "https://github.com/foggy-projects/foggy-data-mcp-bridge/releases/download/foggy-runtime-launcher-v0.1.
|
|
76
|
-
"sha256": "
|
|
74
|
+
"file": "foggy-runtime-launcher-0.1.23.jar",
|
|
75
|
+
"url": "https://github.com/foggy-projects/foggy-data-mcp-bridge/releases/download/foggy-runtime-launcher-v0.1.23/foggy-runtime-launcher-0.1.23.jar",
|
|
76
|
+
"sha256": "e3575c51e457d6b88740ef5949d7e206d5d6046d960fc8ef0884765bf3be8c66"
|
|
77
77
|
},
|
|
78
78
|
{
|
|
79
79
|
"file": "start-foggy-runtime.ps1",
|
|
80
|
-
"url": "https://github.com/foggy-projects/foggy-data-mcp-bridge/releases/download/foggy-runtime-launcher-v0.1.
|
|
81
|
-
"sha256": "
|
|
80
|
+
"url": "https://github.com/foggy-projects/foggy-data-mcp-bridge/releases/download/foggy-runtime-launcher-v0.1.23/start-foggy-runtime.ps1",
|
|
81
|
+
"sha256": "e6e2ac995a2a84c3de53878e8e0db4d701eab8b3a7ca6dbe9d4fb4ad15b00ae4"
|
|
82
82
|
},
|
|
83
83
|
{
|
|
84
84
|
"file": "start-foggy-runtime.sh",
|
|
85
|
-
"url": "https://github.com/foggy-projects/foggy-data-mcp-bridge/releases/download/foggy-runtime-launcher-v0.1.
|
|
86
|
-
"sha256": "
|
|
85
|
+
"url": "https://github.com/foggy-projects/foggy-data-mcp-bridge/releases/download/foggy-runtime-launcher-v0.1.23/start-foggy-runtime.sh",
|
|
86
|
+
"sha256": "562ef5614e02c4635c21d5fa9d6c2edc0dfb69d8da0ae57c4247c0c8202d50ae"
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
89
|
"file": "README-foggy-runtime-launcher.md",
|
|
90
|
-
"url": "https://github.com/foggy-projects/foggy-data-mcp-bridge/releases/download/foggy-runtime-launcher-v0.1.
|
|
91
|
-
"sha256": "
|
|
90
|
+
"url": "https://github.com/foggy-projects/foggy-data-mcp-bridge/releases/download/foggy-runtime-launcher-v0.1.23/README-foggy-runtime-launcher.md",
|
|
91
|
+
"sha256": "759e3be46eb97a8f62b7ffb1dc5a977c52d0b91d1d31860e4e799125ce25e376"
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
94
|
"file": "runtime-launcher-manifest.json",
|
|
95
|
-
"url": "https://github.com/foggy-projects/foggy-data-mcp-bridge/releases/download/foggy-runtime-launcher-v0.1.
|
|
96
|
-
"sha256": "
|
|
95
|
+
"url": "https://github.com/foggy-projects/foggy-data-mcp-bridge/releases/download/foggy-runtime-launcher-v0.1.23/runtime-launcher-manifest.json",
|
|
96
|
+
"sha256": "d25a9a0026495fd47e6ca03c957bf9999df9cffe73c6d6b0fc5c7dfc3931d317"
|
|
97
97
|
},
|
|
98
98
|
{
|
|
99
99
|
"file": "SHA256SUMS",
|
|
100
|
-
"url": "https://github.com/foggy-projects/foggy-data-mcp-bridge/releases/download/foggy-runtime-launcher-v0.1.
|
|
101
|
-
"sha256": "
|
|
100
|
+
"url": "https://github.com/foggy-projects/foggy-data-mcp-bridge/releases/download/foggy-runtime-launcher-v0.1.23/SHA256SUMS",
|
|
101
|
+
"sha256": "49354e281c9f854651074b292aa003710334ae2f5494b3c07eafddf1d08a7dac"
|
|
102
102
|
}
|
|
103
103
|
]
|
|
104
104
|
},
|
|
@@ -506,28 +506,27 @@ def materialize(
|
|
|
506
506
|
progress_total: int = 1,
|
|
507
507
|
progress_message: str = "Downloading and verifying asset",
|
|
508
508
|
replace_corrupt: bool = False,
|
|
509
|
+
previous_sha256: str | None = None,
|
|
509
510
|
) -> dict:
|
|
510
511
|
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
512
|
+
previous_valid = False
|
|
511
513
|
if destination.is_file():
|
|
512
514
|
try:
|
|
513
515
|
verify_asset(destination, asset["sha256"])
|
|
514
516
|
return {"file": asset["file"], "path": str(destination), "source": "existing", "sha256": asset["sha256"]}
|
|
515
517
|
except OnboardingError:
|
|
516
|
-
|
|
518
|
+
previous_valid = bool(previous_sha256 and sha256(destination).lower() == previous_sha256.lower())
|
|
519
|
+
if not previous_valid and not replace_corrupt:
|
|
517
520
|
raise
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
temporary = destination.with_name(destination.name + ".download")
|
|
528
|
-
if temporary.exists():
|
|
529
|
-
temporary.unlink()
|
|
530
|
-
try:
|
|
521
|
+
temporary = destination.with_name(destination.name + ".download")
|
|
522
|
+
if temporary.exists():
|
|
523
|
+
temporary.unlink()
|
|
524
|
+
try:
|
|
525
|
+
cached = cached_asset(asset["file"], asset["sha256"], cache_dirs)
|
|
526
|
+
if cached:
|
|
527
|
+
shutil.copy2(cached, temporary)
|
|
528
|
+
source = "cache"
|
|
529
|
+
else:
|
|
531
530
|
def reporthook(block_count: int, block_size: int, total_size: int) -> None:
|
|
532
531
|
if progress is None or not progress_phase or total_size <= 0:
|
|
533
532
|
return
|
|
@@ -540,12 +539,18 @@ def materialize(
|
|
|
540
539
|
)
|
|
541
540
|
|
|
542
541
|
urllib.request.urlretrieve(asset["url"], temporary, reporthook=reporthook)
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
if
|
|
547
|
-
|
|
548
|
-
|
|
542
|
+
source = "network"
|
|
543
|
+
verify_asset(temporary, asset["sha256"])
|
|
544
|
+
if destination.is_file():
|
|
545
|
+
suffix = "previous" if previous_valid else "corrupt"
|
|
546
|
+
backup = destination.with_name(
|
|
547
|
+
destination.name + f".{suffix}-{dt.datetime.now().strftime('%Y%m%d-%H%M%S-%f')}"
|
|
548
|
+
)
|
|
549
|
+
shutil.copy2(destination, backup)
|
|
550
|
+
os.replace(temporary, destination)
|
|
551
|
+
finally:
|
|
552
|
+
if temporary.exists():
|
|
553
|
+
temporary.unlink()
|
|
549
554
|
verify_asset(destination, asset["sha256"])
|
|
550
555
|
return {"file": asset["file"], "path": str(destination), "source": source, "sha256": asset["sha256"]}
|
|
551
556
|
|
|
@@ -1345,6 +1350,16 @@ def install_command(args: argparse.Namespace) -> dict:
|
|
|
1345
1350
|
progress.update("cli", 2, "CLI ready", fraction=1.0)
|
|
1346
1351
|
|
|
1347
1352
|
launcher_dir = install_root / "launcher"
|
|
1353
|
+
previous_state = read_install_state(install_root, required=False)
|
|
1354
|
+
previous_launcher_assets = {}
|
|
1355
|
+
if previous_state and previous_state.get("launcher", {}).get("version") != components["launcher"]["version"]:
|
|
1356
|
+
previous_launcher_assets = {
|
|
1357
|
+
item["file"]: item["sha256"]
|
|
1358
|
+
for item in previous_state.get("verifiedAssets", [])
|
|
1359
|
+
if item.get("file") and item.get("sha256")
|
|
1360
|
+
and item.get("path")
|
|
1361
|
+
and normalized(item["path"]) == normalized(launcher_dir / item["file"])
|
|
1362
|
+
}
|
|
1348
1363
|
launcher_assets = components["launcher"]["assets"]
|
|
1349
1364
|
for index, asset in enumerate(launcher_assets):
|
|
1350
1365
|
progress.update(
|
|
@@ -1358,6 +1373,7 @@ def install_command(args: argparse.Namespace) -> dict:
|
|
|
1358
1373
|
progress_index=index, progress_total=len(launcher_assets),
|
|
1359
1374
|
progress_message="Downloading and verifying Launcher",
|
|
1360
1375
|
replace_corrupt=repair_component == "launcher",
|
|
1376
|
+
previous_sha256=previous_launcher_assets.get(asset["file"]),
|
|
1361
1377
|
))
|
|
1362
1378
|
progress.update(
|
|
1363
1379
|
"launcher", 3, "Downloading and verifying Launcher",
|