@femtomc/mu-server 26.2.65 → 26.2.66

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.
@@ -1,5 +1,5 @@
1
1
  import { type MessagingOperatorBackend, MessagingOperatorRuntime } from "@femtomc/mu-agent";
2
- import { type Channel, type GenerationTelemetryRecorder, type ReloadableGenerationIdentity } from "@femtomc/mu-control-plane";
2
+ import { type Channel, type CommandPipelineResult, type GenerationTelemetryRecorder, type ReloadableGenerationIdentity } from "@femtomc/mu-control-plane";
3
3
  import { type MuConfig } from "./config.js";
4
4
  import type { ActivityHeartbeatScheduler } from "./heartbeat_scheduler.js";
5
5
  import { type ControlPlaneRunHeartbeatResult, type ControlPlaneRunInterruptResult, type ControlPlaneRunSnapshot, type ControlPlaneRunSupervisorOpts, type ControlPlaneRunTrace } from "./run_supervisor.js";
@@ -76,6 +76,11 @@ export type ControlPlaneHandle = {
76
76
  idOrRoot: string;
77
77
  limit?: number;
78
78
  }): Promise<ControlPlaneRunTrace | null>;
79
+ submitTerminalCommand?(opts: {
80
+ commandText: string;
81
+ repoRoot: string;
82
+ requestId?: string;
83
+ }): Promise<CommandPipelineResult>;
79
84
  stop(): Promise<void>;
80
85
  };
81
86
  export type ControlPlaneConfig = MuConfig["control_plane"];
@@ -138,6 +143,7 @@ export type BootstrapControlPlaneOpts = {
138
143
  generation?: ControlPlaneGenerationContext;
139
144
  telemetry?: GenerationTelemetryRecorder | null;
140
145
  telegramGenerationHooks?: TelegramGenerationSwapHooks;
146
+ terminalEnabled?: boolean;
141
147
  };
142
148
  export declare function bootstrapControlPlane(opts: BootstrapControlPlaneOpts): Promise<ControlPlaneHandle | null>;
143
149
  export {};
@@ -702,7 +702,7 @@ export async function bootstrapControlPlane(opts) {
702
702
  },
703
703
  }
704
704
  : undefined;
