@samveys/console

Version
1.0.2Nov 5, 2026
Install
pnpm add @samveys/console

From packages/console/README.md in the framework repository.

@samveys/console provides the svs command kernel, command definition helpers, argument parsing, project loading, and agent-aware output. The repository CLI entrypoint is node packages/console/src/bin/svs.ts; after installation in a project environment, the command is svs. The examples below are checked against the public exports and types (tested).

1. Install

Samveys packages are internal-only. Use the organization’s restricted registry and workspace tooling; never publish or install packages through the public npm registry. In this monorepo, run CLI commands from the repository with node packages/console/src/bin/svs.ts.

2. Built-in commands

The following twenty-one commands are registered by createKernel(). Plugins add more once they are registered (for example migrate from @samveys/database, make:model from @samveys/orm, queue:work from @samveys/queue, mcp from @samveys/mcp). Run svs <command> --help for the command’s full usage.

CommandArguments and command flagsExample
aboutNonenode packages/console/src/bin/svs.ts about
addRequired <name>; --yes/-y, --dry-run, --skip-installnode packages/console/src/bin/svs.ts add http
build--out <dir> (default dist), --docker, --sea (with optional --entry)node packages/console/src/bin/svs.ts build --docker
check--deploy; repeatable --skip <check-id>node packages/console/src/bin/svs.ts check --deploy --skip core.app_key
config:showOptional [path]node packages/console/src/bin/svs.ts config:show app.name
env:checkNonenode packages/console/src/bin/svs.ts env:check
explainRequired <code>node packages/console/src/bin/svs.ts explain SVS_E040
make:commandRequired <name:part>node packages/console/src/bin/svs.ts make:command report:daily
make:controllerRequired <Name>node packages/console/src/bin/svs.ts make:controller BlogPost
make:middlewareRequired <name> (kebab-case)node packages/console/src/bin/svs.ts make:middleware request-id
make:pluginRequired <name>; optional --dir <directory>node packages/console/src/bin/svs.ts make:plugin @acme/audit
make:providerRequired <Name>node packages/console/src/bin/svs.ts make:provider Mail
make:testRequired <name> (kebab-case)node packages/console/src/bin/svs.ts make:test checkout
newRequired <name>; --kit=api (default), --dir <directory>node packages/console/src/bin/svs.ts new blog --kit=api
plugin:listNonenode packages/console/src/bin/svs.ts plugin:list
replNone; boots the appnode packages/console/src/bin/svs.ts repl
route:listNonenode packages/console/src/bin/svs.ts route:list
route:typesNone; needs the http() plugin and @samveys/http installed in the projectnode packages/console/src/bin/svs.ts route:types
serve--watch; optional --entry <file>node packages/console/src/bin/svs.ts serve --watch
start--out <dir>, optional --entry <file>, --permission with --allow-write <dirs>node packages/console/src/bin/svs.ts start --permission --allow-write storage
upgrade--to <version>, --dry-runnode packages/console/src/bin/svs.ts upgrade --to 2.0.0 --dry-run

svs serve runs the server entry (entry in samveys.config.ts, default bin/server.ts) directly from .ts with Node, and sets APP_ENV=local unless it is already set, so the development error page is on. It loads .env and then .env.<APP_ENV> when they exist, with Node's --env-file; variables already set in the shell win (tested). --watch adds node --watch plus watch paths for samveys.config.ts, app/, config/, routes/ and start/ when they exist; an edit restarts the server in about 0.3 s (tested). Ctrl+C and SIGTERM are forwarded so the app shuts down gracefully.

svs build compiles every .ts file of the app (not node_modules, tests/, storage/ or dot-folders) into dist/ with module.stripTypeScriptTypes, rewrites relative .ts import specifiers to .js, and copies package.json so type: module applies. The app must use erasable TypeScript only (no enum, no parameter properties); a file that cannot be compiled stops the build with SVS_E098 and the previous dist/ stays. Nothing from .env* or samveys.config.ts values is baked in: configuration is read from the environment when the server starts (tested). --docker also writes a multi-stage Dockerfile (node:26-alpine, USER node, ENV NODE_ENV=production, CMD ["node", "dist/bin/server.js"]) and a .dockerignore (.env*, node_modules, .git); existing files are never overwritten. The image test builds the generated Dockerfile and asserts the container user is not root; it is skipped with the reason when docker or the base image is unavailable, or when SVS_DOCKER=0.

