@clicksmith/daemon 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/{chunk-25CDLKXI.js → chunk-3M6UR4EB.js} +2 -2
- package/dist/{chunk-WDOX7SFY.js → chunk-H7GZFKN4.js} +4 -5
- package/dist/chunk-H7GZFKN4.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/mcp.js +1 -1
- package/package.json +18 -16
- package/dist/chunk-WDOX7SFY.js.map +0 -1
- /package/dist/{chunk-25CDLKXI.js.map → chunk-3M6UR4EB.js.map} +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ClickSmith contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
Git,
|
|
4
4
|
describeSandbox,
|
|
5
5
|
version
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-H7GZFKN4.js";
|
|
7
7
|
|
|
8
8
|
// src/events.ts
|
|
9
9
|
var EventBus = class {
|
|
@@ -612,4 +612,4 @@ export {
|
|
|
612
612
|
NotFoundError,
|
|
613
613
|
buildServer
|
|
614
614
|
};
|
|
615
|
-
//# sourceMappingURL=chunk-
|
|
615
|
+
//# sourceMappingURL=chunk-3M6UR4EB.js.map
|
|
@@ -245,7 +245,7 @@ async function loadAgentsConfig(storageRoot) {
|
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
// src/store.ts
|
|
248
|
-
import { mkdir, readFile as readFile2, readdir, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
248
|
+
import { appendFile, mkdir, readFile as readFile2, readdir, rm as rm2, writeFile as writeFile2 } from "fs/promises";
|
|
249
249
|
import { join as join3 } from "path";
|
|
250
250
|
import {
|
|
251
251
|
deserializeBundle,
|
|
@@ -344,8 +344,7 @@ var FileStore = class {
|
|
|
344
344
|
async appendLog(runId, chunk) {
|
|
345
345
|
const file = join3(this.runDir(runId), "agent.log");
|
|
346
346
|
await mkdir(this.runDir(runId), { recursive: true });
|
|
347
|
-
|
|
348
|
-
await writeFile2(file, existing + chunk, "utf8");
|
|
347
|
+
await appendFile(file, chunk, "utf8");
|
|
349
348
|
}
|
|
350
349
|
/* ----------------------------- maintenance ----------------------------- */
|
|
351
350
|
/** Delete expired, unsubmitted sessions. Returns the ids removed. */
|
|
@@ -480,7 +479,7 @@ function json(value) {
|
|
|
480
479
|
}
|
|
481
480
|
|
|
482
481
|
// src/version.ts
|
|
483
|
-
var version = "0.1.
|
|
482
|
+
var version = "0.1.4";
|
|
484
483
|
|
|
485
484
|
// src/mcp.ts
|
|
486
485
|
function createMcpServer(reader) {
|
|
@@ -539,4 +538,4 @@ export {
|
|
|
539
538
|
createMcpServer,
|
|
540
539
|
startMcp
|
|
541
540
|
};
|
|
542
|
-
//# sourceMappingURL=chunk-
|
|
541
|
+
//# sourceMappingURL=chunk-H7GZFKN4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp.ts","../src/config.ts","../src/git.ts","../src/paths.ts","../src/logger.ts","../src/store.ts","../src/mcp-tools.ts","../src/version.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';\nimport { resolveDaemonConfig } from './config.js';\nimport { FileStore } from './store.js';\nimport { callTool, readerFromStore, TOOL_DEFINITIONS, type McpReader } from './mcp-tools.js';\nimport { version } from './version.js';\n\n/**\n * Create an MCP {@link Server} exposing ClickSmith's read-only tools over the\n * given reader. The daemon and a standalone `clicksmith mcp` process both use\n * this; state is shared via the on-disk store, so the MCP process never needs\n * to talk to the HTTP daemon directly.\n */\nexport function createMcpServer(reader: McpReader): Server {\n const server = new Server(\n { name: 'clicksmith', version },\n { capabilities: { tools: {} } },\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: TOOL_DEFINITIONS.map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema,\n })),\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n const result = await callTool(name, args ?? {}, reader);\n if (!result.ok) {\n return { content: [{ type: 'text', text: result.error }], isError: true };\n }\n return { content: [{ type: 'text', text: result.text }] };\n });\n\n return server;\n}\n\n/** Entry point for `clicksmith mcp`: connect the stdio transport. */\nexport async function startMcp(): Promise<void> {\n const config = await resolveDaemonConfig({ logLevel: 'silent' });\n const store = new FileStore(config.storageRoot);\n await store.init();\n const server = createMcpServer(readerFromStore(store));\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\n// Allow running this file directly as the MCP server.\nif (import.meta.url === `file://${process.argv[1]}`) {\n startMcp().catch((err) => {\n process.stderr.write(`clicksmith mcp failed: ${err instanceof Error ? err.stack : String(err)}\\n`);\n process.exit(1);\n });\n}\n","import { readFile } from 'node:fs/promises';\nimport {\n DEFAULT_AGENTS_CONFIG,\n mergeAgentsConfig,\n parseAgentsConfig,\n type AgentsConfig,\n} from '@clicksmith/agent-config';\nimport { DEFAULT_DAEMON_HOST, DEFAULT_DAEMON_PORT, DEFAULT_SESSION_TTL_MS } from '@clicksmith/core';\nimport { Git } from './git.js';\nimport { resolveStorageRoot, storagePaths } from './paths.js';\nimport { createLogger, type LogLevel, type Logger } from './logger.js';\n\nexport interface DaemonConfigInput {\n cwd?: string;\n host?: string;\n port?: number;\n ttlMs?: number;\n logLevel?: LogLevel;\n /** Override the storage root (mainly for tests). */\n storageRoot?: string;\n /** Override repo detection (mainly for tests). */\n repoRoot?: string | null;\n}\n\nexport interface DaemonConfig {\n host: string;\n port: number;\n ttlMs: number;\n cwd: string;\n repoRoot: string | null;\n storageRoot: string;\n agents: AgentsConfig;\n logger: Logger;\n}\n\n/**\n * Resolve the full daemon configuration: detect the repo, choose a storage\n * root, and layer agent configs (shipped defaults → project `agents.config.json`).\n */\nexport async function resolveDaemonConfig(input: DaemonConfigInput = {}): Promise<DaemonConfig> {\n const cwd = input.cwd ?? process.cwd();\n const repoRoot = input.repoRoot !== undefined ? input.repoRoot : await Git.findRepoRoot(cwd);\n const storageRoot = input.storageRoot ?? resolveStorageRoot(repoRoot);\n const agents = await loadAgentsConfig(storageRoot);\n\n return {\n host: input.host ?? DEFAULT_DAEMON_HOST,\n port: input.port ?? DEFAULT_DAEMON_PORT,\n ttlMs: input.ttlMs ?? DEFAULT_SESSION_TTL_MS,\n cwd,\n repoRoot,\n storageRoot,\n agents,\n logger: createLogger(input.logLevel ?? 'info'),\n };\n}\n\n/** Load `agents.config.json` from the storage root and merge over defaults. */\nexport async function loadAgentsConfig(storageRoot: string): Promise<AgentsConfig> {\n const file = storagePaths(storageRoot).config;\n let raw: string | undefined;\n try {\n raw = await readFile(file, 'utf8');\n } catch {\n return DEFAULT_AGENTS_CONFIG;\n }\n let json: unknown;\n try {\n json = JSON.parse(raw);\n } catch {\n return DEFAULT_AGENTS_CONFIG;\n }\n const parsed = parseAgentsConfig(json);\n if (!parsed.ok) return DEFAULT_AGENTS_CONFIG;\n return mergeAgentsConfig(DEFAULT_AGENTS_CONFIG, parsed.config);\n}\n","import { execa } from 'execa';\nimport { mkdtemp, rm, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Isolation, SandboxInfo } from '@clicksmith/core';\n\nexport class GitError extends Error {}\n\n/** Thin wrapper around the `git` CLI, scoped to a working directory. */\nexport class Git {\n constructor(private readonly cwd: string) {}\n\n private async run(args: string[], opts: { reject?: boolean } = {}) {\n const result = await execa('git', args, { cwd: this.cwd, reject: false });\n if (opts.reject !== false && result.exitCode !== 0) {\n throw new GitError(`git ${args.join(' ')} failed: ${result.stderr || result.stdout}`);\n }\n return result;\n }\n\n /** Absolute repo root, or `null` if `cwd` is not inside a git repo. */\n static async findRepoRoot(cwd: string): Promise<string | null> {\n const result = await execa('git', ['rev-parse', '--show-toplevel'], { cwd, reject: false });\n return result.exitCode === 0 ? result.stdout.trim() : null;\n }\n\n async headCommit(): Promise<string> {\n return (await this.run(['rev-parse', 'HEAD'])).stdout.trim();\n }\n\n async currentBranch(): Promise<string> {\n return (await this.run(['rev-parse', '--abbrev-ref', 'HEAD'])).stdout.trim();\n }\n\n /**\n * Whether the working tree has uncommitted (tracked or untracked) changes,\n * ignoring any paths under `exclude` prefixes (e.g. ClickSmith's own\n * `.clicksmith/` state directory).\n */\n async isDirty(opts: { exclude?: string[] } = {}): Promise<boolean> {\n const result = await this.run(['status', '--porcelain']);\n const exclude = opts.exclude ?? [];\n return result.stdout\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean)\n .some((line) => {\n const path = line.slice(2).trim();\n const actual = path.includes(' -> ') ? path.split(' -> ')[1]! : path;\n return !exclude.some((prefix) => actual.startsWith(prefix));\n });\n }\n\n /** Whether this git supports worktrees (>= 2.5). */\n async supportsWorktree(): Promise<boolean> {\n const result = await execa('git', ['worktree', 'list'], { cwd: this.cwd, reject: false });\n return result.exitCode === 0;\n }\n\n /**\n * Create a throwaway worktree on a fresh branch for a run. The worktree lives\n * outside the main tree so the agent's edits never touch it.\n */\n async createWorktree(path: string, branch: string, baseRef: string): Promise<void> {\n await this.run(['worktree', 'add', '-b', branch, path, baseRef]);\n }\n\n async removeWorktree(path: string, branch?: string): Promise<void> {\n await this.run(['worktree', 'remove', '--force', path], { reject: false });\n if (branch) await this.run(['branch', '-D', branch], { reject: false });\n }\n\n /** Create + checkout a dedicated branch (the worktree fallback). */\n async createBranch(branch: string, baseRef: string): Promise<void> {\n await this.run(['switch', '-c', branch, baseRef]);\n }\n\n async switchTo(ref: string): Promise<void> {\n await this.run(['switch', ref]);\n }\n\n async deleteBranch(branch: string): Promise<void> {\n await this.run(['branch', '-D', branch], { reject: false });\n }\n\n /**\n * Capture every change in a sandbox (relative to its HEAD) as a single\n * binary-safe patch, including new and deleted files. Returns '' if clean.\n */\n static async captureDiff(sandboxPath: string): Promise<string> {\n await execa('git', ['add', '-A'], { cwd: sandboxPath, reject: false });\n const result = await execa('git', ['diff', '--cached', '--binary'], {\n cwd: sandboxPath,\n reject: false,\n });\n return result.exitCode === 0 ? result.stdout : '';\n }\n\n /**\n * Apply a captured patch onto the main working tree using a 3-way merge,\n * staging the result. Returns the list of conflicted files (empty on success).\n */\n async applyPatch(patch: string): Promise<{ ok: boolean; conflicts: string[] }> {\n if (!patch.trim()) return { ok: true, conflicts: [] };\n const tmp = await mkdtemp(join(tmpdir(), 'clicksmith-patch-'));\n const patchFile = join(tmp, 'run.patch');\n try {\n await writeFile(patchFile, patch.endsWith('\\n') ? patch : `${patch}\\n`, 'utf8');\n const result = await this.run(['apply', '--index', '--3way', patchFile], { reject: false });\n if (result.exitCode === 0) return { ok: true, conflicts: [] };\n const unmerged = (await this.run(['diff', '--name-only', '--diff-filter=U'], { reject: false }))\n .stdout.split(/\\r?\\n/)\n .map((s) => s.trim())\n .filter(Boolean);\n const conflicts = [...new Set([...unmerged, ...parseConflicts(result.stderr)])];\n return { ok: false, conflicts: conflicts.length ? conflicts : ['(unresolved — see git status)'] };\n } finally {\n await rm(tmp, { recursive: true, force: true });\n }\n }\n\n /** Commit the currently staged changes; returns the new commit sha. */\n async commit(message: string): Promise<string> {\n await this.run(['commit', '-m', message, '--no-verify']);\n return this.headCommit();\n }\n\n /** Whether there is anything staged or unstaged to commit. */\n async hasChanges(): Promise<boolean> {\n return this.isDirty();\n }\n\n /**\n * Merge a branch into the current branch with `--no-ff`. On conflict, the\n * merge is aborted and the conflicted files are returned.\n */\n async merge(branch: string, message: string): Promise<{ ok: boolean; conflicts: string[] }> {\n const result = await this.run(['merge', '--no-ff', '-m', message, branch], { reject: false });\n if (result.exitCode === 0) return { ok: true, conflicts: [] };\n const conflicts = (await this.run(['diff', '--name-only', '--diff-filter=U'], { reject: false }))\n .stdout.split(/\\r?\\n/)\n .map((s) => s.trim())\n .filter(Boolean);\n await this.run(['merge', '--abort'], { reject: false });\n return { ok: false, conflicts };\n }\n\n async resetHard(ref: string): Promise<void> {\n await this.run(['reset', '--hard', ref]);\n }\n}\n\nfunction parseConflicts(stderr: string): string[] {\n const files = new Set<string>();\n for (const line of stderr.split(/\\r?\\n/)) {\n // `error: <path>: already exists in working directory`\n const errColon = line.match(/^error:\\s*(.+?):\\s/);\n if (errColon?.[1]) files.add(errColon[1].trim());\n // Quoted paths, e.g. `Applied patch to 'foo.ts' with conflicts.`\n for (const q of line.matchAll(/'([^']+)'/g)) files.add(q[1]!.trim());\n // Porcelain unmerged lines.\n const u = line.match(/^U\\s+(.+)$/);\n if (u?.[1]) files.add(u[1].trim());\n }\n return [...files];\n}\n\n/** Build the sandbox descriptor for a prepared run. */\nexport function describeSandbox(\n isolation: Isolation,\n path: string,\n branch: string | null,\n baseCommit: string,\n): SandboxInfo {\n return { isolation, path, branch, baseCommit };\n}\n","import { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/** OS-appropriate cache root used when not inside a git repo. */\nexport function osCacheRoot(): string {\n if (process.platform === 'win32') {\n return join(process.env.LOCALAPPDATA ?? join(homedir(), 'AppData', 'Local'), 'clicksmith', 'Cache');\n }\n if (process.platform === 'darwin') {\n return join(homedir(), 'Library', 'Caches', 'clicksmith');\n }\n return join(process.env.XDG_CACHE_HOME ?? join(homedir(), '.cache'), 'clicksmith');\n}\n\n/**\n * The storage root for sessions/runs: the project's `.clicksmith/` when inside\n * a repo, otherwise the OS cache directory.\n */\nexport function resolveStorageRoot(repoRoot: string | null): string {\n return repoRoot ? join(repoRoot, '.clicksmith') : osCacheRoot();\n}\n\n/** Well-known sub-paths within a storage root. */\nexport function storagePaths(root: string) {\n return {\n root,\n sessions: join(root, 'sessions'),\n runs: join(root, 'runs'),\n screenshots: join(root, 'screenshots'),\n config: join(root, 'agents.config.json'),\n runDir: (runId: string) => join(root, 'runs', runId),\n sandboxDir: (runId: string) => join(root, 'worktrees', runId),\n };\n}\n\nexport type StoragePaths = ReturnType<typeof storagePaths>;\n","/* Minimal leveled logger. Writes to stderr so it never corrupts MCP stdio. */\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\nconst ORDER: Record<LogLevel, number> = { debug: 0, info: 1, warn: 2, error: 3, silent: 4 };\n\nexport interface Logger {\n debug(msg: string, ...rest: unknown[]): void;\n info(msg: string, ...rest: unknown[]): void;\n warn(msg: string, ...rest: unknown[]): void;\n error(msg: string, ...rest: unknown[]): void;\n}\n\nexport function createLogger(level: LogLevel = 'info', prefix = 'clicksmith'): Logger {\n const min = ORDER[level];\n const emit = (lvl: LogLevel, msg: string, rest: unknown[]) => {\n if (ORDER[lvl] < min) return;\n const line = `[${prefix}] ${lvl.toUpperCase()} ${msg}`;\n // Always stderr — stdout is reserved for MCP's JSON-RPC transport.\n process.stderr.write(rest.length ? `${line} ${rest.map(fmt).join(' ')}\\n` : `${line}\\n`);\n };\n return {\n debug: (m, ...r) => emit('debug', m, r),\n info: (m, ...r) => emit('info', m, r),\n warn: (m, ...r) => emit('warn', m, r),\n error: (m, ...r) => emit('error', m, r),\n };\n}\n\nfunction fmt(v: unknown): string {\n if (typeof v === 'string') return v;\n if (v instanceof Error) return v.stack ?? v.message;\n try {\n return JSON.stringify(v);\n } catch {\n return String(v);\n }\n}\n","import { appendFile, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n deserializeBundle,\n isExpired,\n serializeBundle,\n type CaptureBundle,\n type Session,\n} from '@clicksmith/core';\nimport { storagePaths, type StoragePaths } from './paths.js';\nimport type { RunRecord } from './types.js';\n\n/**\n * File-backed persistence for sessions, runs, and run artifacts. Everything is\n * stored as JSON/markdown/patch files under the storage root — no database, no\n * network. Writes are atomic (temp file + rename) to survive crashes.\n */\nexport class FileStore {\n readonly paths: StoragePaths;\n\n constructor(root: string) {\n this.paths = storagePaths(root);\n }\n\n async init(): Promise<void> {\n await Promise.all([\n mkdir(this.paths.sessions, { recursive: true }),\n mkdir(this.paths.runs, { recursive: true }),\n mkdir(this.paths.screenshots, { recursive: true }),\n ]);\n }\n\n /* ----------------------------- sessions ------------------------------ */\n\n private sessionFile(id: string): string {\n return join(this.paths.sessions, `${sanitize(id)}.json`);\n }\n\n async saveSession(session: Session): Promise<void> {\n await atomicWrite(this.sessionFile(session.id), JSON.stringify(session, null, 2));\n }\n\n async getSession(id: string): Promise<Session | undefined> {\n return readJson<Session>(this.sessionFile(id));\n }\n\n async listSessions(): Promise<Session[]> {\n const out: Session[] = [];\n for (const file of await listJson(this.paths.sessions)) {\n const s = await readJson<Session>(join(this.paths.sessions, file));\n if (s) out.push(s);\n }\n return out;\n }\n\n async deleteSession(id: string): Promise<void> {\n await rm(this.sessionFile(id), { force: true });\n }\n\n /* -------------------------------- runs -------------------------------- */\n\n private runDir(runId: string): string {\n return this.paths.runDir(runId);\n }\n\n private runFile(runId: string): string {\n return join(this.runDir(runId), 'run.json');\n }\n\n async saveRun(run: RunRecord): Promise<void> {\n await mkdir(this.runDir(run.runId), { recursive: true });\n await atomicWrite(this.runFile(run.runId), JSON.stringify(run, null, 2));\n }\n\n async getRun(runId: string): Promise<RunRecord | undefined> {\n return readJson<RunRecord>(this.runFile(runId));\n }\n\n async listRuns(): Promise<RunRecord[]> {\n let dirs: string[];\n try {\n dirs = await readdir(this.paths.runs);\n } catch {\n return [];\n }\n const out: RunRecord[] = [];\n for (const dir of dirs) {\n const run = await readJson<RunRecord>(join(this.paths.runs, dir, 'run.json'));\n if (run) out.push(run);\n }\n return out.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n }\n\n /** The most recent run that has a persisted bundle (for `get_latest_request`). */\n async latestRun(): Promise<RunRecord | undefined> {\n const runs = await this.listRuns();\n return runs.at(-1);\n }\n\n /* ----------------------------- artifacts ------------------------------ */\n\n async saveBundle(runId: string, bundle: CaptureBundle): Promise<string> {\n await mkdir(this.runDir(runId), { recursive: true });\n const file = join(this.runDir(runId), 'bundle.json');\n await atomicWrite(file, serializeBundle(bundle));\n return file;\n }\n\n async getBundle(runId: string): Promise<CaptureBundle | undefined> {\n const raw = await readText(join(this.runDir(runId), 'bundle.json'));\n return raw ? deserializeBundle(raw) : undefined;\n }\n\n bundlePath(runId: string): string {\n return join(this.runDir(runId), 'bundle.json');\n }\n\n async writeArtifact(runId: string, name: string, content: string): Promise<string> {\n await mkdir(this.runDir(runId), { recursive: true });\n const file = join(this.runDir(runId), name);\n await atomicWrite(file, content);\n return file;\n }\n\n async readArtifact(runId: string, name: string): Promise<string | undefined> {\n return readText(join(this.runDir(runId), name));\n }\n\n async appendLog(runId: string, chunk: string): Promise<void> {\n const file = join(this.runDir(runId), 'agent.log');\n await mkdir(this.runDir(runId), { recursive: true });\n await appendFile(file, chunk, 'utf8');\n }\n\n /* ----------------------------- maintenance ----------------------------- */\n\n /** Delete expired, unsubmitted sessions. Returns the ids removed. */\n async cleanupExpired(now: Date = new Date()): Promise<string[]> {\n const removed: string[] = [];\n for (const session of await this.listSessions()) {\n if (isExpired(session, now)) {\n await this.deleteSession(session.id);\n removed.push(session.id);\n }\n }\n return removed;\n }\n}\n\n/* -------------------------------- helpers --------------------------------- */\n\nfunction sanitize(id: string): string {\n return id.replace(/[^a-zA-Z0-9._-]/g, '_');\n}\n\nasync function atomicWrite(file: string, content: string): Promise<void> {\n const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;\n await writeFile(tmp, content, 'utf8');\n const { rename } = await import('node:fs/promises');\n await rename(tmp, file);\n}\n\nasync function readText(file: string): Promise<string | undefined> {\n try {\n return await readFile(file, 'utf8');\n } catch {\n return undefined;\n }\n}\n\nasync function readJson<T>(file: string): Promise<T | undefined> {\n const raw = await readText(file);\n if (raw == null) return undefined;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return undefined;\n }\n}\n\nasync function listJson(dir: string): Promise<string[]> {\n try {\n return (await readdir(dir)).filter((f) => f.endsWith('.json'));\n } catch {\n return [];\n }\n}\n","import type { CaptureBundle, CapturedElement, Session } from '@clicksmith/core';\nimport type { FileStore } from './store.js';\n\n/** Read-only view the MCP tools operate over, backed by daemon persistence. */\nexport interface McpReader {\n getSession(id: string): Promise<Session | undefined>;\n /** The bundle from the most recent submission, if any. */\n latestBundle(): Promise<CaptureBundle | undefined>;\n}\n\n/** Build an {@link McpReader} from a {@link FileStore}. */\nexport function readerFromStore(store: FileStore): McpReader {\n return {\n getSession: (id) => store.getSession(id),\n latestBundle: async () => {\n const run = await store.latestRun();\n return run ? store.getBundle(run.runId) : undefined;\n },\n };\n}\n\n/**\n * Tool definitions exposed over MCP. The **descriptions** deliberately teach the\n * agent the three ClickSmith conventions: `#N` references, locator priority, and\n * the plan/worktree safety contract.\n */\nexport const TOOL_DEFINITIONS = [\n {\n name: 'get_latest_request',\n description:\n 'Get the most recently submitted ClickSmith capture bundle (the latest UI change request). ' +\n 'Returns the prompt, the app route, and the captured elements numbered #1, #2, … . ' +\n 'The user prompt refers to elements by these numbers. Trust each element’s locator in the ' +\n 'order source → attr → behavioral → dom (source = exact file:line). You are running in an ' +\n 'isolated git worktree; in plan mode propose changes — the human clicks Apply to ship them.',\n inputSchema: { type: 'object', properties: {}, additionalProperties: false },\n },\n {\n name: 'get_session',\n description:\n 'Get a ClickSmith capture session by id, including all captured elements (#1, #2, …) and the ' +\n 'app/route context. Use this to resolve which concrete elements the user’s #N references mean.',\n inputSchema: {\n type: 'object',\n properties: { sessionId: { type: 'string', description: 'The session id.' } },\n required: ['sessionId'],\n additionalProperties: false,\n },\n },\n {\n name: 'list_elements',\n description:\n 'List the captured elements for a session (or the latest request if no sessionId is given). ' +\n 'Each element has an id (its #N), a ranked locator (source → attr → behavioral → dom), the ' +\n 'tag/text/role/label, and nearby context for disambiguation.',\n inputSchema: {\n type: 'object',\n properties: { sessionId: { type: 'string', description: 'Optional session id.' } },\n additionalProperties: false,\n },\n },\n {\n name: 'get_element_by_id',\n description:\n 'Resolve a single captured element by its #N id (e.g. 1 for #1), within a session or the ' +\n 'latest request. Returns its locator (prefer source over attr over behavioral over dom), the ' +\n 'element descriptor, and near context.',\n inputSchema: {\n type: 'object',\n properties: {\n id: { type: 'number', description: 'The element’s #N number.' },\n sessionId: { type: 'string', description: 'Optional session id; defaults to latest.' },\n },\n required: ['id'],\n additionalProperties: false,\n },\n },\n] as const;\n\nexport type ToolResult = { ok: true; text: string } | { ok: false; error: string };\n\n/** Execute a read-only tool by name. Pure with respect to the reader. */\nexport async function callTool(\n name: string,\n args: Record<string, unknown>,\n reader: McpReader,\n): Promise<ToolResult> {\n switch (name) {\n case 'get_latest_request': {\n const bundle = await reader.latestBundle();\n if (!bundle) return { ok: false, error: 'No request has been submitted yet.' };\n return { ok: true, text: json(bundle) };\n }\n case 'get_session': {\n const session = await reader.getSession(String(args.sessionId));\n if (!session) return { ok: false, error: `Unknown session: ${String(args.sessionId)}` };\n return { ok: true, text: json(session) };\n }\n case 'list_elements': {\n const elements = await resolveElements(reader, args.sessionId as string | undefined);\n if (!elements) return { ok: false, error: 'No session or latest request found.' };\n return { ok: true, text: json(elements) };\n }\n case 'get_element_by_id': {\n const id = Number(args.id);\n const elements = await resolveElements(reader, args.sessionId as string | undefined);\n if (!elements) return { ok: false, error: 'No session or latest request found.' };\n const element = elements.find((e) => e.id === id);\n if (!element) return { ok: false, error: `No element #${id} in this session.` };\n return { ok: true, text: json(element) };\n }\n default:\n return { ok: false, error: `Unknown tool: ${name}` };\n }\n}\n\nasync function resolveElements(\n reader: McpReader,\n sessionId?: string,\n): Promise<CapturedElement[] | undefined> {\n if (sessionId) return (await reader.getSession(sessionId))?.elements;\n return (await reader.latestBundle())?.elements;\n}\n\nfunction json(value: unknown): string {\n return JSON.stringify(value, null, 2);\n}\n","/** The daemon's semantic version, surfaced via /health and MCP. */\nexport const version = '0.1.4';\n"],"mappings":"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","names":["join","json","readFile","rm","writeFile","join","join","rm","writeFile","readFile"]}
|
package/dist/cli.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import {
|
|
3
3
|
DaemonService,
|
|
4
4
|
buildServer
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-3M6UR4EB.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveDaemonConfig,
|
|
8
8
|
startMcp,
|
|
9
9
|
version
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-H7GZFKN4.js";
|
|
11
11
|
|
|
12
12
|
// src/cli.ts
|
|
13
13
|
import { defaultBinExists } from "@clicksmith/agent-config";
|
package/dist/index.d.ts
CHANGED
|
@@ -411,6 +411,6 @@ declare function createMcpServer(reader: McpReader): Server;
|
|
|
411
411
|
declare function startMcp(): Promise<void>;
|
|
412
412
|
|
|
413
413
|
/** The daemon's semantic version, surfaced via /health and MCP. */
|
|
414
|
-
declare const version = "0.1.
|
|
414
|
+
declare const version = "0.1.4";
|
|
415
415
|
|
|
416
416
|
export { type DaemonConfig, type DaemonConfigInput, DaemonService, type DaemonServiceOptions, type EnrichmentProvider, EventBus, FileStore, Git, GitError, type LaunchHandlers, type LaunchResult, type LogLevel, type Logger, type McpReader, NotFoundError, RefusalError, type RevertMeta, type RunArtifacts, RunManager, type RunManagerDeps, type RunRecord, TOOL_DEFINITIONS, type ToolResult, buildServer, callTool, createLogger, createMcpServer, describeSandbox, enrichBundle, launchAgent, loadAgentsConfig, osCacheRoot, readerFromStore, resolveDaemonConfig, resolveStorageRoot, startMcp, storagePaths, version };
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
buildServer,
|
|
8
8
|
enrichBundle,
|
|
9
9
|
launchAgent
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3M6UR4EB.js";
|
|
11
11
|
import {
|
|
12
12
|
FileStore,
|
|
13
13
|
Git,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
startMcp,
|
|
26
26
|
storagePaths,
|
|
27
27
|
version
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-H7GZFKN4.js";
|
|
29
29
|
export {
|
|
30
30
|
DaemonService,
|
|
31
31
|
EventBus,
|
package/dist/mcp.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clicksmith/daemon",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "The ClickSmith localhost daemon: Fastify HTTP + WebSocket, MCP stdio server, persistence, git sandbox orchestration, and config-driven agent launching.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -15,28 +15,30 @@
|
|
|
15
15
|
"bin": {
|
|
16
16
|
"clicksmith": "./dist/cli.js"
|
|
17
17
|
},
|
|
18
|
-
"files": [
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"dev": "tsup --watch",
|
|
22
|
-
"start": "node dist/cli.js daemon",
|
|
23
|
-
"test": "vitest run",
|
|
24
|
-
"test:watch": "vitest",
|
|
25
|
-
"typecheck": "tsc --noEmit",
|
|
26
|
-
"lint": "eslint src",
|
|
27
|
-
"clean": "rimraf dist .turbo"
|
|
28
|
-
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
29
21
|
"dependencies": {
|
|
30
|
-
"@clicksmith/agent-config": "workspace:*",
|
|
31
|
-
"@clicksmith/core": "workspace:*",
|
|
32
22
|
"@fastify/websocket": "^11.0.1",
|
|
33
23
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
34
24
|
"execa": "^9.5.1",
|
|
35
25
|
"fastify": "^5.1.0",
|
|
36
|
-
"zod": "^3.23.8"
|
|
26
|
+
"zod": "^3.23.8",
|
|
27
|
+
"@clicksmith/agent-config": "0.1.1",
|
|
28
|
+
"@clicksmith/core": "0.1.0"
|
|
37
29
|
},
|
|
38
30
|
"devDependencies": {
|
|
39
31
|
"@types/ws": "^8.5.13",
|
|
40
32
|
"ws": "^8.18.0"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsup",
|
|
36
|
+
"dev": "tsup --watch",
|
|
37
|
+
"start": "node dist/cli.js daemon",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"test:watch": "vitest",
|
|
40
|
+
"typecheck": "tsc --noEmit",
|
|
41
|
+
"lint": "eslint src",
|
|
42
|
+
"clean": "rimraf dist .turbo"
|
|
41
43
|
}
|
|
42
|
-
}
|
|
44
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp.ts","../src/config.ts","../src/git.ts","../src/paths.ts","../src/logger.ts","../src/store.ts","../src/mcp-tools.ts","../src/version.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';\nimport { resolveDaemonConfig } from './config.js';\nimport { FileStore } from './store.js';\nimport { callTool, readerFromStore, TOOL_DEFINITIONS, type McpReader } from './mcp-tools.js';\nimport { version } from './version.js';\n\n/**\n * Create an MCP {@link Server} exposing ClickSmith's read-only tools over the\n * given reader. The daemon and a standalone `clicksmith mcp` process both use\n * this; state is shared via the on-disk store, so the MCP process never needs\n * to talk to the HTTP daemon directly.\n */\nexport function createMcpServer(reader: McpReader): Server {\n const server = new Server(\n { name: 'clicksmith', version },\n { capabilities: { tools: {} } },\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: TOOL_DEFINITIONS.map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema,\n })),\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n const result = await callTool(name, args ?? {}, reader);\n if (!result.ok) {\n return { content: [{ type: 'text', text: result.error }], isError: true };\n }\n return { content: [{ type: 'text', text: result.text }] };\n });\n\n return server;\n}\n\n/** Entry point for `clicksmith mcp`: connect the stdio transport. */\nexport async function startMcp(): Promise<void> {\n const config = await resolveDaemonConfig({ logLevel: 'silent' });\n const store = new FileStore(config.storageRoot);\n await store.init();\n const server = createMcpServer(readerFromStore(store));\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\n// Allow running this file directly as the MCP server.\nif (import.meta.url === `file://${process.argv[1]}`) {\n startMcp().catch((err) => {\n process.stderr.write(`clicksmith mcp failed: ${err instanceof Error ? err.stack : String(err)}\\n`);\n process.exit(1);\n });\n}\n","import { readFile } from 'node:fs/promises';\nimport {\n DEFAULT_AGENTS_CONFIG,\n mergeAgentsConfig,\n parseAgentsConfig,\n type AgentsConfig,\n} from '@clicksmith/agent-config';\nimport { DEFAULT_DAEMON_HOST, DEFAULT_DAEMON_PORT, DEFAULT_SESSION_TTL_MS } from '@clicksmith/core';\nimport { Git } from './git.js';\nimport { resolveStorageRoot, storagePaths } from './paths.js';\nimport { createLogger, type LogLevel, type Logger } from './logger.js';\n\nexport interface DaemonConfigInput {\n cwd?: string;\n host?: string;\n port?: number;\n ttlMs?: number;\n logLevel?: LogLevel;\n /** Override the storage root (mainly for tests). */\n storageRoot?: string;\n /** Override repo detection (mainly for tests). */\n repoRoot?: string | null;\n}\n\nexport interface DaemonConfig {\n host: string;\n port: number;\n ttlMs: number;\n cwd: string;\n repoRoot: string | null;\n storageRoot: string;\n agents: AgentsConfig;\n logger: Logger;\n}\n\n/**\n * Resolve the full daemon configuration: detect the repo, choose a storage\n * root, and layer agent configs (shipped defaults → project `agents.config.json`).\n */\nexport async function resolveDaemonConfig(input: DaemonConfigInput = {}): Promise<DaemonConfig> {\n const cwd = input.cwd ?? process.cwd();\n const repoRoot = input.repoRoot !== undefined ? input.repoRoot : await Git.findRepoRoot(cwd);\n const storageRoot = input.storageRoot ?? resolveStorageRoot(repoRoot);\n const agents = await loadAgentsConfig(storageRoot);\n\n return {\n host: input.host ?? DEFAULT_DAEMON_HOST,\n port: input.port ?? DEFAULT_DAEMON_PORT,\n ttlMs: input.ttlMs ?? DEFAULT_SESSION_TTL_MS,\n cwd,\n repoRoot,\n storageRoot,\n agents,\n logger: createLogger(input.logLevel ?? 'info'),\n };\n}\n\n/** Load `agents.config.json` from the storage root and merge over defaults. */\nexport async function loadAgentsConfig(storageRoot: string): Promise<AgentsConfig> {\n const file = storagePaths(storageRoot).config;\n let raw: string | undefined;\n try {\n raw = await readFile(file, 'utf8');\n } catch {\n return DEFAULT_AGENTS_CONFIG;\n }\n let json: unknown;\n try {\n json = JSON.parse(raw);\n } catch {\n return DEFAULT_AGENTS_CONFIG;\n }\n const parsed = parseAgentsConfig(json);\n if (!parsed.ok) return DEFAULT_AGENTS_CONFIG;\n return mergeAgentsConfig(DEFAULT_AGENTS_CONFIG, parsed.config);\n}\n","import { execa } from 'execa';\nimport { mkdtemp, rm, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Isolation, SandboxInfo } from '@clicksmith/core';\n\nexport class GitError extends Error {}\n\n/** Thin wrapper around the `git` CLI, scoped to a working directory. */\nexport class Git {\n constructor(private readonly cwd: string) {}\n\n private async run(args: string[], opts: { reject?: boolean } = {}) {\n const result = await execa('git', args, { cwd: this.cwd, reject: false });\n if (opts.reject !== false && result.exitCode !== 0) {\n throw new GitError(`git ${args.join(' ')} failed: ${result.stderr || result.stdout}`);\n }\n return result;\n }\n\n /** Absolute repo root, or `null` if `cwd` is not inside a git repo. */\n static async findRepoRoot(cwd: string): Promise<string | null> {\n const result = await execa('git', ['rev-parse', '--show-toplevel'], { cwd, reject: false });\n return result.exitCode === 0 ? result.stdout.trim() : null;\n }\n\n async headCommit(): Promise<string> {\n return (await this.run(['rev-parse', 'HEAD'])).stdout.trim();\n }\n\n async currentBranch(): Promise<string> {\n return (await this.run(['rev-parse', '--abbrev-ref', 'HEAD'])).stdout.trim();\n }\n\n /**\n * Whether the working tree has uncommitted (tracked or untracked) changes,\n * ignoring any paths under `exclude` prefixes (e.g. ClickSmith's own\n * `.clicksmith/` state directory).\n */\n async isDirty(opts: { exclude?: string[] } = {}): Promise<boolean> {\n const result = await this.run(['status', '--porcelain']);\n const exclude = opts.exclude ?? [];\n return result.stdout\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean)\n .some((line) => {\n const path = line.slice(2).trim();\n const actual = path.includes(' -> ') ? path.split(' -> ')[1]! : path;\n return !exclude.some((prefix) => actual.startsWith(prefix));\n });\n }\n\n /** Whether this git supports worktrees (>= 2.5). */\n async supportsWorktree(): Promise<boolean> {\n const result = await execa('git', ['worktree', 'list'], { cwd: this.cwd, reject: false });\n return result.exitCode === 0;\n }\n\n /**\n * Create a throwaway worktree on a fresh branch for a run. The worktree lives\n * outside the main tree so the agent's edits never touch it.\n */\n async createWorktree(path: string, branch: string, baseRef: string): Promise<void> {\n await this.run(['worktree', 'add', '-b', branch, path, baseRef]);\n }\n\n async removeWorktree(path: string, branch?: string): Promise<void> {\n await this.run(['worktree', 'remove', '--force', path], { reject: false });\n if (branch) await this.run(['branch', '-D', branch], { reject: false });\n }\n\n /** Create + checkout a dedicated branch (the worktree fallback). */\n async createBranch(branch: string, baseRef: string): Promise<void> {\n await this.run(['switch', '-c', branch, baseRef]);\n }\n\n async switchTo(ref: string): Promise<void> {\n await this.run(['switch', ref]);\n }\n\n async deleteBranch(branch: string): Promise<void> {\n await this.run(['branch', '-D', branch], { reject: false });\n }\n\n /**\n * Capture every change in a sandbox (relative to its HEAD) as a single\n * binary-safe patch, including new and deleted files. Returns '' if clean.\n */\n static async captureDiff(sandboxPath: string): Promise<string> {\n await execa('git', ['add', '-A'], { cwd: sandboxPath, reject: false });\n const result = await execa('git', ['diff', '--cached', '--binary'], {\n cwd: sandboxPath,\n reject: false,\n });\n return result.exitCode === 0 ? result.stdout : '';\n }\n\n /**\n * Apply a captured patch onto the main working tree using a 3-way merge,\n * staging the result. Returns the list of conflicted files (empty on success).\n */\n async applyPatch(patch: string): Promise<{ ok: boolean; conflicts: string[] }> {\n if (!patch.trim()) return { ok: true, conflicts: [] };\n const tmp = await mkdtemp(join(tmpdir(), 'clicksmith-patch-'));\n const patchFile = join(tmp, 'run.patch');\n try {\n await writeFile(patchFile, patch.endsWith('\\n') ? patch : `${patch}\\n`, 'utf8');\n const result = await this.run(['apply', '--index', '--3way', patchFile], { reject: false });\n if (result.exitCode === 0) return { ok: true, conflicts: [] };\n const unmerged = (await this.run(['diff', '--name-only', '--diff-filter=U'], { reject: false }))\n .stdout.split(/\\r?\\n/)\n .map((s) => s.trim())\n .filter(Boolean);\n const conflicts = [...new Set([...unmerged, ...parseConflicts(result.stderr)])];\n return { ok: false, conflicts: conflicts.length ? conflicts : ['(unresolved — see git status)'] };\n } finally {\n await rm(tmp, { recursive: true, force: true });\n }\n }\n\n /** Commit the currently staged changes; returns the new commit sha. */\n async commit(message: string): Promise<string> {\n await this.run(['commit', '-m', message, '--no-verify']);\n return this.headCommit();\n }\n\n /** Whether there is anything staged or unstaged to commit. */\n async hasChanges(): Promise<boolean> {\n return this.isDirty();\n }\n\n /**\n * Merge a branch into the current branch with `--no-ff`. On conflict, the\n * merge is aborted and the conflicted files are returned.\n */\n async merge(branch: string, message: string): Promise<{ ok: boolean; conflicts: string[] }> {\n const result = await this.run(['merge', '--no-ff', '-m', message, branch], { reject: false });\n if (result.exitCode === 0) return { ok: true, conflicts: [] };\n const conflicts = (await this.run(['diff', '--name-only', '--diff-filter=U'], { reject: false }))\n .stdout.split(/\\r?\\n/)\n .map((s) => s.trim())\n .filter(Boolean);\n await this.run(['merge', '--abort'], { reject: false });\n return { ok: false, conflicts };\n }\n\n async resetHard(ref: string): Promise<void> {\n await this.run(['reset', '--hard', ref]);\n }\n}\n\nfunction parseConflicts(stderr: string): string[] {\n const files = new Set<string>();\n for (const line of stderr.split(/\\r?\\n/)) {\n // `error: <path>: already exists in working directory`\n const errColon = line.match(/^error:\\s*(.+?):\\s/);\n if (errColon?.[1]) files.add(errColon[1].trim());\n // Quoted paths, e.g. `Applied patch to 'foo.ts' with conflicts.`\n for (const q of line.matchAll(/'([^']+)'/g)) files.add(q[1]!.trim());\n // Porcelain unmerged lines.\n const u = line.match(/^U\\s+(.+)$/);\n if (u?.[1]) files.add(u[1].trim());\n }\n return [...files];\n}\n\n/** Build the sandbox descriptor for a prepared run. */\nexport function describeSandbox(\n isolation: Isolation,\n path: string,\n branch: string | null,\n baseCommit: string,\n): SandboxInfo {\n return { isolation, path, branch, baseCommit };\n}\n","import { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/** OS-appropriate cache root used when not inside a git repo. */\nexport function osCacheRoot(): string {\n if (process.platform === 'win32') {\n return join(process.env.LOCALAPPDATA ?? join(homedir(), 'AppData', 'Local'), 'clicksmith', 'Cache');\n }\n if (process.platform === 'darwin') {\n return join(homedir(), 'Library', 'Caches', 'clicksmith');\n }\n return join(process.env.XDG_CACHE_HOME ?? join(homedir(), '.cache'), 'clicksmith');\n}\n\n/**\n * The storage root for sessions/runs: the project's `.clicksmith/` when inside\n * a repo, otherwise the OS cache directory.\n */\nexport function resolveStorageRoot(repoRoot: string | null): string {\n return repoRoot ? join(repoRoot, '.clicksmith') : osCacheRoot();\n}\n\n/** Well-known sub-paths within a storage root. */\nexport function storagePaths(root: string) {\n return {\n root,\n sessions: join(root, 'sessions'),\n runs: join(root, 'runs'),\n screenshots: join(root, 'screenshots'),\n config: join(root, 'agents.config.json'),\n runDir: (runId: string) => join(root, 'runs', runId),\n sandboxDir: (runId: string) => join(root, 'worktrees', runId),\n };\n}\n\nexport type StoragePaths = ReturnType<typeof storagePaths>;\n","/* Minimal leveled logger. Writes to stderr so it never corrupts MCP stdio. */\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\nconst ORDER: Record<LogLevel, number> = { debug: 0, info: 1, warn: 2, error: 3, silent: 4 };\n\nexport interface Logger {\n debug(msg: string, ...rest: unknown[]): void;\n info(msg: string, ...rest: unknown[]): void;\n warn(msg: string, ...rest: unknown[]): void;\n error(msg: string, ...rest: unknown[]): void;\n}\n\nexport function createLogger(level: LogLevel = 'info', prefix = 'clicksmith'): Logger {\n const min = ORDER[level];\n const emit = (lvl: LogLevel, msg: string, rest: unknown[]) => {\n if (ORDER[lvl] < min) return;\n const line = `[${prefix}] ${lvl.toUpperCase()} ${msg}`;\n // Always stderr — stdout is reserved for MCP's JSON-RPC transport.\n process.stderr.write(rest.length ? `${line} ${rest.map(fmt).join(' ')}\\n` : `${line}\\n`);\n };\n return {\n debug: (m, ...r) => emit('debug', m, r),\n info: (m, ...r) => emit('info', m, r),\n warn: (m, ...r) => emit('warn', m, r),\n error: (m, ...r) => emit('error', m, r),\n };\n}\n\nfunction fmt(v: unknown): string {\n if (typeof v === 'string') return v;\n if (v instanceof Error) return v.stack ?? v.message;\n try {\n return JSON.stringify(v);\n } catch {\n return String(v);\n }\n}\n","import { mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n deserializeBundle,\n isExpired,\n serializeBundle,\n type CaptureBundle,\n type Session,\n} from '@clicksmith/core';\nimport { storagePaths, type StoragePaths } from './paths.js';\nimport type { RunRecord } from './types.js';\n\n/**\n * File-backed persistence for sessions, runs, and run artifacts. Everything is\n * stored as JSON/markdown/patch files under the storage root — no database, no\n * network. Writes are atomic (temp file + rename) to survive crashes.\n */\nexport class FileStore {\n readonly paths: StoragePaths;\n\n constructor(root: string) {\n this.paths = storagePaths(root);\n }\n\n async init(): Promise<void> {\n await Promise.all([\n mkdir(this.paths.sessions, { recursive: true }),\n mkdir(this.paths.runs, { recursive: true }),\n mkdir(this.paths.screenshots, { recursive: true }),\n ]);\n }\n\n /* ----------------------------- sessions ------------------------------ */\n\n private sessionFile(id: string): string {\n return join(this.paths.sessions, `${sanitize(id)}.json`);\n }\n\n async saveSession(session: Session): Promise<void> {\n await atomicWrite(this.sessionFile(session.id), JSON.stringify(session, null, 2));\n }\n\n async getSession(id: string): Promise<Session | undefined> {\n return readJson<Session>(this.sessionFile(id));\n }\n\n async listSessions(): Promise<Session[]> {\n const out: Session[] = [];\n for (const file of await listJson(this.paths.sessions)) {\n const s = await readJson<Session>(join(this.paths.sessions, file));\n if (s) out.push(s);\n }\n return out;\n }\n\n async deleteSession(id: string): Promise<void> {\n await rm(this.sessionFile(id), { force: true });\n }\n\n /* -------------------------------- runs -------------------------------- */\n\n private runDir(runId: string): string {\n return this.paths.runDir(runId);\n }\n\n private runFile(runId: string): string {\n return join(this.runDir(runId), 'run.json');\n }\n\n async saveRun(run: RunRecord): Promise<void> {\n await mkdir(this.runDir(run.runId), { recursive: true });\n await atomicWrite(this.runFile(run.runId), JSON.stringify(run, null, 2));\n }\n\n async getRun(runId: string): Promise<RunRecord | undefined> {\n return readJson<RunRecord>(this.runFile(runId));\n }\n\n async listRuns(): Promise<RunRecord[]> {\n let dirs: string[];\n try {\n dirs = await readdir(this.paths.runs);\n } catch {\n return [];\n }\n const out: RunRecord[] = [];\n for (const dir of dirs) {\n const run = await readJson<RunRecord>(join(this.paths.runs, dir, 'run.json'));\n if (run) out.push(run);\n }\n return out.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n }\n\n /** The most recent run that has a persisted bundle (for `get_latest_request`). */\n async latestRun(): Promise<RunRecord | undefined> {\n const runs = await this.listRuns();\n return runs.at(-1);\n }\n\n /* ----------------------------- artifacts ------------------------------ */\n\n async saveBundle(runId: string, bundle: CaptureBundle): Promise<string> {\n await mkdir(this.runDir(runId), { recursive: true });\n const file = join(this.runDir(runId), 'bundle.json');\n await atomicWrite(file, serializeBundle(bundle));\n return file;\n }\n\n async getBundle(runId: string): Promise<CaptureBundle | undefined> {\n const raw = await readText(join(this.runDir(runId), 'bundle.json'));\n return raw ? deserializeBundle(raw) : undefined;\n }\n\n bundlePath(runId: string): string {\n return join(this.runDir(runId), 'bundle.json');\n }\n\n async writeArtifact(runId: string, name: string, content: string): Promise<string> {\n await mkdir(this.runDir(runId), { recursive: true });\n const file = join(this.runDir(runId), name);\n await atomicWrite(file, content);\n return file;\n }\n\n async readArtifact(runId: string, name: string): Promise<string | undefined> {\n return readText(join(this.runDir(runId), name));\n }\n\n async appendLog(runId: string, chunk: string): Promise<void> {\n const file = join(this.runDir(runId), 'agent.log');\n await mkdir(this.runDir(runId), { recursive: true });\n const existing = (await readText(file)) ?? '';\n await writeFile(file, existing + chunk, 'utf8');\n }\n\n /* ----------------------------- maintenance ----------------------------- */\n\n /** Delete expired, unsubmitted sessions. Returns the ids removed. */\n async cleanupExpired(now: Date = new Date()): Promise<string[]> {\n const removed: string[] = [];\n for (const session of await this.listSessions()) {\n if (isExpired(session, now)) {\n await this.deleteSession(session.id);\n removed.push(session.id);\n }\n }\n return removed;\n }\n}\n\n/* -------------------------------- helpers --------------------------------- */\n\nfunction sanitize(id: string): string {\n return id.replace(/[^a-zA-Z0-9._-]/g, '_');\n}\n\nasync function atomicWrite(file: string, content: string): Promise<void> {\n const tmp = `${file}.${process.pid}.${Date.now()}.tmp`;\n await writeFile(tmp, content, 'utf8');\n const { rename } = await import('node:fs/promises');\n await rename(tmp, file);\n}\n\nasync function readText(file: string): Promise<string | undefined> {\n try {\n return await readFile(file, 'utf8');\n } catch {\n return undefined;\n }\n}\n\nasync function readJson<T>(file: string): Promise<T | undefined> {\n const raw = await readText(file);\n if (raw == null) return undefined;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return undefined;\n }\n}\n\nasync function listJson(dir: string): Promise<string[]> {\n try {\n return (await readdir(dir)).filter((f) => f.endsWith('.json'));\n } catch {\n return [];\n }\n}\n","import type { CaptureBundle, CapturedElement, Session } from '@clicksmith/core';\nimport type { FileStore } from './store.js';\n\n/** Read-only view the MCP tools operate over, backed by daemon persistence. */\nexport interface McpReader {\n getSession(id: string): Promise<Session | undefined>;\n /** The bundle from the most recent submission, if any. */\n latestBundle(): Promise<CaptureBundle | undefined>;\n}\n\n/** Build an {@link McpReader} from a {@link FileStore}. */\nexport function readerFromStore(store: FileStore): McpReader {\n return {\n getSession: (id) => store.getSession(id),\n latestBundle: async () => {\n const run = await store.latestRun();\n return run ? store.getBundle(run.runId) : undefined;\n },\n };\n}\n\n/**\n * Tool definitions exposed over MCP. The **descriptions** deliberately teach the\n * agent the three ClickSmith conventions: `#N` references, locator priority, and\n * the plan/worktree safety contract.\n */\nexport const TOOL_DEFINITIONS = [\n {\n name: 'get_latest_request',\n description:\n 'Get the most recently submitted ClickSmith capture bundle (the latest UI change request). ' +\n 'Returns the prompt, the app route, and the captured elements numbered #1, #2, … . ' +\n 'The user prompt refers to elements by these numbers. Trust each element’s locator in the ' +\n 'order source → attr → behavioral → dom (source = exact file:line). You are running in an ' +\n 'isolated git worktree; in plan mode propose changes — the human clicks Apply to ship them.',\n inputSchema: { type: 'object', properties: {}, additionalProperties: false },\n },\n {\n name: 'get_session',\n description:\n 'Get a ClickSmith capture session by id, including all captured elements (#1, #2, …) and the ' +\n 'app/route context. Use this to resolve which concrete elements the user’s #N references mean.',\n inputSchema: {\n type: 'object',\n properties: { sessionId: { type: 'string', description: 'The session id.' } },\n required: ['sessionId'],\n additionalProperties: false,\n },\n },\n {\n name: 'list_elements',\n description:\n 'List the captured elements for a session (or the latest request if no sessionId is given). ' +\n 'Each element has an id (its #N), a ranked locator (source → attr → behavioral → dom), the ' +\n 'tag/text/role/label, and nearby context for disambiguation.',\n inputSchema: {\n type: 'object',\n properties: { sessionId: { type: 'string', description: 'Optional session id.' } },\n additionalProperties: false,\n },\n },\n {\n name: 'get_element_by_id',\n description:\n 'Resolve a single captured element by its #N id (e.g. 1 for #1), within a session or the ' +\n 'latest request. Returns its locator (prefer source over attr over behavioral over dom), the ' +\n 'element descriptor, and near context.',\n inputSchema: {\n type: 'object',\n properties: {\n id: { type: 'number', description: 'The element’s #N number.' },\n sessionId: { type: 'string', description: 'Optional session id; defaults to latest.' },\n },\n required: ['id'],\n additionalProperties: false,\n },\n },\n] as const;\n\nexport type ToolResult = { ok: true; text: string } | { ok: false; error: string };\n\n/** Execute a read-only tool by name. Pure with respect to the reader. */\nexport async function callTool(\n name: string,\n args: Record<string, unknown>,\n reader: McpReader,\n): Promise<ToolResult> {\n switch (name) {\n case 'get_latest_request': {\n const bundle = await reader.latestBundle();\n if (!bundle) return { ok: false, error: 'No request has been submitted yet.' };\n return { ok: true, text: json(bundle) };\n }\n case 'get_session': {\n const session = await reader.getSession(String(args.sessionId));\n if (!session) return { ok: false, error: `Unknown session: ${String(args.sessionId)}` };\n return { ok: true, text: json(session) };\n }\n case 'list_elements': {\n const elements = await resolveElements(reader, args.sessionId as string | undefined);\n if (!elements) return { ok: false, error: 'No session or latest request found.' };\n return { ok: true, text: json(elements) };\n }\n case 'get_element_by_id': {\n const id = Number(args.id);\n const elements = await resolveElements(reader, args.sessionId as string | undefined);\n if (!elements) return { ok: false, error: 'No session or latest request found.' };\n const element = elements.find((e) => e.id === id);\n if (!element) return { ok: false, error: `No element #${id} in this session.` };\n return { ok: true, text: json(element) };\n }\n default:\n return { ok: false, error: `Unknown tool: ${name}` };\n }\n}\n\nasync function resolveElements(\n reader: McpReader,\n sessionId?: string,\n): Promise<CapturedElement[] | undefined> {\n if (sessionId) return (await reader.getSession(sessionId))?.elements;\n return (await reader.latestBundle())?.elements;\n}\n\nfunction json(value: unknown): string {\n return JSON.stringify(value, null, 2);\n}\n","/** The daemon's semantic version, surfaced via /health and MCP. */\nexport const version = '0.1.2';\n"],"mappings":"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","names":["join","json","readFile","rm","writeFile","join","join","rm","writeFile","readFile"]}
|
|
File without changes
|