@castlemilk/omega 0.1.3

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 (2) hide show
  1. package/dist/cli.js +221 -0
  2. package/package.json +34 -0
package/dist/cli.js ADDED
@@ -0,0 +1,221 @@
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(path2, init) {
16
+ const url = `${getApiUrl()}${path2}`;
17
+ const res = await fetch(url, init);
18
+ const data = await res.json().catch(() => ({}));
19
+ if (!res.ok) {
20
+ throw new Error(data.error || `HTTP ${res.status}`);
21
+ }
22
+ return data;
23
+ }
24
+
25
+ // ../../apps/cli/src/commands/project.ts
26
+ var projectCmd = new Command("project").description("Manage projects");
27
+ 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) => {
28
+ const project = await apiFetch("/projects", {
29
+ method: "POST",
30
+ headers: { "Content-Type": "application/json" },
31
+ body: JSON.stringify({
32
+ name: opts.name,
33
+ path: opts.path,
34
+ repoUrl: opts.repoUrl,
35
+ description: opts.description
36
+ })
37
+ });
38
+ console.log(JSON.stringify(project, null, 2));
39
+ });
40
+ projectCmd.command("list").description("List projects").action(async () => {
41
+ const projects = await apiFetch("/projects");
42
+ console.log(JSON.stringify(projects, null, 2));
43
+ });
44
+ projectCmd.command("remove").description("Remove a project").argument("<id>", "project id").action(async (id) => {
45
+ await apiFetch(`/projects/${id}`, { method: "DELETE" });
46
+ console.log("Project removed.");
47
+ });
48
+
49
+ // ../../apps/cli/src/commands/task.ts
50
+ import { Command as Command2 } from "commander";
51
+ var taskCmd = new Command2("task").description("Manage tasks");
52
+ 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
+ const task = await apiFetch("/tasks", {
54
+ method: "POST",
55
+ headers: { "Content-Type": "application/json" },
56
+ body: JSON.stringify({
57
+ projectId: opts.project,
58
+ title: opts.title,
59
+ description: opts.description,
60
+ complexity: opts.complexity,
61
+ tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : []
62
+ })
63
+ });
64
+ console.log(JSON.stringify(task, null, 2));
65
+ });
66
+ taskCmd.command("list").description("List tasks").option("--project <id>", "filter by project id").action(async (opts) => {
67
+ const query = opts.project ? `?projectId=${opts.project}` : "";
68
+ const tasks = await apiFetch(`/tasks${query}`);
69
+ console.log(JSON.stringify(tasks, null, 2));
70
+ });
71
+ taskCmd.command("run").description("Run a task through the router").argument("<id>", "task id").action(async (id) => {
72
+ const result = await apiFetch(`/tasks/${id}/run`, { method: "POST" });
73
+ console.log(JSON.stringify(result, null, 2));
74
+ });
75
+
76
+ // ../../apps/cli/src/commands/ui.ts
77
+ import { Command as Command3 } from "commander";
78
+ import { spawn } from "child_process";
79
+ import open from "open";
80
+ var uiCmd = new Command3("ui").description("Open the harness web UI").action(async () => {
81
+ const server = spawn("pnpm", ["--filter", "@omega/server", "dev"], {
82
+ stdio: "inherit",
83
+ shell: true
84
+ });
85
+ setTimeout(async () => {
86
+ await open("http://localhost:4000");
87
+ }, 2500);
88
+ server.on("exit", (code) => {
89
+ process.exit(code ?? 0);
90
+ });
91
+ });
92
+
93
+ // ../../apps/cli/src/commands/skill.ts
94
+ import { Command as Command4 } from "commander";
95
+ import path from "path";
96
+ import { fileURLToPath } from "url";
97
+
98
+ // ../skills/src/parse.ts
99
+ import matter from "gray-matter";
100
+ import YAML from "yaml";
101
+ function parseSkill(md) {
102
+ const parsed = matter(md);
103
+ const frontmatter = YAML.parse(parsed.matter || "{}");
104
+ if (typeof frontmatter.name !== "string" || frontmatter.name.trim() === "") {
105
+ throw new Error('SKILL.md frontmatter must include a non-empty "name" string');
106
+ }
107
+ if (typeof frontmatter.description !== "string" || frontmatter.description.trim() === "") {
108
+ throw new Error('SKILL.md frontmatter must include a non-empty "description" string');
109
+ }
110
+ let args = [];
111
+ if ("args" in frontmatter) {
112
+ if (!Array.isArray(frontmatter.args)) {
113
+ throw new Error('SKILL.md frontmatter "args" must be an array');
114
+ }
115
+ args = frontmatter.args.map((entry, index) => {
116
+ if (typeof entry !== "object" || entry === null) {
117
+ throw new Error(`SKILL.md arg at index ${index} must be an object`);
118
+ }
119
+ const arg = entry;
120
+ if (typeof arg.name !== "string" || arg.name.trim() === "") {
121
+ throw new Error(`SKILL.md arg at index ${index} must have a non-empty "name"`);
122
+ }
123
+ if (typeof arg.type !== "string" || arg.type.trim() === "") {
124
+ throw new Error(`SKILL.md arg at index ${index} must have a non-empty "type"`);
125
+ }
126
+ return {
127
+ name: arg.name.trim(),
128
+ type: arg.type.trim(),
129
+ required: typeof arg.required === "boolean" ? arg.required : true,
130
+ description: typeof arg.description === "string" ? arg.description : void 0
131
+ };
132
+ });
133
+ }
134
+ return {
135
+ name: frontmatter.name.trim(),
136
+ description: frontmatter.description.trim(),
137
+ args,
138
+ instructions: parsed.content.trim()
139
+ };
140
+ }
141
+
142
+ // ../skills/src/generate.ts
143
+ function toClassName(name) {
144
+ const normalized = name.replace(/[^a-zA-Z0-9]+/g, " ").trim().split(" ").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
145
+ let className = normalized || "Skill";
146
+ if (/^[0-9]/.test(className)) {
147
+ className = `_${className}`;
148
+ }
149
+ return className;
150
+ }
151
+ function generateAdapter(manifest) {
152
+ const className = toClassName(manifest.name);
153
+ const instructionsLiteral = JSON.stringify(manifest.instructions);
154
+ const descriptionLiteral = JSON.stringify(manifest.description);
155
+ return `import type { Provider } from '@omega/core';
156
+
157
+ export class ${className} {
158
+ constructor(private readonly provider: Provider) {}
159
+
160
+ async execute(args: Record<string, unknown>): Promise<string> {
161
+ const prompt = ${instructionsLiteral} + '\\n\\nArgs:\\n' + JSON.stringify(args, null, 2);
162
+ return this.provider.send(prompt, { system: ${descriptionLiteral} });
163
+ }
164
+ }
165
+ `;
166
+ }
167
+
168
+ // ../skills/src/register.ts
169
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
170
+ import { join } from "node:path";
171
+ async function registerSkill(sourcePath, outputDir) {
172
+ const source = await readFile(sourcePath, "utf-8");
173
+ const manifest = parseSkill(source);
174
+ const generatedDir = join(outputDir, "generated");
175
+ await mkdir(generatedDir, { recursive: true });
176
+ const className = toClassName(manifest.name);
177
+ const fileName = `${className}.ts`;
178
+ const filePath = join(generatedDir, fileName);
179
+ await writeFile(filePath, generateAdapter(manifest), "utf-8");
180
+ const indexPath = join(generatedDir, "index.ts");
181
+ const exportLine = `export * from './${className}.js';
182
+ `;
183
+ let indexContent = "";
184
+ try {
185
+ indexContent = await readFile(indexPath, "utf-8");
186
+ } catch {
187
+ }
188
+ if (!indexContent.includes(exportLine)) {
189
+ await writeFile(indexPath, indexContent + exportLine, "utf-8");
190
+ }
191
+ return manifest;
192
+ }
193
+
194
+ // ../../apps/cli/src/commands/skill.ts
195
+ function getOutputDir() {
196
+ if (process.env.OMEGA_HARNESS_ROOT) {
197
+ return path.join(path.resolve(process.env.OMEGA_HARNESS_ROOT), "packages/skills/src");
198
+ }
199
+ try {
200
+ const __filename = fileURLToPath(import.meta.url);
201
+ const __dirname = path.dirname(__filename);
202
+ return path.join(path.resolve(__dirname, "../../../.."), "packages/skills/src");
203
+ } catch {
204
+ return path.join(process.cwd(), "harness-skills");
205
+ }
206
+ }
207
+ var skillCmd = new Command4("skill").description("Manage skill artifacts");
208
+ skillCmd.command("generate").description("Generate a harness adapter from a SKILL.md file").argument("<source>", "path to SKILL.md").action(async (source) => {
209
+ const outputDir = getOutputDir();
210
+ const manifest = await registerSkill(path.resolve(source), outputDir);
211
+ console.log(`Generated adapter for skill: ${manifest.name}`);
212
+ console.log(`Output directory: ${path.join(outputDir, "generated")}`);
213
+ });
214
+
215
+ // ../../apps/cli/src/index.ts
216
+ program2.name("harness").description("Omega harness CLI").version("0.1.0").option("--api <url>", "API base URL", "http://localhost:4000");
217
+ program2.addCommand(projectCmd);
218
+ program2.addCommand(taskCmd);
219
+ program2.addCommand(uiCmd);
220
+ program2.addCommand(skillCmd);
221
+ program2.parse();
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@castlemilk/omega",
3
+ "version": "0.1.3",
4
+ "description": "Omega Harness CLI - installable via npx",
5
+ "type": "module",
6
+ "main": "./dist/cli.js",
7
+ "bin": {
8
+ "harness": "./dist/cli.js",
9
+ "omega-harness": "./dist/cli.js"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "dependencies": {
15
+ "commander": "^12.1.0",
16
+ "open": "^10.1.0",
17
+ "gray-matter": "^4.0.3",
18
+ "yaml": "^2.4.0"
19
+ },
20
+ "devDependencies": {
21
+ "esbuild": "^0.23.0"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "license": "MIT",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/castlemilk/harness.git"
30
+ },
31
+ "scripts": {
32
+ "build": "esbuild ../../apps/cli/src/index.ts --bundle --platform=node --format=esm --outfile=dist/cli.js --external:commander --external:open --external:gray-matter --external:yaml --alias:@omega/core=../../packages/core/src/index.ts --alias:@omega/skills=../../packages/skills/src/index.ts"
33
+ }
34
+ }