@duckmind/dm-darwin-x64 0.48.5 → 0.49.6
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/dm +0 -0
- package/extensions/.dm-extensions.json +159 -220
- package/extensions/dm-9router-ext/package.json +0 -6
- package/extensions/dm-9router-ext/src/index.js +1 -1
- package/extensions/dm-ask-user/package.json +0 -4
- package/extensions/dm-caveman/extensions/caveman.js +29 -0
- package/extensions/dm-caveman/package.json +20 -0
- package/extensions/dm-cli-anything/index.js +5 -5
- package/extensions/dm-cli-anything/package.json +0 -7
- package/extensions/dm-cli-anything/skills/cli-anything/SKILL.md +1 -3
- package/extensions/dm-context/package.json +0 -1
- package/extensions/dm-cua/package.json +0 -7
- package/extensions/dm-fff/package.json +0 -6
- package/extensions/dm-goal/package.json +0 -8
- package/extensions/dm-grill-me/index.js +2 -2
- package/extensions/dm-grill-me/package.json +0 -7
- package/extensions/dm-image2/package.json +0 -8
- package/extensions/dm-subagents/.m/artifacts/shell/shell_output_1783845384621_9cf9262bf674.txt +1336 -0
- package/extensions/dm-subagents/.m/artifacts/shell/shell_output_1783846154938_6a41cefee0bf.txt +1336 -0
- package/extensions/dm-subagents/package.json +0 -11
- package/extensions/dm-subagents/src/extension/doctor.js +10 -10
- package/extensions/dm-subagents/src/extension/fanout-child.js +97 -97
- package/extensions/dm-subagents/src/extension/index.js +121 -121
- package/extensions/dm-subagents/src/extension/rpc.js +5 -5
- package/extensions/dm-subagents/src/extension/schemas.js +1 -1
- package/extensions/dm-subagents/src/extension/tool-description.js +2 -2
- package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +5 -5
- package/extensions/dm-subagents/src/runs/background/async-execution.js +19 -19
- package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +9 -9
- package/extensions/dm-subagents/src/runs/background/async-resume.js +5 -5
- package/extensions/dm-subagents/src/runs/background/async-status.js +8 -8
- package/extensions/dm-subagents/src/runs/background/fleet-view.js +13 -13
- package/extensions/dm-subagents/src/runs/background/result-watcher.js +5 -5
- package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +3 -3
- package/extensions/dm-subagents/src/runs/background/run-status.js +19 -19
- package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +7 -7
- package/extensions/dm-subagents/src/runs/background/subagent-runner.js +35 -35
- package/extensions/dm-subagents/src/runs/background/wait.js +7 -7
- package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +32 -32
- package/extensions/dm-subagents/src/runs/foreground/execution.js +26 -26
- package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +96 -96
- package/extensions/dm-subagents/src/runs/shared/dm-args.js +1 -1
- package/extensions/dm-subagents/src/runs/shared/nested-events.js +6 -6
- package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +13 -13
- package/extensions/dm-subagents/src/shared/fork-context.js +4 -4
- package/extensions/dm-tasks/package.json +0 -7
- package/extensions/dm-usage/package.json +0 -7
- package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +1 -8
- package/extensions/greedysearch-dm/bin/gschrome.mjs +3 -3
- package/extensions/greedysearch-dm/bin/launch-visible.mjs +3 -3
- package/extensions/greedysearch-dm/bin/launch.mjs +4 -4
- package/extensions/greedysearch-dm/bin/search.mjs +103 -103
- package/extensions/greedysearch-dm/extractors/consensus.mjs +35 -35
- package/extensions/greedysearch-dm/extractors/gemini.mjs +38 -38
- package/extensions/greedysearch-dm/extractors/logically.mjs +35 -35
- package/extensions/greedysearch-dm/package.json +0 -10
- package/extensions/greedysearch-dm/src/search/chrome.mjs +23 -23
- package/extensions/greedysearch-dm/src/search/fetch-source.mjs +35 -35
- package/extensions/greedysearch-dm/src/search/research.mjs +61 -61
- package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +4 -4
- package/package.json +1 -1
- package/extensions/dm-9router-ext/README.md +0 -142
- package/extensions/dm-9router-ext/tsconfig.json +0 -17
- package/extensions/dm-ask-user/README.md +0 -226
- package/extensions/dm-cli-anything/LICENSE +0 -201
- package/extensions/dm-cli-anything/README.md +0 -33
- package/extensions/dm-cli-anything/vendor/UPSTREAM.md +0 -14
- package/extensions/dm-context/AGENTS.md +0 -41
- package/extensions/dm-context/README.md +0 -18
- package/extensions/dm-context/tsconfig.json +0 -16
- package/extensions/dm-cua/README.md +0 -24
- package/extensions/dm-fff/README.md +0 -36
- package/extensions/dm-fff/tsconfig.json +0 -13
- package/extensions/dm-goal/CHANGELOG.md +0 -12
- package/extensions/dm-goal/LICENSE +0 -21
- package/extensions/dm-goal/README.md +0 -29
- package/extensions/dm-goal/tsconfig.json +0 -15
- package/extensions/dm-grill-me/DESIGN.md +0 -301
- package/extensions/dm-grill-me/LICENSE +0 -21
- package/extensions/dm-grill-me/README.md +0 -82
- package/extensions/dm-grill-me/tsconfig.json +0 -17
- package/extensions/dm-image2/README.md +0 -33
- package/extensions/dm-subagents/CHANGELOG.md +0 -1211
- package/extensions/dm-subagents/README.md +0 -29
- package/extensions/dm-subagents/banner.png +0 -0
- package/extensions/dm-subagents/biome.json +0 -26
- package/extensions/dm-subagents/tsconfig.json +0 -18
- package/extensions/dm-tasks/LICENSE +0 -21
- package/extensions/dm-tasks/README.md +0 -30
- package/extensions/dm-tasks/biome.json +0 -26
- package/extensions/dm-tasks/tsconfig.json +0 -14
- package/extensions/dm-usage/LICENSE +0 -21
- package/extensions/dm-usage/README.md +0 -29
- package/extensions/dm-usage/insights-screenshot.png +0 -0
- package/extensions/dm-usage/screenshot.png +0 -0
- package/extensions/greedysearch-dm/LICENSE +0 -21
- package/extensions/greedysearch-dm/README.md +0 -222
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import{spawn as ve}from"node:child_process";import{basename as B}from"node:path";function H(t=process.env,e=process.execPath){let i=t.GREEDY_SEARCH_NODE||t.NODE_BINARY||t.NODE;if(i?.trim())return i.trim();let
|
|
1
|
+
import{spawn as ve}from"node:child_process";import{basename as B}from"node:path";function H(t=process.env,e=process.execPath){let i=t.GREEDY_SEARCH_NODE||t.NODE_BINARY||t.NODE;if(i?.trim())return i.trim();let n=B(e||"").toLowerCase();if(n==="node"||n==="node.exe")return e;return"node"}import{existsSync as O,mkdirSync as V,readFileSync as k,writeFileSync as F}from"node:fs";import{homedir as z}from"node:os";import{join as M}from"node:path";import{tmpdir as T}from"node:os";var N=`${T().replaceAll("\\","/")}/greedysearch-chrome-profile`,we=`${N}/DevToolsActivePort`,Ue=`${T().replaceAll("\\","/")}/cdp-pages.json`,We=`${T().replaceAll("\\","/")}/greedysearch-chrome-mode`,De=`${T().replaceAll("\\","/")}/greedysearch-visible-recovery.jsonl`,w=M(z(),".dm"),E=M(w,"greedyconfig"),U=["perplexity","google","chatgpt"],W="gemini";function ee(){try{if(O(E)){let t=k(E,"utf8"),e=JSON.parse(t);if(Array.isArray(e.engines)&&e.engines.length>0&&e.engines.every((i)=>typeof i==="string")){let i=e.engines.filter((s)=>y[s]),n=e.engines.filter((s)=>!y[s]);if(n.length>0)process.stderr.write(`[greedysearch] Warning: ignoring unknown engine(s) in ${E}: ${n.join(", ")}
|
|
2
2
|
[greedysearch] Available engines: ${Object.keys(y).join(", ")}
|
|
3
3
|
`);if(i.length>0)return i;process.stderr.write(`[greedysearch] Warning: no valid engines in ${E}, falling back to defaults: ${U.join(", ")}
|
|
4
4
|
`)}}}catch{}return U}function ie(){try{if(!O(w))V(w,{recursive:!0});if(!O(E))F(E,JSON.stringify({engines:U,synthesizer:W},null,2)+`
|
|
5
5
|
`,"utf8")}catch{}}ie();var C=["gemini","chatgpt"];function te(){try{if(O(E)){let t=k(E,"utf8"),e=JSON.parse(t);if(typeof e.synthesizer==="string"){let i=e.synthesizer.toLowerCase();if(C.includes(i))return i;process.stderr.write(`[greedysearch] Warning: unknown synthesizer "${e.synthesizer}" in ${E}
|
|
6
6
|
[greedysearch] Available synthesizers: ${C.join(", ")}
|
|
7
7
|
[greedysearch] Falling back to default: ${W}
|
|
8
|
-
`)}}}catch{}return W}var y={perplexity:"perplexity.mjs",p:"perplexity.mjs",bing:"bing-copilot.mjs",b:"bing-copilot.mjs",google:"google-ai.mjs",g:"google-ai.mjs",gemini:"gemini.mjs",gem:"gemini.mjs",chatgpt:"chatgpt.mjs",gpt:"chatgpt.mjs","semantic-scholar":"semantic-scholar.mjs",semanticscholar:"semantic-scholar.mjs",s2:"semantic-scholar.mjs",logically:"logically.mjs",log:"logically.mjs"},ne=ee();var Le=te(),He=Math.max(1,Number.parseInt(process.env.GREEDY_FETCH_CONCURRENCY||"5",10)||5);process.env.CDP_PROFILE_DIR=N;var oe=["fbclid","gclid","ref","ref_src","ref_url","source","utm_campaign","utm_content","utm_medium","utm_source","utm_term"],se=["dev.to","hashnode.com","medium.com","reddit.com","stackoverflow.com","stackexchange.com","substack.com"],le=["arstechnica.com","techcrunch.com","theverge.com","venturebeat.com","wired.com","zdnet.com"],J=["facebook.com","instagram.com","linkedin.com","pinterest.com","tiktok.com","twitter.com","x.com"];function v(t="",e=240){let i=String(t).replaceAll(/\s+/g," ").trim();if(i.length<=e)return i;let
|
|
9
|
-
`)e+="\\n";else if(i&&s==="\r")e+="\\r";else if(i&&s==="\t")e+="\\t";else e+=s}return e}function Z(t){if(!t)return null;let e=String(t).trim(),i=e.indexOf("BEGIN_JSON"),
|
|
8
|
+
`)}}}catch{}return W}var y={perplexity:"perplexity.mjs",p:"perplexity.mjs",bing:"bing-copilot.mjs",b:"bing-copilot.mjs",google:"google-ai.mjs",g:"google-ai.mjs",gemini:"gemini.mjs",gem:"gemini.mjs",chatgpt:"chatgpt.mjs",gpt:"chatgpt.mjs","semantic-scholar":"semantic-scholar.mjs",semanticscholar:"semantic-scholar.mjs",s2:"semantic-scholar.mjs",logically:"logically.mjs",log:"logically.mjs"},ne=ee();var Le=te(),He=Math.max(1,Number.parseInt(process.env.GREEDY_FETCH_CONCURRENCY||"5",10)||5);process.env.CDP_PROFILE_DIR=N;var oe=["fbclid","gclid","ref","ref_src","ref_url","source","utm_campaign","utm_content","utm_medium","utm_source","utm_term"],se=["dev.to","hashnode.com","medium.com","reddit.com","stackoverflow.com","stackexchange.com","substack.com"],le=["arstechnica.com","techcrunch.com","theverge.com","venturebeat.com","wired.com","zdnet.com"],J=["facebook.com","instagram.com","linkedin.com","pinterest.com","tiktok.com","twitter.com","x.com"];function v(t="",e=240){let i=String(t).replaceAll(/\s+/g," ").trim();if(i.length<=e)return i;let n=i.slice(0,e),s=n.lastIndexOf(" ");return s>0?`${n.slice(0,s)}...`:`${n}...`}function D(t=""){let e=v(t,180);if(!e)return"";if(/^https?:\/\//i.test(e))return"";let i=e.split(/\s+/).filter(Boolean).length,n=/[A-Z]/.test(e),s=/\d/.test(e);return e===e.toLowerCase()&&i<=4&&!n&&!s?"":e}function G(t="",e=""){let i=D(t),n=D(e);if(!n)return i;if(!i)return n;let s=/^https?:\/\//i.test(i),r=/^https?:\/\//i.test(n);if(s&&!r)return n;if(!s&&r)return i;return n.length>i.length?n:i}function ce(t){if(!t)return null;try{let e=new URL(t);if(!["http:","https:"].includes(e.protocol))return null;if(e.hash="",e.hostname=e.hostname.toLowerCase(),e.protocol==="https:"&&e.port==="443"||e.protocol==="http:"&&e.port==="80")e.port="";for(let s of[...e.searchParams.keys()]){let r=s.toLowerCase();if(oe.includes(r)||r.startsWith("utm_"))e.searchParams.delete(s)}e.searchParams.sort();let i=e.pathname.replace(/\/{1,10}$/,"")||"/";e.pathname=i;let n=e.toString();return i==="/"?n.replace(/\/$/,""):n}catch{return null}}function re(t){try{return new URL(t).hostname.toLowerCase().replace(/^www\./,"")}catch{return""}}function _(t,e){return e.some((i)=>t===i||t.endsWith(`.${i}`))}function ae(t,e="",i=""){let n=e.toLowerCase(),s=i.toLowerCase();if(t==="github.com"||t==="gitlab.com")return"repo";if(t==="arxiv.org"||t==="doi.org"||t==="semanticscholar.org"||t.endsWith(".semanticscholar.org")||s.includes("/paper/")||s.includes("/pdf/"))return"academic";if(_(t,J))return"social";if(_(t,se))return"community";if(_(t,le))return"news";if(t.startsWith("docs.")||t.startsWith("developer.")||t.startsWith("developers.")||t.startsWith("api.")||n.includes("documentation")||n.includes("docs")||n.includes("reference")||s.includes("/docs/")||s.includes("/reference/")||s.includes("/api/"))return"official-docs";if(t.startsWith("blog.")||s.includes("/blog/"))return"maintainer-blog";return"website"}function fe(t){switch(t){case"official-docs":return 5;case"repo":return 4;case"academic":return 4;case"maintainer-blog":return 3;case"website":return 2;case"community":return 1;case"news":return 0;case"social":return-6;default:return 0}}function ge(t){let e=Object.values(t.perEngine||{}).map((i)=>i?.rank||99);return e.length?Math.min(...e):99}var pe=["reddit.com","news.ycombinator.com","lobste.rs"];function R(t){return t.smartScore*3+t.engineCount*5+fe(t.sourceType)*2+Math.max(0,7-ge(t))}function ue(t){let e=t.toLowerCase(),i=[];if(e.includes("openai")||e.includes("gpt")||e.includes("chatgpt"))i.push("openai.com","platform.openai.com","help.openai.com");if(e.includes("anthropic")||e.includes("claude"))i.push("anthropic.com","docs.anthropic.com");if(e.includes("bun"))i.push("bun.sh","bun.com");if(e.includes("next.js")||e.includes("nextjs"))i.push("nextjs.org","vercel.com");if(e.includes("playwright"))i.push("playwright.dev");if(e.includes("supabase"))i.push("supabase.com","supabase.io");if(e.includes("prisma"))i.push("prisma.io");if(e.includes("tailwind"))i.push("tailwindcss.com");if(e.includes("vite"))i.push("vitejs.dev","vite.dev");if(e.includes("astro"))i.push("astro.build");if(e.includes("svelte"))i.push("svelte.dev");if(e.includes("solid"))i.push("solidjs.com");if(e.includes("vue")||e.includes("nuxt"))i.push("vuejs.org","nuxt.com");if(e.includes("react")||e.includes("react native"))i.push("react.dev","reactnative.dev");if(e.includes("angular"))i.push("angular.io","angular.dev");if(e.includes("node.js")||e.includes("nodejs"))i.push("nodejs.org","nodejs.dev","npmjs.com");if(/\bgo\b/.test(e)||e.includes("golang"))i.push("go.dev","golang.org","pkg.go.dev");if(e.includes("deno"))i.push("deno.land","deno.com");if(e.includes("fresh"))i.push("fresh.deno.dev");if(e.includes("typescript")||e.includes("ts"))i.push("typescriptlang.org");if(e.includes("python"))i.push("python.org","docs.python.org");if(e.includes("rust"))i.push("rust-lang.org","docs.rs","crates.io");if(e.includes("zig"))i.push("ziglang.org");if(e.includes("docker"))i.push("docker.com","docs.docker.com","hub.docker.com");if(e.includes("kubernetes")||e.includes("k8s"))i.push("kubernetes.io","k8s.io");if(e.includes("postgres")||e.includes("postgresql"))i.push("postgresql.org","neon.tech","supabase.com");if(e.includes("redis"))i.push("redis.io");if(e.includes("sqlite"))i.push("sqlite.org");if(e.includes("cloudflare"))i.push("developers.cloudflare.com","cloudflare.com");if(e.includes("vercel"))i.push("vercel.com","nextjs.org");if(e.includes("netlify"))i.push("netlify.com","docs.netlify.com");if(e.includes("stripe"))i.push("stripe.com","docs.stripe.com");if(e.includes("github"))i.push("github.com","docs.github.com");if(e.includes("gitlab"))i.push("gitlab.com","docs.gitlab.com");if(e.includes("aws"))i.push("aws.amazon.com","docs.aws.amazon.com");if(e.includes("azure"))i.push("azure.microsoft.com","learn.microsoft.com");if(e.includes("gcp")||e.includes("google cloud"))i.push("cloud.google.com","developers.google.com");if(e.includes("gemini")||e.includes("google ai"))i.push("ai.google.dev","developers.google.com");for(let n of J){let s=n.replace(/\.com$/,"");if(e.includes(s))i.push(n)}return[...new Set(i)]}function I(t,e){return t===e||t.endsWith(`.${e}`)}function Y(t,e=""){let i=new Map,n=Object.keys(t||{}).filter((o)=>!o.startsWith("_")),s=ue(e);for(let o of n){let c=t[o];if(!c?.sources)continue;for(let a=0;a<c.sources.length;a++){let h=c.sources[a],g=ce(h.url);if(!g||g.length<10)continue;let j=D(h.title||""),u=re(g),d=ae(u,j,g),m=0;if(s.some(($)=>I(u,$)))m+=10;if(d==="official-docs")m+=3;let Q=g.toLowerCase();if(/\/docs\/|\/documentation\/|\.dev\/|\/api\/|\/reference\//.test(Q))m+=2;let q=s.some(($)=>I(u,$));if(d==="social"&&!q)m-=20;if(s.length>0){if(_(u,pe))m-=3;else if(d==="community"&&!_(u,["stackoverflow.com","stackexchange.com"]))m-=1}let p=i.get(g)||{id:"",canonicalUrl:g,displayUrl:h.url||g,domain:u,title:"",engines:[],engineCount:0,perEngine:{},sourceType:d,isOfficial:d==="official-docs",smartScore:0};if(p.title=G(p.title,j),p.displayUrl=p.displayUrl||h.url||g,p.sourceType=p.sourceType||d,p.isOfficial=p.isOfficial||d==="official-docs",p.smartScore=Math.max(p.smartScore,m),!p.engines.includes(o))p.engines.push(o);p.perEngine[o]={rank:a+1,title:G(p.perEngine[o]?.title||"",j)},i.set(g,p)}}let r=Array.from(i.values()).map((o)=>({...o,engineCount:o.engines.length})),f=r.filter((o)=>o.sourceType!=="social"),l=r.filter((o)=>o.sourceType==="social");return f.sort((o,c)=>{let a=R(c)-R(o);if(a!==0)return a;return o.domain.localeCompare(c.domain)}),l.sort((o,c)=>{let a=R(c)-R(o);if(a!==0)return a;return o.domain.localeCompare(c.domain)}),[...f,...l].slice(0,12).map((o,c)=>({...o,id:`S${c+1}`,title:o.title||o.domain||o.canonicalUrl}))}function me(t){let e="",i=!1,n=!1;for(let s of String(t)){if(n){e+=s,n=!1;continue}if(s==="\\"){e+=s,n=!0;continue}if(s==='"'){i=!i,e+=s;continue}if(i&&s===`
|
|
9
|
+
`)e+="\\n";else if(i&&s==="\r")e+="\\r";else if(i&&s==="\t")e+="\\t";else e+=s}return e}function Z(t){if(!t)return null;let e=String(t).trim(),i=e.indexOf("BEGIN_JSON"),n=e.indexOf("END_JSON");if(i!==-1&&n!==-1&&i<n)e=e.slice(i+10,n).trim();else{let l=e.indexOf("{");if(l>0)e=e.slice(l)}let s=[e,e.replace(/^```json\s*/i,"").replace(/^```\s*/i,"").replace(/```$/i,"").trim()],r=e.indexOf("{"),f=e.lastIndexOf("}");if(r!==-1&&f!==-1&&r<f)s.push(e.slice(r,f+1));for(let l of[...s]){let o=me(l);if(o!==l)s.push(o)}for(let l of s)try{return JSON.parse(l)}catch{}return null}function x(t,e,i=""){let n=new Set(e.map((o)=>o.id)),s=["high","medium","low","mixed","conflicting"].includes(t?.agreement?.level)?t.agreement.level:"mixed",r=Array.isArray(t?.claims)?t.claims.map((o)=>({claim:v(o?.claim||"",260),support:["strong","moderate","weak","conflicting"].includes(o?.support)?o.support:"moderate",sourceIds:Array.isArray(o?.sourceIds)?o.sourceIds.filter((c)=>n.has(c)):[]})).filter((o)=>o.claim):[],f=Array.isArray(t?.recommendedSources)?t.recommendedSources.filter((o)=>n.has(o)).slice(0,6):[],l="";if(i){let o=i.indexOf("{"),c=i.lastIndexOf("}");if(o!==-1&&c!==-1&&o<c)l=i.slice(o,c+1);else l=i}return{answer:v(t?.answer||l||i,4000),agreement:{level:s,summary:v(t?.agreement?.summary||"",280)},differences:Array.isArray(t?.differences)?t.differences.map((o)=>v(o,220)).filter(Boolean).slice(0,5):[],caveats:Array.isArray(t?.caveats)?t.caveats.map((o)=>v(o,220)).filter(Boolean).slice(0,5):[],claims:r,recommendedSources:f}}function A(t,e,i,{grounded:n=!1}={}){let s={};for(let l of["perplexity","bing","google"]){let o=e[l];if(!o)continue;if(o.error){s[l]={status:"error",error:String(o.error)};continue}s[l]={status:"ok",answer:v(o.answer||"",n?4500:2200),sourceIds:i.filter((c)=>c.engines.includes(l)).sort((c,a)=>(c.perEngine[l]?.rank||99)-(a.perEngine[l]?.rank||99)).map((c)=>c.id).slice(0,6)}}let r=n?700:300,f=i.slice(0,n?10:8).map((l)=>({id:l.id,title:l.title,domain:l.domain,canonicalUrl:l.canonicalUrl,sourceType:l.sourceType,isOfficial:l.isOfficial,engines:l.engines,engineCount:l.engineCount,fetch:l.fetch?.attempted?{ok:l.fetch.ok,publishedTime:l.fetch.publishedTime||"",byline:l.fetch.byline||"",snippet:v(l.fetch.snippet||"",r)}:void 0}));return["You are a research synthesizer. Combine these search engine results into a single authoritative answer.","",`Query: ${t}`,"",`Engine summaries:
|
|
10
10
|
${JSON.stringify(s,null,2)}`,"",`Source registry:
|
|
11
11
|
${JSON.stringify(f,null,2)}`,"","Instructions:","- Write a clear, direct answer in markdown (use headers/bullets where they help readability)","- Cite sources inline as [S1], [S2] etc. when making specific claims","- Prefer sources with content (fetch.ok=true and non-empty snippet) for citations","- Note where the engines agree or meaningfully disagree","- List any important caveats or limitations","- recommendedSources: the 2-4 source IDs most worth reading for this query","","Respond ONLY with a JSON object wrapped in BEGIN_JSON / END_JSON markers:","","BEGIN_JSON",JSON.stringify({answer:"<your markdown answer here>",agreement:{level:"high|medium|mixed|conflicting",summary:"<one sentence>"},differences:["<notable difference between engines, if any>"],caveats:["<important caveat or limitation>"],recommendedSources:["S1","S2"]},null,2),"END_JSON"].join(`
|
|
12
|
-
`)}import{existsSync as S}from"node:fs";import{dirname as he,join as b}from"node:path";import{fileURLToPath as de}from"node:url";function P(t){return de(new URL(".",t)).replace(/^\/([A-Z]:)/,"$1")}function Ee(t,e=S){let i=new Set;for(let
|
|
12
|
+
`)}import{existsSync as S}from"node:fs";import{dirname as he,join as b}from"node:path";import{fileURLToPath as de}from"node:url";function P(t){return de(new URL(".",t)).replace(/^\/([A-Z]:)/,"$1")}function Ee(t,e=S){let i=new Set;for(let n of t.filter(Boolean)){if(i.has(n))continue;if(i.add(n),e(n))return n}return t.filter(Boolean).at(-1)}function K(t,{moduleDir:e,entrypoint:i=process.argv[1],env:n=process.env,exists:s=S}={}){let r=i?he(i):null,f=n.GREEDY_SEARCH_EXTENSION_DIR?.trim()||null,l=[e?b(e,"..","..","extractors",t):null,e?b(e,"..","extractors",t):null,f?b(f,"extractors",t):null,r?b(r,"..","extractors",t):null];return Ee(l,s)}var je=P(import.meta.url),Ce={gemini:"gemini.mjs",chatgpt:"chatgpt.mjs"},_e={gemini:"https://gemini.google.com/app",chatgpt:"https://chatgpt.com/"};function L(t="gemini"){let e=String(t||"gemini").toLowerCase();if(e==="gem")return"gemini";if(e==="gpt")return"chatgpt";return e}function Be(t="gemini"){return _e[L(t)]||"about:blank"}async function X(t,e,{tabPrefix:i=null,timeoutMs:n=180000,visible:s=null}={}){let r=L(t),f=Ce[r];if(!f||!C.includes(r))throw Error(`Unsupported synthesizer "${t}". Supported: ${C.join(", ")}`);let l=K(f,{moduleDir:je});return new Promise((o,c)=>{let a=i?["--tab",String(i)]:[],h={...process.env,CDP_PROFILE_DIR:N};if(s!==!0)delete h.GREEDY_SEARCH_VISIBLE,delete h.GREEDY_SEARCH_ALWAYS_VISIBLE;else h.GREEDY_SEARCH_VISIBLE="1",h.GREEDY_SEARCH_ALWAYS_VISIBLE="1";let g=ve(H(),[l,"--stdin",...a],{stdio:["pipe","pipe","pipe"],env:h});g.stdin.write(e),g.stdin.end();let j="",u="";g.stdout.on("data",(m)=>j+=m),g.stderr.on("data",(m)=>u+=m);let d=setTimeout(()=>{g.kill(),c(Error(`${r} prompt timed out after ${n/1000}s`))},n);g.on("close",(m)=>{if(clearTimeout(d),m!==0){c(Error(u.trim()||`${r} extractor failed`));return}try{o(JSON.parse(j.trim()))}catch{c(Error(`bad JSON from ${r}: ${j.slice(0,100)}`))}})})}async function Ve(t,e={}){return X("gemini",t,e)}async function Oe(t,e,{grounded:i=!1,tabPrefix:n=null,visible:s=null,synthesizer:r="gemini"}={}){let f=L(r),l=Array.isArray(e._sources)?e._sources:Y(e),o=A(t,e,l,{grounded:i}),c=await X(f,o,{tabPrefix:n,timeoutMs:180000,visible:s}),a=Z(c.answer||""),g=a&&["answer","agreement","claims","differences","caveats"].some((u)=>(u in a));if(a&&["perplexity","bing","google","chatgpt","gemini"].some((u)=>(u in a))&&!g)a=null;return{...x(a,l,c.answer||""),rawAnswer:c.answer||"",synthesizedBy:f,synthesizerSources:c.sources||[],geminiSources:f==="gemini"?c.sources||[]:[]}}async function Fe(t,e,i={}){return Oe(t,e,{...i,synthesizer:"gemini"})}export{Fe as synthesizeWithGemini,Oe as synthesizeResults,X as runSynthesisPrompt,Ve as runGeminiPrompt,L as normalizeSynthesizer,Be as getSynthesisStartUrl};
|
package/package.json
CHANGED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
# dm-9router-ext
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/dm-9router-ext)
|
|
4
|
-
|
|
5
|
-
DM extension for [9router](https://github.com/decolua/9router) — an open-source AI routing proxy.
|
|
6
|
-
|
|
7
|
-
**Install:** `dm install npm:dm-9router-ext`
|
|
8
|
-
|
|
9
|
-
Connects DM to your 9router instance via its OpenAI-compatible API, with dynamic model discovery and interactive configuration.
|
|
10
|
-
|
|
11
|
-
## Features
|
|
12
|
-
|
|
13
|
-
- **Auto-discovery** — Fetches available models and combos from 9router on startup
|
|
14
|
-
- **Dynamic provider** — Registers 9router as a DM provider with live model list
|
|
15
|
-
- **DM-native streaming** — Uses DM's built-in OpenAI completions provider without overriding other providers
|
|
16
|
-
- **Status commands** — `/9router-status`, `/9router-models`, `/9router-config`, `/9router-reload`
|
|
17
|
-
- **User-wide persistence** — Configuration survives new DM instances via `~/.dm/agent/9router-config.json`
|
|
18
|
-
- **Routing detection** — Captures upstream model info from response headers when available
|
|
19
|
-
|
|
20
|
-
## Installation
|
|
21
|
-
|
|
22
|
-
### npm (Recommended)
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
dm install npm:dm-9router-ext
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
### Via local path
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
# Clone or download the DM repo
|
|
32
|
-
git clone https://github.com/que-nguyen/dm.git
|
|
33
|
-
|
|
34
|
-
# Install locally
|
|
35
|
-
dm install /path/to/dm-9router-ext
|
|
36
|
-
|
|
37
|
-
# Or try without installing
|
|
38
|
-
dm -e /path/to/dm-9router-ext
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### Manual (copy to extensions)
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
cp -r dm-9router-ext/src/index.ts ~/.dm/agent/extensions/dm-9router-ext.ts
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Configuration
|
|
48
|
-
|
|
49
|
-
### Environment Variables
|
|
50
|
-
|
|
51
|
-
| Variable | Default | Description |
|
|
52
|
-
|----------|---------|-------------|
|
|
53
|
-
| `NINE_ROUTER_BASE_URL` | `http://localhost:20128` | Your 9router instance URL |
|
|
54
|
-
| `NINE_ROUTER_API_KEY` | — | API key if 9router has `REQUIRE_API_KEY=true` |
|
|
55
|
-
|
|
56
|
-
Set them in your shell profile or prefix your `dm` command:
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
NINE_ROUTER_BASE_URL=http://my-vps:20128 NINE_ROUTER_API_KEY=nr-... dm
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Interactive Configuration
|
|
63
|
-
|
|
64
|
-
Use the `/9router-config` command inside DM to set base URL and API key interactively. This is saved to `~/.dm/agent/9router-config.json` and is shared by new DM instances. Environment variables still take precedence when set.
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
/9router-config
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Usage
|
|
71
|
-
|
|
72
|
-
### Selecting a 9router Model
|
|
73
|
-
|
|
74
|
-
After the extension loads, 9router models are available in DM's model picker under the dedicated `9router/` provider namespace:
|
|
75
|
-
|
|
76
|
-
```
|
|
77
|
-
/model 9router/cc/claude-opus-4-7
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Built-in providers remain separate. To use Ollama Cloud, OpenRouter, opencode-go, etc., select their normal provider/model entries (for example `ollama-cloud/...`), not a `9router/...` model.
|
|
81
|
-
|
|
82
|
-
Or browse interactively:
|
|
83
|
-
|
|
84
|
-
```
|
|
85
|
-
/9router-models
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### Available Commands
|
|
89
|
-
|
|
90
|
-
| Command | Description |
|
|
91
|
-
|---------|-------------|
|
|
92
|
-
| `/9router-status` | Show connection status, model count, and config |
|
|
93
|
-
| `/9router-models` | Browse and select from available 9router models |
|
|
94
|
-
| `/9router-config` | Interactively configure base URL and API key |
|
|
95
|
-
| `/9router-reload` | Refresh model list from 9router |
|
|
96
|
-
|
|
97
|
-
### Available Tool
|
|
98
|
-
|
|
99
|
-
The LLM can call `ninerouter_status` to check connection status and list models programmatically.
|
|
100
|
-
|
|
101
|
-
## How It Works
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
┌─────────┐ OpenAI-compatible ┌──────────┐ ┌─────────────┐
|
|
105
|
-
│ DM │ ──────────────────────────▶│ 9router │ ──▶ │ Providers │
|
|
106
|
-
│ │ /v1/chat/completions │ (proxy) │ │ (40+) │
|
|
107
|
-
└─────────┘ └──────────┘ └─────────────┘
|
|
108
|
-
│
|
|
109
|
-
│ 1. Fetches /v1/models on startup
|
|
110
|
-
│ 2. Registers as provider "9router"
|
|
111
|
-
│ 3. Uses DM AI's OpenAI-compatible implementation for only 9router models
|
|
112
|
-
│ 4. Leaves built-in/non-9router model switching untouched
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
## Troubleshooting
|
|
116
|
-
|
|
117
|
-
**"Failed to discover models from 9router"**
|
|
118
|
-
- Check that 9router is running: `curl http://localhost:20128/v1/models`
|
|
119
|
-
- Verify `NINE_ROUTER_BASE_URL` points to the correct host/port
|
|
120
|
-
- If `REQUIRE_API_KEY=true`, set `NINE_ROUTER_API_KEY`
|
|
121
|
-
|
|
122
|
-
**"No 9router models discovered"**
|
|
123
|
-
- 9router may have no active providers. Open the dashboard and connect a provider.
|
|
124
|
-
- Use `/9router-reload` to retry discovery.
|
|
125
|
-
|
|
126
|
-
**Models not showing in `/model` selector**
|
|
127
|
-
- Ensure the extension loaded: check for "9router connected" notification on startup
|
|
128
|
-
- Run `/9router-reload` to retry discovery
|
|
129
|
-
- Run `/reload` to refresh extensions
|
|
130
|
-
|
|
131
|
-
**Built-in provider returns 401 after installing this extension**
|
|
132
|
-
- Make sure the active model is the built-in provider (`ollama-cloud/...`, `openrouter/...`, etc.), not a `9router/...` route.
|
|
133
|
-
- Re-run `/login` for the built-in provider if its subscription token expired.
|
|
134
|
-
- This extension only registers provider id `9router`; it does not override built-in providers. If 9router is unreachable, the extension unregisters the `9router` provider instead of leaving an empty/broken provider around.
|
|
135
|
-
|
|
136
|
-
## Similar Projects
|
|
137
|
-
|
|
138
|
-
- [omniroute-pi-extension](https://www.npmjs.com/package/omniroute-pi-extension) — DM extension for OmniRoute (a fork of 9router with additional features)
|
|
139
|
-
|
|
140
|
-
## License
|
|
141
|
-
|
|
142
|
-
MIT
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"strict": true,
|
|
7
|
-
"noEmit": true,
|
|
8
|
-
"allowImportingTsExtensions": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"types": [
|
|
11
|
-
"node"
|
|
12
|
-
]
|
|
13
|
-
},
|
|
14
|
-
"include": [
|
|
15
|
-
"src/**/*.ts"
|
|
16
|
-
]
|
|
17
|
-
}
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
# dm-ask-user — Interactive Form Tool for DM
|
|
2
|
-
|
|
3
|
-
A DM extension that registers a tool the LLM can call to ask the user structured questions using rich form controls: **radio buttons**, **checkboxes**, and **text inputs**.
|
|
4
|
-
|
|
5
|
-
Instead of the LLM asking questions in plain text and waiting for a freeform response, this tool presents an interactive TUI form where each question is typed, validated, and returned as structured data.
|
|
6
|
-
|
|
7
|
-
## How It Works
|
|
8
|
-
|
|
9
|
-
1. **LLM calls the tool** — Passes a JSON schema of questions with types, options, and metadata.
|
|
10
|
-
2. **Form renders** — An interactive panel appears in the terminal with typed controls for each question.
|
|
11
|
-
3. **User answers** — Navigate between questions, select options, type text, toggle checkboxes.
|
|
12
|
-
4. **Structured return** — Answers are returned to the LLM in a clean, structured format.
|
|
13
|
-
|
|
14
|
-
## Question Types
|
|
15
|
-
|
|
16
|
-
### Radio (single-select)
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
❯ ◉ PostgreSQL
|
|
20
|
-
○ MySQL
|
|
21
|
-
○ SQLite
|
|
22
|
-
○ Other...
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Pick exactly one option. Press Enter to select. The "Other..." option opens a text editor for a custom answer.
|
|
26
|
-
|
|
27
|
-
### Checkbox (multi-select)
|
|
28
|
-
|
|
29
|
-
```
|
|
30
|
-
❯ ☑ Unit tests
|
|
31
|
-
☑ Integration tests
|
|
32
|
-
☐ E2E tests
|
|
33
|
-
☐ Other...
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
Toggle multiple options with Space. The "Other..." option opens a text editor. Press Enter to advance.
|
|
37
|
-
|
|
38
|
-
### Text (free input)
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
┌─────────────────────────────────┐
|
|
42
|
-
│ Describe the migration strategy │
|
|
43
|
-
└─────────────────────────────────┘
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
A full multi-line editor. Shift+Enter for newlines, Enter to submit.
|
|
47
|
-
|
|
48
|
-
## Tool Schema
|
|
49
|
-
|
|
50
|
-
```json
|
|
51
|
-
{
|
|
52
|
-
"title": "Project Setup",
|
|
53
|
-
"description": "Let me configure the project based on your preferences",
|
|
54
|
-
"questions": [
|
|
55
|
-
{
|
|
56
|
-
"id": "database",
|
|
57
|
-
"type": "radio",
|
|
58
|
-
"prompt": "Which database should we use?",
|
|
59
|
-
"label": "Database",
|
|
60
|
-
"options": [
|
|
61
|
-
{ "value": "postgres", "label": "PostgreSQL", "description": "Best for complex queries" },
|
|
62
|
-
{ "value": "mysql", "label": "MySQL", "description": "Widely supported" },
|
|
63
|
-
{ "value": "sqlite", "label": "SQLite", "description": "Lightweight, file-based" }
|
|
64
|
-
],
|
|
65
|
-
"allowOther": true
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
"id": "testing",
|
|
69
|
-
"type": "checkbox",
|
|
70
|
-
"prompt": "Which test types should we set up?",
|
|
71
|
-
"label": "Testing",
|
|
72
|
-
"options": [
|
|
73
|
-
{ "value": "unit", "label": "Unit tests" },
|
|
74
|
-
{ "value": "integration", "label": "Integration tests" },
|
|
75
|
-
{ "value": "e2e", "label": "E2E tests" }
|
|
76
|
-
],
|
|
77
|
-
"allowOther": true
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
"id": "notes",
|
|
81
|
-
"type": "text",
|
|
82
|
-
"prompt": "Any additional notes or requirements?",
|
|
83
|
-
"label": "Notes",
|
|
84
|
-
"required": false,
|
|
85
|
-
"placeholder": "Type any extra context here..."
|
|
86
|
-
}
|
|
87
|
-
]
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### Question Fields
|
|
92
|
-
|
|
93
|
-
| Field | Type | Default | Description |
|
|
94
|
-
| ------------- | --------------------------------- | ---------------------- | ----------------------------------------------------- |
|
|
95
|
-
| `id` | `string` | _required_ | Unique identifier |
|
|
96
|
-
| `type` | `"radio"` \| `"checkbox"` \| `"text"` | _required_ | Control type |
|
|
97
|
-
| `prompt` | `string` | _required_ | The question text |
|
|
98
|
-
| `label` | `string` | `Q1`, `Q2`... | Short label for tab bar |
|
|
99
|
-
| `options` | `Option[]` | `[]` | Choices for radio/checkbox |
|
|
100
|
-
| `allowOther` | `boolean` | `true` (radio/checkbox) | Show "Other..." option with text input |
|
|
101
|
-
| `required` | `boolean` | `true` | Must be answered before submit |
|
|
102
|
-
| `placeholder` | `string` | — | Placeholder text for text inputs |
|
|
103
|
-
| `default` | `string` \| `string[]` | — | Default value(s) |
|
|
104
|
-
|
|
105
|
-
### Option Fields
|
|
106
|
-
|
|
107
|
-
| Field | Type | Description |
|
|
108
|
-
| ------------- | -------- | ---------------------------------- |
|
|
109
|
-
| `value` | `string` | Value returned to the LLM |
|
|
110
|
-
| `label` | `string` | Display label |
|
|
111
|
-
| `description` | `string` | Help text shown below the label |
|
|
112
|
-
|
|
113
|
-
## Panel Interface
|
|
114
|
-
|
|
115
|
-
### Single Question
|
|
116
|
-
|
|
117
|
-
```
|
|
118
|
-
──────────────────────────────────────────────────────
|
|
119
|
-
Which database should we use? [single-select]
|
|
120
|
-
*required
|
|
121
|
-
|
|
122
|
-
❯ ◉ PostgreSQL
|
|
123
|
-
Best for complex queries
|
|
124
|
-
○ MySQL
|
|
125
|
-
Widely supported
|
|
126
|
-
○ SQLite
|
|
127
|
-
Lightweight, file-based
|
|
128
|
-
○ Other...
|
|
129
|
-
|
|
130
|
-
↑↓ navigate • Enter select • Esc cancel
|
|
131
|
-
──────────────────────────────────────────────────────
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### Multiple Questions (tab bar)
|
|
135
|
-
|
|
136
|
-
```
|
|
137
|
-
──────────────────────────────────────────────────────
|
|
138
|
-
Project Setup
|
|
139
|
-
Let me configure the project based on your preferences
|
|
140
|
-
|
|
141
|
-
✓ Database │· Testing │· Notes │✓ Submit
|
|
142
|
-
|
|
143
|
-
Which test types should we set up? [multi-select]
|
|
144
|
-
*required
|
|
145
|
-
|
|
146
|
-
❯ ☑ Unit tests
|
|
147
|
-
☑ Integration tests
|
|
148
|
-
☐ E2E tests
|
|
149
|
-
☐ Other...
|
|
150
|
-
|
|
151
|
-
↑↓ navigate • Space toggle • Tab/←→ navigate • Enter next • Esc cancel
|
|
152
|
-
──────────────────────────────────────────────────────
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### Submit Tab (review)
|
|
156
|
-
|
|
157
|
-
```
|
|
158
|
-
──────────────────────────────────────────────────────
|
|
159
|
-
✓ Database │✓ Testing │✓ Notes │✓ Submit
|
|
160
|
-
|
|
161
|
-
Review & Submit
|
|
162
|
-
|
|
163
|
-
Database: PostgreSQL
|
|
164
|
-
Testing: unit, integration
|
|
165
|
-
Notes: Focus on API layer first
|
|
166
|
-
|
|
167
|
-
Press Enter to submit
|
|
168
|
-
|
|
169
|
-
Tab/←→ navigate questions • Enter submit • Esc cancel
|
|
170
|
-
──────────────────────────────────────────────────────
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
## Keyboard Reference
|
|
174
|
-
|
|
175
|
-
### Navigation
|
|
176
|
-
|
|
177
|
-
| Key | Action |
|
|
178
|
-
| ----------------- | ------------------------------------- |
|
|
179
|
-
| `Tab` / `→` | Next question (multi-question mode) |
|
|
180
|
-
| `Shift+Tab` / `←` | Previous question |
|
|
181
|
-
| `↑` / `↓` | Navigate options within a question |
|
|
182
|
-
|
|
183
|
-
### Selection
|
|
184
|
-
|
|
185
|
-
| Key | Action |
|
|
186
|
-
| ----------------- | ------------------------------------- |
|
|
187
|
-
| `Enter` | Select radio option / advance / submit |
|
|
188
|
-
| `Space` | Toggle checkbox option |
|
|
189
|
-
| `Enter` (text) | Submit text answer |
|
|
190
|
-
| `Shift+Enter` | Newline in text/other editor |
|
|
191
|
-
|
|
192
|
-
### Other
|
|
193
|
-
|
|
194
|
-
| Key | Action |
|
|
195
|
-
| ----------------- | ------------------------------------- |
|
|
196
|
-
| `Esc` | Cancel (in "Other" mode: go back) |
|
|
197
|
-
|
|
198
|
-
## Output Format
|
|
199
|
-
|
|
200
|
-
The tool returns structured text to the LLM:
|
|
201
|
-
|
|
202
|
-
```
|
|
203
|
-
Database: PostgreSQL
|
|
204
|
-
Testing: unit, integration, (wrote) GraphQL tests
|
|
205
|
-
Notes: Focus on API layer first
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
Custom "Other" answers are prefixed with `(wrote)` so the LLM knows they were user-typed.
|
|
209
|
-
|
|
210
|
-
## System Prompt Integration
|
|
211
|
-
|
|
212
|
-
The tool includes `promptSnippet` and `promptGuidelines` so the LLM knows when and how to use it:
|
|
213
|
-
|
|
214
|
-
- Prefers `ask_user_question` over plain-text questions
|
|
215
|
-
- Uses radio for single-choice, checkbox for multi-choice, text for open-ended
|
|
216
|
-
- Groups related questions in a single call
|
|
217
|
-
- Includes "Other" escape hatches by default
|
|
218
|
-
|
|
219
|
-
## Dependencies
|
|
220
|
-
|
|
221
|
-
| Package | Role |
|
|
222
|
-
| ------------------------------- | ------------------------------------------------- |
|
|
223
|
-
| `@duckmind/dm-coding-agent` | Extension API, theme types |
|
|
224
|
-
| `@duckmind/dm-tui` | TUI primitives: Editor, Key, matchesKey, etc. |
|
|
225
|
-
| `@duckmind/dm-ai` | `StringEnum` for Google-compatible enum schemas |
|
|
226
|
-
| `@sinclair/typebox` | JSON Schema definitions for tool parameters |
|