@mutagent/cli 0.1.196 → 0.1.198
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/bin/cli.js +262 -617
- package/dist/bin/cli.js.map +13 -13
- package/dist/index.js +1 -566
- package/dist/index.js.map +5 -6
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -317,125 +317,6 @@ var init_errors = __esm(() => {
|
|
|
317
317
|
};
|
|
318
318
|
});
|
|
319
319
|
|
|
320
|
-
// src/lib/scorecard-extraction.ts
|
|
321
|
-
function extractScorecardDetails(rawState, iterCtx) {
|
|
322
|
-
if (!iterCtx)
|
|
323
|
-
return {};
|
|
324
|
-
const gc = rawState.globalContext;
|
|
325
|
-
const gcCtx = gc?.context;
|
|
326
|
-
const beforeExec = gcCtx?.executions;
|
|
327
|
-
const beforeResults = beforeExec?.results ?? [];
|
|
328
|
-
const beforeById = new Map;
|
|
329
|
-
for (const r of beforeResults) {
|
|
330
|
-
const id = r.id;
|
|
331
|
-
if (id)
|
|
332
|
-
beforeById.set(id, r);
|
|
333
|
-
}
|
|
334
|
-
let originalScore;
|
|
335
|
-
if (beforeResults.length > 0) {
|
|
336
|
-
const sum = beforeResults.reduce((acc, r) => {
|
|
337
|
-
const eval_ = r.evaluation;
|
|
338
|
-
return acc + (eval_?.score ?? 0);
|
|
339
|
-
}, 0);
|
|
340
|
-
originalScore = sum / beforeResults.length;
|
|
341
|
-
}
|
|
342
|
-
const afterExec = iterCtx.executionResults;
|
|
343
|
-
const afterResults = afterExec?.executions ?? [];
|
|
344
|
-
const datasetResults = afterResults.length > 0 ? afterResults.map((r) => {
|
|
345
|
-
const id = r.id || "unknown";
|
|
346
|
-
const afterEval = r.evaluation;
|
|
347
|
-
const afterScore = afterEval?.score ?? 0;
|
|
348
|
-
const beforeResult = beforeById.get(id);
|
|
349
|
-
const beforeEval = beforeResult?.evaluation;
|
|
350
|
-
const beforeScore = beforeEval?.score;
|
|
351
|
-
return { id, beforeScore, afterScore };
|
|
352
|
-
}) : undefined;
|
|
353
|
-
const criteriaScores = extractCriteriaScores(beforeResults, afterResults);
|
|
354
|
-
const rawFailureModes = iterCtx.failureModes;
|
|
355
|
-
const failureModes = rawFailureModes?.categories && rawFailureModes.failures ? rawFailureModes.categories.map((category) => ({
|
|
356
|
-
category,
|
|
357
|
-
failures: (rawFailureModes.failures?.[category] ?? []).map((f) => ({
|
|
358
|
-
description: f.description ?? f.label,
|
|
359
|
-
summary: f.summary
|
|
360
|
-
}))
|
|
361
|
-
})) : undefined;
|
|
362
|
-
const rawMutations = iterCtx.mutations;
|
|
363
|
-
const mutations = rawMutations && rawMutations.length > 0 ? rawMutations.map((m) => ({
|
|
364
|
-
label: m.label ?? "Unknown mutation",
|
|
365
|
-
status: m.status ?? "pending",
|
|
366
|
-
priority: m.priority,
|
|
367
|
-
rationale: m.target?.rationale
|
|
368
|
-
})) : undefined;
|
|
369
|
-
const evaluationDetails = afterResults.length > 0 ? afterResults.map((r) => {
|
|
370
|
-
const id = r.id || "unknown";
|
|
371
|
-
const eval_ = r.evaluation;
|
|
372
|
-
const score = eval_?.score ?? 0;
|
|
373
|
-
const success = eval_?.success ?? false;
|
|
374
|
-
const metrics = eval_?.evaluations?.map((metric) => {
|
|
375
|
-
const criteria = metric.evaluationChecklist?.items?.map((item) => ({
|
|
376
|
-
name: item.evaluationParameter ?? item.criteria ?? "unknown",
|
|
377
|
-
score: item.llmScore ?? 0,
|
|
378
|
-
success: item.success ?? false
|
|
379
|
-
}));
|
|
380
|
-
return {
|
|
381
|
-
name: metric.name ?? "unknown",
|
|
382
|
-
score: metric.score ?? 0,
|
|
383
|
-
success: metric.success ?? false,
|
|
384
|
-
failureMode: metric.failureMode,
|
|
385
|
-
reasoning: metric.reasoning,
|
|
386
|
-
criteria: criteria && criteria.length > 0 ? criteria : undefined
|
|
387
|
-
};
|
|
388
|
-
});
|
|
389
|
-
return {
|
|
390
|
-
itemId: id,
|
|
391
|
-
score,
|
|
392
|
-
success,
|
|
393
|
-
metrics: metrics && metrics.length > 0 ? metrics : undefined
|
|
394
|
-
};
|
|
395
|
-
}) : undefined;
|
|
396
|
-
return {
|
|
397
|
-
originalScore,
|
|
398
|
-
criteriaScores,
|
|
399
|
-
datasetResults,
|
|
400
|
-
failureModes,
|
|
401
|
-
mutations,
|
|
402
|
-
evaluationDetails
|
|
403
|
-
};
|
|
404
|
-
}
|
|
405
|
-
function extractCriteriaScores(beforeResults, afterResults) {
|
|
406
|
-
const metricNames = new Set;
|
|
407
|
-
const beforeScores = new Map;
|
|
408
|
-
const afterScores = new Map;
|
|
409
|
-
for (const r of beforeResults) {
|
|
410
|
-
const eval_ = r.evaluation;
|
|
411
|
-
for (const m of eval_?.evaluations ?? []) {
|
|
412
|
-
const name = m.name ?? "unknown";
|
|
413
|
-
metricNames.add(name);
|
|
414
|
-
const existing = beforeScores.get(name) ?? [];
|
|
415
|
-
existing.push(m.score ?? 0);
|
|
416
|
-
beforeScores.set(name, existing);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
for (const r of afterResults) {
|
|
420
|
-
const eval_ = r.evaluation;
|
|
421
|
-
for (const m of eval_?.evaluations ?? []) {
|
|
422
|
-
const name = m.name ?? "unknown";
|
|
423
|
-
metricNames.add(name);
|
|
424
|
-
const existing = afterScores.get(name) ?? [];
|
|
425
|
-
existing.push(m.score ?? 0);
|
|
426
|
-
afterScores.set(name, existing);
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
if (metricNames.size === 0)
|
|
430
|
-
return;
|
|
431
|
-
const avg = (arr) => arr.reduce((a, b) => a + b, 0) / arr.length;
|
|
432
|
-
return Array.from(metricNames).map((name) => ({
|
|
433
|
-
name,
|
|
434
|
-
before: beforeScores.has(name) ? avg(beforeScores.get(name) ?? []) : undefined,
|
|
435
|
-
after: afterScores.has(name) ? avg(afterScores.get(name) ?? []) : undefined
|
|
436
|
-
}));
|
|
437
|
-
}
|
|
438
|
-
|
|
439
320
|
// src/lib/sdk-client.ts
|
|
440
321
|
var exports_sdk_client = {};
|
|
441
322
|
__export(exports_sdk_client, {
|
|
@@ -546,416 +427,6 @@ class SDKClientWrapper {
|
|
|
546
427
|
}
|
|
547
428
|
return response.json();
|
|
548
429
|
}
|
|
549
|
-
async requestRaw(path, options) {
|
|
550
|
-
const optHeaders = options?.headers;
|
|
551
|
-
let extraHeaders = {};
|
|
552
|
-
if (optHeaders instanceof Headers) {
|
|
553
|
-
optHeaders.forEach((value, key) => {
|
|
554
|
-
extraHeaders[key] = value;
|
|
555
|
-
});
|
|
556
|
-
} else if (optHeaders) {
|
|
557
|
-
extraHeaders = optHeaders;
|
|
558
|
-
}
|
|
559
|
-
const tenancyHeaders = {};
|
|
560
|
-
if (this.workspaceId)
|
|
561
|
-
tenancyHeaders["x-workspace-id"] = this.workspaceId;
|
|
562
|
-
if (this.organizationId)
|
|
563
|
-
tenancyHeaders["x-organization-id"] = this.organizationId;
|
|
564
|
-
return fetch(`${this.endpoint}${path}`, {
|
|
565
|
-
...options,
|
|
566
|
-
headers: {
|
|
567
|
-
"x-api-key": this.apiKey,
|
|
568
|
-
"Content-Type": "application/json",
|
|
569
|
-
...tenancyHeaders,
|
|
570
|
-
...extraHeaders
|
|
571
|
-
}
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
async listPrompts() {
|
|
575
|
-
try {
|
|
576
|
-
const response = await this.sdk.prompt.listPrompts();
|
|
577
|
-
return response.result.data;
|
|
578
|
-
} catch (error) {
|
|
579
|
-
this.handleError(error);
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
async getPrompt(id) {
|
|
583
|
-
try {
|
|
584
|
-
const response = await this.sdk.prompt.getPrompt({ id: parseInt(id, 10) });
|
|
585
|
-
return response;
|
|
586
|
-
} catch (error) {
|
|
587
|
-
this.handleError(error);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
async createPrompt(data) {
|
|
591
|
-
try {
|
|
592
|
-
const response = await this.sdk.prompt.createPrompt({
|
|
593
|
-
name: data.name ?? "",
|
|
594
|
-
description: data.description ?? undefined,
|
|
595
|
-
version: data.version ?? undefined,
|
|
596
|
-
isLatest: data.isLatest ?? undefined,
|
|
597
|
-
systemPrompt: data.systemPrompt ?? undefined,
|
|
598
|
-
humanPrompt: data.humanPrompt ?? undefined,
|
|
599
|
-
rawPrompt: data.rawPrompt ?? undefined,
|
|
600
|
-
inputSchema: data.inputSchema ?? undefined,
|
|
601
|
-
outputSchema: data.outputSchema ?? undefined,
|
|
602
|
-
metadata: data.metadata ?? undefined,
|
|
603
|
-
tags: data.tags ?? undefined
|
|
604
|
-
});
|
|
605
|
-
return response;
|
|
606
|
-
} catch (error) {
|
|
607
|
-
this.handleError(error);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
async updatePrompt(id, data) {
|
|
611
|
-
try {
|
|
612
|
-
const body = {
|
|
613
|
-
description: data.description ?? undefined,
|
|
614
|
-
isLatest: data.isLatest ?? undefined,
|
|
615
|
-
systemPrompt: data.systemPrompt ?? undefined,
|
|
616
|
-
humanPrompt: data.humanPrompt ?? undefined,
|
|
617
|
-
rawPrompt: data.rawPrompt ?? undefined,
|
|
618
|
-
inputSchema: data.inputSchema,
|
|
619
|
-
outputSchema: data.outputSchema,
|
|
620
|
-
metadata: data.metadata,
|
|
621
|
-
tags: data.tags ?? undefined
|
|
622
|
-
};
|
|
623
|
-
if (data.name !== undefined) {
|
|
624
|
-
body.name = data.name;
|
|
625
|
-
}
|
|
626
|
-
const updateArgs = { id: parseInt(id, 10), body };
|
|
627
|
-
const response = await this.sdk.prompt.updatePrompt(updateArgs);
|
|
628
|
-
return response;
|
|
629
|
-
} catch (error) {
|
|
630
|
-
this.handleError(error);
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
async deletePrompt(id, options) {
|
|
634
|
-
try {
|
|
635
|
-
if (options?.force) {
|
|
636
|
-
await this.request(`/api/prompt/${id}?force=true`, { method: "DELETE" });
|
|
637
|
-
} else {
|
|
638
|
-
await this.sdk.prompt.deletePrompt({ id: parseInt(id, 10) });
|
|
639
|
-
}
|
|
640
|
-
} catch (error) {
|
|
641
|
-
this.handleError(error);
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
async getDataset(datasetId) {
|
|
645
|
-
try {
|
|
646
|
-
return await this.request(`/api/prompts/datasets/${String(datasetId)}`);
|
|
647
|
-
} catch (error) {
|
|
648
|
-
this.handleError(error);
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
async getDatasetItem(itemId) {
|
|
652
|
-
try {
|
|
653
|
-
return await this.request(`/api/prompts/dataset-items/${String(itemId)}`);
|
|
654
|
-
} catch (error) {
|
|
655
|
-
this.handleError(error);
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
async listDatasets(promptId) {
|
|
659
|
-
try {
|
|
660
|
-
const response = await this.request(`/api/prompt/${promptId}/datasets`);
|
|
661
|
-
return Array.isArray(response) ? response : response.data;
|
|
662
|
-
} catch (error) {
|
|
663
|
-
this.handleError(error);
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
async addDataset(promptId, fileContent, name) {
|
|
667
|
-
try {
|
|
668
|
-
let parsed;
|
|
669
|
-
try {
|
|
670
|
-
parsed = JSON.parse(fileContent);
|
|
671
|
-
} catch {
|
|
672
|
-
parsed = null;
|
|
673
|
-
}
|
|
674
|
-
let datasetName = name ?? `Dataset ${new Date().toISOString().slice(0, 16)}`;
|
|
675
|
-
let items;
|
|
676
|
-
if (parsed !== null && !Array.isArray(parsed) && typeof parsed === "object" && "name" in parsed) {
|
|
677
|
-
const meta = parsed;
|
|
678
|
-
datasetName = meta.name ?? datasetName;
|
|
679
|
-
if (Array.isArray(meta.items)) {
|
|
680
|
-
items = meta.items;
|
|
681
|
-
}
|
|
682
|
-
} else if (Array.isArray(parsed)) {
|
|
683
|
-
items = parsed;
|
|
684
|
-
}
|
|
685
|
-
const dataset = await this.request(`/api/prompt/${promptId}/datasets`, {
|
|
686
|
-
method: "POST",
|
|
687
|
-
body: JSON.stringify({
|
|
688
|
-
name: datasetName
|
|
689
|
-
})
|
|
690
|
-
});
|
|
691
|
-
let itemCount = 0;
|
|
692
|
-
if (items && items.length > 0) {
|
|
693
|
-
const mappedItems = items.map((item, index) => ({
|
|
694
|
-
input: item.input ?? item,
|
|
695
|
-
expectedOutput: item.expectedOutput ?? item.expected_output ?? undefined,
|
|
696
|
-
name: item.name ?? `Item ${String(index + 1)}`,
|
|
697
|
-
userFeedback: item.userFeedback,
|
|
698
|
-
systemFeedback: item.systemFeedback,
|
|
699
|
-
labels: item.labels,
|
|
700
|
-
metadata: item.metadata
|
|
701
|
-
}));
|
|
702
|
-
const missingExpectedOutputCount = mappedItems.filter((item) => item.expectedOutput === undefined).length;
|
|
703
|
-
const bulkResult = await this.requestRaw(`/api/prompts/datasets/${String(dataset.id)}/items/bulk`, {
|
|
704
|
-
method: "POST",
|
|
705
|
-
body: JSON.stringify({ items: mappedItems })
|
|
706
|
-
});
|
|
707
|
-
if (!bulkResult.ok) {
|
|
708
|
-
const bodyText = await bulkResult.text();
|
|
709
|
-
let parsed2;
|
|
710
|
-
try {
|
|
711
|
-
parsed2 = JSON.parse(bodyText);
|
|
712
|
-
} catch {}
|
|
713
|
-
const typed = parsed2;
|
|
714
|
-
if (typed && typed.kind === "bulk_insert_rollback") {
|
|
715
|
-
const constraint = typeof typed.failingConstraint === "string" ? typed.failingConstraint : "unknown";
|
|
716
|
-
const rowIndex = typeof typed.failingRowIndex === "number" ? typed.failingRowIndex : null;
|
|
717
|
-
throw new ApiError(bulkResult.status, `Bulk insert rolled back — constraint: ${constraint}` + (rowIndex !== null ? `, first failing row: ${String(rowIndex)}` : ""));
|
|
718
|
-
}
|
|
719
|
-
throw new ApiError(bulkResult.status, bodyText || "Bulk insert failed");
|
|
720
|
-
}
|
|
721
|
-
itemCount = mappedItems.length;
|
|
722
|
-
return { ...dataset, itemCount, missingExpectedOutputCount };
|
|
723
|
-
}
|
|
724
|
-
return { ...dataset, itemCount };
|
|
725
|
-
} catch (error) {
|
|
726
|
-
this.handleError(error);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
async listDatasetItems(datasetId) {
|
|
730
|
-
try {
|
|
731
|
-
const response = await this.request(`/api/prompts/datasets/${datasetId}/items`);
|
|
732
|
-
return Array.isArray(response) ? response : response.data;
|
|
733
|
-
} catch (error) {
|
|
734
|
-
this.handleError(error);
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
async deleteDataset(_promptId, datasetId, options) {
|
|
738
|
-
try {
|
|
739
|
-
const query = options?.force ? "?force=true" : "";
|
|
740
|
-
await this.request(`/api/prompts/datasets/${datasetId}${query}`, { method: "DELETE" });
|
|
741
|
-
} catch (error) {
|
|
742
|
-
this.handleError(error);
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
async listEvaluations(promptId) {
|
|
746
|
-
try {
|
|
747
|
-
const response = await this.request(`/api/prompts/evaluations?promptId=${promptId}`);
|
|
748
|
-
return response.data;
|
|
749
|
-
} catch (error) {
|
|
750
|
-
this.handleError(error);
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
async getEvaluation(evaluationId) {
|
|
754
|
-
try {
|
|
755
|
-
return await this.request(`/api/prompts/evaluations/${evaluationId}`);
|
|
756
|
-
} catch (error) {
|
|
757
|
-
this.handleError(error);
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
async createEvaluation(promptId, data) {
|
|
761
|
-
try {
|
|
762
|
-
return await this.request("/api/prompts/evaluations", {
|
|
763
|
-
method: "POST",
|
|
764
|
-
body: JSON.stringify({
|
|
765
|
-
promptId: parseInt(promptId, 10),
|
|
766
|
-
name: data.name,
|
|
767
|
-
description: data.description,
|
|
768
|
-
evalConfig: data.evalConfig,
|
|
769
|
-
llmConfig: data.llmConfig,
|
|
770
|
-
tags: data.tags,
|
|
771
|
-
metadata: data.metadata
|
|
772
|
-
})
|
|
773
|
-
});
|
|
774
|
-
} catch (error) {
|
|
775
|
-
this.handleError(error);
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
async deleteEvaluation(evaluationId) {
|
|
779
|
-
try {
|
|
780
|
-
await this.request(`/api/prompts/evaluations/${evaluationId}`, { method: "DELETE" });
|
|
781
|
-
} catch (error) {
|
|
782
|
-
this.handleError(error);
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
async listOptimizations() {
|
|
786
|
-
try {
|
|
787
|
-
const response = await this.request("/api/optimizations");
|
|
788
|
-
if (Array.isArray(response))
|
|
789
|
-
return response;
|
|
790
|
-
const r = response;
|
|
791
|
-
if (Array.isArray(r.data))
|
|
792
|
-
return r.data;
|
|
793
|
-
return [];
|
|
794
|
-
} catch (error) {
|
|
795
|
-
this.handleError(error);
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
async listExperiments(filters) {
|
|
799
|
-
try {
|
|
800
|
-
const params = new URLSearchParams;
|
|
801
|
-
if (filters?.promptId !== undefined)
|
|
802
|
-
params.set("promptId", String(filters.promptId));
|
|
803
|
-
if (filters?.status)
|
|
804
|
-
params.set("status", filters.status);
|
|
805
|
-
if (filters?.limit !== undefined)
|
|
806
|
-
params.set("limit", String(filters.limit));
|
|
807
|
-
if (filters?.offset !== undefined)
|
|
808
|
-
params.set("offset", String(filters.offset));
|
|
809
|
-
const qs = params.toString();
|
|
810
|
-
const response = await this.request(`/api/prompts/experiments${qs ? `?${qs}` : ""}`);
|
|
811
|
-
if (Array.isArray(response))
|
|
812
|
-
return { experiments: response, total: response.length };
|
|
813
|
-
const r = response;
|
|
814
|
-
const experiments = r.experiments ?? r.data ?? [];
|
|
815
|
-
return { experiments, total: r.total ?? experiments.length };
|
|
816
|
-
} catch (error) {
|
|
817
|
-
this.handleError(error);
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
async createExperiment(data) {
|
|
821
|
-
try {
|
|
822
|
-
return await this.request("/api/prompts/experiments", {
|
|
823
|
-
method: "POST",
|
|
824
|
-
body: JSON.stringify(data)
|
|
825
|
-
});
|
|
826
|
-
} catch (error) {
|
|
827
|
-
this.handleError(error);
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
async getExperiment(id) {
|
|
831
|
-
try {
|
|
832
|
-
return await this.request(`/api/prompts/experiments/${id}`);
|
|
833
|
-
} catch (error) {
|
|
834
|
-
this.handleError(error);
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
async deleteExperiment(id) {
|
|
838
|
-
try {
|
|
839
|
-
await this.request(`/api/prompts/experiments/${id}`, { method: "DELETE" });
|
|
840
|
-
} catch (error) {
|
|
841
|
-
this.handleError(error);
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
async executeExperiment(id) {
|
|
845
|
-
try {
|
|
846
|
-
return await this.request(`/api/prompts/experiments/${id}/execute`, { method: "POST", body: JSON.stringify({}) });
|
|
847
|
-
} catch (error) {
|
|
848
|
-
this.handleError(error);
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
async playgroundEval(promptId, data) {
|
|
852
|
-
try {
|
|
853
|
-
return await this.request(`/api/prompt/${promptId}/playground/eval`, {
|
|
854
|
-
method: "POST",
|
|
855
|
-
body: JSON.stringify(data)
|
|
856
|
-
});
|
|
857
|
-
} catch (error) {
|
|
858
|
-
this.handleError(error);
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
async cancelOptimization(jobId) {
|
|
862
|
-
try {
|
|
863
|
-
return await this.request(`/api/optimization/${jobId}/cancel`, {
|
|
864
|
-
method: "POST"
|
|
865
|
-
});
|
|
866
|
-
} catch (error) {
|
|
867
|
-
this.handleError(error);
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
async startOptimization(promptId, datasetId, evaluationId, config) {
|
|
871
|
-
try {
|
|
872
|
-
return await this.request(`/api/prompt/${promptId}/optimize`, {
|
|
873
|
-
method: "POST",
|
|
874
|
-
body: JSON.stringify({
|
|
875
|
-
datasetId: parseInt(datasetId, 10),
|
|
876
|
-
evaluationId: parseInt(evaluationId, 10),
|
|
877
|
-
config: {
|
|
878
|
-
maxIterations: config?.maxIterations ?? 1,
|
|
879
|
-
targetScore: config?.targetScore ?? 0.8,
|
|
880
|
-
patience: config?.patience,
|
|
881
|
-
...config?.executionModel ? { executionModel: config.executionModel } : {},
|
|
882
|
-
...config?.evaluationModel ? { evaluationModel: config.evaluationModel } : {},
|
|
883
|
-
...config?.optimizationModel ? { optimizationModel: config.optimizationModel } : {},
|
|
884
|
-
...config?.providerId ? { executionProviderId: config.providerId } : {},
|
|
885
|
-
...config?.evalProviderId ? { evaluationProviderId: config.evalProviderId } : {},
|
|
886
|
-
...config?.optProviderId ? { optimizationProviderId: config.optProviderId } : {}
|
|
887
|
-
},
|
|
888
|
-
executionMode: "worker_loop"
|
|
889
|
-
})
|
|
890
|
-
});
|
|
891
|
-
} catch (error) {
|
|
892
|
-
this.handleError(error);
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
async getOptimizationStatus(jobId) {
|
|
896
|
-
try {
|
|
897
|
-
const raw = await this.request(`/api/optimization/${jobId}`);
|
|
898
|
-
const id = raw.id;
|
|
899
|
-
return {
|
|
900
|
-
...raw,
|
|
901
|
-
jobId: id ?? jobId,
|
|
902
|
-
progressPercent: typeof raw.progress === "number" ? raw.progress : 0
|
|
903
|
-
};
|
|
904
|
-
} catch (error) {
|
|
905
|
-
this.handleError(error);
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
async getOptimizationScorecard(jobId) {
|
|
909
|
-
try {
|
|
910
|
-
const res = await this.request(`/api/optimization/${jobId}/results`);
|
|
911
|
-
if (res.scorecard?.rendered) {
|
|
912
|
-
return { rendered: res.scorecard.rendered, data: res.scorecard.data ?? [] };
|
|
913
|
-
}
|
|
914
|
-
return null;
|
|
915
|
-
} catch {
|
|
916
|
-
return null;
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
async getOptimizationResults(jobId) {
|
|
920
|
-
try {
|
|
921
|
-
const job = await this.request(`/api/optimization/${jobId}`);
|
|
922
|
-
const progress = await this.request(`/api/optimization/${jobId}/progress`);
|
|
923
|
-
const prompt = await this.getPrompt(String(job.promptId ?? ""));
|
|
924
|
-
const statesRes = await this.request(`/api/optimization/${jobId}/states`).catch(() => ({ states: [] }));
|
|
925
|
-
const scorecardDigest = await this.getOptimizationScorecard(jobId);
|
|
926
|
-
const latestState = statesRes.states[statesRes.states.length - 1];
|
|
927
|
-
const rawState = latestState?.state ?? {};
|
|
928
|
-
const iterCtx = rawState.iterationContext ?? rawState.current?.context;
|
|
929
|
-
const basePromptObj = iterCtx?.basePrompt;
|
|
930
|
-
const currentPromptObj = iterCtx?.currentPrompt;
|
|
931
|
-
const mutatedPromptText = typeof currentPromptObj?.prompt === "string" ? currentPromptObj.prompt : undefined;
|
|
932
|
-
const originalPromptText = typeof basePromptObj?.prompt === "string" ? basePromptObj.prompt : undefined;
|
|
933
|
-
const extracted = extractScorecardDetails(rawState, iterCtx);
|
|
934
|
-
return {
|
|
935
|
-
job: {
|
|
936
|
-
id: job.id ?? jobId,
|
|
937
|
-
promptId: job.promptId ?? 0,
|
|
938
|
-
status: job.status ?? "unknown",
|
|
939
|
-
config: job.config
|
|
940
|
-
},
|
|
941
|
-
prompt,
|
|
942
|
-
bestScore: job.bestScore,
|
|
943
|
-
originalScore: extracted.originalScore,
|
|
944
|
-
iterationsCompleted: job.currentIteration,
|
|
945
|
-
scoreProgression: Array.isArray(progress.progression) ? progress.progression.map((p) => typeof p.score === "number" ? p.score : 0) : undefined,
|
|
946
|
-
mutatedPromptText,
|
|
947
|
-
originalPromptText,
|
|
948
|
-
criteriaScores: extracted.criteriaScores,
|
|
949
|
-
datasetResults: extracted.datasetResults,
|
|
950
|
-
failureModes: extracted.failureModes,
|
|
951
|
-
mutations: extracted.mutations,
|
|
952
|
-
evaluationDetails: extracted.evaluationDetails,
|
|
953
|
-
...scorecardDigest ? { scorecard: scorecardDigest } : {}
|
|
954
|
-
};
|
|
955
|
-
} catch (error) {
|
|
956
|
-
this.handleError(error);
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
430
|
async listAgents(filters) {
|
|
960
431
|
try {
|
|
961
432
|
const response = await this.sdk.agents.listAgents({
|
|
@@ -1063,42 +534,6 @@ class SDKClientWrapper {
|
|
|
1063
534
|
this.handleError(error);
|
|
1064
535
|
}
|
|
1065
536
|
}
|
|
1066
|
-
async executePrompt(promptId, input, options) {
|
|
1067
|
-
try {
|
|
1068
|
-
return await this.request(`/api/prompt/${promptId}/playground/call`, {
|
|
1069
|
-
method: "POST",
|
|
1070
|
-
body: JSON.stringify({ input, model: options?.model })
|
|
1071
|
-
});
|
|
1072
|
-
} catch (error) {
|
|
1073
|
-
this.handleError(error);
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
async executePromptStream(promptId, input, options) {
|
|
1077
|
-
const response = await fetch(`${this.endpoint}/api/prompt/${promptId}/execute/stream`, {
|
|
1078
|
-
method: "POST",
|
|
1079
|
-
headers: {
|
|
1080
|
-
"x-api-key": this.apiKey,
|
|
1081
|
-
"Content-Type": "application/json",
|
|
1082
|
-
Accept: "text/event-stream"
|
|
1083
|
-
},
|
|
1084
|
-
body: JSON.stringify({ input, ...options })
|
|
1085
|
-
});
|
|
1086
|
-
if (!response.ok) {
|
|
1087
|
-
if (response.status === 401) {
|
|
1088
|
-
throw new AuthenticationError;
|
|
1089
|
-
}
|
|
1090
|
-
if (response.status === 403) {
|
|
1091
|
-
throw new ApiError(403, await response.text() || "Access denied");
|
|
1092
|
-
}
|
|
1093
|
-
const error = await response.text();
|
|
1094
|
-
const errorLower = error.toLowerCase();
|
|
1095
|
-
if (errorLower.includes("workspace") && (errorLower.includes("missing") || errorLower.includes("required")) || errorLower.includes("x-workspace-id")) {
|
|
1096
|
-
throw new WorkspaceContextError(error);
|
|
1097
|
-
}
|
|
1098
|
-
throw new ApiError(response.status, error);
|
|
1099
|
-
}
|
|
1100
|
-
return response;
|
|
1101
|
-
}
|
|
1102
537
|
async listProviders(filters) {
|
|
1103
538
|
try {
|
|
1104
539
|
const response = await this.sdk.providerConfigs.listProviders({
|
|
@@ -1293,8 +728,8 @@ var init_sdk_client = __esm(() => {
|
|
|
1293
728
|
// src/bin/cli.ts
|
|
1294
729
|
import { Command as Command12 } from "commander";
|
|
1295
730
|
import chalk18 from "chalk";
|
|
1296
|
-
import { readFileSync as
|
|
1297
|
-
import { join as
|
|
731
|
+
import { readFileSync as readFileSync9, existsSync as existsSync10 } from "fs";
|
|
732
|
+
import { join as join12, dirname as dirname3 } from "path";
|
|
1298
733
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1299
734
|
|
|
1300
735
|
// src/commands/auth.ts
|
|
@@ -3664,7 +3099,8 @@ name: mutagent-cli-workflows-install
|
|
|
3664
3099
|
description: |
|
|
3665
3100
|
Meta-installer workflow. Installs a MutagenT package (helix, diagnostics, or
|
|
3666
3101
|
evaluator) into the user's environment via \`mutagent install <package>\`.
|
|
3667
|
-
Login-gated. diagnostics/evaluator come from public npm; helix
|
|
3102
|
+
Login-gated. diagnostics/evaluator come from public npm; helix is fetched
|
|
3103
|
+
from a private registry via a login-brokered signed URL (no static secret).
|
|
3668
3104
|
triggers:
|
|
3669
3105
|
- "install diagnostics"
|
|
3670
3106
|
- "install evaluator"
|
|
@@ -3703,7 +3139,7 @@ Where \`<package>\` is one of:
|
|
|
3703
3139
|
|---|---|---|
|
|
3704
3140
|
| \`diagnostics\` | public npm \`@mutagent/diagnostics\` | Ready to install |
|
|
3705
3141
|
| \`evaluator\` | public npm \`@mutagent/evaluator\` | Ready to install |
|
|
3706
|
-
| \`helix\` |
|
|
3142
|
+
| \`helix\` | private registry via login-brokered signed URL | Ready to install — login-gated download, sha256-verified, then initialized into your project |
|
|
3707
3143
|
|
|
3708
3144
|
**Flags** (verify against \`--help\`):
|
|
3709
3145
|
- \`--harness <claude-code|codex|omp>\` -- target coding-agent harness (default \`claude-code\`).
|
|
@@ -3736,6 +3172,8 @@ Where \`<package>\` is one of:
|
|
|
3736
3172
|
## Examples
|
|
3737
3173
|
|
|
3738
3174
|
\`\`\`bash
|
|
3175
|
+
mutagent install helix --json
|
|
3176
|
+
mutagent install helix --harness codex --json
|
|
3739
3177
|
mutagent install diagnostics --json
|
|
3740
3178
|
mutagent install evaluator --version 1.2.3 --json
|
|
3741
3179
|
mutagent install diagnostics --harness codex --json
|
|
@@ -3746,15 +3184,15 @@ mutagent install diagnostics --harness codex --json
|
|
|
3746
3184
|
## Output handling
|
|
3747
3185
|
|
|
3748
3186
|
- On success (\`{ success: true, package, version, harness, global }\`): tell the user what was installed and the resolved version. Surface \`_links.install\` / \`_links.login\`.
|
|
3749
|
-
-
|
|
3750
|
-
- On an auth error: route to the login workflow, then retry.
|
|
3187
|
+
- For \`helix\`: the CLI resolves a signed download URL from the login broker, downloads + sha256-verifies the plugin, then runs its init into the project. An \`INTEGRITY_ERROR\` means the download failed checksum verification — retry.
|
|
3188
|
+
- On an auth error (including a broker \`AUTH_REQUIRED\`): route to the login workflow, then retry.
|
|
3751
3189
|
|
|
3752
3190
|
---
|
|
3753
3191
|
|
|
3754
3192
|
## Common pitfalls
|
|
3755
3193
|
|
|
3756
3194
|
- Running before login → auth error (install is login-gated).
|
|
3757
|
-
- Assuming \`helix\` installs
|
|
3195
|
+
- Assuming \`helix\` installs from public npm — it is fetched from a private registry via a login-brokered signed URL (the CLI holds no static secret).
|
|
3758
3196
|
- Installing without confirming with the user first (Core Rule 5).
|
|
3759
3197
|
|
|
3760
3198
|
---
|
|
@@ -4011,7 +3449,7 @@ init_errors();
|
|
|
4011
3449
|
init_sdk_client();
|
|
4012
3450
|
var PROVIDERS_URL = "https://app.mutagent.io/settings/providers";
|
|
4013
3451
|
function createUsageCommand() {
|
|
4014
|
-
const usage = new Command8("usage").description("Show resource counts (
|
|
3452
|
+
const usage = new Command8("usage").description("Show account resource counts (providers, workspaces) and provider status").addHelpText("after", `
|
|
4015
3453
|
Examples:
|
|
4016
3454
|
${chalk14.dim("$")} mutagent usage
|
|
4017
3455
|
${chalk14.dim("$")} mutagent usage --json
|
|
@@ -4026,41 +3464,20 @@ Examples:
|
|
|
4026
3464
|
}
|
|
4027
3465
|
const spinner = await createSpinner("Fetching usage data...", isJson).start();
|
|
4028
3466
|
const client = await getSDKClient();
|
|
4029
|
-
const
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
let evaluationCount = 0;
|
|
4033
|
-
if (promptCount > 0) {
|
|
4034
|
-
const results = await Promise.all(prompts.map(async (prompt) => {
|
|
4035
|
-
const id = String(prompt.id);
|
|
4036
|
-
const [datasets, evaluations] = await Promise.all([
|
|
4037
|
-
client.listDatasets(id).catch(() => []),
|
|
4038
|
-
client.listEvaluations(id).catch(() => [])
|
|
4039
|
-
]);
|
|
4040
|
-
return { datasets: datasets.length, evaluations: evaluations.length };
|
|
4041
|
-
}));
|
|
4042
|
-
for (const r of results) {
|
|
4043
|
-
datasetCount += r.datasets;
|
|
4044
|
-
evaluationCount += r.evaluations;
|
|
4045
|
-
}
|
|
4046
|
-
}
|
|
4047
|
-
const [optimizations, experiments] = await Promise.all([
|
|
4048
|
-
client.listOptimizations().catch(() => []),
|
|
4049
|
-
client.listExperiments().catch(() => [])
|
|
3467
|
+
const [providers, workspaces] = await Promise.all([
|
|
3468
|
+
client.listProviders().catch(() => ({ data: [], total: 0 })),
|
|
3469
|
+
client.listWorkspaces().catch(() => ({ data: [], total: 0 }))
|
|
4050
3470
|
]);
|
|
4051
|
-
const
|
|
4052
|
-
const
|
|
3471
|
+
const providerCount = providers.total || providers.data.length;
|
|
3472
|
+
const workspaceCount = workspaces.total || workspaces.data.length;
|
|
4053
3473
|
if (spinner && typeof spinner.stop === "function") {
|
|
4054
3474
|
spinner.stop();
|
|
4055
3475
|
}
|
|
4056
3476
|
if (isJson) {
|
|
4057
3477
|
output.output({
|
|
4058
3478
|
resources: {
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
evaluations: evaluationCount,
|
|
4062
|
-
optimizations: optimizationCount,
|
|
4063
|
-
experiments: experimentCount
|
|
3479
|
+
providers: providerCount,
|
|
3480
|
+
workspaces: workspaceCount
|
|
4064
3481
|
},
|
|
4065
3482
|
_links: {
|
|
4066
3483
|
providers: PROVIDERS_URL,
|
|
@@ -4073,13 +3490,10 @@ Examples:
|
|
|
4073
3490
|
console.log(chalk14.dim("─".repeat(45)));
|
|
4074
3491
|
console.log("");
|
|
4075
3492
|
console.log(chalk14.bold("Resources:"));
|
|
4076
|
-
console.log(`
|
|
4077
|
-
console.log(`
|
|
4078
|
-
console.log(` Evaluations: ${chalk14.cyan(String(evaluationCount))}`);
|
|
4079
|
-
console.log(` Optimizations: ${chalk14.cyan(String(optimizationCount))}`);
|
|
4080
|
-
console.log(` Experiments: ${chalk14.cyan(String(experimentCount))}`);
|
|
3493
|
+
console.log(` Providers: ${chalk14.cyan(String(providerCount))}`);
|
|
3494
|
+
console.log(` Workspaces: ${chalk14.cyan(String(workspaceCount))}`);
|
|
4081
3495
|
console.log("");
|
|
4082
|
-
console.log(`
|
|
3496
|
+
console.log(` Manage providers: ${chalk14.underline(PROVIDERS_URL)}`);
|
|
4083
3497
|
console.log("");
|
|
4084
3498
|
}
|
|
4085
3499
|
} catch (error) {
|
|
@@ -5312,7 +4726,229 @@ init_errors();
|
|
|
5312
4726
|
// src/lib/installer.ts
|
|
5313
4727
|
init_errors();
|
|
5314
4728
|
init_config();
|
|
4729
|
+
import { spawn as spawn2 } from "child_process";
|
|
4730
|
+
|
|
4731
|
+
// src/lib/installer-helix.ts
|
|
4732
|
+
init_errors();
|
|
4733
|
+
init_config();
|
|
5315
4734
|
import { spawn } from "child_process";
|
|
4735
|
+
import { createHash } from "crypto";
|
|
4736
|
+
import { homedir as homedir2 } from "os";
|
|
4737
|
+
import { join as join11 } from "path";
|
|
4738
|
+
import {
|
|
4739
|
+
existsSync as existsSync9,
|
|
4740
|
+
mkdirSync as mkdirSync5,
|
|
4741
|
+
readFileSync as readFileSync8,
|
|
4742
|
+
renameSync as renameSync2,
|
|
4743
|
+
rmSync,
|
|
4744
|
+
writeFileSync as writeFileSync6
|
|
4745
|
+
} from "fs";
|
|
4746
|
+
async function installHelix(opts, deps = {}) {
|
|
4747
|
+
const auth = (deps.resolveAuth ?? defaultResolveAuth)();
|
|
4748
|
+
const fetchImpl = deps.fetchImpl ?? globalThis.fetch;
|
|
4749
|
+
const descriptor = await fetchDescriptor(fetchImpl, auth, opts.version);
|
|
4750
|
+
const baseDir = deps.homeDir ?? join11(homedir2(), ".mutagent", "helix");
|
|
4751
|
+
const versionDir = join11(baseDir, descriptor.version);
|
|
4752
|
+
mkdirSync5(versionDir, { recursive: true });
|
|
4753
|
+
const tgzPath = join11(versionDir, `helix-plugin-${descriptor.version}.tgz`);
|
|
4754
|
+
const tmpPath = `${tgzPath}.${String(process.pid)}.${String(Date.now())}.part`;
|
|
4755
|
+
const download = deps.download ?? defaultDownload;
|
|
4756
|
+
await download(descriptor.url, tmpPath);
|
|
4757
|
+
const sha256 = deps.sha256 ?? defaultSha256;
|
|
4758
|
+
const actual = (await sha256(tmpPath)).toLowerCase();
|
|
4759
|
+
const expected = descriptor.sha256.toLowerCase();
|
|
4760
|
+
if (actual !== expected) {
|
|
4761
|
+
safeRm(tmpPath);
|
|
4762
|
+
throw new MutagentError("INTEGRITY_ERROR", `Downloaded helix plugin failed sha256 verification (expected ${expected.slice(0, 12)}…, got ${actual.slice(0, 12)}…).`, "The download may be corrupt or tampered with. Retry: mutagent install helix");
|
|
4763
|
+
}
|
|
4764
|
+
renameSync2(tmpPath, tgzPath);
|
|
4765
|
+
const extract = deps.extract ?? defaultExtract;
|
|
4766
|
+
await extract(tgzPath, versionDir);
|
|
4767
|
+
const locateInitBin = deps.locateInitBin ?? defaultLocateInitBin;
|
|
4768
|
+
const binPath = await locateInitBin(versionDir);
|
|
4769
|
+
const initArgs = ["init", "--harness", opts.harness];
|
|
4770
|
+
if (opts.global)
|
|
4771
|
+
initArgs.push("--global");
|
|
4772
|
+
const runInit = deps.runInit ?? defaultRunInit;
|
|
4773
|
+
const code = await runInit(binPath, initArgs, process.cwd());
|
|
4774
|
+
if (code !== 0) {
|
|
4775
|
+
throw new MutagentError("INSTALL_FAILED", `helix plugin init exited with code ${String(code)}.`, "Re-run: mutagent install helix — or run the plugin init manually and report the error.");
|
|
4776
|
+
}
|
|
4777
|
+
await postTelemetry(fetchImpl, auth, {
|
|
4778
|
+
pkg: "helix",
|
|
4779
|
+
version: descriptor.version,
|
|
4780
|
+
harness: opts.harness,
|
|
4781
|
+
cliVersion: deps.cliVersion ?? readCliVersion()
|
|
4782
|
+
});
|
|
4783
|
+
return { version: descriptor.version };
|
|
4784
|
+
}
|
|
4785
|
+
async function fetchDescriptor(fetchImpl, auth, version) {
|
|
4786
|
+
if (!auth.apiKey) {
|
|
4787
|
+
throw new MutagentError("AUTH_REQUIRED", "Authentication required to install helix.", "Run: mutagent login");
|
|
4788
|
+
}
|
|
4789
|
+
const url = `${auth.apiBase}/api/helix/plugin/download?version=${encodeURIComponent(version)}`;
|
|
4790
|
+
let res;
|
|
4791
|
+
try {
|
|
4792
|
+
res = await fetchImpl(url, {
|
|
4793
|
+
method: "GET",
|
|
4794
|
+
headers: { "x-api-key": auth.apiKey, ...auth.headers }
|
|
4795
|
+
});
|
|
4796
|
+
} catch {
|
|
4797
|
+
throw new MutagentError("SERVER_UNAVAILABLE", "Could not reach the MutagenT plugin broker.", "Check your network connection or verify the endpoint with: mutagent config show");
|
|
4798
|
+
}
|
|
4799
|
+
if (res.status === 401) {
|
|
4800
|
+
throw new MutagentError("AUTH_REQUIRED", "The plugin broker rejected your credentials.", "Re-authenticate: mutagent login");
|
|
4801
|
+
}
|
|
4802
|
+
if (!res.ok) {
|
|
4803
|
+
const detail = await readErrorMessage(res);
|
|
4804
|
+
throw new MutagentError("INSTALL_FAILED", `Plugin broker returned ${String(res.status)}.${detail ? ` ${detail}` : ""}`, "Verify the requested version exists, then retry: mutagent install helix");
|
|
4805
|
+
}
|
|
4806
|
+
const raw = await res.json();
|
|
4807
|
+
if (!isBrokerResponse(raw)) {
|
|
4808
|
+
throw new MutagentError("INSTALL_FAILED", "Plugin broker returned a malformed response (missing version/sha256/url).", "Retry: mutagent install helix — if it persists, report it.");
|
|
4809
|
+
}
|
|
4810
|
+
return raw;
|
|
4811
|
+
}
|
|
4812
|
+
async function postTelemetry(fetchImpl, auth, event) {
|
|
4813
|
+
if (!auth.apiKey)
|
|
4814
|
+
return;
|
|
4815
|
+
try {
|
|
4816
|
+
await fetchImpl(`${auth.apiBase}/api/helix/installs`, {
|
|
4817
|
+
method: "POST",
|
|
4818
|
+
headers: {
|
|
4819
|
+
"Content-Type": "application/json",
|
|
4820
|
+
"x-api-key": auth.apiKey,
|
|
4821
|
+
...auth.headers
|
|
4822
|
+
},
|
|
4823
|
+
body: JSON.stringify(event)
|
|
4824
|
+
});
|
|
4825
|
+
} catch {}
|
|
4826
|
+
}
|
|
4827
|
+
function defaultResolveAuth() {
|
|
4828
|
+
const apiKey = getApiKey();
|
|
4829
|
+
const config = loadConfig();
|
|
4830
|
+
const apiBase = config.endpoint ?? "https://api.mutagent.io";
|
|
4831
|
+
const headers = {};
|
|
4832
|
+
if (config.defaultWorkspace)
|
|
4833
|
+
headers["x-workspace-id"] = config.defaultWorkspace;
|
|
4834
|
+
if (config.defaultOrganization)
|
|
4835
|
+
headers["x-organization-id"] = config.defaultOrganization;
|
|
4836
|
+
return { apiBase, apiKey, headers };
|
|
4837
|
+
}
|
|
4838
|
+
async function defaultDownload(url, destPath) {
|
|
4839
|
+
let res;
|
|
4840
|
+
try {
|
|
4841
|
+
res = await globalThis.fetch(url);
|
|
4842
|
+
} catch {
|
|
4843
|
+
throw new MutagentError("SERVER_UNAVAILABLE", "Failed to download the helix plugin from storage.", "Check your network connection and retry: mutagent install helix");
|
|
4844
|
+
}
|
|
4845
|
+
if (!res.ok) {
|
|
4846
|
+
throw new MutagentError("INSTALL_FAILED", `Plugin download failed with status ${String(res.status)}.`, "The signed URL may have expired — retry: mutagent install helix");
|
|
4847
|
+
}
|
|
4848
|
+
const bytes = Buffer.from(await res.arrayBuffer());
|
|
4849
|
+
writeFileSync6(destPath, bytes);
|
|
4850
|
+
}
|
|
4851
|
+
async function defaultSha256(filePath) {
|
|
4852
|
+
return Promise.resolve(createHash("sha256").update(readFileSync8(filePath)).digest("hex"));
|
|
4853
|
+
}
|
|
4854
|
+
function defaultExtract(tgzPath, destDir) {
|
|
4855
|
+
return new Promise((resolve, reject) => {
|
|
4856
|
+
const child = spawn("tar", ["-xzf", tgzPath, "-C", destDir], {
|
|
4857
|
+
stdio: ["ignore", "ignore", "pipe"]
|
|
4858
|
+
});
|
|
4859
|
+
let stderr = "";
|
|
4860
|
+
child.stderr.on("data", (chunk) => {
|
|
4861
|
+
stderr += chunk.toString("utf-8");
|
|
4862
|
+
});
|
|
4863
|
+
child.on("error", (err) => {
|
|
4864
|
+
reject(new MutagentError("INSTALL_FAILED", `Failed to extract the helix plugin: ${err.message}`, 'Ensure "tar" is installed and available on your PATH.'));
|
|
4865
|
+
});
|
|
4866
|
+
child.on("close", (code) => {
|
|
4867
|
+
if (code === 0) {
|
|
4868
|
+
resolve();
|
|
4869
|
+
} else {
|
|
4870
|
+
reject(new MutagentError("INSTALL_FAILED", `Extracting the helix plugin failed (tar exit ${String(code ?? 1)}).${stderr ? ` ${stderr.trim().slice(0, 200)}` : ""}`, "The downloaded archive may be corrupt — retry: mutagent install helix"));
|
|
4871
|
+
}
|
|
4872
|
+
});
|
|
4873
|
+
});
|
|
4874
|
+
}
|
|
4875
|
+
function defaultLocateInitBin(extractedDir) {
|
|
4876
|
+
const pkgDir = existsSync9(join11(extractedDir, "package", "package.json")) ? join11(extractedDir, "package") : extractedDir;
|
|
4877
|
+
const pkgJsonPath = join11(pkgDir, "package.json");
|
|
4878
|
+
if (!existsSync9(pkgJsonPath)) {
|
|
4879
|
+
return Promise.reject(new MutagentError("INSTALL_FAILED", "Could not find package.json in the extracted helix plugin.", "The archive layout is unexpected — retry or report: mutagent install helix"));
|
|
4880
|
+
}
|
|
4881
|
+
const raw = JSON.parse(readFileSync8(pkgJsonPath, "utf-8"));
|
|
4882
|
+
const binRel = resolveBinField(raw);
|
|
4883
|
+
if (!binRel) {
|
|
4884
|
+
return Promise.reject(new MutagentError("INSTALL_FAILED", "The helix plugin package.json declares no runnable bin.", "The plugin package is malformed — report: mutagent install helix"));
|
|
4885
|
+
}
|
|
4886
|
+
const binPath = join11(pkgDir, binRel);
|
|
4887
|
+
if (!existsSync9(binPath)) {
|
|
4888
|
+
return Promise.reject(new MutagentError("INSTALL_FAILED", `The helix plugin bin was not found at ${binRel}.`, "The plugin package is incomplete — report: mutagent install helix"));
|
|
4889
|
+
}
|
|
4890
|
+
return Promise.resolve(binPath);
|
|
4891
|
+
}
|
|
4892
|
+
function defaultRunInit(binPath, args, cwd) {
|
|
4893
|
+
return new Promise((resolve, reject) => {
|
|
4894
|
+
const child = spawn("node", [binPath, ...args], { cwd, stdio: "inherit" });
|
|
4895
|
+
child.on("error", (err) => {
|
|
4896
|
+
reject(new MutagentError("INSTALL_FAILED", `Failed to run the helix plugin init: ${err.message}`, 'Ensure "node" is installed and available on your PATH.'));
|
|
4897
|
+
});
|
|
4898
|
+
child.on("close", (code) => {
|
|
4899
|
+
resolve(code ?? 1);
|
|
4900
|
+
});
|
|
4901
|
+
});
|
|
4902
|
+
}
|
|
4903
|
+
function resolveBinField(pkg) {
|
|
4904
|
+
if (!pkg || typeof pkg !== "object")
|
|
4905
|
+
return;
|
|
4906
|
+
const bin = pkg.bin;
|
|
4907
|
+
if (typeof bin === "string")
|
|
4908
|
+
return bin;
|
|
4909
|
+
if (bin && typeof bin === "object") {
|
|
4910
|
+
const entries = bin;
|
|
4911
|
+
const preferred = entries["mutagent-helix"];
|
|
4912
|
+
if (typeof preferred === "string")
|
|
4913
|
+
return preferred;
|
|
4914
|
+
for (const value of Object.values(entries)) {
|
|
4915
|
+
if (typeof value === "string")
|
|
4916
|
+
return value;
|
|
4917
|
+
}
|
|
4918
|
+
}
|
|
4919
|
+
return;
|
|
4920
|
+
}
|
|
4921
|
+
function isBrokerResponse(value) {
|
|
4922
|
+
if (!value || typeof value !== "object")
|
|
4923
|
+
return false;
|
|
4924
|
+
const v = value;
|
|
4925
|
+
return typeof v.version === "string" && typeof v.sha256 === "string" && typeof v.url === "string";
|
|
4926
|
+
}
|
|
4927
|
+
async function readErrorMessage(res) {
|
|
4928
|
+
try {
|
|
4929
|
+
const body = await res.json();
|
|
4930
|
+
if (body && typeof body === "object") {
|
|
4931
|
+
const b = body;
|
|
4932
|
+
if (typeof b.message === "string")
|
|
4933
|
+
return b.message;
|
|
4934
|
+
if (typeof b.error === "string")
|
|
4935
|
+
return b.error;
|
|
4936
|
+
}
|
|
4937
|
+
} catch {}
|
|
4938
|
+
return;
|
|
4939
|
+
}
|
|
4940
|
+
function readCliVersion() {
|
|
4941
|
+
if (process.env.CLI_VERSION)
|
|
4942
|
+
return process.env.CLI_VERSION;
|
|
4943
|
+
return "unknown";
|
|
4944
|
+
}
|
|
4945
|
+
function safeRm(path) {
|
|
4946
|
+
try {
|
|
4947
|
+
rmSync(path, { force: true });
|
|
4948
|
+
} catch {}
|
|
4949
|
+
}
|
|
4950
|
+
|
|
4951
|
+
// src/lib/installer.ts
|
|
5316
4952
|
var VALID_PACKAGES = ["helix", "diagnostics", "evaluator"];
|
|
5317
4953
|
var VALID_HARNESSES = ["claude-code", "codex", "omp"];
|
|
5318
4954
|
var VERSION_MATRIX = {
|
|
@@ -5325,7 +4961,7 @@ var NPM_PACKAGES = {
|
|
|
5325
4961
|
evaluator: "@mutagent/evaluator"
|
|
5326
4962
|
};
|
|
5327
4963
|
var defaultRunner = (cmd, args) => new Promise((resolve, reject) => {
|
|
5328
|
-
const child =
|
|
4964
|
+
const child = spawn2(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
5329
4965
|
let stdout = "";
|
|
5330
4966
|
let stderr = "";
|
|
5331
4967
|
child.stdout.on("data", (chunk) => {
|
|
@@ -5360,7 +4996,13 @@ async function installPackage(pkg, opts, deps = {}) {
|
|
|
5360
4996
|
}
|
|
5361
4997
|
const version = opts.version ?? VERSION_MATRIX[pkg];
|
|
5362
4998
|
if (pkg === "helix") {
|
|
5363
|
-
|
|
4999
|
+
const { version: resolved } = await installHelix({ harness: opts.harness, global: opts.global, version }, deps.helix ?? {});
|
|
5000
|
+
return {
|
|
5001
|
+
package: pkg,
|
|
5002
|
+
version: resolved,
|
|
5003
|
+
harness: opts.harness,
|
|
5004
|
+
global: opts.global
|
|
5005
|
+
};
|
|
5364
5006
|
}
|
|
5365
5007
|
const npmPackage = NPM_PACKAGES[pkg];
|
|
5366
5008
|
const args = ["install", "-g", `${npmPackage}@${version}`];
|
|
@@ -5390,15 +5032,18 @@ ${chalk17.bold("Arguments & flags:")}
|
|
|
5390
5032
|
${chalk17.bold("--json")} Structured output
|
|
5391
5033
|
|
|
5392
5034
|
${chalk17.bold("Examples:")}
|
|
5035
|
+
${chalk17.dim("$")} mutagent install helix
|
|
5036
|
+
${chalk17.dim("$")} mutagent install helix --harness codex
|
|
5393
5037
|
${chalk17.dim("$")} mutagent install diagnostics
|
|
5394
5038
|
${chalk17.dim("$")} mutagent install evaluator --version 1.2.3
|
|
5395
5039
|
${chalk17.dim("$")} mutagent install diagnostics --harness codex --json
|
|
5396
5040
|
|
|
5397
5041
|
${chalk17.bold("Packages:")}
|
|
5042
|
+
${chalk17.bold("helix")} ${chalk17.green("(available)")} — the ADL conductor. Downloaded from a private
|
|
5043
|
+
registry via a login-brokered signed URL, sha256-verified, then
|
|
5044
|
+
initialized into your project. No static secret ships in the CLI.
|
|
5398
5045
|
${chalk17.bold("diagnostics")} Public npm package @mutagent/diagnostics ${chalk17.green("(available)")}
|
|
5399
5046
|
${chalk17.bold("evaluator")} Public npm package @mutagent/evaluator ${chalk17.green("(available)")}
|
|
5400
|
-
${chalk17.bold("helix")} ${chalk17.yellow("NOT yet available")} — self-host on install.mutagent.io is pending (#1191).
|
|
5401
|
-
Running it today errors with ${chalk17.bold("NOT_IMPLEMENTED")} by design (no fake install).
|
|
5402
5047
|
|
|
5403
5048
|
${chalk17.yellow("Note:")} install is login-gated. Run ${chalk17.cyan("mutagent login")} first (else exits with a login directive).
|
|
5404
5049
|
`).action(async (pkg, options) => {
|
|
@@ -5436,14 +5081,14 @@ if (process.env.CLI_VERSION) {
|
|
|
5436
5081
|
} else {
|
|
5437
5082
|
try {
|
|
5438
5083
|
const __dirname2 = dirname3(fileURLToPath2(import.meta.url));
|
|
5439
|
-
const pkgPath =
|
|
5440
|
-
const pkg = JSON.parse(
|
|
5084
|
+
const pkgPath = join12(__dirname2, "..", "..", "package.json");
|
|
5085
|
+
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
5441
5086
|
cliVersion = pkg.version ?? cliVersion;
|
|
5442
5087
|
} catch {}
|
|
5443
5088
|
}
|
|
5444
5089
|
setCliVersion(cliVersion);
|
|
5445
5090
|
var program = new Command12;
|
|
5446
|
-
program.name("mutagent").description(`MutagenT CLI -
|
|
5091
|
+
program.name("mutagent").description(`MutagenT CLI - command-line client for the MutagenT platform
|
|
5447
5092
|
|
|
5448
5093
|
Documentation: https://docs.mutagent.io/cli
|
|
5449
5094
|
Dashboard: https://app.mutagent.io`).option("-v, --version", "Display the version number").option("--json", "Output results as JSON (for AI agents)").option("--api-key <key>", "MutagenT API key").option("--endpoint <url>", "MutagenT server endpoint").option("--non-interactive", "Disable interactive prompts (for CI/AI agents)").configureHelp({
|
|
@@ -5554,12 +5199,12 @@ program.addCommand(createFeedbackCommand());
|
|
|
5554
5199
|
var isInteractive = process.stdin.isTTY && !rawArgs.includes("--json") && process.env.CI !== "true";
|
|
5555
5200
|
var isSkillCommand = rawArgs[0] === "skills" || rawArgs[0] === "hooks";
|
|
5556
5201
|
if (isInteractive && !isSkillCommand) {
|
|
5557
|
-
const skillPath =
|
|
5558
|
-
if (!
|
|
5202
|
+
const skillPath = join12(process.cwd(), ".claude/skills/mutagent-cli/SKILL.md");
|
|
5203
|
+
if (!existsSync10(skillPath)) {
|
|
5559
5204
|
console.log(chalk18.dim("MutagenT SKILL not installed. Install it for AI agent support? Run:"), chalk18.cyan("mutagent skills install"));
|
|
5560
5205
|
}
|
|
5561
5206
|
}
|
|
5562
5207
|
program.parse();
|
|
5563
5208
|
|
|
5564
|
-
//# debugId=
|
|
5209
|
+
//# debugId=9CA84168C389E42C64756E2164756E21
|
|
5565
5210
|
//# sourceMappingURL=cli.js.map
|