@vpxa/aikit 0.1.219 → 0.1.221

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.219",
3
+ "version": "0.1.221",
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",
@@ -1 +1 @@
1
- import{fork as e}from"node:child_process";import{randomUUID as t}from"node:crypto";import{existsSync as n}from"node:fs";import{dirname as r,join as i}from"node:path";import{fileURLToPath as a}from"node:url";import{CircuitBreaker as o,CircuitOpenError as s,EMBEDDING_DEFAULTS as c,HealthBus as l}from"../../core/dist/index.js";import{rm as u}from"node:fs/promises";import{homedir as d}from"node:os";var f=class{options;logger;healthBus=l.instance();cb;initTimeoutMs;requestTimeoutMs;maxRetries;retryBaseDelayMs;workerAvailable=!0;workerPath=i(r(a(import.meta.url)),`embedder-worker.js`);pendingRequests=new Map;childState=new WeakMap;child=null;readyChild=null;pendingInit=null;pendingShutdown=null;initializePromise=null;shutdownPromise=null;cooldownRespawnTimer=null;currentDimensions;currentModelId;coldStart=!0;constructor(e={}){this.options=e,this.logger=e.logger,this.healthBus.register(`embedder`),this.cb=new o({threshold:3,cooldownMs:6e4,name:`embedder`}),this.cb.on(`open`,()=>{this.healthBus.reportDegraded(`embedder`,`Circuit breaker open — consecutive timeouts`),this.startCooldownRespawn()}),this.cb.on(`closed`,()=>{this.healthBus.reportRecovered(`embedder`)}),this.initTimeoutMs=Math.max(0,e.initTimeoutMs??6e4),this.requestTimeoutMs=Math.max(0,e.requestTimeoutMs??3e4),this.maxRetries=Math.max(0,e.maxRetries??3),this.retryBaseDelayMs=Math.max(0,e.retryBaseDelayMs??500),this.currentDimensions=e.dimensions??c.dimensions,this.currentModelId=e.model??c.model}get dimensions(){return this.currentDimensions}get modelId(){return this.currentModelId}get isCircuitOpen(){return this.cb.isOpen()}async initialize(){if(!(this.readyChild&&this.child===this.readyChild)&&this.workerAvailable){if(!n(this.workerPath)){this.workerAvailable=!1,console.warn(`[aikit] Embedder worker not found at ${this.workerPath}. Embedding disabled - search will use keyword matching only. This usually means the npx cache is corrupted; restart to fix.`);return}if(this.initializePromise)return this.initializePromise;if(this.shutdownPromise){try{await this.shutdownPromise}catch{}if(this.readyChild&&this.child===this.readyChild)return}return this.initializePromise=this.startWorker().finally(()=>{this.initializePromise=null}),this.initializePromise}}async embed(e){if(!this.workerAvailable||(this.assertCircuitClosed(),await this.initialize(),!this.workerAvailable))throw Error(`Embedding worker is not available — embeddings cannot be computed. Check server logs for initialization errors.`);return this.sendVectorRequestWithRetry({type:`embed`,text:e})}async embedQuery(e){if(!this.workerAvailable||(this.assertCircuitClosed(),await this.initialize(),!this.workerAvailable))throw Error(`Embedding worker is not available — embeddings cannot be computed. Check server logs for initialization errors.`);return this.sendVectorRequestWithRetry({type:`embedQuery`,text:e})}async embedBatch(e,t){if(e.length===0)return[];if(!this.workerAvailable||(this.assertCircuitClosed(),await this.initialize(),!this.workerAvailable))throw Error(`Embedding worker is not available — embeddings cannot be computed. Check server logs for initialization errors.`);return this.withWorkerExitRetry(`embedBatch`,()=>this.sendBatchRequest(e,t))}async sendBatchRequest(e,n){await this.initialize();let r=this.requireReadyChild(),i=t(),a=new Promise((e,t)=>{this.pendingRequests.set(i,{child:r,resolve:t=>e(t),reject:t})});try{r.send({type:`embedBatch`,id:i,texts:e,batchSize:n})}catch(e){throw this.pendingRequests.delete(i),this.toError(e,`Failed to send embedBatch request to worker`)}let o=this.requestTimeoutMs>0?Math.max(this.requestTimeoutMs*3,9e4):0;if(o>0){let t,n=new Promise((n,r)=>{t=setTimeout(()=>{this.pendingRequests.delete(i),this.markWorkerUnresponsive(),r(Error(`Embedder embedBatch request timed out after ${o/1e3}s (${e.length} texts). The worker has been killed and will attempt to respawn automatically.`))},o)});try{return await Promise.race([a,n])}finally{t!==void 0&&clearTimeout(t)}}return a}async shutdown(){if(this.clearCooldownRespawnTimer(),this.shutdownPromise)return this.shutdownPromise;let e=this.child;if(!e)return;let t=this.requireChildState(e);t.shutdownRequested=!0,this.readyChild===e&&(this.readyChild=null),this.shutdownPromise=new Promise((t,n)=>{this.pendingShutdown={child:e,resolve:t,reject:n}}).finally(()=>{this.shutdownPromise=null});try{e.send({type:`shutdown`})}catch(t){let n=this.toError(t,`Failed to send shutdown request to worker`);throw this.clearChildReference(e),this.rejectPendingForChild(e,n),this.rejectLifecycleIfOwned(`shutdown`,e,n),n}return this.shutdownPromise}async startWorker(){this.child&&this.readyChild!==this.child&&(this.child=null),this.clearCooldownRespawnTimer(),this.coldStart=!0;let e=this.spawnChild();this.child=e,this.readyChild=null;let t=new Promise((t,n)=>{this.pendingInit={child:e,resolve:t,reject:n}});try{e.send({type:`init`,config:this.buildInitConfig()})}catch(t){let n=this.toError(t,`Failed to send init request to worker`);throw this.pendingInit=null,this.clearChildReference(e),n}if(this.initTimeoutMs>0){let n,r=new Promise((e,t)=>{n=setTimeout(()=>{t(Error(`Embedder worker initialization timed out after ${this.initTimeoutMs/1e3}s. The ONNX model may be downloading or the child process is stuck. Check network connectivity and disk space, or restart the server.`))},this.initTimeoutMs)});try{await Promise.race([t,r]);return}catch(t){this.pendingInit=null;try{e.kill()}catch{}throw this.clearChildReference(e),t}finally{n!==void 0&&clearTimeout(n)}}await t}spawnChild(){let t=e(this.workerPath,[],{env:this.buildChildEnv()});return this.childState.set(t,{idleExitNotified:!1,shutdownRequested:!1,terminated:!1}),t.on(`message`,e=>{this.handleChildMessage(t,e)}),t.once(`error`,e=>{this.handleChildFailure(t,this.toError(e,`Embedder worker failed`))}),t.once(`exit`,(e,n)=>{this.handleChildExit(t,e,n)}),t}handleChildMessage(e,t){switch(t.type){case`ready`:{this.currentDimensions=t.dimensions,this.currentModelId=t.modelId,this.healthBus.reportRecovered(`embedder`),this.child===e&&(this.readyChild=e,this.cb.getState()!==`closed`&&this.cb.reset());let n=this.pendingInit;n?.child===e&&(this.pendingInit=null,n.resolve());return}case`result`:{let n=this.pendingRequests.get(t.id);if(!n||n.child!==e)return;this.pendingRequests.delete(t.id),this.coldStart=!1,this.cb.recordSuccess(),n.resolve(new Float32Array(t.data));return}case`batchResult`:{let n=this.pendingRequests.get(t.id);if(!n||n.child!==e)return;if(this.pendingRequests.delete(t.id),!t.data||!Array.isArray(t.data)||t.data.length===0)n.reject(Error(`Worker returned empty or invalid batch result`));else{let e=t.data.map(e=>new Float32Array(e)),r=e.findIndex(e=>e.length===0);r>=0?n.reject(Error(`Worker returned zero-length vector at index ${r}`)):(this.coldStart=!1,this.cb.recordSuccess(),n.resolve(e))}return}case`error`:{let n=Error(t.message);if(t.id===`init`){this.clearChildReference(e),this.rejectLifecycleIfOwned(`init`,e,n);return}if(t.id===`shutdown`){this.rejectLifecycleIfOwned(`shutdown`,e,n);return}let r=this.pendingRequests.get(t.id);if(!r||r.child!==e)return;this.pendingRequests.delete(t.id),r.reject(n);return}case`idle-exit`:{let t=this.requireChildState(e);t.idleExitNotified=!0,this.clearChildReference(e);return}}}handleChildExit(e,t,n){let r=this.requireChildState(e);if(r.terminated)return;r.terminated=!0,this.clearChildReference(e);let i=r.shutdownRequested||r.idleExitNotified,a=Error(i?`Embedder worker exited before completing request`:`Embedder worker exited unexpectedly (code ${t??`null`}${n?`, signal ${n}`:``})`);this.rejectLifecycleIfOwned(`init`,e,a),i?this.resolveLifecycleIfOwned(`shutdown`,e):this.rejectLifecycleIfOwned(`shutdown`,e,a),this.rejectPendingForChild(e,a)}handleChildFailure(e,t){let n=this.requireChildState(e);n.terminated||(n.terminated=!0,this.clearChildReference(e),this.rejectLifecycleIfOwned(`init`,e,t),this.rejectLifecycleIfOwned(`shutdown`,e,t),this.rejectPendingForChild(e,t))}async sendVectorRequestWithRetry(e){return this.withWorkerExitRetry(e.type,()=>this.sendVectorRequest(e))}async sendVectorRequest(e){await this.initialize();let n=this.requireReadyChild(),r=t(),i=this.requestTimeoutMs>0?this.coldStart?this.requestTimeoutMs*2:this.requestTimeoutMs:0,a=new Promise((e,t)=>{this.pendingRequests.set(r,{child:n,resolve:t=>e(t),reject:t})});try{n.send({...e,id:r})}catch(t){throw this.pendingRequests.delete(r),this.toError(t,`Failed to send ${e.type} request to worker`)}if(i>0){let t,n=new Promise((n,a)=>{t=setTimeout(()=>{this.pendingRequests.delete(r),this.markWorkerUnresponsive(),a(Error(`Embedder ${e.type} request timed out after ${i/1e3}s. The worker has been killed and will attempt to respawn automatically.`))},i)});try{return await Promise.race([a,n])}finally{t!==void 0&&clearTimeout(t)}}return a}async withWorkerExitRetry(e,t){let n=null;for(let r=0;r<=this.maxRetries;r++)try{return await t()}catch(t){let i=this.toError(t,`Failed to process ${e} request`);if(!this.isWorkerExitError(i))throw i;if(n??=i,r===this.maxRetries)throw n;let a=r+1,o=this.retryBaseDelayMs*2**r;this.logger?.warn?.(`Embedder retry ${a}/${this.maxRetries} after ${o}ms`,{requestType:e,delayMs:o,error:i.message}),this.child=null,this.readyChild=null,await this.wait(o)}throw n??Error(`Failed to process ${e} request`)}isWorkerExitError(e){return/embedder worker exited|EPIPE|ECONNRESET|ERR_IPC_CHANNEL_CLOSED|channel closed|write after end/i.test(e.message)}wait(e){return new Promise(t=>{setTimeout(t,e)})}requireReadyChild(){if(!this.child||this.readyChild!==this.child)throw Error(`Embedder worker is not initialized`);return this.child}buildInitConfig(){return{model:this.options.model,dimensions:this.options.dimensions,nativeDim:this.options.nativeDim,queryPrefix:this.options.queryPrefix,interOpNumThreads:this.options.interOpNumThreads,intraOpNumThreads:this.options.intraOpNumThreads}}buildChildEnv(){return this.options.idleTimeoutMs===void 0?process.env:{...process.env,AIKIT_EMBED_IDLE_MS:String(this.options.idleTimeoutMs)}}requireChildState(e){let t=this.childState.get(e);if(!t)throw Error(`Embedder worker state not found`);return t}clearChildReference(e){this.child===e&&(this.child=null),this.readyChild===e&&(this.readyChild=null)}clearCooldownRespawnTimer(){this.cooldownRespawnTimer&&=(clearTimeout(this.cooldownRespawnTimer),null)}startCooldownRespawn(){this.clearCooldownRespawnTimer(),this.cooldownRespawnTimer=setTimeout(()=>{this.cooldownRespawnTimer=null,!this.child&&!this.shutdownPromise&&this.workerAvailable&&this.initialize().catch(()=>{})},6e4),this.logger?.warn?.(`Embedder circuit breaker OPEN — too many consecutive failures`,{cooldownMs:6e4})}markWorkerUnresponsive(){let e=this.child;if(e){try{e.kill()}catch{}this.clearChildReference(e),this.cb.recordFailure(),this.cb.isOpen()||setImmediate(()=>{!this.child&&this.workerAvailable&&!this.shutdownPromise&&this.initialize().catch(()=>{})})}}assertCircuitClosed(){if(this.cb.isOpen())throw new s(this.cb.remainingCooldownMs())}rejectPendingForChild(e,t){for(let[n,r]of this.pendingRequests)r.child===e&&(this.pendingRequests.delete(n),r.reject(t))}resolveLifecycleIfOwned(e,t){let n=this.pendingShutdown;!n||n.child!==t||(this.pendingShutdown=null,n.resolve())}rejectLifecycleIfOwned(e,t,n){let r=e===`init`?this.pendingInit:this.pendingShutdown;!r||r.child!==t||(e===`init`?this.pendingInit=null:this.pendingShutdown=null,r.reject(n))}toError(e,t){return e instanceof Error?e:Error(`${t}: ${String(e)}`)}};let p=null;async function m(){if(!p){try{p=await import(`@huggingface/transformers`)}catch(e){if(e instanceof Error&&e.message.includes(`Cannot find module`)){let{createRequire:e}=await import(`node:module`);p=e(import.meta.url)(`@huggingface/transformers`)}else throw e}p.env.cacheDir=i(d(),`.cache`,`huggingface`,`transformers-js`)}return p}var h=class{pipe=null;shutdownPromise=null;dimensions;modelId;nativeDim;queryPrefix;threadConfig;constructor(e){if(this.modelId=e?.model??c.model,this.nativeDim=e?.nativeDim??1024,this.dimensions=e?.dimensions??c.dimensions,this.dimensions>this.nativeDim)throw Error(`Configured dimensions (${this.dimensions}) exceeds model native output (${this.nativeDim}). Matryoshka truncation cannot upscale — dimensions must be <= nativeDim.`);this.queryPrefix=e?.queryPrefix??this.detectQueryPrefix(this.modelId),this.threadConfig={interOp:e?.interOpNumThreads??1,intraOp:e?.intraOpNumThreads??4}}getPipelineOptions(e){let t=e.backends.onnx;t.wasm||={};let n=t.wasm;return n.numThreads=this.threadConfig.intraOp,{dtype:`q8`,session_options:{interOpNumThreads:this.threadConfig.interOp,intraOpNumThreads:this.threadConfig.intraOp}}}computeNorm(e){let t=0;for(let n=0;n<e.length;n++)t+=e[n]*e[n];return Math.sqrt(t)}truncateAndRenorm(e){if(this.dimensions>=this.nativeDim){let t=this.computeNorm(e);if(!Number.isFinite(t))throw Error(`Embedding produced non-finite norm — output contained NaN or Infinity`);if(t===0)throw Error(`Embedding produced zero-norm vector from ONNX output`);return e}let t=e.subarray(0,this.dimensions),n=this.computeNorm(t);if(!Number.isFinite(n))throw Error(`Embedding produced non-finite norm — output contained NaN or Infinity`);if(n===0)throw Error(`Embedding produced zero-norm vector after truncation — input may be degenerate`);let r=new Float32Array(this.dimensions);for(let e=0;e<this.dimensions;e++)r[e]=t[e]/n;return r}detectQueryPrefix(e){let t=e.toLowerCase();return t.includes(`bge`)||t.includes(`mxbai-embed`)?`Represent this sentence for searching relevant passages: `:t.includes(`/e5-`)||t.includes(`multilingual-e5`)?`query: `:``}async initialize(){if(this.pipe)return;this.shutdownPromise=null;let{pipeline:e,env:t}=await m();try{this.pipe=await e(`feature-extraction`,this.modelId,this.getPipelineOptions(t))}catch(n){let r=n.message?.toLowerCase()??``;if(this.isCorruptionError(r)){let n=i(t.cacheDir??i(d(),`.cache`,`huggingface`,`transformers-js`),this.modelId);console.error(`[aikit:auto-heal] Detected corrupted model cache for "${this.modelId}". Clearing cache at ${n} and retrying download...`);try{await u(n,{recursive:!0,force:!0})}catch{}try{this.pipe=await e(`feature-extraction`,this.modelId,this.getPipelineOptions(t)),console.error(`[aikit:auto-heal] Model "${this.modelId}" re-downloaded successfully.`);return}catch(e){throw Error(`Failed to initialize embedding model "${this.modelId}" after auto-heal: ${e.message}`)}}throw Error(`Failed to initialize embedding model "${this.modelId}": ${n.message}`)}}isCorruptionError(e){return[`protobuf`,`invalid model`,`invalid onnx`,`unexpected end`,`unexpected token`,`failed to load`,`checksum`,`corrupt`,`could not load`,`onnx`,`malformed`].some(t=>e.includes(t))}async shutdown(){return this.shutdownPromise||=this._doShutdown(),this.shutdownPromise}async _doShutdown(){let e=this.pipe;if(e)try{let t=e;typeof t.dispose==`function`?await t.dispose():typeof t.model?.dispose==`function`&&await t.model.dispose()}catch{}finally{this.pipe=null}}async embed(e){this.pipe||await this.initialize();let t=await this.pipe?.(e,{pooling:`mean`,normalize:!0});if(!t?.data)throw Error(`Embedding pipeline returned no output`);try{let e=new Float32Array(t.data);return this.truncateAndRenorm(e)}finally{t.dispose?.()}}async embedQuery(e){return this.embed(this.queryPrefix+e)}async embedBatch(e,t=64){if(e.length===0)return[];this.pipe||await this.initialize();let n=[];for(let r=0;r<e.length;r+=t){let i=e.slice(r,r+t),a=await this.pipe?.(i,{pooling:`mean`,normalize:!0});if(!a?.data)throw Error(`Embedding pipeline returned no output`);try{if(i.length===1){let e=new Float32Array(a.data);n.push(this.truncateAndRenorm(e))}else for(let e=0;e<i.length;e++){let t=e*this.nativeDim,r=a.data.slice(t,t+this.nativeDim);n.push(this.truncateAndRenorm(new Float32Array(r)))}}finally{a.dispose?.()}}return n}};export{f as EmbedderProxy,h as OnnxEmbedder};
1
+ import{fork as e}from"node:child_process";import{randomUUID as t}from"node:crypto";import{existsSync as n}from"node:fs";import{dirname as r,join as i}from"node:path";import{fileURLToPath as a}from"node:url";import{CircuitBreaker as o,CircuitOpenError as s,EMBEDDING_DEFAULTS as c,HealthBus as l}from"../../core/dist/index.js";import{rm as u}from"node:fs/promises";import{homedir as d}from"node:os";var f=class{options;logger;healthBus=l.instance();cb;initTimeoutMs;requestTimeoutMs;maxRetries;retryBaseDelayMs;workerAvailable=!0;workerPath=i(r(a(import.meta.url)),`embedder-worker.js`);pendingRequests=new Map;childState=new WeakMap;child=null;readyChild=null;pendingInit=null;pendingShutdown=null;initializePromise=null;shutdownPromise=null;cooldownRespawnTimer=null;currentDimensions;currentModelId;coldStart=!0;constructor(e={}){this.options=e,this.logger=e.logger,this.healthBus.register(`embedder`),this.cb=new o({threshold:3,cooldownMs:6e4,name:`embedder`}),this.cb.on(`open`,()=>{this.healthBus.reportDegraded(`embedder`,`Circuit breaker open — consecutive timeouts`),this.startCooldownRespawn()}),this.cb.on(`closed`,()=>{this.healthBus.reportRecovered(`embedder`)}),this.initTimeoutMs=Math.max(0,e.initTimeoutMs??6e4),this.requestTimeoutMs=Math.max(0,e.requestTimeoutMs??3e4),this.maxRetries=Math.max(0,e.maxRetries??3),this.retryBaseDelayMs=Math.max(0,e.retryBaseDelayMs??500),this.currentDimensions=e.dimensions??c.dimensions,this.currentModelId=e.model??c.model}get dimensions(){return this.currentDimensions}get modelId(){return this.currentModelId}get isCircuitOpen(){return this.cb.isOpen()}async initialize(){if(!(this.readyChild&&this.child===this.readyChild)&&this.workerAvailable){if(!n(this.workerPath)){this.workerAvailable=!1,console.warn(`[aikit] Embedder worker not found at ${this.workerPath}. Embedding disabled - search will use keyword matching only. This usually means the npx cache is corrupted; restart to fix.`);return}if(this.initializePromise)return this.initializePromise;if(this.shutdownPromise){try{await this.shutdownPromise}catch{}if(this.readyChild&&this.child===this.readyChild)return}return this.initializePromise=this.startWorker().finally(()=>{this.initializePromise=null}),this.initializePromise}}async embed(e){if(!this.workerAvailable||(this.assertCircuitClosed(),await this.initialize(),!this.workerAvailable))throw Error(`Embedding worker is not available — embeddings cannot be computed. Check server logs for initialization errors.`);return this.sendVectorRequestWithRetry({type:`embed`,text:e})}async embedQuery(e){if(!this.workerAvailable||(this.assertCircuitClosed(),await this.initialize(),!this.workerAvailable))throw Error(`Embedding worker is not available — embeddings cannot be computed. Check server logs for initialization errors.`);return this.sendVectorRequestWithRetry({type:`embedQuery`,text:e})}async embedBatch(e,t){if(e.length===0)return[];if(!this.workerAvailable||(this.assertCircuitClosed(),await this.initialize(),!this.workerAvailable))throw Error(`Embedding worker is not available — embeddings cannot be computed. Check server logs for initialization errors.`);return this.withWorkerExitRetry(`embedBatch`,()=>this.sendBatchRequest(e,t))}async sendBatchRequest(e,n){await this.initialize();let r=this.requireReadyChild(),i=t(),a=new Promise((e,t)=>{this.pendingRequests.set(i,{child:r,resolve:t=>e(t),reject:t})});try{r.send({type:`embedBatch`,id:i,texts:e,batchSize:n})}catch(e){throw this.pendingRequests.delete(i),this.toError(e,`Failed to send embedBatch request to worker`)}let o=this.requestTimeoutMs>0?Math.max(this.requestTimeoutMs*3,9e4):0;if(o>0){let t,n=new Promise((n,r)=>{t=setTimeout(()=>{this.pendingRequests.delete(i),this.markWorkerUnresponsive(),r(Error(`Embedder embedBatch request timed out after ${o/1e3}s (${e.length} texts). The worker has been killed and will attempt to respawn automatically.`))},o)});try{return await Promise.race([a,n])}finally{t!==void 0&&clearTimeout(t)}}return a}async shutdown(){if(this.clearCooldownRespawnTimer(),this.shutdownPromise)return this.shutdownPromise;let e=this.child;if(!e)return;let t=this.requireChildState(e);t.shutdownRequested=!0,this.readyChild===e&&(this.readyChild=null),this.shutdownPromise=new Promise((t,n)=>{this.pendingShutdown={child:e,resolve:t,reject:n}}).finally(()=>{this.shutdownPromise=null});try{e.send({type:`shutdown`})}catch(t){let n=this.toError(t,`Failed to send shutdown request to worker`);throw this.clearChildReference(e),this.rejectPendingForChild(e,n),this.rejectLifecycleIfOwned(`shutdown`,e,n),n}return this.shutdownPromise}async startWorker(){this.child&&this.readyChild!==this.child&&(this.child=null),this.clearCooldownRespawnTimer(),this.coldStart=!0;let e=this.spawnChild();this.child=e,this.readyChild=null;let t=new Promise((t,n)=>{this.pendingInit={child:e,resolve:t,reject:n}});try{e.send({type:`init`,config:this.buildInitConfig()})}catch(t){let n=this.toError(t,`Failed to send init request to worker`);throw this.pendingInit=null,this.clearChildReference(e),n}if(this.initTimeoutMs>0){let n,r=new Promise((e,t)=>{n=setTimeout(()=>{t(Error(`Embedder worker initialization timed out after ${this.initTimeoutMs/1e3}s. The ONNX model may be downloading or the child process is stuck. Check network connectivity and disk space, or restart the server.`))},this.initTimeoutMs)});try{await Promise.race([t,r]);return}catch(t){this.pendingInit=null;try{e.kill()}catch{}throw this.clearChildReference(e),t}finally{n!==void 0&&clearTimeout(n)}}await t}spawnChild(){let t=e(this.workerPath,[],{env:this.buildChildEnv()});return this.childState.set(t,{idleExitNotified:!1,shutdownRequested:!1,terminated:!1}),t.on(`message`,e=>{this.handleChildMessage(t,e)}),t.once(`error`,e=>{this.handleChildFailure(t,this.toError(e,`Embedder worker failed`))}),t.once(`exit`,(e,n)=>{this.handleChildExit(t,e,n)}),t}handleChildMessage(e,t){switch(t.type){case`ready`:{this.currentDimensions=t.dimensions,this.currentModelId=t.modelId,this.healthBus.reportRecovered(`embedder`),this.child===e&&(this.readyChild=e,this.cb.getState()!==`closed`&&this.cb.reset());let n=this.pendingInit;n?.child===e&&(this.pendingInit=null,n.resolve());return}case`result`:{let n=this.pendingRequests.get(t.id);if(!n||n.child!==e)return;this.pendingRequests.delete(t.id),this.coldStart=!1,this.cb.recordSuccess(),n.resolve(new Float32Array(t.data));return}case`batchResult`:{let n=this.pendingRequests.get(t.id);if(!n||n.child!==e)return;if(this.pendingRequests.delete(t.id),!t.data||!Array.isArray(t.data)||t.data.length===0)n.reject(Error(`Worker returned empty or invalid batch result`));else{let e=t.data.map(e=>new Float32Array(e)),r=e.findIndex(e=>e.length===0);r>=0?n.reject(Error(`Worker returned zero-length vector at index ${r}`)):(this.coldStart=!1,this.cb.recordSuccess(),n.resolve(e))}return}case`error`:{let n=Error(t.message);if(t.id===`init`){this.clearChildReference(e),this.rejectLifecycleIfOwned(`init`,e,n);return}if(t.id===`shutdown`){this.rejectLifecycleIfOwned(`shutdown`,e,n);return}let r=this.pendingRequests.get(t.id);if(!r||r.child!==e)return;this.pendingRequests.delete(t.id),r.reject(n);return}case`idle-exit`:{let t=this.requireChildState(e);t.idleExitNotified=!0,this.clearChildReference(e);return}}}handleChildExit(e,t,n){let r=this.requireChildState(e);if(r.terminated)return;r.terminated=!0,this.clearChildReference(e);let i=r.shutdownRequested||r.idleExitNotified,a=Error(i?`Embedder worker exited before completing request`:`Embedder worker exited unexpectedly (code ${t??`null`}${n?`, signal ${n}`:``})`);this.rejectLifecycleIfOwned(`init`,e,a),i?this.resolveLifecycleIfOwned(`shutdown`,e):this.rejectLifecycleIfOwned(`shutdown`,e,a),this.rejectPendingForChild(e,a),i||this.cb.recordFailure()}handleChildFailure(e,t){let n=this.requireChildState(e);n.terminated||(n.terminated=!0,this.clearChildReference(e),this.rejectLifecycleIfOwned(`init`,e,t),this.rejectLifecycleIfOwned(`shutdown`,e,t),this.rejectPendingForChild(e,t))}async sendVectorRequestWithRetry(e){return this.withWorkerExitRetry(e.type,()=>this.sendVectorRequest(e))}async sendVectorRequest(e){await this.initialize();let n=this.requireReadyChild(),r=t(),i=this.requestTimeoutMs>0?this.coldStart?this.requestTimeoutMs*2:this.requestTimeoutMs:0,a=new Promise((e,t)=>{this.pendingRequests.set(r,{child:n,resolve:t=>e(t),reject:t})});try{n.send({...e,id:r})}catch(t){throw this.pendingRequests.delete(r),this.toError(t,`Failed to send ${e.type} request to worker`)}if(i>0){let t,n=new Promise((n,a)=>{t=setTimeout(()=>{this.pendingRequests.delete(r),this.markWorkerUnresponsive(),a(Error(`Embedder ${e.type} request timed out after ${i/1e3}s. The worker has been killed and will attempt to respawn automatically.`))},i)});try{return await Promise.race([a,n])}finally{t!==void 0&&clearTimeout(t)}}return a}async withWorkerExitRetry(e,t){let n=null,r=this.maxRetries;for(let i=0;i<=r;i++)try{return await t()}catch(t){let a=this.toError(t,`Failed to process ${e} request`);if(!this.isWorkerExitError(a))throw a;if(n??=a,i===0&&/exited/i.test(a.message)&&!/timed out/i.test(a.message)&&(r=Math.min(r,1)),i===r)throw n;let o=i+1,s=this.retryBaseDelayMs*2**i;if(this.healthBus.reportDegraded(`embedder`,`Worker crashed during ${e} — retrying (${o}/${r})`),this.logger?.warn?.(`Embedder retry ${o}/${r} after ${s}ms`,{requestType:e,delayMs:s,error:a.message}),this.child=null,this.readyChild=null,await this.wait(s),this.cb.isOpen())throw n??a}throw n??Error(`Failed to process ${e} request`)}isWorkerExitError(e){return/embedder worker exited|EPIPE|ECONNRESET|ERR_IPC_CHANNEL_CLOSED|channel closed|write after end/i.test(e.message)}wait(e){return new Promise(t=>{setTimeout(t,e)})}requireReadyChild(){if(!this.child||this.readyChild!==this.child)throw Error(`Embedder worker is not initialized`);return this.child}buildInitConfig(){return{model:this.options.model,dimensions:this.options.dimensions,nativeDim:this.options.nativeDim,queryPrefix:this.options.queryPrefix,interOpNumThreads:this.options.interOpNumThreads,intraOpNumThreads:this.options.intraOpNumThreads}}buildChildEnv(){return this.options.idleTimeoutMs===void 0?process.env:{...process.env,AIKIT_EMBED_IDLE_MS:String(this.options.idleTimeoutMs)}}requireChildState(e){let t=this.childState.get(e);if(!t)throw Error(`Embedder worker state not found`);return t}clearChildReference(e){this.child===e&&(this.child=null),this.readyChild===e&&(this.readyChild=null)}clearCooldownRespawnTimer(){this.cooldownRespawnTimer&&=(clearTimeout(this.cooldownRespawnTimer),null)}startCooldownRespawn(){this.clearCooldownRespawnTimer(),this.cooldownRespawnTimer=setTimeout(()=>{this.cooldownRespawnTimer=null,!this.child&&!this.shutdownPromise&&this.workerAvailable&&this.initialize().catch(()=>{})},6e4),this.logger?.warn?.(`Embedder circuit breaker OPEN — too many consecutive failures`,{cooldownMs:6e4})}markWorkerUnresponsive(){let e=this.child;if(e){try{e.kill()}catch{}this.clearChildReference(e),this.cb.recordFailure(),this.cb.isOpen()||setImmediate(()=>{!this.child&&this.workerAvailable&&!this.shutdownPromise&&this.initialize().catch(()=>{})})}}assertCircuitClosed(){if(this.cb.isOpen())throw new s(this.cb.remainingCooldownMs())}rejectPendingForChild(e,t){for(let[n,r]of this.pendingRequests)r.child===e&&(this.pendingRequests.delete(n),r.reject(t))}resolveLifecycleIfOwned(e,t){let n=this.pendingShutdown;!n||n.child!==t||(this.pendingShutdown=null,n.resolve())}rejectLifecycleIfOwned(e,t,n){let r=e===`init`?this.pendingInit:this.pendingShutdown;!r||r.child!==t||(e===`init`?this.pendingInit=null:this.pendingShutdown=null,r.reject(n))}toError(e,t){return e instanceof Error?e:Error(`${t}: ${String(e)}`)}};let p=null;async function m(){if(!p){try{p=await import(`@huggingface/transformers`)}catch(e){if(e instanceof Error&&e.message.includes(`Cannot find module`)){let{createRequire:e}=await import(`node:module`);p=e(import.meta.url)(`@huggingface/transformers`)}else throw e}p.env.cacheDir=i(d(),`.cache`,`huggingface`,`transformers-js`)}return p}var h=class{pipe=null;shutdownPromise=null;dimensions;modelId;nativeDim;queryPrefix;threadConfig;constructor(e){if(this.modelId=e?.model??c.model,this.nativeDim=e?.nativeDim??1024,this.dimensions=e?.dimensions??c.dimensions,this.dimensions>this.nativeDim)throw Error(`Configured dimensions (${this.dimensions}) exceeds model native output (${this.nativeDim}). Matryoshka truncation cannot upscale — dimensions must be <= nativeDim.`);this.queryPrefix=e?.queryPrefix??this.detectQueryPrefix(this.modelId),this.threadConfig={interOp:e?.interOpNumThreads??1,intraOp:e?.intraOpNumThreads??4}}getPipelineOptions(e){let t=e.backends.onnx;t.wasm||={};let n=t.wasm;return n.numThreads=this.threadConfig.intraOp,{dtype:`q8`,session_options:{interOpNumThreads:this.threadConfig.interOp,intraOpNumThreads:this.threadConfig.intraOp}}}computeNorm(e){let t=0;for(let n=0;n<e.length;n++)t+=e[n]*e[n];return Math.sqrt(t)}truncateAndRenorm(e){if(this.dimensions>=this.nativeDim){let t=this.computeNorm(e);if(!Number.isFinite(t))throw Error(`Embedding produced non-finite norm — output contained NaN or Infinity`);if(t===0)throw Error(`Embedding produced zero-norm vector from ONNX output`);return e}let t=e.subarray(0,this.dimensions),n=this.computeNorm(t);if(!Number.isFinite(n))throw Error(`Embedding produced non-finite norm — output contained NaN or Infinity`);if(n===0)throw Error(`Embedding produced zero-norm vector after truncation — input may be degenerate`);let r=new Float32Array(this.dimensions);for(let e=0;e<this.dimensions;e++)r[e]=t[e]/n;return r}detectQueryPrefix(e){let t=e.toLowerCase();return t.includes(`bge`)||t.includes(`mxbai-embed`)?`Represent this sentence for searching relevant passages: `:t.includes(`/e5-`)||t.includes(`multilingual-e5`)?`query: `:``}async initialize(){if(this.pipe)return;this.shutdownPromise=null;let{pipeline:e,env:t}=await m();try{this.pipe=await e(`feature-extraction`,this.modelId,this.getPipelineOptions(t))}catch(n){let r=n.message?.toLowerCase()??``;if(this.isCorruptionError(r)){let n=i(t.cacheDir??i(d(),`.cache`,`huggingface`,`transformers-js`),this.modelId);console.error(`[aikit:auto-heal] Detected corrupted model cache for "${this.modelId}". Clearing cache at ${n} and retrying download...`);try{await u(n,{recursive:!0,force:!0})}catch{}try{this.pipe=await e(`feature-extraction`,this.modelId,this.getPipelineOptions(t)),console.error(`[aikit:auto-heal] Model "${this.modelId}" re-downloaded successfully.`);return}catch(e){throw Error(`Failed to initialize embedding model "${this.modelId}" after auto-heal: ${e.message}`)}}throw Error(`Failed to initialize embedding model "${this.modelId}": ${n.message}`)}}isCorruptionError(e){return[`protobuf`,`invalid model`,`invalid onnx`,`unexpected end`,`unexpected token`,`failed to load`,`checksum`,`corrupt`,`could not load`,`onnx`,`malformed`].some(t=>e.includes(t))}async shutdown(){return this.shutdownPromise||=this._doShutdown(),this.shutdownPromise}async _doShutdown(){let e=this.pipe;if(e)try{let t=e;typeof t.dispose==`function`?await t.dispose():typeof t.model?.dispose==`function`&&await t.model.dispose()}catch{}finally{this.pipe=null}}async embed(e){this.pipe||await this.initialize();let t=await this.pipe?.(e,{pooling:`mean`,normalize:!0});if(!t?.data)throw Error(`Embedding pipeline returned no output`);try{let e=new Float32Array(t.data);return this.truncateAndRenorm(e)}finally{t.dispose?.()}}async embedQuery(e){return this.embed(this.queryPrefix+e)}async embedBatch(e,t=64){if(e.length===0)return[];this.pipe||await this.initialize();let n=[];for(let r=0;r<e.length;r+=t){let i=e.slice(r,r+t),a=await this.pipe?.(i,{pooling:`mean`,normalize:!0});if(!a?.data)throw Error(`Embedding pipeline returned no output`);try{if(i.length===1){let e=new Float32Array(a.data);n.push(this.truncateAndRenorm(e))}else for(let e=0;e<i.length;e++){let t=e*this.nativeDim,r=a.data.slice(t,t+this.nativeDim);n.push(this.truncateAndRenorm(new Float32Array(r)))}}finally{a.dispose?.()}}return n}};export{f as EmbedderProxy,h as OnnxEmbedder};
@@ -28,6 +28,14 @@ interface FlowHookConfig {
28
28
  full?: number;
29
29
  brief?: number;
30
30
  };
31
+ /** Custom hooks declared by the flow (loaded at runtime from installPath) */
32
+ custom?: Array<{
33
+ /** Relative path to hook module (from flow install directory) */path: string; /** Execution order (50+ recommended to run after built-in hooks) */
34
+ order: number; /** Maximum token budget for this hook */
35
+ maxTokens?: number; /** Whether to run in brief mode */
36
+ runInBrief?: boolean; /** Whether to only fire once per flow run */
37
+ runOnce?: boolean;
38
+ }>;
31
39
  }
32
40
  /** Flow manifest — the flow.json schema */
33
41
  interface FlowManifest {
@@ -37,9 +37,12 @@ interface CrawlOptions {
37
37
  declare class FilesystemCrawler {
38
38
  /** Binary file extensions that should always be skipped */
39
39
  private static readonly BINARY_EXTENSIONS;
40
+ private static readonly GENERATED_PATH_PATTERN;
41
+ private currentFileSizeBytes;
40
42
  crawl(options: CrawlOptions): Promise<CrawlResult[]>;
41
43
  private walkDir;
42
44
  private isExcluded;
45
+ private isLikelyGenerated;
43
46
  }
44
47
  //#endregion
45
48
  //#region packages/indexer/src/graph-extractor.d.ts
@@ -1 +1,3 @@
1
- import{createHash as e}from"node:crypto";import{existsSync as t,readFileSync as n,realpathSync as r,statSync as i,writeFileSync as a}from"node:fs";import{lstat as o,readFile as s,readdir as c,stat as l}from"node:fs/promises";import{dirname as u,extname as d,join as f,relative as p,resolve as m}from"node:path";import{AIKIT_PATHS as h,FILE_LIMITS as g,createLogger as _,detectContentType as v,serializeError as y}from"../../core/dist/index.js";import{minimatch as b}from"minimatch";import{availableParallelism as x,loadavg as S}from"node:os";import{createChunkerSync as C}from"../../chunker/dist/index.js";function w(t){return e(`sha256`).update(t).digest(`hex`).slice(0,16)}function T(t,n){let r=`${t}:${n}`;return e(`sha256`).update(r).digest(`hex`).slice(0,16)}const E=_(`indexer`);var D=class e{static BINARY_EXTENSIONS=new Set(`.node,.so,.dylib,.dll,.wasm,.bin,.exe,.png,.jpg,.jpeg,.gif,.bmp,.ico,.webp,.svg,.mp3,.mp4,.wav,.avi,.mov,.flac,.zip,.gz,.tar,.bz2,.7z,.rar,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.ttf,.otf,.woff,.woff2,.eot,.pyc,.class,.o,.obj,.a,.lib`.split(`,`));async crawl(e){let t=[],n=new Set;return await this.walkDir(e.rootDir,e.rootDir,e.excludePatterns,t,n),t}async walkDir(t,n,i,a,u){let m;try{m=await c(t,{withFileTypes:!0})}catch(e){let n=e.code;(n===`EACCES`||n===`EPERM`)&&E.warn(`Permission denied, skipping directory`,{dir:t});return}for(let c of m){let m=f(t,c.name),_=p(n,m).replace(/\\/g,`/`);if(!this.isExcluded(_,i)){if(c.isDirectory()){if(c.name.startsWith(`.`)&&!(c.name===h.ai.slice(1)&&_.startsWith(h.ai)))continue;try{if((await o(m)).isSymbolicLink())continue}catch{continue}let e;try{e=r(m)}catch{continue}if(u.has(e))continue;u.add(e),await this.walkDir(m,n,i,a,u)}else if(c.isFile()){let t=d(c.name).toLowerCase();if(e.BINARY_EXTENSIONS.has(t))continue;try{if((await l(m)).size>g.maxFileSizeBytes)continue;let e=await s(m,`utf-8`);if(e.includes(`\0`))continue;a.push({relativePath:_,absolutePath:m,content:e,extension:t})}catch{}}}}}isExcluded(e,t){return t.some(t=>b(e,t,{dot:!0}))}};const O=new Set([`.ts`,`.tsx`,`.js`,`.jsx`,`.mjs`,`.cjs`]),k=[{pattern:/^export\s+(?:async\s+)?function\s+(\w+)/gm,kind:`function`,exported:!0},{pattern:/^export\s+(?:default\s+)?class\s+(\w+)/gm,kind:`class`,exported:!0},{pattern:/^export\s+interface\s+(\w+)/gm,kind:`interface`,exported:!0},{pattern:/^export\s+type\s+(\w+)/gm,kind:`type`,exported:!0},{pattern:/^export\s+(?:const|let)\s+(\w+)/gm,kind:`const`,exported:!0},{pattern:/^export\s+enum\s+(\w+)/gm,kind:`enum`,exported:!0},{pattern:/^(?:async\s+)?function\s+(\w+)/gm,kind:`function`,exported:!1},{pattern:/^class\s+(\w+)/gm,kind:`class`,exported:!1},{pattern:/^interface\s+(\w+)/gm,kind:`interface`,exported:!1},{pattern:/^type\s+(\w+)/gm,kind:`type`,exported:!1},{pattern:/^enum\s+(\w+)/gm,kind:`enum`,exported:!1}],A=[/import\s+(?:(?:type\s+)?(?:(?:\{[^}]*\}|[\w*]+)\s+from\s+)?)['"]([^'"]+)['"]/g,/import\(\s*['"]([^'"]+)['"]\s*\)/g,/require\(\s*['"]([^'"]+)['"]\s*\)/g];function j(t,n,r){return e(`sha256`).update(`${t}:${n}:${r}`).digest(`hex`).slice(0,16)}function M(t,n,r){return e(`sha256`).update(`${t}-${r}-${n}`).digest(`hex`).slice(0,16)}function N(e,t){return f(u(t),e).replace(/\\/g,`/`).replace(/\.(js|jsx|ts|tsx|mjs|cjs)$/,``)}function P(e){return e.replace(/\.(js|jsx|ts|tsx|mjs|cjs)$/,``)}function F(e,t,n){let r=d(t).toLowerCase();if(!O.has(r))return{nodes:[],edges:[]};let i=[],a=[],o=new Date().toISOString(),s=new Set,c=P(t),l=j(`module`,c,c);i.push({id:l,type:`module`,name:t,properties:{ext:r},sourcePath:t,createdAt:o});for(let{pattern:n,kind:r,exported:c}of k){let u=new RegExp(n.source,n.flags),d;for(;(d=u.exec(e))!==null;){let e=d[1],n=`${r}:${e}`;if(s.has(n))continue;s.add(n);let u=j(r,e,t);i.push({id:u,type:r,name:e,properties:{exported:c},sourcePath:t,createdAt:o}),a.push({id:M(l,u,`defines`),fromId:l,toId:u,type:`defines`,weight:c?1:.5})}}let u=n?.workspacePackages,f=new Set;for(let n of A){let r=new RegExp(n.source,n.flags),i;for(;(i=r.exec(e))!==null;){let e=i[1];if(f.has(e))continue;let n;if(e.startsWith(`.`))n=N(e,t);else if(u){let t=e.startsWith(`@`)?e.split(`/`).slice(0,2).join(`/`):e.split(`/`)[0],r=u.get(t);if(!r)continue;n=r}else continue;f.add(e);let r=P(n),o=j(`module`,r,r);a.push({id:M(l,o,`imports`),fromId:l,toId:o,type:`imports`,properties:{source:e}})}}return{nodes:i,edges:a}}const I=_(`hash-cache`);var L=class{cache;filePath;dirty=!1;constructor(e){this.filePath=m(e,`file-hashes.json`),this.cache=new Map}load(){if(t(this.filePath))try{let e=n(this.filePath,`utf-8`),t=JSON.parse(e);this.cache=new Map(Object.entries(t)),I.info(`Hash cache loaded`,{entries:this.cache.size})}catch(e){I.warn(`Hash cache load failed, starting fresh`,{err:e}),this.cache=new Map}}get(e){return this.cache.get(e)}set(e,t){this.cache.set(e,t),this.dirty=!0}delete(e){this.cache.delete(e)&&(this.dirty=!0)}flush(){if(this.dirty)try{let e={};for(let[t,n]of this.cache)e[t]=n;a(this.filePath,JSON.stringify(e),`utf-8`),this.dirty=!1}catch(e){I.warn(`Hash cache flush failed`,{err:e})}}clear(){this.cache.clear(),this.dirty=!0,this.flush()}get size(){return this.cache.size}};const R=_(`indexer`),z=()=>new Promise(e=>setImmediate(e));async function B(e,t,n,r){let i=0;async function a(){for(;i<e.length;){let n=i++;try{await t(e[n])}catch(t){r?.(e[n],t)}n%10==0&&await z()}}await Promise.all(Array.from({length:Math.min(n,e.length)},()=>a()))}function V(e){let t=x(),n=S()[0]/t;return n>1.5?2:n>1?Math.max(2,Math.floor(e/2)):e}const H=Math.max(2,Math.min(4,Math.floor(x()*.5)));var U=class{embedder;store;crawler;indexing=!1;graphStore;hashCache;get isIndexing(){return this.indexing}constructor(e,t){this.embedder=e,this.store=t,this.crawler=new D}normalizeChunkText(e){return e.replace(/^\/\/ File: [^\n]*\n?/,``).toLowerCase().replace(/\s+/g,` `).trim()}setGraphStore(e){this.graphStore=e}setHashCache(e){this.hashCache=e}async index(e,t){if(this.indexing)throw Error(`Indexing is already in progress`);this.indexing=!0;try{return await this.doIndex(e,t,{})}finally{this.indexing=!1}}async getChangedFiles(e){let t=e.indexing.concurrency??H,n=await this.crawlSources(e),{filesToProcess:r}=await this.planIndexWork(n,t,{});return r.map(e=>e.relativePath)}async indexFiles(e,t,n){if(this.indexing)throw Error(`Indexing is already in progress`);this.indexing=!0;try{return await this.doIndexFiles(e,t,n)}finally{this.indexing=!1}}async doIndex(e,t,n={}){let r=Date.now(),i=e.indexing.concurrency??H;t?.({phase:`crawling`,filesTotal:0,filesProcessed:0,chunksTotal:0,chunksProcessed:0});let a=await this.crawlSources(e),{filesToProcess:o,filesSkipped:s,pathsToRemove:c}=await this.planIndexWork(a,i,{skipHashCheck:n.skipHashCheck}),{filesProcessed:l,chunksCreated:u,chunksDeduped:d}=await this.processFiles(a,o,i,t,{graphCleared:n.graphCleared}),f=await this.cleanupRemovedFiles(c,i,o.length,l,u,t);return this.hashCache?.flush(),t?.({phase:`done`,filesTotal:o.length,filesProcessed:l,chunksTotal:u,chunksProcessed:u}),{filesProcessed:l,filesSkipped:s,chunksCreated:u,chunksDeduped:d,filesRemoved:f,durationMs:Date.now()-r}}async doIndexFiles(e,t,n){let r=Date.now(),i=e.indexing.concurrency??H,a=new Set(t);if(a.size===0)return{filesProcessed:0,filesSkipped:0,chunksCreated:0,chunksDeduped:0,filesRemoved:0,durationMs:Date.now()-r};n?.({phase:`crawling`,filesTotal:0,filesProcessed:0,chunksTotal:0,chunksProcessed:0});let o=await this.crawlSources(e),{filesToProcess:s,filesSkipped:c}=await this.planIndexWork(o,i,{requestedPaths:a}),{filesProcessed:l,chunksCreated:u,chunksDeduped:d}=await this.processFiles(o,s,i,n,{});return this.hashCache?.flush(),n?.({phase:`done`,filesTotal:s.length,filesProcessed:l,chunksTotal:u,chunksProcessed:u}),{filesProcessed:l,filesSkipped:c,chunksCreated:u,chunksDeduped:d,filesRemoved:0,durationMs:Date.now()-r}}async crawlSources(e){return(await Promise.all(e.sources.map(e=>this.crawler.crawl({rootDir:e.path,excludePatterns:e.excludePatterns})))).flat()}async planIndexWork(e,t,n){let r=n.requestedPaths,i;if(r){let t=e=>e.replace(/\\/g,`/`).toLowerCase(),n=new Set([...r].map(t));i=e.filter(e=>n.has(t(e.relativePath))||n.has(t(e.absolutePath)))}else i=e;if(n.skipHashCheck)return{filesToProcess:i,filesSkipped:0,pathsToRemove:[]};let a=r?[]:await this.getPathsToRemove(e),o=0,s=[];return await B(i,async e=>{let t=w(e.content);if(this.hashCache){if(this.hashCache.get(e.relativePath)===t){o++;return}}else{let n=await this.store.getBySourcePath(e.relativePath);if(n.length>0&&n[0].fileHash===t){o++;return}}s.push(e)},V(t),(e,t)=>R.error(`Hash check failed`,{sourcePath:e.relativePath,...y(t)})),{filesToProcess:s,filesSkipped:o,pathsToRemove:a}}async getPathsToRemove(e){let t=await this.store.listSourcePaths(),n=new Set(e.map(e=>e.relativePath));return t.filter(e=>!n.has(e)&&!e.startsWith(`${h.aiCurated}/`))}async buildWorkspacePackageMap(e){let t=new Map;for(let n of e)if(n.relativePath.endsWith(`package.json`))try{let e=JSON.parse(n.content);if(typeof e.name!=`string`||e.name.length===0)continue;let r=n.relativePath===`package.json`?``:n.relativePath.replace(/\/package\.json$/,``),i=``;if(typeof e.exports==`string`)i=e.exports;else if(e.exports&&typeof e.exports==`object`){let t=e.exports,n=t[`.`]??t;if(typeof n==`string`)i=n;else if(n&&typeof n==`object`){let e=n,t=e.import??e.module??e.default??e.require;typeof t==`string`&&(i=t)}}!i&&typeof e.module==`string`&&(i=e.module),!i&&typeof e.main==`string`&&(i=e.main);let a=i.replace(/^\.\//,``).replace(/^dist\//,`src/`).replace(/\.(ts|js|mjs|cjs|tsx|jsx)$/,``),o=a?r?`${r}/${a}`:a:r?`${r}/src/index`:`src/index`;t.set(e.name,o)}catch{}return t}async processFiles(t,n,r,i,a={}){let o=0,s=0,c=0,l=n.length,u=this.graphStore?await this.buildWorkspacePackageMap(t):void 0,d=new Map,f=[],p=[],m=0,h=[],g=[],_=new Map,b=0,x=async()=>{if(h.length===0)return;let e=h,t=g,n=_;h=[],g=[],_=new Map,b=0;try{await this.store.upsert(e,t);for(let[e,t]of n)this.hashCache?.set(e,t)}catch(r){h.push(...e),g.push(...t);for(let[e,t]of n)_.set(e,t);throw r}},S=async()=>{if(this.graphStore){try{f.length>0&&await this.graphStore.upsertNodes(f),p.length>0&&await this.graphStore.upsertEdges(p)}catch(e){R.warn(`Graph batch flush failed`,y(e))}f=[],p=[],m=0}};return await B(n,async t=>{i?.({phase:`chunking`,filesTotal:l,filesProcessed:o,chunksTotal:s,chunksProcessed:s,currentFile:t.relativePath});let n=v(t.relativePath),r=C(t.extension).chunk(t.content,{sourcePath:t.relativePath,contentType:n});if(r.length===0)return;let E=w(t.content),D=new Date().toISOString(),O=(e,n,r)=>({id:T(t.relativePath,n),content:e.text,sourcePath:e.sourcePath,contentType:e.contentType,headingPath:e.headingPath,chunkIndex:e.chunkIndex,totalChunks:e.totalChunks,startLine:e.startLine,endLine:e.endLine,fileHash:E,contentHash:r,indexedAt:D,origin:`indexed`,tags:[],version:1}),k=[],A=[];for(let t=0;t<r.length;t++){let n=r[t],i=e(`sha256`).update(this.normalizeChunkText(n.text)).digest(`hex`),a=O(n,t,i),o=d.get(i);if(o&&this.store.upsertWithoutVector){A.push({record:a,sourceRecordId:o}),c++;continue}d.set(i,a.id),k.push({chunk:n,record:a})}i?.({phase:`embedding`,filesTotal:l,filesProcessed:o,chunksTotal:s+r.length,chunksProcessed:s,currentFile:t.relativePath});let j=k.length>0?await this.embedder.embedBatch(k.map(({chunk:e})=>e.text)):[],M=k.map(({record:e})=>e);if(i?.({phase:`storing`,filesTotal:l,filesProcessed:o,chunksTotal:s+r.length,chunksProcessed:s,currentFile:t.relativePath}),M.length>0&&(h.push(...M),g.push(...j),_.set(t.relativePath,E),b++,b>=20&&await x()),A.length>0&&h.length>0&&await x(),this.store.upsertWithoutVector)for(let{record:e,sourceRecordId:t}of A)await this.store.upsertWithoutVector(e,t);if(M.length===0&&A.length>0&&this.hashCache?.set(t.relativePath,E),this.graphStore)try{a.graphCleared||await this.graphStore.deleteBySourcePath(t.relativePath);let e=F(t.content,t.relativePath,{workspacePackages:u});e.nodes.length>0&&f.push(...e.nodes),e.edges.length>0&&p.push(...e.edges),m++,m>=50&&await S()}catch(e){R.warn(`Graph extraction failed`,{sourcePath:t.relativePath,...y(e)})}o++,s+=r.length},V(r),(e,t)=>R.error(`Processing failed`,{sourcePath:e.relativePath,...y(t)})),await x(),await S(),{filesProcessed:o,chunksCreated:s,chunksDeduped:c}}async cleanupRemovedFiles(e,t,n,r,i,a){if(e.length===0)return 0;let o=0;return a?.({phase:`cleanup`,filesTotal:n,filesProcessed:r,chunksTotal:i,chunksProcessed:i}),await B(e,async e=>{await this.store.deleteBySourcePath(e),this.hashCache?.delete(e),this.graphStore&&await this.graphStore.deleteBySourcePath(e).catch(t=>R.warn(`Graph cleanup failed`,{sourcePath:e,...y(t)})),o++},V(t),(e,t)=>R.error(`Cleanup failed`,{sourcePath:e,...y(t)})),o}async reindexAll(e,t){if(this.indexing)throw Error(`Indexing is already in progress`);this.indexing=!0;try{if(await this.store.dropTable(),this.graphStore)try{let e=await this.graphStore.getStats();e.nodeCount>0&&(await this.graphStore.clear(),R.info(`Graph store cleared`,{nodeCount:e.nodeCount,edgeCount:e.edgeCount}))}catch(e){R.warn(`Graph store clear failed`,y(e))}return await this.doReindex(e,t)}catch(e){throw this.indexing=!1,e}}async doReindex(e,t){try{return await this.doIndex(e,t,{skipHashCheck:!0,graphCleared:!0})}finally{this.indexing=!1}}async getStats(){return this.store.getStats()}};const W=_(`smart-index`),G=1.5;var K=class{indexer;config;store;trickleTimer=null;stopped=!1;trickleIntervalMs;batchSize;priorityQueue=[];changedFiles=[];lastRefreshTime=0;refreshing=!1;constructor(e,t,n){this.indexer=e,this.config=t,this.store=n,this.trickleIntervalMs=t.indexing.trickleIntervalMs??this.readPositiveIntEnv(`AIKIT_SMART_TRICKLE_MS`,3e4),this.batchSize=t.indexing.trickleBatchSize??this.readPositiveIntEnv(`AIKIT_SMART_BATCH_SIZE`,1)}start(){this.trickleTimer&&=(clearTimeout(this.trickleTimer),null),this.stopped=!1,W.info(`Smart index scheduler started (trickle mode)`,{intervalMs:this.trickleIntervalMs,batchSize:this.batchSize}),this.scheduleTick()}stop(){this.stopped=!0,this.trickleTimer&&=(clearTimeout(this.trickleTimer),null)}prioritize(...e){let t=[...new Set(e.filter(Boolean))].filter(e=>{try{return!i(e).isDirectory()}catch{return W.debug(`Skipping non-existent path`,{path:e}),!1}});for(let e of t){let t=this.priorityQueue.indexOf(e);t>=0&&this.priorityQueue.splice(t,1)}for(let e of t.reverse())this.priorityQueue.unshift(e);this.priorityQueue.length>500&&(this.priorityQueue.length=500),t.length>0&&W.debug(`Files prioritized for trickle indexing`,{added:t.length,queued:this.priorityQueue.length})}getState(){return{mode:`smart`,queueSize:this.priorityQueue.length,changedFilesSize:this.changedFiles.length,intervalMs:this.trickleIntervalMs,batchSize:this.batchSize,running:this.trickleTimer!==null}}readPositiveIntEnv(e,t){let n=Number(process.env[e]);return Number.isFinite(n)&&n>0?n:t}scheduleTick(){this.trickleTimer=setTimeout(()=>void this.tick(),this.trickleIntervalMs),this.trickleTimer.unref&&this.trickleTimer.unref()}async tick(){if(!this.stopped)try{if(this.indexer.isIndexing){W.info(`Skipping trickle tick — indexing already in progress`);return}let e=this.getCpuCount(),t=S()[0];if(e>0&&t/e>G){W.info(`Skipping trickle tick — system load too high`,{load:t.toFixed(2),cpuCount:e,threshold:G});return}let n=await this.pickFiles();if(n.length===0){await this.maybeRefreshChangedFiles();return}W.debug(`Trickle indexing tick started`,{count:n.length,files:n});let r=await this.indexer.indexFiles(this.config,n);if(this.store)try{await this.store.createFtsIndex()}catch(e){W.warn(`FTS index rebuild failed after trickle tick`,{error:String(e)})}this.changedFiles=this.changedFiles.filter(e=>!n.includes(e)),W.debug(`Trickle indexing tick complete`,{filesProcessed:r.filesProcessed,filesSkipped:r.filesSkipped,chunksCreated:r.chunksCreated})}catch(e){let t=String(e);if(t.includes(`not initialized`)||t.includes(`has been closed`)){W.warn(`Store closed — stopping smart index scheduler`,{error:t}),this.stop();return}W.error(`Trickle indexing tick failed`,{error:t})}finally{this.stopped||this.scheduleTick()}}getCpuCount(){try{return typeof x==`function`?x():4}catch{return 4}}async pickFiles(){let e=[];for(;e.length<this.batchSize&&this.priorityQueue.length>0;){let t=this.priorityQueue.shift();t&&!e.includes(t)&&e.push(t)}if(e.length<this.batchSize)for(await this.maybeRefreshChangedFiles();e.length<this.batchSize&&this.changedFiles.length>0;){let t=this.changedFiles.shift();t&&!e.includes(t)&&e.push(t)}return e}async maybeRefreshChangedFiles(){let e=Date.now();if(!(this.refreshing||this.changedFiles.length>0&&e-this.lastRefreshTime<6e5)){this.refreshing=!0;try{this.changedFiles=await this.indexer.getChangedFiles(this.config),this.lastRefreshTime=e,this.changedFiles.length>0&&W.debug(`Refreshed changed files for trickle indexing`,{count:this.changedFiles.length})}catch(e){let t=String(e);if(t.includes(`not initialized`)||t.includes(`has been closed`)){W.warn(`Store closed — stopping smart index scheduler`,{error:t}),this.stop();return}W.error(`Failed to refresh changed files for trickle indexing`,{error:t})}finally{this.refreshing=!1}}}};export{L as FileHashCache,D as FilesystemCrawler,U as IncrementalIndexer,K as SmartIndexScheduler,F as extractGraph,T as generateRecordId,w as hashContent};
1
+ import{createHash as e}from"node:crypto";import{existsSync as t,readFileSync as n,realpathSync as r,statSync as i,writeFileSync as a}from"node:fs";import{lstat as o,readFile as s,readdir as c,stat as l}from"node:fs/promises";import{dirname as u,extname as d,join as f,relative as p,resolve as m}from"node:path";import{AIKIT_PATHS as h,FILE_LIMITS as g,createLogger as _,detectContentType as v,serializeError as y}from"../../core/dist/index.js";import{minimatch as b}from"minimatch";import{availableParallelism as x,loadavg as S}from"node:os";import{createChunkerSync as C}from"../../chunker/dist/index.js";function w(t){return e(`sha256`).update(t).digest(`hex`).slice(0,16)}function T(t,n){let r=`${t}:${n}`;return e(`sha256`).update(r).digest(`hex`).slice(0,16)}const E=_(`indexer`);var D=class e{static BINARY_EXTENSIONS=new Set(`.node,.so,.dylib,.dll,.wasm,.bin,.exe,.png,.jpg,.jpeg,.gif,.bmp,.ico,.webp,.svg,.mp3,.mp4,.wav,.avi,.mov,.flac,.zip,.gz,.tar,.bz2,.7z,.rar,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.ttf,.otf,.woff,.woff2,.eot,.pyc,.class,.o,.obj,.a,.lib`.split(`,`));static GENERATED_PATH_PATTERN=/(?:lcov\.info|\.min\.(?:js|css)|\.css\.map|\.js\.map|\.map)$/i;currentFileSizeBytes=0;async crawl(e){let t=[],n=new Set;return await this.walkDir(e.rootDir,e.rootDir,e.excludePatterns,t,n),t}async walkDir(t,n,i,a,u){let m;try{m=await c(t,{withFileTypes:!0})}catch(e){let n=e.code;(n===`EACCES`||n===`EPERM`)&&E.warn(`Permission denied, skipping directory`,{dir:t});return}for(let c of m){let m=f(t,c.name),_=p(n,m).replace(/\\/g,`/`);if(!this.isExcluded(_,i)){if(c.isDirectory()){if(c.name.startsWith(`.`)&&!(c.name===h.ai.slice(1)&&_.startsWith(h.ai)))continue;try{if((await o(m)).isSymbolicLink())continue}catch{continue}let e;try{e=r(m)}catch{continue}if(u.has(e))continue;u.add(e),await this.walkDir(m,n,i,a,u)}else if(c.isFile()){let t=d(c.name).toLowerCase();if(e.BINARY_EXTENSIONS.has(t))continue;try{let e=await l(m);if(this.currentFileSizeBytes=e.size,e.size>g.maxFileSizeBytes)continue;let n=await s(m,`utf-8`);if(n.includes(`\0`))continue;if(this.isLikelyGenerated(n,_)){E.info(`Skipping likely generated file`,{path:_});continue}a.push({relativePath:_,absolutePath:m,content:n,extension:t})}catch{}}}}}isExcluded(e,t){return t.some(t=>b(e,t,{dot:!0}))}isLikelyGenerated(t,n){let r=d(n).toLowerCase();if(e.GENERATED_PATH_PATTERN.test(n)||r===`.snap`&&this.currentFileSizeBytes>5e4||n.split(`/`).includes(`coverage`)&&r===``)return!0;let i=t.slice(0,5e4).split(`
2
+ `),a=i.slice(0,100);if(a.length>0&&a.reduce((e,t)=>e+t.length,0)/a.length>500)return!0;let o=i.slice(1,201);if(o.length>=20){let e=new Map,t=0;for(let n of o){let r=n.replace(/\d/g,`#`).slice(0,40),i=(e.get(r)??0)+1;e.set(r,i),i>t&&(t=i)}if(t/o.length>.8)return!0}if(t.length>1e5){let e=0;for(let n of t)if(n===`
3
+ `&&(e+=1,e>=10))break;if(e<10)return!0}return!1}};const O=new Set([`.ts`,`.tsx`,`.js`,`.jsx`,`.mjs`,`.cjs`]),k=[{pattern:/^export\s+(?:async\s+)?function\s+(\w+)/gm,kind:`function`,exported:!0},{pattern:/^export\s+(?:default\s+)?class\s+(\w+)/gm,kind:`class`,exported:!0},{pattern:/^export\s+interface\s+(\w+)/gm,kind:`interface`,exported:!0},{pattern:/^export\s+type\s+(\w+)/gm,kind:`type`,exported:!0},{pattern:/^export\s+(?:const|let)\s+(\w+)/gm,kind:`const`,exported:!0},{pattern:/^export\s+enum\s+(\w+)/gm,kind:`enum`,exported:!0},{pattern:/^(?:async\s+)?function\s+(\w+)/gm,kind:`function`,exported:!1},{pattern:/^class\s+(\w+)/gm,kind:`class`,exported:!1},{pattern:/^interface\s+(\w+)/gm,kind:`interface`,exported:!1},{pattern:/^type\s+(\w+)/gm,kind:`type`,exported:!1},{pattern:/^enum\s+(\w+)/gm,kind:`enum`,exported:!1}],A=[/import\s+(?:(?:type\s+)?(?:(?:\{[^}]*\}|[\w*]+)\s+from\s+)?)['"]([^'"]+)['"]/g,/import\(\s*['"]([^'"]+)['"]\s*\)/g,/require\(\s*['"]([^'"]+)['"]\s*\)/g];function j(t,n,r){return e(`sha256`).update(`${t}:${n}:${r}`).digest(`hex`).slice(0,16)}function M(t,n,r){return e(`sha256`).update(`${t}-${r}-${n}`).digest(`hex`).slice(0,16)}function N(e,t){return f(u(t),e).replace(/\\/g,`/`).replace(/\.(js|jsx|ts|tsx|mjs|cjs)$/,``)}function P(e){return e.replace(/\.(js|jsx|ts|tsx|mjs|cjs)$/,``)}function F(e,t,n){let r=d(t).toLowerCase();if(!O.has(r))return{nodes:[],edges:[]};let i=[],a=[],o=new Date().toISOString(),s=new Set,c=P(t),l=j(`module`,c,c);i.push({id:l,type:`module`,name:t,properties:{ext:r},sourcePath:t,createdAt:o});for(let{pattern:n,kind:r,exported:c}of k){let u=new RegExp(n.source,n.flags),d;for(;(d=u.exec(e))!==null;){let e=d[1],n=`${r}:${e}`;if(s.has(n))continue;s.add(n);let u=j(r,e,t);i.push({id:u,type:r,name:e,properties:{exported:c},sourcePath:t,createdAt:o}),a.push({id:M(l,u,`defines`),fromId:l,toId:u,type:`defines`,weight:c?1:.5})}}let u=n?.workspacePackages,f=new Set;for(let n of A){let r=new RegExp(n.source,n.flags),i;for(;(i=r.exec(e))!==null;){let e=i[1];if(f.has(e))continue;let n;if(e.startsWith(`.`))n=N(e,t);else if(u){let t=e.startsWith(`@`)?e.split(`/`).slice(0,2).join(`/`):e.split(`/`)[0],r=u.get(t);if(!r)continue;n=r}else continue;f.add(e);let r=P(n),o=j(`module`,r,r);a.push({id:M(l,o,`imports`),fromId:l,toId:o,type:`imports`,properties:{source:e}})}}return{nodes:i,edges:a}}const I=_(`hash-cache`);var L=class{cache;filePath;dirty=!1;constructor(e){this.filePath=m(e,`file-hashes.json`),this.cache=new Map}load(){if(t(this.filePath))try{let e=n(this.filePath,`utf-8`),t=JSON.parse(e);this.cache=new Map(Object.entries(t)),I.info(`Hash cache loaded`,{entries:this.cache.size})}catch(e){I.warn(`Hash cache load failed, starting fresh`,{err:e}),this.cache=new Map}}get(e){return this.cache.get(e)}set(e,t){this.cache.set(e,t),this.dirty=!0}delete(e){this.cache.delete(e)&&(this.dirty=!0)}flush(){if(this.dirty)try{let e={};for(let[t,n]of this.cache)e[t]=n;a(this.filePath,JSON.stringify(e),`utf-8`),this.dirty=!1}catch(e){I.warn(`Hash cache flush failed`,{err:e})}}clear(){this.cache.clear(),this.dirty=!0,this.flush()}get size(){return this.cache.size}};const R=_(`indexer`),z=()=>new Promise(e=>setImmediate(e));async function B(e,t,n,r){let i=0;async function a(){for(;i<e.length;){let n=i++;try{await t(e[n])}catch(t){r?.(e[n],t)}n%10==0&&await z()}}await Promise.all(Array.from({length:Math.min(n,e.length)},()=>a()))}function V(e){let t=x(),n=S()[0]/t;return n>1.5?2:n>1?Math.max(2,Math.floor(e/2)):e}const H=Math.max(2,Math.min(4,Math.floor(x()*.5)));var U=class{embedder;store;crawler;indexing=!1;graphStore;hashCache;get isIndexing(){return this.indexing}constructor(e,t){this.embedder=e,this.store=t,this.crawler=new D}normalizeChunkText(e){return e.replace(/^\/\/ File: [^\n]*\n?/,``).toLowerCase().replace(/\s+/g,` `).trim()}setGraphStore(e){this.graphStore=e}setHashCache(e){this.hashCache=e}async index(e,t){if(this.indexing)throw Error(`Indexing is already in progress`);this.indexing=!0;try{return await this.doIndex(e,t,{})}finally{this.indexing=!1}}async getChangedFiles(e){let t=e.indexing.concurrency??H,n=await this.crawlSources(e),{filesToProcess:r}=await this.planIndexWork(n,t,{});return r.map(e=>e.relativePath)}async indexFiles(e,t,n){if(this.indexing)throw Error(`Indexing is already in progress`);this.indexing=!0;try{return await this.doIndexFiles(e,t,n)}finally{this.indexing=!1}}async doIndex(e,t,n={}){let r=Date.now(),i=e.indexing.concurrency??H;t?.({phase:`crawling`,filesTotal:0,filesProcessed:0,chunksTotal:0,chunksProcessed:0});let a=await this.crawlSources(e),{filesToProcess:o,filesSkipped:s,pathsToRemove:c}=await this.planIndexWork(a,i,{skipHashCheck:n.skipHashCheck}),{filesProcessed:l,chunksCreated:u,chunksDeduped:d}=await this.processFiles(a,o,i,t,{graphCleared:n.graphCleared}),f=await this.cleanupRemovedFiles(c,i,o.length,l,u,t);return this.hashCache?.flush(),t?.({phase:`done`,filesTotal:o.length,filesProcessed:l,chunksTotal:u,chunksProcessed:u}),{filesProcessed:l,filesSkipped:s,chunksCreated:u,chunksDeduped:d,filesRemoved:f,durationMs:Date.now()-r}}async doIndexFiles(e,t,n){let r=Date.now(),i=e.indexing.concurrency??H,a=new Set(t);if(a.size===0)return{filesProcessed:0,filesSkipped:0,chunksCreated:0,chunksDeduped:0,filesRemoved:0,durationMs:Date.now()-r};n?.({phase:`crawling`,filesTotal:0,filesProcessed:0,chunksTotal:0,chunksProcessed:0});let o=await this.crawlSources(e),{filesToProcess:s,filesSkipped:c}=await this.planIndexWork(o,i,{requestedPaths:a}),{filesProcessed:l,chunksCreated:u,chunksDeduped:d}=await this.processFiles(o,s,i,n,{});return this.hashCache?.flush(),n?.({phase:`done`,filesTotal:s.length,filesProcessed:l,chunksTotal:u,chunksProcessed:u}),{filesProcessed:l,filesSkipped:c,chunksCreated:u,chunksDeduped:d,filesRemoved:0,durationMs:Date.now()-r}}async crawlSources(e){return(await Promise.all(e.sources.map(e=>this.crawler.crawl({rootDir:e.path,excludePatterns:e.excludePatterns})))).flat()}async planIndexWork(e,t,n){let r=n.requestedPaths,i;if(r){let t=e=>e.replace(/\\/g,`/`).toLowerCase(),n=new Set([...r].map(t));i=e.filter(e=>n.has(t(e.relativePath))||n.has(t(e.absolutePath)))}else i=e;if(n.skipHashCheck)return{filesToProcess:i,filesSkipped:0,pathsToRemove:[]};let a=r?[]:await this.getPathsToRemove(e),o=0,s=[];return await B(i,async e=>{let t=w(e.content);if(this.hashCache){if(this.hashCache.get(e.relativePath)===t){o++;return}}else{let n=await this.store.getBySourcePath(e.relativePath);if(n.length>0&&n[0].fileHash===t){o++;return}}s.push(e)},V(t),(e,t)=>R.error(`Hash check failed`,{sourcePath:e.relativePath,...y(t)})),{filesToProcess:s,filesSkipped:o,pathsToRemove:a}}async getPathsToRemove(e){let t=await this.store.listSourcePaths(),n=new Set(e.map(e=>e.relativePath));return t.filter(e=>!n.has(e)&&!e.startsWith(`${h.aiCurated}/`))}async buildWorkspacePackageMap(e){let t=new Map;for(let n of e)if(n.relativePath.endsWith(`package.json`))try{let e=JSON.parse(n.content);if(typeof e.name!=`string`||e.name.length===0)continue;let r=n.relativePath===`package.json`?``:n.relativePath.replace(/\/package\.json$/,``),i=``;if(typeof e.exports==`string`)i=e.exports;else if(e.exports&&typeof e.exports==`object`){let t=e.exports,n=t[`.`]??t;if(typeof n==`string`)i=n;else if(n&&typeof n==`object`){let e=n,t=e.import??e.module??e.default??e.require;typeof t==`string`&&(i=t)}}!i&&typeof e.module==`string`&&(i=e.module),!i&&typeof e.main==`string`&&(i=e.main);let a=i.replace(/^\.\//,``).replace(/^dist\//,`src/`).replace(/\.(ts|js|mjs|cjs|tsx|jsx)$/,``),o=a?r?`${r}/${a}`:a:r?`${r}/src/index`:`src/index`;t.set(e.name,o)}catch{}return t}async processFiles(t,n,r,i,a={}){let o=0,s=0,c=0,l=n.length,u=this.graphStore?await this.buildWorkspacePackageMap(t):void 0,d=new Map,f=[],p=[],m=0,h=[],g=[],_=new Map,b=0,x=async()=>{if(h.length===0)return;let e=h,t=g,n=_;h=[],g=[],_=new Map,b=0;try{await this.store.upsert(e,t);for(let[e,t]of n)this.hashCache?.set(e,t)}catch(r){h.push(...e),g.push(...t);for(let[e,t]of n)_.set(e,t);throw r}},S=async()=>{if(this.graphStore){try{f.length>0&&await this.graphStore.upsertNodes(f),p.length>0&&await this.graphStore.upsertEdges(p)}catch(e){R.warn(`Graph batch flush failed`,y(e))}f=[],p=[],m=0}};return await B(n,async t=>{i?.({phase:`chunking`,filesTotal:l,filesProcessed:o,chunksTotal:s,chunksProcessed:s,currentFile:t.relativePath});let n=v(t.relativePath),r=C(t.extension).chunk(t.content,{sourcePath:t.relativePath,contentType:n});if(r.length===0)return;let E=w(t.content),D=new Date().toISOString(),O=(e,n,r)=>({id:T(t.relativePath,n),content:e.text,sourcePath:e.sourcePath,contentType:e.contentType,headingPath:e.headingPath,chunkIndex:e.chunkIndex,totalChunks:e.totalChunks,startLine:e.startLine,endLine:e.endLine,fileHash:E,contentHash:r,indexedAt:D,origin:`indexed`,tags:[],version:1}),k=[],A=[];for(let t=0;t<r.length;t++){let n=r[t],i=e(`sha256`).update(this.normalizeChunkText(n.text)).digest(`hex`),a=O(n,t,i),o=d.get(i);if(o&&this.store.upsertWithoutVector){A.push({record:a,sourceRecordId:o}),c++;continue}d.set(i,a.id),k.push({chunk:n,record:a})}i?.({phase:`embedding`,filesTotal:l,filesProcessed:o,chunksTotal:s+r.length,chunksProcessed:s,currentFile:t.relativePath});let j=k.length>0?await this.embedder.embedBatch(k.map(({chunk:e})=>e.text)):[],M=k.map(({record:e})=>e);if(i?.({phase:`storing`,filesTotal:l,filesProcessed:o,chunksTotal:s+r.length,chunksProcessed:s,currentFile:t.relativePath}),M.length>0&&(h.push(...M),g.push(...j),_.set(t.relativePath,E),b++,b>=20&&await x()),A.length>0&&h.length>0&&await x(),this.store.upsertWithoutVector)for(let{record:e,sourceRecordId:t}of A)await this.store.upsertWithoutVector(e,t);if(M.length===0&&A.length>0&&this.hashCache?.set(t.relativePath,E),this.graphStore)try{a.graphCleared||await this.graphStore.deleteBySourcePath(t.relativePath);let e=F(t.content,t.relativePath,{workspacePackages:u});e.nodes.length>0&&f.push(...e.nodes),e.edges.length>0&&p.push(...e.edges),m++,m>=50&&await S()}catch(e){R.warn(`Graph extraction failed`,{sourcePath:t.relativePath,...y(e)})}o++,s+=r.length},V(r),(e,t)=>R.error(`Processing failed`,{sourcePath:e.relativePath,...y(t)})),await x(),await S(),{filesProcessed:o,chunksCreated:s,chunksDeduped:c}}async cleanupRemovedFiles(e,t,n,r,i,a){if(e.length===0)return 0;let o=0;return a?.({phase:`cleanup`,filesTotal:n,filesProcessed:r,chunksTotal:i,chunksProcessed:i}),await B(e,async e=>{await this.store.deleteBySourcePath(e),this.hashCache?.delete(e),this.graphStore&&await this.graphStore.deleteBySourcePath(e).catch(t=>R.warn(`Graph cleanup failed`,{sourcePath:e,...y(t)})),o++},V(t),(e,t)=>R.error(`Cleanup failed`,{sourcePath:e,...y(t)})),o}async reindexAll(e,t){if(this.indexing)throw Error(`Indexing is already in progress`);this.indexing=!0;try{if(await this.store.dropTable(),this.graphStore)try{let e=await this.graphStore.getStats();e.nodeCount>0&&(await this.graphStore.clear(),R.info(`Graph store cleared`,{nodeCount:e.nodeCount,edgeCount:e.edgeCount}))}catch(e){R.warn(`Graph store clear failed`,y(e))}return await this.doReindex(e,t)}catch(e){throw this.indexing=!1,e}}async doReindex(e,t){try{return await this.doIndex(e,t,{skipHashCheck:!0,graphCleared:!0})}finally{this.indexing=!1}}async getStats(){return this.store.getStats()}};const W=_(`smart-index`),G=1.5;var K=class{indexer;config;store;trickleTimer=null;stopped=!1;trickleIntervalMs;batchSize;priorityQueue=[];changedFiles=[];lastRefreshTime=0;refreshing=!1;constructor(e,t,n){this.indexer=e,this.config=t,this.store=n,this.trickleIntervalMs=t.indexing.trickleIntervalMs??this.readPositiveIntEnv(`AIKIT_SMART_TRICKLE_MS`,3e4),this.batchSize=t.indexing.trickleBatchSize??this.readPositiveIntEnv(`AIKIT_SMART_BATCH_SIZE`,1)}start(){this.trickleTimer&&=(clearTimeout(this.trickleTimer),null),this.stopped=!1,W.info(`Smart index scheduler started (trickle mode)`,{intervalMs:this.trickleIntervalMs,batchSize:this.batchSize}),this.scheduleTick()}stop(){this.stopped=!0,this.trickleTimer&&=(clearTimeout(this.trickleTimer),null)}prioritize(...e){let t=[...new Set(e.filter(Boolean))].filter(e=>{try{return!i(e).isDirectory()}catch{return W.debug(`Skipping non-existent path`,{path:e}),!1}});for(let e of t){let t=this.priorityQueue.indexOf(e);t>=0&&this.priorityQueue.splice(t,1)}for(let e of t.reverse())this.priorityQueue.unshift(e);this.priorityQueue.length>500&&(this.priorityQueue.length=500),t.length>0&&W.debug(`Files prioritized for trickle indexing`,{added:t.length,queued:this.priorityQueue.length})}getState(){return{mode:`smart`,queueSize:this.priorityQueue.length,changedFilesSize:this.changedFiles.length,intervalMs:this.trickleIntervalMs,batchSize:this.batchSize,running:this.trickleTimer!==null}}readPositiveIntEnv(e,t){let n=Number(process.env[e]);return Number.isFinite(n)&&n>0?n:t}scheduleTick(){this.trickleTimer=setTimeout(()=>void this.tick(),this.trickleIntervalMs),this.trickleTimer.unref&&this.trickleTimer.unref()}async tick(){if(!this.stopped)try{if(this.indexer.isIndexing){W.info(`Skipping trickle tick — indexing already in progress`);return}let e=this.getCpuCount(),t=S()[0];if(e>0&&t/e>G){W.info(`Skipping trickle tick — system load too high`,{load:t.toFixed(2),cpuCount:e,threshold:G});return}let n=await this.pickFiles();if(n.length===0){await this.maybeRefreshChangedFiles();return}W.debug(`Trickle indexing tick started`,{count:n.length,files:n});let r=await this.indexer.indexFiles(this.config,n);if(this.store)try{await this.store.createFtsIndex()}catch(e){W.warn(`FTS index rebuild failed after trickle tick`,{error:String(e)})}this.changedFiles=this.changedFiles.filter(e=>!n.includes(e)),W.debug(`Trickle indexing tick complete`,{filesProcessed:r.filesProcessed,filesSkipped:r.filesSkipped,chunksCreated:r.chunksCreated})}catch(e){let t=String(e);if(t.includes(`not initialized`)||t.includes(`has been closed`)){W.warn(`Store closed — stopping smart index scheduler`,{error:t}),this.stop();return}W.error(`Trickle indexing tick failed`,{error:t})}finally{this.stopped||this.scheduleTick()}}getCpuCount(){try{return typeof x==`function`?x():4}catch{return 4}}async pickFiles(){let e=[];for(;e.length<this.batchSize&&this.priorityQueue.length>0;){let t=this.priorityQueue.shift();t&&!e.includes(t)&&e.push(t)}if(e.length<this.batchSize)for(await this.maybeRefreshChangedFiles();e.length<this.batchSize&&this.changedFiles.length>0;){let t=this.changedFiles.shift();t&&!e.includes(t)&&e.push(t)}return e}async maybeRefreshChangedFiles(){let e=Date.now();if(!(this.refreshing||this.changedFiles.length>0&&e-this.lastRefreshTime<6e5)){this.refreshing=!0;try{this.changedFiles=await this.indexer.getChangedFiles(this.config),this.lastRefreshTime=e,this.changedFiles.length>0&&W.debug(`Refreshed changed files for trickle indexing`,{count:this.changedFiles.length})}catch(e){let t=String(e);if(t.includes(`not initialized`)||t.includes(`has been closed`)){W.warn(`Store closed — stopping smart index scheduler`,{error:t}),this.stop();return}W.error(`Failed to refresh changed files for trickle indexing`,{error:t})}finally{this.refreshing=!1}}}};export{L as FileHashCache,D as FilesystemCrawler,U as IncrementalIndexer,K as SmartIndexScheduler,F as extractGraph,T as generateRecordId,w as hashContent};
@@ -5,4 +5,4 @@ import{t as e}from"./rolldown-runtime-yuFVEuWy.js";import{createHash as t,random
5
5
  `).length,fileHash:this.hash(e.content),indexedAt:i,origin:`curated`,tags:e.frontmatter.tags,category:e.frontmatter.category,version:e.frontmatter.version}});return await this.store.upsert(a,r),{indexed:n.length,errors:t}}gitCommitKnowledge(e,t,n){try{if(!h(this.curatedDir))return;let r=this.knowledgeRefForPath(e);if(!r)return;g(r,`entry.md`,t,n,this.curatedDir)}catch{}}gitDeleteKnowledgeRef(e){try{if(!h(this.curatedDir))return;let t=this.knowledgeRefForPath(e);if(!t)return;_([`update-ref`,`-d`,t],this.curatedDir)}catch{}}knowledgeRefForPath(e){let t=e.replace(/\.md$/,``).split(`/`).map(e=>v(e)).join(`/`);return t.split(`/`).every(e=>m.test(e))?`${F}/${t}`:null}async indexCuratedFile(e,t,n){let r=await this.embedder.embed(t),i=`.ai/curated/${e}`,a=new Date().toISOString(),o={id:this.hashId(i,0),content:t,sourcePath:i,contentType:`curated-knowledge`,headingPath:n.title,chunkIndex:0,totalChunks:1,startLine:1,endLine:t.split(`
6
6
  `).length,fileHash:this.hash(t),indexedAt:a,origin:`curated`,tags:n.tags,category:n.category,version:n.version};await this.store.upsert([o],[r])}async indexCuratedFileBestEffort(e,t,n,r){if(d.instance().isDegraded(`embedder`)){I.debug(`Skipping vector indexing — embedder degraded`,{relativePath:e,operation:r,subsystem:`embedder`});return}try{await this.indexCuratedFile(e,t,n)}catch(t){I.warn(`Curated file persisted but vector indexing deferred`,{relativePath:e,operation:r,...p(t)})}}async discoverCategories(){return this.adapter.listDirectories()}guardPath(e){let t=e.replace(/^\.ai\/curated\//,``);if(t.endsWith(`.md`)||(t+=`.md`),t.includes(`..`)||a(t))throw Error(`Invalid path: ${t}. Must be relative within .ai/curated/ directory.`);let n=t.split(`/`)[0];return this.validateCategoryName(n),t}validateCategoryName(e){if(!/^[a-z][a-z0-9-]*$/.test(e))throw Error(`Invalid category name: "${e}". Must be lowercase kebab-case (e.g., "decisions", "api-contracts").`)}validateContentSize(e){if(Buffer.byteLength(e,`utf-8`)>P)throw Error(`Content exceeds maximum size of ${P/1024}KB`)}slugify(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-|-$/g,``).slice(0,80)}async uniqueRelativePath(e,t){let n=`${e}/${t}.md`;if(!await this.adapter.exists(n))return n;for(let n=2;n<=100;n++){let r=`${e}/${t}-${n}.md`;if(!await this.adapter.exists(r))return r}throw Error(`Too many entries with slug "${t}" in category "${e}"`)}hash(e){return t(`sha256`).update(e).digest(`hex`).slice(0,16)}hashId(e,t){return this.hash(`${e}::${t}`)}serializeFile(e,t){return`${[`---`,`title: "${t.title.replace(/"/g,`\\"`)}"`,`category: ${t.category}`,`tags: [${t.tags.map(e=>`"${e}"`).join(`, `)}]`,`created: ${t.created}`,`updated: ${t.updated}`,`version: ${t.version}`,`origin: ${t.origin}`,`changelog:`,...t.changelog.map(e=>` - version: ${e.version}\n date: ${e.date}\n reason: "${e.reason.replace(/"/g,`\\"`)}"`),`---`].join(`
7
7
  `)}\n\n${e}\n`}parseFile(e){let t=e.match(/^---\n([\s\S]*?)\n---\n\n?([\s\S]*)$/);if(!t)return{frontmatter:{title:`Untitled`,category:`notes`,tags:[],created:``,updated:``,version:1,origin:`curated`,changelog:[]},content:e};let n=t[1],r=t[2].trim(),i={},a=[],o=n.split(`
8
- `),s=!1,c={};for(let e of o){if(/^changelog:\s*$/.test(e)){s=!0;continue}if(s){let t=e.match(/^\s+-\s+version:\s*(\d+)$/);if(t){c.version!=null&&a.push(c),c={version:parseInt(t[1],10)};continue}let n=e.match(/^\s+date:\s*(.+)$/);if(n){c.date=n[1].trim();continue}let r=e.match(/^\s+reason:\s*"?(.*?)"?\s*$/);if(r){c.reason=r[1];continue}/^\w/.test(e)&&(s=!1,c.version!=null&&a.push(c),c={});continue}let t=e.match(/^(\w+):\s*(.*)$/);if(t){let e=t[1],n=t[2];typeof n==`string`&&n.startsWith(`[`)&&n.endsWith(`]`)?n=n.slice(1,-1).split(`,`).map(e=>e.trim().replace(/^"|"$/g,``)).filter(e=>e.length>0):typeof n==`string`&&/^\d+$/.test(n)?n=parseInt(n,10):typeof n==`string`&&n.startsWith(`"`)&&n.endsWith(`"`)&&(n=n.slice(1,-1)),i[e]=n}}return c.version!=null&&a.push(c),{frontmatter:{title:i.title??`Untitled`,category:i.category??`notes`,tags:i.tags??[],created:i.created??``,updated:i.updated??``,version:i.version??1,origin:`curated`,changelog:a},content:r}}};function R(){try{let e=s(i(c(import.meta.url)),`..`,`..`,`..`,`package.json`);return JSON.parse(r(e,`utf-8`)).version??`0.0.0`}catch{return`0.0.0`}}const z=f(`server`),B=/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/i;function V({requestOrigin:e,configuredOrigin:t,allowAnyOrigin:n,fallbackOrigin:r}){let i=t??r;return i===`*`?n?{allowOrigin:`*`,warn:!1}:e?B.test(e)?{allowOrigin:e,warn:!1}:{allowOrigin:null,warn:!0}:{allowOrigin:r,warn:!1}:{allowOrigin:i,warn:!1}}function H({limit:e,windowMs:t}){let n=new Map,r=(e,r)=>{let i=r-t,a=n.get(e)?.filter(e=>e>i)??[];return a.length===0?(n.delete(e),[]):(n.set(e,a),a)};return{allow(t,i=Date.now()){let a=r(t,i);return a.length>=e?!1:(a.push(i),n.set(t,a),!0)},getRetryAfterMs(n,i=Date.now()){let a=r(n,i);return a.length<e?0:Math.max(0,a[0]+t-i)}}}function U(){return process.env.AIKIT_TRANSPORT?process.env.AIKIT_TRANSPORT:process.stdin.isTTY?`http`:`stdio`}function W(){let e=process.argv[1];if(!e)return!1;try{return import.meta.url===l(e).href}catch{return!1}}function G(e){let t=e.headers[`mcp-session-id`];return Array.isArray(t)?t[0]:t}function K(e,t){let n=process.env[e];if(!n)return t;let r=Number.parseInt(n,10);return Number.isFinite(r)&&r>0?r:t}function q(){return W()?u({allowPositionals:!0,options:{transport:{type:`string`,default:U()},port:{type:`string`,default:process.env.AIKIT_PORT??`3210`}}}).values:{transport:U(),port:process.env.AIKIT_PORT??`3210`}}async function J(){let e=R(),t=q();process.on(`unhandledRejection`,e=>{z.error(`Unhandled rejection`,p(e))}),process.on(`uncaughtException`,e=>{z.error(`Uncaught exception — exiting`,p(e)),process.exit(1)});let r=(e,t)=>{e.then(async()=>{try{let{markPromoteRun:e,markPruneRun:n,prune:r,shouldRunStartupPrune:i,shouldRunWeeklyPromote:a}=await import(`../../tools/dist/index.js`),o=t();if(!o)return;if(i()){let e=await r({});n(),e.totalBytesFreed>0&&z.info(`Storage maintenance complete`,{forgeOrphans:e.forgeGroundOrphans.count,legacyLance:e.legacyLance.count,bytesFreed:e.totalBytesFreed});let{groupLessons:t,pruneLessons:i}=await import(`./evolution-DWaEE6XW.js`).then(e=>e.t),a=await i(o.curated,o.stateStore,{dryRun:!1});a.pruned.length>0&&z.info(`Startup lesson prune complete`,{pruned:a.pruned.length});let s=await t(o.curated,o.stateStore,{dryRun:!1});(s.groupsCreated>0||s.lessonsGrouped>0)&&z.info(`Startup lesson grouping complete`,{groupsCreated:s.groupsCreated,lessonsGrouped:s.lessonsGrouped})}if(a()){let{DEFAULT_PROMOTE_CONFIG:t,collectWorkspaceLessons:n,getGlobalCuratedDir:r,promoteLessons:i,scanForDuplicates:a}=await import(`./promotion-CJFYv4Ye.js`).then(e=>e.o),{CuratedKnowledgeManager:s}=await Promise.resolve().then(()=>N),c=o.curated,l=new s(r(),c.store,c.embedder),u=await n(),d={...t,dryRun:!1},f=await i(a(u,d),l,d);e(),f.promoted.length>0&&z.info(`Weekly lesson promotion complete`,{promoted:f.promoted.length,candidates:f.candidates.length})}}catch(e){z.warn(`Startup maintenance failed (non-critical)`,p(e))}}).catch(()=>{})};if(z.info(`Starting MCP AI Kit server`,{version:e}),t.transport===`http`){let[{default:e},{loadConfig:i,resolveIndexMode:a},{registerDashboardRoutes:o,resolveDashboardDir:s},{registerSettingsRoutes:c,resolveSettingsDir:l},{createSettingsRouter:u},{authMiddleware:d,getOrCreateToken:f}]=await Promise.all([import(`express`),import(`./config-8WXJx-zc.js`),import(`./dashboard-static-CRfR1yKU.js`),import(`./settings-static-B3lnYvcb.js`),import(`./routes-Afg7J7xK.js`),import(`./auth-lzZKfxlV.js`)]),m=i();z.info(`Config loaded`,{sourceCount:m.sources.length,storePath:m.store.path});let h=e();h.use(e.json({limit:`1mb`}));let g=Number(t.port),_=`http://localhost:${g}`,v=process.env.AIKIT_CORS_ORIGIN??_,y=process.env.AIKIT_ALLOW_ANY_ORIGIN===`true`,b=K(`AIKIT_HTTP_MAX_SESSIONS`,8),x=K(`AIKIT_HTTP_SESSION_TIMEOUT_MINUTES`,30),S=K(`AIKIT_HTTP_SESSION_GC_INTERVAL_MINUTES`,5),C=H({limit:100,windowMs:6e4}),w=!1;h.use((e,t,n)=>{let r=Array.isArray(e.headers.origin)?e.headers.origin[0]:e.headers.origin,i=V({requestOrigin:r,configuredOrigin:v,allowAnyOrigin:y,fallbackOrigin:_});if(i.warn&&!w&&(w=!0,z.warn(`Rejected non-local CORS origin while AIKIT_CORS_ORIGIN=*`,{origin:r,allowAnyOriginEnv:`AIKIT_ALLOW_ANY_ORIGIN=true`})),r&&!i.allowOrigin){t.status(403).json({error:`Origin not allowed`});return}if(i.allowOrigin&&t.setHeader(`Access-Control-Allow-Origin`,i.allowOrigin),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, PUT, PATCH, DELETE, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID`),t.setHeader(`Access-Control-Expose-Headers`,`Mcp-Session-Id`),e.method===`OPTIONS`){t.status(204).end();return}n()});let T=f();console.error(`[aikit] Auth token: ~/.aikit/token`),h.use(d(T)),h.use(`/mcp`,(e,t,n)=>{let r=G(e)??e.ip??e.socket.remoteAddress??`anonymous`;if(C.allow(r)){n();return}let i=Math.max(1,Math.ceil(C.getRetryAfterMs(r)/1e3));t.setHeader(`Retry-After`,String(i)),t.status(429).json({jsonrpc:`2.0`,error:{code:-32003,message:`Rate limit exceeded`},id:null})}),o(h,s(),z);let E=new Date().toISOString();h.use(`/settings/api`,u({log:z,mcpInfo:()=>({transport:`http`,port:g,pid:process.pid,startedAt:E})})),c(h,l(),z),h.get(`/health`,(e,t)=>{t.json({status:`ok`})});let D=!1,O=null,A=null,M=null,N=null,P=null,F=null,I=null,L=Promise.resolve(),R=async(e,t)=>{if(!D||!M||!N){t.status(503).json({jsonrpc:`2.0`,error:{code:-32603,message:`Server initializing — please retry in a few seconds`},id:null});return}let r=L,i;L=new Promise(e=>{i=e}),await r;try{let r=G(e);if(!F){if(r){t.status(404).json({jsonrpc:`2.0`,error:{code:-32001,message:`Session not found`},id:null});return}let e=new N({sessionIdGenerator:()=>n(),onsessioninitialized:async e=>{I=e,A?.onSessionStart(e,{transport:`http`})},onsessionclosed:async e=>{e&&A?.onSessionEnd(e),I=null}});e.onclose=()=>{F===e&&(F=null),I===e.sessionId&&(I=null)},F=e,await M.connect(e)}let i=F;await i.handleRequest(e,t,e.body),e.method!==`DELETE`&&(!r&&i.sessionId?(I=i.sessionId,A?.onSessionStart(i.sessionId,{transport:`http`}),A?.onSessionActivity(i.sessionId)):r&&A?.onSessionActivity(r))}catch(e){if(z.error(`MCP handler error`,p(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{i()}},B=async(e,t)=>{let n=G(e);if(P&&(!F||n!==I)){await P.handleRequest(e,t,e.body);return}await R(e,t)};h.post(`/mcp`,B),h.get(`/mcp`,B),h.delete(`/mcp`,B);let U=h.listen(g,`127.0.0.1`,()=>{z.info(`MCP server listening`,{url:`http://127.0.0.1:${g}/mcp`,port:g}),setTimeout(async()=>{try{let[{createLazyServer:e,createMcpServer:t,ALL_TOOL_NAMES:n},{StreamableHTTPServerTransport:i},{checkForUpdates:o,autoUpgradeScaffold:s}]=await Promise.all([import(`./server-Cw6VoN0q.js`),import(`@modelcontextprotocol/sdk/server/streamableHttp.js`),import(`./version-check-gazMo-D4.js`)]);o(),s();let c=a(m),l=e(m,c);M=l.server,N=i,D=!0,z.info(`MCP server configured (lazy — AI Kit initializing in background)`,{toolCount:n.length,resourceCount:2}),l.startInit(),l.ready.then(()=>{if(!l.aikit)throw Error(`AI Kit components are not available after initialization`);A=new j(l.aikit.stateStore,{staleTimeoutMinutes:x,gcIntervalMinutes:S,onBeforeSessionDelete:e=>{if(I===e&&F){let e=F;F=null,I=null,e.close().catch(()=>void 0)}P?.closeSession(e,{notifySessionEnd:!1})},onSessionEndMaintenance:async()=>{if(!l.aikit?.curated||!l.aikit?.stateStore)return;let{pruneLessons:e}=await import(`./evolution-DWaEE6XW.js`).then(e=>e.t),t=await e(l.aikit.curated,l.aikit.stateStore,{dryRun:!1});t.pruned.length>0&&z.info(`Session-end lesson prune`,{pruned:t.pruned.length})}}),P=new k({createServer:()=>{if(!l.aikit)throw Error(`AI Kit components are not available after initialization`);return t(l.aikit,m)},createTransport:e=>new i(e),maxSessions:b,sessionTimeoutMinutes:x,onSessionStart:e=>A?.onSessionStart(e,{transport:`http`}),onSessionActivity:e=>A?.onSessionActivity(e),onSessionEnd:e=>A?.onSessionEnd(e)}),A.startGC(),I&&(A.onSessionStart(I,{transport:`http`}),A.onSessionActivity(I)),z.info(`HTTP session runtime ready`,{maxSessions:b,sessionTimeoutMinutes:x,gcIntervalMinutes:S})}).catch(e=>z.error(`Failed to start session manager`,p(e))),c===`auto`?l.ready.then(async()=>{try{let e=m.sources.map(e=>e.path).join(`, `);z.info(`Running initial index`,{sourcePaths:e}),await l.runInitialIndex(),z.info(`Initial index complete`)}catch(e){z.error(`Initial index failed; will retry on aikit_reindex`,p(e))}}).catch(e=>z.error(`AI Kit init or indexing failed`,p(e))):c===`smart`?l.ready.then(async()=>{try{if(!l.aikit)throw Error(`AI Kit components are not available after initialization`);let{SmartIndexScheduler:e}=await import(`../../indexer/dist/index.js`),t=new e(l.aikit.indexer,m,l.aikit.store),n=l.aikit.store;O=t,t.start(),n.onBeforeClose&&n.onBeforeClose(()=>t.stop()),l.setSmartScheduler(t),z.info(`Smart index scheduler started (HTTP mode)`)}catch(e){z.error(`Failed to start smart index scheduler`,p(e))}}).catch(e=>z.error(`AI Kit initialization failed`,p(e))):(l.ready.catch(e=>z.error(`AI Kit initialization failed`,p(e))),z.info(`Initial full indexing skipped in HTTP mode`,{indexMode:c})),r(l.ready,()=>l.aikit?{curated:l.aikit.curated,stateStore:l.aikit.stateStore}:null)}catch(e){z.error(`Failed to load server modules`,p(e))}},100)}),W=async e=>{z.info(`Shutdown signal received`,{signal:e}),O?.stop(),A?.stop(),await P?.closeAll().catch(()=>void 0),I&&A?.onSessionEnd(I),F&&(await F.close().catch(()=>void 0),F=null,I=null),U.close(),M&&await M.close(),process.exit(0)};process.on(`SIGINT`,()=>W(`SIGINT`)),process.on(`SIGTERM`,()=>W(`SIGTERM`))}else{let[{loadConfig:e,reconfigureForWorkspace:t,resolveIndexMode:n},{createLazyServer:i},{checkForUpdates:a,autoUpgradeScaffold:o},{RootsListChangedNotificationSchema:s}]=await Promise.all([import(`./config-8WXJx-zc.js`),import(`./server-Cw6VoN0q.js`),import(`./version-check-gazMo-D4.js`),import(`@modelcontextprotocol/sdk/types.js`)]),l=e();z.info(`Config loaded`,{sourceCount:l.sources.length,storePath:l.store.path}),a(),o();let u=n(l),d=i(l,u),{server:f,startInit:m,ready:h,runInitialIndex:g}=d,{StdioServerTransport:_}=await import(`@modelcontextprotocol/sdk/server/stdio.js`),v=new _;await f.connect(v),z.info(`MCP server started`,{transport:`stdio`});let y=e=>{if(e.length===0)return!1;let n=e[0].uri,r=n.startsWith(`file://`)?c(n):n;return z.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://`)?c(t):t}),!0},b=!1;try{b=y((await f.server.listRoots()).roots),b||z.info(`No MCP roots yet; waiting for roots/list_changed notification`)}catch(e){z.warn(`MCP roots/list not supported by client; using cwd fallback`,{cwd:process.cwd(),...p(e)}),b=!0}b||=await new Promise(e=>{let t=setTimeout(()=>{z.warn(`Timed out waiting for MCP roots/list_changed; using cwd fallback`,{cwd:process.cwd()}),e(!1)},5e3);f.server.setNotificationHandler(s,async()=>{clearTimeout(t);try{e(y((await f.server.listRoots()).roots))}catch(t){z.warn(`roots/list retry failed after notification`,p(t)),e(!1)}})}),m();let x=null,S=()=>{x&&clearTimeout(x),x=setTimeout(async()=>{z.info(`Auto-shutdown: no activity for 30 minutes — shutting down gracefully`);try{let e=d.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=>{z.error(`Initialization failed — server will continue with limited tools`,p(e))}),u===`auto`?g().catch(e=>z.error(`Initial index failed`,p(e))):u===`smart`?h.then(async()=>{try{if(!d.aikit)throw Error(`AI Kit components are not available after initialization`);let{SmartIndexScheduler:e}=await import(`../../indexer/dist/index.js`),t=new e(d.aikit.indexer,l,d.aikit.store),n=d.aikit.store;t.start(),n.onBeforeClose&&n.onBeforeClose(()=>t.stop()),d.setSmartScheduler(t),z.info(`Smart index scheduler started (stdio mode)`)}catch(e){z.error(`Failed to start smart index scheduler`,p(e))}}).catch(e=>z.error(`AI Kit init failed for smart scheduler`,p(e))):z.warn(`Initial full indexing skipped; use aikit_reindex to index manually`,{indexMode:u}),r(h,()=>d.aikit?{curated:d.aikit.curated,stateStore:d.aikit.stateStore}:null)}}J();export{M as n,L as t};
8
+ `),s=!1,c={};for(let e of o){if(/^changelog:\s*$/.test(e)){s=!0;continue}if(s){let t=e.match(/^\s+-\s+version:\s*(\d+)$/);if(t){c.version!=null&&a.push(c),c={version:parseInt(t[1],10)};continue}let n=e.match(/^\s+date:\s*(.+)$/);if(n){c.date=n[1].trim();continue}let r=e.match(/^\s+reason:\s*"?(.*?)"?\s*$/);if(r){c.reason=r[1];continue}/^\w/.test(e)&&(s=!1,c.version!=null&&a.push(c),c={});continue}let t=e.match(/^(\w+):\s*(.*)$/);if(t){let e=t[1],n=t[2];typeof n==`string`&&n.startsWith(`[`)&&n.endsWith(`]`)?n=n.slice(1,-1).split(`,`).map(e=>e.trim().replace(/^"|"$/g,``)).filter(e=>e.length>0):typeof n==`string`&&/^\d+$/.test(n)?n=parseInt(n,10):typeof n==`string`&&n.startsWith(`"`)&&n.endsWith(`"`)&&(n=n.slice(1,-1)),i[e]=n}}return c.version!=null&&a.push(c),{frontmatter:{title:i.title??`Untitled`,category:i.category??`notes`,tags:i.tags??[],created:i.created??``,updated:i.updated??``,version:i.version??1,origin:`curated`,changelog:a},content:r}}};function R(){try{let e=s(i(c(import.meta.url)),`..`,`..`,`..`,`package.json`);return JSON.parse(r(e,`utf-8`)).version??`0.0.0`}catch{return`0.0.0`}}const z=f(`server`),B=/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/i;function V({requestOrigin:e,configuredOrigin:t,allowAnyOrigin:n,fallbackOrigin:r}){let i=t??r;return i===`*`?n?{allowOrigin:`*`,warn:!1}:e?B.test(e)?{allowOrigin:e,warn:!1}:{allowOrigin:null,warn:!0}:{allowOrigin:r,warn:!1}:{allowOrigin:i,warn:!1}}function H({limit:e,windowMs:t}){let n=new Map,r=(e,r)=>{let i=r-t,a=n.get(e)?.filter(e=>e>i)??[];return a.length===0?(n.delete(e),[]):(n.set(e,a),a)};return{allow(t,i=Date.now()){let a=r(t,i);return a.length>=e?!1:(a.push(i),n.set(t,a),!0)},getRetryAfterMs(n,i=Date.now()){let a=r(n,i);return a.length<e?0:Math.max(0,a[0]+t-i)}}}function U(){return process.env.AIKIT_TRANSPORT?process.env.AIKIT_TRANSPORT:process.stdin.isTTY?`http`:`stdio`}function W(){let e=process.argv[1];if(!e)return!1;try{return import.meta.url===l(e).href}catch{return!1}}function G(e){let t=e.headers[`mcp-session-id`];return Array.isArray(t)?t[0]:t}function K(e,t){let n=process.env[e];if(!n)return t;let r=Number.parseInt(n,10);return Number.isFinite(r)&&r>0?r:t}function q(){return W()?u({allowPositionals:!0,options:{transport:{type:`string`,default:U()},port:{type:`string`,default:process.env.AIKIT_PORT??`3210`}}}).values:{transport:U(),port:process.env.AIKIT_PORT??`3210`}}async function J(){let e=R(),t=q();process.on(`unhandledRejection`,e=>{z.error(`Unhandled rejection`,p(e))}),process.on(`uncaughtException`,e=>{z.error(`Uncaught exception — exiting`,p(e)),process.exit(1)});let r=(e,t)=>{e.then(async()=>{try{let{markPromoteRun:e,markPruneRun:n,prune:r,shouldRunStartupPrune:i,shouldRunWeeklyPromote:a}=await import(`../../tools/dist/index.js`),o=t();if(!o)return;if(i()){let e=await r({});n(),e.totalBytesFreed>0&&z.info(`Storage maintenance complete`,{forgeOrphans:e.forgeGroundOrphans.count,legacyLance:e.legacyLance.count,bytesFreed:e.totalBytesFreed});let{groupLessons:t,pruneLessons:i}=await import(`./evolution-DWaEE6XW.js`).then(e=>e.t),a=await i(o.curated,o.stateStore,{dryRun:!1});a.pruned.length>0&&z.info(`Startup lesson prune complete`,{pruned:a.pruned.length});let s=await t(o.curated,o.stateStore,{dryRun:!1});(s.groupsCreated>0||s.lessonsGrouped>0)&&z.info(`Startup lesson grouping complete`,{groupsCreated:s.groupsCreated,lessonsGrouped:s.lessonsGrouped})}if(a()){let{DEFAULT_PROMOTE_CONFIG:t,collectWorkspaceLessons:n,getGlobalCuratedDir:r,promoteLessons:i,scanForDuplicates:a}=await import(`./promotion-CJFYv4Ye.js`).then(e=>e.o),{CuratedKnowledgeManager:s}=await Promise.resolve().then(()=>N),c=o.curated,l=new s(r(),c.store,c.embedder),u=await n(),d={...t,dryRun:!1},f=await i(a(u,d),l,d);e(),f.promoted.length>0&&z.info(`Weekly lesson promotion complete`,{promoted:f.promoted.length,candidates:f.candidates.length})}}catch(e){z.warn(`Startup maintenance failed (non-critical)`,p(e))}}).catch(()=>{})};if(z.info(`Starting MCP AI Kit server`,{version:e}),t.transport===`http`){let[{default:e},{loadConfig:i,resolveIndexMode:a},{registerDashboardRoutes:o,resolveDashboardDir:s},{registerSettingsRoutes:c,resolveSettingsDir:l},{createSettingsRouter:u},{authMiddleware:d,getOrCreateToken:f}]=await Promise.all([import(`express`),import(`./config-8WXJx-zc.js`),import(`./dashboard-static-CRfR1yKU.js`),import(`./settings-static-B3lnYvcb.js`),import(`./routes-Afg7J7xK.js`),import(`./auth-lzZKfxlV.js`)]),m=i();z.info(`Config loaded`,{sourceCount:m.sources.length,storePath:m.store.path});let h=e();h.use(e.json({limit:`1mb`}));let g=Number(t.port),_=`http://localhost:${g}`,v=process.env.AIKIT_CORS_ORIGIN??_,y=process.env.AIKIT_ALLOW_ANY_ORIGIN===`true`,b=K(`AIKIT_HTTP_MAX_SESSIONS`,8),x=K(`AIKIT_HTTP_SESSION_TIMEOUT_MINUTES`,30),S=K(`AIKIT_HTTP_SESSION_GC_INTERVAL_MINUTES`,5),C=H({limit:100,windowMs:6e4}),w=!1;h.use((e,t,n)=>{let r=Array.isArray(e.headers.origin)?e.headers.origin[0]:e.headers.origin,i=V({requestOrigin:r,configuredOrigin:v,allowAnyOrigin:y,fallbackOrigin:_});if(i.warn&&!w&&(w=!0,z.warn(`Rejected non-local CORS origin while AIKIT_CORS_ORIGIN=*`,{origin:r,allowAnyOriginEnv:`AIKIT_ALLOW_ANY_ORIGIN=true`})),r&&!i.allowOrigin){t.status(403).json({error:`Origin not allowed`});return}if(i.allowOrigin&&t.setHeader(`Access-Control-Allow-Origin`,i.allowOrigin),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, PUT, PATCH, DELETE, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID`),t.setHeader(`Access-Control-Expose-Headers`,`Mcp-Session-Id`),e.method===`OPTIONS`){t.status(204).end();return}n()});let T=f();console.error(`[aikit] Auth token: ~/.aikit/token`),h.use(d(T)),h.use(`/mcp`,(e,t,n)=>{let r=G(e)??e.ip??e.socket.remoteAddress??`anonymous`;if(C.allow(r)){n();return}let i=Math.max(1,Math.ceil(C.getRetryAfterMs(r)/1e3));t.setHeader(`Retry-After`,String(i)),t.status(429).json({jsonrpc:`2.0`,error:{code:-32003,message:`Rate limit exceeded`},id:null})}),o(h,s(),z);let E=new Date().toISOString();h.use(`/settings/api`,u({log:z,mcpInfo:()=>({transport:`http`,port:g,pid:process.pid,startedAt:E})})),c(h,l(),z),h.get(`/health`,(e,t)=>{t.json({status:`ok`})});let D=!1,O=null,A=null,M=null,N=null,P=null,F=null,I=null,L=Promise.resolve(),R=async(e,t)=>{if(!D||!M||!N){t.status(503).json({jsonrpc:`2.0`,error:{code:-32603,message:`Server initializing — please retry in a few seconds`},id:null});return}let r=L,i;L=new Promise(e=>{i=e}),await r;try{let r=G(e);if(!F){if(r){t.status(404).json({jsonrpc:`2.0`,error:{code:-32001,message:`Session not found`},id:null});return}let e=new N({sessionIdGenerator:()=>n(),onsessioninitialized:async e=>{I=e,A?.onSessionStart(e,{transport:`http`})},onsessionclosed:async e=>{e&&A?.onSessionEnd(e),I=null}});e.onclose=()=>{F===e&&(F=null),I===e.sessionId&&(I=null)},F=e,await M.connect(e)}let i=F;await i.handleRequest(e,t,e.body),e.method!==`DELETE`&&(!r&&i.sessionId?(I=i.sessionId,A?.onSessionStart(i.sessionId,{transport:`http`}),A?.onSessionActivity(i.sessionId)):r&&A?.onSessionActivity(r))}catch(e){if(z.error(`MCP handler error`,p(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{i()}},B=async(e,t)=>{let n=G(e);if(P&&(!F||n!==I)){await P.handleRequest(e,t,e.body);return}await R(e,t)};h.post(`/mcp`,B),h.get(`/mcp`,B),h.delete(`/mcp`,B);let U=h.listen(g,`127.0.0.1`,()=>{z.info(`MCP server listening`,{url:`http://127.0.0.1:${g}/mcp`,port:g}),setTimeout(async()=>{try{let[{createLazyServer:e,createMcpServer:t,ALL_TOOL_NAMES:n},{StreamableHTTPServerTransport:i},{checkForUpdates:o,autoUpgradeScaffold:s}]=await Promise.all([import(`./server-Dawuk9A2.js`),import(`@modelcontextprotocol/sdk/server/streamableHttp.js`),import(`./version-check-gazMo-D4.js`)]);o(),s();let c=a(m),l=e(m,c);M=l.server,N=i,D=!0,z.info(`MCP server configured (lazy — AI Kit initializing in background)`,{toolCount:n.length,resourceCount:2}),l.startInit(),l.ready.then(()=>{if(!l.aikit)throw Error(`AI Kit components are not available after initialization`);A=new j(l.aikit.stateStore,{staleTimeoutMinutes:x,gcIntervalMinutes:S,onBeforeSessionDelete:e=>{if(I===e&&F){let e=F;F=null,I=null,e.close().catch(()=>void 0)}P?.closeSession(e,{notifySessionEnd:!1})},onSessionEndMaintenance:async()=>{if(!l.aikit?.curated||!l.aikit?.stateStore)return;let{pruneLessons:e}=await import(`./evolution-DWaEE6XW.js`).then(e=>e.t),t=await e(l.aikit.curated,l.aikit.stateStore,{dryRun:!1});t.pruned.length>0&&z.info(`Session-end lesson prune`,{pruned:t.pruned.length})}}),P=new k({createServer:()=>{if(!l.aikit)throw Error(`AI Kit components are not available after initialization`);return t(l.aikit,m)},createTransport:e=>new i(e),maxSessions:b,sessionTimeoutMinutes:x,onSessionStart:e=>A?.onSessionStart(e,{transport:`http`}),onSessionActivity:e=>A?.onSessionActivity(e),onSessionEnd:e=>A?.onSessionEnd(e)}),A.startGC(),I&&(A.onSessionStart(I,{transport:`http`}),A.onSessionActivity(I)),z.info(`HTTP session runtime ready`,{maxSessions:b,sessionTimeoutMinutes:x,gcIntervalMinutes:S})}).catch(e=>z.error(`Failed to start session manager`,p(e))),c===`auto`?l.ready.then(async()=>{try{let e=m.sources.map(e=>e.path).join(`, `);z.info(`Running initial index`,{sourcePaths:e}),await l.runInitialIndex(),z.info(`Initial index complete`)}catch(e){z.error(`Initial index failed; will retry on aikit_reindex`,p(e))}}).catch(e=>z.error(`AI Kit init or indexing failed`,p(e))):c===`smart`?l.ready.then(async()=>{try{if(!l.aikit)throw Error(`AI Kit components are not available after initialization`);let{SmartIndexScheduler:e}=await import(`../../indexer/dist/index.js`),t=new e(l.aikit.indexer,m,l.aikit.store),n=l.aikit.store;O=t,t.start(),n.onBeforeClose&&n.onBeforeClose(()=>t.stop()),l.setSmartScheduler(t),z.info(`Smart index scheduler started (HTTP mode)`)}catch(e){z.error(`Failed to start smart index scheduler`,p(e))}}).catch(e=>z.error(`AI Kit initialization failed`,p(e))):(l.ready.catch(e=>z.error(`AI Kit initialization failed`,p(e))),z.info(`Initial full indexing skipped in HTTP mode`,{indexMode:c})),r(l.ready,()=>l.aikit?{curated:l.aikit.curated,stateStore:l.aikit.stateStore}:null)}catch(e){z.error(`Failed to load server modules`,p(e))}},100)}),W=async e=>{z.info(`Shutdown signal received`,{signal:e}),O?.stop(),A?.stop(),await P?.closeAll().catch(()=>void 0),I&&A?.onSessionEnd(I),F&&(await F.close().catch(()=>void 0),F=null,I=null),U.close(),M&&await M.close(),process.exit(0)};process.on(`SIGINT`,()=>W(`SIGINT`)),process.on(`SIGTERM`,()=>W(`SIGTERM`))}else{let[{loadConfig:e,reconfigureForWorkspace:t,resolveIndexMode:n},{createLazyServer:i},{checkForUpdates:a,autoUpgradeScaffold:o},{RootsListChangedNotificationSchema:s}]=await Promise.all([import(`./config-8WXJx-zc.js`),import(`./server-Dawuk9A2.js`),import(`./version-check-gazMo-D4.js`),import(`@modelcontextprotocol/sdk/types.js`)]),l=e();z.info(`Config loaded`,{sourceCount:l.sources.length,storePath:l.store.path}),a(),o();let u=n(l),d=i(l,u),{server:f,startInit:m,ready:h,runInitialIndex:g}=d,{StdioServerTransport:_}=await import(`@modelcontextprotocol/sdk/server/stdio.js`),v=new _;await f.connect(v),z.info(`MCP server started`,{transport:`stdio`});let y=e=>{if(e.length===0)return!1;let n=e[0].uri,r=n.startsWith(`file://`)?c(n):n;return z.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://`)?c(t):t}),!0},b=!1;try{b=y((await f.server.listRoots()).roots),b||z.info(`No MCP roots yet; waiting for roots/list_changed notification`)}catch(e){z.warn(`MCP roots/list not supported by client; using cwd fallback`,{cwd:process.cwd(),...p(e)}),b=!0}b||=await new Promise(e=>{let t=setTimeout(()=>{z.warn(`Timed out waiting for MCP roots/list_changed; using cwd fallback`,{cwd:process.cwd()}),e(!1)},5e3);f.server.setNotificationHandler(s,async()=>{clearTimeout(t);try{e(y((await f.server.listRoots()).roots))}catch(t){z.warn(`roots/list retry failed after notification`,p(t)),e(!1)}})}),m();let x=null,S=()=>{x&&clearTimeout(x),x=setTimeout(async()=>{z.info(`Auto-shutdown: no activity for 30 minutes — shutting down gracefully`);try{let e=d.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=>{z.error(`Initialization failed — server will continue with limited tools`,p(e))}),u===`auto`?g().catch(e=>z.error(`Initial index failed`,p(e))):u===`smart`?h.then(async()=>{try{if(!d.aikit)throw Error(`AI Kit components are not available after initialization`);let{SmartIndexScheduler:e}=await import(`../../indexer/dist/index.js`),t=new e(d.aikit.indexer,l,d.aikit.store),n=d.aikit.store;t.start(),n.onBeforeClose&&n.onBeforeClose(()=>t.stop()),d.setSmartScheduler(t),z.info(`Smart index scheduler started (stdio mode)`)}catch(e){z.error(`Failed to start smart index scheduler`,p(e))}}).catch(e=>z.error(`AI Kit init failed for smart scheduler`,p(e))):z.warn(`Initial full indexing skipped; use aikit_reindex to index manually`,{indexMode:u}),r(h,()=>d.aikit?{curated:d.aikit.curated,stateStore:d.aikit.stateStore}:null)}}J();export{M as n,L as t};
@@ -1 +1 @@
1
- import{t as e}from"./curated-manager-CxKwx3Ym.js";import{randomUUID as t}from"node:crypto";import{readFileSync as n}from"node:fs";import{dirname as r,resolve as i}from"node:path";import{fileURLToPath as a,pathToFileURL as o}from"node:url";import{parseArgs as s}from"node:util";import{createLogger as c,serializeError as l}from"../../core/dist/index.js";const u=`__pending__:`;function d(e){return e.startsWith(u)}function f(e){let t=e.headers[`mcp-session-id`];return Array.isArray(t)?t[0]:t}function p(e,t,n,r){e.status(t).json({jsonrpc:`2.0`,error:{code:n,message:r},id:null})}var m=class{options;runtimes=new Map;maxSessions;sessionTimeoutMs;now;constructor(e){this.options=e,this.maxSessions=e.maxSessions??8,this.sessionTimeoutMs=(e.sessionTimeoutMinutes??30)*60*1e3,this.now=e.now??(()=>Date.now())}hasSession(e){return this.runtimes.has(e)}getSessionCount(){return this.runtimes.size}async handleRequest(e,t,n=e.body){let r=f(e),i=r?this.runtimes.get(r):void 0;if(r&&!i){p(t,404,-32001,`Session not found`);return}if(!i){if(e.method!==`POST`){p(t,400,-32e3,`Session required`);return}if(i=await this.createRuntime(t),!i)return}await this.withRuntimeLock(i,async()=>{await i.transport.handleRequest(e,t,n),i.lastAccessAt=this.now();let r=i.transport.sessionId??i.id;e.method!==`DELETE`&&!d(r)&&this.options.onSessionActivity?.(r),e.method===`DELETE`&&!d(r)&&await this.closeSession(r,{closeTransport:!1})})}async closeExpiredSessions(){let e=[...this.runtimes.values()].filter(e=>this.now()-e.lastAccessAt>=this.sessionTimeoutMs).map(e=>e.id);for(let t of e)await this.closeSession(t);return e.length}async closeSession(e,t={}){let n=this.runtimes.get(e);return n?(this.runtimes.delete(e),t.notifySessionEnd!==!1&&!d(e)&&this.options.onSessionEnd?.(e),t.closeTransport!==!1&&await n.transport.close().catch(()=>void 0),await n.server.close().catch(()=>void 0),!0):!1}async closeAll(){let e=[...this.runtimes.keys()];for(let t of e)await this.closeSession(t)}async createRuntime(e){if(await this.closeExpiredSessions(),this.runtimes.size>=this.maxSessions){p(e,503,-32003,`Session capacity reached`);return}let n=this.now(),r=await this.options.createServer(),i={id:`${u}${t()}`,transport:void 0,createdAt:n,lastAccessAt:n,server:r,requestChain:Promise.resolve()},a=this.options.createTransport({sessionIdGenerator:()=>t(),onsessioninitialized:async e=>{this.runtimes.delete(i.id),i.id=e,this.runtimes.set(e,i),this.options.onSessionStart?.(e)},onsessionclosed:async e=>{e&&await this.closeSession(e,{closeTransport:!1})}});return i.transport=a,a.onclose=()=>{let e=i.transport.sessionId??i.id;this.closeSession(e,{closeTransport:!1})},this.runtimes.set(i.id,i),await r.connect(a),i}async withRuntimeLock(e,t){let n=e.requestChain,r;e.requestChain=new Promise(e=>{r=e}),await n;try{await t()}finally{r()}}};function h(e){let t=e.includes(`T`)?e:`${e.replace(` `,`T`)}Z`;return Date.parse(t)}var g=class{stateStore;options;gcTimer=null;constructor(e,t={}){this.stateStore=e,this.options=t}onSessionStart(e,t){this.stateStore.sessionCreate(e,t)}onSessionActivity(e){this.stateStore.sessionTouch(e)}onSessionEnd(e){this.stateStore.sessionDelete(e),Promise.resolve(this.options.onSessionEndMaintenance?.(e)).catch(()=>{})}startGC(){if(this.gcTimer)return;let e=(this.options.gcIntervalMinutes??5)*60*1e3;this.gcTimer=setInterval(()=>{this.runGC()},e),this.gcTimer.unref()}runGC(){let e=this.getStaleSessionIds();for(let t of e)this.options.onBeforeSessionDelete?.(t),Promise.resolve(this.options.onSessionEndMaintenance?.(t)).catch(()=>{}),this.stateStore.sessionDelete(t);return e.length}stop(){this.gcTimer&&=(clearInterval(this.gcTimer),null)}getActiveSessions(){return this.stateStore.sessionList().length}listSessions(){return this.stateStore.sessionList()}getStaleSessionIds(e=Date.now()){let t=(this.options.staleTimeoutMinutes??30)*60*1e3;return this.stateStore.sessionList().filter(n=>{let r=h(n.lastActivity);return Number.isFinite(r)&&e-r>=t}).map(e=>e.sessionId)}};function _(){try{let e=i(r(a(import.meta.url)),`..`,`..`,`..`,`package.json`);return JSON.parse(n(e,`utf-8`)).version??`0.0.0`}catch{return`0.0.0`}}const v=c(`server`),y=/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/i;function b({requestOrigin:e,configuredOrigin:t,allowAnyOrigin:n,fallbackOrigin:r}){let i=t??r;return i===`*`?n?{allowOrigin:`*`,warn:!1}:e?y.test(e)?{allowOrigin:e,warn:!1}:{allowOrigin:null,warn:!0}:{allowOrigin:r,warn:!1}:{allowOrigin:i,warn:!1}}function x({limit:e,windowMs:t}){let n=new Map,r=(e,r)=>{let i=r-t,a=n.get(e)?.filter(e=>e>i)??[];return a.length===0?(n.delete(e),[]):(n.set(e,a),a)};return{allow(t,i=Date.now()){let a=r(t,i);return a.length>=e?!1:(a.push(i),n.set(t,a),!0)},getRetryAfterMs(n,i=Date.now()){let a=r(n,i);return a.length<e?0:Math.max(0,a[0]+t-i)}}}function S(){return process.env.AIKIT_TRANSPORT?process.env.AIKIT_TRANSPORT:process.stdin.isTTY?`http`:`stdio`}function C(){let e=process.argv[1];if(!e)return!1;try{return import.meta.url===o(e).href}catch{return!1}}function w(e){let t=e.headers[`mcp-session-id`];return Array.isArray(t)?t[0]:t}function T(e,t){let n=process.env[e];if(!n)return t;let r=Number.parseInt(n,10);return Number.isFinite(r)&&r>0?r:t}function E(){return C()?s({allowPositionals:!0,options:{transport:{type:`string`,default:S()},port:{type:`string`,default:process.env.AIKIT_PORT??`3210`}}}).values:{transport:S(),port:process.env.AIKIT_PORT??`3210`}}async function D(){let e=_(),n=E();process.on(`unhandledRejection`,e=>{v.error(`Unhandled rejection`,l(e))}),process.on(`uncaughtException`,e=>{v.error(`Uncaught exception — exiting`,l(e)),process.exit(1)});let r=(e,t)=>{e.then(async()=>{try{let{markPromoteRun:e,markPruneRun:n,prune:r,shouldRunStartupPrune:i,shouldRunWeeklyPromote:a}=await import(`../../tools/dist/index.js`),o=t();if(!o)return;if(i()){let e=await r({});n(),e.totalBytesFreed>0&&v.info(`Storage maintenance complete`,{forgeOrphans:e.forgeGroundOrphans.count,legacyLance:e.legacyLance.count,bytesFreed:e.totalBytesFreed});let{groupLessons:t,pruneLessons:i}=await import(`./evolution-BX_zTSdj.js`).then(e=>e.t),a=await i(o.curated,o.stateStore,{dryRun:!1});a.pruned.length>0&&v.info(`Startup lesson prune complete`,{pruned:a.pruned.length});let s=await t(o.curated,o.stateStore,{dryRun:!1});(s.groupsCreated>0||s.lessonsGrouped>0)&&v.info(`Startup lesson grouping complete`,{groupsCreated:s.groupsCreated,lessonsGrouped:s.lessonsGrouped})}if(a()){let{DEFAULT_PROMOTE_CONFIG:t,collectWorkspaceLessons:n,getGlobalCuratedDir:r,promoteLessons:i,scanForDuplicates:a}=await import(`./promotion-VH4M_cWb.js`).then(e=>e.o),{CuratedKnowledgeManager:s}=await import(`./curated-manager-CxKwx3Ym.js`).then(e=>e.n),c=o.curated,l=new s(r(),c.store,c.embedder),u=await n(),d={...t,dryRun:!1},f=await i(a(u,d),l,d);e(),f.promoted.length>0&&v.info(`Weekly lesson promotion complete`,{promoted:f.promoted.length,candidates:f.candidates.length})}}catch(e){v.warn(`Startup maintenance failed (non-critical)`,l(e))}}).catch(()=>{})};if(v.info(`Starting MCP AI Kit server`,{version:e}),n.transport===`http`){let[{default:e},{loadConfig:i,resolveIndexMode:a},{registerDashboardRoutes:o,resolveDashboardDir:s},{registerSettingsRoutes:c,resolveSettingsDir:u},{createSettingsRouter:d},{authMiddleware:f,getOrCreateToken:p}]=await Promise.all([import(`express`),import(`./config-C35F4tJm.js`),import(`./dashboard-static-FmfoS46e.js`),import(`./settings-static-BtvyIrza.js`),import(`./routes-CR3fI-HJ.js`),import(`./auth-Bz5dmZgR.js`).then(e=>e.t)]),h=i();v.info(`Config loaded`,{sourceCount:h.sources.length,storePath:h.store.path});let _=e();_.use(e.json({limit:`1mb`}));let y=Number(n.port),S=`http://localhost:${y}`,C=process.env.AIKIT_CORS_ORIGIN??S,E=process.env.AIKIT_ALLOW_ANY_ORIGIN===`true`,D=T(`AIKIT_HTTP_MAX_SESSIONS`,8),O=T(`AIKIT_HTTP_SESSION_TIMEOUT_MINUTES`,30),k=T(`AIKIT_HTTP_SESSION_GC_INTERVAL_MINUTES`,5),A=x({limit:100,windowMs:6e4}),j=!1;_.use((e,t,n)=>{let r=Array.isArray(e.headers.origin)?e.headers.origin[0]:e.headers.origin,i=b({requestOrigin:r,configuredOrigin:C,allowAnyOrigin:E,fallbackOrigin:S});if(i.warn&&!j&&(j=!0,v.warn(`Rejected non-local CORS origin while AIKIT_CORS_ORIGIN=*`,{origin:r,allowAnyOriginEnv:`AIKIT_ALLOW_ANY_ORIGIN=true`})),r&&!i.allowOrigin){t.status(403).json({error:`Origin not allowed`});return}if(i.allowOrigin&&t.setHeader(`Access-Control-Allow-Origin`,i.allowOrigin),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, PUT, PATCH, DELETE, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID`),t.setHeader(`Access-Control-Expose-Headers`,`Mcp-Session-Id`),e.method===`OPTIONS`){t.status(204).end();return}n()});let M=p();console.error(`[aikit] Auth token: ~/.aikit/token`),_.use(f(M)),_.use(`/mcp`,(e,t,n)=>{let r=w(e)??e.ip??e.socket.remoteAddress??`anonymous`;if(A.allow(r)){n();return}let i=Math.max(1,Math.ceil(A.getRetryAfterMs(r)/1e3));t.setHeader(`Retry-After`,String(i)),t.status(429).json({jsonrpc:`2.0`,error:{code:-32003,message:`Rate limit exceeded`},id:null})}),o(_,s(),v);let N=new Date().toISOString();_.use(`/settings/api`,d({log:v,mcpInfo:()=>({transport:`http`,port:y,pid:process.pid,startedAt:N})})),c(_,u(),v),_.get(`/health`,(e,t)=>{t.json({status:`ok`})});let P=!1,F=null,I=null,L=null,R=null,z=null,B=null,V=null,H=Promise.resolve(),U=async(e,n)=>{if(!P||!L||!R){n.status(503).json({jsonrpc:`2.0`,error:{code:-32603,message:`Server initializing — please retry in a few seconds`},id:null});return}let r=H,i;H=new Promise(e=>{i=e}),await r;try{let r=w(e);if(!B){if(r){n.status(404).json({jsonrpc:`2.0`,error:{code:-32001,message:`Session not found`},id:null});return}let e=new R({sessionIdGenerator:()=>t(),onsessioninitialized:async e=>{V=e,I?.onSessionStart(e,{transport:`http`})},onsessionclosed:async e=>{e&&I?.onSessionEnd(e),V=null}});e.onclose=()=>{B===e&&(B=null),V===e.sessionId&&(V=null)},B=e,await L.connect(e)}let i=B;await i.handleRequest(e,n,e.body),e.method!==`DELETE`&&(!r&&i.sessionId?(V=i.sessionId,I?.onSessionStart(i.sessionId,{transport:`http`}),I?.onSessionActivity(i.sessionId)):r&&I?.onSessionActivity(r))}catch(e){if(v.error(`MCP handler error`,l(e)),!n.headersSent){let t=e instanceof Error?e.message:String(e),r=t.includes(`Not Acceptable`);n.status(r?406:500).json({jsonrpc:`2.0`,error:{code:r?-32e3:-32603,message:r?t:`Internal server error`},id:null})}}finally{i()}},W=async(e,t)=>{let n=w(e);if(z&&(!B||n!==V)){await z.handleRequest(e,t,e.body);return}await U(e,t)};_.post(`/mcp`,W),_.get(`/mcp`,W),_.delete(`/mcp`,W);let G=_.listen(y,`127.0.0.1`,()=>{v.info(`MCP server listening`,{url:`http://127.0.0.1:${y}/mcp`,port:y}),setTimeout(async()=>{try{let[{createLazyServer:e,createMcpServer:t,ALL_TOOL_NAMES:n},{StreamableHTTPServerTransport:i},{checkForUpdates:o,autoUpgradeScaffold:s}]=await Promise.all([import(`./server-RQkMdvwT.js`),import(`@modelcontextprotocol/sdk/server/streamableHttp.js`),import(`./version-check-BgHzxxCW.js`)]);o(),s();let c=a(h),u=e(h,c);L=u.server,R=i,P=!0,v.info(`MCP server configured (lazy — AI Kit initializing in background)`,{toolCount:n.length,resourceCount:2}),u.startInit(),u.ready.then(()=>{if(!u.aikit)throw Error(`AI Kit components are not available after initialization`);I=new g(u.aikit.stateStore,{staleTimeoutMinutes:O,gcIntervalMinutes:k,onBeforeSessionDelete:e=>{if(V===e&&B){let e=B;B=null,V=null,e.close().catch(()=>void 0)}z?.closeSession(e,{notifySessionEnd:!1})},onSessionEndMaintenance:async()=>{if(!u.aikit?.curated||!u.aikit?.stateStore)return;let{pruneLessons:e}=await import(`./evolution-BX_zTSdj.js`).then(e=>e.t),t=await e(u.aikit.curated,u.aikit.stateStore,{dryRun:!1});t.pruned.length>0&&v.info(`Session-end lesson prune`,{pruned:t.pruned.length})}}),z=new m({createServer:()=>{if(!u.aikit)throw Error(`AI Kit components are not available after initialization`);return t(u.aikit,h)},createTransport:e=>new i(e),maxSessions:D,sessionTimeoutMinutes:O,onSessionStart:e=>I?.onSessionStart(e,{transport:`http`}),onSessionActivity:e=>I?.onSessionActivity(e),onSessionEnd:e=>I?.onSessionEnd(e)}),I.startGC(),V&&(I.onSessionStart(V,{transport:`http`}),I.onSessionActivity(V)),v.info(`HTTP session runtime ready`,{maxSessions:D,sessionTimeoutMinutes:O,gcIntervalMinutes:k})}).catch(e=>v.error(`Failed to start session manager`,l(e))),c===`auto`?u.ready.then(async()=>{try{let e=h.sources.map(e=>e.path).join(`, `);v.info(`Running initial index`,{sourcePaths:e}),await u.runInitialIndex(),v.info(`Initial index complete`)}catch(e){v.error(`Initial index failed; will retry on aikit_reindex`,l(e))}}).catch(e=>v.error(`AI Kit init or indexing failed`,l(e))):c===`smart`?u.ready.then(async()=>{try{if(!u.aikit)throw Error(`AI Kit components are not available after initialization`);let{SmartIndexScheduler:e}=await import(`../../indexer/dist/index.js`),t=new e(u.aikit.indexer,h,u.aikit.store),n=u.aikit.store;F=t,t.start(),n.onBeforeClose&&n.onBeforeClose(()=>t.stop()),u.setSmartScheduler(t),v.info(`Smart index scheduler started (HTTP mode)`)}catch(e){v.error(`Failed to start smart index scheduler`,l(e))}}).catch(e=>v.error(`AI Kit initialization failed`,l(e))):(u.ready.catch(e=>v.error(`AI Kit initialization failed`,l(e))),v.info(`Initial full indexing skipped in HTTP mode`,{indexMode:c})),r(u.ready,()=>u.aikit?{curated:u.aikit.curated,stateStore:u.aikit.stateStore}:null)}catch(e){v.error(`Failed to load server modules`,l(e))}},100)}),K=async e=>{v.info(`Shutdown signal received`,{signal:e}),F?.stop(),I?.stop(),await z?.closeAll().catch(()=>void 0),V&&I?.onSessionEnd(V),B&&(await B.close().catch(()=>void 0),B=null,V=null),G.close(),L&&await L.close(),process.exit(0)};process.on(`SIGINT`,()=>K(`SIGINT`)),process.on(`SIGTERM`,()=>K(`SIGTERM`))}else{let[{loadConfig:e,reconfigureForWorkspace:t,resolveIndexMode:n},{createLazyServer:i},{checkForUpdates:o,autoUpgradeScaffold:s},{RootsListChangedNotificationSchema:c}]=await Promise.all([import(`./config-C35F4tJm.js`),import(`./server-RQkMdvwT.js`),import(`./version-check-BgHzxxCW.js`),import(`@modelcontextprotocol/sdk/types.js`)]),u=e();v.info(`Config loaded`,{sourceCount:u.sources.length,storePath:u.store.path}),o(),s();let d=n(u),f=i(u,d),{server:p,startInit:m,ready:h,runInitialIndex:g}=f,{StdioServerTransport:_}=await import(`@modelcontextprotocol/sdk/server/stdio.js`),y=new _;await p.connect(y),v.info(`MCP server started`,{transport:`stdio`});let b=e=>{if(e.length===0)return!1;let n=e[0].uri,r=n.startsWith(`file://`)?a(n):n;return v.info(`MCP roots resolved`,{rootUri:n,rootPath:r,rootCount:e.length}),t(u,r),u.allRoots=e.map(e=>{let t=e.uri;return t.startsWith(`file://`)?a(t):t}),!0},x=!1;try{x=b((await p.server.listRoots()).roots),x||v.info(`No MCP roots yet; waiting for roots/list_changed notification`)}catch(e){v.warn(`MCP roots/list not supported by client; using cwd fallback`,{cwd:process.cwd(),...l(e)}),x=!0}x||=await new Promise(e=>{let t=setTimeout(()=>{v.warn(`Timed out waiting for MCP roots/list_changed; using cwd fallback`,{cwd:process.cwd()}),e(!1)},5e3);p.server.setNotificationHandler(c,async()=>{clearTimeout(t);try{e(b((await p.server.listRoots()).roots))}catch(t){v.warn(`roots/list retry failed after notification`,l(t)),e(!1)}})}),m();let S=null,C=()=>{S&&clearTimeout(S),S=setTimeout(async()=>{v.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),S.unref&&S.unref()};C(),process.stdin.on(`data`,()=>C()),h.catch(e=>{v.error(`Initialization failed — server will continue with limited tools`,l(e))}),d===`auto`?g().catch(e=>v.error(`Initial index failed`,l(e))):d===`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,u,f.aikit.store),n=f.aikit.store;t.start(),n.onBeforeClose&&n.onBeforeClose(()=>t.stop()),f.setSmartScheduler(t),v.info(`Smart index scheduler started (stdio mode)`)}catch(e){v.error(`Failed to start smart index scheduler`,l(e))}}).catch(e=>v.error(`AI Kit init failed for smart scheduler`,l(e))):v.warn(`Initial full indexing skipped; use aikit_reindex to index manually`,{indexMode:d}),r(h,()=>f.aikit?{curated:f.aikit.curated,stateStore:f.aikit.stateStore}:null)}}export{e as CuratedKnowledgeManager,x as createSlidingWindowRateLimiter,D as main,b as resolveCorsOrigin};
1
+ import{t as e}from"./curated-manager-CxKwx3Ym.js";import{randomUUID as t}from"node:crypto";import{readFileSync as n}from"node:fs";import{dirname as r,resolve as i}from"node:path";import{fileURLToPath as a,pathToFileURL as o}from"node:url";import{parseArgs as s}from"node:util";import{createLogger as c,serializeError as l}from"../../core/dist/index.js";const u=`__pending__:`;function d(e){return e.startsWith(u)}function f(e){let t=e.headers[`mcp-session-id`];return Array.isArray(t)?t[0]:t}function p(e,t,n,r){e.status(t).json({jsonrpc:`2.0`,error:{code:n,message:r},id:null})}var m=class{options;runtimes=new Map;maxSessions;sessionTimeoutMs;now;constructor(e){this.options=e,this.maxSessions=e.maxSessions??8,this.sessionTimeoutMs=(e.sessionTimeoutMinutes??30)*60*1e3,this.now=e.now??(()=>Date.now())}hasSession(e){return this.runtimes.has(e)}getSessionCount(){return this.runtimes.size}async handleRequest(e,t,n=e.body){let r=f(e),i=r?this.runtimes.get(r):void 0;if(r&&!i){p(t,404,-32001,`Session not found`);return}if(!i){if(e.method!==`POST`){p(t,400,-32e3,`Session required`);return}if(i=await this.createRuntime(t),!i)return}await this.withRuntimeLock(i,async()=>{await i.transport.handleRequest(e,t,n),i.lastAccessAt=this.now();let r=i.transport.sessionId??i.id;e.method!==`DELETE`&&!d(r)&&this.options.onSessionActivity?.(r),e.method===`DELETE`&&!d(r)&&await this.closeSession(r,{closeTransport:!1})})}async closeExpiredSessions(){let e=[...this.runtimes.values()].filter(e=>this.now()-e.lastAccessAt>=this.sessionTimeoutMs).map(e=>e.id);for(let t of e)await this.closeSession(t);return e.length}async closeSession(e,t={}){let n=this.runtimes.get(e);return n?(this.runtimes.delete(e),t.notifySessionEnd!==!1&&!d(e)&&this.options.onSessionEnd?.(e),t.closeTransport!==!1&&await n.transport.close().catch(()=>void 0),await n.server.close().catch(()=>void 0),!0):!1}async closeAll(){let e=[...this.runtimes.keys()];for(let t of e)await this.closeSession(t)}async createRuntime(e){if(await this.closeExpiredSessions(),this.runtimes.size>=this.maxSessions){p(e,503,-32003,`Session capacity reached`);return}let n=this.now(),r=await this.options.createServer(),i={id:`${u}${t()}`,transport:void 0,createdAt:n,lastAccessAt:n,server:r,requestChain:Promise.resolve()},a=this.options.createTransport({sessionIdGenerator:()=>t(),onsessioninitialized:async e=>{this.runtimes.delete(i.id),i.id=e,this.runtimes.set(e,i),this.options.onSessionStart?.(e)},onsessionclosed:async e=>{e&&await this.closeSession(e,{closeTransport:!1})}});return i.transport=a,a.onclose=()=>{let e=i.transport.sessionId??i.id;this.closeSession(e,{closeTransport:!1})},this.runtimes.set(i.id,i),await r.connect(a),i}async withRuntimeLock(e,t){let n=e.requestChain,r;e.requestChain=new Promise(e=>{r=e}),await n;try{await t()}finally{r()}}};function h(e){let t=e.includes(`T`)?e:`${e.replace(` `,`T`)}Z`;return Date.parse(t)}var g=class{stateStore;options;gcTimer=null;constructor(e,t={}){this.stateStore=e,this.options=t}onSessionStart(e,t){this.stateStore.sessionCreate(e,t)}onSessionActivity(e){this.stateStore.sessionTouch(e)}onSessionEnd(e){this.stateStore.sessionDelete(e),Promise.resolve(this.options.onSessionEndMaintenance?.(e)).catch(()=>{})}startGC(){if(this.gcTimer)return;let e=(this.options.gcIntervalMinutes??5)*60*1e3;this.gcTimer=setInterval(()=>{this.runGC()},e),this.gcTimer.unref()}runGC(){let e=this.getStaleSessionIds();for(let t of e)this.options.onBeforeSessionDelete?.(t),Promise.resolve(this.options.onSessionEndMaintenance?.(t)).catch(()=>{}),this.stateStore.sessionDelete(t);return e.length}stop(){this.gcTimer&&=(clearInterval(this.gcTimer),null)}getActiveSessions(){return this.stateStore.sessionList().length}listSessions(){return this.stateStore.sessionList()}getStaleSessionIds(e=Date.now()){let t=(this.options.staleTimeoutMinutes??30)*60*1e3;return this.stateStore.sessionList().filter(n=>{let r=h(n.lastActivity);return Number.isFinite(r)&&e-r>=t}).map(e=>e.sessionId)}};function _(){try{let e=i(r(a(import.meta.url)),`..`,`..`,`..`,`package.json`);return JSON.parse(n(e,`utf-8`)).version??`0.0.0`}catch{return`0.0.0`}}const v=c(`server`),y=/^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/i;function b({requestOrigin:e,configuredOrigin:t,allowAnyOrigin:n,fallbackOrigin:r}){let i=t??r;return i===`*`?n?{allowOrigin:`*`,warn:!1}:e?y.test(e)?{allowOrigin:e,warn:!1}:{allowOrigin:null,warn:!0}:{allowOrigin:r,warn:!1}:{allowOrigin:i,warn:!1}}function x({limit:e,windowMs:t}){let n=new Map,r=(e,r)=>{let i=r-t,a=n.get(e)?.filter(e=>e>i)??[];return a.length===0?(n.delete(e),[]):(n.set(e,a),a)};return{allow(t,i=Date.now()){let a=r(t,i);return a.length>=e?!1:(a.push(i),n.set(t,a),!0)},getRetryAfterMs(n,i=Date.now()){let a=r(n,i);return a.length<e?0:Math.max(0,a[0]+t-i)}}}function S(){return process.env.AIKIT_TRANSPORT?process.env.AIKIT_TRANSPORT:process.stdin.isTTY?`http`:`stdio`}function C(){let e=process.argv[1];if(!e)return!1;try{return import.meta.url===o(e).href}catch{return!1}}function w(e){let t=e.headers[`mcp-session-id`];return Array.isArray(t)?t[0]:t}function T(e,t){let n=process.env[e];if(!n)return t;let r=Number.parseInt(n,10);return Number.isFinite(r)&&r>0?r:t}function E(){return C()?s({allowPositionals:!0,options:{transport:{type:`string`,default:S()},port:{type:`string`,default:process.env.AIKIT_PORT??`3210`}}}).values:{transport:S(),port:process.env.AIKIT_PORT??`3210`}}async function D(){let e=_(),n=E();process.on(`unhandledRejection`,e=>{v.error(`Unhandled rejection`,l(e))}),process.on(`uncaughtException`,e=>{v.error(`Uncaught exception — exiting`,l(e)),process.exit(1)});let r=(e,t)=>{e.then(async()=>{try{let{markPromoteRun:e,markPruneRun:n,prune:r,shouldRunStartupPrune:i,shouldRunWeeklyPromote:a}=await import(`../../tools/dist/index.js`),o=t();if(!o)return;if(i()){let e=await r({});n(),e.totalBytesFreed>0&&v.info(`Storage maintenance complete`,{forgeOrphans:e.forgeGroundOrphans.count,legacyLance:e.legacyLance.count,bytesFreed:e.totalBytesFreed});let{groupLessons:t,pruneLessons:i}=await import(`./evolution-BX_zTSdj.js`).then(e=>e.t),a=await i(o.curated,o.stateStore,{dryRun:!1});a.pruned.length>0&&v.info(`Startup lesson prune complete`,{pruned:a.pruned.length});let s=await t(o.curated,o.stateStore,{dryRun:!1});(s.groupsCreated>0||s.lessonsGrouped>0)&&v.info(`Startup lesson grouping complete`,{groupsCreated:s.groupsCreated,lessonsGrouped:s.lessonsGrouped})}if(a()){let{DEFAULT_PROMOTE_CONFIG:t,collectWorkspaceLessons:n,getGlobalCuratedDir:r,promoteLessons:i,scanForDuplicates:a}=await import(`./promotion-VH4M_cWb.js`).then(e=>e.o),{CuratedKnowledgeManager:s}=await import(`./curated-manager-CxKwx3Ym.js`).then(e=>e.n),c=o.curated,l=new s(r(),c.store,c.embedder),u=await n(),d={...t,dryRun:!1},f=await i(a(u,d),l,d);e(),f.promoted.length>0&&v.info(`Weekly lesson promotion complete`,{promoted:f.promoted.length,candidates:f.candidates.length})}}catch(e){v.warn(`Startup maintenance failed (non-critical)`,l(e))}}).catch(()=>{})};if(v.info(`Starting MCP AI Kit server`,{version:e}),n.transport===`http`){let[{default:e},{loadConfig:i,resolveIndexMode:a},{registerDashboardRoutes:o,resolveDashboardDir:s},{registerSettingsRoutes:c,resolveSettingsDir:u},{createSettingsRouter:d},{authMiddleware:f,getOrCreateToken:p}]=await Promise.all([import(`express`),import(`./config-C35F4tJm.js`),import(`./dashboard-static-FmfoS46e.js`),import(`./settings-static-BtvyIrza.js`),import(`./routes-CR3fI-HJ.js`),import(`./auth-Bz5dmZgR.js`).then(e=>e.t)]),h=i();v.info(`Config loaded`,{sourceCount:h.sources.length,storePath:h.store.path});let _=e();_.use(e.json({limit:`1mb`}));let y=Number(n.port),S=`http://localhost:${y}`,C=process.env.AIKIT_CORS_ORIGIN??S,E=process.env.AIKIT_ALLOW_ANY_ORIGIN===`true`,D=T(`AIKIT_HTTP_MAX_SESSIONS`,8),O=T(`AIKIT_HTTP_SESSION_TIMEOUT_MINUTES`,30),k=T(`AIKIT_HTTP_SESSION_GC_INTERVAL_MINUTES`,5),A=x({limit:100,windowMs:6e4}),j=!1;_.use((e,t,n)=>{let r=Array.isArray(e.headers.origin)?e.headers.origin[0]:e.headers.origin,i=b({requestOrigin:r,configuredOrigin:C,allowAnyOrigin:E,fallbackOrigin:S});if(i.warn&&!j&&(j=!0,v.warn(`Rejected non-local CORS origin while AIKIT_CORS_ORIGIN=*`,{origin:r,allowAnyOriginEnv:`AIKIT_ALLOW_ANY_ORIGIN=true`})),r&&!i.allowOrigin){t.status(403).json({error:`Origin not allowed`});return}if(i.allowOrigin&&t.setHeader(`Access-Control-Allow-Origin`,i.allowOrigin),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, PUT, PATCH, DELETE, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID`),t.setHeader(`Access-Control-Expose-Headers`,`Mcp-Session-Id`),e.method===`OPTIONS`){t.status(204).end();return}n()});let M=p();console.error(`[aikit] Auth token: ~/.aikit/token`),_.use(f(M)),_.use(`/mcp`,(e,t,n)=>{let r=w(e)??e.ip??e.socket.remoteAddress??`anonymous`;if(A.allow(r)){n();return}let i=Math.max(1,Math.ceil(A.getRetryAfterMs(r)/1e3));t.setHeader(`Retry-After`,String(i)),t.status(429).json({jsonrpc:`2.0`,error:{code:-32003,message:`Rate limit exceeded`},id:null})}),o(_,s(),v);let N=new Date().toISOString();_.use(`/settings/api`,d({log:v,mcpInfo:()=>({transport:`http`,port:y,pid:process.pid,startedAt:N})})),c(_,u(),v),_.get(`/health`,(e,t)=>{t.json({status:`ok`})});let P=!1,F=null,I=null,L=null,R=null,z=null,B=null,V=null,H=Promise.resolve(),U=async(e,n)=>{if(!P||!L||!R){n.status(503).json({jsonrpc:`2.0`,error:{code:-32603,message:`Server initializing — please retry in a few seconds`},id:null});return}let r=H,i;H=new Promise(e=>{i=e}),await r;try{let r=w(e);if(!B){if(r){n.status(404).json({jsonrpc:`2.0`,error:{code:-32001,message:`Session not found`},id:null});return}let e=new R({sessionIdGenerator:()=>t(),onsessioninitialized:async e=>{V=e,I?.onSessionStart(e,{transport:`http`})},onsessionclosed:async e=>{e&&I?.onSessionEnd(e),V=null}});e.onclose=()=>{B===e&&(B=null),V===e.sessionId&&(V=null)},B=e,await L.connect(e)}let i=B;await i.handleRequest(e,n,e.body),e.method!==`DELETE`&&(!r&&i.sessionId?(V=i.sessionId,I?.onSessionStart(i.sessionId,{transport:`http`}),I?.onSessionActivity(i.sessionId)):r&&I?.onSessionActivity(r))}catch(e){if(v.error(`MCP handler error`,l(e)),!n.headersSent){let t=e instanceof Error?e.message:String(e),r=t.includes(`Not Acceptable`);n.status(r?406:500).json({jsonrpc:`2.0`,error:{code:r?-32e3:-32603,message:r?t:`Internal server error`},id:null})}}finally{i()}},W=async(e,t)=>{let n=w(e);if(z&&(!B||n!==V)){await z.handleRequest(e,t,e.body);return}await U(e,t)};_.post(`/mcp`,W),_.get(`/mcp`,W),_.delete(`/mcp`,W);let G=_.listen(y,`127.0.0.1`,()=>{v.info(`MCP server listening`,{url:`http://127.0.0.1:${y}/mcp`,port:y}),setTimeout(async()=>{try{let[{createLazyServer:e,createMcpServer:t,ALL_TOOL_NAMES:n},{StreamableHTTPServerTransport:i},{checkForUpdates:o,autoUpgradeScaffold:s}]=await Promise.all([import(`./server-DEWRYAsN.js`),import(`@modelcontextprotocol/sdk/server/streamableHttp.js`),import(`./version-check-BgHzxxCW.js`)]);o(),s();let c=a(h),u=e(h,c);L=u.server,R=i,P=!0,v.info(`MCP server configured (lazy — AI Kit initializing in background)`,{toolCount:n.length,resourceCount:2}),u.startInit(),u.ready.then(()=>{if(!u.aikit)throw Error(`AI Kit components are not available after initialization`);I=new g(u.aikit.stateStore,{staleTimeoutMinutes:O,gcIntervalMinutes:k,onBeforeSessionDelete:e=>{if(V===e&&B){let e=B;B=null,V=null,e.close().catch(()=>void 0)}z?.closeSession(e,{notifySessionEnd:!1})},onSessionEndMaintenance:async()=>{if(!u.aikit?.curated||!u.aikit?.stateStore)return;let{pruneLessons:e}=await import(`./evolution-BX_zTSdj.js`).then(e=>e.t),t=await e(u.aikit.curated,u.aikit.stateStore,{dryRun:!1});t.pruned.length>0&&v.info(`Session-end lesson prune`,{pruned:t.pruned.length})}}),z=new m({createServer:()=>{if(!u.aikit)throw Error(`AI Kit components are not available after initialization`);return t(u.aikit,h)},createTransport:e=>new i(e),maxSessions:D,sessionTimeoutMinutes:O,onSessionStart:e=>I?.onSessionStart(e,{transport:`http`}),onSessionActivity:e=>I?.onSessionActivity(e),onSessionEnd:e=>I?.onSessionEnd(e)}),I.startGC(),V&&(I.onSessionStart(V,{transport:`http`}),I.onSessionActivity(V)),v.info(`HTTP session runtime ready`,{maxSessions:D,sessionTimeoutMinutes:O,gcIntervalMinutes:k})}).catch(e=>v.error(`Failed to start session manager`,l(e))),c===`auto`?u.ready.then(async()=>{try{let e=h.sources.map(e=>e.path).join(`, `);v.info(`Running initial index`,{sourcePaths:e}),await u.runInitialIndex(),v.info(`Initial index complete`)}catch(e){v.error(`Initial index failed; will retry on aikit_reindex`,l(e))}}).catch(e=>v.error(`AI Kit init or indexing failed`,l(e))):c===`smart`?u.ready.then(async()=>{try{if(!u.aikit)throw Error(`AI Kit components are not available after initialization`);let{SmartIndexScheduler:e}=await import(`../../indexer/dist/index.js`),t=new e(u.aikit.indexer,h,u.aikit.store),n=u.aikit.store;F=t,t.start(),n.onBeforeClose&&n.onBeforeClose(()=>t.stop()),u.setSmartScheduler(t),v.info(`Smart index scheduler started (HTTP mode)`)}catch(e){v.error(`Failed to start smart index scheduler`,l(e))}}).catch(e=>v.error(`AI Kit initialization failed`,l(e))):(u.ready.catch(e=>v.error(`AI Kit initialization failed`,l(e))),v.info(`Initial full indexing skipped in HTTP mode`,{indexMode:c})),r(u.ready,()=>u.aikit?{curated:u.aikit.curated,stateStore:u.aikit.stateStore}:null)}catch(e){v.error(`Failed to load server modules`,l(e))}},100)}),K=async e=>{v.info(`Shutdown signal received`,{signal:e}),F?.stop(),I?.stop(),await z?.closeAll().catch(()=>void 0),V&&I?.onSessionEnd(V),B&&(await B.close().catch(()=>void 0),B=null,V=null),G.close(),L&&await L.close(),process.exit(0)};process.on(`SIGINT`,()=>K(`SIGINT`)),process.on(`SIGTERM`,()=>K(`SIGTERM`))}else{let[{loadConfig:e,reconfigureForWorkspace:t,resolveIndexMode:n},{createLazyServer:i},{checkForUpdates:o,autoUpgradeScaffold:s},{RootsListChangedNotificationSchema:c}]=await Promise.all([import(`./config-C35F4tJm.js`),import(`./server-DEWRYAsN.js`),import(`./version-check-BgHzxxCW.js`),import(`@modelcontextprotocol/sdk/types.js`)]),u=e();v.info(`Config loaded`,{sourceCount:u.sources.length,storePath:u.store.path}),o(),s();let d=n(u),f=i(u,d),{server:p,startInit:m,ready:h,runInitialIndex:g}=f,{StdioServerTransport:_}=await import(`@modelcontextprotocol/sdk/server/stdio.js`),y=new _;await p.connect(y),v.info(`MCP server started`,{transport:`stdio`});let b=e=>{if(e.length===0)return!1;let n=e[0].uri,r=n.startsWith(`file://`)?a(n):n;return v.info(`MCP roots resolved`,{rootUri:n,rootPath:r,rootCount:e.length}),t(u,r),u.allRoots=e.map(e=>{let t=e.uri;return t.startsWith(`file://`)?a(t):t}),!0},x=!1;try{x=b((await p.server.listRoots()).roots),x||v.info(`No MCP roots yet; waiting for roots/list_changed notification`)}catch(e){v.warn(`MCP roots/list not supported by client; using cwd fallback`,{cwd:process.cwd(),...l(e)}),x=!0}x||=await new Promise(e=>{let t=setTimeout(()=>{v.warn(`Timed out waiting for MCP roots/list_changed; using cwd fallback`,{cwd:process.cwd()}),e(!1)},5e3);p.server.setNotificationHandler(c,async()=>{clearTimeout(t);try{e(b((await p.server.listRoots()).roots))}catch(t){v.warn(`roots/list retry failed after notification`,l(t)),e(!1)}})}),m();let S=null,C=()=>{S&&clearTimeout(S),S=setTimeout(async()=>{v.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),S.unref&&S.unref()};C(),process.stdin.on(`data`,()=>C()),h.catch(e=>{v.error(`Initialization failed — server will continue with limited tools`,l(e))}),d===`auto`?g().catch(e=>v.error(`Initial index failed`,l(e))):d===`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,u,f.aikit.store),n=f.aikit.store;t.start(),n.onBeforeClose&&n.onBeforeClose(()=>t.stop()),f.setSmartScheduler(t),v.info(`Smart index scheduler started (stdio mode)`)}catch(e){v.error(`Failed to start smart index scheduler`,l(e))}}).catch(e=>v.error(`AI Kit init failed for smart scheduler`,l(e))):v.warn(`Initial full indexing skipped; use aikit_reindex to index manually`,{indexMode:d}),r(h,()=>f.aikit?{curated:f.aikit.curated,stateStore:f.aikit.stateStore}:null)}}export{e as CuratedKnowledgeManager,x as createSlidingWindowRateLimiter,D as main,b as resolveCorsOrigin};
@@ -159,10 +159,10 @@ _Metrics have been reset._`)),{content:[{type:`text`,text:i.join(`
159
159
  `).replace(/\\t/g,` `),t);return{content:[{type:`text`,text:JSON.stringify(n)}]}}catch(e){return kl.error(`Parse failed`,I(e)),J(`INTERNAL`,`Parse failed: ${e instanceof Error?e.message:String(e)}`)}})}function Pl(e,t){let n=G(`delegate`);e.registerTool(`delegate`,{title:n.title,description:`Delegate a subtask to a local Ollama model. Use for summarization, classification, naming, or any task that can offload work from the host agent. Fails fast if Ollama is not running.`,inputSchema:{prompt:R.string().max(2e5).describe(`The task or question to send to the local model`),model:R.string().optional().describe(`Ollama model name (default: first available model)`),system:R.string().optional().describe(`System prompt for the model`),context:R.string().max(5e5).optional().describe(`Context text to include before the prompt (e.g. file contents)`),temperature:R.number().min(0).max(2).default(.3).optional().describe(`Sampling temperature (0=deterministic, default 0.3)`),timeout:R.number().min(1e3).max(6e5).default(12e4).optional().describe(`Timeout in milliseconds (default 120000)`),action:R.enum([`generate`,`list_models`]).default(`generate`).optional().describe(`Action: generate a response or list available models`)},annotations:n.annotations},async({prompt:e,model:n,system:r,context:i,temperature:a,timeout:o,action:s})=>{try{if(s===`list_models`){let e=await it();return{content:[{type:`text`,text:JSON.stringify({models:e,count:e.length,_Next:`Use delegate with a model name`},null,2)}]}}if(t?.available)try{let n=await t.createMessage({prompt:e,systemPrompt:r,context:i,maxTokens:4e3,modelPreferences:{intelligencePriority:.8,speedPriority:.5,costPriority:.3}});return{content:[{type:`text`,text:JSON.stringify({model:n.model??`sampling`,response:n.text,provider:`mcp-sampling`,_Next:`Use the response in your workflow. stash to save it.`},null,2)}]}}catch{kl.debug(`Sampling failed, falling back to Ollama`)}let c=await rt({prompt:e,model:n,system:r,context:i,temperature:a,timeout:o});return c.error?J(`INTERNAL`,JSON.stringify({error:c.error,model:c.model,durationMs:c.durationMs},null,2)):{content:[{type:`text`,text:JSON.stringify({model:c.model,response:c.response,durationMs:c.durationMs,tokenCount:c.tokenCount,_Next:`Use the response in your workflow. stash to save it.`},null,2)}]}}catch(e){return kl.error(`Delegate failed`,I(e)),J(`INTERNAL`,`Delegate failed: ${e instanceof Error?e.message:String(e)}`)}})}function Fl(e){let t=[`Vitest run: ${e.passed?`passed`:`failed`}`,`Duration: ${e.durationMs}ms`,`Passed: ${e.summary.passed}`,`Failed: ${e.summary.failed}`,`Skipped: ${e.summary.skipped}`];e.summary.suites!==void 0&&t.push(`Suites: ${e.summary.suites}`);let n=e.summary.tests.filter(e=>e.status===`fail`);if(n.length>0){t.push(``,`Failed tests:`);for(let e of n)t.push(`- ${e.name}${e.file?` (${e.file})`:``}`),e.error&&t.push(` ${e.error}`)}return t.join(`
160
160
  `)}const Il=F(`sampling`);function Ll(e){if(!e.modelPreferences)return;let t={...e.modelPreferences.costPriority===void 0?{}:{costPriority:e.modelPreferences.costPriority},...e.modelPreferences.speedPriority===void 0?{}:{speedPriority:e.modelPreferences.speedPriority},...e.modelPreferences.intelligencePriority===void 0?{}:{intelligencePriority:e.modelPreferences.intelligencePriority}};return Object.keys(t).length>0?t:void 0}function Rl(e){if(Array.isArray(e))return e.map(e=>Rl(e)).filter(e=>e.length>0).join(`
161
161
  `);if(e&&typeof e==`object`&&`type`in e){let t=e;if(t.type===`text`&&typeof t.text==`string`)return t.text}return JSON.stringify(e)}function zl(e){let t=e.server,n=typeof t?.createMessage==`function`;return{get available(){return n},async createMessage(e){if(!n)throw Error(`Sampling not available: client does not support createMessage`);let r=e.context?`${e.context}\n\n---\n\n${e.prompt}`:e.prompt;try{let n=await t.createMessage({messages:[{role:`user`,content:{type:`text`,text:r}}],systemPrompt:e.systemPrompt,modelPreferences:Ll(e),maxTokens:e.maxTokens??4e3});return{text:Rl(n.content),model:n.model,stopReason:n.stopReason}}catch(e){throw Il.warn(`Sampling createMessage failed`,{error:String(e)}),e}}}}const Bl=[],Vl=[`_docs-sync`],Hl=new Map([[`_docs-sync`,`Synchronize project documentation — update docs/ folder based on changes made during the flow.`]]);function Ul(e){function t(t,n,r){let i=n?.installPath?ge(n.installPath):t.replaceAll(`:`,`-`),a=P(Bn(),`.copilot`,`flows`,i).replaceAll(`\\`,`/`);if(A(a))return a;let o=P(Bn(),`.claude`,`flows`,i).replaceAll(`\\`,`/`);if(A(o))return o;let s=P(r??e(),`.github`,`flows`,i).replaceAll(`\\`,`/`);return A(s)?s:n?.installPath&&A(n.installPath)?n.installPath.replaceAll(`\\`,`/`):null}function n(e,n,r){let i=t(e.name,e,r);return i?P(i,n).replaceAll(`\\`,`/`):n}function r(t,n){let r=t.replace(/^_/,``),i=n??e(),a=[N(i,`.github`,`flows`,`_epilogue`,`steps`,r,`README.md`),N(i,`.github`,`flows`,`_epilogue`,r,`README.md`)];for(let e of a)if(A(e))return e.replaceAll(`\\`,`/`);return null}function i(e){return[...Bl,...e.manifest.steps.map(e=>e.id),...Vl]}function a(e,t,r){let i=t?e.manifest.steps.find(e=>e.id===t)??null:null,a=t?Hl.get(t)??null:null;return{currentStep:i,epilogueStep:a?{id:t,description:a}:null,instructionPath:i&&t?n(e,i.instruction,r):null,description:i?.description??a}}function o(){try{let e=N(zn(`npm root -g`,{encoding:`utf-8`}).trim(),`@fission-ai`,`openspec`);if(A(e))return{path:e,sourceType:`npm-global`,isGit:!1}}catch{}return{path:`https://github.com/Fission-AI/OpenSpec.git`,sourceType:`git`,isGit:!0}}function s(e){let t=P(e);if(A(N(t,`.claude-plugin`,`plugin.json`)))return{path:t,sourceType:`claude-plugin`};let n=Bn(),r=N(n,`.claude`,`plugins`,e);if(A(N(r,`.claude-plugin`,`plugin.json`)))return{path:r,sourceType:`claude-plugin`};let i=N(n,`.claude`,`plugins`);if(!A(i))return null;for(let t of ue(i,{withFileTypes:!0})){if(!t.isDirectory())continue;let n=N(i,t.name,`.claude-plugin`,`plugin.json`);if(A(n))try{if(JSON.parse(M(n,`utf-8`)).name===e)return{path:N(i,t.name),sourceType:`claude-plugin`}}catch{}}return null}return{resolveInstallPath:t,resolveInstructionPath:n,resolveEpilogueInstructionPath:r,getStepSequence:i,resolveCurrentStepInfo:a,resolveOpenSpecSource:o,resolveClaudePluginSource:s}}function Wl(e){function t(){return e.sources?.[0]?.path??process.cwd()}function n(){return e.allRoots?.length?e.allRoots:[t()]}function r(e){return e.map(e=>e.replaceAll(`\\`,`/`))}function i(e){let t=[];try{let n=ue(e,{withFileTypes:!0});for(let r of n){if(!r.isDirectory()||r.name.startsWith(`.`))continue;let n=N(e,r.name);A(N(n,`.git`))&&t.push(n)}}catch{}return t}function a(){let e=n(),t=new Set(e);for(let n of e)for(let e of i(n))t.add(e);return[...t]}function o(e){let t=e.replaceAll(`\\`,`/`);if(r(a()).includes(t))return!0;let i=r(n());for(let n of i)if(t.startsWith(`${n}/`)&&A(N(e,`.git`)))return!0;return!1}function s(e){return N(e??t(),`.flows`)}async function c(){let e=a();for(let t of e){let e=s(t);if(A(e))for(let n of ue(e,{withFileTypes:!0})){if(!n.isDirectory())continue;let r=N(e,n.name,`meta.json`);if(A(r))try{let e=JSON.parse(M(r,`utf-8`));if(e.status===`active`)return e.primaryRoot?e.primaryRoot:t}catch{}}}return null}async function l(e){return e||(await c()??t())}function u(){let e=t(),i=r(n()),o=a(),s=r(o),c=s.filter(e=>!i.includes(e));return{workspaceRoot:e,allRoots:o,normalizedAllRoots:s,discoveredRepos:c.length>0?c:void 0}}function d(e,t,n){let r=N(s(t),e,`meta.json`),i=M(r,`utf-8`),a=JSON.parse(i);a.roots=n.map(e=>e.replaceAll(`\\`,`/`)),a.primaryRoot=t.replaceAll(`\\`,`/`);let o=`${r}.tmp`;he(o,JSON.stringify(a,null,2),`utf-8`),de(o,r)}function f(e,t){let n=N(s(t),e,`meta.json`);if(!A(n))return;let r=M(n,`utf-8`),i=JSON.parse(r),a=i.roots;if(!a||a.length<=1)return;let o=t.replaceAll(`\\`,`/`);for(let t of a){if(t===o)continue;let n=N(t,`.flows`,e);j(n,{recursive:!0});let a=N(n,`meta.json`),s=`${a}.tmp`;he(s,r,`utf-8`),de(s,a),j(N(n,i.artifactsDir??`.spec`),{recursive:!0})}}return{getWorkspaceRoot:t,getAllRoots:a,getFlowsDir:s,isValidFlowRoot:o,resolveFlowRoot:l,resolveRoots:u,patchMetaRoots:d,syncMetaToRoots:f}}const Gl={name:`flow-context`,order:40,maxTokens:120,runInBrief:!1,async execute(e){let t=["**Flow Context:** Call `knowledge({ action: 'withdraw', scope: 'flow', profile: 'implementer', budget: 4000 })` as FIRST action for prior context.","Remember decisions: `knowledge({ action: 'remember', title: '...', content: '...', category: 'flow-context', scope: 'flow' })`"];e.completedSteps.length>0&&t.push(`Completed steps: ${e.completedSteps.join(`, `)}`);let n=t.join(`
162
- `);return{content:n,tokens:Math.ceil(n.length/4)}}};function Kl(e){return{name:`knowledge-recall`,order:20,maxTokens:200,runInBrief:!1,async execute(t){if(!e.store)return null;let n=[t.stepDescription,t.topic].filter(Boolean).join(` `);if(!n.trim())return null;try{let t=await e.store.search(n,{limit:3});if(!t||t.length===0)return null;let r=t.map(e=>`• ${e.content.slice(0,200)}`).join(`
163
- `),i=Math.ceil(r.length/4);return{content:`**Recalled Knowledge:**\n${r}`,tokens:Math.min(i,200)}}catch{return null}}}}const ql=[`**Read Code:** Structure → file_summary(). Specific section → compact(path, query).`,`Multiple files → digest(). Repeated ref → stratum_card(). Edit lines → read_file().`,`NEVER read_file >50 lines to understand. Use search() for discovery.`].join(` `),Jl={name:`token-efficiency`,order:30,maxTokens:80,runInBrief:!1,async execute(e){return{content:ql,tokens:25}}},Yl=[`**Tool Routing:** search() not grep_search. file_summary() or compact() not read_file (for understanding).`,`check() not terminal tsc/lint. test_run() not terminal test. trace() for data flow.`,`read_file ONLY for exact lines before editing. symbol() for definition+refs.`].join(` `),Xl={name:`tool-routing`,order:10,maxTokens:100,runInBrief:!0,async execute(e){return{content:Yl,tokens:30}}};function Zl(e,t){return Promise.race([e,new Promise(e=>setTimeout(()=>e(null),t))])}var Ql=class{hooks=[];sealed=!1;log;constructor(e){this.log=e?.log}seal(){this.sealed=!0}register(e){if(this.sealed){this.log?.warn(`Attempted to register hook "%s" on sealed pipeline`,e.name);return}this.hooks.push(e),this.hooks.sort((e,t)=>e.order-t.order)}get hookCount(){return this.hooks.length}async enrich(e,t,n){let r=this.resolveBudget(t.mode,n),i=new Set(n?.disable??[]),a=this.hooks.filter(e=>!(i.has(e.name)||t.mode===`brief`&&!e.runInBrief));if(a.length===0)return e;let o=[],s=0;for(let e of a){if(s>=r){this.log?.debug(`[step-hooks] Budget exhausted (${s}/${r}), skipping remaining hooks`);break}try{let n=await Zl(e.execute(t),5e3);if(!n||n.content.length===0)continue;let i=n.content.replace(/<\/(step-context|step-hints)>/gi,``);if(i.length===0)continue;let a=this.truncateToTokens(i,e.maxTokens),c=Math.min(n.tokens,e.maxTokens);if(s+c<=r){o.push({content:a,tokens:c}),s+=c;continue}let l=r-s;if(l<=0)break;o.push({content:this.truncateToTokens(a,l),tokens:l}),s=r}catch(t){this.log?.warn(`[step-hooks] Hook "${e.name}" failed: ${t instanceof Error?t.message:String(t)}`)}}if(o.length===0)return e;let c=t.mode===`full`?`<step-context>`:`<step-hints>`,l=t.mode===`full`?`</step-context>`:`</step-hints>`;return`${e}\n\n${c}\n${o.map(e=>e.content).join(`
162
+ `);return{content:n,tokens:Math.ceil(n.length/4)}}};function Kl(e){return{name:`knowledge-recall`,order:20,maxTokens:200,runInBrief:!1,async execute(t){if(!e.store)return null;let n=[t.stepDescription,t.topic].filter(e=>typeof e==`string`&&e.trim().length>0);if(n.length===0)return null;let r=[...n,t.flowName].filter(Boolean).join(` `);if(!r.trim())return null;try{let t=await e.store.search(r,{limit:3});if(!t||t.length===0)return null;let n=t.map(e=>`• ${e.content.slice(0,200)}`).join(`
163
+ `),i=Math.ceil(n.length/4);return{content:`**Recalled Knowledge:**\n${n}`,tokens:Math.min(i,200)}}catch{return null}}}}const ql=[`**Read Code:** Structure → file_summary(). Specific section → compact(path, query).`,`Multiple files → digest(). Repeated ref → stratum_card(). Edit lines → read_file().`,`NEVER read_file >50 lines to understand. Use search() for discovery.`].join(` `),Jl={name:`token-efficiency`,order:30,maxTokens:80,runInBrief:!1,runOnce:!0,async execute(e){return{content:ql,tokens:25}}},Yl=[`**Tool Routing:** search() not grep_search. file_summary() or compact() not read_file (for understanding).`,`check() not terminal tsc/lint. test_run() not terminal test. trace() for data flow.`,`read_file ONLY for exact lines before editing. symbol() for definition+refs.`].join(` `),Xl={name:`tool-routing`,order:10,maxTokens:100,runInBrief:!0,runOnce:!0,async execute(e){return{content:Yl,tokens:30}}};function Zl(e,t){return Promise.race([e,new Promise(e=>setTimeout(()=>e(null),t))])}var Ql=class{hooks=[];firedOnce=new Set;sealed=!1;log;constructor(e){this.log=e?.log}seal(){this.sealed=!0}register(e){if(this.sealed){this.log?.warn(`Attempted to register hook "%s" on sealed pipeline`,e.name);return}this.hooks.push(e),this.hooks.sort((e,t)=>e.order-t.order)}get hookCount(){return this.hooks.length}async enrich(e,t,n){let r=this.resolveBudget(t.mode,n),i=new Set(n?.disable??[]),a=this.hooks.filter(e=>!(i.has(e.name)||t.mode===`brief`&&!e.runInBrief||e.runOnce&&this.firedOnce.has(e.name)));if(a.length===0)return e;let o=[],s=0;for(let e of a){if(s>=r){this.log?.debug(`[step-hooks] Budget exhausted (${s}/${r}), skipping remaining hooks`);break}try{let n=await Zl(e.execute(t),5e3);if(!n||n.content.length===0)continue;e.runOnce&&this.firedOnce.add(e.name);let i=n.content.replace(/<\/(step-context|step-hints)>/gi,``);if(i.length===0)continue;let a=this.truncateToTokens(i,e.maxTokens),c=Math.min(n.tokens,e.maxTokens);if(s+c<=r){o.push({content:a,tokens:c}),s+=c;continue}let l=r-s;if(l<=0)break;o.push({content:this.truncateToTokens(a,l),tokens:l}),s=r}catch(t){this.log?.warn(`[step-hooks] Hook "${e.name}" failed: ${t instanceof Error?t.message:String(t)}`)}}if(o.length===0)return e;let c=t.mode===`full`?`<step-context>`:`<step-hints>`,l=t.mode===`full`?`</step-context>`:`</step-hints>`;return`${e}\n\n${c}\n${o.map(e=>e.content).join(`
164
164
 
165
- `)}\n${l}`}resolveBudget(e,t){return e===`full`?t?.tokenBudget?.full??500:t?.tokenBudget?.brief??150}truncateToTokens(e,t){let n=t*4;return e.length<=n?e:`${e.slice(0,n).trimEnd()}…`}};function $l(e={}){let t=new Ql({log:e.log});return t.register(Xl),t.register(Kl({store:e.store,graphStore:e.graphStore,embedder:e.embedder})),t.register(Jl),t.register(Gl),t.seal(),t}const eu=F(`flow-tools`);function tu(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`&&e.trim().length>0):[]}function nu(e){return{content:[{type:`text`,text:e}]}}function ru(e){return e instanceof Error?e.message:String(e)}const iu={before:[],after:[{id:`_docs-sync`,description:`Synchronize project documentation — update docs/ folder based on changes made during the flow.`,position:`after`,skills:[`docs`]}]};function au(e,t){let n=Wl(t),r=Ul(n.getWorkspaceRoot),i=$l({log:eu});function a(){return N(Me(),`flows`,`registry.json`)}function o(){let t=zl(e);return async({content:e,sourceFormat:n,stepName:r,metadata:i})=>{let a=r.charAt(0).toUpperCase()+r.slice(1),o=i?JSON.stringify(i,null,2):void 0,s=`You are converting a flow step definition from "${n}" format to aikit native flow step README.md format.
165
+ `)}\n${l}`}resolveBudget(e,t){return e===`full`?t?.tokenBudget?.full??500:t?.tokenBudget?.brief??150}truncateToTokens(e,t){let n=t*4;return e.length<=n?e:`${e.slice(0,n).trimEnd()}…`}};function $l(e={}){let t=new Ql({log:e.log});return t.register(Xl),t.register(Kl({store:e.store,graphStore:e.graphStore,embedder:e.embedder})),t.register(Jl),t.register(Gl),t.seal(),t}const eu=F(`flow-tools`);function tu(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`&&e.trim().length>0):[]}function nu(e){return{content:[{type:`text`,text:e}]}}function ru(e){return e instanceof Error?e.message:String(e)}const iu={before:[],after:[{id:`_docs-sync`,description:`Synchronize project documentation — update docs/ folder based on changes made during the flow.`,position:`after`,skills:[`docs`]}]};function au(e,t,n){let r=Wl(t),i=Ul(r.getWorkspaceRoot),a=$l({store:n?.store,graphStore:n?.graphStore,embedder:n?.embedder,log:eu});function o(){return N(Me(),`flows`,`registry.json`)}function s(){let t=zl(e);return async({content:e,sourceFormat:n,stepName:r,metadata:i})=>{let a=r.charAt(0).toUpperCase()+r.slice(1),o=i?JSON.stringify(i,null,2):void 0,s=`You are converting a flow step definition from "${n}" format to aikit native flow step README.md format.
166
166
 
167
167
  Convert the provided content into a well-structured README.md for a flow step named "${r}".
168
168
 
@@ -177,12 +177,12 @@ The output must:
177
177
 
178
178
  Output ONLY the README.md content, nothing else.`;if(t.available)try{let i=(await t.createMessage({prompt:e,systemPrompt:s,context:o?`Step name: ${r}\nSource format: ${n}\nMetadata:\n${o}`:`Step name: ${r}\nSource format: ${n}`,maxTokens:4096,modelPreferences:{intelligencePriority:.8,speedPriority:.4,costPriority:.2}})).text.trim();if(i.length>0)return i}catch(e){eu.debug(`Flow transform sampling failed; using fallback formatting`,{error:ru(e),sourceFormat:n,stepName:r})}let c=typeof i?.description==`string`&&i.description.trim().length>0?i.description.trim():null,l=tu(i?.produces),u=tu(i?.requires);return[`# ${a}`,``,`## Purpose`,``,c??`${a} step.`,``,`## Instructions`,``,e.trim(),``,`## Artifacts`,``,...l.length>0?l.map(e=>`- ${e}`):[`- ${r}.md`],...u.length>0?[``,`## Prerequisites`,``,...u.map(e=>`- ${e}`)]:[],``].join(`
179
179
  `).trimEnd().concat(`
180
- `)}}async function s(e){let{FlowRegistryManager:r,FlowStateMachine:i,FlowLoader:o,GitInstaller:s}=await import(`../../flows/dist/index.js`),c=N(t.stateDir??``,`flows`,`installed`);return{registry:new r(a()),stateMachine:new i(n.getFlowsDir(e),iu),loader:new o,installer:new s(c)}}return{server:e,config:t,log:eu,toTextResponse:nu,toErrorText:ru,createFlowTransform:o,getFlows:s,stepPipeline:i,stateDir:t.stateDir??``,...n,...r}}var ou=class extends Error{code;constructor(e,t){super(t),this.code=e,this.name=`FlowError`}};function su(e){return e instanceof ou}async function cu(e){let{entry:t,stepId:n,runDir:r,slug:i,primaryRoot:a,roots:o,activeRoot:s,resolveInstructionPath:c,resolveEpilogueInstructionPath:l}=e;if(!n)return null;try{let e=t.manifest.steps.find(e=>e.id===n||e.name===n),u;if(e)u=await Mn(c(t,e.instruction,s),`utf-8`);else{let e=l(n,s);if(!e)return null;u=await Mn(e,`utf-8`)}let d=N(r,t.manifest.artifacts_dir).replaceAll(`\\`,`/`),f=r.replaceAll(`\\`,`/`);u=u.replaceAll(`{{artifacts_path}}`,d).replaceAll(`{{run_dir}}`,f).replaceAll(`{{workspace_root}}`,(a??s).replaceAll(`\\`,`/`)).replaceAll(`{{all_roots}}`,JSON.stringify(o??[s.replaceAll(`\\`,`/`)],null,2));for(let e of[`spec-driven`])u=u.replaceAll(`${e}/${i}/`,`${d}/`);return u}catch{return null}}async function lu(e,t){let{getFlows:n,log:r,resolveEpilogueInstructionPath:i,resolveFlowRoot:a,resolveInstructionPath:o,stepPipeline:s,toErrorText:c,toTextResponse:l}=t,{step:u}=e;try{let e=await a(),{registry:t,stateMachine:r}=await n(e),c=r.getStatus();if(!c.success||!c.data)throw new ou(`NO_ACTIVE_FLOW`,`No active flow. Use flow({ action: "start", name: "<flow>" }) to begin one, or flow({ action: "list" }) to see available flows.`);let d=c.data,f=t.get(d.flow);if(!f)throw new ou(`FLOW_NOT_FOUND`,`Flow "${d.flow}" not found in registry.`);let p=u??d.currentStep;if(!p)throw new ou(`STEP_OUT_OF_RANGE`,`No current step is available for the active flow.`);let m=await cu({entry:f,stepId:p,runDir:d.runDir,slug:d.slug,primaryRoot:d.primaryRoot,roots:d.roots,activeRoot:e,resolveInstructionPath:o,resolveEpilogueInstructionPath:i});if(!m)throw new ou(`STEP_OUT_OF_RANGE`,`Step "${p}" not found in flow "${d.flow}".`);let h=f.manifest.steps.find(e=>e.id===p||e.name===p),g=N(d.runDir,f.manifest.artifacts_dir).replaceAll(`\\`,`/`),_={stepId:p,flowName:d.flow,flowSlug:d.slug,phase:d.phase??`flow`,runDir:d.runDir,artifactsPath:g,completedSteps:d.completedSteps??[],stepDescription:h?.description,agents:h?.agents??[],mode:`full`,topic:d.topic??``,activeRoot:e};return l(await s.enrich(m,_,f.manifest.hooks))}catch(e){return su(e)?l(e.message):(r.error(`flow action read failed`,I(e)),e instanceof Error&&`code`in e&&e.code===`ENOENT`?l(`Could not read instruction file: ${e.message}`):l(`Error: ${c(e)}`))}}async function uu(e,t){let{registry:n,loader:r,installer:i}=await e.getFlows(),a=e.createFlowTransform(),o=P(t.source);if(!A(o))return e.toTextResponse(`Source path no longer exists: ${o}`);let s=`${t.installPath}.updating`,c=`${t.installPath}.backup`;A(s)&&fe(s,{recursive:!0,force:!0}),A(c)&&fe(c,{recursive:!0,force:!0});let l=i.copyLocal(o,ge(s));if(!l.success||!l.data)return e.toTextResponse(`Failed to copy flow: ${l.error}`);let u=await r.load(s,{forceAssetSync:!0,transform:a});if(!u.success||!u.data)return i.remove(s),e.toTextResponse(`Failed to load flow manifest: ${u.error}`);let d=!1;try{de(t.installPath,c),de(s,t.installPath);let e=await r.load(t.installPath,{forceAssetSync:!0,transform:a});if(!e.success||!e.data)throw Error(`Failed to load flow manifest: ${e.error}`);let o=e.data.manifest,l=e.data.format,u=n.register({...t,version:o.version,format:l,installPath:t.installPath,manifest:o,updatedAt:new Date().toISOString()});if(!u.success)throw Error(`Failed to refresh flow registry entry: ${u.error}`);if(d=!0,o.install.length>0){let e=i.runInstallDeps(o.install);if(!e.success)throw Error(`Dependency install failed: ${e.error}`)}fe(c,{recursive:!0,force:!0})}catch(r){return A(s)&&fe(s,{recursive:!0,force:!0}),A(c)&&(A(t.installPath)&&fe(t.installPath,{recursive:!0,force:!0}),de(c,t.installPath)),d&&n.register(t),e.toTextResponse(e.toErrorText(r))}return e.toTextResponse(`Flow "${t.name}" updated from ${t.sourceType} source successfully.`)}async function du(e,t){let{registry:n,loader:r}=await e.getFlows(),i=e.createFlowTransform();try{zn(`npm update -g @fission-ai/openspec`,{encoding:`utf-8`,stdio:`pipe`})}catch(t){return e.toTextResponse(`npm update failed: ${e.toErrorText(t)}`)}let a=e.resolveOpenSpecSource(),o=await r.load(a.path,{forceAssetSync:!0,transform:i}),s=o.success&&o.data?o.data.manifest:null,c=o.success&&o.data?o.data.format:t.format;if(s){let r=n.register({...t,version:s.version,format:c,installPath:a.path,manifest:s,updatedAt:new Date().toISOString()});if(!r.success)return e.toTextResponse(`Failed to refresh flow registry entry: ${r.error}`)}return e.toTextResponse(`Flow "${t.name}" updated via npm successfully.`)}async function fu(e,t){let{registry:n,loader:r,installer:i}=await e.getFlows(),a=e.createFlowTransform(),o=i.update(t.installPath);if(!o.success)return e.toTextResponse(`Update failed: ${o.error}`);let s=await r.load(t.installPath,{forceAssetSync:!0,transform:a}),c=s.success&&s.data?s.data.manifest:null,l=s.success&&s.data?s.data.format:t.format;if(c){let r=i.getLocalCommit(t.installPath),a=n.register({...t,version:c.version,format:l,manifest:c,updatedAt:new Date().toISOString(),...r?{commitSha:r}:{}});if(!a.success)return e.toTextResponse(`Failed to refresh flow registry entry: ${a.error}`)}let u=c?.install??t.manifest.install;if(u.length>0){let t=i.runInstallDeps(u);if(!t.success)return e.toTextResponse(`Dependency install failed: ${t.error}`)}return e.toTextResponse(`Flow "${t.name}" updated successfully.`)}async function pu(e,t){let{createFlowTransform:n,getFlows:r,log:i,resolveClaudePluginSource:a,resolveOpenSpecSource:o,toErrorText:s,toTextResponse:c}=t,{source:l,name:u,token:d}=e;try{let{registry:e,loader:t,installer:i}=await r(),s=n(),f=l===`openspec`||l.startsWith(`openspec:`),p,m=l,h;if(f){let e=o();m=e.path,p=e.sourceType}let g=f?null:a(m);g&&(m=g.path,p=g.sourceType);let _=/^https?:\/\/|^git@/.test(m),v;if(_){let e=i.clone(m,d);if(!e.success||!e.data)return c(`Failed to clone flow: ${e.error}`);v=e.data}else{let e=P(m);h=e;let t=u||ge(e)||`custom-flow`,n=i.copyLocal(e,t);if(!n.success||!n.data)return c(`Failed to copy flow: ${n.error}`);v=n.data}let y=await t.load(v,{forceAssetSync:!0,transform:s});if(!y.success||!y.data)return i.remove(v),c(`Failed to load flow manifest: ${y.error}`);let{manifest:b,format:x}=y.data,S=u||b.name,C=p??(_?`git`:`local`);if(e.has(S))return i.remove(v),c(`Flow "${S}" is already installed. Use flow({ action: "update", name: "${S}" }) to update it, or flow({ action: "remove", name: "${S}" }) then flow({ action: "add", source: "..." }) to replace.`);if(b.install.length>0){let e=i.runInstallDeps(b.install);if(!e.success)return i.remove(v),c(`Dependency install failed: ${e.error}`)}let w=new Date().toISOString(),T=_?i.getLocalCommit(v):void 0,E=e.register({name:S,version:b.version,source:C===`local`||C===`claude-plugin`?h??l:l,sourceType:C,installPath:v,format:x,registeredAt:w,updatedAt:w,manifest:b,...T?{commitSha:T}:{}});if(!E.success)return i.remove(v),c(`Failed to register flow: ${E.error}`);let D=b.steps.length;return c(`Flow "${S}" installed successfully (${D} steps). Use flow({ action: "start", name: "${S}" }) to begin.`)}catch(e){return i.error(`flow action add failed`,I(e)),c(`Error: ${s(e)}`)}}async function mu(e,t){let{getFlows:n,log:r,toErrorText:i,toTextResponse:a}=t,{name:o}=e;try{let{registry:e,installer:t}=await n();if(!e.has(o))return a(`Flow "${o}" is not installed.`);let r=e.get(o);if(!r)return a(`Flow "${o}" is not installed.`);if(r.sourceType===`builtin`)return a(`Cannot remove builtin flow "${o}".`);let i=t.remove(r.installPath);if(!i.success)return a(`Failed to remove flow files: ${i.error}`);let s=e.unregister(o);return s.success?a(`Flow "${o}" removed successfully.`):a(`Failed to unregister flow: ${s.error}`)}catch(e){return r.error(`flow action remove failed`,I(e)),a(`Error: ${i(e)}`)}}async function hu(e,t){let{getFlows:n,log:r,toErrorText:i,toTextResponse:a}=t,{name:o}=e,s={createFlowTransform:t.createFlowTransform,getFlows:t.getFlows,resolveOpenSpecSource:t.resolveOpenSpecSource,toErrorText:t.toErrorText,toTextResponse:t.toTextResponse};try{let{registry:e}=await n();if(!e.has(o))return a(`Flow "${o}" is not installed.`);let t=e.get(o);return!t||t.sourceType!==`git`&&t.sourceType!==`npm-global`&&t.sourceType!==`local`&&t.sourceType!==`claude-plugin`?a(`Flow "${o}" was not installed from git, npm, or a local source — cannot update. Remove and re-add instead.`):t.sourceType===`local`||t.sourceType===`claude-plugin`?uu(s,t):t.sourceType===`npm-global`?du(s,t):fu(s,t)}catch(e){return r.error(`flow action update failed`,I(e)),a(`Error: ${i(e)}`)}}const gu=`IMPORTANT: Start/status/step only include a brief. Call flow({ action: "read" }) before executing this flow step.`,_u=1200,vu=/artifact|output contract|gate|completion criteria|deliverable|must|do not|forbidden/i;function yu(){return{artifactsPath:null,currentStepInstruction:null,currentStepDescription:null,currentStepContent:null,currentStepBrief:null,currentStepPins:null,stepSequence:[]}}function bu(e){if(e.length<=_u)return e;let t=e.slice(0,_u-1),n=Math.max(t.lastIndexOf(`
180
+ `)}}async function c(e){let{FlowRegistryManager:n,FlowStateMachine:i,FlowLoader:a,GitInstaller:s}=await import(`../../flows/dist/index.js`),c=N(t.stateDir??``,`flows`,`installed`);return{registry:new n(o()),stateMachine:new i(r.getFlowsDir(e),iu),loader:new a,installer:new s(c)}}return{server:e,config:t,log:eu,toTextResponse:nu,toErrorText:ru,createFlowTransform:s,getFlows:c,stepPipeline:a,stateDir:t.stateDir??``,...r,...i}}var ou=class extends Error{code;constructor(e,t){super(t),this.code=e,this.name=`FlowError`}};function su(e){return e instanceof ou}async function cu(e){let{entry:t,stepId:n,runDir:r,slug:i,primaryRoot:a,roots:o,activeRoot:s,resolveInstructionPath:c,resolveEpilogueInstructionPath:l}=e;if(!n)return null;try{let e=t.manifest.steps.find(e=>e.id===n||e.name===n),u;if(e)u=await Mn(c(t,e.instruction,s),`utf-8`);else{let e=l(n,s);if(!e)return null;u=await Mn(e,`utf-8`)}let d=N(r,t.manifest.artifacts_dir).replaceAll(`\\`,`/`),f=r.replaceAll(`\\`,`/`);u=u.replaceAll(`{{artifacts_path}}`,d).replaceAll(`{{run_dir}}`,f).replaceAll(`{{workspace_root}}`,(a??s).replaceAll(`\\`,`/`)).replaceAll(`{{all_roots}}`,JSON.stringify(o??[s.replaceAll(`\\`,`/`)],null,2));for(let e of[`spec-driven`])u=u.replaceAll(`${e}/${i}/`,`${d}/`);return u}catch{return null}}async function lu(e,t){let{getFlows:n,log:r,resolveEpilogueInstructionPath:i,resolveFlowRoot:a,resolveInstructionPath:o,stepPipeline:s,toErrorText:c,toTextResponse:l}=t,{step:u}=e;try{let e=await a(),{registry:t,stateMachine:r}=await n(e),c=r.getStatus();if(!c.success||!c.data)throw new ou(`NO_ACTIVE_FLOW`,`No active flow. Use flow({ action: "start", name: "<flow>" }) to begin one, or flow({ action: "list" }) to see available flows.`);let d=c.data,f=t.get(d.flow);if(!f)throw new ou(`FLOW_NOT_FOUND`,`Flow "${d.flow}" not found in registry.`);let p=u??d.currentStep;if(!p)throw new ou(`STEP_OUT_OF_RANGE`,`No current step is available for the active flow.`);let m=await cu({entry:f,stepId:p,runDir:d.runDir,slug:d.slug,primaryRoot:d.primaryRoot,roots:d.roots,activeRoot:e,resolveInstructionPath:o,resolveEpilogueInstructionPath:i});if(!m)throw new ou(`STEP_OUT_OF_RANGE`,`Step "${p}" not found in flow "${d.flow}".`);let h=f.manifest.steps.find(e=>e.id===p||e.name===p),g=N(d.runDir,f.manifest.artifacts_dir).replaceAll(`\\`,`/`),_={stepId:p,flowName:d.flow,flowSlug:d.slug,phase:d.phase??`flow`,runDir:d.runDir,artifactsPath:g,completedSteps:d.completedSteps??[],stepDescription:h?.description,agents:h?.agents??[],mode:`full`,topic:d.topic??``,activeRoot:e};return l(await s.enrich(m,_,f.manifest.hooks))}catch(e){return su(e)?l(e.message):(r.error(`flow action read failed`,I(e)),e instanceof Error&&`code`in e&&e.code===`ENOENT`?l(`Could not read instruction file: ${e.message}`):l(`Error: ${c(e)}`))}}async function uu(e,t){let{registry:n,loader:r,installer:i}=await e.getFlows(),a=e.createFlowTransform(),o=P(t.source);if(!A(o))return e.toTextResponse(`Source path no longer exists: ${o}`);let s=`${t.installPath}.updating`,c=`${t.installPath}.backup`;A(s)&&fe(s,{recursive:!0,force:!0}),A(c)&&fe(c,{recursive:!0,force:!0});let l=i.copyLocal(o,ge(s));if(!l.success||!l.data)return e.toTextResponse(`Failed to copy flow: ${l.error}`);let u=await r.load(s,{forceAssetSync:!0,transform:a});if(!u.success||!u.data)return i.remove(s),e.toTextResponse(`Failed to load flow manifest: ${u.error}`);let d=!1;try{de(t.installPath,c),de(s,t.installPath);let e=await r.load(t.installPath,{forceAssetSync:!0,transform:a});if(!e.success||!e.data)throw Error(`Failed to load flow manifest: ${e.error}`);let o=e.data.manifest,l=e.data.format,u=n.register({...t,version:o.version,format:l,installPath:t.installPath,manifest:o,updatedAt:new Date().toISOString()});if(!u.success)throw Error(`Failed to refresh flow registry entry: ${u.error}`);if(d=!0,o.install.length>0){let e=i.runInstallDeps(o.install);if(!e.success)throw Error(`Dependency install failed: ${e.error}`)}fe(c,{recursive:!0,force:!0})}catch(r){return A(s)&&fe(s,{recursive:!0,force:!0}),A(c)&&(A(t.installPath)&&fe(t.installPath,{recursive:!0,force:!0}),de(c,t.installPath)),d&&n.register(t),e.toTextResponse(e.toErrorText(r))}return e.toTextResponse(`Flow "${t.name}" updated from ${t.sourceType} source successfully.`)}async function du(e,t){let{registry:n,loader:r}=await e.getFlows(),i=e.createFlowTransform();try{zn(`npm update -g @fission-ai/openspec`,{encoding:`utf-8`,stdio:`pipe`})}catch(t){return e.toTextResponse(`npm update failed: ${e.toErrorText(t)}`)}let a=e.resolveOpenSpecSource(),o=await r.load(a.path,{forceAssetSync:!0,transform:i}),s=o.success&&o.data?o.data.manifest:null,c=o.success&&o.data?o.data.format:t.format;if(s){let r=n.register({...t,version:s.version,format:c,installPath:a.path,manifest:s,updatedAt:new Date().toISOString()});if(!r.success)return e.toTextResponse(`Failed to refresh flow registry entry: ${r.error}`)}return e.toTextResponse(`Flow "${t.name}" updated via npm successfully.`)}async function fu(e,t){let{registry:n,loader:r,installer:i}=await e.getFlows(),a=e.createFlowTransform(),o=i.update(t.installPath);if(!o.success)return e.toTextResponse(`Update failed: ${o.error}`);let s=await r.load(t.installPath,{forceAssetSync:!0,transform:a}),c=s.success&&s.data?s.data.manifest:null,l=s.success&&s.data?s.data.format:t.format;if(c){let r=i.getLocalCommit(t.installPath),a=n.register({...t,version:c.version,format:l,manifest:c,updatedAt:new Date().toISOString(),...r?{commitSha:r}:{}});if(!a.success)return e.toTextResponse(`Failed to refresh flow registry entry: ${a.error}`)}let u=c?.install??t.manifest.install;if(u.length>0){let t=i.runInstallDeps(u);if(!t.success)return e.toTextResponse(`Dependency install failed: ${t.error}`)}return e.toTextResponse(`Flow "${t.name}" updated successfully.`)}async function pu(e,t){let{createFlowTransform:n,getFlows:r,log:i,resolveClaudePluginSource:a,resolveOpenSpecSource:o,toErrorText:s,toTextResponse:c}=t,{source:l,name:u,token:d}=e;try{let{registry:e,loader:t,installer:i}=await r(),s=n(),f=l===`openspec`||l.startsWith(`openspec:`),p,m=l,h;if(f){let e=o();m=e.path,p=e.sourceType}let g=f?null:a(m);g&&(m=g.path,p=g.sourceType);let _=/^https?:\/\/|^git@/.test(m),v;if(_){let e=i.clone(m,d);if(!e.success||!e.data)return c(`Failed to clone flow: ${e.error}`);v=e.data}else{let e=P(m);h=e;let t=u||ge(e)||`custom-flow`,n=i.copyLocal(e,t);if(!n.success||!n.data)return c(`Failed to copy flow: ${n.error}`);v=n.data}let y=await t.load(v,{forceAssetSync:!0,transform:s});if(!y.success||!y.data)return i.remove(v),c(`Failed to load flow manifest: ${y.error}`);let{manifest:b,format:x}=y.data,S=u||b.name,C=p??(_?`git`:`local`);if(e.has(S))return i.remove(v),c(`Flow "${S}" is already installed. Use flow({ action: "update", name: "${S}" }) to update it, or flow({ action: "remove", name: "${S}" }) then flow({ action: "add", source: "..." }) to replace.`);if(b.install.length>0){let e=i.runInstallDeps(b.install);if(!e.success)return i.remove(v),c(`Dependency install failed: ${e.error}`)}let w=new Date().toISOString(),T=_?i.getLocalCommit(v):void 0,E=e.register({name:S,version:b.version,source:C===`local`||C===`claude-plugin`?h??l:l,sourceType:C,installPath:v,format:x,registeredAt:w,updatedAt:w,manifest:b,...T?{commitSha:T}:{}});if(!E.success)return i.remove(v),c(`Failed to register flow: ${E.error}`);let D=b.steps.length;return c(`Flow "${S}" installed successfully (${D} steps). Use flow({ action: "start", name: "${S}" }) to begin.`)}catch(e){return i.error(`flow action add failed`,I(e)),c(`Error: ${s(e)}`)}}async function mu(e,t){let{getFlows:n,log:r,toErrorText:i,toTextResponse:a}=t,{name:o}=e;try{let{registry:e,installer:t}=await n();if(!e.has(o))return a(`Flow "${o}" is not installed.`);let r=e.get(o);if(!r)return a(`Flow "${o}" is not installed.`);if(r.sourceType===`builtin`)return a(`Cannot remove builtin flow "${o}".`);let i=t.remove(r.installPath);if(!i.success)return a(`Failed to remove flow files: ${i.error}`);let s=e.unregister(o);return s.success?a(`Flow "${o}" removed successfully.`):a(`Failed to unregister flow: ${s.error}`)}catch(e){return r.error(`flow action remove failed`,I(e)),a(`Error: ${i(e)}`)}}async function hu(e,t){let{getFlows:n,log:r,toErrorText:i,toTextResponse:a}=t,{name:o}=e,s={createFlowTransform:t.createFlowTransform,getFlows:t.getFlows,resolveOpenSpecSource:t.resolveOpenSpecSource,toErrorText:t.toErrorText,toTextResponse:t.toTextResponse};try{let{registry:e}=await n();if(!e.has(o))return a(`Flow "${o}" is not installed.`);let t=e.get(o);return!t||t.sourceType!==`git`&&t.sourceType!==`npm-global`&&t.sourceType!==`local`&&t.sourceType!==`claude-plugin`?a(`Flow "${o}" was not installed from git, npm, or a local source — cannot update. Remove and re-add instead.`):t.sourceType===`local`||t.sourceType===`claude-plugin`?uu(s,t):t.sourceType===`npm-global`?du(s,t):fu(s,t)}catch(e){return r.error(`flow action update failed`,I(e)),a(`Error: ${i(e)}`)}}const gu=`IMPORTANT: Start/status/step only include a brief. Call flow({ action: "read" }) before executing this flow step.`,_u=1200,vu=/artifact|output contract|gate|completion criteria|deliverable|must|do not|forbidden/i;function yu(){return{artifactsPath:null,currentStepInstruction:null,currentStepDescription:null,currentStepContent:null,currentStepBrief:null,currentStepPins:null,stepSequence:[]}}function bu(e){if(e.length<=_u)return e;let t=e.slice(0,_u-1),n=Math.max(t.lastIndexOf(`
181
181
  `),t.lastIndexOf(` `),t.lastIndexOf(` `));return`${(n>=Math.floor(t.length*.6)?t.slice(0,n):t).trimEnd()}…`}function xu(e){if(!e?.trim())return{brief:null,pins:null};let t=/^##\s+/m.exec(e),n=(t?e.slice(0,t.index):e).trim(),r=null;if(n){let e=n.split(/\n\s*\n/).filter(e=>e.trim().length>0),t=(e[0]?.startsWith(`#`)&&e[1]?e.slice(0,2):e.slice(0,1)).join(`
182
182
 
183
183
  `).trim();r=t?bu(t):null}let i=Array.from(e.matchAll(/^##\s+.*$/gm)),a=[];for(let[t,n]of i.entries()){let r=n[0];if(!vu.test(r))continue;let o=n.index??0,s=i[t+1]?.index??e.length;a.push(e.slice(o,s).replace(/\s+$/,``))}return{brief:r,pins:a.length>0?a.join(`
184
184
 
185
- `):null}}function Su(e,t){return t(e)}async function Cu(e){let{context:t,entry:n,state:r,activeRoot:i,primaryRoot:a,roots:o}=e,{instructionPath:s,description:c}=t.resolveCurrentStepInfo(n,r.currentStep,i),l=Su(n,t.getStepSequence),u=await cu({entry:n,stepId:r.currentStep,runDir:r.runDir,slug:r.slug,primaryRoot:a,roots:o,activeRoot:i,resolveInstructionPath:t.resolveInstructionPath,resolveEpilogueInstructionPath:t.resolveEpilogueInstructionPath}),{brief:d,pins:f}=xu(u),p=d;if(d&&r.currentStep){let e=n.manifest.steps.find(e=>e.id===r.currentStep),a={stepId:r.currentStep,flowName:r.flow,flowSlug:r.slug,phase:`flow`,runDir:r.runDir,artifactsPath:N(r.runDir,n.manifest.artifacts_dir).replaceAll(`\\`,`/`),completedSteps:[],stepDescription:e?.description??c??void 0,agents:e?.agents??[],mode:`brief`,topic:r.topic??``,activeRoot:i};p=await t.stepPipeline.enrich(d,a,n.manifest.hooks)}return{artifactsPath:N(r.runDir,n.manifest.artifacts_dir).replaceAll(`\\`,`/`),currentStepInstruction:s,currentStepDescription:c,currentStepContent:u,currentStepBrief:p,currentStepPins:f,stepSequence:l}}function wu(e){let{state:t,data:n,started:r,includeStatus:i,action:a,includeInstructionPath:o}=e,s={};return r&&(s.started=!0),s.flow=t.flow,i&&(s.status=t.status),a&&(s.action=a),s.slug=t.slug,s.topic=t.topic,s.runDir=t.runDir,s.artifactsPath=n.artifactsPath,s.currentStep=t.currentStep,s.currentStepInstruction=n.currentStepInstruction,o&&(s.instructionPath=n.currentStepInstruction),s.currentStepDescription=n.currentStepDescription,s.currentStepContent=null,s.currentStepBrief=n.currentStepBrief,s.currentStepPins=n.currentStepPins,s.fullContentHint=`Call flow({ action: 'read' }) for the complete step instructions.`,s}async function Tu(e,t){let{getAllRoots:n,getFlows:r,getWorkspaceRoot:i,isValidFlowRoot:a,log:o,patchMetaRoots:s,stateDir:c,toErrorText:l,toTextResponse:u}=t,{flow:d,topic:f,roots:p}=e;try{if(p&&p.length>0){let e=n().map(e=>e.replaceAll(`\\`,`/`)),t=p.filter(e=>!a(e));if(t.length>0)return u(`Invalid roots — not part of the workspace or a recognized sub-repository: ${t.join(`, `)}. Available roots: ${e.join(`, `)}`)}let e=n(),o=e.map(e=>e.replaceAll(`\\`,`/`)),l=i(),m=e.length>1,h=!p&&m,g=p?.[0]??l,{registry:_,stateMachine:v}=await r(g),y=_.get(d);if(!y)throw new ou(`UNKNOWN_FLOW`,`Flow "${d}" not found. Use flow({ action: "list" }) to see available flows.`);let b=v.start(y.name,y.manifest,f);if(!b.success||!b.data){let e=b.error??`Unknown flow start error.`;return e.includes(`already active`)?u(`Cannot start: ${new ou(`FLOW_ALREADY_ACTIVE`,e).message}`):u(`Cannot start: ${e}`)}let x=b.data;if(p&&p.length>1)try{s(x.slug,g,p),t.syncMetaToRoots(x.slug,g)}catch(e){return v.reset(),u(`Flow created but failed to sync to secondary roots — rolled back. Error: ${e instanceof Error?e.message:String(e)}`)}let S=N(c,`flow-context`),C=typeof Nn==`function`?await Nn(S).catch(()=>[]):[];for(let e of C)e!==x.slug&&typeof Pn==`function`&&await Pn(N(S,e),{recursive:!0,force:!0}).catch(()=>{});if(typeof jn==`function`)try{await jn(N(S,x.slug),{recursive:!0})}catch{}let w=await Cu({context:t,entry:y,state:x,activeRoot:g,primaryRoot:null,roots:p??null}),T={...wu({state:x,data:w,started:!0}),phase:x.phase,isEpilogue:x.isEpilogue,totalSteps:w.stepSequence.length,stepSequence:w.stepSequence,artifactsDir:y.manifest.artifacts_dir,roots:p??[g.replaceAll(`\\`,`/`)],_hint:gu,...h?{multiRootWarning:`No roots specified in multi-root workspace. Flow created at workspace root. Pass roots parameter with target repo for precise placement.`,availableRoots:o}:{}};return u(JSON.stringify(T,null,2))}catch(e){return su(e)?u(e.message):(o.error(`flow action start failed`,I(e)),u(`Error: ${l(e)}`))}}async function Eu(e){let{getFlows:t,log:n,resolveFlowRoot:r,resolveRoots:i,toErrorText:a,toTextResponse:o}=e;try{let n=await r(),{registry:a,stateMachine:s}=await t(n),c=s.getStatus();if(!c.success||!c.data)throw new ou(`NO_ACTIVE_FLOW`,`No active flow. Use flow({ action: "start", name: "<flow>" }) to begin one, or flow({ action: "list" }) to see available flows.`);let l=c.data,u=a.get(l.flow),d=u?await Cu({context:e,entry:u,state:l,activeRoot:n,primaryRoot:l.primaryRoot,roots:l.roots}):yu(),f={...wu({state:l,data:d,includeStatus:!0,includeInstructionPath:!0}),_hint:l.currentStep?gu:void 0,phase:l.phase,isEpilogue:l.isEpilogue,completedSteps:l.completedSteps,skippedSteps:l.skippedSteps,artifacts:l.artifacts,startedAt:l.startedAt,updatedAt:l.updatedAt,totalSteps:d.stepSequence.length,progress:u?`${l.completedSteps.length+l.skippedSteps.length}/${d.stepSequence.length}`:`unknown`,workspaceRoot:n.replaceAll(`\\`,`/`),primaryRoot:(l.primaryRoot??n).replaceAll(`\\`,`/`),roots:l.roots??[n.replaceAll(`\\`,`/`)],allRoots:i().normalizedAllRoots,discoveredRepos:i().discoveredRepos};return o(JSON.stringify(f,null,2))}catch(e){return su(e)?o(e.message):(n.error(`flow action status failed`,I(e)),o(`Error: ${a(e)}`))}}async function Du(e){let{getFlows:t,log:n,resolveFlowRoot:r,stateDir:i,syncMetaToRoots:a,toErrorText:o,toTextResponse:s}=e;try{let e=await r(),{stateMachine:n}=await t(e),o=n.getStatus(),c=n.reset();if(!c.success)return s(`Reset failed: ${c.error}`);if(o.success&&o.data&&a(o.data.slug,e),o.success&&o.data?.slug)try{await Pn(N(i,`flow-context`,o.data.slug),{recursive:!0,force:!0})}catch{}return s(`Flow abandoned. Use flow({ action: "start", name: "<flow>" }) to begin a new flow.`)}catch(e){return n.error(`flow action reset failed`,I(e)),s(`Error: ${o(e)}`)}}async function Ou(e,t){let{getFlows:n,log:r,resolveFlowRoot:i,syncMetaToRoots:a,toErrorText:o,toTextResponse:s}=t,{action:c}=e;try{let e=await i(),{registry:r,stateMachine:o}=await n(e),l=o.getStatus();if(!l.success||!l.data)throw new ou(`NO_ACTIVE_FLOW`,`No active flow. Use flow({ action: "start", name: "<flow>" }) first.`);let u=r.get(l.data.flow);if(!u)throw new ou(`FLOW_NOT_FOUND`,`Flow "${l.data.flow}" not found in registry.`);let d=o.step(c,u.manifest);if(!d.success||!d.data)return s(`Cannot ${c}: ${d.error}`);a(d.data.slug,e);let f=d.data,p=[];if(f.status===`completed`){let e=N(t.stateDir,`flow-context`,f.slug);for(let t of[`decision`,`pattern`]){let n=N(e,t);try{let e=await Nn(n);for(let r of e){if(!r.endsWith(`.md`))continue;let e=await Mn(N(n,r),`utf-8`);e.length>100&&p.push({type:t,title:r.replace(/\.md$/,``).replace(/-/g,` `),content:e.length>500?`${e.slice(0,497)}...`:e})}}catch{}}typeof Pn==`function`&&await Pn(e,{recursive:!0,force:!0}).catch(()=>{})}let m=await Cu({context:t,entry:u,state:f,activeRoot:e,primaryRoot:f.primaryRoot,roots:f.roots}),h={...wu({state:f,data:m,includeStatus:!0,action:c}),_hint:f.currentStep?gu:void 0,phase:f.phase,isEpilogue:f.isEpilogue,completedSteps:f.completedSteps,skippedSteps:f.skippedSteps,totalSteps:m.stepSequence.length,remaining:m.stepSequence.filter(e=>!f.completedSteps.includes(e)&&!f.skippedSteps.includes(e)&&e!==f.currentStep),...p.length>0?{promotionCandidates:p}:{}};return s(JSON.stringify(h,null,2))}catch(e){return su(e)?s(e.message):(r.error(`flow action step failed`,I(e)),s(`Error: ${o(e)}`))}}async function ku(e){let{getFlows:t,log:n,resolveFlowRoot:r,resolveRoots:i,toErrorText:a,toTextResponse:o}=e;try{let{registry:e,stateMachine:n,installer:a}=await t(await r()),s=e.list(),c=n.getStatus(),l={flows:s.map(e=>{let t={name:e.name,version:e.version,source:e.source,sourceType:e.sourceType,format:e.format,steps:e.manifest.steps.map(e=>e.id)};if(e.sourceType===`git`&&e.commitSha){let n=a.hasUpdates(e.installPath);return{...t,commitSha:e.commitSha,updateAvailable:n.success&&n.data?n.data.hasUpdates:void 0}}return t}),activeFlow:c.success&&c.data?{flow:c.data.flow,status:c.data.status,currentStep:c.data.currentStep,slug:c.data.slug,topic:c.data.topic,runDir:c.data.runDir}:null,allRoots:i().normalizedAllRoots,discoveredRepos:i().discoveredRepos};return o(JSON.stringify(l,null,2))}catch(e){return n.error(`flow action list failed`,I(e)),o(`Error: ${a(e)}`)}}async function Au(e,t){let{getFlows:n,log:r,resolveInstallPath:i,resolveInstructionPath:a,toErrorText:o,toTextResponse:s}=t,{name:c}=e;try{let{registry:e,installer:t}=await n(),r=e.get(c);if(!r)throw new ou(`UNKNOWN_FLOW`,`Flow "${c}" not found. Use flow({ action: "list" }) to see available flows.`);let o=r.commitSha??null,l;if(r.sourceType===`git`&&r.installPath){let e=t.hasUpdates(r.installPath);l=e.success&&e.data?e.data.hasUpdates:void 0}let u={name:r.name,version:r.version,description:r.manifest.description,source:r.source,sourceType:r.sourceType,format:r.format,commitSha:o,updateAvailable:l,installPath:i(r.name,r),registeredAt:r.registeredAt,updatedAt:r.updatedAt,steps:r.manifest.steps.map(e=>({id:e.id,name:e.name,instruction:a(r,e.instruction),produces:e.produces,requires:e.requires,description:e.description})),agents:r.manifest.agents,artifactsDir:r.manifest.artifacts_dir,install:r.manifest.install};return s(JSON.stringify(u,null,2))}catch(e){return su(e)?s(e.message):(r.error(`flow action info failed`,I(e)),s(`Error: ${o(e)}`))}}async function ju(e,t){let{getAllRoots:n,getFlows:r,log:i,toErrorText:a,toTextResponse:o}=t,{flow:s,status:c,limit:l=50}=e,u=e=>{for(let t of[`updatedAt`,`startedAt`,`createdAt`]){let n=e[t];if(typeof n==`number`&&Number.isFinite(n))return n;if(typeof n==`string`){let e=Date.parse(n);if(!Number.isNaN(e))return e}}return null};try{let e=n(),t=[];for(let n of e){let{stateMachine:e}=await r(n),i=e.listRuns({flow:s,status:c});for(let e of i)t.push({...JSON.parse(JSON.stringify(e)),root:n.replaceAll(`\\`,`/`)})}let i=new Set,a=t.filter(e=>{let t=e.id;return i.has(t)?!1:(i.add(t),!0)});if(a.length===0)return o(`No flow runs found.`);let d=a.map((e,t)=>({run:e,index:t,recency:u(e)})).sort((e,t)=>e.recency==null&&t.recency==null?e.index-t.index:e.recency==null?1:t.recency==null?-1:t.recency===e.recency?e.index-t.index:t.recency-e.recency).map(({run:e})=>e).slice(0,l);return o(JSON.stringify({total:a.length,returned:d.length,truncated:a.length>d.length,runs:d},null,2))}catch(e){return i.error(`flow action runs failed`,I(e)),o(`Error: ${a(e)}`)}}function Mu(e){let t=e.content?.find(e=>e.type===`text`)?.text??``;if(!t)return null;try{let e=JSON.parse(t);if(typeof e.slug==`string`&&e.slug.length>0)return e.slug}catch{}return t.match(/[Ss]lug[:\s]*`?([^`\s,]+)`?/)?.[1]??null}function Nu(e,t,n){let r=au(e,t),i=G(`flow`);e.registerTool(`flow`,{title:i.title,description:`Manage development flows — list available flows, start/stop runs, navigate steps, read instructions, and install/remove/update flows. Use action parameter to select operation.`,annotations:i.annotations,inputSchema:{action:R.enum([`list`,`info`,`start`,`step`,`status`,`reset`,`read`,`runs`,`add`,`remove`,`update`]).describe(`The flow operation to perform.`),name:R.string().optional().describe(`Flow name — required for info, start, remove, update. Optional override for add.`),topic:R.string().optional().describe(`Human-readable topic for the run (used by start).`),roots:R.array(R.string()).optional().describe(`Workspace roots participating in this flow (used by start).`),advance:R.enum([`next`,`skip`,`redo`]).optional().describe(`Step navigation action — required for step.`),step:R.string().optional().describe(`Step id or name to read (used by read). Defaults to current step.`),source:R.string().optional().describe(`Git URL, local path, or "openspec" shorthand — required for add.`),token:R.string().optional().describe(`Auth token for private repos (used by add).`),filter_flow:R.string().optional().describe(`Filter runs by flow name (used by runs).`),filter_status:R.string().optional().describe(`Filter runs by status: active, completed, abandoned (used by runs).`),limit:R.number().int().positive().optional().describe(`Max runs to return (default 50).`)}},Y(`flow`,async e=>{switch(e.action){case`list`:return ku(r);case`info`:return e.name?Au({name:e.name},r):r.toTextResponse(`Missing required parameter: name`);case`start`:{if(!e.name)return r.toTextResponse(`Missing required parameter: name (flow to start)`);let t=await Tu({flow:e.name,topic:e.topic,roots:e.roots},r),i=Mu(t);return i&&n&&n(i),t}case`step`:return e.advance?Ou({action:e.advance},r):r.toTextResponse(`Missing required parameter: advance (next/skip/redo)`);case`status`:{let e=await Eu(r);return n&&n(Mu(e)),e}case`reset`:{let e=await Du(r);return n&&n(null),e}case`read`:return lu({step:e.step},r);case`runs`:return ju({flow:e.filter_flow,status:e.filter_status,limit:e.limit},r);case`add`:return e.source?pu({source:e.source,name:e.name,token:e.token},r):r.toTextResponse(`Missing required parameter: source`);case`remove`:return e.name?mu({name:e.name},r):r.toTextResponse(`Missing required parameter: name`);case`update`:return e.name?hu({name:e.name},r):r.toTextResponse(`Missing required parameter: name`);default:return r.toTextResponse(`Unknown action: ${e.action}`)}}))}const Pu=F(`tools`);function Fu(e){let t=G(`evidence_map`);e.registerTool(`evidence_map`,{title:t.title,description:`Track verified/assumed/unresolved claims for complex tasks. Gate readiness: YIELD (proceed), HOLD (unknowns), HARD_BLOCK (critical gaps). Persists across calls.`,inputSchema:{action:R.enum([`create`,`add`,`update`,`get`,`gate`,`list`,`delete`]).describe(`Operation to perform`),task_id:R.string().optional().describe(`Task identifier (required for all except list)`),tier:R.enum([`floor`,`standard`,`critical`]).optional().describe(`FORGE tier (required for create)`),claim:R.string().optional().describe(`Critical-path claim text (for add)`),status:R.enum([`V`,`A`,`U`]).optional().describe(`Evidence status: V=Verified, A=Assumed, U=Unresolved`),receipt:R.string().optional().describe(`Evidence receipt: tool→ref for V, reasoning for A, attempts for U`),id:R.number().optional().describe(`Entry ID (for update)`),critical_path:R.boolean().default(!0).describe(`Whether this claim is on the critical path`),unknown_type:R.enum([`contract`,`convention`,`freshness`,`runtime`,`data-flow`,`impact`]).optional().describe(`Typed unknown classification`),safety_gate:R.enum([`provenance`,`commitment`,`coverage`]).optional().describe(`Safety gate tag: provenance (claim→evidence), commitment (user-approved), coverage (nothing dropped)`),retry_count:R.number().default(0).describe(`Retry count for gate evaluation (0 = first attempt)`),max_retries:R.number().int().min(0).optional().describe(`Maximum retries before escalating. Default: 3`),timeout_action:R.enum([`iterate`,`retry`,`manual`,`terminate`]).optional().describe(`Action to take when gate retries are exhausted. Default: manual`),cwd:R.string().optional().describe(`Working directory for evidence map storage (default: server cwd). Use root_path from forge_ground to match.`)},annotations:t.annotations},Y(`evidence_map`,async({action:e,task_id:t,tier:n,claim:r,status:i,receipt:a,id:o,critical_path:s,unknown_type:c,safety_gate:l,retry_count:u,max_retries:d,timeout_action:f,cwd:p})=>{try{switch(e){case`create`:if(!t)throw Error(`task_id required for create`);if(!n)throw Error(`tier required for create`);return ft({action:`create`,taskId:t,tier:n},p),{content:[{type:`text`,text:`Created evidence map "${t}" (tier: ${n}).\n\n---\n_Next: Use \`evidence_map\` with action "add" to record critical-path claims._`}]};case`add`:{if(!t)throw Error(`task_id required for add`);if(!r)throw Error(`claim required for add`);if(!i)throw Error(`status required for add`);let e=ft({action:`add`,taskId:t,claim:r,status:i,receipt:a??``,criticalPath:s,unknownType:c,safetyGate:l},p),n=e.autoCreated?[`⚠️ Evidence map "${t}" was auto-created with tier "standard". Use \`create\` action to set a specific tier.`,``,`Added entry #${e.entry?.id} to "${t}": [${i}] ${r}`]:[`Added entry #${e.entry?.id} to "${t}": [${i}] ${r}`];return e.summary&&n.push(``,e.summary),{content:[{type:`text`,text:n.join(`
185
+ `):null}}function Su(e,t){return t(e)}async function Cu(e){let{context:t,entry:n,state:r,activeRoot:i,primaryRoot:a,roots:o}=e,{instructionPath:s,description:c}=t.resolveCurrentStepInfo(n,r.currentStep,i),l=Su(n,t.getStepSequence),u=await cu({entry:n,stepId:r.currentStep,runDir:r.runDir,slug:r.slug,primaryRoot:a,roots:o,activeRoot:i,resolveInstructionPath:t.resolveInstructionPath,resolveEpilogueInstructionPath:t.resolveEpilogueInstructionPath}),{brief:d,pins:f}=xu(u),p=d;if(d&&r.currentStep){let e=n.manifest.steps.find(e=>e.id===r.currentStep),a={stepId:r.currentStep,flowName:r.flow,flowSlug:r.slug,phase:`flow`,runDir:r.runDir,artifactsPath:N(r.runDir,n.manifest.artifacts_dir).replaceAll(`\\`,`/`),completedSteps:r.completedSteps??[],stepDescription:e?.description??c??void 0,agents:e?.agents??[],mode:`brief`,topic:r.topic??``,activeRoot:i};p=await t.stepPipeline.enrich(d,a,n.manifest.hooks)}return{artifactsPath:N(r.runDir,n.manifest.artifacts_dir).replaceAll(`\\`,`/`),currentStepInstruction:s,currentStepDescription:c,currentStepContent:u,currentStepBrief:p,currentStepPins:f,stepSequence:l}}function wu(e){let{state:t,data:n,started:r,includeStatus:i,action:a,includeInstructionPath:o}=e,s={};return r&&(s.started=!0),s.flow=t.flow,i&&(s.status=t.status),a&&(s.action=a),s.slug=t.slug,s.topic=t.topic,s.runDir=t.runDir,s.artifactsPath=n.artifactsPath,s.currentStep=t.currentStep,s.currentStepInstruction=n.currentStepInstruction,o&&(s.instructionPath=n.currentStepInstruction),s.currentStepDescription=n.currentStepDescription,s.currentStepContent=null,s.currentStepBrief=n.currentStepBrief,s.currentStepPins=n.currentStepPins,s.fullContentHint=`Call flow({ action: 'read' }) for the complete step instructions.`,s}async function Tu(e,t){let{getAllRoots:n,getFlows:r,getWorkspaceRoot:i,isValidFlowRoot:a,log:o,patchMetaRoots:s,stateDir:c,toErrorText:l,toTextResponse:u}=t,{flow:d,topic:f,roots:p}=e;try{if(p&&p.length>0){let e=n().map(e=>e.replaceAll(`\\`,`/`)),t=p.filter(e=>!a(e));if(t.length>0)return u(`Invalid roots — not part of the workspace or a recognized sub-repository: ${t.join(`, `)}. Available roots: ${e.join(`, `)}`)}let e=n(),o=e.map(e=>e.replaceAll(`\\`,`/`)),l=i(),m=e.length>1,h=!p&&m,g=p?.[0]??l,{registry:_,stateMachine:v}=await r(g),y=_.get(d);if(!y)throw new ou(`UNKNOWN_FLOW`,`Flow "${d}" not found. Use flow({ action: "list" }) to see available flows.`);let b=v.start(y.name,y.manifest,f);if(!b.success||!b.data){let e=b.error??`Unknown flow start error.`;return e.includes(`already active`)?u(`Cannot start: ${new ou(`FLOW_ALREADY_ACTIVE`,e).message}`):u(`Cannot start: ${e}`)}let x=b.data;if(p&&p.length>1)try{s(x.slug,g,p),t.syncMetaToRoots(x.slug,g)}catch(e){return v.reset(),u(`Flow created but failed to sync to secondary roots — rolled back. Error: ${e instanceof Error?e.message:String(e)}`)}let S=N(c,`flow-context`),C=typeof Nn==`function`?await Nn(S).catch(()=>[]):[];for(let e of C)e!==x.slug&&typeof Pn==`function`&&await Pn(N(S,e),{recursive:!0,force:!0}).catch(()=>{});if(typeof jn==`function`)try{await jn(N(S,x.slug),{recursive:!0})}catch{}let w=await Cu({context:t,entry:y,state:x,activeRoot:g,primaryRoot:null,roots:p??null}),T={...wu({state:x,data:w,started:!0}),phase:x.phase,isEpilogue:x.isEpilogue,totalSteps:w.stepSequence.length,stepSequence:w.stepSequence,artifactsDir:y.manifest.artifacts_dir,roots:p??[g.replaceAll(`\\`,`/`)],_hint:gu,...h?{multiRootWarning:`No roots specified in multi-root workspace. Flow created at workspace root. Pass roots parameter with target repo for precise placement.`,availableRoots:o}:{}};return u(JSON.stringify(T,null,2))}catch(e){return su(e)?u(e.message):(o.error(`flow action start failed`,I(e)),u(`Error: ${l(e)}`))}}async function Eu(e){let{getFlows:t,log:n,resolveFlowRoot:r,resolveRoots:i,toErrorText:a,toTextResponse:o}=e;try{let n=await r(),{registry:a,stateMachine:s}=await t(n),c=s.getStatus();if(!c.success||!c.data)throw new ou(`NO_ACTIVE_FLOW`,`No active flow. Use flow({ action: "start", name: "<flow>" }) to begin one, or flow({ action: "list" }) to see available flows.`);let l=c.data,u=a.get(l.flow),d=u?await Cu({context:e,entry:u,state:l,activeRoot:n,primaryRoot:l.primaryRoot,roots:l.roots}):yu(),f={...wu({state:l,data:d,includeStatus:!0,includeInstructionPath:!0}),_hint:l.currentStep?gu:void 0,phase:l.phase,isEpilogue:l.isEpilogue,completedSteps:l.completedSteps,skippedSteps:l.skippedSteps,artifacts:l.artifacts,startedAt:l.startedAt,updatedAt:l.updatedAt,totalSteps:d.stepSequence.length,progress:u?`${l.completedSteps.length+l.skippedSteps.length}/${d.stepSequence.length}`:`unknown`,workspaceRoot:n.replaceAll(`\\`,`/`),primaryRoot:(l.primaryRoot??n).replaceAll(`\\`,`/`),roots:l.roots??[n.replaceAll(`\\`,`/`)],allRoots:i().normalizedAllRoots,discoveredRepos:i().discoveredRepos};return o(JSON.stringify(f,null,2))}catch(e){return su(e)?o(e.message):(n.error(`flow action status failed`,I(e)),o(`Error: ${a(e)}`))}}async function Du(e){let{getFlows:t,log:n,resolveFlowRoot:r,stateDir:i,syncMetaToRoots:a,toErrorText:o,toTextResponse:s}=e;try{let e=await r(),{stateMachine:n}=await t(e),o=n.getStatus(),c=n.reset();if(!c.success)return s(`Reset failed: ${c.error}`);if(o.success&&o.data&&a(o.data.slug,e),o.success&&o.data?.slug)try{await Pn(N(i,`flow-context`,o.data.slug),{recursive:!0,force:!0})}catch{}return s(`Flow abandoned. Use flow({ action: "start", name: "<flow>" }) to begin a new flow.`)}catch(e){return n.error(`flow action reset failed`,I(e)),s(`Error: ${o(e)}`)}}async function Ou(e,t){let{getFlows:n,log:r,resolveFlowRoot:i,syncMetaToRoots:a,toErrorText:o,toTextResponse:s}=t,{action:c}=e;try{let e=await i(),{registry:r,stateMachine:o}=await n(e),l=o.getStatus();if(!l.success||!l.data)throw new ou(`NO_ACTIVE_FLOW`,`No active flow. Use flow({ action: "start", name: "<flow>" }) first.`);let u=r.get(l.data.flow);if(!u)throw new ou(`FLOW_NOT_FOUND`,`Flow "${l.data.flow}" not found in registry.`);let d=o.step(c,u.manifest);if(!d.success||!d.data)return s(`Cannot ${c}: ${d.error}`);a(d.data.slug,e);let f=d.data,p=[];if(f.status===`completed`){let e=N(t.stateDir,`flow-context`,f.slug);for(let t of[`decision`,`pattern`]){let n=N(e,t);try{let e=await Nn(n);for(let r of e){if(!r.endsWith(`.md`))continue;let e=await Mn(N(n,r),`utf-8`);e.length>100&&p.push({type:t,title:r.replace(/\.md$/,``).replace(/-/g,` `),content:e.length>500?`${e.slice(0,497)}...`:e})}}catch{}}typeof Pn==`function`&&await Pn(e,{recursive:!0,force:!0}).catch(()=>{})}let m=await Cu({context:t,entry:u,state:f,activeRoot:e,primaryRoot:f.primaryRoot,roots:f.roots}),h={...wu({state:f,data:m,includeStatus:!0,action:c}),_hint:f.currentStep?gu:void 0,phase:f.phase,isEpilogue:f.isEpilogue,completedSteps:f.completedSteps,skippedSteps:f.skippedSteps,totalSteps:m.stepSequence.length,remaining:m.stepSequence.filter(e=>!f.completedSteps.includes(e)&&!f.skippedSteps.includes(e)&&e!==f.currentStep),...p.length>0?{promotionCandidates:p}:{}};return s(JSON.stringify(h,null,2))}catch(e){return su(e)?s(e.message):(r.error(`flow action step failed`,I(e)),s(`Error: ${o(e)}`))}}async function ku(e){let{getFlows:t,log:n,resolveFlowRoot:r,resolveRoots:i,toErrorText:a,toTextResponse:o}=e;try{let{registry:e,stateMachine:n,installer:a}=await t(await r()),s=e.list(),c=n.getStatus(),l={flows:s.map(e=>{let t={name:e.name,version:e.version,source:e.source,sourceType:e.sourceType,format:e.format,steps:e.manifest.steps.map(e=>e.id)};if(e.sourceType===`git`&&e.commitSha){let n=a.hasUpdates(e.installPath);return{...t,commitSha:e.commitSha,updateAvailable:n.success&&n.data?n.data.hasUpdates:void 0}}return t}),activeFlow:c.success&&c.data?{flow:c.data.flow,status:c.data.status,currentStep:c.data.currentStep,slug:c.data.slug,topic:c.data.topic,runDir:c.data.runDir}:null,allRoots:i().normalizedAllRoots,discoveredRepos:i().discoveredRepos};return o(JSON.stringify(l,null,2))}catch(e){return n.error(`flow action list failed`,I(e)),o(`Error: ${a(e)}`)}}async function Au(e,t){let{getFlows:n,log:r,resolveInstallPath:i,resolveInstructionPath:a,toErrorText:o,toTextResponse:s}=t,{name:c}=e;try{let{registry:e,installer:t}=await n(),r=e.get(c);if(!r)throw new ou(`UNKNOWN_FLOW`,`Flow "${c}" not found. Use flow({ action: "list" }) to see available flows.`);let o=r.commitSha??null,l;if(r.sourceType===`git`&&r.installPath){let e=t.hasUpdates(r.installPath);l=e.success&&e.data?e.data.hasUpdates:void 0}let u={name:r.name,version:r.version,description:r.manifest.description,source:r.source,sourceType:r.sourceType,format:r.format,commitSha:o,updateAvailable:l,installPath:i(r.name,r),registeredAt:r.registeredAt,updatedAt:r.updatedAt,steps:r.manifest.steps.map(e=>({id:e.id,name:e.name,instruction:a(r,e.instruction),produces:e.produces,requires:e.requires,description:e.description})),agents:r.manifest.agents,artifactsDir:r.manifest.artifacts_dir,install:r.manifest.install};return s(JSON.stringify(u,null,2))}catch(e){return su(e)?s(e.message):(r.error(`flow action info failed`,I(e)),s(`Error: ${o(e)}`))}}async function ju(e,t){let{getAllRoots:n,getFlows:r,log:i,toErrorText:a,toTextResponse:o}=t,{flow:s,status:c,limit:l=50}=e,u=e=>{for(let t of[`updatedAt`,`startedAt`,`createdAt`]){let n=e[t];if(typeof n==`number`&&Number.isFinite(n))return n;if(typeof n==`string`){let e=Date.parse(n);if(!Number.isNaN(e))return e}}return null};try{let e=n(),t=[];for(let n of e){let{stateMachine:e}=await r(n),i=e.listRuns({flow:s,status:c});for(let e of i)t.push({...JSON.parse(JSON.stringify(e)),root:n.replaceAll(`\\`,`/`)})}let i=new Set,a=t.filter(e=>{let t=e.id;return i.has(t)?!1:(i.add(t),!0)});if(a.length===0)return o(`No flow runs found.`);let d=a.map((e,t)=>({run:e,index:t,recency:u(e)})).sort((e,t)=>e.recency==null&&t.recency==null?e.index-t.index:e.recency==null?1:t.recency==null?-1:t.recency===e.recency?e.index-t.index:t.recency-e.recency).map(({run:e})=>e).slice(0,l);return o(JSON.stringify({total:a.length,returned:d.length,truncated:a.length>d.length,runs:d},null,2))}catch(e){return i.error(`flow action runs failed`,I(e)),o(`Error: ${a(e)}`)}}function Mu(e){let t=e.content?.find(e=>e.type===`text`)?.text??``;if(!t)return null;try{let e=JSON.parse(t);if(typeof e.slug==`string`&&e.slug.length>0)return e.slug}catch{}return t.match(/[Ss]lug[:\s]*`?([^`\s,]+)`?/)?.[1]??null}function Nu(e,t,n,r){let i=n&&typeof n!=`function`?n:void 0,a=typeof n==`function`?n:r,o=au(e,t,i),s=G(`flow`);e.registerTool(`flow`,{title:s.title,description:`Manage development flows — list available flows, start/stop runs, navigate steps, read instructions, and install/remove/update flows. Use action parameter to select operation.`,annotations:s.annotations,inputSchema:{action:R.enum([`list`,`info`,`start`,`step`,`status`,`reset`,`read`,`runs`,`add`,`remove`,`update`]).describe(`The flow operation to perform.`),name:R.string().optional().describe(`Flow name — required for info, start, remove, update. Optional override for add.`),topic:R.string().optional().describe(`Human-readable topic for the run (used by start).`),roots:R.array(R.string()).optional().describe(`Workspace roots participating in this flow (used by start).`),advance:R.enum([`next`,`skip`,`redo`]).optional().describe(`Step navigation action — required for step.`),step:R.string().optional().describe(`Step id or name to read (used by read). Defaults to current step.`),source:R.string().optional().describe(`Git URL, local path, or "openspec" shorthand — required for add.`),token:R.string().optional().describe(`Auth token for private repos (used by add).`),filter_flow:R.string().optional().describe(`Filter runs by flow name (used by runs).`),filter_status:R.string().optional().describe(`Filter runs by status: active, completed, abandoned (used by runs).`),limit:R.number().int().positive().optional().describe(`Max runs to return (default 50).`)}},Y(`flow`,async e=>{switch(e.action){case`list`:return ku(o);case`info`:return e.name?Au({name:e.name},o):o.toTextResponse(`Missing required parameter: name`);case`start`:{if(!e.name)return o.toTextResponse(`Missing required parameter: name (flow to start)`);let t=await Tu({flow:e.name,topic:e.topic,roots:e.roots},o),n=Mu(t);return n&&a&&a(n),t}case`step`:return e.advance?Ou({action:e.advance},o):o.toTextResponse(`Missing required parameter: advance (next/skip/redo)`);case`status`:{let e=await Eu(o);return a&&a(Mu(e)),e}case`reset`:{let e=await Du(o);return a&&a(null),e}case`read`:return lu({step:e.step},o);case`runs`:return ju({flow:e.filter_flow,status:e.filter_status,limit:e.limit},o);case`add`:return e.source?pu({source:e.source,name:e.name,token:e.token},o):o.toTextResponse(`Missing required parameter: source`);case`remove`:return e.name?mu({name:e.name},o):o.toTextResponse(`Missing required parameter: name`);case`update`:return e.name?hu({name:e.name},o):o.toTextResponse(`Missing required parameter: name`);default:return o.toTextResponse(`Unknown action: ${e.action}`)}}))}const Pu=F(`tools`);function Fu(e){let t=G(`evidence_map`);e.registerTool(`evidence_map`,{title:t.title,description:`Track verified/assumed/unresolved claims for complex tasks. Gate readiness: YIELD (proceed), HOLD (unknowns), HARD_BLOCK (critical gaps). Persists across calls.`,inputSchema:{action:R.enum([`create`,`add`,`update`,`get`,`gate`,`list`,`delete`]).describe(`Operation to perform`),task_id:R.string().optional().describe(`Task identifier (required for all except list)`),tier:R.enum([`floor`,`standard`,`critical`]).optional().describe(`FORGE tier (required for create)`),claim:R.string().optional().describe(`Critical-path claim text (for add)`),status:R.enum([`V`,`A`,`U`]).optional().describe(`Evidence status: V=Verified, A=Assumed, U=Unresolved`),receipt:R.string().optional().describe(`Evidence receipt: tool→ref for V, reasoning for A, attempts for U`),id:R.number().optional().describe(`Entry ID (for update)`),critical_path:R.boolean().default(!0).describe(`Whether this claim is on the critical path`),unknown_type:R.enum([`contract`,`convention`,`freshness`,`runtime`,`data-flow`,`impact`]).optional().describe(`Typed unknown classification`),safety_gate:R.enum([`provenance`,`commitment`,`coverage`]).optional().describe(`Safety gate tag: provenance (claim→evidence), commitment (user-approved), coverage (nothing dropped)`),retry_count:R.number().default(0).describe(`Retry count for gate evaluation (0 = first attempt)`),max_retries:R.number().int().min(0).optional().describe(`Maximum retries before escalating. Default: 3`),timeout_action:R.enum([`iterate`,`retry`,`manual`,`terminate`]).optional().describe(`Action to take when gate retries are exhausted. Default: manual`),cwd:R.string().optional().describe(`Working directory for evidence map storage (default: server cwd). Use root_path from forge_ground to match.`)},annotations:t.annotations},Y(`evidence_map`,async({action:e,task_id:t,tier:n,claim:r,status:i,receipt:a,id:o,critical_path:s,unknown_type:c,safety_gate:l,retry_count:u,max_retries:d,timeout_action:f,cwd:p})=>{try{switch(e){case`create`:if(!t)throw Error(`task_id required for create`);if(!n)throw Error(`tier required for create`);return ft({action:`create`,taskId:t,tier:n},p),{content:[{type:`text`,text:`Created evidence map "${t}" (tier: ${n}).\n\n---\n_Next: Use \`evidence_map\` with action "add" to record critical-path claims._`}]};case`add`:{if(!t)throw Error(`task_id required for add`);if(!r)throw Error(`claim required for add`);if(!i)throw Error(`status required for add`);let e=ft({action:`add`,taskId:t,claim:r,status:i,receipt:a??``,criticalPath:s,unknownType:c,safetyGate:l},p),n=e.autoCreated?[`⚠️ Evidence map "${t}" was auto-created with tier "standard". Use \`create\` action to set a specific tier.`,``,`Added entry #${e.entry?.id} to "${t}": [${i}] ${r}`]:[`Added entry #${e.entry?.id} to "${t}": [${i}] ${r}`];return e.summary&&n.push(``,e.summary),{content:[{type:`text`,text:n.join(`
186
186
  `)}]}}case`update`:{if(!t)throw Error(`task_id required for update`);if(o===void 0)throw Error(`id required for update`);if(!i)throw Error(`status required for update`);let e=ft({action:`update`,taskId:t,id:o,status:i,receipt:a??``},p),n=[`Updated entry #${o} in "${t}" → ${i}`];return e.summary&&n.push(``,e.summary),{content:[{type:`text`,text:n.join(`
187
187
  `)}]}}case`get`:{if(!t)throw Error(`task_id required for get`);let e=ft({action:`get`,taskId:t},p);return e.state?{content:[{type:`text`,text:[`## Evidence Map: ${t} (${e.state.tier})`,``,e.formattedMap??`No entries.`,``,`_${e.state.entries.length} entries — created ${e.state.createdAt}_`].join(`
188
188
  `)}]}:{content:[{type:`text`,text:`Evidence map "${t}" not found.`}]}}case`gate`:{if(!t)throw Error(`task_id required for gate`);let e=ft({action:`gate`,taskId:t,retryCount:u,maxRetries:d,timeoutAction:f},p);if(!e.gate)return{content:[{type:`text`,text:`Evidence map "${t}" not found.`}]};let n=e.gate,r=[`## FORGE Gate: **${n.verdict}**`,``,`**Reason:** ${n.reason}`,``,`**Stats:** ${n.stats.verified}V / ${n.stats.assumed}A / ${n.stats.unresolved}U (${n.stats.total} total)`];return n.action&&r.push(``,`**Recommended action:** ${n.action}`),n.retriesRemaining!==void 0&&r.push(`**Retries remaining:** ${n.retriesRemaining}`),n.summary&&r.push(``,`**Summary:** ${n.summary}`),n.warnings.length>0&&r.push(``,`**Warnings:**`,...n.warnings.map(e=>`- ⚠️ ${e}`)),n.unresolvedCritical.length>0&&r.push(``,`**Blocking entries:**`,...n.unresolvedCritical.map(e=>`- #${e.id}: ${e.claim} [${e.unknownType??`untyped`}]`)),n.safetyGates&&(r.push(``,`**Safety Gates:**`,`- Provenance: ${n.safetyGates.provenance}`,`- Commitment: ${n.safetyGates.commitment}`,`- Coverage: ${n.safetyGates.coverage}`),n.safetyGates.failures.length>0&&r.push(``,`**Safety failures:**`,...n.safetyGates.failures.map(e=>`- \u{1F6D1} ${e}`))),n.annotation&&r.push(``,`**Annotation:**`,n.annotation),e.formattedMap&&r.push(``,`---`,``,e.formattedMap),r.push(``,`---`,`_Next: ${n.verdict===`YIELD`?`Proceed to implementation.`:n.action===`iterate`?`Re-run the build loop, then evaluate the gate again.`:n.action===`retry`?`Re-evaluate the gate after refreshing evidence.`:n.action===`manual`?`Ask for human review before proceeding.`:`Abort the current path and terminate the task.`}_`),{content:[{type:`text`,text:r.join(`
@@ -2966,12 +2966,8 @@ window.addEventListener('message', function(e) {
2966
2966
  });
2967
2967
  <\/script>`,`</div>`].join(`
2968
2968
  `),css:[[`.present-viewer-container {`,` flex: 1;`,` min-height: 640px;`,` position: relative;`,` border-radius: 0.75rem;`,` overflow: hidden;`,` border: none;`,`}`,`.present-viewer-iframe {`,` border: none;`,` width: 100%;`,` height: 100%;`,` position: absolute;`,` inset: 0;`,` border-radius: inherit;`,`}`].join(`
2969
- `)],islands:[],payload:void 0,nonce:``,generatedAt:new Date().toISOString(),colorScheme:e.colorScheme,lang:e.lang,dir:e.dir,transport:`mcp-app`,exportPolicy:`local-interactive`}))),{content:[{type:`text`,text:[Ym(e,{kind:`rendered`,reason:`no-response-required`}),`If this content doesn't render inline, retry with format: 'browser'.`].join(`
2970
-
2971
- `)}],ui:{type:`resource`,uri:Am}}}catch(t){return th(`VIEWER_RENDER_FAILED`,t instanceof Error?t.message:`Failed to render viewer template`,void 0,e.title)}}function ah(e){try{let t=jr(e,{transport:`mcp-app`,registry:am,blockVendorScripts:hp()}),n=fm(t.vendorScripts,`mcp-app`);return jm=$m(Cr({title:e.title,html:[Jm(e),t.html].filter(Boolean).join(`
2972
- `),css:t.css,islands:t.islands,payload:t.payload,nonce:t.nonce,colorScheme:e.colorScheme,lang:e.lang,dir:e.dir,transport:`mcp-app`,exportPolicy:t.exportPolicy,headScripts:n})),{content:[{type:`text`,text:[Ym(e,{kind:`rendered`,reason:`no-response-required`}),`If this content doesn't render inline, retry with format: 'browser'.`].join(`
2973
-
2974
- `)}],ui:{type:`resource`,uri:Am}}}catch(t){return th(`RENDER_FAILED`,t instanceof Error?t.message:`Failed to render ChannelSurface`,void 0,e.title)}}const oh=R.object({label:R.string(),value:R.string(),description:R.string().optional()}),sh=R.object({id:R.string().describe(`Unique action identifier`),type:R.enum([`button`,`select`,`multi-select`,`form-submit`,`text-submit`,`confirm`,`custom`]).describe(`Interactive action type`),label:R.string().describe(`Visible action label`),variant:R.enum([`primary`,`danger`,`default`]).optional(),options:R.array(oh).optional(),schema:R.record(R.string(),R.unknown()).optional()}),ch=R.object({type:R.string(),title:R.string().optional(),value:R.unknown().optional(),language:R.string().optional()}).catchall(R.unknown()),lh={schemaVersion:R.literal(1).describe(`ChannelSurface schema version. Must be 1.`),title:R.string().describe(`Surface title shown to the user.`),description:R.string().optional().describe(`Optional supporting copy for the surface.`),template:R.string().optional().describe(`Optional template id such as report@1.`),layout:R.object({maxWidth:R.string().optional(),padding:R.string().optional(),columns:R.number().optional()}).optional(),blocks:R.array(ch).optional().describe(`Typed block content for the surface.`),data:R.unknown().optional().describe(`Template data payload, if the template expands data.`),actions:R.array(sh).optional().describe(`Interactive actions. Presence triggers browser transport.`),response:R.object({timeout:R.number().optional(),required:R.boolean().optional()}).optional(),metadata:R.object({surfaceId:R.string().optional(),createdAt:R.string().optional(),source:R.string().optional()}).optional(),colorScheme:R.enum([`light`,`dark`,`auto`]).optional(),lang:R.string().optional(),dir:R.enum([`ltr`,`rtl`,`auto`]).optional()};R.object({surfaceId:R.string(),actionId:R.string(),actionType:R.enum([`button`,`select`,`multi-select`,`form-submit`,`text-submit`,`confirm`,`custom`]),value:R.unknown().optional(),formData:R.record(R.string(),R.unknown()).optional(),selection:R.union([R.string(),R.array(R.string())]).optional(),label:R.string().optional(),timestamp:R.string(),sourceTransport:R.enum([`mcp-app`,`browser`,`export`])});function uh(e,t){let n=G(`present`),r=[`Render a ChannelSurface for the user.`,`Quick ref:`,`- Full schema: aikit://schemas/channel-surface`,`- Required: schemaVersion: 1, title`,`- Content: blocks[] for direct rendering, or template + data for registry-backed rendering`,`- Actions: actions[] of SurfaceAction; interactive surfaces use browser transport and return ChannelOutcome`,`- Optional fields: description, layout, response, metadata, colorScheme, lang, dir`,`- Transports: mcp-app, browser, export`,`- Use schema resource for block enums and action details.`].join(`
2969
+ `)],islands:[],payload:void 0,nonce:``,generatedAt:new Date().toISOString(),colorScheme:e.colorScheme,lang:e.lang,dir:e.dir,transport:`mcp-app`,exportPolicy:`local-interactive`}))),{content:[{type:`text`,text:Ym(e,{kind:`rendered`,reason:`no-response-required`})}],ui:{type:`resource`,uri:Am}}}catch(t){return th(`VIEWER_RENDER_FAILED`,t instanceof Error?t.message:`Failed to render viewer template`,void 0,e.title)}}function ah(e){try{let t=jr(e,{transport:`mcp-app`,registry:am,blockVendorScripts:hp()}),n=fm(t.vendorScripts,`mcp-app`);return jm=$m(Cr({title:e.title,html:[Jm(e),t.html].filter(Boolean).join(`
2970
+ `),css:t.css,islands:t.islands,payload:t.payload,nonce:t.nonce,colorScheme:e.colorScheme,lang:e.lang,dir:e.dir,transport:`mcp-app`,exportPolicy:t.exportPolicy,headScripts:n})),{content:[{type:`text`,text:Ym(e,{kind:`rendered`,reason:`no-response-required`})}],ui:{type:`resource`,uri:Am}}}catch(t){return th(`RENDER_FAILED`,t instanceof Error?t.message:`Failed to render ChannelSurface`,void 0,e.title)}}const oh=R.object({label:R.string(),value:R.string(),description:R.string().optional()}),sh=R.object({id:R.string().describe(`Unique action identifier`),type:R.enum([`button`,`select`,`multi-select`,`form-submit`,`text-submit`,`confirm`,`custom`]).describe(`Interactive action type`),label:R.string().describe(`Visible action label`),variant:R.enum([`primary`,`danger`,`default`]).optional(),options:R.array(oh).optional(),schema:R.record(R.string(),R.unknown()).optional()}),ch=R.object({type:R.string(),title:R.string().optional(),value:R.unknown().optional(),language:R.string().optional()}).catchall(R.unknown()),lh={schemaVersion:R.literal(1).describe(`ChannelSurface schema version. Must be 1.`),title:R.string().describe(`Surface title shown to the user.`),description:R.string().optional().describe(`Optional supporting copy for the surface.`),template:R.string().optional().describe(`Optional template id such as report@1.`),layout:R.object({maxWidth:R.string().optional(),padding:R.string().optional(),columns:R.number().optional()}).optional(),blocks:R.array(ch).optional().describe(`Typed block content for the surface.`),data:R.unknown().optional().describe(`Template data payload, if the template expands data.`),actions:R.array(sh).optional().describe(`Interactive actions. Presence triggers browser transport.`),response:R.object({timeout:R.number().optional(),required:R.boolean().optional()}).optional(),metadata:R.object({surfaceId:R.string().optional(),createdAt:R.string().optional(),source:R.string().optional()}).optional(),colorScheme:R.enum([`light`,`dark`,`auto`]).optional(),lang:R.string().optional(),dir:R.enum([`ltr`,`rtl`,`auto`]).optional()};R.object({surfaceId:R.string(),actionId:R.string(),actionType:R.enum([`button`,`select`,`multi-select`,`form-submit`,`text-submit`,`confirm`,`custom`]),value:R.unknown().optional(),formData:R.record(R.string(),R.unknown()).optional(),selection:R.union([R.string(),R.array(R.string())]).optional(),label:R.string().optional(),timestamp:R.string(),sourceTransport:R.enum([`mcp-app`,`browser`,`export`])});function uh(e,t){let n=G(`present`),r=[`Render a ChannelSurface for the user.`,`Quick ref:`,`- Full schema: aikit://schemas/channel-surface`,`- Required: schemaVersion: 1, title`,`- Content: blocks[] for direct rendering, or template + data for registry-backed rendering`,`- Actions: actions[] of SurfaceAction; interactive surfaces use browser transport and return ChannelOutcome`,`- Optional fields: description, layout, response, metadata, colorScheme, lang, dir`,`- Transports: mcp-app, browser, export`,`- Use schema resource for block enums and action details.`].join(`
2975
2971
  `);hr(e,`present`,{title:n.title,description:r,inputSchema:lh,annotations:n.annotations,_meta:{ui:{resourceUri:Am}}},Y(`present`,async(e,t)=>{let n=nh(e,t);return n.ok?await rh(n.surface,n.options):n.response}));try{mr(e,`Present View`,Am,{description:`AI Kit present tool viewer`},async()=>({contents:[{uri:Am,mimeType:pr,text:Mm()||`<html><body><p>No content generated yet. Call the present tool first.</p></body></html>`}]}))}catch{}try{e.registerResource(`present-templates`,`aikit://present/templates`,{description:`List all registered present viewer templates with their input schemas`},async()=>{let e=Fp().map(e=>({id:e.id,label:e.label,description:e.description,transports:e.supportedTransports,inputSchema:e.inputSchema}));return{contents:[{uri:`aikit://present/templates`,mimeType:`application/json`,text:JSON.stringify(e,null,2)}]}})}catch{}}const dh=F(`tools`);function fh(e,t){let n=new er({structure:new nr,dependencies:new Zn,symbols:new rr,patterns:new tr,entryPoints:new $n,diagrams:new Qn}),r=G(`produce_knowledge`);e.registerTool(`produce_knowledge`,{title:r.title,description:`Run automated codebase analysis and produce synthesis instructions. Executes Tier 1 deterministic analyzers, then returns structured baselines and instructions for you to synthesize knowledge using remember.`,inputSchema:{scope:R.string().optional().describe(`Root path to analyze (defaults to workspace root)`),aspects:R.array(R.enum([`all`,`structure`,`dependencies`,`symbols`,`patterns`,`entry-points`,`diagrams`])).default([`all`]).describe(`Which analysis aspects to run`)},annotations:r.annotations},Y(`produce_knowledge`,async({scope:e,aspects:r},i)=>{let a;try{a=Oc(i).createTask(`Produce Knowledge`,3),a.progress(0,`Running analyzers`);let o=e??`.`;dh.info(`Running knowledge production`,{rootPath:o,aspects:r});let s=await n.runExtraction(o,r);try{let e=t?.onboardDir??``;if(!e)throw dh.warn(`onboardDir not configured — skipping artifact persistence.`),Error(`skip`);j(e,{recursive:!0});let n=`<!-- Generated by produce_knowledge at ${new Date().toISOString()} -->\n\n`;for(let[t,r]of Object.entries(s))r&&typeof r==`string`&&he(N(e,`${t}.md`),n+r,`utf-8`);dh.info(`Knowledge persisted to .ai/context/`,{files:Object.keys(s).length})}catch(e){dh.warn(`Failed to persist knowledge to .ai/context/`,{error:I(e)})}a.progress(1,`Synthesizing results`);let c=n.buildSynthesisInstructions(s,r);return a.complete(`Knowledge production complete`),{content:[{type:`text`,text:c+`
2976
2972
 
2977
2973
  ---
@@ -3016,7 +3012,7 @@ Use \`status({})\` to check smart indexing queue status.`}]};let l=Oc(c).createT
3016
3012
  Data matches the schema.`}]};let r=[`## Validation: FAILED`,``,`**${n.errors.length} error(s):**`,``];for(let e of n.errors){let t=e.expected?` (expected: ${e.expected}, got: ${e.received})`:``;r.push(`- \`${e.path}\`: ${e.message}${t}`)}return{content:[{type:`text`,text:r.join(`
3017
3013
  `)}]}}catch(e){return _g.error(`Schema validation failed`,I(e)),J(`INTERNAL`,`Schema validation failed: ${e instanceof Error?e.message:String(e)}`)}}))}function Tg(e){let t=G(`env`);e.registerTool(`env`,{title:t.title,description:`Get system and runtime environment info. Sensitive env vars are redacted by default.`,outputSchema:Ss,inputSchema:{include_env:R.boolean().default(!1).describe(`Include environment variables`),filter_env:R.string().optional().describe(`Filter env vars by name substring`),show_sensitive:R.boolean().default(!1).describe(`Show sensitive values (keys, tokens, etc.) — redacted by default`)},annotations:t.annotations},Y(`env`,async({include_env:e,filter_env:t,show_sensitive:n})=>{let r=ut({includeEnv:e,filterEnv:t,showSensitive:n}),i=[`## Environment`,``,`**Platform:** ${r.system.platform} ${r.system.arch}`,`**OS:** ${r.system.type} ${r.system.release}`,`**Host:** ${r.system.hostname}`,`**CPUs:** ${r.system.cpus}`,`**Memory:** ${r.system.memoryFreeGb}GB free / ${r.system.memoryTotalGb}GB total`,``,`**Node:** ${r.runtime.node}`,`**V8:** ${r.runtime.v8}`,`**CWD:** ${r.cwd}`];if(r.env){i.push(``,`### Environment Variables`,``);for(let[e,t]of Object.entries(r.env))i.push(`- \`${e}\`: ${t}`)}let a={platform:r.system.platform,arch:r.system.arch,nodeVersion:r.runtime.node,cwd:r.cwd,cpus:r.system.cpus,memoryFreeGb:r.system.memoryFreeGb,memoryTotalGb:r.system.memoryTotalGb};return{content:[{type:`text`,text:i.join(`
3018
3014
  `)}],structuredContent:a}}))}function Eg(e){let t=G(`time`);e.registerTool(`time`,{title:t.title,description:`Parse dates, convert timezones, calculate durations, add time. Supports ISO 8601, unix timestamps, and human-readable formats.`,outputSchema:Cs,inputSchema:{operation:R.enum([`now`,`parse`,`convert`,`diff`,`add`]).describe(`now: current time | parse: parse a date string | convert: timezone conversion | diff: duration between two dates | add: add duration to date`),input:R.string().optional().describe(`Date input (ISO, unix timestamp, or parseable string). For diff: two comma-separated dates`),timezone:R.string().optional().describe(`Target timezone (e.g., "America/New_York", "Asia/Tokyo")`),duration:R.string().optional().describe(`Duration to add (e.g., "2h30m", "1d", "30s") — for add operation`)},annotations:t.annotations},Y(`time`,async({operation:e,input:t,timezone:n,duration:r})=>{try{let i=wn({operation:e,input:t,timezone:n,duration:r}),a=[`**${i.output}**`,``,`ISO: ${i.iso}`,`Unix: ${i.unix}`];i.details&&a.push(``,"```json",JSON.stringify(i.details),"```");let o={iso:i.iso,unix:i.unix,timezone:n??Intl.DateTimeFormat().resolvedOptions().timeZone,formatted:i.output};return{content:[{type:`text`,text:a.join(`
3019
- `)}],structuredContent:o}}catch(e){return _g.error(`Time failed`,I(e)),J(`INTERNAL`,`Time failed: ${e instanceof Error?e.message:String(e)}`)}}))}function Dg(e){try{let t=N(e,`.flows`);if(!A(t))return null;let n=ue(t,{withFileTypes:!0});for(let e of n){if(!e.isDirectory())continue;let n=N(t,e.name,`meta.json`);if(A(n)&&JSON.parse(M(n,`utf-8`)).status===`active`)return e.name}}catch{return null}return null}function Og(e,t,n,r,i,a,o,s,c,l){let u=new co,d=n.sources[0]?.path??process.cwd(),f={activeSlug:null};f.activeSlug=Dg(d);let p=new Oa(N(n.stateDir??``,`flow-context`),()=>f.activeSlug),m=new ya;m.register(Ei()),m.register(ga),m.register(Ii),m.register(aa),m.register(Ni),m.register(Di),m.register(Oi),m.register(pa),m.register(Ai),m.register(va),m.register(ia(()=>f.activeSlug?{active:!0,slug:f.activeSlug}:null));let h=new wa(m,t.curated,{},p),g=l??ms(n,[...Bo,...Po],W,Io(n)),_=e=>g.has(e),v=new Set([...g].filter(e=>!Yf.includes(e)&&!Ja.has(e))),y=new Qa;u.use(Sa(h),{order:5,name:`auto-knowledge`}),u.use(Eo(),{order:10,name:`replay`}),u.use(to(y,{stateStore:t.stateStore,curatedStore:t.curated},{trackedTools:v}),{order:94,name:`procedural-memory`}),u.use(Wa(new Ha(t.stateStore,t.curated)),{order:95,name:`observation-capture`}),u.use(Ho(),{order:1,name:`structured-content-guard`}),u.use(Da(Ea(n.tokenBudget)),{order:90,name:`compression`}),$o(e,u,n.toolPrefix??``);let b=[...g].filter(e=>Fo.has(e)?No.includes(e)?!!t.bridge:e===`er_update_policy`?!!t.policyStore:e===`er_evolve_review`?!!t.evolutionCollector:!1:!0);_(`search`)&&Ph(e,t.embedder,t.store,t.graphStore,t.bridge,t.evolutionCollector,a,t.stateStore,n.memory?.retention,n.memory?.consolidation);let x={store:t.store,graphStore:t.graphStore,embedder:t.embedder},S=c?e=>{c()?.prioritize(e)}:void 0;_(`lookup`)&&Rf(e,t.store,x);let C={onboardComplete:t.onboardComplete,onboardTimestamp:t.onboardTimestamp};_(`status`)&&gg(e,t.store,t.graphStore,t.curated,C,n,o,s,t.stateStore),_(`config`)&&ol(e,n),_(`reindex`)&&mh(e,t.indexer,n,t.curated,t.store,i,o),_(`knowledge`)&&If(e,t.curated,t.policyStore,t.evolutionCollector,i,p,t.stateStore,n.memory?.retention,n.memory?.supersession,n.memory?.consolidation,n.memory?.lessons,x),_(`analyze`)&&wc(e,t.store,t.embedder,x),_(`blast_radius`)&&Tc(e,t.store,t.embedder,t.graphStore,x),_(`produce_knowledge`)&&fh(e,n),_(`onboard`)&&tp(e,t.store,t.embedder,n,C,x),_(`graph`)&&Uu(e,t.graphStore,x),_(`audit`)&&Ac(e,t.store,t.embedder,n.tokenBudget),_(`compact`)&&_l(e,t.embedder,t.fileCache,d,n.allRoots,x,S),_(`scope_map`)&&vl(e,t.embedder,t.store,x),_(`find`)&&yl(e,t.embedder,t.store,d,x),_(`parse_output`)&&Nl(e),_(`workset`)&&rp(e),_(`check`)&&Al(e,x,n.tokenBudget),_(`symbol`)&&bl(e,t.embedder,t.store,t.graphStore,x),_(`eval`)&&jl(e),_(`test_run`)&&Ml(e,x),_(`stash`)&&ip(e,t.stateStore),_(`signal`)&&$h(e,t.stateStore),_(`git_context`)&&Hf(e),_(`diff_parse`)&&Uf(e),_(`rename`)&&Wf(e,n),_(`codemod`)&&Gf(e,n),_(`restore`)&&vh(e),_(`file_summary`)&&xl(e,t.fileCache,d,n.allRoots,x,S),_(`checkpoint`)&&ap(e,t.stateStore),_(`data_transform`)&&Kf(e),_(`trace`)&&Sl(e,t.embedder,t.store,t.graphStore,x),_(`process`)&&Gu(e),_(`watch`)&&Ku(e),_(`dead_symbols`)&&Cl(e,t.embedder,t.store,d,n.allRoots,x),_(`delegate`)&&Pl(e,a),_(`health`)&&qu(e),_(`lane`)&&op(e),_(`queue`)&&sp(e),_(`web_fetch`)&&Ju(e),_(`guide`)&&Yu(e,o),Yf.some(e=>_(e))&&Xf(e,n,b),_(`evidence_map`)&&Fu(e),_(`digest`)&&Iu(e,t.embedder),_(`forge_classify`)&&Lu(e,x),_(`stratum_card`)&&Ru(e,t.embedder,t.fileCache),_(`forge_ground`)&&zu(e,t.embedder,t.store),_(`present`)&&uh(e,r),_(`browser`)&&Yn(e,n),_(`web_search`)&&vg(e),_(`http`)&&yg(e),_(`regex_test`)&&bg(e),_(`encode`)&&xg(e),_(`measure`)&&Sg(e),_(`changelog`)&&Cg(e),_(`schema_validate`)&&wg(e),_(`env`)&&Tg(e),_(`time`)&&Eg(e),_(`flow`)&&Nu(e,n,e=>{f.activeSlug=e}),t.bridge&&No.some(e=>_(e))&&(Pc(e,t.bridge,t.evolutionCollector),Fc(e,t.bridge),Ic(e,t.bridge)),t.policyStore&&_(`er_update_policy`)&&pp(e,t.policyStore),t.evolutionCollector&&_(`er_evolve_review`)&&Ol(e,t.evolutionCollector),Mo(e,t.store,t.curated),_(`compliance_score`)&&zc(e),_(`replay`)&&gh(e),_(`session_digest`)&&Ih(e,t.stateStore,a)}function kg(e,t,n){let r=e=>!n||n.has(e);r(`check`)&&Al(e,void 0,t.tokenBudget),r(`eval`)&&jl(e),r(`test_run`)&&Ml(e),r(`parse_output`)&&Nl(e),r(`delegate`)&&Pl(e),r(`git_context`)&&Hf(e),r(`diff_parse`)&&Uf(e),r(`rename`)&&Wf(e,t),r(`codemod`)&&Gf(e,t),r(`data_transform`)&&Kf(e),r(`workset`)&&rp(e),r(`restore`)&&vh(e),r(`lane`)&&op(e),r(`queue`)&&sp(e),r(`session_digest`)&&Ih(e),r(`health`)&&qu(e),r(`process`)&&Gu(e),r(`watch`)&&Ku(e),r(`web_fetch`)&&Ju(e),r(`guide`)&&Yu(e),Yf.some(e=>r(e))&&Xf(e,t,[...n??new Set(Bo)]),r(`evidence_map`)&&Fu(e),r(`forge_classify`)&&Lu(e),r(`present`)&&uh(e),r(`browser`)&&Yn(e,t),r(`produce_knowledge`)&&fh(e),r(`compliance_score`)&&zc(e),r(`replay`)&&gh(e),r(`status`)&&hg(e),r(`flow`)&&Nu(e,t),r(`web_search`)&&vg(e),r(`http`)&&yg(e),r(`regex_test`)&&bg(e),r(`encode`)&&xg(e),r(`measure`)&&Sg(e),r(`changelog`)&&Cg(e),r(`schema_validate`)&&wg(e),r(`env`)&&Tg(e),r(`time`)&&Eg(e)}const Ag=F(`resource-notifier`);var jg=class{mcpServer;constructor(e){this.mcpServer=e}async notifyStatusChanged(){await this.sendUpdate(`aikit://status`)}async notifyFileTreeChanged(){await this.sendUpdate(`aikit://file-tree`)}async notifyCuratedIndexChanged(){await this.sendUpdate(`aikit://curated`)}async notifyCuratedEntryChanged(e){await this.sendUpdate(`aikit://curated/${e}`)}async notifyResourceListChanged(){try{await this.mcpServer.server.sendResourceListChanged()}catch(e){Ag.debug(`sendResourceListChanged failed`,{error:String(e)})}}async notifyAfterReindex(){await Promise.allSettled([this.notifyStatusChanged(),this.notifyFileTreeChanged()])}async notifyAfterCuratedWrite(e){let t=[this.notifyStatusChanged(),this.notifyCuratedIndexChanged()];e&&t.push(this.notifyCuratedEntryChanged(e)),await Promise.allSettled(t)}async sendUpdate(e){try{await this.mcpServer.server.sendResourceUpdated({uri:e})}catch(t){Ag.debug(`sendResourceUpdated failed`,{uri:e,error:String(t)})}}};const Q=F(`server`);function Mg(e){let t=e?.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`||t===`on`}async function Ng(n){Q.info(`Initializing AI Kit components`);let r=n.store.backend,i=n.store.path,a=Mg(process.env.AIKIT_SPLIT_STATE),o=N(i,`aikit.db`),s={splitEnabled:a,contentDbPath:o,controlDbPath:a?N(i,`aikit-control.db`):o},c=null;if(r===`sqlite-vec`){let e=s.contentDbPath;A(i)||j(i,{recursive:!0}),c=await vr(e),Q.info(`SQLite adapter ready`,{type:c.type,vectorCapable:c.vectorCapable,dbPath:e}),c.vectorCapable||Q.warn(`┌──────────────────────────────────────────────────────────────────┐
3015
+ `)}],structuredContent:o}}catch(e){return _g.error(`Time failed`,I(e)),J(`INTERNAL`,`Time failed: ${e instanceof Error?e.message:String(e)}`)}}))}function Dg(e){try{let t=N(e,`.flows`);if(!A(t))return null;let n=ue(t,{withFileTypes:!0});for(let e of n){if(!e.isDirectory())continue;let n=N(t,e.name,`meta.json`);if(A(n)&&JSON.parse(M(n,`utf-8`)).status===`active`)return e.name}}catch{return null}return null}function Og(e,t,n,r,i,a,o,s,c,l){let u=new co,d=n.sources[0]?.path??process.cwd(),f={activeSlug:null};f.activeSlug=Dg(d);let p=new Oa(N(n.stateDir??``,`flow-context`),()=>f.activeSlug),m=new ya;m.register(Ei()),m.register(ga),m.register(Ii),m.register(aa),m.register(Ni),m.register(Di),m.register(Oi),m.register(pa),m.register(Ai),m.register(va),m.register(ia(()=>f.activeSlug?{active:!0,slug:f.activeSlug}:null));let h=new wa(m,t.curated,{},p),g=l??ms(n,[...Bo,...Po],W,Io(n)),_=e=>g.has(e),v=new Set([...g].filter(e=>!Yf.includes(e)&&!Ja.has(e))),y=new Qa;u.use(Sa(h),{order:5,name:`auto-knowledge`}),u.use(Eo(),{order:10,name:`replay`}),u.use(to(y,{stateStore:t.stateStore,curatedStore:t.curated},{trackedTools:v}),{order:94,name:`procedural-memory`}),u.use(Wa(new Ha(t.stateStore,t.curated)),{order:95,name:`observation-capture`}),u.use(Ho(),{order:1,name:`structured-content-guard`}),u.use(Da(Ea(n.tokenBudget)),{order:90,name:`compression`}),$o(e,u,n.toolPrefix??``);let b=[...g].filter(e=>Fo.has(e)?No.includes(e)?!!t.bridge:e===`er_update_policy`?!!t.policyStore:e===`er_evolve_review`?!!t.evolutionCollector:!1:!0);_(`search`)&&Ph(e,t.embedder,t.store,t.graphStore,t.bridge,t.evolutionCollector,a,t.stateStore,n.memory?.retention,n.memory?.consolidation);let x={store:t.store,graphStore:t.graphStore,embedder:t.embedder},S=c?e=>{c()?.prioritize(e)}:void 0;_(`lookup`)&&Rf(e,t.store,x);let C={onboardComplete:t.onboardComplete,onboardTimestamp:t.onboardTimestamp};_(`status`)&&gg(e,t.store,t.graphStore,t.curated,C,n,o,s,t.stateStore),_(`config`)&&ol(e,n),_(`reindex`)&&mh(e,t.indexer,n,t.curated,t.store,i,o),_(`knowledge`)&&If(e,t.curated,t.policyStore,t.evolutionCollector,i,p,t.stateStore,n.memory?.retention,n.memory?.supersession,n.memory?.consolidation,n.memory?.lessons,x),_(`analyze`)&&wc(e,t.store,t.embedder,x),_(`blast_radius`)&&Tc(e,t.store,t.embedder,t.graphStore,x),_(`produce_knowledge`)&&fh(e,n),_(`onboard`)&&tp(e,t.store,t.embedder,n,C,x),_(`graph`)&&Uu(e,t.graphStore,x),_(`audit`)&&Ac(e,t.store,t.embedder,n.tokenBudget),_(`compact`)&&_l(e,t.embedder,t.fileCache,d,n.allRoots,x,S),_(`scope_map`)&&vl(e,t.embedder,t.store,x),_(`find`)&&yl(e,t.embedder,t.store,d,x),_(`parse_output`)&&Nl(e),_(`workset`)&&rp(e),_(`check`)&&Al(e,x,n.tokenBudget),_(`symbol`)&&bl(e,t.embedder,t.store,t.graphStore,x),_(`eval`)&&jl(e),_(`test_run`)&&Ml(e,x),_(`stash`)&&ip(e,t.stateStore),_(`signal`)&&$h(e,t.stateStore),_(`git_context`)&&Hf(e),_(`diff_parse`)&&Uf(e),_(`rename`)&&Wf(e,n),_(`codemod`)&&Gf(e,n),_(`restore`)&&vh(e),_(`file_summary`)&&xl(e,t.fileCache,d,n.allRoots,x,S),_(`checkpoint`)&&ap(e,t.stateStore),_(`data_transform`)&&Kf(e),_(`trace`)&&Sl(e,t.embedder,t.store,t.graphStore,x),_(`process`)&&Gu(e),_(`watch`)&&Ku(e),_(`dead_symbols`)&&Cl(e,t.embedder,t.store,d,n.allRoots,x),_(`delegate`)&&Pl(e,a),_(`health`)&&qu(e),_(`lane`)&&op(e),_(`queue`)&&sp(e),_(`web_fetch`)&&Ju(e),_(`guide`)&&Yu(e,o),Yf.some(e=>_(e))&&Xf(e,n,b),_(`evidence_map`)&&Fu(e),_(`digest`)&&Iu(e,t.embedder),_(`forge_classify`)&&Lu(e,x),_(`stratum_card`)&&Ru(e,t.embedder,t.fileCache),_(`forge_ground`)&&zu(e,t.embedder,t.store),_(`present`)&&uh(e,r),_(`browser`)&&Yn(e,n),_(`web_search`)&&vg(e),_(`http`)&&yg(e),_(`regex_test`)&&bg(e),_(`encode`)&&xg(e),_(`measure`)&&Sg(e),_(`changelog`)&&Cg(e),_(`schema_validate`)&&wg(e),_(`env`)&&Tg(e),_(`time`)&&Eg(e),_(`flow`)&&Nu(e,n,{store:t.store?{search:async(e,n)=>(await t.store.ftsSearch(e,n)).map(e=>({content:e.record.content}))}:null,graphStore:t.graphStore,embedder:t.embedder},e=>{f.activeSlug=e}),t.bridge&&No.some(e=>_(e))&&(Pc(e,t.bridge,t.evolutionCollector),Fc(e,t.bridge),Ic(e,t.bridge)),t.policyStore&&_(`er_update_policy`)&&pp(e,t.policyStore),t.evolutionCollector&&_(`er_evolve_review`)&&Ol(e,t.evolutionCollector),Mo(e,t.store,t.curated),_(`compliance_score`)&&zc(e),_(`replay`)&&gh(e),_(`session_digest`)&&Ih(e,t.stateStore,a)}function kg(e,t,n){let r=e=>!n||n.has(e);r(`check`)&&Al(e,void 0,t.tokenBudget),r(`eval`)&&jl(e),r(`test_run`)&&Ml(e),r(`parse_output`)&&Nl(e),r(`delegate`)&&Pl(e),r(`git_context`)&&Hf(e),r(`diff_parse`)&&Uf(e),r(`rename`)&&Wf(e,t),r(`codemod`)&&Gf(e,t),r(`data_transform`)&&Kf(e),r(`workset`)&&rp(e),r(`restore`)&&vh(e),r(`lane`)&&op(e),r(`queue`)&&sp(e),r(`session_digest`)&&Ih(e),r(`health`)&&qu(e),r(`process`)&&Gu(e),r(`watch`)&&Ku(e),r(`web_fetch`)&&Ju(e),r(`guide`)&&Yu(e),Yf.some(e=>r(e))&&Xf(e,t,[...n??new Set(Bo)]),r(`evidence_map`)&&Fu(e),r(`forge_classify`)&&Lu(e),r(`present`)&&uh(e),r(`browser`)&&Yn(e,t),r(`produce_knowledge`)&&fh(e),r(`compliance_score`)&&zc(e),r(`replay`)&&gh(e),r(`status`)&&hg(e),r(`flow`)&&Nu(e,t),r(`web_search`)&&vg(e),r(`http`)&&yg(e),r(`regex_test`)&&bg(e),r(`encode`)&&xg(e),r(`measure`)&&Sg(e),r(`changelog`)&&Cg(e),r(`schema_validate`)&&wg(e),r(`env`)&&Tg(e),r(`time`)&&Eg(e)}const Ag=F(`resource-notifier`);var jg=class{mcpServer;constructor(e){this.mcpServer=e}async notifyStatusChanged(){await this.sendUpdate(`aikit://status`)}async notifyFileTreeChanged(){await this.sendUpdate(`aikit://file-tree`)}async notifyCuratedIndexChanged(){await this.sendUpdate(`aikit://curated`)}async notifyCuratedEntryChanged(e){await this.sendUpdate(`aikit://curated/${e}`)}async notifyResourceListChanged(){try{await this.mcpServer.server.sendResourceListChanged()}catch(e){Ag.debug(`sendResourceListChanged failed`,{error:String(e)})}}async notifyAfterReindex(){await Promise.allSettled([this.notifyStatusChanged(),this.notifyFileTreeChanged()])}async notifyAfterCuratedWrite(e){let t=[this.notifyStatusChanged(),this.notifyCuratedIndexChanged()];e&&t.push(this.notifyCuratedEntryChanged(e)),await Promise.allSettled(t)}async sendUpdate(e){try{await this.mcpServer.server.sendResourceUpdated({uri:e})}catch(t){Ag.debug(`sendResourceUpdated failed`,{uri:e,error:String(t)})}}};const Q=F(`server`);function Mg(e){let t=e?.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`||t===`on`}async function Ng(n){Q.info(`Initializing AI Kit components`);let r=n.store.backend,i=n.store.path,a=Mg(process.env.AIKIT_SPLIT_STATE),o=N(i,`aikit.db`),s={splitEnabled:a,contentDbPath:o,controlDbPath:a?N(i,`aikit-control.db`):o},c=null;if(r===`sqlite-vec`){let e=s.contentDbPath;A(i)||j(i,{recursive:!0}),c=await vr(e),Q.info(`SQLite adapter ready`,{type:c.type,vectorCapable:c.vectorCapable,dbPath:e}),c.vectorCapable||Q.warn(`┌──────────────────────────────────────────────────────────────────┐
3020
3016
  │ ⚠ SQLite vector extension unavailable — DEGRADED MODE │
3021
3017
  │ Vector search is disabled. Hybrid search returns FTS only. │
3022
3018
  │ To enable: install/rebuild better-sqlite3 (native module). │
@@ -160,10 +160,10 @@ _Metrics have been reset._`)),{content:[{type:`text`,text:i.join(`
160
160
  `).replace(/\\t/g,` `),t);return{content:[{type:`text`,text:JSON.stringify(n)}]}}catch(e){return kl.error(`Parse failed`,I(e)),J(`INTERNAL`,`Parse failed: ${e instanceof Error?e.message:String(e)}`)}})}function Pl(e,t){let n=G(`delegate`);e.registerTool(`delegate`,{title:n.title,description:`Delegate a subtask to a local Ollama model. Use for summarization, classification, naming, or any task that can offload work from the host agent. Fails fast if Ollama is not running.`,inputSchema:{prompt:R.string().max(2e5).describe(`The task or question to send to the local model`),model:R.string().optional().describe(`Ollama model name (default: first available model)`),system:R.string().optional().describe(`System prompt for the model`),context:R.string().max(5e5).optional().describe(`Context text to include before the prompt (e.g. file contents)`),temperature:R.number().min(0).max(2).default(.3).optional().describe(`Sampling temperature (0=deterministic, default 0.3)`),timeout:R.number().min(1e3).max(6e5).default(12e4).optional().describe(`Timeout in milliseconds (default 120000)`),action:R.enum([`generate`,`list_models`]).default(`generate`).optional().describe(`Action: generate a response or list available models`)},annotations:n.annotations},async({prompt:e,model:n,system:r,context:i,temperature:a,timeout:o,action:s})=>{try{if(s===`list_models`){let e=await it();return{content:[{type:`text`,text:JSON.stringify({models:e,count:e.length,_Next:`Use delegate with a model name`},null,2)}]}}if(t?.available)try{let n=await t.createMessage({prompt:e,systemPrompt:r,context:i,maxTokens:4e3,modelPreferences:{intelligencePriority:.8,speedPriority:.5,costPriority:.3}});return{content:[{type:`text`,text:JSON.stringify({model:n.model??`sampling`,response:n.text,provider:`mcp-sampling`,_Next:`Use the response in your workflow. stash to save it.`},null,2)}]}}catch{kl.debug(`Sampling failed, falling back to Ollama`)}let c=await rt({prompt:e,model:n,system:r,context:i,temperature:a,timeout:o});return c.error?J(`INTERNAL`,JSON.stringify({error:c.error,model:c.model,durationMs:c.durationMs},null,2)):{content:[{type:`text`,text:JSON.stringify({model:c.model,response:c.response,durationMs:c.durationMs,tokenCount:c.tokenCount,_Next:`Use the response in your workflow. stash to save it.`},null,2)}]}}catch(e){return kl.error(`Delegate failed`,I(e)),J(`INTERNAL`,`Delegate failed: ${e instanceof Error?e.message:String(e)}`)}})}function Fl(e){let t=[`Vitest run: ${e.passed?`passed`:`failed`}`,`Duration: ${e.durationMs}ms`,`Passed: ${e.summary.passed}`,`Failed: ${e.summary.failed}`,`Skipped: ${e.summary.skipped}`];e.summary.suites!==void 0&&t.push(`Suites: ${e.summary.suites}`);let n=e.summary.tests.filter(e=>e.status===`fail`);if(n.length>0){t.push(``,`Failed tests:`);for(let e of n)t.push(`- ${e.name}${e.file?` (${e.file})`:``}`),e.error&&t.push(` ${e.error}`)}return t.join(`
161
161
  `)}const Il=F(`sampling`);function Ll(e){if(!e.modelPreferences)return;let t={...e.modelPreferences.costPriority===void 0?{}:{costPriority:e.modelPreferences.costPriority},...e.modelPreferences.speedPriority===void 0?{}:{speedPriority:e.modelPreferences.speedPriority},...e.modelPreferences.intelligencePriority===void 0?{}:{intelligencePriority:e.modelPreferences.intelligencePriority}};return Object.keys(t).length>0?t:void 0}function Rl(e){if(Array.isArray(e))return e.map(e=>Rl(e)).filter(e=>e.length>0).join(`
162
162
  `);if(e&&typeof e==`object`&&`type`in e){let t=e;if(t.type===`text`&&typeof t.text==`string`)return t.text}return JSON.stringify(e)}function zl(e){let t=e.server,n=typeof t?.createMessage==`function`;return{get available(){return n},async createMessage(e){if(!n)throw Error(`Sampling not available: client does not support createMessage`);let r=e.context?`${e.context}\n\n---\n\n${e.prompt}`:e.prompt;try{let n=await t.createMessage({messages:[{role:`user`,content:{type:`text`,text:r}}],systemPrompt:e.systemPrompt,modelPreferences:Ll(e),maxTokens:e.maxTokens??4e3});return{text:Rl(n.content),model:n.model,stopReason:n.stopReason}}catch(e){throw Il.warn(`Sampling createMessage failed`,{error:String(e)}),e}}}}const Bl=[],Vl=[`_docs-sync`],Hl=new Map([[`_docs-sync`,`Synchronize project documentation — update docs/ folder based on changes made during the flow.`]]);function Ul(e){function t(t,n,r){let i=n?.installPath?ge(n.installPath):t.replaceAll(`:`,`-`),a=P(Rn(),`.copilot`,`flows`,i).replaceAll(`\\`,`/`);if(A(a))return a;let o=P(Rn(),`.claude`,`flows`,i).replaceAll(`\\`,`/`);if(A(o))return o;let s=P(r??e(),`.github`,`flows`,i).replaceAll(`\\`,`/`);return A(s)?s:n?.installPath&&A(n.installPath)?n.installPath.replaceAll(`\\`,`/`):null}function n(e,n,r){let i=t(e.name,e,r);return i?P(i,n).replaceAll(`\\`,`/`):n}function r(t,n){let r=t.replace(/^_/,``),i=n??e(),a=[N(i,`.github`,`flows`,`_epilogue`,`steps`,r,`README.md`),N(i,`.github`,`flows`,`_epilogue`,r,`README.md`)];for(let e of a)if(A(e))return e.replaceAll(`\\`,`/`);return null}function i(e){return[...Bl,...e.manifest.steps.map(e=>e.id),...Vl]}function a(e,t,r){let i=t?e.manifest.steps.find(e=>e.id===t)??null:null,a=t?Hl.get(t)??null:null;return{currentStep:i,epilogueStep:a?{id:t,description:a}:null,instructionPath:i&&t?n(e,i.instruction,r):null,description:i?.description??a}}function o(){try{let e=N(xr(`npm root -g`,{encoding:`utf-8`}).trim(),`@fission-ai`,`openspec`);if(A(e))return{path:e,sourceType:`npm-global`,isGit:!1}}catch{}return{path:`https://github.com/Fission-AI/OpenSpec.git`,sourceType:`git`,isGit:!0}}function s(e){let t=P(e);if(A(N(t,`.claude-plugin`,`plugin.json`)))return{path:t,sourceType:`claude-plugin`};let n=Rn(),r=N(n,`.claude`,`plugins`,e);if(A(N(r,`.claude-plugin`,`plugin.json`)))return{path:r,sourceType:`claude-plugin`};let i=N(n,`.claude`,`plugins`);if(!A(i))return null;for(let t of ue(i,{withFileTypes:!0})){if(!t.isDirectory())continue;let n=N(i,t.name,`.claude-plugin`,`plugin.json`);if(A(n))try{if(JSON.parse(M(n,`utf-8`)).name===e)return{path:N(i,t.name),sourceType:`claude-plugin`}}catch{}}return null}return{resolveInstallPath:t,resolveInstructionPath:n,resolveEpilogueInstructionPath:r,getStepSequence:i,resolveCurrentStepInfo:a,resolveOpenSpecSource:o,resolveClaudePluginSource:s}}function Wl(e){function t(){return e.sources?.[0]?.path??process.cwd()}function n(){return e.allRoots?.length?e.allRoots:[t()]}function r(e){return e.map(e=>e.replaceAll(`\\`,`/`))}function i(e){let t=[];try{let n=ue(e,{withFileTypes:!0});for(let r of n){if(!r.isDirectory()||r.name.startsWith(`.`))continue;let n=N(e,r.name);A(N(n,`.git`))&&t.push(n)}}catch{}return t}function a(){let e=n(),t=new Set(e);for(let n of e)for(let e of i(n))t.add(e);return[...t]}function o(e){let t=e.replaceAll(`\\`,`/`);if(r(a()).includes(t))return!0;let i=r(n());for(let n of i)if(t.startsWith(`${n}/`)&&A(N(e,`.git`)))return!0;return!1}function s(e){return N(e??t(),`.flows`)}async function c(){let e=a();for(let t of e){let e=s(t);if(A(e))for(let n of ue(e,{withFileTypes:!0})){if(!n.isDirectory())continue;let r=N(e,n.name,`meta.json`);if(A(r))try{let e=JSON.parse(M(r,`utf-8`));if(e.status===`active`)return e.primaryRoot?e.primaryRoot:t}catch{}}}return null}async function l(e){return e||(await c()??t())}function u(){let e=t(),i=r(n()),o=a(),s=r(o),c=s.filter(e=>!i.includes(e));return{workspaceRoot:e,allRoots:o,normalizedAllRoots:s,discoveredRepos:c.length>0?c:void 0}}function d(e,t,n){let r=N(s(t),e,`meta.json`),i=M(r,`utf-8`),a=JSON.parse(i);a.roots=n.map(e=>e.replaceAll(`\\`,`/`)),a.primaryRoot=t.replaceAll(`\\`,`/`);let o=`${r}.tmp`;he(o,JSON.stringify(a,null,2),`utf-8`),de(o,r)}function f(e,t){let n=N(s(t),e,`meta.json`);if(!A(n))return;let r=M(n,`utf-8`),i=JSON.parse(r),a=i.roots;if(!a||a.length<=1)return;let o=t.replaceAll(`\\`,`/`);for(let t of a){if(t===o)continue;let n=N(t,`.flows`,e);j(n,{recursive:!0});let a=N(n,`meta.json`),s=`${a}.tmp`;he(s,r,`utf-8`),de(s,a),j(N(n,i.artifactsDir??`.spec`),{recursive:!0})}}return{getWorkspaceRoot:t,getAllRoots:a,getFlowsDir:s,isValidFlowRoot:o,resolveFlowRoot:l,resolveRoots:u,patchMetaRoots:d,syncMetaToRoots:f}}const Gl={name:`flow-context`,order:40,maxTokens:120,runInBrief:!1,async execute(e){let t=["**Flow Context:** Call `knowledge({ action: 'withdraw', scope: 'flow', profile: 'implementer', budget: 4000 })` as FIRST action for prior context.","Remember decisions: `knowledge({ action: 'remember', title: '...', content: '...', category: 'flow-context', scope: 'flow' })`"];e.completedSteps.length>0&&t.push(`Completed steps: ${e.completedSteps.join(`, `)}`);let n=t.join(`
163
- `);return{content:n,tokens:Math.ceil(n.length/4)}}};function Kl(e){return{name:`knowledge-recall`,order:20,maxTokens:200,runInBrief:!1,async execute(t){if(!e.store)return null;let n=[t.stepDescription,t.topic].filter(Boolean).join(` `);if(!n.trim())return null;try{let t=await e.store.search(n,{limit:3});if(!t||t.length===0)return null;let r=t.map(e=>`• ${e.content.slice(0,200)}`).join(`
164
- `),i=Math.ceil(r.length/4);return{content:`**Recalled Knowledge:**\n${r}`,tokens:Math.min(i,200)}}catch{return null}}}}const ql=[`**Read Code:** Structure → file_summary(). Specific section → compact(path, query).`,`Multiple files → digest(). Repeated ref → stratum_card(). Edit lines → read_file().`,`NEVER read_file >50 lines to understand. Use search() for discovery.`].join(` `),Jl={name:`token-efficiency`,order:30,maxTokens:80,runInBrief:!1,async execute(e){return{content:ql,tokens:25}}},Yl=[`**Tool Routing:** search() not grep_search. file_summary() or compact() not read_file (for understanding).`,`check() not terminal tsc/lint. test_run() not terminal test. trace() for data flow.`,`read_file ONLY for exact lines before editing. symbol() for definition+refs.`].join(` `),Xl={name:`tool-routing`,order:10,maxTokens:100,runInBrief:!0,async execute(e){return{content:Yl,tokens:30}}};function Zl(e,t){return Promise.race([e,new Promise(e=>setTimeout(()=>e(null),t))])}var Ql=class{hooks=[];sealed=!1;log;constructor(e){this.log=e?.log}seal(){this.sealed=!0}register(e){if(this.sealed){this.log?.warn(`Attempted to register hook "%s" on sealed pipeline`,e.name);return}this.hooks.push(e),this.hooks.sort((e,t)=>e.order-t.order)}get hookCount(){return this.hooks.length}async enrich(e,t,n){let r=this.resolveBudget(t.mode,n),i=new Set(n?.disable??[]),a=this.hooks.filter(e=>!(i.has(e.name)||t.mode===`brief`&&!e.runInBrief));if(a.length===0)return e;let o=[],s=0;for(let e of a){if(s>=r){this.log?.debug(`[step-hooks] Budget exhausted (${s}/${r}), skipping remaining hooks`);break}try{let n=await Zl(e.execute(t),5e3);if(!n||n.content.length===0)continue;let i=n.content.replace(/<\/(step-context|step-hints)>/gi,``);if(i.length===0)continue;let a=this.truncateToTokens(i,e.maxTokens),c=Math.min(n.tokens,e.maxTokens);if(s+c<=r){o.push({content:a,tokens:c}),s+=c;continue}let l=r-s;if(l<=0)break;o.push({content:this.truncateToTokens(a,l),tokens:l}),s=r}catch(t){this.log?.warn(`[step-hooks] Hook "${e.name}" failed: ${t instanceof Error?t.message:String(t)}`)}}if(o.length===0)return e;let c=t.mode===`full`?`<step-context>`:`<step-hints>`,l=t.mode===`full`?`</step-context>`:`</step-hints>`;return`${e}\n\n${c}\n${o.map(e=>e.content).join(`
163
+ `);return{content:n,tokens:Math.ceil(n.length/4)}}};function Kl(e){return{name:`knowledge-recall`,order:20,maxTokens:200,runInBrief:!1,async execute(t){if(!e.store)return null;let n=[t.stepDescription,t.topic].filter(e=>typeof e==`string`&&e.trim().length>0);if(n.length===0)return null;let r=[...n,t.flowName].filter(Boolean).join(` `);if(!r.trim())return null;try{let t=await e.store.search(r,{limit:3});if(!t||t.length===0)return null;let n=t.map(e=>`• ${e.content.slice(0,200)}`).join(`
164
+ `),i=Math.ceil(n.length/4);return{content:`**Recalled Knowledge:**\n${n}`,tokens:Math.min(i,200)}}catch{return null}}}}const ql=[`**Read Code:** Structure → file_summary(). Specific section → compact(path, query).`,`Multiple files → digest(). Repeated ref → stratum_card(). Edit lines → read_file().`,`NEVER read_file >50 lines to understand. Use search() for discovery.`].join(` `),Jl={name:`token-efficiency`,order:30,maxTokens:80,runInBrief:!1,runOnce:!0,async execute(e){return{content:ql,tokens:25}}},Yl=[`**Tool Routing:** search() not grep_search. file_summary() or compact() not read_file (for understanding).`,`check() not terminal tsc/lint. test_run() not terminal test. trace() for data flow.`,`read_file ONLY for exact lines before editing. symbol() for definition+refs.`].join(` `),Xl={name:`tool-routing`,order:10,maxTokens:100,runInBrief:!0,runOnce:!0,async execute(e){return{content:Yl,tokens:30}}};function Zl(e,t){return Promise.race([e,new Promise(e=>setTimeout(()=>e(null),t))])}var Ql=class{hooks=[];firedOnce=new Set;sealed=!1;log;constructor(e){this.log=e?.log}seal(){this.sealed=!0}register(e){if(this.sealed){this.log?.warn(`Attempted to register hook "%s" on sealed pipeline`,e.name);return}this.hooks.push(e),this.hooks.sort((e,t)=>e.order-t.order)}get hookCount(){return this.hooks.length}async enrich(e,t,n){let r=this.resolveBudget(t.mode,n),i=new Set(n?.disable??[]),a=this.hooks.filter(e=>!(i.has(e.name)||t.mode===`brief`&&!e.runInBrief||e.runOnce&&this.firedOnce.has(e.name)));if(a.length===0)return e;let o=[],s=0;for(let e of a){if(s>=r){this.log?.debug(`[step-hooks] Budget exhausted (${s}/${r}), skipping remaining hooks`);break}try{let n=await Zl(e.execute(t),5e3);if(!n||n.content.length===0)continue;e.runOnce&&this.firedOnce.add(e.name);let i=n.content.replace(/<\/(step-context|step-hints)>/gi,``);if(i.length===0)continue;let a=this.truncateToTokens(i,e.maxTokens),c=Math.min(n.tokens,e.maxTokens);if(s+c<=r){o.push({content:a,tokens:c}),s+=c;continue}let l=r-s;if(l<=0)break;o.push({content:this.truncateToTokens(a,l),tokens:l}),s=r}catch(t){this.log?.warn(`[step-hooks] Hook "${e.name}" failed: ${t instanceof Error?t.message:String(t)}`)}}if(o.length===0)return e;let c=t.mode===`full`?`<step-context>`:`<step-hints>`,l=t.mode===`full`?`</step-context>`:`</step-hints>`;return`${e}\n\n${c}\n${o.map(e=>e.content).join(`
165
165
 
166
- `)}\n${l}`}resolveBudget(e,t){return e===`full`?t?.tokenBudget?.full??500:t?.tokenBudget?.brief??150}truncateToTokens(e,t){let n=t*4;return e.length<=n?e:`${e.slice(0,n).trimEnd()}…`}};function $l(e={}){let t=new Ql({log:e.log});return t.register(Xl),t.register(Kl({store:e.store,graphStore:e.graphStore,embedder:e.embedder})),t.register(Jl),t.register(Gl),t.seal(),t}const eu=F(`flow-tools`);function tu(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`&&e.trim().length>0):[]}function nu(e){return{content:[{type:`text`,text:e}]}}function ru(e){return e instanceof Error?e.message:String(e)}const iu={before:[],after:[{id:`_docs-sync`,description:`Synchronize project documentation — update docs/ folder based on changes made during the flow.`,position:`after`,skills:[`docs`]}]};function au(e,t){let n=Wl(t),r=Ul(n.getWorkspaceRoot),i=$l({log:eu});function a(){return N(Me(),`flows`,`registry.json`)}function o(){let t=zl(e);return async({content:e,sourceFormat:n,stepName:r,metadata:i})=>{let a=r.charAt(0).toUpperCase()+r.slice(1),o=i?JSON.stringify(i,null,2):void 0,s=`You are converting a flow step definition from "${n}" format to aikit native flow step README.md format.
166
+ `)}\n${l}`}resolveBudget(e,t){return e===`full`?t?.tokenBudget?.full??500:t?.tokenBudget?.brief??150}truncateToTokens(e,t){let n=t*4;return e.length<=n?e:`${e.slice(0,n).trimEnd()}…`}};function $l(e={}){let t=new Ql({log:e.log});return t.register(Xl),t.register(Kl({store:e.store,graphStore:e.graphStore,embedder:e.embedder})),t.register(Jl),t.register(Gl),t.seal(),t}const eu=F(`flow-tools`);function tu(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`&&e.trim().length>0):[]}function nu(e){return{content:[{type:`text`,text:e}]}}function ru(e){return e instanceof Error?e.message:String(e)}const iu={before:[],after:[{id:`_docs-sync`,description:`Synchronize project documentation — update docs/ folder based on changes made during the flow.`,position:`after`,skills:[`docs`]}]};function au(e,t,n){let r=Wl(t),i=Ul(r.getWorkspaceRoot),a=$l({store:n?.store,graphStore:n?.graphStore,embedder:n?.embedder,log:eu});function o(){return N(Me(),`flows`,`registry.json`)}function s(){let t=zl(e);return async({content:e,sourceFormat:n,stepName:r,metadata:i})=>{let a=r.charAt(0).toUpperCase()+r.slice(1),o=i?JSON.stringify(i,null,2):void 0,s=`You are converting a flow step definition from "${n}" format to aikit native flow step README.md format.
167
167
 
168
168
  Convert the provided content into a well-structured README.md for a flow step named "${r}".
169
169
 
@@ -178,12 +178,12 @@ The output must:
178
178
 
179
179
  Output ONLY the README.md content, nothing else.`;if(t.available)try{let i=(await t.createMessage({prompt:e,systemPrompt:s,context:o?`Step name: ${r}\nSource format: ${n}\nMetadata:\n${o}`:`Step name: ${r}\nSource format: ${n}`,maxTokens:4096,modelPreferences:{intelligencePriority:.8,speedPriority:.4,costPriority:.2}})).text.trim();if(i.length>0)return i}catch(e){eu.debug(`Flow transform sampling failed; using fallback formatting`,{error:ru(e),sourceFormat:n,stepName:r})}let c=typeof i?.description==`string`&&i.description.trim().length>0?i.description.trim():null,l=tu(i?.produces),u=tu(i?.requires);return[`# ${a}`,``,`## Purpose`,``,c??`${a} step.`,``,`## Instructions`,``,e.trim(),``,`## Artifacts`,``,...l.length>0?l.map(e=>`- ${e}`):[`- ${r}.md`],...u.length>0?[``,`## Prerequisites`,``,...u.map(e=>`- ${e}`)]:[],``].join(`
180
180
  `).trimEnd().concat(`
181
- `)}}async function s(e){let{FlowRegistryManager:r,FlowStateMachine:i,FlowLoader:o,GitInstaller:s}=await import(`../../flows/dist/index.js`),c=N(t.stateDir??``,`flows`,`installed`);return{registry:new r(a()),stateMachine:new i(n.getFlowsDir(e),iu),loader:new o,installer:new s(c)}}return{server:e,config:t,log:eu,toTextResponse:nu,toErrorText:ru,createFlowTransform:o,getFlows:s,stepPipeline:i,stateDir:t.stateDir??``,...n,...r}}var ou=class extends Error{code;constructor(e,t){super(t),this.code=e,this.name=`FlowError`}};function su(e){return e instanceof ou}async function cu(e){let{entry:t,stepId:n,runDir:r,slug:i,primaryRoot:a,roots:o,activeRoot:s,resolveInstructionPath:c,resolveEpilogueInstructionPath:l}=e;if(!n)return null;try{let e=t.manifest.steps.find(e=>e.id===n||e.name===n),u;if(e)u=await Mn(c(t,e.instruction,s),`utf-8`);else{let e=l(n,s);if(!e)return null;u=await Mn(e,`utf-8`)}let d=N(r,t.manifest.artifacts_dir).replaceAll(`\\`,`/`),f=r.replaceAll(`\\`,`/`);u=u.replaceAll(`{{artifacts_path}}`,d).replaceAll(`{{run_dir}}`,f).replaceAll(`{{workspace_root}}`,(a??s).replaceAll(`\\`,`/`)).replaceAll(`{{all_roots}}`,JSON.stringify(o??[s.replaceAll(`\\`,`/`)],null,2));for(let e of[`spec-driven`])u=u.replaceAll(`${e}/${i}/`,`${d}/`);return u}catch{return null}}async function lu(e,t){let{getFlows:n,log:r,resolveEpilogueInstructionPath:i,resolveFlowRoot:a,resolveInstructionPath:o,stepPipeline:s,toErrorText:c,toTextResponse:l}=t,{step:u}=e;try{let e=await a(),{registry:t,stateMachine:r}=await n(e),c=r.getStatus();if(!c.success||!c.data)throw new ou(`NO_ACTIVE_FLOW`,`No active flow. Use flow({ action: "start", name: "<flow>" }) to begin one, or flow({ action: "list" }) to see available flows.`);let d=c.data,f=t.get(d.flow);if(!f)throw new ou(`FLOW_NOT_FOUND`,`Flow "${d.flow}" not found in registry.`);let p=u??d.currentStep;if(!p)throw new ou(`STEP_OUT_OF_RANGE`,`No current step is available for the active flow.`);let m=await cu({entry:f,stepId:p,runDir:d.runDir,slug:d.slug,primaryRoot:d.primaryRoot,roots:d.roots,activeRoot:e,resolveInstructionPath:o,resolveEpilogueInstructionPath:i});if(!m)throw new ou(`STEP_OUT_OF_RANGE`,`Step "${p}" not found in flow "${d.flow}".`);let h=f.manifest.steps.find(e=>e.id===p||e.name===p),g=N(d.runDir,f.manifest.artifacts_dir).replaceAll(`\\`,`/`),_={stepId:p,flowName:d.flow,flowSlug:d.slug,phase:d.phase??`flow`,runDir:d.runDir,artifactsPath:g,completedSteps:d.completedSteps??[],stepDescription:h?.description,agents:h?.agents??[],mode:`full`,topic:d.topic??``,activeRoot:e};return l(await s.enrich(m,_,f.manifest.hooks))}catch(e){return su(e)?l(e.message):(r.error(`flow action read failed`,I(e)),e instanceof Error&&`code`in e&&e.code===`ENOENT`?l(`Could not read instruction file: ${e.message}`):l(`Error: ${c(e)}`))}}async function uu(e,t){let{registry:n,loader:r,installer:i}=await e.getFlows(),a=e.createFlowTransform(),o=P(t.source);if(!A(o))return e.toTextResponse(`Source path no longer exists: ${o}`);let s=`${t.installPath}.updating`,c=`${t.installPath}.backup`;A(s)&&fe(s,{recursive:!0,force:!0}),A(c)&&fe(c,{recursive:!0,force:!0});let l=i.copyLocal(o,ge(s));if(!l.success||!l.data)return e.toTextResponse(`Failed to copy flow: ${l.error}`);let u=await r.load(s,{forceAssetSync:!0,transform:a});if(!u.success||!u.data)return i.remove(s),e.toTextResponse(`Failed to load flow manifest: ${u.error}`);let d=!1;try{de(t.installPath,c),de(s,t.installPath);let e=await r.load(t.installPath,{forceAssetSync:!0,transform:a});if(!e.success||!e.data)throw Error(`Failed to load flow manifest: ${e.error}`);let o=e.data.manifest,l=e.data.format,u=n.register({...t,version:o.version,format:l,installPath:t.installPath,manifest:o,updatedAt:new Date().toISOString()});if(!u.success)throw Error(`Failed to refresh flow registry entry: ${u.error}`);if(d=!0,o.install.length>0){let e=i.runInstallDeps(o.install);if(!e.success)throw Error(`Dependency install failed: ${e.error}`)}fe(c,{recursive:!0,force:!0})}catch(r){return A(s)&&fe(s,{recursive:!0,force:!0}),A(c)&&(A(t.installPath)&&fe(t.installPath,{recursive:!0,force:!0}),de(c,t.installPath)),d&&n.register(t),e.toTextResponse(e.toErrorText(r))}return e.toTextResponse(`Flow "${t.name}" updated from ${t.sourceType} source successfully.`)}async function du(e,t){let{registry:n,loader:r}=await e.getFlows(),i=e.createFlowTransform();try{xr(`npm update -g @fission-ai/openspec`,{encoding:`utf-8`,stdio:`pipe`})}catch(t){return e.toTextResponse(`npm update failed: ${e.toErrorText(t)}`)}let a=e.resolveOpenSpecSource(),o=await r.load(a.path,{forceAssetSync:!0,transform:i}),s=o.success&&o.data?o.data.manifest:null,c=o.success&&o.data?o.data.format:t.format;if(s){let r=n.register({...t,version:s.version,format:c,installPath:a.path,manifest:s,updatedAt:new Date().toISOString()});if(!r.success)return e.toTextResponse(`Failed to refresh flow registry entry: ${r.error}`)}return e.toTextResponse(`Flow "${t.name}" updated via npm successfully.`)}async function fu(e,t){let{registry:n,loader:r,installer:i}=await e.getFlows(),a=e.createFlowTransform(),o=i.update(t.installPath);if(!o.success)return e.toTextResponse(`Update failed: ${o.error}`);let s=await r.load(t.installPath,{forceAssetSync:!0,transform:a}),c=s.success&&s.data?s.data.manifest:null,l=s.success&&s.data?s.data.format:t.format;if(c){let r=i.getLocalCommit(t.installPath),a=n.register({...t,version:c.version,format:l,manifest:c,updatedAt:new Date().toISOString(),...r?{commitSha:r}:{}});if(!a.success)return e.toTextResponse(`Failed to refresh flow registry entry: ${a.error}`)}let u=c?.install??t.manifest.install;if(u.length>0){let t=i.runInstallDeps(u);if(!t.success)return e.toTextResponse(`Dependency install failed: ${t.error}`)}return e.toTextResponse(`Flow "${t.name}" updated successfully.`)}async function pu(e,t){let{createFlowTransform:n,getFlows:r,log:i,resolveClaudePluginSource:a,resolveOpenSpecSource:o,toErrorText:s,toTextResponse:c}=t,{source:l,name:u,token:d}=e;try{let{registry:e,loader:t,installer:i}=await r(),s=n(),f=l===`openspec`||l.startsWith(`openspec:`),p,m=l,h;if(f){let e=o();m=e.path,p=e.sourceType}let g=f?null:a(m);g&&(m=g.path,p=g.sourceType);let _=/^https?:\/\/|^git@/.test(m),v;if(_){let e=i.clone(m,d);if(!e.success||!e.data)return c(`Failed to clone flow: ${e.error}`);v=e.data}else{let e=P(m);h=e;let t=u||ge(e)||`custom-flow`,n=i.copyLocal(e,t);if(!n.success||!n.data)return c(`Failed to copy flow: ${n.error}`);v=n.data}let y=await t.load(v,{forceAssetSync:!0,transform:s});if(!y.success||!y.data)return i.remove(v),c(`Failed to load flow manifest: ${y.error}`);let{manifest:b,format:x}=y.data,S=u||b.name,C=p??(_?`git`:`local`);if(e.has(S))return i.remove(v),c(`Flow "${S}" is already installed. Use flow({ action: "update", name: "${S}" }) to update it, or flow({ action: "remove", name: "${S}" }) then flow({ action: "add", source: "..." }) to replace.`);if(b.install.length>0){let e=i.runInstallDeps(b.install);if(!e.success)return i.remove(v),c(`Dependency install failed: ${e.error}`)}let w=new Date().toISOString(),T=_?i.getLocalCommit(v):void 0,E=e.register({name:S,version:b.version,source:C===`local`||C===`claude-plugin`?h??l:l,sourceType:C,installPath:v,format:x,registeredAt:w,updatedAt:w,manifest:b,...T?{commitSha:T}:{}});if(!E.success)return i.remove(v),c(`Failed to register flow: ${E.error}`);let D=b.steps.length;return c(`Flow "${S}" installed successfully (${D} steps). Use flow({ action: "start", name: "${S}" }) to begin.`)}catch(e){return i.error(`flow action add failed`,I(e)),c(`Error: ${s(e)}`)}}async function mu(e,t){let{getFlows:n,log:r,toErrorText:i,toTextResponse:a}=t,{name:o}=e;try{let{registry:e,installer:t}=await n();if(!e.has(o))return a(`Flow "${o}" is not installed.`);let r=e.get(o);if(!r)return a(`Flow "${o}" is not installed.`);if(r.sourceType===`builtin`)return a(`Cannot remove builtin flow "${o}".`);let i=t.remove(r.installPath);if(!i.success)return a(`Failed to remove flow files: ${i.error}`);let s=e.unregister(o);return s.success?a(`Flow "${o}" removed successfully.`):a(`Failed to unregister flow: ${s.error}`)}catch(e){return r.error(`flow action remove failed`,I(e)),a(`Error: ${i(e)}`)}}async function hu(e,t){let{getFlows:n,log:r,toErrorText:i,toTextResponse:a}=t,{name:o}=e,s={createFlowTransform:t.createFlowTransform,getFlows:t.getFlows,resolveOpenSpecSource:t.resolveOpenSpecSource,toErrorText:t.toErrorText,toTextResponse:t.toTextResponse};try{let{registry:e}=await n();if(!e.has(o))return a(`Flow "${o}" is not installed.`);let t=e.get(o);return!t||t.sourceType!==`git`&&t.sourceType!==`npm-global`&&t.sourceType!==`local`&&t.sourceType!==`claude-plugin`?a(`Flow "${o}" was not installed from git, npm, or a local source — cannot update. Remove and re-add instead.`):t.sourceType===`local`||t.sourceType===`claude-plugin`?uu(s,t):t.sourceType===`npm-global`?du(s,t):fu(s,t)}catch(e){return r.error(`flow action update failed`,I(e)),a(`Error: ${i(e)}`)}}const gu=`IMPORTANT: Start/status/step only include a brief. Call flow({ action: "read" }) before executing this flow step.`,_u=1200,vu=/artifact|output contract|gate|completion criteria|deliverable|must|do not|forbidden/i;function yu(){return{artifactsPath:null,currentStepInstruction:null,currentStepDescription:null,currentStepContent:null,currentStepBrief:null,currentStepPins:null,stepSequence:[]}}function bu(e){if(e.length<=_u)return e;let t=e.slice(0,_u-1),n=Math.max(t.lastIndexOf(`
181
+ `)}}async function c(e){let{FlowRegistryManager:n,FlowStateMachine:i,FlowLoader:a,GitInstaller:s}=await import(`../../flows/dist/index.js`),c=N(t.stateDir??``,`flows`,`installed`);return{registry:new n(o()),stateMachine:new i(r.getFlowsDir(e),iu),loader:new a,installer:new s(c)}}return{server:e,config:t,log:eu,toTextResponse:nu,toErrorText:ru,createFlowTransform:s,getFlows:c,stepPipeline:a,stateDir:t.stateDir??``,...r,...i}}var ou=class extends Error{code;constructor(e,t){super(t),this.code=e,this.name=`FlowError`}};function su(e){return e instanceof ou}async function cu(e){let{entry:t,stepId:n,runDir:r,slug:i,primaryRoot:a,roots:o,activeRoot:s,resolveInstructionPath:c,resolveEpilogueInstructionPath:l}=e;if(!n)return null;try{let e=t.manifest.steps.find(e=>e.id===n||e.name===n),u;if(e)u=await Mn(c(t,e.instruction,s),`utf-8`);else{let e=l(n,s);if(!e)return null;u=await Mn(e,`utf-8`)}let d=N(r,t.manifest.artifacts_dir).replaceAll(`\\`,`/`),f=r.replaceAll(`\\`,`/`);u=u.replaceAll(`{{artifacts_path}}`,d).replaceAll(`{{run_dir}}`,f).replaceAll(`{{workspace_root}}`,(a??s).replaceAll(`\\`,`/`)).replaceAll(`{{all_roots}}`,JSON.stringify(o??[s.replaceAll(`\\`,`/`)],null,2));for(let e of[`spec-driven`])u=u.replaceAll(`${e}/${i}/`,`${d}/`);return u}catch{return null}}async function lu(e,t){let{getFlows:n,log:r,resolveEpilogueInstructionPath:i,resolveFlowRoot:a,resolveInstructionPath:o,stepPipeline:s,toErrorText:c,toTextResponse:l}=t,{step:u}=e;try{let e=await a(),{registry:t,stateMachine:r}=await n(e),c=r.getStatus();if(!c.success||!c.data)throw new ou(`NO_ACTIVE_FLOW`,`No active flow. Use flow({ action: "start", name: "<flow>" }) to begin one, or flow({ action: "list" }) to see available flows.`);let d=c.data,f=t.get(d.flow);if(!f)throw new ou(`FLOW_NOT_FOUND`,`Flow "${d.flow}" not found in registry.`);let p=u??d.currentStep;if(!p)throw new ou(`STEP_OUT_OF_RANGE`,`No current step is available for the active flow.`);let m=await cu({entry:f,stepId:p,runDir:d.runDir,slug:d.slug,primaryRoot:d.primaryRoot,roots:d.roots,activeRoot:e,resolveInstructionPath:o,resolveEpilogueInstructionPath:i});if(!m)throw new ou(`STEP_OUT_OF_RANGE`,`Step "${p}" not found in flow "${d.flow}".`);let h=f.manifest.steps.find(e=>e.id===p||e.name===p),g=N(d.runDir,f.manifest.artifacts_dir).replaceAll(`\\`,`/`),_={stepId:p,flowName:d.flow,flowSlug:d.slug,phase:d.phase??`flow`,runDir:d.runDir,artifactsPath:g,completedSteps:d.completedSteps??[],stepDescription:h?.description,agents:h?.agents??[],mode:`full`,topic:d.topic??``,activeRoot:e};return l(await s.enrich(m,_,f.manifest.hooks))}catch(e){return su(e)?l(e.message):(r.error(`flow action read failed`,I(e)),e instanceof Error&&`code`in e&&e.code===`ENOENT`?l(`Could not read instruction file: ${e.message}`):l(`Error: ${c(e)}`))}}async function uu(e,t){let{registry:n,loader:r,installer:i}=await e.getFlows(),a=e.createFlowTransform(),o=P(t.source);if(!A(o))return e.toTextResponse(`Source path no longer exists: ${o}`);let s=`${t.installPath}.updating`,c=`${t.installPath}.backup`;A(s)&&fe(s,{recursive:!0,force:!0}),A(c)&&fe(c,{recursive:!0,force:!0});let l=i.copyLocal(o,ge(s));if(!l.success||!l.data)return e.toTextResponse(`Failed to copy flow: ${l.error}`);let u=await r.load(s,{forceAssetSync:!0,transform:a});if(!u.success||!u.data)return i.remove(s),e.toTextResponse(`Failed to load flow manifest: ${u.error}`);let d=!1;try{de(t.installPath,c),de(s,t.installPath);let e=await r.load(t.installPath,{forceAssetSync:!0,transform:a});if(!e.success||!e.data)throw Error(`Failed to load flow manifest: ${e.error}`);let o=e.data.manifest,l=e.data.format,u=n.register({...t,version:o.version,format:l,installPath:t.installPath,manifest:o,updatedAt:new Date().toISOString()});if(!u.success)throw Error(`Failed to refresh flow registry entry: ${u.error}`);if(d=!0,o.install.length>0){let e=i.runInstallDeps(o.install);if(!e.success)throw Error(`Dependency install failed: ${e.error}`)}fe(c,{recursive:!0,force:!0})}catch(r){return A(s)&&fe(s,{recursive:!0,force:!0}),A(c)&&(A(t.installPath)&&fe(t.installPath,{recursive:!0,force:!0}),de(c,t.installPath)),d&&n.register(t),e.toTextResponse(e.toErrorText(r))}return e.toTextResponse(`Flow "${t.name}" updated from ${t.sourceType} source successfully.`)}async function du(e,t){let{registry:n,loader:r}=await e.getFlows(),i=e.createFlowTransform();try{xr(`npm update -g @fission-ai/openspec`,{encoding:`utf-8`,stdio:`pipe`})}catch(t){return e.toTextResponse(`npm update failed: ${e.toErrorText(t)}`)}let a=e.resolveOpenSpecSource(),o=await r.load(a.path,{forceAssetSync:!0,transform:i}),s=o.success&&o.data?o.data.manifest:null,c=o.success&&o.data?o.data.format:t.format;if(s){let r=n.register({...t,version:s.version,format:c,installPath:a.path,manifest:s,updatedAt:new Date().toISOString()});if(!r.success)return e.toTextResponse(`Failed to refresh flow registry entry: ${r.error}`)}return e.toTextResponse(`Flow "${t.name}" updated via npm successfully.`)}async function fu(e,t){let{registry:n,loader:r,installer:i}=await e.getFlows(),a=e.createFlowTransform(),o=i.update(t.installPath);if(!o.success)return e.toTextResponse(`Update failed: ${o.error}`);let s=await r.load(t.installPath,{forceAssetSync:!0,transform:a}),c=s.success&&s.data?s.data.manifest:null,l=s.success&&s.data?s.data.format:t.format;if(c){let r=i.getLocalCommit(t.installPath),a=n.register({...t,version:c.version,format:l,manifest:c,updatedAt:new Date().toISOString(),...r?{commitSha:r}:{}});if(!a.success)return e.toTextResponse(`Failed to refresh flow registry entry: ${a.error}`)}let u=c?.install??t.manifest.install;if(u.length>0){let t=i.runInstallDeps(u);if(!t.success)return e.toTextResponse(`Dependency install failed: ${t.error}`)}return e.toTextResponse(`Flow "${t.name}" updated successfully.`)}async function pu(e,t){let{createFlowTransform:n,getFlows:r,log:i,resolveClaudePluginSource:a,resolveOpenSpecSource:o,toErrorText:s,toTextResponse:c}=t,{source:l,name:u,token:d}=e;try{let{registry:e,loader:t,installer:i}=await r(),s=n(),f=l===`openspec`||l.startsWith(`openspec:`),p,m=l,h;if(f){let e=o();m=e.path,p=e.sourceType}let g=f?null:a(m);g&&(m=g.path,p=g.sourceType);let _=/^https?:\/\/|^git@/.test(m),v;if(_){let e=i.clone(m,d);if(!e.success||!e.data)return c(`Failed to clone flow: ${e.error}`);v=e.data}else{let e=P(m);h=e;let t=u||ge(e)||`custom-flow`,n=i.copyLocal(e,t);if(!n.success||!n.data)return c(`Failed to copy flow: ${n.error}`);v=n.data}let y=await t.load(v,{forceAssetSync:!0,transform:s});if(!y.success||!y.data)return i.remove(v),c(`Failed to load flow manifest: ${y.error}`);let{manifest:b,format:x}=y.data,S=u||b.name,C=p??(_?`git`:`local`);if(e.has(S))return i.remove(v),c(`Flow "${S}" is already installed. Use flow({ action: "update", name: "${S}" }) to update it, or flow({ action: "remove", name: "${S}" }) then flow({ action: "add", source: "..." }) to replace.`);if(b.install.length>0){let e=i.runInstallDeps(b.install);if(!e.success)return i.remove(v),c(`Dependency install failed: ${e.error}`)}let w=new Date().toISOString(),T=_?i.getLocalCommit(v):void 0,E=e.register({name:S,version:b.version,source:C===`local`||C===`claude-plugin`?h??l:l,sourceType:C,installPath:v,format:x,registeredAt:w,updatedAt:w,manifest:b,...T?{commitSha:T}:{}});if(!E.success)return i.remove(v),c(`Failed to register flow: ${E.error}`);let D=b.steps.length;return c(`Flow "${S}" installed successfully (${D} steps). Use flow({ action: "start", name: "${S}" }) to begin.`)}catch(e){return i.error(`flow action add failed`,I(e)),c(`Error: ${s(e)}`)}}async function mu(e,t){let{getFlows:n,log:r,toErrorText:i,toTextResponse:a}=t,{name:o}=e;try{let{registry:e,installer:t}=await n();if(!e.has(o))return a(`Flow "${o}" is not installed.`);let r=e.get(o);if(!r)return a(`Flow "${o}" is not installed.`);if(r.sourceType===`builtin`)return a(`Cannot remove builtin flow "${o}".`);let i=t.remove(r.installPath);if(!i.success)return a(`Failed to remove flow files: ${i.error}`);let s=e.unregister(o);return s.success?a(`Flow "${o}" removed successfully.`):a(`Failed to unregister flow: ${s.error}`)}catch(e){return r.error(`flow action remove failed`,I(e)),a(`Error: ${i(e)}`)}}async function hu(e,t){let{getFlows:n,log:r,toErrorText:i,toTextResponse:a}=t,{name:o}=e,s={createFlowTransform:t.createFlowTransform,getFlows:t.getFlows,resolveOpenSpecSource:t.resolveOpenSpecSource,toErrorText:t.toErrorText,toTextResponse:t.toTextResponse};try{let{registry:e}=await n();if(!e.has(o))return a(`Flow "${o}" is not installed.`);let t=e.get(o);return!t||t.sourceType!==`git`&&t.sourceType!==`npm-global`&&t.sourceType!==`local`&&t.sourceType!==`claude-plugin`?a(`Flow "${o}" was not installed from git, npm, or a local source — cannot update. Remove and re-add instead.`):t.sourceType===`local`||t.sourceType===`claude-plugin`?uu(s,t):t.sourceType===`npm-global`?du(s,t):fu(s,t)}catch(e){return r.error(`flow action update failed`,I(e)),a(`Error: ${i(e)}`)}}const gu=`IMPORTANT: Start/status/step only include a brief. Call flow({ action: "read" }) before executing this flow step.`,_u=1200,vu=/artifact|output contract|gate|completion criteria|deliverable|must|do not|forbidden/i;function yu(){return{artifactsPath:null,currentStepInstruction:null,currentStepDescription:null,currentStepContent:null,currentStepBrief:null,currentStepPins:null,stepSequence:[]}}function bu(e){if(e.length<=_u)return e;let t=e.slice(0,_u-1),n=Math.max(t.lastIndexOf(`
182
182
  `),t.lastIndexOf(` `),t.lastIndexOf(` `));return`${(n>=Math.floor(t.length*.6)?t.slice(0,n):t).trimEnd()}…`}function xu(e){if(!e?.trim())return{brief:null,pins:null};let t=/^##\s+/m.exec(e),n=(t?e.slice(0,t.index):e).trim(),r=null;if(n){let e=n.split(/\n\s*\n/).filter(e=>e.trim().length>0),t=(e[0]?.startsWith(`#`)&&e[1]?e.slice(0,2):e.slice(0,1)).join(`
183
183
 
184
184
  `).trim();r=t?bu(t):null}let i=Array.from(e.matchAll(/^##\s+.*$/gm)),a=[];for(let[t,n]of i.entries()){let r=n[0];if(!vu.test(r))continue;let o=n.index??0,s=i[t+1]?.index??e.length;a.push(e.slice(o,s).replace(/\s+$/,``))}return{brief:r,pins:a.length>0?a.join(`
185
185
 
186
- `):null}}function Su(e,t){return t(e)}async function Cu(e){let{context:t,entry:n,state:r,activeRoot:i,primaryRoot:a,roots:o}=e,{instructionPath:s,description:c}=t.resolveCurrentStepInfo(n,r.currentStep,i),l=Su(n,t.getStepSequence),u=await cu({entry:n,stepId:r.currentStep,runDir:r.runDir,slug:r.slug,primaryRoot:a,roots:o,activeRoot:i,resolveInstructionPath:t.resolveInstructionPath,resolveEpilogueInstructionPath:t.resolveEpilogueInstructionPath}),{brief:d,pins:f}=xu(u),p=d;if(d&&r.currentStep){let e=n.manifest.steps.find(e=>e.id===r.currentStep),a={stepId:r.currentStep,flowName:r.flow,flowSlug:r.slug,phase:`flow`,runDir:r.runDir,artifactsPath:N(r.runDir,n.manifest.artifacts_dir).replaceAll(`\\`,`/`),completedSteps:[],stepDescription:e?.description??c??void 0,agents:e?.agents??[],mode:`brief`,topic:r.topic??``,activeRoot:i};p=await t.stepPipeline.enrich(d,a,n.manifest.hooks)}return{artifactsPath:N(r.runDir,n.manifest.artifacts_dir).replaceAll(`\\`,`/`),currentStepInstruction:s,currentStepDescription:c,currentStepContent:u,currentStepBrief:p,currentStepPins:f,stepSequence:l}}function wu(e){let{state:t,data:n,started:r,includeStatus:i,action:a,includeInstructionPath:o}=e,s={};return r&&(s.started=!0),s.flow=t.flow,i&&(s.status=t.status),a&&(s.action=a),s.slug=t.slug,s.topic=t.topic,s.runDir=t.runDir,s.artifactsPath=n.artifactsPath,s.currentStep=t.currentStep,s.currentStepInstruction=n.currentStepInstruction,o&&(s.instructionPath=n.currentStepInstruction),s.currentStepDescription=n.currentStepDescription,s.currentStepContent=null,s.currentStepBrief=n.currentStepBrief,s.currentStepPins=n.currentStepPins,s.fullContentHint=`Call flow({ action: 'read' }) for the complete step instructions.`,s}async function Tu(e,t){let{getAllRoots:n,getFlows:r,getWorkspaceRoot:i,isValidFlowRoot:a,log:o,patchMetaRoots:s,stateDir:c,toErrorText:l,toTextResponse:u}=t,{flow:d,topic:f,roots:p}=e;try{if(p&&p.length>0){let e=n().map(e=>e.replaceAll(`\\`,`/`)),t=p.filter(e=>!a(e));if(t.length>0)return u(`Invalid roots — not part of the workspace or a recognized sub-repository: ${t.join(`, `)}. Available roots: ${e.join(`, `)}`)}let e=n(),o=e.map(e=>e.replaceAll(`\\`,`/`)),l=i(),m=e.length>1,h=!p&&m,g=p?.[0]??l,{registry:_,stateMachine:v}=await r(g),y=_.get(d);if(!y)throw new ou(`UNKNOWN_FLOW`,`Flow "${d}" not found. Use flow({ action: "list" }) to see available flows.`);let b=v.start(y.name,y.manifest,f);if(!b.success||!b.data){let e=b.error??`Unknown flow start error.`;return e.includes(`already active`)?u(`Cannot start: ${new ou(`FLOW_ALREADY_ACTIVE`,e).message}`):u(`Cannot start: ${e}`)}let x=b.data;if(p&&p.length>1)try{s(x.slug,g,p),t.syncMetaToRoots(x.slug,g)}catch(e){return v.reset(),u(`Flow created but failed to sync to secondary roots — rolled back. Error: ${e instanceof Error?e.message:String(e)}`)}let S=N(c,`flow-context`),C=typeof Nn==`function`?await Nn(S).catch(()=>[]):[];for(let e of C)e!==x.slug&&typeof Pn==`function`&&await Pn(N(S,e),{recursive:!0,force:!0}).catch(()=>{});if(typeof jn==`function`)try{await jn(N(S,x.slug),{recursive:!0})}catch{}let w=await Cu({context:t,entry:y,state:x,activeRoot:g,primaryRoot:null,roots:p??null}),T={...wu({state:x,data:w,started:!0}),phase:x.phase,isEpilogue:x.isEpilogue,totalSteps:w.stepSequence.length,stepSequence:w.stepSequence,artifactsDir:y.manifest.artifacts_dir,roots:p??[g.replaceAll(`\\`,`/`)],_hint:gu,...h?{multiRootWarning:`No roots specified in multi-root workspace. Flow created at workspace root. Pass roots parameter with target repo for precise placement.`,availableRoots:o}:{}};return u(JSON.stringify(T,null,2))}catch(e){return su(e)?u(e.message):(o.error(`flow action start failed`,I(e)),u(`Error: ${l(e)}`))}}async function Eu(e){let{getFlows:t,log:n,resolveFlowRoot:r,resolveRoots:i,toErrorText:a,toTextResponse:o}=e;try{let n=await r(),{registry:a,stateMachine:s}=await t(n),c=s.getStatus();if(!c.success||!c.data)throw new ou(`NO_ACTIVE_FLOW`,`No active flow. Use flow({ action: "start", name: "<flow>" }) to begin one, or flow({ action: "list" }) to see available flows.`);let l=c.data,u=a.get(l.flow),d=u?await Cu({context:e,entry:u,state:l,activeRoot:n,primaryRoot:l.primaryRoot,roots:l.roots}):yu(),f={...wu({state:l,data:d,includeStatus:!0,includeInstructionPath:!0}),_hint:l.currentStep?gu:void 0,phase:l.phase,isEpilogue:l.isEpilogue,completedSteps:l.completedSteps,skippedSteps:l.skippedSteps,artifacts:l.artifacts,startedAt:l.startedAt,updatedAt:l.updatedAt,totalSteps:d.stepSequence.length,progress:u?`${l.completedSteps.length+l.skippedSteps.length}/${d.stepSequence.length}`:`unknown`,workspaceRoot:n.replaceAll(`\\`,`/`),primaryRoot:(l.primaryRoot??n).replaceAll(`\\`,`/`),roots:l.roots??[n.replaceAll(`\\`,`/`)],allRoots:i().normalizedAllRoots,discoveredRepos:i().discoveredRepos};return o(JSON.stringify(f,null,2))}catch(e){return su(e)?o(e.message):(n.error(`flow action status failed`,I(e)),o(`Error: ${a(e)}`))}}async function Du(e){let{getFlows:t,log:n,resolveFlowRoot:r,stateDir:i,syncMetaToRoots:a,toErrorText:o,toTextResponse:s}=e;try{let e=await r(),{stateMachine:n}=await t(e),o=n.getStatus(),c=n.reset();if(!c.success)return s(`Reset failed: ${c.error}`);if(o.success&&o.data&&a(o.data.slug,e),o.success&&o.data?.slug)try{await Pn(N(i,`flow-context`,o.data.slug),{recursive:!0,force:!0})}catch{}return s(`Flow abandoned. Use flow({ action: "start", name: "<flow>" }) to begin a new flow.`)}catch(e){return n.error(`flow action reset failed`,I(e)),s(`Error: ${o(e)}`)}}async function Ou(e,t){let{getFlows:n,log:r,resolveFlowRoot:i,syncMetaToRoots:a,toErrorText:o,toTextResponse:s}=t,{action:c}=e;try{let e=await i(),{registry:r,stateMachine:o}=await n(e),l=o.getStatus();if(!l.success||!l.data)throw new ou(`NO_ACTIVE_FLOW`,`No active flow. Use flow({ action: "start", name: "<flow>" }) first.`);let u=r.get(l.data.flow);if(!u)throw new ou(`FLOW_NOT_FOUND`,`Flow "${l.data.flow}" not found in registry.`);let d=o.step(c,u.manifest);if(!d.success||!d.data)return s(`Cannot ${c}: ${d.error}`);a(d.data.slug,e);let f=d.data,p=[];if(f.status===`completed`){let e=N(t.stateDir,`flow-context`,f.slug);for(let t of[`decision`,`pattern`]){let n=N(e,t);try{let e=await Nn(n);for(let r of e){if(!r.endsWith(`.md`))continue;let e=await Mn(N(n,r),`utf-8`);e.length>100&&p.push({type:t,title:r.replace(/\.md$/,``).replace(/-/g,` `),content:e.length>500?`${e.slice(0,497)}...`:e})}}catch{}}typeof Pn==`function`&&await Pn(e,{recursive:!0,force:!0}).catch(()=>{})}let m=await Cu({context:t,entry:u,state:f,activeRoot:e,primaryRoot:f.primaryRoot,roots:f.roots}),h={...wu({state:f,data:m,includeStatus:!0,action:c}),_hint:f.currentStep?gu:void 0,phase:f.phase,isEpilogue:f.isEpilogue,completedSteps:f.completedSteps,skippedSteps:f.skippedSteps,totalSteps:m.stepSequence.length,remaining:m.stepSequence.filter(e=>!f.completedSteps.includes(e)&&!f.skippedSteps.includes(e)&&e!==f.currentStep),...p.length>0?{promotionCandidates:p}:{}};return s(JSON.stringify(h,null,2))}catch(e){return su(e)?s(e.message):(r.error(`flow action step failed`,I(e)),s(`Error: ${o(e)}`))}}async function ku(e){let{getFlows:t,log:n,resolveFlowRoot:r,resolveRoots:i,toErrorText:a,toTextResponse:o}=e;try{let{registry:e,stateMachine:n,installer:a}=await t(await r()),s=e.list(),c=n.getStatus(),l={flows:s.map(e=>{let t={name:e.name,version:e.version,source:e.source,sourceType:e.sourceType,format:e.format,steps:e.manifest.steps.map(e=>e.id)};if(e.sourceType===`git`&&e.commitSha){let n=a.hasUpdates(e.installPath);return{...t,commitSha:e.commitSha,updateAvailable:n.success&&n.data?n.data.hasUpdates:void 0}}return t}),activeFlow:c.success&&c.data?{flow:c.data.flow,status:c.data.status,currentStep:c.data.currentStep,slug:c.data.slug,topic:c.data.topic,runDir:c.data.runDir}:null,allRoots:i().normalizedAllRoots,discoveredRepos:i().discoveredRepos};return o(JSON.stringify(l,null,2))}catch(e){return n.error(`flow action list failed`,I(e)),o(`Error: ${a(e)}`)}}async function Au(e,t){let{getFlows:n,log:r,resolveInstallPath:i,resolveInstructionPath:a,toErrorText:o,toTextResponse:s}=t,{name:c}=e;try{let{registry:e,installer:t}=await n(),r=e.get(c);if(!r)throw new ou(`UNKNOWN_FLOW`,`Flow "${c}" not found. Use flow({ action: "list" }) to see available flows.`);let o=r.commitSha??null,l;if(r.sourceType===`git`&&r.installPath){let e=t.hasUpdates(r.installPath);l=e.success&&e.data?e.data.hasUpdates:void 0}let u={name:r.name,version:r.version,description:r.manifest.description,source:r.source,sourceType:r.sourceType,format:r.format,commitSha:o,updateAvailable:l,installPath:i(r.name,r),registeredAt:r.registeredAt,updatedAt:r.updatedAt,steps:r.manifest.steps.map(e=>({id:e.id,name:e.name,instruction:a(r,e.instruction),produces:e.produces,requires:e.requires,description:e.description})),agents:r.manifest.agents,artifactsDir:r.manifest.artifacts_dir,install:r.manifest.install};return s(JSON.stringify(u,null,2))}catch(e){return su(e)?s(e.message):(r.error(`flow action info failed`,I(e)),s(`Error: ${o(e)}`))}}async function ju(e,t){let{getAllRoots:n,getFlows:r,log:i,toErrorText:a,toTextResponse:o}=t,{flow:s,status:c,limit:l=50}=e,u=e=>{for(let t of[`updatedAt`,`startedAt`,`createdAt`]){let n=e[t];if(typeof n==`number`&&Number.isFinite(n))return n;if(typeof n==`string`){let e=Date.parse(n);if(!Number.isNaN(e))return e}}return null};try{let e=n(),t=[];for(let n of e){let{stateMachine:e}=await r(n),i=e.listRuns({flow:s,status:c});for(let e of i)t.push({...JSON.parse(JSON.stringify(e)),root:n.replaceAll(`\\`,`/`)})}let i=new Set,a=t.filter(e=>{let t=e.id;return i.has(t)?!1:(i.add(t),!0)});if(a.length===0)return o(`No flow runs found.`);let d=a.map((e,t)=>({run:e,index:t,recency:u(e)})).sort((e,t)=>e.recency==null&&t.recency==null?e.index-t.index:e.recency==null?1:t.recency==null?-1:t.recency===e.recency?e.index-t.index:t.recency-e.recency).map(({run:e})=>e).slice(0,l);return o(JSON.stringify({total:a.length,returned:d.length,truncated:a.length>d.length,runs:d},null,2))}catch(e){return i.error(`flow action runs failed`,I(e)),o(`Error: ${a(e)}`)}}function Mu(e){let t=e.content?.find(e=>e.type===`text`)?.text??``;if(!t)return null;try{let e=JSON.parse(t);if(typeof e.slug==`string`&&e.slug.length>0)return e.slug}catch{}return t.match(/[Ss]lug[:\s]*`?([^`\s,]+)`?/)?.[1]??null}function Nu(e,t,n){let r=au(e,t),i=G(`flow`);e.registerTool(`flow`,{title:i.title,description:`Manage development flows — list available flows, start/stop runs, navigate steps, read instructions, and install/remove/update flows. Use action parameter to select operation.`,annotations:i.annotations,inputSchema:{action:R.enum([`list`,`info`,`start`,`step`,`status`,`reset`,`read`,`runs`,`add`,`remove`,`update`]).describe(`The flow operation to perform.`),name:R.string().optional().describe(`Flow name — required for info, start, remove, update. Optional override for add.`),topic:R.string().optional().describe(`Human-readable topic for the run (used by start).`),roots:R.array(R.string()).optional().describe(`Workspace roots participating in this flow (used by start).`),advance:R.enum([`next`,`skip`,`redo`]).optional().describe(`Step navigation action — required for step.`),step:R.string().optional().describe(`Step id or name to read (used by read). Defaults to current step.`),source:R.string().optional().describe(`Git URL, local path, or "openspec" shorthand — required for add.`),token:R.string().optional().describe(`Auth token for private repos (used by add).`),filter_flow:R.string().optional().describe(`Filter runs by flow name (used by runs).`),filter_status:R.string().optional().describe(`Filter runs by status: active, completed, abandoned (used by runs).`),limit:R.number().int().positive().optional().describe(`Max runs to return (default 50).`)}},Y(`flow`,async e=>{switch(e.action){case`list`:return ku(r);case`info`:return e.name?Au({name:e.name},r):r.toTextResponse(`Missing required parameter: name`);case`start`:{if(!e.name)return r.toTextResponse(`Missing required parameter: name (flow to start)`);let t=await Tu({flow:e.name,topic:e.topic,roots:e.roots},r),i=Mu(t);return i&&n&&n(i),t}case`step`:return e.advance?Ou({action:e.advance},r):r.toTextResponse(`Missing required parameter: advance (next/skip/redo)`);case`status`:{let e=await Eu(r);return n&&n(Mu(e)),e}case`reset`:{let e=await Du(r);return n&&n(null),e}case`read`:return lu({step:e.step},r);case`runs`:return ju({flow:e.filter_flow,status:e.filter_status,limit:e.limit},r);case`add`:return e.source?pu({source:e.source,name:e.name,token:e.token},r):r.toTextResponse(`Missing required parameter: source`);case`remove`:return e.name?mu({name:e.name},r):r.toTextResponse(`Missing required parameter: name`);case`update`:return e.name?hu({name:e.name},r):r.toTextResponse(`Missing required parameter: name`);default:return r.toTextResponse(`Unknown action: ${e.action}`)}}))}const Pu=F(`tools`);function Fu(e){let t=G(`evidence_map`);e.registerTool(`evidence_map`,{title:t.title,description:`Track verified/assumed/unresolved claims for complex tasks. Gate readiness: YIELD (proceed), HOLD (unknowns), HARD_BLOCK (critical gaps). Persists across calls.`,inputSchema:{action:R.enum([`create`,`add`,`update`,`get`,`gate`,`list`,`delete`]).describe(`Operation to perform`),task_id:R.string().optional().describe(`Task identifier (required for all except list)`),tier:R.enum([`floor`,`standard`,`critical`]).optional().describe(`FORGE tier (required for create)`),claim:R.string().optional().describe(`Critical-path claim text (for add)`),status:R.enum([`V`,`A`,`U`]).optional().describe(`Evidence status: V=Verified, A=Assumed, U=Unresolved`),receipt:R.string().optional().describe(`Evidence receipt: tool→ref for V, reasoning for A, attempts for U`),id:R.number().optional().describe(`Entry ID (for update)`),critical_path:R.boolean().default(!0).describe(`Whether this claim is on the critical path`),unknown_type:R.enum([`contract`,`convention`,`freshness`,`runtime`,`data-flow`,`impact`]).optional().describe(`Typed unknown classification`),safety_gate:R.enum([`provenance`,`commitment`,`coverage`]).optional().describe(`Safety gate tag: provenance (claim→evidence), commitment (user-approved), coverage (nothing dropped)`),retry_count:R.number().default(0).describe(`Retry count for gate evaluation (0 = first attempt)`),max_retries:R.number().int().min(0).optional().describe(`Maximum retries before escalating. Default: 3`),timeout_action:R.enum([`iterate`,`retry`,`manual`,`terminate`]).optional().describe(`Action to take when gate retries are exhausted. Default: manual`),cwd:R.string().optional().describe(`Working directory for evidence map storage (default: server cwd). Use root_path from forge_ground to match.`)},annotations:t.annotations},Y(`evidence_map`,async({action:e,task_id:t,tier:n,claim:r,status:i,receipt:a,id:o,critical_path:s,unknown_type:c,safety_gate:l,retry_count:u,max_retries:d,timeout_action:f,cwd:p})=>{try{switch(e){case`create`:if(!t)throw Error(`task_id required for create`);if(!n)throw Error(`tier required for create`);return ft({action:`create`,taskId:t,tier:n},p),{content:[{type:`text`,text:`Created evidence map "${t}" (tier: ${n}).\n\n---\n_Next: Use \`evidence_map\` with action "add" to record critical-path claims._`}]};case`add`:{if(!t)throw Error(`task_id required for add`);if(!r)throw Error(`claim required for add`);if(!i)throw Error(`status required for add`);let e=ft({action:`add`,taskId:t,claim:r,status:i,receipt:a??``,criticalPath:s,unknownType:c,safetyGate:l},p),n=e.autoCreated?[`⚠️ Evidence map "${t}" was auto-created with tier "standard". Use \`create\` action to set a specific tier.`,``,`Added entry #${e.entry?.id} to "${t}": [${i}] ${r}`]:[`Added entry #${e.entry?.id} to "${t}": [${i}] ${r}`];return e.summary&&n.push(``,e.summary),{content:[{type:`text`,text:n.join(`
186
+ `):null}}function Su(e,t){return t(e)}async function Cu(e){let{context:t,entry:n,state:r,activeRoot:i,primaryRoot:a,roots:o}=e,{instructionPath:s,description:c}=t.resolveCurrentStepInfo(n,r.currentStep,i),l=Su(n,t.getStepSequence),u=await cu({entry:n,stepId:r.currentStep,runDir:r.runDir,slug:r.slug,primaryRoot:a,roots:o,activeRoot:i,resolveInstructionPath:t.resolveInstructionPath,resolveEpilogueInstructionPath:t.resolveEpilogueInstructionPath}),{brief:d,pins:f}=xu(u),p=d;if(d&&r.currentStep){let e=n.manifest.steps.find(e=>e.id===r.currentStep),a={stepId:r.currentStep,flowName:r.flow,flowSlug:r.slug,phase:`flow`,runDir:r.runDir,artifactsPath:N(r.runDir,n.manifest.artifacts_dir).replaceAll(`\\`,`/`),completedSteps:r.completedSteps??[],stepDescription:e?.description??c??void 0,agents:e?.agents??[],mode:`brief`,topic:r.topic??``,activeRoot:i};p=await t.stepPipeline.enrich(d,a,n.manifest.hooks)}return{artifactsPath:N(r.runDir,n.manifest.artifacts_dir).replaceAll(`\\`,`/`),currentStepInstruction:s,currentStepDescription:c,currentStepContent:u,currentStepBrief:p,currentStepPins:f,stepSequence:l}}function wu(e){let{state:t,data:n,started:r,includeStatus:i,action:a,includeInstructionPath:o}=e,s={};return r&&(s.started=!0),s.flow=t.flow,i&&(s.status=t.status),a&&(s.action=a),s.slug=t.slug,s.topic=t.topic,s.runDir=t.runDir,s.artifactsPath=n.artifactsPath,s.currentStep=t.currentStep,s.currentStepInstruction=n.currentStepInstruction,o&&(s.instructionPath=n.currentStepInstruction),s.currentStepDescription=n.currentStepDescription,s.currentStepContent=null,s.currentStepBrief=n.currentStepBrief,s.currentStepPins=n.currentStepPins,s.fullContentHint=`Call flow({ action: 'read' }) for the complete step instructions.`,s}async function Tu(e,t){let{getAllRoots:n,getFlows:r,getWorkspaceRoot:i,isValidFlowRoot:a,log:o,patchMetaRoots:s,stateDir:c,toErrorText:l,toTextResponse:u}=t,{flow:d,topic:f,roots:p}=e;try{if(p&&p.length>0){let e=n().map(e=>e.replaceAll(`\\`,`/`)),t=p.filter(e=>!a(e));if(t.length>0)return u(`Invalid roots — not part of the workspace or a recognized sub-repository: ${t.join(`, `)}. Available roots: ${e.join(`, `)}`)}let e=n(),o=e.map(e=>e.replaceAll(`\\`,`/`)),l=i(),m=e.length>1,h=!p&&m,g=p?.[0]??l,{registry:_,stateMachine:v}=await r(g),y=_.get(d);if(!y)throw new ou(`UNKNOWN_FLOW`,`Flow "${d}" not found. Use flow({ action: "list" }) to see available flows.`);let b=v.start(y.name,y.manifest,f);if(!b.success||!b.data){let e=b.error??`Unknown flow start error.`;return e.includes(`already active`)?u(`Cannot start: ${new ou(`FLOW_ALREADY_ACTIVE`,e).message}`):u(`Cannot start: ${e}`)}let x=b.data;if(p&&p.length>1)try{s(x.slug,g,p),t.syncMetaToRoots(x.slug,g)}catch(e){return v.reset(),u(`Flow created but failed to sync to secondary roots — rolled back. Error: ${e instanceof Error?e.message:String(e)}`)}let S=N(c,`flow-context`),C=typeof Nn==`function`?await Nn(S).catch(()=>[]):[];for(let e of C)e!==x.slug&&typeof Pn==`function`&&await Pn(N(S,e),{recursive:!0,force:!0}).catch(()=>{});if(typeof jn==`function`)try{await jn(N(S,x.slug),{recursive:!0})}catch{}let w=await Cu({context:t,entry:y,state:x,activeRoot:g,primaryRoot:null,roots:p??null}),T={...wu({state:x,data:w,started:!0}),phase:x.phase,isEpilogue:x.isEpilogue,totalSteps:w.stepSequence.length,stepSequence:w.stepSequence,artifactsDir:y.manifest.artifacts_dir,roots:p??[g.replaceAll(`\\`,`/`)],_hint:gu,...h?{multiRootWarning:`No roots specified in multi-root workspace. Flow created at workspace root. Pass roots parameter with target repo for precise placement.`,availableRoots:o}:{}};return u(JSON.stringify(T,null,2))}catch(e){return su(e)?u(e.message):(o.error(`flow action start failed`,I(e)),u(`Error: ${l(e)}`))}}async function Eu(e){let{getFlows:t,log:n,resolveFlowRoot:r,resolveRoots:i,toErrorText:a,toTextResponse:o}=e;try{let n=await r(),{registry:a,stateMachine:s}=await t(n),c=s.getStatus();if(!c.success||!c.data)throw new ou(`NO_ACTIVE_FLOW`,`No active flow. Use flow({ action: "start", name: "<flow>" }) to begin one, or flow({ action: "list" }) to see available flows.`);let l=c.data,u=a.get(l.flow),d=u?await Cu({context:e,entry:u,state:l,activeRoot:n,primaryRoot:l.primaryRoot,roots:l.roots}):yu(),f={...wu({state:l,data:d,includeStatus:!0,includeInstructionPath:!0}),_hint:l.currentStep?gu:void 0,phase:l.phase,isEpilogue:l.isEpilogue,completedSteps:l.completedSteps,skippedSteps:l.skippedSteps,artifacts:l.artifacts,startedAt:l.startedAt,updatedAt:l.updatedAt,totalSteps:d.stepSequence.length,progress:u?`${l.completedSteps.length+l.skippedSteps.length}/${d.stepSequence.length}`:`unknown`,workspaceRoot:n.replaceAll(`\\`,`/`),primaryRoot:(l.primaryRoot??n).replaceAll(`\\`,`/`),roots:l.roots??[n.replaceAll(`\\`,`/`)],allRoots:i().normalizedAllRoots,discoveredRepos:i().discoveredRepos};return o(JSON.stringify(f,null,2))}catch(e){return su(e)?o(e.message):(n.error(`flow action status failed`,I(e)),o(`Error: ${a(e)}`))}}async function Du(e){let{getFlows:t,log:n,resolveFlowRoot:r,stateDir:i,syncMetaToRoots:a,toErrorText:o,toTextResponse:s}=e;try{let e=await r(),{stateMachine:n}=await t(e),o=n.getStatus(),c=n.reset();if(!c.success)return s(`Reset failed: ${c.error}`);if(o.success&&o.data&&a(o.data.slug,e),o.success&&o.data?.slug)try{await Pn(N(i,`flow-context`,o.data.slug),{recursive:!0,force:!0})}catch{}return s(`Flow abandoned. Use flow({ action: "start", name: "<flow>" }) to begin a new flow.`)}catch(e){return n.error(`flow action reset failed`,I(e)),s(`Error: ${o(e)}`)}}async function Ou(e,t){let{getFlows:n,log:r,resolveFlowRoot:i,syncMetaToRoots:a,toErrorText:o,toTextResponse:s}=t,{action:c}=e;try{let e=await i(),{registry:r,stateMachine:o}=await n(e),l=o.getStatus();if(!l.success||!l.data)throw new ou(`NO_ACTIVE_FLOW`,`No active flow. Use flow({ action: "start", name: "<flow>" }) first.`);let u=r.get(l.data.flow);if(!u)throw new ou(`FLOW_NOT_FOUND`,`Flow "${l.data.flow}" not found in registry.`);let d=o.step(c,u.manifest);if(!d.success||!d.data)return s(`Cannot ${c}: ${d.error}`);a(d.data.slug,e);let f=d.data,p=[];if(f.status===`completed`){let e=N(t.stateDir,`flow-context`,f.slug);for(let t of[`decision`,`pattern`]){let n=N(e,t);try{let e=await Nn(n);for(let r of e){if(!r.endsWith(`.md`))continue;let e=await Mn(N(n,r),`utf-8`);e.length>100&&p.push({type:t,title:r.replace(/\.md$/,``).replace(/-/g,` `),content:e.length>500?`${e.slice(0,497)}...`:e})}}catch{}}typeof Pn==`function`&&await Pn(e,{recursive:!0,force:!0}).catch(()=>{})}let m=await Cu({context:t,entry:u,state:f,activeRoot:e,primaryRoot:f.primaryRoot,roots:f.roots}),h={...wu({state:f,data:m,includeStatus:!0,action:c}),_hint:f.currentStep?gu:void 0,phase:f.phase,isEpilogue:f.isEpilogue,completedSteps:f.completedSteps,skippedSteps:f.skippedSteps,totalSteps:m.stepSequence.length,remaining:m.stepSequence.filter(e=>!f.completedSteps.includes(e)&&!f.skippedSteps.includes(e)&&e!==f.currentStep),...p.length>0?{promotionCandidates:p}:{}};return s(JSON.stringify(h,null,2))}catch(e){return su(e)?s(e.message):(r.error(`flow action step failed`,I(e)),s(`Error: ${o(e)}`))}}async function ku(e){let{getFlows:t,log:n,resolveFlowRoot:r,resolveRoots:i,toErrorText:a,toTextResponse:o}=e;try{let{registry:e,stateMachine:n,installer:a}=await t(await r()),s=e.list(),c=n.getStatus(),l={flows:s.map(e=>{let t={name:e.name,version:e.version,source:e.source,sourceType:e.sourceType,format:e.format,steps:e.manifest.steps.map(e=>e.id)};if(e.sourceType===`git`&&e.commitSha){let n=a.hasUpdates(e.installPath);return{...t,commitSha:e.commitSha,updateAvailable:n.success&&n.data?n.data.hasUpdates:void 0}}return t}),activeFlow:c.success&&c.data?{flow:c.data.flow,status:c.data.status,currentStep:c.data.currentStep,slug:c.data.slug,topic:c.data.topic,runDir:c.data.runDir}:null,allRoots:i().normalizedAllRoots,discoveredRepos:i().discoveredRepos};return o(JSON.stringify(l,null,2))}catch(e){return n.error(`flow action list failed`,I(e)),o(`Error: ${a(e)}`)}}async function Au(e,t){let{getFlows:n,log:r,resolveInstallPath:i,resolveInstructionPath:a,toErrorText:o,toTextResponse:s}=t,{name:c}=e;try{let{registry:e,installer:t}=await n(),r=e.get(c);if(!r)throw new ou(`UNKNOWN_FLOW`,`Flow "${c}" not found. Use flow({ action: "list" }) to see available flows.`);let o=r.commitSha??null,l;if(r.sourceType===`git`&&r.installPath){let e=t.hasUpdates(r.installPath);l=e.success&&e.data?e.data.hasUpdates:void 0}let u={name:r.name,version:r.version,description:r.manifest.description,source:r.source,sourceType:r.sourceType,format:r.format,commitSha:o,updateAvailable:l,installPath:i(r.name,r),registeredAt:r.registeredAt,updatedAt:r.updatedAt,steps:r.manifest.steps.map(e=>({id:e.id,name:e.name,instruction:a(r,e.instruction),produces:e.produces,requires:e.requires,description:e.description})),agents:r.manifest.agents,artifactsDir:r.manifest.artifacts_dir,install:r.manifest.install};return s(JSON.stringify(u,null,2))}catch(e){return su(e)?s(e.message):(r.error(`flow action info failed`,I(e)),s(`Error: ${o(e)}`))}}async function ju(e,t){let{getAllRoots:n,getFlows:r,log:i,toErrorText:a,toTextResponse:o}=t,{flow:s,status:c,limit:l=50}=e,u=e=>{for(let t of[`updatedAt`,`startedAt`,`createdAt`]){let n=e[t];if(typeof n==`number`&&Number.isFinite(n))return n;if(typeof n==`string`){let e=Date.parse(n);if(!Number.isNaN(e))return e}}return null};try{let e=n(),t=[];for(let n of e){let{stateMachine:e}=await r(n),i=e.listRuns({flow:s,status:c});for(let e of i)t.push({...JSON.parse(JSON.stringify(e)),root:n.replaceAll(`\\`,`/`)})}let i=new Set,a=t.filter(e=>{let t=e.id;return i.has(t)?!1:(i.add(t),!0)});if(a.length===0)return o(`No flow runs found.`);let d=a.map((e,t)=>({run:e,index:t,recency:u(e)})).sort((e,t)=>e.recency==null&&t.recency==null?e.index-t.index:e.recency==null?1:t.recency==null?-1:t.recency===e.recency?e.index-t.index:t.recency-e.recency).map(({run:e})=>e).slice(0,l);return o(JSON.stringify({total:a.length,returned:d.length,truncated:a.length>d.length,runs:d},null,2))}catch(e){return i.error(`flow action runs failed`,I(e)),o(`Error: ${a(e)}`)}}function Mu(e){let t=e.content?.find(e=>e.type===`text`)?.text??``;if(!t)return null;try{let e=JSON.parse(t);if(typeof e.slug==`string`&&e.slug.length>0)return e.slug}catch{}return t.match(/[Ss]lug[:\s]*`?([^`\s,]+)`?/)?.[1]??null}function Nu(e,t,n,r){let i=n&&typeof n!=`function`?n:void 0,a=typeof n==`function`?n:r,o=au(e,t,i),s=G(`flow`);e.registerTool(`flow`,{title:s.title,description:`Manage development flows — list available flows, start/stop runs, navigate steps, read instructions, and install/remove/update flows. Use action parameter to select operation.`,annotations:s.annotations,inputSchema:{action:R.enum([`list`,`info`,`start`,`step`,`status`,`reset`,`read`,`runs`,`add`,`remove`,`update`]).describe(`The flow operation to perform.`),name:R.string().optional().describe(`Flow name — required for info, start, remove, update. Optional override for add.`),topic:R.string().optional().describe(`Human-readable topic for the run (used by start).`),roots:R.array(R.string()).optional().describe(`Workspace roots participating in this flow (used by start).`),advance:R.enum([`next`,`skip`,`redo`]).optional().describe(`Step navigation action — required for step.`),step:R.string().optional().describe(`Step id or name to read (used by read). Defaults to current step.`),source:R.string().optional().describe(`Git URL, local path, or "openspec" shorthand — required for add.`),token:R.string().optional().describe(`Auth token for private repos (used by add).`),filter_flow:R.string().optional().describe(`Filter runs by flow name (used by runs).`),filter_status:R.string().optional().describe(`Filter runs by status: active, completed, abandoned (used by runs).`),limit:R.number().int().positive().optional().describe(`Max runs to return (default 50).`)}},Y(`flow`,async e=>{switch(e.action){case`list`:return ku(o);case`info`:return e.name?Au({name:e.name},o):o.toTextResponse(`Missing required parameter: name`);case`start`:{if(!e.name)return o.toTextResponse(`Missing required parameter: name (flow to start)`);let t=await Tu({flow:e.name,topic:e.topic,roots:e.roots},o),n=Mu(t);return n&&a&&a(n),t}case`step`:return e.advance?Ou({action:e.advance},o):o.toTextResponse(`Missing required parameter: advance (next/skip/redo)`);case`status`:{let e=await Eu(o);return a&&a(Mu(e)),e}case`reset`:{let e=await Du(o);return a&&a(null),e}case`read`:return lu({step:e.step},o);case`runs`:return ju({flow:e.filter_flow,status:e.filter_status,limit:e.limit},o);case`add`:return e.source?pu({source:e.source,name:e.name,token:e.token},o):o.toTextResponse(`Missing required parameter: source`);case`remove`:return e.name?mu({name:e.name},o):o.toTextResponse(`Missing required parameter: name`);case`update`:return e.name?hu({name:e.name},o):o.toTextResponse(`Missing required parameter: name`);default:return o.toTextResponse(`Unknown action: ${e.action}`)}}))}const Pu=F(`tools`);function Fu(e){let t=G(`evidence_map`);e.registerTool(`evidence_map`,{title:t.title,description:`Track verified/assumed/unresolved claims for complex tasks. Gate readiness: YIELD (proceed), HOLD (unknowns), HARD_BLOCK (critical gaps). Persists across calls.`,inputSchema:{action:R.enum([`create`,`add`,`update`,`get`,`gate`,`list`,`delete`]).describe(`Operation to perform`),task_id:R.string().optional().describe(`Task identifier (required for all except list)`),tier:R.enum([`floor`,`standard`,`critical`]).optional().describe(`FORGE tier (required for create)`),claim:R.string().optional().describe(`Critical-path claim text (for add)`),status:R.enum([`V`,`A`,`U`]).optional().describe(`Evidence status: V=Verified, A=Assumed, U=Unresolved`),receipt:R.string().optional().describe(`Evidence receipt: tool→ref for V, reasoning for A, attempts for U`),id:R.number().optional().describe(`Entry ID (for update)`),critical_path:R.boolean().default(!0).describe(`Whether this claim is on the critical path`),unknown_type:R.enum([`contract`,`convention`,`freshness`,`runtime`,`data-flow`,`impact`]).optional().describe(`Typed unknown classification`),safety_gate:R.enum([`provenance`,`commitment`,`coverage`]).optional().describe(`Safety gate tag: provenance (claim→evidence), commitment (user-approved), coverage (nothing dropped)`),retry_count:R.number().default(0).describe(`Retry count for gate evaluation (0 = first attempt)`),max_retries:R.number().int().min(0).optional().describe(`Maximum retries before escalating. Default: 3`),timeout_action:R.enum([`iterate`,`retry`,`manual`,`terminate`]).optional().describe(`Action to take when gate retries are exhausted. Default: manual`),cwd:R.string().optional().describe(`Working directory for evidence map storage (default: server cwd). Use root_path from forge_ground to match.`)},annotations:t.annotations},Y(`evidence_map`,async({action:e,task_id:t,tier:n,claim:r,status:i,receipt:a,id:o,critical_path:s,unknown_type:c,safety_gate:l,retry_count:u,max_retries:d,timeout_action:f,cwd:p})=>{try{switch(e){case`create`:if(!t)throw Error(`task_id required for create`);if(!n)throw Error(`tier required for create`);return ft({action:`create`,taskId:t,tier:n},p),{content:[{type:`text`,text:`Created evidence map "${t}" (tier: ${n}).\n\n---\n_Next: Use \`evidence_map\` with action "add" to record critical-path claims._`}]};case`add`:{if(!t)throw Error(`task_id required for add`);if(!r)throw Error(`claim required for add`);if(!i)throw Error(`status required for add`);let e=ft({action:`add`,taskId:t,claim:r,status:i,receipt:a??``,criticalPath:s,unknownType:c,safetyGate:l},p),n=e.autoCreated?[`⚠️ Evidence map "${t}" was auto-created with tier "standard". Use \`create\` action to set a specific tier.`,``,`Added entry #${e.entry?.id} to "${t}": [${i}] ${r}`]:[`Added entry #${e.entry?.id} to "${t}": [${i}] ${r}`];return e.summary&&n.push(``,e.summary),{content:[{type:`text`,text:n.join(`
187
187
  `)}]}}case`update`:{if(!t)throw Error(`task_id required for update`);if(o===void 0)throw Error(`id required for update`);if(!i)throw Error(`status required for update`);let e=ft({action:`update`,taskId:t,id:o,status:i,receipt:a??``},p),n=[`Updated entry #${o} in "${t}" → ${i}`];return e.summary&&n.push(``,e.summary),{content:[{type:`text`,text:n.join(`
188
188
  `)}]}}case`get`:{if(!t)throw Error(`task_id required for get`);let e=ft({action:`get`,taskId:t},p);return e.state?{content:[{type:`text`,text:[`## Evidence Map: ${t} (${e.state.tier})`,``,e.formattedMap??`No entries.`,``,`_${e.state.entries.length} entries — created ${e.state.createdAt}_`].join(`
189
189
  `)}]}:{content:[{type:`text`,text:`Evidence map "${t}" not found.`}]}}case`gate`:{if(!t)throw Error(`task_id required for gate`);let e=ft({action:`gate`,taskId:t,retryCount:u,maxRetries:d,timeoutAction:f},p);if(!e.gate)return{content:[{type:`text`,text:`Evidence map "${t}" not found.`}]};let n=e.gate,r=[`## FORGE Gate: **${n.verdict}**`,``,`**Reason:** ${n.reason}`,``,`**Stats:** ${n.stats.verified}V / ${n.stats.assumed}A / ${n.stats.unresolved}U (${n.stats.total} total)`];return n.action&&r.push(``,`**Recommended action:** ${n.action}`),n.retriesRemaining!==void 0&&r.push(`**Retries remaining:** ${n.retriesRemaining}`),n.summary&&r.push(``,`**Summary:** ${n.summary}`),n.warnings.length>0&&r.push(``,`**Warnings:**`,...n.warnings.map(e=>`- ⚠️ ${e}`)),n.unresolvedCritical.length>0&&r.push(``,`**Blocking entries:**`,...n.unresolvedCritical.map(e=>`- #${e.id}: ${e.claim} [${e.unknownType??`untyped`}]`)),n.safetyGates&&(r.push(``,`**Safety Gates:**`,`- Provenance: ${n.safetyGates.provenance}`,`- Commitment: ${n.safetyGates.commitment}`,`- Coverage: ${n.safetyGates.coverage}`),n.safetyGates.failures.length>0&&r.push(``,`**Safety failures:**`,...n.safetyGates.failures.map(e=>`- \u{1F6D1} ${e}`))),n.annotation&&r.push(``,`**Annotation:**`,n.annotation),e.formattedMap&&r.push(``,`---`,``,e.formattedMap),r.push(``,`---`,`_Next: ${n.verdict===`YIELD`?`Proceed to implementation.`:n.action===`iterate`?`Re-run the build loop, then evaluate the gate again.`:n.action===`retry`?`Re-evaluate the gate after refreshing evidence.`:n.action===`manual`?`Ask for human review before proceeding.`:`Abort the current path and terminate the task.`}_`),{content:[{type:`text`,text:r.join(`
@@ -2967,12 +2967,8 @@ window.addEventListener('message', function(e) {
2967
2967
  });
2968
2968
  <\/script>`,`</div>`].join(`
2969
2969
  `),css:[[`.present-viewer-container {`,` flex: 1;`,` min-height: 640px;`,` position: relative;`,` border-radius: 0.75rem;`,` overflow: hidden;`,` border: none;`,`}`,`.present-viewer-iframe {`,` border: none;`,` width: 100%;`,` height: 100%;`,` position: absolute;`,` inset: 0;`,` border-radius: inherit;`,`}`].join(`
2970
- `)],islands:[],payload:void 0,nonce:``,generatedAt:new Date().toISOString(),colorScheme:e.colorScheme,lang:e.lang,dir:e.dir,transport:`mcp-app`,exportPolicy:`local-interactive`}))),{content:[{type:`text`,text:[Ym(e,{kind:`rendered`,reason:`no-response-required`}),`If this content doesn't render inline, retry with format: 'browser'.`].join(`
2971
-
2972
- `)}],ui:{type:`resource`,uri:Am}}}catch(t){return th(`VIEWER_RENDER_FAILED`,t instanceof Error?t.message:`Failed to render viewer template`,void 0,e.title)}}function ah(e){try{let t=jr(e,{transport:`mcp-app`,registry:am,blockVendorScripts:hp()}),n=fm(t.vendorScripts,`mcp-app`);return jm=$m(Cr({title:e.title,html:[Jm(e),t.html].filter(Boolean).join(`
2973
- `),css:t.css,islands:t.islands,payload:t.payload,nonce:t.nonce,colorScheme:e.colorScheme,lang:e.lang,dir:e.dir,transport:`mcp-app`,exportPolicy:t.exportPolicy,headScripts:n})),{content:[{type:`text`,text:[Ym(e,{kind:`rendered`,reason:`no-response-required`}),`If this content doesn't render inline, retry with format: 'browser'.`].join(`
2974
-
2975
- `)}],ui:{type:`resource`,uri:Am}}}catch(t){return th(`RENDER_FAILED`,t instanceof Error?t.message:`Failed to render ChannelSurface`,void 0,e.title)}}const oh=R.object({label:R.string(),value:R.string(),description:R.string().optional()}),sh=R.object({id:R.string().describe(`Unique action identifier`),type:R.enum([`button`,`select`,`multi-select`,`form-submit`,`text-submit`,`confirm`,`custom`]).describe(`Interactive action type`),label:R.string().describe(`Visible action label`),variant:R.enum([`primary`,`danger`,`default`]).optional(),options:R.array(oh).optional(),schema:R.record(R.string(),R.unknown()).optional()}),ch=R.object({type:R.string(),title:R.string().optional(),value:R.unknown().optional(),language:R.string().optional()}).catchall(R.unknown()),lh={schemaVersion:R.literal(1).describe(`ChannelSurface schema version. Must be 1.`),title:R.string().describe(`Surface title shown to the user.`),description:R.string().optional().describe(`Optional supporting copy for the surface.`),template:R.string().optional().describe(`Optional template id such as report@1.`),layout:R.object({maxWidth:R.string().optional(),padding:R.string().optional(),columns:R.number().optional()}).optional(),blocks:R.array(ch).optional().describe(`Typed block content for the surface.`),data:R.unknown().optional().describe(`Template data payload, if the template expands data.`),actions:R.array(sh).optional().describe(`Interactive actions. Presence triggers browser transport.`),response:R.object({timeout:R.number().optional(),required:R.boolean().optional()}).optional(),metadata:R.object({surfaceId:R.string().optional(),createdAt:R.string().optional(),source:R.string().optional()}).optional(),colorScheme:R.enum([`light`,`dark`,`auto`]).optional(),lang:R.string().optional(),dir:R.enum([`ltr`,`rtl`,`auto`]).optional()};R.object({surfaceId:R.string(),actionId:R.string(),actionType:R.enum([`button`,`select`,`multi-select`,`form-submit`,`text-submit`,`confirm`,`custom`]),value:R.unknown().optional(),formData:R.record(R.string(),R.unknown()).optional(),selection:R.union([R.string(),R.array(R.string())]).optional(),label:R.string().optional(),timestamp:R.string(),sourceTransport:R.enum([`mcp-app`,`browser`,`export`])});function uh(e,t){let n=G(`present`),r=[`Render a ChannelSurface for the user.`,`Quick ref:`,`- Full schema: aikit://schemas/channel-surface`,`- Required: schemaVersion: 1, title`,`- Content: blocks[] for direct rendering, or template + data for registry-backed rendering`,`- Actions: actions[] of SurfaceAction; interactive surfaces use browser transport and return ChannelOutcome`,`- Optional fields: description, layout, response, metadata, colorScheme, lang, dir`,`- Transports: mcp-app, browser, export`,`- Use schema resource for block enums and action details.`].join(`
2970
+ `)],islands:[],payload:void 0,nonce:``,generatedAt:new Date().toISOString(),colorScheme:e.colorScheme,lang:e.lang,dir:e.dir,transport:`mcp-app`,exportPolicy:`local-interactive`}))),{content:[{type:`text`,text:Ym(e,{kind:`rendered`,reason:`no-response-required`})}],ui:{type:`resource`,uri:Am}}}catch(t){return th(`VIEWER_RENDER_FAILED`,t instanceof Error?t.message:`Failed to render viewer template`,void 0,e.title)}}function ah(e){try{let t=jr(e,{transport:`mcp-app`,registry:am,blockVendorScripts:hp()}),n=fm(t.vendorScripts,`mcp-app`);return jm=$m(Cr({title:e.title,html:[Jm(e),t.html].filter(Boolean).join(`
2971
+ `),css:t.css,islands:t.islands,payload:t.payload,nonce:t.nonce,colorScheme:e.colorScheme,lang:e.lang,dir:e.dir,transport:`mcp-app`,exportPolicy:t.exportPolicy,headScripts:n})),{content:[{type:`text`,text:Ym(e,{kind:`rendered`,reason:`no-response-required`})}],ui:{type:`resource`,uri:Am}}}catch(t){return th(`RENDER_FAILED`,t instanceof Error?t.message:`Failed to render ChannelSurface`,void 0,e.title)}}const oh=R.object({label:R.string(),value:R.string(),description:R.string().optional()}),sh=R.object({id:R.string().describe(`Unique action identifier`),type:R.enum([`button`,`select`,`multi-select`,`form-submit`,`text-submit`,`confirm`,`custom`]).describe(`Interactive action type`),label:R.string().describe(`Visible action label`),variant:R.enum([`primary`,`danger`,`default`]).optional(),options:R.array(oh).optional(),schema:R.record(R.string(),R.unknown()).optional()}),ch=R.object({type:R.string(),title:R.string().optional(),value:R.unknown().optional(),language:R.string().optional()}).catchall(R.unknown()),lh={schemaVersion:R.literal(1).describe(`ChannelSurface schema version. Must be 1.`),title:R.string().describe(`Surface title shown to the user.`),description:R.string().optional().describe(`Optional supporting copy for the surface.`),template:R.string().optional().describe(`Optional template id such as report@1.`),layout:R.object({maxWidth:R.string().optional(),padding:R.string().optional(),columns:R.number().optional()}).optional(),blocks:R.array(ch).optional().describe(`Typed block content for the surface.`),data:R.unknown().optional().describe(`Template data payload, if the template expands data.`),actions:R.array(sh).optional().describe(`Interactive actions. Presence triggers browser transport.`),response:R.object({timeout:R.number().optional(),required:R.boolean().optional()}).optional(),metadata:R.object({surfaceId:R.string().optional(),createdAt:R.string().optional(),source:R.string().optional()}).optional(),colorScheme:R.enum([`light`,`dark`,`auto`]).optional(),lang:R.string().optional(),dir:R.enum([`ltr`,`rtl`,`auto`]).optional()};R.object({surfaceId:R.string(),actionId:R.string(),actionType:R.enum([`button`,`select`,`multi-select`,`form-submit`,`text-submit`,`confirm`,`custom`]),value:R.unknown().optional(),formData:R.record(R.string(),R.unknown()).optional(),selection:R.union([R.string(),R.array(R.string())]).optional(),label:R.string().optional(),timestamp:R.string(),sourceTransport:R.enum([`mcp-app`,`browser`,`export`])});function uh(e,t){let n=G(`present`),r=[`Render a ChannelSurface for the user.`,`Quick ref:`,`- Full schema: aikit://schemas/channel-surface`,`- Required: schemaVersion: 1, title`,`- Content: blocks[] for direct rendering, or template + data for registry-backed rendering`,`- Actions: actions[] of SurfaceAction; interactive surfaces use browser transport and return ChannelOutcome`,`- Optional fields: description, layout, response, metadata, colorScheme, lang, dir`,`- Transports: mcp-app, browser, export`,`- Use schema resource for block enums and action details.`].join(`
2976
2972
  `);pr(e,`present`,{title:n.title,description:r,inputSchema:lh,annotations:n.annotations,_meta:{ui:{resourceUri:Am}}},Y(`present`,async(e,t)=>{let n=nh(e,t);return n.ok?await rh(n.surface,n.options):n.response}));try{fr(e,`Present View`,Am,{description:`AI Kit present tool viewer`},async()=>({contents:[{uri:Am,mimeType:dr,text:Mm()||`<html><body><p>No content generated yet. Call the present tool first.</p></body></html>`}]}))}catch{}try{e.registerResource(`present-templates`,`aikit://present/templates`,{description:`List all registered present viewer templates with their input schemas`},async()=>{let e=Fp().map(e=>({id:e.id,label:e.label,description:e.description,transports:e.supportedTransports,inputSchema:e.inputSchema}));return{contents:[{uri:`aikit://present/templates`,mimeType:`application/json`,text:JSON.stringify(e,null,2)}]}})}catch{}}const dh=F(`tools`);function fh(e,t){let n=new Qn({structure:new er,dependencies:new Yn,symbols:new tr,patterns:new $n,entryPoints:new Zn,diagrams:new Xn}),r=G(`produce_knowledge`);e.registerTool(`produce_knowledge`,{title:r.title,description:`Run automated codebase analysis and produce synthesis instructions. Executes Tier 1 deterministic analyzers, then returns structured baselines and instructions for you to synthesize knowledge using remember.`,inputSchema:{scope:R.string().optional().describe(`Root path to analyze (defaults to workspace root)`),aspects:R.array(R.enum([`all`,`structure`,`dependencies`,`symbols`,`patterns`,`entry-points`,`diagrams`])).default([`all`]).describe(`Which analysis aspects to run`)},annotations:r.annotations},Y(`produce_knowledge`,async({scope:e,aspects:r},i)=>{let a;try{a=Oc(i).createTask(`Produce Knowledge`,3),a.progress(0,`Running analyzers`);let o=e??`.`;dh.info(`Running knowledge production`,{rootPath:o,aspects:r});let s=await n.runExtraction(o,r);try{let e=t?.onboardDir??``;if(!e)throw dh.warn(`onboardDir not configured — skipping artifact persistence.`),Error(`skip`);j(e,{recursive:!0});let n=`<!-- Generated by produce_knowledge at ${new Date().toISOString()} -->\n\n`;for(let[t,r]of Object.entries(s))r&&typeof r==`string`&&he(N(e,`${t}.md`),n+r,`utf-8`);dh.info(`Knowledge persisted to .ai/context/`,{files:Object.keys(s).length})}catch(e){dh.warn(`Failed to persist knowledge to .ai/context/`,{error:I(e)})}a.progress(1,`Synthesizing results`);let c=n.buildSynthesisInstructions(s,r);return a.complete(`Knowledge production complete`),{content:[{type:`text`,text:c+`
2977
2973
 
2978
2974
  ---
@@ -3017,7 +3013,7 @@ Use \`status({})\` to check smart indexing queue status.`}]};let l=Oc(c).createT
3017
3013
  Data matches the schema.`}]};let r=[`## Validation: FAILED`,``,`**${n.errors.length} error(s):**`,``];for(let e of n.errors){let t=e.expected?` (expected: ${e.expected}, got: ${e.received})`:``;r.push(`- \`${e.path}\`: ${e.message}${t}`)}return{content:[{type:`text`,text:r.join(`
3018
3014
  `)}]}}catch(e){return _g.error(`Schema validation failed`,I(e)),J(`INTERNAL`,`Schema validation failed: ${e instanceof Error?e.message:String(e)}`)}}))}function Tg(e){let t=G(`env`);e.registerTool(`env`,{title:t.title,description:`Get system and runtime environment info. Sensitive env vars are redacted by default.`,outputSchema:Ss,inputSchema:{include_env:R.boolean().default(!1).describe(`Include environment variables`),filter_env:R.string().optional().describe(`Filter env vars by name substring`),show_sensitive:R.boolean().default(!1).describe(`Show sensitive values (keys, tokens, etc.) — redacted by default`)},annotations:t.annotations},Y(`env`,async({include_env:e,filter_env:t,show_sensitive:n})=>{let r=ut({includeEnv:e,filterEnv:t,showSensitive:n}),i=[`## Environment`,``,`**Platform:** ${r.system.platform} ${r.system.arch}`,`**OS:** ${r.system.type} ${r.system.release}`,`**Host:** ${r.system.hostname}`,`**CPUs:** ${r.system.cpus}`,`**Memory:** ${r.system.memoryFreeGb}GB free / ${r.system.memoryTotalGb}GB total`,``,`**Node:** ${r.runtime.node}`,`**V8:** ${r.runtime.v8}`,`**CWD:** ${r.cwd}`];if(r.env){i.push(``,`### Environment Variables`,``);for(let[e,t]of Object.entries(r.env))i.push(`- \`${e}\`: ${t}`)}let a={platform:r.system.platform,arch:r.system.arch,nodeVersion:r.runtime.node,cwd:r.cwd,cpus:r.system.cpus,memoryFreeGb:r.system.memoryFreeGb,memoryTotalGb:r.system.memoryTotalGb};return{content:[{type:`text`,text:i.join(`
3019
3015
  `)}],structuredContent:a}}))}function Eg(e){let t=G(`time`);e.registerTool(`time`,{title:t.title,description:`Parse dates, convert timezones, calculate durations, add time. Supports ISO 8601, unix timestamps, and human-readable formats.`,outputSchema:Cs,inputSchema:{operation:R.enum([`now`,`parse`,`convert`,`diff`,`add`]).describe(`now: current time | parse: parse a date string | convert: timezone conversion | diff: duration between two dates | add: add duration to date`),input:R.string().optional().describe(`Date input (ISO, unix timestamp, or parseable string). For diff: two comma-separated dates`),timezone:R.string().optional().describe(`Target timezone (e.g., "America/New_York", "Asia/Tokyo")`),duration:R.string().optional().describe(`Duration to add (e.g., "2h30m", "1d", "30s") — for add operation`)},annotations:t.annotations},Y(`time`,async({operation:e,input:t,timezone:n,duration:r})=>{try{let i=wn({operation:e,input:t,timezone:n,duration:r}),a=[`**${i.output}**`,``,`ISO: ${i.iso}`,`Unix: ${i.unix}`];i.details&&a.push(``,"```json",JSON.stringify(i.details),"```");let o={iso:i.iso,unix:i.unix,timezone:n??Intl.DateTimeFormat().resolvedOptions().timeZone,formatted:i.output};return{content:[{type:`text`,text:a.join(`
3020
- `)}],structuredContent:o}}catch(e){return _g.error(`Time failed`,I(e)),J(`INTERNAL`,`Time failed: ${e instanceof Error?e.message:String(e)}`)}}))}function Dg(e){try{let t=N(e,`.flows`);if(!A(t))return null;let n=ue(t,{withFileTypes:!0});for(let e of n){if(!e.isDirectory())continue;let n=N(t,e.name,`meta.json`);if(A(n)&&JSON.parse(M(n,`utf-8`)).status===`active`)return e.name}}catch{return null}return null}function Og(e,t,n,r,i,a,o,s,c,l){let u=new co,d=n.sources[0]?.path??process.cwd(),f={activeSlug:null};f.activeSlug=Dg(d);let p=new Oa(N(n.stateDir??``,`flow-context`),()=>f.activeSlug),m=new ya;m.register(Ei()),m.register(ga),m.register(Ii),m.register(aa),m.register(Ni),m.register(Di),m.register(Oi),m.register(pa),m.register(Ai),m.register(va),m.register(ia(()=>f.activeSlug?{active:!0,slug:f.activeSlug}:null));let h=new wa(m,t.curated,{},p),g=l??ms(n,[...Bo,...Po],W,Io(n)),_=e=>g.has(e),v=new Set([...g].filter(e=>!Yf.includes(e)&&!Ja.has(e))),y=new Qa;u.use(Sa(h),{order:5,name:`auto-knowledge`}),u.use(Eo(),{order:10,name:`replay`}),u.use(to(y,{stateStore:t.stateStore,curatedStore:t.curated},{trackedTools:v}),{order:94,name:`procedural-memory`}),u.use(Wa(new Ha(t.stateStore,t.curated)),{order:95,name:`observation-capture`}),u.use(Ho(),{order:1,name:`structured-content-guard`}),u.use(Da(Ea(n.tokenBudget)),{order:90,name:`compression`}),$o(e,u,n.toolPrefix??``);let b=[...g].filter(e=>Fo.has(e)?No.includes(e)?!!t.bridge:e===`er_update_policy`?!!t.policyStore:e===`er_evolve_review`?!!t.evolutionCollector:!1:!0);_(`search`)&&Ph(e,t.embedder,t.store,t.graphStore,t.bridge,t.evolutionCollector,a,t.stateStore,n.memory?.retention,n.memory?.consolidation);let x={store:t.store,graphStore:t.graphStore,embedder:t.embedder},S=c?e=>{c()?.prioritize(e)}:void 0;_(`lookup`)&&Rf(e,t.store,x);let C={onboardComplete:t.onboardComplete,onboardTimestamp:t.onboardTimestamp};_(`status`)&&gg(e,t.store,t.graphStore,t.curated,C,n,o,s,t.stateStore),_(`config`)&&ol(e,n),_(`reindex`)&&mh(e,t.indexer,n,t.curated,t.store,i,o),_(`knowledge`)&&If(e,t.curated,t.policyStore,t.evolutionCollector,i,p,t.stateStore,n.memory?.retention,n.memory?.supersession,n.memory?.consolidation,n.memory?.lessons,x),_(`analyze`)&&wc(e,t.store,t.embedder,x),_(`blast_radius`)&&Tc(e,t.store,t.embedder,t.graphStore,x),_(`produce_knowledge`)&&fh(e,n),_(`onboard`)&&tp(e,t.store,t.embedder,n,C,x),_(`graph`)&&Uu(e,t.graphStore,x),_(`audit`)&&Ac(e,t.store,t.embedder,n.tokenBudget),_(`compact`)&&_l(e,t.embedder,t.fileCache,d,n.allRoots,x,S),_(`scope_map`)&&vl(e,t.embedder,t.store,x),_(`find`)&&yl(e,t.embedder,t.store,d,x),_(`parse_output`)&&Nl(e),_(`workset`)&&rp(e),_(`check`)&&Al(e,x,n.tokenBudget),_(`symbol`)&&bl(e,t.embedder,t.store,t.graphStore,x),_(`eval`)&&jl(e),_(`test_run`)&&Ml(e,x),_(`stash`)&&ip(e,t.stateStore),_(`signal`)&&$h(e,t.stateStore),_(`git_context`)&&Hf(e),_(`diff_parse`)&&Uf(e),_(`rename`)&&Wf(e,n),_(`codemod`)&&Gf(e,n),_(`restore`)&&vh(e),_(`file_summary`)&&xl(e,t.fileCache,d,n.allRoots,x,S),_(`checkpoint`)&&ap(e,t.stateStore),_(`data_transform`)&&Kf(e),_(`trace`)&&Sl(e,t.embedder,t.store,t.graphStore,x),_(`process`)&&Gu(e),_(`watch`)&&Ku(e),_(`dead_symbols`)&&Cl(e,t.embedder,t.store,d,n.allRoots,x),_(`delegate`)&&Pl(e,a),_(`health`)&&qu(e),_(`lane`)&&op(e),_(`queue`)&&sp(e),_(`web_fetch`)&&Ju(e),_(`guide`)&&Yu(e,o),Yf.some(e=>_(e))&&Xf(e,n,b),_(`evidence_map`)&&Fu(e),_(`digest`)&&Iu(e,t.embedder),_(`forge_classify`)&&Lu(e,x),_(`stratum_card`)&&Ru(e,t.embedder,t.fileCache),_(`forge_ground`)&&zu(e,t.embedder,t.store),_(`present`)&&uh(e,r),_(`browser`)&&qn(e,n),_(`web_search`)&&vg(e),_(`http`)&&yg(e),_(`regex_test`)&&bg(e),_(`encode`)&&xg(e),_(`measure`)&&Sg(e),_(`changelog`)&&Cg(e),_(`schema_validate`)&&wg(e),_(`env`)&&Tg(e),_(`time`)&&Eg(e),_(`flow`)&&Nu(e,n,e=>{f.activeSlug=e}),t.bridge&&No.some(e=>_(e))&&(Pc(e,t.bridge,t.evolutionCollector),Fc(e,t.bridge),Ic(e,t.bridge)),t.policyStore&&_(`er_update_policy`)&&pp(e,t.policyStore),t.evolutionCollector&&_(`er_evolve_review`)&&Ol(e,t.evolutionCollector),Mo(e,t.store,t.curated),_(`compliance_score`)&&zc(e),_(`replay`)&&gh(e),_(`session_digest`)&&Ih(e,t.stateStore,a)}function kg(e,t,n){let r=e=>!n||n.has(e);r(`check`)&&Al(e,void 0,t.tokenBudget),r(`eval`)&&jl(e),r(`test_run`)&&Ml(e),r(`parse_output`)&&Nl(e),r(`delegate`)&&Pl(e),r(`git_context`)&&Hf(e),r(`diff_parse`)&&Uf(e),r(`rename`)&&Wf(e,t),r(`codemod`)&&Gf(e,t),r(`data_transform`)&&Kf(e),r(`workset`)&&rp(e),r(`restore`)&&vh(e),r(`lane`)&&op(e),r(`queue`)&&sp(e),r(`session_digest`)&&Ih(e),r(`health`)&&qu(e),r(`process`)&&Gu(e),r(`watch`)&&Ku(e),r(`web_fetch`)&&Ju(e),r(`guide`)&&Yu(e),Yf.some(e=>r(e))&&Xf(e,t,[...n??new Set(Bo)]),r(`evidence_map`)&&Fu(e),r(`forge_classify`)&&Lu(e),r(`present`)&&uh(e),r(`browser`)&&qn(e,t),r(`produce_knowledge`)&&fh(e),r(`compliance_score`)&&zc(e),r(`replay`)&&gh(e),r(`status`)&&hg(e),r(`flow`)&&Nu(e,t),r(`web_search`)&&vg(e),r(`http`)&&yg(e),r(`regex_test`)&&bg(e),r(`encode`)&&xg(e),r(`measure`)&&Sg(e),r(`changelog`)&&Cg(e),r(`schema_validate`)&&wg(e),r(`env`)&&Tg(e),r(`time`)&&Eg(e)}const Ag=F(`resource-notifier`);var jg=class{mcpServer;constructor(e){this.mcpServer=e}async notifyStatusChanged(){await this.sendUpdate(`aikit://status`)}async notifyFileTreeChanged(){await this.sendUpdate(`aikit://file-tree`)}async notifyCuratedIndexChanged(){await this.sendUpdate(`aikit://curated`)}async notifyCuratedEntryChanged(e){await this.sendUpdate(`aikit://curated/${e}`)}async notifyResourceListChanged(){try{await this.mcpServer.server.sendResourceListChanged()}catch(e){Ag.debug(`sendResourceListChanged failed`,{error:String(e)})}}async notifyAfterReindex(){await Promise.allSettled([this.notifyStatusChanged(),this.notifyFileTreeChanged()])}async notifyAfterCuratedWrite(e){let t=[this.notifyStatusChanged(),this.notifyCuratedIndexChanged()];e&&t.push(this.notifyCuratedEntryChanged(e)),await Promise.allSettled(t)}async sendUpdate(e){try{await this.mcpServer.server.sendResourceUpdated({uri:e})}catch(t){Ag.debug(`sendResourceUpdated failed`,{uri:e,error:String(t)})}}};const Q=F(`server`);function Mg(e){let t=e?.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`||t===`on`}async function Ng(n){Q.info(`Initializing AI Kit components`);let r=n.store.backend,i=n.store.path,a=Mg(process.env.AIKIT_SPLIT_STATE),o=N(i,`aikit.db`),s={splitEnabled:a,contentDbPath:o,controlDbPath:a?N(i,`aikit-control.db`):o},c=null;if(r===`sqlite-vec`){let e=s.contentDbPath;A(i)||j(i,{recursive:!0}),c=await gr(e),Q.info(`SQLite adapter ready`,{type:c.type,vectorCapable:c.vectorCapable,dbPath:e}),c.vectorCapable||Q.warn(`┌──────────────────────────────────────────────────────────────────┐
3016
+ `)}],structuredContent:o}}catch(e){return _g.error(`Time failed`,I(e)),J(`INTERNAL`,`Time failed: ${e instanceof Error?e.message:String(e)}`)}}))}function Dg(e){try{let t=N(e,`.flows`);if(!A(t))return null;let n=ue(t,{withFileTypes:!0});for(let e of n){if(!e.isDirectory())continue;let n=N(t,e.name,`meta.json`);if(A(n)&&JSON.parse(M(n,`utf-8`)).status===`active`)return e.name}}catch{return null}return null}function Og(e,t,n,r,i,a,o,s,c,l){let u=new co,d=n.sources[0]?.path??process.cwd(),f={activeSlug:null};f.activeSlug=Dg(d);let p=new Oa(N(n.stateDir??``,`flow-context`),()=>f.activeSlug),m=new ya;m.register(Ei()),m.register(ga),m.register(Ii),m.register(aa),m.register(Ni),m.register(Di),m.register(Oi),m.register(pa),m.register(Ai),m.register(va),m.register(ia(()=>f.activeSlug?{active:!0,slug:f.activeSlug}:null));let h=new wa(m,t.curated,{},p),g=l??ms(n,[...Bo,...Po],W,Io(n)),_=e=>g.has(e),v=new Set([...g].filter(e=>!Yf.includes(e)&&!Ja.has(e))),y=new Qa;u.use(Sa(h),{order:5,name:`auto-knowledge`}),u.use(Eo(),{order:10,name:`replay`}),u.use(to(y,{stateStore:t.stateStore,curatedStore:t.curated},{trackedTools:v}),{order:94,name:`procedural-memory`}),u.use(Wa(new Ha(t.stateStore,t.curated)),{order:95,name:`observation-capture`}),u.use(Ho(),{order:1,name:`structured-content-guard`}),u.use(Da(Ea(n.tokenBudget)),{order:90,name:`compression`}),$o(e,u,n.toolPrefix??``);let b=[...g].filter(e=>Fo.has(e)?No.includes(e)?!!t.bridge:e===`er_update_policy`?!!t.policyStore:e===`er_evolve_review`?!!t.evolutionCollector:!1:!0);_(`search`)&&Ph(e,t.embedder,t.store,t.graphStore,t.bridge,t.evolutionCollector,a,t.stateStore,n.memory?.retention,n.memory?.consolidation);let x={store:t.store,graphStore:t.graphStore,embedder:t.embedder},S=c?e=>{c()?.prioritize(e)}:void 0;_(`lookup`)&&Rf(e,t.store,x);let C={onboardComplete:t.onboardComplete,onboardTimestamp:t.onboardTimestamp};_(`status`)&&gg(e,t.store,t.graphStore,t.curated,C,n,o,s,t.stateStore),_(`config`)&&ol(e,n),_(`reindex`)&&mh(e,t.indexer,n,t.curated,t.store,i,o),_(`knowledge`)&&If(e,t.curated,t.policyStore,t.evolutionCollector,i,p,t.stateStore,n.memory?.retention,n.memory?.supersession,n.memory?.consolidation,n.memory?.lessons,x),_(`analyze`)&&wc(e,t.store,t.embedder,x),_(`blast_radius`)&&Tc(e,t.store,t.embedder,t.graphStore,x),_(`produce_knowledge`)&&fh(e,n),_(`onboard`)&&tp(e,t.store,t.embedder,n,C,x),_(`graph`)&&Uu(e,t.graphStore,x),_(`audit`)&&Ac(e,t.store,t.embedder,n.tokenBudget),_(`compact`)&&_l(e,t.embedder,t.fileCache,d,n.allRoots,x,S),_(`scope_map`)&&vl(e,t.embedder,t.store,x),_(`find`)&&yl(e,t.embedder,t.store,d,x),_(`parse_output`)&&Nl(e),_(`workset`)&&rp(e),_(`check`)&&Al(e,x,n.tokenBudget),_(`symbol`)&&bl(e,t.embedder,t.store,t.graphStore,x),_(`eval`)&&jl(e),_(`test_run`)&&Ml(e,x),_(`stash`)&&ip(e,t.stateStore),_(`signal`)&&$h(e,t.stateStore),_(`git_context`)&&Hf(e),_(`diff_parse`)&&Uf(e),_(`rename`)&&Wf(e,n),_(`codemod`)&&Gf(e,n),_(`restore`)&&vh(e),_(`file_summary`)&&xl(e,t.fileCache,d,n.allRoots,x,S),_(`checkpoint`)&&ap(e,t.stateStore),_(`data_transform`)&&Kf(e),_(`trace`)&&Sl(e,t.embedder,t.store,t.graphStore,x),_(`process`)&&Gu(e),_(`watch`)&&Ku(e),_(`dead_symbols`)&&Cl(e,t.embedder,t.store,d,n.allRoots,x),_(`delegate`)&&Pl(e,a),_(`health`)&&qu(e),_(`lane`)&&op(e),_(`queue`)&&sp(e),_(`web_fetch`)&&Ju(e),_(`guide`)&&Yu(e,o),Yf.some(e=>_(e))&&Xf(e,n,b),_(`evidence_map`)&&Fu(e),_(`digest`)&&Iu(e,t.embedder),_(`forge_classify`)&&Lu(e,x),_(`stratum_card`)&&Ru(e,t.embedder,t.fileCache),_(`forge_ground`)&&zu(e,t.embedder,t.store),_(`present`)&&uh(e,r),_(`browser`)&&qn(e,n),_(`web_search`)&&vg(e),_(`http`)&&yg(e),_(`regex_test`)&&bg(e),_(`encode`)&&xg(e),_(`measure`)&&Sg(e),_(`changelog`)&&Cg(e),_(`schema_validate`)&&wg(e),_(`env`)&&Tg(e),_(`time`)&&Eg(e),_(`flow`)&&Nu(e,n,{store:t.store?{search:async(e,n)=>(await t.store.ftsSearch(e,n)).map(e=>({content:e.record.content}))}:null,graphStore:t.graphStore,embedder:t.embedder},e=>{f.activeSlug=e}),t.bridge&&No.some(e=>_(e))&&(Pc(e,t.bridge,t.evolutionCollector),Fc(e,t.bridge),Ic(e,t.bridge)),t.policyStore&&_(`er_update_policy`)&&pp(e,t.policyStore),t.evolutionCollector&&_(`er_evolve_review`)&&Ol(e,t.evolutionCollector),Mo(e,t.store,t.curated),_(`compliance_score`)&&zc(e),_(`replay`)&&gh(e),_(`session_digest`)&&Ih(e,t.stateStore,a)}function kg(e,t,n){let r=e=>!n||n.has(e);r(`check`)&&Al(e,void 0,t.tokenBudget),r(`eval`)&&jl(e),r(`test_run`)&&Ml(e),r(`parse_output`)&&Nl(e),r(`delegate`)&&Pl(e),r(`git_context`)&&Hf(e),r(`diff_parse`)&&Uf(e),r(`rename`)&&Wf(e,t),r(`codemod`)&&Gf(e,t),r(`data_transform`)&&Kf(e),r(`workset`)&&rp(e),r(`restore`)&&vh(e),r(`lane`)&&op(e),r(`queue`)&&sp(e),r(`session_digest`)&&Ih(e),r(`health`)&&qu(e),r(`process`)&&Gu(e),r(`watch`)&&Ku(e),r(`web_fetch`)&&Ju(e),r(`guide`)&&Yu(e),Yf.some(e=>r(e))&&Xf(e,t,[...n??new Set(Bo)]),r(`evidence_map`)&&Fu(e),r(`forge_classify`)&&Lu(e),r(`present`)&&uh(e),r(`browser`)&&qn(e,t),r(`produce_knowledge`)&&fh(e),r(`compliance_score`)&&zc(e),r(`replay`)&&gh(e),r(`status`)&&hg(e),r(`flow`)&&Nu(e,t),r(`web_search`)&&vg(e),r(`http`)&&yg(e),r(`regex_test`)&&bg(e),r(`encode`)&&xg(e),r(`measure`)&&Sg(e),r(`changelog`)&&Cg(e),r(`schema_validate`)&&wg(e),r(`env`)&&Tg(e),r(`time`)&&Eg(e)}const Ag=F(`resource-notifier`);var jg=class{mcpServer;constructor(e){this.mcpServer=e}async notifyStatusChanged(){await this.sendUpdate(`aikit://status`)}async notifyFileTreeChanged(){await this.sendUpdate(`aikit://file-tree`)}async notifyCuratedIndexChanged(){await this.sendUpdate(`aikit://curated`)}async notifyCuratedEntryChanged(e){await this.sendUpdate(`aikit://curated/${e}`)}async notifyResourceListChanged(){try{await this.mcpServer.server.sendResourceListChanged()}catch(e){Ag.debug(`sendResourceListChanged failed`,{error:String(e)})}}async notifyAfterReindex(){await Promise.allSettled([this.notifyStatusChanged(),this.notifyFileTreeChanged()])}async notifyAfterCuratedWrite(e){let t=[this.notifyStatusChanged(),this.notifyCuratedIndexChanged()];e&&t.push(this.notifyCuratedEntryChanged(e)),await Promise.allSettled(t)}async sendUpdate(e){try{await this.mcpServer.server.sendResourceUpdated({uri:e})}catch(t){Ag.debug(`sendResourceUpdated failed`,{uri:e,error:String(t)})}}};const Q=F(`server`);function Mg(e){let t=e?.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`||t===`on`}async function Ng(n){Q.info(`Initializing AI Kit components`);let r=n.store.backend,i=n.store.path,a=Mg(process.env.AIKIT_SPLIT_STATE),o=N(i,`aikit.db`),s={splitEnabled:a,contentDbPath:o,controlDbPath:a?N(i,`aikit-control.db`):o},c=null;if(r===`sqlite-vec`){let e=s.contentDbPath;A(i)||j(i,{recursive:!0}),c=await gr(e),Q.info(`SQLite adapter ready`,{type:c.type,vectorCapable:c.vectorCapable,dbPath:e}),c.vectorCapable||Q.warn(`┌──────────────────────────────────────────────────────────────────┐
3021
3017
  │ ⚠ SQLite vector extension unavailable — DEGRADED MODE │
3022
3018
  │ Vector search is disabled. Hybrid search returns FTS only. │
3023
3019
  │ To enable: install/rebuild better-sqlite3 (native module). │
@@ -1 +1 @@
1
- const e={Orchestrator:[`Claude Opus 4.6 (copilot)`,`GPT-5.4 (copilot)`,`Auto (copilot)`],Planner:[`Claude Opus 4.6 (copilot)`,`GPT-5.4 (copilot)`,`Auto (copilot)`],Implementer:[`GPT-5.4 (copilot)`,`Gemini 3.1 Pro (Preview) (copilot)`,`GPT-5.3-Codex (copilot)`,`Auto (copilot)`],Frontend:[`GPT-5.4 (copilot)`,`Gemini 3.1 Pro (Preview) (copilot)`,`GPT-5.3-Codex (copilot)`,`Auto (copilot)`],Debugger:[`Claude Opus 4.6 (copilot)`,`GPT-5.4 (copilot)`,`GPT-5.3-Codex (copilot)`,`Auto (copilot)`],Refactor:[`GPT-5.4 (copilot)`,`GPT-5.3-Codex (copilot)`,`Auto (copilot)`],Security:[`Claude Opus 4.6 (copilot)`,`GPT-5.4 (copilot)`,`Auto (copilot)`],Documenter:[`GPT-5.4 (copilot)`,`Gemini 3.1 Pro (Preview) (copilot)`,`Auto (copilot)`],Explorer:[`Claude Haiku 4.5 (copilot)`,`Gemini 3 Flash (Preview) (copilot)`,`Auto (copilot)`],"Researcher-Alpha":[`Claude Opus 4.6 (copilot)`,`Auto (copilot)`],"Researcher-Beta":[`Claude Sonnet 4.6 (copilot)`,`Auto (copilot)`],"Researcher-Gamma":[`GPT-5.4 (copilot)`,`Auto (copilot)`],"Researcher-Delta":[`Gemini 3.1 Pro (Preview) (copilot)`,`Auto (copilot)`],"Code-Reviewer-Alpha":[`GPT-5.4 (copilot)`,`Auto (copilot)`],"Code-Reviewer-Beta":[`Claude Opus 4.6 (copilot)`,`Auto (copilot)`],"Architect-Reviewer-Alpha":[`GPT-5.4 (copilot)`,`Auto (copilot)`],"Architect-Reviewer-Beta":[`Claude Opus 4.6 (copilot)`,`Auto (copilot)`]},t=Object.fromEntries(Object.entries(e).map(([e,t])=>[e,(Array.isArray(t)?t[0]:t)?.replace(/ \(copilot\)$/,``)||`Auto`])),n={Researcher:[`Alpha`,`Beta`,`Gamma`,`Delta`],"Code-Reviewer":[`Alpha`,`Beta`],"Architect-Reviewer":[`Alpha`,`Beta`]},r={Researcher:`Alpha`,"Code-Reviewer":`Alpha`,"Architect-Reviewer":`Alpha`};export{t as CLAUDE_MODELS,e as COPILOT_MODELS,r as PRIMARY_VARIANT,n as VARIANT_GROUPS};
1
+ const e={Orchestrator:[`GPT-5.4 mini (copilot)`,`GPT-5.4 (copilot)`,`Auto (copilot)`],Planner:[`Claude Opus 4.6 (copilot)`,`GPT-5.4 (copilot)`,`Auto (copilot)`],Implementer:[`GPT-5.4 mini (copilot)`,`GPT-5.4 (copilot)`,`GPT-5.3-Codex (copilot)`,`Auto (copilot)`],Frontend:[`GPT-5.4 (copilot)`,`Gemini 3.1 Pro (Preview) (copilot)`,`GPT-5.3-Codex (copilot)`,`Auto (copilot)`],Debugger:[`Claude Opus 4.6 (copilot)`,`GPT-5.4 (copilot)`,`GPT-5.3-Codex (copilot)`,`Auto (copilot)`],Refactor:[`GPT-5.4 (copilot)`,`GPT-5.3-Codex (copilot)`,`Auto (copilot)`],Security:[`Claude Opus 4.6 (copilot)`,`GPT-5.4 (copilot)`,`Auto (copilot)`],Documenter:[`GPT-5 mini (copilot)`,`GPT-5.4 mini (copilot)`,`Auto (copilot)`],Explorer:[`GPT-5 mini (copilot)`,`Gemini 3 Flash (Preview) (copilot)`,`Auto (copilot)`],"Researcher-Alpha":[`Claude Opus 4.6 (copilot)`,`Auto (copilot)`],"Researcher-Beta":[`Claude Sonnet 4.6 (copilot)`,`Auto (copilot)`],"Researcher-Gamma":[`GPT-5.4 (copilot)`,`Auto (copilot)`],"Researcher-Delta":[`Gemini 3.1 Pro (Preview) (copilot)`,`Auto (copilot)`],"Code-Reviewer-Alpha":[`GPT-5.4 (copilot)`,`Auto (copilot)`],"Code-Reviewer-Beta":[`Claude Opus 4.6 (copilot)`,`Auto (copilot)`],"Architect-Reviewer-Alpha":[`GPT-5.4 (copilot)`,`Auto (copilot)`],"Architect-Reviewer-Beta":[`Claude Opus 4.6 (copilot)`,`Auto (copilot)`]},t=Object.fromEntries(Object.entries(e).map(([e,t])=>[e,(Array.isArray(t)?t[0]:t)?.replace(/ \(copilot\)$/,``)||`Auto`])),n={Researcher:[`Alpha`,`Beta`,`Gamma`,`Delta`],"Code-Reviewer":[`Alpha`,`Beta`],"Architect-Reviewer":[`Alpha`,`Beta`]},r={Researcher:`Alpha`,"Code-Reviewer":`Alpha`,"Architect-Reviewer":`Alpha`};export{t as CLAUDE_MODELS,e as COPILOT_MODELS,r as PRIMARY_VARIANT,n as VARIANT_GROUPS};
@@ -362,8 +362,8 @@ Verify each before returning handoff:
362
362
 
363
363
  | Priority | Transport | When to use | Example |
364
364
  |----------|-----------|-------------|---------|
365
- | **1st — Interactive** | Browser (\`present\` with \`actions[]\` or template) | Plans, decisions needing approval, comparisons, status boards, any data >3 rows | \`present({ ..., template: "task-plan@1", actions: [...] })\` |
366
- | **2nd — Inline Visual** | MCP App (\`present\` without actions) | Reports, summaries, diagrams, progress updates, any structured content | \`present({ ..., blocks: [...] })\` |
365
+ | **1st — Inline Visual** | MCP App (\`present\` without \`actions[]\`) | Reports, summaries, task plans, progress, status boards, diagrams, any structured content | \`present({ ..., blocks: [...] })\` or \`present({ ..., template: "report@1", data: {...} })\` |
366
+ | **2nd — Interactive** | Browser (\`present\` WITH \`actions[]\`) | ONLY when user approval/input is required: STOP gates, confirmations, selections | \`present({ ..., actions: [{ id: "approve", type: "confirm", label: "Approve?" }] })\` |
367
367
  | **3rd — Plain Text** | Markdown in chat | Short confirmations (≤3 sentences), simple questions, status one-liners | "Done. 3 files updated." |
368
368
 
369
369
  **Rules:**