@castlemilk/omega 0.1.9 → 0.3.0

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 CHANGED
@@ -10,14 +10,15 @@ import { Command } from "commander";
10
10
  import { program } from "commander";
11
11
  function getApiUrl() {
12
12
  const opts = program.opts();
13
- return opts.api || "http://localhost:4000";
13
+ return opts.api ?? "http://localhost:4000";
14
14
  }
15
- async function apiFetch(path3, init) {
16
- const url = `${getApiUrl()}${path3}`;
15
+ async function apiFetch(path4, init) {
16
+ const url = `${getApiUrl()}${path4}`;
17
17
  const res = await fetch(url, init);
18
18
  const data = await res.json().catch(() => ({}));
19
19
  if (!res.ok) {
20
- throw new Error(data.error || `HTTP ${res.status}`);
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);
21
22
  }
22
23
  return data;
23
24
  }
@@ -47,8 +48,85 @@ projectCmd.command("remove").description("Remove a project").argument("<id>", "p
47
48
  });
48
49
 
49
50
  // ../../apps/cli/src/commands/task.ts
51
+ import { Command as Command3 } from "commander";
52
+
53
+ // ../../apps/cli/src/commands/task-feed.ts
50
54
  import { Command as Command2 } from "commander";
51
- var taskCmd = new Command2("task").description("Manage tasks");
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");
52
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) => {
53
131
  const task = await apiFetch("/tasks", {
54
132
  method: "POST",
@@ -72,13 +150,14 @@ taskCmd.command("run").description("Run a task through the router").argument("<i
72
150
  const result = await apiFetch(`/tasks/${id}/run`, { method: "POST" });
73
151
  console.log(JSON.stringify(result, null, 2));
74
152
  });
153
+ taskCmd.addCommand(taskFeedCmd);
75
154
 
76
155
  // ../../apps/cli/src/commands/ui.ts
77
- import { Command as Command3 } from "commander";
156
+ import { Command as Command4 } from "commander";
78
157
  import { spawn } from "child_process";
79
- import { existsSync } from "fs";
80
- import path from "path";
81
- import { fileURLToPath } from "url";
158
+ import { existsSync as existsSync2 } from "fs";
159
+ import path2 from "path";
160
+ import { fileURLToPath as fileURLToPath2 } from "url";
82
161
  import open from "open";
83
162
  import { render } from "ink";
84
163
  import React2 from "react";
@@ -87,7 +166,7 @@ import React2 from "react";
87
166
  import { useEffect, useMemo, useRef, useState } from "react";
88
167
  import { Box, Text, useApp, useInput, useWindowSize } from "ink";
89
168
  import { jsx, jsxs } from "react/jsx-runtime";
90
- var API = process.env.HARNESS_API_URL || "http://localhost:4000";
169
+ var API = process.env.HARNESS_API_URL ?? "http://localhost:4000";
91
170
  function formatTime(d) {
92
171
  return d.toLocaleTimeString("en-US", { hour12: false });
93
172
  }
@@ -131,7 +210,7 @@ function useTasks(pollMs = 1e3) {
131
210
  const tick = async () => {
132
211
  try {
133
212
  const res = await fetch(`${API}/tasks`);
134
- if (!res.ok) throw new Error(`HTTP ${res.status}`);
213
+ if (!res.ok) throw new Error(`HTTP ${res.status.toString()}`);
135
214
  const data = await res.json();
136
215
  setConnected(true);
137
216
  const current = {};
@@ -142,8 +221,8 @@ function useTasks(pollMs = 1e3) {
142
221
  addLog(`New task queued: "${task.title}"`, "info");
143
222
  } else if (prev.status !== task.status) {
144
223
  if (task.status === "in_progress") {
145
- const provider = task.provider || "unknown";
146
- const model = task.model || "unknown";
224
+ const provider = task.provider ?? "unknown";
225
+ const model = task.model ?? "unknown";
147
226
  addLog(`LLM picked up "${task.title}" \u2192 ${provider}/${model}`, "info");
148
227
  } else if (task.status === "done") {
149
228
  addLog(`Completed: "${task.title}"`, "success");
@@ -153,8 +232,9 @@ function useTasks(pollMs = 1e3) {
153
232
  }
154
233
  }
155
234
  for (const id of Object.keys(previousTasks.current)) {
156
- if (!current[id] && !id.startsWith("__")) {
157
- addLog(`Task removed: "${previousTasks.current[id].title}"`, "warning");
235
+ const removed = previousTasks.current[id];
236
+ if (!current[id] && !id.startsWith("__") && removed) {
237
+ addLog(`Task removed: "${removed.title}"`, "warning");
158
238
  }
159
239
  }
160
240
  previousTasks.current = current;
@@ -162,16 +242,18 @@ function useTasks(pollMs = 1e3) {
162
242
  } catch (err) {
163
243
  setConnected(false);
164
244
  const message = err instanceof Error ? err.message : String(err);
165
- if (message !== previousTasks.current["__last_error"]?.title) {
245
+ if (message !== previousTasks.current.__last_error?.title) {
166
246
  addLog(`Connection lost: ${message}`, "error");
167
- previousTasks.current["__last_error"] = { title: message };
247
+ previousTasks.current.__last_error = { title: message };
168
248
  }
169
249
  }
170
250
  if (!cancelled) {
171
- setTimeout(tick, pollMs);
251
+ setTimeout(() => {
252
+ void tick();
253
+ }, pollMs);
172
254
  }
173
255
  };
174
- tick();
256
+ void tick();
175
257
  return () => {
176
258
  cancelled = true;
177
259
  };
@@ -229,7 +311,7 @@ function TaskList({
229
311
  tasks,
230
312
  height,
231
313
  collapsed,
232
- toggle,
314
+ toggle: _toggle,
233
315
  columns
234
316
  }) {
235
317
  const sorted = useMemo(
@@ -258,7 +340,7 @@ function TaskList({
258
340
  header,
259
341
  visible.length === 0 && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No tasks yet. Create one in the web UI." }),
260
342
  visible.map((task) => {
261
- const providerText = task.provider ? `${task.provider}/${task.model}` : "-";
343
+ const providerText = task.provider ? `${task.provider}/${task.model ?? ""}` : "-";
262
344
  const titleMax = Math.max(10, columns - 50);
263
345
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
264
346
  /* @__PURE__ */ jsx(Text, { color: statusColor(task.status), children: statusSymbol(task.status) }),
@@ -321,7 +403,9 @@ function TuiApp() {
321
403
  tasks,
322
404
  height: taskListHeight,
323
405
  collapsed: tasksCollapsed,
324
- toggle: () => setTasksCollapsed((c) => !c),
406
+ toggle: () => {
407
+ setTasksCollapsed((c) => !c);
408
+ },
325
409
  columns: taskListWidth ?? columns
326
410
  }
327
411
  ),
@@ -332,12 +416,12 @@ function TuiApp() {
332
416
  }
333
417
 
334
418
  // ../../apps/cli/src/commands/ui.ts
335
- var __filename = fileURLToPath(import.meta.url);
336
- var __dirname = path.dirname(__filename);
337
- var API2 = process.env.HARNESS_API_URL || "http://localhost:4000";
419
+ var __filename2 = fileURLToPath2(import.meta.url);
420
+ var __dirname2 = path2.dirname(__filename2);
421
+ var API2 = process.env.HARNESS_API_URL ?? "http://localhost:4000";
338
422
  function startBundledServer() {
339
- const serverPath = path.resolve(__dirname, "server.js");
340
- if (existsSync(serverPath)) {
423
+ const serverPath = path2.resolve(__dirname2, "server.js");
424
+ if (existsSync2(serverPath)) {
341
425
  return spawn(process.execPath, [serverPath], { stdio: "inherit" });
342
426
  }
343
427
  return void 0;
@@ -360,7 +444,7 @@ async function waitForApi(maxMs = 15e3) {
360
444
  }
361
445
  async function ensureProject() {
362
446
  const cwd = process.cwd();
363
- const name = path.basename(cwd);
447
+ const name = path2.basename(cwd);
364
448
  try {
365
449
  const listRes = await fetch(`${API2}/projects`);
366
450
  const projects = await listRes.json();
@@ -383,10 +467,10 @@ async function ensureProject() {
383
467
  console.warn("Could not auto-detect project:", err);
384
468
  }
385
469
  }
386
- var uiCmd = new Command3("ui").description("Open the harness web UI").option("--no-tui", "Do not open the terminal console alongside the web UI").action(async (options) => {
470
+ 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) => {
387
471
  let server = void 0;
388
472
  const alreadyRunning = await isApiReady();
389
- const useTui = options.tui !== false;
473
+ const useTui = options.tui;
390
474
  if (!alreadyRunning) {
391
475
  server = startBundledServer() ?? spawn("pnpm", ["--filter", "@omega/server", "dev"], {
392
476
  stdio: "inherit",
@@ -421,10 +505,10 @@ var uiCmd = new Command3("ui").description("Open the harness web UI").option("--
421
505
  });
422
506
 
423
507
  // ../../apps/cli/src/commands/console.ts
424
- import { Command as Command4 } from "commander";
508
+ import { Command as Command5 } from "commander";
425
509
  import { render as render2 } from "ink";
426
510
  import React3 from "react";
427
- var consoleCmd = new Command4("console").description("Open the harness TUI console").action(async () => {
511
+ var consoleCmd = new Command5("console").description("Open the harness TUI console").action(() => {
428
512
  if (!process.stdin.isTTY) {
429
513
  console.error("The harness console requires an interactive terminal (TTY).");
430
514
  process.exit(1);
@@ -433,9 +517,9 @@ var consoleCmd = new Command4("console").description("Open the harness TUI conso
433
517
  });
434
518
 
435
519
  // ../../apps/cli/src/commands/skill.ts
436
- import { Command as Command5 } from "commander";
437
- import path2 from "path";
438
- import { fileURLToPath as fileURLToPath2 } from "url";
520
+ import { Command as Command6 } from "commander";
521
+ import path3 from "path";
522
+ import { fileURLToPath as fileURLToPath3 } from "url";
439
523
 
440
524
  // ../skills/src/parse.ts
441
525
  import matter from "gray-matter";
@@ -456,14 +540,14 @@ function parseSkill(md) {
456
540
  }
457
541
  args = frontmatter.args.map((entry, index) => {
458
542
  if (typeof entry !== "object" || entry === null) {
459
- throw new Error(`SKILL.md arg at index ${index} must be an object`);
543
+ throw new Error(`SKILL.md arg at index ${index.toString()} must be an object`);
460
544
  }
461
545
  const arg = entry;
462
546
  if (typeof arg.name !== "string" || arg.name.trim() === "") {
463
- throw new Error(`SKILL.md arg at index ${index} must have a non-empty "name"`);
547
+ throw new Error(`SKILL.md arg at index ${index.toString()} must have a non-empty "name"`);
464
548
  }
465
549
  if (typeof arg.type !== "string" || arg.type.trim() === "") {
466
- throw new Error(`SKILL.md arg at index ${index} must have a non-empty "type"`);
550
+ throw new Error(`SKILL.md arg at index ${index.toString()} must have a non-empty "type"`);
467
551
  }
468
552
  return {
469
553
  name: arg.name.trim(),
@@ -536,22 +620,22 @@ async function registerSkill(sourcePath, outputDir) {
536
620
  // ../../apps/cli/src/commands/skill.ts
537
621
  function getOutputDir() {
538
622
  if (process.env.OMEGA_HARNESS_ROOT) {
539
- return path2.join(path2.resolve(process.env.OMEGA_HARNESS_ROOT), "packages/skills/src");
623
+ return path3.join(path3.resolve(process.env.OMEGA_HARNESS_ROOT), "packages/skills/src");
540
624
  }
541
625
  try {
542
- const __filename2 = fileURLToPath2(import.meta.url);
543
- const __dirname2 = path2.dirname(__filename2);
544
- return path2.join(path2.resolve(__dirname2, "../../../.."), "packages/skills/src");
626
+ const __filename3 = fileURLToPath3(import.meta.url);
627
+ const __dirname3 = path3.dirname(__filename3);
628
+ return path3.join(path3.resolve(__dirname3, "../../../.."), "packages/skills/src");
545
629
  } catch {
546
- return path2.join(process.cwd(), "harness-skills");
630
+ return path3.join(process.cwd(), "harness-skills");
547
631
  }
548
632
  }
549
- var skillCmd = new Command5("skill").description("Manage skill artifacts");
633
+ var skillCmd = new Command6("skill").description("Manage skill artifacts");
550
634
  skillCmd.command("generate").description("Generate a harness adapter from a SKILL.md file").argument("<source>", "path to SKILL.md").action(async (source) => {
551
635
  const outputDir = getOutputDir();
552
- const manifest = await registerSkill(path2.resolve(source), outputDir);
636
+ const manifest = await registerSkill(path3.resolve(source), outputDir);
553
637
  console.log(`Generated adapter for skill: ${manifest.name}`);
554
- console.log(`Output directory: ${path2.join(outputDir, "generated")}`);
638
+ console.log(`Output directory: ${path3.join(outputDir, "generated")}`);
555
639
  });
556
640
 
557
641
  // ../../apps/cli/src/index.ts
@@ -0,0 +1,37 @@
1
+ syntax = "proto3";
2
+
3
+ package omega;
4
+
5
+ service TaskIngestion {
6
+ rpc SubmitTask (TaskRequest) returns (TaskResponse);
7
+ rpc StreamTasks (TaskStreamRequest) returns (stream TaskEvent);
8
+ }
9
+
10
+ message TaskRequest {
11
+ string project_id = 1;
12
+ string title = 2;
13
+ string description = 3;
14
+ string complexity = 4;
15
+ repeated string tags = 5;
16
+ bool auto_run = 6;
17
+ }
18
+
19
+ message TaskResponse {
20
+ string id = 1;
21
+ string status = 2;
22
+ string error = 3;
23
+ }
24
+
25
+ message TaskStreamRequest {
26
+ string project_id = 1;
27
+ }
28
+
29
+ message TaskEvent {
30
+ string id = 1;
31
+ string title = 2;
32
+ string status = 3;
33
+ string provider = 4;
34
+ string model = 5;
35
+ string result = 6;
36
+ string error = 7;
37
+ }