@vpxa/aikit 0.1.141 → 0.1.142

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vpxa/aikit",
3
- "version": "0.1.141",
3
+ "version": "0.1.142",
4
4
  "type": "module",
5
5
  "description": "Local-first AI developer toolkit — knowledge base, code analysis, context management, and developer tools for LLM agents",
6
6
  "license": "MIT",
@@ -35,6 +35,7 @@
35
35
  "!scaffold/_preview/",
36
36
  "!scaffold/generate.mjs",
37
37
  "!scaffold/adapters/",
38
+ "!scaffold/generated/",
38
39
  "!scaffold/general/viewers/",
39
40
  "!scaffold/README.md",
40
41
  "README.md",
@@ -0,0 +1,92 @@
1
+ import { BrowserContext, Page } from "playwright-core";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+
4
+ //#region packages/browser/src/types.d.ts
5
+ type BrowserMode = 'ui' | 'headless' | 'panel';
6
+ interface BrowserConfig {
7
+ defaultMode: BrowserMode;
8
+ browsersPath: string | null;
9
+ userDataDirRoot: string | null;
10
+ idleShutdownMinutes: number;
11
+ allowInternalSchemes: boolean;
12
+ evalTimeoutMs: number;
13
+ evalMaxResultBytes: number;
14
+ redactPasswordFieldsInScreenshots: boolean;
15
+ }
16
+ declare const DEFAULT_BROWSER_CONFIG: BrowserConfig;
17
+ interface PageInfo {
18
+ pageId: string;
19
+ url: string;
20
+ title: string;
21
+ createdAt: Date;
22
+ }
23
+ interface SecurityCheckResult {
24
+ allowed: boolean;
25
+ reason?: string;
26
+ }
27
+ interface EvalValidationResult {
28
+ valid: boolean;
29
+ result?: string;
30
+ truncated?: boolean;
31
+ reason?: string;
32
+ }
33
+ //#endregion
34
+ //#region packages/browser/src/session.d.ts
35
+ declare class SessionRegistry {
36
+ private pages;
37
+ registerPage(page: Page, url: string, title: string): string;
38
+ getPage(pageId: string): Page;
39
+ getPageInfo(pageId: string): PageInfo;
40
+ updatePageInfo(pageId: string, url: string, title: string): void;
41
+ removePage(pageId: string): Promise<void>;
42
+ listPages(): PageInfo[];
43
+ closeAll(): Promise<void>;
44
+ get size(): number;
45
+ }
46
+ //#endregion
47
+ //#region packages/browser/src/engine.d.ts
48
+ declare class BrowserEngine {
49
+ private browser;
50
+ private context;
51
+ private idleTimer;
52
+ private launchPromise;
53
+ readonly session: SessionRegistry;
54
+ private config;
55
+ constructor(config?: Partial<BrowserConfig>);
56
+ launch(mode?: BrowserMode, onProgress?: (msg: string) => void): Promise<void>;
57
+ private doLaunch;
58
+ private stopIdleTimer;
59
+ resetIdleTimer(): void;
60
+ close(): Promise<void>;
61
+ getContext(): BrowserContext;
62
+ getConfig(): BrowserConfig;
63
+ isLaunched(): boolean;
64
+ }
65
+ declare function getEngine(config?: Partial<BrowserConfig>): BrowserEngine;
66
+ declare function closeEngine(): Promise<void>;
67
+ //#endregion
68
+ //#region packages/browser/src/install.d.ts
69
+ declare function getDefaultBrowsersPath(): string;
70
+ declare function resolveBrowsersPath(config: BrowserConfig): string;
71
+ declare function isBrowserInstalled(browsersPath: string): boolean;
72
+ declare function ensureBrowserInstalled(config: BrowserConfig, onProgress?: (msg: string) => void): Promise<string>;
73
+ //#endregion
74
+ //#region packages/browser/src/modes.d.ts
75
+ interface LaunchArgs {
76
+ headless: boolean;
77
+ args: string[];
78
+ }
79
+ declare function detectDisplayAvailable(): boolean;
80
+ declare function autoSelectMode(requested: BrowserMode): BrowserMode;
81
+ declare function getLaunchArgs(mode: BrowserMode): LaunchArgs;
82
+ //#endregion
83
+ //#region packages/browser/src/security.d.ts
84
+ declare function isUrlAllowed(url: string, config: BrowserConfig): SecurityCheckResult;
85
+ declare function isCookieAccessAllowed(confirm: boolean): SecurityCheckResult;
86
+ declare function validateEvalResult(result: unknown, maxBytes: number): EvalValidationResult;
87
+ declare function redactPasswordFields(html: string): string;
88
+ //#endregion
89
+ //#region packages/browser/src/tools/index.d.ts
90
+ declare function registerBrowserTools(server: McpServer, config: Record<string, unknown>): void;
91
+ //#endregion
92
+ export { BrowserConfig, BrowserEngine, BrowserMode, DEFAULT_BROWSER_CONFIG, EvalValidationResult, LaunchArgs, PageInfo, SecurityCheckResult, SessionRegistry, autoSelectMode, closeEngine, detectDisplayAvailable, ensureBrowserInstalled, getDefaultBrowsersPath, getEngine, getLaunchArgs, isBrowserInstalled, isCookieAccessAllowed, isUrlAllowed, redactPasswordFields, registerBrowserTools, resolveBrowsersPath, validateEvalResult };
@@ -0,0 +1,10 @@
1
+ import{createRequire as e}from"node:module";import{createHash as t,randomUUID as n}from"node:crypto";import{homedir as r}from"node:os";import{join as i}from"node:path";import{chromium as a}from"playwright-core";import{execFileSync as o}from"node:child_process";import{existsSync as s,readdirSync as c}from"node:fs";import{Buffer as l}from"node:buffer";import{z as u}from"zod";const d=e(import.meta.url);function f(e){return typeof e==`string`?e.trim():e instanceof Buffer?e.toString(`utf8`).trim():``}function p(e){process.env.PLAYWRIGHT_BROWSERS_PATH=e}async function m(e){p(e);let{chromium:t}=await import(`playwright-core`),n=t.executablePath();if(!n)throw Error(`Chromium executable not found in ${e}`);return n}function h(){return i(r(),`.aikit`,`browsers`)}function g(e){return e.browsersPath??process.env.PLAYWRIGHT_BROWSERS_PATH??h()}function _(e){return s(e)?c(e,{withFileTypes:!0}).some(e=>e.isDirectory()&&e.name.toLowerCase().startsWith(`chromium-`)):!1}async function v(e,t){let n=g(e);if(p(n),t?.(`Using Chromium cache at ${n}`),_(n))return t?.(`Chromium already installed`),m(n);let r=d.resolve(`playwright-core/cli.js`);t?.(`Installing Chromium via playwright-core`);try{o(process.execPath,[r,`install`,`chromium`],{env:{...process.env,PLAYWRIGHT_BROWSERS_PATH:n},encoding:`utf8`,stdio:`pipe`})}catch(e){let t=e,n=f(t.stderr),r=f(t.stdout),i=n||r||t.message||`Unknown playwright install failure`;throw Error(`Failed to install Chromium: ${i}`)}return t?.(`Chromium install complete`),m(n)}function y(){return process.platform===`win32`||process.platform===`darwin`?!0:!!(process.env.DISPLAY||process.env.WAYLAND_DISPLAY)}function b(e){return e===`headless`||!y()?`headless`:e}function x(e){switch(e){case`headless`:return{headless:!0,args:[]};case`panel`:return{headless:!1,args:[`--app=data:text/html,<title>aikit</title>`]};default:return{headless:!1,args:[]}}}var S=class{pages=new Map;registerPage(e,t,r){let i=n();return this.pages.set(i,{page:e,url:t,title:r,createdAt:new Date}),i}getPage(e){let t=this.pages.get(e);if(!t)throw Error(`Page not found: ${e}`);return t.page}getPageInfo(e){let t=this.pages.get(e);if(!t)throw Error(`Page not found: ${e}`);return{pageId:e,url:t.url,title:t.title,createdAt:t.createdAt}}updatePageInfo(e,t,n){let r=this.pages.get(e);if(!r)throw Error(`Page not found: ${e}`);this.pages.set(e,{...r,url:t,title:n})}async removePage(e){let t=this.pages.get(e);t&&(await t.page.close(),this.pages.delete(e))}listPages(){return[...this.pages.entries()].map(([e,t])=>({pageId:e,url:t.url,title:t.title,createdAt:t.createdAt}))}async closeAll(){await Promise.allSettled([...this.pages.keys()].map(async e=>this.removePage(e)))}get size(){return this.pages.size}};const C={defaultMode:`ui`,browsersPath:null,userDataDirRoot:null,idleShutdownMinutes:10,allowInternalSchemes:!1,evalTimeoutMs:1e4,evalMaxResultBytes:262144,redactPasswordFieldsInScreenshots:!0};var w=class{browser=null;context=null;idleTimer=null;launchPromise=null;session=new S;config;constructor(e={}){this.config={...C,...e}}async launch(e,t){if(!this.context){if(this.launchPromise)return this.launchPromise;this.launchPromise=this.doLaunch(e,t);try{await this.launchPromise}finally{this.launchPromise=null}}}async doLaunch(e,n){if(this.browser&&this.context)return;let o=b(e??this.config.defaultMode),s=g(this.config);process.env.PLAYWRIGHT_BROWSERS_PATH=s;let c=await v(this.config,n),l=x(o),u=t(`sha256`).update(process.cwd()).digest(`hex`).slice(0,12),d=i(this.config.userDataDirRoot??i(r(),`.aikit`,`profiles`),u);if(n?.(`Launching Chromium in ${o} mode`),this.context=await a.launchPersistentContext(d,{headless:l.headless,args:l.args,executablePath:c}),this.browser=this.context.browser(),!this.browser)throw await this.context.close(),this.context=null,Error(`Failed to acquire Chromium browser instance`);this.browser.on(`disconnected`,()=>{this.browser=null,this.context=null,this.session.closeAll().catch(()=>{}),this.stopIdleTimer()}),this.resetIdleTimer()}stopIdleTimer(){this.idleTimer&&=(clearTimeout(this.idleTimer),null)}resetIdleTimer(){this.stopIdleTimer();let e=setTimeout(()=>{this.close()},this.config.idleShutdownMinutes*6e4);e.unref?.(),this.idleTimer=e}async close(){this.stopIdleTimer(),this.launchPromise=null;let e=this.context,t=this.browser;this.context=null,this.browser=null;let n;try{await this.session.closeAll()}catch(e){n=e}try{e&&await e.close()}catch(e){n??=e}finally{try{t&&await t.close()}catch(e){n??=e}}if(n)throw n}getContext(){if(!this.context)throw Error(`Browser not launched. Call launch() first.`);return this.context}getConfig(){return this.config}isLaunched(){return this.browser!==null}};let T=null;function E(e){return T||=new w(e),T}async function ee(){T&&=(await T.close(),null)}const te=[`file:`,`chrome:`,`chrome-extension:`,`data:`,`javascript:`],ne=[`169.254.169.254`,`metadata.google.internal`,`metadata.google.com`],D=[`localhost`,`127.0.0.1`,`::1`,`[::1]`];function re(e){return e.replace(/^\[(.*)\]$/,`$1`).toLowerCase()}function ie(e){let t=new WeakSet,n=JSON.stringify(e,(e,n)=>{if(typeof n==`bigint`)return n.toString();if(typeof n==`function`)return`[Function ${n.name||`anonymous`}]`;if(typeof n==`symbol`)return n.toString();if(n instanceof Error)return{name:n.name,message:n.message,stack:n.stack};if(typeof n==`object`&&n){if(t.has(n))return`[Circular]`;t.add(n)}return n});return n===void 0?e===void 0?`undefined`:String(e):n}function ae(e,t){let n=l.from(e,`utf8`);return n.byteLength<=t?e:n.subarray(0,t).toString(`utf8`)}function O(e,t){let n;try{n=new URL(e)}catch{return{allowed:!1,reason:`Invalid URL: ${e}`}}let r=n.protocol.toLowerCase();if(te.includes(r)&&!t.allowInternalSchemes)return{allowed:!1,reason:`Blocked URL scheme: ${r}`};let i=re(n.hostname);return ne.includes(i)?{allowed:!1,reason:`Blocked host: ${n.hostname}`}:(D.includes(i)||D.includes(n.hostname),{allowed:!0})}function k(e){return e?{allowed:!0}:{allowed:!1,reason:`Cookie access requires explicit confirmation (confirm: true)`}}function A(e,t){if(t<=0)return{valid:!1,reason:`maxBytes must be greater than 0`};try{let n=ie(e);return l.byteLength(n,`utf8`)<=t?{valid:!0,result:n,truncated:!1}:{valid:!0,result:`${ae(n,Math.max(t-3,0))}...`,truncated:!0,reason:`Result exceeded ${t} bytes and was truncated`}}catch(e){return{valid:!1,reason:`Unable to serialize eval result: ${e instanceof Error?e.message:String(e)}`}}}function oe(e){return e.replace(/<input\b[^>]*>/gi,e=>/\btype\s*=\s*(["'])password\1/i.test(e)?/\bvalue\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/i.test(e)?e.replace(/\bvalue\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/i,`value="***"`):e.replace(/\s*\/?>$/,e=>` value="***"${e}`):e)}const se=[`ui`,`headless`,`panel`];function ce(e){return typeof e==`object`&&e?e:null}function j(e){return typeof e==`string`&&e.length>0?e:void 0}function M(e){return typeof e==`boolean`?e:void 0}function N(e){return typeof e==`number`&&Number.isFinite(e)?e:void 0}function P(e){return typeof e==`string`&&se.includes(e)?e:void 0}function F(e){let t=process.env[e];if(!t)return;let n=Number(t);return Number.isFinite(n)?n:void 0}function le(e){let t=ce(e.browser)??{};return{...C,defaultMode:P(process.env.AIKIT_BROWSER_DEFAULT_MODE)??P(t.defaultMode)??C.defaultMode,browsersPath:j(process.env.AIKIT_BROWSER_PATH)??j(process.env.AIKIT_BROWSER_BROWSERS_PATH)??j(t.browsersPath)??C.browsersPath,userDataDirRoot:j(t.userDataDirRoot)??C.userDataDirRoot,idleShutdownMinutes:F(`AIKIT_BROWSER_IDLE_MINUTES`)??N(t.idleShutdownMinutes)??C.idleShutdownMinutes,allowInternalSchemes:M(t.allowInternalSchemes)??C.allowInternalSchemes,evalTimeoutMs:F(`AIKIT_BROWSER_EVAL_TIMEOUT_MS`)??N(t.evalTimeoutMs)??C.evalTimeoutMs,evalMaxResultBytes:N(t.evalMaxResultBytes)??C.evalMaxResultBytes,redactPasswordFieldsInScreenshots:M(t.redactPasswordFieldsInScreenshots)??C.redactPasswordFieldsInScreenshots}}function I(e,t){return{content:[{type:`text`,text:e}],structuredContent:t}}function L(e,t){let n=e.selector??e.ref;if(!n)throw Error(`${t} requires selector or ref`);return n}function ue(e){if(!e)return`empty snapshot`;let t=[],n=(e,r)=>{let i=[e.role??`node`];e.name&&i.push(e.name),e.value!==void 0&&i.push(`value=${String(e.value)}`),e.description&&i.push(`description=${e.description}`),t.push(`${` `.repeat(r)}${i.join(`: `)}`);for(let t of e.children??[])n(t,r+1)};return n(e,0),t.join(`
2
+ `)}async function R(e,t,n){let r=null;try{return await Promise.race([e,new Promise((e,i)=>{r=setTimeout(()=>{i(Error(`${n} timed out after ${t}ms`))},t)})])}finally{r&&clearTimeout(r)}}u.string().describe(`Tracked browser page identifier`),u.enum([`click`,`type`,`press`,`hover`,`drag`,`select`]).describe(`Interaction kind`),u.string().optional().describe(`Optional target ref alias`),u.string().optional().describe(`Playwright selector for the target element`),u.string().optional().describe(`Human-readable element label`),u.string().optional().describe(`Text to type for kind="type"`),u.string().optional().describe(`Key or chord to press for kind="press"`),u.string().optional().describe(`Option value for kind="select" or drag target selector`),u.string().optional().describe(`Optional drag source ref alias`),u.string().optional().describe(`Optional drag source selector`),u.string().optional().describe(`Optional drag target ref alias`),u.string().optional().describe(`Optional drag target selector`);function de(e){return async({pageId:t,kind:n,ref:r,selector:i,text:a,key:o,value:s,fromRef:c,fromSelector:l,toRef:u,toSelector:d})=>{let f=E(e),p=f.session.getPage(t);switch(n){case`click`:{let e=L({ref:r,selector:i},`browser_act(click)`);await p.click(e);break}case`type`:{let e=L({ref:r,selector:i},`browser_act(type)`);await p.fill(e,a??``);break}case`press`:{let e=L({ref:r,selector:i},`browser_act(press)`);if(!o)throw Error(`browser_act(press) requires key`);await p.press(e,o);break}case`hover`:{let e=L({ref:r,selector:i},`browser_act(hover)`);await p.hover(e);break}case`drag`:{let e=L({ref:c??r,selector:l??i},`browser_act(drag) source`),t=L({ref:u,selector:d??s},`browser_act(drag) target`);await p.dragAndDrop(e,t);break}case`select`:{let e=L({ref:r,selector:i},`browser_act(select)`);if(s===void 0)throw Error(`browser_act(select) requires value`);await p.selectOption(e,s);break}}return f.resetIdleTimer(),I(`ok`,{ok:!0})}}u.string().describe(`Tracked browser page identifier`),u.boolean().describe(`Whether to accept the next dialog`),u.string().optional().describe(`Text to provide when accepting a prompt dialog`);function fe(e){return async({pageId:t,accept:n,promptText:r})=>{let i=E(e);return i.session.getPage(t).once(`dialog`,async e=>{n?await e.accept(r):await e.dismiss()}),i.resetIdleTimer(),I(`ok`,{ok:!0})}}u.string().describe(`Tracked browser page identifier`),u.string().describe(`JavaScript expression or function source evaluated in the page`),u.number().min(1).max(6e4).optional().describe(`Optional evaluation timeout`);function z(e){return async({pageId:t,code:n,timeoutMs:r})=>{let i=E(e),a=i.session.getPage(t),o=Math.min(r??e.evalTimeoutMs,6e4),s=A(await R(a.evaluate(e=>{let t=Function(`return (${e});`)();return typeof t==`function`?t():t},n),o,`browser_eval`),e.evalMaxResultBytes);if(!s.valid||s.result===void 0)throw Error(s.reason??`browser_eval result validation failed`);return i.resetIdleTimer(),I(s.result,{pageId:t,result:s.result,truncated:s.truncated??!1,reason:s.reason})}}u.string().describe(`Tracked browser page identifier`),u.string().url().optional().describe(`Optional URL to navigate to`),u.enum([`back`,`forward`,`reload`,`waitFor`]).optional().describe(`Navigation helper action`),u.string().optional().describe(`Selector to wait for when type="waitFor"`),u.number().min(1).max(6e4).optional().describe(`Optional wait timeout`);function B(e){return async({pageId:t,url:n,type:r,selector:i,timeoutMs:a})=>{let o=E(e),s=o.session.getPage(t);if(n){let r=O(n,e);if(!r.allowed)return I(`Navigation blocked: ${r.reason}`,{blocked:!0,pageId:t,reason:r.reason});await s.goto(n)}else if(!r)return I(`Navigation requires url or type`,{error:`Navigation requires url or type`,pageId:t});else if(r===`back`)await s.goBack();else if(r===`forward`)await s.goForward();else if(r===`reload`)await s.reload();else if(r===`waitFor`){if(!i)throw Error(`browser_navigate(waitFor) requires selector`);await s.waitForSelector(i,a?{timeout:a}:void 0)}let c=s.url(),l=await s.title();return o.session.updatePageInfo(t,c,l),o.resetIdleTimer(),I(`${l||c}\n${c}`,{pageId:t,url:c,title:l})}}u.string().url().describe(`Absolute URL to open`),u.enum([`ui`,`headless`,`panel`]).optional().describe(`Browser launch mode`),u.boolean().optional().describe(`Reserved for future tab reuse control`),u.enum([`load`,`domcontentloaded`,`networkidle`]).optional().describe(`Navigation readiness event`);function pe(e){return async({url:t,mode:n,waitUntil:r})=>{let i=O(t,e);if(!i.allowed)throw Error(i.reason??`Blocked URL: ${t}`);let a=E(e);a.isLaunched()||await a.launch(n??e.defaultMode);let o=await a.getContext().newPage();r?await o.goto(t,{waitUntil:r}):await o.goto(t);let s=await o.title(),c=a.session.registerPage(o,t,s);return a.resetIdleTimer(),I(`Opened ${s||t}\npageId: ${c}`,{pageId:c,url:t,title:s})}}u.string().describe(`Tracked browser page identifier`);function me(e){return async({pageId:t})=>{let n=await E(e).session.getPage(t).accessibility.snapshot(),r=ue(n);return I(r,{pageId:t,snapshot:n,text:r})}}u.string().describe(`Tracked browser page identifier`),u.string().optional().describe(`Optional target ref alias`),u.string().optional().describe(`Optional target selector`),u.boolean().optional().describe(`Capture the full page when no selector is provided`),u.boolean().optional().describe(`Mask password fields before capture`);function he(e){return async({pageId:t,ref:n,selector:r,fullPage:i,redactPasswords:a})=>{let o=E(e),s=o.session.getPage(t),c=a??e.redactPasswordFieldsInScreenshots,l=[];c&&(l=await s.evaluate(()=>{let e=globalThis.document;return Array.from(e.querySelectorAll(`input[type="password"]`)).map((e,t)=>{let n=e,r=`data-aikit-password-mask-${t}`;return n.setAttribute(r,n.value),n.value=`***`,r})}));try{let e=r??n?await s.locator(L({ref:n,selector:r},`browser_screenshot`)).screenshot():await s.screenshot({fullPage:i??!1});return o.resetIdleTimer(),I(`Screenshot captured`,{pageId:t,base64:e.toString(`base64`)})}finally{c&&l.length>0&&await s.evaluate(e=>{let t=globalThis.document;for(let n of e){let e=t.querySelector(`input[${n}]`);e&&(e.value=e.getAttribute(n)??``,e.removeAttribute(n))}},l)}}}u.enum([`list`,`close`,`cookies`]).describe(`Browser session action`),u.string().optional().describe(`Optional tracked page identifier`),u.boolean().optional().describe(`Explicit confirmation required for cookie export`);function ge(e){return async({action:t,pageId:n,confirm:r})=>{let i=E(e);if(t===`list`){let e=i.session.listPages();return I(JSON.stringify(e,null,2),{pages:e})}if(t===`close`){if(!n)throw Error(`browser_session(close) requires pageId`);return await i.session.removePage(n),i.resetIdleTimer(),I(`ok`,{ok:!0,pageId:n})}let a=k(!!r);if(!a.allowed)throw Error(a.reason??`Cookie access denied`);let o=await i.getContext().cookies();return i.resetIdleTimer(),I(JSON.stringify(o,null,2),{cookies:o})}}const V=[`open`,`read`,`act`,`navigate`,`eval`,`screenshot`,`dialog`,`session`],H=[`ui`,`headless`,`panel`],U=[`load`,`domcontentloaded`,`networkidle`],W=[`click`,`type`,`press`,`hover`,`drag`,`select`],G=[`back`,`forward`,`reload`,`waitFor`],K=[`list`,`close`,`cookies`],_e={action:u.enum(V).describe(`Browser action to perform`),pageId:u.string().optional().describe(`Tracked browser page identifier`),url:u.string().url().optional().describe(`URL to open or navigate to`),mode:u.enum(H).optional().describe(`Browser launch mode (open only)`),forceNew:u.boolean().optional().describe(`Reserved for future tab reuse`),waitUntil:u.enum(U).optional().describe(`Navigation readiness event`),kind:u.enum(W).optional().describe(`Interaction kind (act only)`),ref:u.string().optional().describe(`Target ref alias`),selector:u.string().optional().describe(`Playwright selector`),element:u.string().optional().describe(`Human-readable element label`),text:u.string().optional().describe(`Text to type`),key:u.string().optional().describe(`Key to press`),value:u.string().optional().describe(`Option value or drag target`),fromRef:u.string().optional().describe(`Drag source ref`),fromSelector:u.string().optional().describe(`Drag source selector`),toRef:u.string().optional().describe(`Drag target ref`),toSelector:u.string().optional().describe(`Drag target selector`),type:u.enum(G).optional().describe(`Navigation type`),code:u.string().optional().describe(`JavaScript to evaluate in the page`),timeoutMs:u.number().min(1).max(6e4).optional().describe(`Timeout in milliseconds`),fullPage:u.boolean().optional().describe(`Capture full page`),redactPasswords:u.boolean().optional().describe(`Mask password fields`),accept:u.boolean().optional().describe(`Accept or dismiss dialog`),promptText:u.string().optional().describe(`Text for prompt dialog`),sessionAction:u.enum(K).optional().describe(`Session sub-action (session only)`),confirm:u.boolean().optional().describe(`Explicit confirmation for cookie export`)};function q(e,t){return typeof e==`string`&&t.includes(e)}function J(e,t,n){let r=e[t];if(typeof r!=`string`)throw Error(`${n} requires ${t}`);return r}function ve(e,t,n){let r=e[t];if(typeof r!=`boolean`)throw Error(`${n} requires ${t}`);return r}function Y(e,t){let n=e[t];return typeof n==`string`?n:void 0}function X(e,t){let n=e[t];return typeof n==`boolean`?n:void 0}function Z(e,t){let n=e[t];return typeof n==`number`?n:void 0}function Q(e,t,n,r){let i=e[t];if(!q(i,n))throw Error(`${r} requires ${t}`);return i}function $(e,t,n,r){let i=e[t];if(i!==void 0){if(!q(i,n))throw Error(`${r} received invalid ${t}`);return i}}function ye(e,t){let n=le(t),r=pe(n),i=me(n),a=de(n),o=B(n),s=z(n),c=he(n),l=fe(n),u=ge(n);e.registerTool(`browser`,{title:`Browser Automation`,description:`Unified browser automation tool. Actions:
3
+ - open: Launch a browser page (url required, mode/waitUntil optional)
4
+ - read: Get accessibility snapshot of a page (pageId required)
5
+ - act: Interact with elements — click/type/press/hover/drag/select (pageId + kind required)
6
+ - navigate: Go to URL, back/forward/reload, or waitFor selector (pageId required)
7
+ - eval: Evaluate JavaScript in page context (pageId + code required)
8
+ - screenshot: Capture page or element screenshot (pageId required)
9
+ - dialog: Accept or dismiss next browser dialog (pageId + accept required)
10
+ - session: List pages, close a page, or export cookies (sessionAction required)`,inputSchema:_e,annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!0}},async e=>{switch(Q(e,`action`,V,`browser`)){case`open`:return r({url:J(e,`url`,`browser(open)`),mode:$(e,`mode`,H,`browser(open)`),forceNew:X(e,`forceNew`),waitUntil:$(e,`waitUntil`,U,`browser(open)`)});case`read`:return i({pageId:J(e,`pageId`,`browser(read)`)});case`act`:return a({pageId:J(e,`pageId`,`browser(act)`),kind:Q(e,`kind`,W,`browser(act)`),ref:Y(e,`ref`),selector:Y(e,`selector`),element:Y(e,`element`),text:Y(e,`text`),key:Y(e,`key`),value:Y(e,`value`),fromRef:Y(e,`fromRef`),fromSelector:Y(e,`fromSelector`),toRef:Y(e,`toRef`),toSelector:Y(e,`toSelector`)});case`navigate`:return o({pageId:J(e,`pageId`,`browser(navigate)`),url:Y(e,`url`),type:$(e,`type`,G,`browser(navigate)`),selector:Y(e,`selector`),timeoutMs:Z(e,`timeoutMs`)});case`eval`:return s({pageId:J(e,`pageId`,`browser(eval)`),code:J(e,`code`,`browser(eval)`),timeoutMs:Z(e,`timeoutMs`)});case`screenshot`:return c({pageId:J(e,`pageId`,`browser(screenshot)`),ref:Y(e,`ref`),selector:Y(e,`selector`),fullPage:X(e,`fullPage`),redactPasswords:X(e,`redactPasswords`)});case`dialog`:return l({pageId:J(e,`pageId`,`browser(dialog)`),accept:ve(e,`accept`,`browser(dialog)`),promptText:Y(e,`promptText`)});case`session`:return u({action:Q(e,`sessionAction`,K,`browser(session)`),pageId:Y(e,`pageId`),confirm:X(e,`confirm`)})}})}export{w as BrowserEngine,C as DEFAULT_BROWSER_CONFIG,S as SessionRegistry,b as autoSelectMode,ee as closeEngine,y as detectDisplayAvailable,v as ensureBrowserInstalled,h as getDefaultBrowsersPath,E as getEngine,x as getLaunchArgs,_ as isBrowserInstalled,k as isCookieAccessAllowed,O as isUrlAllowed,oe as redactPasswordFields,ye as registerBrowserTools,g as resolveBrowsersPath,A as validateEvalResult};
@@ -1 +1 @@
1
- import{t as e}from"./curated-manager-BkSgtNC2.js";import{readFileSync as t}from"node:fs";import{dirname as n,resolve as r}from"node:path";import{fileURLToPath as i,pathToFileURL as a}from"node:url";import{parseArgs as o}from"node:util";import{createLogger as s,serializeError as c}from"../../core/dist/index.js";const l=n(i(import.meta.url)),u=(()=>{try{let e=r(l,`..`,`..`,`..`,`package.json`);return JSON.parse(t(e,`utf-8`)).version??`0.0.0`}catch{return`0.0.0`}})(),d=s(`server`);function f(){return process.env.AIKIT_TRANSPORT?process.env.AIKIT_TRANSPORT:process.stdin.isTTY?`http`:`stdio`}const{values:p}=(()=>{let e=process.argv[1];if(!e)return!1;try{return import.meta.url===a(e).href}catch{return!1}})()?o({allowPositionals:!0,options:{transport:{type:`string`,default:f()},port:{type:`string`,default:process.env.AIKIT_PORT??`3210`}}}):{values:{transport:f(),port:process.env.AIKIT_PORT??`3210`}};async function m(){if(process.on(`unhandledRejection`,e=>{d.error(`Unhandled rejection`,c(e))}),process.on(`uncaughtException`,e=>{d.error(`Uncaught exception — exiting`,c(e)),process.exit(1)}),d.info(`Starting MCP AI Kit server`,{version:u}),p.transport===`http`){let[{default:e},{loadConfig:t,resolveIndexMode:n},{registerDashboardRoutes:r,resolveDashboardDir:i},{registerSettingsRoutes:a,resolveSettingsDir:o},{createSettingsRouter:s}]=await Promise.all([import(`express`),import(`./config-D4z6-EcI.js`),import(`./dashboard-static-BfIe0Si1.js`),import(`./settings-static-BosGZSPf.js`),import(`./routes-OaSHcA6x.js`)]),l=t();d.info(`Config loaded`,{sourceCount:l.sources.length,storePath:l.store.path});let u=e();u.use(e.json());let f=Number(p.port);u.use((e,t,n)=>{if(t.setHeader(`Access-Control-Allow-Origin`,process.env.AIKIT_CORS_ORIGIN??`http://localhost:${f}`),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, PUT, PATCH, DELETE, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization`),e.method===`OPTIONS`){t.status(204).end();return}n()}),r(u,i(),d);let m=new Date().toISOString();u.use(`/settings/api`,s({log:d,mcpInfo:()=>({transport:`http`,port:f,pid:process.pid,startedAt:m})})),a(u,o(),d),u.get(`/health`,(e,t)=>{t.json({status:`ok`})});let h=!1,g=null,_=null,v=null,y=Promise.resolve();u.post(`/mcp`,async(e,t)=>{if(!h||!_||!v){t.status(503).json({jsonrpc:`2.0`,error:{code:-32603,message:`Server initializing — please retry in a few seconds`},id:null});return}let n=y,r;y=new Promise(e=>{r=e}),await n;try{let n=new v({sessionIdGenerator:void 0});await _.connect(n),await n.handleRequest(e,t,e.body),n.close()}catch(e){if(d.error(`MCP handler error`,c(e)),!t.headersSent){let n=e instanceof Error?e.message:String(e),r=n.includes(`Not Acceptable`);t.status(r?406:500).json({jsonrpc:`2.0`,error:{code:r?-32e3:-32603,message:r?n:`Internal server error`},id:null})}}finally{r()}}),u.get(`/mcp`,(e,t)=>{t.writeHead(405).end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not allowed.`},id:null}))}),u.delete(`/mcp`,(e,t)=>{t.writeHead(405).end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not allowed.`},id:null}))});let b=u.listen(f,`127.0.0.1`,()=>{d.info(`MCP server listening`,{url:`http://127.0.0.1:${f}/mcp`,port:f}),setTimeout(async()=>{try{let[{createLazyServer:e,ALL_TOOL_NAMES:t},{StreamableHTTPServerTransport:r},{checkForUpdates:i,autoUpgradeScaffold:a}]=await Promise.all([import(`./server-DmbZccrE.js`),import(`@modelcontextprotocol/sdk/server/streamableHttp.js`),import(`./version-check-Bj07vc5x.js`)]);i(),a();let o=n(l),s=e(l,o);_=s.server,v=r,h=!0,d.info(`MCP server configured (lazy — AI Kit initializing in background)`,{toolCount:t.length,resourceCount:2}),s.startInit(),o===`auto`?s.ready.then(async()=>{try{let e=l.sources.map(e=>e.path).join(`, `);d.info(`Running initial index`,{sourcePaths:e}),await s.runInitialIndex(),d.info(`Initial index complete`)}catch(e){d.error(`Initial index failed; will retry on aikit_reindex`,c(e))}}).catch(e=>d.error(`AI Kit init or indexing failed`,c(e))):o===`smart`?s.ready.then(async()=>{try{if(!s.aikit)throw Error(`AI Kit components are not available after initialization`);let{SmartIndexScheduler:e}=await import(`../../indexer/dist/index.js`),t=new e(s.aikit.indexer,l,s.aikit.store),n=s.aikit.store;g=t,t.start(),n.onBeforeClose&&n.onBeforeClose(()=>t.stop()),s.setSmartScheduler(t),d.info(`Smart index scheduler started (HTTP mode)`)}catch(e){d.error(`Failed to start smart index scheduler`,c(e))}}).catch(e=>d.error(`AI Kit initialization failed`,c(e))):(s.ready.catch(e=>d.error(`AI Kit initialization failed`,c(e))),d.info(`Initial full indexing skipped in HTTP mode`,{indexMode:o}))}catch(e){d.error(`Failed to load server modules`,c(e))}},100)}),x=async e=>{d.info(`Shutdown signal received`,{signal:e}),g?.stop(),b.close(),_&&await _.close(),process.exit(0)};process.on(`SIGINT`,()=>x(`SIGINT`)),process.on(`SIGTERM`,()=>x(`SIGTERM`))}else{let[{loadConfig:e,reconfigureForWorkspace:t,resolveIndexMode:n},{createLazyServer:r},{checkForUpdates:a,autoUpgradeScaffold:o},{RootsListChangedNotificationSchema:s}]=await Promise.all([import(`./config-D4z6-EcI.js`),import(`./server-DmbZccrE.js`),import(`./version-check-Bj07vc5x.js`),import(`@modelcontextprotocol/sdk/types.js`)]),l=e();d.info(`Config loaded`,{sourceCount:l.sources.length,storePath:l.store.path}),a(),o();let u=n(l),f=r(l,u),{server:p,startInit:m,ready:h,runInitialIndex:g}=f,{StdioServerTransport:_}=await import(`@modelcontextprotocol/sdk/server/stdio.js`),v=new _;await p.connect(v),d.info(`MCP server started`,{transport:`stdio`});let y=e=>{if(e.length===0)return!1;let n=e[0].uri,r=n.startsWith(`file://`)?i(n):n;return d.info(`MCP roots resolved`,{rootUri:n,rootPath:r,rootCount:e.length}),t(l,r),l.allRoots=e.map(e=>{let t=e.uri;return t.startsWith(`file://`)?i(t):t}),!0},b=!1;try{b=y((await p.server.listRoots()).roots),b||d.info(`No MCP roots yet; waiting for roots/list_changed notification`)}catch(e){d.warn(`MCP roots/list not supported by client; using cwd fallback`,{cwd:process.cwd(),...c(e)}),b=!0}b||=await new Promise(e=>{let t=setTimeout(()=>{d.warn(`Timed out waiting for MCP roots/list_changed; using cwd fallback`,{cwd:process.cwd()}),e(!1)},5e3);p.server.setNotificationHandler(s,async()=>{clearTimeout(t);try{e(y((await p.server.listRoots()).roots))}catch(t){d.warn(`roots/list retry failed after notification`,c(t)),e(!1)}})}),m();let x=null,S=()=>{x&&clearTimeout(x),x=setTimeout(async()=>{d.info(`Auto-shutdown: no activity for 30 minutes — shutting down gracefully`);try{let e=f.aikit;e&&await Promise.all([e.embedder.shutdown?.().catch(()=>{})??Promise.resolve(),e.graphStore.close().catch(()=>{}),e.store.close().catch(()=>{})])}catch{}process.exit(0)},18e5),x.unref&&x.unref()};S(),process.stdin.on(`data`,()=>S()),h.catch(e=>{d.error(`Initialization failed — server will continue with limited tools`,c(e))}),u===`auto`?g().catch(e=>d.error(`Initial index failed`,c(e))):u===`smart`?h.then(async()=>{try{if(!f.aikit)throw Error(`AI Kit components are not available after initialization`);let{SmartIndexScheduler:e}=await import(`../../indexer/dist/index.js`),t=new e(f.aikit.indexer,l,f.aikit.store),n=f.aikit.store;t.start(),n.onBeforeClose&&n.onBeforeClose(()=>t.stop()),f.setSmartScheduler(t),d.info(`Smart index scheduler started (stdio mode)`)}catch(e){d.error(`Failed to start smart index scheduler`,c(e))}}).catch(e=>d.error(`AI Kit init failed for smart scheduler`,c(e))):d.warn(`Initial full indexing skipped; use aikit_reindex to index manually`,{indexMode:u})}}m().catch(e=>{d.error(`Fatal error`,c(e)),process.exit(1)});export{e as CuratedKnowledgeManager};
1
+ import{t as e}from"./curated-manager-BkSgtNC2.js";import{readFileSync as t}from"node:fs";import{dirname as n,resolve as r}from"node:path";import{fileURLToPath as i,pathToFileURL as a}from"node:url";import{parseArgs as o}from"node:util";import{createLogger as s,serializeError as c}from"../../core/dist/index.js";const l=n(i(import.meta.url)),u=(()=>{try{let e=r(l,`..`,`..`,`..`,`package.json`);return JSON.parse(t(e,`utf-8`)).version??`0.0.0`}catch{return`0.0.0`}})(),d=s(`server`);function f(){return process.env.AIKIT_TRANSPORT?process.env.AIKIT_TRANSPORT:process.stdin.isTTY?`http`:`stdio`}const{values:p}=(()=>{let e=process.argv[1];if(!e)return!1;try{return import.meta.url===a(e).href}catch{return!1}})()?o({allowPositionals:!0,options:{transport:{type:`string`,default:f()},port:{type:`string`,default:process.env.AIKIT_PORT??`3210`}}}):{values:{transport:f(),port:process.env.AIKIT_PORT??`3210`}};async function m(){if(process.on(`unhandledRejection`,e=>{d.error(`Unhandled rejection`,c(e))}),process.on(`uncaughtException`,e=>{d.error(`Uncaught exception — exiting`,c(e)),process.exit(1)}),d.info(`Starting MCP AI Kit server`,{version:u}),p.transport===`http`){let[{default:e},{loadConfig:t,resolveIndexMode:n},{registerDashboardRoutes:r,resolveDashboardDir:i},{registerSettingsRoutes:a,resolveSettingsDir:o},{createSettingsRouter:s}]=await Promise.all([import(`express`),import(`./config-D4z6-EcI.js`),import(`./dashboard-static-BfIe0Si1.js`),import(`./settings-static-BosGZSPf.js`),import(`./routes-gbC5Wmr9.js`)]),l=t();d.info(`Config loaded`,{sourceCount:l.sources.length,storePath:l.store.path});let u=e();u.use(e.json());let f=Number(p.port);u.use((e,t,n)=>{if(t.setHeader(`Access-Control-Allow-Origin`,process.env.AIKIT_CORS_ORIGIN??`http://localhost:${f}`),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, PUT, PATCH, DELETE, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization`),e.method===`OPTIONS`){t.status(204).end();return}n()}),r(u,i(),d);let m=new Date().toISOString();u.use(`/settings/api`,s({log:d,mcpInfo:()=>({transport:`http`,port:f,pid:process.pid,startedAt:m})})),a(u,o(),d),u.get(`/health`,(e,t)=>{t.json({status:`ok`})});let h=!1,g=null,_=null,v=null,y=Promise.resolve();u.post(`/mcp`,async(e,t)=>{if(!h||!_||!v){t.status(503).json({jsonrpc:`2.0`,error:{code:-32603,message:`Server initializing — please retry in a few seconds`},id:null});return}let n=y,r;y=new Promise(e=>{r=e}),await n;try{let n=new v({sessionIdGenerator:void 0});await _.connect(n),await n.handleRequest(e,t,e.body),n.close()}catch(e){if(d.error(`MCP handler error`,c(e)),!t.headersSent){let n=e instanceof Error?e.message:String(e),r=n.includes(`Not Acceptable`);t.status(r?406:500).json({jsonrpc:`2.0`,error:{code:r?-32e3:-32603,message:r?n:`Internal server error`},id:null})}}finally{r()}}),u.get(`/mcp`,(e,t)=>{t.writeHead(405).end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not allowed.`},id:null}))}),u.delete(`/mcp`,(e,t)=>{t.writeHead(405).end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32e3,message:`Method not allowed.`},id:null}))});let b=u.listen(f,`127.0.0.1`,()=>{d.info(`MCP server listening`,{url:`http://127.0.0.1:${f}/mcp`,port:f}),setTimeout(async()=>{try{let[{createLazyServer:e,ALL_TOOL_NAMES:t},{StreamableHTTPServerTransport:r},{checkForUpdates:i,autoUpgradeScaffold:a}]=await Promise.all([import(`./server-Mioq3dZQ.js`),import(`@modelcontextprotocol/sdk/server/streamableHttp.js`),import(`./version-check-Bj07vc5x.js`)]);i(),a();let o=n(l),s=e(l,o);_=s.server,v=r,h=!0,d.info(`MCP server configured (lazy — AI Kit initializing in background)`,{toolCount:t.length,resourceCount:2}),s.startInit(),o===`auto`?s.ready.then(async()=>{try{let e=l.sources.map(e=>e.path).join(`, `);d.info(`Running initial index`,{sourcePaths:e}),await s.runInitialIndex(),d.info(`Initial index complete`)}catch(e){d.error(`Initial index failed; will retry on aikit_reindex`,c(e))}}).catch(e=>d.error(`AI Kit init or indexing failed`,c(e))):o===`smart`?s.ready.then(async()=>{try{if(!s.aikit)throw Error(`AI Kit components are not available after initialization`);let{SmartIndexScheduler:e}=await import(`../../indexer/dist/index.js`),t=new e(s.aikit.indexer,l,s.aikit.store),n=s.aikit.store;g=t,t.start(),n.onBeforeClose&&n.onBeforeClose(()=>t.stop()),s.setSmartScheduler(t),d.info(`Smart index scheduler started (HTTP mode)`)}catch(e){d.error(`Failed to start smart index scheduler`,c(e))}}).catch(e=>d.error(`AI Kit initialization failed`,c(e))):(s.ready.catch(e=>d.error(`AI Kit initialization failed`,c(e))),d.info(`Initial full indexing skipped in HTTP mode`,{indexMode:o}))}catch(e){d.error(`Failed to load server modules`,c(e))}},100)}),x=async e=>{d.info(`Shutdown signal received`,{signal:e}),g?.stop(),b.close(),_&&await _.close(),process.exit(0)};process.on(`SIGINT`,()=>x(`SIGINT`)),process.on(`SIGTERM`,()=>x(`SIGTERM`))}else{let[{loadConfig:e,reconfigureForWorkspace:t,resolveIndexMode:n},{createLazyServer:r},{checkForUpdates:a,autoUpgradeScaffold:o},{RootsListChangedNotificationSchema:s}]=await Promise.all([import(`./config-D4z6-EcI.js`),import(`./server-Mioq3dZQ.js`),import(`./version-check-Bj07vc5x.js`),import(`@modelcontextprotocol/sdk/types.js`)]),l=e();d.info(`Config loaded`,{sourceCount:l.sources.length,storePath:l.store.path}),a(),o();let u=n(l),f=r(l,u),{server:p,startInit:m,ready:h,runInitialIndex:g}=f,{StdioServerTransport:_}=await import(`@modelcontextprotocol/sdk/server/stdio.js`),v=new _;await p.connect(v),d.info(`MCP server started`,{transport:`stdio`});let y=e=>{if(e.length===0)return!1;let n=e[0].uri,r=n.startsWith(`file://`)?i(n):n;return d.info(`MCP roots resolved`,{rootUri:n,rootPath:r,rootCount:e.length}),t(l,r),l.allRoots=e.map(e=>{let t=e.uri;return t.startsWith(`file://`)?i(t):t}),!0},b=!1;try{b=y((await p.server.listRoots()).roots),b||d.info(`No MCP roots yet; waiting for roots/list_changed notification`)}catch(e){d.warn(`MCP roots/list not supported by client; using cwd fallback`,{cwd:process.cwd(),...c(e)}),b=!0}b||=await new Promise(e=>{let t=setTimeout(()=>{d.warn(`Timed out waiting for MCP roots/list_changed; using cwd fallback`,{cwd:process.cwd()}),e(!1)},5e3);p.server.setNotificationHandler(s,async()=>{clearTimeout(t);try{e(y((await p.server.listRoots()).roots))}catch(t){d.warn(`roots/list retry failed after notification`,c(t)),e(!1)}})}),m();let x=null,S=()=>{x&&clearTimeout(x),x=setTimeout(async()=>{d.info(`Auto-shutdown: no activity for 30 minutes — shutting down gracefully`);try{let e=f.aikit;e&&await Promise.all([e.embedder.shutdown?.().catch(()=>{})??Promise.resolve(),e.graphStore.close().catch(()=>{}),e.store.close().catch(()=>{})])}catch{}process.exit(0)},18e5),x.unref&&x.unref()};S(),process.stdin.on(`data`,()=>S()),h.catch(e=>{d.error(`Initialization failed — server will continue with limited tools`,c(e))}),u===`auto`?g().catch(e=>d.error(`Initial index failed`,c(e))):u===`smart`?h.then(async()=>{try{if(!f.aikit)throw Error(`AI Kit components are not available after initialization`);let{SmartIndexScheduler:e}=await import(`../../indexer/dist/index.js`),t=new e(f.aikit.indexer,l,f.aikit.store),n=f.aikit.store;t.start(),n.onBeforeClose&&n.onBeforeClose(()=>t.stop()),f.setSmartScheduler(t),d.info(`Smart index scheduler started (stdio mode)`)}catch(e){d.error(`Failed to start smart index scheduler`,c(e))}}).catch(e=>d.error(`AI Kit init failed for smart scheduler`,c(e))):d.warn(`Initial full indexing skipped; use aikit_reindex to index manually`,{indexMode:u})}}m().catch(e=>{d.error(`Fatal error`,c(e)),process.exit(1)});export{e as CuratedKnowledgeManager};
@@ -1,4 +1,4 @@
1
- import{existsSync as e,mkdirSync as t,readFileSync as n,renameSync as r,writeFileSync as i}from"node:fs";import{dirname as a,resolve as o}from"node:path";import{getGlobalDataDir as s,isUserInstalled as c}from"../../core/dist/index.js";import{z as l}from"zod";import{Router as u}from"express";const d=[{key:`serverName`,type:`string`,default:`aikit`,description:`MCP server name advertised to clients.`,group:`general`,requiresRestart:!0},{key:`toolPrefix`,type:`string`,default:``,description:`Prefix prepended to every MCP tool name (e.g. "aikit_").`,group:`general`,requiresRestart:!0},{key:`toolProfile`,type:`string`,default:`full`,description:`Active tool profile.`,group:`general`,enum:[`full`,`safe`,`research`,`minimal`,`discovery`],requiresRestart:!0},{key:`autoIndex`,type:`boolean`,default:!1,description:`Deprecated. Prefer indexMode. true → auto, false → manual.`,group:`indexing`},{key:`indexMode`,type:`string`,default:`smart`,description:`Indexing strategy. auto = full on startup, manual = on demand, smart = on-demand + idle.`,group:`indexing`,enum:[`auto`,`manual`,`smart`]},{key:`sources`,type:`array`,description:`Source roots to index. Each entry has { path, excludePatterns }.`,group:`indexing`,requiresRestart:!0},{key:`indexing.chunkSize`,type:`number`,default:1500,description:`Maximum chunk size in characters.`,group:`indexing`},{key:`indexing.chunkOverlap`,type:`number`,default:200,description:`Overlap between adjacent chunks.`,group:`indexing`},{key:`indexing.minChunkSize`,type:`number`,default:100,description:`Minimum chunk size before merging into the next chunk.`,group:`indexing`},{key:`indexing.concurrency`,type:`number`,description:`Max files processed concurrently. Defaults to half of CPU cores.`,group:`indexing`},{key:`embedding.model`,type:`string`,default:`mixedbread-ai/mxbai-embed-large-v1`,description:`Embedding model identifier.`,group:`embedding`,requiresRestart:!0},{key:`embedding.dimensions`,type:`number`,default:1024,description:`Embedding vector dimensions. Must match the model.`,group:`embedding`,requiresRestart:!0},{key:`store.backend`,type:`string`,default:`sqlite-vec`,description:`Vector store backend (sqlite-vec | lancedb).`,group:`store`,requiresRestart:!0},{key:`store.path`,type:`string`,description:`Filesystem path for the vector store.`,group:`store`,requiresRestart:!0},{key:`curated.path`,type:`string`,description:`Path to curated knowledge directory.`,group:`store`,requiresRestart:!0},{key:`onboardDir`,type:`string`,description:`Directory for onboard / produce_knowledge output.`,group:`store`,requiresRestart:!0},{key:`stateDir`,type:`string`,description:`Directory for session state (stash, checkpoints, etc.).`,group:`store`,requiresRestart:!0},{key:`er.enabled`,type:`boolean`,default:!1,description:`Enable enterprise RAG bridge integration.`,group:`enterprise-bridge`,requiresRestart:!0},{key:`er.baseUrl`,type:`string`,description:`Base URL of the ER API.`,group:`enterprise-bridge`,requiresRestart:!0},{key:`er.timeoutMs`,type:`number`,default:5e3,description:`ER request timeout in milliseconds.`,group:`enterprise-bridge`},{key:`er.fallbackThreshold`,type:`number`,default:.45,description:`Vector similarity threshold below which ER fallback triggers.`,group:`enterprise-bridge`}],f=[{key:`AIKIT_TRANSPORT`,type:`string`,default:`stdio`,description:`MCP transport mode.`,group:`transport`,enum:[`stdio`,`http`],defaultScope:`workspace`},{key:`AIKIT_PORT`,type:`string`,default:`3210`,description:`HTTP port when transport = http.`,group:`transport`,defaultScope:`workspace`},{key:`AIKIT_CORS_ORIGIN`,type:`string`,description:`CORS Access-Control-Allow-Origin header for HTTP mode.`,group:`transport`,defaultScope:`workspace`},{key:`AIKIT_CONFIG_PATH`,type:`string`,description:`Override path to aikit.config.json.`,group:`paths`,defaultScope:`workspace`},{key:`AIKIT_WORKSPACE_ROOT`,type:`string`,description:`Override workspace root used when no config file is present.`,group:`paths`,defaultScope:`workspace`},{key:`AIKIT_GLOBAL_DATA_DIR`,type:`string`,description:`Override global data directory (default: ~/.aikit-data).`,group:`paths`,defaultScope:`global`},{key:`AIKIT_INDEX_MODE`,type:`string`,description:`Override config indexMode.`,group:`indexing`,enum:[`auto`,`manual`,`smart`],defaultScope:`workspace`},{key:`AIKIT_AUTO_INDEX`,type:`string`,description:`Legacy boolean override. Prefer AIKIT_INDEX_MODE.`,group:`indexing`,enum:[`true`,`false`],defaultScope:`workspace`},{key:`AIKIT_TOOLSET`,type:`string`,description:`Override active tool profile.`,group:`general`,defaultScope:`workspace`},{key:`AIKIT_SEARCH_DEADLINE_MS`,type:`string`,default:`10000`,description:`Multi-provider web search deadline (milliseconds).`,group:`search-providers`,defaultScope:`global`},{key:`SEARXNG_URL`,type:`string`,description:`Optional SearXNG instance URL for the web_search tool.`,group:`search-providers`,defaultScope:`global`},{key:`GOOGLE_API_KEY`,type:`secret`,description:`Google Custom Search API key.`,group:`search-providers`,defaultScope:`global`},{key:`GOOGLE_CSE_ID`,type:`string`,description:`Google Custom Search Engine ID.`,group:`search-providers`,defaultScope:`global`},{key:`BRAVE_API_KEY`,type:`secret`,description:`Brave Search API key.`,group:`search-providers`,defaultScope:`global`},{key:`BING_API_KEY`,type:`secret`,description:`Bing Web Search API key.`,group:`search-providers`,defaultScope:`global`}];function p(e){return f.find(t=>t.key===e)}function m(e){let t=p(e);return t?t.type===`secret`:/(_KEY|_TOKEN|_SECRET|_PASSWORD|_PASS|_PWD)$/i.test(e)}const h=/^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=(.*)$/;function g(e){let t=e.replace(/^\s+/,``);if(t.startsWith(`"`)){let e=1,n=``;for(;e<t.length;){let r=t[e];if(r===`\\`&&e+1<t.length){let r=t[e+1];r===`n`?n+=`
1
+ import{existsSync as e,mkdirSync as t,readFileSync as n,renameSync as r,writeFileSync as i}from"node:fs";import{dirname as a,resolve as o}from"node:path";import{getGlobalDataDir as s,isUserInstalled as c}from"../../core/dist/index.js";import{z as l}from"zod";import{Router as u}from"express";const d=[{key:`serverName`,type:`string`,default:`aikit`,description:`MCP server name advertised to clients.`,group:`general`,requiresRestart:!0},{key:`toolPrefix`,type:`string`,default:``,description:`Prefix prepended to every MCP tool name (e.g. "aikit_").`,group:`general`,requiresRestart:!0},{key:`toolProfile`,type:`string`,default:`full`,description:`Active tool profile.`,group:`general`,enum:[`full`,`safe`,`research`,`minimal`,`discovery`],requiresRestart:!0},{key:`autoIndex`,type:`boolean`,default:!1,description:`Deprecated. Prefer indexMode. true → auto, false → manual.`,group:`indexing`},{key:`indexMode`,type:`string`,default:`smart`,description:`Indexing strategy. auto = full on startup, manual = on demand, smart = on-demand + idle.`,group:`indexing`,enum:[`auto`,`manual`,`smart`]},{key:`sources`,type:`array`,description:`Source roots to index. Each entry has { path, excludePatterns }.`,group:`indexing`,requiresRestart:!0},{key:`indexing.chunkSize`,type:`number`,default:1500,description:`Maximum chunk size in characters.`,group:`indexing`},{key:`indexing.chunkOverlap`,type:`number`,default:200,description:`Overlap between adjacent chunks.`,group:`indexing`},{key:`indexing.minChunkSize`,type:`number`,default:100,description:`Minimum chunk size before merging into the next chunk.`,group:`indexing`},{key:`indexing.concurrency`,type:`number`,description:`Max files processed concurrently. Defaults to half of CPU cores.`,group:`indexing`},{key:`embedding.model`,type:`string`,default:`mixedbread-ai/mxbai-embed-large-v1`,description:`Embedding model identifier.`,group:`embedding`,requiresRestart:!0},{key:`embedding.dimensions`,type:`number`,default:1024,description:`Embedding vector dimensions. Must match the model.`,group:`embedding`,requiresRestart:!0},{key:`store.backend`,type:`string`,default:`sqlite-vec`,description:`Vector store backend (sqlite-vec | lancedb).`,group:`store`,requiresRestart:!0},{key:`store.path`,type:`string`,description:`Filesystem path for the vector store.`,group:`store`,requiresRestart:!0},{key:`curated.path`,type:`string`,description:`Path to curated knowledge directory.`,group:`store`,requiresRestart:!0},{key:`onboardDir`,type:`string`,description:`Directory for onboard / produce_knowledge output.`,group:`store`,requiresRestart:!0},{key:`stateDir`,type:`string`,description:`Directory for session state (stash, checkpoints, etc.).`,group:`store`,requiresRestart:!0},{key:`er.enabled`,type:`boolean`,default:!1,description:`Enable enterprise RAG bridge integration.`,group:`enterprise-bridge`,requiresRestart:!0},{key:`er.baseUrl`,type:`string`,description:`Base URL of the ER API.`,group:`enterprise-bridge`,requiresRestart:!0},{key:`er.timeoutMs`,type:`number`,default:5e3,description:`ER request timeout in milliseconds.`,group:`enterprise-bridge`},{key:`er.fallbackThreshold`,type:`number`,default:.45,description:`Vector similarity threshold below which ER fallback triggers.`,group:`enterprise-bridge`}],f=[{key:`AIKIT_TRANSPORT`,type:`string`,default:`stdio`,description:`MCP transport mode.`,group:`transport`,enum:[`stdio`,`http`],defaultScope:`workspace`},{key:`AIKIT_PORT`,type:`string`,default:`3210`,description:`HTTP port when transport = http.`,group:`transport`,defaultScope:`workspace`},{key:`AIKIT_CORS_ORIGIN`,type:`string`,description:`CORS Access-Control-Allow-Origin header for HTTP mode.`,group:`transport`,defaultScope:`workspace`},{key:`AIKIT_CONFIG_PATH`,type:`string`,description:`Override path to aikit.config.json.`,group:`paths`,defaultScope:`workspace`},{key:`AIKIT_WORKSPACE_ROOT`,type:`string`,description:`Override workspace root used when no config file is present.`,group:`paths`,defaultScope:`workspace`},{key:`AIKIT_GLOBAL_DATA_DIR`,type:`string`,description:`Override global data directory (default: ~/.aikit-data).`,group:`paths`,defaultScope:`global`},{key:`AIKIT_INDEX_MODE`,type:`string`,description:`Override config indexMode.`,group:`indexing`,enum:[`auto`,`manual`,`smart`],defaultScope:`workspace`},{key:`AIKIT_AUTO_INDEX`,type:`string`,description:`Legacy boolean override. Prefer AIKIT_INDEX_MODE.`,group:`indexing`,enum:[`true`,`false`],defaultScope:`workspace`},{key:`AIKIT_TOOLSET`,type:`string`,description:`Override active tool profile.`,group:`general`,defaultScope:`workspace`},{key:`AIKIT_BROWSER_DEFAULT_MODE`,type:`string`,default:`ui`,description:`Default browser launch mode for browser_* tools.`,group:`browser`,enum:[`ui`,`headless`,`panel`],defaultScope:`workspace`},{key:`AIKIT_BROWSER_PATH`,type:`string`,description:`Optional Playwright browser download path override.`,group:`browser`,defaultScope:`workspace`},{key:`AIKIT_BROWSER_IDLE_MINUTES`,type:`string`,default:`10`,description:`Idle shutdown timeout in minutes for the shared browser runtime.`,group:`browser`,defaultScope:`workspace`},{key:`AIKIT_BROWSER_EVAL_TIMEOUT_MS`,type:`string`,default:`5000`,description:`Default browser_eval timeout in milliseconds.`,group:`browser`,defaultScope:`workspace`},{key:`AIKIT_SEARCH_DEADLINE_MS`,type:`string`,default:`10000`,description:`Multi-provider web search deadline (milliseconds).`,group:`search-providers`,defaultScope:`global`},{key:`SEARXNG_URL`,type:`string`,description:`Optional SearXNG instance URL for the web_search tool.`,group:`search-providers`,defaultScope:`global`},{key:`GOOGLE_API_KEY`,type:`secret`,description:`Google Custom Search API key.`,group:`search-providers`,defaultScope:`global`},{key:`GOOGLE_CSE_ID`,type:`string`,description:`Google Custom Search Engine ID.`,group:`search-providers`,defaultScope:`global`},{key:`BRAVE_API_KEY`,type:`secret`,description:`Brave Search API key.`,group:`search-providers`,defaultScope:`global`},{key:`BING_API_KEY`,type:`secret`,description:`Bing Web Search API key.`,group:`search-providers`,defaultScope:`global`}];function p(e){return f.find(t=>t.key===e)}function m(e){let t=p(e);return t?t.type===`secret`:/(_KEY|_TOKEN|_SECRET|_PASSWORD|_PASS|_PWD)$/i.test(e)}const h=/^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=(.*)$/;function g(e){let t=e.replace(/^\s+/,``);if(t.startsWith(`"`)){let e=1,n=``;for(;e<t.length;){let r=t[e];if(r===`\\`&&e+1<t.length){let r=t[e+1];r===`n`?n+=`
2
2
  `:r===`r`?n+=`\r`:r===`t`?n+=` `:n+=r,e+=2;continue}if(r===`"`){let r=t.slice(e+1),i=r.indexOf(`#`),a=i===-1?``:r.slice(i);return{value:n,quoted:!0,inlineComment:a}}n+=r,e+=1}return{value:t.slice(1),quoted:!0,inlineComment:``}}let n=t.match(/(\s+#.*)$/);return n&&n.index!==void 0?{value:t.slice(0,n.index).trimEnd(),quoted:!1,inlineComment:n[1].trimStart()}:{value:t.trimEnd(),quoted:!1,inlineComment:``}}function _(e){let t;t=e.quoted||/[\s#"']/.test(e.value)||e.value.includes(`
3
3
  `)||e.value.length===0?`"${e.value.replace(/\\/g,`\\\\`).replace(/"/g,`\\"`).replace(/\n/g,`\\n`).replace(/\r/g,`\\r`).replace(/\t/g,`\\t`)}"`:e.value;let n=e.inlineComment?` ${e.inlineComment}`:``;return`${e.key}=${t}${n}`}function v(e){let t=[],n=e.split(/\r?\n/),r=e.endsWith(`
4
4
  `)?n.slice(0,-1):n;for(let e of r){let n=e.match(h);if(!n){t.push({kind:`raw`,text:e});continue}let r=n[1],{value:i,quoted:a,inlineComment:o}=g(n[2]);t.push({kind:`assign`,key:r,value:i,quoted:a,inlineComment:o})}return{lines:t}}function y(e){return`${e.lines.map(e=>e.kind===`assign`?_(e):e.text).join(`