☰
VSuite

@vsuite/core

The generation pipeline: loads and migrates vsuite.json, loads packs, resolves the selection, renders agents, skills, instructions, the vsuite MCP server, job-metrics tooling, and native/MCP configs for each target, and writes them atomically. Non-goals: interactive prompts and argument parsing (@krizic/vsuite), catalog contents, and target formats.

This is a private, source-only workspace package (exports → ./src/index.ts). It is bundled into the @krizic/vsuite CLI and is not published to npm. Workspace consumers depend on it with "@vsuite/core": "workspace:*".

Public API

Export Kind Signature Description
loadConfig function (root: string, options: LoadConfigOptions) => Promise<LoadedConfig> Reads <root>/vsuite.json, runs migrateConfig to cliVersion, validates with parseConfig, and, only when the migration changed the config and write is true, writes it atomically. Missing file: Cannot find <path>. Run "vsuite init" to create vsuite.json, then run "vsuite generate" again.; invalid JSON: Cannot read <path>: <reason>; non-object: <path> must contain a JSON object.
LoadConfigOptions type { cliVersion: string; write?: boolean } Target vsuite version; write defaults to true (false for dry runs).
LoadedConfig type { config: VsuiteConfig; migration: MigrationResult; path: string; before: string; after: string } Validated config, migration result, file path, and original/migrated text (after === before when unchanged).
Migration, MigrationResult type re-export from @vsuite/migrations See @vsuite/migrations.
readGenerationConfig function (root: string) => Promise<VsuiteConfig> Reads vsuite.json for generation, migrating legacy files in memory without writing them.
planGeneration function (root, options) => Promise<GenerationPlan> Renders every output without writing (used by preview and generate).
generate function (root: string, options: GenerateOptions) => Promise<RenderedOutput[]> Plans, merges legacy .agent-metrics/ records into .vsuite/agent-metrics/, writes all outputs, git-ignores .vsuite/, removes stale skills and pack outputs, and updates vsuite.lock.json. GenerateOptions: cliVersion (required), updatePacks, onWarning, packSources.
parseEnvFile, readProjectEnvFile, updateProjectEnvFile, ensureVsuiteGitignored, and related functions Read and update the git-ignored .vsuite/.env that holds MCP secrets.
migrateLegacyMetrics, mergeJobLogs functions Move pre-0.7 .agent-metrics/ content into .vsuite/agent-metrics/.
loadProjectSkills function (root: string, directory: string, ids: readonly string[]) => Promise<RenderableSkill[]> Loads <directory>/<id>/SKILL.md; rejects paths escaping the root (including via symlinks), and requires YAML frontmatter with name equal to the id and a description containing “use when” or “use for”.
writePlan function (root: string, outputs: readonly RenderedOutput[]) => Promise<void> Validates and writes all outputs via temp files and renames.
RenderedOutput type re-export from @vsuite/targets A file to write.

Dependencies

  • Workspace: @vsuite/catalog, @vsuite/config, @vsuite/json, @vsuite/migrations, @vsuite/packs, @vsuite/targets, @vsuite/templates.
  • Third-party: yaml (frontmatter), jsonc-parser (existing JSONC configs). Dev: @vsuite/test-utils.
  • Used by: @vsuite/workflows, @krizic/vsuite.

Diagrams

sequenceDiagram
  participant CLI as "vsuite generate / migrate"
  participant L as loadConfig
  participant M as "@vsuite/migrations"
  participant C as "@vsuite/config"
  participant G as generate
  CLI->>L: loadConfig(root, { cliVersion, write })
  L->>L: read and JSON.parse vsuite.json
  L->>M: migrateConfig(raw, cliVersion)
  M-->>L: { config, from, to, applied, changed }
  L->>C: parseConfig(migration.config)
  opt changed and write
    L->>C: writeJsonAtomically(vsuite.json, migration.config)
  end
  L-->>CLI: LoadedConfig
  opt not a dry run
    CLI->>G: generate(root)
  end
flowchart TD
  A["writePlan(root, outputs)"] --> B["resolve each output path under root"]
  B --> C{"absolute, root itself, or escapes root?"}
  C -- yes --> X1["throw: unsafe path"]
  C -- no --> D{"duplicate path?"}
  D -- yes --> X2["throw: Multiple renderers produced path"]
  D -- no --> E{"existing ancestor is a symlink?"}
  E -- yes --> X3["throw: path beneath symbolic link"]
  E -- no --> F["mkdir parent, write each to path.pid.uuid.tmp"]
  F --> G["rename every temp file onto its target"]
  G --> H["finally: remove leftover temp files"]

Existing native configs are only extended: MCP servers already present in .opencode/opencode.json, .mcp.json, or .vscode/mcp.json are not overwritten. Existing Copilot agent frontmatter tools/agents are read so the adapter can preserve them.

Usage

import { generate } from "@vsuite/core";
 
const outputs = await generate(process.cwd(), { cliVersion: "0.7.1" });
for (const output of outputs) console.log(output.path);

Testing

pnpm vitest run --project @vsuite/core