@@ -431,8 +431,8 @@ var require_escape = __commonJS({
431431 }
432432 function escapeArgument(arg, doubleEscapeMetaChars) {
433433 arg = `${arg}`;
434- arg = arg.replace(/(\\*) "/g, '$1$1\\"');
435- arg = arg.replace(/(\\*) $/, "$1$1");
434+ arg = arg.replace(/(?=(\\+?)?)\1 "/g, '$1$1\\"');
435+ arg = arg.replace(/(?=(\\+?)?)\1 $/, "$1$1");
436436 arg = `"${arg}"`;
437437 arg = arg.replace(metaCharsRegExp, "^$1");
438438 if (doubleEscapeMetaChars) {
@@ -578,7 +578,7 @@ var require_enoent = __commonJS({
578578 const originalEmit = cp.emit;
579579 cp.emit = function(name, arg1) {
580580 if (name === "exit") {
581- const err = verifyENOENT(arg1, parsed, "spawn" );
581+ const err = verifyENOENT(arg1, parsed);
582582 if (err) {
583583 return originalEmit.call(cp, "error", err);
584584 }
@@ -1672,7 +1672,7 @@ var require_mappingTable = __commonJS({
16721672var require_tr46 = __commonJS({
16731673 "node_modules/node-fetch/node_modules/tr46/index.js"(exports, module2) {
16741674 "use strict";
1675- var punycode = require(" punycode" );
1675+ const punycode = require(' punycode/' );
16761676 var mappingTable = require_mappingTable();
16771677 var PROCESSING_OPTIONS = {
16781678 TRANSITIONAL: 0,
@@ -1834,7 +1834,7 @@ var require_tr46 = __commonJS({
18341834var require_url_state_machine = __commonJS({
18351835 "node_modules/node-fetch/node_modules/whatwg-url/lib/url-state-machine.js"(exports, module2) {
18361836 "use strict";
1837- var punycode = require(" punycode" );
1837+ const punycode = require(' punycode/' );
18381838 var tr46 = require_tr46();
18391839 var specialSchemes = {
18401840 ftp: 21,
@@ -27389,7 +27389,8 @@ var package_default = {
2738927389 "test:unit:docker": "npm run test:docker-build && DOCKER_CONTENT_TRUST=0 docker run --rm oco-test npm run test:unit",
2739027390 "test:e2e": "npm run test:e2e:setup && jest test/e2e",
2739127391 "test:e2e:setup": "sh test/e2e/setup.sh",
27392- "test:e2e:docker": "npm run test:docker-build && DOCKER_CONTENT_TRUST=0 docker run --rm oco-test npm run test:e2e"
27392+ "test:e2e:docker": "npm run test:docker-build && DOCKER_CONTENT_TRUST=0 docker run --rm oco-test npm run test:e2e",
27393+ "mlx:start": "OCO_AI_PROVIDER='mlx' node ./out/cli.cjs"
2739327394 },
2739427395 devDependencies: {
2739527396 "@commitlint/types": "^17.4.4",
@@ -29933,6 +29934,8 @@ var getDefaultModel = (provider) => {
2993329934 switch (provider) {
2993429935 case "ollama":
2993529936 return "";
29937+ case "mlx":
29938+ return "";
2993629939 case "anthropic":
2993729940 return MODEL_LIST.anthropic[0];
2993829941 case "gemini":
@@ -29964,7 +29967,7 @@ var configValidators = {
2996429967 validateConfig(
2996529968 "OCO_API_KEY",
2996629969 value,
29967- 'You need to provide the OCO_API_KEY when OCO_AI_PROVIDER set to "openai" (default) or "ollama" or "azure" or "gemini" or "flowise" or "anthropic". Run `oco config set OCO_API_KEY=your_key OCO_AI_PROVIDER=openai`'
29970+ 'You need to provide the OCO_API_KEY when OCO_AI_PROVIDER set to "openai" (default) or "ollama" or "mlx" or " azure" or "gemini" or "flowise" or "anthropic". Run `oco config set OCO_API_KEY=your_key OCO_AI_PROVIDER=openai`'
2996829971 );
2996929972 return value;
2997029973 },
@@ -30070,8 +30073,8 @@ var configValidators = {
3007030073 "test",
3007130074 "flowise",
3007230075 "groq"
30073- ].includes(value) || value.startsWith("ollama"),
30074- `${value} is not supported yet, use 'ollama', 'anthropic', 'azure', 'gemini', 'flowise' or 'openai' (default)`
30076+ ].includes(value) || value.startsWith("ollama") || value.startsWith("mlx") ,
30077+ `${value} is not supported yet, use 'ollama', 'mlx', anthropic', 'azure', 'gemini', 'flowise' or 'openai' (default)`
3007530078 );
3007630079 return value;
3007730080 },
@@ -30111,6 +30114,7 @@ var OCO_AI_PROVIDER_ENUM = /* @__PURE__ */ ((OCO_AI_PROVIDER_ENUM2) => {
3011130114 OCO_AI_PROVIDER_ENUM2["TEST"] = "test";
3011230115 OCO_AI_PROVIDER_ENUM2["FLOWISE"] = "flowise";
3011330116 OCO_AI_PROVIDER_ENUM2["GROQ"] = "groq";
30117+ OCO_AI_PROVIDER_ENUM2["MLX"] = "mlx";
3011430118 return OCO_AI_PROVIDER_ENUM2;
3011530119})(OCO_AI_PROVIDER_ENUM || {});
3011630120var defaultConfigPath = (0, import_path.join)((0, import_os.homedir)(), ".opencommit");
@@ -44524,6 +44528,38 @@ var GroqEngine = class extends OpenAiEngine {
4452444528 }
4452544529};
4452644530
44531+ // src/engine/mlx.ts
44532+ var MLXEngine = class {
44533+ constructor(config7) {
44534+ this.config = config7;
44535+ this.client = axios_default.create({
44536+ url: config7.baseURL ? `${config7.baseURL}/${config7.apiKey}` : "http://localhost:8080/v1/chat/completions",
44537+ headers: { "Content-Type": "application/json" }
44538+ });
44539+ }
44540+ async generateCommitMessage(messages) {
44541+ const params = {
44542+ messages,
44543+ temperature: 0,
44544+ top_p: 0.1,
44545+ repetition_penalty: 1.5,
44546+ stream: false
44547+ };
44548+ try {
44549+ const response = await this.client.post(
44550+ this.client.getUri(this.config),
44551+ params
44552+ );
44553+ const choices = response.data.choices;
44554+ const message = choices[0].message;
44555+ return message?.content;
44556+ } catch (err) {
44557+ const message = err.response?.data?.error ?? err.message;
44558+ throw new Error(`MLX provider error: ${message}`);
44559+ }
44560+ }
44561+ };
44562+
4452744563// src/utils/engine.ts
4452844564function getEngine() {
4452944565 const config7 = getConfig();
@@ -44550,6 +44586,8 @@ function getEngine() {
4455044586 return new FlowiseEngine(DEFAULT_CONFIG2);
4455144587 case "groq" /* GROQ */:
4455244588 return new GroqEngine(DEFAULT_CONFIG2);
44589+ case "mlx" /* MLX */:
44590+ return new MLXEngine(DEFAULT_CONFIG2);
4455344591 default:
4455444592 return new OpenAiEngine(DEFAULT_CONFIG2);
4455544593 }
@@ -44931,7 +44969,14 @@ var CONVENTIONAL_COMMIT_KEYWORDS = "Do not preface the commit with anything, exc
4493144969var getCommitConvention = (fullGitMojiSpec) => config4.OCO_EMOJI ? fullGitMojiSpec ? FULL_GITMOJI_SPEC : GITMOJI_HELP : CONVENTIONAL_COMMIT_KEYWORDS;
4493244970var getDescriptionInstruction = () => config4.OCO_DESCRIPTION ? `Add a short description of WHY the changes are done after the commit message. Don't start it with "This commit", just describe the changes.` : "Don't add any descriptions to the commit, only commit message.";
4493344971var getOneLineCommitInstruction = () => config4.OCO_ONE_LINE_COMMIT ? "Craft a concise commit message that encapsulates all changes made, with an emphasis on the primary updates. If the modifications share a common theme or scope, mention it succinctly; otherwise, leave the scope out to maintain focus. The goal is to provide a clear and unified overview of the changes in a one single message, without diverging into a list of commit per file change." : "";
44934- var INIT_MAIN_PROMPT2 = (language, fullGitMojiSpec) => ({
44972+ var userInputCodeContext = (context) => {
44973+ if (context !== "" && context !== " ") {
44974+ return `Additional context provided by the user: <context>${context}</context>
44975+ Consider this context when generating the commit message, incorporating relevant information when appropriate.`;
44976+ }
44977+ return "";
44978+ };
44979+ var INIT_MAIN_PROMPT2 = (language, fullGitMojiSpec, context) => ({
4493544980 role: "system",
4493644981 content: (() => {
4493744982 const commitConvention = fullGitMojiSpec ? "GitMoji specification" : "Conventional Commit Convention";
@@ -44941,12 +44986,14 @@ var INIT_MAIN_PROMPT2 = (language, fullGitMojiSpec) => ({
4494144986 const descriptionGuideline = getDescriptionInstruction();
4494244987 const oneLineCommitGuideline = getOneLineCommitInstruction();
4494344988 const generalGuidelines = `Use the present tense. Lines must not be longer than 74 characters. Use ${language} for the commit message.`;
44989+ const userInputContext = userInputCodeContext(context);
4494444990 return `${missionStatement}
4494544991${diffInstruction}
4494644992${conventionGuidelines}
4494744993${descriptionGuideline}
4494844994${oneLineCommitGuideline}
44949- ${generalGuidelines}`;
44995+ ${generalGuidelines}
44996+ ${userInputContext}`;
4495044997 })()
4495144998});
4495244999var INIT_DIFF_PROMPT = {
@@ -44988,7 +45035,7 @@ var INIT_CONSISTENCY_PROMPT = (translation4) => ({
4498845035 role: "assistant",
4498945036 content: getContent(translation4)
4499045037});
44991- var getMainCommitPrompt = async (fullGitMojiSpec) => {
45038+ var getMainCommitPrompt = async (fullGitMojiSpec, context ) => {
4499245039 switch (config4.OCO_PROMPT_MODULE) {
4499345040 case "@commitlint":
4499445041 if (!await commitlintLLMConfigExists()) {
@@ -45010,7 +45057,7 @@ var getMainCommitPrompt = async (fullGitMojiSpec) => {
4501045057 ];
4501145058 default:
4501245059 return [
45013- INIT_MAIN_PROMPT2(translation3.localLanguage, fullGitMojiSpec),
45060+ INIT_MAIN_PROMPT2(translation3.localLanguage, fullGitMojiSpec, context ),
4501445061 INIT_DIFF_PROMPT,
4501545062 INIT_CONSISTENCY_PROMPT(translation3)
4501645063 ];
@@ -45037,8 +45084,8 @@ function mergeDiffs(arr, maxStringLength) {
4503745084var config5 = getConfig();
4503845085var MAX_TOKENS_INPUT = config5.OCO_TOKENS_MAX_INPUT;
4503945086var MAX_TOKENS_OUTPUT = config5.OCO_TOKENS_MAX_OUTPUT;
45040- var generateCommitMessageChatCompletionPrompt = async (diff, fullGitMojiSpec) => {
45041- const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec);
45087+ var generateCommitMessageChatCompletionPrompt = async (diff, fullGitMojiSpec, context ) => {
45088+ const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec, context );
4504245089 const chatContextAsCompletionRequest = [...INIT_MESSAGES_PROMPT];
4504345090 chatContextAsCompletionRequest.push({
4504445091 role: "user",
@@ -45054,9 +45101,12 @@ var GenerateCommitMessageErrorEnum = ((GenerateCommitMessageErrorEnum2) => {
4505445101 return GenerateCommitMessageErrorEnum2;
4505545102})(GenerateCommitMessageErrorEnum || {});
4505645103var ADJUSTMENT_FACTOR = 20;
45057- var generateCommitMessageByDiff = async (diff, fullGitMojiSpec = false) => {
45104+ var generateCommitMessageByDiff = async (diff, fullGitMojiSpec = false, context = "" ) => {
4505845105 try {
45059- const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec);
45106+ const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(
45107+ fullGitMojiSpec,
45108+ context
45109+ );
4506045110 const INIT_MESSAGES_PROMPT_LENGTH = INIT_MESSAGES_PROMPT.map(
4506145111 (msg) => tokenCount(msg.content) + 4
4506245112 ).reduce((a4, b7) => a4 + b7, 0);
@@ -45076,7 +45126,8 @@ var generateCommitMessageByDiff = async (diff, fullGitMojiSpec = false) => {
4507645126 }
4507745127 const messages = await generateCommitMessageChatCompletionPrompt(
4507845128 diff,
45079- fullGitMojiSpec
45129+ fullGitMojiSpec,
45130+ context
4508045131 );
4508145132 const engine = getEngine();
4508245133 const commitMessage = await engine.generateCommitMessage(messages);
@@ -45283,6 +45334,7 @@ var checkMessageTemplate = (extraArgs2) => {
4528345334var generateCommitMessageFromGitDiff = async ({
4528445335 diff,
4528545336 extraArgs: extraArgs2,
45337+ context = "",
4528645338 fullGitMojiSpec = false,
4528745339 skipCommitConfirmation = false
4528845340}) => {
@@ -45292,7 +45344,8 @@ var generateCommitMessageFromGitDiff = async ({
4529245344 try {
4529345345 let commitMessage = await generateCommitMessageByDiff(
4529445346 diff,
45295- fullGitMojiSpec
45347+ fullGitMojiSpec,
45348+ context
4529645349 );
4529745350 const messageTemplate = checkMessageTemplate(extraArgs2);
4529845351 if (config6.OCO_MESSAGE_TEMPLATE_PLACEHOLDER && typeof messageTemplate === "string") {
@@ -45402,7 +45455,7 @@ ${source_default.grey("\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2
4540245455 process.exit(1);
4540345456 }
4540445457};
45405- async function commit(extraArgs2 = [], isStageAllFlag = false, fullGitMojiSpec = false, skipCommitConfirmation = false) {
45458+ async function commit(extraArgs2 = [], context = "", isStageAllFlag = false, fullGitMojiSpec = false, skipCommitConfirmation = false) {
4540645459 if (isStageAllFlag) {
4540745460 const changedFiles2 = await getChangedFiles();
4540845461 if (changedFiles2)
@@ -45433,7 +45486,7 @@ async function commit(extraArgs2 = [], isStageAllFlag = false, fullGitMojiSpec =
4543345486 if (hD2(isStageAllAndCommitConfirmedByUser))
4543445487 process.exit(1);
4543545488 if (isStageAllAndCommitConfirmedByUser) {
45436- await commit(extraArgs2, true, fullGitMojiSpec);
45489+ await commit(extraArgs2, context, true, fullGitMojiSpec);
4543745490 process.exit(1);
4543845491 }
4543945492 if (stagedFiles.length === 0 && changedFiles.length > 0) {
@@ -45448,7 +45501,7 @@ async function commit(extraArgs2 = [], isStageAllFlag = false, fullGitMojiSpec =
4544845501 process.exit(1);
4544945502 await gitAdd({ files });
4545045503 }
45451- await commit(extraArgs2, false, fullGitMojiSpec);
45504+ await commit(extraArgs2, context, false, fullGitMojiSpec);
4545245505 process.exit(1);
4545345506 }
4545445507 stagedFilesSpinner.stop(
@@ -45459,6 +45512,7 @@ ${stagedFiles.map((file) => ` ${file}`).join("\n")}`
4545945512 generateCommitMessageFromGitDiff({
4546045513 diff: await getDiff({ files: stagedFiles }),
4546145514 extraArgs: extraArgs2,
45515+ context,
4546245516 fullGitMojiSpec,
4546345517 skipCommitConfirmation
4546445518 })
@@ -45817,6 +45871,12 @@ Z2(
4581745871 commands: [configCommand, hookCommand, commitlintConfigCommand],
4581845872 flags: {
4581945873 fgm: Boolean,
45874+ context: {
45875+ type: String,
45876+ alias: "c",
45877+ description: "Additional user input context for the commit message",
45878+ default: ""
45879+ },
4582045880 yes: {
4582145881 type: Boolean,
4582245882 alias: "y",
@@ -45833,7 +45893,7 @@ Z2(
4583345893 if (await isHookCalled()) {
4583445894 prepareCommitMessageHook();
4583545895 } else {
45836- commit(extraArgs, false, flags.fgm, flags.yes);
45896+ commit(extraArgs, flags.context, false, flags.fgm, flags.yes);
4583745897 }
4583845898 },
4583945899 extraArgs
0 commit comments