@foggy-projects/deepseek-harness-plugin 0.4.0-beta.4 → 0.4.0-beta.6
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 +23 -18
- package/lib/client.js +10 -13
- package/lib/index.js +27 -32
- package/lib/skill-provider.js +111 -0
- package/package.json +4 -3
- package/skills/foggy-deepseek-onboarding/SKILL.md +39 -22
- package/skills/foggy-deepseek-onboarding/assets/versions.json +2 -2
- package/skills/foggy-deepseek-onboarding/references/onboarding-workflow.md +22 -0
- package/skills/foggy-deepseek-onboarding/scripts/onboarding.py +393 -268
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ only when the user selects **Initialize Foggy**.
|
|
|
8
8
|
## Local beta installation
|
|
9
9
|
|
|
10
10
|
```powershell
|
|
11
|
-
dsh plugin --profile web add --workspace-root ./foggy-projects-deepseek-harness-plugin-0.4.0-beta.
|
|
11
|
+
dsh plugin --profile web add --workspace-root ./foggy-projects-deepseek-harness-plugin-0.4.0-beta.6.tgz
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
Restart `dsh web`, open Settings → Plugins → Foggy Data Analysis, and initialize
|
|
@@ -20,27 +20,32 @@ After npm beta publication, the corresponding one-line install is:
|
|
|
20
20
|
dsh plugin --profile web add --workspace-root @foggy-projects/deepseek-harness-plugin@beta
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
For development, `
|
|
24
|
-
|
|
25
|
-
asset-cache directories. Neither variable is required for a normal install.
|
|
23
|
+
For development, `FOGGY_ASSET_CACHE_DIRS` can contain platform-delimited verified
|
|
24
|
+
asset-cache directories. It is not required for a normal install.
|
|
26
25
|
|
|
27
|
-
Database credentials
|
|
28
|
-
|
|
26
|
+
Database credentials remain outside the ordinary DSH settings document. The
|
|
27
|
+
bundled onboarding Skill drives datasource discovery, semantic drafting,
|
|
28
|
+
checkpointed publication, and bounded read-only query verification.
|
|
29
29
|
|
|
30
|
-
##
|
|
30
|
+
## Native Skill and workspace contract
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
The Bundle registers `foggy-deepseek-onboarding` and the downloaded
|
|
33
|
+
`foggy-ai-analysis` through DeepSeek Harness's native Skill provider API. Skills
|
|
34
|
+
are available in every DSH workspace without copying or symlinking `.agents`.
|
|
35
|
+
The current session `cwd` remains the workspace boundary for semantic drafts and
|
|
36
|
+
evidence.
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
Opaque CLI profiles default to the private persistent
|
|
39
|
+
`<dataRoot>/cli-profiles` directory. Composite onboarding commands are
|
|
40
|
+
idempotent: unchanged completed phases are resumed rather than re-adding a
|
|
41
|
+
datasource or re-registering a published bundle.
|
|
42
|
+
|
|
43
|
+
CLI, Launcher, the analysis Skill, install state, and Runtime state live in the
|
|
44
|
+
user-level Foggy component directories. The managed CLI is intentionally isolated
|
|
45
|
+
and does not need to be on `PATH`. **Re-download / Repair** verifies the global
|
|
46
|
+
analysis Skill, backs up modified or outdated managed content, restores it, and
|
|
47
|
+
invalidates DSH's Skill catalog. The onboarding Skill is bundled with the plugin
|
|
48
|
+
and is restored by reinstalling or upgrading the plugin package.
|
|
44
49
|
|
|
45
50
|
## Linux and WSL2 experience
|
|
46
51
|
|
package/lib/client.js
CHANGED
|
@@ -42,7 +42,7 @@ window.__ModuleLoader__.load({
|
|
|
42
42
|
launcher: 'Launcher',
|
|
43
43
|
analysisSkill: '分析 Skill',
|
|
44
44
|
onboardingSkill: '引导 Skill',
|
|
45
|
-
|
|
45
|
+
skillRegistry: 'DSH Skill 注册',
|
|
46
46
|
python: 'Python',
|
|
47
47
|
java: 'Java',
|
|
48
48
|
installed: '已安装',
|
|
@@ -59,7 +59,7 @@ window.__ModuleLoader__.load({
|
|
|
59
59
|
progressCli: '准备 CLI',
|
|
60
60
|
progressLauncher: '准备 Launcher',
|
|
61
61
|
progressAnalysis: '准备分析 Skill',
|
|
62
|
-
progressSkills: '
|
|
62
|
+
progressSkills: '注册 DSH Skills',
|
|
63
63
|
progressState: '写入安装状态',
|
|
64
64
|
progressComplete: '初始化完成',
|
|
65
65
|
progressFiles: '文件',
|
|
@@ -68,11 +68,10 @@ window.__ModuleLoader__.load({
|
|
|
68
68
|
roots: '本地目录',
|
|
69
69
|
installRoot: '组件目录',
|
|
70
70
|
dataRoot: '数据目录',
|
|
71
|
+
profileStore: 'CLI Profile',
|
|
71
72
|
runtimeUrl: 'Runtime 地址',
|
|
72
|
-
projectRoot: 'Skill 目标工作区',
|
|
73
|
-
contextPath: '对话发现文件',
|
|
74
73
|
nextTitle: '后续配置',
|
|
75
|
-
nextCopy: '
|
|
74
|
+
nextCopy: 'Skills 已通过 DeepSeek Harness 原生注册表提供给所有工作区;每个会话直接使用自己的工作目录。Runtime 启动成功后,将继续进入数据库连接与语义层向导。',
|
|
76
75
|
beta: 'Beta',
|
|
77
76
|
}
|
|
78
77
|
|
|
@@ -92,7 +91,7 @@ window.__ModuleLoader__.load({
|
|
|
92
91
|
launcher: 'Launcher',
|
|
93
92
|
analysisSkill: 'Analysis Skill',
|
|
94
93
|
onboardingSkill: 'Onboarding Skill',
|
|
95
|
-
|
|
94
|
+
skillRegistry: 'DSH Skill registry',
|
|
96
95
|
python: 'Python',
|
|
97
96
|
java: 'Java',
|
|
98
97
|
installed: 'Installed',
|
|
@@ -109,7 +108,7 @@ window.__ModuleLoader__.load({
|
|
|
109
108
|
progressCli: 'Preparing CLI',
|
|
110
109
|
progressLauncher: 'Preparing Launcher',
|
|
111
110
|
progressAnalysis: 'Preparing analysis Skill',
|
|
112
|
-
progressSkills: '
|
|
111
|
+
progressSkills: 'Registering DSH Skills',
|
|
113
112
|
progressState: 'Writing install state',
|
|
114
113
|
progressComplete: 'Initialization complete',
|
|
115
114
|
progressFiles: 'files',
|
|
@@ -118,11 +117,10 @@ window.__ModuleLoader__.load({
|
|
|
118
117
|
roots: 'Local directories',
|
|
119
118
|
installRoot: 'Components',
|
|
120
119
|
dataRoot: 'Data',
|
|
120
|
+
profileStore: 'CLI profiles',
|
|
121
121
|
runtimeUrl: 'Runtime URL',
|
|
122
|
-
projectRoot: 'Skill target workspace',
|
|
123
|
-
contextPath: 'Conversation discovery file',
|
|
124
122
|
nextTitle: 'Next configuration',
|
|
125
|
-
nextCopy: '
|
|
123
|
+
nextCopy: 'Skills are provided to every workspace through the native DeepSeek Harness registry, and each session uses its own working directory. After Runtime starts, the database connection and semantic-layer wizard comes next.',
|
|
126
124
|
beta: 'Beta',
|
|
127
125
|
}
|
|
128
126
|
|
|
@@ -285,15 +283,14 @@ window.__ModuleLoader__.load({
|
|
|
285
283
|
componentCard(t('launcher'), status.components.launcher, 'runtime', t),
|
|
286
284
|
componentCard(t('analysisSkill'), status.components.analysisSkill, 'runtime', t),
|
|
287
285
|
componentCard(t('onboardingSkill'), status.components.onboardingSkill, 'runtime', t),
|
|
288
|
-
componentCard(t('
|
|
286
|
+
componentCard(t('skillRegistry'), { installed: status.components.onboardingSkill?.provider === 'foggy-managed-skills', version: 'native' }, 'runtime', t),
|
|
289
287
|
] }),
|
|
290
288
|
jsxs('div', { className: 'foggy-paths', children: [
|
|
291
289
|
jsx('h4', { children: t('roots') }),
|
|
292
290
|
jsxs('dl', { children: [
|
|
293
291
|
jsx('dt', { children: t('installRoot') }), jsx('dd', { children: status.roots.installRoot }),
|
|
294
292
|
jsx('dt', { children: t('dataRoot') }), jsx('dd', { children: status.roots.dataRoot }),
|
|
295
|
-
jsx('dt', { children: t('
|
|
296
|
-
jsx('dt', { children: t('contextPath') }), jsx('dd', { children: status.contextPath }),
|
|
293
|
+
jsx('dt', { children: t('profileStore') }), jsx('dd', { children: status.roots.profileStore }),
|
|
297
294
|
status.runtimeUrl ? jsx('dt', { children: t('runtimeUrl') }) : null,
|
|
298
295
|
status.runtimeUrl ? jsx('dd', { children: status.runtimeUrl }) : null,
|
|
299
296
|
] }),
|
package/lib/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { dirname, join, delimiter } from 'node:path'
|
|
|
5
5
|
import { fileURLToPath } from 'node:url'
|
|
6
6
|
import { promisify } from 'node:util'
|
|
7
7
|
import { Remote, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol'
|
|
8
|
+
import { createFoggySkillProvider } from './skill-provider.js'
|
|
8
9
|
import { compatible } from './version.js'
|
|
9
10
|
|
|
10
11
|
const execFileAsync = promisify(execFile)
|
|
@@ -19,17 +20,20 @@ function defaultRoots() {
|
|
|
19
20
|
return {
|
|
20
21
|
installRoot: join(base, 'Foggy', 'DeepSeekHarness'),
|
|
21
22
|
dataRoot: join(base, 'Foggy', 'DeepSeekHarnessData'),
|
|
23
|
+
profileStore: process.env.FOGGY_RUNTIME_PROFILE_STORE || join(base, 'Foggy', 'DeepSeekHarnessData', 'cli-profiles'),
|
|
22
24
|
}
|
|
23
25
|
}
|
|
24
26
|
const home = process.env.HOME
|
|
25
27
|
if (!home) throw new Error('HOME is not set')
|
|
28
|
+
const dataRoot = process.env.XDG_STATE_HOME
|
|
29
|
+
? join(process.env.XDG_STATE_HOME, 'foggy', 'deepseek-harness')
|
|
30
|
+
: join(home, '.local', 'state', 'foggy', 'deepseek-harness')
|
|
26
31
|
return {
|
|
27
32
|
installRoot: process.env.XDG_DATA_HOME
|
|
28
33
|
? join(process.env.XDG_DATA_HOME, 'foggy', 'deepseek-harness')
|
|
29
34
|
: join(home, '.local', 'share', 'foggy', 'deepseek-harness'),
|
|
30
|
-
dataRoot
|
|
31
|
-
|
|
32
|
-
: join(home, '.local', 'state', 'foggy', 'deepseek-harness'),
|
|
35
|
+
dataRoot,
|
|
36
|
+
profileStore: process.env.FOGGY_RUNTIME_PROFILE_STORE || join(dataRoot, 'cli-profiles'),
|
|
33
37
|
}
|
|
34
38
|
}
|
|
35
39
|
|
|
@@ -120,20 +124,26 @@ function operationView(operation) {
|
|
|
120
124
|
}
|
|
121
125
|
|
|
122
126
|
export class FoggyIntegrationGateway extends TypertRemoteService {
|
|
127
|
+
static inject = ['skills']
|
|
128
|
+
|
|
123
129
|
operation = null
|
|
130
|
+
skillProviderControl = null
|
|
124
131
|
|
|
125
132
|
constructor(ctx) {
|
|
126
133
|
super(ctx, 'foggyIntegration')
|
|
134
|
+
const roots = defaultRoots()
|
|
135
|
+
ctx.skills.registerProvider((control) => {
|
|
136
|
+
this.skillProviderControl = control
|
|
137
|
+
return createFoggySkillProvider({ installRoot: roots.installRoot, versionsFile })
|
|
138
|
+
})
|
|
127
139
|
for (const initialize of markerInitializers) initialize.call(this)
|
|
128
140
|
}
|
|
129
141
|
|
|
130
142
|
async status() {
|
|
131
143
|
const roots = defaultRoots()
|
|
132
|
-
const projectRoot = process.env.FOGGY_PROJECT_ROOT || process.cwd()
|
|
133
144
|
const statePath = join(roots.installRoot, 'install-state.json')
|
|
134
145
|
const runtimeStatePath = join(roots.dataRoot, 'runtime-state.json')
|
|
135
146
|
const progressPath = join(roots.dataRoot, 'operation-progress.json')
|
|
136
|
-
const contextPath = join(projectRoot, '.foggy', 'deepseek-harness', 'context.json')
|
|
137
147
|
const manifest = await readJson(versionsFile)
|
|
138
148
|
let pythonProbe
|
|
139
149
|
try {
|
|
@@ -145,16 +155,13 @@ export class FoggyIntegrationGateway extends TypertRemoteService {
|
|
|
145
155
|
const java = compatible(await commandVersion(process.env.JAVA_EXE || 'java', ['-version']), '17.0')
|
|
146
156
|
let state = null
|
|
147
157
|
let runtime = null
|
|
148
|
-
let context = null
|
|
149
158
|
try { state = await readJson(statePath) } catch {}
|
|
150
159
|
try { runtime = await readJson(runtimeStatePath) } catch {}
|
|
151
|
-
try { context = await readJson(contextPath) } catch {}
|
|
152
160
|
const cliPath = state?.cli?.command
|
|
153
161
|
const launcherPath = state?.launcher?.path
|
|
154
|
-
const analysisSkillPath = state?.skills?.analysis?.path || join(
|
|
155
|
-
const onboardingSkillPath =
|
|
162
|
+
const analysisSkillPath = state?.skills?.analysis?.path || join(roots.installRoot, 'skills', 'foggy-ai-analysis')
|
|
163
|
+
const onboardingSkillPath = join(packageRoot, 'skills', 'foggy-deepseek-onboarding')
|
|
156
164
|
const analysisMarker = await readOptionalJson(join(analysisSkillPath, '.foggy-managed-skill.json'))
|
|
157
|
-
const onboardingMarker = await readOptionalJson(join(onboardingSkillPath, '.foggy-managed-skill.json'))
|
|
158
165
|
const components = {
|
|
159
166
|
python,
|
|
160
167
|
java,
|
|
@@ -175,28 +182,15 @@ export class FoggyIntegrationGateway extends TypertRemoteService {
|
|
|
175
182
|
version: state?.skills?.analysis?.version ?? manifest.components.analysisSkill.version,
|
|
176
183
|
},
|
|
177
184
|
onboardingSkill: {
|
|
178
|
-
installed:
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
&& onboardingMarker?.packageVersion === manifest.packageVersion
|
|
182
|
-
),
|
|
183
|
-
version: state?.skills?.onboarding?.version ?? state?.packageVersion ?? manifest.packageVersion,
|
|
184
|
-
},
|
|
185
|
-
projectContext: {
|
|
186
|
-
installed: Boolean(
|
|
187
|
-
context?.schemaVersion === 'foggy-deepseek-harness-context/v1'
|
|
188
|
-
&& context?.packageVersion === manifest.packageVersion
|
|
189
|
-
&& context?.projectRoot === projectRoot
|
|
190
|
-
&& context?.installStatePath === statePath
|
|
191
|
-
),
|
|
192
|
-
version: context?.schemaVersion ?? 'foggy-deepseek-harness-context/v1',
|
|
185
|
+
installed: await exists(join(onboardingSkillPath, 'SKILL.md')),
|
|
186
|
+
version: manifest.packageVersion,
|
|
187
|
+
provider: 'foggy-managed-skills',
|
|
193
188
|
},
|
|
194
189
|
}
|
|
195
190
|
const installed = components.cli.installed
|
|
196
191
|
&& components.launcher.installed
|
|
197
192
|
&& components.analysisSkill.installed
|
|
198
193
|
&& components.onboardingSkill.installed
|
|
199
|
-
&& components.projectContext.installed
|
|
200
194
|
const running = Boolean(runtime && processRunning(Number(runtime.pid)))
|
|
201
195
|
const progress = await readOptionalJson(progressPath)
|
|
202
196
|
let operation = operationView(this.operation)
|
|
@@ -222,8 +216,6 @@ export class FoggyIntegrationGateway extends TypertRemoteService {
|
|
|
222
216
|
running,
|
|
223
217
|
runtimeUrl: running ? runtime.runtimeUrl ?? null : null,
|
|
224
218
|
roots,
|
|
225
|
-
projectRoot,
|
|
226
|
-
contextPath,
|
|
227
219
|
components,
|
|
228
220
|
operation,
|
|
229
221
|
next: installed ? (running ? 'configure-database' : 'start-runtime') : 'initialize',
|
|
@@ -236,13 +228,14 @@ export class FoggyIntegrationGateway extends TypertRemoteService {
|
|
|
236
228
|
return {
|
|
237
229
|
success: true,
|
|
238
230
|
roots,
|
|
239
|
-
|
|
231
|
+
workspaceMode: 'dsh-session-cwd',
|
|
240
232
|
versions: Object.fromEntries(Object.entries(manifest.components).map(([name, value]) => [name, value.version])),
|
|
241
233
|
operations: [
|
|
242
234
|
'create isolated Python environment',
|
|
243
235
|
'download and verify pinned CLI and Launcher assets',
|
|
244
|
-
'install Foggy analysis
|
|
245
|
-
'
|
|
236
|
+
'install the Foggy analysis Skill into the global managed component directory',
|
|
237
|
+
'register onboarding and analysis Skills through the native DSH Skill registry',
|
|
238
|
+
'write global install state; resolve each workspace from the DSH session cwd',
|
|
246
239
|
],
|
|
247
240
|
secretsInDshSettings: false,
|
|
248
241
|
}
|
|
@@ -269,7 +262,7 @@ export class FoggyIntegrationGateway extends TypertRemoteService {
|
|
|
269
262
|
return { success: false, accepted: false, operation: operationView(this.operation), error: 'another Foggy operation is running' }
|
|
270
263
|
}
|
|
271
264
|
const id = `${Date.now()}-${Math.random().toString(16).slice(2, 10)}`
|
|
272
|
-
const args = explicitArgs ?? ['install'
|
|
265
|
+
const args = explicitArgs ?? ['install']
|
|
273
266
|
if (!explicitArgs) {
|
|
274
267
|
const roots = defaultRoots()
|
|
275
268
|
args.push('--progress-file', join(roots.dataRoot, 'operation-progress.json'), '--operation-id', id, '--operation-kind', kind)
|
|
@@ -304,6 +297,7 @@ export class FoggyIntegrationGateway extends TypertRemoteService {
|
|
|
304
297
|
operation.state = result.success === false ? 'failed' : 'succeeded'
|
|
305
298
|
operation.result = result
|
|
306
299
|
operation.finishedAt = new Date().toISOString()
|
|
300
|
+
this.skillProviderControl?.invalidate()
|
|
307
301
|
if (operation.progress) {
|
|
308
302
|
operation.progress = {
|
|
309
303
|
...operation.progress,
|
|
@@ -318,6 +312,7 @@ export class FoggyIntegrationGateway extends TypertRemoteService {
|
|
|
318
312
|
operation.state = 'failed'
|
|
319
313
|
operation.error = String(error.message ?? error)
|
|
320
314
|
operation.finishedAt = new Date().toISOString()
|
|
315
|
+
this.skillProviderControl?.invalidate()
|
|
321
316
|
if (operation.progress) {
|
|
322
317
|
operation.progress = {
|
|
323
318
|
...operation.progress,
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { access, readFile } from 'node:fs/promises'
|
|
2
|
+
import { constants as fsConstants } from 'node:fs'
|
|
3
|
+
import { dirname, join } from 'node:path'
|
|
4
|
+
import { fileURLToPath } from 'node:url'
|
|
5
|
+
import { BUNDLED_SKILL_RANK } from '@deepseek-ai/dsh-skill'
|
|
6
|
+
|
|
7
|
+
const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)))
|
|
8
|
+
const onboardingRoot = join(packageRoot, 'skills', 'foggy-deepseek-onboarding')
|
|
9
|
+
const onboardingPath = join(onboardingRoot, 'SKILL.md')
|
|
10
|
+
const providerName = 'foggy-managed-skills'
|
|
11
|
+
const invocation = { modelInvocable: true, userInvocable: true }
|
|
12
|
+
|
|
13
|
+
async function exists(path) {
|
|
14
|
+
try {
|
|
15
|
+
await access(path, fsConstants.F_OK)
|
|
16
|
+
return true
|
|
17
|
+
} catch {
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function readOptionalJson(path) {
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(await readFile(path, 'utf8'))
|
|
25
|
+
} catch {
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function parseSkill(source, expectedName) {
|
|
31
|
+
const match = source.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/)
|
|
32
|
+
if (!match) throw new Error(`Foggy Skill ${expectedName} has no valid frontmatter`)
|
|
33
|
+
const metadata = Object.fromEntries(match[1].split(/\r?\n/).flatMap((line) => {
|
|
34
|
+
const separator = line.indexOf(':')
|
|
35
|
+
if (separator < 1) return []
|
|
36
|
+
return [[line.slice(0, separator).trim(), line.slice(separator + 1).trim().replace(/^(['\"])(.*)\1$/, '$2')]]
|
|
37
|
+
}))
|
|
38
|
+
if (metadata.name !== expectedName || !metadata.description) {
|
|
39
|
+
throw new Error(`Foggy Skill ${expectedName} has invalid name or description metadata`)
|
|
40
|
+
}
|
|
41
|
+
return { metadata, content: match[2] }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function candidate(name, description, path, source) {
|
|
45
|
+
const root = dirname(path)
|
|
46
|
+
return {
|
|
47
|
+
name,
|
|
48
|
+
description,
|
|
49
|
+
invocation,
|
|
50
|
+
provider: providerName,
|
|
51
|
+
source,
|
|
52
|
+
resourceBase: { kind: 'directory', path: root },
|
|
53
|
+
rank: BUNDLED_SKILL_RANK,
|
|
54
|
+
locator: { name, path },
|
|
55
|
+
path,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function managedAnalysisSkill(installRoot, manifest) {
|
|
60
|
+
const state = await readOptionalJson(join(installRoot, 'install-state.json'))
|
|
61
|
+
const path = state?.skills?.analysis?.path
|
|
62
|
+
if (!path || !await exists(join(path, 'SKILL.md'))) return null
|
|
63
|
+
const marker = await readOptionalJson(join(path, '.foggy-managed-skill.json'))
|
|
64
|
+
if (
|
|
65
|
+
marker?.schemaVersion !== 'foggy-managed-skill/v1'
|
|
66
|
+
|| marker?.kind !== 'analysis'
|
|
67
|
+
|| marker?.componentVersion !== manifest.components.analysisSkill.version
|
|
68
|
+
) return null
|
|
69
|
+
return join(path, 'SKILL.md')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function createFoggySkillProvider({ installRoot, versionsFile }) {
|
|
73
|
+
return {
|
|
74
|
+
name: providerName,
|
|
75
|
+
async list(options = {}) {
|
|
76
|
+
if (options.signal?.aborted) return []
|
|
77
|
+
const manifest = await readOptionalJson(versionsFile)
|
|
78
|
+
const onboarding = parseSkill(await readFile(onboardingPath, 'utf8'), 'foggy-deepseek-onboarding')
|
|
79
|
+
const result = [candidate(
|
|
80
|
+
'foggy-deepseek-onboarding',
|
|
81
|
+
onboarding.metadata.description,
|
|
82
|
+
onboardingPath,
|
|
83
|
+
'bundled',
|
|
84
|
+
)]
|
|
85
|
+
if (!manifest) return result
|
|
86
|
+
const analysisPath = await managedAnalysisSkill(installRoot, manifest)
|
|
87
|
+
if (analysisPath) {
|
|
88
|
+
const analysis = parseSkill(await readFile(analysisPath, 'utf8'), 'foggy-ai-analysis')
|
|
89
|
+
result.push(candidate('foggy-ai-analysis', analysis.metadata.description, analysisPath, 'bundled'))
|
|
90
|
+
}
|
|
91
|
+
return result
|
|
92
|
+
},
|
|
93
|
+
async get(selected, options = {}) {
|
|
94
|
+
if (options.signal?.aborted) return undefined
|
|
95
|
+
const locator = selected?.locator
|
|
96
|
+
if (!locator?.name || !locator?.path || !await exists(locator.path)) return undefined
|
|
97
|
+
const parsed = parseSkill(await readFile(locator.path, 'utf8'), locator.name)
|
|
98
|
+
return {
|
|
99
|
+
name: locator.name,
|
|
100
|
+
description: parsed.metadata.description,
|
|
101
|
+
invocation,
|
|
102
|
+
provider: providerName,
|
|
103
|
+
source: selected.source,
|
|
104
|
+
resourceBase: { kind: 'directory', path: dirname(locator.path) },
|
|
105
|
+
content: parsed.content,
|
|
106
|
+
path: locator.path,
|
|
107
|
+
metadata: parsed.metadata,
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foggy-projects/deepseek-harness-plugin",
|
|
3
|
-
"version": "0.4.0-beta.
|
|
3
|
+
"version": "0.4.0-beta.6",
|
|
4
4
|
"description": "Foggy Java data analysis engine integration for DeepSeek Harness",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -50,10 +50,11 @@
|
|
|
50
50
|
"@deepseek-ai/dsh-client-runtime": "^0.1.1-rc.2",
|
|
51
51
|
"@deepseek-ai/dsh-client-ui-settings": "^0.1.1-rc.2",
|
|
52
52
|
"@deepseek-ai/dsh-client-ui-settings-plugins": "^0.1.1-rc.2",
|
|
53
|
+
"@deepseek-ai/dsh-skill": "^0.1.1-rc.2",
|
|
53
54
|
"@deepseek-ai/dsh-typert-protocol": "^0.1.1-rc.2"
|
|
54
55
|
},
|
|
55
56
|
"scripts": {
|
|
56
|
-
"check": "node --check lib/index.js && node --check lib/client.js && node --check lib/typert.js && node --check lib/remote.js",
|
|
57
|
-
"test": "node --test test/package.test.js"
|
|
57
|
+
"check": "node --check lib/index.js && node --check lib/skill-provider.js && node --check lib/client.js && node --check lib/typert.js && node --check lib/remote.js",
|
|
58
|
+
"test": "node --test test/package.test.js && python test/onboarding_unit.py"
|
|
58
59
|
}
|
|
59
60
|
}
|
|
@@ -7,22 +7,29 @@ description: Install and operate a pinned Foggy CLI-first dev/test environment f
|
|
|
7
7
|
|
|
8
8
|
Set up Foggy through shell and `foggy-runtime` CLI. Do not configure Foggy MCP for this local workflow.
|
|
9
9
|
|
|
10
|
-
##
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
10
|
+
## Native registry and installed-state gate
|
|
11
|
+
|
|
12
|
+
This Skill is registered by the Foggy plugin through DeepSeek Harness's native Skill registry. Its
|
|
13
|
+
resource base is the authoritative location for these scripts and references; do not search for or
|
|
14
|
+
copy this Skill into the current workspace.
|
|
15
|
+
|
|
16
|
+
- Resolve the global install state from the platform default component directory: on Linux use
|
|
17
|
+
`${XDG_DATA_HOME:-$HOME/.local/share}/foggy/deepseek-harness/install-state.json`; on Windows use
|
|
18
|
+
`%LOCALAPPDATA%\Foggy\DeepSeekHarness\install-state.json`.
|
|
19
|
+
- Confirm the installation with this Skill's `doctor` wrapper and pass the current DSH session
|
|
20
|
+
workspace as `--project-root`. The absence of `foggy-runtime` from `PATH` is not evidence that the
|
|
21
|
+
managed CLI is missing; the plugin intentionally installs it in an isolated environment and records
|
|
22
|
+
its absolute command in the global install state.
|
|
23
|
+
- Do not independently download or reinstall the CLI. If the global install state, managed marker, or
|
|
24
|
+
analysis Skill is missing or invalid, ask the user to open the Foggy plugin settings and use
|
|
25
|
+
**Re-download / Repair**. Repair restores the global managed analysis Skill and invalidates the
|
|
26
|
+
native DSH Skill catalog. Reinstall or upgrade the plugin itself to restore this bundled Skill.
|
|
27
|
+
- Treat the current DSH session workspace as the authoritative `projectRoot` for the whole onboarding
|
|
28
|
+
run. Do not redirect semantic drafts or contracts to a different repository merely because another
|
|
29
|
+
Skill or example was found there. Place non-secret contracts below
|
|
30
|
+
`<projectRoot>/.foggy/onboarding-contracts/<profile>/`, drafts below
|
|
31
|
+
`<projectRoot>/.foggy/onboarding-drafts/<profile>/`, and published files below the approved
|
|
32
|
+
project-relative `modelsDir`.
|
|
26
33
|
|
|
27
34
|
## Mandatory orchestration boundary
|
|
28
35
|
|
|
@@ -45,6 +52,9 @@ For every new-database onboarding session, this Skill is the orchestration autho
|
|
|
45
52
|
- Never read query-execution evidence back into the conversation. Report only validation state,
|
|
46
53
|
execution state, row count, and evidence path; do not report row values or generated SQL containing
|
|
47
54
|
business literals.
|
|
55
|
+
- Prefer one composite command per approval boundary. Do not inspect this Skill's Python implementation
|
|
56
|
+
or the CLI package source during a normal run; use the documented command contract and inspect code
|
|
57
|
+
only after a structured wrapper error requires troubleshooting.
|
|
48
58
|
|
|
49
59
|
## Boundaries
|
|
50
60
|
|
|
@@ -59,20 +69,22 @@ For every new-database onboarding session, this Skill is the orchestration autho
|
|
|
59
69
|
|
|
60
70
|
## Workflow
|
|
61
71
|
|
|
62
|
-
1.
|
|
63
|
-
`bash scripts/doctor.sh --project-root <
|
|
64
|
-
2. If the pinned CLI, Launcher,
|
|
72
|
+
1. Run `scripts/doctor.ps1 --project-root <current-session-workspace>` on Windows or
|
|
73
|
+
`bash scripts/doctor.sh --project-root <current-session-workspace>` on Linux.
|
|
74
|
+
2. If the pinned CLI, Launcher, or global managed analysis Skill is missing, use the Foggy
|
|
65
75
|
plugin's Repair action. Use the matching install script only when the plugin UI is unavailable;
|
|
66
76
|
use `--dry-run` first when paths or permissions are uncertain.
|
|
67
77
|
3. Run `runtime-start` and require successful `wait-ready` plus `capabilities`. Record engine,
|
|
68
78
|
Runtime API version, schema version, security mode, URL, namespace, PID, and evidence path.
|
|
69
|
-
4.
|
|
79
|
+
4. Load `foggy-ai-analysis` from the native DSH Skill registry. Do not require a workspace copy.
|
|
70
80
|
5. For a new business database, read [references/onboarding-workflow.md](references/onboarding-workflow.md)
|
|
71
81
|
and prefer its two composite `onboard-datasource-run` / `onboard-semantic-run` commands. Require the
|
|
72
|
-
trusted operator to create the private CLI profile outside Harness.
|
|
82
|
+
trusted operator to create the private CLI profile outside Harness. Unless the operator explicitly
|
|
83
|
+
overrides it, use the persistent profile store reported by the wrapper under the Foggy data root
|
|
84
|
+
(`<dataRoot>/cli-profiles`), never `/tmp`. Accept only the opaque profile
|
|
73
85
|
ID, exact revision, datasource name/type, and namespace; never request JDBC URL, username,
|
|
74
86
|
password, or password environment-variable name in Harness.
|
|
75
|
-
6. After schema discovery, use `foggy-ai-analysis` only to author TM/QM files in
|
|
87
|
+
6. After schema discovery, use `foggy-ai-analysis` only to author TM/QM files in the standard project-local
|
|
76
88
|
draft directory. Register, validate, publish, and verify them through this Skill's wrapper using the deterministic commands in
|
|
77
89
|
[references/onboarding-workflow.md](references/onboarding-workflow.md). Do not publish, prune, replace
|
|
78
90
|
a bundle, or execute a business-data query without the matching explicit flag and user approval.
|
|
@@ -97,5 +109,10 @@ In DeepSeek Harness, do not expand the composite onboarding commands back into t
|
|
|
97
109
|
operations. This order documents what the wrapper enforces internally and becomes a direct CLI workflow
|
|
98
110
|
only after onboarding is complete.
|
|
99
111
|
|
|
112
|
+
Composite commands are checkpointed and idempotent: a retry skips completed datasource, validation,
|
|
113
|
+
publication, and verification phases when the approved contract and draft digest are unchanged. Fix a
|
|
114
|
+
query payload in place and rerun the same semantic composite command; do not remove a successfully
|
|
115
|
+
published bundle merely to recover from a later query-validation failure.
|
|
116
|
+
|
|
100
117
|
Keep user business data separate from the sales-drop SQLite demo. Prefer a read-only database account,
|
|
101
118
|
opaque CLI profile references, and bounded query limits.
|
|
@@ -23,6 +23,16 @@ to paste a password and do not put a JDBC URL, username, password environment-va
|
|
|
23
23
|
line, logs, or evidence. For non-SQLite databases, ask the user to set the named environment variable
|
|
24
24
|
before Runtime starts so the Java process inherits it. Recommend a read-only database account.
|
|
25
25
|
|
|
26
|
+
Use the current DSH session workspace as `projectRoot`. Store approved non-secret contracts at
|
|
27
|
+
`.foggy/onboarding-contracts/<profile>/`, semantic drafts at `.foggy/onboarding-drafts/<profile>/`, and
|
|
28
|
+
command evidence at `.foggy/onboarding-command-evidence/<profile>/`. Do not split these files across the
|
|
29
|
+
session workspace and a separate example repository. The wrapper rejects a query payload outside the
|
|
30
|
+
recorded project root before any semantic validation or publication mutation occurs.
|
|
31
|
+
|
|
32
|
+
The wrapper defaults `FOGGY_RUNTIME_PROFILE_STORE` to the private persistent directory
|
|
33
|
+
`<dataRoot>/cli-profiles`. An explicit operator-provided value still wins. Do not use `/tmp` for a profile
|
|
34
|
+
that must survive a WSL or Harness restart.
|
|
35
|
+
|
|
26
36
|
Treat every user-supplied identifier and bound as immutable input: profile, datasource, namespace,
|
|
27
37
|
models directory, bundle name, TM/QM name, query fields, and limit. Do not swap in demo names, add
|
|
28
38
|
fields, raise the limit, or introduce replacement flags. If one of these inputs is missing, pause for
|
|
@@ -53,6 +63,13 @@ onboard-semantic-run --semantic-plan <approved-json> --query-payload <approved-j
|
|
|
53
63
|
Include an approval flag only after the user approves that exact action. Without it, the composite
|
|
54
64
|
command stops after the corresponding dry-run and returns `phaseStatus=awaiting-...-approval`.
|
|
55
65
|
|
|
66
|
+
Both composite commands are resumable. When the approved contract is unchanged, they skip completed
|
|
67
|
+
checkpoints instead of re-adding an existing datasource, revalidating an already published draft, or
|
|
68
|
+
registering the same bundle twice. If query validation fails after publication, correct the project-local
|
|
69
|
+
payload and rerun `onboard-semantic-run`; it resumes at query verification and leaves the active bundle in
|
|
70
|
+
place. A same-name datasource is accepted idempotently only when its public name and database type match
|
|
71
|
+
the approved plan; otherwise replacement still requires explicit approval.
|
|
72
|
+
|
|
56
73
|
The granular commands below remain available for manual troubleshooting and resumption. Do not expand
|
|
57
74
|
the composite commands into this list during a normal Harness turn.
|
|
58
75
|
|
|
@@ -111,6 +128,11 @@ requires an integer `limit` from 1 through 100. The first `semantic-verify` call
|
|
|
111
128
|
validates the query; only `--execute` reads business data. Full results stay in evidence and the command
|
|
112
129
|
returns only counts and paths.
|
|
113
130
|
|
|
131
|
+
Before the first semantic mutation, the composite command checks that the query payload is inside
|
|
132
|
+
`projectRoot`, has a bounded limit, and targets a query model declared in the approved semantic plan.
|
|
133
|
+
After publication, `semantic-verify` always describes the live model before validation. If a field is
|
|
134
|
+
rejected, update the payload from those described names and rerun the same composite command.
|
|
135
|
+
|
|
114
136
|
Do not open, summarize, or quote `query-execute.json` or the Runtime's generated SQL after execution.
|
|
115
137
|
The conversational result may contain only `queryValidated`, `queryExecuted`, `rowCount`, the model
|
|
116
138
|
name, and the evidence path. A successful direct CLI command is not proof that onboarding completed;
|