@femtomc/mu-server 26.2.55 → 26.2.56
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/README.md +33 -4
- package/dist/control_plane.d.ts +61 -2
- package/dist/control_plane.js +621 -37
- package/dist/generation_supervisor.d.ts +21 -0
- package/dist/generation_supervisor.js +107 -0
- package/dist/server.d.ts +5 -2
- package/dist/server.js +495 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ Bun.serve(server);
|
|
|
34
34
|
|
|
35
35
|
### Status
|
|
36
36
|
|
|
37
|
-
- `GET /api/status` - Returns repository status
|
|
37
|
+
- `GET /api/status` - Returns repository + control-plane runtime status
|
|
38
38
|
```json
|
|
39
39
|
{
|
|
40
40
|
"repo_root": "/path/to/repo",
|
|
@@ -43,7 +43,32 @@ Bun.serve(server);
|
|
|
43
43
|
"control_plane": {
|
|
44
44
|
"active": true,
|
|
45
45
|
"adapters": ["slack"],
|
|
46
|
-
"routes": [{ "name": "slack", "route": "/webhooks/slack" }]
|
|
46
|
+
"routes": [{ "name": "slack", "route": "/webhooks/slack" }],
|
|
47
|
+
"generation": {
|
|
48
|
+
"supervisor_id": "control-plane",
|
|
49
|
+
"active_generation": { "generation_id": "control-plane-gen-3", "generation_seq": 3 },
|
|
50
|
+
"pending_reload": null,
|
|
51
|
+
"last_reload": {
|
|
52
|
+
"attempt_id": "control-plane-reload-4",
|
|
53
|
+
"reason": "mu_setup_apply_slack",
|
|
54
|
+
"state": "completed",
|
|
55
|
+
"requested_at_ms": 0,
|
|
56
|
+
"swapped_at_ms": 0,
|
|
57
|
+
"finished_at_ms": 0,
|
|
58
|
+
"from_generation": { "generation_id": "control-plane-gen-2", "generation_seq": 2 },
|
|
59
|
+
"to_generation": { "generation_id": "control-plane-gen-3", "generation_seq": 3 }
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"observability": {
|
|
63
|
+
"counters": {
|
|
64
|
+
"reload_success_total": 4,
|
|
65
|
+
"reload_failure_total": 0,
|
|
66
|
+
"reload_drain_duration_ms_total": 73,
|
|
67
|
+
"reload_drain_duration_samples_total": 4,
|
|
68
|
+
"duplicate_signal_total": 0,
|
|
69
|
+
"drop_signal_total": 0
|
|
70
|
+
}
|
|
71
|
+
}
|
|
47
72
|
}
|
|
48
73
|
}
|
|
49
74
|
```
|
|
@@ -64,12 +89,15 @@ Bun.serve(server);
|
|
|
64
89
|
}
|
|
65
90
|
}
|
|
66
91
|
```
|
|
67
|
-
- `POST /api/control-plane/reload` -
|
|
68
|
-
- Re-reads current config from `.mu/config.json` and
|
|
92
|
+
- `POST /api/control-plane/reload` - Trigger generation-scoped control-plane hot reload
|
|
93
|
+
- Re-reads current config from `.mu/config.json` and executes warmup/cutover/drain/rollback flow
|
|
94
|
+
- Coalesces concurrent requests onto a single in-flight attempt
|
|
69
95
|
- Body (optional):
|
|
70
96
|
```json
|
|
71
97
|
{ "reason": "mu_setup_apply" }
|
|
72
98
|
```
|
|
99
|
+
- Response includes generation metadata and, when telegram generation handling runs, `telegram_generation` lifecycle detail.
|
|
100
|
+
- `POST /api/control-plane/rollback` - Explicit rollback trigger (same pipeline, reason=`rollback`)
|
|
73
101
|
|
|
74
102
|
### Issues
|
|
75
103
|
|
|
@@ -169,6 +197,7 @@ The server uses:
|
|
|
169
197
|
- IssueStore and ForumStore from mu packages
|
|
170
198
|
- Bun's built-in HTTP server
|
|
171
199
|
- Simple REST-style JSON API
|
|
200
|
+
- Generation-supervised control-plane hot reload lifecycle (see `docs/adr-0001-control-plane-hot-reload.md`)
|
|
172
201
|
|
|
173
202
|
All data is persisted to `.mu/` directory:
|
|
174
203
|
- `.mu/issues.jsonl` - Issue data
|
package/dist/control_plane.d.ts
CHANGED
|
@@ -1,15 +1,54 @@
|
|
|
1
1
|
import { type MessagingOperatorBackend, MessagingOperatorRuntime } from "@femtomc/mu-agent";
|
|
2
|
-
import { type Channel } from "@femtomc/mu-control-plane";
|
|
2
|
+
import { type Channel, type GenerationTelemetryRecorder, type ReloadableGenerationIdentity } from "@femtomc/mu-control-plane";
|
|
3
3
|
import { type MuConfig } from "./config.js";
|
|
4
|
-
import { type ControlPlaneRunHeartbeatResult, type ControlPlaneRunInterruptResult, type ControlPlaneRunSnapshot, type ControlPlaneRunTrace } from "./run_supervisor.js";
|
|
5
4
|
import type { ActivityHeartbeatScheduler } from "./heartbeat_scheduler.js";
|
|
5
|
+
import { type ControlPlaneRunHeartbeatResult, type ControlPlaneRunInterruptResult, type ControlPlaneRunSnapshot, type ControlPlaneRunTrace } from "./run_supervisor.js";
|
|
6
6
|
export type ActiveAdapter = {
|
|
7
7
|
name: Channel;
|
|
8
8
|
route: string;
|
|
9
9
|
};
|
|
10
|
+
export type TelegramGenerationRollbackTrigger = "manual" | "warmup_failed" | "health_gate_failed" | "cutover_failed" | "post_cutover_health_failed" | "rollback_unavailable" | "rollback_failed";
|
|
11
|
+
export type TelegramGenerationReloadResult = {
|
|
12
|
+
handled: boolean;
|
|
13
|
+
ok: boolean;
|
|
14
|
+
reason: string;
|
|
15
|
+
route: string;
|
|
16
|
+
from_generation: ReloadableGenerationIdentity | null;
|
|
17
|
+
to_generation: ReloadableGenerationIdentity | null;
|
|
18
|
+
active_generation: ReloadableGenerationIdentity | null;
|
|
19
|
+
warmup: {
|
|
20
|
+
ok: boolean;
|
|
21
|
+
elapsed_ms: number;
|
|
22
|
+
error?: string;
|
|
23
|
+
} | null;
|
|
24
|
+
cutover: {
|
|
25
|
+
ok: boolean;
|
|
26
|
+
elapsed_ms: number;
|
|
27
|
+
error?: string;
|
|
28
|
+
} | null;
|
|
29
|
+
drain: {
|
|
30
|
+
ok: boolean;
|
|
31
|
+
elapsed_ms: number;
|
|
32
|
+
timed_out: boolean;
|
|
33
|
+
forced_stop: boolean;
|
|
34
|
+
error?: string;
|
|
35
|
+
} | null;
|
|
36
|
+
rollback: {
|
|
37
|
+
requested: boolean;
|
|
38
|
+
trigger: TelegramGenerationRollbackTrigger | null;
|
|
39
|
+
attempted: boolean;
|
|
40
|
+
ok: boolean;
|
|
41
|
+
error?: string;
|
|
42
|
+
};
|
|
43
|
+
error?: string;
|
|
44
|
+
};
|
|
10
45
|
export type ControlPlaneHandle = {
|
|
11
46
|
activeAdapters: ActiveAdapter[];
|
|
12
47
|
handleWebhook(path: string, req: Request): Promise<Response | null>;
|
|
48
|
+
reloadTelegramGeneration?(opts: {
|
|
49
|
+
config: ControlPlaneConfig;
|
|
50
|
+
reason: string;
|
|
51
|
+
}): Promise<TelegramGenerationReloadResult>;
|
|
13
52
|
listRuns?(opts?: {
|
|
14
53
|
status?: string;
|
|
15
54
|
limit?: number;
|
|
@@ -39,6 +78,23 @@ export type ControlPlaneHandle = {
|
|
|
39
78
|
stop(): Promise<void>;
|
|
40
79
|
};
|
|
41
80
|
export type ControlPlaneConfig = MuConfig["control_plane"];
|
|
81
|
+
export type ControlPlaneGenerationContext = ReloadableGenerationIdentity;
|
|
82
|
+
export type TelegramGenerationSwapHooks = {
|
|
83
|
+
onWarmup?: (ctx: {
|
|
84
|
+
generation: ReloadableGenerationIdentity;
|
|
85
|
+
reason: string;
|
|
86
|
+
}) => void | Promise<void>;
|
|
87
|
+
onCutover?: (ctx: {
|
|
88
|
+
from_generation: ReloadableGenerationIdentity | null;
|
|
89
|
+
to_generation: ReloadableGenerationIdentity;
|
|
90
|
+
reason: string;
|
|
91
|
+
}) => void | Promise<void>;
|
|
92
|
+
onDrain?: (ctx: {
|
|
93
|
+
generation: ReloadableGenerationIdentity;
|
|
94
|
+
reason: string;
|
|
95
|
+
timeout_ms: number;
|
|
96
|
+
}) => void | Promise<void>;
|
|
97
|
+
};
|
|
42
98
|
type DetectedAdapter = {
|
|
43
99
|
name: "slack";
|
|
44
100
|
signingSecret: string;
|
|
@@ -76,6 +132,9 @@ export type BootstrapControlPlaneOpts = {
|
|
|
76
132
|
operatorRuntime?: MessagingOperatorRuntime | null;
|
|
77
133
|
operatorBackend?: MessagingOperatorBackend;
|
|
78
134
|
heartbeatScheduler?: ActivityHeartbeatScheduler;
|
|
135
|
+
generation?: ControlPlaneGenerationContext;
|
|
136
|
+
telemetry?: GenerationTelemetryRecorder | null;
|
|
137
|
+
telegramGenerationHooks?: TelegramGenerationSwapHooks;
|
|
79
138
|
};
|
|
80
139
|
export declare function bootstrapControlPlane(opts: BootstrapControlPlaneOpts): Promise<ControlPlaneHandle | null>;
|
|
81
140
|
export {};
|