npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@yinzer-tech/vini

v0.4.0

Published

Vini - AI CLI for Yinzer Tech

Readme

Vini

Vini is a terminal-based AI chat CLI for Yinzer Tech, built with React (Ink for the TUI), TypeScript, and Bun. It connects to a Yinzer backend (/api/chat) and gives the AI assistant hands-on access to your local environment — files, git, notebooks, web search, scheduling, and more — with a Claude Code–style permission system.

Features

  • Interactive chat REPL in your terminal, streaming responses via the Vercel AI SDK (useChat)
  • Local file tools — list, read, write, and edit files, with undo support (/undo)
  • Rich tool set — git operations, Jupyter notebook editing, web search/fetch, task tracking, sub-agents, and debug logging
  • Permission system modeled after Claude Code:
    • Reads inside the current working directory are auto-approved
    • Reads outside cwd and all writes/edits prompt for approval
    • Session-level "always allow" overrides, plus /auto-accept and read-only /plan mode
  • On-device models — download and run local GGUF models (e.g. Gemma) via node-llama-cpp, switchable with /model and managed with /models
  • Multi-agent sessions — run concurrent chat sessions and switch between them with /agents
  • Scheduled prompts — recurring intervals (/loop) and cron-style schedules (/schedule), run locally or in the cloud
  • Goal mode (/goal) — the model works autonomously until the task is verifiably complete
  • Voice — dictation (/dictate), read-aloud (/say), hands-free conversation (/voice) and live speech-to-speech (/live); plus conversation save/resume, history compression, and token usage tracking
  • Skills & workspace tools — custom prompts and tool definitions merged in from your Yinzer workspace
  • User-defined slash commands — drop Markdown files into ~/.vini/commands/ or ./.vini/commands/

Getting Started

Prerequisites

  • Bun ≥ 1.3
  • A Yinzer Tech account (login is via SMS one-time passcode)

Install & Run

npm install
npm run dev      # run in development mode (Bun, no build step)

Build a production binary

npm run build    # minified build to dist/
npm run start    # run the built binary

The package exposes a vini bin pointing at dist/index.js.

Usage

On first launch, Vini walks you through a three-stage startup:

  1. Login — OTP via SMS → JWT + session cookie stored in ~/.vini/credentials.json
  2. Workspace selection — choose a Team → Space (stored in ~/.vini/config.json)
  3. Chat — talk to the AI; it can call tools on your behalf, asking permission when needed

Slash Commands

