@foggy-projects/deepseek-harness-plugin 0.4.0-beta.13 → 0.4.0-beta.15

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/lib/index.js CHANGED
@@ -10,6 +10,11 @@ import { writeJsonAtomic } from './atomic-json.js'
10
10
  import { ensurePythonRuntime, probePythonRuntime } from './python-runtime.js'
11
11
  import { compatible, compatibleNode } from './version.js'
12
12
  import { enrichRuntimeStartFailure } from './diagnostics.js'
13
+ import {
14
+ DEFAULT_RUNTIME_PORT,
15
+ readRuntimeSettings,
16
+ writeRuntimeSettings,
17
+ } from './runtime-settings.js'
13
18
 
14
19
  const execFileAsync = promisify(execFile)
15
20
  const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)))
@@ -197,13 +202,19 @@ export class FoggyIntegrationGateway extends TypertRemoteService {
197
202
  const statePath = join(roots.installRoot, 'install-state.json')
198
203
  const runtimeStatePath = join(roots.dataRoot, 'runtime-state.json')
199
204
  const progressPath = join(roots.dataRoot, 'operation-progress.json')
205
+ const portConflictPath = join(roots.dataRoot, 'last-runtime-port-conflict.json')
200
206
  const manifest = await readJson(versionsFile)
207
+ const runtimeSettings = await readRuntimeSettings(roots.dataRoot, {
208
+ defaultPort: manifest.defaults?.port ?? DEFAULT_RUNTIME_PORT,
209
+ })
201
210
  const python = await probePythonRuntime({ installRoot: roots.installRoot, manifest })
202
211
  const java = compatible(await commandVersion(process.env.JAVA_EXE || 'java', ['-version']), '17.0')
203
212
  let state = null
204
213
  let runtime = null
214
+ let lastRuntimePortConflict = null
205
215
  try { state = await readJson(statePath) } catch {}
206
216
  try { runtime = await readJson(runtimeStatePath) } catch {}
217
+ try { lastRuntimePortConflict = await readJson(portConflictPath) } catch {}
207
218
  let onboarding = { success: true, profiles: [], profileCount: 0 }
208
219
  let profileMigration = { success: true, entries: [], pendingCount: 0, conflictCount: 0, profileStore: roots.profileStore }
209
220
  if (state) {
@@ -250,6 +261,7 @@ export class FoggyIntegrationGateway extends TypertRemoteService {
250
261
  && components.analysisSkill.installed
251
262
  && components.onboardingSkill.installed
252
263
  const running = Boolean(runtime && processRunning(Number(runtime.pid)))
264
+ const activePort = running && Number.isInteger(Number(runtime?.port)) ? Number(runtime.port) : null
253
265
  const progress = await readOptionalJson(progressPath)
254
266
  let operation = operationView(this.operation)
255
267
  if (operation.state === 'running' && progress?.operationId === operation.id) {
@@ -273,6 +285,14 @@ export class FoggyIntegrationGateway extends TypertRemoteService {
273
285
  installed,
274
286
  running,
275
287
  runtimeUrl: running ? runtime.runtimeUrl ?? null : null,
288
+ runtimeSettings: {
289
+ ...runtimeSettings,
290
+ activePort,
291
+ activeRuntimeUrl: running ? runtime.runtimeUrl ?? null : null,
292
+ pendingRestart: Boolean(running && activePort && activePort !== runtimeSettings.port),
293
+ lastConflict: lastRuntimePortConflict,
294
+ conflictApplies: Number(lastRuntimePortConflict?.port) === runtimeSettings.port,
295
+ },
276
296
  roots,
277
297
  components,
278
298
  operation,
@@ -355,6 +375,7 @@ export class FoggyIntegrationGateway extends TypertRemoteService {
355
375
  components: status.components,
356
376
  onboarding: status.onboarding,
357
377
  profileMigration: status.profileMigration,
378
+ runtimeSettings: status.runtimeSettings,
358
379
  lastRuntimeStartFailure,
359
380
  doctor,
360
381
  }
@@ -367,8 +388,23 @@ export class FoggyIntegrationGateway extends TypertRemoteService {
367
388
 
368
389
  async runtimeStart() {
369
390
  const roots = defaultRoots()
391
+ const manifest = await readJson(versionsFile)
392
+ const settings = await readRuntimeSettings(roots.dataRoot, {
393
+ defaultPort: manifest.defaults?.port ?? DEFAULT_RUNTIME_PORT,
394
+ })
395
+ if (!settings.valid) {
396
+ return {
397
+ success: false,
398
+ accepted: false,
399
+ error: {
400
+ code: 'RUNTIME_SETTINGS_INVALID',
401
+ message: `Runtime settings are invalid: ${settings.error}. Save a valid port in Foggy plugin settings.`,
402
+ },
403
+ }
404
+ }
370
405
  return this.startOperation('runtime-start', false, [
371
406
  'runtime-start', '--install-root', roots.installRoot, '--data-root', roots.dataRoot,
407
+ '--port', String(settings.port),
372
408
  ])
373
409
  }
374
410
 
@@ -379,6 +415,35 @@ export class FoggyIntegrationGateway extends TypertRemoteService {
379
415
  ])
380
416
  }
381
417
 
418
+ async saveRuntimeSettings(input) {
419
+ const roots = defaultRoots()
420
+ if (this.operation?.state === 'running') {
421
+ return {
422
+ success: false,
423
+ error: { code: 'OPERATION_RUNNING', message: 'Wait for the current Foggy operation to finish before changing the Runtime port.' },
424
+ }
425
+ }
426
+ const runtime = await readOptionalJson(join(roots.dataRoot, 'runtime-state.json'))
427
+ if (runtime && processRunning(Number(runtime.pid))) {
428
+ return {
429
+ success: false,
430
+ error: { code: 'RUNTIME_RUNNING', message: 'Stop Foggy Runtime before changing its port.' },
431
+ }
432
+ }
433
+ try {
434
+ const settings = await writeRuntimeSettings(roots.dataRoot, input)
435
+ if (this.operation?.state === 'failed' && this.operation.result?.error?.code === 'RUNTIME_PORT_UNAVAILABLE') {
436
+ this.operation = null
437
+ }
438
+ return { success: true, settings }
439
+ } catch (error) {
440
+ return {
441
+ success: false,
442
+ error: { code: 'RUNTIME_PORT_INVALID', message: String(error?.message ?? error) },
443
+ }
444
+ }
445
+ }
446
+
382
447
  startOperation(kind, replaceSkill, explicitArgs) {
383
448
  if (this.operation?.state === 'running') {
384
449
  return { success: false, accepted: false, operation: operationView(this.operation), error: 'another Foggy operation is running' }
@@ -467,6 +532,7 @@ const markerInitializers = []
467
532
  for (const method of [
468
533
  'status', 'plan', 'initialize', 'repair', 'repairPython', 'repairCli', 'repairLauncher', 'repairAnalysisSkill',
469
534
  'migrateProfiles', 'diagnostics', 'runtimeStart', 'runtimeStop',
535
+ 'saveRuntimeSettings',
470
536
  ]) {
471
537
  Remote(method)(FoggyIntegrationGateway.prototype[method], {
472
538
  kind: 'method',
@@ -1,15 +1,18 @@
1
1
  import { z } from 'zod'
2
2
 
3
3
  const resultSchema = z.unknown()
4
+ const runtimeSettingsInputSchema = z.object({
5
+ port: z.number().int().min(1024).max(65535),
6
+ }).strict()
4
7
 
5
- function descriptor(method) {
8
+ function descriptor(method, parameters = []) {
6
9
  return {
7
10
  id: `@foggy-projects/deepseek-harness-plugin#foggyIntegration/${method}`,
8
11
  service: 'foggyIntegration',
9
12
  namespace: 'foggyIntegration',
10
13
  method,
11
14
  invocation: { kind: 'direct' },
12
- parameters: [],
15
+ parameters,
13
16
  result: {
14
17
  mode: 'strict',
15
18
  typeSymbol: '@foggy-projects/deepseek-harness-plugin#FoggyIntegrationResult',
@@ -27,4 +30,14 @@ export const descriptors = [
27
30
  descriptor('repairPython'),
28
31
  descriptor('runtimeStart'),
29
32
  descriptor('runtimeStop'),
33
+ descriptor('saveRuntimeSettings', [{
34
+ name: 'input',
35
+ wire: 'input',
36
+ source: 'json',
37
+ codec: {
38
+ mode: 'strict',
39
+ typeSymbol: '@foggy-projects/deepseek-harness-plugin#FoggyRuntimeSettingsInput',
40
+ schema: runtimeSettingsInputSchema,
41
+ },
42
+ }]),
30
43
  ]
@@ -0,0 +1,89 @@
1
+ import { readFile } from 'node:fs/promises'
2
+ import { join } from 'node:path'
3
+ import { writeJsonAtomic } from './atomic-json.js'
4
+
5
+ export const RUNTIME_SETTINGS_SCHEMA = 'foggy-deepseek-runtime-settings/v1'
6
+ export const DEFAULT_RUNTIME_PORT = 18166
7
+ export const MIN_RUNTIME_PORT = 1024
8
+ export const MAX_RUNTIME_PORT = 65535
9
+
10
+ export function normalizeRuntimePort(value) {
11
+ const port = typeof value === 'string' && value.trim() !== '' ? Number(value) : value
12
+ if (!Number.isInteger(port) || port < MIN_RUNTIME_PORT || port > MAX_RUNTIME_PORT) {
13
+ throw new Error(`Runtime port must be an integer between ${MIN_RUNTIME_PORT} and ${MAX_RUNTIME_PORT}`)
14
+ }
15
+ return port
16
+ }
17
+
18
+ export function runtimeUrlForPort(port) {
19
+ return `http://127.0.0.1:${normalizeRuntimePort(port)}`
20
+ }
21
+
22
+ export function runtimeSettingsPath(dataRoot) {
23
+ return join(dataRoot, 'runtime-settings.json')
24
+ }
25
+
26
+ export async function readRuntimeSettings(dataRoot, { defaultPort = DEFAULT_RUNTIME_PORT } = {}) {
27
+ const path = runtimeSettingsPath(dataRoot)
28
+ const fallbackPort = normalizeRuntimePort(defaultPort)
29
+ try {
30
+ const payload = JSON.parse(await readFile(path, 'utf8'))
31
+ if (payload?.schemaVersion !== RUNTIME_SETTINGS_SCHEMA) {
32
+ throw new Error(`expected schemaVersion ${RUNTIME_SETTINGS_SCHEMA}`)
33
+ }
34
+ const port = normalizeRuntimePort(payload.runtimePort)
35
+ return {
36
+ valid: true,
37
+ source: 'configured',
38
+ schemaVersion: RUNTIME_SETTINGS_SCHEMA,
39
+ port,
40
+ runtimeUrl: runtimeUrlForPort(port),
41
+ updatedAt: payload.updatedAt ?? null,
42
+ path,
43
+ error: null,
44
+ }
45
+ } catch (error) {
46
+ if (error?.code === 'ENOENT') {
47
+ return {
48
+ valid: true,
49
+ source: 'default',
50
+ schemaVersion: RUNTIME_SETTINGS_SCHEMA,
51
+ port: fallbackPort,
52
+ runtimeUrl: runtimeUrlForPort(fallbackPort),
53
+ updatedAt: null,
54
+ path,
55
+ error: null,
56
+ }
57
+ }
58
+ return {
59
+ valid: false,
60
+ source: 'invalid',
61
+ schemaVersion: RUNTIME_SETTINGS_SCHEMA,
62
+ port: fallbackPort,
63
+ runtimeUrl: runtimeUrlForPort(fallbackPort),
64
+ updatedAt: null,
65
+ path,
66
+ error: String(error?.message ?? error),
67
+ }
68
+ }
69
+ }
70
+
71
+ export async function writeRuntimeSettings(dataRoot, input) {
72
+ const runtimePort = normalizeRuntimePort(input?.port)
73
+ const payload = {
74
+ schemaVersion: RUNTIME_SETTINGS_SCHEMA,
75
+ runtimePort,
76
+ updatedAt: new Date().toISOString(),
77
+ }
78
+ const path = runtimeSettingsPath(dataRoot)
79
+ await writeJsonAtomic(path, payload)
80
+ return {
81
+ valid: true,
82
+ source: 'configured',
83
+ ...payload,
84
+ port: runtimePort,
85
+ runtimeUrl: runtimeUrlForPort(runtimePort),
86
+ path,
87
+ error: null,
88
+ }
89
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foggy-projects/deepseek-harness-plugin",
3
- "version": "0.4.0-beta.13",
3
+ "version": "0.4.0-beta.15",
4
4
  "description": "Foggy Java data analysis engine integration for DeepSeek Harness",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -57,7 +57,7 @@
57
57
  "@deepseek-ai/dsh-typert-protocol": "^0.1.2-rc.1"
58
58
  },
59
59
  "scripts": {
60
- "check": "node --check lib/index.js && node --check lib/atomic-json.js && node --check lib/diagnostics.js && node --check lib/python-runtime.js && node --check lib/skill-provider.js && node --check lib/client.js && node --check lib/typert.js && node --check lib/remote.js",
60
+ "check": "node --check lib/index.js && node --check lib/atomic-json.js && node --check lib/diagnostics.js && node --check lib/python-runtime.js && node --check lib/runtime-settings.js && node --check lib/skill-provider.js && node --check lib/client.js && node --check lib/typert.js && node --check lib/remote.js",
61
61
  "test": "node --test test/package.test.js && node test/run-onboarding-tests.js"
62
62
  }
63
63
  }
@@ -1,137 +1,116 @@
1
1
  ---
2
2
  name: foggy-deepseek-onboarding
3
- description: Install and operate a pinned Foggy CLI-first dev/test environment from DeepSeek Harness, including opaque datasource profiles, resumable verification, and schema discovery before semantic authoring. Use for initial Foggy setup or local Runtime onboarding; do not use for production deployment or MCP configuration.
3
+ description: Set up and use Foggy Runtime for data-source exploration and semantic-model development inside DeepSeek Harness. Use for local experience, datasource onboarding, TM/QM authoring, validation, and development publication; route production deployment or updates to a separate release workflow.
4
4
  ---
5
5
 
6
6
  # Foggy DeepSeek onboarding
7
7
 
8
- Set up Foggy through shell and `foggy-runtime` CLI. Do not configure Foggy MCP for this local workflow.
9
-
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
- - The plugin downloads and verifies a pinned private Python runtime before running this Skill. Do not
24
- search for, install, or repair a system Python. Wrappers resolve the interpreter recorded in the
25
- global install state. If private Python is missing, use the plugin's Python repair action. Only use
26
- `FOGGY_PYTHON` or `FOGGY_ONBOARDING_PYTHON` when the user explicitly supplied an advanced override.
27
- - Do not independently download or reinstall the CLI. If the global install state, managed marker, or
28
- analysis Skill is missing or invalid, ask the user to open the Foggy plugin settings and use
29
- the matching component repair action. Repair restores managed components and invalidates the
30
- native DSH Skill catalog. Reinstall or upgrade the plugin itself to restore this bundled Skill.
31
- - Treat the current DSH session workspace as the authoritative `projectRoot` for the whole onboarding
32
- run. Do not redirect semantic drafts or contracts to a different repository merely because another
33
- Skill or example was found there. Place non-secret contracts below
34
- `<projectRoot>/.foggy/onboarding-contracts/<profile>/`, drafts below
35
- `<projectRoot>/.foggy/onboarding-drafts/<profile>/`, and published files below the approved
36
- project-relative `modelsDir`.
37
-
38
- ## Mandatory orchestration boundary
39
-
40
- For every new-database onboarding session, this Skill is the orchestration authority until
41
- `onboard-status` reports `next.status=completed`:
42
-
43
- - Invoke datasource, schema, semantic, bundle, and query operations only through this Skill's
44
- `scripts/onboard.ps1` or `scripts/onboard.sh`. Do not call `foggy-runtime` directly for those
45
- operations, even if another loaded Skill documents equivalent CLI commands.
46
- - Use `foggy-ai-analysis` only to author TM/QM draft content. Its general direct-CLI workflow does not
47
- supersede this Skill's state machine, approval gates, names, paths, query limit, or evidence rules.
48
- - Use the exact profile, datasource, namespace, bundle, model names, paths, fields, and query limit
49
- supplied or confirmed by the user. Do not replace them with examples or inferred alternatives.
50
- - Do not use raw SQL to sample business rows during onboarding. `schema-discover` is the metadata gate;
51
- any later SQL probe requires separate explicit approval and must be bounded and read-only.
52
- - Never use `--replace`, `--replace-bundle`, `--prune`, `--watch`, or `--execute` unless that exact
53
- mutation was explicitly approved. Approval for adding a new resource is not approval to replace one.
54
- - Save each wrapper result as the single JSON object returned on stdout when the user requests evidence.
55
- Do not claim completion when required evidence is missing or the persisted status is incomplete.
56
- - Never read query-execution evidence back into the conversation. Report only validation state,
57
- execution state, row count, and evidence path; do not report row values or generated SQL containing
58
- business literals.
59
- - Prefer one composite command per approval boundary. Do not inspect this Skill's Python implementation
60
- or the CLI package source during a normal run; use the documented command contract and inspect code
61
- only after a structured wrapper error requires troubleshooting.
62
-
63
- ## Boundaries
64
-
65
- - Treat the bundled Launcher as local dev/test only. Its expected security mode is
66
- `none-dev-test-only`; never expose it to a network.
67
- - Do not print, persist, or request secrets in chat. Use named environment variables or a private env
68
- file outside the Skill and evidence directories.
69
- - Do not modify Foggy engine or CLI source. If setup cannot continue without such a change, stop and
70
- ask the user for explicit authorization.
71
- - Before downloads, installs, replacement, Runtime start/stop, or removal, state the concrete action
72
- and obtain any authorization required by the host.
73
-
74
- ## Workflow
75
-
76
- 1. Run `scripts/doctor.ps1 --project-root <current-session-workspace>` on Windows or
77
- `bash scripts/doctor.sh --project-root <current-session-workspace>` on Linux.
78
- 2. If private Python, the pinned CLI, Launcher, or global managed analysis Skill is missing, use the
79
- Foggy plugin's matching Repair action. First-time Python bootstrap requires the plugin UI unless
80
- the user explicitly supplies `FOGGY_ONBOARDING_PYTHON`. Use a matching install script only after
81
- private Python exists and the plugin UI is unavailable; use `--dry-run` first when paths or
82
- permissions are uncertain.
83
- 3. Run `runtime-start` and require successful `wait-ready` plus `capabilities`. Record engine,
84
- Runtime API version, schema version, security mode, URL, namespace, PID, and evidence path. If the
85
- recorded Runtime is already running, `runtime-start` verifies and reuses it instead of starting a
86
- second process.
87
- 4. Load `foggy-ai-analysis` from the native DSH Skill registry. Do not require a workspace copy.
88
- 5. For a new business database, read [references/onboarding-workflow.md](references/onboarding-workflow.md)
89
- and prefer its two composite `onboard-datasource-run` / `onboard-semantic-run` commands. Require the
90
- trusted operator to create the private CLI profile outside Harness. Unless the operator explicitly
91
- overrides it, use the persistent profile store reported by the wrapper under the Foggy data root
92
- (`<dataRoot>/cli-profiles`), never `/tmp`. Accept only the opaque profile
93
- ID, exact revision, datasource name/type, and namespace; never request JDBC URL, username,
94
- password, or password environment-variable name in Harness.
95
- If plugin settings report a legacy temporary profile, use the explicit migration action before
96
- onboarding. It moves only validated connection metadata and environment-variable references; it
97
- never copies a password value and leaves a recoverable private backup below the Foggy data root.
98
- 6. After schema discovery, use `foggy-ai-analysis` only to author TM/QM files in the standard project-local
99
- draft directory. Register, validate, publish, and verify them through this Skill's wrapper using the deterministic commands in
100
- [references/onboarding-workflow.md](references/onboarding-workflow.md). Do not publish, prune, replace
101
- a bundle, or execute a business-data query without the matching explicit flag and user approval.
102
- 7. Stop only the Runtime PID recorded by this package. Preserve Runtime data unless the user explicitly
103
- requests purge.
104
-
105
- ## Command contract
106
-
107
- All package scripts return one JSON object on stdout. Treat `success=false` or a nonzero exit code as a
108
- failure. Do not infer readiness from a fixed sleep; require CLI `wait-ready` and `capabilities`.
109
-
110
- Use this analysis order after setup:
8
+ Use this Skill for the normal DeepSeek Harness experience: connect a development datasource, inspect
9
+ it, create TM/QM files in the current workspace, and iterate until queries pass. Use the managed
10
+ `foggy-runtime` CLI and this Skill's wrappers; do not configure Foggy MCP for this local workflow.
11
+
12
+ ## Product boundary
13
+
14
+ - Treat the plugin and bundled Launcher as local experience and development tooling.
15
+ - Datasources, namespace bindings, model Bundles, refreshes, and query checks are online Runtime
16
+ operations. They do not require a Runtime restart.
17
+ - Start Runtime only when it is absent. Reuse a healthy running Runtime. Restart only when the user
18
+ asks, a Launcher/JAR upgrade requires it, Runtime is unhealthy, or an actual startup setting such as
19
+ port, JVM options, Runtime authentication, or an opt-in module changes.
20
+ - Do not turn production publication into a continuation of local onboarding. When the user wants to
21
+ deploy or update a formal environment, recommend a manual release or a dedicated production
22
+ deployment workflow with separately supplied target access, credentials, version, verification, and
23
+ rollback information.
24
+ - Do not modify Foggy engine or CLI source. If progress genuinely requires either change, stop and ask
25
+ for explicit authorization.
26
+
27
+ ## Managed installation
28
+
29
+ This Skill is registered through DeepSeek Harness's native Skill registry. Its scripts and references
30
+ are authoritative; do not copy the Skill into the current workspace.
31
+
32
+ - Linux install state: `${XDG_DATA_HOME:-$HOME/.local/share}/foggy/deepseek-harness/install-state.json`.
33
+ - Windows install state: `%LOCALAPPDATA%\Foggy\DeepSeekHarness\install-state.json`.
34
+ - Run this Skill's `doctor` wrapper with the current DSH workspace as `--project-root`. The managed CLI
35
+ is intentionally isolated, so absence from `PATH` does not mean it is missing.
36
+ - Use plugin settings to initialize or repair private Python, CLI, Launcher, or the managed analysis
37
+ Skill. Do not independently reinstall them during a normal analysis session.
38
+ - Treat the current DSH workspace as `projectRoot`. Keep model drafts and final model files there rather
39
+ than redirecting them to an example repository.
40
+
41
+ ## Development workflow
42
+
43
+ 1. Run `doctor`. Start Runtime only if it is not already healthy; require `wait-ready` and
44
+ `capabilities` after a new start.
45
+ 2. Accept datasource connection details from the user's message, a user-supplied local JSON file, an
46
+ environment variable, or Runtime Console. Direct `password` is supported for local development.
47
+ The wrapper submits it to the public Runtime API without copying it into onboarding state or
48
+ evidence. Do not echo it in the response.
49
+ 3. Create or select the namespace, add/test the datasource online, and bind it to the namespace. Do
50
+ not stop or restart Runtime to make a password available. A running Runtime can accept a direct
51
+ development password through its datasource API.
52
+ 4. Inspect tables, columns, keys, and relationships. Small, bounded, read-only SQL samples are allowed
53
+ when they help infer captions, enums, units, or date semantics. Do not run mutations unless the user
54
+ explicitly requests them.
55
+ 5. Load `foggy-ai-analysis` from the native registry only for TM/QM authoring and query tuning; its
56
+ generic installation, datasource-secret, and production-deployment guidance does not override this
57
+ development workflow. Default to a project-local `models/` directory unless the user specifies
58
+ another directory.
59
+ 6. Iterate through model validation, Bundle registration/update, model refresh/describe, query
60
+ validation, and bounded query execution. Development publication means making the local model
61
+ directory effective in this local Runtime; it is not a production release.
62
+ 7. When the model works, recommend committing the model directory to the user's own Git repository.
63
+ Do not initialize a repository, commit, push, or create a remote unless the user requests it.
64
+
65
+ Read [references/onboarding-workflow.md](references/onboarding-workflow.md) for the wrapper commands and
66
+ credential shapes. Use `foggy-ai-analysis` references for detailed TM/QM modeling and query tuning.
67
+
68
+ ## Credential choices for local development
69
+
70
+ Choose the simplest source the user provides:
71
+
72
+ - `password` in a connection file: simplest for an experience session; the source file remains under
73
+ the user's control and should normally stay outside Git.
74
+ - `passwordEnv`: the wrapper reads the variable from the Agent process and submits the value online;
75
+ Runtime does not need to inherit it at startup.
76
+ - Opaque profile: optional for users who already have one; never require it for ordinary onboarding.
77
+ - Runtime Console: when a Launcher exposing Runtime Console is installed, the user may enter the
78
+ connection there using the management token shown by the host/plugin.
79
+
80
+ Keep only a minimal development safety baseline: do not echo passwords, put them in TM/QM files,
81
+ include them in evidence/diagnostics, or commit them to Git. Do not impose production IAM, audit,
82
+ approval, secret-store, or network-governance requirements on this local flow.
83
+
84
+ ## Command behavior
85
+
86
+ All scripts emit one JSON object. Treat `success=false` or a nonzero exit code as failure. Prefer the
87
+ two resumable composite commands for a complete requested experience:
111
88
 
112
89
  ```text
113
- datasource test -> bind -> diagnostics
114
- tables list -> inspect -> optional bounded read-only SQL
115
- models validate -> bundles add/update -> models refresh -> models describe
116
- query validate -> query execute -> interpretation
90
+ onboard-datasource-run --project-root <workspace> --connection-file <json> \
91
+ --approve-configure --approve-bind --include-indexes
92
+
93
+ onboard-semantic-run --project-root <workspace> --semantic-plan <json> \
94
+ --query-payload <json> --approve-validate --approve-publish --approve-execute
95
+ ```
96
+
97
+ When the user has already asked to connect, build, and test a new local model, those flags implement
98
+ that request and do not require separate question-by-question confirmation. Replacement, pruning, broad
99
+ queries, destructive SQL, Git push, and production deployment still require their own clear scope.
100
+
101
+ The normal analysis order is:
102
+
103
+ ```text
104
+ datasource add/test -> namespace bind -> table/schema inspection
105
+ TM/QM authoring -> models validate -> bundle add/update -> refresh/describe
106
+ query validate -> bounded query execute -> tune -> optional Git handoff
117
107
  ```
118
108
 
119
- In DeepSeek Harness, do not expand the composite onboarding commands back into these individual CLI
120
- operations. This order documents what the wrapper enforces internally and becomes a direct CLI workflow
121
- only after onboarding is complete.
122
-
123
- Composite commands are checkpointed and idempotent: a retry skips completed datasource, validation,
124
- publication, and verification phases when the approved contract and draft digest are unchanged. Fix a
125
- query payload in place and rerun the same semantic composite command; do not remove a successfully
126
- published bundle merely to recover from a later query-validation failure.
127
-
128
- An already-completed profile may be reused from another DSH workspace when the approved connection
129
- contract is byte-for-byte equivalent. Run the datasource composite in the new workspace first; it adds
130
- that workspace as a non-destructive binding and reuses datasource/schema checkpoints. Then pass the
131
- current workspace explicitly as `--project-root` to the semantic composite. A secondary workspace may
132
- reuse an identical published semantic digest and run its own bounded verification query, but it cannot
133
- replace the published semantic layer; changes must be published from the original workspace or a new
134
- profile.
135
-
136
- Keep user business data separate from the sales-drop SQLite demo. Prefer a read-only database account,
137
- opaque CLI profile references, and bounded query limits.
109
+ Stop only the PID recorded by this package and preserve the Runtime work directory unless the user
110
+ explicitly requests removal.
111
+
112
+ ## Result
113
+
114
+ Report the Runtime URL, namespace, datasource name, model directory, Bundle and QueryModel names,
115
+ validation/query status, and useful evidence paths. Never include the password or business row values
116
+ unless the user specifically asks for those values.
@@ -12,6 +12,7 @@
12
12
  "type": {"enum": ["sqlite", "mysql", "postgres", "postgresql"]},
13
13
  "jdbcUrl": {"type": "string", "minLength": 1},
14
14
  "username": {"type": "string"},
15
+ "password": {"type": "string", "description": "Optional local development password. It is submitted once and is not copied into onboarding state or evidence."},
15
16
  "passwordEnv": {"type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"},
16
17
  "opaqueProfileId": {"type": "string", "pattern": "^fop_[a-f0-9]{32}$"},
17
18
  "opaqueRevision": {"type": "string", "pattern": "^sha256:[a-f0-9]{64}$"},
@@ -27,6 +28,7 @@
27
28
  "not": {"anyOf": [
28
29
  {"required": ["jdbcUrl"]},
29
30
  {"required": ["username"]},
31
+ {"required": ["password"]},
30
32
  {"required": ["passwordEnv"]}
31
33
  ]}
32
34
  },
@@ -38,13 +40,9 @@
38
40
  ]}
39
41
  }
40
42
  ],
41
- "allOf": [
42
- {
43
- "if": {
44
- "required": ["jdbcUrl"],
45
- "properties": {"type": {"not": {"const": "sqlite"}}}
46
- },
47
- "then": {"required": ["passwordEnv"]}
43
+ "allOf": [{
44
+ "not": {
45
+ "required": ["password", "passwordEnv"]
48
46
  }
49
- ]
47
+ }]
50
48
  }
@@ -3,8 +3,9 @@
3
3
  "profile": "business",
4
4
  "name": "business-db",
5
5
  "type": "mysql",
6
- "opaqueProfileId": "fop_0123456789abcdef0123456789abcdef",
7
- "opaqueRevision": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
6
+ "jdbcUrl": "jdbc:mysql://127.0.0.1:3306/business",
7
+ "username": "business_dev",
8
+ "password": "replace-for-local-development",
8
9
  "namespace": "business",
9
10
  "schemas": ["public"],
10
11
  "modelsDir": "models",
@@ -1,7 +1,7 @@
1
- # Copy only the variables you need into a private, gitignored env file.
2
- # Never put provider keys or database passwords in DSH settings, Skill files, or evidence.
1
+ # Optional development configuration. Direct passwords in a user-supplied connection file are also
2
+ # supported; the onboarding wrapper does not copy them into state or evidence.
3
3
 
4
- FOGGY_RUNTIME_API_URL=http://127.0.0.1:18066
4
+ FOGGY_RUNTIME_API_URL=http://127.0.0.1:18166
5
5
  FOGGY_NAMESPACE=default
6
6
 
7
7
  # Optional when Runtime reports securityMode=auth-code.
@@ -10,5 +10,5 @@ FOGGY_NAMESPACE=default
10
10
  # Optional data-plane authorization value.
11
11
  # FOGGY_RUNTIME_AUTHORIZATION=
12
12
 
13
- # Example datasource password reference. Use a datasource-specific variable name.
13
+ # Optional alternative to a direct development password.
14
14
  # FOGGY_DATASOURCE_PASSWORD=
@@ -34,7 +34,29 @@
34
34
  }
35
35
  },
36
36
  "runtime": {"type": "object"},
37
- "connection": {"$ref": "connection.schema.json"},
37
+ "connection": {
38
+ "type": "object",
39
+ "additionalProperties": false,
40
+ "required": ["schemaVersion", "connectionMode", "name", "type", "namespace"],
41
+ "properties": {
42
+ "schemaVersion": {"const": "foggy-deepseek-connection/v1"},
43
+ "connectionMode": {"enum": ["legacy-inline", "opaque-profile"]},
44
+ "credentialMode": {"enum": ["inline-development", "agent-environment", "opaque-profile", "none"]},
45
+ "name": {"type": "string"},
46
+ "type": {"type": "string"},
47
+ "jdbcUrl": {"type": ["string", "null"]},
48
+ "username": {"type": ["string", "null"]},
49
+ "passwordEnv": {"type": ["string", "null"]},
50
+ "opaqueProfileId": {"type": "string"},
51
+ "opaqueRevision": {"type": "string"},
52
+ "namespace": {"type": "string"},
53
+ "schemas": {"type": "array", "items": {"type": "string"}},
54
+ "modelsDir": {"type": "string"},
55
+ "readOnlyRecommended": {"type": "boolean"},
56
+ "profile": {"type": "string"},
57
+ "evidenceDir": {"type": "string"}
58
+ }
59
+ },
38
60
  "semantic": {"type": "object"},
39
61
  "steps": {"type": "object"},
40
62
  "artifacts": {"type": "object"}