v1.1.0/#18: windows MSI build — sync.sh + tracked manifest

windows/ was previously an untracked working tree with manually-
copied .lua files that drifted ~6 months out of date (missed every
feature added since April 2026). #18 introduces Option 1 from the
issue body: build-time sync.

New tracked files:
  - windows/sync.sh — copies root {lmcp,server,json}.lua to pkg/.
    Idempotent; run before WiX. Catches missing source files; logs
    each sync.
  - windows/README.md — workflow doc + tracked-vs-generated map.
  - windows/lmcp.wxs — MSI manifest (Version bumped 0.1.0 → 1.1.0).
  - windows/pkg/{install_service,start}.bat — Windows service
    installer + launcher (now tracked; they were already in pkg/).

New .gitignore at repo root:
  - windows/pkg/{lmcp,server,json}.lua — regenerated by sync.sh
  - windows/pkg/lua/ — bundled Lua + LuaSocket runtime (downloaded
    separately, not in git)
  - editor noise (*.swp, *.swo, .DS_Store)

Verification (Phase 7):
  $ ./windows/sync.sh
    synced lmcp.lua
    synced server.lua
    synced json.lua
  $ diff lmcp.lua windows/pkg/lmcp.lua  → empty
  $ git ls-files -o --exclude-standard windows/
    windows/README.md
    windows/lmcp.wxs
    windows/pkg/install_service.bat
    windows/pkg/start.bat
    windows/sync.sh
  $ git check-ignore windows/pkg/{lmcp,server,json}.lua  → all 3 ignored

The "missed every feature since April" failure mode this fixes:
running sync.sh before each MSI build now guarantees pkg/ matches
master. Forgetting to run it is failure-loud (the MSI ships the
last sync's snapshot, easy to spot in QA), not silent (the manifest
points at fresh files that mismatch root).

