@mutagent/cli 0.1.396 → 0.1.397
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 +37 -17
- package/dist/bin/cli.js +31095 -25976
- package/dist/index.js +547 -313
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -425,116 +425,357 @@ var init_config = __esm(() => {
|
|
|
425
425
|
CREDENTIALS_FILE = join(CREDENTIALS_DIR, "credentials.json");
|
|
426
426
|
});
|
|
427
427
|
|
|
428
|
-
// src/lib/
|
|
429
|
-
function
|
|
430
|
-
|
|
431
|
-
|
|
428
|
+
// src/lib/command-path.ts
|
|
429
|
+
function commandPathOf(command) {
|
|
430
|
+
const names = [];
|
|
431
|
+
for (let current = command;current.parent; current = current.parent) {
|
|
432
|
+
names.unshift(current.name());
|
|
432
433
|
}
|
|
433
|
-
|
|
434
|
-
return new MutagentError("UNKNOWN_ERROR", error.message, undefined, 1);
|
|
435
|
-
}
|
|
436
|
-
return new MutagentError("UNKNOWN_ERROR", typeof error === "string" ? error : "An unknown error occurred", undefined, 1);
|
|
434
|
+
return names.join(" ");
|
|
437
435
|
}
|
|
438
|
-
function
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
436
|
+
function setRunningCommandPath(path) {
|
|
437
|
+
runningPath = path;
|
|
438
|
+
}
|
|
439
|
+
function runningHelpCommand() {
|
|
440
|
+
return runningPath ? `mutagent ${runningPath} --help` : "mutagent --help";
|
|
441
|
+
}
|
|
442
|
+
var runningPath;
|
|
443
|
+
|
|
444
|
+
// src/lib/output.ts
|
|
445
|
+
import chalk from "chalk";
|
|
446
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
447
|
+
import { join as join2 } from "path";
|
|
448
|
+
function setCliVersion(version) {
|
|
449
|
+
_globalCliVersion = version;
|
|
450
|
+
_compatCache = null;
|
|
451
|
+
}
|
|
452
|
+
function getCliVersion() {
|
|
453
|
+
return _globalCliVersion;
|
|
454
|
+
}
|
|
455
|
+
function getCompatMetadata(cliVersion = _globalCliVersion) {
|
|
456
|
+
if (_compatCache !== null)
|
|
457
|
+
return _compatCache;
|
|
458
|
+
let skillVersion = "unknown";
|
|
459
|
+
let skillMinCliVersion = "unknown";
|
|
460
|
+
try {
|
|
461
|
+
const candidatePaths = [
|
|
462
|
+
join2(process.cwd(), ".claude", "skills", "mutagent-cli", "SKILL.md"),
|
|
463
|
+
join2(process.cwd(), "mutagent-cli", ".claude", "skills", "mutagent-cli", "SKILL.md")
|
|
464
|
+
];
|
|
465
|
+
for (const p of candidatePaths) {
|
|
466
|
+
if (existsSync2(p)) {
|
|
467
|
+
const content = readFileSync2(p, "utf-8");
|
|
468
|
+
const verMatch = /^\s+skill_version:\s+"?([^"\n]+)"?\s*$/m.exec(content);
|
|
469
|
+
const minMatch = /^\s+skill_min_cli_version:\s+"?([^"\n]+)"?\s*$/m.exec(content);
|
|
470
|
+
if (/^metadata:/m.test(content) && !verMatch && !minMatch) {
|
|
471
|
+
throw new Error("Bundled SKILL.md is missing metadata.skill_version / skill_min_cli_version" + " — re-run `bun run sync-skill` to regenerate.");
|
|
472
|
+
}
|
|
473
|
+
if (verMatch?.[1])
|
|
474
|
+
skillVersion = verMatch[1].trim();
|
|
475
|
+
if (minMatch?.[1])
|
|
476
|
+
skillMinCliVersion = minMatch[1].trim();
|
|
477
|
+
break;
|
|
461
478
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
479
|
+
}
|
|
480
|
+
} catch (err) {
|
|
481
|
+
if (err instanceof Error && err.message.startsWith("Bundled SKILL.md is missing")) {
|
|
482
|
+
throw err;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
_compatCache = { cliVersion, skillVersion, skillMinCliVersion };
|
|
486
|
+
return _compatCache;
|
|
487
|
+
}
|
|
488
|
+
function getJsonFlag(command) {
|
|
489
|
+
if (!command)
|
|
490
|
+
return false;
|
|
491
|
+
const parentOpts = command.parent ? command.parent.opts() : null;
|
|
492
|
+
const ownOpts = command.opts();
|
|
493
|
+
return Boolean(parentOpts?.json ?? ownOpts.json);
|
|
494
|
+
}
|
|
495
|
+
function startJsonLines() {
|
|
496
|
+
jsonLines = true;
|
|
497
|
+
}
|
|
498
|
+
function jsonText(value) {
|
|
499
|
+
return jsonLines ? JSON.stringify(value) : JSON.stringify(value, null, 2);
|
|
500
|
+
}
|
|
501
|
+
function withSuccess(value) {
|
|
502
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
503
|
+
return value;
|
|
504
|
+
if ("success" in value)
|
|
505
|
+
return value;
|
|
506
|
+
return { success: true, ...value };
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
class OutputFormatter {
|
|
510
|
+
format;
|
|
511
|
+
constructor(format) {
|
|
512
|
+
this.format = format;
|
|
513
|
+
}
|
|
514
|
+
output(data) {
|
|
515
|
+
const clean = scrubKnownSuccessDeep(data);
|
|
516
|
+
if (this.format === "json") {
|
|
517
|
+
let enriched = withSuccess(clean);
|
|
518
|
+
if (_globalCliVersion !== "0.0.0" && clean !== null && typeof clean === "object" && !Array.isArray(clean) && "_directive" in clean) {
|
|
519
|
+
enriched = {
|
|
520
|
+
...enriched,
|
|
521
|
+
_compat: getCompatMetadata(_globalCliVersion)
|
|
468
522
|
};
|
|
469
523
|
}
|
|
470
|
-
console.log(
|
|
524
|
+
console.log(jsonText(enriched));
|
|
471
525
|
} else {
|
|
472
|
-
|
|
473
|
-
if (error.name === "TenancyError") {} else if (error instanceof AuthenticationError) {
|
|
474
|
-
console.error("");
|
|
475
|
-
console.error(AUTH_REMEDIATION_MESSAGE);
|
|
476
|
-
} else if (error instanceof WorkspaceContextError) {
|
|
477
|
-
console.error("");
|
|
478
|
-
console.error(WORKSPACE_REMEDIATION_MESSAGE);
|
|
479
|
-
} else if (error instanceof ApiError && error.statusCode === 403) {
|
|
480
|
-
console.error("");
|
|
481
|
-
console.error("Access denied. To fix:");
|
|
482
|
-
console.error(" mutagent auth login --browser # Re-authenticate");
|
|
483
|
-
console.error(" export MUTAGENT_API_KEY=mt_xxx # Or use a different API key");
|
|
484
|
-
} else if (error instanceof ValidationError) {
|
|
485
|
-
if (error.suggestion) {
|
|
486
|
-
console.error(`Suggestion: ${scrubKnown(error.suggestion)}`);
|
|
487
|
-
}
|
|
488
|
-
console.error("");
|
|
489
|
-
console.error("Run `mutagent <command> --help` for usage information.");
|
|
490
|
-
} else if (error.suggestion) {
|
|
491
|
-
console.error(`Suggestion: ${scrubKnown(error.suggestion)}`);
|
|
492
|
-
}
|
|
493
|
-
if (error.code === "MISSING_ARGUMENTS" || error.code === "INVALID_ARGUMENTS" || error.code === "INVALID_INPUT") {
|
|
494
|
-
console.error("");
|
|
495
|
-
console.error("Run `mutagent <command> --help` for usage information.");
|
|
496
|
-
}
|
|
526
|
+
this.formatTable(clean);
|
|
497
527
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
if (
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
528
|
+
}
|
|
529
|
+
formatTable(data) {
|
|
530
|
+
if (Array.isArray(data)) {
|
|
531
|
+
this.formatArray(data);
|
|
532
|
+
} else if (data && typeof data === "object") {
|
|
533
|
+
this.formatObject(data);
|
|
534
|
+
} else {
|
|
535
|
+
console.log(data);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
formatArray(data) {
|
|
539
|
+
if (data.length === 0) {
|
|
540
|
+
console.log(chalk.gray("No results"));
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
const firstItem = data[0];
|
|
544
|
+
if (!firstItem || typeof firstItem !== "object") {
|
|
545
|
+
data.forEach((item) => {
|
|
546
|
+
console.log(` ${String(item)}`);
|
|
547
|
+
});
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
const keys = Object.keys(firstItem);
|
|
551
|
+
const toDisplayString = (val) => {
|
|
552
|
+
if (val === null || val === undefined)
|
|
553
|
+
return "";
|
|
554
|
+
if (typeof val === "object")
|
|
555
|
+
return JSON.stringify(val);
|
|
556
|
+
if (typeof val === "string")
|
|
557
|
+
return val;
|
|
558
|
+
if (typeof val === "number" || typeof val === "boolean" || typeof val === "bigint") {
|
|
559
|
+
return val.toString();
|
|
560
|
+
}
|
|
561
|
+
return JSON.stringify(val);
|
|
562
|
+
};
|
|
563
|
+
const widths = {};
|
|
564
|
+
keys.forEach((key) => {
|
|
565
|
+
widths[key] = Math.max(key.length, ...data.map((item) => toDisplayString(item[key]).length));
|
|
566
|
+
});
|
|
567
|
+
const header = keys.map((key) => chalk.bold(key.toUpperCase().padEnd(widths[key] ?? 10))).join(" ");
|
|
568
|
+
console.log(header);
|
|
569
|
+
console.log(keys.map((key) => "-".repeat(widths[key] ?? 10)).join(" "));
|
|
570
|
+
data.forEach((item) => {
|
|
571
|
+
const row = keys.map((key) => {
|
|
572
|
+
const value = toDisplayString(item[key]);
|
|
573
|
+
const width = widths[key] ?? 10;
|
|
574
|
+
return value.padEnd(width).slice(0, width);
|
|
575
|
+
}).join(" ");
|
|
576
|
+
console.log(row);
|
|
577
|
+
});
|
|
578
|
+
console.log(chalk.gray(`
|
|
579
|
+
${String(data.length)} result(s)`));
|
|
580
|
+
}
|
|
581
|
+
formatObject(data) {
|
|
582
|
+
const maxKeyLength = Math.max(...Object.keys(data).map((k) => k.length));
|
|
583
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
584
|
+
const formattedKey = chalk.bold(key.padEnd(maxKeyLength));
|
|
585
|
+
let formattedValue;
|
|
586
|
+
if (value === null || value === undefined) {
|
|
587
|
+
formattedValue = "";
|
|
588
|
+
} else if (typeof value === "object") {
|
|
589
|
+
formattedValue = JSON.stringify(value, null, 2);
|
|
590
|
+
} else if (typeof value === "string") {
|
|
591
|
+
formattedValue = value;
|
|
592
|
+
} else if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
593
|
+
formattedValue = value.toString();
|
|
507
594
|
} else {
|
|
508
|
-
|
|
509
|
-
if (wrapped.suggestion) {
|
|
510
|
-
console.error(`Suggestion: ${wrapped.suggestion}`);
|
|
511
|
-
}
|
|
595
|
+
formattedValue = JSON.stringify(value);
|
|
512
596
|
}
|
|
513
|
-
|
|
597
|
+
console.log(`${formattedKey} ${formattedValue}`);
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
success(message) {
|
|
601
|
+
const text = scrubKnownSuccess(message);
|
|
602
|
+
if (this.format === "json") {
|
|
603
|
+
console.log(JSON.stringify({ success: true, message: text }, null, 2));
|
|
604
|
+
} else {
|
|
605
|
+
console.log(chalk.green(`✓ ${text}`));
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
error(message, code, suggestedAction) {
|
|
609
|
+
const text = scrubKnownSuccess(message);
|
|
610
|
+
const action = suggestedAction === undefined ? undefined : scrubKnownSuccess(suggestedAction);
|
|
611
|
+
if (this.format === "json") {
|
|
612
|
+
const result = { success: false, error: text };
|
|
613
|
+
if (code)
|
|
614
|
+
result.code = code;
|
|
615
|
+
if (action)
|
|
616
|
+
result.suggestedAction = action;
|
|
617
|
+
console.log(JSON.stringify(result, null, 2));
|
|
618
|
+
} else {
|
|
619
|
+
console.log(chalk.red(`✗ ${text}`));
|
|
514
620
|
}
|
|
515
621
|
}
|
|
516
|
-
|
|
622
|
+
info(message) {
|
|
623
|
+
if (this.format !== "json") {
|
|
624
|
+
console.log(chalk.blue(`ℹ ${scrubKnownSuccess(message)}`));
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
warn(message) {
|
|
628
|
+
const text = scrubKnownSuccess(message);
|
|
629
|
+
if (this.format === "json") {
|
|
630
|
+
console.log(JSON.stringify({ warning: text }, null, 2));
|
|
631
|
+
} else {
|
|
632
|
+
console.log(chalk.yellow(`⚠ ${text}`));
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
function createSpinner(text, isJson) {
|
|
517
637
|
if (isJson) {
|
|
518
|
-
|
|
638
|
+
const noop = () => {
|
|
639
|
+
return;
|
|
640
|
+
};
|
|
641
|
+
return {
|
|
642
|
+
start: noop,
|
|
643
|
+
stop: noop,
|
|
644
|
+
succeed: noop,
|
|
645
|
+
fail: noop
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
const start = async () => {
|
|
649
|
+
const { default: ora } = await import("ora");
|
|
650
|
+
return ora(text).start();
|
|
651
|
+
};
|
|
652
|
+
return { start };
|
|
653
|
+
}
|
|
654
|
+
var _compatCache = null, _globalCliVersion = "0.0.0", jsonLines = false;
|
|
655
|
+
var init_output = __esm(() => {
|
|
656
|
+
init_known_secrets();
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
// src/lib/errors.ts
|
|
660
|
+
function exitCodeFor(code) {
|
|
661
|
+
if (KEY_REJECTED_CODES.has(code))
|
|
662
|
+
return EXIT_CODES.keyExpiredOrInvalid;
|
|
663
|
+
if (NOT_SIGNED_IN_CODES.has(code))
|
|
664
|
+
return EXIT_CODES.notSignedInOrNoWorkspace;
|
|
665
|
+
return EXIT_CODES.failure;
|
|
666
|
+
}
|
|
667
|
+
function createErrorFromUnknown(error) {
|
|
668
|
+
if (error instanceof MutagentError) {
|
|
669
|
+
return error;
|
|
670
|
+
}
|
|
671
|
+
const message = error instanceof Error ? error.message : typeof error === "string" ? error : "An unknown error occurred";
|
|
672
|
+
return new MutagentError("UNKNOWN_ERROR", message);
|
|
673
|
+
}
|
|
674
|
+
function runnableCommand(suggestion) {
|
|
675
|
+
const line = suggestion?.replace(/^(Run|See|To switch):\s+/, "").trim();
|
|
676
|
+
return line !== undefined && /^mutagent [^\s]/.test(line) && !/[\n:]|\s\(/.test(line) ? line : undefined;
|
|
677
|
+
}
|
|
678
|
+
function agentGuidance(error, own) {
|
|
679
|
+
const command = runnableCommand(error.suggestion);
|
|
680
|
+
const helpMatch = error.suggestion === undefined ? null : /^Run:\s+(mutagent\s+[^\n]+--help)$/.exec(error.suggestion);
|
|
681
|
+
const signIn = error.exitCode !== EXIT_CODES.failure && error.code !== "WORKSPACE_REQUIRED";
|
|
682
|
+
return {
|
|
683
|
+
helpCommand: helpMatch?.[1] ?? runningHelpCommand(),
|
|
684
|
+
suggestion: error.suggestion,
|
|
685
|
+
fix: command === undefined ? [] : [command],
|
|
686
|
+
notes: command === undefined && error.suggestion !== undefined ? [error.suggestion] : [],
|
|
687
|
+
...signIn ? { escalate: SIGN_IN_ESCALATION } : {},
|
|
688
|
+
...own !== null && typeof own === "object" ? own : {}
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
function errorBody(error) {
|
|
692
|
+
const body = { ...error.toJSON() };
|
|
693
|
+
if (error instanceof AuthenticationError)
|
|
694
|
+
body.remediation = { ...AUTH_REMEDIATION };
|
|
695
|
+
if (error instanceof WorkspaceContextError) {
|
|
696
|
+
body.remediation = { setWorkspace: "mutagent workspaces use <name>", listWorkspaces: "mutagent workspaces list" };
|
|
697
|
+
}
|
|
698
|
+
if (error instanceof ApiError && error.statusCode === 403) {
|
|
699
|
+
body.remediation = {
|
|
700
|
+
interactive: SIGN_IN_COMMAND,
|
|
701
|
+
nonInteractive: "export MUTAGENT_API_KEY=<your-key>",
|
|
702
|
+
checkPermissions: "Verify your API key has the required permissions"
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
const guidance = agentGuidance(error, body._agentGuidance);
|
|
706
|
+
body._agentGuidance = guidance;
|
|
707
|
+
if (typeof body.suggestedAction !== "string" || body.suggestedAction === "") {
|
|
708
|
+
body.suggestedAction = `Run: ${String(guidance.helpCommand)}`;
|
|
709
|
+
}
|
|
710
|
+
return body;
|
|
711
|
+
}
|
|
712
|
+
function printHuman(error) {
|
|
713
|
+
console.error(`Error: ${scrubKnown(error.message)}`);
|
|
714
|
+
if (error.name === "TenancyError") {} else if (error instanceof AuthenticationError && error.code === "AUTH_REQUIRED") {
|
|
715
|
+
console.error("");
|
|
716
|
+
console.error(AUTH_REMEDIATION_MESSAGE);
|
|
717
|
+
} else if (error instanceof WorkspaceContextError) {
|
|
718
|
+
console.error("");
|
|
719
|
+
console.error(WORKSPACE_REMEDIATION_MESSAGE);
|
|
720
|
+
} else if (error instanceof ApiError && error.statusCode === 403) {
|
|
721
|
+
console.error("");
|
|
722
|
+
console.error("Access denied. To fix:");
|
|
723
|
+
console.error(` ${SIGN_IN_COMMAND} # Re-authenticate`);
|
|
724
|
+
console.error(" export MUTAGENT_API_KEY=mg_live_... # Or use a different API key");
|
|
725
|
+
} else if (error.suggestion) {
|
|
726
|
+
console.error(`Suggestion: ${scrubKnown(error.suggestion)}`);
|
|
727
|
+
}
|
|
728
|
+
const usage = ["MISSING_ARGUMENTS", "INVALID_ARGUMENTS", "INVALID_INPUT", "VALIDATION_ERROR", "UNKNOWN_OPTION", "UNKNOWN_COMMAND"];
|
|
729
|
+
if (usage.includes(error.code) && !(error.suggestion ?? "").includes(runningHelpCommand())) {
|
|
730
|
+
console.error("");
|
|
731
|
+
console.error(`Run \`${runningHelpCommand()}\` for usage information.`);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
function asSdkError(error) {
|
|
735
|
+
if (!error || typeof error !== "object")
|
|
736
|
+
return;
|
|
737
|
+
const sdkErr = error;
|
|
738
|
+
if (sdkErr.name !== "SDKValidationError" && sdkErr.name !== "SDKError" && sdkErr.rawValue === undefined && sdkErr.rawMessage === undefined) {
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
return new MutagentError("REQUEST_FAILED", scrubKnown(sdkErr.rawMessage ?? sdkErr.message ?? "Request failed"), "Check your input and try again. Run the command with --help for usage details.");
|
|
742
|
+
}
|
|
743
|
+
function toFailure(error) {
|
|
744
|
+
return error instanceof MutagentError ? error : asSdkError(error) ?? new MutagentError("UNKNOWN_ERROR", error instanceof Error ? scrubKnown(error.message) : "Unknown error", 'If it keeps happening, report it: mutagent feedback send "<what happened>" --category cli');
|
|
745
|
+
}
|
|
746
|
+
function handleError(error, isJson) {
|
|
747
|
+
const failure = toFailure(error);
|
|
748
|
+
if (isJson) {
|
|
749
|
+
console.log(jsonText(scrubKnownDeep(errorBody(failure))));
|
|
519
750
|
} else {
|
|
520
|
-
|
|
751
|
+
printHuman(failure);
|
|
521
752
|
}
|
|
522
|
-
process.exit(
|
|
753
|
+
process.exit(failure.exitCode);
|
|
523
754
|
}
|
|
524
|
-
var MutagentError, AUTH_REMEDIATION_MESSAGE, AuthenticationError, ApiError, WORKSPACE_REMEDIATION_MESSAGE, WorkspaceContextError, ValidationError, NetworkError, RateLimitError, NotFoundError;
|
|
755
|
+
var EXIT_CODES, KEY_REJECTED_CODES, NOT_SIGNED_IN_CODES, EXIT_CODES_LINE = "Exit codes: 0 success · 1 failure (usage errors included) · 2 key expired or invalid · 3 not signed in or no workspace", MutagentError, SIGN_IN_COMMAND = "mutagent login --browser", SIGN_IN_WITH_KEY = "export MUTAGENT_API_KEY=<key>, then: mutagent login --json", AUTH_REMEDIATION_MESSAGE, AUTH_REMEDIATION, AuthenticationError, ApiError, WORKSPACE_REMEDIATION_MESSAGE, WorkspaceContextError, ValidationError, NetworkError, RateLimitError, NotFoundError, SIGN_IN_ESCALATION = "Signing in needs a person at a browser, or a MUTAGENT_API_KEY from them.";
|
|
525
756
|
var init_errors = __esm(() => {
|
|
526
757
|
init_known_secrets();
|
|
758
|
+
init_output();
|
|
759
|
+
EXIT_CODES = {
|
|
760
|
+
success: 0,
|
|
761
|
+
failure: 1,
|
|
762
|
+
keyExpiredOrInvalid: 2,
|
|
763
|
+
notSignedInOrNoWorkspace: 3
|
|
764
|
+
};
|
|
765
|
+
KEY_REJECTED_CODES = new Set(["AUTH_EXPIRED", "INVALID_API_KEY", "FOREIGN_API_KEY", "API_401", "SANDBOX_TOKEN_REFUSED"]);
|
|
766
|
+
NOT_SIGNED_IN_CODES = new Set(["AUTH_REQUIRED", "WORKSPACE_REQUIRED", "SANDBOX_WORKSPACE_FORBIDDEN"]);
|
|
527
767
|
MutagentError = class MutagentError extends Error {
|
|
528
768
|
code;
|
|
529
769
|
suggestion;
|
|
530
|
-
|
|
531
|
-
constructor(code, message, suggestion, exitCode = 1) {
|
|
770
|
+
constructor(code, message, suggestion) {
|
|
532
771
|
super(message);
|
|
533
772
|
this.code = code;
|
|
534
773
|
this.suggestion = suggestion;
|
|
535
|
-
this.exitCode = exitCode;
|
|
536
774
|
this.name = "MutagentError";
|
|
537
775
|
}
|
|
776
|
+
get exitCode() {
|
|
777
|
+
return exitCodeFor(this.code);
|
|
778
|
+
}
|
|
538
779
|
toJSON() {
|
|
539
780
|
return {
|
|
540
781
|
success: false,
|
|
@@ -546,29 +787,34 @@ var init_errors = __esm(() => {
|
|
|
546
787
|
};
|
|
547
788
|
AUTH_REMEDIATION_MESSAGE = [
|
|
548
789
|
"Authentication required. Options:",
|
|
549
|
-
|
|
790
|
+
` Interactive: ${SIGN_IN_COMMAND}`,
|
|
550
791
|
" Non-interactive: export MUTAGENT_API_KEY=<your-key>",
|
|
551
|
-
|
|
792
|
+
` CI/CD: ${SIGN_IN_WITH_KEY}`
|
|
552
793
|
].join(`
|
|
553
794
|
`);
|
|
795
|
+
AUTH_REMEDIATION = {
|
|
796
|
+
interactive: SIGN_IN_COMMAND,
|
|
797
|
+
nonInteractive: "export MUTAGENT_API_KEY=<your-key>",
|
|
798
|
+
ciCd: SIGN_IN_WITH_KEY
|
|
799
|
+
};
|
|
554
800
|
AuthenticationError = class AuthenticationError extends MutagentError {
|
|
555
801
|
suggestions;
|
|
556
802
|
cause;
|
|
557
803
|
constructor(message, options = {}) {
|
|
558
|
-
|
|
804
|
+
const suggestion = options.suggestions ? options.suggestions[0] : `Run: ${SIGN_IN_COMMAND}`;
|
|
805
|
+
super("AUTH_REQUIRED", message ?? "Not signed in. Run: mutagent login", suggestion);
|
|
559
806
|
this.suggestions = options.suggestions ?? [
|
|
560
|
-
|
|
807
|
+
SIGN_IN_COMMAND,
|
|
561
808
|
"export MUTAGENT_API_KEY=<your-key>",
|
|
562
|
-
|
|
809
|
+
SIGN_IN_WITH_KEY
|
|
563
810
|
];
|
|
564
|
-
this.suggestion = options.suggestions ? options.suggestions[0] : "Run: mutagent auth login --browser";
|
|
565
811
|
this.cause = options.cause;
|
|
566
812
|
}
|
|
567
813
|
};
|
|
568
814
|
ApiError = class ApiError extends MutagentError {
|
|
569
815
|
statusCode;
|
|
570
816
|
constructor(status, message) {
|
|
571
|
-
super(`API_${String(status)}`, scrubKnown(message), status === 401 ? "Check your API key with: mutagent auth status" : undefined
|
|
817
|
+
super(`API_${String(status)}`, scrubKnown(message), status === 401 ? "Check your API key with: mutagent auth status" : undefined);
|
|
572
818
|
this.statusCode = status;
|
|
573
819
|
}
|
|
574
820
|
};
|
|
@@ -580,19 +826,19 @@ var init_errors = __esm(() => {
|
|
|
580
826
|
`);
|
|
581
827
|
WorkspaceContextError = class WorkspaceContextError extends MutagentError {
|
|
582
828
|
constructor(message) {
|
|
583
|
-
super("WORKSPACE_REQUIRED", message ?? "Workspace context is required but not configured", "Run: mutagent workspaces use <name>"
|
|
829
|
+
super("WORKSPACE_REQUIRED", message ?? "Workspace context is required but not configured", "Run: mutagent workspaces use <name>");
|
|
584
830
|
}
|
|
585
831
|
};
|
|
586
832
|
ValidationError = class ValidationError extends MutagentError {
|
|
587
833
|
constructor(message) {
|
|
588
|
-
super("VALIDATION_ERROR", message, "Check the command syntax with: mutagent <command> --help"
|
|
834
|
+
super("VALIDATION_ERROR", message, "Check the command syntax with: mutagent <command> --help");
|
|
589
835
|
}
|
|
590
836
|
};
|
|
591
837
|
NetworkError = class NetworkError extends MutagentError {
|
|
592
838
|
url;
|
|
593
839
|
statusCode;
|
|
594
840
|
constructor(message = "Network error", url, statusCode) {
|
|
595
|
-
super("NETWORK_ERROR", message, "Check your internet connection and verify the server URL"
|
|
841
|
+
super("NETWORK_ERROR", message, "Check your internet connection and verify the server URL");
|
|
596
842
|
this.url = url;
|
|
597
843
|
this.statusCode = statusCode;
|
|
598
844
|
}
|
|
@@ -604,12 +850,208 @@ var init_errors = __esm(() => {
|
|
|
604
850
|
this.code = "RATE_LIMIT_ERROR";
|
|
605
851
|
this.suggestion = retryAfter ? `Wait ${String(retryAfter)} seconds before retrying` : "Wait a few seconds before retrying";
|
|
606
852
|
this.retryAfter = retryAfter;
|
|
607
|
-
this.exitCode = 6;
|
|
608
853
|
}
|
|
609
854
|
};
|
|
610
855
|
NotFoundError = class NotFoundError extends MutagentError {
|
|
611
856
|
constructor(resource, id) {
|
|
612
|
-
super("NOT_FOUND", `${resource} not found: ${id}`, `Check the ID and try again. List available ${resource.toLowerCase()}s with the appropriate list command
|
|
857
|
+
super("NOT_FOUND", `${resource} not found: ${id}`, `Check the ID and try again. List available ${resource.toLowerCase()}s with the appropriate list command.`);
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
// src/lib/secret-scan.ts
|
|
863
|
+
function foreignCredential(key) {
|
|
864
|
+
const hit = FOREIGN_KEY_PREFIXES.find((family) => family.prefix.test(key));
|
|
865
|
+
if (hit === undefined)
|
|
866
|
+
return;
|
|
867
|
+
const label = PATTERNS.find((pattern) => pattern.kind === hit.kind)?.label ?? "credential from another service";
|
|
868
|
+
return { kind: hit.kind, label };
|
|
869
|
+
}
|
|
870
|
+
function hasCredentialEntropy(candidate) {
|
|
871
|
+
if (candidate.length < 16)
|
|
872
|
+
return false;
|
|
873
|
+
const distinct = new Set(candidate).size;
|
|
874
|
+
if (distinct < 8)
|
|
875
|
+
return false;
|
|
876
|
+
return !/(.)\1{7,}/.test(candidate);
|
|
877
|
+
}
|
|
878
|
+
function maskSecret(secret) {
|
|
879
|
+
const head = secret.slice(0, 6);
|
|
880
|
+
return `${head}${"*".repeat(Math.min(12, Math.max(4, secret.length - head.length)))}`;
|
|
881
|
+
}
|
|
882
|
+
function collectHits(content) {
|
|
883
|
+
const accepted = [];
|
|
884
|
+
const overlaps = (start, end) => accepted.some((hit) => start < hit.end && end > hit.start);
|
|
885
|
+
for (const pattern of PATTERNS) {
|
|
886
|
+
const regex = new RegExp(pattern.regex.source, pattern.regex.flags);
|
|
887
|
+
let match;
|
|
888
|
+
while ((match = regex.exec(content)) !== null) {
|
|
889
|
+
if (match[0].length === 0) {
|
|
890
|
+
regex.lastIndex += 1;
|
|
891
|
+
continue;
|
|
892
|
+
}
|
|
893
|
+
const captured = match[1];
|
|
894
|
+
const secret = captured ?? match[0];
|
|
895
|
+
const start = captured === undefined ? match.index : match.index + match[0].indexOf(captured);
|
|
896
|
+
const end = start + secret.length;
|
|
897
|
+
const exemptFromEntropy = pattern.kind === "private-key";
|
|
898
|
+
if (!exemptFromEntropy && !hasCredentialEntropy(secret))
|
|
899
|
+
continue;
|
|
900
|
+
if (overlaps(start, end))
|
|
901
|
+
continue;
|
|
902
|
+
accepted.push({ kind: pattern.kind, label: pattern.label, start, end, secret });
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
return accepted.sort((a, b) => a.start - b.start);
|
|
906
|
+
}
|
|
907
|
+
function lineOf(content, offset) {
|
|
908
|
+
let line = 1;
|
|
909
|
+
for (let i = 0;i < offset && i < content.length; i++) {
|
|
910
|
+
if (content[i] === `
|
|
911
|
+
`)
|
|
912
|
+
line++;
|
|
913
|
+
}
|
|
914
|
+
return line;
|
|
915
|
+
}
|
|
916
|
+
function redactSecrets(content) {
|
|
917
|
+
if (!content)
|
|
918
|
+
return { content, matches: [] };
|
|
919
|
+
const hits = collectHits(content);
|
|
920
|
+
if (hits.length === 0)
|
|
921
|
+
return { content, matches: [] };
|
|
922
|
+
let out = "";
|
|
923
|
+
let cursor = 0;
|
|
924
|
+
for (const hit of hits) {
|
|
925
|
+
out += content.slice(cursor, hit.start);
|
|
926
|
+
out += `[REDACTED:${hit.kind}]`;
|
|
927
|
+
cursor = hit.end;
|
|
928
|
+
}
|
|
929
|
+
out += content.slice(cursor);
|
|
930
|
+
return {
|
|
931
|
+
content: out,
|
|
932
|
+
matches: hits.map((hit) => ({
|
|
933
|
+
kind: hit.kind,
|
|
934
|
+
label: hit.label,
|
|
935
|
+
line: lineOf(content, hit.start),
|
|
936
|
+
preview: maskSecret(hit.secret)
|
|
937
|
+
}))
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
var PATTERNS, FOREIGN_KEY_PREFIXES;
|
|
941
|
+
var init_secret_scan = __esm(() => {
|
|
942
|
+
PATTERNS = [
|
|
943
|
+
{
|
|
944
|
+
kind: "private-key",
|
|
945
|
+
label: "Private key block",
|
|
946
|
+
regex: /-----BEGIN(?: [A-Z]+)* PRIVATE KEY-----[\s\S]*?-----END(?: [A-Z]+)* PRIVATE KEY-----/g
|
|
947
|
+
},
|
|
948
|
+
{
|
|
949
|
+
kind: "anthropic-api-key",
|
|
950
|
+
label: "Anthropic API key",
|
|
951
|
+
regex: /sk-ant-[A-Za-z0-9_-]{16,}/g
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
kind: "openai-api-key",
|
|
955
|
+
label: "OpenAI API key",
|
|
956
|
+
regex: /sk-(?!ant-)(?:proj-)?[A-Za-z0-9_-]{20,}/g
|
|
957
|
+
},
|
|
958
|
+
{
|
|
959
|
+
kind: "aws-access-key-id",
|
|
960
|
+
label: "AWS access key ID",
|
|
961
|
+
regex: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g
|
|
962
|
+
},
|
|
963
|
+
{
|
|
964
|
+
kind: "github-token",
|
|
965
|
+
label: "GitHub token",
|
|
966
|
+
regex: /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b|\bgithub_pat_[A-Za-z0-9_]{22,}\b/g
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
kind: "google-api-key",
|
|
970
|
+
label: "Google API key",
|
|
971
|
+
regex: /\bAIza[0-9A-Za-z_-]{35}\b/g
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
kind: "slack-token",
|
|
975
|
+
label: "Slack token",
|
|
976
|
+
regex: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g
|
|
977
|
+
},
|
|
978
|
+
{
|
|
979
|
+
kind: "mutagent-api-key",
|
|
980
|
+
label: "Mutagent API key",
|
|
981
|
+
regex: /\bmt_[A-Za-z0-9]{16,}\b/g
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
kind: "bearer-token",
|
|
985
|
+
label: "Bearer token",
|
|
986
|
+
regex: /\bBearer\s+([A-Za-z0-9._-]{20,})/g
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
kind: "generic-assignment",
|
|
990
|
+
label: "Credential assignment",
|
|
991
|
+
regex: /(?:api[_-]?key|apikey|secret|password|passwd|token|access[_-]?key)["']?\s*[:=]\s*["']?([A-Za-z0-9._/+-]{16,})/gi
|
|
992
|
+
}
|
|
993
|
+
];
|
|
994
|
+
FOREIGN_KEY_PREFIXES = [
|
|
995
|
+
{ kind: "anthropic-api-key", prefix: /^sk-ant-/ },
|
|
996
|
+
{ kind: "openai-api-key", prefix: /^sk-/ },
|
|
997
|
+
{ kind: "aws-access-key-id", prefix: /^(?:AKIA|ASIA)[0-9A-Z]/ },
|
|
998
|
+
{ kind: "github-token", prefix: /^(?:gh[pousr]_|github_pat_)/ },
|
|
999
|
+
{ kind: "google-api-key", prefix: /^AIza/ },
|
|
1000
|
+
{ kind: "slack-token", prefix: /^xox[baprs]-/ }
|
|
1001
|
+
];
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
// src/lib/key-check.ts
|
|
1005
|
+
async function checkApiKey(apiKey, endpoint) {
|
|
1006
|
+
let response;
|
|
1007
|
+
try {
|
|
1008
|
+
response = await fetch(`${endpoint}/api/providers`, { headers: { "x-api-key": apiKey } });
|
|
1009
|
+
} catch (error) {
|
|
1010
|
+
return { ok: false, reason: "unreachable", cause: error instanceof Error ? error.message : String(error) };
|
|
1011
|
+
}
|
|
1012
|
+
if (response.ok)
|
|
1013
|
+
return { ok: true };
|
|
1014
|
+
if (response.status === 401 || response.status === 403)
|
|
1015
|
+
return { ok: false, reason: "rejected", status: response.status };
|
|
1016
|
+
return { ok: false, reason: "failed", status: response.status };
|
|
1017
|
+
}
|
|
1018
|
+
function endpointUnreachableError(endpoint, cause) {
|
|
1019
|
+
const why = cause ? ` (${cause})` : "";
|
|
1020
|
+
return new MutagentError("ENDPOINT_UNREACHABLE", `Could not reach the Mutagent server at ${endpoint}${why}. The API key was not checked.`, "Check the endpoint (MUTAGENT_ENDPOINT or --endpoint) and the network, then run the same command again.");
|
|
1021
|
+
}
|
|
1022
|
+
function keyCheckError(check, endpoint) {
|
|
1023
|
+
if (check.reason === "unreachable")
|
|
1024
|
+
return endpointUnreachableError(endpoint, check.cause);
|
|
1025
|
+
if (check.reason === "rejected") {
|
|
1026
|
+
return new MutagentError("INVALID_API_KEY", `The API key was rejected by ${endpoint} (HTTP ${String(check.status)}).`, "Run: mutagent login --browser");
|
|
1027
|
+
}
|
|
1028
|
+
return new MutagentError("KEY_CHECK_FAILED", `The Mutagent server at ${endpoint} answered HTTP ${String(check.status)} while checking the API key.`, "Run the same command again; if it keeps failing, check the endpoint with: mutagent config get endpoint");
|
|
1029
|
+
}
|
|
1030
|
+
function assertMutagentKey(apiKey, source) {
|
|
1031
|
+
const foreign = foreignCredential(apiKey.trim());
|
|
1032
|
+
if (foreign !== undefined)
|
|
1033
|
+
throw new ForeignApiKeyError(source, foreign.label);
|
|
1034
|
+
}
|
|
1035
|
+
var ForeignApiKeyError;
|
|
1036
|
+
var init_key_check = __esm(() => {
|
|
1037
|
+
init_errors();
|
|
1038
|
+
init_secret_scan();
|
|
1039
|
+
ForeignApiKeyError = class ForeignApiKeyError extends MutagentError {
|
|
1040
|
+
constructor(source, label) {
|
|
1041
|
+
super("FOREIGN_API_KEY", `${source} looks like ${/^[AEIOU]/.test(label) ? "an" : "a"} ${label}, not a Mutagent API key. Nothing was sent.`, "Run: mutagent login --browser");
|
|
1042
|
+
this.name = "ForeignApiKeyError";
|
|
1043
|
+
}
|
|
1044
|
+
toJSON() {
|
|
1045
|
+
return {
|
|
1046
|
+
...super.toJSON(),
|
|
1047
|
+
_agentGuidance: {
|
|
1048
|
+
fix: ["mutagent login --browser"],
|
|
1049
|
+
notes: [
|
|
1050
|
+
"Mutagent API keys come from signing in (mutagent login), or from the dashboard; they start with mg_live_.",
|
|
1051
|
+
"An LLM provider key belongs in the workspace: mutagent providers add --provider <type> --name <name> --api-key <key>"
|
|
1052
|
+
]
|
|
1053
|
+
}
|
|
1054
|
+
};
|
|
613
1055
|
}
|
|
614
1056
|
};
|
|
615
1057
|
});
|
|
@@ -674,7 +1116,7 @@ function parseBody(body) {
|
|
|
674
1116
|
return {};
|
|
675
1117
|
}
|
|
676
1118
|
function deadKeyError() {
|
|
677
|
-
return new TenancyError("AUTH_EXPIRED", "Your CLI key expired or was revoked.", "Run: mutagent login"
|
|
1119
|
+
return new TenancyError("AUTH_EXPIRED", "Your CLI key expired or was revoked.", "Run: mutagent login");
|
|
678
1120
|
}
|
|
679
1121
|
function tenancyFailure(status, body, ctx) {
|
|
680
1122
|
const parsed = parseBody(body);
|
|
@@ -698,7 +1140,7 @@ function tenancyFailure(status, body, ctx) {
|
|
|
698
1140
|
}
|
|
699
1141
|
function noWorkspaceSelected() {
|
|
700
1142
|
const fix = envKeyReplacesFile() ? ENV_KEY_WORKSPACE_FIX : "Run: mutagent workspaces use <name>";
|
|
701
|
-
return new TenancyError("WORKSPACE_REQUIRED", "No workspace selected.", fix
|
|
1143
|
+
return new TenancyError("WORKSPACE_REQUIRED", "No workspace selected.", fix);
|
|
702
1144
|
}
|
|
703
1145
|
function envKeyHasNoSelection() {
|
|
704
1146
|
return new TenancyError("WORKSPACE_FROM_ENV", "With MUTAGENT_API_KEY set, the workspace comes from --workspace or MUTAGENT_WORKSPACE_ID.", ENV_KEY_WORKSPACE_FIX);
|
|
@@ -889,8 +1331,8 @@ var init_organization_scope = __esm(() => {
|
|
|
889
1331
|
init_config();
|
|
890
1332
|
UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
891
1333
|
TenancyError = class TenancyError extends MutagentError {
|
|
892
|
-
constructor(code, what, fix
|
|
893
|
-
super(code, `${what} ${fix}`, fix.replace(/^(Run|See|To switch): /, "")
|
|
1334
|
+
constructor(code, what, fix) {
|
|
1335
|
+
super(code, `${what} ${fix}`, fix.replace(/^(Run|See|To switch): /, ""));
|
|
894
1336
|
this.name = "TenancyError";
|
|
895
1337
|
}
|
|
896
1338
|
};
|
|
@@ -1485,19 +1927,13 @@ function resetSDKClient() {
|
|
|
1485
1927
|
sdkClient = null;
|
|
1486
1928
|
}
|
|
1487
1929
|
async function validateApiKey(apiKey, endpoint) {
|
|
1488
|
-
|
|
1489
|
-
const response = await fetch(`${endpoint}/api/providers`, {
|
|
1490
|
-
headers: { "x-api-key": apiKey }
|
|
1491
|
-
});
|
|
1492
|
-
return response.ok;
|
|
1493
|
-
} catch {
|
|
1494
|
-
return false;
|
|
1495
|
-
}
|
|
1930
|
+
return (await checkApiKey(apiKey, endpoint)).ok;
|
|
1496
1931
|
}
|
|
1497
1932
|
var SDK_TRANSPORT_ERRORS, sdkClient = null;
|
|
1498
1933
|
var init_sdk_client = __esm(() => {
|
|
1499
1934
|
init_errors();
|
|
1500
1935
|
init_config();
|
|
1936
|
+
init_key_check();
|
|
1501
1937
|
init_organization_scope();
|
|
1502
1938
|
init_sdk_debug();
|
|
1503
1939
|
init_known_secrets();
|
|
@@ -1509,209 +1945,7 @@ var init_sdk_client = __esm(() => {
|
|
|
1509
1945
|
// src/index.ts
|
|
1510
1946
|
init_config();
|
|
1511
1947
|
init_sdk_client();
|
|
1512
|
-
|
|
1513
|
-
// src/lib/output.ts
|
|
1514
|
-
init_known_secrets();
|
|
1515
|
-
import chalk from "chalk";
|
|
1516
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
1517
|
-
import { join as join2 } from "path";
|
|
1518
|
-
var _compatCache = null;
|
|
1519
|
-
var _globalCliVersion = "0.0.0";
|
|
1520
|
-
function setCliVersion(version) {
|
|
1521
|
-
_globalCliVersion = version;
|
|
1522
|
-
_compatCache = null;
|
|
1523
|
-
}
|
|
1524
|
-
function getCliVersion() {
|
|
1525
|
-
return _globalCliVersion;
|
|
1526
|
-
}
|
|
1527
|
-
function getCompatMetadata(cliVersion = _globalCliVersion) {
|
|
1528
|
-
if (_compatCache !== null)
|
|
1529
|
-
return _compatCache;
|
|
1530
|
-
let skillVersion = "unknown";
|
|
1531
|
-
let skillMinCliVersion = "unknown";
|
|
1532
|
-
try {
|
|
1533
|
-
const candidatePaths = [
|
|
1534
|
-
join2(process.cwd(), ".claude", "skills", "mutagent-cli", "SKILL.md"),
|
|
1535
|
-
join2(process.cwd(), "mutagent-cli", ".claude", "skills", "mutagent-cli", "SKILL.md")
|
|
1536
|
-
];
|
|
1537
|
-
for (const p of candidatePaths) {
|
|
1538
|
-
if (existsSync2(p)) {
|
|
1539
|
-
const content = readFileSync2(p, "utf-8");
|
|
1540
|
-
const verMatch = /^\s+skill_version:\s+"?([^"\n]+)"?\s*$/m.exec(content);
|
|
1541
|
-
const minMatch = /^\s+skill_min_cli_version:\s+"?([^"\n]+)"?\s*$/m.exec(content);
|
|
1542
|
-
if (/^metadata:/m.test(content) && !verMatch && !minMatch) {
|
|
1543
|
-
throw new Error("Bundled SKILL.md is missing metadata.skill_version / skill_min_cli_version" + " — re-run `bun run sync-skill` to regenerate.");
|
|
1544
|
-
}
|
|
1545
|
-
if (verMatch?.[1])
|
|
1546
|
-
skillVersion = verMatch[1].trim();
|
|
1547
|
-
if (minMatch?.[1])
|
|
1548
|
-
skillMinCliVersion = minMatch[1].trim();
|
|
1549
|
-
break;
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
|
-
} catch (err) {
|
|
1553
|
-
if (err instanceof Error && err.message.startsWith("Bundled SKILL.md is missing")) {
|
|
1554
|
-
throw err;
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
_compatCache = { cliVersion, skillVersion, skillMinCliVersion };
|
|
1558
|
-
return _compatCache;
|
|
1559
|
-
}
|
|
1560
|
-
function getJsonFlag(command) {
|
|
1561
|
-
if (!command)
|
|
1562
|
-
return false;
|
|
1563
|
-
const parentOpts = command.parent ? command.parent.opts() : null;
|
|
1564
|
-
const ownOpts = command.opts();
|
|
1565
|
-
return Boolean(parentOpts?.json ?? ownOpts.json);
|
|
1566
|
-
}
|
|
1567
|
-
|
|
1568
|
-
class OutputFormatter {
|
|
1569
|
-
format;
|
|
1570
|
-
constructor(format2) {
|
|
1571
|
-
this.format = format2;
|
|
1572
|
-
}
|
|
1573
|
-
output(data) {
|
|
1574
|
-
const clean = scrubKnownSuccessDeep(data);
|
|
1575
|
-
if (this.format === "json") {
|
|
1576
|
-
let enriched = clean;
|
|
1577
|
-
if (_globalCliVersion !== "0.0.0" && clean !== null && typeof clean === "object" && !Array.isArray(clean) && "_directive" in clean) {
|
|
1578
|
-
enriched = {
|
|
1579
|
-
...clean,
|
|
1580
|
-
_compat: getCompatMetadata(_globalCliVersion)
|
|
1581
|
-
};
|
|
1582
|
-
}
|
|
1583
|
-
console.log(JSON.stringify(enriched, null, 2));
|
|
1584
|
-
} else {
|
|
1585
|
-
this.formatTable(clean);
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1588
|
-
formatTable(data) {
|
|
1589
|
-
if (Array.isArray(data)) {
|
|
1590
|
-
this.formatArray(data);
|
|
1591
|
-
} else if (data && typeof data === "object") {
|
|
1592
|
-
this.formatObject(data);
|
|
1593
|
-
} else {
|
|
1594
|
-
console.log(data);
|
|
1595
|
-
}
|
|
1596
|
-
}
|
|
1597
|
-
formatArray(data) {
|
|
1598
|
-
if (data.length === 0) {
|
|
1599
|
-
console.log(chalk.gray("No results"));
|
|
1600
|
-
return;
|
|
1601
|
-
}
|
|
1602
|
-
const firstItem = data[0];
|
|
1603
|
-
if (!firstItem || typeof firstItem !== "object") {
|
|
1604
|
-
data.forEach((item) => {
|
|
1605
|
-
console.log(` ${String(item)}`);
|
|
1606
|
-
});
|
|
1607
|
-
return;
|
|
1608
|
-
}
|
|
1609
|
-
const keys = Object.keys(firstItem);
|
|
1610
|
-
const toDisplayString = (val) => {
|
|
1611
|
-
if (val === null || val === undefined)
|
|
1612
|
-
return "";
|
|
1613
|
-
if (typeof val === "object")
|
|
1614
|
-
return JSON.stringify(val);
|
|
1615
|
-
if (typeof val === "string")
|
|
1616
|
-
return val;
|
|
1617
|
-
if (typeof val === "number" || typeof val === "boolean" || typeof val === "bigint") {
|
|
1618
|
-
return val.toString();
|
|
1619
|
-
}
|
|
1620
|
-
return JSON.stringify(val);
|
|
1621
|
-
};
|
|
1622
|
-
const widths = {};
|
|
1623
|
-
keys.forEach((key) => {
|
|
1624
|
-
widths[key] = Math.max(key.length, ...data.map((item) => toDisplayString(item[key]).length));
|
|
1625
|
-
});
|
|
1626
|
-
const header = keys.map((key) => chalk.bold(key.toUpperCase().padEnd(widths[key] ?? 10))).join(" ");
|
|
1627
|
-
console.log(header);
|
|
1628
|
-
console.log(keys.map((key) => "-".repeat(widths[key] ?? 10)).join(" "));
|
|
1629
|
-
data.forEach((item) => {
|
|
1630
|
-
const row = keys.map((key) => {
|
|
1631
|
-
const value = toDisplayString(item[key]);
|
|
1632
|
-
const width = widths[key] ?? 10;
|
|
1633
|
-
return value.padEnd(width).slice(0, width);
|
|
1634
|
-
}).join(" ");
|
|
1635
|
-
console.log(row);
|
|
1636
|
-
});
|
|
1637
|
-
console.log(chalk.gray(`
|
|
1638
|
-
${String(data.length)} result(s)`));
|
|
1639
|
-
}
|
|
1640
|
-
formatObject(data) {
|
|
1641
|
-
const maxKeyLength = Math.max(...Object.keys(data).map((k) => k.length));
|
|
1642
|
-
Object.entries(data).forEach(([key, value]) => {
|
|
1643
|
-
const formattedKey = chalk.bold(key.padEnd(maxKeyLength));
|
|
1644
|
-
let formattedValue;
|
|
1645
|
-
if (value === null || value === undefined) {
|
|
1646
|
-
formattedValue = "";
|
|
1647
|
-
} else if (typeof value === "object") {
|
|
1648
|
-
formattedValue = JSON.stringify(value, null, 2);
|
|
1649
|
-
} else if (typeof value === "string") {
|
|
1650
|
-
formattedValue = value;
|
|
1651
|
-
} else if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
1652
|
-
formattedValue = value.toString();
|
|
1653
|
-
} else {
|
|
1654
|
-
formattedValue = JSON.stringify(value);
|
|
1655
|
-
}
|
|
1656
|
-
console.log(`${formattedKey} ${formattedValue}`);
|
|
1657
|
-
});
|
|
1658
|
-
}
|
|
1659
|
-
success(message) {
|
|
1660
|
-
const text = scrubKnownSuccess(message);
|
|
1661
|
-
if (this.format === "json") {
|
|
1662
|
-
console.log(JSON.stringify({ success: true, message: text }, null, 2));
|
|
1663
|
-
} else {
|
|
1664
|
-
console.log(chalk.green(`✓ ${text}`));
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
error(message, code, suggestedAction) {
|
|
1668
|
-
const text = scrubKnownSuccess(message);
|
|
1669
|
-
const action = suggestedAction === undefined ? undefined : scrubKnownSuccess(suggestedAction);
|
|
1670
|
-
if (this.format === "json") {
|
|
1671
|
-
const result = { success: false, error: text };
|
|
1672
|
-
if (code)
|
|
1673
|
-
result.code = code;
|
|
1674
|
-
if (action)
|
|
1675
|
-
result.suggestedAction = action;
|
|
1676
|
-
console.log(JSON.stringify(result, null, 2));
|
|
1677
|
-
} else {
|
|
1678
|
-
console.log(chalk.red(`✗ ${text}`));
|
|
1679
|
-
}
|
|
1680
|
-
}
|
|
1681
|
-
info(message) {
|
|
1682
|
-
if (this.format !== "json") {
|
|
1683
|
-
console.log(chalk.blue(`ℹ ${scrubKnownSuccess(message)}`));
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
1686
|
-
warn(message) {
|
|
1687
|
-
const text = scrubKnownSuccess(message);
|
|
1688
|
-
if (this.format === "json") {
|
|
1689
|
-
console.log(JSON.stringify({ warning: text }, null, 2));
|
|
1690
|
-
} else {
|
|
1691
|
-
console.log(chalk.yellow(`⚠ ${text}`));
|
|
1692
|
-
}
|
|
1693
|
-
}
|
|
1694
|
-
}
|
|
1695
|
-
function createSpinner(text, isJson) {
|
|
1696
|
-
if (isJson) {
|
|
1697
|
-
const noop = () => {
|
|
1698
|
-
return;
|
|
1699
|
-
};
|
|
1700
|
-
return {
|
|
1701
|
-
start: noop,
|
|
1702
|
-
stop: noop,
|
|
1703
|
-
succeed: noop,
|
|
1704
|
-
fail: noop
|
|
1705
|
-
};
|
|
1706
|
-
}
|
|
1707
|
-
const start = async () => {
|
|
1708
|
-
const { default: ora } = await import("ora");
|
|
1709
|
-
return ora(text).start();
|
|
1710
|
-
};
|
|
1711
|
-
return { start };
|
|
1712
|
-
}
|
|
1713
|
-
|
|
1714
|
-
// src/index.ts
|
|
1948
|
+
init_output();
|
|
1715
1949
|
init_errors();
|
|
1716
1950
|
var version = "0.1.0";
|
|
1717
1951
|
export {
|
|
@@ -1727,4 +1961,4 @@ export {
|
|
|
1727
1961
|
ApiError
|
|
1728
1962
|
};
|
|
1729
1963
|
|
|
1730
|
-
//# debugId=
|
|
1964
|
+
//# debugId=8CB01A1E19F664D264756E2164756E21
|