citesight 0.12.0__tar.gz

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.
@@ -0,0 +1,56 @@
1
+ # Dependencies
2
+ node_modules/
3
+ npm-debug.log*
4
+ yarn-debug.log*
5
+ yarn-error.log*
6
+
7
+ # Production builds
8
+ dist/
9
+ build/
10
+
11
+ # Environment variables
12
+ .env
13
+ .env.local
14
+ .env.development.local
15
+ .env.test.local
16
+ .env.production.local
17
+
18
+ # IDE
19
+ .vscode/
20
+ .idea/
21
+ *.swp
22
+ *.swo
23
+ *~
24
+
25
+ # OS
26
+ .DS_Store
27
+ .DS_Store?
28
+ ._*
29
+ .Spotlight-V100
30
+ .Trashes
31
+ ehthumbs.db
32
+ Thumbs.db
33
+
34
+ # Logs
35
+ logs/
36
+ *.log
37
+
38
+ # Coverage
39
+ coverage/
40
+
41
+ # ESLint
42
+ .eslintcache
43
+
44
+ # TypeScript
45
+ *.tsbuildinfo
46
+
47
+ # Temporary folders
48
+ tmp/
49
+ temp/
50
+
51
+ # Claude Code
52
+ .claude/
53
+ .superpowers/
54
+ packages/desktop/resources/runtime/
55
+ packages/desktop/resources/runtime-downloads/
56
+ packages/desktop/release/
@@ -0,0 +1,47 @@
1
+ Metadata-Version: 2.5
2
+ Name: citesight
3
+ Version: 0.12.0
4
+ Summary: Python wrapper for the CiteSight CLI (citation verification and local claim evidence review)
5
+ Project-URL: Homepage, https://github.com/michael-borck/cite-sight
6
+ Author: Michael Borck
7
+ License: MIT
8
+ Keywords: academic-integrity,citations,references
9
+ Requires-Python: >=3.9
10
+ Description-Content-Type: text/markdown
11
+
12
+ # citesight
13
+
14
+ Python wrapper for the [CiteSight](https://github.com/michael-borck/cite-sight) CLI —
15
+ citation verification and (experimental) local claim-evidence review for student work.
16
+
17
+ ## Install
18
+
19
+ 1. Node.js 20+, then: `npm install -g cite-sight`
20
+ 2. This package: `pip install citesight` (or from this folder: `pip install .`)
21
+
22
+ ## Use
23
+
24
+ ```python
25
+ from cite_sight import check, library_plan, claim_overlap
26
+
27
+ result = check("essay.pdf", email="you@example.edu")
28
+ for v in result["references"]["verifications"]:
29
+ print(v["status"], "—", v["reference"]["title"])
30
+
31
+ # Coordinator pass: common vs unique sources across a cohort
32
+ plan = library_plan(["submissions/*.pdf"], output="unit-sources.json")
33
+ ```
34
+
35
+ Claim evidence review (experimental, local-only, requires
36
+ `cite-sight setup-claims runtime` + `model install`):
37
+
38
+ ```python
39
+ from cite_sight import claims
40
+ result = claims("essay.pdf", "sources.json", library="./unit-readings/")
41
+ for f in result["claims"]["findings"]:
42
+ print(f["status"], "—", f["claim"])
43
+ ```
44
+
45
+ All functions shell out to the CLI and return parsed JSON — same verdicts as
46
+ the desktop app, no data leaves the machine beyond what the CLI itself sends
47
+ (reference metadata to open scholarly APIs; claim checking is fully offline).
@@ -0,0 +1,36 @@
1
+ # citesight
2
+
3
+ Python wrapper for the [CiteSight](https://github.com/michael-borck/cite-sight) CLI —
4
+ citation verification and (experimental) local claim-evidence review for student work.
5
+
6
+ ## Install
7
+
8
+ 1. Node.js 20+, then: `npm install -g cite-sight`
9
+ 2. This package: `pip install citesight` (or from this folder: `pip install .`)
10
+
11
+ ## Use
12
+
13
+ ```python
14
+ from cite_sight import check, library_plan, claim_overlap
15
+
16
+ result = check("essay.pdf", email="you@example.edu")
17
+ for v in result["references"]["verifications"]:
18
+ print(v["status"], "—", v["reference"]["title"])
19
+
20
+ # Coordinator pass: common vs unique sources across a cohort
21
+ plan = library_plan(["submissions/*.pdf"], output="unit-sources.json")
22
+ ```
23
+
24
+ Claim evidence review (experimental, local-only, requires
25
+ `cite-sight setup-claims runtime` + `model install`):
26
+
27
+ ```python
28
+ from cite_sight import claims
29
+ result = claims("essay.pdf", "sources.json", library="./unit-readings/")
30
+ for f in result["claims"]["findings"]:
31
+ print(f["status"], "—", f["claim"])
32
+ ```
33
+
34
+ All functions shell out to the CLI and return parsed JSON — same verdicts as
35
+ the desktop app, no data leaves the machine beyond what the CLI itself sends
36
+ (reference metadata to open scholarly APIs; claim checking is fully offline).
@@ -0,0 +1,153 @@
1
+ """Python wrapper for the CiteSight CLI.
2
+
3
+ Thin and honest: every function shells out to the `cite-sight` command
4
+ (Node.js, installed via `npm install -g cite-sight`) and returns the parsed
5
+ JSON. Requires Node.js 20+; nothing else. Set CITESIGHT_CLI to point at a
6
+ specific binary.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import os
12
+ import shutil
13
+ import subprocess
14
+ from pathlib import Path
15
+ from typing import Any, Iterable
16
+
17
+ __version__ = "0.12.0"
18
+ __all__ = ["CiteSightError", "is_cli_available", "check", "claims", "library_plan", "claim_overlap", "about"]
19
+
20
+
21
+ class CiteSightError(RuntimeError):
22
+ """The cite-sight CLI is missing, or exited non-zero."""
23
+
24
+
25
+ def is_cli_available() -> bool:
26
+ """True when the cite-sight CLI can be found. Call this before showing
27
+ claim-checking UI in your own tool; all wrapper functions raise
28
+ CiteSightError with install instructions when it is missing."""
29
+ return bool(os.environ.get("CITESIGHT_CLI") or shutil.which("cite-sight"))
30
+
31
+
32
+ def _cli() -> str:
33
+ override = os.environ.get("CITESIGHT_CLI")
34
+ if override:
35
+ return override
36
+ found = shutil.which("cite-sight")
37
+ if not found:
38
+ raise CiteSightError(
39
+ "The 'cite-sight' CLI was not found on PATH. "
40
+ "Install Node.js 20+ and run: npm install -g cite-sight "
41
+ "(or set CITESIGHT_CLI to the binary path)."
42
+ )
43
+ return found
44
+
45
+
46
+ def _run(args: list[str], *, timeout: float | None) -> dict[str, Any]:
47
+ result = subprocess.run(
48
+ [_cli(), *args],
49
+ capture_output=True,
50
+ text=True,
51
+ timeout=timeout,
52
+ )
53
+ if result.returncode not in (0, 2): # 2 = findings met --fail-on, still valid JSON
54
+ raise CiteSightError(f"cite-sight exited {result.returncode}: {result.stderr.strip()[:2000]}")
55
+ try:
56
+ return json.loads(result.stdout)
57
+ except json.JSONDecodeError as exc:
58
+ raise CiteSightError(f"cite-sight returned non-JSON output: {exc}") from exc
59
+
60
+
61
+ def check(
62
+ paths: Iterable[str | Path],
63
+ *,
64
+ style: str | None = None,
65
+ email: str | None = None,
66
+ offline: bool = False,
67
+ source_list: bool = False,
68
+ fail_on: str | None = None,
69
+ bibtex: str | None = None,
70
+ timeout: float | None = None,
71
+ ) -> dict[str, Any]:
72
+ """Verify references in one or more documents. Returns the analysis JSON.
73
+
74
+ The JSON shape matches the CLI: `references.verifications[]` with
75
+ `status`, `flags`, `matchedWork`, `publicationCheck`, plus
76
+ `crossReference` (orphan/near-match suggestions) and `detectedStyle`.
77
+ """
78
+ args = ["check", *[str(p) for p in paths], "--json"]
79
+ if style:
80
+ args += ["--style", style]
81
+ if email:
82
+ args += ["--email", email]
83
+ if offline:
84
+ args.append("--offline")
85
+ if source_list:
86
+ args.append("--source-list")
87
+ if fail_on:
88
+ args += ["--fail-on", fail_on]
89
+ if bibtex:
90
+ args += ["--bibtex", bibtex]
91
+ return _run(args, timeout=timeout)
92
+
93
+
94
+ def claims(
95
+ document: str | Path,
96
+ sources_manifest: str | Path,
97
+ *,
98
+ model: str | None = None,
99
+ runner: str | None = None,
100
+ library: str | None = None,
101
+ max_claims: int = 50,
102
+ model_timeout: int = 180,
103
+ output: str | None = None,
104
+ timeout: float | None = None,
105
+ ) -> dict[str, Any]:
106
+ """Local claim-evidence review against mapped source files (experimental).
107
+
108
+ Uses the managed runtime/model installed via
109
+ `cite-sight setup-claims runtime` / `cite-sight setup-claims model <id>`
110
+ unless explicit `model`/`runner` paths are given. Findings are labelled
111
+ suggestions; quotations are verified against the source text.
112
+ """
113
+ args = ["claims", str(document), "--sources", str(sources_manifest), "--max-claims", str(max_claims), "--model-timeout", str(model_timeout)]
114
+ if model:
115
+ args += ["--model", model]
116
+ if runner:
117
+ args += ["--runner", runner]
118
+ if library:
119
+ args += ["--library", str(library)]
120
+ if output:
121
+ args += ["--output", str(output)]
122
+ else:
123
+ args += ["--json"]
124
+ return _run(args, timeout=timeout)
125
+
126
+
127
+ def library_plan(
128
+ paths: Iterable[str | Path],
129
+ *,
130
+ output: str | None = None,
131
+ timeout: float | None = None,
132
+ ) -> dict[str, Any]:
133
+ """Common vs unique references across submissions — the coordinator's
134
+ shopping list of sources to collect once per unit."""
135
+ args = ["library", "plan", *[str(p) for p in paths]]
136
+ if output:
137
+ args += ["--output", str(output)]
138
+ return _run(args, timeout=timeout)
139
+
140
+
141
+ def claim_overlap(report: str | Path, *, threshold: float = 0.6) -> dict[str, Any]:
142
+ """Similar claims on shared references across submissions (a signal, not proof)."""
143
+ result = subprocess.run(
144
+ [_cli(), "claim-overlap", str(report), "--threshold", str(threshold)],
145
+ capture_output=True, text=True,
146
+ )
147
+ return {"report": str(report), "output": result.stdout, "exit_code": result.returncode}
148
+
149
+
150
+ def about(topic: str | None = None) -> str:
151
+ args = ["about"] + ([topic] if topic else [])
152
+ result = subprocess.run([_cli(), *args], capture_output=True, text=True)
153
+ return result.stdout
@@ -0,0 +1,20 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "citesight"
7
+ version = "0.12.0"
8
+ description = "Python wrapper for the CiteSight CLI (citation verification and local claim evidence review)"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Michael Borck" }]
13
+ keywords = ["citations", "academic-integrity", "references"]
14
+ dependencies = []
15
+
16
+ [project.urls]
17
+ Homepage = "https://github.com/michael-borck/cite-sight"
18
+
19
+ [tool.hatch.build.targets.wheel]
20
+ packages = ["cite_sight"]