stock-weekly-report 0.1.9 → 0.2.1
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.
- package/cli.py +38 -35
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/requirements.txt +4 -2
- package/scripts/postinstall.js +36 -0
package/cli.py
CHANGED
|
@@ -17,7 +17,6 @@ Usage:
|
|
|
17
17
|
|
|
18
18
|
import os
|
|
19
19
|
import re
|
|
20
|
-
import shutil
|
|
21
20
|
import smtplib
|
|
22
21
|
import subprocess
|
|
23
22
|
import sys
|
|
@@ -90,24 +89,6 @@ def _write_zprofile_var(var_name: str, value: str) -> None:
|
|
|
90
89
|
zprofile.write_text(content, encoding="utf-8")
|
|
91
90
|
|
|
92
91
|
|
|
93
|
-
def _detect_nlm() -> str:
|
|
94
|
-
"""Auto-detect the nlm binary path. Returns '' if not found."""
|
|
95
|
-
# 1. Check PATH
|
|
96
|
-
found = shutil.which("nlm")
|
|
97
|
-
if found:
|
|
98
|
-
return found
|
|
99
|
-
# 2. Check common install locations
|
|
100
|
-
candidates = [
|
|
101
|
-
"~/.local/bin/nlm",
|
|
102
|
-
"/usr/local/bin/nlm",
|
|
103
|
-
"/opt/homebrew/bin/nlm",
|
|
104
|
-
]
|
|
105
|
-
for candidate in candidates:
|
|
106
|
-
expanded = Path(candidate).expanduser()
|
|
107
|
-
if expanded.exists():
|
|
108
|
-
return str(expanded)
|
|
109
|
-
return ""
|
|
110
|
-
|
|
111
92
|
|
|
112
93
|
def _install_cron_job(schedule: str) -> None:
|
|
113
94
|
run_sh = PROJECT_ROOT / "run.sh"
|
|
@@ -151,12 +132,15 @@ def init(ctx):
|
|
|
151
132
|
|
|
152
133
|
# 0. Project root (where pipeline.py and venv/ live)
|
|
153
134
|
cwd = Path.cwd()
|
|
135
|
+
saved_root = cfg.get("project_root", "")
|
|
154
136
|
if (cwd / "pipeline.py").exists():
|
|
155
137
|
suggested_root = str(cwd)
|
|
138
|
+
elif saved_root and (Path(saved_root) / "pipeline.py").exists():
|
|
139
|
+
suggested_root = saved_root
|
|
156
140
|
elif (PROJECT_ROOT / "pipeline.py").exists():
|
|
157
141
|
suggested_root = str(PROJECT_ROOT)
|
|
158
142
|
else:
|
|
159
|
-
suggested_root =
|
|
143
|
+
suggested_root = saved_root or ""
|
|
160
144
|
project_root_input = click.prompt("Project root [required]", default=suggested_root)
|
|
161
145
|
project_root_path = Path(project_root_input).expanduser().resolve()
|
|
162
146
|
if not (project_root_path / "pipeline.py").exists():
|
|
@@ -168,21 +152,21 @@ def init(ctx):
|
|
|
168
152
|
default_folder = cfg.get("parent_folder", str(Path.home() / "swr-data"))
|
|
169
153
|
parent_folder = click.prompt("Data folder path [required]", default=default_folder)
|
|
170
154
|
|
|
171
|
-
# 2. nlm
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if
|
|
180
|
-
click.echo(
|
|
181
|
-
|
|
182
|
-
|
|
155
|
+
# 2. nlm — installed automatically by postinstall; check auth status
|
|
156
|
+
nlm_path_expanded = cfg.get("nlm_path", "")
|
|
157
|
+
if nlm_path_expanded and Path(nlm_path_expanded).exists():
|
|
158
|
+
click.echo(f" ✓ nlm found at {nlm_path_expanded}")
|
|
159
|
+
auth_ok = subprocess.run(
|
|
160
|
+
[nlm_path_expanded, "login", "--check"],
|
|
161
|
+
capture_output=True,
|
|
162
|
+
).returncode == 0
|
|
163
|
+
if auth_ok:
|
|
164
|
+
click.echo(" ✓ nlm already authenticated")
|
|
165
|
+
elif click.confirm(" Log in to NotebookLM now? [optional — needed for upload stage]", default=True):
|
|
166
|
+
subprocess.run([nlm_path_expanded, "login"], check=False)
|
|
183
167
|
else:
|
|
184
|
-
|
|
185
|
-
click.echo("
|
|
168
|
+
click.echo(" ! nlm not found — run: swr config set nlm_path /path/to/nlm")
|
|
169
|
+
click.echo(" (or reinstall: npm install -g stock-weekly-report)")
|
|
186
170
|
|
|
187
171
|
# 3. SMTP password → ~/.zprofile (optional)
|
|
188
172
|
existing_password = os.environ.get("EMAIL_SMTP_PASSWORD", "")
|
|
@@ -277,7 +261,6 @@ def init(ctx):
|
|
|
277
261
|
cfg.update({
|
|
278
262
|
"project_root": str(project_root_path),
|
|
279
263
|
"parent_folder": parent_folder,
|
|
280
|
-
"nlm_path": nlm_path_expanded,
|
|
281
264
|
"email": email_cfg,
|
|
282
265
|
"retention": {
|
|
283
266
|
"audio_months": audio_months,
|
|
@@ -581,6 +564,26 @@ def config_set(ctx, key, value):
|
|
|
581
564
|
click.echo(f"Set {key} = {obj[leaf]}")
|
|
582
565
|
|
|
583
566
|
|
|
567
|
+
# ─── nlm-login ────────────────────────────────────────────────────────────────
|
|
568
|
+
|
|
569
|
+
@main.command("nlm-login")
|
|
570
|
+
@click.pass_context
|
|
571
|
+
def nlm_login_cmd(ctx):
|
|
572
|
+
"""Log in to NotebookLM (browser OAuth). Run once, or again if auth expires."""
|
|
573
|
+
cfg = _load_cfg(ctx.obj["config"])
|
|
574
|
+
nlm_path = cfg.get("nlm_path", "")
|
|
575
|
+
if not nlm_path or not Path(nlm_path).exists():
|
|
576
|
+
click.echo("Error: nlm not found. Set it with: swr config set nlm_path /path/to/nlm", err=True)
|
|
577
|
+
sys.exit(1)
|
|
578
|
+
auth_ok = subprocess.run([nlm_path, "login", "--check"], capture_output=True).returncode == 0
|
|
579
|
+
if auth_ok:
|
|
580
|
+
click.echo("Already authenticated. Use --force to re-login.")
|
|
581
|
+
if not click.confirm("Re-login anyway?", default=False):
|
|
582
|
+
return
|
|
583
|
+
result = subprocess.run([nlm_path, "login"], check=False)
|
|
584
|
+
sys.exit(result.returncode)
|
|
585
|
+
|
|
586
|
+
|
|
584
587
|
# ─── mcp ──────────────────────────────────────────────────────────────────────
|
|
585
588
|
|
|
586
589
|
@main.command("mcp")
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
package/requirements.txt
CHANGED
|
@@ -5,8 +5,10 @@ tqdm>=4.0
|
|
|
5
5
|
faster-whisper>=1.0
|
|
6
6
|
markdown>=3.0
|
|
7
7
|
click>=8.0
|
|
8
|
-
# notebooklm-mcp-cli
|
|
9
|
-
# pip install notebooklm-mcp-cli
|
|
8
|
+
# notebooklm-mcp-cli requires Python >=3.11 — install into the CLI venv, not the pipeline venv:
|
|
9
|
+
# ~/.config/swr/venv/bin/pip install notebooklm-mcp-cli
|
|
10
|
+
# Then set nlm_path in config:
|
|
11
|
+
# swr config set nlm_path ~/.config/swr/venv/bin/nlm
|
|
10
12
|
|
|
11
13
|
# CLI + MCP entry points require Python >=3.10; install via:
|
|
12
14
|
# venv14/bin/pip install -e .
|
package/scripts/postinstall.js
CHANGED
|
@@ -72,8 +72,44 @@ try {
|
|
|
72
72
|
|
|
73
73
|
const pip = path.join(VENV, "bin", "pip");
|
|
74
74
|
execFileSync(pip, ["install", "."], { stdio: "inherit", cwd: ROOT });
|
|
75
|
+
execFileSync(pip, ["install", "notebooklm-mcp-cli"], { stdio: "inherit", cwd: ROOT });
|
|
75
76
|
|
|
76
77
|
fs.writeFileSync(VERSION_FILE, CURRENT_VER + "\n", "utf8");
|
|
78
|
+
|
|
79
|
+
// ── Set project_root in config if not already pointing to a valid location ─
|
|
80
|
+
const configPath = path.join(SWR_DIR, "config.yaml");
|
|
81
|
+
let needsProjectRoot = true;
|
|
82
|
+
if (fs.existsSync(configPath)) {
|
|
83
|
+
const content = fs.readFileSync(configPath, "utf8");
|
|
84
|
+
const match = content.match(/^project_root:\s*(.+)$/m);
|
|
85
|
+
if (match) {
|
|
86
|
+
const existing = match[1].trim().replace(/^['"]|['"]$/g, "");
|
|
87
|
+
if (fs.existsSync(path.join(existing, "pipeline.py"))) {
|
|
88
|
+
needsProjectRoot = false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (needsProjectRoot) {
|
|
93
|
+
execFileSync(SWR_BIN, ["config", "set", "project_root", ROOT], { stdio: "inherit" });
|
|
94
|
+
console.log(`swr: Set project_root to ${ROOT}`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ── Set nlm_path if not already pointing to a working binary ─────────────
|
|
98
|
+
const nlmBin = path.join(VENV, "bin", "nlm");
|
|
99
|
+
let needsNlmPath = true;
|
|
100
|
+
if (fs.existsSync(configPath)) {
|
|
101
|
+
const content = fs.readFileSync(configPath, "utf8");
|
|
102
|
+
const match = content.match(/^nlm_path:\s*(.+)$/m);
|
|
103
|
+
if (match) {
|
|
104
|
+
const existing = match[1].trim().replace(/^['"]|['"]$/g, "");
|
|
105
|
+
if (fs.existsSync(existing)) needsNlmPath = false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (needsNlmPath && fs.existsSync(nlmBin)) {
|
|
109
|
+
execFileSync(SWR_BIN, ["config", "set", "nlm_path", nlmBin], { stdio: "inherit" });
|
|
110
|
+
console.log(`swr: Set nlm_path to ${nlmBin}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
77
113
|
console.log(`\nswr: Setup complete (v${CURRENT_VER}). Run \`swr --help\` to get started.\n`);
|
|
78
114
|
} catch (err) {
|
|
79
115
|
console.error("\nswr postinstall failed:", err.message);
|