makaron-cli 0.7.7 → 0.7.8
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/README.md +31 -0
- package/SKILL.md +31 -0
- package/bin/makaron.mjs +198 -0
- package/package.json +1 -1
- package/skills/makaron/SKILL.md +31 -0
package/README.md
CHANGED
|
@@ -134,6 +134,37 @@ Outputs one JSON per line as artifacts appear:
|
|
|
134
134
|
{"event":"done","status":"completed"}
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
+
### Dialogue events for external Agents
|
|
138
|
+
|
|
139
|
+
Use this when another Agent needs to read what Makaron said, detect approval requirements, and relay artifacts without inventing customer-service wording.
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
npx makaron-cli responses events <runId> --jsonl
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Events use only three factual types:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{"type":"message","id":"msg_1","runId":"run_xxx","seq":1,"text":"Makaron original message","requires_approval":true,"approval_options":["approve","revise","ask_user","continue"]}
|
|
149
|
+
{"type":"approval","messageId":"msg_1","choice":"approve","status":"recorded"}
|
|
150
|
+
{"type":"artifact","kind":"image","status":"completed","url":"https://..."}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
If a message has `requires_approval: true`, the external Agent must record an approval before continuing to wait for artifacts or claiming completion:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
npx makaron-cli responses approve msg_1 --run <runId> --note "Proceed."
|
|
157
|
+
npx makaron-cli responses revise msg_1 --run <runId> "make it softer"
|
|
158
|
+
npx makaron-cli responses ask-user msg_1 --run <runId>
|
|
159
|
+
npx makaron-cli responses continue msg_1 --run <runId>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Wrappers can enforce this with:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
npx makaron-cli responses events <runId> --jsonl --fail-on-unapproved
|
|
166
|
+
```
|
|
167
|
+
|
|
137
168
|
### Extract specific results
|
|
138
169
|
|
|
139
170
|
```bash
|
package/SKILL.md
CHANGED
|
@@ -126,6 +126,37 @@ Outputs one JSON per line as artifacts appear:
|
|
|
126
126
|
{"event":"done","status":"completed"}
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
+
### Dialogue events for external Agents
|
|
130
|
+
|
|
131
|
+
Use this when another Agent needs to read what Makaron said, detect approval requirements, and relay artifacts without inventing customer-service wording.
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
npx makaron-cli responses events <runId> --jsonl
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Events use only three factual types:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{"type":"message","id":"msg_1","runId":"run_xxx","seq":1,"text":"Makaron original message","requires_approval":true,"approval_options":["approve","revise","ask_user","continue"]}
|
|
141
|
+
{"type":"approval","messageId":"msg_1","choice":"approve","status":"recorded"}
|
|
142
|
+
{"type":"artifact","kind":"image","status":"completed","url":"https://..."}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
If a message has `requires_approval: true`, the external Agent must record an approval before continuing to wait for artifacts or claiming completion:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
npx makaron-cli responses approve msg_1 --run <runId> --note "Proceed."
|
|
149
|
+
npx makaron-cli responses revise msg_1 --run <runId> "make it softer"
|
|
150
|
+
npx makaron-cli responses ask-user msg_1 --run <runId>
|
|
151
|
+
npx makaron-cli responses continue msg_1 --run <runId>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Wrappers can enforce this with:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
npx makaron-cli responses events <runId> --jsonl --fail-on-unapproved
|
|
158
|
+
```
|
|
159
|
+
|
|
129
160
|
### Extract specific results
|
|
130
161
|
|
|
131
162
|
```bash
|
package/bin/makaron.mjs
CHANGED
|
@@ -19,6 +19,7 @@ import { execFileSync } from 'child_process';
|
|
|
19
19
|
// ─── Config ──────────────────────────────────────────────────────────────────
|
|
20
20
|
|
|
21
21
|
const AUTH_FILE = path.join(process.env.HOME || '~', '.makaron', 'auth.json');
|
|
22
|
+
const APPROVALS_FILE = path.join(path.dirname(AUTH_FILE), 'approvals.json');
|
|
22
23
|
const DEFAULT_URL = 'https://www.makaron.app';
|
|
23
24
|
const BASE_URL = process.env.MAKARON_URL || DEFAULT_URL;
|
|
24
25
|
const APP_URL = process.env.MAKARON_APP_URL || DEFAULT_URL;
|
|
@@ -62,6 +63,20 @@ function saveAuth(data) {
|
|
|
62
63
|
fs.writeFileSync(AUTH_FILE, JSON.stringify(data, null, 2));
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
function loadApprovals() {
|
|
67
|
+
try {
|
|
68
|
+
return JSON.parse(fs.readFileSync(APPROVALS_FILE, 'utf-8'));
|
|
69
|
+
} catch {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function saveApprovals(approvals) {
|
|
75
|
+
const dir = path.dirname(APPROVALS_FILE);
|
|
76
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
77
|
+
fs.writeFileSync(APPROVALS_FILE, JSON.stringify(approvals, null, 2));
|
|
78
|
+
}
|
|
79
|
+
|
|
65
80
|
function buildCookie(tokenJson) {
|
|
66
81
|
const url = tokenJson._supabaseUrl || SUPABASE_URL;
|
|
67
82
|
const ref = url.match(/\/\/([^.]+)\./)?.[1] || '';
|
|
@@ -426,6 +441,157 @@ function applyPick(data, field) {
|
|
|
426
441
|
}
|
|
427
442
|
}
|
|
428
443
|
|
|
444
|
+
// ─── Dialogue Events (message / approval / artifact) ─────────────────────────
|
|
445
|
+
|
|
446
|
+
function stableEventId(prefix, runId, seq, fallback) {
|
|
447
|
+
return fallback || `${prefix}_${runId}_${seq ?? Date.now()}`;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function normalizeDialogueMessage(runId, projectId, ev) {
|
|
451
|
+
const data = ev.data || ev;
|
|
452
|
+
const text = data.text || data.message || data.content || data.statusText || '';
|
|
453
|
+
if (!text && ev.type !== 'tool_call') return null;
|
|
454
|
+
const requiresApproval = Boolean(data.requires_approval || data.requiresApproval || data.action_required || data.actionRequired);
|
|
455
|
+
const message = {
|
|
456
|
+
type: 'message',
|
|
457
|
+
id: stableEventId('msg', runId, ev.seq, data.id || ev.id),
|
|
458
|
+
runId,
|
|
459
|
+
projectId,
|
|
460
|
+
seq: ev.seq,
|
|
461
|
+
status: data.status || undefined,
|
|
462
|
+
text: text || `${data.tool || 'tool_call'}${data.input?.description ? `: ${data.input.description}` : ''}`,
|
|
463
|
+
};
|
|
464
|
+
if (ev.type) message.source_type = ev.type;
|
|
465
|
+
if (requiresApproval) {
|
|
466
|
+
message.requires_approval = true;
|
|
467
|
+
message.approval_options = data.approval_options || data.approvalOptions || ['approve', 'revise', 'ask_user', 'continue'];
|
|
468
|
+
}
|
|
469
|
+
if (data.proposal) message.proposal = data.proposal;
|
|
470
|
+
return message;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function normalizeDialogueArtifact(runId, projectId, item, seq) {
|
|
474
|
+
if (!item) return null;
|
|
475
|
+
const kind = item.type || item.kind || (item.imageUrl ? 'image' : item.videoUrl ? 'video' : undefined);
|
|
476
|
+
if (!kind) return null;
|
|
477
|
+
const artifact = {
|
|
478
|
+
type: 'artifact',
|
|
479
|
+
id: stableEventId('artifact', runId, seq, item.id || item.snapshotId || item.taskId),
|
|
480
|
+
runId,
|
|
481
|
+
projectId,
|
|
482
|
+
seq,
|
|
483
|
+
kind,
|
|
484
|
+
status: item.status || (item.url || item.imageUrl || item.videoUrl || item.audioUrl ? 'completed' : 'running'),
|
|
485
|
+
};
|
|
486
|
+
const url = item.url || item.imageUrl || item.videoUrl || item.audioUrl;
|
|
487
|
+
if (url) artifact.url = url;
|
|
488
|
+
if (item.error) artifact.error = item.error;
|
|
489
|
+
if (item.taskId) artifact.taskId = item.taskId;
|
|
490
|
+
if (item.snapshotId) artifact.snapshotId = item.snapshotId;
|
|
491
|
+
return artifact;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function normalizeDialogueEvent(runId, projectId, ev) {
|
|
495
|
+
const data = ev.data || {};
|
|
496
|
+
if (ev.type === 'message' || ev.type === 'approval' || ev.type === 'artifact') {
|
|
497
|
+
return { ...data, ...ev, runId: ev.runId || runId, projectId: ev.projectId || projectId };
|
|
498
|
+
}
|
|
499
|
+
switch (ev.type) {
|
|
500
|
+
case 'content':
|
|
501
|
+
case 'status':
|
|
502
|
+
case 'tool_call':
|
|
503
|
+
case 'error':
|
|
504
|
+
return normalizeDialogueMessage(runId, projectId, ev);
|
|
505
|
+
case 'image':
|
|
506
|
+
return normalizeDialogueArtifact(runId, projectId, { type: 'image', status: data.imageUrl ? 'completed' : 'running', imageUrl: data.imageUrl, snapshotId: data.snapshotId }, ev.seq);
|
|
507
|
+
case 'render':
|
|
508
|
+
return normalizeDialogueArtifact(runId, projectId, { type: data.animation ? 'video' : 'design', status: data.published ? 'completed' : 'running', url: data.url, snapshotId: data.snapshotId }, ev.seq);
|
|
509
|
+
case 'animation_task':
|
|
510
|
+
case 'video_snapshot':
|
|
511
|
+
return normalizeDialogueArtifact(runId, projectId, { type: 'video', status: 'running', taskId: data.taskId, snapshotId: data.snapshotId }, ev.seq);
|
|
512
|
+
case 'music_task':
|
|
513
|
+
return normalizeDialogueArtifact(runId, projectId, { type: 'music', status: 'running', taskId: data.taskId }, ev.seq);
|
|
514
|
+
default:
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function buildDialogueEvents(runId, data) {
|
|
520
|
+
const projectId = data.projectId || data.project_id;
|
|
521
|
+
const events = [];
|
|
522
|
+
for (const ev of data.events || []) {
|
|
523
|
+
const normalized = normalizeDialogueEvent(runId, projectId, ev);
|
|
524
|
+
if (normalized) events.push(normalized);
|
|
525
|
+
}
|
|
526
|
+
for (const item of data.output || []) {
|
|
527
|
+
const normalized = normalizeDialogueArtifact(runId, projectId, item, item.seq);
|
|
528
|
+
if (normalized && !events.some(ev => ev.type === 'artifact' && ev.id === normalized.id)) events.push(normalized);
|
|
529
|
+
}
|
|
530
|
+
for (const approval of loadApprovals().filter(item => item.runId === runId)) {
|
|
531
|
+
events.push(approval);
|
|
532
|
+
}
|
|
533
|
+
return events;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function findUnhandledApprovalMessages(events) {
|
|
537
|
+
const approved = new Set(events.filter(ev => ev.type === 'approval').map(ev => ev.messageId || ev.message_id));
|
|
538
|
+
return events.filter(ev => ev.type === 'message' && ev.requires_approval && !approved.has(ev.id));
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
async function fetchRun(baseUrl, headers, runId, opts = {}) {
|
|
542
|
+
const params = new URLSearchParams();
|
|
543
|
+
if (opts.events) params.set('events', 'true');
|
|
544
|
+
const suffix = params.toString() ? `?${params}` : '';
|
|
545
|
+
const res = await fetch(`${baseUrl}/api/agent/run/${runId}${suffix}`, { headers });
|
|
546
|
+
if (!res.ok) { process.stderr.write(`Error ${res.status}: ${await res.text()}\n`); process.exit(1); }
|
|
547
|
+
return normalizeRunResponse(await res.json());
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
async function printDialogueEvents(baseUrl, headers, runId, opts = {}) {
|
|
551
|
+
const { jsonl = false, failOnUnapproved = false, follow = false, interval = 5000 } = opts;
|
|
552
|
+
const printed = new Set();
|
|
553
|
+
|
|
554
|
+
while (true) {
|
|
555
|
+
const data = await fetchRun(baseUrl, headers, runId, { events: true });
|
|
556
|
+
const events = buildDialogueEvents(runId, data);
|
|
557
|
+
const unhandled = findUnhandledApprovalMessages(events);
|
|
558
|
+
if (failOnUnapproved && unhandled.length) {
|
|
559
|
+
process.stderr.write(`Unhandled Makaron message requires approval: ${unhandled.map(ev => ev.id).join(', ')}\n`);
|
|
560
|
+
process.exit(3);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
const nextEvents = follow ? events.filter(ev => !printed.has(`${ev.type}:${ev.id || ev.seq}`)) : events;
|
|
564
|
+
for (const ev of nextEvents) {
|
|
565
|
+
printed.add(`${ev.type}:${ev.id || ev.seq}`);
|
|
566
|
+
if (jsonl) console.log(JSON.stringify(ev));
|
|
567
|
+
}
|
|
568
|
+
if (!jsonl) console.log(JSON.stringify(nextEvents, null, 2));
|
|
569
|
+
|
|
570
|
+
if (!follow || (!data.incomplete && ['completed', 'failed', 'aborted'].includes(data.status))) {
|
|
571
|
+
if (data.status === 'failed' || data.status === 'aborted') process.exit(1);
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
await new Promise(r => setTimeout(r, data.next_poll_after_ms || interval));
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
function recordApproval(runId, messageId, choice, note) {
|
|
579
|
+
const approvals = loadApprovals();
|
|
580
|
+
const approval = {
|
|
581
|
+
type: 'approval',
|
|
582
|
+
id: `approval_${Date.now()}`,
|
|
583
|
+
runId,
|
|
584
|
+
messageId,
|
|
585
|
+
choice,
|
|
586
|
+
status: 'recorded',
|
|
587
|
+
createdAt: new Date().toISOString(),
|
|
588
|
+
};
|
|
589
|
+
if (note) approval.note = note;
|
|
590
|
+
approvals.push(approval);
|
|
591
|
+
saveApprovals(approvals);
|
|
592
|
+
console.log(JSON.stringify(approval));
|
|
593
|
+
}
|
|
594
|
+
|
|
429
595
|
// ─── Watch (incremental event stream) ───────────────────────────────────────
|
|
430
596
|
|
|
431
597
|
async function watchRun(baseUrl, headers, runId, opts = {}) {
|
|
@@ -1060,6 +1226,32 @@ if (command === '--version' || command === '-v' || command === 'version') {
|
|
|
1060
1226
|
}
|
|
1061
1227
|
await watchRun(baseUrl, headers, runId, { interval, jsonl });
|
|
1062
1228
|
|
|
1229
|
+
} else if (sub === 'events') {
|
|
1230
|
+
const runId = args[2];
|
|
1231
|
+
if (!runId) { console.error('Usage: makaron responses events <runId> [--jsonl] [--follow] [--interval <ms>] [--fail-on-unapproved]'); process.exit(1); }
|
|
1232
|
+
let interval = 5000, jsonl = false, follow = false, failOnUnapproved = false;
|
|
1233
|
+
for (let i = 3; i < args.length; i++) {
|
|
1234
|
+
if (args[i] === '--jsonl') jsonl = true;
|
|
1235
|
+
else if (args[i] === '--follow') follow = true;
|
|
1236
|
+
else if (args[i] === '--fail-on-unapproved') failOnUnapproved = true;
|
|
1237
|
+
else if (args[i] === '--interval' && args[i + 1]) interval = parseInt(args[++i]);
|
|
1238
|
+
}
|
|
1239
|
+
await printDialogueEvents(baseUrl, headers, runId, { interval, jsonl, follow, failOnUnapproved });
|
|
1240
|
+
|
|
1241
|
+
} else if (['approve', 'revise', 'ask-user', 'continue'].includes(sub)) {
|
|
1242
|
+
const messageId = args[2];
|
|
1243
|
+
if (!messageId) { console.error(`Usage: makaron responses ${sub} <messageId> --run <runId> [--note <text>]`); process.exit(1); }
|
|
1244
|
+
let runId = null, note = null;
|
|
1245
|
+
const noteParts = [];
|
|
1246
|
+
for (let i = 3; i < args.length; i++) {
|
|
1247
|
+
if (args[i] === '--run' && args[i + 1]) runId = args[++i];
|
|
1248
|
+
else if (args[i] === '--note' && args[i + 1]) note = args[++i];
|
|
1249
|
+
else noteParts.push(args[i]);
|
|
1250
|
+
}
|
|
1251
|
+
if (!runId) { console.error(`Usage: makaron responses ${sub} <messageId> --run <runId> [--note <text>]`); process.exit(1); }
|
|
1252
|
+
if (!note && noteParts.length) note = noteParts.join(' ');
|
|
1253
|
+
recordApproval(runId, messageId, sub === 'ask-user' ? 'ask_user' : sub, note);
|
|
1254
|
+
|
|
1063
1255
|
} else if (sub === 'list') {
|
|
1064
1256
|
let projectId = null;
|
|
1065
1257
|
for (let i = 2; i < args.length; i++) {
|
|
@@ -1083,6 +1275,11 @@ if (command === '--version' || command === '-v' || command === 'version') {
|
|
|
1083
1275
|
responses get <runId> Get status and output (JSON)
|
|
1084
1276
|
responses get <runId> --wait Poll until completed
|
|
1085
1277
|
responses get <runId> --pick <field> Extract: first_image_url, first_video_url, project_url, output
|
|
1278
|
+
responses events <runId> --jsonl Emit message/approval/artifact events for external Agents
|
|
1279
|
+
responses approve <messageId> --run <runId> Record approval for a Makaron message
|
|
1280
|
+
responses revise <messageId> --run <runId> Record revision request for a Makaron message
|
|
1281
|
+
responses ask-user <messageId> --run <runId> Record that the user must decide
|
|
1282
|
+
responses continue <messageId> --run <runId> Record continue decision
|
|
1086
1283
|
responses watch <runId> --jsonl Watch until done (incremental events)
|
|
1087
1284
|
responses list --project <id> List runs for a project
|
|
1088
1285
|
`);
|
|
@@ -1520,6 +1717,7 @@ Commands:
|
|
|
1520
1717
|
|
|
1521
1718
|
responses get <runId> Get run status and results
|
|
1522
1719
|
responses get <runId> --wait Poll until completed
|
|
1720
|
+
responses events <runId> --jsonl Emit message/approval/artifact events
|
|
1523
1721
|
responses list --project <id> List runs for a project
|
|
1524
1722
|
abort <runId> Abort a running Agent
|
|
1525
1723
|
|
package/package.json
CHANGED
package/skills/makaron/SKILL.md
CHANGED
|
@@ -126,6 +126,37 @@ Outputs one JSON per line as artifacts appear:
|
|
|
126
126
|
{"event":"done","status":"completed"}
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
+
### Dialogue events for external Agents
|
|
130
|
+
|
|
131
|
+
Use this when another Agent needs to read what Makaron said, detect approval requirements, and relay artifacts without inventing customer-service wording.
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
npx makaron-cli responses events <runId> --jsonl
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Events use only three factual types:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{"type":"message","id":"msg_1","runId":"run_xxx","seq":1,"text":"Makaron original message","requires_approval":true,"approval_options":["approve","revise","ask_user","continue"]}
|
|
141
|
+
{"type":"approval","messageId":"msg_1","choice":"approve","status":"recorded"}
|
|
142
|
+
{"type":"artifact","kind":"image","status":"completed","url":"https://..."}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
If a message has `requires_approval: true`, the external Agent must record an approval before continuing to wait for artifacts or claiming completion:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
npx makaron-cli responses approve msg_1 --run <runId> --note "Proceed."
|
|
149
|
+
npx makaron-cli responses revise msg_1 --run <runId> "make it softer"
|
|
150
|
+
npx makaron-cli responses ask-user msg_1 --run <runId>
|
|
151
|
+
npx makaron-cli responses continue msg_1 --run <runId>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Wrappers can enforce this with:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
npx makaron-cli responses events <runId> --jsonl --fail-on-unapproved
|
|
158
|
+
```
|
|
159
|
+
|
|
129
160
|
### Extract specific results
|
|
130
161
|
|
|
131
162
|
```bash
|