mirror of
https://github.com/di-sukharev/opencommit.git
synced 2026-01-13 15:47:58 -05:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ae2f7ddf1 | ||
|
|
b318d1d882 | ||
|
|
af0f2c1df4 | ||
|
|
c5ce50aaa3 | ||
|
|
c1756b85af | ||
|
|
dac1271782 | ||
|
|
1cc7a64f99 | ||
|
|
4deb7bca65 | ||
|
|
1a90485a10 | ||
|
|
48b8d9d7b2 | ||
|
|
7e60c68ba5 | ||
|
|
24adc16adf | ||
|
|
881f07eebe | ||
|
|
3a255a3ad9 | ||
|
|
9971b3c74e | ||
|
|
66a5695d89 | ||
|
|
fd22f713ed | ||
|
|
43dc5e6c2b | ||
|
|
3d42dde48c | ||
|
|
19f32ca57d | ||
|
|
c1070789fd | ||
|
|
1f0f44ede0 | ||
|
|
45aed936b1 | ||
|
|
e4f7e8dc80 |
18
.github/workflows/test.yml
vendored
18
.github/workflows/test.yml
vendored
@@ -51,3 +51,21 @@ jobs:
|
|||||||
run: npm run build
|
run: npm run build
|
||||||
- name: Run E2E Tests
|
- name: Run E2E Tests
|
||||||
run: npm run test:e2e
|
run: npm run test:e2e
|
||||||
|
prettier:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Use Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20.x'
|
||||||
|
cache: 'npm'
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
- name: Run Prettier
|
||||||
|
run: npm run format:check
|
||||||
|
- name: Prettier Output
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
echo "Prettier check failed. Please run 'npm run format' to fix formatting issues."
|
||||||
|
exit 1
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ Create a `.env` file and add OpenCommit config variables there like this:
|
|||||||
|
|
||||||
```env
|
```env
|
||||||
...
|
...
|
||||||
OCO_AI_PROVIDER=<openai (default), anthropic, azure, ollama, gemini, flowise, deepseek>
|
OCO_AI_PROVIDER=<openai (default), anthropic, azure, ollama, gemini, flowise, deepseek, aimlapi>
|
||||||
OCO_API_KEY=<your OpenAI API token> // or other LLM provider API token
|
OCO_API_KEY=<your OpenAI API token> // or other LLM provider API token
|
||||||
OCO_API_URL=<may be used to set proxy path to OpenAI api>
|
OCO_API_URL=<may be used to set proxy path to OpenAI api>
|
||||||
OCO_API_CUSTOM_HEADERS=<JSON string of custom HTTP headers to include in API requests>
|
OCO_API_CUSTOM_HEADERS=<JSON string of custom HTTP headers to include in API requests>
|
||||||
|
|||||||
387
out/cli.cjs
387
out/cli.cjs
@@ -47672,7 +47672,7 @@ function G3(t2, e3) {
|
|||||||
// package.json
|
// package.json
|
||||||
var package_default = {
|
var package_default = {
|
||||||
name: "opencommit",
|
name: "opencommit",
|
||||||
version: "3.2.8",
|
version: "3.2.9",
|
||||||
description: "Auto-generate impressive commits in 1 second. Killing lame commits with AI \u{1F92F}\u{1F52B}",
|
description: "Auto-generate impressive commits in 1 second. Killing lame commits with AI \u{1F92F}\u{1F52B}",
|
||||||
keywords: [
|
keywords: [
|
||||||
"git",
|
"git",
|
||||||
@@ -50371,7 +50371,338 @@ var MODEL_LIST = {
|
|||||||
"mistral-moderation-2411",
|
"mistral-moderation-2411",
|
||||||
"mistral-moderation-latest"
|
"mistral-moderation-latest"
|
||||||
],
|
],
|
||||||
deepseek: ["deepseek-chat", "deepseek-reasoner"]
|
deepseek: ["deepseek-chat", "deepseek-reasoner"],
|
||||||
|
// OpenRouter available models
|
||||||
|
// input_modalities: 'text'
|
||||||
|
// output_modalities: 'text'
|
||||||
|
// https://openrouter.ai/api/v1/models
|
||||||
|
openrouter: [
|
||||||
|
"openai/gpt-4o-mini",
|
||||||
|
// used by default
|
||||||
|
"01-ai/yi-large",
|
||||||
|
"aetherwiing/mn-starcannon-12b",
|
||||||
|
"agentica-org/deepcoder-14b-preview:free",
|
||||||
|
"ai21/jamba-1.6-large",
|
||||||
|
"ai21/jamba-1.6-mini",
|
||||||
|
"aion-labs/aion-1.0",
|
||||||
|
"aion-labs/aion-1.0-mini",
|
||||||
|
"aion-labs/aion-rp-llama-3.1-8b",
|
||||||
|
"alfredpros/codellama-7b-instruct-solidity",
|
||||||
|
"all-hands/openhands-lm-32b-v0.1",
|
||||||
|
"alpindale/goliath-120b",
|
||||||
|
"alpindale/magnum-72b",
|
||||||
|
"amazon/nova-lite-v1",
|
||||||
|
"amazon/nova-micro-v1",
|
||||||
|
"amazon/nova-pro-v1",
|
||||||
|
"anthracite-org/magnum-v2-72b",
|
||||||
|
"anthracite-org/magnum-v4-72b",
|
||||||
|
"anthropic/claude-2",
|
||||||
|
"anthropic/claude-2.0",
|
||||||
|
"anthropic/claude-2.0:beta",
|
||||||
|
"anthropic/claude-2.1",
|
||||||
|
"anthropic/claude-2.1:beta",
|
||||||
|
"anthropic/claude-2:beta",
|
||||||
|
"anthropic/claude-3-haiku",
|
||||||
|
"anthropic/claude-3-haiku:beta",
|
||||||
|
"anthropic/claude-3-opus",
|
||||||
|
"anthropic/claude-3-opus:beta",
|
||||||
|
"anthropic/claude-3-sonnet",
|
||||||
|
"anthropic/claude-3-sonnet:beta",
|
||||||
|
"anthropic/claude-3.5-haiku",
|
||||||
|
"anthropic/claude-3.5-haiku-20241022",
|
||||||
|
"anthropic/claude-3.5-haiku-20241022:beta",
|
||||||
|
"anthropic/claude-3.5-haiku:beta",
|
||||||
|
"anthropic/claude-3.5-sonnet",
|
||||||
|
"anthropic/claude-3.5-sonnet-20240620",
|
||||||
|
"anthropic/claude-3.5-sonnet-20240620:beta",
|
||||||
|
"anthropic/claude-3.5-sonnet:beta",
|
||||||
|
"anthropic/claude-3.7-sonnet",
|
||||||
|
"anthropic/claude-3.7-sonnet:beta",
|
||||||
|
"anthropic/claude-3.7-sonnet:thinking",
|
||||||
|
"anthropic/claude-opus-4",
|
||||||
|
"anthropic/claude-sonnet-4",
|
||||||
|
"arcee-ai/arcee-blitz",
|
||||||
|
"arcee-ai/caller-large",
|
||||||
|
"arcee-ai/coder-large",
|
||||||
|
"arcee-ai/maestro-reasoning",
|
||||||
|
"arcee-ai/spotlight",
|
||||||
|
"arcee-ai/virtuoso-large",
|
||||||
|
"arcee-ai/virtuoso-medium-v2",
|
||||||
|
"arliai/qwq-32b-arliai-rpr-v1:free",
|
||||||
|
"cognitivecomputations/dolphin-mixtral-8x22b",
|
||||||
|
"cognitivecomputations/dolphin3.0-mistral-24b:free",
|
||||||
|
"cognitivecomputations/dolphin3.0-r1-mistral-24b:free",
|
||||||
|
"cohere/command",
|
||||||
|
"cohere/command-a",
|
||||||
|
"cohere/command-r",
|
||||||
|
"cohere/command-r-03-2024",
|
||||||
|
"cohere/command-r-08-2024",
|
||||||
|
"cohere/command-r-plus",
|
||||||
|
"cohere/command-r-plus-04-2024",
|
||||||
|
"cohere/command-r-plus-08-2024",
|
||||||
|
"cohere/command-r7b-12-2024",
|
||||||
|
"deepseek/deepseek-chat",
|
||||||
|
"deepseek/deepseek-chat-v3-0324",
|
||||||
|
"deepseek/deepseek-chat-v3-0324:free",
|
||||||
|
"deepseek/deepseek-chat:free",
|
||||||
|
"deepseek/deepseek-prover-v2",
|
||||||
|
"deepseek/deepseek-prover-v2:free",
|
||||||
|
"deepseek/deepseek-r1",
|
||||||
|
"deepseek/deepseek-r1-0528",
|
||||||
|
"deepseek/deepseek-r1-0528-qwen3-8b",
|
||||||
|
"deepseek/deepseek-r1-0528-qwen3-8b:free",
|
||||||
|
"deepseek/deepseek-r1-0528:free",
|
||||||
|
"deepseek/deepseek-r1-distill-llama-70b",
|
||||||
|
"deepseek/deepseek-r1-distill-llama-70b:free",
|
||||||
|
"deepseek/deepseek-r1-distill-llama-8b",
|
||||||
|
"deepseek/deepseek-r1-distill-qwen-1.5b",
|
||||||
|
"deepseek/deepseek-r1-distill-qwen-14b",
|
||||||
|
"deepseek/deepseek-r1-distill-qwen-14b:free",
|
||||||
|
"deepseek/deepseek-r1-distill-qwen-32b",
|
||||||
|
"deepseek/deepseek-r1-distill-qwen-32b:free",
|
||||||
|
"deepseek/deepseek-r1-distill-qwen-7b",
|
||||||
|
"deepseek/deepseek-r1-zero:free",
|
||||||
|
"deepseek/deepseek-r1:free",
|
||||||
|
"deepseek/deepseek-v3-base:free",
|
||||||
|
"eleutherai/llemma_7b",
|
||||||
|
"eva-unit-01/eva-llama-3.33-70b",
|
||||||
|
"eva-unit-01/eva-qwen-2.5-32b",
|
||||||
|
"eva-unit-01/eva-qwen-2.5-72b",
|
||||||
|
"featherless/qwerky-72b:free",
|
||||||
|
"google/gemini-2.0-flash-001",
|
||||||
|
"google/gemini-2.0-flash-exp:free",
|
||||||
|
"google/gemini-2.0-flash-lite-001",
|
||||||
|
"google/gemini-2.5-flash-preview",
|
||||||
|
"google/gemini-2.5-flash-preview-05-20",
|
||||||
|
"google/gemini-2.5-flash-preview-05-20:thinking",
|
||||||
|
"google/gemini-2.5-flash-preview:thinking",
|
||||||
|
"google/gemini-2.5-pro-exp-03-25",
|
||||||
|
"google/gemini-2.5-pro-preview",
|
||||||
|
"google/gemini-2.5-pro-preview-05-06",
|
||||||
|
"google/gemini-flash-1.5",
|
||||||
|
"google/gemini-flash-1.5-8b",
|
||||||
|
"google/gemini-pro-1.5",
|
||||||
|
"google/gemma-2-27b-it",
|
||||||
|
"google/gemma-2-9b-it",
|
||||||
|
"google/gemma-2-9b-it:free",
|
||||||
|
"google/gemma-3-12b-it",
|
||||||
|
"google/gemma-3-12b-it:free",
|
||||||
|
"google/gemma-3-1b-it:free",
|
||||||
|
"google/gemma-3-27b-it",
|
||||||
|
"google/gemma-3-27b-it:free",
|
||||||
|
"google/gemma-3-4b-it",
|
||||||
|
"google/gemma-3-4b-it:free",
|
||||||
|
"google/gemma-3n-e4b-it:free",
|
||||||
|
"gryphe/mythomax-l2-13b",
|
||||||
|
"inception/mercury-coder-small-beta",
|
||||||
|
"infermatic/mn-inferor-12b",
|
||||||
|
"inflection/inflection-3-pi",
|
||||||
|
"inflection/inflection-3-productivity",
|
||||||
|
"liquid/lfm-3b",
|
||||||
|
"liquid/lfm-40b",
|
||||||
|
"liquid/lfm-7b",
|
||||||
|
"mancer/weaver",
|
||||||
|
"meta-llama/llama-2-70b-chat",
|
||||||
|
"meta-llama/llama-3-70b-instruct",
|
||||||
|
"meta-llama/llama-3-8b-instruct",
|
||||||
|
"meta-llama/llama-3.1-405b",
|
||||||
|
"meta-llama/llama-3.1-405b-instruct",
|
||||||
|
"meta-llama/llama-3.1-405b:free",
|
||||||
|
"meta-llama/llama-3.1-70b-instruct",
|
||||||
|
"meta-llama/llama-3.1-8b-instruct",
|
||||||
|
"meta-llama/llama-3.1-8b-instruct:free",
|
||||||
|
"meta-llama/llama-3.2-11b-vision-instruct",
|
||||||
|
"meta-llama/llama-3.2-11b-vision-instruct:free",
|
||||||
|
"meta-llama/llama-3.2-1b-instruct",
|
||||||
|
"meta-llama/llama-3.2-1b-instruct:free",
|
||||||
|
"meta-llama/llama-3.2-3b-instruct",
|
||||||
|
"meta-llama/llama-3.2-3b-instruct:free",
|
||||||
|
"meta-llama/llama-3.2-90b-vision-instruct",
|
||||||
|
"meta-llama/llama-3.3-70b-instruct",
|
||||||
|
"meta-llama/llama-3.3-70b-instruct:free",
|
||||||
|
"meta-llama/llama-3.3-8b-instruct:free",
|
||||||
|
"meta-llama/llama-4-maverick",
|
||||||
|
"meta-llama/llama-4-maverick:free",
|
||||||
|
"meta-llama/llama-4-scout",
|
||||||
|
"meta-llama/llama-4-scout:free",
|
||||||
|
"meta-llama/llama-guard-2-8b",
|
||||||
|
"meta-llama/llama-guard-3-8b",
|
||||||
|
"meta-llama/llama-guard-4-12b",
|
||||||
|
"microsoft/mai-ds-r1:free",
|
||||||
|
"microsoft/phi-3-medium-128k-instruct",
|
||||||
|
"microsoft/phi-3-mini-128k-instruct",
|
||||||
|
"microsoft/phi-3.5-mini-128k-instruct",
|
||||||
|
"microsoft/phi-4",
|
||||||
|
"microsoft/phi-4-multimodal-instruct",
|
||||||
|
"microsoft/phi-4-reasoning-plus",
|
||||||
|
"microsoft/phi-4-reasoning-plus:free",
|
||||||
|
"microsoft/phi-4-reasoning:free",
|
||||||
|
"microsoft/wizardlm-2-8x22b",
|
||||||
|
"minimax/minimax-01",
|
||||||
|
"mistralai/codestral-2501",
|
||||||
|
"mistralai/devstral-small",
|
||||||
|
"mistralai/devstral-small:free",
|
||||||
|
"mistralai/magistral-medium-2506",
|
||||||
|
"mistralai/magistral-medium-2506:thinking",
|
||||||
|
"mistralai/magistral-small-2506",
|
||||||
|
"mistralai/ministral-3b",
|
||||||
|
"mistralai/ministral-8b",
|
||||||
|
"mistralai/mistral-7b-instruct",
|
||||||
|
"mistralai/mistral-7b-instruct-v0.1",
|
||||||
|
"mistralai/mistral-7b-instruct-v0.2",
|
||||||
|
"mistralai/mistral-7b-instruct-v0.3",
|
||||||
|
"mistralai/mistral-7b-instruct:free",
|
||||||
|
"mistralai/mistral-large",
|
||||||
|
"mistralai/mistral-large-2407",
|
||||||
|
"mistralai/mistral-large-2411",
|
||||||
|
"mistralai/mistral-medium",
|
||||||
|
"mistralai/mistral-medium-3",
|
||||||
|
"mistralai/mistral-nemo",
|
||||||
|
"mistralai/mistral-nemo:free",
|
||||||
|
"mistralai/mistral-saba",
|
||||||
|
"mistralai/mistral-small",
|
||||||
|
"mistralai/mistral-small-24b-instruct-2501",
|
||||||
|
"mistralai/mistral-small-24b-instruct-2501:free",
|
||||||
|
"mistralai/mistral-small-3.1-24b-instruct",
|
||||||
|
"mistralai/mistral-small-3.1-24b-instruct:free",
|
||||||
|
"mistralai/mistral-tiny",
|
||||||
|
"mistralai/mixtral-8x22b-instruct",
|
||||||
|
"mistralai/mixtral-8x7b-instruct",
|
||||||
|
"mistralai/pixtral-12b",
|
||||||
|
"mistralai/pixtral-large-2411",
|
||||||
|
"moonshotai/kimi-vl-a3b-thinking:free",
|
||||||
|
"moonshotai/moonlight-16b-a3b-instruct:free",
|
||||||
|
"neversleep/llama-3-lumimaid-70b",
|
||||||
|
"neversleep/llama-3-lumimaid-8b",
|
||||||
|
"neversleep/llama-3.1-lumimaid-70b",
|
||||||
|
"neversleep/llama-3.1-lumimaid-8b",
|
||||||
|
"neversleep/noromaid-20b",
|
||||||
|
"nothingiisreal/mn-celeste-12b",
|
||||||
|
"nousresearch/deephermes-3-llama-3-8b-preview:free",
|
||||||
|
"nousresearch/deephermes-3-mistral-24b-preview:free",
|
||||||
|
"nousresearch/hermes-2-pro-llama-3-8b",
|
||||||
|
"nousresearch/hermes-3-llama-3.1-405b",
|
||||||
|
"nousresearch/hermes-3-llama-3.1-70b",
|
||||||
|
"nousresearch/nous-hermes-2-mixtral-8x7b-dpo",
|
||||||
|
"nvidia/llama-3.1-nemotron-70b-instruct",
|
||||||
|
"nvidia/llama-3.1-nemotron-ultra-253b-v1",
|
||||||
|
"nvidia/llama-3.1-nemotron-ultra-253b-v1:free",
|
||||||
|
"nvidia/llama-3.3-nemotron-super-49b-v1",
|
||||||
|
"nvidia/llama-3.3-nemotron-super-49b-v1:free",
|
||||||
|
"open-r1/olympiccoder-32b:free",
|
||||||
|
"openai/chatgpt-4o-latest",
|
||||||
|
"openai/codex-mini",
|
||||||
|
"openai/gpt-3.5-turbo",
|
||||||
|
"openai/gpt-3.5-turbo-0125",
|
||||||
|
"openai/gpt-3.5-turbo-0613",
|
||||||
|
"openai/gpt-3.5-turbo-1106",
|
||||||
|
"openai/gpt-3.5-turbo-16k",
|
||||||
|
"openai/gpt-3.5-turbo-instruct",
|
||||||
|
"openai/gpt-4",
|
||||||
|
"openai/gpt-4-0314",
|
||||||
|
"openai/gpt-4-1106-preview",
|
||||||
|
"openai/gpt-4-turbo",
|
||||||
|
"openai/gpt-4-turbo-preview",
|
||||||
|
"openai/gpt-4.1",
|
||||||
|
"openai/gpt-4.1-mini",
|
||||||
|
"openai/gpt-4.1-nano",
|
||||||
|
"openai/gpt-4.5-preview",
|
||||||
|
"openai/gpt-4o",
|
||||||
|
"openai/gpt-4o-2024-05-13",
|
||||||
|
"openai/gpt-4o-2024-08-06",
|
||||||
|
"openai/gpt-4o-2024-11-20",
|
||||||
|
"openai/gpt-4o-mini-2024-07-18",
|
||||||
|
"openai/gpt-4o-mini-search-preview",
|
||||||
|
"openai/gpt-4o-search-preview",
|
||||||
|
"openai/gpt-4o:extended",
|
||||||
|
"openai/o1",
|
||||||
|
"openai/o1-mini",
|
||||||
|
"openai/o1-mini-2024-09-12",
|
||||||
|
"openai/o1-preview",
|
||||||
|
"openai/o1-preview-2024-09-12",
|
||||||
|
"openai/o1-pro",
|
||||||
|
"openai/o3",
|
||||||
|
"openai/o3-mini",
|
||||||
|
"openai/o3-mini-high",
|
||||||
|
"openai/o3-pro",
|
||||||
|
"openai/o4-mini",
|
||||||
|
"openai/o4-mini-high",
|
||||||
|
"opengvlab/internvl3-14b:free",
|
||||||
|
"opengvlab/internvl3-2b:free",
|
||||||
|
"openrouter/auto",
|
||||||
|
"perplexity/llama-3.1-sonar-large-128k-online",
|
||||||
|
"perplexity/llama-3.1-sonar-small-128k-online",
|
||||||
|
"perplexity/r1-1776",
|
||||||
|
"perplexity/sonar",
|
||||||
|
"perplexity/sonar-deep-research",
|
||||||
|
"perplexity/sonar-pro",
|
||||||
|
"perplexity/sonar-reasoning",
|
||||||
|
"perplexity/sonar-reasoning-pro",
|
||||||
|
"pygmalionai/mythalion-13b",
|
||||||
|
"qwen/qwen-2-72b-instruct",
|
||||||
|
"qwen/qwen-2.5-72b-instruct",
|
||||||
|
"qwen/qwen-2.5-72b-instruct:free",
|
||||||
|
"qwen/qwen-2.5-7b-instruct",
|
||||||
|
"qwen/qwen-2.5-7b-instruct:free",
|
||||||
|
"qwen/qwen-2.5-coder-32b-instruct",
|
||||||
|
"qwen/qwen-2.5-coder-32b-instruct:free",
|
||||||
|
"qwen/qwen-2.5-vl-7b-instruct",
|
||||||
|
"qwen/qwen-2.5-vl-7b-instruct:free",
|
||||||
|
"qwen/qwen-max",
|
||||||
|
"qwen/qwen-plus",
|
||||||
|
"qwen/qwen-turbo",
|
||||||
|
"qwen/qwen-vl-max",
|
||||||
|
"qwen/qwen-vl-plus",
|
||||||
|
"qwen/qwen2.5-vl-32b-instruct",
|
||||||
|
"qwen/qwen2.5-vl-32b-instruct:free",
|
||||||
|
"qwen/qwen2.5-vl-3b-instruct:free",
|
||||||
|
"qwen/qwen2.5-vl-72b-instruct",
|
||||||
|
"qwen/qwen2.5-vl-72b-instruct:free",
|
||||||
|
"qwen/qwen3-14b",
|
||||||
|
"qwen/qwen3-14b:free",
|
||||||
|
"qwen/qwen3-235b-a22b",
|
||||||
|
"qwen/qwen3-235b-a22b:free",
|
||||||
|
"qwen/qwen3-30b-a3b",
|
||||||
|
"qwen/qwen3-30b-a3b:free",
|
||||||
|
"qwen/qwen3-32b",
|
||||||
|
"qwen/qwen3-32b:free",
|
||||||
|
"qwen/qwen3-8b",
|
||||||
|
"qwen/qwen3-8b:free",
|
||||||
|
"qwen/qwq-32b",
|
||||||
|
"qwen/qwq-32b-preview",
|
||||||
|
"qwen/qwq-32b:free",
|
||||||
|
"raifle/sorcererlm-8x22b",
|
||||||
|
"rekaai/reka-flash-3:free",
|
||||||
|
"sao10k/fimbulvetr-11b-v2",
|
||||||
|
"sao10k/l3-euryale-70b",
|
||||||
|
"sao10k/l3-lunaris-8b",
|
||||||
|
"sao10k/l3.1-euryale-70b",
|
||||||
|
"sao10k/l3.3-euryale-70b",
|
||||||
|
"sarvamai/sarvam-m:free",
|
||||||
|
"scb10x/llama3.1-typhoon2-70b-instruct",
|
||||||
|
"sentientagi/dobby-mini-unhinged-plus-llama-3.1-8b",
|
||||||
|
"shisa-ai/shisa-v2-llama3.3-70b:free",
|
||||||
|
"sophosympatheia/midnight-rose-70b",
|
||||||
|
"thedrummer/anubis-pro-105b-v1",
|
||||||
|
"thedrummer/rocinante-12b",
|
||||||
|
"thedrummer/skyfall-36b-v2",
|
||||||
|
"thedrummer/unslopnemo-12b",
|
||||||
|
"thedrummer/valkyrie-49b-v1",
|
||||||
|
"thudm/glm-4-32b",
|
||||||
|
"thudm/glm-4-32b:free",
|
||||||
|
"thudm/glm-z1-32b",
|
||||||
|
"thudm/glm-z1-32b:free",
|
||||||
|
"thudm/glm-z1-rumination-32b",
|
||||||
|
"tngtech/deepseek-r1t-chimera:free",
|
||||||
|
"undi95/remm-slerp-l2-13b",
|
||||||
|
"undi95/toppy-m-7b",
|
||||||
|
"x-ai/grok-2-1212",
|
||||||
|
"x-ai/grok-2-vision-1212",
|
||||||
|
"x-ai/grok-3-beta",
|
||||||
|
"x-ai/grok-3-mini-beta",
|
||||||
|
"x-ai/grok-beta",
|
||||||
|
"x-ai/grok-vision-beta"
|
||||||
|
]
|
||||||
};
|
};
|
||||||
var getDefaultModel = (provider) => {
|
var getDefaultModel = (provider) => {
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
@@ -50389,6 +50720,8 @@ var getDefaultModel = (provider) => {
|
|||||||
return MODEL_LIST.mistral[0];
|
return MODEL_LIST.mistral[0];
|
||||||
case "deepseek":
|
case "deepseek":
|
||||||
return MODEL_LIST.deepseek[0];
|
return MODEL_LIST.deepseek[0];
|
||||||
|
case "openrouter":
|
||||||
|
return MODEL_LIST.openrouter[0];
|
||||||
default:
|
default:
|
||||||
return MODEL_LIST.openai[0];
|
return MODEL_LIST.openai[0];
|
||||||
}
|
}
|
||||||
@@ -50542,7 +50875,8 @@ var configValidators = {
|
|||||||
"test",
|
"test",
|
||||||
"flowise",
|
"flowise",
|
||||||
"groq",
|
"groq",
|
||||||
"deepseek"
|
"deepseek",
|
||||||
|
"openrouter"
|
||||||
].includes(value) || value.startsWith("ollama"),
|
].includes(value) || value.startsWith("ollama"),
|
||||||
`${value} is not supported yet, use 'ollama', 'mlx', 'anthropic', 'azure', 'gemini', 'flowise', 'mistral', 'deepseek' or 'openai' (default)`
|
`${value} is not supported yet, use 'ollama', 'mlx', 'anthropic', 'azure', 'gemini', 'flowise', 'mistral', 'deepseek' or 'openai' (default)`
|
||||||
);
|
);
|
||||||
@@ -50587,6 +50921,7 @@ var OCO_AI_PROVIDER_ENUM = /* @__PURE__ */ ((OCO_AI_PROVIDER_ENUM2) => {
|
|||||||
OCO_AI_PROVIDER_ENUM2["MISTRAL"] = "mistral";
|
OCO_AI_PROVIDER_ENUM2["MISTRAL"] = "mistral";
|
||||||
OCO_AI_PROVIDER_ENUM2["MLX"] = "mlx";
|
OCO_AI_PROVIDER_ENUM2["MLX"] = "mlx";
|
||||||
OCO_AI_PROVIDER_ENUM2["DEEPSEEK"] = "deepseek";
|
OCO_AI_PROVIDER_ENUM2["DEEPSEEK"] = "deepseek";
|
||||||
|
OCO_AI_PROVIDER_ENUM2["OPENROUTER"] = "openrouter";
|
||||||
return OCO_AI_PROVIDER_ENUM2;
|
return OCO_AI_PROVIDER_ENUM2;
|
||||||
})(OCO_AI_PROVIDER_ENUM || {});
|
})(OCO_AI_PROVIDER_ENUM || {});
|
||||||
var defaultConfigPath = (0, import_path.join)((0, import_os.homedir)(), ".opencommit");
|
var defaultConfigPath = (0, import_path.join)((0, import_os.homedir)(), ".opencommit");
|
||||||
@@ -50874,7 +51209,11 @@ ${key}:`));
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(source_default.yellow('\nUse "oco config describe [PARAMETER]" to see accepted values and more details for a specific config parameter.'));
|
console.log(
|
||||||
|
source_default.yellow(
|
||||||
|
'\nUse "oco config describe [PARAMETER]" to see accepted values and more details for a specific config parameter.'
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
var configCommand = G3(
|
var configCommand = G3(
|
||||||
{
|
{
|
||||||
@@ -66182,6 +66521,40 @@ var DeepseekEngine = class extends OpenAiEngine {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// src/engine/openrouter.ts
|
||||||
|
var OpenRouterEngine = class {
|
||||||
|
constructor(config7) {
|
||||||
|
this.config = config7;
|
||||||
|
this.generateCommitMessage = async (messages) => {
|
||||||
|
try {
|
||||||
|
const response = await this.client.post("", {
|
||||||
|
model: this.config.model,
|
||||||
|
messages
|
||||||
|
});
|
||||||
|
const message = response.data.choices[0].message;
|
||||||
|
let content = message?.content;
|
||||||
|
return removeContentTags(content, "think");
|
||||||
|
} catch (error) {
|
||||||
|
const err = error;
|
||||||
|
if (axios_default.isAxiosError(error) && error.response?.status === 401) {
|
||||||
|
const openRouterError = error.response.data.error;
|
||||||
|
if (openRouterError) throw new Error(openRouterError.message);
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.client = axios_default.create({
|
||||||
|
baseURL: "https://openrouter.ai/api/v1/chat/completions",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${config7.apiKey}`,
|
||||||
|
"HTTP-Referer": "https://github.com/di-sukharev/opencommit",
|
||||||
|
"X-Title": "OpenCommit",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// src/utils/engine.ts
|
// src/utils/engine.ts
|
||||||
function parseCustomHeaders(headers) {
|
function parseCustomHeaders(headers) {
|
||||||
let parsedHeaders = {};
|
let parsedHeaders = {};
|
||||||
@@ -66195,7 +66568,9 @@ function parseCustomHeaders(headers) {
|
|||||||
parsedHeaders = JSON.parse(headers);
|
parsedHeaders = JSON.parse(headers);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn("Invalid OCO_API_CUSTOM_HEADERS format, ignoring custom headers");
|
console.warn(
|
||||||
|
"Invalid OCO_API_CUSTOM_HEADERS format, ignoring custom headers"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return parsedHeaders;
|
return parsedHeaders;
|
||||||
}
|
}
|
||||||
@@ -66232,6 +66607,8 @@ function getEngine() {
|
|||||||
return new MLXEngine(DEFAULT_CONFIG2);
|
return new MLXEngine(DEFAULT_CONFIG2);
|
||||||
case "deepseek" /* DEEPSEEK */:
|
case "deepseek" /* DEEPSEEK */:
|
||||||
return new DeepseekEngine(DEFAULT_CONFIG2);
|
return new DeepseekEngine(DEFAULT_CONFIG2);
|
||||||
|
case "openrouter" /* OPENROUTER */:
|
||||||
|
return new OpenRouterEngine(DEFAULT_CONFIG2);
|
||||||
default:
|
default:
|
||||||
return new OpenAiEngine(DEFAULT_CONFIG2);
|
return new OpenAiEngine(DEFAULT_CONFIG2);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70984,7 +70984,338 @@ var MODEL_LIST = {
|
|||||||
"mistral-moderation-2411",
|
"mistral-moderation-2411",
|
||||||
"mistral-moderation-latest"
|
"mistral-moderation-latest"
|
||||||
],
|
],
|
||||||
deepseek: ["deepseek-chat", "deepseek-reasoner"]
|
deepseek: ["deepseek-chat", "deepseek-reasoner"],
|
||||||
|
// OpenRouter available models
|
||||||
|
// input_modalities: 'text'
|
||||||
|
// output_modalities: 'text'
|
||||||
|
// https://openrouter.ai/api/v1/models
|
||||||
|
openrouter: [
|
||||||
|
"openai/gpt-4o-mini",
|
||||||
|
// used by default
|
||||||
|
"01-ai/yi-large",
|
||||||
|
"aetherwiing/mn-starcannon-12b",
|
||||||
|
"agentica-org/deepcoder-14b-preview:free",
|
||||||
|
"ai21/jamba-1.6-large",
|
||||||
|
"ai21/jamba-1.6-mini",
|
||||||
|
"aion-labs/aion-1.0",
|
||||||
|
"aion-labs/aion-1.0-mini",
|
||||||
|
"aion-labs/aion-rp-llama-3.1-8b",
|
||||||
|
"alfredpros/codellama-7b-instruct-solidity",
|
||||||
|
"all-hands/openhands-lm-32b-v0.1",
|
||||||
|
"alpindale/goliath-120b",
|
||||||
|
"alpindale/magnum-72b",
|
||||||
|
"amazon/nova-lite-v1",
|
||||||
|
"amazon/nova-micro-v1",
|
||||||
|
"amazon/nova-pro-v1",
|
||||||
|
"anthracite-org/magnum-v2-72b",
|
||||||
|
"anthracite-org/magnum-v4-72b",
|
||||||
|
"anthropic/claude-2",
|
||||||
|
"anthropic/claude-2.0",
|
||||||
|
"anthropic/claude-2.0:beta",
|
||||||
|
"anthropic/claude-2.1",
|
||||||
|
"anthropic/claude-2.1:beta",
|
||||||
|
"anthropic/claude-2:beta",
|
||||||
|
"anthropic/claude-3-haiku",
|
||||||
|
"anthropic/claude-3-haiku:beta",
|
||||||
|
"anthropic/claude-3-opus",
|
||||||
|
"anthropic/claude-3-opus:beta",
|
||||||
|
"anthropic/claude-3-sonnet",
|
||||||
|
"anthropic/claude-3-sonnet:beta",
|
||||||
|
"anthropic/claude-3.5-haiku",
|
||||||
|
"anthropic/claude-3.5-haiku-20241022",
|
||||||
|
"anthropic/claude-3.5-haiku-20241022:beta",
|
||||||
|
"anthropic/claude-3.5-haiku:beta",
|
||||||
|
"anthropic/claude-3.5-sonnet",
|
||||||
|
"anthropic/claude-3.5-sonnet-20240620",
|
||||||
|
"anthropic/claude-3.5-sonnet-20240620:beta",
|
||||||
|
"anthropic/claude-3.5-sonnet:beta",
|
||||||
|
"anthropic/claude-3.7-sonnet",
|
||||||
|
"anthropic/claude-3.7-sonnet:beta",
|
||||||
|
"anthropic/claude-3.7-sonnet:thinking",
|
||||||
|
"anthropic/claude-opus-4",
|
||||||
|
"anthropic/claude-sonnet-4",
|
||||||
|
"arcee-ai/arcee-blitz",
|
||||||
|
"arcee-ai/caller-large",
|
||||||
|
"arcee-ai/coder-large",
|
||||||
|
"arcee-ai/maestro-reasoning",
|
||||||
|
"arcee-ai/spotlight",
|
||||||
|
"arcee-ai/virtuoso-large",
|
||||||
|
"arcee-ai/virtuoso-medium-v2",
|
||||||
|
"arliai/qwq-32b-arliai-rpr-v1:free",
|
||||||
|
"cognitivecomputations/dolphin-mixtral-8x22b",
|
||||||
|
"cognitivecomputations/dolphin3.0-mistral-24b:free",
|
||||||
|
"cognitivecomputations/dolphin3.0-r1-mistral-24b:free",
|
||||||
|
"cohere/command",
|
||||||
|
"cohere/command-a",
|
||||||
|
"cohere/command-r",
|
||||||
|
"cohere/command-r-03-2024",
|
||||||
|
"cohere/command-r-08-2024",
|
||||||
|
"cohere/command-r-plus",
|
||||||
|
"cohere/command-r-plus-04-2024",
|
||||||
|
"cohere/command-r-plus-08-2024",
|
||||||
|
"cohere/command-r7b-12-2024",
|
||||||
|
"deepseek/deepseek-chat",
|
||||||
|
"deepseek/deepseek-chat-v3-0324",
|
||||||
|
"deepseek/deepseek-chat-v3-0324:free",
|
||||||
|
"deepseek/deepseek-chat:free",
|
||||||
|
"deepseek/deepseek-prover-v2",
|
||||||
|
"deepseek/deepseek-prover-v2:free",
|
||||||
|
"deepseek/deepseek-r1",
|
||||||
|
"deepseek/deepseek-r1-0528",
|
||||||
|
"deepseek/deepseek-r1-0528-qwen3-8b",
|
||||||
|
"deepseek/deepseek-r1-0528-qwen3-8b:free",
|
||||||
|
"deepseek/deepseek-r1-0528:free",
|
||||||
|
"deepseek/deepseek-r1-distill-llama-70b",
|
||||||
|
"deepseek/deepseek-r1-distill-llama-70b:free",
|
||||||
|
"deepseek/deepseek-r1-distill-llama-8b",
|
||||||
|
"deepseek/deepseek-r1-distill-qwen-1.5b",
|
||||||
|
"deepseek/deepseek-r1-distill-qwen-14b",
|
||||||
|
"deepseek/deepseek-r1-distill-qwen-14b:free",
|
||||||
|
"deepseek/deepseek-r1-distill-qwen-32b",
|
||||||
|
"deepseek/deepseek-r1-distill-qwen-32b:free",
|
||||||
|
"deepseek/deepseek-r1-distill-qwen-7b",
|
||||||
|
"deepseek/deepseek-r1-zero:free",
|
||||||
|
"deepseek/deepseek-r1:free",
|
||||||
|
"deepseek/deepseek-v3-base:free",
|
||||||
|
"eleutherai/llemma_7b",
|
||||||
|
"eva-unit-01/eva-llama-3.33-70b",
|
||||||
|
"eva-unit-01/eva-qwen-2.5-32b",
|
||||||
|
"eva-unit-01/eva-qwen-2.5-72b",
|
||||||
|
"featherless/qwerky-72b:free",
|
||||||
|
"google/gemini-2.0-flash-001",
|
||||||
|
"google/gemini-2.0-flash-exp:free",
|
||||||
|
"google/gemini-2.0-flash-lite-001",
|
||||||
|
"google/gemini-2.5-flash-preview",
|
||||||
|
"google/gemini-2.5-flash-preview-05-20",
|
||||||
|
"google/gemini-2.5-flash-preview-05-20:thinking",
|
||||||
|
"google/gemini-2.5-flash-preview:thinking",
|
||||||
|
"google/gemini-2.5-pro-exp-03-25",
|
||||||
|
"google/gemini-2.5-pro-preview",
|
||||||
|
"google/gemini-2.5-pro-preview-05-06",
|
||||||
|
"google/gemini-flash-1.5",
|
||||||
|
"google/gemini-flash-1.5-8b",
|
||||||
|
"google/gemini-pro-1.5",
|
||||||
|
"google/gemma-2-27b-it",
|
||||||
|
"google/gemma-2-9b-it",
|
||||||
|
"google/gemma-2-9b-it:free",
|
||||||
|
"google/gemma-3-12b-it",
|
||||||
|
"google/gemma-3-12b-it:free",
|
||||||
|
"google/gemma-3-1b-it:free",
|
||||||
|
"google/gemma-3-27b-it",
|
||||||
|
"google/gemma-3-27b-it:free",
|
||||||
|
"google/gemma-3-4b-it",
|
||||||
|
"google/gemma-3-4b-it:free",
|
||||||
|
"google/gemma-3n-e4b-it:free",
|
||||||
|
"gryphe/mythomax-l2-13b",
|
||||||
|
"inception/mercury-coder-small-beta",
|
||||||
|
"infermatic/mn-inferor-12b",
|
||||||
|
"inflection/inflection-3-pi",
|
||||||
|
"inflection/inflection-3-productivity",
|
||||||
|
"liquid/lfm-3b",
|
||||||
|
"liquid/lfm-40b",
|
||||||
|
"liquid/lfm-7b",
|
||||||
|
"mancer/weaver",
|
||||||
|
"meta-llama/llama-2-70b-chat",
|
||||||
|
"meta-llama/llama-3-70b-instruct",
|
||||||
|
"meta-llama/llama-3-8b-instruct",
|
||||||
|
"meta-llama/llama-3.1-405b",
|
||||||
|
"meta-llama/llama-3.1-405b-instruct",
|
||||||
|
"meta-llama/llama-3.1-405b:free",
|
||||||
|
"meta-llama/llama-3.1-70b-instruct",
|
||||||
|
"meta-llama/llama-3.1-8b-instruct",
|
||||||
|
"meta-llama/llama-3.1-8b-instruct:free",
|
||||||
|
"meta-llama/llama-3.2-11b-vision-instruct",
|
||||||
|
"meta-llama/llama-3.2-11b-vision-instruct:free",
|
||||||
|
"meta-llama/llama-3.2-1b-instruct",
|
||||||
|
"meta-llama/llama-3.2-1b-instruct:free",
|
||||||
|
"meta-llama/llama-3.2-3b-instruct",
|
||||||
|
"meta-llama/llama-3.2-3b-instruct:free",
|
||||||
|
"meta-llama/llama-3.2-90b-vision-instruct",
|
||||||
|
"meta-llama/llama-3.3-70b-instruct",
|
||||||
|
"meta-llama/llama-3.3-70b-instruct:free",
|
||||||
|
"meta-llama/llama-3.3-8b-instruct:free",
|
||||||
|
"meta-llama/llama-4-maverick",
|
||||||
|
"meta-llama/llama-4-maverick:free",
|
||||||
|
"meta-llama/llama-4-scout",
|
||||||
|
"meta-llama/llama-4-scout:free",
|
||||||
|
"meta-llama/llama-guard-2-8b",
|
||||||
|
"meta-llama/llama-guard-3-8b",
|
||||||
|
"meta-llama/llama-guard-4-12b",
|
||||||
|
"microsoft/mai-ds-r1:free",
|
||||||
|
"microsoft/phi-3-medium-128k-instruct",
|
||||||
|
"microsoft/phi-3-mini-128k-instruct",
|
||||||
|
"microsoft/phi-3.5-mini-128k-instruct",
|
||||||
|
"microsoft/phi-4",
|
||||||
|
"microsoft/phi-4-multimodal-instruct",
|
||||||
|
"microsoft/phi-4-reasoning-plus",
|
||||||
|
"microsoft/phi-4-reasoning-plus:free",
|
||||||
|
"microsoft/phi-4-reasoning:free",
|
||||||
|
"microsoft/wizardlm-2-8x22b",
|
||||||
|
"minimax/minimax-01",
|
||||||
|
"mistralai/codestral-2501",
|
||||||
|
"mistralai/devstral-small",
|
||||||
|
"mistralai/devstral-small:free",
|
||||||
|
"mistralai/magistral-medium-2506",
|
||||||
|
"mistralai/magistral-medium-2506:thinking",
|
||||||
|
"mistralai/magistral-small-2506",
|
||||||
|
"mistralai/ministral-3b",
|
||||||
|
"mistralai/ministral-8b",
|
||||||
|
"mistralai/mistral-7b-instruct",
|
||||||
|
"mistralai/mistral-7b-instruct-v0.1",
|
||||||
|
"mistralai/mistral-7b-instruct-v0.2",
|
||||||
|
"mistralai/mistral-7b-instruct-v0.3",
|
||||||
|
"mistralai/mistral-7b-instruct:free",
|
||||||
|
"mistralai/mistral-large",
|
||||||
|
"mistralai/mistral-large-2407",
|
||||||
|
"mistralai/mistral-large-2411",
|
||||||
|
"mistralai/mistral-medium",
|
||||||
|
"mistralai/mistral-medium-3",
|
||||||
|
"mistralai/mistral-nemo",
|
||||||
|
"mistralai/mistral-nemo:free",
|
||||||
|
"mistralai/mistral-saba",
|
||||||
|
"mistralai/mistral-small",
|
||||||
|
"mistralai/mistral-small-24b-instruct-2501",
|
||||||
|
"mistralai/mistral-small-24b-instruct-2501:free",
|
||||||
|
"mistralai/mistral-small-3.1-24b-instruct",
|
||||||
|
"mistralai/mistral-small-3.1-24b-instruct:free",
|
||||||
|
"mistralai/mistral-tiny",
|
||||||
|
"mistralai/mixtral-8x22b-instruct",
|
||||||
|
"mistralai/mixtral-8x7b-instruct",
|
||||||
|
"mistralai/pixtral-12b",
|
||||||
|
"mistralai/pixtral-large-2411",
|
||||||
|
"moonshotai/kimi-vl-a3b-thinking:free",
|
||||||
|
"moonshotai/moonlight-16b-a3b-instruct:free",
|
||||||
|
"neversleep/llama-3-lumimaid-70b",
|
||||||
|
"neversleep/llama-3-lumimaid-8b",
|
||||||
|
"neversleep/llama-3.1-lumimaid-70b",
|
||||||
|
"neversleep/llama-3.1-lumimaid-8b",
|
||||||
|
"neversleep/noromaid-20b",
|
||||||
|
"nothingiisreal/mn-celeste-12b",
|
||||||
|
"nousresearch/deephermes-3-llama-3-8b-preview:free",
|
||||||
|
"nousresearch/deephermes-3-mistral-24b-preview:free",
|
||||||
|
"nousresearch/hermes-2-pro-llama-3-8b",
|
||||||
|
"nousresearch/hermes-3-llama-3.1-405b",
|
||||||
|
"nousresearch/hermes-3-llama-3.1-70b",
|
||||||
|
"nousresearch/nous-hermes-2-mixtral-8x7b-dpo",
|
||||||
|
"nvidia/llama-3.1-nemotron-70b-instruct",
|
||||||
|
"nvidia/llama-3.1-nemotron-ultra-253b-v1",
|
||||||
|
"nvidia/llama-3.1-nemotron-ultra-253b-v1:free",
|
||||||
|
"nvidia/llama-3.3-nemotron-super-49b-v1",
|
||||||
|
"nvidia/llama-3.3-nemotron-super-49b-v1:free",
|
||||||
|
"open-r1/olympiccoder-32b:free",
|
||||||
|
"openai/chatgpt-4o-latest",
|
||||||
|
"openai/codex-mini",
|
||||||
|
"openai/gpt-3.5-turbo",
|
||||||
|
"openai/gpt-3.5-turbo-0125",
|
||||||
|
"openai/gpt-3.5-turbo-0613",
|
||||||
|
"openai/gpt-3.5-turbo-1106",
|
||||||
|
"openai/gpt-3.5-turbo-16k",
|
||||||
|
"openai/gpt-3.5-turbo-instruct",
|
||||||
|
"openai/gpt-4",
|
||||||
|
"openai/gpt-4-0314",
|
||||||
|
"openai/gpt-4-1106-preview",
|
||||||
|
"openai/gpt-4-turbo",
|
||||||
|
"openai/gpt-4-turbo-preview",
|
||||||
|
"openai/gpt-4.1",
|
||||||
|
"openai/gpt-4.1-mini",
|
||||||
|
"openai/gpt-4.1-nano",
|
||||||
|
"openai/gpt-4.5-preview",
|
||||||
|
"openai/gpt-4o",
|
||||||
|
"openai/gpt-4o-2024-05-13",
|
||||||
|
"openai/gpt-4o-2024-08-06",
|
||||||
|
"openai/gpt-4o-2024-11-20",
|
||||||
|
"openai/gpt-4o-mini-2024-07-18",
|
||||||
|
"openai/gpt-4o-mini-search-preview",
|
||||||
|
"openai/gpt-4o-search-preview",
|
||||||
|
"openai/gpt-4o:extended",
|
||||||
|
"openai/o1",
|
||||||
|
"openai/o1-mini",
|
||||||
|
"openai/o1-mini-2024-09-12",
|
||||||
|
"openai/o1-preview",
|
||||||
|
"openai/o1-preview-2024-09-12",
|
||||||
|
"openai/o1-pro",
|
||||||
|
"openai/o3",
|
||||||
|
"openai/o3-mini",
|
||||||
|
"openai/o3-mini-high",
|
||||||
|
"openai/o3-pro",
|
||||||
|
"openai/o4-mini",
|
||||||
|
"openai/o4-mini-high",
|
||||||
|
"opengvlab/internvl3-14b:free",
|
||||||
|
"opengvlab/internvl3-2b:free",
|
||||||
|
"openrouter/auto",
|
||||||
|
"perplexity/llama-3.1-sonar-large-128k-online",
|
||||||
|
"perplexity/llama-3.1-sonar-small-128k-online",
|
||||||
|
"perplexity/r1-1776",
|
||||||
|
"perplexity/sonar",
|
||||||
|
"perplexity/sonar-deep-research",
|
||||||
|
"perplexity/sonar-pro",
|
||||||
|
"perplexity/sonar-reasoning",
|
||||||
|
"perplexity/sonar-reasoning-pro",
|
||||||
|
"pygmalionai/mythalion-13b",
|
||||||
|
"qwen/qwen-2-72b-instruct",
|
||||||
|
"qwen/qwen-2.5-72b-instruct",
|
||||||
|
"qwen/qwen-2.5-72b-instruct:free",
|
||||||
|
"qwen/qwen-2.5-7b-instruct",
|
||||||
|
"qwen/qwen-2.5-7b-instruct:free",
|
||||||
|
"qwen/qwen-2.5-coder-32b-instruct",
|
||||||
|
"qwen/qwen-2.5-coder-32b-instruct:free",
|
||||||
|
"qwen/qwen-2.5-vl-7b-instruct",
|
||||||
|
"qwen/qwen-2.5-vl-7b-instruct:free",
|
||||||
|
"qwen/qwen-max",
|
||||||
|
"qwen/qwen-plus",
|
||||||
|
"qwen/qwen-turbo",
|
||||||
|
"qwen/qwen-vl-max",
|
||||||
|
"qwen/qwen-vl-plus",
|
||||||
|
"qwen/qwen2.5-vl-32b-instruct",
|
||||||
|
"qwen/qwen2.5-vl-32b-instruct:free",
|
||||||
|
"qwen/qwen2.5-vl-3b-instruct:free",
|
||||||
|
"qwen/qwen2.5-vl-72b-instruct",
|
||||||
|
"qwen/qwen2.5-vl-72b-instruct:free",
|
||||||
|
"qwen/qwen3-14b",
|
||||||
|
"qwen/qwen3-14b:free",
|
||||||
|
"qwen/qwen3-235b-a22b",
|
||||||
|
"qwen/qwen3-235b-a22b:free",
|
||||||
|
"qwen/qwen3-30b-a3b",
|
||||||
|
"qwen/qwen3-30b-a3b:free",
|
||||||
|
"qwen/qwen3-32b",
|
||||||
|
"qwen/qwen3-32b:free",
|
||||||
|
"qwen/qwen3-8b",
|
||||||
|
"qwen/qwen3-8b:free",
|
||||||
|
"qwen/qwq-32b",
|
||||||
|
"qwen/qwq-32b-preview",
|
||||||
|
"qwen/qwq-32b:free",
|
||||||
|
"raifle/sorcererlm-8x22b",
|
||||||
|
"rekaai/reka-flash-3:free",
|
||||||
|
"sao10k/fimbulvetr-11b-v2",
|
||||||
|
"sao10k/l3-euryale-70b",
|
||||||
|
"sao10k/l3-lunaris-8b",
|
||||||
|
"sao10k/l3.1-euryale-70b",
|
||||||
|
"sao10k/l3.3-euryale-70b",
|
||||||
|
"sarvamai/sarvam-m:free",
|
||||||
|
"scb10x/llama3.1-typhoon2-70b-instruct",
|
||||||
|
"sentientagi/dobby-mini-unhinged-plus-llama-3.1-8b",
|
||||||
|
"shisa-ai/shisa-v2-llama3.3-70b:free",
|
||||||
|
"sophosympatheia/midnight-rose-70b",
|
||||||
|
"thedrummer/anubis-pro-105b-v1",
|
||||||
|
"thedrummer/rocinante-12b",
|
||||||
|
"thedrummer/skyfall-36b-v2",
|
||||||
|
"thedrummer/unslopnemo-12b",
|
||||||
|
"thedrummer/valkyrie-49b-v1",
|
||||||
|
"thudm/glm-4-32b",
|
||||||
|
"thudm/glm-4-32b:free",
|
||||||
|
"thudm/glm-z1-32b",
|
||||||
|
"thudm/glm-z1-32b:free",
|
||||||
|
"thudm/glm-z1-rumination-32b",
|
||||||
|
"tngtech/deepseek-r1t-chimera:free",
|
||||||
|
"undi95/remm-slerp-l2-13b",
|
||||||
|
"undi95/toppy-m-7b",
|
||||||
|
"x-ai/grok-2-1212",
|
||||||
|
"x-ai/grok-2-vision-1212",
|
||||||
|
"x-ai/grok-3-beta",
|
||||||
|
"x-ai/grok-3-mini-beta",
|
||||||
|
"x-ai/grok-beta",
|
||||||
|
"x-ai/grok-vision-beta"
|
||||||
|
]
|
||||||
};
|
};
|
||||||
var getDefaultModel = (provider) => {
|
var getDefaultModel = (provider) => {
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
@@ -71002,6 +71333,8 @@ var getDefaultModel = (provider) => {
|
|||||||
return MODEL_LIST.mistral[0];
|
return MODEL_LIST.mistral[0];
|
||||||
case "deepseek":
|
case "deepseek":
|
||||||
return MODEL_LIST.deepseek[0];
|
return MODEL_LIST.deepseek[0];
|
||||||
|
case "openrouter":
|
||||||
|
return MODEL_LIST.openrouter[0];
|
||||||
default:
|
default:
|
||||||
return MODEL_LIST.openai[0];
|
return MODEL_LIST.openai[0];
|
||||||
}
|
}
|
||||||
@@ -71155,7 +71488,8 @@ var configValidators = {
|
|||||||
"test",
|
"test",
|
||||||
"flowise",
|
"flowise",
|
||||||
"groq",
|
"groq",
|
||||||
"deepseek"
|
"deepseek",
|
||||||
|
"openrouter"
|
||||||
].includes(value) || value.startsWith("ollama"),
|
].includes(value) || value.startsWith("ollama"),
|
||||||
`${value} is not supported yet, use 'ollama', 'mlx', 'anthropic', 'azure', 'gemini', 'flowise', 'mistral', 'deepseek' or 'openai' (default)`
|
`${value} is not supported yet, use 'ollama', 'mlx', 'anthropic', 'azure', 'gemini', 'flowise', 'mistral', 'deepseek' or 'openai' (default)`
|
||||||
);
|
);
|
||||||
@@ -71200,6 +71534,7 @@ var OCO_AI_PROVIDER_ENUM = /* @__PURE__ */ ((OCO_AI_PROVIDER_ENUM2) => {
|
|||||||
OCO_AI_PROVIDER_ENUM2["MISTRAL"] = "mistral";
|
OCO_AI_PROVIDER_ENUM2["MISTRAL"] = "mistral";
|
||||||
OCO_AI_PROVIDER_ENUM2["MLX"] = "mlx";
|
OCO_AI_PROVIDER_ENUM2["MLX"] = "mlx";
|
||||||
OCO_AI_PROVIDER_ENUM2["DEEPSEEK"] = "deepseek";
|
OCO_AI_PROVIDER_ENUM2["DEEPSEEK"] = "deepseek";
|
||||||
|
OCO_AI_PROVIDER_ENUM2["OPENROUTER"] = "openrouter";
|
||||||
return OCO_AI_PROVIDER_ENUM2;
|
return OCO_AI_PROVIDER_ENUM2;
|
||||||
})(OCO_AI_PROVIDER_ENUM || {});
|
})(OCO_AI_PROVIDER_ENUM || {});
|
||||||
var defaultConfigPath = (0, import_path.join)((0, import_os.homedir)(), ".opencommit");
|
var defaultConfigPath = (0, import_path.join)((0, import_os.homedir)(), ".opencommit");
|
||||||
@@ -71487,7 +71822,11 @@ ${key}:`));
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(source_default.yellow('\nUse "oco config describe [PARAMETER]" to see accepted values and more details for a specific config parameter.'));
|
console.log(
|
||||||
|
source_default.yellow(
|
||||||
|
'\nUse "oco config describe [PARAMETER]" to see accepted values and more details for a specific config parameter.'
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
var configCommand = G2(
|
var configCommand = G2(
|
||||||
{
|
{
|
||||||
@@ -86795,6 +87134,40 @@ var DeepseekEngine = class extends OpenAiEngine {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// src/engine/openrouter.ts
|
||||||
|
var OpenRouterEngine = class {
|
||||||
|
constructor(config6) {
|
||||||
|
this.config = config6;
|
||||||
|
this.generateCommitMessage = async (messages) => {
|
||||||
|
try {
|
||||||
|
const response = await this.client.post("", {
|
||||||
|
model: this.config.model,
|
||||||
|
messages
|
||||||
|
});
|
||||||
|
const message = response.data.choices[0].message;
|
||||||
|
let content = message?.content;
|
||||||
|
return removeContentTags(content, "think");
|
||||||
|
} catch (error) {
|
||||||
|
const err = error;
|
||||||
|
if (axios_default.isAxiosError(error) && error.response?.status === 401) {
|
||||||
|
const openRouterError = error.response.data.error;
|
||||||
|
if (openRouterError) throw new Error(openRouterError.message);
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.client = axios_default.create({
|
||||||
|
baseURL: "https://openrouter.ai/api/v1/chat/completions",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${config6.apiKey}`,
|
||||||
|
"HTTP-Referer": "https://github.com/di-sukharev/opencommit",
|
||||||
|
"X-Title": "OpenCommit",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// src/utils/engine.ts
|
// src/utils/engine.ts
|
||||||
function parseCustomHeaders(headers) {
|
function parseCustomHeaders(headers) {
|
||||||
let parsedHeaders = {};
|
let parsedHeaders = {};
|
||||||
@@ -86808,7 +87181,9 @@ function parseCustomHeaders(headers) {
|
|||||||
parsedHeaders = JSON.parse(headers);
|
parsedHeaders = JSON.parse(headers);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn("Invalid OCO_API_CUSTOM_HEADERS format, ignoring custom headers");
|
console.warn(
|
||||||
|
"Invalid OCO_API_CUSTOM_HEADERS format, ignoring custom headers"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return parsedHeaders;
|
return parsedHeaders;
|
||||||
}
|
}
|
||||||
@@ -86845,6 +87220,8 @@ function getEngine() {
|
|||||||
return new MLXEngine(DEFAULT_CONFIG2);
|
return new MLXEngine(DEFAULT_CONFIG2);
|
||||||
case "deepseek" /* DEEPSEEK */:
|
case "deepseek" /* DEEPSEEK */:
|
||||||
return new DeepseekEngine(DEFAULT_CONFIG2);
|
return new DeepseekEngine(DEFAULT_CONFIG2);
|
||||||
|
case "openrouter" /* OPENROUTER */:
|
||||||
|
return new OpenRouterEngine(DEFAULT_CONFIG2);
|
||||||
default:
|
default:
|
||||||
return new OpenAiEngine(DEFAULT_CONFIG2);
|
return new OpenAiEngine(DEFAULT_CONFIG2);
|
||||||
}
|
}
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "opencommit",
|
"name": "opencommit",
|
||||||
"version": "3.2.9",
|
"version": "3.2.10",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "opencommit",
|
"name": "opencommit",
|
||||||
"version": "3.2.9",
|
"version": "3.2.10",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.10.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "opencommit",
|
"name": "opencommit",
|
||||||
"version": "3.2.9",
|
"version": "3.2.10",
|
||||||
"description": "Auto-generate impressive commits in 1 second. Killing lame commits with AI 🤯🔫",
|
"description": "Auto-generate impressive commits in 1 second. Killing lame commits with AI 🤯🔫",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"git",
|
"git",
|
||||||
@@ -51,6 +51,7 @@
|
|||||||
"deploy:patch": "npm version patch && npm run deploy:build",
|
"deploy:patch": "npm version patch && npm run deploy:build",
|
||||||
"lint": "eslint src --ext ts && tsc --noEmit",
|
"lint": "eslint src --ext ts && tsc --noEmit",
|
||||||
"format": "prettier --write src",
|
"format": "prettier --write src",
|
||||||
|
"format:check": "prettier --check src",
|
||||||
"test": "node --no-warnings --experimental-vm-modules $( [ -f ./node_modules/.bin/jest ] && echo ./node_modules/.bin/jest || which jest ) test/unit",
|
"test": "node --no-warnings --experimental-vm-modules $( [ -f ./node_modules/.bin/jest ] && echo ./node_modules/.bin/jest || which jest ) test/unit",
|
||||||
"test:all": "npm run test:unit:docker && npm run test:e2e:docker",
|
"test:all": "npm run test:unit:docker && npm run test:e2e:docker",
|
||||||
"test:docker-build": "docker build -t oco-test -f test/Dockerfile .",
|
"test:docker-build": "docker build -t oco-test -f test/Dockerfile .",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
text,
|
||||||
confirm,
|
confirm,
|
||||||
intro,
|
intro,
|
||||||
isCancel,
|
isCancel,
|
||||||
@@ -85,15 +86,29 @@ ${commitMessage}
|
|||||||
${chalk.grey('——————————————————')}`
|
${chalk.grey('——————————————————')}`
|
||||||
);
|
);
|
||||||
|
|
||||||
const isCommitConfirmedByUser =
|
const userAction = skipCommitConfirmation
|
||||||
skipCommitConfirmation ||
|
? 'Yes'
|
||||||
(await confirm({
|
: await select({
|
||||||
message: 'Confirm the commit message?'
|
message: 'Confirm the commit message?',
|
||||||
}));
|
options: [
|
||||||
|
{ value: 'Yes', label: 'Yes' },
|
||||||
|
{ value: 'No', label: 'No' },
|
||||||
|
{ value: 'Edit', label: 'Edit' }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
if (isCancel(isCommitConfirmedByUser)) process.exit(1);
|
if (isCancel(userAction)) process.exit(1);
|
||||||
|
|
||||||
if (isCommitConfirmedByUser) {
|
if (userAction === 'Edit') {
|
||||||
|
const textResponse = await text({
|
||||||
|
message: 'Please edit the commit message: (press Enter to continue)',
|
||||||
|
initialValue: commitMessage
|
||||||
|
});
|
||||||
|
|
||||||
|
commitMessage = textResponse.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userAction === 'Yes' || userAction === 'Edit') {
|
||||||
const committingChangesSpinner = spinner();
|
const committingChangesSpinner = spinner();
|
||||||
committingChangesSpinner.start('Committing the changes');
|
committingChangesSpinner.start('Committing the changes');
|
||||||
const { stdout } = await execa('git', [
|
const { stdout } = await execa('git', [
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ export enum CONFIG_KEYS {
|
|||||||
OCO_API_URL = 'OCO_API_URL',
|
OCO_API_URL = 'OCO_API_URL',
|
||||||
OCO_API_CUSTOM_HEADERS = 'OCO_API_CUSTOM_HEADERS',
|
OCO_API_CUSTOM_HEADERS = 'OCO_API_CUSTOM_HEADERS',
|
||||||
OCO_OMIT_SCOPE = 'OCO_OMIT_SCOPE',
|
OCO_OMIT_SCOPE = 'OCO_OMIT_SCOPE',
|
||||||
OCO_GITPUSH = 'OCO_GITPUSH' // todo: deprecate
|
OCO_GITPUSH = 'OCO_GITPUSH', // todo: deprecate
|
||||||
|
OCO_HOOK_AUTO_UNCOMMENT = 'OCO_HOOK_AUTO_UNCOMMENT'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum CONFIG_MODES {
|
export enum CONFIG_MODES {
|
||||||
@@ -132,9 +133,113 @@ export const MODEL_LIST = {
|
|||||||
'mistral-moderation-2411',
|
'mistral-moderation-2411',
|
||||||
'mistral-moderation-latest'
|
'mistral-moderation-latest'
|
||||||
],
|
],
|
||||||
|
|
||||||
deepseek: ['deepseek-chat', 'deepseek-reasoner'],
|
deepseek: ['deepseek-chat', 'deepseek-reasoner'],
|
||||||
|
|
||||||
|
// AI/ML API available chat-completion models
|
||||||
|
// https://api.aimlapi.com/v1/models
|
||||||
|
aimlapi: [
|
||||||
|
'openai/gpt-4o',
|
||||||
|
'gpt-4o-2024-08-06',
|
||||||
|
'gpt-4o-2024-05-13',
|
||||||
|
'gpt-4o-mini',
|
||||||
|
'gpt-4o-mini-2024-07-18',
|
||||||
|
'chatgpt-4o-latest',
|
||||||
|
'gpt-4-turbo',
|
||||||
|
'gpt-4-turbo-2024-04-09',
|
||||||
|
'gpt-4',
|
||||||
|
'gpt-4-0125-preview',
|
||||||
|
'gpt-4-1106-preview',
|
||||||
|
'gpt-3.5-turbo',
|
||||||
|
'gpt-3.5-turbo-0125',
|
||||||
|
'gpt-3.5-turbo-1106',
|
||||||
|
'o1-preview',
|
||||||
|
'o1-preview-2024-09-12',
|
||||||
|
'o1-mini',
|
||||||
|
'o1-mini-2024-09-12',
|
||||||
|
'o3-mini',
|
||||||
|
'gpt-4o-audio-preview',
|
||||||
|
'gpt-4o-mini-audio-preview',
|
||||||
|
'gpt-4o-search-preview',
|
||||||
|
'gpt-4o-mini-search-preview',
|
||||||
|
'openai/gpt-4.1-2025-04-14',
|
||||||
|
'openai/gpt-4.1-mini-2025-04-14',
|
||||||
|
'openai/gpt-4.1-nano-2025-04-14',
|
||||||
|
'openai/o4-mini-2025-04-16',
|
||||||
|
'openai/o3-2025-04-16',
|
||||||
|
'o1',
|
||||||
|
'openai/o3-pro',
|
||||||
|
'meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo',
|
||||||
|
'google/gemma-2-27b-it',
|
||||||
|
'meta-llama/Llama-Vision-Free',
|
||||||
|
'Qwen/Qwen2-72B-Instruct',
|
||||||
|
'mistralai/Mixtral-8x7B-Instruct-v0.1',
|
||||||
|
'nvidia/Llama-3.1-Nemotron-70B-Instruct-HF',
|
||||||
|
'NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO',
|
||||||
|
'meta-llama/Llama-3.3-70B-Instruct-Turbo',
|
||||||
|
'meta-llama/Llama-3.2-3B-Instruct-Turbo',
|
||||||
|
'meta-llama/Llama-3.2-11B-Vision-Instruct-Turbo',
|
||||||
|
'meta-llama/Llama-Guard-3-11B-Vision-Turbo',
|
||||||
|
'Qwen/Qwen2.5-7B-Instruct-Turbo',
|
||||||
|
'Qwen/Qwen2.5-Coder-32B-Instruct',
|
||||||
|
'meta-llama/Meta-Llama-3-8B-Instruct-Lite',
|
||||||
|
'meta-llama/Llama-3-8b-chat-hf',
|
||||||
|
'meta-llama/Llama-3-70b-chat-hf',
|
||||||
|
'Qwen/Qwen2.5-72B-Instruct-Turbo',
|
||||||
|
'Qwen/QwQ-32B',
|
||||||
|
'meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo',
|
||||||
|
'meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo',
|
||||||
|
'meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo',
|
||||||
|
'mistralai/Mistral-7B-Instruct-v0.2',
|
||||||
|
'meta-llama/LlamaGuard-2-8b',
|
||||||
|
'mistralai/Mistral-7B-Instruct-v0.1',
|
||||||
|
'mistralai/Mistral-7B-Instruct-v0.3',
|
||||||
|
'meta-llama/Meta-Llama-Guard-3-8B',
|
||||||
|
'meta-llama/llama-4-scout',
|
||||||
|
'meta-llama/llama-4-maverick',
|
||||||
|
'Qwen/Qwen3-235B-A22B-fp8-tput',
|
||||||
|
'claude-3-opus-20240229',
|
||||||
|
'claude-3-haiku-20240307',
|
||||||
|
'claude-3-5-sonnet-20240620',
|
||||||
|
'claude-3-5-sonnet-20241022',
|
||||||
|
'claude-3-5-haiku-20241022',
|
||||||
|
'claude-3-7-sonnet-20250219',
|
||||||
|
'claude-sonnet-4-20250514',
|
||||||
|
'claude-opus-4-20250514',
|
||||||
|
'google/gemini-2.0-flash-exp',
|
||||||
|
'google/gemini-2.0-flash',
|
||||||
|
'google/gemini-2.5-pro',
|
||||||
|
'google/gemini-2.5-flash',
|
||||||
|
'deepseek-chat',
|
||||||
|
'deepseek-reasoner',
|
||||||
|
'qwen-max',
|
||||||
|
'qwen-plus',
|
||||||
|
'qwen-turbo',
|
||||||
|
'qwen-max-2025-01-25',
|
||||||
|
'mistralai/mistral-tiny',
|
||||||
|
'mistralai/mistral-nemo',
|
||||||
|
'anthracite-org/magnum-v4-72b',
|
||||||
|
'nvidia/llama-3.1-nemotron-70b-instruct',
|
||||||
|
'cohere/command-r-plus',
|
||||||
|
'mistralai/codestral-2501',
|
||||||
|
'google/gemma-3-4b-it',
|
||||||
|
'google/gemma-3-12b-it',
|
||||||
|
'google/gemma-3-27b-it',
|
||||||
|
'google/gemini-2.5-flash-lite-preview',
|
||||||
|
'deepseek/deepseek-prover-v2',
|
||||||
|
'google/gemma-3n-e4b-it',
|
||||||
|
'cohere/command-a',
|
||||||
|
'MiniMax-Text-01',
|
||||||
|
'abab6.5s-chat',
|
||||||
|
'minimax/m1',
|
||||||
|
'bagoodex/bagoodex-search-v1',
|
||||||
|
'moonshot/kimi-k2-preview',
|
||||||
|
'perplexity/sonar',
|
||||||
|
'perplexity/sonar-pro',
|
||||||
|
'x-ai/grok-4-07-09',
|
||||||
|
'x-ai/grok-3-beta',
|
||||||
|
'x-ai/grok-3-mini-beta'
|
||||||
|
],
|
||||||
|
|
||||||
// OpenRouter available models
|
// OpenRouter available models
|
||||||
// input_modalities: 'text'
|
// input_modalities: 'text'
|
||||||
// output_modalities: 'text'
|
// output_modalities: 'text'
|
||||||
@@ -483,6 +588,8 @@ const getDefaultModel = (provider: string | undefined): string => {
|
|||||||
return MODEL_LIST.mistral[0];
|
return MODEL_LIST.mistral[0];
|
||||||
case 'deepseek':
|
case 'deepseek':
|
||||||
return MODEL_LIST.deepseek[0];
|
return MODEL_LIST.deepseek[0];
|
||||||
|
case 'aimlapi':
|
||||||
|
return MODEL_LIST.aimlapi[0];
|
||||||
case 'openrouter':
|
case 'openrouter':
|
||||||
return MODEL_LIST.openrouter[0];
|
return MODEL_LIST.openrouter[0];
|
||||||
default:
|
default:
|
||||||
@@ -675,9 +782,10 @@ export const configValidators = {
|
|||||||
'flowise',
|
'flowise',
|
||||||
'groq',
|
'groq',
|
||||||
'deepseek',
|
'deepseek',
|
||||||
|
'aimlapi',
|
||||||
'openrouter'
|
'openrouter'
|
||||||
].includes(value) || value.startsWith('ollama'),
|
].includes(value) || value.startsWith('ollama'),
|
||||||
`${value} is not supported yet, use 'ollama', 'mlx', 'anthropic', 'azure', 'gemini', 'flowise', 'mistral', 'deepseek' or 'openai' (default)`
|
`${value} is not supported yet, use 'ollama', 'mlx', 'anthropic', 'azure', 'gemini', 'flowise', 'mistral', 'deepseek', 'aimlapi' or 'openai' (default)`
|
||||||
);
|
);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
@@ -711,6 +819,14 @@ export const configValidators = {
|
|||||||
'Must be true or false'
|
'Must be true or false'
|
||||||
);
|
);
|
||||||
return value;
|
return value;
|
||||||
|
},
|
||||||
|
|
||||||
|
[CONFIG_KEYS.OCO_HOOK_AUTO_UNCOMMENT](value: any) {
|
||||||
|
validateConfig(
|
||||||
|
CONFIG_KEYS.OCO_HOOK_AUTO_UNCOMMENT,
|
||||||
|
typeof value === 'boolean',
|
||||||
|
'Must be true or false'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -726,6 +842,7 @@ export enum OCO_AI_PROVIDER_ENUM {
|
|||||||
MISTRAL = 'mistral',
|
MISTRAL = 'mistral',
|
||||||
MLX = 'mlx',
|
MLX = 'mlx',
|
||||||
DEEPSEEK = 'deepseek',
|
DEEPSEEK = 'deepseek',
|
||||||
|
AIMLAPI = 'aimlapi',
|
||||||
OPENROUTER = 'openrouter'
|
OPENROUTER = 'openrouter'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -747,6 +864,7 @@ export type ConfigType = {
|
|||||||
[CONFIG_KEYS.OCO_ONE_LINE_COMMIT]: boolean;
|
[CONFIG_KEYS.OCO_ONE_LINE_COMMIT]: boolean;
|
||||||
[CONFIG_KEYS.OCO_OMIT_SCOPE]: boolean;
|
[CONFIG_KEYS.OCO_OMIT_SCOPE]: boolean;
|
||||||
[CONFIG_KEYS.OCO_TEST_MOCK_TYPE]: string;
|
[CONFIG_KEYS.OCO_TEST_MOCK_TYPE]: string;
|
||||||
|
[CONFIG_KEYS.OCO_HOOK_AUTO_UNCOMMENT]: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const defaultConfigPath = pathJoin(homedir(), '.opencommit');
|
export const defaultConfigPath = pathJoin(homedir(), '.opencommit');
|
||||||
@@ -794,7 +912,8 @@ export const DEFAULT_CONFIG = {
|
|||||||
OCO_TEST_MOCK_TYPE: 'commit-message',
|
OCO_TEST_MOCK_TYPE: 'commit-message',
|
||||||
OCO_WHY: false,
|
OCO_WHY: false,
|
||||||
OCO_OMIT_SCOPE: false,
|
OCO_OMIT_SCOPE: false,
|
||||||
OCO_GITPUSH: true // todo: deprecate
|
OCO_GITPUSH: true, // todo: deprecate
|
||||||
|
OCO_HOOK_AUTO_UNCOMMENT: false
|
||||||
};
|
};
|
||||||
|
|
||||||
const initGlobalConfig = (configPath: string = defaultConfigPath) => {
|
const initGlobalConfig = (configPath: string = defaultConfigPath) => {
|
||||||
@@ -1046,6 +1165,11 @@ function getConfigKeyDetails(key) {
|
|||||||
description: 'Message template placeholder',
|
description: 'Message template placeholder',
|
||||||
values: ['String (must start with $)']
|
values: ['String (must start with $)']
|
||||||
};
|
};
|
||||||
|
case CONFIG_KEYS.OCO_HOOK_AUTO_UNCOMMENT:
|
||||||
|
return {
|
||||||
|
description: 'Automatically uncomment the commit message in the hook',
|
||||||
|
values: ['true', 'false']
|
||||||
|
};
|
||||||
default:
|
default:
|
||||||
return {
|
return {
|
||||||
description: 'String value',
|
description: 'String value',
|
||||||
|
|||||||
@@ -56,10 +56,14 @@ export const prepareCommitMessageHook = async (
|
|||||||
|
|
||||||
const fileContent = await fs.readFile(messageFilePath);
|
const fileContent = await fs.readFile(messageFilePath);
|
||||||
|
|
||||||
await fs.writeFile(
|
const messageWithComment = `# ${commitMessage}\n\n# ---------- [OpenCommit] ---------- #\n# Remove the # above to use this generated commit message.\n# To cancel the commit, just close this window without making any changes.\n\n${fileContent.toString()}`;
|
||||||
messageFilePath,
|
const messageWithoutComment = `${commitMessage}\n\n${fileContent.toString()}`;
|
||||||
commitMessage + '\n' + fileContent.toString()
|
|
||||||
);
|
const message = config.OCO_HOOK_AUTO_UNCOMMENT
|
||||||
|
? messageWithoutComment
|
||||||
|
: messageWithComment;
|
||||||
|
|
||||||
|
await fs.writeFile(messageFilePath, message);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
outro(`${chalk.red('✖')} ${error}`);
|
outro(`${chalk.red('✖')} ${error}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|||||||
47
src/engine/aimlapi.ts
Normal file
47
src/engine/aimlapi.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import OpenAI from 'openai';
|
||||||
|
import axios, { AxiosInstance } from 'axios';
|
||||||
|
import { AiEngine, AiEngineConfig } from './Engine';
|
||||||
|
|
||||||
|
interface AimlApiConfig extends AiEngineConfig {}
|
||||||
|
|
||||||
|
export class AimlApiEngine implements AiEngine {
|
||||||
|
client: AxiosInstance;
|
||||||
|
|
||||||
|
constructor(public config: AimlApiConfig) {
|
||||||
|
this.client = axios.create({
|
||||||
|
baseURL: config.baseURL || 'https://api.aimlapi.com/v1/chat/completions',
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${config.apiKey}`,
|
||||||
|
'HTTP-Referer': 'https://github.com/di-sukharev/opencommit',
|
||||||
|
'X-Title': 'opencommit',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...config.customHeaders
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public generateCommitMessage = async (
|
||||||
|
messages: Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>
|
||||||
|
): Promise<string | null> => {
|
||||||
|
try {
|
||||||
|
const response = await this.client.post('', {
|
||||||
|
model: this.config.model,
|
||||||
|
messages
|
||||||
|
});
|
||||||
|
|
||||||
|
const message = response.data.choices?.[0]?.message;
|
||||||
|
return message?.content ?? null;
|
||||||
|
} catch (error) {
|
||||||
|
const err = error as Error;
|
||||||
|
if (
|
||||||
|
axios.isAxiosError<{ error?: { message: string } }>(error) &&
|
||||||
|
error.response?.status === 401
|
||||||
|
) {
|
||||||
|
const apiError = error.response.data.error;
|
||||||
|
if (apiError) throw new Error(apiError.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -23,7 +23,10 @@ export class MistralAiEngine implements AiEngine {
|
|||||||
if (!config.baseURL) {
|
if (!config.baseURL) {
|
||||||
this.client = new Mistral({ apiKey: config.apiKey });
|
this.client = new Mistral({ apiKey: config.apiKey });
|
||||||
} else {
|
} else {
|
||||||
this.client = new Mistral({ apiKey: config.apiKey, serverURL: config.baseURL });
|
this.client = new Mistral({
|
||||||
|
apiKey: config.apiKey,
|
||||||
|
serverURL: config.baseURL
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,13 +53,12 @@ export class MistralAiEngine implements AiEngine {
|
|||||||
|
|
||||||
const completion = await this.client.chat.complete(params);
|
const completion = await this.client.chat.complete(params);
|
||||||
|
|
||||||
if (!completion.choices)
|
if (!completion.choices) throw Error('No completion choice available.');
|
||||||
throw Error('No completion choice available.')
|
|
||||||
|
|
||||||
const message = completion.choices[0].message;
|
const message = completion.choices[0].message;
|
||||||
|
|
||||||
if (!message || !message.content)
|
if (!message || !message.content)
|
||||||
throw Error('No completion choice available.')
|
throw Error('No completion choice available.');
|
||||||
|
|
||||||
let content = message.content as string;
|
let content = message.content as string;
|
||||||
return removeContentTags(content, 'think');
|
return removeContentTags(content, 'think');
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ export class MLXEngine implements AiEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async generateCommitMessage(
|
async generateCommitMessage(
|
||||||
messages: Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>):
|
messages: Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>
|
||||||
Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
const params = {
|
const params = {
|
||||||
messages,
|
messages,
|
||||||
temperature: 0,
|
temperature: 0,
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ const generateCommitMessageChatCompletionPrompt = async (
|
|||||||
fullGitMojiSpec: boolean,
|
fullGitMojiSpec: boolean,
|
||||||
context: string
|
context: string
|
||||||
): Promise<Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>> => {
|
): Promise<Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>> => {
|
||||||
const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec, context);
|
const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(
|
||||||
|
fullGitMojiSpec,
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
const chatContextAsCompletionRequest = [...INIT_MESSAGES_PROMPT];
|
const chatContextAsCompletionRequest = [...INIT_MESSAGES_PROMPT];
|
||||||
|
|
||||||
@@ -38,7 +41,7 @@ const ADJUSTMENT_FACTOR = 20;
|
|||||||
export const generateCommitMessageByDiff = async (
|
export const generateCommitMessageByDiff = async (
|
||||||
diff: string,
|
diff: string,
|
||||||
fullGitMojiSpec: boolean = false,
|
fullGitMojiSpec: boolean = false,
|
||||||
context: string = ""
|
context: string = ''
|
||||||
): Promise<string> => {
|
): Promise<string> => {
|
||||||
try {
|
try {
|
||||||
const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(
|
const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(
|
||||||
@@ -75,7 +78,7 @@ export const generateCommitMessageByDiff = async (
|
|||||||
const messages = await generateCommitMessageChatCompletionPrompt(
|
const messages = await generateCommitMessageChatCompletionPrompt(
|
||||||
diff,
|
diff,
|
||||||
fullGitMojiSpec,
|
fullGitMojiSpec,
|
||||||
context,
|
context
|
||||||
);
|
);
|
||||||
|
|
||||||
const engine = getEngine();
|
const engine = getEngine();
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"localLanguage": "한국어",
|
"localLanguage": "한국어",
|
||||||
"commitFix": "fix(server.ts): 포트 변수를 소문자 port에서 대문자 PORT로 변경",
|
"commitFix": "fix(server.ts): 포트 변수를 소문자 port에서 대문자 PORT로 변경",
|
||||||
"commitFeat": "피트(server.ts): process.env.PORT 환경 변수 지원 추가",
|
"commitFeat": "feat(server.ts): process.env.PORT 환경 변수 지원 추가",
|
||||||
"commitDescription": "포트 변수는 이제 PORT로 이름이 지정되어 상수인 PORT와 일관성 있는 이름 규칙을 따릅니다. 환경 변수 지원을 통해 애플리케이션은 이제 process.env.PORT 환경 변수로 지정된 사용 가능한 모든 포트에서 실행할 수 있으므로 더 유연해졌습니다.",
|
"commitDescription": "포트 변수는 이제 PORT로 이름이 지정되어 상수인 PORT와 일관성 있는 이름 규칙을 따릅니다. 환경 변수 지원을 통해 애플리케이션은 이제 process.env.PORT 환경 변수로 지정된 사용 가능한 모든 포트에서 실행할 수 있으므로 더 유연해졌습니다.",
|
||||||
"commitFixOmitScope": "fix: 포트 변수를 소문자 port에서 대문자 PORT로 변경",
|
"commitFixOmitScope": "fix: 포트 변수를 소문자 port에서 대문자 PORT로 변경",
|
||||||
"commitFeatOmitScope": "피트: process.env.PORT 환경 변수 지원 추가"
|
"commitFeatOmitScope": "feat: process.env.PORT 환경 변수 지원 추가"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,19 @@ export const runMigrations = async () => {
|
|||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
if (config.OCO_AI_PROVIDER === OCO_AI_PROVIDER_ENUM.TEST) return;
|
if (config.OCO_AI_PROVIDER === OCO_AI_PROVIDER_ENUM.TEST) return;
|
||||||
|
|
||||||
|
// skip unhandled providers in migration00
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
OCO_AI_PROVIDER_ENUM.DEEPSEEK,
|
||||||
|
OCO_AI_PROVIDER_ENUM.GROQ,
|
||||||
|
OCO_AI_PROVIDER_ENUM.MISTRAL,
|
||||||
|
OCO_AI_PROVIDER_ENUM.MLX,
|
||||||
|
OCO_AI_PROVIDER_ENUM.OPENROUTER
|
||||||
|
].includes(config.OCO_AI_PROVIDER)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const completedMigrations = getCompletedMigrations();
|
const completedMigrations = getCompletedMigrations();
|
||||||
|
|
||||||
let isMigrated = false;
|
let isMigrated = false;
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ const llmReadableRules: {
|
|||||||
blankline: (key, applicable) =>
|
blankline: (key, applicable) =>
|
||||||
`There should ${applicable} be a blank line at the beginning of the ${key}.`,
|
`There should ${applicable} be a blank line at the beginning of the ${key}.`,
|
||||||
caseRule: (key, applicable, value: string | Array<string>) =>
|
caseRule: (key, applicable, value: string | Array<string>) =>
|
||||||
`The ${key} should ${applicable} be in ${Array.isArray(value)
|
`The ${key} should ${applicable} be in ${
|
||||||
|
Array.isArray(value)
|
||||||
? `one of the following case:
|
? `one of the following case:
|
||||||
- ${value.join('\n - ')}.`
|
- ${value.join('\n - ')}.`
|
||||||
: `${value} case.`
|
: `${value} case.`
|
||||||
@@ -67,7 +68,8 @@ const llmReadableRules: {
|
|||||||
- ${Array.isArray(value) ? value.join('\n - ') : value}.`,
|
- ${Array.isArray(value) ? value.join('\n - ') : value}.`,
|
||||||
enumTypeRule: (key, applicable, value: string | Array<string>, prompt) =>
|
enumTypeRule: (key, applicable, value: string | Array<string>, prompt) =>
|
||||||
`The ${key} should ${applicable} be one of the following values:
|
`The ${key} should ${applicable} be one of the following values:
|
||||||
- ${Array.isArray(value)
|
- ${
|
||||||
|
Array.isArray(value)
|
||||||
? value
|
? value
|
||||||
.map((v) => {
|
.map((v) => {
|
||||||
const description = getTypeRuleExtraDescription(v, prompt);
|
const description = getTypeRuleExtraDescription(v, prompt);
|
||||||
@@ -223,7 +225,11 @@ Here are the specific requirements and conventions that should be strictly follo
|
|||||||
Commit Message Conventions:
|
Commit Message Conventions:
|
||||||
- The commit message consists of three parts: Header, Body, and Footer.
|
- The commit message consists of three parts: Header, Body, and Footer.
|
||||||
- Header:
|
- Header:
|
||||||
- Format: ${config.OCO_OMIT_SCOPE ? '`<type>: <subject>`' : '`<type>(<scope>): <subject>`'}
|
- Format: ${
|
||||||
|
config.OCO_OMIT_SCOPE
|
||||||
|
? '`<type>: <subject>`'
|
||||||
|
: '`<type>(<scope>): <subject>`'
|
||||||
|
}
|
||||||
- ${prompts.join('\n- ')}
|
- ${prompts.join('\n- ')}
|
||||||
|
|
||||||
JSON Output Format:
|
JSON Output Format:
|
||||||
@@ -262,22 +268,27 @@ const INIT_MAIN_PROMPT = (
|
|||||||
prompts: string[]
|
prompts: string[]
|
||||||
): OpenAI.Chat.Completions.ChatCompletionMessageParam => ({
|
): OpenAI.Chat.Completions.ChatCompletionMessageParam => ({
|
||||||
role: 'system',
|
role: 'system',
|
||||||
content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages in the given @commitlint convention and explain WHAT were the changes ${config.OCO_WHY ? 'and WHY the changes were done' : ''
|
content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages in the given @commitlint convention and explain WHAT were the changes ${
|
||||||
|
config.OCO_WHY ? 'and WHY the changes were done' : ''
|
||||||
}. I'll send you an output of 'git diff --staged' command, and you convert it into a commit message.
|
}. I'll send you an output of 'git diff --staged' command, and you convert it into a commit message.
|
||||||
${config.OCO_EMOJI
|
${
|
||||||
|
config.OCO_EMOJI
|
||||||
? 'Use GitMoji convention to preface the commit.'
|
? 'Use GitMoji convention to preface the commit.'
|
||||||
: 'Do not preface the commit with anything.'
|
: 'Do not preface the commit with anything.'
|
||||||
}
|
}
|
||||||
${config.OCO_DESCRIPTION
|
${
|
||||||
|
config.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.'
|
? '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."
|
: "Don't add any descriptions to the commit, only commit message."
|
||||||
}
|
}
|
||||||
Use the present tense. Use ${language} to answer.
|
Use the present tense. Use ${language} to answer.
|
||||||
${config.OCO_ONE_LINE_COMMIT
|
${
|
||||||
|
config.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.'
|
? '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.'
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
${config.OCO_OMIT_SCOPE
|
${
|
||||||
|
config.OCO_OMIT_SCOPE
|
||||||
? 'Do not include a scope in the commit message format. Use the format: <type>: <subject>'
|
? 'Do not include a scope in the commit message format. Use the format: <type>: <subject>'
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,17 +193,17 @@ const generateCommitString = (
|
|||||||
message: string
|
message: string
|
||||||
): string => {
|
): string => {
|
||||||
const cleanMessage = removeConventionalCommitWord(message);
|
const cleanMessage = removeConventionalCommitWord(message);
|
||||||
return config.OCO_EMOJI
|
return config.OCO_EMOJI ? `${COMMIT_TYPES[type]} ${cleanMessage}` : message;
|
||||||
? `${COMMIT_TYPES[type]} ${cleanMessage}`
|
|
||||||
: message;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getConsistencyContent = (translation: ConsistencyPrompt) => {
|
const getConsistencyContent = (translation: ConsistencyPrompt) => {
|
||||||
const fixMessage = config.OCO_OMIT_SCOPE && translation.commitFixOmitScope
|
const fixMessage =
|
||||||
|
config.OCO_OMIT_SCOPE && translation.commitFixOmitScope
|
||||||
? translation.commitFixOmitScope
|
? translation.commitFixOmitScope
|
||||||
: translation.commitFix;
|
: translation.commitFix;
|
||||||
|
|
||||||
const featMessage = config.OCO_OMIT_SCOPE && translation.commitFeatOmitScope
|
const featMessage =
|
||||||
|
config.OCO_OMIT_SCOPE && translation.commitFeatOmitScope
|
||||||
? translation.commitFeatOmitScope
|
? translation.commitFeatOmitScope
|
||||||
: translation.commitFeat;
|
: translation.commitFeat;
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { TestAi, TestMockType } from '../engine/testAi';
|
|||||||
import { GroqEngine } from '../engine/groq';
|
import { GroqEngine } from '../engine/groq';
|
||||||
import { MLXEngine } from '../engine/mlx';
|
import { MLXEngine } from '../engine/mlx';
|
||||||
import { DeepseekEngine } from '../engine/deepseek';
|
import { DeepseekEngine } from '../engine/deepseek';
|
||||||
|
import { AimlApiEngine } from '../engine/aimlapi';
|
||||||
import { OpenRouterEngine } from '../engine/openrouter';
|
import { OpenRouterEngine } from '../engine/openrouter';
|
||||||
|
|
||||||
export function parseCustomHeaders(headers: any): Record<string, string> {
|
export function parseCustomHeaders(headers: any): Record<string, string> {
|
||||||
@@ -81,6 +82,9 @@ export function getEngine(): AiEngine {
|
|||||||
case OCO_AI_PROVIDER_ENUM.DEEPSEEK:
|
case OCO_AI_PROVIDER_ENUM.DEEPSEEK:
|
||||||
return new DeepseekEngine(DEFAULT_CONFIG);
|
return new DeepseekEngine(DEFAULT_CONFIG);
|
||||||
|
|
||||||
|
case OCO_AI_PROVIDER_ENUM.AIMLAPI:
|
||||||
|
return new AimlApiEngine(DEFAULT_CONFIG);
|
||||||
|
|
||||||
case OCO_AI_PROVIDER_ENUM.OPENROUTER:
|
case OCO_AI_PROVIDER_ENUM.OPENROUTER:
|
||||||
return new OpenRouterEngine(DEFAULT_CONFIG);
|
return new OpenRouterEngine(DEFAULT_CONFIG);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { execa } from 'execa';
|
import { execa } from 'execa';
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import ignore, { Ignore } from 'ignore';
|
import ignore, { Ignore } from 'ignore';
|
||||||
|
import { join } from 'path';
|
||||||
import { outro, spinner } from '@clack/prompts';
|
import { outro, spinner } from '@clack/prompts';
|
||||||
|
|
||||||
export const assertGitRepo = async () => {
|
export const assertGitRepo = async () => {
|
||||||
@@ -16,41 +16,44 @@ export const assertGitRepo = async () => {
|
|||||||
// (file) => `:(exclude)${file}`
|
// (file) => `:(exclude)${file}`
|
||||||
// );
|
// );
|
||||||
|
|
||||||
export const getOpenCommitIgnore = (): Ignore => {
|
export const getOpenCommitIgnore = async (): Promise<Ignore> => {
|
||||||
|
const gitDir = await getGitDir();
|
||||||
|
|
||||||
const ig = ignore();
|
const ig = ignore();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ig.add(readFileSync('.opencommitignore').toString().split('\n'));
|
ig.add(
|
||||||
|
readFileSync(join(gitDir, '.opencommitignore')).toString().split('\n')
|
||||||
|
);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
return ig;
|
return ig;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getCoreHooksPath = async (): Promise<string> => {
|
export const getCoreHooksPath = async (): Promise<string> => {
|
||||||
const { stdout } = await execa('git', ['config', 'core.hooksPath']);
|
const gitDir = await getGitDir();
|
||||||
|
|
||||||
|
const { stdout } = await execa('git', ['config', 'core.hooksPath'], {
|
||||||
|
cwd: gitDir
|
||||||
|
});
|
||||||
|
|
||||||
return stdout;
|
return stdout;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getStagedFiles = async (): Promise<string[]> => {
|
export const getStagedFiles = async (): Promise<string[]> => {
|
||||||
const { stdout: gitDir } = await execa('git', [
|
const gitDir = await getGitDir();
|
||||||
'rev-parse',
|
|
||||||
'--show-toplevel'
|
|
||||||
]);
|
|
||||||
|
|
||||||
const { stdout: files } = await execa('git', [
|
const { stdout: files } = await execa(
|
||||||
'diff',
|
'git',
|
||||||
'--name-only',
|
['diff', '--name-only', '--cached', '--relative'],
|
||||||
'--cached',
|
{ cwd: gitDir }
|
||||||
'--relative',
|
);
|
||||||
gitDir
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!files) return [];
|
if (!files) return [];
|
||||||
|
|
||||||
const filesList = files.split('\n');
|
const filesList = files.split('\n');
|
||||||
|
|
||||||
const ig = getOpenCommitIgnore();
|
const ig = await getOpenCommitIgnore();
|
||||||
const allowedFiles = filesList.filter((file) => !ig.ignores(file));
|
const allowedFiles = filesList.filter((file) => !ig.ignores(file));
|
||||||
|
|
||||||
if (!allowedFiles) return [];
|
if (!allowedFiles) return [];
|
||||||
@@ -59,12 +62,17 @@ export const getStagedFiles = async (): Promise<string[]> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getChangedFiles = async (): Promise<string[]> => {
|
export const getChangedFiles = async (): Promise<string[]> => {
|
||||||
const { stdout: modified } = await execa('git', ['ls-files', '--modified']);
|
const gitDir = await getGitDir();
|
||||||
const { stdout: others } = await execa('git', [
|
|
||||||
'ls-files',
|
const { stdout: modified } = await execa('git', ['ls-files', '--modified'], {
|
||||||
'--others',
|
cwd: gitDir
|
||||||
'--exclude-standard'
|
});
|
||||||
]);
|
|
||||||
|
const { stdout: others } = await execa(
|
||||||
|
'git',
|
||||||
|
['ls-files', '--others', '--exclude-standard'],
|
||||||
|
{ cwd: gitDir }
|
||||||
|
);
|
||||||
|
|
||||||
const files = [...modified.split('\n'), ...others.split('\n')].filter(
|
const files = [...modified.split('\n'), ...others.split('\n')].filter(
|
||||||
(file) => !!file
|
(file) => !!file
|
||||||
@@ -74,16 +82,20 @@ export const getChangedFiles = async (): Promise<string[]> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const gitAdd = async ({ files }: { files: string[] }) => {
|
export const gitAdd = async ({ files }: { files: string[] }) => {
|
||||||
|
const gitDir = await getGitDir();
|
||||||
|
|
||||||
const gitAddSpinner = spinner();
|
const gitAddSpinner = spinner();
|
||||||
|
|
||||||
gitAddSpinner.start('Adding files to commit');
|
gitAddSpinner.start('Adding files to commit');
|
||||||
|
|
||||||
await execa('git', ['add', ...files]);
|
await execa('git', ['add', ...files], { cwd: gitDir });
|
||||||
|
|
||||||
gitAddSpinner.stop(`Staged ${files.length} files`);
|
gitAddSpinner.stop(`Staged ${files.length} files`);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDiff = async ({ files }: { files: string[] }) => {
|
export const getDiff = async ({ files }: { files: string[] }) => {
|
||||||
|
const gitDir = await getGitDir();
|
||||||
|
|
||||||
const lockFiles = files.filter(
|
const lockFiles = files.filter(
|
||||||
(file) =>
|
(file) =>
|
||||||
file.includes('.lock') ||
|
file.includes('.lock') ||
|
||||||
@@ -108,12 +120,20 @@ export const getDiff = async ({ files }: { files: string[] }) => {
|
|||||||
(file) => !file.includes('.lock') && !file.includes('-lock.')
|
(file) => !file.includes('.lock') && !file.includes('-lock.')
|
||||||
);
|
);
|
||||||
|
|
||||||
const { stdout: diff } = await execa('git', [
|
const { stdout: diff } = await execa(
|
||||||
'diff',
|
'git',
|
||||||
'--staged',
|
['diff', '--staged', '--', ...filesWithoutLocks],
|
||||||
'--',
|
{ cwd: gitDir }
|
||||||
...filesWithoutLocks
|
);
|
||||||
]);
|
|
||||||
|
|
||||||
return diff;
|
return diff;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getGitDir = async (): Promise<string> => {
|
||||||
|
const { stdout: gitDir } = await execa('git', [
|
||||||
|
'rev-parse',
|
||||||
|
'--show-toplevel'
|
||||||
|
]);
|
||||||
|
|
||||||
|
return gitDir;
|
||||||
|
};
|
||||||
|
|||||||
@@ -4,7 +4,10 @@
|
|||||||
* @param tag The tag name without angle brackets (e.g., 'think' for '<think></think>')
|
* @param tag The tag name without angle brackets (e.g., 'think' for '<think></think>')
|
||||||
* @returns The content with the specified tags and their contents removed, and trimmed
|
* @returns The content with the specified tags and their contents removed, and trimmed
|
||||||
*/
|
*/
|
||||||
export function removeContentTags<T extends string | null | undefined>(content: T, tag: string): T {
|
export function removeContentTags<T extends string | null | undefined>(
|
||||||
|
content: T,
|
||||||
|
tag: string
|
||||||
|
): T {
|
||||||
if (!content || typeof content !== 'string') {
|
if (!content || typeof content !== 'string') {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
@@ -29,7 +32,10 @@ export function removeContentTags<T extends string | null | undefined>(content:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check for closing tag
|
// Check for closing tag
|
||||||
else if (content.substring(i, i + closeTag.length) === closeTag && depth > 0) {
|
else if (
|
||||||
|
content.substring(i, i + closeTag.length) === closeTag &&
|
||||||
|
depth > 0
|
||||||
|
) {
|
||||||
depth--;
|
depth--;
|
||||||
if (depth === 0) {
|
if (depth === 0) {
|
||||||
i = i + closeTag.length - 1; // Skip the closing tag
|
i = i + closeTag.length - 1; // Skip the closing tag
|
||||||
|
|||||||
Reference in New Issue
Block a user