Metadata-Version: 2.4
Name: oh-my-common
Version: 0.2.0
Summary: Shared runtime for the oh-my-* Flask services: settings DB, Claude CLI gateway, timezone, base-url, scheduler.
Author-email: Dennis L <dennisl@udel.edu>
License: MIT
Project-URL: Homepage, https://github.com/ByteDennis/oh-my-common
Keywords: oh-my,flask,claude,settings
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Framework :: Flask
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Provides-Extra: flask
Requires-Dist: flask>=3.0; extra == "flask"
Provides-Extra: scheduler
Requires-Dist: apscheduler>=3.10; extra == "scheduler"

# oh-my-common

Shared runtime for the `oh-my-*` Flask services. Extracted so each split-out
service (oh-my-rss / oh-my-msg / oh-my-write) shares one implementation instead
of drifting copies. Per the split design, each service keeps its **own**
settings DB — this package is the **code** layer, not a shared store.

## Modules

- **`settings`** — SQLite settings client + secret resolution.
  `get_setting/put_setting/get_all`, the `provider_tokens` cache
  (`get/set/clear_cached_token`), and `resolve_secret(key, env_key)` with
  precedence **service-namespace > `global` > env**. Convenience:
  `resolve_claude_token()`, `resolve_openai_key()`.
  Config via env: `SETTINGS_DB` (path), `OMI_SERVICE_NS` (this service's
  namespace, e.g. `clipboard`).
- **`claude`** — Claude CLI gateway: `resolve_claude_bin`, `claude_text`,
  `run_claude_capture`, `gate_ai`, `claude_status`, `extract_json`,
  `estimate_tokens`, `estimate_cost`, `MODEL_PRICING`. Flask-free.
- **`tz`** — `local_tz()/now_local()/today_local()` from `OMI_TZ_OFFSET` (hours, default +8).
- **`urls`** — `request_base_url()` (honors `X-Forwarded-Proto/Host`). Imports flask lazily.
- **`scheduler`** — `make_scheduler(ENABLED_ENV)` → a guarded `BackgroundScheduler`
  (returns `None` when `ENABLED_ENV=0`, so extra gunicorn workers don't double-run).
  Imports apscheduler lazily.
- **`llm`** — `complete(prompt, model='sonnet', backend='claude_cli')`: backend-routed
  one-shot completion. Only `claude_cli` (the `claude -p` gateway) is wired today;
  Anthropic/OpenAI HTTP backends are a future add (the seam is in place). `claude_text`
  stays as the claude-cli shortcut.
- **`agent`** — `dify_run(inputs, query, ...)`: shared client for a self-hosted **Dify**
  app (blocking). Creds (`dify_url`/`dify_key`) from per-service settings or args.
  Returns `{connected, result|error}`. Consolidates the hand-rolled Dify calls that
  lived in service route code.

## Usage

```python
import os
os.environ.setdefault('OMI_SERVICE_NS', 'clipboard')
from oh_my_common import get_setting, claude_text, resolve_openai_key, now_local

key, src = resolve_openai_key()
text = claude_text('Summarize: ...', model='sonnet')
```

## Install

```
pip install oh-my-common            # core (stdlib only)
pip install 'oh-my-common[flask,scheduler]'   # + request_base_url + make_scheduler
```

Distribution into Docker services is TBD — see the migration plan. Options:
publish to a registry, vendor into each monorepo, or a git dependency.