Closes v1.1.0 milestone with #11, #20.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-17 19:43:27 +00:00
parent 55ead8041f
commit 7e62f71931
6 changed files with 229 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
# Generated by windows/sync.sh — see windows/README.md
windows/pkg/lmcp.lua
windows/pkg/server.lua
windows/pkg/json.lua
# Bundled Lua + LuaSocket runtime for the Windows MSI; downloaded
# separately, not in git.
windows/pkg/lua/
# Editor / OS noise
*.swp
*.swo
.DS_Store
+41
View File
@@ -0,0 +1,41 @@
# lmcp Windows MSI build
This directory contains the WiX manifest and packaging files for the
Windows MSI build of lmcp.
## Workflow
```sh
# 1. Pull the Lua + LuaSocket runtime into pkg/lua/ (one-time, see below).
# 2. Sync the lmcp .lua sources from the root of the repo:
./sync.sh
# 3. Bump windows/lmcp.wxs `Version="…"` to match the release tag.
# 4. Invoke WiX:
candle.exe lmcp.wxs
light.exe lmcp.wixobj -o lmcp-1.x.y.msi
```
## What's tracked vs. generated
- **Tracked** (edit in git):
- `lmcp.wxs` — WiX MSI manifest
- `sync.sh` — copies root .lua sources → `pkg/`
- `README.md` — this file
- `pkg/install_service.bat` — Windows service installer
- `pkg/start.bat` — manual launcher
- **Generated / external** (gitignored):
- `pkg/lmcp.lua`, `pkg/server.lua`, `pkg/json.lua` — produced by
`sync.sh`. Never edit directly; edit the root files and re-sync.
- `pkg/lua/` — the Lua + LuaSocket runtime drop-in. Download
separately and place here. Suggested source: the lua-binaries
project (https://github.com/rjpcomputing/luaforwindows) or a
similar pre-built bundle. The MSI expects `pkg/lua/lua.exe`,
`pkg/lua/lua54.dll`, and the `pkg/lua/socket/` + `pkg/lua/mime/`
subdirectories per the manifest.
## Issue history
Issue #18 (closed in v1.1.0) introduced this workflow after the
`pkg/` lua sources had silently drifted ~6 months out of date,
missing every feature added since April 2026.
+119
View File
@@ -0,0 +1,119 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<!-- Bump Version on every release. See windows/README.md. -->
<Product Id="*"
Name="lmcp — Lua MCP Server"
Language="1033"
Version="1.1.0"
Manufacturer="QAP'LA Project"
UpgradeCode="A7F3E2D1-4B5C-6D7E-8F9A-0B1C2D3E4F5A">
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine"
Description="Lightweight MCP server in Lua. 2MB RSS."
Comments="Zero-dependency MCP server." />
<MediaTemplate EmbedCab="yes" />
<MajorUpgrade DowngradeErrorMessage="A newer version is already installed." />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="INSTALLFOLDER" Name="lmcp">
<Directory Id="LUA_DIR" Name="lua">
<Directory Id="SOCKET_DIR" Name="socket" />
<Directory Id="MIME_DIR" Name="mime" />
</Directory>
</Directory>
</Directory>
</Directory>
<!-- lmcp application files -->
<DirectoryRef Id="INSTALLFOLDER">
<Component Id="JsonLua" Guid="B1A2C3D4-E5F6-7890-ABCD-EF1234567890">
<File Id="json.lua" Source="pkg\json.lua" KeyPath="yes" />
</Component>
<Component Id="LmcpLua" Guid="B1A2C3D4-E5F6-7890-ABCD-EF1234567891">
<File Id="lmcp.lua" Source="pkg\lmcp.lua" KeyPath="yes" />
</Component>
<Component Id="ServerLua" Guid="B1A2C3D4-E5F6-7890-ABCD-EF1234567892">
<File Id="server.lua" Source="pkg\server.lua" KeyPath="yes" />
</Component>
<Component Id="StartBat" Guid="B1A2C3D4-E5F6-7890-ABCD-EF1234567893">
<File Id="start.bat" Source="pkg\start.bat" KeyPath="yes" />
</Component>
<Component Id="InstallService" Guid="B1A2C3D4-E5F6-7890-ABCD-EF1234567894">
<File Id="install_service.bat" Source="pkg\install_service.bat" KeyPath="yes" />
</Component>
</DirectoryRef>
<!-- Lua runtime -->
<DirectoryRef Id="LUA_DIR">
<Component Id="LuaExe" Guid="C2B3D4E5-F6A7-8901-BCDE-F12345678900">
<File Id="lua.exe" Source="pkg\lua\lua.exe" KeyPath="yes" />
</Component>
<Component Id="LuaDll" Guid="C2B3D4E5-F6A7-8901-BCDE-F12345678901">
<File Id="lua54.dll" Source="pkg\lua\lua54.dll" KeyPath="yes" />
</Component>
<Component Id="SocketLua" Guid="C2B3D4E5-F6A7-8901-BCDE-F12345678902">
<File Id="socket.lua" Source="pkg\lua\socket.lua" KeyPath="yes" />
</Component>
<Component Id="MimeLua" Guid="C2B3D4E5-F6A7-8901-BCDE-F12345678903">
<File Id="mime.lua" Source="pkg\lua\mime.lua" KeyPath="yes" />
</Component>
<Component Id="Ltn12Lua" Guid="C2B3D4E5-F6A7-8901-BCDE-F12345678904">
<File Id="ltn12.lua" Source="pkg\lua\ltn12.lua" KeyPath="yes" />
</Component>
</DirectoryRef>
<!-- LuaSocket native DLLs -->
<DirectoryRef Id="SOCKET_DIR">
<Component Id="SocketCoreDll" Guid="D3C4E5F6-A7B8-9012-CDEF-123456789010">
<File Id="socket_core.dll" Name="core.dll" Source="pkg\lua\socket\core.dll" KeyPath="yes" />
</Component>
<Component Id="SocketFtp" Guid="D3C4E5F6-A7B8-9012-CDEF-123456789011">
<File Id="ftp.lua" Source="pkg\lua\socket\ftp.lua" KeyPath="yes" />
</Component>
<Component Id="SocketHeaders" Guid="D3C4E5F6-A7B8-9012-CDEF-123456789012">
<File Id="headers.lua" Source="pkg\lua\socket\headers.lua" KeyPath="yes" />
</Component>
<Component Id="SocketHttp" Guid="D3C4E5F6-A7B8-9012-CDEF-123456789013">
<File Id="http.lua" Source="pkg\lua\socket\http.lua" KeyPath="yes" />
</Component>
<Component Id="SocketTp" Guid="D3C4E5F6-A7B8-9012-CDEF-123456789014">
<File Id="tp.lua" Source="pkg\lua\socket\tp.lua" KeyPath="yes" />
</Component>
<Component Id="SocketUrl" Guid="D3C4E5F6-A7B8-9012-CDEF-123456789015">
<File Id="url.lua" Source="pkg\lua\socket\url.lua" KeyPath="yes" />
</Component>
</DirectoryRef>
<DirectoryRef Id="MIME_DIR">
<Component Id="MimeCoreDll" Guid="E4D5F6A7-B8C9-0123-DEFA-234567890120">
<File Id="mime_core.dll" Name="core.dll" Source="pkg\lua\mime\core.dll" KeyPath="yes" />
</Component>
</DirectoryRef>
<Feature Id="MainFeature" Title="lmcp Server" Level="1">
<ComponentRef Id="JsonLua" />
<ComponentRef Id="LmcpLua" />
<ComponentRef Id="ServerLua" />
<ComponentRef Id="StartBat" />
<ComponentRef Id="InstallService" />
<ComponentRef Id="LuaExe" />
<ComponentRef Id="LuaDll" />
<ComponentRef Id="SocketLua" />
<ComponentRef Id="MimeLua" />
<ComponentRef Id="Ltn12Lua" />
<ComponentRef Id="SocketCoreDll" />
<ComponentRef Id="SocketFtp" />
<ComponentRef Id="SocketHeaders" />
<ComponentRef Id="SocketHttp" />
<ComponentRef Id="SocketTp" />
<ComponentRef Id="SocketUrl" />
<ComponentRef Id="MimeCoreDll" />
</Feature>
</Product>
</Wix>
+24
View File
@@ -0,0 +1,24 @@
@echo off
REM Install lmcp as a Windows service using NSSM (Non-Sucking Service Manager)
REM Download nssm from https://nssm.cc if not present
if not exist "%~dp0nssm.exe" (
echo ERROR: nssm.exe not found in %~dp0
echo Download from https://nssm.cc and place nssm.exe here.
exit /b 1
)
set INSTALL_DIR=%~dp0
set SERVICE_NAME=lmcp
echo Installing lmcp as Windows service...
%INSTALL_DIR%nssm.exe install %SERVICE_NAME% "%INSTALL_DIR%lua\lua.exe" "%INSTALL_DIR%server.lua"
%INSTALL_DIR%nssm.exe set %SERVICE_NAME% AppDirectory "%INSTALL_DIR%"
%INSTALL_DIR%nssm.exe set %SERVICE_NAME% AppEnvironmentExtra "LMCP_PORT=8080"
%INSTALL_DIR%nssm.exe set %SERVICE_NAME% DisplayName "lmcp MCP Server"
%INSTALL_DIR%nssm.exe set %SERVICE_NAME% Description "Lightweight MCP server in Lua"
%INSTALL_DIR%nssm.exe set %SERVICE_NAME% Start SERVICE_AUTO_START
%INSTALL_DIR%nssm.exe start %SERVICE_NAME%
echo Done. Service '%SERVICE_NAME%' installed and started.
echo Check: sc query %SERVICE_NAME%
+7
View File
@@ -0,0 +1,7 @@
@echo off
REM lmcp — Lua MCP Server
REM Start the server on port 8080 (or LMCP_PORT if set)
cd /d "%~dp0"
if not defined LMCP_PORT set LMCP_PORT=8080
echo Starting lmcp on port %LMCP_PORT%...
lua\lua.exe server.lua
+25
View File
@@ -0,0 +1,25 @@
#!/bin/sh
# windows/sync.sh — refresh windows/pkg/ from root .lua sources (issue #18).
#
# Run BEFORE invoking the WiX build so the MSI bundles whatever is in
# master. The .lua files in windows/pkg/ are regenerated on every run
# and are gitignored — never edit them directly.
#
# Idempotent: re-running just re-copies. Safe to call from a Makefile,
# a CI step, or by hand before `candle.exe + light.exe`.
set -eu
here=$(dirname "$(readlink -f "$0")")
root=$(cd "$here/.." && pwd)
for f in lmcp.lua server.lua json.lua; do
if [ ! -f "$root/$f" ]; then
echo "windows/sync.sh: missing source $root/$f" >&2
exit 1
fi
cp "$root/$f" "$here/pkg/$f"
echo " synced $f"
done
echo "windows/sync.sh: done — pkg/ matches root .lua at $(date +%Y-%m-%dT%H:%M:%S)"