@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.
Files changed (3) hide show
  1. package/dist/cli.js +234 -182
  2. package/dist/server.js +1 -1
  3. package/package.json +3 -3
package/dist/cli.js CHANGED
@@ -1,172 +1,22 @@
1
1
  #!/usr/bin/env node
2
-
3
- // ../../apps/cli/src/index.ts
4
- import { program as program2 } from "commander";
5
-
6
- // ../../apps/cli/src/commands/project.ts
7
- import { Command } from "commander";
8
-
9
- // ../../apps/cli/src/api.ts
10
- import { program } from "commander";
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 API2 = process.env.HARNESS_API_URL ?? "http://localhost:4000";
422
- function startBundledServer() {
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(`${API2}/projects`);
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(`${API2}/projects`);
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(`${API2}/projects`, {
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
- let server = void 0;
472
- const alreadyRunning = await isApiReady();
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
- server = startBundledServer() ?? spawn("pnpm", ["--filter", "@omega/server", "dev"], {
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("Using existing harness server on port 4000");
533
+ console.log(`Using existing harness server on ${defaultApiUrl}`);
484
534
  }
485
535
  try {
486
- await waitForApi();
487
- await ensureProject();
488
- await open(API2);
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 { waitUntilExit } = render(React2.createElement(TuiApp));
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.moonshot.cn/v1",
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.0",
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": "./dist/cli.js",
9
- "omega-harness": "./dist/cli.js"
8
+ "harness": "dist/cli.js",
9
+ "omega-harness": "dist/cli.js"
10
10
  },
11
11
  "files": [
12
12
  "dist"