scamscript 0.2.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.
- scamscript/__init__.py +3 -0
- scamscript/__main__.py +4 -0
- scamscript/analysis.py +138 -0
- scamscript/cli.py +521 -0
- scamscript/client.py +207 -0
- scamscript/config.py +55 -0
- scamscript/ingest.py +85 -0
- scamscript/models.py +169 -0
- scamscript/prompts.py +90 -0
- scamscript/redact.py +62 -0
- scamscript/render.py +232 -0
- scamscript/report.py +196 -0
- scamscript/store.py +187 -0
- scamscript/verify.py +103 -0
- scamscript-0.2.0.dist-info/METADATA +278 -0
- scamscript-0.2.0.dist-info/RECORD +19 -0
- scamscript-0.2.0.dist-info/WHEEL +4 -0
- scamscript-0.2.0.dist-info/entry_points.txt +2 -0
- scamscript-0.2.0.dist-info/licenses/LICENSE +21 -0
scamscript/verify.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Check model quotations against the source script."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from difflib import SequenceMatcher
|
|
8
|
+
|
|
9
|
+
from scamscript.models import ScriptBreakdown
|
|
10
|
+
|
|
11
|
+
QUOTE_PATTERN = re.compile(r"[\"“”'‘’]([^\"“”'‘’]{8,400})[\"“”'‘’]")
|
|
12
|
+
WORD = re.compile(r"[a-z0-9]+")
|
|
13
|
+
MIN_QUOTE_WORDS = 3
|
|
14
|
+
CLOSE_RATIO = 0.75
|
|
15
|
+
|
|
16
|
+
FIELDS = ("opening_hook", "red_flags")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(slots=True)
|
|
20
|
+
class Issue:
|
|
21
|
+
field: str
|
|
22
|
+
quote: str
|
|
23
|
+
status: str
|
|
24
|
+
ratio: float = 0.0
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def ok(self) -> bool:
|
|
28
|
+
return self.status == "verbatim"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def normalize(text: str) -> str:
|
|
32
|
+
lowered = (
|
|
33
|
+
text.lower()
|
|
34
|
+
.replace("“", '"')
|
|
35
|
+
.replace("”", '"')
|
|
36
|
+
.replace("‘", "'")
|
|
37
|
+
.replace("’", "'")
|
|
38
|
+
.replace("–", "-")
|
|
39
|
+
.replace("—", "-")
|
|
40
|
+
)
|
|
41
|
+
return " ".join(re.sub(r"[^a-z0-9 ]+", " ", lowered).split())
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def extract_quotes(value: str) -> list[str]:
|
|
45
|
+
quotes = [match.group(1).strip() for match in QUOTE_PATTERN.finditer(value)]
|
|
46
|
+
return [quote for quote in quotes if len(WORD.findall(quote)) >= MIN_QUOTE_WORDS]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def classify(quote: str, source: str) -> tuple[str, float]:
|
|
50
|
+
"""Return (status, ratio) for one quote against the source."""
|
|
51
|
+
needle = normalize(quote)
|
|
52
|
+
if not needle:
|
|
53
|
+
return "missing", 0.0
|
|
54
|
+
hay = normalize(source)
|
|
55
|
+
if needle in hay:
|
|
56
|
+
return "verbatim", 1.0
|
|
57
|
+
|
|
58
|
+
words = needle.split()
|
|
59
|
+
hay_words = hay.split()
|
|
60
|
+
window = len(words)
|
|
61
|
+
step = max(1, window // 3)
|
|
62
|
+
best = 0.0
|
|
63
|
+
for start in range(0, max(1, len(hay_words) - window + 1), step):
|
|
64
|
+
candidate = " ".join(hay_words[start : start + window])
|
|
65
|
+
ratio = SequenceMatcher(None, needle, candidate).ratio()
|
|
66
|
+
if ratio > best:
|
|
67
|
+
best = ratio
|
|
68
|
+
if best >= 0.97:
|
|
69
|
+
break
|
|
70
|
+
if best >= CLOSE_RATIO:
|
|
71
|
+
return "close", round(best, 3)
|
|
72
|
+
return "missing", round(best, 3)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def verify_breakdown(breakdown: ScriptBreakdown, source: str) -> list[Issue]:
|
|
76
|
+
"""Check quoted claims in the hook and red flags. Paraphrase without quotes is skipped."""
|
|
77
|
+
issues: list[Issue] = []
|
|
78
|
+
for field in FIELDS:
|
|
79
|
+
value = getattr(breakdown, field)
|
|
80
|
+
values = value if isinstance(value, list) else [value]
|
|
81
|
+
for item in values:
|
|
82
|
+
if not item:
|
|
83
|
+
continue
|
|
84
|
+
quotes = extract_quotes(item)
|
|
85
|
+
if not quotes and field == "opening_hook" and len(WORD.findall(item)) >= 4:
|
|
86
|
+
quotes = [item]
|
|
87
|
+
for quote in quotes:
|
|
88
|
+
status, ratio = classify(quote, source)
|
|
89
|
+
issues.append(
|
|
90
|
+
Issue(field=field, quote=quote.strip(), status=status, ratio=ratio)
|
|
91
|
+
)
|
|
92
|
+
return issues
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def summarize(issues: list[Issue]) -> dict[str, int]:
|
|
96
|
+
counts = {"checked": len(issues), "verbatim": 0, "close": 0, "missing": 0}
|
|
97
|
+
for issue in issues:
|
|
98
|
+
counts[issue.status] = counts.get(issue.status, 0) + 1
|
|
99
|
+
return counts
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def has_problems(issues: list[Issue]) -> bool:
|
|
103
|
+
return any(issue.status != "verbatim" for issue in issues)
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: scamscript
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Reverse-engineer scam scripts and vishing transcripts into structured counter-playbooks
|
|
5
|
+
Project-URL: Homepage, https://github.com/sjdsjadjajdjsa/scamscript
|
|
6
|
+
Project-URL: Repository, https://github.com/sjdsjadjajdjsa/scamscript
|
|
7
|
+
Project-URL: Issues, https://github.com/sjdsjadjajdjsa/scamscript/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/sjdsjadjajdjsa/scamscript/blob/master/CHANGELOG.md
|
|
9
|
+
Author-email: scamscript contributors <313729361+sjdsjadjajdjsa@users.noreply.github.com>
|
|
10
|
+
Maintainer-email: scamscript contributors <313729361+sjdsjadjajdjsa@users.noreply.github.com>
|
|
11
|
+
License: MIT License
|
|
12
|
+
|
|
13
|
+
Copyright (c) 2026 scamscript contributors
|
|
14
|
+
|
|
15
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
16
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
17
|
+
in the Software without restriction, including without limitation the rights
|
|
18
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
19
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
20
|
+
furnished to do so, subject to the following conditions:
|
|
21
|
+
|
|
22
|
+
The above copyright notice and this permission notice shall be included in all
|
|
23
|
+
copies or substantial portions of the Software.
|
|
24
|
+
|
|
25
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
26
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
27
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
28
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
29
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
30
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
31
|
+
SOFTWARE.
|
|
32
|
+
License-File: LICENSE
|
|
33
|
+
Keywords: cli,fraud,osint,phishing,scam,security,smishing,social-engineering,transcripts,vishing
|
|
34
|
+
Classifier: Development Status :: 4 - Beta
|
|
35
|
+
Classifier: Environment :: Console
|
|
36
|
+
Classifier: Intended Audience :: Information Technology
|
|
37
|
+
Classifier: Intended Audience :: Science/Research
|
|
38
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
39
|
+
Classifier: Natural Language :: English
|
|
40
|
+
Classifier: Operating System :: OS Independent
|
|
41
|
+
Classifier: Programming Language :: Python :: 3
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
44
|
+
Classifier: Topic :: Security
|
|
45
|
+
Classifier: Typing :: Typed
|
|
46
|
+
Requires-Python: >=3.12
|
|
47
|
+
Requires-Dist: httpx==0.28.1
|
|
48
|
+
Requires-Dist: pydantic==2.14.2
|
|
49
|
+
Requires-Dist: rich==15.0.0
|
|
50
|
+
Requires-Dist: typer==0.27.3
|
|
51
|
+
Provides-Extra: dev
|
|
52
|
+
Requires-Dist: build==1.3.0; extra == 'dev'
|
|
53
|
+
Requires-Dist: pytest==8.4.1; extra == 'dev'
|
|
54
|
+
Requires-Dist: twine==6.1.0; extra == 'dev'
|
|
55
|
+
Description-Content-Type: text/markdown
|
|
56
|
+
|
|
57
|
+
<p align="center">
|
|
58
|
+
<img src="docs/banner.svg" alt="scamscript: reverse-engineer the playbook, not the story" width="100%">
|
|
59
|
+
</p>
|
|
60
|
+
|
|
61
|
+
<p align="center">
|
|
62
|
+
<img src="docs/demo.gif" alt="terminal demo: analyzing a script, then ranking a directory" width="760">
|
|
63
|
+
<br>
|
|
64
|
+
<sub>Recorded against a local stub endpoint, so no API spend.</sub>
|
|
65
|
+
</p>
|
|
66
|
+
|
|
67
|
+
# scamscript
|
|
68
|
+
|
|
69
|
+
[](https://github.com/sjdsjadjajdjsa/scamscript/actions/workflows/ci.yml)
|
|
70
|
+
[](pyproject.toml)
|
|
71
|
+
[](LICENSE)
|
|
72
|
+
[](#scope-and-disclaimer)
|
|
73
|
+
|
|
74
|
+
A reverse-engineering analyzer for leaked or public scam call scripts and vishing transcripts.
|
|
75
|
+
Point it at a script and a model takes the fraud apart: the persona, the hook that catches you,
|
|
76
|
+
how trust is manufactured, the pressure applied, what happens when you hesitate, and how to
|
|
77
|
+
counter that exact playbook.
|
|
78
|
+
|
|
79
|
+
> **Security research and fraud-awareness training only.** Output is a model-produced reading of
|
|
80
|
+
> a captured script, not legal advice and not attribution. A script is evidence of a *pattern*;
|
|
81
|
+
> the live scam that reuses it will differ in details.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Why
|
|
86
|
+
|
|
87
|
+
Scripts leak. Call centres dump their flows, victims publish transcripts, researchers collect
|
|
88
|
+
samples. Reading them one by one teaches you that `your account is at risk` is bad, but not how a
|
|
89
|
+
particular operation sequences trust into a transfer. This tool turns each artifact into a
|
|
90
|
+
comparable record, so a corpus can be ranked and a defender's briefing can quote the actual
|
|
91
|
+
mechanics instead of general advice.
|
|
92
|
+
|
|
93
|
+
## Quickstart
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pip install scamscript # or, for development:
|
|
97
|
+
# git clone https://github.com/sjdsjadjajdjsa/scamscript && cd scamscript && pip install -e ".[dev]"
|
|
98
|
+
|
|
99
|
+
export API_KEY=... # never committed, never logged
|
|
100
|
+
|
|
101
|
+
scamscript --dry-run analyze --file examples/tech_support_scam.txt # inspect the prompt, spend nothing
|
|
102
|
+
scamscript analyze --file examples/tech_support_scam.txt
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Any OpenAI-compatible `/chat/completions` endpoint works. Defaults are Venice with
|
|
106
|
+
`deepseek-v4-1-flash-1017-uncensored`; OpenRouter needs only the model slug:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
scamscript --base-url https://openrouter.ai/api/v1 \
|
|
110
|
+
--model deepseek/deepseek-v4.1-flash-1017 analyze --file script.txt
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## What it produces
|
|
114
|
+
|
|
115
|
+
Each script renders as a colour-coded panel:
|
|
116
|
+
|
|
117
|
+
```text
|
|
118
|
+
╭──────────────────────────── tech_support_scam.txt ────────────────────────────╮
|
|
119
|
+
│ ATTACK TYPE TECH SUPPORT SCAM SOPHISTICATION 6/10 │
|
|
120
|
+
│ │
|
|
121
|
+
│ OPENING HOOK │
|
|
122
|
+
│ "Our telemetry shows your machine has been broadcasting error ..." │
|
|
123
|
+
│ │
|
|
124
|
+
│ RED FLAGS │
|
|
125
|
+
│ ✗ Unsolicited call claiming Windows telemetry │
|
|
126
|
+
│ ✗ Caller asks for a Remote Desktop session ID │
|
|
127
|
+
╰────────────────────────────────── 7 red flags ───────────────────────────────╯
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Fields: `attack_type`, `persona`, `opening_hook`, `trust_building_moves`, `urgency_tactics`,
|
|
131
|
+
`escalation_ladder`, `target_demographics`, `red_flags`, `defense_summary`, `sophistication_score`.
|
|
132
|
+
|
|
133
|
+
The panel also carries a **quote check**: every quoted claim in `opening_hook` and `red_flags` is
|
|
134
|
+
compared against the source, and lines that are paraphrased or simply not there are marked. Use
|
|
135
|
+
`--strict-quotes` to make a missing line fail the run, and `--no-verify` to skip it.
|
|
136
|
+
|
|
137
|
+
Batch mode ranks a whole directory into one markdown report. A redacted report from the sample
|
|
138
|
+
corpus is at [`docs/sample-report.md`](docs/sample-report.md).
|
|
139
|
+
|
|
140
|
+
## Commands
|
|
141
|
+
|
|
142
|
+
| Command | Purpose |
|
|
143
|
+
| --- | --- |
|
|
144
|
+
| `analyze --file` | Break down one script |
|
|
145
|
+
| `analyze --dir --batch` | Directory, aggregated report |
|
|
146
|
+
| `batch <dir>` | Same as above, ranked |
|
|
147
|
+
| `report --run-id` | Regenerate a report from a past run's log |
|
|
148
|
+
| `history` | List previous runs |
|
|
149
|
+
| `prune` | Delete old logs |
|
|
150
|
+
|
|
151
|
+
Useful flags: `--dry-run`, `--json`, `--redact`, `--top N`, `--recursive`, `--timeout`,
|
|
152
|
+
`--retries`, `--max-tokens`, `--no-color`. `--json` puts one object per script on stdout and all
|
|
153
|
+
Rich output on stderr, so it pipes:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
scamscript --json batch examples | jq -s 'map(select(.event == "result")) | length'
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## How it works
|
|
160
|
+
|
|
161
|
+
```text
|
|
162
|
+
script ──▶ ingest (type/size guards, optional redaction)
|
|
163
|
+
──▶ analyst prompt ──▶ /chat/completions
|
|
164
|
+
──▶ JSON extraction ──▶ Pydantic schema
|
|
165
|
+
│ invalid / truncated
|
|
166
|
+
└──▶ one repair retry with the error fed back
|
|
167
|
+
──▶ Rich panel | JSONL record | ranked markdown
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
- **Validation.** Replies are parsed tolerantly (fences, prose, string lists, `9/10` scores) and
|
|
171
|
+
then validated. One malformed reply earns exactly one repair attempt; a second failure is
|
|
172
|
+
reported, not retried forever.
|
|
173
|
+
- **Transport.** Retryable statuses (408, 409, 425, 429, 5xx) and empty replies back off and
|
|
174
|
+
retry within `--retries`; `Retry-After` is honoured. A `finish_reason: length` reply is treated
|
|
175
|
+
as truncation and repaired with a shorter-answer instruction.
|
|
176
|
+
- **Reasoning models.** If a provider returns only reasoning text with `finish_reason: length`, the
|
|
177
|
+
client treats it as truncation, and when a provider parks the answer in `reasoning` with an empty
|
|
178
|
+
`content`, that text is used as a last resort. Raise `--max-tokens` for models that think first.
|
|
179
|
+
- **Quote checking.** Quoted claims are normalised (case, quotes, punctuation) and matched against
|
|
180
|
+
the script. `close` means a paraphrase, `missing` means the line is not in the artifact.
|
|
181
|
+
Verification never drops a finding, it only marks it for the reader.
|
|
182
|
+
- **Scoring.** `sophistication_score` follows fixed anchors (1-2 one device, 5-6 staged trust and
|
|
183
|
+
one deadline, 9-10 rehearsed objection handling and controlled transfers) so rankings compare
|
|
184
|
+
across runs instead of drifting with prose.
|
|
185
|
+
|
|
186
|
+
## Redaction and logs
|
|
187
|
+
|
|
188
|
+
`--redact` masks emails, card numbers, SSNs, phone numbers and long digit runs before the prompt
|
|
189
|
+
is sent, before anything is logged, and inside the returned breakdown. Counts are logged. Regex
|
|
190
|
+
masking is best effort: names, case IDs and spelled-out digits survive it.
|
|
191
|
+
|
|
192
|
+
Every request appends to a timestamped JSONL file under `~/.scamscript/logs/` (override with
|
|
193
|
+
`--home` or `SCAMSCRIPT_HOME`). The API key is never written. Logs are the source for `report`, so
|
|
194
|
+
a run replays without spending tokens, and `prune --keep 200 --keep-days 30` keeps the store
|
|
195
|
+
bounded.
|
|
196
|
+
|
|
197
|
+
## Install and configure
|
|
198
|
+
|
|
199
|
+
Python 3.12+. `pip install scamscript` for use, `pip install -e ".[dev]"` from a clone for tests.
|
|
200
|
+
Release history is in [CHANGELOG.md](CHANGELOG.md).
|
|
201
|
+
|
|
202
|
+
| Setting | Flag | Env | Default |
|
|
203
|
+
| --- | --- | --- | --- |
|
|
204
|
+
| API key | `--api-key` | `API_KEY` | none, required unless `--dry-run` |
|
|
205
|
+
| Base URL | `--base-url` | `SCAMSCRIPT_BASE_URL` | `https://api.venice.ai/api/v1` |
|
|
206
|
+
| Model | `--model` | `SCAMSCRIPT_MODEL` | `deepseek-v4-1-flash-1017-uncensored` |
|
|
207
|
+
| State dir | `--home` | `SCAMSCRIPT_HOME` | `~/.scamscript` |
|
|
208
|
+
|
|
209
|
+
## Tests, CI and calibration
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
pytest
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The suite mocks the HTTP layer with `httpx.MockTransport`; no network or key needed. CI runs the
|
|
216
|
+
suite and a wheel build on Python 3.12 and 3.13.
|
|
217
|
+
|
|
218
|
+
Calibration is evidence, not vibes. `scripts/calibrate.py` measures first-attempt schema
|
|
219
|
+
adherence, repair rate, latency, score spread and billed cost against a live endpoint:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
API_KEY=... python scripts/calibrate.py --dir examples --repeat 3 \
|
|
223
|
+
--model deepseek/deepseek-v4.1-flash-1017 \
|
|
224
|
+
--base-url https://openrouter.ai/api/v1
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Recorded passes with their numbers are in [`docs/calibration.md`](docs/calibration.md): three rubric
|
|
228
|
+
repeats, a three-model comparison, an adversarial set and end-case stability runs. The current rubric
|
|
229
|
+
reaches both ends of the scale, and quote checking flags the invented lines a plain reading would
|
|
230
|
+
take as evidence.
|
|
231
|
+
|
|
232
|
+
The adversarial set lives in `examples/adversarial/` and has its own harness:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
API_KEY=... python scripts/injection_eval.py --model ... --base-url ...
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Format held in 7/7 cases; embedded demands were obeyed in 1 of 6. The fence protects the schema, not
|
|
239
|
+
the classification.
|
|
240
|
+
|
|
241
|
+
## Layout
|
|
242
|
+
|
|
243
|
+
```text
|
|
244
|
+
src/scamscript/
|
|
245
|
+
cli.py command wiring, exit codes
|
|
246
|
+
client.py OpenAI-compatible client, retries, truncation
|
|
247
|
+
analysis.py per-script loop, one repair retry
|
|
248
|
+
ingest.py file and directory reading with guards
|
|
249
|
+
models.py Pydantic schema, tolerant JSON extraction
|
|
250
|
+
prompts.py analyst prompt and score rubric
|
|
251
|
+
redact.py identifier masking
|
|
252
|
+
render.py Rich panels and summary
|
|
253
|
+
report.py ranked markdown aggregation
|
|
254
|
+
store.py JSONL log, run discovery, retention
|
|
255
|
+
verify.py quote checking against the source
|
|
256
|
+
tests/ schema, retry, redaction, verification, client and CLI tests
|
|
257
|
+
examples/ six fictional transcripts, plus adversarial/ fixtures
|
|
258
|
+
scripts/ calibration and injection harnesses
|
|
259
|
+
docs/ calibration record, sample report, banner, demo
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Limits
|
|
263
|
+
|
|
264
|
+
- Breakdowns are model readings; a bad prompt or a weak model produces confident nonsense. Read
|
|
265
|
+
`opening_hook` and `red_flags` against the source before quoting anything.
|
|
266
|
+
- Redaction is regex-based and will miss names and identifiers without a fixed shape.
|
|
267
|
+
- One script per request; no cross-script deduplication yet, so reprints inflate a ranking.
|
|
268
|
+
- Analysis is English-centric: the prompt and schema assume English artifacts.
|
|
269
|
+
- Quote checking compares text, not meaning. A legitimate paraphrase left in quotes is flagged;
|
|
270
|
+
an accurate paraphrase without quotes is skipped rather than judged.
|
|
271
|
+
|
|
272
|
+
## Scope and disclaimer
|
|
273
|
+
|
|
274
|
+
For security research and fraud-awareness training only. Not legal advice, not an attribution
|
|
275
|
+
tool, no warranty. Keep API keys out of commits; the key is read from the environment.
|
|
276
|
+
|
|
277
|
+
MIT licensed, see [LICENSE](LICENSE). Contribution notes in [CONTRIBUTING.md](CONTRIBUTING.md),
|
|
278
|
+
vulnerability reports in [SECURITY.md](.github/SECURITY.md).
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
scamscript/__init__.py,sha256=ve6tW4xYXG0aWgQdTqxFMv7YyUwjxn3_PoLfAFQjpJg,93
|
|
2
|
+
scamscript/__main__.py,sha256=1FkTauyNgx-VTivcgblCC--ehR94Le1jOwKbqsaPtNI,69
|
|
3
|
+
scamscript/analysis.py,sha256=PzHgxwdWyuXMltRyPO8bu0B7Ps0GQn8axlG7otCPxis,4483
|
|
4
|
+
scamscript/cli.py,sha256=wwr0iPTmPvrjkx53tnti03vfR3X5HkAnaymGoYIH4VA,16871
|
|
5
|
+
scamscript/client.py,sha256=IXoCpTaI0dY56E_IUlWHKgC0ncF97-ZQ5owo8n7c1yo,6734
|
|
6
|
+
scamscript/config.py,sha256=Zp1dzQMhR7T4lM-rgv9n-CrGSI8TT2MCOOcw8JunGSM,1628
|
|
7
|
+
scamscript/ingest.py,sha256=UK0dKuz0DiIVNYRlqOXrsppdXfD2_SB6aQ2xa9XtdYM,2639
|
|
8
|
+
scamscript/models.py,sha256=XvEeRrOdTK-94Qf9kylcumTCtlK5sLpuslLRI4k5f50,4935
|
|
9
|
+
scamscript/prompts.py,sha256=OjvdE--4LLi-KGgt5ofctBVfAjSBIOS_-sVpmeG7vMo,4896
|
|
10
|
+
scamscript/redact.py,sha256=XRtoyICpvHa_ShutSY7xPI-CA2ynwl1mhMrKG5Ku-J4,1885
|
|
11
|
+
scamscript/render.py,sha256=77h2SAyfxuVkdQ2JeNZTpmahevUh4emNEKGsiVbUOLo,7309
|
|
12
|
+
scamscript/report.py,sha256=7qPAoM2ySmH6fP7gov4Xd7tDNpDerl2n_u1tLzHYulE,6970
|
|
13
|
+
scamscript/store.py,sha256=ivqpkK9-4ZLjpwhTfbyfKdUi3SLQRLcdHz3raJcDDuA,5694
|
|
14
|
+
scamscript/verify.py,sha256=r-LAsixI0VBhS8B1kysGpOH25gFNxTOx8YWShqKTrSY,3136
|
|
15
|
+
scamscript-0.2.0.dist-info/METADATA,sha256=O9tXoKOAsJ27dWVxsX-SNY0tMmUAFMlP686KB6uySUc,13564
|
|
16
|
+
scamscript-0.2.0.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
|
|
17
|
+
scamscript-0.2.0.dist-info/entry_points.txt,sha256=0_9QvsVOPGBfHyKJeIuMRipxlZ93RkSzBi0BbuVxRFw,50
|
|
18
|
+
scamscript-0.2.0.dist-info/licenses/LICENSE,sha256=igeAjcsoQ1OuxBrqTyijwNZ9mcsYmJLkLfn7M5rmGg4,1080
|
|
19
|
+
scamscript-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 scamscript contributors
|
|
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.
|