svs build --sea also builds one executable from dist/ and the production node_modules with Node's --build-sea and its virtual file system (Node ≥ 26.9). The binary runs without Node installed, refuses NODE_OPTIONS, cannot load native addons, and is ad-hoc signed on macOS; it targets the platform it was built on (tested: it serves the app with no node on PATH).

svs start runs node dist/bin/server.js (an argv array, no shell) with NODE_ENV=production unless set, and forwards SIGTERM and SIGINT so graceful shutdown runs. --permission runs it under Node's permission model: read the app directory, use the network, write only to --allow-write directories; child processes, workers, addons and WASI stay denied (tested).

svs upgrade --to <version> moves every @samveys/* dependency to a new major and runs the codemods those packages ship ("samveys": { "codemods": "./codemods/index.js" } in their package.json): only codemods for the majors being crossed run, in order, and a second run is a no-op (tested on a fixture app).

svs new <name> --kit=api creates <name>/ (or --dir) with package.json, .npmrc (@samveys:registry=https://registry.sadata.dev/api/packages/sadata/npm/; the registry is public, so no token is needed; for a private registry the token goes in ~/.npmrc or the SAMVEYS_NPM_TOKEN CI secret, never in the project .npmrc), samveys.config.ts (http(), database() on SQLite file storage/app.db, orm(), health(), and a commented @samveys/auth OIDC section), bin/server.ts, app/routes.ts with GET /ping, tests/ping.test.ts, a CI workflow, Dockerfile, .gitignore, and an .env.example with every variable the framework reads (placeholders only). It also creates the standard folders, each with a .gitkeep note: app/{controllers,middleware,models,policies,jobs,commands,providers}, config, database/{migrations,seeders}, resources/views, lang, public and storage. examples/api in this repository is that output. An existing directory stops with SVS_E099. The generated test passes, the project type-checks and its server answers /ping and /health/ready without manual edits (tested).

svs repl boots the app and opens a REPL with app, container and db (when @samveys/database is installed); top-level await works, and .exit shuts the app down (tested with a model query on SQLite).

The generators make:controller <Name>, make:middleware <name>, make:command <name:part> and make:provider <Name> write app/controllers|middleware|commands|providers/<slug>.ts and a matching test in tests/; make:test <name> writes tests/<name>.test.ts. They write relative to the project root (the folder of samveys.config.ts), refuse names that are not safe identifiers (SVS_E061), and never overwrite: if any target exists nothing is written and the command stops with SVS_E099. The generated files type-check with the repo tsc and their tests pass (tested).

Global flags include --help, --no-color, and --json. --json writes a single JSON document to stdout; for commands that return result data, it uses the command’s result object or array.

sh
node packages/console/src/bin/svs.ts route:list --json
node packages/console/src/bin/svs.ts config:show app.name --json

3. Agent-condensed output

The output helper detects common agent environments and removes color, spinners, and table formatting. Agent detection checks these environment variables for a non-empty value:

Environment variable
CLAUDECODE
CLAUDE_CODE
CURSOR_AGENT
CODEX_SANDBOX
GEMINI_CLI
AIDER
NEURON_AGENT
AI_AGENT

In agent mode Output.table() writes compact key=value lines. TERM=dumb also triggers agent mode when not in CI and stdout is not a TTY. NO_COLOR disables color independently.

4. Define and extend commands

defineCommand(name, definition) creates a command with typed positional arguments and flags. Names use lowercase letters, digits and hyphens, with : separators. Register command factories with createKernel().register() or expose a plugin command through extend.command().

ts
import { defineCommand } from '@samveys/console'

export const reportCommand = defineCommand('report:daily', {
  description: 'Show the daily report',
  flags: {
    format: { type: 'string', description: 'Output format', default: 'text' },
  },
  run({ flags, output }) {
    output.result({ format: flags.format })
    return 0
  },
})
ts
import { definePlugin } from '@samveys/core'
import { defineCommand } from '@samveys/console'

const auditPrune = defineCommand('audit:prune', {
  description: 'Prune audit records',
  run({ output }) {
    output.success('Audit records pruned')
    return 0
  },
})

export const auditPlugin = definePlugin({
  name: '@acme/audit',
  boot({ extend }) {
    extend.command(auditPrune)
  },
})

5. svs check and silencing

svs check runs registered system checks. Add --deploy to include deployment-only checks. Exclude one or more checks with --skip <id>; SVS_SILENCED_CHECKS accepts comma-separated IDs and combines with --skip.

sh
node packages/console/src/bin/svs.ts check --skip core.app_key --skip console.internal_imports
SVS_SILENCED_CHECKS=core.app_key,console.internal_imports node packages/console/src/bin/svs.ts check

A silenced check is skipped, not marked as passed. The check currently includes plugin type-declaration and internal-import checks alongside checks registered by extensions.

6. make:plugin

svs make:plugin <name> creates a plugin skeleton under plugins/<slug> by default. --dir <directory> selects another target directory. The generator refuses to overwrite any files already present in the target, and <name> must be an npm package name (audit or @acme/audit). It creates a package manifest configured for restricted publishing, a definePlugin() entrypoint, a node:test test that installs the plugin with createTestApp() from @samveys/testing, and a README. The generated package’s registry and release setup remain the project owner’s responsibility.

sh
node packages/console/src/bin/svs.ts make:plugin @acme/audit --dir ./plugins/audit

7. svs add and recipes

svs add <name> installs and configures a package from its recipe. A recipe is data: imports and plugin entries to add to samveys.config.ts, files to create, .env.example keys, and next steps. It never runs code in your project.

  1. Plan. svs finds the recipe and computes every change without writing anything. Built-in recipes cover http (@samveys/http), validator, and testing. For any other package, svs loads the default export of its ./recipe subpath.
  2. Show. It prints the install command and a diff of every file it will change.
  3. Confirm. It asks Apply these changes?. Declining leaves every file unchanged and installs nothing. Without a TTY (CI, pipes, AI agents) the answer is no unless you pass --yes.
  4. Install. It runs the package manager it detected from packageManager in package.json, then lockfiles, then the user agent, and falls back to npm. Inside this monorepo it runs pnpm add --workspace, so internal packages are linked, not fetched. If the install fails (SVS_E065), no file has been changed yet.
  5. Write. Only after a successful install are the planned files written. svs then prints the next steps.
sh
node packages/console/src/bin/svs.ts add http --dry-run   # show the plan, change nothing
node packages/console/src/bin/svs.ts add http             # show, ask, then apply
node packages/console/src/bin/svs.ts add http --yes --json

svs edits only export default defineConfig({ … }) or export default { … } with a literal plugins: [ … ] array (or no plugins yet). It skips brackets inside strings and comments, and parses the result with Node's TypeScript stripper before accepting it. A config of any other shape, or a recipe file that already exists with different content, stops the command with SVS_E064 and the change to make by hand. Running svs add twice is safe: the second run reports that there is nothing to do.

Package authors ship a recipe with defineRecipe(), which validates it when it loads: relative paths inside the project, identifier import names, single-line values. Published packages must ship the recipe as .js, because Node does not run TypeScript under node_modules.

ts
// @acme/audit/src/recipe.ts → published as ./recipe (dist/recipe.js)
import { defineRecipe } from '@samveys/console'

export default defineRecipe({
  package: '@acme/audit',
  imports: [{ names: ['audit'], from: '@acme/audit' }],
  plugins: ['audit()'],
  files: [{ path: 'config/audit.ts', content: "export default { table: 'audit_logs' }\n" }],
  env: [{ key: 'AUDIT_RETENTION_DAYS', example: '90', comment: 'Days to keep audit entries.' }],
  nextSteps: ['Run `svs plugin:list` to see the audit hooks.'],
})

8. Programmatic kernel and output

createKernel({ cwd, env, stdout, stderr, confirm }) returns a Kernel; confirm replaces the yes/no prompt (tests, GUIs); register commands and call run(argv) with arguments excluding the node and script names. It returns an exit code and does not call process.exit(). parseArgv() parses an argument vector, while createOutput() and detectAgent() expose the output behavior for integrations.

9. Reference

Value exports from @samveys/console:

ExportPurpose
defineCommandDefine a command with typed args and flags.
createKernelCreate a command kernel.
createOutputCreate an output helper with JSON and agent modes.
detectAgentDetect agent or non-interactive output mode.
parseArgvParse positional args and flags.
findConfigFileFind samveys.config.ts from a working directory.
loadProjectLoad the project configuration and root directory.
defineRecipeDeclare and validate a package recipe for svs add.