@opencomputer/cli 0.6.6 → 0.6.7

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.
@@ -0,0 +1,326 @@
1
+ import { readFile, stat } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ import { buildAgentArtifact, readProjectAgents, readProjectResources, } from "./project.js";
4
+ const TEMPLATE_FILE = "oc-template.toml";
5
+ const MAX_TEMPLATE_BYTES = 64 * 1024;
6
+ const PROJECT_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
7
+ const REQUIREMENT_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_]{0,127}$/;
8
+ function fail(message, line) {
9
+ throw new Error(`${TEMPLATE_FILE}${line ? `:${line}` : ""}: ${message}`);
10
+ }
11
+ function parseString(value, line) {
12
+ if (!value.startsWith('"'))
13
+ fail("values must be strings or booleans", line);
14
+ try {
15
+ const parsed = JSON.parse(value);
16
+ if (typeof parsed !== "string")
17
+ fail("expected a string", line);
18
+ return parsed;
19
+ }
20
+ catch (error) {
21
+ if (error instanceof Error && error.message.startsWith(TEMPLATE_FILE)) {
22
+ throw error;
23
+ }
24
+ return fail("invalid quoted string", line);
25
+ }
26
+ }
27
+ function parseScalar(value, line) {
28
+ if (value === "true")
29
+ return true;
30
+ if (value === "false")
31
+ return false;
32
+ if (/^[0-9]+$/.test(value))
33
+ return Number(value);
34
+ return parseString(value, line);
35
+ }
36
+ function parseFlatToml(source) {
37
+ const values = new Map();
38
+ const sections = new Set();
39
+ let section = "";
40
+ for (const [index, original] of source.split(/\r?\n/).entries()) {
41
+ const line = index + 1;
42
+ const trimmed = original.trim();
43
+ if (!trimmed || trimmed.startsWith("#"))
44
+ continue;
45
+ const sectionMatch = trimmed.match(/^\[([^\]]+)\]$/);
46
+ if (sectionMatch) {
47
+ section = sectionMatch[1].trim();
48
+ if (!section)
49
+ fail("empty table name", line);
50
+ const dynamicSection = section.match(/^template\.(secrets|runtime_variables|connections)\.([A-Za-z][A-Za-z0-9_]{0,127})$/);
51
+ if (section !== "template" &&
52
+ section !== "template.first_run" &&
53
+ !dynamicSection) {
54
+ fail(`unknown table ${section}`, line);
55
+ }
56
+ if (sections.has(section))
57
+ fail(`duplicate table ${section}`, line);
58
+ sections.add(section);
59
+ continue;
60
+ }
61
+ const assignment = trimmed.match(/^([A-Za-z0-9_-]+)\s*=\s*(.+)$/);
62
+ if (!assignment)
63
+ fail("unsupported TOML syntax", line);
64
+ const key = section ? `${section}.${assignment[1]}` : assignment[1];
65
+ if (values.has(key))
66
+ fail(`duplicate field ${key}`, line);
67
+ values.set(key, { value: parseScalar(assignment[2].trim(), line), line });
68
+ }
69
+ return values;
70
+ }
71
+ function stringField(values, key, required = false) {
72
+ const entry = values.get(key);
73
+ if (!entry) {
74
+ if (required)
75
+ fail(`missing required field ${key}`);
76
+ return undefined;
77
+ }
78
+ if (typeof entry.value !== "string" || !entry.value.trim()) {
79
+ fail(`${key} must be a non-empty string`, entry.line);
80
+ }
81
+ return entry.value;
82
+ }
83
+ function httpsField(values, key) {
84
+ const value = stringField(values, key);
85
+ if (!value)
86
+ return undefined;
87
+ let parsed;
88
+ try {
89
+ parsed = new URL(value);
90
+ }
91
+ catch {
92
+ return fail(`${key} must be an HTTPS URL`, values.get(key)?.line);
93
+ }
94
+ if (parsed.protocol !== "https:") {
95
+ fail(`${key} must be an HTTPS URL`, values.get(key)?.line);
96
+ }
97
+ return value;
98
+ }
99
+ function annotations(values, prefix, runtimeVariable) {
100
+ const result = {};
101
+ for (const [key, entry] of values) {
102
+ if (!key.startsWith(`${prefix}.`))
103
+ continue;
104
+ const remainder = key.slice(prefix.length + 1);
105
+ const separator = remainder.lastIndexOf(".");
106
+ if (separator < 1)
107
+ fail(`invalid requirement field ${key}`, entry.line);
108
+ const name = remainder.slice(0, separator);
109
+ const field = remainder.slice(separator + 1);
110
+ if (!REQUIREMENT_NAME_PATTERN.test(name)) {
111
+ fail(`invalid requirement name ${name}`, entry.line);
112
+ }
113
+ const allowed = runtimeVariable
114
+ ? ["description", "documentation", "required", "example"]
115
+ : ["description", "documentation", "required"];
116
+ if (!allowed.includes(field))
117
+ fail(`unknown field ${key}`, entry.line);
118
+ const target = (result[name] ??= {});
119
+ if (field === "required") {
120
+ if (typeof entry.value !== "boolean") {
121
+ fail(`${key} must be a boolean`, entry.line);
122
+ }
123
+ target.required = entry.value;
124
+ }
125
+ else {
126
+ if (typeof entry.value !== "string" || !entry.value.trim()) {
127
+ fail(`${key} must be a non-empty string`, entry.line);
128
+ }
129
+ if (field === "documentation") {
130
+ httpsField(values, key);
131
+ }
132
+ target[field] =
133
+ entry.value;
134
+ }
135
+ }
136
+ return result;
137
+ }
138
+ export function parseTemplateManifest(source) {
139
+ if (Buffer.byteLength(source, "utf8") > MAX_TEMPLATE_BYTES) {
140
+ fail(`file exceeds ${MAX_TEMPLATE_BYTES} bytes`);
141
+ }
142
+ const values = parseFlatToml(source);
143
+ const knownExact = new Set([
144
+ "schema",
145
+ "template.name",
146
+ "template.description",
147
+ "template.documentation",
148
+ "template.default_project_name",
149
+ "template.first_run.agent",
150
+ "template.first_run.prompt",
151
+ ]);
152
+ const knownPrefixes = [
153
+ "template.secrets.",
154
+ "template.runtime_variables.",
155
+ "template.connections.",
156
+ ];
157
+ for (const [key, entry] of values) {
158
+ if (!knownExact.has(key) &&
159
+ !knownPrefixes.some((prefix) => key.startsWith(prefix))) {
160
+ fail(`unknown field ${key}`, entry.line);
161
+ }
162
+ }
163
+ const schema = values.get("schema");
164
+ if (schema?.value !== 1)
165
+ fail("schema must be 1", schema?.line);
166
+ const name = stringField(values, "template.name", true);
167
+ const description = stringField(values, "template.description", true);
168
+ const documentation = httpsField(values, "template.documentation");
169
+ const defaultProjectName = stringField(values, "template.default_project_name");
170
+ if (defaultProjectName && !PROJECT_NAME_PATTERN.test(defaultProjectName)) {
171
+ fail("template.default_project_name must use lowercase letters, numbers, and single hyphens", values.get("template.default_project_name")?.line);
172
+ }
173
+ const firstRunAgent = stringField(values, "template.first_run.agent");
174
+ const firstRunPrompt = stringField(values, "template.first_run.prompt");
175
+ if (Boolean(firstRunAgent) !== Boolean(firstRunPrompt)) {
176
+ fail("template.first_run.agent and template.first_run.prompt must be provided together");
177
+ }
178
+ return {
179
+ schema: 1,
180
+ template: {
181
+ name,
182
+ description,
183
+ ...(documentation ? { documentation } : {}),
184
+ ...(defaultProjectName ? { defaultProjectName } : {}),
185
+ ...(firstRunAgent && firstRunPrompt
186
+ ? { firstRun: { agent: firstRunAgent, prompt: firstRunPrompt } }
187
+ : {}),
188
+ secrets: annotations(values, "template.secrets", false),
189
+ runtimeVariables: annotations(values, "template.runtime_variables", true),
190
+ connections: annotations(values, "template.connections", false),
191
+ },
192
+ };
193
+ }
194
+ export async function readTemplateManifest(root = process.cwd()) {
195
+ const path = resolve(root, TEMPLATE_FILE);
196
+ const metadata = await stat(path).catch(() => undefined);
197
+ if (!metadata?.isFile())
198
+ fail(`expected a regular file at ${path}`);
199
+ if (metadata.size > MAX_TEMPLATE_BYTES)
200
+ fail(`file exceeds ${MAX_TEMPLATE_BYTES} bytes`);
201
+ return parseTemplateManifest(await readFile(path, "utf8"));
202
+ }
203
+ export async function buildTemplateProject(root = process.cwd()) {
204
+ const template = await readTemplateManifest(root);
205
+ const sources = await readProjectAgents(root);
206
+ const projectResources = await readProjectResources(root);
207
+ const artifacts = [];
208
+ const secretRequirements = new Map();
209
+ const compiledConnections = new Set();
210
+ for (const source of sources) {
211
+ const built = await buildAgentArtifact(source.root);
212
+ artifacts.push({
213
+ localAgentId: source.localId,
214
+ name: built.name,
215
+ digest: built.digest,
216
+ size: built.body.byteLength,
217
+ contentType: "application/vnd.opencomputer.agent+json",
218
+ body: built.body.toString("utf8"),
219
+ connections: built.connections,
220
+ httpConnections: built.httpConnections,
221
+ });
222
+ for (const connection of built.connections)
223
+ compiledConnections.add(connection);
224
+ for (const connection of built.httpConnections) {
225
+ compiledConnections.add(connection.id);
226
+ for (const header of Object.values(connection.headers)) {
227
+ if (typeof header === "string")
228
+ continue;
229
+ const key = `${source.localId}:${header.name}`;
230
+ const annotation = template.template.secrets[header.name];
231
+ const requirement = secretRequirements.get(key) ?? {
232
+ name: header.name,
233
+ ...(annotation?.description
234
+ ? { description: annotation.description }
235
+ : {}),
236
+ ...(annotation?.documentation
237
+ ? { documentation: annotation.documentation }
238
+ : {}),
239
+ required: annotation?.required ?? true,
240
+ localAgentId: source.localId,
241
+ allowedOrigins: new Set(),
242
+ };
243
+ requirement.allowedOrigins.add(connection.origin);
244
+ secretRequirements.set(key, requirement);
245
+ }
246
+ }
247
+ }
248
+ const compiledSecretNames = new Set([...secretRequirements.values()].map((requirement) => requirement.name));
249
+ for (const name of Object.keys(template.template.secrets)) {
250
+ if (!compiledSecretNames.has(name)) {
251
+ throw new Error(`${TEMPLATE_FILE}: template.secrets.${name} is not referenced by a compiled connection`);
252
+ }
253
+ }
254
+ for (const id of Object.keys(template.template.connections)) {
255
+ if (!compiledConnections.has(id)) {
256
+ throw new Error(`${TEMPLATE_FILE}: template.connections.${id} is not present in the compiled project`);
257
+ }
258
+ }
259
+ if (template.template.firstRun &&
260
+ !sources.some((source) => source.localId === template.template.firstRun?.agent)) {
261
+ throw new Error(`${TEMPLATE_FILE}: template.first_run.agent does not name a project agent`);
262
+ }
263
+ return {
264
+ schema: 1,
265
+ template: template.template,
266
+ agents: sources.map((source) => ({
267
+ id: source.localId,
268
+ name: source.manifest.name,
269
+ })),
270
+ artifacts,
271
+ resources: projectResources.manifest,
272
+ requirements: {
273
+ secrets: [...secretRequirements.values()].map((requirement) => ({
274
+ ...requirement,
275
+ allowedOrigins: [...requirement.allowedOrigins].sort(),
276
+ })),
277
+ runtimeVariables: Object.entries(template.template.runtimeVariables).map(([name, requirement]) => ({
278
+ name,
279
+ ...(requirement.description
280
+ ? { description: requirement.description }
281
+ : {}),
282
+ ...(requirement.documentation
283
+ ? { documentation: requirement.documentation }
284
+ : {}),
285
+ required: requirement.required ?? false,
286
+ ...(requirement.example ? { example: requirement.example } : {}),
287
+ })),
288
+ connections: Object.entries(template.template.connections).map(([id, requirement]) => ({
289
+ id,
290
+ ...(requirement.description
291
+ ? { description: requirement.description }
292
+ : {}),
293
+ })),
294
+ },
295
+ };
296
+ }
297
+ export function normalizeTemplateRepositoryUrl(value) {
298
+ let url;
299
+ try {
300
+ url = new URL(value);
301
+ }
302
+ catch {
303
+ throw new Error("Repository URL must be https://github.com/<owner>/<repository>");
304
+ }
305
+ const parts = url.pathname.split("/").filter(Boolean);
306
+ if (url.protocol !== "https:" ||
307
+ url.hostname.toLowerCase() !== "github.com" ||
308
+ url.username ||
309
+ url.password ||
310
+ url.port ||
311
+ url.search ||
312
+ url.hash ||
313
+ parts.length !== 2 ||
314
+ !/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})$/.test(parts[0]) ||
315
+ !/^[A-Za-z0-9._-]+$/.test(parts[1]) ||
316
+ parts[1].endsWith(".git")) {
317
+ throw new Error("Repository URL must be https://github.com/<owner>/<repository> without a ref or query");
318
+ }
319
+ return `https://github.com/${parts[0]}/${parts[1]}`;
320
+ }
321
+ export function templateDeployUrl(repositoryUrl, appUrl = "https://app.opencomputer.dev") {
322
+ const target = new URL("/new", appUrl);
323
+ target.searchParams.set("repository-url", normalizeTemplateRepositoryUrl(repositoryUrl));
324
+ return target.toString();
325
+ }
326
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,109 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { resolve } from "node:path";
5
+ import test from "node:test";
6
+ import { buildTemplateProject, normalizeTemplateRepositoryUrl, parseTemplateManifest, templateDeployUrl, } from "./template.js";
7
+ import { initializeAgentProject } from "./project.js";
8
+ const example = `schema = 1
9
+
10
+ [template]
11
+ name = "GitHub Actions Triage"
12
+ description = "Investigate failed workflows."
13
+ documentation = "https://github.com/diggerhq/example"
14
+ default_project_name = "github-actions-triage"
15
+
16
+ [template.first_run]
17
+ agent = "triage"
18
+ prompt = "Inspect the latest failed workflow."
19
+
20
+ [template.secrets.GITHUB_TOKEN]
21
+ description = "Fine-grained token."
22
+
23
+ [template.runtime_variables.GITHUB_REPOSITORY]
24
+ description = "Repository in owner/name form."
25
+ required = true
26
+ example = "diggerhq/opencomputer"
27
+
28
+ [template.connections.github]
29
+ description = "Connect GitHub."
30
+ `;
31
+ test("parses the v1 template contract", () => {
32
+ assert.deepEqual(parseTemplateManifest(example), {
33
+ schema: 1,
34
+ template: {
35
+ name: "GitHub Actions Triage",
36
+ description: "Investigate failed workflows.",
37
+ documentation: "https://github.com/diggerhq/example",
38
+ defaultProjectName: "github-actions-triage",
39
+ firstRun: {
40
+ agent: "triage",
41
+ prompt: "Inspect the latest failed workflow.",
42
+ },
43
+ secrets: { GITHUB_TOKEN: { description: "Fine-grained token." } },
44
+ runtimeVariables: {
45
+ GITHUB_REPOSITORY: {
46
+ description: "Repository in owner/name form.",
47
+ required: true,
48
+ example: "diggerhq/opencomputer",
49
+ },
50
+ },
51
+ connections: { github: { description: "Connect GitHub." } },
52
+ },
53
+ });
54
+ });
55
+ test("rejects unknown fields and incomplete first-run metadata", () => {
56
+ assert.throws(() => parseTemplateManifest(`${example}\n[template.unsafe]\n`), /unknown table template\.unsafe/);
57
+ assert.throws(() => parseTemplateManifest(example.replace('description = "Investigate failed workflows."', 'description = "Investigate failed workflows."\nunsafe = "yes"')), /unknown field template\.unsafe/);
58
+ assert.throws(() => parseTemplateManifest(`schema = 1\n[template]\nname = "A"\ndescription = "B"\n[template.first_run]\nagent = "a"\n`), /must be provided together/);
59
+ });
60
+ test("requires HTTPS documentation URLs", () => {
61
+ assert.throws(() => parseTemplateManifest(example.replace("https://github.com", "http://github.com")), /must be an HTTPS URL/);
62
+ });
63
+ test("normalizes only root GitHub repository URLs", () => {
64
+ assert.equal(normalizeTemplateRepositoryUrl("https://github.com/diggerhq/opencomputer"), "https://github.com/diggerhq/opencomputer");
65
+ for (const invalid of [
66
+ "https://gitlab.com/diggerhq/opencomputer",
67
+ "https://github.com/diggerhq/opencomputer/tree/main",
68
+ "https://github.com/diggerhq/opencomputer.git",
69
+ "https://github.com/diggerhq/opencomputer?ref=main",
70
+ ]) {
71
+ assert.throws(() => normalizeTemplateRepositoryUrl(invalid), /Repository URL/);
72
+ }
73
+ });
74
+ test("builds the canonical dashboard handoff without a ref", () => {
75
+ assert.equal(templateDeployUrl("https://github.com/diggerhq/opencomputer"), "https://app.opencomputer.dev/new?repository-url=https%3A%2F%2Fgithub.com%2Fdiggerhq%2Fopencomputer");
76
+ });
77
+ test("builds reusable project artifacts without customer configuration", async () => {
78
+ const parent = await mkdtemp(resolve(tmpdir(), "opencomputer-template-build-"));
79
+ try {
80
+ const initialized = await initializeAgentProject(resolve(parent, "app"));
81
+ await writeFile(resolve(initialized.root, "oc-template.toml"), `schema = 1
82
+ [template]
83
+ name = "Hello template"
84
+ description = "A reusable hello-world project."
85
+ default_project_name = "hello-template"
86
+ [template.first_run]
87
+ agent = "hello-world"
88
+ prompt = "Say hello."
89
+ `);
90
+ const bundle = await buildTemplateProject(initialized.root);
91
+ assert.equal(bundle.schema, 1);
92
+ assert.equal(bundle.template.name, "Hello template");
93
+ assert.deepEqual(bundle.agents, [
94
+ { id: "hello-world", name: "Hello World" },
95
+ ]);
96
+ assert.equal(bundle.artifacts.length, 1);
97
+ assert.match(bundle.artifacts[0].digest, /^[0-9a-f]{64}$/);
98
+ assert.ok(bundle.artifacts[0].size > 0);
99
+ assert.deepEqual(bundle.requirements, {
100
+ secrets: [],
101
+ runtimeVariables: [],
102
+ connections: [],
103
+ });
104
+ }
105
+ finally {
106
+ await rm(parent, { recursive: true, force: true });
107
+ }
108
+ });
109
+ //# sourceMappingURL=template.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.test.js","sourceRoot":"","sources":["../src/template.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencomputer/cli",
3
- "version": "0.6.6",
3
+ "version": "0.6.7",
4
4
  "description": "Build, test, deploy, and share OpenComputer agents as code.",
5
5
  "type": "module",
6
6
  "bin": {