@ordewell/web 0.7.2 → 0.8.1
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 +6 -3
- package/dist/server/main.js +47 -130
- package/dist/server/main.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @ordewell/web
|
|
2
2
|
|
|
3
|
-
The local API server for **[Ordewell](https://ordewell.ai)
|
|
3
|
+
The local API server for **[Ordewell](https://ordewell.ai)**: a Hono HTTP +
|
|
4
4
|
WebSocket daemon bound to `127.0.0.1:3742` that the Ordewell CLI, terminal UI
|
|
5
5
|
and VS Code extension all drive.
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ and VS Code extension all drive.
|
|
|
8
8
|
port in a browser will show you an API response, not a dashboard. A browser UI
|
|
9
9
|
may come later; it does not exist today.
|
|
10
10
|
|
|
11
|
-
You almost certainly do not need to install this directly
|
|
11
|
+
You almost certainly do not need to install this directly.
|
|
12
12
|
[@ordewell/cli](https://www.npmjs.com/package/@ordewell/cli) depends on it and
|
|
13
13
|
starts it on demand.
|
|
14
14
|
|
|
@@ -23,12 +23,15 @@ ordewell web --daemon # background; logs to ~/.config/ordewell/server.log
|
|
|
23
23
|
`/api/commands`, `/api/workspaces`, `/api/approvals`, plus a WebSocket stream
|
|
24
24
|
for live planner and execution events.
|
|
25
25
|
|
|
26
|
+
Skills are read by the planner and the task orchestrator, not served as a
|
|
27
|
+
route; the format is in [Writing skills](https://github.com/ordewell/ordewell/blob/main/docs/skills.md).
|
|
28
|
+
|
|
26
29
|
## Security
|
|
27
30
|
|
|
28
31
|
The server is **unauthenticated by design** and binds the loopback interface
|
|
29
32
|
only, on the assumption that local access is trusted. Do not expose it to a
|
|
30
33
|
network. If you find a way to reach it off-host, or from a browser page, that's
|
|
31
|
-
a vulnerability
|
|
34
|
+
a vulnerability; see
|
|
32
35
|
[SECURITY.md](https://github.com/ordewell/ordewell/blob/main/SECURITY.md).
|
|
33
36
|
|
|
34
37
|
Licensed under the [Apache License 2.0](./LICENSE).
|
package/dist/server/main.js
CHANGED
|
@@ -336,20 +336,22 @@ ${err}` : out;
|
|
|
336
336
|
return { success: true, output: combined || "(no output)", truncated: combined.length > 2e4 };
|
|
337
337
|
}
|
|
338
338
|
};
|
|
339
|
+
|
|
340
|
+
// server/adapters/PoolAwareRunner.ts
|
|
339
341
|
var PoolAwareRunner = class {
|
|
340
342
|
constructor(sessionId, broadcast, inner) {
|
|
341
343
|
this.sessionId = sessionId;
|
|
342
344
|
this.broadcast = broadcast;
|
|
343
|
-
this.inner = inner
|
|
345
|
+
this.inner = inner;
|
|
344
346
|
}
|
|
345
347
|
sessionId;
|
|
346
348
|
broadcast;
|
|
347
349
|
inner;
|
|
348
350
|
/**
|
|
349
|
-
* Sessions this plan spawned. The inner runner
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
*
|
|
351
|
+
* Sessions this plan spawned. The inner runner is shared by every plan in
|
|
352
|
+
* the pool, so "stop everything" and "how many are running" must be
|
|
353
|
+
* answered from this set, never delegated — delegating would let one plan's
|
|
354
|
+
* /stop kill another plan's tasks.
|
|
353
355
|
*/
|
|
354
356
|
owned = /* @__PURE__ */ new Set();
|
|
355
357
|
get activeCount() {
|
|
@@ -374,65 +376,22 @@ var PoolAwareRunner = class {
|
|
|
374
376
|
this.owned.clear();
|
|
375
377
|
}
|
|
376
378
|
};
|
|
377
|
-
var TMUX_MISSING_ADVICE = "tmux is not installed, so terminal-transport tasks run without a terminal window you can open or type into. Install tmux, or keep the structured transport (/transport structured).";
|
|
378
|
-
function startTerminalHost(port2, deps = {}) {
|
|
379
|
-
const hasTmuxImpl = deps.hasTmuxImpl ?? core.hasTmux;
|
|
380
|
-
if (!hasTmuxImpl()) return { advice: TMUX_MISSING_ADVICE };
|
|
381
|
-
const runner = (deps.createTmuxRunner ?? ((p) => new core.TmuxRunner({ port: p })))(port2);
|
|
382
|
-
runner.ensureSession().catch((err) => {
|
|
383
|
-
console.error(`[web] tmux session setup failed (will retry on next task spawn): ${err?.message ?? err}`);
|
|
384
|
-
});
|
|
385
|
-
return { runner };
|
|
386
|
-
}
|
|
387
|
-
var AdvisingRunner = class {
|
|
388
|
-
constructor(inner, advice, advise) {
|
|
389
|
-
this.inner = inner;
|
|
390
|
-
this.advice = advice;
|
|
391
|
-
this.advise = advise;
|
|
392
|
-
}
|
|
393
|
-
inner;
|
|
394
|
-
advice;
|
|
395
|
-
advise;
|
|
396
|
-
advised = false;
|
|
397
|
-
get activeCount() {
|
|
398
|
-
return this.inner.activeCount;
|
|
399
|
-
}
|
|
400
|
-
spawn(opts) {
|
|
401
|
-
if (!this.advised) {
|
|
402
|
-
this.advised = true;
|
|
403
|
-
this.advise(this.advice);
|
|
404
|
-
}
|
|
405
|
-
return this.inner.spawn(opts);
|
|
406
|
-
}
|
|
407
|
-
stop(sessionId) {
|
|
408
|
-
this.inner.stop(sessionId);
|
|
409
|
-
}
|
|
410
|
-
stopAll() {
|
|
411
|
-
this.inner.stopAll();
|
|
412
|
-
}
|
|
413
|
-
};
|
|
414
379
|
|
|
415
380
|
// server/pool/orchestratorPool.ts
|
|
416
381
|
var OrchestratorPool = class {
|
|
417
382
|
sessions = /* @__PURE__ */ new Map();
|
|
418
383
|
clients = /* @__PURE__ */ new Map();
|
|
419
|
-
registry = (
|
|
420
|
-
const r = new core.RunnerRegistry();
|
|
421
|
-
r.loadUserPlugins();
|
|
422
|
-
return r;
|
|
423
|
-
})();
|
|
384
|
+
registry = new core.RunnerRegistry();
|
|
424
385
|
modelResolver;
|
|
425
386
|
runnerInstallation = new core.RunnerInstallation(this.registry);
|
|
426
387
|
cachedProviderLists;
|
|
427
388
|
settingsService = new core.SettingsService();
|
|
428
389
|
plannerModelMemory = new core.PlannerModelMemory(this.settingsService);
|
|
429
|
-
|
|
430
|
-
structuredRunner;
|
|
431
|
-
terminalAdvice;
|
|
390
|
+
runner;
|
|
432
391
|
constructor(deps = {}) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
this.
|
|
392
|
+
const pluginNotice = core.removedPluginNotice();
|
|
393
|
+
if (pluginNotice) console.warn(pluginNotice);
|
|
394
|
+
this.runner = deps.runner ?? new core.StructuredRunner();
|
|
436
395
|
this.modelResolver = deps.modelResolver ?? new core.ModelResolver(this.registry, new WebConfig());
|
|
437
396
|
}
|
|
438
397
|
subscribe(sessionId, ws) {
|
|
@@ -498,12 +457,7 @@ var OrchestratorPool = class {
|
|
|
498
457
|
});
|
|
499
458
|
const fsAdapter = new PoolFileSystem(workspace);
|
|
500
459
|
const broadcast = (msg) => this.broadcast(sessionId, msg);
|
|
501
|
-
const
|
|
502
|
-
const router = new core.TransportRouter({
|
|
503
|
-
terminal: this.terminalAdvice ? new AdvisingRunner(terminal, this.terminalAdvice, (message) => this.broadcast(sessionId, { type: "notice", level: "warn", message })) : terminal,
|
|
504
|
-
structured: this.structuredRunner
|
|
505
|
-
});
|
|
506
|
-
const runner = new PoolAwareRunner(sessionId, broadcast, router);
|
|
460
|
+
const runner = new PoolAwareRunner(sessionId, broadcast, this.runner);
|
|
507
461
|
return core.createSession({
|
|
508
462
|
config,
|
|
509
463
|
notifications: { info() {
|
|
@@ -557,14 +511,10 @@ var OrchestratorPool = class {
|
|
|
557
511
|
// for a planner that is running at "high".
|
|
558
512
|
plannerThinkingEffort: config.plannerThinkingEffort ?? "",
|
|
559
513
|
maxParallel: config.maxParallelSessions,
|
|
560
|
-
tdd: userSettings.tdd,
|
|
561
|
-
verification: userSettings.verification,
|
|
562
514
|
modelAllowlist: userSettings.modelAllowlist,
|
|
563
515
|
// The model remembered per planner backend (this task), so a surface can
|
|
564
516
|
// render what's remembered without a second round-trip.
|
|
565
|
-
plannerModels: userSettings.plannerModels
|
|
566
|
-
// ADR-0018; a run copies it when it starts.
|
|
567
|
-
runnerTransport: userSettings.runnerTransport
|
|
517
|
+
plannerModels: userSettings.plannerModels
|
|
568
518
|
};
|
|
569
519
|
}
|
|
570
520
|
/**
|
|
@@ -592,22 +542,18 @@ var OrchestratorPool = class {
|
|
|
592
542
|
const envChanges = admission2 ? admission2.accepted : void 0;
|
|
593
543
|
const incomingAiProvider = typeof envChanges?.AI_PROVIDER === "string" ? envChanges.AI_PROVIDER : void 0;
|
|
594
544
|
const switchedToProvider = incomingAiProvider && incomingAiProvider !== providerBefore ? incomingAiProvider : void 0;
|
|
595
|
-
const
|
|
545
|
+
const requestedModel = envChanges?.ORCHESTRATOR_MODEL ?? changes.orchestratorModel;
|
|
546
|
+
const explicitModel = typeof requestedModel === "string" && requestedModel.trim().length > 0;
|
|
547
|
+
const switchRecall = switchedToProvider && !explicitModel ? this.plannerModelMemory.recall(switchedToProvider, this.plannerCatalogFor(switchedToProvider)) : void 0;
|
|
548
|
+
if (switchedToProvider && explicitModel && typeof changes.plannerThinkingEffort !== "string" && envChanges?.ORDEWELL_PLANNER_EFFORT === void 0) {
|
|
549
|
+
process.env.ORDEWELL_PLANNER_EFFORT = "";
|
|
550
|
+
}
|
|
596
551
|
if (typeof changes.orchestratorModel === "string") {
|
|
597
552
|
process.env.ORCHESTRATOR_MODEL = changes.orchestratorModel;
|
|
598
553
|
}
|
|
599
554
|
if (typeof changes.plannerThinkingEffort === "string") {
|
|
600
555
|
process.env.ORDEWELL_PLANNER_EFFORT = changes.plannerThinkingEffort;
|
|
601
556
|
}
|
|
602
|
-
if (changes.tdd && typeof changes.tdd.enabled === "boolean") {
|
|
603
|
-
this.settingsService.setTdd(changes.tdd.enabled);
|
|
604
|
-
}
|
|
605
|
-
if (changes.verification && typeof changes.verification.enabled === "boolean") {
|
|
606
|
-
this.settingsService.setVerification(changes.verification.enabled);
|
|
607
|
-
}
|
|
608
|
-
if (core.isRunnerTransport(changes.runnerTransport)) {
|
|
609
|
-
this.settingsService.setRunnerTransport(changes.runnerTransport);
|
|
610
|
-
}
|
|
611
557
|
if (envChanges) {
|
|
612
558
|
let touched = false;
|
|
613
559
|
for (const [key, value] of Object.entries(envChanges)) {
|
|
@@ -640,7 +586,7 @@ var OrchestratorPool = class {
|
|
|
640
586
|
}
|
|
641
587
|
}
|
|
642
588
|
}
|
|
643
|
-
const envCarriesModelOrEffort = envChanges?.AI_PROVIDER === void 0 && (typeof envChanges?.ORCHESTRATOR_MODEL === "string" || typeof envChanges?.ORDEWELL_PLANNER_EFFORT === "string");
|
|
589
|
+
const envCarriesModelOrEffort = (envChanges?.AI_PROVIDER === void 0 || explicitModel) && (typeof envChanges?.ORCHESTRATOR_MODEL === "string" || typeof envChanges?.ORDEWELL_PLANNER_EFFORT === "string");
|
|
644
590
|
if (typeof changes.orchestratorModel === "string" || typeof changes.plannerThinkingEffort === "string" || envCarriesModelOrEffort) {
|
|
645
591
|
const rememberProvider = switchedToProvider ?? new WebConfig({
|
|
646
592
|
enabledRunners: this.enabledRunnerOverride(),
|
|
@@ -707,11 +653,11 @@ var OrchestratorPool = class {
|
|
|
707
653
|
async getInstalledRunners() {
|
|
708
654
|
const config = new WebConfig({ enabledRunners: this.enabledRunnerOverride() });
|
|
709
655
|
const enabled = new Set(config.enabledRunners);
|
|
710
|
-
const
|
|
656
|
+
const runners = this.registry.list();
|
|
711
657
|
const installedIds = new Set(
|
|
712
|
-
await this.runnerInstallation.filterInstalled(
|
|
658
|
+
await this.runnerInstallation.filterInstalled(runners.map((p) => p.manifest.name))
|
|
713
659
|
);
|
|
714
|
-
return
|
|
660
|
+
return runners.filter((p) => installedIds.has(p.manifest.name)).map((p) => ({
|
|
715
661
|
id: p.manifest.name,
|
|
716
662
|
name: p.manifest.displayName,
|
|
717
663
|
enabled: enabled.has(p.manifest.name)
|
|
@@ -857,14 +803,14 @@ function sessionsRoute(pool2) {
|
|
|
857
803
|
const id = c.req.param("id");
|
|
858
804
|
const saved = core.loadSessionPlanState(id, ws);
|
|
859
805
|
if (!saved) return refuse(c, 404, "Session not found", "session_not_found");
|
|
860
|
-
return c.json({ meta: saved.meta, plan: pool2.getPlanState(id) ?? saved.plan });
|
|
806
|
+
return c.json({ meta: saved.meta, plan: core.surfacePlanState(pool2.getPlanState(id) ?? saved.plan) });
|
|
861
807
|
});
|
|
862
808
|
router.post("/:id/load", (c) => {
|
|
863
809
|
const ws = c.req.query("workspace") || process.cwd();
|
|
864
810
|
try {
|
|
865
811
|
const id = c.req.param("id");
|
|
866
812
|
const plan = pool2.adoptSavedSession(id, ws);
|
|
867
|
-
return c.json({ ok: true, plan, goal: pool2.getGoal(id) });
|
|
813
|
+
return c.json({ ok: true, plan: core.surfacePlan(plan), goal: pool2.getGoal(id) });
|
|
868
814
|
} catch (err) {
|
|
869
815
|
return failure(c, err, "load session", { message: "Failed to load session" });
|
|
870
816
|
}
|
|
@@ -877,7 +823,7 @@ function sessionsRoute(pool2) {
|
|
|
877
823
|
const ws = c.req.query("workspace") || process.cwd();
|
|
878
824
|
const attempt = Number(c.req.param("attempt"));
|
|
879
825
|
if (!Number.isInteger(attempt) || attempt < 1) return refuse(c, 400, "attempt must be a positive integer");
|
|
880
|
-
return c.json({ attempt, events: core.readTaskLog({ baseDir: ws, sessionId: c.req.param("id") }, c.req.param("taskId"), attempt) });
|
|
826
|
+
return c.json({ attempt, events: core.taskLogForSurface(core.readTaskLog({ baseDir: ws, sessionId: c.req.param("id") }, c.req.param("taskId"), attempt)) });
|
|
881
827
|
});
|
|
882
828
|
router.delete("/:id", (c) => {
|
|
883
829
|
const ws = c.req.query("workspace") || process.cwd();
|
|
@@ -902,7 +848,8 @@ function plansRoute(pool2) {
|
|
|
902
848
|
const runnerList = Array.isArray(runners) ? runners : runners ? [runners] : queryRunners ? queryRunners.split(",").map((s) => s.trim()).filter(Boolean) : pool2.getRunnerState().enabledRunners;
|
|
903
849
|
const plan = await pool2.generatePlan(c.req.param("sessionId"), goal, runnerList, ws, model, { allowInit });
|
|
904
850
|
const { models, modelsByRunner } = await pool2.getProviderModels();
|
|
905
|
-
|
|
851
|
+
const notes = (pool2.session(c.req.param("sessionId")).planState?.conversationHistory ?? []).filter((e) => e.kind === "system").map((e) => e.content);
|
|
852
|
+
return c.json({ plan: core.surfacePlanState(plan), models, modelsByRunner, ...notes.length > 0 ? { notes } : {} });
|
|
906
853
|
} catch (err) {
|
|
907
854
|
return failure(c, err, "generate", { message: "Plan generation failed" });
|
|
908
855
|
}
|
|
@@ -1071,7 +1018,7 @@ function plansRoute(pool2) {
|
|
|
1071
1018
|
router.post("/:sessionId/tasks/:taskId/resolve-conflict", async (c) => {
|
|
1072
1019
|
try {
|
|
1073
1020
|
const plan = await pool2.session(c.req.param("sessionId")).resolveConflictAsTask(c.req.param("taskId"));
|
|
1074
|
-
return c.json({ plan });
|
|
1021
|
+
return c.json({ plan: plan && core.surfacePlan(plan) });
|
|
1075
1022
|
} catch (err) {
|
|
1076
1023
|
return failure(c, err, "task edit");
|
|
1077
1024
|
}
|
|
@@ -1121,7 +1068,7 @@ function plansRoute(pool2) {
|
|
|
1121
1068
|
router.post("/:sessionId/review/approve", async (c) => {
|
|
1122
1069
|
try {
|
|
1123
1070
|
const plan = await pool2.session(c.req.param("sessionId")).approveReview();
|
|
1124
|
-
return c.json({ plan });
|
|
1071
|
+
return c.json({ plan: core.surfacePlan(plan) });
|
|
1125
1072
|
} catch (err) {
|
|
1126
1073
|
return failure(c, err, "review approve");
|
|
1127
1074
|
}
|
|
@@ -1133,7 +1080,7 @@ function plansRoute(pool2) {
|
|
|
1133
1080
|
return c.json({ error: "taskIds array with at least two ids is required" }, 400);
|
|
1134
1081
|
}
|
|
1135
1082
|
const plan = await pool2.session(c.req.param("sessionId")).requestMerge(taskIds);
|
|
1136
|
-
return c.json({ plan });
|
|
1083
|
+
return c.json({ plan: core.surfacePlan(plan) });
|
|
1137
1084
|
} catch (err) {
|
|
1138
1085
|
return failure(c, err, "merge", { fallback: 400 });
|
|
1139
1086
|
}
|
|
@@ -1141,7 +1088,7 @@ function plansRoute(pool2) {
|
|
|
1141
1088
|
router.post("/:sessionId/tasks/:taskId/split", async (c) => {
|
|
1142
1089
|
try {
|
|
1143
1090
|
const plan = await pool2.session(c.req.param("sessionId")).requestSplit(c.req.param("taskId"));
|
|
1144
|
-
return c.json({ plan });
|
|
1091
|
+
return c.json({ plan: core.surfacePlan(plan) });
|
|
1145
1092
|
} catch (err) {
|
|
1146
1093
|
return failure(c, err, "split", { fallback: 400 });
|
|
1147
1094
|
}
|
|
@@ -1153,7 +1100,7 @@ function plansRoute(pool2) {
|
|
|
1153
1100
|
const ws = workspace || c.req.query("workspace") || process.cwd();
|
|
1154
1101
|
const runnerList = Array.isArray(runners) ? runners : runners ? [runners] : pool2.getRunnerState().enabledRunners;
|
|
1155
1102
|
const plan = await pool2.startPlanning(c.req.param("sessionId"), goal, runnerList, ws, model, { allowInit });
|
|
1156
|
-
return c.json({ plan });
|
|
1103
|
+
return c.json({ plan: core.surfacePlan(plan) });
|
|
1157
1104
|
} catch (err) {
|
|
1158
1105
|
return failure(c, err, "converse start", { message: "Planning failed" });
|
|
1159
1106
|
}
|
|
@@ -1163,14 +1110,15 @@ function plansRoute(pool2) {
|
|
|
1163
1110
|
const { message } = await c.req.json();
|
|
1164
1111
|
if (!message) return c.json({ error: "message is required" }, 400);
|
|
1165
1112
|
const plan = await pool2.continuePlanning(c.req.param("sessionId"), message);
|
|
1166
|
-
return c.json({ plan });
|
|
1113
|
+
return c.json({ plan: core.surfacePlan(plan) });
|
|
1167
1114
|
} catch (err) {
|
|
1168
1115
|
return failure(c, err, "conversation message");
|
|
1169
1116
|
}
|
|
1170
1117
|
});
|
|
1171
1118
|
router.post("/:sessionId/conversation/fork", (c) => {
|
|
1172
1119
|
try {
|
|
1173
|
-
|
|
1120
|
+
const fork = pool2.forkConversation(c.req.param("sessionId"));
|
|
1121
|
+
return c.json({ ...fork, plan: core.surfacePlan(fork.plan) });
|
|
1174
1122
|
} catch (err) {
|
|
1175
1123
|
return failure(c, err, "conversation edit");
|
|
1176
1124
|
}
|
|
@@ -1186,14 +1134,16 @@ function plansRoute(pool2) {
|
|
|
1186
1134
|
try {
|
|
1187
1135
|
const { index } = await c.req.json();
|
|
1188
1136
|
if (!Number.isInteger(index) || index < 0) return c.json({ error: "index must be a non-negative integer" }, 400);
|
|
1189
|
-
|
|
1137
|
+
const rewound = pool2.rewindConversation(c.req.param("sessionId"), index);
|
|
1138
|
+
return c.json({ ...rewound, plan: core.surfacePlan(rewound.plan) });
|
|
1190
1139
|
} catch (err) {
|
|
1191
1140
|
return failure(c, err, "conversation edit");
|
|
1192
1141
|
}
|
|
1193
1142
|
});
|
|
1194
1143
|
router.post("/:sessionId/conversation/compact", async (c) => {
|
|
1195
1144
|
try {
|
|
1196
|
-
|
|
1145
|
+
const compacted = await pool2.compactConversation(c.req.param("sessionId"));
|
|
1146
|
+
return c.json({ ...compacted, plan: core.surfacePlan(compacted.plan) });
|
|
1197
1147
|
} catch (err) {
|
|
1198
1148
|
return failure(c, err, "conversation edit");
|
|
1199
1149
|
}
|
|
@@ -1286,44 +1236,14 @@ function settingsRoute(pool2) {
|
|
|
1286
1236
|
});
|
|
1287
1237
|
return router;
|
|
1288
1238
|
}
|
|
1289
|
-
var COMMANDS = [
|
|
1290
|
-
|
|
1291
|
-
{ name: "verify", description: "Toggle verification mode \u2014 adds a final evidence-based verification task that runs the full suite (on|off|status)" },
|
|
1292
|
-
{ name: "transport", description: "Drive tasks through each runner's protocol (structured) or a terminal, from the next run (terminal|structured|status)" }
|
|
1293
|
-
];
|
|
1294
|
-
var BOOLEAN_TOGGLES = { tdd: "tdd", verify: "verification" };
|
|
1295
|
-
function commandsRoute(pool2) {
|
|
1239
|
+
var COMMANDS = [];
|
|
1240
|
+
function commandsRoute() {
|
|
1296
1241
|
const router = new hono.Hono();
|
|
1297
1242
|
router.get("/", (c) => {
|
|
1298
1243
|
return c.json({ commands: COMMANDS });
|
|
1299
1244
|
});
|
|
1300
|
-
router.post("/:name",
|
|
1245
|
+
router.post("/:name", (c) => {
|
|
1301
1246
|
const name = c.req.param("name");
|
|
1302
|
-
const body = await c.req.json().catch(() => ({}));
|
|
1303
|
-
const args2 = body?.args || {};
|
|
1304
|
-
const command = COMMANDS.find((cmd) => cmd.name === name);
|
|
1305
|
-
if (!command) {
|
|
1306
|
-
return refuse(c, 404, `Unknown command: ${name}`);
|
|
1307
|
-
}
|
|
1308
|
-
const toggle = BOOLEAN_TOGGLES[name];
|
|
1309
|
-
if (toggle) {
|
|
1310
|
-
const action = args2.action || "status";
|
|
1311
|
-
if (action === "on") {
|
|
1312
|
-
pool2.updateSettings({ [toggle]: { enabled: true } });
|
|
1313
|
-
} else if (action === "off") {
|
|
1314
|
-
pool2.updateSettings({ [toggle]: { enabled: false } });
|
|
1315
|
-
}
|
|
1316
|
-
return c.json({ ok: true, settings: pool2.getSettings() });
|
|
1317
|
-
}
|
|
1318
|
-
if (name === "transport") {
|
|
1319
|
-
const action = args2.action || "status";
|
|
1320
|
-
if (action === "terminal" || action === "structured") {
|
|
1321
|
-
pool2.updateSettings({ runnerTransport: action });
|
|
1322
|
-
} else if (action !== "status") {
|
|
1323
|
-
return refuse(c, 400, `Unknown transport: ${action} (terminal|structured)`);
|
|
1324
|
-
}
|
|
1325
|
-
return c.json({ ok: true, settings: pool2.getSettings() });
|
|
1326
|
-
}
|
|
1327
1247
|
return refuse(c, 404, `Unknown command: ${name}`);
|
|
1328
1248
|
});
|
|
1329
1249
|
return router;
|
|
@@ -1430,7 +1350,7 @@ function createApp(pool2, admission2) {
|
|
|
1430
1350
|
app2.route("/api/runners", runnersRoute(pool2));
|
|
1431
1351
|
app2.route("/api/models", modelsRoute(pool2));
|
|
1432
1352
|
app2.route("/api/settings", settingsRoute(pool2));
|
|
1433
|
-
app2.route("/api/commands", commandsRoute(
|
|
1353
|
+
app2.route("/api/commands", commandsRoute());
|
|
1434
1354
|
app2.route("/api/workspaces", workspacesRoute());
|
|
1435
1355
|
app2.route("/api/approvals", approvalsRoute(pool2));
|
|
1436
1356
|
return app2;
|
|
@@ -1518,10 +1438,9 @@ if (portIdx !== -1 && args[portIdx + 1]) {
|
|
|
1518
1438
|
}
|
|
1519
1439
|
var watchParentIdx = args.indexOf("--watch-parent");
|
|
1520
1440
|
var watchParentPid = watchParentIdx !== -1 ? parseInt(args[watchParentIdx + 1], 10) : void 0;
|
|
1521
|
-
var { runner: tmuxRunner, advice: terminalAdvice } = startTerminalHost(port);
|
|
1522
1441
|
var { token, file: tokenFile } = core.mintDaemonToken(port);
|
|
1523
1442
|
var admission = { port, token, tokenFile };
|
|
1524
|
-
var pool = new OrchestratorPool({ runner:
|
|
1443
|
+
var pool = new OrchestratorPool({ runner: new core.StructuredRunner() });
|
|
1525
1444
|
var app = createApp(pool, admission);
|
|
1526
1445
|
pool.getProviderModels().catch((err) => {
|
|
1527
1446
|
console.error(`[web] model discovery warmup failed: ${err?.message ?? err}`);
|
|
@@ -1532,11 +1451,9 @@ attachWsHandler(server, pool, admission);
|
|
|
1532
1451
|
server.listen(port, "127.0.0.1", () => {
|
|
1533
1452
|
console.error(`[web] Ordewell API server: http://localhost:${port}`);
|
|
1534
1453
|
});
|
|
1535
|
-
|
|
1454
|
+
function shutdown() {
|
|
1536
1455
|
core.clearDaemonToken(port);
|
|
1537
1456
|
pool.destroyAll();
|
|
1538
|
-
if (tmuxRunner) await tmuxRunner.killSession().catch(() => {
|
|
1539
|
-
});
|
|
1540
1457
|
server.close();
|
|
1541
1458
|
process.exit(0);
|
|
1542
1459
|
}
|