@donotdev/mcp-server 0.0.10 → 0.0.11
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/dist/index.js +69 -66
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,96 +1,99 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Server as $e}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as
|
|
3
|
-
`);if(
|
|
2
|
+
import{Server as $e}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as we}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as Ee,ListToolsRequestSchema as _e}from"@modelcontextprotocol/sdk/types.js";import{appendFileSync as Ce,readFileSync as v,existsSync as h,readdirSync as M,statSync as Pe,writeFileSync as O,mkdirSync as j}from"fs";import{join as g,resolve as V,normalize as z,sep as ke,basename as ce}from"path";const K=2,le=10;function Te(){let t=process.cwd();for(let n=0;n<le;n++){if(h(g(t,"AI.md"))||h(g(t,".dndev"))||h(g(t,"package.json")))return t;const o=V(t,"..");if(o===t)break;t=o}return process.cwd()}const b=Te(),w=g(b,".dndev"),J=g(w,"protocol.json"),P=g(w,"LESSONS.md"),B=g(w,"implementation.md"),Y=g(w,"captain-log.json"),pe=g(w,"args.json"),Le=g(b,"docs","architecture"),W=g(b,"packages","cli","templates","root-consumer","guides","dndev"),A=[{id:0,name:"BRAINSTORM",agent:"extractor",blueprint:"0_brainstorm",agentFile:"extractor"},{id:1,name:"SCAFFOLD",agent:"extractor",blueprint:"1_scaffold",agentFile:"extractor"},{id:2,name:"ENTITIES",agent:"architect",blueprint:"2_entities",agentFile:"architect"},{id:3,name:"COMPOSE",agent:"builder",blueprint:"3_compose",agentFile:"builder"},{id:4,name:"CONFIGURE",agent:"polisher",blueprint:"4_configure",agentFile:"polisher"}],G={version:K,currentPhase:null,phaseName:null,agent:null,startedAt:null,completedPhases:[],lookedUpSymbols:[],pendingReview:!1,currentModule:null};function k(){if(!h(J))return{...G,completedPhases:[],lookedUpSymbols:[]};try{const t=JSON.parse(v(J,"utf-8"));return t.version!==K?{...G,completedPhases:[],lookedUpSymbols:[]}:{...G,...t}}catch{return{...G,completedPhases:[],lookedUpSymbols:[]}}}function I(t){h(w)||j(w,{recursive:!0}),O(J,JSON.stringify(t,null,2))}function Ie(t){const n=k();n.toolCallCounts||(n.toolCallCounts={}),n.toolCallCounts[t]=(n.toolCallCounts[t]??0)+1,I(n)}function Re(){const t=k();t.lessonsRecorded=(t.lessonsRecorded??0)+1,I(t)}function Oe(t){const n=k();n.lessonsScored||(n.lessonsScored={helpful:0,harmful:0}),n.lessonsScored[t]++,I(n)}function ue(){const t=k();if((t.toolCallCounts?Object.values(t.toolCallCounts).reduce((e,i)=>e+i,0):0)===0)return;const l={id:F().sessions.length+1,date:new Date().toISOString().split("T")[0],phase:t.currentPhase??-1,phase_name:t.phaseName||"ad-hoc",module:t.currentModule||void 0,started_at:t.startedAt||new Date().toISOString(),completed_at:new Date().toISOString(),outcome:t.pendingLogData?.summary||(t.currentPhase!==null?`Phase ${t.currentPhase} (${t.phaseName}) \u2014 session ended without approval`:"Ad-hoc session"),files_touched:t.pendingLogData?.files_touched||0,symbols_used:t.lookedUpSymbols?.length||0,tool_calls:t.toolCallCounts&&Object.keys(t.toolCallCounts).length>0?t.toolCallCounts:void 0,lessons_recorded:t.lessonsRecorded||void 0,lessons_scored:t.lessonsScored&&(t.lessonsScored.helpful>0||t.lessonsScored.harmful>0)?t.lessonsScored:void 0,validation:t.pendingLogData?.validation};ge(l),t.toolCallCounts=void 0,t.lessonsRecorded=void 0,t.lessonsScored=void 0,t.pendingLogData=void 0,I(t)}process.on("exit",()=>{try{ue()}catch{}}),process.on("SIGINT",()=>{process.exit(0)}),process.on("SIGTERM",()=>{process.exit(0)});const X={platform:"firebase",strictness:"enforced",features:["crud","auth","i18n","billing","oauth","functions"],region:"europe-west1"};function de(){if(!h(pe))return{...X};try{const t=JSON.parse(v(pe,"utf-8"));return{...X,...t}}catch{return{...X}}}function Ae(){const t=ne();if(!t)return[];let n=null;for(const i of["GOTCHAS.md","GOTCHAS.md.example"]){const r=g(t,i);if(h(r)){n=r;break}}if(!n)return[];const o=v(n,"utf-8"),l=[],e=o.split(/^## /m);for(const i of e){if(!i.trim())continue;const r=i.indexOf(`
|
|
3
|
+
`);if(r===-1)continue;const s=i.substring(0,r).trim(),a=i.substring(r+1).trim(),c=s.match(/\[Phase\s+([\d,\s]+)\]/i),p=[];if(c?.[1])for(const d of c[1].split(",")){const u=parseInt(d.trim());isNaN(u)||p.push(u)}p.length>0&&a&&l.push({title:s.replace(/\s*\[Phase.*?\]/,""),phases:p,content:a})}return l}function Ne(t,n){const o=Ae();if(o.length===0)return"";const l=o.filter(r=>r.phases.includes(t));if(l.length===0)return"";const e={CRUD:"crud",Functions:"functions",i18n:"i18n"},i=n?l.filter(r=>{const s=e[r.title];return!s||n.includes(s)}):l;return i.length===0?"":i.map(r=>`### ${r.title}
|
|
4
4
|
|
|
5
|
-
${
|
|
5
|
+
${r.content}`).join(`
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
`)}function
|
|
10
|
-
`),l=[];for(const i of
|
|
11
|
-
`).trim();return!
|
|
12
|
-
- [${
|
|
13
|
-
`+
|
|
14
|
-
`);let
|
|
15
|
-
`)),{found:
|
|
16
|
-
`))c.startsWith("LH:")&&(l+=parseInt(c.slice(3))||0),c.startsWith("LF:")&&(
|
|
17
|
-
${
|
|
9
|
+
`)}function Fe(t){const n=z(b)+ke,o=z(V(b,t));return!o.startsWith(n)&&o!==z(b)?null:o}const Ue=90,De=4,je=.15;function fe(t){const n=t.match(/\{helpful:(\d+),harmful:(\d+),lastSeen:([^,}]+)(?:,status:([^}]+))?\}$/);return n?{helpful:parseInt(n[1]),harmful:parseInt(n[2]),lastSeen:n[3],status:n[4]||"candidate"}:{helpful:0,harmful:0,lastSeen:null,status:"candidate"}}function Me(t){if(t.lastSeen===null)return .5;const n=(Date.now()-new Date(t.lastSeen).getTime())/(1e3*60*60*24),o=Math.pow(.5,n/Ue),l=t.helpful-t.harmful*De;return(l>=0?.5+Math.min(l/10,.5):Math.max(.1,.5+l/10))*o}function Be(t){const n=t.helpful+t.harmful;if(n===0)return"candidate";const o=t.harmful/n;return o>.5&&t.harmful>=3?"anti-pattern":o>.25?"deprecated":t.helpful>=10&&o<.1?"proven":t.helpful>=3&&o<.25?"established":"candidate"}function Z(t){return t.replace(/\s*\{helpful:\d+,harmful:\d+,lastSeen:[^}]+\}$/,"")}function We(t,n){return`${Z(t)} {helpful:${n.helpful},harmful:${n.harmful},lastSeen:${n.lastSeen},status:${n.status}}`}function Ge(t){if(!h(P))return"";const n=v(P,"utf-8");if(!t)return n;const o=n.split(`
|
|
10
|
+
`),l=[];for(const i of o){if(!i.startsWith("- [")){l.push(i);continue}const r=fe(i);if(Me(r)<je||r.status==="deprecated")continue;const a=i.match(/\[Phase (\d+):/),c=a?parseInt(a[1]):null,d=[...i.matchAll(/\[([^\]]*)\]/g)].map(f=>f[1]).filter(f=>!/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(f)&&!/^Phase \d+:/.test(f)&&!/^\d{4}-\d{2}-\d{2}$/.test(f)).flatMap(f=>f.split(",").map($=>$.trim().toLowerCase())).filter(Boolean),u=d.length===0,m=t.phase!==void 0&&c!==null&&(c===t.phase||c===t.phase-1),y=!!t.module&&d.includes(t.module.toLowerCase());if(u||m||y)if(r.status==="anti-pattern"){const f=Z(i),$=f.replace(/^- \[[^\]]*\](\[[^\]]*\])*\s*/,""),T=f.substring(0,f.length-$.length);l.push(`${T}PITFALL: ${$}`)}else l.push(Z(i))}const e=l.join(`
|
|
11
|
+
`).trim();return!e||e==="# Lessons Learned"?"":e}function me(t,n="",o){const l=o&&o.length>0?`[${o.join(", ")}]`:"",e=new Date().toISOString().split("T")[0],i=` {helpful:0,harmful:0,lastSeen:${e},status:candidate}`,r=`
|
|
12
|
+
- [${e}]${n}${l} ${t}${i}`;try{h(w)||j(w,{recursive:!0}),h(P)?Ce(P,r):O(P,`# Lessons Learned
|
|
13
|
+
`+r)}catch(s){const a=s instanceof Error?s.message:String(s);throw new Error(`Failed to write lesson: ${a}`)}}function He(t,n){if(!h(P))return{found:!1,newStatus:""};const l=v(P,"utf-8").split(`
|
|
14
|
+
`);let e=!1,i="";for(let r=0;r<l.length;r++){if(!l[r].startsWith("- [")||!l[r].toLowerCase().includes(t.toLowerCase()))continue;const s=fe(l[r]),a=new Date().toISOString().split("T")[0];n==="helpful"?s.helpful++:s.harmful++,s.lastSeen=a;const c=Be(s);i=c,l[r]=We(l[r],{helpful:s.helpful,harmful:s.harmful,lastSeen:a,status:c}),e=!0;break}return e&&O(P,l.join(`
|
|
15
|
+
`)),{found:e,newStatus:i}}const Q=g(w,"coverage-baseline.json");function qe(){const t=g(b,"coverage","coverage-summary.json");if(h(t))try{const l=JSON.parse(v(t,"utf-8")).total;if(l)return{lines:l.lines?.pct??0,branches:l.branches?.pct??0,functions:l.functions?.pct??0}}catch{}const n=g(b,"coverage","lcov.info");if(!h(n))return null;try{const o=v(n,"utf-8");let l=0,e=0,i=0,r=0,s=0,a=0;for(const c of o.split(`
|
|
16
|
+
`))c.startsWith("LH:")&&(l+=parseInt(c.slice(3))||0),c.startsWith("LF:")&&(e+=parseInt(c.slice(3))||0),c.startsWith("BRH:")&&(i+=parseInt(c.slice(4))||0),c.startsWith("BRF:")&&(r+=parseInt(c.slice(4))||0),c.startsWith("FNH:")&&(s+=parseInt(c.slice(4))||0),c.startsWith("FNF:")&&(a+=parseInt(c.slice(4))||0);return{lines:e>0?l/e*100:0,branches:r>0?i/r*100:0,functions:a>0?s/a*100:0}}catch{return null}}function Ve(){if(!h(Q))return null;try{return JSON.parse(v(Q,"utf-8"))}catch{return null}}function he(t){h(w)||j(w,{recursive:!0});const n={...t,timestamp:new Date().toISOString()};O(Q,JSON.stringify(n,null,2))}function ze(){const t=qe();if(!t)return null;const n=Ve();if(!n)return he(t),`- Coverage baseline set: ${t.lines.toFixed(1)}% lines, ${t.branches.toFixed(1)}% branches, ${t.functions.toFixed(1)}% functions`;const o=[];return t.lines<n.lines-.5&&o.push(`Lines: ${t.lines.toFixed(1)}% (was ${n.lines.toFixed(1)}%)`),t.branches<n.branches-.5&&o.push(`Branches: ${t.branches.toFixed(1)}% (was ${n.branches.toFixed(1)}%)`),t.functions<n.functions-.5&&o.push(`Functions: ${t.functions.toFixed(1)}% (was ${n.functions.toFixed(1)}%)`),o.length>0?`- BLOCKED: Test coverage decreased:
|
|
17
|
+
${o.join(`
|
|
18
18
|
`)}
|
|
19
|
-
Run tests with coverage and add tests for new code.`:(
|
|
20
|
-
`),l=[];let
|
|
21
|
-
`):
|
|
22
|
-
`)}function
|
|
23
|
-
`);let
|
|
24
|
-
`),t=e.split("/").pop()||"";if(!t.endsWith(".tsx")&&!t.endsWith(".ts"))return[];for(let o=0;o<l.length;o++){const r=l[o],a=o+1;/style\s*=\s*\{\{/.test(r)&&n.push(`L${a}: Inline style found. Use className or framework utilities.`),/fontSize|font-size/i.test(r)&&!/\/\/|\/\*|\*/.test(r.trimStart().substring(0,2))&&n.push(`L${a}: fontSize detected. Use Text level or Card title/subtitle props.`),/text-align:\s*(left|right)|textAlign:\s*['"]?(left|right)/i.test(r)&&n.push(`L${a}: textAlign left/right detected. Use start/end for RTL support.`),/\brequire\s*\(/.test(r)&&!/\/\/|\/\*|\*/.test(r.trimStart().substring(0,2))&&n.push(`L${a}: require() found. Use ESM import.`),/\.toLocaleDateString|\.toLocaleTimeString|new Intl\.DateTimeFormat/i.test(r)&&n.push(`L${a}: Manual date formatting. Use formatDate() from @donotdev/core.`),/@donotdev\//.test(s)&&/(?:gap|spacing|size)=["'](?:xs|sm|md|lg|xl|2xl)["']/.test(r)&&n.push(`L${a}: Invalid size token. DoNotDev uses none/tight/medium/large \u2014 not xs/sm/md/lg/xl.`)}const i=l.map((o,r)=>({line:o,num:r+1})).filter(({line:o})=>/^import\s/.test(o));if(i.length>1){let o=0;for(const{line:r,num:a}of i){let c=4;if(/from\s+['"]react/.test(r)?c=1:/from\s+['"]@donotdev\//.test(r)?c=3:/from\s+['"][^.]/.test(r)&&(c=2),c<o){n.push(`L${a}: Import order violation. Expected: React > vendors > @donotdev > relative.`);break}o=c}}return n}function nt(e,n){const s=[],l=/<([A-Z]\w+)/g;for(const t of e){if(!h(t))continue;const i=$(t,"utf-8");if(!/@donotdev\//.test(i))continue;const o=i.matchAll(l);for(const r of o){const a=r[1];a&&(["React","Fragment","Suspense","Provider","Router","Route","Switch"].includes(a)||!n.includes(a)&&!n.includes(`${a}Props`)&&s.push(`${t}: <${a}> used but lookup_symbol("${a}") was never called. Props may be hallucinated.`))}}return[...new Set(s)]}const oe=new $e({name:"donotdev-mcp",version:"0.0.6"},{capabilities:{tools:{}}});oe.setRequestHandler(ve,async()=>({tools:[{name:"start_phase",description:"Begin a WAI-WAY phase (0-4). Returns blueprint, agent definition, context, and lessons. For large projects, pass module to scope work.",inputSchema:{type:"object",properties:{phase:{type:"number",description:"Phase number: 0=BRAINSTORM, 1=SCAFFOLD, 2=ENTITIES, 3=COMPOSE, 4=CONFIGURE"},module:{type:"string",description:'Optional module name to scope work (e.g., "user-management", "billing"). For large projects.'}},required:["phase"]}},{name:"complete_phase",description:"Validate and submit phase for user review. Pass files to run convention checks and symbol verification. Phase stays pending until user calls approve_phase.",inputSchema:{type:"object",properties:{files:{type:"array",items:{type:"string"},description:"File paths to validate (relative to project root). Convention checks + symbol usage verification run automatically."},lesson:{type:"string",description:"Optional lesson learned during this phase"},summary:{type:"string",description:`Brief outcome summary for the captain's log (e.g., "8 pages scaffolded, auth flow complete")`}}}},{name:"approve_phase",description:"User approves the completed phase after review. Only call this after complete_phase and user has confirmed the output is correct.",inputSchema:{type:"object",properties:{}}},{name:"get_phase_status",description:"Get current WAI-WAY phase, completed phases, active agent, lookup coverage, and pending review status.",inputSchema:{type:"object",properties:{}}},{name:"lookup_symbol",description:"Get JSDoc context, @examples, and TypeScript types for any DoNotDev symbol. MUST be called before using any @donotdev component.",inputSchema:{type:"object",properties:{symbol:{type:"string",description:'Symbol name (e.g., "defineEntity", "useCrud", "DataTable")'},package:{type:"string",description:"Package name (optional)"}},required:["symbol"]}},{name:"get_guide",description:"Fetch a framework setup guide from guides/dndev/ (e.g., CRUD setup, Auth setup).",inputSchema:{type:"object",properties:{topic:{type:"string",description:'Topic (e.g., "CRUD", "AUTH")'}},required:["topic"]}},{name:"get_guideline",description:"Fetch architectural guidelines for maintenance or app building.",inputSchema:{type:"object",properties:{topic:{type:"string",description:'Topic with optional section (e.g., "styling", "styling:colors")'}},required:["topic"]}},{name:"search_framework",description:"Search across ALL guides and public symbols for a keyword.",inputSchema:{type:"object",properties:{query:{type:"string",description:"Keyword or phrase"}},required:["query"]}},{name:"list_features",description:"List all framework packages with a one-line summary from each README. Call in Phase 0 before designing custom solutions.",inputSchema:{type:"object",properties:{}}},{name:"init_implementation",description:"Create .dndev/implementation.md to track progress across sessions. Pass sections manually or use from_spec to auto-generate from spec_template.md.",inputSchema:{type:"object",properties:{sections:{type:"array",items:{type:"object",properties:{title:{type:"string",description:'Section heading (e.g., "Phase 1: SCAFFOLD", "Auth Module")'},items:{type:"array",items:{type:"string"},description:"Checklist items for this section"}},required:["title","items"]},description:"Manual sections with checklist items"},from_spec:{type:"boolean",description:"Auto-generate sections from spec_template.md (entities \u2192 Phase 2, pages \u2192 Phase 1/3)"},force:{type:"boolean",description:"Overwrite existing implementation.md without warning"}}}},{name:"update_progress",description:"Tick or untick an item in .dndev/implementation.md. Matches by substring. Optionally add a note.",inputSchema:{type:"object",properties:{item:{type:"string",description:'Substring to match the checklist item (e.g., "HomePage", "Product entity")'},done:{type:"boolean",description:"true = tick [x], false = untick [ ]"},note:{type:"string",description:"Optional note appended to the Notes section"}},required:["item","done"]}},{name:"get_progress",description:"Read .dndev/implementation.md with progress stats. Optionally filter to a section.",inputSchema:{type:"object",properties:{section:{type:"string",description:'Filter to section containing this text (e.g., "Phase 1", "SCAFFOLD")'}}}},{name:"get_project_history",description:"Get the captain's log: full session history with metrics. For post-mortem, team review, and project analysis.",inputSchema:{type:"object",properties:{}}},{name:"run_typecheck",description:"Run TypeScript type-check on the consumer project. Returns structured results. Run after every code change.",inputSchema:{type:"object",properties:{package:{type:"string",description:"Optional: scope to a specific app/package name or path fragment"}}}},{name:"record_lesson",description:"Record a lesson/gotcha to .dndev/LESSONS.md with inline tags. Filtered by phase + module on next start_phase. Also add a code comment where the gotcha applies.",inputSchema:{type:"object",properties:{lesson:{type:"string",description:"The lesson content (gotcha, quirk, operational knowledge)"},tags:{type:"array",items:{type:"string"},description:'Tags for filtering: entity names, service names, module names (e.g., ["stripe", "billing", "webhook"])'}},required:["lesson"]}},{name:"score_lesson",description:"Score a lesson as helpful or harmful. Updates confidence metadata. Lessons decay over time (half-life: 90 days). High harmful ratio auto-converts to anti-pattern.",inputSchema:{type:"object",properties:{lesson:{type:"string",description:'Substring to match the lesson (e.g., "Zustand store actions", "use client directive")'},outcome:{type:"string",enum:["helpful","harmful"],description:"Whether this lesson helped or harmed the current task"}},required:["lesson","outcome"]}},{name:"setup_coach",description:"Get contextual setup instructions for a specific manual step. Reads from guide files \u2014 never accesses .env or secrets. Returns markdown coaching for dashboard-click steps.",inputSchema:{type:"object",properties:{topic:{type:"string",description:'Setup topic (e.g., "stripe-webhook", "oauth-google", "firebase-service-account", "supabase-credentials")'},provider:{type:"string",description:"Optional provider context (firebase, supabase, vercel, stripe)"},projectId:{type:"string",description:"Optional project ID for generating console URLs (public, not a secret)"},region:{type:"string",description:'Optional Firebase Cloud Functions region (e.g., "europe-west1", "us-central1"). Defaults to europe-west1.'}},required:["topic"]}}]}));function w(e,n){if(typeof e!="string")throw new Error(`Expected "${n}" to be a string, got ${typeof e}`)}function st(e,n){if(typeof e!="number"||!Number.isFinite(e))throw new Error(`Expected "${n}" to be a number, got ${typeof e}`)}function ot(e,n){if(typeof e!="boolean")throw new Error(`Expected "${n}" to be a boolean, got ${typeof e}`)}function ye(e,n){if(!Array.isArray(e)||e.some(s=>typeof s!="string"))throw new Error(`Expected "${n}" to be a string array`)}oe.setRequestHandler(be,async e=>{try{const{name:n,arguments:s}=e.params,l=Ye();if(n!=="start_phase"&&n!=="approve_phase"&&Le(n),n==="start_phase"){le(),st(s?.phase,"phase");const t=s.phase,i=s?.module!=null?(w(s.module,"module"),s.module):void 0,o=O.find(y=>y.id===t);if(!o)return{content:[{type:"text",text:`Invalid phase: ${t}. Valid: 0-4.`}],isError:!0};const r=te();if(!r)return{content:[{type:"text",text:"Error: guides/wai-way/ directory not found."}],isError:!0};const a=ne(g(r,"blueprints"),o.blueprint),c=ne(g(r,"agents"),o.agentFile),u=ge(r,t),p=Me({phase:t,module:i}),d=C();d.version=V,d.currentPhase=o.id,d.phaseName=o.name,d.agent=o.agent,d.startedAt=new Date().toISOString(),d.lookedUpSymbols=[],d.pendingReview=!1,d.currentModule=i||null,d.toolCallCounts=void 0,d.lessonsRecorded=void 0,d.lessonsScored=void 0,R(d);const f=[`# Phase ${o.id}: ${o.name}`,`**Agent:** ${o.agent}`];i&&f.push(`**Module:** ${i}`);const S=d.completedPhases.sort().map(y=>{const E=O.find(k=>k.id===y);return E?E.name:`${y}`}),m=N(),v=m?I(m):null,T=F(),_=[`
|
|
25
|
-
|
|
26
|
-
## Phase
|
|
19
|
+
Run tests with coverage and add tests for new code.`:(he(t),null)}function N(){return h(B)?v(B,"utf-8"):null}function ee(t){h(w)||j(w,{recursive:!0}),O(B,t)}function R(t,n){const o=t.split(`
|
|
20
|
+
`),l=[];let e=null,i=0,r=0;for(const a of o)/^###?\s/.test(a)&&!a.startsWith("# Implementation")&&(e&&l.push(e),e={title:a.replace(/^#+\s*/,""),total:0,done:0}),/^\s*- \[x\]/i.test(a)?(i++,r++,e&&e.done++,e&&e.total++):/^\s*- \[ \]/.test(a)&&(r++,e&&e.total++);e&&l.push(e);let s=t;if(n){const a=n.toLowerCase(),c=[];let p=!1;for(const d of o)/^###?\s/.test(d)&&(p=d.toLowerCase().includes(a)),p&&c.push(d);s=c.length>0?c.join(`
|
|
21
|
+
`):t}return{stats:{total:r,done:i,pending:r-i,percent:r>0?Math.round(i/r*100):0},sections:l.filter(a=>a.total>0),filtered:s}}function Ke(t){const n=["# Implementation Progress","",`**Last updated:** ${new Date().toISOString()}`,"**Current phase:** 0 - BRAINSTORM",""];for(const o of t){n.push(`### ${o.title}`);for(const l of o.items)n.push(`- [ ] ${l}`);n.push("")}return n.push("## Notes",""),n.join(`
|
|
22
|
+
`)}function Je(){const t=oe();if(!t)return null;const n=se(t,"spec_template");if(!n)return null;const o=[{title:"Phase 0: BRAINSTORM",items:["Spec complete","User validated"]}],l=n.matchAll(/### Entity:\s*\[?(\w+)\]?/g),e=[];for(const s of l)s[1]&&s[1]!=="Name"&&e.push(s[1]);const i=n.matchAll(/\|\s*`?\/[\w-]*`?\s*\|\s*(\w+Page)\s*\|/g),r=[];for(const s of i)s[1]&&r.push(s[1]);return o.push({title:"Phase 1: SCAFFOLD",items:r.length>0?r.map(s=>`${s}.tsx`):["(generate from validated spec)"]}),o.push({title:"Phase 2: ENTITIES",items:e.length>0?e.map(s=>`${s} entity`):["(generate from validated spec)"]}),o.push({title:"Phase 3: COMPOSE",items:r.length>0?r.map(s=>`${s} composition`):["(generate from validated spec)"]}),o.push({title:"Phase 4: CONFIGURE",items:["Tests generated","Firestore rules","Config finalized","Mobile check"]}),o}function Ye(t,n){const o=N();if(!o)return;const l=o.replace(/\*\*Current phase:\*\*\s*.*/,`**Current phase:** ${t} - ${n}`);l!==o&&ee(l.replace(/\*\*Last updated:\*\*\s*.*/,`**Last updated:** ${new Date().toISOString()}`))}function F(){if(!h(Y))return{project:ce(b)||"unknown",started:new Date().toISOString().split("T")[0],sessions:[]};try{return JSON.parse(v(Y,"utf-8"))}catch{return{project:ce(b)||"unknown",started:new Date().toISOString().split("T")[0],sessions:[]}}}function ge(t){const n=F();n.sessions.push(t),h(w)||j(w,{recursive:!0}),O(Y,JSON.stringify(n,null,2))}const te=["@donotdev/core","@donotdev/ui","@donotdev/components","@donotdev/templates","@donotdev/crud","@donotdev/auth","@donotdev/billing","@donotdev/oauth","@donotdev/components","@donotdev/firebase","@donotdev/supabase","@donotdev/functions","@donotdev/security","@donotdev/expo","@donotdev/mcp-server"],Xe=["@donotdev/cli"],Ze=[...te,...Xe];function Qe(){let t=b;for(let n=0;n<le;n++){const o=g(t,"node_modules");if(h(o))return o;const l=V(t,"..");if(l===t)break;t=l}return null}function ne(){const t=g(b,"guides","dndev");return h(t)?t:h(W)?W:null}function oe(){const t=g(b,"guides","wai-way");if(h(t))return t;const n=g(b,"packages","cli","templates","root-consumer","guides","wai-way");return h(n)?n:null}function se(t,n){for(const o of[".md",".md.example"]){const l=g(t,n+o);if(h(l))return v(l,"utf-8")}return null}function re(t,n=5){const o=[];if(!h(t)||n<=0)return o;const l=M(t);for(const e of l){const i=g(t,e);try{Pe(i).isDirectory()?o.push(...re(i,n-1)):e.endsWith(".d.ts")&&o.push(i)}catch{}}return o}function ye(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function et(t,n){let o=0,l=-1;for(let e=n;e<t.length;e++)if(t[e]==="{")o===0&&(l=e),o++;else if(t[e]==="}"&&(o--,o===0))return t.slice(l,e+1);return""}function tt(t,n){const o=ye(n),e=new RegExp(`(\\/\\*\\*[\\s\\S]*?\\*\\/\\s*)?(?:export\\s+)?(?:declare\\s+)?(?:interface|type|const|function|class)\\s+${o}\\b`,"g").exec(t);if(!e)return null;const i=e.index,r=e.index+e[0].length,s=t.slice(r),a=s.indexOf("{"),c=s.indexOf(";");if(c!==-1&&(a===-1||c<a))return t.slice(i,r+c+1).trim();if(a!==-1){const p=et(t,r+a);if(p)return t.slice(i,r+a+p.length).trim()}return null}function nt(t){const n=[],o=t.matchAll(/export\s*\{([^}]+)\}/g);for(const s of o)if(s[1]){const a=s[1].split(",").map(c=>{const p=c.trim().split(/\s+as\s+/);return(p.length>1?p[1]:p[0])?.trim()}).filter(c=>!!c);n.push(...a)}const l=t.matchAll(/export\s+interface\s+(\w+)/g);for(const s of l)s[1]&&n.push(s[1]);const e=t.matchAll(/export\s+type\s+(\w+)/g);for(const s of e)s[1]&&n.push(s[1]);const i=t.matchAll(/export\s+const\s+(\w+)/g);for(const s of i)s[1]&&n.push(s[1]);const r=t.matchAll(/export\s+default\s+(\w+)/g);for(const s of r)s[1]&&n.push(s[1]);return[...new Set(n)].filter(s=>s&&s!=="default")}function ot(t){if(!h(t))return null;try{const n=v(t,"utf-8").split(`
|
|
23
|
+
`);let o=!1;for(const l of n){if(l.startsWith("# ")){o=!0;continue}if(o&&l.trim().length>0)return l.trim()}}catch{}return null}function Se(t,n){const o=h(g(t,"context_map.json"))?g(t,"context_map.json"):g(t,"context_map.json.example");if(!h(o))return null;try{const l=JSON.parse(v(o,"utf-8")),i=Object.keys(l.phases||{}).find(r=>r.startsWith(`${n}_`));if(i&&l.phases[i])return l.phases[i]}catch{}return null}const xe={div:"Stack, Card, Section, or Box from @donotdev/components",span:"Text from @donotdev/components",p:"Text from @donotdev/components",h1:"Text level={1} from @donotdev/components",h2:"Text level={2} from @donotdev/components",h3:"Text level={3} from @donotdev/components",h4:"Text level={4} from @donotdev/components",h5:"Text level={5} from @donotdev/components",h6:"Text level={6} from @donotdev/components",button:"Button from @donotdev/components",a:"Link from @donotdev/components",input:"TextInput from @donotdev/components",textarea:"TextInput multiline from @donotdev/components",select:"Select from @donotdev/components",form:"Form from @donotdev/components",table:"DataTable from @donotdev/crud",tr:"DataTable from @donotdev/crud",td:"DataTable from @donotdev/crud",th:"DataTable from @donotdev/crud",ul:"List from @donotdev/components",ol:"List ordered from @donotdev/components",li:"List.Item from @donotdev/components",img:"Image from @donotdev/components",section:"Section from @donotdev/components",nav:"Navigation from @donotdev/ui",header:"Header from @donotdev/ui",footer:"Footer from @donotdev/ui"},gt=Object.keys(xe),st=[{prop:"size",components:["Button","Text","Icon","Card","Stack","Badge"],message:"`size` is not a framework prop. Use `level` for Text, no size prop for Button/Card."},{prop:"tone",components:["Button","Text","Badge","Alert"],message:"`tone` is not a framework prop. Use `variant` instead."},{prop:"color",components:["Button","Text","Icon","Badge","Card"],message:"`color` is not a framework prop. Colors come from theme/variant, not inline props."},{prop:"padding",components:["Card","Stack","Section","Box"],message:"`padding` is not a framework prop. Use `spacing` tokens or framework layout props."},{prop:"margin",components:["Card","Stack","Section","Box","Button","Text"],message:"`margin` is not a framework prop. Use `gap` on parent Stack or layout spacing."},{prop:"spacing",components:["Card","Section","Box"],message:"`spacing` is not a prop on this component. Use `gap` on Stack or framework layout."},{prop:"columns",components:["DataTable","Grid","List"],message:"`columns` is not a framework prop. Check lookup_symbol for the correct prop name."},{prop:"background",components:["Card","Section","Box","Stack"],message:"`background` is not a framework prop. Use `variant` or theme tokens."},{prop:"fields",components:["Form","DataTable","Card"],message:"`fields` is not a framework prop. Check lookup_symbol for the correct prop name."}],rt=["bg-","text-","p-","px-","py-","pt-","pb-","pl-","pr-","ps-","pe-","m-","mx-","my-","mt-","mb-","ml-","mr-","ms-","me-","flex","grid","w-","h-","min-w-","min-h-","max-w-","max-h-","gap-","space-","rounded-","border-","shadow-","opacity-","justify-","items-","self-","overflow-","z-"];function it(t){const n=[];if(!h(t))return[`File not found: ${t}`];const o=v(t,"utf-8"),l=o.split(`
|
|
24
|
+
`),e=t.split("/").pop()||"";if(!e.endsWith(".tsx")&&!e.endsWith(".ts"))return[];for(let r=0;r<l.length;r++){const s=l[r],a=r+1;/style\s*=\s*\{\{/.test(s)&&n.push(`L${a}: Inline style found. Use className or framework utilities.`),/fontSize|font-size/i.test(s)&&!/\/\/|\/\*|\*/.test(s.trimStart().substring(0,2))&&n.push(`L${a}: fontSize detected. Use Text level or Card title/subtitle props.`),/text-align:\s*(left|right)|textAlign:\s*['"]?(left|right)/i.test(s)&&n.push(`L${a}: textAlign left/right detected. Use start/end for RTL support.`),/\brequire\s*\(/.test(s)&&!/\/\/|\/\*|\*/.test(s.trimStart().substring(0,2))&&n.push(`L${a}: require() found. Use ESM import.`),/\.toLocaleDateString|\.toLocaleTimeString|new Intl\.DateTimeFormat/i.test(s)&&n.push(`L${a}: Manual date formatting. Use formatDate() from @donotdev/core.`),/@donotdev\//.test(o)&&/(?:gap|spacing|size)=["'](?:xs|sm|md|lg|xl|2xl)["']/.test(s)&&n.push(`L${a}: Invalid size token. DoNotDev uses none/tight/medium/large \u2014 not xs/sm/md/lg/xl.`);const c=/\/\/|\/\*|\*/.test(s.trimStart().substring(0,2));if(e.endsWith(".tsx")&&/@donotdev\//.test(o)&&!c){const p=s.match(/<(div|span|p|h[1-6]|button|a|input|textarea|select|form|table|tr|td|th|ul|ol|li|img|section|nav|header|footer)[\s>\/]/);if(p){const u=p[1];n.push(`L${a}: Native <${u}> detected. Use ${xe[u]??"a framework component"} instead.`)}for(const u of st)if(new RegExp(`\\b${u.prop}\\s*=`).test(s)){const y=Math.max(0,r-3),f=l.slice(y,r+1).join(`
|
|
25
|
+
`);u.components.some(T=>new RegExp(`<${T}[\\s>]`).test(f))&&n.push(`L${a}: ${u.message}`)}const d=s.match(/className="([^"]+)"/);if(d){const u=d[1],m=rt.filter(y=>u.split(/\s+/).some(f=>f.startsWith(y)||f===y.replace(/-$/,"")));m.length>0&&n.push(`L${a}: Tailwind utility classes in className (${m.join(", ")}). Use framework components and props instead.`)}}}const i=l.map((r,s)=>({line:r,num:s+1})).filter(({line:r})=>/^import\s/.test(r));if(i.length>1){let r=0;for(const{line:s,num:a}of i){let c=4;if(/from\s+['"]react/.test(s)?c=1:/from\s+['"]@donotdev\//.test(s)?c=3:/from\s+['"][^.]/.test(s)&&(c=2),c<r){n.push(`L${a}: Import order violation. Expected: React > vendors > @donotdev > relative.`);break}r=c}}return n}function at(t,n){const o=[],l=/<([A-Z]\w+)/g;for(const e of t){if(!h(e))continue;const i=v(e,"utf-8");if(!/@donotdev\//.test(i))continue;const r=i.matchAll(l);for(const s of r){const a=s[1];a&&(["React","Fragment","Suspense","Provider","Router","Route","Switch"].includes(a)||!n.includes(a)&&!n.includes(`${a}Props`)&&o.push(`${e}: <${a}> used but lookup_symbol("${a}") was never called. Props may be hallucinated.`))}}return[...new Set(o)]}const ie=new $e({name:"donotdev-mcp",version:"0.0.6"},{capabilities:{tools:{}}});ie.setRequestHandler(_e,async()=>({tools:[{name:"start_phase",description:"Begin a WAI-WAY phase (0-4). Returns blueprint, agent definition, context, and lessons. For large projects, pass module to scope work.",inputSchema:{type:"object",properties:{phase:{type:"number",description:"Phase number: 0=BRAINSTORM, 1=SCAFFOLD, 2=ENTITIES, 3=COMPOSE, 4=CONFIGURE"},module:{type:"string",description:'Optional module name to scope work (e.g., "user-management", "billing"). For large projects.'}},required:["phase"]}},{name:"complete_phase",description:"Validate and submit phase for user review. Pass files to run convention checks and symbol verification. Phase stays pending until user calls approve_phase.",inputSchema:{type:"object",properties:{files:{type:"array",items:{type:"string"},description:"File paths to validate (relative to project root). Convention checks + symbol usage verification run automatically."},lesson:{type:"string",description:"Optional lesson learned during this phase"},summary:{type:"string",description:`Brief outcome summary for the captain's log (e.g., "8 pages scaffolded, auth flow complete")`}}}},{name:"approve_phase",description:"User approves the completed phase after review. Only call this after complete_phase and user has confirmed the output is correct.",inputSchema:{type:"object",properties:{}}},{name:"get_phase_status",description:"Get current WAI-WAY phase, completed phases, active agent, lookup coverage, and pending review status.",inputSchema:{type:"object",properties:{}}},{name:"lookup_symbol",description:"Get JSDoc context, @examples, and TypeScript types for any DoNotDev symbol. MUST be called before using any @donotdev component.",inputSchema:{type:"object",properties:{symbol:{type:"string",description:'Symbol name (e.g., "defineEntity", "useCrud", "DataTable")'},package:{type:"string",description:"Package name (optional)"}},required:["symbol"]}},{name:"get_guide",description:"Fetch a framework setup guide from guides/dndev/ (e.g., CRUD setup, Auth setup).",inputSchema:{type:"object",properties:{topic:{type:"string",description:'Topic (e.g., "CRUD", "AUTH")'}},required:["topic"]}},{name:"get_guideline",description:"Fetch architectural guidelines for maintenance or app building.",inputSchema:{type:"object",properties:{topic:{type:"string",description:'Topic with optional section (e.g., "styling", "styling:colors")'}},required:["topic"]}},{name:"search_framework",description:"Search across ALL guides and public symbols for a keyword.",inputSchema:{type:"object",properties:{query:{type:"string",description:"Keyword or phrase"}},required:["query"]}},{name:"list_features",description:"List all framework packages with a one-line summary from each README. Call in Phase 0 before designing custom solutions.",inputSchema:{type:"object",properties:{}}},{name:"init_implementation",description:"Create .dndev/implementation.md to track progress across sessions. Pass sections manually or use from_spec to auto-generate from spec_template.md.",inputSchema:{type:"object",properties:{sections:{type:"array",items:{type:"object",properties:{title:{type:"string",description:'Section heading (e.g., "Phase 1: SCAFFOLD", "Auth Module")'},items:{type:"array",items:{type:"string"},description:"Checklist items for this section"}},required:["title","items"]},description:"Manual sections with checklist items"},from_spec:{type:"boolean",description:"Auto-generate sections from spec_template.md (entities \u2192 Phase 2, pages \u2192 Phase 1/3)"},force:{type:"boolean",description:"Overwrite existing implementation.md without warning"}}}},{name:"update_progress",description:"Tick or untick an item in .dndev/implementation.md. Matches by substring. Optionally add a note.",inputSchema:{type:"object",properties:{item:{type:"string",description:'Substring to match the checklist item (e.g., "HomePage", "Product entity")'},done:{type:"boolean",description:"true = tick [x], false = untick [ ]"},note:{type:"string",description:"Optional note appended to the Notes section"}},required:["item","done"]}},{name:"get_progress",description:"Read .dndev/implementation.md with progress stats. Optionally filter to a section.",inputSchema:{type:"object",properties:{section:{type:"string",description:'Filter to section containing this text (e.g., "Phase 1", "SCAFFOLD")'}}}},{name:"get_project_history",description:"Get the captain's log: full session history with metrics. For post-mortem, team review, and project analysis.",inputSchema:{type:"object",properties:{}}},{name:"run_typecheck",description:"Run TypeScript type-check on the consumer project. Returns structured results. Run after every code change.",inputSchema:{type:"object",properties:{package:{type:"string",description:"Optional: scope to a specific app/package name or path fragment"}}}},{name:"record_lesson",description:"Record a lesson/gotcha to .dndev/LESSONS.md with inline tags. Filtered by phase + module on next start_phase. Also add a code comment where the gotcha applies.",inputSchema:{type:"object",properties:{lesson:{type:"string",description:"The lesson content (gotcha, quirk, operational knowledge)"},tags:{type:"array",items:{type:"string"},description:'Tags for filtering: entity names, service names, module names (e.g., ["stripe", "billing", "webhook"])'}},required:["lesson"]}},{name:"score_lesson",description:"Score a lesson as helpful or harmful. Updates confidence metadata. Lessons decay over time (half-life: 90 days). High harmful ratio auto-converts to anti-pattern.",inputSchema:{type:"object",properties:{lesson:{type:"string",description:'Substring to match the lesson (e.g., "Zustand store actions", "use client directive")'},outcome:{type:"string",enum:["helpful","harmful"],description:"Whether this lesson helped or harmed the current task"}},required:["lesson","outcome"]}},{name:"setup_coach",description:"Get contextual setup instructions for a specific manual step. Reads from guide files \u2014 never accesses .env or secrets. Returns markdown coaching for dashboard-click steps.",inputSchema:{type:"object",properties:{topic:{type:"string",description:'Setup topic (e.g., "stripe-webhook", "oauth-google", "firebase-service-account", "supabase-credentials")'},provider:{type:"string",description:"Optional provider context (firebase, supabase, vercel, stripe)"},projectId:{type:"string",description:"Optional project ID for generating console URLs (public, not a secret)"},region:{type:"string",description:'Optional Firebase Cloud Functions region (e.g., "europe-west1", "us-central1"). Defaults to europe-west1.'}},required:["topic"]}}]}));function _(t,n){if(typeof t!="string")throw new Error(`Expected "${n}" to be a string, got ${typeof t}`)}function ct(t,n){if(typeof t!="number"||!Number.isFinite(t))throw new Error(`Expected "${n}" to be a number, got ${typeof t}`)}function lt(t,n){if(typeof t!="boolean")throw new Error(`Expected "${n}" to be a boolean, got ${typeof t}`)}function ve(t,n){if(!Array.isArray(t)||t.some(o=>typeof o!="string"))throw new Error(`Expected "${n}" to be a string array`)}ie.setRequestHandler(Ee,async t=>{try{const{name:n,arguments:o}=t.params,l=Qe();if(n!=="start_phase"&&n!=="approve_phase"&&Ie(n),n==="start_phase"){ue(),ct(o?.phase,"phase");const e=o.phase,i=o?.module!=null?(_(o.module,"module"),o.module):void 0,r=A.find(E=>E.id===e);if(!r)return{content:[{type:"text",text:`Invalid phase: ${e}. Valid: 0-4.`}],isError:!0};const s=oe();if(!s)return{content:[{type:"text",text:"Error: guides/wai-way/ directory not found."}],isError:!0};const a=se(g(s,"blueprints"),r.blueprint),c=se(g(s,"agents"),r.agentFile),p=Se(s,e),d=Ge({phase:e,module:i}),u=k();u.version=K,u.currentPhase=r.id,u.phaseName=r.name,u.agent=r.agent,u.startedAt=new Date().toISOString(),u.lookedUpSymbols=[],u.pendingReview=!1,u.currentModule=i||null,u.toolCallCounts=void 0,u.lessonsRecorded=void 0,u.lessonsScored=void 0,I(u);const m=[`# Phase ${r.id}: ${r.name}`,`**Agent:** ${r.agent}`];i&&m.push(`**Module:** ${i}`);const y=u.completedPhases.sort().map(E=>{const x=A.find(L=>L.id===E);return x?x.name:`${E}`}),f=N(),$=f?R(f):null,T=F(),C=[`
|
|
26
|
+
## Project State`];if(C.push(`- **Phase:** ${r.id}/4 ${r.name}${y.length>0?` (done: ${y.join(", ")})`:""}`),$&&C.push(`- **Progress:** ${$.stats.done}/${$.stats.total} (${$.stats.percent}%)`),T.sessions.length>0&&C.push(`- **Sessions so far:** ${T.sessions.length}`),m.push(...C),p&&m.push(`
|
|
27
|
+
## Phase Context`,`**Goal:** ${p.goal}`,`**Done when:** ${p.done_when}`,`**Output:** ${p.output}`,"**Read these files first:**",...p.read_files.map(E=>`- ${E}`)),a&&m.push(`
|
|
27
28
|
---
|
|
28
29
|
## Blueprint
|
|
29
30
|
|
|
30
|
-
${a}`),c&&
|
|
31
|
+
${a}`),c&&m.push(`
|
|
31
32
|
---
|
|
32
33
|
## Agent Definition
|
|
33
34
|
|
|
34
|
-
${c}`),
|
|
35
|
+
${c}`),d.trim().length>20&&m.push(`
|
|
35
36
|
---
|
|
36
37
|
## Lessons (Filtered)
|
|
37
38
|
|
|
38
|
-
${
|
|
39
|
+
${d}`),f){const{stats:E,filtered:x}=R(f,`Phase ${e}`);m.push(`
|
|
39
40
|
---
|
|
40
|
-
## Implementation Progress`,`**Overall:** ${
|
|
41
|
+
## Implementation Progress`,`**Overall:** ${E.done}/${E.total} (${E.percent}%)`,"",x,"",'Use `update_progress({ item: "...", done: true })` to tick items as you complete them.')}else e>0&&m.push(`
|
|
41
42
|
---
|
|
42
|
-
## Implementation Progress`,"No implementation.md found. Consider running `init_implementation({ from_spec: true })` to track progress across sessions.");
|
|
43
|
+
## Implementation Progress`,"No implementation.md found. Consider running `init_implementation({ from_spec: true })` to track progress across sessions.");const U=[`
|
|
43
44
|
---
|
|
44
|
-
## Enforcement Rules`,'- **BEFORE using any @donotdev component:** call `lookup_symbol("ComponentName")`','- **AFTER building:** call `complete_phase({ files: [...], summary: "..." })` \u2014 validates + submits for review',"- **WHEN recording a lesson:** also add a `// GOTCHA: ...` comment in the relevant source file","- **NEVER create .md files** unless explicitly asked \u2014 session notes go in `.dndev/`"
|
|
45
|
+
## Enforcement Rules`,'- **BEFORE using any @donotdev component:** call `lookup_symbol("ComponentName")`','- **AFTER building:** call `complete_phase({ files: [...], summary: "..." })` \u2014 validates + submits for review',"- **WHEN recording a lesson:** also add a `// GOTCHA: ...` comment in the relevant source file","- **NEVER create .md files** unless explicitly asked \u2014 session notes go in `.dndev/`",`- Tracked symbols so far: ${u.lookedUpSymbols.length>0?u.lookedUpSymbols.join(", "):"none (call lookup_symbol to add)"}`];e>=3&&U.push("",`### Convention Enforcement (Phase ${e})`,"These are checked by `complete_phase` and WILL BLOCK completion in enforced mode:","","**NO native HTML elements.** The following tags are forbidden in @donotdev files:","`<div>` `<span>` `<p>` `<h1-6>` `<button>` `<a>` `<input>` `<textarea>` `<select>` `<form>` `<table>` `<tr>` `<td>` `<th>` `<ul>` `<ol>` `<li>` `<img>` `<section>` `<nav>` `<header>` `<footer>`","Use instead: Stack, Card, Section, Box, Text, Button, Link, TextInput, Select, Form, DataTable, List, Image, Navigation, Header, Footer","","**NO custom CSS files.** Never create `.css`, `.module.css`, `.scss`, `.sass`, or `.less` files. Use variant props, theme tokens, and framework layout.","","**NO custom component files.** Do not create files in `components/`. Compose pages using framework components. If a component is missing, say what you need and STOP.","","**NO inventing props.** Only use props returned by `lookup_symbol()`. Common hallucination traps:","`size` `tone` `color` `padding` `margin` `spacing` `columns` `background` `fields` \u2014 NONE of these exist.","","**NO Tailwind utilities.** Do not use `bg-`, `text-`, `p-`, `m-`, `flex`, `grid`, `w-`, `h-`, etc. in className."),m.push(...U);const q={0:[],1:[],2:[],3:["After composing, run `/grill` to review code quality before moving to Phase 4."],4:["Run `/grill` for a staff-engineer code review.","Run `/techdebt` to surface cleanup items before shipping."]}[e]||[];q.length>0&&m.push(`
|
|
45
46
|
---
|
|
46
|
-
## Recommended Skills`,...
|
|
47
|
+
## Recommended Skills`,...q.map(E=>`- ${E}`));const S=de();m.push(`
|
|
47
48
|
---
|
|
48
|
-
## Project Args`,`- **Platform:** ${
|
|
49
|
+
## Project Args`,`- **Platform:** ${S.platform}`,`- **Strictness:** ${S.strictness}`,`- **Features:** ${S.features.join(", ")}`,`- **Region:** ${S.region}`);const D=Ne(e,S.features);return D&&m.push(`
|
|
49
50
|
---
|
|
50
|
-
## Gotchas (Phase ${
|
|
51
|
+
## Gotchas (Phase ${e})
|
|
51
52
|
|
|
52
|
-
${
|
|
53
|
-
No blueprint or agent definition found for this phase.`),{content:[{type:"text",text:
|
|
54
|
-
`)}]}}if(n==="complete_phase"){const
|
|
55
|
-
### ${a[
|
|
56
|
-
### Unverified Component Usage`),c.push(...
|
|
57
|
-
###
|
|
58
|
-
###
|
|
59
|
-
`)
|
|
60
|
-
###
|
|
61
|
-
`)}]}
|
|
62
|
-
${
|
|
53
|
+
${D}`),!a&&!c&&m.push(`
|
|
54
|
+
No blueprint or agent definition found for this phase.`),{content:[{type:"text",text:m.join(`
|
|
55
|
+
`)}]}}if(n==="complete_phase"){const e=k();if(e.currentPhase===null)return{content:[{type:"text",text:"No active phase to complete."}],isError:!0};if(e.pendingReview)return{content:[{type:"text",text:"Phase already pending review. Ask the user to review the output, then call approve_phase()."}],isError:!0};const i=e.currentPhase,r=e.phaseName,s=e.currentModule?` [${e.currentModule}]`:"",a=o?.files!=null?(ve(o.files,"files"),o.files):[],c=[],p=[];if(a.length>0){for(const x of a){const L=Fe(x);if(!L){c.push(`- BLOCKED: "${x}" resolves outside project root. Skipped.`);continue}p.push(L)}for(let x=0;x<p.length;x++){const L=it(p[x]);L.length>0&&c.push(`
|
|
56
|
+
### ${a[x]}`,...L.map(be=>`- ${be}`))}const S=at(p,e.lookedUpSymbols);S.length>0&&(c.push(`
|
|
57
|
+
### Unverified Component Usage`),c.push(...S.map(x=>`- ${x}`)));const D=p.filter(x=>/\.(css|module\.css|scss|sass|less)$/.test(x));if(D.length>0){c.push(`
|
|
58
|
+
### Custom CSS Files`);for(const x of D)c.push(`- BLOCKED: "${x}" \u2014 custom CSS files are not allowed. Use framework components, variant props, and theme tokens instead.`)}const E=p.filter(x=>{if(!x.endsWith(".tsx")||!/\/components\//.test(x))return!1;const L=x.split("/").pop()||"";return!/Page|Entity|Layout|Template|\.test\.|\.spec\./.test(L)});if(E.length>0){c.push(`
|
|
59
|
+
### Custom Component Files`);for(const x of E)c.push(`- BLOCKED: "${x}" \u2014 custom component files in components/ are not allowed. Compose with framework components instead. If a component is missing, say what you need and STOP.`)}}const d=ze();d&&(c.push(`
|
|
60
|
+
### Test Coverage`),c.push(d));const u=oe();if(u){const S=Se(u,i);S&&c.push(`
|
|
61
|
+
### Done Criteria`,`**Required:** ${S.done_when}`,`**Expected output:** ${S.output}`,"","Verify these criteria are met.")}const m=de(),y=c.some(S=>S.startsWith("- L")||S.includes("Unverified Component")||S.includes("BLOCKED"));if(y&&m.strictness==="enforced")return{content:[{type:"text",text:[`## Validation Failed: Phase ${i} (${r})${s}`,"","**Status:** ISSUES FOUND \u2014 fix before completing phase","**Strictness:** enforced (change in .dndev/args.json to override)",...c,"","### Type Check","Run `dndev type-check` or `bun run type-check` to verify TypeScript compiles without errors.","","Fix the issues above, then call `complete_phase({ files: [...] })` again."].join(`
|
|
62
|
+
`)}]};y&&m.strictness==="warnings"&&c.unshift(`
|
|
63
|
+
### Warnings (non-blocking)`,"**Strictness:** warnings \u2014 issues reported but phase can proceed.");const f=o?.lesson!=null?(_(o.lesson,"lesson"),o.lesson):void 0;if(f){const S=i!==null?` [Phase ${i}: ${r}]`:"";me(f,S)}const $=o?.summary!=null?(_(o.summary,"summary"),o.summary):void 0;e.pendingLogData={files_touched:p.length,summary:$,validation:y?"failed":"passed"},e.pendingReview=!0,I(e);const T=e.lookedUpSymbols.length,C=A.find(S=>S.id===i+1),ae=C?`Next: Phase ${C.id} (${C.name})`:"This was the final phase.";let U="";const H=N();if(H){const{stats:S}=R(H,`Phase ${i}`);U=`**Implementation:** ${S.done}/${S.total} items (${S.percent}%)`}return{content:[{type:"text",text:[`## Phase ${i} (${r})${s} \u2014 Ready for Review`,"",`**Validation:** ${a.length>0?"PASSED":"No files provided (skipped)"}`,`**Symbols looked up:** ${T} (${e.lookedUpSymbols.join(", ")||"none"})`,U,f?`**Lesson recorded:** ${f}`:"","","### User Review Required","","Present the phase output to the user. Ask them to verify:","- Does the output match what they expected?","- Are there any issues or changes needed?","","**After user confirms:** call `approve_phase()` to advance.","**If user wants changes:** make the changes, then call `complete_phase({ files: [...] })` again.","",ae].filter(Boolean).join(`
|
|
64
|
+
`)}]}}if(n==="approve_phase"){const e=k();if(!e.pendingReview||e.currentPhase===null)return{content:[{type:"text",text:"No phase pending review. Call complete_phase() first."}],isError:!0};const i=e.currentPhase,r=e.phaseName,s=F();ge({id:s.sessions.length+1,date:new Date().toISOString().split("T")[0],phase:i,phase_name:r||A[i]?.name||"UNKNOWN",module:e.currentModule||void 0,started_at:e.startedAt||new Date().toISOString(),completed_at:new Date().toISOString(),outcome:e.pendingLogData?.summary||`Phase ${i} (${r}) completed.`,files_touched:e.pendingLogData?.files_touched||0,symbols_used:e.lookedUpSymbols.length,tool_calls:e.toolCallCounts&&Object.keys(e.toolCallCounts).length>0?e.toolCallCounts:void 0,lessons_recorded:e.lessonsRecorded||void 0,lessons_scored:e.lessonsScored&&(e.lessonsScored.helpful>0||e.lessonsScored.harmful>0)?e.lessonsScored:void 0,validation:e.pendingLogData?.validation}),e.completedPhases.includes(i)||e.completedPhases.push(i),e.currentPhase=null,e.phaseName=null,e.agent=null,e.startedAt=null,e.pendingReview=!1,e.lookedUpSymbols=[],e.currentModule=null,e.pendingLogData=void 0,e.toolCallCounts=void 0,e.lessonsRecorded=void 0,e.lessonsScored=void 0,I(e);const a=A.find(p=>p.id===i+1),c=a?`Next: call start_phase(${a.id}) to begin ${a.name}.`:"All phases complete. App is ready.";return a&&Ye(a.id,a.name),{content:[{type:"text",text:`Phase ${i} (${r}) approved and completed.
|
|
65
|
+
${c}`}]}}if(n==="get_phase_status"){const e=k(),i=e.completedPhases.sort().map(s=>{const a=A.find(c=>c.id===s);return a?`${a.id}: ${a.name}`:`${s}`}).join(", ");return e.currentPhase===null?{content:[{type:"text",text:`No active phase.
|
|
63
66
|
Completed: ${i||"none"}
|
|
64
|
-
Call start_phase(N) to begin a phase.`}]}:{content:[{type:"text",text:[`Active: Phase ${
|
|
65
|
-
`)}]}}if(n==="get_project_history"){const
|
|
66
|
-
`)}]}}if(n==="run_typecheck"){const
|
|
67
|
-
`).find(
|
|
68
|
-
RESULT: unknown`)}]}}catch(a){return{content:[{type:"text",text:((a.stdout??"")+(a.stderr??"")).trim()||"Type-check failed with no output"}],isError:!0}}}if(n==="record_lesson"){
|
|
69
|
-
`).filter(
|
|
70
|
-
**Similar lesson exists** \u2014 consider scoring the existing one instead of recording a duplicate.`),
|
|
71
|
-
**Corroborated** by ${
|
|
72
|
-
**Uncorroborated** \u2014 no prior sessions match. Starts as candidate, needs validation.`),
|
|
73
|
-
Also add a \`// GOTCHA: ...\` comment in the relevant source file.`}]}}if(n==="score_lesson"){
|
|
74
|
-
Pass force: true to overwrite, or use update_progress/get_progress to work with existing file.`}]}}let
|
|
67
|
+
Call start_phase(N) to begin a phase.`}]}:{content:[{type:"text",text:[`Active: Phase ${e.currentPhase} (${e.phaseName})`,`Agent: ${e.agent}`,`Started: ${e.startedAt}`,e.currentModule?`Module: ${e.currentModule}`:null,`Pending review: ${e.pendingReview?"YES \u2014 user must approve":"no"}`,`Symbols looked up: ${e.lookedUpSymbols.length} (${e.lookedUpSymbols.join(", ")||"none"})`,`Completed phases: ${i||"none"}`].filter(Boolean).join(`
|
|
68
|
+
`)}]}}if(n==="get_project_history"){const e=F();if(e.sessions.length===0)return{content:[{type:"text",text:"No sessions logged yet. Captain's log entries are created automatically when phases are approved."}]};const i=e.sessions.reduce((c,p)=>c+p.files_touched,0),r=e.sessions.reduce((c,p)=>c+p.symbols_used,0),s=[...new Set(e.sessions.map(c=>c.phase))].length,a=[`## Captain's Log \u2014 ${e.project}`,`**Started:** ${e.started}`,`**Sessions:** ${e.sessions.length}`,`**Phases completed:** ${s}/5`,`**Total files touched:** ${i}`,`**Total symbols used:** ${r}`,"","### Timeline"];for(const c of e.sessions){const p=c.module?` [${c.module}]`:"",d=[];if(c.files_touched&&d.push(`${c.files_touched} files`),c.symbols_used&&d.push(`${c.symbols_used} symbols`),c.tool_calls){const m=Object.values(c.tool_calls).reduce((y,f)=>y+f,0);d.push(`${m} tool calls`)}if(c.lessons_recorded&&d.push(`${c.lessons_recorded} lessons`),c.lessons_scored){const m=c.lessons_scored;d.push(`scored ${m.helpful}H/${m.harmful}X`)}c.validation&&d.push(`validation: ${c.validation}`);const u=d.length>0?` (${d.join(", ")})`:"";a.push(`${c.id}. **[${c.date}]** Phase ${c.phase} (${c.phase_name})${p} \u2014 ${c.outcome}${u}`)}return a.push("","Raw JSON: .dndev/captain-log.json"),{content:[{type:"text",text:a.join(`
|
|
69
|
+
`)}]}}if(n==="run_typecheck"){const e=o?.package!=null?(_(o.package,"package"),o.package):void 0,{execFileSync:i}=await import("child_process"),r=["tc"];e&&r.push(e);let s="dn";try{i("dn",["--version"],{encoding:"utf8",stdio:"ignore"})}catch{try{i("dndev",["--version"],{encoding:"utf8",stdio:"ignore"}),s="dndev"}catch{return{content:[{type:"text",text:'Neither "dn" nor "dndev" CLI found in PATH. Install @donotdev/cli or ensure packages/tooling is linked.'}],isError:!0}}}try{const a=i(s,r,{cwd:b,encoding:"utf8",env:{...process.env,FORCE_COLOR:"0"},stdio:["ignore","pipe","pipe"]}),c=a.split(`
|
|
70
|
+
`).find(p=>p.startsWith("RESULT:"));return{content:[{type:"text",text:a.trim()+(c?"":`
|
|
71
|
+
RESULT: unknown`)}]}}catch(a){return{content:[{type:"text",text:((a.stdout??"")+(a.stderr??"")).trim()||"Type-check failed with no output"}],isError:!0}}}if(n==="record_lesson"){_(o?.lesson,"lesson");const e=o.lesson,i=o?.tags!=null?(ve(o.tags,"tags"),o.tags):void 0,r=k(),s=r.currentPhase!==null?` [Phase ${r.currentPhase}: ${r.phaseName}]`:"",a=h(P)?v(P,"utf-8"):"",c=e.toLowerCase().split(/\s+/).filter(f=>f.length>4),p=a.split(`
|
|
72
|
+
`).filter(f=>{if(!f.startsWith("- ["))return!1;const $=f.toLowerCase();return c.filter(C=>$.includes(C)).length>=Math.min(3,c.length)}),d=F(),u=d.sessions.filter(f=>i&&i.length>0&&f.module?i.some($=>f.module.toLowerCase().includes($.toLowerCase())):r.currentPhase!==null?f.phase===r.currentPhase:!1);let m="";return p.length>0&&(m=`
|
|
73
|
+
**Similar lesson exists** \u2014 consider scoring the existing one instead of recording a duplicate.`),u.length>0?m+=`
|
|
74
|
+
**Corroborated** by ${u.length} prior session(s) in same phase/module.`:d.sessions.length>0&&(m+=`
|
|
75
|
+
**Uncorroborated** \u2014 no prior sessions match. Starts as candidate, needs validation.`),me(e,s,i),Re(),{content:[{type:"text",text:`Lesson recorded${i&&i.length>0?` [${i.join(", ")}]`:""}. Filtered by tags on next start_phase().${m}
|
|
76
|
+
Also add a \`// GOTCHA: ...\` comment in the relevant source file.`}]}}if(n==="score_lesson"){_(o?.lesson,"lesson"),_(o?.outcome,"outcome");const e=o.lesson,i=o.outcome;if(i!=="helpful"&&i!=="harmful")return{content:[{type:"text",text:'outcome must be "helpful" or "harmful"'}],isError:!0};const{found:r,newStatus:s}=He(e,i);return r&&Oe(i),r?{content:[{type:"text",text:`Lesson scored as ${i}. Status: ${{candidate:"candidate",established:"established (3+ helpful)",proven:"proven (10+ helpful)",deprecated:"DEPRECATED (>25% harmful)","anti-pattern":"ANTI-PATTERN (>50% harmful, auto-inverted as PITFALL)"}[s]??s}.`}]}:{content:[{type:"text",text:`No lesson found matching "${e}".`}],isError:!0}}if(n==="setup_coach"){_(o?.topic,"topic");const e=o.topic,i=typeof o?.provider=="string"?o.provider:void 0,r=typeof o?.projectId=="string"?o.projectId:void 0,s={"stripe-webhook":"SETUP_STRIPE.md.example","stripe-keys":"SETUP_STRIPE.md.example",stripe:"SETUP_STRIPE.md.example","oauth-google":"SETUP_OAUTH_PROVIDERS.md.example","oauth-github":"SETUP_OAUTH_PROVIDERS.md.example","oauth-apple":"SETUP_OAUTH_PROVIDERS.md.example",oauth:"SETUP_OAUTH_PROVIDERS.md.example","firebase-service-account":"SETUP_FIREBASE.md.example","firebase-enable-services":"SETUP_FIREBASE.md.example",firebase:"SETUP_FIREBASE.md.example","supabase-credentials":"SETUP_SUPABASE.md.example","supabase-secret-key":"SETUP_SUPABASE.md.example","supabase-rls":"SETUP_SUPABASE.md.example",supabase:"SETUP_SUPABASE.md.example","vercel-domain":"SETUP_VERCEL.md.example",vercel:"SETUP_VERCEL.md.example","auth-firebase":"SETUP_AUTH.md.example","auth-supabase":"SETUP_AUTH.md.example",auth:"SETUP_AUTH.md.example",billing:"SETUP_BILLING.md.example"},a=s[e.toLowerCase()]??s[i?.toLowerCase()??""],c=[a?g(W,a):null,g(b,"guides","dndev",a||`SETUP_${e.toUpperCase()}.md.example`),g(b,"guides","dndev",a||`SETUP_${e.toUpperCase()}.md`)].filter(Boolean);let p="";for(const u of c)if(h(u)){p=v(u,"utf-8");break}if(!p)return{content:[{type:"text",text:`No guide found for topic "${e}". Available topics: ${Object.keys(s).join(", ")}`}]};r&&(p=p.replace(/\{\{PROJECT_ID\}\}/g,r));const d=o?.region;return p=p.replace(/\{\{REGION\}\}/g,typeof d=="string"?d:"europe-west1"),{content:[{type:"text",text:p}]}}if(n==="init_implementation"){const e=o?.sections,i=o?.from_spec,r=o?.force;if(i!==void 0&&typeof i!="boolean")throw new Error("from_spec must be a boolean");if(r!==void 0&&typeof r!="boolean")throw new Error("force must be a boolean");if(e!==void 0){if(!Array.isArray(e))throw new Error("sections must be an array");for(const p of e){if(!p||typeof p!="object")throw new Error("each section must be an object");if(typeof p.title!="string")throw new Error("section.title must be a string");if(!Array.isArray(p.items))throw new Error("section.items must be an array")}}if(h(B)&&!r){const p=N(),{stats:d}=R(p);return{content:[{type:"text",text:`implementation.md already exists (${d.done}/${d.total} items done, ${d.percent}%).
|
|
77
|
+
Pass force: true to overwrite, or use update_progress/get_progress to work with existing file.`}]}}let s;if(i){const p=Je();if(!p)return{content:[{type:"text",text:"Could not generate from spec: spec_template.md not found in guides/wai-way/."}],isError:!0};s=p}else if(e&&e.length>0)s=e;else return{content:[{type:"text",text:"Provide sections (array of {title, items}) or set from_spec: true."}],isError:!0};const a=Ke(s);ee(a);const{stats:c}=R(a);return{content:[{type:"text",text:`implementation.md created with ${c.total} items across ${s.length} sections.
|
|
75
78
|
|
|
76
|
-
${a}`}]}}if(n==="update_progress"){
|
|
77
|
-
`),c=
|
|
78
|
-
`);if(
|
|
79
|
-
${
|
|
79
|
+
${a}`}]}}if(n==="update_progress"){_(o?.item,"item"),lt(o?.done,"done");const e=o.item,i=o.done,r=o?.note!=null?(_(o.note,"note"),o.note):void 0,s=N();if(!s)return{content:[{type:"text",text:"No implementation.md found. Call init_implementation() first."}],isError:!0};const a=s.split(`
|
|
80
|
+
`),c=e.toLowerCase();let p=!1,d="";for(let y=0;y<a.length;y++){const f=a[y];if(/^\s*- \[[ x]\]/i.test(f)&&f.toLowerCase().includes(c)){i?a[y]=f.replace(/- \[ \]/,"- [x]"):a[y]=f.replace(/- \[x\]/i,"- [ ]"),d=a[y],p=!0;break}}if(!p)return{content:[{type:"text",text:`No checklist item matching "${e}" found in implementation.md.`}],isError:!0};let u=a.join(`
|
|
81
|
+
`);if(u=u.replace(/\*\*Last updated:\*\*\s*.*/,`**Last updated:** ${new Date().toISOString()}`),r){const y=`- ${r}`;u.includes("## Notes")?u=u.replace("## Notes",`## Notes
|
|
82
|
+
${y}`):u+=`
|
|
80
83
|
## Notes
|
|
81
|
-
${
|
|
82
|
-
`}
|
|
83
|
-
Progress: ${
|
|
84
|
-
`)}]}}if(!l&&!["get_guide","get_guideline","search_framework"].includes(n))return{content:[{type:"text",text:"Error: node_modules not found. Run bun install first."}],isError:!0};if(n==="get_guide"){
|
|
84
|
+
${y}
|
|
85
|
+
`}ee(u);const{stats:m}=R(u);return{content:[{type:"text",text:`Updated: ${d.trim()}
|
|
86
|
+
Progress: ${m.done}/${m.total} (${m.percent}%)`}]}}if(n==="get_progress"){const e=o?.section!=null?(_(o.section,"section"),o.section):void 0,i=N();if(!i)return{content:[{type:"text",text:"No implementation.md found. Call init_implementation() first."}],isError:!0};const{stats:r,sections:s,filtered:a}=R(i,e),c=["## Implementation Progress",`**Overall:** ${r.done}/${r.total} (${r.percent}%)`,""];if(s.length>0){c.push("### By Section");for(const p of s){const d=p.total>0?Math.round(p.done/p.total*100):0;c.push(`- **${p.title}:** ${p.done}/${p.total} (${d}%)`)}c.push("")}return c.push("---","",a),{content:[{type:"text",text:c.join(`
|
|
87
|
+
`)}]}}if(!l&&!["get_guide","get_guideline","search_framework"].includes(n))return{content:[{type:"text",text:"Error: node_modules not found. Run bun install first."}],isError:!0};if(n==="get_guide"){_(o?.topic,"topic");const e=o.topic,i=ne();if(!i)return{content:[{type:"text",text:"Error: guides directory not found."}],isError:!0};const r=M(i).filter(s=>s.endsWith(".md")||s.endsWith(".md.example"));for(const s of r)if(s.toLowerCase().includes(e.toLowerCase()))return{content:[{type:"text",text:`[GUIDE] ${e} (from ${s}):
|
|
85
88
|
|
|
86
|
-
${
|
|
89
|
+
${v(g(i,s),"utf-8")}`}]};return{content:[{type:"text",text:`No guide found for: ${e}`}],isError:!0}}if(n==="get_guideline"){_(o?.topic,"topic");const e=o.topic,[i,r]=e.split(":"),s=[{dir:W,type:"GUIDE"},{dir:Le,type:"ARCHITECTURE"}];for(const a of s){if(!h(a.dir))continue;const c=M(a.dir).filter(p=>p.endsWith(".md")||p.endsWith(".md.example"));for(const p of c)if(i&&p.toLowerCase().includes(i.toLowerCase())){const d=v(g(a.dir,p),"utf-8");if(!r){const y=d.match(/^([\s\S]*?)(?=##|$)/),f=y&&y[1]?y[1].trim():"No overview found.";return{content:[{type:"text",text:`[${a.type}] Overview for ${i}:
|
|
87
90
|
|
|
88
|
-
${
|
|
91
|
+
${f}`}]}}const u=ye(r),m=d.match(new RegExp(`##\\s+.*${u}.*\\n([\\s\\S]*?)(?=##|$)`,"i"));if(m&&m[1])return{content:[{type:"text",text:`[${a.type}] ${i} > ${r}:
|
|
89
92
|
|
|
90
|
-
${
|
|
93
|
+
${m[1].trim()}`}]}}}return{content:[{type:"text",text:`No guideline found for: ${e}`}],isError:!0}}if(n==="search_framework"){_(o?.query,"query");const e=o.query.toLowerCase(),i=[],r=ne();if(r){const s=M(r).filter(a=>a.endsWith(".md")||a.endsWith(".md.example"));for(const a of s)v(g(r,a),"utf-8").toLowerCase().includes(e)&&i.push(`[GUIDE] ${a}`)}if(l)for(const s of te){const a=g(l,s,"dist");if(h(a))for(const c of re(a)){const p=v(c,"utf-8");if(p.toLowerCase().includes(e)){const d=nt(p).filter(u=>u.toLowerCase().includes(e));d.length>0&&i.push(`[SYMBOL] ${s}: ${d.join(", ")}`)}}}return{content:[{type:"text",text:i.length>0?`Results:
|
|
91
94
|
${i.join(`
|
|
92
|
-
`)}`:"No results found."}]}}if(n==="lookup_symbol"){
|
|
95
|
+
`)}`:"No results found."}]}}if(n==="lookup_symbol"){_(o?.symbol,"symbol");const e=o.symbol;if(!l)return{content:[{type:"text",text:"Error: node_modules not found. Run bun install first."}],isError:!0};const i=k();i.lookedUpSymbols.includes(e)||(i.lookedUpSymbols.push(e),I(i));const r=[e,`${e}Props`,`${e.replace(/Props$/,"")}Props`],s=["@donotdev/core","@donotdev/ui","@donotdev/crud"],a=[...s,...te.filter(c=>!s.includes(c))];for(const c of a){const p=g(l,c,"dist");if(h(p))for(const d of re(p)){const u=v(d,"utf-8");for(const m of r){const y=tt(u,m);if(y)return{content:[{type:"text",text:`[TYPE INTELLIGENCE] ${c}:
|
|
93
96
|
|
|
94
|
-
${
|
|
95
|
-
`];for(const i of
|
|
96
|
-
`)}]}}return{content:[{type:"text",text:`Unknown tool: ${n}`}],isError:!0}}catch(n){return{content:[{type:"text",text:n instanceof Error?n.message:String(n)}],isError:!0}}});async function
|
|
97
|
+
${y}`}]}}}}return{content:[{type:"text",text:`Not found: ${e}`}],isError:!0}}if(n==="list_features"){if(!l)return{content:[{type:"text",text:"Error: node_modules not found. Run bun install first."}],isError:!0};const e=[`## Available Framework Features
|
|
98
|
+
`];for(const i of Ze){const r=g(l,i,"README.md"),s=ot(r);e.push(`- **${i}** \u2014 ${s||"(no description available)"}`)}return e.push('\nUse `search_framework("topic")` or `get_guide("TOPIC")` to go deeper on any package.'),{content:[{type:"text",text:e.join(`
|
|
99
|
+
`)}]}}return{content:[{type:"text",text:`Unknown tool: ${n}`}],isError:!0}}catch(n){return{content:[{type:"text",text:n instanceof Error?n.message:String(n)}],isError:!0}}});async function pt(){const t=new we;await ie.connect(t)}pt().catch(t=>{process.exit(1)});
|