705
- if (detected.length === 0) {
705
+ if (detected.length === 0 && !opts.terminalEnabled) {
706
706
  return null;
707
707
  }
708
708
  const paths = getControlPlanePaths(opts.repoRoot);
@@ -1050,6 +1050,12 @@ export async function bootstrapControlPlane(opts) {
1050
1050
  async traceRun(traceOpts) {
1051
1051
  return (await runSupervisor?.trace(traceOpts.idOrRoot, { limit: traceOpts.limit })) ?? null;
1052
1052
  },
1053
+ async submitTerminalCommand(terminalOpts) {
1054
+ if (!pipeline) {
1055
+ throw new Error("control_plane_pipeline_unavailable");
1056
+ }
1057
+ return await pipeline.handleTerminalInbound(terminalOpts);
1058
+ },
1053
1059
  async stop() {
1054
1060
  if (drainInterval) {
1055
1061
  clearInterval(drainInterval);
package/dist/server.js CHANGED
@@ -214,6 +214,7 @@ export function createServer(options = {}) {
214
214
  heartbeatScheduler,
215
215
  generation,
216
216
  telemetry: generationTelemetry,
217
+ terminalEnabled: true,
217
218
  });
218
219
  });
219
220
  const controlPlaneProxy = {
@@ -272,6 +273,13 @@ export function createServer(options = {}) {
272
273
  return null;
273
274
  return await handle.traceRun(opts);
274
275
  },
276
+ async submitTerminalCommand(opts) {
277
+ const handle = controlPlaneCurrent;
278
+ if (!handle?.submitTerminalCommand) {
279
+ throw new Error("control_plane_unavailable");
280
+ }
281
+ return await handle.submitTerminalCommand(opts);
282
+ },
275
283
  async stop() {
276
284
  const handle = controlPlaneCurrent;
277
285
  controlPlaneCurrent = null;
@@ -1102,6 +1110,94 @@ export function createServer(options = {}) {
1102
1110
  control_plane: controlPlane,
1103
1111
  }, { headers });
1104
1112
  }
1113
+ if (path === "/api/commands/submit") {
1114
+ if (request.method !== "POST") {
1115
+ return Response.json({ error: "Method Not Allowed" }, { status: 405, headers });
1116
+ }
1117
+ let body;
1118
+ try {
1119
+ body = (await request.json());
1120
+ }
1121
+ catch {
1122
+ return Response.json({ error: "invalid json body" }, { status: 400, headers });
1123
+ }
1124
+ const kind = typeof body.kind === "string" ? body.kind.trim() : "";
1125
+ if (!kind) {
1126
+ return Response.json({ error: "kind is required" }, { status: 400, headers });
1127
+ }
1128
+ let commandText;
1129
+ switch (kind) {
1130
+ case "run_start": {
1131
+ const prompt = typeof body.prompt === "string" ? body.prompt.trim() : "";
1132
+ if (!prompt) {
1133
+ return Response.json({ error: "prompt is required for run_start" }, { status: 400, headers });
1134
+ }
1135
+ const maxStepsSuffix = typeof body.max_steps === "number" && Number.isFinite(body.max_steps)
1136
+ ? ` --max-steps ${Math.max(1, Math.trunc(body.max_steps))}`
1137
+ : "";
1138
+ commandText = `mu! run start ${prompt}${maxStepsSuffix}`;
1139
+ break;
1140
+ }
1141
+ case "run_resume": {
1142
+ const rootId = typeof body.root_issue_id === "string" ? body.root_issue_id.trim() : "";
1143
+ const maxSteps = typeof body.max_steps === "number" && Number.isFinite(body.max_steps)
1144
+ ? ` ${Math.max(1, Math.trunc(body.max_steps))}`
1145
+ : "";
1146
+ commandText = `mu! run resume${rootId ? ` ${rootId}` : ""}${maxSteps}`;
1147
+ break;
1148
+ }
1149
+ case "run_interrupt": {
1150
+ const rootId = typeof body.root_issue_id === "string" ? body.root_issue_id.trim() : "";
1151
+ commandText = `mu! run interrupt${rootId ? ` ${rootId}` : ""}`;
1152
+ break;
1153
+ }
1154
+ case "status":
1155
+ commandText = "/mu status";
1156
+ break;
1157
+ case "issue_list":
1158
+ commandText = "/mu issue list";
1159
+ break;
1160
+ case "issue_get": {
1161
+ const issueId = typeof body.issue_id === "string" ? body.issue_id.trim() : "";
1162
+ commandText = `/mu issue get${issueId ? ` ${issueId}` : ""}`;
1163
+ break;
1164
+ }
1165
+ case "forum_read": {
1166
+ const topic = typeof body.topic === "string" ? body.topic.trim() : "";
1167
+ const limit = typeof body.limit === "number" && Number.isFinite(body.limit)
1168
+ ? ` ${Math.max(1, Math.trunc(body.limit))}`
1169
+ : "";
1170
+ commandText = `/mu forum read${topic ? ` ${topic}` : ""}${limit}`;
1171
+ break;
1172
+ }
1173
+ case "run_list":
1174
+ commandText = "/mu run list";
1175
+ break;
1176
+ case "run_status": {
1177
+ const rootId = typeof body.root_issue_id === "string" ? body.root_issue_id.trim() : "";
1178
+ commandText = `/mu run status${rootId ? ` ${rootId}` : ""}`;
1179
+ break;
1180
+ }
1181
+ case "ready":
1182
+ commandText = "/mu ready";
1183
+ break;
1184
+ default:
1185
+ return Response.json({ error: `unknown command kind: ${kind}` }, { status: 400, headers });
1186
+ }
1187
+ try {
1188
+ if (!controlPlaneProxy.submitTerminalCommand) {
1189
+ return Response.json({ error: "control plane not available" }, { status: 503, headers });
1190
+ }
1191
+ const result = await controlPlaneProxy.submitTerminalCommand({
1192
+ commandText,
1193
+ repoRoot: context.repoRoot,
1194
+ });
1195
+ return Response.json({ ok: true, result }, { headers });
1196
+ }
1197
+ catch (err) {
1198
+ return Response.json({ error: `command failed: ${describeError(err)}` }, { status: 500, headers });
1199
+ }
1200
+ }
1105
1201
  if (path === "/api/runs") {
1106
1202
  if (request.method !== "GET") {
1107
1203
  return Response.json({ error: "Method Not Allowed" }, { status: 405, headers });
@@ -2016,6 +2112,7 @@ export async function createServerAsync(options = {}) {
2016
2112
  generation_seq: 0,
2017
2113
  },
2018
2114
  telemetry: generationTelemetry,
2115
+ terminalEnabled: true,
2019
2116
  });
2020
2117
  const serverConfig = createServer({
2021
2118
  ...options,
package/package.json CHANGED
@@ -1,40 +1,40 @@
1
1
  {
2
- "name": "@femtomc/mu-server",
3
- "version": "26.2.65",
4
- "description": "HTTP API server for mu status, work items, messaging setup, and web UI.",
5
- "keywords": [
6
- "mu",
7
- "server",
8
- "api",
9
- "web",
10
- "automation"
11
- ],
12
- "type": "module",
13
- "main": "./dist/index.js",
14
- "types": "./dist/index.d.ts",
15
- "bin": {
16
- "mu-server": "./dist/cli.js"
17
- },
18
- "exports": {
19
- ".": {
20
- "types": "./dist/index.d.ts",
21
- "default": "./dist/index.js"
22
- }
23
- },
24
- "files": [
25
- "dist/**",
26
- "public/**"
27
- ],
28
- "scripts": {
29
- "build": "tsc -p tsconfig.build.json",
30
- "test": "bun test",
31
- "start": "bun run dist/cli.js"
32
- },
33
- "dependencies": {
34
- "@femtomc/mu-agent": "26.2.65",
35
- "@femtomc/mu-control-plane": "26.2.65",
36
- "@femtomc/mu-core": "26.2.65",
37
- "@femtomc/mu-forum": "26.2.65",
38
- "@femtomc/mu-issue": "26.2.65"
39
- }
2
+ "name": "@femtomc/mu-server",
3
+ "version": "26.2.66",
4
+ "description": "HTTP API server for mu status, work items, messaging setup, and web UI.",
5
+ "keywords": [
6
+ "mu",
7
+ "server",
8
+ "api",
9
+ "web",
10
+ "automation"
11
+ ],
12
+ "type": "module",
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "bin": {
16
+ "mu-server": "./dist/cli.js"
17
+ },
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "default": "./dist/index.js"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist/**",
26
+ "public/**"
27
+ ],
28
+ "scripts": {
29
+ "build": "tsc -p tsconfig.build.json",
30
+ "test": "bun test",
31
+ "start": "bun run dist/cli.js"
32
+ },
33
+ "dependencies": {
34
+ "@femtomc/mu-agent": "26.2.65",
35
+ "@femtomc/mu-control-plane": "26.2.65",
36
+ "@femtomc/mu-core": "26.2.65",
37
+ "@femtomc/mu-forum": "26.2.65",
38
+ "@femtomc/mu-issue": "26.2.65"
39
+ }
40
40
  }