@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 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 readFileSync8, existsSync as existsSync9 } from "fs";
1297
- import { join as join11, dirname as dirname3 } from "path";
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 self-hosts.
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\` | self-hosted install | Pendingmay return \`NOT_IMPLEMENTED\` for now |
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
- - If \`helix\` returns \`NOT_IMPLEMENTED\`: explain that self-hosted helix install is still pending (tracked upstream) and suggest \`diagnostics\` / \`evaluator\`, which install from public npm today.
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 like the npm packages — it self-hosts and may not be wired yet.
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 (prompts, datasets, evaluations, optimizations, experiments)").addHelpText("after", `
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 prompts = await client.listPrompts();
4030
- const promptCount = prompts.length;
4031
- let datasetCount = 0;
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 optimizationCount = Array.isArray(optimizations) ? optimizations.length : 0;
4052
- const experimentCount = Array.isArray(experiments) ? experiments.length : 0;
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
- prompts: promptCount,
4060
- datasets: datasetCount,
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(` Prompts: ${chalk14.cyan(String(promptCount))}`);
4077
- console.log(` Datasets: ${chalk14.cyan(String(datasetCount))}`);
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(` Providers: ${chalk14.underline(PROVIDERS_URL)}`);
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 = spawn(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
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
- throw new MutagentError("NOT_IMPLEMENTED", "helix self-host install is not available yet — hosting on install.mutagent.io is pending (see issue #1191, task CI1).", "Track: gh issue view 1191. For now install diagnostics/evaluator via npm.");
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 = join11(__dirname2, "..", "..", "package.json");
5440
- const pkg = JSON.parse(readFileSync8(pkgPath, "utf-8"));
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 - AI-native prompt optimization platform
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 = join11(process.cwd(), ".claude/skills/mutagent-cli/SKILL.md");
5558
- if (!existsSync9(skillPath)) {
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=99CE977B18F421C764756E2164756E21
5209
+ //# debugId=9CA84168C389E42C64756E2164756E21
5565
5210
  //# sourceMappingURL=cli.js.map