salesforce-agent-optimizer 1.0.0__py3-none-any.whl

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.
Files changed (84) hide show
  1. salesforce_agent_optimizer/__init__.py +23 -0
  2. salesforce_agent_optimizer/cli.py +211 -0
  3. salesforce_agent_optimizer/doctor.py +172 -0
  4. salesforce_agent_optimizer/installer.py +416 -0
  5. salesforce_agent_optimizer/knowledge.py +492 -0
  6. salesforce_agent_optimizer/templates/AGENTS.md +32 -0
  7. salesforce_agent_optimizer/templates/SKILL.md +83 -0
  8. salesforce_agent_optimizer/templates/agents/openai.yaml +7 -0
  9. salesforce_agent_optimizer/templates/claude/SKILL.md +83 -0
  10. salesforce_agent_optimizer/templates/codex/SKILL.md +83 -0
  11. salesforce_agent_optimizer/templates/github/copilot-instructions.md +32 -0
  12. salesforce_agent_optimizer/templates/github/instructions/salesforce-agent-optimizer.instructions.md +34 -0
  13. salesforce_agent_optimizer/templates/references/agent-installation.md +112 -0
  14. salesforce_agent_optimizer/templates/references/agent-instruction-spine.md +27 -0
  15. salesforce_agent_optimizer/templates/references/architecture-solution.md +50 -0
  16. salesforce_agent_optimizer/templates/references/backend-apex.md +43 -0
  17. salesforce_agent_optimizer/templates/references/completion-artifacts.md +161 -0
  18. salesforce_agent_optimizer/templates/references/deletion-guardrails.md +70 -0
  19. salesforce_agent_optimizer/templates/references/delivery-methodology.md +155 -0
  20. salesforce_agent_optimizer/templates/references/frontend-lwc.md +45 -0
  21. salesforce_agent_optimizer/templates/references/knowledge-init.md +116 -0
  22. salesforce_agent_optimizer/templates/references/least-privilege-planning.md +54 -0
  23. salesforce_agent_optimizer/templates/references/metadata-dependencies.md +69 -0
  24. salesforce_agent_optimizer/templates/references/official-salesforce-sources.md +32 -0
  25. salesforce_agent_optimizer/templates/references/products-packages/index.md +45 -0
  26. salesforce_agent_optimizer/templates/references/products-packages/packages/advanced-approvals.md +30 -0
  27. salesforce_agent_optimizer/templates/references/products-packages/packages/box-intelligent-content-management.md +29 -0
  28. salesforce_agent_optimizer/templates/references/products-packages/packages/declarative-lookup-rollup-summaries.md +29 -0
  29. salesforce_agent_optimizer/templates/references/products-packages/packages/docusign-esignature-for-salesforce.md +30 -0
  30. salesforce_agent_optimizer/templates/references/products-packages/packages/fieldspy-field-usage-report.md +28 -0
  31. salesforce_agent_optimizer/templates/references/products-packages/packages/linkedin-sales-navigator-for-salesforce.md +29 -0
  32. salesforce_agent_optimizer/templates/references/products-packages/packages/org-check.md +28 -0
  33. salesforce_agent_optimizer/templates/references/products-packages/packages/query-studio-for-marketing-cloud.md +28 -0
  34. salesforce_agent_optimizer/templates/references/products-packages/packages/salesforce-adoption-dashboards.md +28 -0
  35. salesforce_agent_optimizer/templates/references/products-packages/packages/user-access-and-permissions-assistant.md +28 -0
  36. salesforce_agent_optimizer/templates/references/products-packages/packages/zoom-for-lightning.md +29 -0
  37. salesforce_agent_optimizer/templates/references/products-packages/products/agentforce.md +30 -0
  38. salesforce_agent_optimizer/templates/references/products-packages/products/commerce-cloud.md +29 -0
  39. salesforce_agent_optimizer/templates/references/products-packages/products/data-360-data-cloud.md +30 -0
  40. salesforce_agent_optimizer/templates/references/products-packages/products/einstein-ai.md +29 -0
  41. salesforce_agent_optimizer/templates/references/products-packages/products/experience-cloud.md +29 -0
  42. salesforce_agent_optimizer/templates/references/products-packages/products/industry-clouds.md +29 -0
  43. salesforce_agent_optimizer/templates/references/products-packages/products/marketing-cloud.md +29 -0
  44. salesforce_agent_optimizer/templates/references/products-packages/products/mobile-development.md +30 -0
  45. salesforce_agent_optimizer/templates/references/products-packages/products/mulesoft.md +29 -0
  46. salesforce_agent_optimizer/templates/references/products-packages/products/net-zero-cloud.md +29 -0
  47. salesforce_agent_optimizer/templates/references/products-packages/products/partner-prm.md +29 -0
  48. salesforce_agent_optimizer/templates/references/products-packages/products/sales-cloud.md +29 -0
  49. salesforce_agent_optimizer/templates/references/products-packages/products/salesforce-cpq.md +29 -0
  50. salesforce_agent_optimizer/templates/references/products-packages/products/salesforce-field-service.md +29 -0
  51. salesforce_agent_optimizer/templates/references/products-packages/products/salesforce-platform-data.md +29 -0
  52. salesforce_agent_optimizer/templates/references/products-packages/products/service-cloud.md +30 -0
  53. salesforce_agent_optimizer/templates/references/products-packages/products/slack.md +29 -0
  54. salesforce_agent_optimizer/templates/references/products-packages/products/success-plans-professional-services.md +27 -0
  55. salesforce_agent_optimizer/templates/references/products-packages/products/tableau.md +29 -0
  56. salesforce_agent_optimizer/templates/references/routing.md +28 -0
  57. salesforce_agent_optimizer/templates/references/salesforce-current-version.md +48 -0
  58. salesforce_agent_optimizer/templates/references/salesforce-version.json +40 -0
  59. salesforce_agent_optimizer/templates/references/sf-agent-cli-commands.md +434 -0
  60. salesforce_agent_optimizer/templates/references/sf-cli-token-patterns.md +50 -0
  61. salesforce_agent_optimizer/templates/references/sf-official-command-catalog.json +2793 -0
  62. salesforce_agent_optimizer/templates/references/sf-official-command-catalog.md +250 -0
  63. salesforce_agent_optimizer/templates/references/testing-and-manifest-guardrails.md +61 -0
  64. salesforce_agent_optimizer/templates/references/version-update.md +72 -0
  65. salesforce_agent_optimizer/templates/scripts/build_release_artifacts.py +100 -0
  66. salesforce_agent_optimizer/templates/scripts/generate_package_manifest.py +285 -0
  67. salesforce_agent_optimizer/templates/scripts/git_knowledge_push.py +126 -0
  68. salesforce_agent_optimizer/templates/scripts/knowledge_history.py +179 -0
  69. salesforce_agent_optimizer/templates/scripts/self_test.py +488 -0
  70. salesforce_agent_optimizer/templates/scripts/sf_agent_cli.py +1003 -0
  71. salesforce_agent_optimizer/templates/scripts/sf_catalog_build.py +120 -0
  72. salesforce_agent_optimizer/templates/scripts/sf_knowledge_init.py +606 -0
  73. salesforce_agent_optimizer/templates/scripts/sf_min.py +150 -0
  74. salesforce_agent_optimizer/templates/scripts/sf_version_update.py +140 -0
  75. salesforce_agent_optimizer/templates/scripts/sync_agent_instructions.py +181 -0
  76. salesforce_agent_optimizer/templates/scripts/validate_skill.py +39 -0
  77. salesforce_agent_optimizer/validation.py +572 -0
  78. salesforce_agent_optimizer/version_context.py +319 -0
  79. salesforce_agent_optimizer-1.0.0.dist-info/METADATA +360 -0
  80. salesforce_agent_optimizer-1.0.0.dist-info/RECORD +84 -0
  81. salesforce_agent_optimizer-1.0.0.dist-info/WHEEL +5 -0
  82. salesforce_agent_optimizer-1.0.0.dist-info/entry_points.txt +2 -0
  83. salesforce_agent_optimizer-1.0.0.dist-info/licenses/LICENSE +21 -0
  84. salesforce_agent_optimizer-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,23 @@
