Initial commit: shiro-neko 0.1.0-beta.1

Agentic coding CLI on Bun, Ink, and the AI SDK.

Core: streamText loop with SDK-level tool approval so a denied call provably never executes; endpoint fallback for OpenAI reasoning models; retry with backoff.

Tools: read/write/edit/glob/grep/bash, path-jailed, gitignore-aware, ripgrep with a JS fallback, binary rejection, live bash streaming.

Agents: five variants crossing thinking level with tool restriction; plan and review withhold mutating tools from the model.

Extensibility: frontmatter skills with on-demand bodies, plugin host with blocking hooks, MCP stdio and HTTP, read-only subagents.

State: durable per-project memory, session task lists, session persistence, compaction that repairs provider-item dependencies.

Distribution: five-platform cross-compiled binaries with checksums, install scripts, CI on three operating systems.

404 tests, typecheck clean.
This commit is contained in:
Muhammad Zakir Ramadhan committed 2026-09-02 17:30:18 +07:00
commit 5b8503fcd9
93 files changed
+12775

No files matched your search

+57
View File
@@ -0,0 +1,57 @@
import { createMCPClient, type MCPClient } from '@ai-sdk/mcp';
import { Experimental_StdioMCPTransport } from '@ai-sdk/mcp/mcp-stdio';
import type { ToolSet } from 'ai';
export type McpServerConfig =
| { command: string; args?: string[]; env?: Record<string, string>; cwd?: string }
| { url: string; type?: 'http' | 'sse'; headers?: Record<string, string> };
export type McpHandle = {
tools: ToolSet;
errors: { server: string; message: string }[];
close: () => Promise<void>;
};
const isRemote = (c: McpServerConfig): c is Extract<McpServerConfig, { url: string }> => 'url' in c;
/**
* Connects every configured server and namespaces its tools as `mcp__<server>__<tool>`
* so two servers exposing `search` cannot silently shadow each other.
* A server that fails to start is reported, never fatal.
*/
export async function connectMcp(servers: Record<string, McpServerConfig>): Promise<McpHandle> {
const clients: MCPClient[] = [];
const tools: ToolSet = {};
const errors: McpHandle['errors'] = [];
await Promise.all(
Object.entries(servers).map(async ([name, cfg]) => {
try {
const client = await createMCPClient({
transport: isRemote(cfg)
? { type: cfg.type ?? 'http', url: cfg.url, ...(cfg.headers ? { headers: cfg.headers } : {}) }
: new Experimental_StdioMCPTransport({
command: cfg.command,
...(cfg.args ? { args: cfg.args } : {}),
...(cfg.env ? { env: cfg.env } : {}),
...(cfg.cwd ? { cwd: cfg.cwd } : {}),
}),
});
clients.push(client);
for (const [toolName, tool] of Object.entries(await client.tools())) {
tools[`mcp__${name}__${toolName}`] = tool;
}
} catch (e) {
errors.push({ server: name, message: e instanceof Error ? e.message : String(e) });
}
}),
);
return {
tools,
errors,
close: async () => {
await Promise.all(clients.map((c) => c.close().catch(() => {})));
},
};
}