@kingcrab/pi-imessage 1.0.0 → 1.1.0

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/ops/README.md CHANGED
@@ -186,6 +186,13 @@ text). Never reset cursors, delete state or replay uncertain sends. Do not use
186
186
 
187
187
  ### 3. Run one private controller
188
188
 
189
+ From a chat, the assistant calls `restart_service` with the full commit hash of
190
+ the prepared release directory (ADR 0052). The host writes the controller
191
+ directory below itself and opens the controller only after that tool call has
192
+ settled; the call returns the directory and the next call verifies (step 4).
193
+ The manual procedure below is for operators and for a cold start when no
194
+ service is running.
195
+
189
196
  In a `mktemp -d /tmp/pi-imessage-restart.XXXXXX` directory with `umask 077`:
190
197
 
191
198
  - `environment.sh`: shell-quoted exports of the running process's `WORKING_DIR`,
@@ -196,44 +203,11 @@ In a `mktemp -d /tmp/pi-imessage-restart.XXXXXX` directory with `umask 077`:
196
203
  - `control.sh`: shell-quoted `OLD_PID`, `OLD_STARTED` (exact `ps -o lstart=`),
197
204
  `EXPECTED_COMMAND`, `REPO` (the release directory), `NODE`, `WORKING_DIR`,
198
205
  `WEB_PORT` and `LOG_FILE`.
199
- - `restart.command`:
200
-
201
- ```sh
202
- #!/bin/bash
203
- set -euo pipefail
204
- umask 077
205
- DEPLOY_DIR="$(cd "$(dirname "$0")" && pwd)"
206
- source "$DEPLOY_DIR/environment.sh"
207
- source "$DEPLOY_DIR/control.sh"
208
- : "${OLD_PID:?}" "${OLD_STARTED:?}" "${EXPECTED_COMMAND:?}"
209
- : "${REPO:?}" "${NODE:?}" "${WORKING_DIR:?}" "${WEB_PORT:?}" "${LOG_FILE:?}"
210
- cd "$REPO"
211
- exec 3>>"$DEPLOY_DIR/controller.log"
212
- [ "$(ps -p "$OLD_PID" -o lstart=)" = "$OLD_STARTED" ]
213
- [ "$(ps -p "$OLD_PID" -o command=)" = "$EXPECTED_COMMAND" ]
214
- printf '%s stopping pid=%s\n' "$(date -u +%FT%TZ)" "$OLD_PID" >&3
215
- kill -TERM "$OLD_PID"
216
- deadline=$((SECONDS + 30))
217
- while kill -0 "$OLD_PID" 2>/dev/null; do
218
- if (( SECONDS >= deadline )); then
219
- echo 'Shutdown timeout; no force-kill and no second process started' >&3
220
- exit 1
221
- fi
222
- sleep 0.1
223
- done
224
- [ ! -e "$WORKING_DIR/durable/owner.lock" ]
225
- port_status=0
226
- lsof -nP -iTCP:"$WEB_PORT" -sTCP:LISTEN -t > /dev/null || port_status=$?
227
- case "$port_status" in
228
- 0) echo 'Port still occupied; refusing startup' >&3; exit 1 ;;
229
- 1) ;; # No listener.
230
- *) echo 'Cannot verify port ownership; refusing startup' >&3; exit 1 ;;
231
- esac
232
- printf '%s old process exited; ownership released\n' "$(date -u +%FT%TZ)" >&3
233
- printf '%s\n' "$$" > "$DEPLOY_DIR/new.pid"
234
- exec 3>&-
235
- exec "$NODE" --use-env-proxy --experimental-strip-types src/cli.ts serve >> "$LOG_FILE" 2>&1
236
- ```
206
+ - `restart.command`: a copy of [`ops/restart.command`](restart.command) from the
207
+ release directory. It checks the old PID's start time and command, sends
208
+ SIGTERM, waits up to 30 s, refuses to start while the lock or port is held,
209
+ writes `controller.log` and `new.pid`, deletes `environment.sh` and then
210
+ `exec`s the new service process.
237
211
 
238
212
  Launch it once with `chmod 700` and `open -a Terminal "$DEPLOY_DIR/restart.command"`
239
213
  (`osascript` `do script` times out on claw). The separate Terminal keeps the
@@ -241,10 +215,17 @@ controller alive when the initiating agent's own turn is interrupted. For a
241
215
  launchd controller, use that job's lifecycle instead; never `launchctl kickstart -k`
242
216
  from inside the service.
243
217
 
218
+ A chat that writes its own controller through `bash` instead of
219
+ `restart_service` must end that call right after `open`: no `sleep`, polling or
220
+ verification in the same call. Tools are replay-safe by default (ADR 0041), so a
221
+ call still running when the controller stops the service reruns on every start,
222
+ launches another controller and loops (#39). Verify in a later call.
223
+
244
224
  ### 4. Verify
245
225
 
246
- Read `controller.log`, `new.pid`, the service log and the listener first. Never
247
- launch the controller twice before the first outcome is known. Require:
226
+ In a new tool call, read `controller.log`, `new.pid`, the service log and the
227
+ listener first. Never launch the controller twice before the first outcome is
228
+ known. Require:
248
229
 
249
230
  1. Old PID gone; exactly one new process and listener, cwd in the release
250
231
  directory.
@@ -252,7 +233,9 @@ launch the controller twice before the first outcome is known. Require:
252
233
  `Messaging ready` and `Application started`; no startup error.
253
234
  3. Root and changed endpoints return 200; check UI changes in a browser.
254
235
  4. Interrupted work continues; scheduler deadlines are unchanged; receipt
255
- counts change only by new sends and sends interrupted by the stop.
236
+ counts change only by new sends and sends interrupted by the stop. After
237
+ `restart_service`, the old log shows `Restart requested` with the
238
+ controller directory.
256
239
 
257
240
  On a timeout, lock, occupied port or startup failure, stop and report it. Do not
258
241
  force-kill, steal the lock, reinstall dependencies or restore a workspace snapshot.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kingcrab/pi-imessage",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "A minimal, self-managing iMessage bot powered by Pi Durable",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -34,10 +34,10 @@
34
34
  "test": "vitest run"
35
35
  },
36
36
  "dependencies": {
37
- "@earendil-works/chord": "1.0.2",
38
- "@earendil-works/pi-ai": "1.0.2",
39
- "@earendil-works/pi-coding-agent": "1.0.2",
40
- "@earendil-works/pi-durable": "1.0.2",
37
+ "@earendil-works/chord": "1.4.0",
38
+ "@earendil-works/pi-ai": "1.4.0",
39
+ "@earendil-works/pi-coding-agent": "1.4.0",
40
+ "@earendil-works/pi-durable": "1.4.0",
41
41
  "better-sqlite3": "13.0.3",
42
42
  "defuddle": "0.19.4",
43
43
  "sharp": "0.35.5",