1. 23 Oct, 2026 12 commits
    • 郭阔's avatar
      feat(panel): homepage shows in-progress harvests · 3994a761
      郭阔 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.
      3994a761
    • 郭阔's avatar
      feat(panel): homepage shows computed next-fire time · 910157b6
      郭阔 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.
      910157b6
    • 郭阔's avatar
      feat(panel): schedule board — 06:00 editorial deadline line · f4b55d54
      郭阔 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.
      f4b55d54
    • 郭阔's avatar
      feat(panel): configurable bind address for LAN access · 0c6460f5
      郭阔 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).
      0c6460f5
    • 郭阔's avatar
      feat(panel): schedule board — 24h timeline visualization + schedule CRUD · eb56fa8e
      郭阔 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
      eb56fa8e
    • 郭阔's avatar
      docs(panel): rename per-source section to 验证登录 · 按源 · f0f61e25
      郭阔 authored
      Clearer purpose naming: the table's function is per-source login
      verification (test button + last result), not state management.
      f0f61e25
    • 郭阔's avatar
      feat(panel): manual login wizard per site · dc52b744
      郭阔 authored
      站点凭据表新增 人工登录 按钮:拉起站点共享实例窗口→用户在里面登录→
      后台 login-capture.js 每15秒自动检测(最长15分钟)→成功后记录登录态、
      缺配方站点自动生成检测配方并回收浏览器实例;页面自动刷新显示
      向导状态(运行中/登录已记录/未检测到)。复用 _login_test 轮询通道,
      键 manual:<site>。
      dc52b744
    • 郭阔's avatar
      fix(macOS): notify-mail empty-array under set -u; digest skip empty result JSON · 9be43efe
      郭阔 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
      9be43efe
    • 郭阔's avatar
      feat(panel): recycle browser instance after login test · 3b49d654
      郭阔 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
      3b49d654
    • 郭阔's avatar
      feat(arch): site-shared browser profiles, auto-recycle and run watchdog · 155faf6a
      郭阔 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
      155faf6a
    • 郭阔's avatar
      feat(panel): site-shared login model and list fixes · 12434efb
      郭阔 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()
      12434efb
    • 郭阔's avatar
  2. 22 Oct, 2026 5 commits
    • 郭阔's avatar
      feat: recipe discovery for source-less sites · 7295d704
      郭阔 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
      7295d704
    • 郭阔's avatar
      feat: site-level login credentials shared across channels · a17c0314
      郭阔 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
      a17c0314
    • 郭阔's avatar
      fix: login preflight auto-launches the source browser instance · acac322d
      郭阔 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.
      acac322d
    • 郭阔's avatar
      feat: one-click recipe auto-discovery from the panel · 55ca6d6f
      郭阔 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
      55ca6d6f
    • 郭阔's avatar
      fix: login test output captures stderr too · 88a67a5f
      郭阔 authored
      88a67a5f
  3. 21 Oct, 2026 6 commits
    • 郭阔's avatar
      fix: remove last hardcoded user, panel refresh loop · 3e8496f6
      郭阔 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)
      3e8496f6
    • 郭阔's avatar
      feat: web panel credential management for site logins · caf7cca6
      郭阔 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
      caf7cca6
    • 郭阔's avatar
      feat: login preflight before harvest · 6be2431a
      郭阔 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)
      6be2431a
    • 郭阔's avatar
      feat: per-source browser instance isolation · 776c3a9a
      郭阔 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
      776c3a9a
    • 郭阔's avatar
      feat: setup.sh bootstrap and cross-platform web panel with harvest toggle · 5e5097d0
      郭阔 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
      5e5097d0
    • 郭阔's avatar
      feat: platform abstraction layer (auto-detect darwin/linux) · 3ac999b0
      郭阔 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
      3ac999b0
  4. 20 Oct, 2026 2 commits
    • 郭阔's avatar
      feat: macOS platform adaptation, concurrency guard and detail page redesign · ed91787c
      郭阔 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/
      ed91787c
    • 谢宇轩's avatar
      feat: new feature · 4e3e086a
      谢宇轩 authored
      4e3e086a
  5. 09 Sep, 2026 1 commit
  6. 07 Sep, 2026 1 commit
  7. 02 Sep, 2026 2 commits