Download desktop/backend/tools.ts from Snapkitty/grisp-shadow-fleet: direct link, hf CLI and curl.
- Browser
- Download file 7.89 kB
-
https://huggingface.co/Snapkitty/grisp-shadow-fleet/resolve/main/desktop/backend/tools.ts
- Command line
-
hf download hf://Snapkitty/grisp-shadow-fleet/desktop/backend/tools.ts
-
curl -L -o tools.ts https://huggingface.co/Snapkitty/grisp-shadow-fleet/resolve/main/desktop/backend/tools.ts
7.89 kB
| import { DesktopCommandBroker } from './sandbox.js'; | |
| import { readWorkspaceTextFile } from './workspace.js'; | |
| import type { DesktopToolEvent, DesktopToolSummary } from '../shared.js'; | |
| export interface ToolCallRequest { | |
| readonly name: string; | |
| readonly input: Record<string, unknown>; | |
| } | |
| const LEDGER_API = 'https://sovereign-email-agent.snapkittywest.workers.dev/api/commit'; | |
| export const SOVEREIGN_TOOLS: ReadonlyArray<DesktopToolSummary> = [ | |
| { | |
| name: 'workspace.search', | |
| description: 'Search this repo with ripgrep. Read-only.', | |
| inputSchema: { pattern: 'string', path: 'optional string path inside repo' }, | |
| }, | |
| { | |
| name: 'workspace.read_file', | |
| description: 'Read a text file from inside this repo. Read-only.', | |
| inputSchema: { path: 'string path inside repo' }, | |
| }, | |
| { | |
| name: 'repo.status', | |
| description: 'Run git status -sb. Read-only.', | |
| inputSchema: {}, | |
| }, | |
| { | |
| name: 'repo.diff_stat', | |
| description: 'Run git diff --stat. Read-only.', | |
| inputSchema: {}, | |
| }, | |
| { | |
| name: 'repo.test', | |
| description: 'Run npm test through the governed command broker.', | |
| inputSchema: {}, | |
| }, | |
| { | |
| name: 'repo.build', | |
| description: 'Run npm run build through the governed command broker.', | |
| inputSchema: {}, | |
| }, | |
| { | |
| name: 'repo.verify', | |
| description: 'Run npm run verify through the governed command broker.', | |
| inputSchema: {}, | |
| }, | |
| { | |
| name: 'ledger.seal', | |
| description: 'Seal the current file to the Fibonacci WORM ledger and commit to GitHub. Artifact hash (SHA-512 β 0xFFFFFFFF β SHA-512) recorded on-chain.', | |
| inputSchema: { path: 'string β owner/repo/file/path.ext', code: 'string β file content', branch: 'optional string β default main' }, | |
| }, | |
| ]; | |
| const TOOL_NAMES = new Set(SOVEREIGN_TOOLS.map(tool => tool.name)); | |
| export class SovereignToolBroker { | |
| constructor( | |
| private readonly repoRoot: string, | |
| private readonly commands: DesktopCommandBroker, | |
| ) {} | |
| list(): ReadonlyArray<DesktopToolSummary> { | |
| return SOVEREIGN_TOOLS; | |
| } | |
| async execute(call: ToolCallRequest): Promise<DesktopToolEvent> { | |
| try { | |
| if (!TOOL_NAMES.has(call.name)) { | |
| return { name: call.name, ok: false, output: `Unknown tool: ${call.name}` }; | |
| } | |
| switch (call.name) { | |
| case 'workspace.search': | |
| return this.runCommandTool(call.name, buildSearchCommand(call.input)); | |
| case 'workspace.read_file': { | |
| const path = requireString(call.input, 'path'); | |
| const file = await readWorkspaceTextFile(this.repoRoot, path); | |
| return { | |
| name: call.name, | |
| ok: true, | |
| output: truncateToolOutput(`FILE ${file.relativePath}\n\n${file.content}`), | |
| }; | |
| } | |
| case 'repo.status': | |
| return this.runCommandTool(call.name, 'git status -sb'); | |
| case 'repo.diff_stat': | |
| return this.runCommandTool(call.name, 'git diff --stat'); | |
| case 'repo.test': | |
| return this.runCommandTool(call.name, 'npm test'); | |
| case 'repo.build': | |
| return this.runCommandTool(call.name, 'npm run build'); | |
| case 'repo.verify': | |
| return this.runCommandTool(call.name, 'npm run verify'); | |
| case 'ledger.seal': | |
| return this.sealToLedger(call); | |
| default: | |
| return { name: call.name, ok: false, output: `Unhandled tool: ${call.name}` }; | |
| } | |
| } catch (error) { | |
| return { | |
| name: call.name, | |
| ok: false, | |
| output: error instanceof Error ? error.message : String(error), | |
| }; | |
| } | |
| } | |
| private async sealToLedger(call: ToolCallRequest): Promise<DesktopToolEvent> { | |
| const path = requireString(call.input, 'path'); | |
| const code = requireString(call.input, 'code'); | |
| const branch = typeof call.input.branch === 'string' ? call.input.branch : 'main'; | |
| const res = await fetch(LEDGER_API, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ path, code, branch, author: 'bob-desktop-ide' }), | |
| }); | |
| if (!res.ok) { | |
| const err = await res.text(); | |
| return { name: call.name, ok: false, output: `Ledger API error ${res.status}: ${err}` }; | |
| } | |
| const data = await res.json() as Record<string, unknown>; | |
| const ledger = data.ledger as Record<string, unknown>; | |
| const output = [ | |
| `SOVEREIGN COMMIT SEALED`, | |
| `ββββββββββββββββββββββββββββββ`, | |
| ` File: ${data.file}`, | |
| ` Branch: ${data.branch}`, | |
| ` Commit: ${data.commit}`, | |
| ` URL: ${data.url}`, | |
| ``, | |
| `FIBONACCI LEDGER`, | |
| ` Block: ${ledger.block}`, | |
| ` F(${ledger.block}): ${ledger.fib}`, | |
| ` Hash: ${data.artifact_hash}`, | |
| ` Pipeline: ${data.pipeline}`, | |
| `ββββββββββββββββββββββββββββββ`, | |
| ].join('\n'); | |
| return { name: call.name, ok: true, output }; | |
| } | |
| private async runCommandTool(name: string, command: string): Promise<DesktopToolEvent> { | |
| const result = await this.commands.run({ command }, () => undefined); | |
| const output = [ | |
| result.reason ? `reason: ${result.reason}` : '', | |
| result.stdout, | |
| result.stderr, | |
| ].filter(Boolean).join('\n'); | |
| return { | |
| name, | |
| ok: result.allowed && result.exitCode === 0, | |
| output: truncateToolOutput(output || `exit=${result.exitCode}`), | |
| }; | |
| } | |
| } | |
| export function parseToolCall(content: string): ToolCallRequest | undefined { | |
| const candidates = [ | |
| ...extractJsonCodeBlocks(content), | |
| content.trim(), | |
| ]; | |
| for (const candidate of candidates) { | |
| try { | |
| const parsed = JSON.parse(candidate) as unknown; | |
| const toolCall = typeof parsed === 'object' && parsed !== null && 'tool_call' in parsed | |
| ? (parsed as { tool_call?: unknown }).tool_call | |
| : parsed; | |
| if (typeof toolCall !== 'object' || toolCall === null) continue; | |
| const record = toolCall as Record<string, unknown>; | |
| if (typeof record.name !== 'string') continue; | |
| const input = typeof record.input === 'object' && record.input !== null | |
| ? record.input as Record<string, unknown> | |
| : {}; | |
| return { name: record.name, input }; | |
| } catch { | |
| continue; | |
| } | |
| } | |
| return undefined; | |
| } | |
| export function removeToolCallJson(content: string): string { | |
| return content | |
| .replace(/```(?:json)?\s*{[\s\S]*?"tool_call"[\s\S]*?}\s*```/gi, '') | |
| .replace(/^\s*{[\s\S]*?"tool_call"[\s\S]*?}\s*$/i, '') | |
| .trim(); | |
| } | |
| export function formatToolResultForModel(call: ToolCallRequest, event: DesktopToolEvent): string { | |
| return JSON.stringify({ | |
| tool_result: { | |
| name: call.name, | |
| ok: event.ok, | |
| output: event.output, | |
| }, | |
| }, null, 2); | |
| } | |
| function buildSearchCommand(input: Record<string, unknown>): string { | |
| const pattern = requireString(input, 'pattern'); | |
| const path = typeof input.path === 'string' && input.path.trim() ? input.path.trim() : '.'; | |
| return `rg ${quoteArg(pattern)} ${quoteArg(path)}`; | |
| } | |
| function requireString(input: Record<string, unknown>, key: string): string { | |
| const value = input[key]; | |
| if (typeof value !== 'string' || !value.trim()) { | |
| throw new Error(`Tool input field "${key}" must be a non-empty string.`); | |
| } | |
| return value.trim(); | |
| } | |
| function quoteArg(value: string): string { | |
| return `"${value.replaceAll('\\', '\\\\').replaceAll('"', '\\"')}"`; | |
| } | |
| function extractJsonCodeBlocks(content: string): string[] { | |
| const matches = [...content.matchAll(/```(?:json)?\s*([\s\S]*?)```/gi)]; | |
| return matches.map(match => match[1]?.trim() ?? '').filter(Boolean); | |
| } | |
| function truncateToolOutput(output: string): string { | |
| const limit = 12_000; | |
| if (output.length <= limit) return output; | |
| return `${output.slice(0, limit)}\n\n[tool output truncated at ${limit} chars]`; | |
| } | |