| Command | Description | |---|---| | /help | Show available commands | | /clear | Clear conversation history | | /status | Current session state (auth, workspace, model, mode, tokens) | | /doctor | Health checks (config dir, credentials, JWT, host reachability, git/gh) | | /init [--force] | Generate a CLAUDE.md by analyzing the repository | | /team / /workspace | Switch team or workspace | | /model | Switch AI provider | | /reasoning | Switch reasoning effort | | /models | Manage on-device models (download, delete) | | /agents | Manage concurrent chat sessions (list/new/switch/rename/kill) | | /agent [name] [task] | List custom agents, or run one | | /plan | Toggle plan mode: the model researches read-only, writes a plan file under ~/.vini/plans/, and calls exitPlanMode for your approval (/plan show\|edit\|list\|use <path\|n>) | | /accept-edits | Toggle accept-edits mode (file edits inside the project auto-approved; other tools still ask) | | /permission-mode [mode] | Show or set the mode: ask, acceptEdits, plan, bypassPermissions (alias auto), dontAsk | | /cd [dir] | Change the directory tools run in (cd inside a bash call persists too); /cd resets | | /add-dir <dir> | Add a directory to the auto-approved read scope (alongside cwd) | | /bg | List background subagent runs and bash tasks; /bg kill <run-id> | | /bashes | List background bash tasks (start with bash run_in_background or Ctrl+B) | | /copy [N] | Copy the last (or Nth-latest) reply to the clipboard | | /context | Context-window breakdown: system prompt, tool schemas, instruction files, messages | | /config | Interactive settings editor with per-scope saving | | /theme [name], /color <name> | Colour theme (dark, light, dark-ansi, light-ansi, mono; NO_COLOR honoured) and a session prompt colour | | /hooks | Interactive hooks editor: browse events, add/delete/test hooks per scope (/hooks edit opens the file) | | /insights [days] [--open] | Usage report from your local sessions, prompts and tool runs | | /teleport | Print and copy the vini --resume <id> line to pick this session up on another machine | | /keybindings | Open ~/.vini/keybindings.json (/keybindings list shows the effective bindings) | | /terminal-setup | How to get shift+enter / option+enter newlines | | /rename <name> | Rename this session (tab, /resume picker, terminal title) | | /branch [name] | Continue as a new session; the original stays resumable | | /sessions | List and resume recent sessions | | /rewind | Rewind code and/or conversation to a turn checkpoint | | /share [off] | Create (or revoke) a public link to this conversation | | /dispatch | Open the team's Dispatch thread (tasks assigned from the phone or web run here) | | /device | This machine on the tool relay: /device name <new>, /device unpair <client> | | /export [path] [--json] | Export this conversation to a file | | /design <brief>, /science <brief> | Design canvas / science artifacts, opened in your browser | | /code-review, /security-review, /simplify | Bundled review skills over the pending changes | | /permissions | List or edit permission rules by scope (--scope user\|project\|local) | | /todos | Show or hide the inline tasks panel (also ctrl+t) | | /memory | List the instruction files and rules in the system prompt; /memory <n\|name> opens one, /memory reload, /memory rules | | /mcp | Interactive MCP panel (Enter tools · e enable/disable · r reconnect · t trust); /mcp list\|tools\|reconnect\|enable\|disable\|trust <name> | | /diff | Show or hide the inline diff panel (/diff session\|uncommitted\|noise\|<path>) | | /goal <task> | Pursue a task autonomously until complete | | /auto-accept | Toggle auto-approval of tool calls | | /loop <interval> <prompt> | Create a recurring interval (e.g. /loop 5m check deploy status) | | /schedule … | Manage scheduled prompts (create, list, pause, resume, delete, runs) | | /btw <question> | Ask a quick side question without derailing the conversation | | /undo | Undo the last file write or edit | | /compact [focus] | Summarize older history with the model to free context (/compact-output toggles abbreviated tool output) | | /compress | Mechanical (no-LLM) history compression | | /save / /resume | Save or resume conversations | | /dictate | Record voice input (Enter to stop) | | /say | Read the last reply aloud (Esc to stop) | | /voice / /voicemode | Hands-free voice conversation (Esc to exit) | | /live / /realtimevoice | Live speech-to-speech conversation (Enter to talk, Esc to exit) | | /output-style [name] | Show or set the output style | | /vim | Toggle vim editing mode for the input line | | /tui | Show or set the renderer: /tui fullscreen / /tui default (restart to apply) | | /verbose | Toggle the verbose transcript (same as ctrl+o in the default renderer) | | /tokens | Show estimated token usage and context-window use | | /cost | Estimated session cost and workspace monthly spend | | /stats | Usage stats across recorded sessions | | /logout | Sign out and exit | | /exit | Exit |

Keyboard

| Key | Action | |---|---| | Shift+Tab | Cycle permission mode: ask → accept edits → plan → bypass (skipped when disableBypassPermissionsMode) | | Esc | Clears the input; Esc Esc on an empty prompt opens the rewind picker | | Ctrl+O | Toggle the verbose transcript (permission decision under each tool call); in the fullscreen renderer it opens transcript mode instead (/verbose toggles verbose there) | | Ctrl+G | Edit the prompt in $EDITOR | | Option+Enter / Shift+Enter | Newline (see /terminal-setup) | | Ctrl+R | Search the persistent prompt history (~/.vini/prompt-history.jsonl) | | Ctrl+T | Toggle the inline tasks panel | | PgUp / PgDn / Home / End | Scroll the transcript (fullscreen renderer; the mouse wheel works too) | | Ctrl+B | Background the running bash command | | Ctrl+V | Attach a clipboard image |

