Files
pbakaus_impeccable/scripts/lib/transformers/providers.js
T
83c37e453a feat: add Mistral Vibe harness support (#373)
* feat: add Mistral Vibe harness support

Mistral Vibe is Mistral AI's open-source CLI coding assistant that ships an
Agent Skills system at .vibe/skills/{name}/SKILL.md with slash-command
invocation, mapping cleanly onto the existing transformer pipeline. Adds
Vibe as a 14th first-class harness:

- PROVIDER_PLACEHOLDERS entry in scripts/lib/utils.js (model, config_file
  = AGENTS.md, ask_instruction, command_prefix) mirroring the Qoder shape.
- PROVIDERS entry in scripts/lib/transformers/providers.js with configDir
  .vibe and frontmatterFields user-invocable, license, compatibility,
  metadata, allowed-tools (Vibe docs do not document argument-hint).
- transformVibe named export in scripts/lib/transformers/index.js for
  test-spy parity.
- vibe added to FILE_DOWNLOAD_PROVIDER_CONFIG_DIRS so the download
  endpoint accepts /api/download/skill/vibe/* and resolves to
  dist/vibe/.vibe/.
- .vibe added to PROVIDER_DIRS, PROVIDER_ALIASES, PROVIDER_DISPLAY,
  PROVIDER_INPUT_ORDER, GLOBAL_HARNESS_HINTS, and the normalizeForHash
  provider regex in cli/bin/commands/skills.mjs so the CLI detects
  existing Vibe installs.
- docs/HARNESSES.md updated: official docs row, frontmatter support
  column, directory structure row, and Last verified date bumped.
- docs/DEVELOP.md, README.md (install instructions, providers list,
  Supported Tools), .github issue/PR templates, sync-generated-output
  workflow, and AGENTS.md extended with Vibe.

The dynamic providers.test.js loop picks up Vibe automatically; all 160
provider tests pass including the 14 new Mistral Vibe cases. The build
regenerates dist/vibe/.vibe/skills/impeccable/ with correct frontmatter
and .vibe-substituted script paths. Generated harness output is left
unstaged per the source-first policy; the sync-generated-output workflow
(now listing .vibe) will commit it back to main after merge.

Co-Authored-By: Mistral Vibe <noreply@mistral.ai>

* Address review on Vibe harness support

Verified the Vibe claims against the docs and the mistralai/mistral-vibe
source, then tightened what the tables say.

- model placeholder: 'Mistral', not 'the model'. Vibe is Mistral's own
  first-party CLI, so it belongs with gemini -> Gemini and codex -> GPT
  rather than with the provider-agnostic harnesses. SKILL.src.md's one
  use of {{model}} now renders 'Mistral is capable of extraordinary
  work.' instead of a lowercase 'the model'.
- Docs links point at the skills page, not the product overview, matching
  every other row in both tables.
- disable-model-invocation is No, not TBD. The field appears nowhere in
  Vibe's source; unknown frontmatter keys are silently ignored.
- Split the directory row into project and global scopes the way the Pi
  row already does. Vibe reads .vibe/skills/ and .agents/skills/ at the
  project level and ~/.vibe/skills/ and ~/.agents/skills/ globally; the
  global .agents dir was missing, and project .agents/skills/ was sitting
  in the global column. Sources: vibe/core/paths/_local_config_files.py
  and vibe/core/config/harness_files/_paths.py.
- Restored 'Last verified' to 2026-04-28 and dated the Vibe row on its
  own. Only that row was checked, and this file warns against trusting
  stale claims, so a blanket re-date made ten other rows look fresher
  than they are.

AI assistance: written with Claude Code.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Mistral Vibe <noreply@mistral.ai>
Co-authored-by: Paul Bakaus <paul.bakaus@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-20 14:50:32 -07:00

133 lines
4.4 KiB
JavaScript

/**
* Provider configurations for the transformer factory.
*
* Each config specifies:
* - provider: key into PROVIDER_PLACEHOLDERS (e.g. 'claude-code')
* - configDir: dot-directory name (e.g. '.claude')
* - displayName: human-readable name for log output (e.g. 'Claude Code')
* - providerTags: markdown block tags kept for this target (e.g. <codex>...</codex>)
* - frontmatterFields: which optional fields to emit beyond name + description
* - bodyTransform: optional function (body, skill) => transformed body
*/
export const PROVIDERS = {
cursor: {
provider: 'cursor',
providerTags: ['cursor'],
configDir: '.cursor',
displayName: 'Cursor',
frontmatterFields: ['license', 'compatibility', 'metadata'],
emitHooks: 'cursor',
// Cursor reads `.cursor/hooks.json`, not `.cursor/hooks/hooks.json`.
hooksManifestRel: 'hooks.json',
},
'claude-code': {
provider: 'claude-code',
providerTags: ['claude-code', 'claude'],
configDir: '.claude',
displayName: 'Claude Code',
frontmatterFields: ['user-invocable', 'argument-hint', 'license', 'compatibility', 'metadata', 'allowed-tools'],
agentFormat: 'claude-md',
emitHooks: 'claude',
// Project-local Claude Code hooks live in `.claude/settings.json`.
hooksManifestRel: 'settings.json',
},
gemini: {
provider: 'gemini',
providerTags: ['gemini'],
configDir: '.gemini',
displayName: 'Gemini',
frontmatterFields: [],
},
codex: {
provider: 'codex',
providerTags: ['codex'],
configDir: '.codex',
displayName: 'Codex',
frontmatterFields: [],
writeOpenAIMetadata: true,
// No agentFormat: the Codex subagent ships nested inside the skill's own
// agents/ folder (see CODEX_SKILL_PROVIDERS in factory.js), which Codex
// auto-discovers on install. No top-level .codex/agents/ sidecar is emitted.
emitHooks: 'codex',
// Codex discovers project-local hooks at `.codex/hooks.json`.
hooksManifestRel: 'hooks.json',
},
agents: {
provider: 'agents',
providerTags: ['agents', 'codex'],
configDir: '.agents',
displayName: 'Codex Repo Skills',
placeholderProvider: 'codex',
frontmatterFields: [],
writeOpenAIMetadata: true,
},
github: {
provider: 'github',
providerTags: ['github'],
configDir: '.github',
displayName: 'GitHub Copilot',
placeholderProvider: 'agents',
frontmatterFields: ['user-invocable', 'argument-hint', 'license', 'compatibility', 'metadata'],
emitHooks: 'github',
// GitHub Copilot discovers repo-level hooks under `.github/hooks/*.json`.
hooksManifestRel: 'hooks/impeccable.json',
},
kiro: {
provider: 'kiro',
providerTags: ['kiro'],
configDir: '.kiro',
displayName: 'Kiro',
frontmatterFields: ['license', 'compatibility', 'metadata'],
},
opencode: {
provider: 'opencode',
providerTags: ['opencode'],
configDir: '.opencode',
displayName: 'OpenCode',
frontmatterFields: ['user-invocable', 'argument-hint', 'license', 'compatibility', 'metadata', 'allowed-tools'],
},
pi: {
provider: 'pi',
providerTags: ['pi'],
configDir: '.pi',
displayName: 'Pi',
frontmatterFields: ['license', 'compatibility', 'metadata', 'allowed-tools'],
},
qoder: {
provider: 'qoder',
providerTags: ['qoder'],
configDir: '.qoder',
displayName: 'Qoder',
frontmatterFields: ['user-invocable', 'argument-hint', 'license', 'compatibility', 'metadata', 'allowed-tools'],
},
'trae-cn': {
provider: 'trae-cn',
providerTags: ['trae-cn', 'trae'],
configDir: '.trae-cn',
displayName: 'Trae China',
placeholderProvider: 'trae',
frontmatterFields: ['user-invocable', 'argument-hint', 'license', 'compatibility', 'metadata'],
},
trae: {
provider: 'trae',
providerTags: ['trae'],
configDir: '.trae',
displayName: 'Trae',
frontmatterFields: ['user-invocable', 'argument-hint', 'license', 'compatibility', 'metadata'],
},
'rovo-dev': {
provider: 'rovo-dev',
providerTags: ['rovo-dev'],
configDir: '.rovodev',
displayName: 'Rovo Dev',
frontmatterFields: ['user-invocable', 'argument-hint', 'license', 'compatibility', 'metadata', 'allowed-tools'],
},
vibe: {
provider: 'vibe',
providerTags: ['vibe'],
configDir: '.vibe',
displayName: 'Mistral Vibe',
frontmatterFields: ['user-invocable', 'license', 'compatibility', 'metadata', 'allowed-tools'],
},
};