From 72c1b0d3df0a3b61fe74e1690eace4bf114dd3c1 Mon Sep 17 00:00:00 2001 From: pixelcola Date: Tue, 12 May 2026 14:46:01 +0800 Subject: [PATCH 1/3] fix: use nssm for windows service --- .trellis/spec/backend/directory-structure.md | 2 +- .trellis/spec/backend/error-handling.md | 12 ++-- .trellis/spec/backend/index.md | 15 ++-- .trellis/spec/backend/quality-guidelines.md | 73 ++++++++++++++++++-- README.md | 8 ++- src/sing_cli/service.py | 37 ++++++---- tests/test_service.py | 41 ++++++++--- 7 files changed, 147 insertions(+), 41 deletions(-) diff --git a/.trellis/spec/backend/directory-structure.md b/.trellis/spec/backend/directory-structure.md index 4b9cb54..246ac43 100644 --- a/.trellis/spec/backend/directory-structure.md +++ b/.trellis/spec/backend/directory-structure.md @@ -32,7 +32,7 @@ def main() -> None: 新增实现时按职责拆分模块: - `cli.py`:Typer 应用、命令参数和用户输出。 -- `service.py`:`sc.exe` 调用、服务安装、卸载、启动、停止、重启。 +- `service.py`:`nssm.exe` 调用、服务安装、卸载、启动、停止、重启。 - `state.py`:`state.json` 读写、profile 名称校验、active 状态维护。 - `profile.py`:profile URL 下载、本地 profile 文件写入。 - `errors.py`:面向 CLI 的异常类型。 diff --git a/.trellis/spec/backend/error-handling.md b/.trellis/spec/backend/error-handling.md index ff950f0..72f94e0 100644 --- a/.trellis/spec/backend/error-handling.md +++ b/.trellis/spec/backend/error-handling.md @@ -17,21 +17,21 @@ CLI 必须让失败清晰暴露。不要为了让命令“看起来成功”添 - 找不到 `sing-box.exe`、路径不存在或路径不是文件时,命令失败。 - `sing install` 不下载或升级 `sing-box.exe`。 -## `sc.exe` 错误 +## `nssm.exe` 错误 -Windows 服务注册和控制统一调用 `sc.exe`。调用时必须使用参数列表: +Windows 服务注册和控制统一调用 `nssm.exe`。调用时必须使用参数列表: ```python -subprocess.run(["sc.exe", "start", "sing-box"], ...) +subprocess.run(["nssm.exe", "start", "sing-box"], ...) ``` 不要使用 shell 字符串拼接: ```python -subprocess.run(f"sc.exe start {service_name}", shell=True) +subprocess.run(f"nssm.exe start {service_name}", shell=True) ``` -`sc.exe` 返回非零退出码时,CLI 命令失败,并把 stderr 或 stdout 中的系统错误摘要展示给用户。 +`nssm.exe` 找不到或返回非零退出码时,CLI 命令失败,并把 stderr 或 stdout 中的系统错误摘要展示给用户。 ## 服务状态错误 @@ -54,4 +54,4 @@ subprocess.run(f"sc.exe start {service_name}", shell=True) - 捕获所有异常后继续执行,会让用户误以为服务已经安装或启动。 - 在服务已运行时让 `start` 自动重启,会隐藏用户选择的配置切换行为。 - 删除 active profile 会让 `state.json` 和 Windows 服务命令行分离。 -- 把 `sc.exe` 命令拼成 shell 字符串会破坏带空格路径,并增加注入风险。 +- 把 `nssm.exe` 命令拼成 shell 字符串会破坏带空格路径,并增加注入风险。 diff --git a/.trellis/spec/backend/index.md b/.trellis/spec/backend/index.md index 2981dcc..bc39297 100644 --- a/.trellis/spec/backend/index.md +++ b/.trellis/spec/backend/index.md @@ -8,7 +8,7 @@ |------|------|------| | [目录结构](./directory-structure.md) | 包布局、入口点、本地数据布局 | 已填写 | | [数据库规范](./database-guidelines.md) | 无数据库约束、本地 JSON 状态边界 | 已填写 | -| [错误处理](./error-handling.md) | CLI 错误、`sc.exe` 错误、profile 状态错误 | 已填写 | +| [错误处理](./error-handling.md) | CLI 错误、NSSM 错误、profile 状态错误 | 已填写 | | [质量规范](./quality-guidelines.md) | Python 版本、依赖、Ruff/ty/CI/Dependabot 契约、命令契约、测试要求 | 已填写 | | [日志规范](./logging-guidelines.md) | CLI 输出边界、stdout/stderr 规则 | 已填写 | @@ -27,7 +27,7 @@ - 可执行命令由 `pyproject.toml` 的 `[project.scripts]` 声明:`sing = "sing_cli.main:main"`。 - 当前源码位于 `src/sing_cli/`。 - CLI 框架使用 `typer`,HTTP 下载使用 `httpx`。 -- Windows 服务管理使用系统内置 `sc.exe`,不使用 `pywin32`。 +- Windows 服务管理使用 `nssm.exe`,不使用 `pywin32`。 - 固定 Windows 服务名为 `sing-box`。 - 本地应用数据目录使用 `typer.get_app_dir("sing-cli")`。 @@ -47,8 +47,8 @@ sing update sing list ``` -- `sing install` 注册 `sing-box` Windows 服务并开启自启;默认使用 `PATH` 中的 `sing-box.exe`,`--bin` 可指定自定义路径。 -- `sing install` 不下载、不升级 `sing-box.exe`,也不指定或写入业务 profile。 +- `sing install` 通过 NSSM 注册 `sing-box` Windows 服务并开启自启;默认使用 `PATH` 中的 `sing-box.exe`,`--bin` 可指定自定义路径。 +- `sing install` 不下载、不升级 `sing-box.exe` 或 `nssm.exe`,也不指定或写入业务 profile。 - `sing start ` 使用 `` 对应的本地 profile 启动服务;服务已运行时失败并提示使用 `sing restart `。 - `sing restart ` 停止当前服务后,用 `` 对应 profile 重新启动。 - `sing stop` 停止服务,不需要 profile 名。 @@ -59,12 +59,13 @@ sing list ## 服务命令行 -`sing start ` 和 `sing restart ` 启动前必须先更新服务命令行: +`sing start ` 和 `sing restart ` 启动前必须先更新 NSSM 服务参数: ```text -sc.exe config sing-box binPath= " run -c " +nssm.exe set sing-box Application +nssm.exe set sing-box AppParameters "run -c \"\"" ``` 随后再启动 `sing-box` 服务。Windows 自启时沿用最后一次 `sing start ` 或 `sing restart ` 写入的 profile。 -调用 `sc.exe` 必须使用参数列表,不使用 shell 字符串拼接。 +调用 `nssm.exe` 必须使用参数列表,不使用 shell 字符串拼接。 diff --git a/.trellis/spec/backend/quality-guidelines.md b/.trellis/spec/backend/quality-guidelines.md index a6b9f0d..49d3fd6 100644 --- a/.trellis/spec/backend/quality-guidelines.md +++ b/.trellis/spec/backend/quality-guidelines.md @@ -12,7 +12,7 @@ - Ruff、ty 和 pytest 是当前已确认的代码质量工具。 - CLI 框架使用 `typer`。 - HTTP 客户端使用 `httpx`。 -- Windows 服务管理使用 `sc.exe`,不使用 `pywin32`。 +- Windows 服务管理使用 `nssm.exe`,不使用 `pywin32`。 - 文档和 Trellis SPEC 使用中文编写。 ## 命令契约 @@ -31,12 +31,75 @@ sing update sing list ``` -- `sing install` 只注册服务并开启自启;不处理业务配置。 -- `sing start ` 负责把服务命令行更新到 `` 对应配置,再启动服务。 -- `sing restart ` 先停止服务,再更新服务命令行并启动服务。 +- `sing install` 通过 NSSM 注册服务并开启自启;不处理业务配置。 +- `sing start ` 负责把 NSSM 服务参数更新到 `` 对应配置,再启动服务。 +- `sing restart ` 先停止服务,再更新 NSSM 服务参数并启动服务。 - `sing stop` 不需要配置名。 - `sing list` 必须标出 active 配置。 +## NSSM 服务管理契约 + +### 1. Scope / Trigger + +- Trigger: 修改 Windows 服务安装、卸载、启动、停止、状态查询或 profile 到服务参数的映射。 + +### 2. Signatures + +```text +nssm.exe install sing-box +nssm.exe set sing-box Start SERVICE_AUTO_START +nssm.exe set sing-box Application +nssm.exe set sing-box AppParameters "run -c \"\"" +nssm.exe status sing-box +nssm.exe start sing-box +nssm.exe stop sing-box +nssm.exe remove sing-box confirm +``` + +### 3. Contracts + +- `sing install [--bin ]` 解析 `sing-box.exe` 后调用 `nssm.exe install`,再设置 `Start` 为 `SERVICE_AUTO_START`。 +- `sing start ` 启动前设置 `Application` 为已安装的 `sing-box.exe` 路径,设置 `AppParameters` 为 `run -c ""`。 +- `sing restart ` 必须先停止服务,停止成功后再写入 NSSM 参数并启动服务。 +- `nssm.exe` 必须从 `PATH` 解析;项目不下载、不内置 NSSM。 +- 外部命令必须用参数列表调用,不通过 shell 字符串执行。 + +### 4. Validation & Error Matrix + +| 条件 | 行为 | +|------|------| +| `nssm.exe` 不在 `PATH` | 命令失败并提示安装 NSSM 且让 `nssm.exe` 可从 `PATH` 访问 | +| `nssm.exe` 返回非零退出码 | 命令失败并暴露 stderr 或 stdout 摘要 | +| `nssm.exe status sing-box` 输出 `SERVICE_RUNNING` | `service_is_running()` 返回 `True` | +| `sing start ` 发现服务已运行 | 命令失败并提示使用 `sing restart ` | + +### 5. Good/Base/Bad Cases + +- Good: `subprocess.run([nssm_path, "set", "sing-box", "AppParameters", 'run -c "C:/profiles/home"'], ...)` +- Base: profile 路径包含空格时,`AppParameters` 仍作为单个参数传给 NSSM。 +- Bad: `subprocess.run(f"nssm.exe set sing-box AppParameters run -c {profile_path}", shell=True)` + +### 6. Tests Required + +- 安装服务测试断言 `nssm.exe install sing-box ` 和 `nssm.exe set sing-box Start SERVICE_AUTO_START`。 +- 配置服务测试断言 `Application` 与 `AppParameters` 分别写入。 +- NSSM 失败测试断言非零退出码转换为 CLI 错误。 +- NSSM 缺失测试断言错误信息说明 `nssm.exe` 不在 `PATH`。 + +### 7. Wrong vs Correct + +#### Wrong + +```python +subprocess.run(f"nssm.exe start {SERVICE_NAME}", shell=True) +``` + +#### Correct + +```python +subprocess.run([nssm_path, "start", SERVICE_NAME], capture_output=True, check=False, text=True) +``` + ## Ruff 工具链契约 ### 1. Scope / Trigger @@ -430,7 +493,7 @@ updates: - Typer 命令参数和错误提示。 - `sing install` 的 PATH 解析、`--bin` 覆盖、找不到二进制失败。 -- `sc.exe` 参数列表构造,不通过 shell 字符串执行。 +- `nssm.exe` 参数列表构造,不通过 shell 字符串执行。 - `sing start ` 服务已运行时失败。 - `sing restart ` 停止失败时不继续启动。 - `state.json` 读写、active 更新和删除 active 配置失败。 diff --git a/README.md b/README.md index 39a79b2..01d9510 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,15 @@ Windows CLI for installing and controlling the `sing-box` Windows service. +## Requirements + +`sing-box.exe` and `nssm.exe` must be available in `PATH`. `sing install --bin ` can use a custom `sing-box.exe` path. + ## Commands | Command | Description | |---|---| -| `sing install [--bin ]` | Register the `sing-box` Windows service and enable autostart. | +| `sing install [--bin ]` | Register the `sing-box` Windows service through NSSM and enable autostart. | | `sing uninstall` | Delete the `sing-box` Windows service. | | `sing start ` | Start the service with a saved profile. | | `sing stop` | Stop the service. | @@ -16,4 +20,4 @@ Windows CLI for installing and controlling the `sing-box` Windows service. | `sing update ` | Redownload a saved profile from its URL. | | `sing list` | List saved profiles and mark the active profile. | -`sing install` uses `sing-box.exe` from `PATH` unless `--bin` is provided. The CLI does not download or upgrade `sing-box.exe`. +`sing install` uses `sing-box.exe` from `PATH` unless `--bin` is provided. The CLI does not download or upgrade `sing-box.exe` or `nssm.exe`. diff --git a/src/sing_cli/service.py b/src/sing_cli/service.py index b90f4c0..0eaef9d 100644 --- a/src/sing_cli/service.py +++ b/src/sing_cli/service.py @@ -9,6 +9,7 @@ from .errors import ExternalCommandError, SingCliError SERVICE_NAME = "sing-box" +NSSM_EXE = "nssm.exe" Runner = Callable[[list[str]], subprocess.CompletedProcess[str]] @@ -36,9 +37,16 @@ def resolve_bin(bin_path: Path | None) -> Path: return resolved -def run_sc(arguments: list[str], runner: Runner = default_runner) -> subprocess.CompletedProcess[str]: +def resolve_nssm() -> str: + found = shutil.which(NSSM_EXE) + if found is None: + raise SingCliError("nssm.exe was not found in PATH. Install NSSM and make nssm.exe available in PATH.") + return found + + +def run_nssm(arguments: list[str], runner: Runner = default_runner) -> subprocess.CompletedProcess[str]: ensure_windows() - command = ["sc.exe", *arguments] + command = [resolve_nssm(), *arguments] result = runner(command) if result.returncode != 0: output = result.stderr.strip() or result.stdout.strip() @@ -47,33 +55,38 @@ def run_sc(arguments: list[str], runner: Runner = default_runner) -> subprocess. def install_service(bin_path: Path, runner: Runner = default_runner) -> None: - run_sc(create_service_arguments(bin_path), runner) + run_nssm(create_service_arguments(bin_path), runner) + run_nssm(["set", SERVICE_NAME, "Start", "SERVICE_AUTO_START"], runner) def uninstall_service(runner: Runner = default_runner) -> None: - run_sc(["delete", SERVICE_NAME], runner) + run_nssm(["remove", SERVICE_NAME, "confirm"], runner) def service_is_running(runner: Runner = default_runner) -> bool: - result = run_sc(["query", SERVICE_NAME], runner) - return "RUNNING" in result.stdout + result = run_nssm(["status", SERVICE_NAME], runner) + return "SERVICE_RUNNING" in result.stdout def configure_service(bin_path: str, profile_path: str, runner: Runner = default_runner) -> None: - run_sc(configure_service_arguments(bin_path, profile_path), runner) + for arguments in configure_service_arguments(bin_path, profile_path): + run_nssm(arguments, runner) def create_service_arguments(bin_path: Path) -> list[str]: - return ["create", SERVICE_NAME, "binPath=", f'"{bin_path}" run', "start=", "auto"] + return ["install", SERVICE_NAME, str(bin_path)] -def configure_service_arguments(bin_path: str, profile_path: str) -> list[str]: - return ["config", SERVICE_NAME, "binPath=", f'"{bin_path}" run -c "{profile_path}"'] +def configure_service_arguments(bin_path: str, profile_path: str) -> list[list[str]]: + return [ + ["set", SERVICE_NAME, "Application", bin_path], + ["set", SERVICE_NAME, "AppParameters", f'run -c "{profile_path}"'], + ] def start_service(runner: Runner = default_runner) -> None: - run_sc(["start", SERVICE_NAME], runner) + run_nssm(["start", SERVICE_NAME], runner) def stop_service(runner: Runner = default_runner) -> None: - run_sc(["stop", SERVICE_NAME], runner) + run_nssm(["stop", SERVICE_NAME], runner) diff --git a/tests/test_service.py b/tests/test_service.py index 51f1f2c..966aef9 100644 --- a/tests/test_service.py +++ b/tests/test_service.py @@ -18,6 +18,7 @@ def completed_process( def enable_windows(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr(service.sys, "platform", "win32") + monkeypatch.setattr(service.shutil, "which", lambda executable: f"C:/tools/{executable}") def test_configure_service_uses_argument_list(monkeypatch: pytest.MonkeyPatch) -> None: @@ -32,12 +33,19 @@ def runner(command: list[str]) -> subprocess.CompletedProcess[str]: assert commands == [ [ - "sc.exe", - "config", + "C:/tools/nssm.exe", + "set", "sing-box", - "binPath=", - '"C:/Program Files/sing-box/sing-box.exe" run -c "C:/Users/me/AppData/profiles/home"', - ] + "Application", + "C:/Program Files/sing-box/sing-box.exe", + ], + [ + "C:/tools/nssm.exe", + "set", + "sing-box", + "AppParameters", + 'run -c "C:/Users/me/AppData/profiles/home"', + ], ] @@ -52,15 +60,32 @@ def runner(command: list[str]) -> subprocess.CompletedProcess[str]: service.install_service(Path("C:/tools/sing-box.exe"), runner) assert commands == [ - ["sc.exe", "create", "sing-box", "binPath=", '"C:/tools/sing-box.exe" run', "start=", "auto"] + ["C:/tools/nssm.exe", "install", "sing-box", "C:/tools/sing-box.exe"], + ["C:/tools/nssm.exe", "set", "sing-box", "Start", "SERVICE_AUTO_START"], ] -def test_run_sc_surfaces_external_command_failure(monkeypatch: pytest.MonkeyPatch) -> None: +def test_run_nssm_surfaces_external_command_failure(monkeypatch: pytest.MonkeyPatch) -> None: enable_windows(monkeypatch) def runner(command: list[str]) -> subprocess.CompletedProcess[str]: return completed_process(command, stderr="Access is denied.", returncode=5) with pytest.raises(ExternalCommandError, match="Access is denied"): - service.run_sc(["start", "sing-box"], runner) + service.run_nssm(["start", "sing-box"], runner) + + +def test_resolve_nssm_reports_missing_executable(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(service.shutil, "which", lambda executable: None) + + with pytest.raises(service.SingCliError, match="nssm.exe was not found"): + service.resolve_nssm() + + +def test_service_is_running_reads_nssm_status(monkeypatch: pytest.MonkeyPatch) -> None: + enable_windows(monkeypatch) + + def runner(command: list[str]) -> subprocess.CompletedProcess[str]: + return completed_process(command, stdout="SERVICE_RUNNING") + + assert service.service_is_running(runner) From 7ea91b3876a44c900d475de2bcd2ab98888c7e9d Mon Sep 17 00:00:00 2001 From: pixelcola Date: Tue, 12 May 2026 14:48:18 +0800 Subject: [PATCH 2/3] chore(task): archive fix windows service start timeout --- .../check.jsonl | 1 + .../implement.jsonl | 1 + .../prd.md | 70 +++++++++++++++++++ .../task.json | 26 +++++++ 4 files changed, 98 insertions(+) create mode 100644 .trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/check.jsonl create mode 100644 .trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/implement.jsonl create mode 100644 .trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/prd.md create mode 100644 .trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/task.json diff --git a/.trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/check.jsonl b/.trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/check.jsonl new file mode 100644 index 0000000..9dd3234 --- /dev/null +++ b/.trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/check.jsonl @@ -0,0 +1 @@ +{"_example": "Fill with {\"file\": \"\", \"reason\": \"\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."} diff --git a/.trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/implement.jsonl b/.trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/implement.jsonl new file mode 100644 index 0000000..9dd3234 --- /dev/null +++ b/.trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/implement.jsonl @@ -0,0 +1 @@ +{"_example": "Fill with {\"file\": \"\", \"reason\": \"\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."} diff --git a/.trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/prd.md b/.trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/prd.md new file mode 100644 index 0000000..06e663c --- /dev/null +++ b/.trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/prd.md @@ -0,0 +1,70 @@ +# Fix Windows Service Start Timeout + +## Goal + +Fix `sing start ` failing with Windows `StartService` error 1053 by using NSSM as the Windows service host while preserving the intended command model: `sing install` installs the Windows service and enables autostart, and `sing start ` starts `sing-box` with the selected configuration. + +## What I Already Know + +* User observed `sing start config.json` failing with `sc.exe failed: [SC] StartService failed 1053`. +* Current service registration and reconfiguration live in `src/sing_cli/service.py`. +* `install_service()` registers `sing-box` with `binPath= " run"`. +* `configure_service()` rewrites the service to `binPath= " run -c """`. +* `sing-box run` is a normal foreground command and does not implement the Windows service control dispatcher expected by the Windows Service Control Manager. +* `sc.exe` operations are tested in `tests/test_service.py`. +* `sing install` is intended to install the Windows service and set it to autostart. +* `sing start ` is intended to use a saved configuration to start `sing-box`. +* NSSM supports command-line service installation with `nssm install []`. +* NSSM service parameters can be updated with `nssm set `, including `Application`, `AppDirectory`, `AppParameters`, and `Start`. +* NSSM supports `nssm start `, `nssm stop `, and `nssm remove confirm`. + +## Assumptions + +* The CLI should keep the existing command surface: `sing install`, `sing start `, `sing stop`, and `sing restart `. +* The fix should preserve the fixed Windows service name `sing-box`. +* The service should run the installed `sing-box.exe` with the selected profile path. +* Autostart should use the last configuration applied by `sing start ` or `sing restart `. +* No backward compatibility with the old direct `sc.exe binPath` format is required. +* `nssm.exe` is available on `PATH` when Windows service commands are used. + +## Requirements + +* Register the `sing-box` Windows service through NSSM. +* Keep `sing install` focused on service installation and autostart setup. +* Make `sing start ` configure the selected profile and start the Windows service without triggering SCM error 1053. +* Make `sing restart ` stop, reconfigure, and start through the same service host. +* Ensure NSSM starts the configured `sing-box.exe run -c ` command. +* Keep external command failures visible as explicit CLI errors. +* Add or update tests for the service command construction and configuration behavior. + +## Acceptance Criteria + +* [ ] `sing install --bin ` calls NSSM to install the `sing-box` service. +* [ ] `sing install --bin ` sets NSSM `Start` to `SERVICE_AUTO_START`. +* [ ] `sing start ` sets NSSM `Application` and `AppParameters` so NSSM runs ` run -c `. +* [ ] `sing start ` starts the service through NSSM. +* [ ] Unit tests cover the updated install/configure/start command behavior. +* [ ] Ruff, ty, and pytest pass. + +## Definition of Done + +* Tests added or updated where behavior changes. +* Lint, type check, and tests pass. +* Documentation is updated if the public command behavior changes. +* Windows-specific behavior remains testable on non-Windows through injected command runners. + +## Out of Scope + +* Downloading or upgrading `sing-box.exe`. +* Supporting multiple Windows service instances. +* Silent fallback to foreground process execution when service startup fails. +* Adding compatibility for the old `binPath= " run"` service format. +* Downloading or bundling `nssm.exe`. + +## Technical Notes + +* Relevant files: `src/sing_cli/service.py`, `src/sing_cli/cli.py`, `tests/test_service.py`, `README.md`. +* Project spec index: `.trellis/spec/backend/index.md`. +* The current implementation uses `sc.exe` with argument lists; NSSM should also be called with argument lists and no shell string. +* NSSM command reference: `https://www.nssm.cc/commands`. +* NSSM usage reference: `https://nssm.cc/usage`. diff --git a/.trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/task.json b/.trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/task.json new file mode 100644 index 0000000..6db1211 --- /dev/null +++ b/.trellis/tasks/archive/2026-05/05-12-fix-windows-service-start-timeout/task.json @@ -0,0 +1,26 @@ +{ + "id": "fix-windows-service-start-timeout", + "name": "fix-windows-service-start-timeout", + "title": "Fix Windows service start timeout", + "description": "", + "status": "completed", + "dev_type": null, + "scope": null, + "package": null, + "priority": "P2", + "creator": "pixelcola", + "assignee": "pixelcola", + "createdAt": "2026-05-12", + "completedAt": "2026-05-12", + "branch": null, + "base_branch": "main", + "worktree_path": null, + "commit": null, + "pr_url": null, + "subtasks": [], + "children": [], + "parent": null, + "relatedFiles": [], + "notes": "", + "meta": {} +} \ No newline at end of file From f8fb7c1f39f67ce2b6bac3b69cec354901ccfb17 Mon Sep 17 00:00:00 2001 From: pixelcola Date: Tue, 12 May 2026 14:48:36 +0800 Subject: [PATCH 3/3] chore: record journal --- .trellis/workspace/pixelcola/index.md | 5 ++-- .trellis/workspace/pixelcola/journal-1.md | 33 +++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/.trellis/workspace/pixelcola/index.md b/.trellis/workspace/pixelcola/index.md index 1bfd10e..ec85b15 100644 --- a/.trellis/workspace/pixelcola/index.md +++ b/.trellis/workspace/pixelcola/index.md @@ -8,7 +8,7 @@ - **Active File**: `journal-1.md` -- **Total Sessions**: 2 +- **Total Sessions**: 3 - **Last Active**: 2026-05-12 @@ -19,7 +19,7 @@ | File | Lines | Status | |------|-------|--------| -| `journal-1.md` | ~73 | Active | +| `journal-1.md` | ~106 | Active | --- @@ -29,6 +29,7 @@ | # | Date | Title | Commits | Branch | |---|------|-------|---------|--------| +| 3 | 2026-05-12 | Use NSSM for Windows service | `72c1b0d` | `fix/use-nssm-service` | | 2 | 2026-05-12 | Windows sing-box CLI | `2f18462` | `feature/windows-sing-box-cli` | | 1 | 2026-05-12 | Bootstrap Guidelines | `ced349d` | `main` | diff --git a/.trellis/workspace/pixelcola/journal-1.md b/.trellis/workspace/pixelcola/journal-1.md index c6ae48e..028dd6b 100644 --- a/.trellis/workspace/pixelcola/journal-1.md +++ b/.trellis/workspace/pixelcola/journal-1.md @@ -71,3 +71,36 @@ Implemented the Windows sing-box CLI with Typer commands, local profile state, s ### Next Steps - None - task complete + + +## Session 3: Use NSSM for Windows service + +**Date**: 2026-05-12 +**Task**: Use NSSM for Windows service +**Branch**: `fix/use-nssm-service` + +### Summary + +Replaced direct sc.exe service management with NSSM commands, updated service tests and documented the NSSM service contract. + +### Main Changes + +(Add details) + +### Git Commits + +| Hash | Message | +|------|---------| +| `72c1b0d` | (see git log) | + +### Testing + +- [OK] (Add test results) + +### Status + +[OK] **Completed** + +### Next Steps + +- None - task complete