codeforerunner 0.4.2__py3-none-any.whl → 0.4.3__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.
@@ -1,6 +1,8 @@
1
+ """codeforerunner — prompt-first repo documentation tooling."""
2
+
1
3
  from importlib.metadata import PackageNotFoundError, version
2
4
 
3
5
  try:
4
6
  __version__ = version("codeforerunner")
5
- except PackageNotFoundError:
7
+ except PackageNotFoundError: # pragma: no cover
6
8
  __version__ = "0.0.0" # running from source without install
codeforerunner/check.py CHANGED
@@ -11,6 +11,8 @@ from codeforerunner.config import CheckConfig
11
11
 
12
12
  @dataclass(frozen=True)
13
13
  class Violation:
14
+ """Single rule match: which doc, which line, which rule, and what it means."""
15
+
14
16
  path: Path
15
17
  line: int
16
18
  rule_id: str
codeforerunner/cli.py CHANGED
@@ -61,7 +61,7 @@ def _doc_for(args: argparse.Namespace, task: str) -> int:
61
61
 
62
62
 
63
63
  def cmd_init(args: argparse.Namespace) -> int:
64
- """Default + --agents-only = onboarding bundle only. --full prepends scan."""
64
+ """Emit onboarding bundle; prepend scan bundle when --full is given."""
65
65
  if getattr(args, "full", False):
66
66
  sys.stdout.write("<!-- forerunner init --full: section 1/2 (scan) -->\n")
67
67
  rc = _doc_for(args, "scan")
@@ -72,6 +72,7 @@ def cmd_init(args: argparse.Namespace) -> int:
72
72
 
73
73
 
74
74
  def cmd_scan(args: argparse.Namespace) -> int:
75
+ """Emit the scan prompt bundle and hint about FORERUNNER_SCAN_DONE."""
75
76
  rc = _doc_for(args, "scan")
76
77
  if rc == 0:
