opencara 0.100.2 → 0.101.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.
Files changed (2) hide show
  1. package/dist/bin.js +153 -16
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -12,9 +12,7 @@ import {
12
12
  totalmem,
13
13
  uptime
14
14
  } from "node:os";
15
- import { readFileSync as readFileSync2, statfsSync } from "node:fs";
16
- import { dirname, join as join2 } from "node:path";
17
- import { fileURLToPath } from "node:url";
15
+ import { statfsSync } from "node:fs";
18
16
 
19
17
  // src/config/store.ts
20
18
  import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from "node:fs";
@@ -179,16 +177,47 @@ var HelloAckSchema = z4.object({
179
177
  });
180
178
  var PingSchema = z4.object({ type: z4.literal("ping") });
181
179
  var PongSchema = z4.object({ type: z4.literal("pong") });
180
+ var AgentCallEnvelope = {
181
+ type: z4.literal("agent-call"),
182
+ runId: z4.string(),
183
+ callId: z4.string()
184
+ };
185
+ var IssueBodySetCallSchema = z4.object({
186
+ ...AgentCallEnvelope,
187
+ kind: z4.literal("issue.body.set"),
188
+ issueNumber: z4.number().int(),
189
+ bodyMd: z4.string()
190
+ });
191
+ var FlowNodeConfigSetCallSchema = z4.object({
192
+ ...AgentCallEnvelope,
193
+ kind: z4.literal("flow.node.config.set"),
194
+ flowSlug: z4.string().min(1),
195
+ nodeId: z4.string().min(1),
196
+ config: z4.record(z4.string(), z4.unknown())
197
+ });
198
+ var TemplateNodeConfigSetCallSchema = z4.object({
199
+ ...AgentCallEnvelope,
200
+ kind: z4.literal("template.node.config.set"),
201
+ templateSlug: z4.string().min(1),
202
+ nodeId: z4.string().min(1),
203
+ config: z4.record(z4.string(), z4.unknown())
204
+ });
205
+ var AgentCallSchema = z4.discriminatedUnion("kind", [
206
+ IssueBodySetCallSchema,
207
+ FlowNodeConfigSetCallSchema,
208
+ TemplateNodeConfigSetCallSchema
209
+ ]);
182
210
  var ServerToDeviceMessageSchema = z4.discriminatedUnion("type", [
183
211
  JobAssignmentSchema,
184
212
  HelloAckSchema,
185
213
  PingSchema
186
214
  ]);
