@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.
Files changed (97) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +159 -220
  3. package/extensions/dm-9router-ext/package.json +0 -6
  4. package/extensions/dm-9router-ext/src/index.js +1 -1
  5. package/extensions/dm-ask-user/package.json +0 -4
  6. package/extensions/dm-caveman/extensions/caveman.js +29 -0
  7. package/extensions/dm-caveman/package.json +20 -0
  8. package/extensions/dm-cli-anything/index.js +5 -5
  9. package/extensions/dm-cli-anything/package.json +0 -7
  10. package/extensions/dm-cli-anything/skills/cli-anything/SKILL.md +1 -3
  11. package/extensions/dm-context/package.json +0 -1
  12. package/extensions/dm-cua/package.json +0 -7
  13. package/extensions/dm-fff/package.json +0 -6
  14. package/extensions/dm-goal/package.json +0 -8
  15. package/extensions/dm-grill-me/index.js +2 -2
  16. package/extensions/dm-grill-me/package.json +0 -7
  17. package/extensions/dm-image2/package.json +0 -8
  18. package/extensions/dm-subagents/.m/artifacts/shell/shell_output_1783845384621_9cf9262bf674.txt +1336 -0
  19. package/extensions/dm-subagents/.m/artifacts/shell/shell_output_1783846154938_6a41cefee0bf.txt +1336 -0
  20. package/extensions/dm-subagents/package.json +0 -11
  21. package/extensions/dm-subagents/src/extension/doctor.js +10 -10
  22. package/extensions/dm-subagents/src/extension/fanout-child.js +97 -97
  23. package/extensions/dm-subagents/src/extension/index.js +121 -121
  24. package/extensions/dm-subagents/src/extension/rpc.js +5 -5
  25. package/extensions/dm-subagents/src/extension/schemas.js +1 -1
  26. package/extensions/dm-subagents/src/extension/tool-description.js +2 -2
  27. package/extensions/dm-subagents/src/intercom/native-supervisor-channel.js +5 -5
  28. package/extensions/dm-subagents/src/runs/background/async-execution.js +19 -19
  29. package/extensions/dm-subagents/src/runs/background/async-job-tracker.js +9 -9
  30. package/extensions/dm-subagents/src/runs/background/async-resume.js +5 -5
  31. package/extensions/dm-subagents/src/runs/background/async-status.js +8 -8
  32. package/extensions/dm-subagents/src/runs/background/fleet-view.js +13 -13
  33. package/extensions/dm-subagents/src/runs/background/result-watcher.js +5 -5
  34. package/extensions/dm-subagents/src/runs/background/run-id-resolver.js +3 -3
  35. package/extensions/dm-subagents/src/runs/background/run-status.js +19 -19
  36. package/extensions/dm-subagents/src/runs/background/stale-run-reconciler.js +7 -7
  37. package/extensions/dm-subagents/src/runs/background/subagent-runner.js +35 -35
  38. package/extensions/dm-subagents/src/runs/background/wait.js +7 -7
  39. package/extensions/dm-subagents/src/runs/foreground/chain-execution.js +32 -32
  40. package/extensions/dm-subagents/src/runs/foreground/execution.js +26 -26
  41. package/extensions/dm-subagents/src/runs/foreground/subagent-executor.js +96 -96
  42. package/extensions/dm-subagents/src/runs/shared/dm-args.js +1 -1
  43. package/extensions/dm-subagents/src/runs/shared/nested-events.js +6 -6
  44. package/extensions/dm-subagents/src/runs/shared/subagent-prompt-runtime.js +13 -13
  45. package/extensions/dm-subagents/src/shared/fork-context.js +4 -4
  46. package/extensions/dm-tasks/package.json +0 -7
  47. package/extensions/dm-usage/package.json +0 -7
  48. package/extensions/greedysearch-dm/bin/cdp-greedy.mjs +1 -8
  49. package/extensions/greedysearch-dm/bin/gschrome.mjs +3 -3
  50. package/extensions/greedysearch-dm/bin/launch-visible.mjs +3 -3
  51. package/extensions/greedysearch-dm/bin/launch.mjs +4 -4
  52. package/extensions/greedysearch-dm/bin/search.mjs +103 -103
  53. package/extensions/greedysearch-dm/extractors/consensus.mjs +35 -35
  54. package/extensions/greedysearch-dm/extractors/gemini.mjs +38 -38
  55. package/extensions/greedysearch-dm/extractors/logically.mjs +35 -35
  56. package/extensions/greedysearch-dm/package.json +0 -10
  57. package/extensions/greedysearch-dm/src/search/chrome.mjs +23 -23
  58. package/extensions/greedysearch-dm/src/search/fetch-source.mjs +35 -35
  59. package/extensions/greedysearch-dm/src/search/research.mjs +61 -61
  60. package/extensions/greedysearch-dm/src/search/synthesis-runner.mjs +4 -4
  61. package/package.json +1 -1
  62. package/extensions/dm-9router-ext/README.md +0 -142
  63. package/extensions/dm-9router-ext/tsconfig.json +0 -17
  64. package/extensions/dm-ask-user/README.md +0 -226
  65. package/extensions/dm-cli-anything/LICENSE +0 -201
  66. package/extensions/dm-cli-anything/README.md +0 -33
  67. package/extensions/dm-cli-anything/vendor/UPSTREAM.md +0 -14
  68. package/extensions/dm-context/AGENTS.md +0 -41
  69. package/extensions/dm-context/README.md +0 -18
  70. package/extensions/dm-context/tsconfig.json +0 -16
  71. package/extensions/dm-cua/README.md +0 -24
  72. package/extensions/dm-fff/README.md +0 -36
  73. package/extensions/dm-fff/tsconfig.json +0 -13
  74. package/extensions/dm-goal/CHANGELOG.md +0 -12
  75. package/extensions/dm-goal/LICENSE +0 -21
  76. package/extensions/dm-goal/README.md +0 -29
  77. package/extensions/dm-goal/tsconfig.json +0 -15
  78. package/extensions/dm-grill-me/DESIGN.md +0 -301
  79. package/extensions/dm-grill-me/LICENSE +0 -21
  80. package/extensions/dm-grill-me/README.md +0 -82
  81. package/extensions/dm-grill-me/tsconfig.json +0 -17
  82. package/extensions/dm-image2/README.md +0 -33
  83. package/extensions/dm-subagents/CHANGELOG.md +0 -1211
  84. package/extensions/dm-subagents/README.md +0 -29
  85. package/extensions/dm-subagents/banner.png +0 -0
  86. package/extensions/dm-subagents/biome.json +0 -26
  87. package/extensions/dm-subagents/tsconfig.json +0 -18
  88. package/extensions/dm-tasks/LICENSE +0 -21
  89. package/extensions/dm-tasks/README.md +0 -30
  90. package/extensions/dm-tasks/biome.json +0 -26
  91. package/extensions/dm-tasks/tsconfig.json +0 -14
  92. package/extensions/dm-usage/LICENSE +0 -21
  93. package/extensions/dm-usage/README.md +0 -29
  94. package/extensions/dm-usage/insights-screenshot.png +0 -0
  95. package/extensions/dm-usage/screenshot.png +0 -0
  96. package/extensions/greedysearch-dm/LICENSE +0 -21
  97. 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 o=B(e||"").toLowerCase();if(o==="node"||o==="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]),o=e.engines.filter((s)=>!y[s]);if(o.length>0)process.stderr.write(`[greedysearch] Warning: ignoring unknown engine(s) in ${E}: ${o.join(", ")}
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 o=i.slice(0,e),s=o.lastIndexOf(" ");return s>0?`${o.slice(0,s)}...`:`${o}...`}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,o=/[A-Z]/.test(e),s=/\d/.test(e);return e===e.toLowerCase()&&i<=4&&!o&&!s?"":e}function G(t="",e=""){let i=D(t),o=D(e);if(!o)return i;if(!i)return o;let s=/^https?:\/\//i.test(i),r=/^https?:\/\//i.test(o);if(s&&!r)return o;if(!s&&r)return i;return o.length>i.length?o: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 o=e.toString();return i==="/"?o.replace(/\/$/,""):o}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 o=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.")||o.includes("documentation")||o.includes("docs")||o.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 o of J){let s=o.replace(/\.com$/,"");if(e.includes(s))i.push(o)}return[...new Set(i)]}function I(t,e){return t===e||t.endsWith(`.${e}`)}function Y(t,e=""){let i=new Map,o=Object.keys(t||{}).filter((n)=>!n.startsWith("_")),s=ue(e);for(let n of o){let c=t[n];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(n))p.engines.push(n);p.perEngine[n]={rank:a+1,title:G(p.perEngine[n]?.title||"",j)},i.set(g,p)}}let r=Array.from(i.values()).map((n)=>({...n,engineCount:n.engines.length})),f=r.filter((n)=>n.sourceType!=="social"),l=r.filter((n)=>n.sourceType==="social");return f.sort((n,c)=>{let a=R(c)-R(n);if(a!==0)return a;return n.domain.localeCompare(c.domain)}),l.sort((n,c)=>{let a=R(c)-R(n);if(a!==0)return a;return n.domain.localeCompare(c.domain)}),[...f,...l].slice(0,12).map((n,c)=>({...n,id:`S${c+1}`,title:n.title||n.domain||n.canonicalUrl}))}function me(t){let e="",i=!1,o=!1;for(let s of String(t)){if(o){e+=s,o=!1;continue}if(s==="\\"){e+=s,o=!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"),o=e.indexOf("END_JSON");if(i!==-1&&o!==-1&&i<o)e=e.slice(i+10,o).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 n=me(l);if(n!==l)s.push(n)}for(let l of s)try{return JSON.parse(l)}catch{}return null}function x(t,e,i=""){let o=new Set(e.map((n)=>n.id)),s=["high","medium","low","mixed","conflicting"].includes(t?.agreement?.level)?t.agreement.level:"mixed",r=Array.isArray(t?.claims)?t.claims.map((n)=>({claim:v(n?.claim||"",260),support:["strong","moderate","weak","conflicting"].includes(n?.support)?n.support:"moderate",sourceIds:Array.isArray(n?.sourceIds)?n.sourceIds.filter((c)=>o.has(c)):[]})).filter((n)=>n.claim):[],f=Array.isArray(t?.recommendedSources)?t.recommendedSources.filter((n)=>o.has(n)).slice(0,6):[],l="";if(i){let n=i.indexOf("{"),c=i.lastIndexOf("}");if(n!==-1&&c!==-1&&n<c)l=i.slice(n,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((n)=>v(n,220)).filter(Boolean).slice(0,5):[],caveats:Array.isArray(t?.caveats)?t.caveats.map((n)=>v(n,220)).filter(Boolean).slice(0,5):[],claims:r,recommendedSources:f}}function A(t,e,i,{grounded:o=!1}={}){let s={};for(let l of["perplexity","bing","google"]){let n=e[l];if(!n)continue;if(n.error){s[l]={status:"error",error:String(n.error)};continue}s[l]={status:"ok",answer:v(n.answer||"",o?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=o?700:300,f=i.slice(0,o?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:
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 o of t.filter(Boolean)){if(i.has(o))continue;if(i.add(o),e(o))return o}return t.filter(Boolean).at(-1)}function K(t,{moduleDir:e,entrypoint:i=process.argv[1],env:o=process.env,exists:s=S}={}){let r=i?he(i):null,f=o.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:o=180000,visible:s=null}={}){let r=L(t),f=Ce[r];if(!f||!C.includes(r))throw Error(`Unsupported synthesizer "${t}". Supported: ${C.join(", ")}`);return new Promise((l,n)=>{let c=i?["--tab",String(i)]:[],a=K(f,{moduleDir:je}),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(),[a,"--stdin",...c],{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(),n(Error(`${r} prompt timed out after ${o/1000}s`))},o);g.on("close",(m)=>{if(clearTimeout(d),m!==0){n(Error(u.trim()||`${r} extractor failed`));return}try{l(JSON.parse(j.trim()))}catch{n(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:o=null,visible:s=null,synthesizer:r="gemini"}={}){let f=L(r),l=Array.isArray(e._sources)?e._sources:Y(e),n=A(t,e,l,{grounded:i}),c=await X(f,n,{tabPrefix:o,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};
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@duckmind/dm-darwin-x64",
3
- "version": "0.48.5",
3
+ "version": "0.49.6",
4
4
  "description": "DuckMind (dm) binary payload for darwin x64",
5
5
  "license": "MIT",
6
6
  "os": [
@@ -1,142 +0,0 @@
1
- # dm-9router-ext
2
-
3
- [![npm](https://img.shields.io/npm/v/dm-9router-ext?color=blue)](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 |