- 26 Oct, 2026 10 commits
-
-
郭阔 authored
Two validation refinements so 'nothing new but junk candidates' stops alarming as FAILED (reuters-markets case: 18 candidates, 16 deduped, the only 2 new ones rejected as non-article pages): - majority-failure rule downgrades to a warning when source_exhausted and every failure is a non-article rejection (og:type/body), same standing as all_seen - preloaded per-URL INVALID_OUTPUT failures no longer set task-failed (task-level no-URL failures and RUNTIME/PERMISSION still fatal); the per-article signal already lives in counts and warnings
-
郭阔 authored
attempt_needs_retry triggers on runtime error / empty output / non-object result (GLM StructuredOutput text-return case) / is_error (1301 etc); content-quality failures do NOT trigger (a provider switch won't fix them). Flow: attempt1 primary → attempt2 same provider (10s backoff) → attempt3 FALLBACK_PROVIDER via resolve_continue_provider with its budget override (ccswitch-gpt=30). Idempotent end-to-end (7-day registry dedup + slug-keyed push), so re-runs only fill gaps; per-attempt raw outputs kept as *.attemptN. Verified decision matrix: success/runtime-error/invalid-output/api-error/ business-fail.
-
郭阔 authored
Disabled/fully-off sources (skill off + schedule not active) no longer appear; transitional state (skill off but schedule still active) stays visible until reconciled.
-
郭阔 authored
-
郭阔 authored
systemd is-active semantics leaked to macOS (merged rows hardcoded active=unknown; scheduled rows showed systemd 'inactive'). Map every row to schedule_state: 调度中 / 已禁用 / 未排程.
-
郭阔 authored
Replace guessed phases with ground truth: harvest.sh seeds logs/<source>.phase=采集中 and the prompt requires the agent to overwrite it the moment it enters each stage (采集中/摘要生成/推送/收尾); trap deletes it on exit. Panel reads the phase file first, falls back to factual disk signals (registry/.summaries/.manifest mtimes), and shows neutral 运行中 when no signal exists — no more inference, no more (推定) labels.
-
郭阔 authored
Redundant runs (all articles deduped by the 7-day registry) burned ~19 turns / $0.6 verifying nothing new. Prompt now instructs: when every candidate is already in the registry, return immediately with empty articles + source_exhausted=true + exhaustion_reason=all_seen — which the result contract already accepts as SUCCESS (exhaustion is not failure), also dodging the GLM StructuredOutput misreport for this case.
-
郭阔 authored
A redundant run (all articles deduped) never rewrites .manifest.json, so the disk-signal inference stayed at 采集中 during the whole summary/finalize phase while the browser sat idle. After 10 minutes with no fetch signals, report 摘要生成(推定) instead.
-
郭阔 authored
active_harvests() only read launchd/systemd service state, so runs started via the panel button or a terminal (not launchd) were invisible on the homepage. Union with runlock-based detection: each port-<port>.<pid>.lock created by harvest.sh itself, PID liveness-checked, source name recovered from the PID's command line — launcher-independent.
-
郭阔 authored
Lock files are port-<port>.<pid>.lock (two dots); ${f##*.} yielded the literal 'lock' instead of the PID, so the liveness check always failed and ANY exiting harvest deleted sibling LIVE locks — with all locks gone the last exiter then quit the site-shared browser out from under a still-running sibling harvest (nikkei-world 09:24 exit killed the browser mid nikkei-markets run; earlier 05:00 run likely degraded the same way until the 60min watchdog TERM'd it at exit=143). Parse correctly: basename minus .lock suffix, then last dot-segment. Self-test: live lock survives, dead-PID lock cleaned.
-
- 23 Oct, 2026 15 commits
-
-
郭阔 authored
上次 trigger time duplicated 最近运行's log mtime — remove it (column now just 下次执行) along with its log-mtime backfill in index().
-
郭阔 authored
launchd exposes no last-trigger either (systemd-only) — fill it from the run log mtime (MM-DD HH:MM); merged unscheduled/disabled rows now carry their parse_last_log too, so only genuinely never-run sources show 从未触发 (verified: 10 ran-today sources show real times, 4 never-run reuters sources remain 从未触发).
-
郭阔 authored
- homepage: drop 成本/Session columns (detail-page info); running badge now shows inferred phase (采集中/摘要生成/推送收尾) via _harvest_phase(): runlock mtime = start, vault-day .manifest/.summaries/.registry mtimes mark phase transitions — zero intrusion into the harvest process - detail page: timeline-style progress bar (采集中→摘要生成→推送/收尾→完成) with pulsing current-stage dot, green done segments, elapsed minutes, 10s auto-refresh while running
-
郭阔 authored
栏目列表 now surfaces running harvests: top banner (⟳ 正在采集: <sources>, browsers stay open until finish), per-row 运行中 badge above 最近运行, and 30s auto-refresh while any harvest is active — previously an in-flight run was invisible until its .last.log landed.
-
郭阔 authored
launchd exposes no next-trigger (systemd-only), so the 栏目列表 下次 column was always '-' on macOS — compute it from schedule times (same _next_fire as the schedule board) and highlight it amber.
-
郭阔 authored
Blue dashed deadline marker at 06:00 on every timeline (交付线 label) + intro copy; multi-time sources show 每日N次 badge. Editorial schedule applied: 02:30 nikkei-world / 03:00 reuters-business / 03:30 bloomberg / 04:00 ft / 04:30 wsj / 05:00+17:00 nikkei-markets (12h interval), all finishing ~35min before the 06:00 deadline.
-
郭阔 authored
app.py honors WEB_HOST/WEB_PORT env (default 127.0.0.1:8080); run-web.sh template exports them from web.conf — set WEB_HOST=0.0.0.0 to reach the panel from other systems on the same network (HTTP + Basic Auth, intranet use intended).
-
郭阔 authored
- new /schedules 调度中心: per-source row with a 24h timeline (green dots at fire times, next fire highlighted amber, red now-line), 定时/下次触发 (countdown)/上次运行 columns, sorted by next fire, 60s auto-refresh - create/update: POST /schedule-time (HH:MM list, validated) → nh_schedule_write + enable (+skill enable for new rows) - delete: POST /schedule-delete/<name> → new platform.sh nh_schedule_remove (bootout + rm plist incl. disabled + entry script + per-source conf; skill source and history kept; digest/web protected) - guards: active harvests block time changes/deletes - nav link 调度中心; schedule_times() string parsed to list
-
郭阔 authored
Clearer purpose naming: the table's function is per-source login verification (test button + last result), not state management.
-
郭阔 authored
站点凭据表新增 人工登录 按钮:拉起站点共享实例窗口→用户在里面登录→ 后台 login-capture.js 每15秒自动检测(最长15分钟)→成功后记录登录态、 缺配方站点自动生成检测配方并回收浏览器实例;页面自动刷新显示 向导状态(运行中/登录已记录/未检测到)。复用 _login_test 轮询通道, 键 manual:<site>。
-
郭阔 authored
- notify-mail.sh: bash 3.2 (stock macOS) treats expanding an empty array under set -u as unbound variable — drop the MSMTP_ARGS array for direct branch invocation (works identically on Linux bash 5) - daily-digest.sh: empty result .json files (run killed / watchdog timeout, claude never wrote output) pass 'jq empty' but emit nothing on extraction, corrupting the summary array with consecutive commas; treat non-empty-size files as parse errors so killed runs show up honestly as interrupted
-
郭阔 authored
- platform.sh: new nh_quit_instance <source> — quits the site-shared instance after panel login tests; skips when a harvest holds the port runlock - app.py: login-test / login-test-src / login-discover background threads now recycle the instance when the test finishes (login state lives in profile, unaffected); manual-login flow (ensure-chromium --login) intentionally left open
-
郭阔 authored
- platform.sh: nh_ensure_instance/nh_entry_write now use per-SITE instance (port 9300+hash(site), profiles/<site>/) so one account logs in once per site; prevents same-account multi-login session kicking (digitimes/nikkei both enforce device limits) - harvest.sh: quit shared instance on EXIT with port-keyed reference counting ($WORK_DIR/runlocks, stale-PID cleanup) — last same-site run recycles - harvest.sh: hard watchdog kills a hung claude run after MAX_RUNTIME_MIN (default 60, per-source conf overridable) so launchd next-day trigger is never blocked
-
郭阔 authored
- index: unscheduled sources no longer link to /source (was 404); show 未排程 badge - index: sources with toggle ON sort first - logins page: split into per-source login-state table (site-shared instance column, per-source test via new /login-test-src route) + site-credential table - platform_layer: skill_sources() exposes method; login_sites() drops direct sources; new login_source_rows()
-
郭阔 authored
-
- 22 Oct, 2026 5 commits
-
-
郭阔 authored
- platform.sh nh_login_autodiscover: no installed source for the site (bloomberg/statista) exports NH_LOGIN_URL from the credential's url - web: site rows without sources can run 自动配置配方/登录测试 (probe falls back to site name); credential url serves as discovery entry
-
郭阔 authored
- platform.sh: credential lookup falls back site-level (logins/<site>.json, site = first segment of source name); nikkei-world/markets/tech share one nikkei account, single file to maintain - platform_layer: login_sites()/login_rows() site view (coverage, probe source, recipe status) for the panel - web: /logins page now site-based — save/delete/discover/test operate per site; discovery probes via the site's representative source
-
郭阔 authored
nh_login_preflight assumed the per-source Chromium was already running (panel login-test failed silently for sources whose window had been closed); extract nh_ensure_instance (no-op when alive) and use it in both preflight and autodiscover. Harvests were unaffected — harvest.js already runs ensure-chromium itself.
-
郭阔 authored
- nh_login_autodiscover (platform.sh): ensure the source's dedicated browser instance is up, load credentials, run skill discover (recipe generation + live login verification) - /login-discover route + 自动配置配方并测试 button for sources with credentials but no recipe; reuses the background-test polling UI
-
郭阔 authored
-
- 21 Oct, 2026 6 commits
-
-
郭阔 authored
- sudo -u yichu replaced by NH_RUN_USER env (linux panels running as root configure the execution user; empty = current user, darwin always direct) — last hardcode outside guarded legacy tools - logins.html: emit meta refresh only while a login test is running (content=0 caused an infinite reload loop) - deploy/migrate keep their overridable yichu defaults (legacy server tools, already parameterized via args/env)
-
郭阔 authored
- /logins page: per-source credentials CRUD (write-only password, masked display, 600-perm files in etc/news-harvester/logins/), recipe availability badge, one-click login test (background thread, page polls result) - nh_login_preflight auto-selects the source's dedicated browser instance (port+profile) when caller didn't set one - panel env carries SKILLS_DIR so recipe detection works in-process
-
郭阔 authored
- nh_login_preflight (platform.sh): sources with credentials at $CONF_DIR/logins/<source>.json (600) get a login check via the skill's login-tools.js before claude runs; auto-login on failure; harvest never blocked (paywall honestly reported by result contract) - harvest.sh invokes preflight after result contract preparation - SKILLS_DIR / SKILLS_REPO_URL documented in default.conf.example - test: preflight invoked when credentials configured (fake skill)
-
郭阔 authored
- nh_cdp_port: stable per-source CDP port (9300+name hash) - nh_entry_write: entry scripts now export CDP_PORT_OVERRIDE + CDP_PROFILE_OVERRIDE so parallel harvests each drive a dedicated Chromium (own port + own profile); regenerated idempotently - pairs with news-hub-skills CDP_PROFILE_OVERRIDE support - darwin test asserts isolation env in generated entry
-
郭阔 authored
- bin/setup.sh: one-command machine bootstrap (auto platform detect) — directory layout, dependency check (brew install on consent), claude auth check, skills repo auto-clone from SKILLS_REPO_URL + npm install + full bundle import (all sources), dual skill symlink registration, default.conf/web.conf generation (random panel password), optional web panel service install, digest schedule, remaining-manual-steps summary; idempotent - web/app.py: platform_layer integration — paths/timer reads/trigger/ active-harvest checks unified; add/edit/disable actions now work on darwin; per-source harvest toggle route (schedule load/unload + skill enable/disable; auto staggered schedule creation on first enable) - index.html: toggle switch column, unscheduled skill sources merged into list, platform-neutral labels - bin/platform_layer.py: python facade reusing platform.sh via 'platform.sh call' dispatcher for all mutations; file reads native
-
郭阔 authored
- bin/platform.sh: single source of truth for platform differences — OS detection (NH_OS override for tests), PATH bootstrap without shadowing caller-injected commands, platform default paths, scheduler abstraction (systemd timer + systemctl <-> launchd plist + launchctl with named entry scripts), file-level disable on darwin (survives reboot, one-click recoverable), sed -i / GNU-sed shims, root check only on linux, conf loading (EnvironmentFile equivalent) - bin/schedule.py: plist parse/write + auto-detect by filename (timer/plist/.disabled); schedule sources listing subcommand - harvest/continue/daily-digest: drop hardcoded nvm//home/yichu paths, self-bootstrap via platform.sh, harvest now loads conf itself (run.sh wrapper no longer required) - add-source/modify-source: fully cross-platform schedule management (plist generation + launchctl on darwin, timer + systemctl on linux) - status.sh: cross-platform overview/detail/journal (launchd log on darwin) - deploy/migrate: linux-only guard with pointer to setup.sh - tests: env-synced platform simulation (NH_OS), fake launchctl suite, darwin plist/disable/enable roundtrip tests; new disable contract (unload + preserve times) replaces clear-times; 37 tests green
-
- 20 Oct, 2026 2 commits
-
-
郭阔 authored
- web/app.py: IS_DARWIN branches (launchctl kickstart for manual trigger, direct execution for digest/continue without sudo); _active_harvests() concurrency guard on /run and /continue; normalized detail state (last run time from log filename, next trigger computed from schedule) - detail.html: layout redesign — status badge header, real overview cards, merged duplicate run metadata, collapsible logs/config, history moved up - gitignore: exclude .zcode/
-
谢宇轩 authored
-
- 09 Sep, 2026 1 commit
-
-
谢宇轩 authored
-
- 07 Sep, 2026 1 commit
-
-
谢宇轩 authored
-