swarph-cli 0.1.1__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.
- swarph_cli/__init__.py +21 -0
- swarph_cli/caller.py +47 -0
- swarph_cli/main.py +223 -0
- swarph_cli-0.1.1.dist-info/METADATA +108 -0
- swarph_cli-0.1.1.dist-info/RECORD +9 -0
- swarph_cli-0.1.1.dist-info/WHEEL +5 -0
- swarph_cli-0.1.1.dist-info/entry_points.txt +2 -0
- swarph_cli-0.1.1.dist-info/licenses/LICENSE +21 -0
- swarph_cli-0.1.1.dist-info/top_level.txt +1 -0
swarph_cli/__init__.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""swarph-cli — the ``swarph`` binary.
|
|
2
|
+
|
|
3
|
+
Thin client over the ``swarph-mesh`` substrate. v0.0.1 ships the entry-
|
|
4
|
+
point + a status banner. Live one-shot mode + REPL ship in Phase 2 / 5
|
|
5
|
+
per PLAN.md §13.
|
|
6
|
+
|
|
7
|
+
The architecture splits CLI from substrate so:
|
|
8
|
+
|
|
9
|
+
* ``swarph-mesh`` stays a library importable from ``omega-boss``,
|
|
10
|
+
``Council`` judges, ``lab-orchestrator``, etc. — no CLI surface or
|
|
11
|
+
console-script entry point required.
|
|
12
|
+
* ``swarph-cli`` is a tiny argparse + REPL layer on top, ~200 LOC at
|
|
13
|
+
ship-out. Console users get the binary; library callers don't pull
|
|
14
|
+
in the CLI surface.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
__version__ = "0.1.1"
|
|
20
|
+
|
|
21
|
+
__all__ = ["__version__"]
|
swarph_cli/caller.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Build a default caller-convention slug for one-shot CLI invocations.
|
|
2
|
+
|
|
3
|
+
Per swarph_shared.caller_convention the slug must match:
|
|
4
|
+
|
|
5
|
+
^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$
|
|
6
|
+
|
|
7
|
+
So we sanitize the OS username (which can have hyphens, capitals,
|
|
8
|
+
digits-first, etc.) into a conformant fragment and prepend a fixed
|
|
9
|
+
``cli.oneshot.`` prefix.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import getpass
|
|
15
|
+
import os
|
|
16
|
+
import re
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_NON_SLUG_CHARS = re.compile(r"[^a-z0-9_]+")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _sanitize_username(name: str) -> str:
|
|
23
|
+
"""Turn an arbitrary username into a caller-convention fragment.
|
|
24
|
+
|
|
25
|
+
- Lowercase
|
|
26
|
+
- Replace any non-alnum/underscore with underscore
|
|
27
|
+
- Collapse runs of underscores
|
|
28
|
+
- Ensure leading char is a letter (prepend ``u_`` if not)
|
|
29
|
+
- Fall back to ``unknown`` if empty
|
|
30
|
+
"""
|
|
31
|
+
s = name.lower()
|
|
32
|
+
s = _NON_SLUG_CHARS.sub("_", s)
|
|
33
|
+
s = re.sub(r"_+", "_", s).strip("_")
|
|
34
|
+
if not s:
|
|
35
|
+
return "unknown"
|
|
36
|
+
if not s[0].isalpha():
|
|
37
|
+
s = "u_" + s
|
|
38
|
+
return s
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def default_caller() -> str:
|
|
42
|
+
"""Return ``cli.oneshot.<sanitized-user>`` for the current OS user."""
|
|
43
|
+
try:
|
|
44
|
+
user = getpass.getuser()
|
|
45
|
+
except Exception:
|
|
46
|
+
user = os.environ.get("USER") or os.environ.get("USERNAME") or "unknown"
|
|
47
|
+
return f"cli.oneshot.{_sanitize_username(user)}"
|
swarph_cli/main.py
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"""``swarph`` entry-point — Phase 2 one-shot mode.
|
|
2
|
+
|
|
3
|
+
v0.0.1 was the scaffold (banner-only). v0.1.0 ships the falsifiability
|
|
4
|
+
gate from PLAN.md §13 Phase 2:
|
|
5
|
+
|
|
6
|
+
swarph "explain Hawkes process briefly" --provider gemini --model flash
|
|
7
|
+
|
|
8
|
+
Subsequent phases extend the CLI:
|
|
9
|
+
- Phase 3: --ask <peer> mesh-aware one-shot via MeshClient
|
|
10
|
+
- Phase 5: interactive REPL (``swarph chat``)
|
|
11
|
+
- Phase 5.5: ``swarph onboard`` + ``swarph ratify``
|
|
12
|
+
- Phase 5.7: ``swarph daemon`` foreground drain
|
|
13
|
+
- Phase 2.5: ``swarph import --report-only`` per PLAN.md §17.6 reorder
|
|
14
|
+
|
|
15
|
+
For now the entry-point handles ONE shape: positional prompt argument
|
|
16
|
+
+ provider/model flags + JSON-mode toggle. argparse subparsers will
|
|
17
|
+
land in Phase 3 when more verbs need their own surface.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import argparse
|
|
23
|
+
import asyncio
|
|
24
|
+
import json
|
|
25
|
+
import os
|
|
26
|
+
import sys
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
from typing import Optional
|
|
29
|
+
|
|
30
|
+
from swarph_cli import __version__
|
|
31
|
+
from swarph_cli.caller import default_caller
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
_BANNER = """\
|
|
35
|
+
swarph v{version}
|
|
36
|
+
|
|
37
|
+
Usage:
|
|
38
|
+
swarph "your prompt here" [--provider gemini] [--model gemini-2.5-flash]
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
swarph "explain Hawkes process briefly"
|
|
42
|
+
swarph "list 5 tickers" --json
|
|
43
|
+
swarph "summarise" --provider gemini --model gemini-2.5-pro
|
|
44
|
+
|
|
45
|
+
Status: Phase 2 one-shot mode. REPL (Phase 5), --ask <peer>
|
|
46
|
+
(Phase 3), onboard/ratify (Phase 5.5), daemon (Phase 5.7) and
|
|
47
|
+
import (Phase 2.5) ship in subsequent releases.
|
|
48
|
+
|
|
49
|
+
Spec: https://github.com/darw007d/hedge-fund-mcp/blob/main/research/swarph_cli/PLAN.md
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
54
|
+
p = argparse.ArgumentParser(
|
|
55
|
+
prog="swarph",
|
|
56
|
+
description=(
|
|
57
|
+
"swarph — multi-LLM CLI with mesh-gateway integration. "
|
|
58
|
+
"Phase 2 one-shot mode."
|
|
59
|
+
),
|
|
60
|
+
)
|
|
61
|
+
p.add_argument(
|
|
62
|
+
"prompt",
|
|
63
|
+
nargs="?",
|
|
64
|
+
default=None,
|
|
65
|
+
help='Prompt to send (one-shot mode). Omit to print a usage banner.',
|
|
66
|
+
)
|
|
67
|
+
p.add_argument(
|
|
68
|
+
"--provider",
|
|
69
|
+
default="gemini",
|
|
70
|
+
help='LLM provider. Phase 1 ships "gemini" only; Phase 4+ adds '
|
|
71
|
+
"deepseek/claude/openai/grok.",
|
|
72
|
+
)
|
|
73
|
+
p.add_argument(
|
|
74
|
+
"--model",
|
|
75
|
+
default=None,
|
|
76
|
+
help="Provider-specific model id. Defaults to the adapter's default_model.",
|
|
77
|
+
)
|
|
78
|
+
p.add_argument(
|
|
79
|
+
"--caller",
|
|
80
|
+
default=None,
|
|
81
|
+
help='Caller-convention slug (dotted lowercase). Defaults to '
|
|
82
|
+
'"cli.oneshot.<user>" for the current OS user.',
|
|
83
|
+
)
|
|
84
|
+
p.add_argument(
|
|
85
|
+
"--system",
|
|
86
|
+
default=None,
|
|
87
|
+
help="System prompt prepended to the conversation.",
|
|
88
|
+
)
|
|
89
|
+
p.add_argument(
|
|
90
|
+
"--temperature",
|
|
91
|
+
type=float,
|
|
92
|
+
default=0.7,
|
|
93
|
+
help="Sampling temperature (default 0.7).",
|
|
94
|
+
)
|
|
95
|
+
p.add_argument(
|
|
96
|
+
"--max-tokens",
|
|
97
|
+
type=int,
|
|
98
|
+
default=None,
|
|
99
|
+
help="Max output tokens (provider default if omitted).",
|
|
100
|
+
)
|
|
101
|
+
p.add_argument(
|
|
102
|
+
"--json",
|
|
103
|
+
action="store_true",
|
|
104
|
+
help="Parse response as JSON (TRIGGER for the swarph-mesh JSON "
|
|
105
|
+
"harness — not strict-validation; a permissive {'type': 'object'} "
|
|
106
|
+
"schema is synthesised when --schema is absent). Malformed-JSON "
|
|
107
|
+
"responses cause exit code 1 with raw text on stdout for caller "
|
|
108
|
+
"recovery — useful for shell scripts gating on "
|
|
109
|
+
"`if swarph 'x' --json; then ...`. Full Pydantic validation lands "
|
|
110
|
+
"in Phase 5+.",
|
|
111
|
+
)
|
|
112
|
+
p.add_argument(
|
|
113
|
+
"--schema",
|
|
114
|
+
default=None,
|
|
115
|
+
help="Path to a JSON Schema file. Implies --json. v0.1.0 uses the "
|
|
116
|
+
"schema only as the harness trigger; full Pydantic validation lands "
|
|
117
|
+
"in Phase 5+.",
|
|
118
|
+
)
|
|
119
|
+
p.add_argument(
|
|
120
|
+
"--quiet",
|
|
121
|
+
"-q",
|
|
122
|
+
action="store_true",
|
|
123
|
+
help="Suppress the per-call attribution footer on stderr.",
|
|
124
|
+
)
|
|
125
|
+
p.add_argument(
|
|
126
|
+
"--version",
|
|
127
|
+
action="version",
|
|
128
|
+
version=f"swarph-cli {__version__}",
|
|
129
|
+
)
|
|
130
|
+
return p
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _print_banner() -> int:
|
|
134
|
+
print(_BANNER.format(version=__version__), file=sys.stderr)
|
|
135
|
+
return 0
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _load_schema(path: Optional[str]) -> Optional[dict]:
|
|
139
|
+
if not path:
|
|
140
|
+
return None
|
|
141
|
+
p = Path(path)
|
|
142
|
+
if not p.exists():
|
|
143
|
+
print(f"swarph: --schema file not found: {path}", file=sys.stderr)
|
|
144
|
+
sys.exit(2)
|
|
145
|
+
try:
|
|
146
|
+
return json.loads(p.read_text(encoding="utf-8"))
|
|
147
|
+
except json.JSONDecodeError as exc:
|
|
148
|
+
print(f"swarph: --schema file is not valid JSON: {exc}", file=sys.stderr)
|
|
149
|
+
sys.exit(2)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
async def _run_one_shot(args: argparse.Namespace) -> int:
|
|
153
|
+
# Local import so unit tests of the CLI shape don't drag in the
|
|
154
|
+
# full SwarphCall wiring + Gemini SDK on import.
|
|
155
|
+
from swarph_mesh import ChatMessage, SwarphCall
|
|
156
|
+
|
|
157
|
+
caller = args.caller or default_caller()
|
|
158
|
+
json_schema = _load_schema(args.schema) or ({"type": "object"} if args.json else None)
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
# SwarphCall construction enforces caller convention via
|
|
162
|
+
# swarph_shared.validate_caller — raises ValueError on
|
|
163
|
+
# invalid slugs. Keep inside try/except so a bad --caller
|
|
164
|
+
# argument exits 1 with a friendly error rather than dumps
|
|
165
|
+
# a traceback.
|
|
166
|
+
sc = SwarphCall(
|
|
167
|
+
provider=args.provider,
|
|
168
|
+
caller=caller,
|
|
169
|
+
model=args.model,
|
|
170
|
+
)
|
|
171
|
+
resp = await sc.chat(
|
|
172
|
+
messages=[ChatMessage(role="user", content=args.prompt)],
|
|
173
|
+
system_prompt=args.system,
|
|
174
|
+
json_schema=json_schema,
|
|
175
|
+
temperature=args.temperature,
|
|
176
|
+
max_tokens=args.max_tokens,
|
|
177
|
+
)
|
|
178
|
+
except Exception as exc:
|
|
179
|
+
print(f"swarph: call failed: {exc}", file=sys.stderr)
|
|
180
|
+
return 1
|
|
181
|
+
|
|
182
|
+
# JSON mode prints parsed dict (pretty) when available; falls back
|
|
183
|
+
# to raw text + error_class footer when the harness couldn't parse.
|
|
184
|
+
if json_schema is not None and resp.parsed is not None:
|
|
185
|
+
print(json.dumps(resp.parsed, indent=2, sort_keys=True))
|
|
186
|
+
else:
|
|
187
|
+
print(resp.text)
|
|
188
|
+
|
|
189
|
+
if not args.quiet:
|
|
190
|
+
# ``$0`` displays the subscription-path / free-tier case
|
|
191
|
+
# (adapter returns exactly 0.0); ``$0.0000`` displays a
|
|
192
|
+
# tiny-but-real API cost. Future adapters that introduce
|
|
193
|
+
# float drift around zero (e.g., 1e-12 due to multiplier
|
|
194
|
+
# rounding) would flip the display spuriously to
|
|
195
|
+
# ``$0.0000`` — audit + tighten the threshold if that bites
|
|
196
|
+
# (drop PR #1 review observation #2, DM #681).
|
|
197
|
+
cost_str = f"${resp.cost_usd:.4f}" if resp.cost_usd > 0 else "$0"
|
|
198
|
+
attribution = (
|
|
199
|
+
f"# {resp.input_tokens}+{resp.output_tokens}t "
|
|
200
|
+
f"{cost_str} {resp.duration_s:.2f}s caller={caller} "
|
|
201
|
+
f"provider={args.provider}"
|
|
202
|
+
)
|
|
203
|
+
if resp.cached:
|
|
204
|
+
attribution += " (cached)"
|
|
205
|
+
if resp.error_class:
|
|
206
|
+
attribution += f" error_class={resp.error_class}"
|
|
207
|
+
print(attribution, file=sys.stderr)
|
|
208
|
+
|
|
209
|
+
return 0 if resp.error_class is None else 1
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def main(argv: Optional[list[str]] = None) -> int:
|
|
213
|
+
parser = _build_parser()
|
|
214
|
+
args = parser.parse_args(argv)
|
|
215
|
+
|
|
216
|
+
if args.prompt is None:
|
|
217
|
+
return _print_banner()
|
|
218
|
+
|
|
219
|
+
return asyncio.run(_run_one_shot(args))
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
if __name__ == "__main__":
|
|
223
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: swarph-cli
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: The `swarph` binary — multi-LLM CLI with mesh-gateway integration. Phase 2 one-shot mode shipped (PLAN.md §13).
|
|
5
|
+
Author: Pierre Samson, Claude Opus
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/darw007d/swarph-cli
|
|
8
|
+
Project-URL: Source, https://github.com/darw007d/swarph-cli
|
|
9
|
+
Project-URL: Substrate, https://github.com/darw007d/swarph-mesh
|
|
10
|
+
Project-URL: Spec, https://github.com/darw007d/hedge-fund-mcp/blob/main/research/swarph_cli/PLAN.md
|
|
11
|
+
Keywords: swarph,llm,cli,mesh,gemini,claude,deepseek
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Topic :: Utilities
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: swarph-mesh>=0.1.0
|
|
28
|
+
Requires-Dist: swarph-shared>=0.2.0
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# swarph-cli
|
|
34
|
+
|
|
35
|
+
The `swarph` binary — multi-LLM CLI with mesh-gateway integration. Thin client over the [`swarph-mesh`](https://github.com/darw007d/swarph-mesh) substrate.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install swarph-cli
|
|
39
|
+
swarph --version
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This is one of three repos in the v0.3.x architecture:
|
|
43
|
+
|
|
44
|
+
| Repo | Role |
|
|
45
|
+
|---|---|
|
|
46
|
+
| [`swarph-mesh`](https://github.com/darw007d/swarph-mesh) | Substrate Python package — Protocol + adapters + SwarphCall + MeshClient. Pure library, no CLI |
|
|
47
|
+
| [`swarph-cli`](https://github.com/darw007d/swarph-cli) | This repo — the `swarph` binary |
|
|
48
|
+
| [`swarph-meshlm`](https://github.com/darw007d/swarph-meshlm) | Simon Willison `llm` plugin |
|
|
49
|
+
|
|
50
|
+
## Status
|
|
51
|
+
|
|
52
|
+
**v0.1.0 — Phase 2 one-shot mode.** The `swarph "prompt"` binary works end-to-end against `--provider gemini` per PLAN.md §13 falsifiability gate. Subsequent phases extend the CLI surface (REPL, `--ask <peer>`, onboard/ratify, daemon, import).
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
$ swarph "say pong" --provider gemini
|
|
56
|
+
Pong!
|
|
57
|
+
# 3+26t $0.0000 0.73s caller=cli.oneshot.ubuntu provider=gemini
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### `--json` mode semantics
|
|
61
|
+
|
|
62
|
+
`--json` is a **harness trigger**, not a strict-validation gate. When set, swarph routes the response through the swarph-mesh JSON harness:
|
|
63
|
+
|
|
64
|
+
- A permissive `{"type": "object"}` schema is synthesised when `--schema` is absent (Phase 5+ adds Pydantic validation).
|
|
65
|
+
- The harness retries once with `[USER]`-turn feedback on parse failure.
|
|
66
|
+
- **Malformed-JSON exits with code 1** + raw text on stdout for caller recovery. Useful for shell scripts:
|
|
67
|
+
```bash
|
|
68
|
+
if swarph "give me a trade" --json; then
|
|
69
|
+
# parsed dict was on stdout
|
|
70
|
+
...
|
|
71
|
+
fi
|
|
72
|
+
```
|
|
73
|
+
- Pretty-printed parsed dict on stdout when parse succeeds; `error_class=malformed_json` shows up in the stderr attribution footer when it doesn't.
|
|
74
|
+
|
|
75
|
+
## Spec
|
|
76
|
+
|
|
77
|
+
→ [hedge-fund-mcp / research/swarph_cli/PLAN.md](https://github.com/darw007d/hedge-fund-mcp/blob/main/research/swarph_cli/PLAN.md)
|
|
78
|
+
|
|
79
|
+
## Phase rollout
|
|
80
|
+
|
|
81
|
+
| Phase | What lands |
|
|
82
|
+
|---|---|
|
|
83
|
+
| **0** (this) | Scaffold — entry-point + status banner |
|
|
84
|
+
| **2** | One-shot mode: `swarph "hello" --provider gemini` |
|
|
85
|
+
| **3** | `--ask <peer>` mesh-aware one-shot via MeshClient |
|
|
86
|
+
| **5** | Interactive REPL — `/inbox`, `/reply`, `/dm`, `/watch` |
|
|
87
|
+
| **5.5** | `swarph onboard <peer-name>` + `swarph ratify <peer-name>` (PLAN.md §15) |
|
|
88
|
+
| **5.7** | `swarph daemon` foreground drain loop + `swarph chat` REPL with drain coroutine (PLAN.md §16) |
|
|
89
|
+
| **6** | PyPI publish |
|
|
90
|
+
|
|
91
|
+
## Why split CLI from substrate
|
|
92
|
+
|
|
93
|
+
`swarph-mesh` (the library) is imported by `omega-boss`, Council judges, `lab-orchestrator`, and any future swarph peer that wants to write programs against the Protocol. Those callers don't need the CLI surface or the console-script entry point. Keeping the CLI in a separate repo means library users `pip install swarph-mesh` without pulling argparse + REPL plumbing they'll never run.
|
|
94
|
+
|
|
95
|
+
## Install (dev)
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
git clone https://github.com/darw007d/swarph-cli
|
|
99
|
+
cd swarph-cli
|
|
100
|
+
python -m venv venv && source venv/bin/activate
|
|
101
|
+
pip install -e ".[dev]"
|
|
102
|
+
pytest
|
|
103
|
+
swarph --version
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
|
|
108
|
+
MIT. Pierre Samson + Claude Opus, 2026.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
swarph_cli/__init__.py,sha256=2exfOKQZEUd0ziPGdrxWSZMG6EBPPhCaZa40hdBmdbU,678
|
|
2
|
+
swarph_cli/caller.py,sha256=NKEbGkoyRf-BCdXzGwYzLsPnr6xgxRldRQbxTEcKHc0,1288
|
|
3
|
+
swarph_cli/main.py,sha256=5CSNu4ENSYpG3aF5dOAW52fApuec1fwHB24dGhchkEo,7255
|
|
4
|
+
swarph_cli-0.1.1.dist-info/licenses/LICENSE,sha256=PFBo9Jfj0JbAYTdIvxVWHbMac93_iM57n27yQs80BJ4,1086
|
|
5
|
+
swarph_cli-0.1.1.dist-info/METADATA,sha256=3u6faTLas5BiT5CHTzHMQ733BkgmnPClBX3U_8YL4_M,4485
|
|
6
|
+
swarph_cli-0.1.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
7
|
+
swarph_cli-0.1.1.dist-info/entry_points.txt,sha256=61jM-mwvdoN9FWnL5AgXxhmbJ39zhP-GsllJzsmRlF0,48
|
|
8
|
+
swarph_cli-0.1.1.dist-info/top_level.txt,sha256=2sTqSJDjO0wW9xURA1IYlRD0kX_1qI0Sm5_rG8jhkQc,11
|
|
9
|
+
swarph_cli-0.1.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pierre Samson and Claude Opus
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
swarph_cli
|