187
- var DeviceToServerMessageSchema = z4.discriminatedUnion("type", [
215
+ var DeviceToServerMessageSchema = z4.union([
188
216
  HelloMessageSchema,
189
217
  LogFrameSchema,
190
218
  RunDoneSchema,
191
- PongSchema
219
+ PongSchema,
220
+ AgentCallSchema
192
221
  ]);
193
222
  var HostRegisterRequestSchema = z4.object({
194
223
  hostId: z4.string(),
@@ -201,6 +230,36 @@ var HostRegisterResponseSchema = z4.object({
201
230
  pollIntervalMs: z4.number().int().positive()
202
231
  });
203
232
 
233
+ // ../shared/dist/issues.js
234
+ import { z as z5 } from "zod";
235
+ var IssueLabelSchema = z5.object({
236
+ name: z5.string(),
237
+ color: z5.string()
238
+ });
239
+ var IssueAssigneeSchema = z5.object({
240
+ login: z5.string(),
241
+ id: z5.number()
242
+ });
243
+ var IssueSummarySchema = z5.object({
244
+ id: z5.string(),
245
+ number: z5.number().int(),
246
+ title: z5.string(),
247
+ state: z5.string(),
248
+ stateReason: z5.string().nullable(),
249
+ labels: z5.array(IssueLabelSchema),
250
+ assignees: z5.array(IssueAssigneeSchema),
251
+ authorLogin: z5.string().nullable(),
252
+ htmlUrl: z5.string(),
253
+ createdAt: z5.string().datetime(),
254
+ updatedAt: z5.string().datetime(),
255
+ closedAt: z5.string().datetime().nullable()
256
+ });
257
+ var IssueDetailSchema = IssueSummarySchema.extend({
258
+ bodyMd: z5.string().nullable(),
259
+ draftBodyMd: z5.string().nullable(),
260
+ draftUpdatedAt: z5.string().datetime().nullable()
261
+ });
262
+
204
263
  // src/commands/register.ts
205
264
  var POLL_INTERVAL_MS = 2e3;
206
265
  async function register(opts = {}) {
@@ -368,9 +427,72 @@ function runJob(spec, stdinJson, handlers) {
368
427
  });
369
428
  }
370
429
 
430
+ // src/runner/agentCallParser.ts
431
+ import { z as z6 } from "zod";
432
+ var MAX_BUFFER_BYTES = 64 * 1024;
433
+ var FENCE_RE = /```opencara-call\r?\n([\s\S]*?)\r?\n```/;
434
+ var VARIANT_SCHEMAS = {
435
+ "issue.body.set": IssueBodySetCallSchema.omit({ type: true, runId: true }),
436
+ "flow.node.config.set": FlowNodeConfigSetCallSchema.omit({
437
+ type: true,
438
+ runId: true
439
+ }),
440
+ "template.node.config.set": TemplateNodeConfigSetCallSchema.omit({
441
+ type: true,
442
+ runId: true
443
+ })
444
+ };
445
+ var KindSchema = z6.enum([
446
+ "issue.body.set",
447
+ "flow.node.config.set",
448
+ "template.node.config.set"
449
+ ]);
450
+ var AgentCallParser = class {
451
+ constructor(emit) {
452
+ this.emit = emit;
453
+ }
454
+ emit;
455
+ buffer = "";
456
+ feed(chunk) {
457
+ this.buffer += chunk;
458
+ if (this.buffer.length > MAX_BUFFER_BYTES) {
459
+ const cutoff = Math.floor(MAX_BUFFER_BYTES / 2);
460
+ const nl = this.buffer.indexOf("\n", this.buffer.length - cutoff);
461
+ this.buffer = nl >= 0 ? this.buffer.slice(nl + 1) : this.buffer.slice(-cutoff);
462
+ }
463
+ while (true) {
464
+ const m = FENCE_RE.exec(this.buffer);
465
+ if (!m) break;
466
+ const inner = m[1] ?? "";
467
+ const consumedTo = m.index + m[0].length;
468
+ this.buffer = this.buffer.slice(consumedTo);
469
+ this.tryEmit(inner);
470
+ }
471
+ }
472
+ tryEmit(inner) {
473
+ let parsed;
474
+ try {
475
+ parsed = JSON.parse(inner);
476
+ } catch {
477
+ return;
478
+ }
479
+ if (!parsed || typeof parsed !== "object") return;
480
+ const raw = parsed;
481
+ const kindResult = KindSchema.safeParse(raw.kind);
482
+ if (!kindResult.success) return;
483
+ const withCallId = {
484
+ ...raw,
485
+ callId: typeof raw.callId === "string" && raw.callId.length > 0 ? raw.callId : `call_${Date.now().toString(36)}`
486
+ };
487
+ const schema = VARIANT_SCHEMAS[kindResult.data];
488
+ const result = schema.safeParse(withCallId);
489
+ if (!result.success) return;
490
+ this.emit(result.data);
491
+ }
492
+ };
493
+
371
494
  // src/commands/run.ts
372
- var __dirname = dirname(fileURLToPath(import.meta.url));
373
- var PKG_VERSION = readPkgVersion();
495
+ var PKG_VERSION = "0.101.0";
374
496
  var LOG_FLUSH_MS = 800;
375
497
  var MAX_CHUNK_SIZE = 4 * 1024;
376
498
  async function run(opts = {}) {
@@ -390,7 +512,12 @@ async function run(opts = {}) {
390
512
  type: "hello",
391
513
  platform: platform(),
392
514
  version: PKG_VERSION,
393
- capabilities: [],
515
+ // Advertise the new opencara-call stdout protocol so the
516
+ // server can later gate the skill prompt to capable CLIs.
517
+ // Older CLIs without this capability would still be sent the
518
+ // skill markdown today (it doesn't crash; the fenced block
519
+ // just shows up in stdout unparsed).
520
+ capabilities: ["agent-call"],
394
521
  systemInfo: collectSystemInfo()
395
522
  });
396
523
  },
@@ -436,11 +563,29 @@ async function executeJob(job, client) {
436
563
  if (flushTimer) return;
437
564
  flushTimer = setTimeout(flush, LOG_FLUSH_MS);
438
565
  };
566
+ const callParser = new AgentCallParser((call) => {
567
+ switch (call.kind) {
568
+ case "issue.body.set":
569
+ client.send({ type: "agent-call", runId, ...call });
570
+ return;
571
+ case "flow.node.config.set":
572
+ client.send({ type: "agent-call", runId, ...call });
573
+ return;
574
+ case "template.node.config.set":
575
+ client.send({ type: "agent-call", runId, ...call });
576
+ return;
577
+ default: {
578
+ const exhaustive = call;
579
+ void exhaustive;
580
+ }
581
+ }
582
+ });
439
583
  try {
440
584
  const result = await runJob(job.spec, job.stdinJson, {
441
585
  onLog: (stream, chunk) => {
442
586
  pending[stream] += chunk;
443
587
  scheduleFlush();
588
+ if (stream === "stdout") callParser.feed(chunk);
444
589
  }
445
590
  });
446
591
  flush();
@@ -458,14 +603,6 @@ async function executeJob(job, client) {
458
603
  console.error(`[opencara] job ${runId.slice(-8)} failed`, message);
459
604
  }
460
605
  }
461
- function readPkgVersion() {
462
- try {
463
- const raw = readFileSync2(join2(__dirname, "..", "..", "package.json"), "utf8");
464
- return JSON.parse(raw).version ?? "0.0.0";
465
- } catch {
466
- return "0.0.0";
467
- }
468
- }
469
606
  function collectSystemInfo() {
470
607
  try {
471
608
  const cpuList = cpus();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencara",
3
- "version": "0.100.2",
3
+ "version": "0.101.0",
4
4
  "description": "OpenCara agent-host CLI: register a machine as an agent host and run dispatched agents.",
5
5
  "license": "MIT",
6
6
  "repository": {