@castlemilk/omega 0.5.0 → 0.5.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/dist/cli.js +234 -182
- package/dist/server.js +1 -1
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -1,172 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
function getApiUrl() {
|
|
12
|
-
const opts = program.opts();
|
|
13
|
-
return opts.api ?? "http://localhost:4000";
|
|
14
|
-
}
|
|
15
|
-
async function apiFetch(path4, init) {
|
|
16
|
-
const url = `${getApiUrl()}${path4}`;
|
|
17
|
-
const res = await fetch(url, init);
|
|
18
|
-
const data = await res.json().catch(() => ({}));
|
|
19
|
-
if (!res.ok) {
|
|
20
|
-
const message = typeof data === "object" && data !== null && "error" in data && typeof data.error === "string" ? data.error : `HTTP ${res.status.toString()}`;
|
|
21
|
-
throw new Error(message);
|
|
22
|
-
}
|
|
23
|
-
return data;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// ../../apps/cli/src/commands/project.ts
|
|
27
|
-
var projectCmd = new Command("project").description("Manage projects");
|
|
28
|
-
projectCmd.command("add").description("Add a project").requiredOption("--name <name>", "project name").requiredOption("--path <path>", "project directory path").option("--repoUrl <url>", "repository URL").option("--description <text>", "project description").action(async (opts) => {
|
|
29
|
-
const project = await apiFetch("/projects", {
|
|
30
|
-
method: "POST",
|
|
31
|
-
headers: { "Content-Type": "application/json" },
|
|
32
|
-
body: JSON.stringify({
|
|
33
|
-
name: opts.name,
|
|
34
|
-
path: opts.path,
|
|
35
|
-
repoUrl: opts.repoUrl,
|
|
36
|
-
description: opts.description
|
|
37
|
-
})
|
|
38
|
-
});
|
|
39
|
-
console.log(JSON.stringify(project, null, 2));
|
|
40
|
-
});
|
|
41
|
-
projectCmd.command("list").description("List projects").action(async () => {
|
|
42
|
-
const projects = await apiFetch("/projects");
|
|
43
|
-
console.log(JSON.stringify(projects, null, 2));
|
|
44
|
-
});
|
|
45
|
-
projectCmd.command("remove").description("Remove a project").argument("<id>", "project id").action(async (id) => {
|
|
46
|
-
await apiFetch(`/projects/${id}`, { method: "DELETE" });
|
|
47
|
-
console.log("Project removed.");
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// ../../apps/cli/src/commands/task.ts
|
|
51
|
-
import { Command as Command3 } from "commander";
|
|
52
|
-
|
|
53
|
-
// ../../apps/cli/src/commands/task-feed.ts
|
|
54
|
-
import { Command as Command2 } from "commander";
|
|
55
|
-
import * as grpc from "@grpc/grpc-js";
|
|
56
|
-
import * as protoLoader from "@grpc/proto-loader";
|
|
57
|
-
|
|
58
|
-
// ../../apps/cli/src/lib/proto-path.ts
|
|
59
|
-
import { existsSync } from "fs";
|
|
60
|
-
import path from "path";
|
|
61
|
-
import { fileURLToPath } from "url";
|
|
62
|
-
var __filename = fileURLToPath(import.meta.url);
|
|
63
|
-
var __dirname = path.dirname(__filename);
|
|
64
|
-
function findProtoPath() {
|
|
65
|
-
const candidates = [
|
|
66
|
-
// Bundled / installed package layout: dist/proto/tasks.proto
|
|
67
|
-
path.join(__dirname, "proto/tasks.proto"),
|
|
68
|
-
// Development layout from apps/cli/src/lib: ../../../../proto/tasks.proto
|
|
69
|
-
path.resolve(__dirname, "../../../../proto/tasks.proto")
|
|
70
|
-
];
|
|
71
|
-
for (const candidate of candidates) {
|
|
72
|
-
if (existsSync(candidate)) return candidate;
|
|
73
|
-
}
|
|
74
|
-
return candidates[0] ?? "proto/tasks.proto";
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// ../../apps/cli/src/commands/task-feed.ts
|
|
78
|
-
var GRPC_TARGET = process.env.HARNESS_GRPC_TARGET ?? "localhost:50051";
|
|
79
|
-
var packageDefinition = protoLoader.loadSync(findProtoPath(), {
|
|
80
|
-
keepCase: true,
|
|
81
|
-
longs: String,
|
|
82
|
-
enums: String,
|
|
83
|
-
defaults: true,
|
|
84
|
-
oneofs: true
|
|
85
|
-
});
|
|
86
|
-
var proto = grpc.loadPackageDefinition(packageDefinition);
|
|
87
|
-
var taskFeedCmd = new Command2("feed").description("Feed a task into the harness via gRPC").requiredOption("--project <id>", "project id").requiredOption("--title <title>", "task title").option("--description <text>", "task description").option("--complexity <level>", "simple | medium | complex", "simple").option("--tags <tags>", "comma-separated tags").option("--auto-run", "run the task immediately after submission", false).option("--stream", "stream task updates after submission", false).action(
|
|
88
|
-
(opts) => {
|
|
89
|
-
const client = new proto.omega.TaskIngestion(
|
|
90
|
-
GRPC_TARGET,
|
|
91
|
-
grpc.credentials.createInsecure()
|
|
92
|
-
);
|
|
93
|
-
const request = {
|
|
94
|
-
project_id: opts.project,
|
|
95
|
-
title: opts.title,
|
|
96
|
-
description: opts.description ?? "",
|
|
97
|
-
complexity: opts.complexity,
|
|
98
|
-
tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : [],
|
|
99
|
-
auto_run: opts.autoRun
|
|
100
|
-
};
|
|
101
|
-
if (opts.stream) {
|
|
102
|
-
const call = client.streamTasks();
|
|
103
|
-
call.on("data", (event) => {
|
|
104
|
-
console.log(JSON.stringify(event, null, 2));
|
|
105
|
-
});
|
|
106
|
-
call.on("error", (err) => {
|
|
107
|
-
console.error("Stream error:", err.message);
|
|
108
|
-
process.exit(1);
|
|
109
|
-
});
|
|
110
|
-
call.on("end", () => {
|
|
111
|
-
process.exit(0);
|
|
112
|
-
});
|
|
113
|
-
call.write({ project_id: opts.project });
|
|
114
|
-
}
|
|
115
|
-
client.submitTask(request, (err, response) => {
|
|
116
|
-
if (err) {
|
|
117
|
-
console.error("gRPC error:", err.message);
|
|
118
|
-
process.exit(1);
|
|
119
|
-
}
|
|
120
|
-
console.log(JSON.stringify(response, null, 2));
|
|
121
|
-
if (!opts.stream) {
|
|
122
|
-
client.close();
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
);
|
|
127
|
-
|
|
128
|
-
// ../../apps/cli/src/commands/task.ts
|
|
129
|
-
var taskCmd = new Command3("task").description("Manage tasks");
|
|
130
|
-
taskCmd.command("create").description("Create a task").requiredOption("--project <id>", "project id").requiredOption("--title <title>", "task title").option("--description <text>", "task description").option("--complexity <level>", "simple | medium | complex", "simple").option("--tags <tags>", "comma-separated tags").action(async (opts) => {
|
|
131
|
-
const task = await apiFetch("/tasks", {
|
|
132
|
-
method: "POST",
|
|
133
|
-
headers: { "Content-Type": "application/json" },
|
|
134
|
-
body: JSON.stringify({
|
|
135
|
-
projectId: opts.project,
|
|
136
|
-
title: opts.title,
|
|
137
|
-
description: opts.description,
|
|
138
|
-
complexity: opts.complexity,
|
|
139
|
-
tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : []
|
|
140
|
-
})
|
|
141
|
-
});
|
|
142
|
-
console.log(JSON.stringify(task, null, 2));
|
|
143
|
-
});
|
|
144
|
-
taskCmd.command("list").description("List tasks").option("--project <id>", "filter by project id").action(async (opts) => {
|
|
145
|
-
const query = opts.project ? `?projectId=${opts.project}` : "";
|
|
146
|
-
const tasks = await apiFetch(`/tasks${query}`);
|
|
147
|
-
console.log(JSON.stringify(tasks, null, 2));
|
|
148
|
-
});
|
|
149
|
-
taskCmd.command("run").description("Run a task through the router").argument("<id>", "task id").action(async (id) => {
|
|
150
|
-
const result = await apiFetch(`/tasks/${id}/run`, { method: "POST" });
|
|
151
|
-
console.log(JSON.stringify(result, null, 2));
|
|
152
|
-
});
|
|
153
|
-
taskCmd.addCommand(taskFeedCmd);
|
|
154
|
-
|
|
155
|
-
// ../../apps/cli/src/commands/ui.ts
|
|
156
|
-
import { Command as Command4 } from "commander";
|
|
157
|
-
import { spawn } from "child_process";
|
|
158
|
-
import { existsSync as existsSync2 } from "fs";
|
|
159
|
-
import path2 from "path";
|
|
160
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
161
|
-
import open from "open";
|
|
162
|
-
import { render } from "ink";
|
|
163
|
-
import React2 from "react";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
164
11
|
|
|
165
12
|
// ../../apps/cli/src/commands/tui.tsx
|
|
13
|
+
var tui_exports = {};
|
|
14
|
+
__export(tui_exports, {
|
|
15
|
+
TuiApp: () => TuiApp
|
|
16
|
+
});
|
|
166
17
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
167
18
|
import { Box, Text, useApp, useInput, useWindowSize } from "ink";
|
|
168
19
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
169
|
-
var API = process.env.HARNESS_API_URL ?? "http://localhost:4000";
|
|
170
20
|
function formatTime(d) {
|
|
171
21
|
return d.toLocaleTimeString("en-US", { hour12: false });
|
|
172
22
|
}
|
|
@@ -414,46 +264,239 @@ function TuiApp() {
|
|
|
414
264
|
/* @__PURE__ */ jsx(Box, { height: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "q/esc quit \u2022 t toggle tasks \u2022 s toggle sidebar" }) })
|
|
415
265
|
] });
|
|
416
266
|
}
|
|
267
|
+
var API;
|
|
268
|
+
var init_tui = __esm({
|
|
269
|
+
"../../apps/cli/src/commands/tui.tsx"() {
|
|
270
|
+
"use strict";
|
|
271
|
+
API = process.env.HARNESS_API_URL ?? "http://localhost:4000";
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// ../../apps/cli/src/index.ts
|
|
276
|
+
import { program as program2 } from "commander";
|
|
277
|
+
|
|
278
|
+
// ../../apps/cli/src/commands/project.ts
|
|
279
|
+
import { Command } from "commander";
|
|
280
|
+
|
|
281
|
+
// ../../apps/cli/src/api.ts
|
|
282
|
+
import { program } from "commander";
|
|
283
|
+
function getApiUrl() {
|
|
284
|
+
const opts = program.opts();
|
|
285
|
+
return opts.api ?? "http://localhost:4000";
|
|
286
|
+
}
|
|
287
|
+
async function apiFetch(path4, init) {
|
|
288
|
+
const url = `${getApiUrl()}${path4}`;
|
|
289
|
+
const res = await fetch(url, init);
|
|
290
|
+
const data = await res.json().catch(() => ({}));
|
|
291
|
+
if (!res.ok) {
|
|
292
|
+
const message = typeof data === "object" && data !== null && "error" in data && typeof data.error === "string" ? data.error : `HTTP ${res.status.toString()}`;
|
|
293
|
+
throw new Error(message);
|
|
294
|
+
}
|
|
295
|
+
return data;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// ../../apps/cli/src/commands/project.ts
|
|
299
|
+
var projectCmd = new Command("project").description("Manage projects");
|
|
300
|
+
projectCmd.command("add").description("Add a project").requiredOption("--name <name>", "project name").requiredOption("--path <path>", "project directory path").option("--repoUrl <url>", "repository URL").option("--description <text>", "project description").action(async (opts) => {
|
|
301
|
+
const project = await apiFetch("/projects", {
|
|
302
|
+
method: "POST",
|
|
303
|
+
headers: { "Content-Type": "application/json" },
|
|
304
|
+
body: JSON.stringify({
|
|
305
|
+
name: opts.name,
|
|
306
|
+
path: opts.path,
|
|
307
|
+
repoUrl: opts.repoUrl,
|
|
308
|
+
description: opts.description
|
|
309
|
+
})
|
|
310
|
+
});
|
|
311
|
+
console.log(JSON.stringify(project, null, 2));
|
|
312
|
+
});
|
|
313
|
+
projectCmd.command("list").description("List projects").action(async () => {
|
|
314
|
+
const projects = await apiFetch("/projects");
|
|
315
|
+
console.log(JSON.stringify(projects, null, 2));
|
|
316
|
+
});
|
|
317
|
+
projectCmd.command("remove").description("Remove a project").argument("<id>", "project id").action(async (id) => {
|
|
318
|
+
await apiFetch(`/projects/${id}`, { method: "DELETE" });
|
|
319
|
+
console.log("Project removed.");
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// ../../apps/cli/src/commands/task.ts
|
|
323
|
+
import { Command as Command3 } from "commander";
|
|
324
|
+
|
|
325
|
+
// ../../apps/cli/src/commands/task-feed.ts
|
|
326
|
+
import { Command as Command2 } from "commander";
|
|
327
|
+
import * as grpc from "@grpc/grpc-js";
|
|
328
|
+
import * as protoLoader from "@grpc/proto-loader";
|
|
329
|
+
|
|
330
|
+
// ../../apps/cli/src/lib/proto-path.ts
|
|
331
|
+
import { existsSync } from "fs";
|
|
332
|
+
import path from "path";
|
|
333
|
+
import { fileURLToPath } from "url";
|
|
334
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
335
|
+
var __dirname = path.dirname(__filename);
|
|
336
|
+
function findProtoPath() {
|
|
337
|
+
const candidates = [
|
|
338
|
+
// Bundled / installed package layout: dist/proto/tasks.proto
|
|
339
|
+
path.join(__dirname, "proto/tasks.proto"),
|
|
340
|
+
// Development layout from apps/cli/src/lib: ../../../../proto/tasks.proto
|
|
341
|
+
path.resolve(__dirname, "../../../../proto/tasks.proto")
|
|
342
|
+
];
|
|
343
|
+
for (const candidate of candidates) {
|
|
344
|
+
if (existsSync(candidate)) return candidate;
|
|
345
|
+
}
|
|
346
|
+
return candidates[0] ?? "proto/tasks.proto";
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// ../../apps/cli/src/commands/task-feed.ts
|
|
350
|
+
var GRPC_TARGET = process.env.HARNESS_GRPC_TARGET ?? "localhost:50051";
|
|
351
|
+
var packageDefinition = protoLoader.loadSync(findProtoPath(), {
|
|
352
|
+
keepCase: true,
|
|
353
|
+
longs: String,
|
|
354
|
+
enums: String,
|
|
355
|
+
defaults: true,
|
|
356
|
+
oneofs: true
|
|
357
|
+
});
|
|
358
|
+
var proto = grpc.loadPackageDefinition(packageDefinition);
|
|
359
|
+
var taskFeedCmd = new Command2("feed").description("Feed a task into the harness via gRPC").requiredOption("--project <id>", "project id").requiredOption("--title <title>", "task title").option("--description <text>", "task description").option("--complexity <level>", "simple | medium | complex", "simple").option("--tags <tags>", "comma-separated tags").option("--auto-run", "run the task immediately after submission", false).option("--stream", "stream task updates after submission", false).action(
|
|
360
|
+
(opts) => {
|
|
361
|
+
const client = new proto.omega.TaskIngestion(
|
|
362
|
+
GRPC_TARGET,
|
|
363
|
+
grpc.credentials.createInsecure()
|
|
364
|
+
);
|
|
365
|
+
const request = {
|
|
366
|
+
project_id: opts.project,
|
|
367
|
+
title: opts.title,
|
|
368
|
+
description: opts.description ?? "",
|
|
369
|
+
complexity: opts.complexity,
|
|
370
|
+
tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : [],
|
|
371
|
+
auto_run: opts.autoRun
|
|
372
|
+
};
|
|
373
|
+
if (opts.stream) {
|
|
374
|
+
const call = client.streamTasks();
|
|
375
|
+
call.on("data", (event) => {
|
|
376
|
+
console.log(JSON.stringify(event, null, 2));
|
|
377
|
+
});
|
|
378
|
+
call.on("error", (err) => {
|
|
379
|
+
console.error("Stream error:", err.message);
|
|
380
|
+
process.exit(1);
|
|
381
|
+
});
|
|
382
|
+
call.on("end", () => {
|
|
383
|
+
process.exit(0);
|
|
384
|
+
});
|
|
385
|
+
call.write({ project_id: opts.project });
|
|
386
|
+
}
|
|
387
|
+
client.submitTask(request, (err, response) => {
|
|
388
|
+
if (err) {
|
|
389
|
+
console.error("gRPC error:", err.message);
|
|
390
|
+
process.exit(1);
|
|
391
|
+
}
|
|
392
|
+
console.log(JSON.stringify(response, null, 2));
|
|
393
|
+
if (!opts.stream) {
|
|
394
|
+
client.close();
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
// ../../apps/cli/src/commands/task.ts
|
|
401
|
+
var taskCmd = new Command3("task").description("Manage tasks");
|
|
402
|
+
taskCmd.command("create").description("Create a task").requiredOption("--project <id>", "project id").requiredOption("--title <title>", "task title").option("--description <text>", "task description").option("--complexity <level>", "simple | medium | complex", "simple").option("--tags <tags>", "comma-separated tags").action(async (opts) => {
|
|
403
|
+
const task = await apiFetch("/tasks", {
|
|
404
|
+
method: "POST",
|
|
405
|
+
headers: { "Content-Type": "application/json" },
|
|
406
|
+
body: JSON.stringify({
|
|
407
|
+
projectId: opts.project,
|
|
408
|
+
title: opts.title,
|
|
409
|
+
description: opts.description,
|
|
410
|
+
complexity: opts.complexity,
|
|
411
|
+
tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : []
|
|
412
|
+
})
|
|
413
|
+
});
|
|
414
|
+
console.log(JSON.stringify(task, null, 2));
|
|
415
|
+
});
|
|
416
|
+
taskCmd.command("list").description("List tasks").option("--project <id>", "filter by project id").action(async (opts) => {
|
|
417
|
+
const query = opts.project ? `?projectId=${opts.project}` : "";
|
|
418
|
+
const tasks = await apiFetch(`/tasks${query}`);
|
|
419
|
+
console.log(JSON.stringify(tasks, null, 2));
|
|
420
|
+
});
|
|
421
|
+
taskCmd.command("run").description("Run a task through the router").argument("<id>", "task id").action(async (id) => {
|
|
422
|
+
const result = await apiFetch(`/tasks/${id}/run`, { method: "POST" });
|
|
423
|
+
console.log(JSON.stringify(result, null, 2));
|
|
424
|
+
});
|
|
425
|
+
taskCmd.addCommand(taskFeedCmd);
|
|
417
426
|
|
|
418
427
|
// ../../apps/cli/src/commands/ui.ts
|
|
428
|
+
import { Command as Command4 } from "commander";
|
|
429
|
+
import { spawn } from "child_process";
|
|
430
|
+
import { existsSync as existsSync2 } from "fs";
|
|
431
|
+
import net from "net";
|
|
432
|
+
import path2 from "path";
|
|
433
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
434
|
+
import open from "open";
|
|
435
|
+
import { render } from "ink";
|
|
436
|
+
import React2 from "react";
|
|
419
437
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
420
438
|
var __dirname2 = path2.dirname(__filename2);
|
|
421
|
-
var
|
|
422
|
-
|
|
439
|
+
var DEFAULT_PORT = 4e3;
|
|
440
|
+
var MAX_PORT = 4010;
|
|
441
|
+
function findAvailablePort(preferred = DEFAULT_PORT, max = MAX_PORT) {
|
|
442
|
+
return new Promise((resolve, reject) => {
|
|
443
|
+
if (preferred > max) {
|
|
444
|
+
reject(new Error(`No available ports between ${DEFAULT_PORT.toString()} and ${max.toString()}`));
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
const tester = net.createServer();
|
|
448
|
+
tester.once("error", (err) => {
|
|
449
|
+
if (err.code === "EADDRINUSE") {
|
|
450
|
+
findAvailablePort(preferred + 1, max).then(resolve, reject);
|
|
451
|
+
} else {
|
|
452
|
+
reject(err);
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
tester.once("listening", () => {
|
|
456
|
+
const address = tester.address();
|
|
457
|
+
const port = typeof address === "object" && address ? address.port : preferred;
|
|
458
|
+
tester.close(() => {
|
|
459
|
+
resolve(port);
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
tester.listen(preferred);
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
function startBundledServer(env) {
|
|
423
466
|
const serverPath = path2.resolve(__dirname2, "server.js");
|
|
424
467
|
if (existsSync2(serverPath)) {
|
|
425
|
-
return spawn(process.execPath, [serverPath], { stdio: "inherit" });
|
|
468
|
+
return spawn(process.execPath, [serverPath], { stdio: "inherit", env });
|
|
426
469
|
}
|
|
427
470
|
return void 0;
|
|
428
471
|
}
|
|
429
|
-
async function isApiReady() {
|
|
472
|
+
async function isApiReady(apiUrl) {
|
|
430
473
|
try {
|
|
431
|
-
const res = await fetch(`${
|
|
474
|
+
const res = await fetch(`${apiUrl}/projects`);
|
|
432
475
|
return res.ok;
|
|
433
476
|
} catch {
|
|
434
477
|
return false;
|
|
435
478
|
}
|
|
436
479
|
}
|
|
437
|
-
async function waitForApi(maxMs = 15e3) {
|
|
480
|
+
async function waitForApi(apiUrl, maxMs = 15e3) {
|
|
438
481
|
const deadline = Date.now() + maxMs;
|
|
439
482
|
while (Date.now() < deadline) {
|
|
440
|
-
if (await isApiReady()) return;
|
|
483
|
+
if (await isApiReady(apiUrl)) return;
|
|
441
484
|
await new Promise((r) => setTimeout(r, 300));
|
|
442
485
|
}
|
|
443
486
|
throw new Error("Server did not become ready in time");
|
|
444
487
|
}
|
|
445
|
-
async function ensureProject() {
|
|
488
|
+
async function ensureProject(apiUrl) {
|
|
446
489
|
const cwd = process.cwd();
|
|
447
490
|
const name = path2.basename(cwd);
|
|
448
491
|
try {
|
|
449
|
-
const listRes = await fetch(`${
|
|
492
|
+
const listRes = await fetch(`${apiUrl}/projects`);
|
|
450
493
|
const projects = await listRes.json();
|
|
451
494
|
const existing = projects.find((p) => p.path === cwd);
|
|
452
495
|
if (existing) {
|
|
453
496
|
console.log(`Using existing project: ${name}`);
|
|
454
497
|
return;
|
|
455
498
|
}
|
|
456
|
-
const createRes = await fetch(`${
|
|
499
|
+
const createRes = await fetch(`${apiUrl}/projects`, {
|
|
457
500
|
method: "POST",
|
|
458
501
|
headers: { "Content-Type": "application/json" },
|
|
459
502
|
body: JSON.stringify({ name, path: cwd })
|
|
@@ -468,24 +511,31 @@ async function ensureProject() {
|
|
|
468
511
|
}
|
|
469
512
|
}
|
|
470
513
|
var uiCmd = new Command4("ui").description("Open the harness web UI").option("--no-tui", "Do not open the terminal console alongside the web UI").action(async (options) => {
|
|
471
|
-
|
|
472
|
-
|
|
514
|
+
const defaultApiUrl = process.env.HARNESS_API_URL ?? `http://localhost:${DEFAULT_PORT.toString()}`;
|
|
515
|
+
let server;
|
|
516
|
+
const alreadyRunning = await isApiReady(defaultApiUrl);
|
|
473
517
|
const useTui = options.tui;
|
|
518
|
+
let apiUrl = defaultApiUrl;
|
|
474
519
|
if (!alreadyRunning) {
|
|
475
|
-
|
|
520
|
+
const port = await findAvailablePort();
|
|
521
|
+
apiUrl = `http://localhost:${port.toString()}`;
|
|
522
|
+
process.env.HARNESS_API_URL = apiUrl;
|
|
523
|
+
const env = { ...process.env, PORT: port.toString(), HARNESS_API_URL: apiUrl };
|
|
524
|
+
server = startBundledServer(env) ?? spawn("pnpm", ["--filter", "@omega/server", "dev"], {
|
|
476
525
|
stdio: "inherit",
|
|
477
|
-
shell: true
|
|
526
|
+
shell: true,
|
|
527
|
+
env
|
|
478
528
|
});
|
|
479
529
|
server.on("exit", (code) => {
|
|
480
530
|
process.exit(code ?? 0);
|
|
481
531
|
});
|
|
482
532
|
} else {
|
|
483
|
-
console.log(
|
|
533
|
+
console.log(`Using existing harness server on ${defaultApiUrl}`);
|
|
484
534
|
}
|
|
485
535
|
try {
|
|
486
|
-
await waitForApi();
|
|
487
|
-
await ensureProject();
|
|
488
|
-
await open(
|
|
536
|
+
await waitForApi(apiUrl);
|
|
537
|
+
await ensureProject(apiUrl);
|
|
538
|
+
await open(apiUrl);
|
|
489
539
|
} catch (err) {
|
|
490
540
|
console.error(err);
|
|
491
541
|
server?.kill();
|
|
@@ -496,7 +546,8 @@ var uiCmd = new Command4("ui").description("Open the harness web UI").option("--
|
|
|
496
546
|
console.log("Terminal is not interactive; skipping TUI. Open the web UI above.");
|
|
497
547
|
return;
|
|
498
548
|
}
|
|
499
|
-
const {
|
|
549
|
+
const { TuiApp: TuiApp2 } = await Promise.resolve().then(() => (init_tui(), tui_exports));
|
|
550
|
+
const { waitUntilExit } = render(React2.createElement(TuiApp2));
|
|
500
551
|
await waitUntilExit();
|
|
501
552
|
if (server && !alreadyRunning) {
|
|
502
553
|
server.kill();
|
|
@@ -505,6 +556,7 @@ var uiCmd = new Command4("ui").description("Open the harness web UI").option("--
|
|
|
505
556
|
});
|
|
506
557
|
|
|
507
558
|
// ../../apps/cli/src/commands/console.ts
|
|
559
|
+
init_tui();
|
|
508
560
|
import { Command as Command5 } from "commander";
|
|
509
561
|
import { render as render2 } from "ink";
|
|
510
562
|
import React3 from "react";
|
package/dist/server.js
CHANGED
|
@@ -352,7 +352,7 @@ if (process.env.KIMI_API_KEY) {
|
|
|
352
352
|
id: "default-kimi",
|
|
353
353
|
name: "kimi",
|
|
354
354
|
kind: "kimi",
|
|
355
|
-
baseUrl: "https://api.
|
|
355
|
+
baseUrl: "https://api.kimi.com/coding/v1",
|
|
356
356
|
apiKey: process.env.KIMI_API_KEY,
|
|
357
357
|
defaultModel: "moonshot-v1-8k",
|
|
358
358
|
capabilities: [{ name: "moonshot-v1-8k", level: "advanced" }],
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@castlemilk/omega",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Omega Harness CLI - installable via npx",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cli.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"harness": "
|
|
9
|
-
"omega-harness": "
|
|
8
|
+
"harness": "dist/cli.js",
|
|
9
|
+
"omega-harness": "dist/cli.js"
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"dist"
|