@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.
@@ -25,7 +25,6 @@ import zipfile
25
25
  STATE_SCHEMA = "foggy-deepseek-onboarding-install/v1"
26
26
  RUNTIME_STATE_SCHEMA = "foggy-deepseek-onboarding-runtime/v1"
27
27
  ONBOARDING_STATE_SCHEMA = "foggy-deepseek-onboarding-state/v1"
28
- CONTEXT_SCHEMA = "foggy-deepseek-harness-context/v1"
29
28
  MANAGED_SKILL_SCHEMA = "foggy-managed-skill/v1"
30
29
  MANAGED_SKILL_MARKER = ".foggy-managed-skill.json"
31
30
  LEGACY_SKILL_MARKER = ".foggy-onboarding-install.json"
@@ -420,60 +419,13 @@ def write_skill_marker(
420
419
  return marker
421
420
 
422
421
 
423
- def backup_skill(destination: Path, project_root: Path) -> Path:
424
- backup_root = project_root / ".foggy" / "onboarding-backups"
422
+ def backup_skill(destination: Path, backup_root: Path) -> Path:
425
423
  backup_root.mkdir(parents=True, exist_ok=True)
426
424
  backup = backup_root / f"{destination.name}-{dt.datetime.now().strftime('%Y%m%d-%H%M%S-%f')}"
427
425
  shutil.move(str(destination), str(backup))
428
426
  return backup
429
427
 
430
428
 
431
- def project_context_path(project_root: Path) -> Path:
432
- return project_root / ".foggy" / "deepseek-harness" / "context.json"
433
-
434
-
435
- def project_relative(path: Path, project_root: Path) -> str:
436
- try:
437
- return path.resolve(strict=False).relative_to(project_root.resolve(strict=False)).as_posix()
438
- except ValueError:
439
- return str(path)
440
-
441
-
442
- def write_project_context(state: dict) -> Path:
443
- project_root = normalized(state["projectRoot"])
444
- install_root = normalized(state["installRoot"])
445
- data_root = normalized(state["dataRoot"])
446
- context_path = project_context_path(project_root)
447
- skills = {}
448
- for kind in ("onboarding", "analysis"):
449
- item = state["skills"][kind]
450
- skill_path = normalized(item["path"])
451
- skills[kind] = {
452
- "version": item.get("version"),
453
- "path": project_relative(skill_path, project_root),
454
- "absolutePath": str(skill_path),
455
- "markerPath": project_relative(skill_path / MANAGED_SKILL_MARKER, project_root),
456
- "managed": bool(item.get("managed")),
457
- }
458
- payload = {
459
- "schemaVersion": CONTEXT_SCHEMA,
460
- "managedBy": "@foggy-projects/deepseek-harness-plugin",
461
- "packageVersion": state["packageVersion"],
462
- "generatedAt": now_utc(),
463
- "projectRoot": str(project_root),
464
- "installStatePath": str(install_root / "install-state.json"),
465
- "runtimeStatePath": str(data_root / "runtime-state.json"),
466
- "operationProgressPath": str(data_root / "operation-progress.json"),
467
- "cli": state["cli"],
468
- "launcher": state["launcher"],
469
- "skills": skills,
470
- "securityMode": state["securityMode"],
471
- "productionReady": False,
472
- }
473
- atomic_json(context_path, payload)
474
- return context_path
475
-
476
-
477
429
  def read_json_object(path: Path, label: str) -> dict:
478
430
  if not path.is_file():
479
431
  raise OnboardingError(f"{label} not found: {path}")
@@ -496,6 +448,33 @@ def onboarding_state_path(data_root: Path, profile: str) -> Path:
496
448
  return data_root / "onboarding" / "profiles" / f"{safe_profile(profile)}.json"
497
449
 
498
450
 
451
+ def configure_profile_store(data_root: Path, *, create: bool = True) -> Path:
452
+ """Keep opaque CLI profiles in the persistent, private Foggy data root by default."""
453
+ configured = os.environ.get("FOGGY_RUNTIME_PROFILE_STORE")
454
+ destination = normalized(configured) if configured else data_root / "cli-profiles"
455
+ if not configured:
456
+ os.environ["FOGGY_RUNTIME_PROFILE_STORE"] = str(destination)
457
+ if create:
458
+ destination.mkdir(parents=True, exist_ok=True)
459
+ if os.name != "nt":
460
+ destination.chmod(0o700)
461
+ return destination
462
+
463
+
464
+ def resolve_profile_name(data_root: Path, requested: str | None) -> str:
465
+ if requested:
466
+ return safe_profile(requested)
467
+ profiles_dir = data_root / "onboarding" / "profiles"
468
+ candidates = sorted(path.stem for path in profiles_dir.glob("*.json") if PROFILE_PATTERN.fullmatch(path.stem))
469
+ if len(candidates) == 1:
470
+ return candidates[0]
471
+ if not candidates:
472
+ return "default"
473
+ raise OnboardingError(
474
+ "Multiple onboarding profiles exist; pass --profile explicitly: " + ", ".join(candidates)
475
+ )
476
+
477
+
499
478
  def read_onboarding_state(data_root: Path, profile: str, required: bool = True) -> dict | None:
500
479
  path = onboarding_state_path(data_root, profile)
501
480
  if not path.is_file():
@@ -766,13 +745,13 @@ def safe_extract(zip_path: Path, destination: Path) -> None:
766
745
 
767
746
  def install_analysis_skill(
768
747
  zip_path: Path,
769
- project_root: Path,
748
+ install_root: Path,
770
749
  version: str,
771
750
  expected_hash: str,
772
751
  package_version: str,
773
752
  replace: bool,
774
753
  ) -> dict:
775
- skills_root = project_root / ".agents" / "skills"
754
+ skills_root = install_root / "skills"
776
755
  destination = skills_root / "foggy-ai-analysis"
777
756
  with tempfile.TemporaryDirectory(prefix="foggy-skill-") as temporary:
778
757
  extract_root = Path(temporary)
@@ -804,7 +783,7 @@ def install_analysis_skill(
804
783
  return {"path": str(destination), "version": version, "digest": marker["installedDigest"], "managed": True, "action": "kept-matching"}
805
784
  if not replace:
806
785
  raise OnboardingError(f"Analysis Skill is missing, modified, or outdated at {destination}; use the plugin Repair action to back it up and restore it")
807
- backup_skill(destination, project_root)
786
+ backup_skill(destination, install_root / "skill-backups")
808
787
  skills_root.mkdir(parents=True, exist_ok=True)
809
788
  shutil.copytree(source, destination)
810
789
  marker = write_skill_marker(
@@ -818,46 +797,6 @@ def install_analysis_skill(
818
797
  return {"path": str(destination), "version": version, "digest": marker["installedDigest"], "managed": True, "action": "installed"}
819
798
 
820
799
 
821
- def install_onboarding_skill(project_root: Path, package_version: str, replace: bool) -> dict:
822
- destination = project_root / ".agents" / "skills" / "foggy-deepseek-onboarding"
823
- source = skill_root()
824
- source_digest = skill_tree_digest(source)
825
- if source.resolve() == destination.resolve(strict=False):
826
- return {"path": str(destination), "version": package_version, "digest": source_digest, "managed": True, "action": "already-running-from-target"}
827
- if destination.exists():
828
- marker = read_skill_marker(destination)
829
- actual_digest = skill_tree_digest(destination)
830
- if (
831
- marker
832
- and marker.get("schemaVersion") == MANAGED_SKILL_SCHEMA
833
- and marker.get("kind") == "onboarding"
834
- and actual_digest == source_digest
835
- and marker.get("sourceDigest") in (None, source_digest)
836
- and marker.get("installedDigest") in (None, source_digest)
837
- ):
838
- written = write_skill_marker(
839
- destination,
840
- kind="onboarding",
841
- package_version=package_version,
842
- component_version=package_version,
843
- source_digest=source_digest,
844
- )
845
- return {"path": str(destination), "version": package_version, "digest": written["installedDigest"], "managed": True, "action": "kept-matching"}
846
- if not replace:
847
- raise OnboardingError(f"Onboarding Skill is missing, modified, or outdated at {destination}; use the plugin Repair action to back it up and restore it")
848
- backup_skill(destination, project_root)
849
- destination.parent.mkdir(parents=True, exist_ok=True)
850
- shutil.copytree(source, destination)
851
- marker = write_skill_marker(
852
- destination,
853
- kind="onboarding",
854
- package_version=package_version,
855
- component_version=package_version,
856
- source_digest=source_digest,
857
- )
858
- return {"path": str(destination), "version": package_version, "digest": marker["installedDigest"], "managed": True, "action": "installed"}
859
-
860
-
861
800
  def read_install_state(install_root: Path, required: bool = True) -> dict | None:
862
801
  path = install_root / "install-state.json"
863
802
  if not path.is_file():
@@ -884,24 +823,26 @@ def install_command(args: argparse.Namespace) -> dict:
884
823
  versions = load_versions()
885
824
  install_root = normalized(args.install_root or default_install_root())
886
825
  data_root = normalized(args.data_root or default_data_root())
887
- project_root = normalized(args.project_root or Path.cwd())
888
826
  cache_dirs = [normalized(item) for item in args.asset_cache_dir]
889
827
  components = versions["components"]
890
828
  assert_managed_root(install_root, "Install root")
891
829
  assert_managed_root(data_root, "Data root")
892
830
  if install_root == data_root:
893
831
  raise OnboardingError("Install root and data root must be different")
832
+ profile_store = normalized(os.environ.get("FOGGY_RUNTIME_PROFILE_STORE") or data_root / "cli-profiles")
894
833
  plan = {
895
834
  "schemaVersion": "foggy-deepseek-onboarding-plan/v1",
896
835
  "installRoot": str(install_root),
897
836
  "dataRoot": str(data_root),
898
- "projectRoot": str(project_root),
837
+ "profileStore": str(profile_store),
838
+ "workspaceMode": "dsh-session-cwd",
899
839
  "versions": {name: value.get("version") for name, value in components.items()},
900
- "operations": ["install isolated CLI", "verify Launcher assets", "install project Skills", "write install state"],
840
+ "operations": ["install isolated CLI", "verify Launcher assets", "install global analysis Skill", "write install state"],
901
841
  "productionReady": False,
902
842
  }
903
843
  if args.dry_run:
904
844
  return {"success": True, "dryRun": True, "plan": plan}
845
+ profile_store = configure_profile_store(data_root)
905
846
  progress = ProgressReporter(
906
847
  getattr(args, "progress_file", None),
907
848
  getattr(args, "operation_id", None),
@@ -911,8 +852,6 @@ def install_command(args: argparse.Namespace) -> dict:
911
852
  progress.update("preflight", 0, "Checking prerequisites")
912
853
  if sys.version_info < (3, 11):
913
854
  raise OnboardingError(f"Python 3.11+ required, got {sys.version.split()[0]}")
914
- if not project_root.is_dir():
915
- raise OnboardingError(f"Project root not found: {project_root}")
916
855
  install_root.mkdir(parents=True, exist_ok=True)
917
856
  data_root.mkdir(parents=True, exist_ok=True)
918
857
  downloads = install_root / "downloads"
@@ -1017,21 +956,27 @@ def install_command(args: argparse.Namespace) -> dict:
1017
956
  zip_asset = next(item for item in analysis_assets if item["role"] == "zip")
1018
957
  progress.update("analysis-skill", 3, "Installing analysis Skill", fraction=0.9, current_file=zip_asset["file"])
1019
958
  analysis_skill = install_analysis_skill(
1020
- downloads / "skill" / zip_asset["file"], project_root, components["analysisSkill"]["version"],
959
+ downloads / "skill" / zip_asset["file"], install_root, components["analysisSkill"]["version"],
1021
960
  zip_asset["sha256"], versions["packageVersion"], args.replace_skill,
1022
961
  )
1023
962
  progress.update("analysis-skill", 3, "Analysis Skill ready", fraction=1.0)
1024
- progress.update("workspace-skills", 4, "Installing onboarding Skill", fraction=0.1)
1025
- onboarding_skill = install_onboarding_skill(project_root, versions["packageVersion"], args.replace_skill)
1026
- progress.update("workspace-skills", 4, "Workspace Skills ready", fraction=1.0)
963
+ progress.update("workspace-skills", 4, "Registering native DSH Skills", fraction=0.1)
964
+ onboarding_skill = {
965
+ "path": str(skill_root()),
966
+ "version": versions["packageVersion"],
967
+ "managed": False,
968
+ "action": "provided-by-plugin",
969
+ "provider": "foggy-managed-skills",
970
+ }
971
+ progress.update("workspace-skills", 4, "Native DSH Skills ready", fraction=1.0)
1027
972
  state = {
1028
973
  "schemaVersion": STATE_SCHEMA,
1029
974
  "installedAt": now_utc(),
1030
975
  "packageVersion": versions["packageVersion"],
1031
976
  "installRoot": str(install_root),
1032
977
  "dataRoot": str(data_root),
1033
- "projectRoot": str(project_root),
1034
- "contextPath": str(project_context_path(project_root)),
978
+ "profileStore": str(profile_store),
979
+ "workspaceMode": "dsh-session-cwd",
1035
980
  "cli": {"version": cli_component["version"], "command": str(cli_command), "mode": cli_mode},
1036
981
  "launcher": {"version": components["launcher"]["version"], "path": str(launcher_dir)},
1037
982
  "skills": {"onboarding": onboarding_skill, "analysis": analysis_skill},
@@ -1041,8 +986,6 @@ def install_command(args: argparse.Namespace) -> dict:
1041
986
  }
1042
987
  progress.update("state", 5, "Writing install state", fraction=0.2, current_file="install-state.json")
1043
988
  atomic_json(install_root / "install-state.json", state)
1044
- progress.update("state", 5, "Writing project context", fraction=0.7, current_file=".foggy/deepseek-harness/context.json")
1045
- context_path = write_project_context(state)
1046
989
  progress.finish()
1047
990
  ACTIVE_PROGRESS = None
1048
991
  return {
@@ -1051,8 +994,7 @@ def install_command(args: argparse.Namespace) -> dict:
1051
994
  "statePath": str(install_root / "install-state.json"),
1052
995
  "installRoot": str(install_root),
1053
996
  "dataRoot": str(data_root),
1054
- "projectRoot": str(project_root),
1055
- "contextPath": str(context_path),
997
+ "workspaceMode": "dsh-session-cwd",
1056
998
  "cliVersion": cli_component["version"],
1057
999
  "launcherVersion": components["launcher"]["version"],
1058
1000
  "analysisSkill": analysis_skill,
@@ -1252,6 +1194,7 @@ def onboarding_context(args: argparse.Namespace, require_runtime: bool = False)
1252
1194
  install_state = read_install_state(install_root)
1253
1195
  data_root = normalized(args.data_root or install_state["dataRoot"])
1254
1196
  assert_managed_root(data_root, "Data root")
1197
+ configure_profile_store(data_root, create=False)
1255
1198
  runtime_state_path = data_root / "runtime-state.json"
1256
1199
  runtime_state = read_json_object(runtime_state_path, "Runtime state") if runtime_state_path.is_file() else None
1257
1200
  if runtime_state and runtime_state.get("schemaVersion") != RUNTIME_STATE_SCHEMA:
@@ -1311,10 +1254,32 @@ def require_opaque_profile_cli(install_state: dict) -> None:
1311
1254
  )
1312
1255
 
1313
1256
 
1257
+ def datasource_entries(payload: dict) -> list[dict]:
1258
+ for item in nested_data_objects(payload):
1259
+ entries = item.get("datasources")
1260
+ if isinstance(entries, list):
1261
+ return [entry for entry in entries if isinstance(entry, dict)]
1262
+ return []
1263
+
1264
+
1265
+ def matching_datasource(payload: dict, connection: dict) -> dict | None:
1266
+ expected_name = connection["name"]
1267
+ expected_type = connection["type"].lower()
1268
+ if expected_type == "postgresql":
1269
+ expected_type = "postgres"
1270
+ for entry in datasource_entries(payload):
1271
+ entry_type = str(entry.get("type", "")).lower()
1272
+ if entry_type == "postgresql":
1273
+ entry_type = "postgres"
1274
+ if entry.get("name") == expected_name and entry_type == expected_type:
1275
+ return entry
1276
+ return None
1277
+
1278
+
1314
1279
  def onboarding_plan_command(args: argparse.Namespace) -> dict:
1315
1280
  install_root, install_state, data_root, runtime_state = onboarding_context(args, require_runtime=False)
1316
1281
  profile = safe_profile(args.profile)
1317
- project_root = normalized(args.project_root or install_state["projectRoot"])
1282
+ project_root = normalized(args.project_root or Path.cwd())
1318
1283
  if not project_root.is_dir():
1319
1284
  raise OnboardingError(f"Project root not found: {project_root}")
1320
1285
  connection_file = normalized(args.connection_file)
@@ -1372,7 +1337,9 @@ def onboarding_plan_command(args: argparse.Namespace) -> dict:
1372
1337
 
1373
1338
  def require_profile(args: argparse.Namespace, require_runtime: bool = False) -> tuple[dict, dict, Path, dict | None]:
1374
1339
  _install_root, install_state, data_root, runtime_state = onboarding_context(args, require_runtime=require_runtime)
1375
- state = read_onboarding_state(data_root, safe_profile(args.profile))
1340
+ profile = resolve_profile_name(data_root, getattr(args, "profile", None))
1341
+ args.profile = profile
1342
+ state = read_onboarding_state(data_root, profile)
1376
1343
  if normalized(state["installRoot"]) != normalized(install_state["installRoot"]):
1377
1344
  raise OnboardingError("Onboarding profile belongs to a different install root")
1378
1345
  return state, install_state, data_root, runtime_state
@@ -1418,10 +1385,31 @@ def datasource_configure_command(args: argparse.Namespace) -> dict:
1418
1385
  label = "datasources add"
1419
1386
  if args.replace:
1420
1387
  command.append("--replace")
1421
- result = redact_connection_material(
1422
- cli_json(install_state, runtime_state, connection["namespace"], command, label)
1423
- )
1424
- mark_step(state, "datasourceConfigured", "completed", replace=args.replace)
1388
+ already_present = False
1389
+ try:
1390
+ result = redact_connection_material(
1391
+ cli_json(install_state, runtime_state, connection["namespace"], command, label)
1392
+ )
1393
+ except OnboardingError as exc:
1394
+ if "DATASOURCE_ALREADY_EXISTS" not in str(exc):
1395
+ raise
1396
+ listed = cli_json(
1397
+ install_state, runtime_state, connection["namespace"], ["datasources", "list"], "datasources list"
1398
+ )
1399
+ existing = matching_datasource(listed, connection)
1400
+ if existing is None:
1401
+ raise OnboardingError(
1402
+ f"Datasource {connection['name']} already exists but its public type does not match the approved plan; "
1403
+ "do not replace it without explicit approval"
1404
+ ) from exc
1405
+ already_present = True
1406
+ result = {
1407
+ "success": True,
1408
+ "idempotent": True,
1409
+ "status": "already-present",
1410
+ "dataSource": redact_connection_material(existing),
1411
+ }
1412
+ mark_step(state, "datasourceConfigured", "completed", replace=args.replace, alreadyPresent=already_present)
1425
1413
  path = write_onboarding_state(data_root, state)
1426
1414
  return {
1427
1415
  "success": True,
@@ -1429,6 +1417,7 @@ def datasource_configure_command(args: argparse.Namespace) -> dict:
1429
1417
  "profile": state["profile"],
1430
1418
  "statePath": str(path),
1431
1419
  "dataSource": connection["name"],
1420
+ "alreadyPresent": already_present,
1432
1421
  "runtime": result,
1433
1422
  "next": "run datasource-verify; add --bind to approve namespace binding",
1434
1423
  "productionReady": False,
@@ -1887,7 +1876,16 @@ def semantic_verify_command(args: argparse.Namespace) -> dict:
1887
1876
  )
1888
1877
  atomic_json(evidence_dir / "query-execute.json", executed)
1889
1878
  row_count = response_row_count(executed)
1890
- mark_step(state, "semanticVerified", "completed", queryModel=query_model, queryValidated=True, queryExecuted=True)
1879
+ mark_step(
1880
+ state,
1881
+ "semanticVerified",
1882
+ "completed",
1883
+ queryModel=query_model,
1884
+ queryValidated=True,
1885
+ queryExecuted=True,
1886
+ rowCount=row_count,
1887
+ queryPayloadDigest=sha256(payload_path),
1888
+ )
1891
1889
  state.setdefault("artifacts", {})["semanticVerifyEvidence"] = str(evidence_dir)
1892
1890
  path = write_onboarding_state(data_root, state)
1893
1891
  return {
@@ -1907,14 +1905,15 @@ def semantic_verify_command(args: argparse.Namespace) -> dict:
1907
1905
 
1908
1906
 
1909
1907
  def next_onboarding_action(state: dict) -> dict:
1908
+ profile_flag = f" --profile {state['profile']}"
1910
1909
  ordered = [
1911
- ("datasourceConfigured", "datasource-configure --apply"),
1912
- ("datasourceVerified", "datasource-verify --bind"),
1913
- ("schemaDiscovered", "schema-discover"),
1914
- ("semanticDrafted", "semantic-draft --semantic-plan <json>"),
1915
- ("semanticValidated", "semantic-validate --apply"),
1916
- ("semanticPublished", "semantic-publish --apply"),
1917
- ("semanticVerified", "semantic-verify --query-payload <json> --execute"),
1910
+ ("datasourceConfigured", f"datasource-configure{profile_flag} --apply"),
1911
+ ("datasourceVerified", f"datasource-verify{profile_flag} --bind"),
1912
+ ("schemaDiscovered", f"schema-discover{profile_flag}"),
1913
+ ("semanticDrafted", f"semantic-draft{profile_flag} --semantic-plan <json>"),
1914
+ ("semanticValidated", f"semantic-validate{profile_flag} --apply"),
1915
+ ("semanticPublished", f"semantic-publish{profile_flag} --apply"),
1916
+ ("semanticVerified", f"semantic-verify{profile_flag} --query-payload <json> --execute"),
1918
1917
  ]
1919
1918
  for name, command in ordered:
1920
1919
  current = state.get("steps", {}).get(name, {})
@@ -1927,7 +1926,7 @@ def next_onboarding_action(state: dict) -> dict:
1927
1926
  "instruction": "Inspect semantic publish evidence and repair refresh before any republish attempt.",
1928
1927
  }
1929
1928
  if name == "semanticValidated" and current.get("status") == "failed":
1930
- command = "repair TM/QM, then semantic-draft --semantic-plan <json>"
1929
+ command = f"repair TM/QM, then semantic-draft{profile_flag} --semantic-plan <json>"
1931
1930
  return {"step": name, "command": command, "status": current.get("status", "pending")}
1932
1931
  return {"step": None, "command": None, "status": "completed"}
1933
1932
 
@@ -1972,9 +1971,24 @@ def save_composite_result(evidence_dir: Path, name: str, payload: dict, files: l
1972
1971
  files.append(str(path))
1973
1972
 
1974
1973
 
1974
+ def resumed_phase(profile: str, phase: str, **values: object) -> dict:
1975
+ return {
1976
+ "success": True,
1977
+ "schemaVersion": "foggy-deepseek-onboarding-resumed/v1",
1978
+ "profile": profile,
1979
+ "phase": phase,
1980
+ "resumed": True,
1981
+ **values,
1982
+ }
1983
+
1984
+
1985
+ def step_completed(state: dict, name: str) -> bool:
1986
+ return state.get("steps", {}).get(name, {}).get("status") == "completed"
1987
+
1988
+
1975
1989
  def datasource_run_command(args: argparse.Namespace) -> dict:
1976
1990
  _install_root, install_state, data_root, _runtime_state = onboarding_context(args, require_runtime=True)
1977
- project_root = normalized(args.project_root or install_state["projectRoot"])
1991
+ project_root = normalized(args.project_root or Path.cwd())
1978
1992
  requested_connection = validate_connection(read_json_object(normalized(args.connection_file), "Connection plan"))
1979
1993
  if not requested_connection.get("profile"):
1980
1994
  raise OnboardingError("Composite datasource onboarding requires connection.profile in the approved contract")
@@ -1991,6 +2005,11 @@ def datasource_run_command(args: argparse.Namespace) -> dict:
1991
2005
  if existing:
1992
2006
  if existing.get("connection") != requested_connection:
1993
2007
  raise OnboardingError("Existing onboarding profile does not match the requested connection plan")
2008
+ if normalized(existing.get("projectRoot", "")) != project_root:
2009
+ raise OnboardingError(
2010
+ "Existing onboarding profile belongs to a different projectRoot; resume from that DSH workspace "
2011
+ "or choose a new profile name"
2012
+ )
1994
2013
  plan_result = {
1995
2014
  "success": True,
1996
2015
  "schemaVersion": "foggy-deepseek-onboarding-plan-result/v1",
@@ -2010,59 +2029,81 @@ def datasource_run_command(args: argparse.Namespace) -> dict:
2010
2029
  replace_plan=False,
2011
2030
  ))
2012
2031
  save_composite_result(evidence_dir, "01-plan.json", plan_result, files)
2032
+ state = read_onboarding_state(data_root, profile)
2013
2033
 
2014
- configure_dry = datasource_configure_command(argparse.Namespace(
2015
- install_root=args.install_root, data_root=args.data_root, profile=profile, apply=False, replace=False,
2016
- ))
2017
- save_composite_result(evidence_dir, "02-datasource-dry.json", configure_dry, files)
2018
- if not args.approve_configure:
2019
- return {
2020
- "success": True,
2021
- "schemaVersion": "foggy-deepseek-datasource-run/v1",
2022
- "profile": profile,
2023
- "phaseStatus": "awaiting-configure-approval",
2024
- "evidenceDir": str(evidence_dir),
2025
- "evidenceFiles": files,
2026
- "next": "rerun with --approve-configure after the datasource mutation is approved",
2027
- "productionReady": False,
2028
- }
2029
-
2030
- configured = datasource_configure_command(argparse.Namespace(
2031
- install_root=args.install_root, data_root=args.data_root, profile=profile, apply=True, replace=False,
2032
- ))
2033
- save_composite_result(evidence_dir, "03-datasource-apply.json", configured, files)
2034
- tested = datasource_verify_command(argparse.Namespace(
2035
- install_root=args.install_root, data_root=args.data_root, profile=profile, bind=False,
2036
- ))
2037
- save_composite_result(evidence_dir, "04-datasource-test.json", tested, files)
2038
- if not args.approve_bind:
2039
- return {
2040
- "success": True,
2041
- "schemaVersion": "foggy-deepseek-datasource-run/v1",
2042
- "profile": profile,
2043
- "phaseStatus": "awaiting-bind-approval",
2044
- "evidenceDir": str(evidence_dir),
2045
- "evidenceFiles": files,
2046
- "next": "rerun with --approve-configure --approve-bind after namespace binding is approved",
2047
- "productionReady": False,
2048
- }
2034
+ if step_completed(state, "datasourceConfigured"):
2035
+ configured = resumed_phase(profile, "datasourceConfigured")
2036
+ save_composite_result(evidence_dir, "02-datasource-dry.json", configured, files)
2037
+ save_composite_result(evidence_dir, "03-datasource-apply.json", configured, files)
2038
+ else:
2039
+ configure_dry = datasource_configure_command(argparse.Namespace(
2040
+ install_root=args.install_root, data_root=args.data_root, profile=profile, apply=False, replace=False,
2041
+ ))
2042
+ save_composite_result(evidence_dir, "02-datasource-dry.json", configure_dry, files)
2043
+ if not args.approve_configure:
2044
+ return {
2045
+ "success": True,
2046
+ "schemaVersion": "foggy-deepseek-datasource-run/v1",
2047
+ "profile": profile,
2048
+ "phaseStatus": "awaiting-configure-approval",
2049
+ "evidenceDir": str(evidence_dir),
2050
+ "evidenceFiles": files,
2051
+ "next": "rerun with --approve-configure after the datasource mutation is approved",
2052
+ "productionReady": False,
2053
+ }
2054
+ configured = datasource_configure_command(argparse.Namespace(
2055
+ install_root=args.install_root, data_root=args.data_root, profile=profile, apply=True, replace=False,
2056
+ ))
2057
+ save_composite_result(evidence_dir, "03-datasource-apply.json", configured, files)
2058
+ state = read_onboarding_state(data_root, profile)
2049
2059
 
2050
- bound = datasource_verify_command(argparse.Namespace(
2051
- install_root=args.install_root, data_root=args.data_root, profile=profile, bind=True,
2052
- ))
2053
- save_composite_result(evidence_dir, "05-datasource-bind.json", bound, files)
2054
- discovered = schema_discover_command(argparse.Namespace(
2055
- install_root=args.install_root,
2056
- data_root=args.data_root,
2057
- profile=profile,
2058
- schema=args.schema,
2059
- pattern=args.pattern,
2060
- table=args.table,
2061
- max_tables=args.max_tables,
2062
- list_only=False,
2063
- no_views=args.no_views,
2064
- include_indexes=args.include_indexes,
2065
- ))
2060
+ if step_completed(state, "datasourceVerified"):
2061
+ bound = resumed_phase(profile, "datasourceVerified")
2062
+ save_composite_result(evidence_dir, "04-datasource-test.json", bound, files)
2063
+ save_composite_result(evidence_dir, "05-datasource-bind.json", bound, files)
2064
+ else:
2065
+ tested = datasource_verify_command(argparse.Namespace(
2066
+ install_root=args.install_root, data_root=args.data_root, profile=profile, bind=False,
2067
+ ))
2068
+ save_composite_result(evidence_dir, "04-datasource-test.json", tested, files)
2069
+ if not args.approve_bind:
2070
+ return {
2071
+ "success": True,
2072
+ "schemaVersion": "foggy-deepseek-datasource-run/v1",
2073
+ "profile": profile,
2074
+ "phaseStatus": "awaiting-bind-approval",
2075
+ "evidenceDir": str(evidence_dir),
2076
+ "evidenceFiles": files,
2077
+ "next": "rerun with --approve-configure --approve-bind after namespace binding is approved",
2078
+ "productionReady": False,
2079
+ }
2080
+ bound = datasource_verify_command(argparse.Namespace(
2081
+ install_root=args.install_root, data_root=args.data_root, profile=profile, bind=True,
2082
+ ))
2083
+ save_composite_result(evidence_dir, "05-datasource-bind.json", bound, files)
2084
+ state = read_onboarding_state(data_root, profile)
2085
+
2086
+ if step_completed(state, "schemaDiscovered"):
2087
+ schema_step = state["steps"]["schemaDiscovered"]
2088
+ discovered = resumed_phase(
2089
+ profile,
2090
+ "schemaDiscovered",
2091
+ selectedCount=schema_step.get("selectedCount", 0),
2092
+ artifactPath=state.get("artifacts", {}).get("schemaDiscovery"),
2093
+ )
2094
+ else:
2095
+ discovered = schema_discover_command(argparse.Namespace(
2096
+ install_root=args.install_root,
2097
+ data_root=args.data_root,
2098
+ profile=profile,
2099
+ schema=args.schema,
2100
+ pattern=args.pattern,
2101
+ table=args.table,
2102
+ max_tables=args.max_tables,
2103
+ list_only=False,
2104
+ no_views=args.no_views,
2105
+ include_indexes=args.include_indexes,
2106
+ ))
2066
2107
  save_composite_result(evidence_dir, "06-schema.json", discovered, files)
2067
2108
  return {
2068
2109
  "success": True,
@@ -2078,6 +2119,29 @@ def datasource_run_command(args: argparse.Namespace) -> dict:
2078
2119
  }
2079
2120
 
2080
2121
 
2122
+ def semantic_plan_snapshot(state: dict, plan: dict) -> tuple[Path, dict, bool]:
2123
+ project_root = normalized(state["projectRoot"])
2124
+ draft_dir = normalized(project_root / plan["draftDir"])
2125
+ if not is_child(draft_dir, project_root) or draft_dir == project_root:
2126
+ raise OnboardingError("draftDir must stay inside projectRoot and cannot equal it")
2127
+ manifest = semantic_manifest(draft_dir)
2128
+ semantic = state.get("semantic", {})
2129
+ registered = semantic.get("draftManifest") or {}
2130
+ matches = bool(
2131
+ step_completed(state, "semanticDrafted")
2132
+ and normalized(semantic.get("draftDir", draft_dir)) == draft_dir
2133
+ and semantic.get("bundleName") == plan["bundleName"]
2134
+ and semantic.get("queryModels") == plan["queryModels"]
2135
+ and registered.get("digest") == manifest["digest"]
2136
+ )
2137
+ return draft_dir, manifest, matches
2138
+
2139
+
2140
+ def published_digest_matches(state: dict, digest: str) -> bool:
2141
+ published = state.get("steps", {}).get("semanticPublished", {})
2142
+ return published.get("status") == "completed" and published.get("digest") == digest
2143
+
2144
+
2081
2145
  def semantic_run_command(args: argparse.Namespace) -> dict:
2082
2146
  approved_plan = validate_semantic_plan(read_json_object(normalized(args.semantic_plan), "Semantic plan"))
2083
2147
  if not approved_plan.get("profile"):
@@ -2089,6 +2153,17 @@ def semantic_run_command(args: argparse.Namespace) -> dict:
2089
2153
  profile_args.profile = profile
2090
2154
  state, _install_state, _data_root, _runtime_state = require_profile(profile_args, require_runtime=True)
2091
2155
  project_root = normalized(state["projectRoot"])
2156
+ payload_path = normalized(args.query_payload)
2157
+ if not is_child(payload_path, project_root):
2158
+ raise OnboardingError(
2159
+ "Query payload must stay inside projectRoot; place contracts under .foggy/onboarding-contracts before approval"
2160
+ )
2161
+ bounded_query_payload(payload_path)
2162
+ declared_query_model = args.query_model or (approved_plan["queryModels"][0] if len(approved_plan["queryModels"]) == 1 else None)
2163
+ if not declared_query_model:
2164
+ raise OnboardingError("--query-model is required when the semantic plan declares multiple query models")
2165
+ if declared_query_model not in approved_plan["queryModels"]:
2166
+ raise OnboardingError("--query-model must be declared in semanticPlan.queryModels")
2092
2167
  contract_evidence = approved_plan.get("evidenceDir")
2093
2168
  if contract_evidence and args.evidence_dir:
2094
2169
  if normalized(project_root / contract_evidence) != normalized(args.evidence_dir):
@@ -2096,78 +2171,141 @@ def semantic_run_command(args: argparse.Namespace) -> dict:
2096
2171
  evidence_dir = composite_evidence_dir(project_root, profile, str(project_root / contract_evidence) if contract_evidence else args.evidence_dir)
2097
2172
  files: list[str] = []
2098
2173
 
2099
- drafted = semantic_draft_command(argparse.Namespace(
2100
- install_root=args.install_root,
2101
- data_root=args.data_root,
2102
- profile=profile,
2103
- semantic_plan=args.semantic_plan,
2104
- ))
2174
+ _draft_dir, manifest, draft_matches = semantic_plan_snapshot(state, approved_plan)
2175
+ published_matches = published_digest_matches(state, manifest["digest"])
2176
+ if draft_matches or published_matches:
2177
+ drafted = resumed_phase(profile, "semanticDrafted", digest=manifest["digest"])
2178
+ else:
2179
+ drafted = semantic_draft_command(argparse.Namespace(
2180
+ install_root=args.install_root,
2181
+ data_root=args.data_root,
2182
+ profile=profile,
2183
+ semantic_plan=args.semantic_plan,
2184
+ ))
2185
+ state = read_onboarding_state(normalized(state["dataRoot"]), profile)
2186
+ manifest = state["semantic"]["draftManifest"]
2105
2187
  save_composite_result(evidence_dir, "07-semantic-draft.json", drafted, files)
2106
- validate_dry = semantic_validate_command(argparse.Namespace(
2107
- install_root=args.install_root,
2108
- data_root=args.data_root,
2109
- profile=profile,
2110
- apply=False,
2111
- include_stack_trace=False,
2112
- ))
2113
- save_composite_result(evidence_dir, "08-semantic-validate-dry.json", validate_dry, files)
2114
- if not args.approve_validate:
2115
- return {
2116
- "success": True,
2117
- "schemaVersion": "foggy-deepseek-semantic-run/v1",
2118
- "profile": profile,
2119
- "phaseStatus": "awaiting-validate-approval",
2120
- "evidenceDir": str(evidence_dir),
2121
- "evidenceFiles": files,
2122
- "next": "rerun with --approve-validate after the validation catalog mutation is approved",
2123
- "productionReady": False,
2124
- }
2125
-
2126
- validated = semantic_validate_command(argparse.Namespace(
2127
- install_root=args.install_root,
2128
- data_root=args.data_root,
2129
- profile=profile,
2130
- apply=True,
2131
- include_stack_trace=False,
2132
- ))
2188
+ state = read_onboarding_state(normalized(state["dataRoot"]), profile)
2189
+ validation_step = state.get("steps", {}).get("semanticValidated", {})
2190
+ published_matches = published_digest_matches(state, manifest["digest"])
2191
+ validation_matches = validation_step.get("status") == "completed" and validation_step.get("digest") == manifest["digest"]
2192
+ if validation_matches or published_matches:
2193
+ if published_matches and not validation_matches:
2194
+ mark_step(state, "semanticValidated", "completed", digest=manifest["digest"], resumedFromPublished=True)
2195
+ write_onboarding_state(normalized(state["dataRoot"]), state)
2196
+ validated = resumed_phase(profile, "semanticValidated", digest=manifest["digest"])
2197
+ save_composite_result(evidence_dir, "08-semantic-validate-dry.json", validated, files)
2198
+ else:
2199
+ validate_dry = semantic_validate_command(argparse.Namespace(
2200
+ install_root=args.install_root,
2201
+ data_root=args.data_root,
2202
+ profile=profile,
2203
+ apply=False,
2204
+ include_stack_trace=False,
2205
+ ))
2206
+ save_composite_result(evidence_dir, "08-semantic-validate-dry.json", validate_dry, files)
2207
+ if not args.approve_validate:
2208
+ return {
2209
+ "success": True,
2210
+ "schemaVersion": "foggy-deepseek-semantic-run/v1",
2211
+ "profile": profile,
2212
+ "phaseStatus": "awaiting-validate-approval",
2213
+ "evidenceDir": str(evidence_dir),
2214
+ "evidenceFiles": files,
2215
+ "next": "rerun with --approve-validate after the validation catalog mutation is approved",
2216
+ "productionReady": False,
2217
+ }
2218
+ validated = semantic_validate_command(argparse.Namespace(
2219
+ install_root=args.install_root,
2220
+ data_root=args.data_root,
2221
+ profile=profile,
2222
+ apply=True,
2223
+ include_stack_trace=False,
2224
+ ))
2133
2225
  save_composite_result(evidence_dir, "09-semantic-validate-apply.json", validated, files)
2134
- publish_dry = semantic_publish_command(argparse.Namespace(
2135
- install_root=args.install_root,
2136
- data_root=args.data_root,
2137
- profile=profile,
2138
- apply=False,
2139
- replace_bundle=False,
2140
- watch=False,
2141
- prune=False,
2142
- ))
2143
- save_composite_result(evidence_dir, "10-semantic-publish-dry.json", publish_dry, files)
2144
- if not args.approve_publish:
2226
+ state = read_onboarding_state(normalized(state["dataRoot"]), profile)
2227
+ if published_digest_matches(state, manifest["digest"]):
2228
+ published = resumed_phase(
2229
+ profile,
2230
+ "semanticPublished",
2231
+ digest=manifest["digest"],
2232
+ bundleName=state["semantic"]["bundleName"],
2233
+ )
2234
+ save_composite_result(evidence_dir, "10-semantic-publish-dry.json", published, files)
2235
+ else:
2236
+ publish_dry = semantic_publish_command(argparse.Namespace(
2237
+ install_root=args.install_root,
2238
+ data_root=args.data_root,
2239
+ profile=profile,
2240
+ apply=False,
2241
+ replace_bundle=False,
2242
+ watch=False,
2243
+ prune=False,
2244
+ ))
2245
+ save_composite_result(evidence_dir, "10-semantic-publish-dry.json", publish_dry, files)
2246
+ if not args.approve_publish:
2247
+ return {
2248
+ "success": True,
2249
+ "schemaVersion": "foggy-deepseek-semantic-run/v1",
2250
+ "profile": profile,
2251
+ "phaseStatus": "awaiting-publish-approval",
2252
+ "evidenceDir": str(evidence_dir),
2253
+ "evidenceFiles": files,
2254
+ "next": "rerun with --approve-validate --approve-publish after publication is approved",
2255
+ "productionReady": False,
2256
+ }
2257
+ published = semantic_publish_command(argparse.Namespace(
2258
+ install_root=args.install_root,
2259
+ data_root=args.data_root,
2260
+ profile=profile,
2261
+ apply=True,
2262
+ replace_bundle=False,
2263
+ watch=False,
2264
+ prune=False,
2265
+ ))
2266
+ save_composite_result(evidence_dir, "11-semantic-publish-apply.json", published, files)
2267
+ state = read_onboarding_state(normalized(state["dataRoot"]), profile)
2268
+ verified_step = state.get("steps", {}).get("semanticVerified", {})
2269
+ payload_digest = sha256(payload_path)
2270
+ if (
2271
+ verified_step.get("status") == "completed"
2272
+ and verified_step.get("queryModel") == declared_query_model
2273
+ and verified_step.get("queryPayloadDigest") == payload_digest
2274
+ ):
2275
+ resumed = resumed_phase(
2276
+ profile,
2277
+ "semanticVerified",
2278
+ queryModel=declared_query_model,
2279
+ queryValidated=True,
2280
+ queryExecuted=True,
2281
+ rowCount=verified_step.get("rowCount"),
2282
+ queryPayloadDigest=payload_digest,
2283
+ )
2284
+ save_composite_result(evidence_dir, "12-query-validate.json", resumed, files)
2285
+ save_composite_result(evidence_dir, "13-query-execute.json", resumed, files)
2286
+ status = onboarding_status_command(argparse.Namespace(
2287
+ install_root=args.install_root, data_root=args.data_root, profile=profile,
2288
+ ))
2289
+ save_composite_result(evidence_dir, "14-status.json", status, files)
2145
2290
  return {
2146
2291
  "success": True,
2147
2292
  "schemaVersion": "foggy-deepseek-semantic-run/v1",
2148
2293
  "profile": profile,
2149
- "phaseStatus": "awaiting-publish-approval",
2294
+ "phaseStatus": "completed",
2295
+ "resumed": True,
2296
+ "queryModel": declared_query_model,
2297
+ "queryValidated": True,
2298
+ "queryExecuted": True,
2299
+ "rowCount": verified_step.get("rowCount"),
2150
2300
  "evidenceDir": str(evidence_dir),
2151
2301
  "evidenceFiles": files,
2152
- "next": "rerun with --approve-validate --approve-publish after publication is approved",
2153
2302
  "productionReady": False,
2154
2303
  }
2155
-
2156
- published = semantic_publish_command(argparse.Namespace(
2157
- install_root=args.install_root,
2158
- data_root=args.data_root,
2159
- profile=profile,
2160
- apply=True,
2161
- replace_bundle=False,
2162
- watch=False,
2163
- prune=False,
2164
- ))
2165
- save_composite_result(evidence_dir, "11-semantic-publish-apply.json", published, files)
2166
2304
  query_validated = semantic_verify_command(argparse.Namespace(
2167
2305
  install_root=args.install_root,
2168
2306
  data_root=args.data_root,
2169
2307
  profile=profile,
2170
- query_model=args.query_model,
2308
+ query_model=declared_query_model,
2171
2309
  query_payload=args.query_payload,
2172
2310
  execute=False,
2173
2311
  ))
@@ -2190,7 +2328,7 @@ def semantic_run_command(args: argparse.Namespace) -> dict:
2190
2328
  install_root=args.install_root,
2191
2329
  data_root=args.data_root,
2192
2330
  profile=profile,
2193
- query_model=args.query_model,
2331
+ query_model=declared_query_model,
2194
2332
  query_payload=args.query_payload,
2195
2333
  execute=True,
2196
2334
  ))
@@ -2234,24 +2372,17 @@ def doctor_command(args: argparse.Namespace) -> dict:
2234
2372
  path = launcher_dir / asset["file"]
2235
2373
  launcher_checks.append({"file": asset["file"], "present": path.is_file(), "sha256Valid": path.is_file() and sha256(path) == asset["sha256"]})
2236
2374
  launcher_ok = bool(launcher_checks) and all(item["present"] and item["sha256Valid"] for item in launcher_checks)
2237
- analysis_skill_root = project_root / ".agents" / "skills" / "foggy-ai-analysis"
2238
- onboarding_skill_root = project_root / ".agents" / "skills" / "foggy-deepseek-onboarding"
2375
+ analysis_skill_root = normalized(state.get("skills", {}).get("analysis", {}).get("path") or install_root / "skills" / "foggy-ai-analysis") if state else install_root / "skills" / "foggy-ai-analysis"
2376
+ onboarding_skill_root = skill_root()
2239
2377
  analysis_skill = managed_skill_status(analysis_skill_root, "analysis", versions["components"]["analysisSkill"]["version"])
2240
- onboarding_skill = managed_skill_status(onboarding_skill_root, "onboarding", versions["packageVersion"])
2241
- context_path = project_context_path(project_root)
2242
- context = None
2243
- if context_path.is_file():
2244
- try:
2245
- context = json.loads(context_path.read_text(encoding="utf-8"))
2246
- except (OSError, json.JSONDecodeError):
2247
- context = None
2248
- context_ok = bool(
2249
- context
2250
- and context.get("schemaVersion") == CONTEXT_SCHEMA
2251
- and context.get("packageVersion") == versions["packageVersion"]
2252
- and normalized(context.get("projectRoot", "")) == project_root
2253
- and normalized(context.get("installStatePath", "")) == install_root / "install-state.json"
2254
- )
2378
+ onboarding_skill = {
2379
+ "path": str(onboarding_skill_root),
2380
+ "present": (onboarding_skill_root / "SKILL.md").is_file(),
2381
+ "managed": False,
2382
+ "version": versions["packageVersion"],
2383
+ "provider": "foggy-managed-skills",
2384
+ "valid": (onboarding_skill_root / "SKILL.md").is_file(),
2385
+ }
2255
2386
  runtime = {"status": "stopped"}
2256
2387
  if state:
2257
2388
  data_root = normalized(state["dataRoot"])
@@ -2267,7 +2398,6 @@ def doctor_command(args: argparse.Namespace) -> dict:
2267
2398
  "launcher": launcher_ok,
2268
2399
  "analysisSkill": analysis_skill["valid"],
2269
2400
  "onboardingSkill": onboarding_skill["valid"],
2270
- "projectContext": context_ok,
2271
2401
  }
2272
2402
  if args.strict_runtime:
2273
2403
  required["runtime"] = runtime["status"] == "running"
@@ -2282,7 +2412,7 @@ def doctor_command(args: argparse.Namespace) -> dict:
2282
2412
  "cli": cli,
2283
2413
  "launcherAssets": launcher_checks,
2284
2414
  "skills": {"analysis": analysis_skill, "onboarding": onboarding_skill},
2285
- "projectContext": {"path": str(context_path), "valid": context_ok},
2415
+ "workspace": {"path": str(project_root), "mode": "dsh-session-cwd"},
2286
2416
  "runtime": runtime,
2287
2417
  "environmentPresence": {name: bool(os.environ.get(name)) for name in ("DEEPSEEK_API_KEY", "ALIYUN_TOKEN_PLAN_API_KEY", "FOGGY_RUNTIME_API_AUTH_CODE", "FOGGY_RUNTIME_AUTHORIZATION")},
2288
2418
  "productionReady": False,
@@ -2298,13 +2428,8 @@ def uninstall_command(args: argparse.Namespace) -> dict:
2298
2428
  assert_managed_root(data_root, "Data root")
2299
2429
  if install_root == data_root:
2300
2430
  raise OnboardingError("Install root and data root must be different")
2301
- project_root = normalized(state["projectRoot"])
2302
- skills_root = project_root / ".agents" / "skills"
2303
- skill_targets = [skills_root / name for name in ("foggy-deepseek-onboarding", "foggy-ai-analysis")]
2304
- if args.remove_skills:
2305
- for target in skill_targets:
2306
- if target.exists() and (target.is_symlink() or not is_child(target, skills_root)):
2307
- raise OnboardingError(f"Refusing to remove unexpected Skill path: {target}")
2431
+ skills_root = install_root / "skills"
2432
+ skill_targets = [skills_root / "foggy-ai-analysis"]
2308
2433
  plan = {"installRoot": str(install_root), "dataRoot": str(data_root), "removeSkills": args.remove_skills, "purgeData": args.purge_data}
2309
2434
  if args.dry_run:
2310
2435
  return {"success": True, "dryRun": True, "plan": plan}
@@ -2382,13 +2507,13 @@ def build_parser() -> argparse.ArgumentParser:
2382
2507
  status = sub.add_parser("onboard-status")
2383
2508
  status.add_argument("--install-root")
2384
2509
  status.add_argument("--data-root")
2385
- status.add_argument("--profile", default="default")
2510
+ status.add_argument("--profile")
2386
2511
  status.set_defaults(handler=onboarding_status_command)
2387
2512
 
2388
2513
  resume = sub.add_parser("onboard-resume")
2389
2514
  resume.add_argument("--install-root")
2390
2515
  resume.add_argument("--data-root")
2391
- resume.add_argument("--profile", default="default")
2516
+ resume.add_argument("--profile")
2392
2517
  resume.set_defaults(handler=onboarding_resume_command)
2393
2518
 
2394
2519
  datasource_run = sub.add_parser("onboard-datasource-run")
@@ -2424,7 +2549,7 @@ def build_parser() -> argparse.ArgumentParser:
2424
2549
  datasource_configure = sub.add_parser("datasource-configure")
2425
2550
  datasource_configure.add_argument("--install-root")
2426
2551
  datasource_configure.add_argument("--data-root")
2427
- datasource_configure.add_argument("--profile", default="default")
2552
+ datasource_configure.add_argument("--profile")
2428
2553
  datasource_configure.add_argument("--apply", action="store_true")
2429
2554
  datasource_configure.add_argument("--replace", action="store_true")
2430
2555
  datasource_configure.set_defaults(handler=datasource_configure_command)
@@ -2432,14 +2557,14 @@ def build_parser() -> argparse.ArgumentParser:
2432
2557
  datasource_verify = sub.add_parser("datasource-verify")
2433
2558
  datasource_verify.add_argument("--install-root")
2434
2559
  datasource_verify.add_argument("--data-root")
2435
- datasource_verify.add_argument("--profile", default="default")
2560
+ datasource_verify.add_argument("--profile")
2436
2561
  datasource_verify.add_argument("--bind", action="store_true")
2437
2562
  datasource_verify.set_defaults(handler=datasource_verify_command)
2438
2563
 
2439
2564
  schema_discover = sub.add_parser("schema-discover")
2440
2565
  schema_discover.add_argument("--install-root")
2441
2566
  schema_discover.add_argument("--data-root")
2442
- schema_discover.add_argument("--profile", default="default")
2567
+ schema_discover.add_argument("--profile")
2443
2568
  schema_discover.add_argument("--schema", action="append")
2444
2569
  schema_discover.add_argument("--pattern")
2445
2570
  schema_discover.add_argument("--table", action="append")
@@ -2452,14 +2577,14 @@ def build_parser() -> argparse.ArgumentParser:
2452
2577
  semantic_draft = sub.add_parser("semantic-draft")
2453
2578
  semantic_draft.add_argument("--install-root")
2454
2579
  semantic_draft.add_argument("--data-root")
2455
- semantic_draft.add_argument("--profile", default="default")
2580
+ semantic_draft.add_argument("--profile")
2456
2581
  semantic_draft.add_argument("--semantic-plan", required=True)
2457
2582
  semantic_draft.set_defaults(handler=semantic_draft_command)
2458
2583
 
2459
2584
  semantic_validate = sub.add_parser("semantic-validate")
2460
2585
  semantic_validate.add_argument("--install-root")
2461
2586
  semantic_validate.add_argument("--data-root")
2462
- semantic_validate.add_argument("--profile", default="default")
2587
+ semantic_validate.add_argument("--profile")
2463
2588
  semantic_validate.add_argument("--apply", action="store_true")
2464
2589
  semantic_validate.add_argument("--include-stack-trace", action="store_true")
2465
2590
  semantic_validate.set_defaults(handler=semantic_validate_command)
@@ -2467,7 +2592,7 @@ def build_parser() -> argparse.ArgumentParser:
2467
2592
  semantic_publish = sub.add_parser("semantic-publish")
2468
2593
  semantic_publish.add_argument("--install-root")
2469
2594
  semantic_publish.add_argument("--data-root")
2470
- semantic_publish.add_argument("--profile", default="default")
2595
+ semantic_publish.add_argument("--profile")
2471
2596
  semantic_publish.add_argument("--apply", action="store_true")
2472
2597
  semantic_publish.add_argument("--replace-bundle", action="store_true")
2473
2598
  semantic_publish.add_argument("--watch", action="store_true")
@@ -2477,7 +2602,7 @@ def build_parser() -> argparse.ArgumentParser:
2477
2602
  semantic_verify = sub.add_parser("semantic-verify")
2478
2603
  semantic_verify.add_argument("--install-root")
2479
2604
  semantic_verify.add_argument("--data-root")
2480
- semantic_verify.add_argument("--profile", default="default")
2605
+ semantic_verify.add_argument("--profile")
2481
2606
  semantic_verify.add_argument("--query-model")
2482
2607
  semantic_verify.add_argument("--query-payload", required=True)
2483
2608
  semantic_verify.add_argument("--execute", action="store_true")