From 9f041c2d3dcf03b67afbaf58dcdf697fd1deeaef Mon Sep 17 00:00:00 2001 From: eshmeshek Date: Sat, 14 Mar 2026 17:08:08 +0300 Subject: [PATCH] Add CONTEXT.md generation on kisync init Creates a comprehensive context file for AI assistants (Claude Code, Codex) that explains the project structure, script execution model, execQuery usage, query file naming conventions, and available sandbox globals. Co-Authored-By: Claude Opus 4.6 --- src/commands/init.ts | 164 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/src/commands/init.ts b/src/commands/init.ts index 4390372..849ceff 100644 --- a/src/commands/init.ts +++ b/src/commands/init.ts @@ -1,3 +1,5 @@ +import * as fs from 'fs'; +import * as path from 'path'; import * as readline from 'readline'; import chalk from 'chalk'; import { writeConfig, findProjectRoot } from '../config'; @@ -91,11 +93,173 @@ export async function initCommand(): Promise { writeConfig({ host, token }, cwd); + // Write default context file for AI assistants + writeDefaultContext(cwd); + console.log(chalk.green('\nProject initialized successfully!')); console.log(chalk.gray(`Config saved to: ${cwd}/.kisync.json`)); + console.log(chalk.gray(`AI context: ${cwd}/CONTEXT.md`)); console.log(''); console.log('Next steps:'); console.log(` ${chalk.cyan('kisync pull')} — download endpoints from server`); console.log(` ${chalk.cyan('kisync status')} — check what changed`); console.log(` ${chalk.cyan('kisync push')} — upload your changes`); } + +function writeDefaultContext(cwd: string): void { + const contextPath = path.join(cwd, 'CONTEXT.md'); + if (fs.existsSync(contextPath)) return; // don't overwrite + + const content = `# KIS API Builder — Project Context + +This directory contains endpoint definitions synced from a KIS API Builder server via \`kisync\`. + +## Directory Structure + +\`\`\` +project-root/ +├── .kisync.json # connection config (host, token) — DO NOT COMMIT +├── .kisync-state.json # sync state (hashes, timestamps) — DO NOT EDIT +├── CONTEXT.md # this file +├── FolderName/ # API folder +│ ├── _folder.json # folder metadata (id, name, parent_id) +│ └── EndpointName/ # single API endpoint +│ ├── endpoint.json # endpoint metadata (method, path, params, config) +│ ├── query.sql # SQL query (for sql-type endpoints) +│ ├── main.js # JavaScript script (for script-type endpoints) +│ ├── main.py # Python script (for script-type endpoints) +│ ├── request.http # HTTP request definition (for AQL-type endpoints) +│ └── queries/ # named queries used by scripts +│ ├── _index.json # query index (name → file, database binding) +│ ├── get_users.sql # SQL query file +│ └── get_data.http # AQL/HTTP query file +\`\`\` + +## Script Execution Model + +Scripts in \`main.js\` / \`main.py\` are NOT standalone programs. +They run inside an API Builder sandbox with pre-injected globals. + +### IMPORTANT: Do NOT wrap code in functions + +WRONG: +\`\`\`js +function main() { + const result = await execQuery('get_users'); + return result.data; +} +main(); +\`\`\` + +CORRECT — write code directly at the top level: +\`\`\`js +const result = await execQuery('get_users'); +return result.data; +\`\`\` + +The server wraps the code in \`(async function() { })()\` automatically. +A top-level \`return\` statement sets the API response body. + +### Available Globals (JavaScript) + +| Global | Description | +|---|---| +| \`params\` | Object with request parameters (query string + body). Example: \`params.user_id\` | +| \`execQuery(name, extraParams?)\` | Execute a named query from the \`queries/\` folder. Returns \`{ success, data, rowCount, error }\` | +| \`console.log/warn/error/info\` | Captured logs, visible in API Builder UI | +| \`JSON, Date, Math, Array, Object, String, Number, Boolean, RegExp, Map, Set, Promise\` | Standard JS built-ins | +| \`setTimeout(fn, ms)\` | Capped at 30 seconds | +| \`parseInt, parseFloat, isNaN, isFinite\` | Standard utility functions | +| \`encodeURIComponent, decodeURIComponent, encodeURI, decodeURI\` | URL encoding | + +No \`require\`, \`import\`, \`fetch\`, \`fs\`, \`process\`, or \`Buffer\` — the sandbox is isolated. + +### Available Globals (Python) + +| Global | Description | +|---|---| +| \`params\` | Dict with request parameters. Example: \`params["user_id"]\` | +| \`exec_query(name, additional_params=None)\` | Execute a named query. Returns dict \`{ "success", "data", "rowCount", "error" }\` | +| \`json, sys, datetime\` | Pre-imported standard modules | + +Use \`return\` to set the response. The code is wrapped in a function automatically. + +### execQuery / exec_query Explained + +The function \`execQuery\` (JS) or \`exec_query\` (Python) runs a query defined in the \`queries/\` folder. + +Each query file is mapped via \`queries/_index.json\`: +\`\`\`json +[ + { + "name": "get_users", + "database_id": "abc-123", + "file": "get_users.sql" + }, + { + "name": "get_data", + "database_id": "def-456", + "file": "get_data.http", + "type": "aql" + } +] +\`\`\` + +**The \`name\` field is the key** — it's what you pass to \`execQuery("get_users")\`. +The \`file\` field is the corresponding SQL or HTTP file in the \`queries/\` directory. + +SQL queries use \`$paramName\` placeholders that auto-bind from \`params\`: +\`\`\`sql +SELECT * FROM users WHERE id = $user_id AND status = $status +\`\`\` + +You can also pass extra params: +\`\`\`js +const result = await execQuery('get_users', { status: 'active' }); +// result.data — array of rows +// result.success — boolean +// result.rowCount — number of rows +\`\`\` + +### AQL (HTTP) Queries + +\`.http\` files define HTTP requests to external APIs: +\`\`\`http +POST https://example.com/api/patients +Content-Type: application/json + +{ + "name": "{{name}}", + "age": {{age}} +} +\`\`\` + +### endpoint.json Fields + +| Field | Description | +|---|---| +| \`id\` | Server-side UUID — do not change | +| \`name\` | Display name of the endpoint | +| \`method\` | HTTP method: GET, POST, PUT, DELETE | +| \`path\` | URL path, e.g. \`/api/users\` | +| \`execution_type\` | \`"sql"\`, \`"script"\`, or \`"aql"\` | +| \`parameters\` | Array of \`{ name, type, required, default_value, description }\` | +| \`database_name\` | Bound database name (for sql-type) | +| \`database_id\` | Bound database UUID | +| \`updated_at\` | Last server update timestamp — do not change | + +## Sync Workflow + +\`\`\`bash +kisync pull # download from server → local files +# ... edit files ... +kisync status # see what changed locally and on server +kisync push # upload changes (with conflict detection) +\`\`\` + +Conflict detection: if someone else modified an endpoint on the server since your +last pull, \`push\` will warn you. Use \`--force\` to overwrite, or \`pull\` first to merge. +`; + + fs.writeFileSync(contextPath, content, 'utf-8'); +}