Launch flags

--permission-mode <ask|acceptEdits|plan|bypassPermissions|dontAsk>   # --dangerously-skip-permissions = bypassPermissions
--settings <file|json> / --setting-sources user,project,local
--session-id <id> / --name <name> / --no-session-persistence
--ax-screen-reader                        # plain rendering: no spinner, borders, or glyphs
--tui <default|fullscreen>                # fullscreen: alternate screen, pinned prompt, in-app scrolling (also settings.tui)
--allowedTools readFile "bash(git *)"     # allow without prompting (Claude Code syntax accepted)
--disallowedTools "bash(git push *)"      # deny for this run; deny beats every other rule
--add-dir <dir...>                        # extra directories treated like the project
--append-system-prompt <text>             # or --append-system-prompt-file <path>
--verbose                                 # full tool output + the permission decision under each call
--debug [api,hooks,permissions,mcp,tools] # JSON-lines log at ~/.vini/debug.log (--debug-file <path>)
--mcp-config <file|json>                  # extra MCP servers for this run (repeatable); --strict-mcp-config uses only those

Fullscreen renderer

/tui fullscreen (or --tui fullscreen, or "tui": "fullscreen" in ~/.vini/settings.json) renders vini on the terminal's alternate screen, like vim or htop: the prompt and status line stay pinned at the bottom, the transcript scrolls inside the app, and dialogs (permissions, questions, pickers) replace the transcript so they are always in view. /tui default switches back; both take effect on the next start. Screen-reader mode and headless -p always use the default renderer.

ctrl+o opens transcript mode: the whole conversation, top-anchored, with / to search (hits are inverted), n/N to hop between them and Esc to return. Scroll with PgUp/PgDn/Home/End or the mouse wheel; a [↑ N rows] badge shows while you are scrolled up, and sending a prompt snaps back to the bottom. On terminals 100 columns or wider the tasks/diff panel (ctrl+t, /todos, /diff) becomes a right-hand sidebar. Mouse reporting is on while vini runs, so use shift-drag (or option-drag in iTerm2) to select text natively, or set VINI_DISABLE_MOUSE=1 to keep the wheel off; if a crash ever leaves the terminal in mouse mode, reset fixes it.

Because the alternate screen leaves nothing in the terminal's scrollback, vini prints a vini --resume <id> line when it exits; /export saves a transcript at any time.

Instruction files and rules

