@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 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.4.tgz
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, `FOGGY_PROJECT_ROOT` can override the workspace that receives
24
- the Skills and `FOGGY_ASSET_CACHE_DIRS` can contain platform-delimited verified
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 are deliberately outside the ordinary DSH settings
28
- document. The database and semantic-layer wizard is the next Bundle milestone.
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
- ## Managed workspace contract
30
+ ## Native Skill and workspace contract
31
31
 
32
- Initialization writes a non-secret discovery document at
33
- `.foggy/deepseek-harness/context.json` in the selected project. It points agents
34
- to the authoritative global install state, the managed CLI's absolute command,
35
- the Runtime state, and the two workspace Skills. The managed CLI is intentionally
36
- isolated and does not need to be on `PATH`.
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
- Both `foggy-deepseek-onboarding` and `foggy-ai-analysis` carry a
39
- `.foggy-managed-skill.json` marker. **Re-download / Repair** verifies their
40
- managed content, backs up a modified or outdated Skill under
41
- `.foggy/onboarding-backups`, restores missing content, and regenerates the
42
- project context. If a Skill is restored while Harness is already running, start
43
- a new task or restart Harness so its Skill registry can reload it.
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
- projectContext: '项目安装上下文',
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: '安装工作区 Skills',
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: '对话会从项目内固定的 context.json 读取 CLI、Runtime 与 Skill 安装状态,不再依赖 PATH 猜测。Runtime 启动成功后,将继续进入数据库连接与语义层向导。',
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
- projectContext: 'Project install context',
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: 'Installing workspace Skills',
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: 'Conversations discover the installed CLI, Runtime, and Skills from the fixed project context.json instead of guessing from PATH. After Runtime starts, the database connection and semantic-layer wizard comes next.',
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('projectContext'), status.components.projectContext, 'runtime', 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('projectRoot') }), jsx('dd', { children: status.projectRoot }),
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: process.env.XDG_STATE_HOME
31
- ? join(process.env.XDG_STATE_HOME, 'foggy', 'deepseek-harness')
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(projectRoot, '.agents', 'skills', 'foggy-ai-analysis')
155
- const onboardingSkillPath = state?.skills?.onboarding?.path || join(projectRoot, '.agents', 'skills', 'foggy-deepseek-onboarding')
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: Boolean(
179
- await exists(join(onboardingSkillPath, 'SKILL.md'))
180
- && onboardingMarker?.schemaVersion === 'foggy-managed-skill/v1'
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
- projectRoot: process.env.FOGGY_PROJECT_ROOT || process.cwd(),
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 and onboarding Skills into the workspace',
245
- 'write global install state and project-relative discovery context',
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', '--project-root', process.env.FOGGY_PROJECT_ROOT || process.cwd()]
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.4",
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
- ## Installed-context gate
11
-
12
- Before deciding that Foggy, its CLI, or either Skill is missing, look for the project-relative file
13
- `.foggy/deepseek-harness/context.json` from the current workspace root:
14
-
15
- - Treat a valid `foggy-deepseek-harness-context/v1` document as the discovery pointer to the global
16
- install state, absolute managed CLI command, Runtime state, and both installed Skills.
17
- - Confirm the installation with this Skill's `doctor` wrapper. The absence of `foggy-runtime` from
18
- `PATH` is not evidence that the managed CLI is missing; the plugin intentionally installs it in an
19
- isolated environment and records its absolute command in the context and install-state files.
20
- - Do not independently download or reinstall the CLI when valid project context exists. If the
21
- context, a managed marker, or a Skill is missing or invalid, ask the user to open the Foggy plugin
22
- settings and use **Re-download / Repair**. That operation regenerates context and restores managed
23
- Skills, preserving a backup of modified or outdated Skill directories.
24
- - If the plugin reports ready but this Skill was restored during the current Harness task, tell the
25
- user that a new task or Harness restart may be needed for the Skill registry to reload.
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. Read `.foggy/deepseek-harness/context.json`, then run `scripts/doctor.ps1 --project-root <root>` on Windows or
63
- `bash scripts/doctor.sh --project-root <root>` on Linux.
64
- 2. If the pinned CLI, Launcher, project context, or either managed Skill is missing, use the Foggy
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. Confirm the project contains `.agents/skills/foggy-ai-analysis/SKILL.md`.
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. Accept only the opaque profile
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 a separate project-local
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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": "foggy-deepseek-onboarding-versions/v1",
3
- "packageVersion": "0.4.0-beta.4",
4
- "validatedAt": "2026-08-28",
3
+ "packageVersion": "0.4.0-beta.6",
4
+ "validatedAt": "2026-09-01",
5
5
  "components": {
6
6
  "deepseekHarness": {
7
7
  "version": "0.1.1-rc.2",
@@ -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;