1
+ """Salesforce Agent Optimizer package."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib.metadata import PackageNotFoundError, version
6
+ from pathlib import Path
7
+
8
+
9
+ PACKAGE_NAME = "salesforce-agent-optimizer"
10
+
11
+
12
+ def get_version() -> str:
13
+ """Return the installed package version."""
14
+ try:
15
+ return version(PACKAGE_NAME)
16
+ except PackageNotFoundError:
17
+ source_version = Path(__file__).resolve().parents[2] / "VERSION"
18
+ if source_version.exists():
19
+ return source_version.read_text(encoding="utf-8").strip()
20
+ return "0.0.0+local"
21
+
22
+
23
+ __version__ = get_version()
@@ -0,0 +1,211 @@
1
+ """Command-line interface for Salesforce Agent Optimizer."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import sys
8
+ from pathlib import Path
9
+
10
+ from . import __version__
11
+ from .doctor import format_report, report_to_json, run_doctor
12
+ from .installer import install, project_destination, uninstall, update, user_destination
13
+ from .knowledge import format_knowledge_report, run_knowledge
14
+ from .validation import validate_auto
15
+ from .version_context import (
16
+ format_report as format_version_context_report,
17
+ scaffold as version_context_scaffold,
18
+ update as version_context_update,
19
+ validate as version_context_validate,
20
+ )
21
+
22
+
23
+ def build_parser() -> argparse.ArgumentParser:
24
+ parser = argparse.ArgumentParser(prog="sfao", description="Salesforce Agent Optimizer CLI")
25
+ subparsers = parser.add_subparsers(dest="command", required=True)
26
+
27
+ install_parser = subparsers.add_parser("install", help="Install agent skill files")
28
+ install_parser.add_argument("--project", action="store_true", help="Install into the current repository")
29
+ install_parser.add_argument(
30
+ "--platform",
31
+ choices=["codex", "claude", "copilot", "all"],
32
+ default="all",
33
+ help="Agent platform to install",
34
+ )
35
+ install_parser.add_argument("--target", type=Path, help="Override installation root")
36
+ install_parser.add_argument("--json", action="store_true", help="Emit compact JSON")
37
+
38
+ update_parser = subparsers.add_parser("update", help="Update generated installed files")
39
+ update_parser.add_argument("--project", action="store_true", help="Update files in the current repository")
40
+ update_parser.add_argument(
41
+ "--platform",
42
+ choices=["codex", "claude", "copilot", "all"],
43
+ default="all",
44
+ help="Agent platform to update",
45
+ )
46
+ update_parser.add_argument("--target", type=Path, help="Override installation root")
47
+ update_parser.add_argument("--json", action="store_true", help="Emit compact JSON")
48
+
49
+ uninstall_parser = subparsers.add_parser("uninstall", help="Remove generated installed files")
50
+ uninstall_parser.add_argument("--project", action="store_true", help="Remove files in the current repository")
51
+ uninstall_parser.add_argument(
52
+ "--platform",
53
+ choices=["codex", "claude", "copilot", "all"],
54
+ default="all",
55
+ help="Agent platform to uninstall",
56
+ )
57
+ uninstall_parser.add_argument("--target", type=Path, help="Override installation root")
58
+ uninstall_parser.add_argument("--yes", action="store_true", help="Confirm non-interactive uninstall")
59
+ uninstall_parser.add_argument("--json", action="store_true", help="Emit compact JSON")
60
+
61
+ doctor_parser = subparsers.add_parser("doctor", help="Diagnose environment and installed files")
62
+ doctor_parser.add_argument("--json", action="store_true", help="Emit JSON")
63
+ doctor_parser.add_argument("--root", type=Path, default=Path.cwd(), help="Root to inspect")
64
+ doctor_parser.add_argument("--summary", action="store_true", help="Emit compact summary")
65
+ doctor_parser.add_argument("--compact", action="store_true", help="Emit compact summary")
66
+ doctor_parser.add_argument("--verbose", action="store_true", help="Emit full diagnostics")
67
+
68
+ validate_parser = subparsers.add_parser("validate", help="Validate source tree or installation")
69
+ validate_parser.add_argument("--json", action="store_true", help="Emit JSON")
70
+ validate_parser.add_argument("--root", type=Path, default=Path.cwd(), help="Root to validate")
71
+ validate_parser.add_argument("--summary", action="store_true", help="Emit compact summary")
72
+ validate_parser.add_argument("--compact", action="store_true", help="Emit compact summary")
73
+ validate_parser.add_argument("--verbose", action="store_true", help="Emit validation details")
74
+
75
+ knowledge_parser = subparsers.add_parser("knowledge", help="Manage local Salesforce Knowledge")
76
+ knowledge_subparsers = knowledge_parser.add_subparsers(dest="knowledge_command", required=True)
77
+ for name in ("init", "refresh", "doctor"):
78
+ parser_for_command = knowledge_subparsers.add_parser(name, help=f"Knowledge {name}")
79
+ parser_for_command.add_argument("--project-root", type=Path, default=Path.cwd())
80
+ parser_for_command.add_argument("--target-org", help="Explicit org alias for optional enrichment")
81
+ parser_for_command.add_argument("--json", action="store_true", help="Emit compact JSON")
82
+ parser_for_command.add_argument("--summary", action="store_true", help="Emit compact summary")
83
+ parser_for_command.add_argument("--compact", action="store_true", help="Emit compact summary")
84
+ parser_for_command.add_argument("--verbose", action="store_true", help="Emit changed paths")
85
+ parser_for_command.add_argument("--max-items", type=int, help="Limit indexed entries")
86
+
87
+ version_context_parser = subparsers.add_parser(
88
+ "version-context",
89
+ help="Manage Salesforce release and API version context",
90
+ )
91
+ version_context_subparsers = version_context_parser.add_subparsers(
92
+ dest="version_context_command",
93
+ required=True,
94
+ )
95
+ for name in ("scaffold", "update", "validate"):
96
+ parser_for_command = version_context_subparsers.add_parser(
97
+ name,
98
+ help=f"Version-context {name}",
99
+ )
100
+ parser_for_command.add_argument("--root", type=Path, default=Path.cwd())
101
+ parser_for_command.add_argument("--json", action="store_true", help="Emit compact JSON")
102
+ parser_for_command.add_argument("--summary", action="store_true", help="Emit compact summary")
103
+ parser_for_command.add_argument("--compact", action="store_true", help="Emit compact summary")
104
+ parser_for_command.add_argument("--verbose", action="store_true", help="Emit details")
105
+ if name == "update":
106
+ parser_for_command.add_argument(
107
+ "--offline",
108
+ action="store_true",
109
+ help="Use existing official-source context without network checks",
110
+ )
111
+
112
+ subparsers.add_parser("version", help="Print package version")
113
+ return parser
114
+
115
+
116
+ def main(argv: list[str] | None = None) -> int:
117
+ parser = build_parser()
118
+ args = parser.parse_args(argv)
119
+ if args.command == "version":
120
+ print(f"salesforce-agent-optimizer {__version__}")
121
+ return 0
122
+ if args.command == "install":
123
+ target = args.target or (project_destination() if args.project else user_destination())
124
+ report = install(target, project=args.project, platform=args.platform)
125
+ print_operation_summary("install", report, json_output=args.json)
126
+ return 0 if report.ok else 1
127
+ if args.command == "update":
128
+ target = args.target or (project_destination() if args.project else user_destination())
129
+ report = update(target, project=args.project, platform=args.platform)
130
+ print_operation_summary("update", report, json_output=args.json)
131
+ return 0 if report.ok else 1
132
+ if args.command == "uninstall":
133
+ target = args.target or (project_destination() if args.project else user_destination())
134
+ report = uninstall(target, project=args.project, platform=args.platform, yes=args.yes)
135
+ print_operation_summary("uninstall", report, json_output=args.json)
136
+ return 0 if report.ok else 1
137
+ if args.command == "doctor":
138
+ report = run_doctor(args.root)
139
+ print(report_to_json(report) if args.json else format_report(report, verbose=args.verbose), end="")
140
+ return 1 if report.has_errors else 0
141
+ if args.command == "validate":
142
+ result = validate_auto(args.root, expected_version=__version__)
143
+ if args.json:
144
+ print(json.dumps(result.to_dict(), separators=(",", ":"), sort_keys=True))
145
+ else:
146
+ output = format_validation_result(result, verbose=args.verbose)
147
+ stream = sys.stdout if result.ok else sys.stderr
148
+ print(output, end="", file=stream)
149
+ return 0 if result.ok else 1
150
+ if args.command == "knowledge":
151
+ report = run_knowledge(
152
+ args.knowledge_command,
153
+ args.project_root,
154
+ target_org=args.target_org,
155
+ max_items=args.max_items,
156
+ )
157
+ if args.json:
158
+ print(json.dumps(report.to_dict(), separators=(",", ":"), sort_keys=True))
159
+ else:
160
+ print(format_knowledge_report(report, verbose=args.verbose), end="")
161
+ return 0 if report.ok else 1
162
+ if args.command == "version-context":
163
+ if args.version_context_command == "scaffold":
164
+ report = version_context_scaffold(args.root)
165
+ elif args.version_context_command == "update":
166
+ report = version_context_update(args.root, offline=args.offline)
167
+ else:
168
+ report = version_context_validate(args.root)
169
+ if args.json:
170
+ print(json.dumps(report.to_dict(), separators=(",", ":"), sort_keys=True))
171
+ else:
172
+ print(format_version_context_report(report, verbose=args.verbose), end="")
173
+ return 0 if report.ok else 1
174
+ parser.print_help()
175
+ return 2
176
+
177
+
178
+ def format_validation_result(result, verbose: bool = False) -> str:
179
+ status = "OK" if result.ok else "ERROR"
180
+ lines = [f"Salesforce Agent Optimizer validation: {status}"]
181
+ if result.warnings or result.errors:
182
+ for error in result.errors:
183
+ lines.append(f"ERROR: {error}")
184
+ for warning in result.warnings:
185
+ lines.append(f"WARN: {warning}")
186
+ else:
187
+ lines.append("No warnings or errors.")
188
+ if verbose and result.ok:
189
+ lines.append("Validated required files, versions, frontmatter, YAML, TOML, JSON, Python, and text shape.")
190
+ return "\n".join(lines) + "\n"
191
+
192
+
193
+ def print_operation_summary(action: str, report, json_output: bool = False) -> None:
194
+ if json_output:
195
+ print(json.dumps(report.to_dict(), separators=(",", ":"), sort_keys=True))
196
+ return
197
+ print(f"Salesforce Agent Optimizer {action} summary")
198
+ for label in ("installed", "updated", "removed", "skipped", "stale", "warnings", "errors"):
199
+ values = getattr(report, label)
200
+ print(f"{label.title()}: {len(values)}")
201
+ for item in values[:20]:
202
+ print(f"- {item}")
203
+ if len(values) > 20:
204
+ print(f"- ... {len(values) - 20} more")
205
+ print("Next steps:")
206
+ print("- Run: sfao doctor")
207
+ print("- Run: sfao validate")
208
+
209
+
210
+ if __name__ == "__main__":
211
+ raise SystemExit(main())
@@ -0,0 +1,172 @@
1
+ """Environment diagnostics for Salesforce Agent Optimizer."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import os
7
+ import platform
8
+ import shutil
9
+ import site
10
+ import subprocess
11
+ import sys
12
+ from dataclasses import dataclass, field
13
+ from pathlib import Path
14
+ from typing import Any
15
+
16
+ from . import __version__
17
+ from .validation import SKILL_NAME, validate_auto
18
+
19
+
20
+ @dataclass
21
+ class Check:
22
+ name: str
23
+ status: str
24
+ detail: str = ""
25
+
26
+
27
+ @dataclass
28
+ class DoctorReport:
29
+ sections: dict[str, list[Check]] = field(default_factory=dict)
30
+
31
+ def add(self, section: str, name: str, status: str, detail: str = "") -> None:
32
+ self.sections.setdefault(section, []).append(Check(name, status, detail))
33
+
34
+ @property
35
+ def has_errors(self) -> bool:
36
+ return any(check.status == "ERROR" for checks in self.sections.values() for check in checks)
37
+
38
+ @property
39
+ def has_warnings(self) -> bool:
40
+ return any(check.status == "WARN" for checks in self.sections.values() for check in checks)
41
+
42
+ @property
43
+ def status(self) -> str:
44
+ if self.has_errors:
45
+ return "ERROR"
46
+ if self.has_warnings:
47
+ return "WARN"
48
+ return "OK"
49
+
50
+ def to_dict(self) -> dict[str, Any]:
51
+ payload: dict[str, Any] = {"ok": not self.has_errors, "status": self.status}
52
+ payload.update(
53
+ {
54
+ section: [check.__dict__ for check in checks]
55
+ for section, checks in self.sections.items()
56
+ }
57
+ )
58
+ return payload
59
+
60
+
61
+ def run_doctor(root: Path | None = None) -> DoctorReport:
62
+ root = (root or Path.cwd()).resolve()
63
+ report = DoctorReport()
64
+ report.add("Core", "Package", "OK", f"salesforce-agent-optimizer v{__version__}")
65
+ py_status = "OK" if sys.version_info >= (3, 10) else "ERROR"
66
+ report.add("Core", "Python", py_status, platform.python_version())
67
+ report.add("Core", "OS", "OK", platform.system() or sys.platform)
68
+ report.add("Core", "Git", "OK" if shutil.which("git") else "WARN", shutil.which("git") or "not found")
69
+ report.add(
70
+ "Core",
71
+ "Salesforce CLI sf",
72
+ "OK" if shutil.which("sf") else "WARN",
73
+ shutil.which("sf") or "not found",
74
+ )
75
+ report.add(
76
+ "Core",
77
+ "Git repository",
78
+ "OK" if is_git_repo(root) else "WARN",
79
+ str(root),
80
+ )
81
+ report.add(
82
+ "Core",
83
+ "Salesforce DX project",
84
+ "OK" if (root / "sfdx-project.json").exists() else "WARN",
85
+ "sfdx-project.json found" if (root / "sfdx-project.json").exists() else "not found",
86
+ )
87
+ report.add(
88
+ "Agent adapters",
89
+ "Codex skill",
90
+ "OK" if (root / ".agents" / "skills" / SKILL_NAME / "SKILL.md").exists() else "WARN",
91
+ ".agents/skills/salesforce-agent-optimizer",
92
+ )
93
+ report.add(
94
+ "Agent adapters",
95
+ "Claude skill",
96
+ "OK" if (root / ".claude" / "skills" / SKILL_NAME / "SKILL.md").exists() else "WARN",
97
+ ".claude/skills/salesforce-agent-optimizer",
98
+ )
99
+ copilot_ok = (root / ".github" / "copilot-instructions.md").exists() and (
100
+ root / ".github" / "instructions" / "salesforce-agent-optimizer.instructions.md"
101
+ ).exists()
102
+ report.add("Agent adapters", "GitHub Copilot instructions", "OK" if copilot_ok else "WARN")
103
+ report.add("Agent adapters", "AGENTS.md", "OK" if (root / "AGENTS.md").exists() else "WARN")
104
+ validation = validate_auto(root, expected_version=__version__)
105
+ report.add(
106
+ "Validation",
107
+ "Skill package",
108
+ "OK" if validation.ok else "ERROR",
109
+ "valid" if validation.ok else "; ".join(validation.errors[:3]),
110
+ )
111
+ if validation.warnings:
112
+ report.add("Validation", "Warnings", "WARN", "; ".join(validation.warnings[:3]))
113
+ report.add("Validation", "Version alignment", "OK" if validation.ok else "ERROR", f"v{__version__}")
114
+ if platform.system().lower().startswith("windows"):
115
+ report.add("Windows", "PATH", "OK" if user_scripts_on_path() else "WARN", windows_path_detail())
116
+ return report
117
+
118
+
119
+ def is_git_repo(root: Path) -> bool:
120
+ completed = subprocess.run(
121
+ ["git", "-C", str(root), "rev-parse", "--is-inside-work-tree"],
122
+ text=True,
123
+ stdout=subprocess.DEVNULL,
124
+ stderr=subprocess.DEVNULL,
125
+ check=False,
126
+ )
127
+ return completed.returncode == 0
128
+
129
+
130
+ def user_scripts_on_path() -> bool:
131
+ scripts = Path(site.USER_BASE) / "Scripts"
132
+ path_parts = [Path(part) for part in (os.environ.get("PATH") or "").split(os.pathsep) if part]
133
+ return any(part == scripts for part in path_parts)
134
+
135
+
136
+ def windows_path_detail() -> str:
137
+ scripts = Path(site.USER_BASE) / "Scripts"
138
+ return f"{scripts} is {'on' if user_scripts_on_path() else 'not on'} PATH"
139
+
140
+
141
+ def format_report(report: DoctorReport, verbose: bool = False) -> str:
142
+ lines = [f"Salesforce Agent Optimizer Doctor: {report.status}"]
143
+ if not verbose:
144
+ issues = [
145
+ (section, check)
146
+ for section, checks in report.sections.items()
147
+ for check in checks
148
+ if check.status in {"WARN", "ERROR"}
149
+ ]
150
+ if issues:
151
+ lines.append("Warnings and errors:")
152
+ for section, check in issues:
153
+ detail = f" {check.detail}" if check.detail else ""
154
+ lines.append(f"- {section} / {check.name}: {check.status}{detail}")
155
+ else:
156
+ lines.append("No warnings or errors.")
157
+ lines.append("Use --verbose for full diagnostics.")
158
+ return "\n".join(lines).rstrip() + "\n"
159
+ lines.append("")
160
+ for section, checks in report.sections.items():
161
+ lines.append(f"{section}:")
162
+ for check in checks:
163
+ detail = f" {check.detail}" if check.detail else ""
164
+ lines.append(f"- {check.name}: {check.status}{detail}")
165
+ lines.append("")
166
+ lines.append("Status:")
167
+ lines.append("Everything looks good." if not report.has_errors else "Problems found.")
168
+ return "\n".join(lines).rstrip() + "\n"
169
+
170
+
171
+ def report_to_json(report: DoctorReport) -> str:
172
+ return json.dumps(report.to_dict(), separators=(",", ":"), sort_keys=True) + "\n"