vini loads, lowest precedence first: ~/.vini/{AGENTS,CLAUDE,MEMORY}.md, then AGENTS.md / CLAUDE.md (plus .local.md overrides) from every directory between the git root and the current directory, then MEMORY.md in the current directory. Lines that are just @path inline another file. Rules live in ~/.vini/rules/*.md and <repo>/.vini/rules/*.md; a rule with paths: frontmatter (comma list or - item lines) is attached the first time a tool touches a matching file. Headless runs and subagents load the same files. /memory lists everything.

MCP servers

vini mcp add <name> [--scope user|project] [-e KEY=VAL] [-H "Key: Value"] -- <command> [args]
vini mcp add <name> https://host/mcp        # streamable HTTP, falls back to SSE
vini mcp add-json <name> '{"command":"…"}'
vini mcp list [--check] · vini mcp get <name> · vini mcp remove <name>

Sources, lowest precedence first: ~/.vini/mcp.json, settings.mcpServers, ./.vini/mcp.json, --mcp-config. Servers declared in a project's .vini/mcp.json ask for approval on first use; the decision is remembered per server config in .vini/settings.local.json. OAuth is not supported (use headers). Space-level remote servers are connected by the backend and listed read-only.

The model can also ask you structured questions (askUserQuestion), rendered as a picker; press Esc to dismiss. Long pastes collapse to [Pasted text #1 +N lines] and expand when sent.

Permissions

Rules live in permission maps or Claude-Code-style permissions: { allow: ["Bash(git *)"], deny: [...], ask: [...] } arrays in any settings file (also permissions.defaultMode, permissions.additionalDirectories, permissions.disableBypassPermissionsMode). Browser tools prompt like any other tool (screenshots, text extraction, links, scrolling are read-only and auto-allowed). Writes require the file to have been read this session, and ambiguous edits are refused. A PermissionRequest hook can answer prompts. Web search/fetch run on the backend for cloud providers (the space's "Web search" toggle governs them); the local copy is used only with on-device models.

Hooks

Events: PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, UserPromptSubmit, Stop, SubagentStart, SubagentStop, SessionStart (with source), SessionEnd, PreCompact, PostCompact, Notification. Hook types: command (exit 2 or {"decision":"block"} blocks; "async": true never blocks), prompt ($INPUT is the event JSON; the model answers with a decision), http (POSTs the event). Outputs: reason, additionalContext, updatedInput, systemMessage, continue: false, permissionDecision (also under hookSpecificOutput).

Sessions on other machines

Chats live on the backend, so vini --resume <chat id> (or /resume <id>) works on any machine signed into the same account; the session is indexed locally on first resume and vini warns when the repo, branch, or directory differ from where it was recorded. /teleport prints the command with those hints and copies it.

Skills and agents may carry hooks: (inline JSON or a JSON file next to the definition) and allowed-tools: in their frontmatter; they apply for the turn the skill runs or while the agent runs.

Subagents

spawnAgents runs up to four agents; built-in types explore, plan (read-only) and general-purpose join your ~/.vini/agents and .vini/agents definitions. fork: true seeds an agent with the conversation so far, background: true returns a run id at once and delivers the report as a later message (agentOutput polls, sendToAgent follows up, /bg lists and cancels).

Architecture

src/
├── index.tsx          # Entry point: CLI arg parsing, config loading, render(<App />)
├── app.tsx            # Startup flow: Login → Workspace selection → Chat
├── api.ts             # Backend API calls (OTP, teams, workspaces, JWT)
├── config.ts          # ~/.vini/config.json and credentials.json (mode 0o600)
├── scheduler.ts       # Local scheduled-prompt execution
├── components/        # Ink UI: Chat, Login, WorkspaceSelect, ToolPermission,
│                      #   ToolCall, AgentsModal, LocalModelManager, …
├── tools/             # Tool schemas + executors: files, git, web, notebooks,
│                      #   tasks, sub-agents, permissions, undo
├── llm/               # Local model catalog & node-llama-cpp manager
├── transport/         # Chat transport to the Yinzer backend
├── commands/          # User-defined slash command loader
└── hooks/, lib/, utils/

Chat requests are sent to ${host}/api/chat with JWT auth and workspace context. The tools exposed to the model are merged from three sources:

  1. Built-in tools (defined locally in src/tools/)
  2. Workspace tools (from the space config fetched from the backend)
  3. Skills — custom prompt + tool definitions (only enabled and approved ones)

Configuration

All persistent state lives in ~/.vini/:

| File | Contents | |---|---| | config.json | Host, team, workspace, API key | | credentials.json | JWT, session cookie, username (permissions 0o600) | | settings.json | Settings (also layered from ./.vini/settings.json and ./.vini/settings.local.json): permissionMode, permission/permissions rules, additionalDirectories, disableBypassPermissionsMode, hooks, notifications (channel auto/bell/osx/iterm2/linux/off), attribution, autoupdate (notify/auto/off), showExpandedTodos, diff, … | | permissions.json | Learned user-scope allow/deny rules | | prompt-history.jsonl | Persistent prompt history for ↑ and Ctrl+R | | mcp.json | User-scope local MCP servers (vini mcp add); project servers in ./.vini/mcp.json | | plans/*.md | Plan-mode plan files | | rules/*.md | User-scope rules (project rules in ./.vini/rules/) | | commands/*.md | User-defined slash commands (also loaded from ./.vini/commands/) |

Development

npm test runs the Bun test suite (src/**/*.test.ts), npm run typecheck runs tsc --noEmit, and npm run smoke does a headless round-trip against the real backend. See CLAUDE.md for AI-assistant-oriented guidance on this codebase.