77
78
  print(
@@ -102,6 +103,7 @@ def cmd_check(args: argparse.Namespace) -> int:
102
103
 
103
104
 
104
105
  def cmd_mcp_server(args: argparse.Namespace) -> int:
106
+ """Start the stdio MCP server exposing prompt bundles as tools."""
105
107
  from codeforerunner import mcp_server
106
108
  try:
107
109
  prompts_root = find_prompts_root(args.repo)
@@ -133,6 +135,7 @@ def cmd_generate(args: argparse.Namespace) -> int:
133
135
  if rc != 0:
134
136
  return rc
135
137
 
138
+
136
139
  explicit_provider = args.provider or (cfg.provider if cfg else None)
137
140
  provider_name = explicit_provider or "anthropic"
138
141
  model = args.model or (cfg.model if cfg else None)
@@ -193,6 +196,7 @@ def cmd_generate(args: argparse.Namespace) -> int:
193
196
 
194
197
 
195
198
  def cmd_doctor(args: argparse.Namespace) -> int:
199
+ """Run health checks and print a single-screen report; exit 1 on errors."""
196
200
  from codeforerunner import doctor
197
201
  from codeforerunner.config import CONFIG_FILENAME
198
202
  root = Path(args.repo).resolve() if args.repo else Path.cwd()
@@ -209,6 +213,7 @@ def cmd_doctor(args: argparse.Namespace) -> int:
209
213
 
210
214
 
211
215
  def build_parser() -> argparse.ArgumentParser:
216
+ """Build and return the top-level argument parser with all subcommands registered."""
212
217
  p = argparse.ArgumentParser(
213
218
  prog="forerunner",
214
219
  description="Prompt-first repo documentation tooling. Thin CLI; product logic in prompts/.",
@@ -285,6 +290,7 @@ def build_parser() -> argparse.ArgumentParser:
285
290
 
286
291
 
287
292
  def main(argv: Sequence[str] | None = None) -> int:
293
+ """Parse argv and dispatch to the appropriate subcommand handler."""
288
294
  parser = build_parser()
289
295
  args = parser.parse_args(argv)
290
296
  if not hasattr(args, "repo"):
codeforerunner/config.py CHANGED
@@ -19,6 +19,8 @@ class ConfigError(Exception):
19
19
 
20
20
  @dataclass(frozen=True)
21
21
  class CheckConfig:
22
+ """Drift-check task configuration: severity gates and path filters."""
23
+
22
24
  block_on: tuple[str, ...] = ("HIGH", "MEDIUM")
23
25
  warn_on: tuple[str, ...] = ("LOW",)
24
26
  enabled_rules: tuple[str, ...] | None = None # None = all rules enabled
@@ -27,6 +29,8 @@ class CheckConfig:
27
29
 
28
30
  @dataclass(frozen=True)
29
31
  class VersionAuditConfig:
32
+ """Version-audit task configuration: staleness window and live EOL data toggle."""
33
+
30
34
  enabled: bool = True
31
35
  stale_after_days: int = 30
32
36
  fetch_live_eol_data: bool = False
@@ -34,6 +38,8 @@ class VersionAuditConfig:
34
38
 
35
39
  @dataclass(frozen=True)
36
40
  class ForerunnerConfig:
41
+ """Top-level forerunner.config.yaml configuration."""
42
+
37
43
  provider: str = "anthropic"
38
44
  model: str = "claude-opus-4-7"
39
45
  approaching_eol_threshold_months: int = 6
@@ -52,7 +58,7 @@ def _require_type(value: Any, expected: type, field_name: str) -> Any:
52
58
 
53
59
 
54
60
  def _coerce_str_tuple(value: Any, field_name: str) -> tuple[str, ...]:
55
- if value is None:
61
+ if value is None: # pragma: no cover - callers supply defaults, never pass None
56
62
  return ()
57
63
  if not isinstance(value, list):
58
64
  raise ConfigError(f"{field_name}: expected list, got {type(value).__name__}")
@@ -71,7 +77,7 @@ def _parse_api_key_env(raw: Any) -> dict[str, str]:
71
77
  raise ConfigError(f"api_key_env: expected dict, got {type(raw).__name__}")
72
78
  out: dict[str, str] = {}
73
79
  for k, v in raw.items():
74
- if not isinstance(k, str):
80
+ if not isinstance(k, str): # pragma: no cover - YAML keys are always strings
75
81
  raise ConfigError(
76
82
  f"api_key_env: keys must be strings, got {type(k).__name__}"
77
83
  )
codeforerunner/doctor.py CHANGED
@@ -33,6 +33,8 @@ _DEFAULT_PROVIDER_ENV = {
33
33
 
34
34
  @dataclass(frozen=True)
35
35
  class Finding:
36
+ """Single health-check result with severity, check name, and human message."""
37
+
36
38
  severity: str # "ok" | "warn" | "error"
37
39
  check: str
38
40
  message: str
@@ -244,7 +246,7 @@ def _check_config_loadable(repo: Path) -> list[Finding]:
244
246
 
245
247
 
246
248
  def _skill_mode_active() -> bool:
247
- """True if any installed skill destination has managed markers agent IS the model."""
249
+ """Return True if any installed skill destination has managed markers (agent is the model)."""
248
250
  for dest in _installed_skill_destinations():
249
251
  if dest.exists():
250
252
  try:
@@ -315,16 +317,13 @@ def _check_provider_api_key(repo: Path) -> list[Finding]:
315
317
  env_var = cfg.api_key_env.get(provider) or _DEFAULT_PROVIDER_ENV.get(provider, "")
316
318
  if os.environ.get(env_var):
317
319
  return [Finding("ok", "provider-api-key", f"{provider}: {env_var} is set")]
320
+ # Emit the same warning regardless of skill mode: an explicit provider in config
321
+ # means the user intends to use that provider, so a missing key is always a real problem.
318
322
  return [
319
323
  Finding(
320
324
  "warn",
321
325
  "provider-api-key",
322
- f"{provider}: ${env_var} is not set; `forerunner generate` will refuse to run"
323
- + (
324
- " (use `--prompt-only` for key-free bundle output)"
325
- if _skill_mode_active()
326
- else ""
327
- ),
326
+ f"{provider}: ${env_var} is not set; `forerunner generate` will refuse to run",
328
327
  )
329
328
  ]
330
329
 
@@ -348,10 +347,12 @@ tasks:
348
347
 
349
348
 
350
349
  def starter_config() -> str:
350
+ """Return the default forerunner.config.yaml content written by --fix."""
351
351
  return _STARTER_CONFIG
352
352
 
353
353
 
354
354
  def run(repo: Path, run_scripts: bool = False) -> list[Finding]:
355
+ """Run all health checks against *repo* and return findings."""
355
356
  repo = repo.resolve()
356
357
  findings: list[Finding] = []
357
358
  findings.extend(_check_skill_body_parity(repo, run_scripts=run_scripts))
@@ -363,16 +364,18 @@ def run(repo: Path, run_scripts: bool = False) -> list[Finding]:
363
364
 
364
365
 
365
366
  def format_report(findings: list[Finding]) -> str:
367
+ """Format findings as a human-readable report string with a summary line."""
366
368
  lines = [f"[{f.severity}] {f.check}: {f.message}" for f in findings]
367
369
  counts: dict[str, int] = {"ok": 0, "warn": 0, "error": 0}
368
370
  for f in findings:
369
- counts[f.severity] = counts.get(f.severity, 0) + 1
371
+ counts[f.severity] += 1
370
372
  summary = f"summary: {counts['ok']} ok, {counts['warn']} warn, {counts['error']} error"
371
373
  lines.append(summary)
372
374
  return "\n".join(lines)
373
375
 
374
376
 
375
377
  def main(argv: list[str] | None = None) -> int:
378
+ """Entry point for `forerunner doctor`; returns 1 when any finding is an error."""
376
379
  parser = argparse.ArgumentParser(
377
380
  prog="forerunner doctor",
378
381
  description="Single-screen health report for codeforerunner repo.",
@@ -41,6 +41,8 @@ TASK_SKILL_SLUGS: tuple[str, ...] = (
41
41
 
42
42
  @dataclass(frozen=True)
43
43
  class Target:
44
+ """Resolved install destination: agent name + absolute path."""
45
+
44
46
  name: str
45
47
  path: Path
46
48
 
@@ -50,6 +52,7 @@ def _home() -> Path:
50
52
 
51
53
 
52
54
  def resolve_target(agent: str, override: Path | None) -> Target:
55
+ """Return the default install Target for the given agent, or use override path."""
53
56
  if agent == "generic":
54
57
  if override is None:
55
58
  raise ValueError("generic target requires --path PATH")
@@ -126,6 +129,7 @@ def install_all_skills(
126
129
 
127
130
 
128
131
  def resolve_marketplace_target(agent: str, override: Path | None) -> Target:
132
+ """Return the marketplace install Target for the given agent, or use override path."""
129
133
  if agent == "generic":
130
134
  if override is None:
131
135
  raise ValueError("generic marketplace target requires --path PATH")
@@ -181,6 +185,7 @@ def render(source_text: str, dest_existing: str | None, agent: str) -> str:
181
185
 
182
186
 
183
187
  def find_markers(text: str) -> tuple[int, int] | None:
188
+ """Return (start, end) byte offsets of the managed region, or None if absent."""
184
189
  a = text.find(MARKER_BEGIN)
185
190
  if a < 0:
186
191
  return None
@@ -202,12 +207,15 @@ def overlay(dest_text: str, source_body: str) -> str:
202
207
 
203
208
  @dataclass
204
209
  class Plan:
210
+ """Pending install action computed by plan_install or plan_marketplace."""
211
+
205
212
  action: str # "create" | "update" | "skip" | "abort"
206
213
  reason: str
207
214
  target: Target
208
215
  new_content: str | None = None
209
216
 
210
217
  def write(self) -> None:
218
+ """Execute the plan: create or update the destination file."""
211
219
  if self.action in ("skip", "abort"):
212
220
  return
213
221
  assert self.new_content is not None
@@ -306,6 +314,7 @@ def install(
306
314
  out=None,
307
315
  err=None,
308
316
  ) -> int:
317
+ """Run one install operation (skill or marketplace). Returns an EXIT_* code."""
309
318
  out = out or sys.stdout
310
319
  err = err or sys.stderr
311
320
 
@@ -356,6 +365,7 @@ def install(
356
365
 
357
366
 
358
367
  def add_subparser(sub: argparse._SubParsersAction) -> None:
368
+ """Register the `forerunner install` subcommand onto *sub*."""
359
369
  p = sub.add_parser("install", help="install skill(s) into agent-specific directories (D.installer)")
360
370
  p.add_argument("agent", choices=["codex", "claude", "generic"], nargs="?",
361
371
  help="target agent (omit with --all to install to all detected agents)")
@@ -114,6 +114,7 @@ def _handle(prompts_root: Path, msg: dict[str, Any], state: dict[str, Any]) -> d
114
114
 
115
115
 
116
116
  def serve(prompts_root: Path, stdin: Iterable[str] = sys.stdin, stdout=sys.stdout, stderr=sys.stderr) -> int:
117
+ """Run the JSON-RPC 2.0 MCP server loop over *stdin*/*stdout* until EOF."""
117
118
  state: dict[str, Any] = {"scan_called": False, "initialized": False}
118
119
  for raw in stdin:
119
120
  line = raw.strip()
@@ -141,6 +142,7 @@ def serve(prompts_root: Path, stdin: Iterable[str] = sys.stdin, stdout=sys.stdou
141
142
 
142
143
 
143
144
  def main(argv: list[str] | None = None) -> int:
145
+ """Locate prompts root and start the MCP server; returns 2 if prompts not found."""
144
146
  try:
145
147
  prompts_root = find_prompts_root()
146
148
  except FileNotFoundError as e:
@@ -149,5 +151,5 @@ def main(argv: list[str] | None = None) -> int:
149
151
  return serve(prompts_root)
150
152
 
151
153
 
152
- if __name__ == "__main__":
154
+ if __name__ == "__main__": # pragma: no cover
153
155
  raise SystemExit(main())
@@ -30,6 +30,7 @@ REGISTRY: dict[str, type] = {
30
30
 
31
31
 
32
32
  def get(name: str) -> type:
33
+ """Return the provider class for *name*, or raise ProviderError if unknown."""
33
34
  if name not in REGISTRY:
34
35
  raise ProviderError(
35
36
  f"unknown provider '{name}' (expected one of {sorted(REGISTRY)})"
@@ -11,6 +11,8 @@ from codeforerunner.providers.base import CompletionResult, ProviderError
11
11
 
12
12
 
13
13
  class AnthropicProvider:
14
+ """Anthropic Messages API provider using stdlib HTTP."""
15
+
14
16
  name = "anthropic"
15
17
  default_env_var = "ANTHROPIC_API_KEY"
16
18
  default_model = "claude-opus-4-7"
@@ -24,6 +26,7 @@ class AnthropicProvider:
24
26
  model: str | None = None,
25
27
  api_key: str | None = None,
26
28
  ) -> CompletionResult:
29
+ """Send *prompt* to the Anthropic Messages API and return the full response."""
27
30
  if not api_key:
28
31
  raise ProviderError(f"missing API key (set ${self.default_env_var})")
29
32
  model = model or self.default_model
@@ -68,6 +71,7 @@ class AnthropicProvider:
68
71
  model: str | None = None,
69
72
  api_key: str | None = None,
70
73
  ) -> Iterator[str]:
74
+ """Yield text chunks from the Anthropic streaming Messages API."""
71
75
  if not api_key:
72
76
  raise ProviderError(f"missing API key (set ${self.default_env_var})")
73
77
  model = model or self.default_model
@@ -8,12 +8,16 @@ from typing import Iterator, Protocol
8
8
 
9
9
  @dataclass(frozen=True)
10
10
  class CompletionResult:
11
+ """Completed text response returned by a provider."""
12
+
11
13
  text: str
12
14
  model: str
13
15
  usage: dict | None = None # provider-reported token counts; None if unknown
14
16
 
15
17
 
16
18
  class Provider(Protocol):
19
+ """Structural protocol that all LLM provider classes must satisfy."""
20
+
17
21
  name: str
18
22
  default_env_var: str # e.g. "ANTHROPIC_API_KEY"
19
23
  default_model: str # provider's recommended default
@@ -24,7 +28,9 @@ class Provider(Protocol):
24
28
  prompt: str,
25
29
  model: str | None = None,
26
30
  api_key: str | None = None,
27
- ) -> CompletionResult: ...
31
+ ) -> CompletionResult:
32
+ """Send *prompt* and return the full completion result."""
33
+ ...
28
34
 
29
35
  def stream(
30
36
  self,
@@ -32,7 +38,9 @@ class Provider(Protocol):
32
38
  prompt: str,
33
39
  model: str | None = None,
34
40
  api_key: str | None = None,
35
- ) -> Iterator[str]: ...
41
+ ) -> Iterator[str]:
42
+ """Yield text chunks from *prompt* as they arrive from the provider."""
43
+ ...
36
44
 
37
45
 
38
46
  class ProviderError(Exception):
@@ -12,6 +12,8 @@ from codeforerunner.providers.base import CompletionResult, ProviderError
12
12
 
13
13
 
14
14
  class GoogleProvider:
15
+ """Google Gemini generateContent provider using stdlib HTTP."""
16
+
15
17
  name = "google"
16
18
  default_env_var = "GOOGLE_API_KEY"
17
19
  default_model = "gemini-2.5-pro"
@@ -33,6 +35,7 @@ class GoogleProvider:
33
35
  model: str | None = None,
34
36
  api_key: str | None = None,
35
37
  ) -> CompletionResult:
38
+ """Send *prompt* to the Gemini generateContent endpoint and return the full response."""
36
39
  if not api_key:
37
40
  raise ProviderError(f"missing API key (set ${self.default_env_var})")
38
41
  model = model or self.default_model
@@ -75,6 +78,7 @@ class GoogleProvider:
75
78
  model: str | None = None,
76
79
  api_key: str | None = None,
77
80
  ) -> Iterator[str]:
81
+ """Yield text chunks from the Gemini streaming generateContent endpoint."""
78
82
  if not api_key:
79
83
  raise ProviderError(f"missing API key (set ${self.default_env_var})")
80
84
  model = model or self.default_model
@@ -20,7 +20,7 @@ def _validate_ollama_base(base: str) -> None:
20
20
  """Reject URLs that look like cloud metadata endpoints or use unexpected schemes."""
21
21
  try:
22
22
  parsed = urllib.parse.urlparse(base)
23
- except Exception as e:
23
+ except Exception as e: # pragma: no cover - urlparse never raises
24
24
  raise ValueError(f"OLLAMA_HOST: invalid URL: {e}") from e
25
25
  if parsed.scheme not in ("http", "https"):
26
26
  raise ValueError(
@@ -46,6 +46,8 @@ def is_available(host: str | None = None) -> bool:
46
46
 
47
47
 
48
48
  class OllamaProvider:
49
+ """Ollama local provider using stdlib HTTP."""
50
+
49
51
  name = "ollama"
50
52
  default_env_var = "OLLAMA_HOST"
51
53
  default_model = "llama3"
@@ -57,6 +59,7 @@ class OllamaProvider:
57
59
  model: str | None = None,
58
60
  api_key: str | None = None,
59
61
  ) -> CompletionResult:
62
+ """Send *prompt* to the Ollama /api/generate endpoint and return the full response."""
60
63
  # api_key is interpreted as a base URL override; fall back to env then default.
61
64
  base = api_key or os.environ.get(self.default_env_var) or DEFAULT_HOST
62
65
  base = base.rstrip("/")
@@ -96,6 +99,7 @@ class OllamaProvider:
96
99
  model: str | None = None,
97
100
  api_key: str | None = None,
98
101
  ) -> Iterator[str]:
102
+ """Yield text chunks from the Ollama /api/generate streaming endpoint."""
99
103
  base = api_key or os.environ.get(self.default_env_var) or DEFAULT_HOST
100
104
  base = base.rstrip("/")
101
105
  _validate_ollama_base(base)
@@ -11,6 +11,8 @@ from codeforerunner.providers.base import CompletionResult, ProviderError
11
11
 
12
12
 
13
13
  class OpenAIProvider:
14
+ """OpenAI chat completions provider using stdlib HTTP."""
15
+
14
16
  name = "openai"
15
17
  default_env_var = "OPENAI_API_KEY"
16
18
  default_model = "gpt-4o"
@@ -24,6 +26,7 @@ class OpenAIProvider:
24
26
  model: str | None = None,
25
27
  api_key: str | None = None,
26
28
  ) -> CompletionResult:
29
+ """Send *prompt* to the OpenAI chat completions endpoint and return the full response."""
27
30
  if not api_key:
28
31
  raise ProviderError(f"missing API key (set ${self.default_env_var})")
29
32
  model = model or self.default_model
@@ -66,6 +69,7 @@ class OpenAIProvider:
66
69
  model: str | None = None,
67
70
  api_key: str | None = None,
68
71
  ) -> Iterator[str]:
72
+ """Yield text chunks from the OpenAI streaming chat completions endpoint."""
69
73
  if not api_key:
70
74
  raise ProviderError(f"missing API key (set ${self.default_env_var})")
71
75
  model = model or self.default_model
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codeforerunner
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Summary: Model-agnostic repository documentation tooling (prompt-first; thin CLI).
5
5
  Author: Derek Palmer
6
6
  License-Expression: LicenseRef-Codeforerunner-SAL-0.1
@@ -1,11 +1,11 @@
1
- codeforerunner/__init__.py,sha256=4ItVS_FzLddTK77jExpkV3QJ1nHl2Bh-QIujM7Hg_5w,205
1
+ codeforerunner/__init__.py,sha256=lDClMqfAXApyQaPIWGp01yvS0zWJC-7sXTCRKPqit9M,292
2
2
  codeforerunner/bundle.py,sha256=2GByXu-oFbplWpCJuGnF_qobcHqv8YjyTZX1BU4WoJM,2053
3
- codeforerunner/check.py,sha256=5sJVwMMSvVCrRmwBIunYbn2pINroUjONrVJAs5ov3O4,8188
4
- codeforerunner/cli.py,sha256=Jxj-x_GwZO74l86ImrFwF0korKTxL2aKWLpcyGUId1U,11058
5
- codeforerunner/config.py,sha256=wnqJmMq1cnCJpOvFlGSpztASED1G0BYyyhOAumkTxkY,6117
6
- codeforerunner/doctor.py,sha256=f6atn2_fbZYAygCwCuU6lg5fsZprUtavWX5n9edmARc,12771
7
- codeforerunner/installer.py,sha256=d5Ymei-nnVYXtGIypV6Ocse8QGeXMY6w-Cw-qo2a5NA,13645
8
- codeforerunner/mcp_server.py,sha256=HuoGqYLBwJQgngqT_2rtdqh7LztX63rBAX_7YZjBpzI,5072
3
+ codeforerunner/check.py,sha256=HhhTuoFUiT2hjeK6JwjZknplJf43GqdSwZnz_V7G8n0,8272
4
+ codeforerunner/cli.py,sha256=yWM72NR8roIM63zBFe3ibzxkDVHpD9X_-HueAdnNvo0,11442
5
+ codeforerunner/config.py,sha256=CC9JhlKv4L3b7cRc4BiB9PHKVRoibbkBGHRBWjoZKpM,6454
6
+ codeforerunner/doctor.py,sha256=GjMJpjXqrn4nCtkbFu22HvApR5dqLp0dMSDlXrxJ1Ys,13164
7
+ codeforerunner/installer.py,sha256=SPBr6Tmfpy3SmKaGQf-P_AhGvjbBz3lRNjGdU3-H-xg,14279
8
+ codeforerunner/mcp_server.py,sha256=DtlR1e9JsRabyB42tboq7hC3yate8M5UoxyAYUQbn0M,5260
9
9
  codeforerunner/prompts/partials/context-format.md,sha256=WNfkr4kf2Awj0R8wLOrFotEiYCe6hfKTq5eA3Rt5_Xw,817
