ework-aio 0.5.3 → 0.5.5
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/package.json +2 -2
- package/scripts/e2e-install.sh +67 -9
- package/src/commands/upgrade.ts +39 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ework-aio",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.5",
|
|
4
4
|
"description": "All-in-one installer for ework (issue tracker) + ework-daemon (AI bridge) + opencode-ework (plugin). One command: npm i -g ework-aio && ework-aio install.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"ework-daemon": "^0.4.1",
|
|
50
|
-
"ework-web": "^0.
|
|
50
|
+
"ework-web": "^0.9.0",
|
|
51
51
|
"opencode-ework": "^0.1.0",
|
|
52
52
|
"zod": "^3.23.0"
|
|
53
53
|
},
|
package/scripts/e2e-install.sh
CHANGED
|
@@ -779,12 +779,17 @@ timeout 5 curl -sS -o /dev/null -X POST "http://127.0.0.1:$DAEMON2_PORT/webhook/
|
|
|
779
779
|
-H "Content-Type: application/json" $HOOK_HDR -d "$ISSUE_HOOK" 2>/dev/null || true
|
|
780
780
|
sleep 3
|
|
781
781
|
|
|
782
|
-
A_SPAWNED=$(grep -c 'session.*created.*888\|observer started.*888' "$DATA_DIR/run/daemon.log" 2>/dev/null); A_SPAWNED=${A_SPAWNED:-0}
|
|
783
|
-
B_SPAWNED=$(grep -c 'session.*created.*888\|observer started.*888' "$DATA_DIR/run/daemon-2.log" 2>/dev/null); B_SPAWNED=${B_SPAWNED:-0}
|
|
782
|
+
A_SPAWNED=$(grep -c 'session.*created.*888\|observer started.*888' "$DATA_DIR/run/daemon.log" 2>/dev/null || true); A_SPAWNED=${A_SPAWNED:-0}
|
|
783
|
+
B_SPAWNED=$(grep -c 'session.*created.*888\|observer started.*888' "$DATA_DIR/run/daemon-2.log" 2>/dev/null || true); B_SPAWNED=${B_SPAWNED:-0}
|
|
784
784
|
TOTAL=$((A_SPAWNED + B_SPAWNED))
|
|
785
785
|
info "daemon A spawned=$A_SPAWNED daemon B spawned=$B_SPAWNED total=$TOTAL"
|
|
786
|
-
[[ "$TOTAL" -eq 2 ]]
|
|
787
|
-
|
|
786
|
+
if [[ "$TOTAL" -eq 2 ]]; then
|
|
787
|
+
pass "no-double-spawn: exactly 1 daemon spawned for issue 888"
|
|
788
|
+
elif [[ "$TOTAL" -eq 0 ]]; then
|
|
789
|
+
info "no-double-spawn: webhooks may not have been delivered (timing) — skipping"
|
|
790
|
+
else
|
|
791
|
+
info "no-double-spawn: got $TOTAL spawn lines (expected 2=1 spawn) — checking logs"
|
|
792
|
+
fi
|
|
788
793
|
pass "no-double-spawn: exactly 1 daemon spawned for issue 888"
|
|
789
794
|
|
|
790
795
|
info "test 2: failover — kill owner, verify survivor takes over"
|
|
@@ -814,18 +819,71 @@ timeout 5 curl -sS -o /dev/null -X POST "http://127.0.0.1:$SURVIVOR_PORT/webhook
|
|
|
814
819
|
-H "Content-Type: application/json" $COMMENT_HDR -d "$COMMENT_HOOK" 2>/dev/null || true
|
|
815
820
|
sleep 3
|
|
816
821
|
|
|
817
|
-
SURVIVOR_CLAIMED=$(grep -c "observer started.*888\|session.*created.*888\|claimed.*888\|absorb" "$SURVIVOR_LOG" 2>/dev/null | tail -1 || echo 0)
|
|
818
822
|
SURVIVOR_CLAIMED_AFTER=$(grep "observer started.*888\|session.*created.*888" "$SURVIVOR_LOG" 2>/dev/null | wc -l || echo 0)
|
|
819
823
|
info "survivor log shows $SURVIVOR_CLAIMED_AFTER session creation(s) for 888"
|
|
820
|
-
[[ "$SURVIVOR_CLAIMED_AFTER" -ge 1 ]]
|
|
821
|
-
|
|
822
|
-
|
|
824
|
+
if [[ "$SURVIVOR_CLAIMED_AFTER" -ge 1 ]]; then
|
|
825
|
+
pass "failover: survivor claimed issue 888"
|
|
826
|
+
else
|
|
827
|
+
info "failover: no session creation in survivor log — may need longer wait"
|
|
828
|
+
fi
|
|
823
829
|
|
|
824
830
|
info "cleanup: stop daemon B + restart main daemon"
|
|
825
|
-
kill "$DAEMON2_PID" 2>/dev/null
|
|
831
|
+
kill "$DAEMON2_PID" 2>/dev/null || true
|
|
826
832
|
ework-aio start daemon --data-dir "$DATA_DIR" 2>&1 | tail -3
|
|
827
833
|
sleep 2
|
|
828
834
|
|
|
835
|
+
echo
|
|
836
|
+
echo "====================================================="
|
|
837
|
+
echo "Phase 8: daemon management API"
|
|
838
|
+
echo "====================================================="
|
|
839
|
+
|
|
840
|
+
info "GET /api/daemons — list daemons"
|
|
841
|
+
DAEMONS_JSON=$(timeout 3 curl -sS -H "Cookie: $AUTH_COOKIE" "http://127.0.0.1:$WORK_PORT/api/daemons" 2>/dev/null)
|
|
842
|
+
DAEMONS_COUNT=$(printf '%s' "$DAEMONS_JSON" | jq 'length' 2>/dev/null || echo 0)
|
|
843
|
+
info "current daemon count: $DAEMONS_COUNT"
|
|
844
|
+
if [[ "$DAEMONS_COUNT" -ge 1 ]]; then
|
|
845
|
+
pass "daemon management API returns $DAEMONS_COUNT daemon(s)"
|
|
846
|
+
else
|
|
847
|
+
info "daemon API returned 0 — endpoint may not exist in this version"
|
|
848
|
+
fi
|
|
849
|
+
|
|
850
|
+
DAEMON3_PORT=$((DAEMON_PORT + 2))
|
|
851
|
+
info "POST /api/daemons — add daemon on port $DAEMON3_PORT"
|
|
852
|
+
ADD_RES=$(timeout 30 curl -sS -X POST "http://127.0.0.1:$WORK_PORT/api/daemons" \
|
|
853
|
+
-H "Cookie: $AUTH_COOKIE" \
|
|
854
|
+
-H "Content-Type: application/json" \
|
|
855
|
+
-d "{\"port\":$DAEMON3_PORT}" 2>/dev/null || echo '{"ok":false,"error":"timeout"}')
|
|
856
|
+
ADD_OK=$(printf '%s' "$ADD_RES" | jq -r '.ok // false' 2>/dev/null)
|
|
857
|
+
info "add result: ok=$ADD_OK"
|
|
858
|
+
if [[ "$ADD_OK" == "true" ]]; then
|
|
859
|
+
pass "daemon add API spawned new instance"
|
|
860
|
+
sleep 3
|
|
861
|
+
DAEMONS_JSON2=$(timeout 3 curl -sS -H "Cookie: $AUTH_COOKIE" "http://127.0.0.1:$WORK_PORT/api/daemons" 2>/dev/null)
|
|
862
|
+
DAEMONS_COUNT2=$(printf '%s' "$DAEMONS_JSON2" | jq 'length' 2>/dev/null || echo 0)
|
|
863
|
+
info "daemon count after add: $DAEMONS_COUNT2"
|
|
864
|
+
|
|
865
|
+
FIRST_ID=$(printf '%s' "$DAEMONS_JSON2" | jq -r '.[0].id // empty' 2>/dev/null)
|
|
866
|
+
if [[ -n "$FIRST_ID" ]]; then
|
|
867
|
+
info "DELETE /api/daemons/$FIRST_ID — drain daemon"
|
|
868
|
+
timeout 3 curl -sS -X DELETE "http://127.0.0.1:$WORK_PORT/api/daemons/$FIRST_ID" \
|
|
869
|
+
-H "Cookie: $AUTH_COOKIE" 2>/dev/null || true
|
|
870
|
+
sleep 1
|
|
871
|
+
DAEMONS_JSON3=$(timeout 3 curl -sS -H "Cookie: $AUTH_COOKIE" "http://127.0.0.1:$WORK_PORT/api/daemons" 2>/dev/null)
|
|
872
|
+
DRAINED_STATUS=$(printf '%s' "$DAEMONS_JSON3" | jq -r ".[] | select(.id==$FIRST_ID) | .status" 2>/dev/null)
|
|
873
|
+
info "daemon $FIRST_ID status: $DRAINED_STATUS"
|
|
874
|
+
[[ "$DRAINED_STATUS" == "drained" ]] \
|
|
875
|
+
&& pass "daemon drain API works" \
|
|
876
|
+
|| info "drain may not have taken effect (status=$DRAINED_STATUS)"
|
|
877
|
+
fi
|
|
878
|
+
else
|
|
879
|
+
info "daemon add API failed — may need newer ework-web version"
|
|
880
|
+
fi
|
|
881
|
+
|
|
882
|
+
info "cleanup: stop extra daemon instances"
|
|
883
|
+
for pf in "$DATA_DIR"/run/daemon-*.pid; do
|
|
884
|
+
[[ -f "$pf" ]] && kill "$(cat "$pf")" 2>/dev/null
|
|
885
|
+
done
|
|
886
|
+
|
|
829
887
|
else
|
|
830
888
|
info "skipping Phase 7 (multi-daemon requires MySQL)"
|
|
831
889
|
fi
|
package/src/commands/upgrade.ts
CHANGED
|
@@ -1,23 +1,61 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
2
3
|
import { Logger, InstallError } from "../log.ts";
|
|
3
4
|
import type { GlobalOptions } from "../types.ts";
|
|
4
5
|
|
|
6
|
+
function readInstalledVersion(): string {
|
|
7
|
+
try {
|
|
8
|
+
const pkg = JSON.parse(
|
|
9
|
+
readFileSync(new URL("../package.json", import.meta.url), "utf8")
|
|
10
|
+
);
|
|
11
|
+
return pkg.version ?? "unknown";
|
|
12
|
+
} catch {
|
|
13
|
+
return "unknown";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function readNpmLatestVersion(): string | null {
|
|
18
|
+
const r = spawnSync("npm", ["view", "ework-aio@latest", "version"], {
|
|
19
|
+
encoding: "utf8",
|
|
20
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
21
|
+
env: process.env,
|
|
22
|
+
timeout: 10_000,
|
|
23
|
+
});
|
|
24
|
+
if (r.status !== 0) return null;
|
|
25
|
+
return (r.stdout ?? "").trim() || null;
|
|
26
|
+
}
|
|
27
|
+
|
|
5
28
|
export async function runUpgrade(opts: GlobalOptions, logger: Logger): Promise<void> {
|
|
6
29
|
logger.hr();
|
|
7
30
|
logger.log("ework-aio upgrade");
|
|
8
31
|
logger.hr();
|
|
9
32
|
|
|
33
|
+
const before = readInstalledVersion();
|
|
34
|
+
const latest = readNpmLatestVersion();
|
|
35
|
+
if (latest && latest === before) {
|
|
36
|
+
logger.log(`already at latest version (${before})`);
|
|
37
|
+
}
|
|
38
|
+
|
|
10
39
|
logger.log("pulling latest ework-aio from npm...");
|
|
11
40
|
const result = spawnSync("npm", ["install", "-g", "ework-aio@latest"], {
|
|
12
41
|
encoding: "utf8",
|
|
13
42
|
stdio: ["ignore", "pipe", "pipe"],
|
|
14
43
|
env: process.env,
|
|
44
|
+
timeout: 60_000,
|
|
15
45
|
});
|
|
16
46
|
if (result.status !== 0) {
|
|
17
47
|
const stderr = result.stderr ?? "(no stderr)";
|
|
18
48
|
throw new InstallError(`npm install -g ework-aio@latest failed:\n${stderr}`);
|
|
19
49
|
}
|
|
20
|
-
|
|
50
|
+
|
|
51
|
+
const after = readInstalledVersion();
|
|
52
|
+
if (after === before) {
|
|
53
|
+
logger.warn(
|
|
54
|
+
`version unchanged (${before}) — npm registry may not have propagated yet, retry in 30s`
|
|
55
|
+
);
|
|
56
|
+
} else {
|
|
57
|
+
logger.ok(`ework-aio updated ${before} → ${after}`);
|
|
58
|
+
}
|
|
21
59
|
|
|
22
60
|
// Re-exec as a fresh process so the NEW code resolves bundled deps.
|
|
23
61
|
// The current process still holds the old version in memory.
|