10
10
  codeforerunner/prompts/partials/output-rules.md,sha256=vfIAX-ImxCa-MVAeNH896uSIO7-cKbJd0KohkgHIiD8,1731
11
11
  codeforerunner/prompts/partials/stack-hints.md,sha256=8E2qELhk-hve2ULSdmiFK48LE4Aprhmuasqr6A1K2QU,2001
@@ -22,15 +22,15 @@ codeforerunner/prompts/tasks/review.md,sha256=IRdIXAKvv0JMOE5WtrnlO1Cd4LHXtcJqb1
22
22
  codeforerunner/prompts/tasks/scan.md,sha256=hYXf-IL1kgpBPHJapRrwTu88cLZ7y3bCmAq9HY0yG3U,2300
23
23
  codeforerunner/prompts/tasks/stack-docs.md,sha256=Dy-JSXpSmHSyhR5shQBXKa_F0PqnjPcmtljthYZpaiM,1923
24
24
  codeforerunner/prompts/tasks/version-audit.md,sha256=oK-pcoxt_VcvDOlj1Sz9OlEhXlcViLPn54r-qP5WfiA,5833
25
- codeforerunner/providers/__init__.py,sha256=hoLODdqQ-beA7-MVFR6aoE29ZUSzxGVPLhwNXNN1xw4,1020
26
- codeforerunner/providers/anthropic.py,sha256=edCZaNwB2WX6mdcQQN9khoKedZDiK13c73Ld8D1Puq4,4075
27
- codeforerunner/providers/base.py,sha256=MMrOUVOXHWP1td-TndxhLhDyDPJZGExZCeFopZUSRCo,923
28
- codeforerunner/providers/google.py,sha256=JsMgEjFIyKo_LGYosKzWLntGB_vw7ArDwJf7XSYonoA,4184
29
- codeforerunner/providers/ollama.py,sha256=yI8RfjZmTw8Iaj2FDvp85uLQ_4oigHbyYN8Pag9FO5g,4759
30
- codeforerunner/providers/openai.py,sha256=BT_YzVQTDxKs-oV_6r4614knjE4LBFXdTZzvs5_yr4Y,3851
31
- codeforerunner-0.4.2.dist-info/licenses/LICENSE.md,sha256=iIhmJHib6GbdjcwiDMM-npiNRf3XgASom1WsOJivEdc,2915
32
- codeforerunner-0.4.2.dist-info/METADATA,sha256=sVF0AMF3VulKTbPgHXcIhzd8YfntPV6bdYpF3wHh2bo,9873
33
- codeforerunner-0.4.2.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
34
- codeforerunner-0.4.2.dist-info/entry_points.txt,sha256=3p8BbPlq-wfcXk42tsweKePRaGlZ1WXho1gOkuZGyIQ,55
35
- codeforerunner-0.4.2.dist-info/top_level.txt,sha256=pV1rt0-NIpNEotKXpL_sF2060DHr-_0F86LWhUlvXis,15
36
- codeforerunner-0.4.2.dist-info/RECORD,,
25
+ codeforerunner/providers/__init__.py,sha256=PYr0Za1gHgAFRExUormDZZlsStI0RUheCgBj71I8b8w,1103
26
+ codeforerunner/providers/anthropic.py,sha256=CYaSDtxIfJR-Z_F17_OfPPWHGEH7l61mQk0fZFsUFzI,4300
27
+ codeforerunner/providers/base.py,sha256=bmOxnzWGGMhIWwuvIm9YQA_tPJyzXoIo1ciGzsDANz4,1220
28
+ codeforerunner/providers/google.py,sha256=_cnidRymoCS32xUXibDTQ4nncwg0k0qI0YvPab2G64E,4434
29
+ codeforerunner/providers/ollama.py,sha256=9ZU110g5qzEP1chC4MfG6zT2pgfl56jREL_dxt25vCw,5032
30
+ codeforerunner/providers/openai.py,sha256=B-c551-NOGazlVVmP6d-hoeH7GKN4-eTEOuhcvhootA,4097
31
+ codeforerunner-0.4.3.dist-info/licenses/LICENSE.md,sha256=iIhmJHib6GbdjcwiDMM-npiNRf3XgASom1WsOJivEdc,2915
32
+ codeforerunner-0.4.3.dist-info/METADATA,sha256=n74THMcrVT-pgL1ZNKljmnVVE1wxu5XeP_O7LvNUlKs,9873
33
+ codeforerunner-0.4.3.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
34
+ codeforerunner-0.4.3.dist-info/entry_points.txt,sha256=3p8BbPlq-wfcXk42tsweKePRaGlZ1WXho1gOkuZGyIQ,55
35
+ codeforerunner-0.4.3.dist-info/top_level.txt,sha256=pV1rt0-NIpNEotKXpL_sF2060DHr-_0F86LWhUlvXis,15
36
+ codeforerunner-0.4.3.dist-info/RECORD,,