octocode-cli 1.5.0 → 1.5.3

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 (113) hide show
  1. package/README.md +167 -90
  2. package/out/chunks/chunk-375ZNU3A.js +317 -0
  3. package/out/chunks/{chunk-V64AXUWB.js → chunk-AYILFPX4.js} +1 -1
  4. package/out/chunks/chunk-BRHVQB64.js +10 -0
  5. package/out/chunks/{command-help-specs-JZXVSLZ5.js → chunk-KWJUBVXJ.js} +1 -1
  6. package/out/chunks/chunk-OMXWZJBJ.js +100 -0
  7. package/out/chunks/command-help-specs-RVJK6V6M.js +8 -0
  8. package/out/chunks/commands-JFDCC4Q7.js +8 -0
  9. package/out/chunks/{help-P7TCOYAJ.js → help-H3WGUJO7.js} +1 -1
  10. package/out/chunks/main-help-BUTDD4IR.js +10 -0
  11. package/out/chunks/{spinner-URV2OX6O.js → spinner-DXD4JQIU.js} +1 -1
  12. package/out/chunks/tool-command-L6PVHUNS.js +8 -0
  13. package/out/octocode-cli.js +1 -1
  14. package/package.json +2 -2
  15. package/skills/octocode-brainstorming/scripts/tavily-search.mjs +1 -10
  16. package/skills/octocode-chrome-devtools/scripts/cdp-runner.mjs +0 -2
  17. package/skills/octocode-chrome-devtools/scripts/cdp-sandbox.mjs +1 -5
  18. package/skills/octocode-chrome-devtools/scripts/cdp-template.mjs +1 -10
  19. package/skills/octocode-chrome-devtools/scripts/open-browser.mjs +0 -3
  20. package/skills/octocode-chrome-devtools/scripts/sourcemap-resolver.mjs +1 -4
  21. package/skills/octocode-chrome-devtools/scripts/undercover.mjs +0 -2
  22. package/skills/octocode-engineer/SKILL.md +7 -33
  23. package/skills/octocode-engineer/references/cli-reference.md +5 -11
  24. package/skills/octocode-engineer/references/externals.md +0 -4
  25. package/skills/octocode-engineer/references/quality-indicators.md +10 -50
  26. package/skills/octocode-engineer/references/tool-workflows.md +10 -13
  27. package/skills/octocode-engineer/src/analysis/dependency-summary.test.ts +2 -2
  28. package/skills/octocode-engineer/src/ast/metrics.test.ts +2 -2
  29. package/skills/octocode-engineer/src/ast/search-main.ts +2 -15
  30. package/skills/octocode-engineer/src/ast/search.ts +1 -7
  31. package/skills/octocode-engineer/src/ast/tree-sitter.test.ts +4 -4
  32. package/skills/octocode-engineer/src/ast/tree-sitter.ts +2 -2
  33. package/skills/octocode-engineer/src/collectors/chains.ts +3 -10
  34. package/skills/octocode-engineer/src/collectors/prototype-pollution.ts +3 -3
  35. package/skills/octocode-engineer/src/collectors/security.ts +3 -3
  36. package/skills/octocode-engineer/src/common/ensure-deps.ts +3 -20
  37. package/skills/octocode-engineer/src/detectors/code-quality.ts +0 -1
  38. package/skills/octocode-engineer/src/index.test.ts +1 -1
  39. package/skills/octocode-engineer/src/index.ts +1 -11
  40. package/skills/octocode-engineer/src/pipeline/affected.ts +2 -7
  41. package/skills/octocode-engineer/src/pipeline/baseline.ts +2 -8
  42. package/skills/octocode-engineer/src/pipeline/cache.ts +2 -2
  43. package/skills/octocode-engineer/src/pipeline/config-loader.test.ts +1 -2
  44. package/skills/octocode-engineer/src/pipeline/config-loader.ts +0 -9
  45. package/skills/octocode-engineer/src/pipeline/create-options.ts +2 -15
  46. package/skills/octocode-engineer/src/pipeline/reporters.ts +2 -12
  47. package/skills/octocode-engineer/src/reporting/summary-md.test.ts +2 -2
  48. package/skills/octocode-engineer/src/run.ts +1 -7
  49. package/skills/octocode-engineer/src/types/constants.ts +0 -5
  50. package/skills/octocode-engineer/src/types/core.ts +0 -5
  51. package/skills/octocode-news/eslint.config.mjs +1 -6
  52. package/skills/octocode-news/src/rss-core.ts +2 -4
  53. package/skills/octocode-research/ecosystem.config.cjs +0 -31
  54. package/skills/octocode-research/package.json +1 -1
  55. package/skills/octocode-research/scripts/server.js +272 -230
  56. package/skills/octocode-research/src/__tests__/integration/circuitBreaker.test.ts +0 -24
  57. package/skills/octocode-research/src/__tests__/integration/routes.test.ts +0 -10
  58. package/skills/octocode-research/src/__tests__/integration/serverLifecycle.test.ts +5 -22
  59. package/skills/octocode-research/src/__tests__/integration/toolsRoutes.test.ts +0 -27
  60. package/skills/octocode-research/src/__tests__/unit/circuitBreaker.test.ts +0 -29
  61. package/skills/octocode-research/src/__tests__/unit/errorHandler.test.ts +1 -12
  62. package/skills/octocode-research/src/__tests__/unit/httpPreprocess.test.ts +1 -9
  63. package/skills/octocode-research/src/__tests__/unit/logger.test.ts +0 -7
  64. package/skills/octocode-research/src/__tests__/unit/queryParser.test.ts +1 -7
  65. package/skills/octocode-research/src/__tests__/unit/responseBuilder.test.ts +0 -11
  66. package/skills/octocode-research/src/__tests__/unit/retry.test.ts +1 -18
  67. package/skills/octocode-research/src/__tests__/unit/schemas.test.ts +2 -25
  68. package/skills/octocode-research/src/index.ts +0 -27
  69. package/skills/octocode-research/src/mcpCache.ts +3 -18
  70. package/skills/octocode-research/src/middleware/errorHandler.ts +1 -4
  71. package/skills/octocode-research/src/middleware/logger.ts +1 -6
  72. package/skills/octocode-research/src/middleware/queryParser.ts +3 -22
  73. package/skills/octocode-research/src/routes/github.ts +0 -11
  74. package/skills/octocode-research/src/routes/local.ts +0 -12
  75. package/skills/octocode-research/src/routes/lsp.ts +1 -10
  76. package/skills/octocode-research/src/routes/package.ts +0 -2
  77. package/skills/octocode-research/src/routes/prompts.ts +2 -32
  78. package/skills/octocode-research/src/routes/tools.ts +12 -177
  79. package/skills/octocode-research/src/server-init.ts +0 -32
  80. package/skills/octocode-research/src/server.ts +8 -37
  81. package/skills/octocode-research/src/types/errorGuards.ts +0 -15
  82. package/skills/octocode-research/src/types/guards.ts +6 -27
  83. package/skills/octocode-research/src/types/mcp.ts +1 -8
  84. package/skills/octocode-research/src/types/responses.ts +0 -15
  85. package/skills/octocode-research/src/utils/asyncTimeout.ts +1 -63
  86. package/skills/octocode-research/src/utils/circuitBreaker.ts +43 -166
  87. package/skills/octocode-research/src/utils/colors.ts +3 -17
  88. package/skills/octocode-research/src/utils/errorQueue.ts +6 -28
  89. package/skills/octocode-research/src/utils/logger.ts +11 -93
  90. package/skills/octocode-research/src/utils/resilience.ts +22 -77
  91. package/skills/octocode-research/src/utils/responseBuilder.ts +26 -78
  92. package/skills/octocode-research/src/utils/responseFactory.ts +0 -7
  93. package/skills/octocode-research/src/utils/responseParser.ts +11 -59
  94. package/skills/octocode-research/src/utils/retry.ts +12 -75
  95. package/skills/octocode-research/src/utils/routeFactory.ts +10 -61
  96. package/skills/octocode-research/src/utils/url.ts +0 -5
  97. package/skills/octocode-research/src/validation/httpPreprocess.ts +15 -61
  98. package/skills/octocode-research/src/validation/schemas.ts +14 -101
  99. package/skills/octocode-research/src/validation/toolCallSchema.ts +5 -65
  100. package/skills/octocode-research/tsdown.config.ts +2 -7
  101. package/skills/octocode-search-skill/SKILL.md +9 -2
  102. package/skills/octocode-search-skill/references/discovery-surfaces.md +2 -1
  103. package/skills/octocode-slides/scripts/navbridge.js +1 -14
  104. package/skills/octocode-slides/scripts/presenter.js +2 -61
  105. package/skills/octocode-stats/scripts/build_dashboard.mjs +1 -19
  106. package/assets/example.png +0 -0
  107. package/out/chunks/chunk-7476PETK.js +0 -309
  108. package/out/chunks/chunk-OQBJTZWK.js +0 -60
  109. package/out/chunks/chunk-UCZCF3BQ.js +0 -9
  110. package/out/chunks/commands-XBFPLHSQ.js +0 -8
  111. package/out/chunks/main-help-ULF5PAQY.js +0 -10
  112. package/out/chunks/tool-command-M6VA7P2F.js +0 -8
  113. package/skills/octocode-research/AGENTS.md +0 -349
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __createRequire } from 'module';
3
+ import { fileURLToPath as __fileURLToPath } from 'url';
4
+ import { dirname as __dirname_fn } from 'path';
5
+ const require = __createRequire(import.meta.url);
6
+ const __filename = __fileURLToPath(import.meta.url);
7
+ const __dirname = __dirname_fn(__filename);
8
+ import{k as o}from"./chunk-OMXWZJBJ.js";import"./chunk-BRHVQB64.js";import"./chunk-CVNNNSMQ.js";import"./chunk-375ZNU3A.js";import"./chunk-KWJUBVXJ.js";import"./chunk-AYILFPX4.js";import"./chunk-YBBF4DTY.js";function C(n){let m=o(n);return m?e(m):void 0}function e(n){let{handler:m,...d}=n;return d}export{C as findStaticCommandHelp};
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __createRequire } from 'module';
3
+ import { fileURLToPath as __fileURLToPath } from 'url';
4
+ import { dirname as __dirname_fn } from 'path';
5
+ const require = __createRequire(import.meta.url);
6
+ const __filename = __fileURLToPath(import.meta.url);
7
+ const __dirname = __dirname_fn(__filename);
8
+ import{a,b,c,d,e,f,g,h,i,j,k}from"./chunk-OMXWZJBJ.js";import"./chunk-BRHVQB64.js";import"./chunk-CVNNNSMQ.js";import"./chunk-375ZNU3A.js";import"./chunk-KWJUBVXJ.js";import"./chunk-AYILFPX4.js";import"./chunk-YBBF4DTY.js";export{e as authCommand,h as cacheCommand,k as findCommand,a as installCommand,c as loginCommand,d as logoutCommand,g as mcpCommand,f as skillsCommand,i as statusCommand,j as syncCommand,b as tokenCommand};
@@ -5,6 +5,6 @@ import { dirname as __dirname_fn } from 'path';
5
5
  const require = __createRequire(import.meta.url);
6
6
  const __filename = __fileURLToPath(import.meta.url);
7
7
  const __dirname = __dirname_fn(__filename);
8
- import{a as n,b as e,c as p}from"./chunk-V64AXUWB.js";import"./chunk-YBBF4DTY.js";function r(t){let o=["",` ${n("magenta",e("\u{1F50D}\u{1F419} octocode "+t.name))}`,"",` ${t.description}`,""];if(t.usage&&(o.push(` ${e("USAGE")}`),o.push(` ${t.usage}`),o.push("")),t.options&&t.options.length>0){o.push(` ${e("OPTIONS")}`);for(let s of t.options){let i=s.short?`-${s.short}, `:" ",u=`--${s.name}`,a=s.hasValue?" <value>":"",l=s.default!==void 0?p(` (default: ${s.default})`):"";o.push(` ${n("cyan",i+u+a)}${l}`),o.push(` ${s.description}`)}o.push("")}process.stdout.write(`${o.join(`
8
+ import{a as n,b as e,c as p}from"./chunk-AYILFPX4.js";import"./chunk-YBBF4DTY.js";function r(t){let o=["",` ${n("magenta",e("\u{1F50D}\u{1F419} octocode "+t.name))}`,"",` ${t.description}`,""];if(t.usage&&(o.push(` ${e("USAGE")}`),o.push(` ${t.usage}`),o.push("")),t.options&&t.options.length>0){o.push(` ${e("OPTIONS")}`);for(let s of t.options){let i=s.short?`-${s.short}, `:" ",u=`--${s.name}`,a=s.hasValue?" <value>":"",l=s.default!==void 0?p(` (default: ${s.default})`):"";o.push(` ${n("cyan",i+u+a)}${l}`),o.push(` ${s.description}`)}o.push("")}process.stdout.write(`${o.join(`
9
9
  `)}
10
10
  `)}export{r as showCommandHelp};
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __createRequire } from 'module';
3
+ import { fileURLToPath as __fileURLToPath } from 'url';
4
+ import { dirname as __dirname_fn } from 'path';
5
+ const require = __createRequire(import.meta.url);
6
+ const __filename = __fileURLToPath(import.meta.url);
7
+ const __dirname = __dirname_fn(__filename);
8
+ import{a as i,b as c,d as r}from"./chunk-375ZNU3A.js";import"./chunk-KWJUBVXJ.js";import{a as o,b as e,c as t}from"./chunk-AYILFPX4.js";import"./chunk-YBBF4DTY.js";function $(){let l=[];for(let a of i){let s=c.filter(n=>r(n.name)===a);if(s.length!==0){l.push(` ${t(a)}`);for(let n of s)l.push(` ${o("cyan",n.name)}`)}}return l}function g(){let l=$(),a=c.length,s=["",` ${o("magenta",e("\u{1F50D}\u{1F419} Octocode CLI"))}`,"",` ${e("INSTRUCTIONS FOR AGENTS")} ${t("(do this before making any tool request)")}`,` ${t("0.")} Load agent context (protocol + tools + fields) ${o("yellow","octocode --agent")}`,` ${t("1.")} List all available tools ${o("yellow","octocode tools")}`,` ${t("2.")} Read a tool's input schema ${o("yellow","octocode tools <name>")}`,` ${t("3.")} Full context with every JSON schema inline ${o("yellow","octocode --agent --full")}`,"",` ${e("USAGE")}`,` ${o("magenta","octocode")} <command> [options] ${t("manage Octocode")}`,` ${o("magenta","octocode")} tools ${t("list all tools")}`,` ${o("magenta","octocode")} tools <name> ${t("show input schema")}`,` ${o("magenta","octocode")} tools <n1> <n2> ... ${t("batch input schemas")}`,` ${o("magenta","octocode")} tools <name> --queries '<json>' ${t("run a tool")}`,` ${o("magenta","octocode")} instructions ${t("MCP instructions + all schemas")}`,"",` ${e("COMMANDS")} ${t("(manage Octocode configuration)")}`,` ${o("magenta","install")} Configure octocode-mcp for an IDE`,` ${o("magenta","auth")} Manage GitHub authentication`,` ${o("magenta","login / logout")} Sign in or out of GitHub`,` ${o("magenta","status / token")} Show auth status or print token`,` ${o("magenta","skills")} Search, install & manage Octocode skills`,` ${o("magenta","mcp")} Manage MCP marketplace`,` ${o("magenta","sync")} Sync MCP configs across IDEs`,` ${o("magenta","cache")} Inspect and clean Octocode cache`,"",` ${e("SKILLS")} ${t("(octocode skills <subcommand>)")}`,` ${o("magenta","search")} ${t("<query>")} Find skills ${t("(agent protocol; --direct for skills.sh results)")}`,` ${o("magenta","read")} ${t("<path|url>")} Print a SKILL.md ${t("(local path, owner/repo/path, or GitHub URL)")}`,` ${o("magenta","list")} List skills installed across all AI clients`,` ${o("magenta","install")} Install skills ${t("(--skill <name>, --local <path>, --targets <list>)")}`,` ${o("magenta","remove")} Remove a skill ${t("(--skill <name> or --local <path>)")}`,` ${o("magenta","sync")} ${t("<from> <to>")} Copy skills from one client target to another`,"",` ${e("TOOLS")} ${t(`(${a} tools \u2014 run directly from terminal)`)}`,...l,"",` ${e("OPTIONS")}`,` ${o("cyan","--json")} Raw JSON (full MCP envelope) for tool runs`,` ${o("cyan","--compact")} Leanest tool output (concise verbosity, fewer tokens)`,` ${o("cyan","--no-color")} Disable ANSI colors (also via NO_COLOR=1)`,` ${o("cyan","-h, --help")} Show this help`,` ${o("cyan","-v, --version")} Show version`,"",` ${e("EXAMPLES")}`,` ${o("yellow","octocode tools")} ${t("# list")}`,` ${o("yellow","octocode tools localSearchCode")} ${t("# schema")}`,` ${o("yellow","octocode tools localSearchCode githubSearchCode")} ${t("# batch schemas")}`,` ${o("yellow",`octocode tools localSearchCode --queries '{"path":".","pattern":"fn"}'`)} ${t("# run")}`,` ${o("yellow","octocode instructions")} ${t("# full context")}`,"",` ${o("yellow","octocode install --ide cursor")}`,` ${o("yellow",'octocode skills search "code review"')} ${t("# find skills")}`,` ${o("yellow",'octocode skills search "code review" --direct')} ${t("# skills.sh results")}`,` ${o("yellow","octocode skills install --targets claude-code,cursor")}`,"",o("magenta",` \u2500\u2500\u2500 \u{1F50D}\u{1F419} ${e("https://octocode.ai")} \u2500\u2500\u2500`),""];process.stdout.write(`${s.join(`
9
+ `)}
10
+ `)}export{g as showHelp};
@@ -5,4 +5,4 @@ import { dirname as __dirname_fn } from 'path';
5
5
  const require = __createRequire(import.meta.url);
6
6
  const __filename = __fileURLToPath(import.meta.url);
7
7
  const __dirname = __dirname_fn(__filename);
8
- import{a}from"./chunk-UCZCF3BQ.js";import"./chunk-V64AXUWB.js";import"./chunk-YBBF4DTY.js";export{a as Spinner};
8
+ import{a}from"./chunk-BRHVQB64.js";import"./chunk-AYILFPX4.js";import"./chunk-YBBF4DTY.js";export{a as Spinner};
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __createRequire } from 'module';
3
+ import { fileURLToPath as __fileURLToPath } from 'url';
4
+ import { dirname as __dirname_fn } from 'path';
5
+ const require = __createRequire(import.meta.url);
6
+ const __filename = __fileURLToPath(import.meta.url);
7
+ const __dirname = __dirname_fn(__filename);
8
+ import{a,b,c,d,e,f,g,h,i,j,k,l}from"./chunk-375ZNU3A.js";import"./chunk-KWJUBVXJ.js";import"./chunk-AYILFPX4.js";import"./chunk-YBBF4DTY.js";export{a as TOOL_CATEGORIES,b as TOOL_DEFINITIONS,k as executeToolCommand,c as findToolDefinition,e as getDisplayFields,d as getToolCategory,i as getToolsContextString,j as printToolsContext,f as showAvailableTools,h as showMultipleToolSchemas,g as showToolHelp,l as toolCommand};
@@ -5,4 +5,4 @@ import { dirname as __dirname_fn } from 'path';
5
5
  const require = __createRequire(import.meta.url);
6
6
  const __filename = __fileURLToPath(import.meta.url);
7
7
  const __dirname = __dirname_fn(__filename);
8
- import{c as d}from"./chunks/chunk-V64AXUWB.js";import"./chunks/chunk-YBBF4DTY.js";var p=new Set(["ide","method","m","output","o","hostname","H","git-protocol","p","type","t","skill","k","local","limit","l","targets","mode","model","resume","r","id","client","c","search","category","env","config","tool","queries","input","responseCharLength","responseCharOffset","target","backup-path"]),S=new Set(["help","h","version","v","force","source","json","status","dry-run","installed","repos","skills","logs","all","tools","full","direct","lsp","api","list","schema","tools-context","check","rollback","install","yes","y","validate","sync"]),T=new Set(["output","responseCharLength","responseCharOffset","tool","queries"]);function h(t,o){return S.has(o)?!1:p.has(o)?!0:t.command==="tool"||typeof t.options.tool=="string"}function g(t=process.argv.slice(2)){let o={command:null,args:[],options:{}},e=0;for(;e<t.length;){let i=t[e];if(i.startsWith("--")){let[s,n]=i.slice(2).split("=");n!==void 0?o.options[s]=n:h(o,s)&&e+1<t.length&&!t[e+1].startsWith("-")?(o.options[s]=t[e+1],e++):o.options[s]=!0}else if(i.startsWith("-")&&!i.startsWith("--")&&i.length>2){let s=i.slice(1),[n,r]=s.split("=");if(T.has(n))r!==void 0?o.options[n]=r:h(o,n)&&e+1<t.length&&!t[e+1].startsWith("-")?(o.options[n]=t[e+1],e++):o.options[n]=!0;else{let a=s,c=a[a.length-1];if(a.length===1&&p.has(c)&&e+1<t.length&&!t[e+1].startsWith("-"))o.options[c]=t[e+1],e++;else for(let m of a)o.options[m]=!0}}else if(i.startsWith("-")&&i.length>1){let s=i.slice(1),n=s[s.length-1];if(s.length===1&&p.has(n)&&e+1<t.length&&!t[e+1].startsWith("-"))o.options[n]=t[e+1],e++;else for(let r of s)o.options[r]=!0}else o.command||typeof o.options.tool=="string"?o.args.push(i):o.command=i;e++}return!o.command&&typeof o.options.tool=="string"&&(o.command="tool",o.args=[o.options.tool,...o.args]),o}function w(t){return!!(t.options.help||t.options.h)}function C(t){return!!(t.options.version||t.options.v)}async function P(){return import("./chunks/commands-XBFPLHSQ.js")}async function H(){return import("./chunks/command-help-specs-JZXVSLZ5.js")}async function l(){return import("./chunks/tool-command-M6VA7P2F.js")}async function u(){return import("./chunks/main-help-ULF5PAQY.js")}async function _(){return import("./chunks/help-P7TCOYAJ.js")}function I(){console.log(),console.log(" Use octocode --tool <toolName> --queries '<json-stringified-input>'."),console.log(` Example: octocode --tool localSearchCode --queries '{"path":".","pattern":"runCLI"}'`),console.log()}function A(){console.log("octocode v1.5.0")}async function y(t){let o=g(t);if(o.options["tools-context"]===!0){let{printToolsContext:s}=await l();return await s(),!0}if(w(o)){if(o.command==="tool"&&typeof o.options.tool=="string"&&typeof o.args[0]=="string"){let{showToolHelp:n}=await l();if(await n(o.args[0]))return!0}if(o.command==="tool"){let{showHelp:n}=await u();return n(),!0}if(o.command==="tools"){if(typeof o.args[0]=="string"){let{showToolHelp:r}=await l();if(await r(o.args[0]))return!0}let{showAvailableTools:n}=await l();return await n(),!0}if(o.command){let[{findStaticCommandHelp:n},{showCommandHelp:r}]=await Promise.all([H(),_()]),a=n(o.command);if(a)return r(a),!0;let[{findCommand:c},{showHelp:m}]=await Promise.all([P(),u()]),f=c(o.command);return f?(r(f),!0):(m(),!0)}let{showHelp:s}=await u();return s(),!0}if(C(o))return A(),!0;if(!o.command)return!1;if(o.command==="tool")return typeof o.options.tool!="string"?(I(),process.exitCode=1,!0):(await(await l()).executeToolCommand(o)||(process.exitCode=1),!0);if(o.command==="tools"){let{executeToolCommand:s}=await l();return await s(o)||(process.exitCode=1),!0}if(o.command==="instructions"){let{printToolsContext:s}=await l();return await s(),!0}let{findCommand:e}=await P(),i=e(o.command);return i?(await i.handler(o),!0):(console.log(),console.log(` Unknown command: ${o.command}`),console.log(" Run 'octocode --help' to see available commands."),console.log(),process.exitCode=1,!0)}async function L(){let{showHelp:t}=await import("./chunks/main-help-ULF5PAQY.js");t()}async function N(){await y()||await L()}function x(){process.stdout.write("\x1B[?25h"),console.log(),console.log(d(" Goodbye! \u{1F44B}")),process.exit(0)}process.on("SIGINT",x);process.on("SIGTERM",x);N().catch(t=>{t?.name==="ExitPromptError"&&(console.log(),console.log(d(" Goodbye! \u{1F44B}")),process.exit(0)),console.error("Error:",t),process.exit(1)});
8
+ import{a as c}from"./chunks/chunk-KWJUBVXJ.js";import{c as u}from"./chunks/chunk-AYILFPX4.js";import"./chunks/chunk-YBBF4DTY.js";var d=new Set(["ide","method","m","output","o","hostname","H","git-protocol","p","type","t","skill","k","local","limit","l","targets","mode","model","resume","r","id","client","c","search","category","env","config","tool","queries","format","input","responseCharLength","responseCharOffset","target","backup-path"]),S=new Set(["help","h","version","v","force","source","json","status","dry-run","installed","repos","skills","logs","all","tools","full","direct","lsp","api","list","schema","tools-context","agent","compact","full","no-color","reveal","raw","check","rollback","install","yes","y","validate","sync"]),_=new Set(["output","responseCharLength","responseCharOffset","tool","queries"]);function g(t,o){return S.has(o)?!1:d.has(o)?!0:t.command==="tool"||typeof t.options.tool=="string"}function w(t=process.argv.slice(2)){let o={command:null,args:[],options:{}},e=0;for(;e<t.length;){let i=t[e];if(i.startsWith("--")){let[s,n]=i.slice(2).split("=");n!==void 0?o.options[s]=n:g(o,s)&&e+1<t.length&&!t[e+1].startsWith("-")?(o.options[s]=t[e+1],e++):o.options[s]=!0}else if(i.startsWith("-")&&!i.startsWith("--")&&i.length>2){let s=i.slice(1),[n,r]=s.split("=");if(_.has(n))r!==void 0?o.options[n]=r:g(o,n)&&e+1<t.length&&!t[e+1].startsWith("-")?(o.options[n]=t[e+1],e++):o.options[n]=!0;else{let l=s,m=l[l.length-1];if(l.length===1&&d.has(m)&&e+1<t.length&&!t[e+1].startsWith("-"))o.options[m]=t[e+1],e++;else for(let p of l)o.options[p]=!0}}else if(i.startsWith("-")&&i.length>1){let s=i.slice(1),n=s[s.length-1];if(s.length===1&&d.has(n)&&e+1<t.length&&!t[e+1].startsWith("-"))o.options[n]=t[e+1],e++;else for(let r of s)o.options[r]=!0}else o.command||typeof o.options.tool=="string"?o.args.push(i):o.command=i;e++}return!o.command&&typeof o.options.tool=="string"&&(o.command="tool",o.args=[o.options.tool,...o.args]),o}function C(t){return!!(t.options.help||t.options.h)}function P(t){return!!(t.options.version||t.options.v)}async function y(){return import("./chunks/commands-JFDCC4Q7.js")}async function A(){return import("./chunks/command-help-specs-RVJK6V6M.js")}async function a(){return import("./chunks/tool-command-L6PVHUNS.js")}async function f(){return import("./chunks/main-help-BUTDD4IR.js")}async function H(){return import("./chunks/help-H3WGUJO7.js")}function I(){console.log(),console.log(" Use octocode --tool <toolName> --queries '<json-stringified-input>'."),console.log(` Example: octocode --tool localSearchCode --queries '{"path":".","pattern":"runCLI"}'`),console.log()}function L(){console.log("octocode v1.5.3")}async function x(t){let o=w(t);if(o.options["no-color"]===!0&&(process.env.NO_COLOR="1"),o.options["tools-context"]===!0||o.options.agent===!0){let{printToolsContext:s}=await a();return await s({full:o.options.full===!0}),!0}if(C(o)){if(o.command==="tool"&&typeof o.options.tool=="string"&&typeof o.args[0]=="string"){let{showToolHelp:n}=await a();if(await n(o.args[0]))return!0}if(o.command==="tool"){let{showHelp:n}=await f();return n(),!0}if(o.command==="tools"){if(typeof o.args[0]=="string"){let{showToolHelp:r}=await a();if(await r(o.args[0]))return!0}let{showAvailableTools:n}=await a();return await n(),!0}if(o.command){let[{findStaticCommandHelp:n},{showCommandHelp:r}]=await Promise.all([A(),H()]),l=n(o.command);if(l)return r(l),!0;let[{findCommand:m},{showHelp:p}]=await Promise.all([y(),f()]),h=m(o.command);return h?(r(h),!0):(p(),!0)}let{showHelp:s}=await f();return s(),!0}if(P(o))return L(),!0;if(!o.command)return!1;if(o.command==="tool")return typeof o.options.tool!="string"?(I(),process.exitCode=c.USAGE,!0):(!await(await a()).executeToolCommand(o)&&!process.exitCode&&(process.exitCode=c.GENERAL),!0);if(o.command==="tools"){let{executeToolCommand:s}=await a();return!await s(o)&&!process.exitCode&&(process.exitCode=c.GENERAL),!0}if(o.command==="instructions"||o.command==="agent"){let{printToolsContext:s}=await a();return await s({full:o.options.full===!0}),!0}let{findCommand:e}=await y(),i=e(o.command);return i?(await i.handler(o),!0):(console.log(),console.log(` Unknown command: ${o.command}`),console.log(" Run 'octocode --help' to see available commands."),console.log(),process.exitCode=c.NOT_FOUND,!0)}async function N(){let{showHelp:t}=await import("./chunks/main-help-BUTDD4IR.js");t()}async function O(){await x()||await N()}function T(){process.stdout.write("\x1B[?25h"),console.log(),console.log(u(" Goodbye! \u{1F44B}")),process.exit(0)}process.on("SIGINT",T);process.on("SIGTERM",T);O().catch(t=>{t?.name==="ExitPromptError"&&(console.log(),console.log(u(" Goodbye! \u{1F44B}")),process.exit(0)),console.error("Error:",t),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "octocode-cli",
3
- "version": "1.5.0",
3
+ "version": "1.5.3",
4
4
  "description": "Interactive CLI installer for octocode-mcp - Configure MCP servers for Cursor, Claude Desktop, and more",
5
5
  "keywords": [
6
6
  "ai-coding",
@@ -68,7 +68,7 @@
68
68
  "@vitest/coverage-v8": "^4.0.16",
69
69
  "esbuild": "^0.27.2",
70
70
  "eslint": "^9.18.0",
71
- "octocode-mcp": "^15.0.0",
71
+ "octocode-mcp": "^15.0.2",
72
72
  "octocode-shared": "workspace:^",
73
73
  "open": "^11.0.0",
74
74
  "tsx": "^4.21.0",
@@ -1,14 +1,5 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * Tavily web search for octocode-brainstorming.
4
- *
5
- * Usage:
6
- * node tavily-search.mjs --query "prior art for X" [--depth basic|advanced] [--max-results 8] [--topic general|news] [--time-range month|year]
7
- * node tavily-search.mjs --check # exits 0 if key is set, 1 otherwise
8
- *
9
- * Requires TAVILY_API_KEY in env or in <skill_dir>/.env
10
- * Outputs JSON to stdout; progress/errors to stderr. Never prints the key.
11
- */
2
+
12
3
 
13
4
  import { readFileSync } from 'node:fs';
14
5
  import { resolve, dirname } from 'node:path';
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- // Run a generated `run(cdp)` script against a Chrome CDP target.
3
2
 
4
3
  import { resolve, join } from 'path';
5
4
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
@@ -392,7 +391,6 @@ async function main() {
392
391
  console.error(`[CDP_RUNNER] Session meta dir: ${sessionMetaDir}`);
393
392
  console.error(`[CDP_RUNNER] Connected - running ${scriptArg}`);
394
393
 
395
- // Node PM has no scoped networking; keep generated script fetch/WebSocket on localhost.
396
394
  const _origFetch = globalThis.fetch;
397
395
  const _OrigWS = globalThis.WebSocket;
398
396
  function isLocalhost(url) {
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- // Run cdp-runner.mjs with Node permissions, output isolation, and a process timeout.
3
2
 
4
3
  import { spawn } from 'child_process';
5
4
  import { resolve, dirname, join } from 'path';
@@ -32,7 +31,6 @@ mkdirSync(OUTPUT_DIR, { recursive: true, mode: 0o700 });
32
31
  const SESSION_META_DIR = join(tmpdir(), '.octocode-chrome-devtools', 'session-meta', `port-${PORT}`);
33
32
  mkdirSync(SESSION_META_DIR, { recursive: true, mode: 0o700 });
34
33
 
35
- // Node 22 normalizes --allow-fs-* entries to realpaths; pass symlink and real forms.
36
34
  const safePath = (p) => { try { return realpathSync(p); } catch { return p; } };
37
35
 
38
36
  const TMPDIR_RAW = tmpdir();
@@ -41,7 +39,6 @@ const RUNNER_REAL = safePath(RUNNER);
41
39
  const OUTPUT_REAL = safePath(OUTPUT_DIR);
42
40
  const SESSION_META_REAL = safePath(SESSION_META_DIR);
43
41
 
44
- // Stage helpers next to generated $TMPDIR scripts so relative imports work.
45
42
  const HELPERS = ['sourcemap-resolver.mjs', 'undercover.mjs'];
46
43
  for (const helper of HELPERS) {
47
44
  const src = resolve(__dir, helper);
@@ -66,7 +63,6 @@ if (scriptArg) {
66
63
 
67
64
  const spawnArgv = argv.map(a => (a === scriptArg && scriptReal) ? scriptReal : a);
68
65
 
69
- // Node PM has no stable scoped --allow-net; cdp-runner restricts fetch/WebSocket to localhost.
70
66
  const readPaths = [...new Set([RUNNER, RUNNER_REAL, TMPDIR_RAW, TMPDIR_REAL, ...allowReadExtra])];
71
67
  const writePaths = [...new Set([OUTPUT_DIR, OUTPUT_REAL, SESSION_META_DIR, SESSION_META_REAL])];
72
68
 
@@ -106,7 +102,7 @@ const scriptTimer = setTimeout(() => {
106
102
  child.kill('SIGTERM');
107
103
  setTimeout(() => child.kill('SIGKILL'), 2000).unref();
108
104
  }, SCRIPT_TIMEOUT_MS);
109
- scriptTimer.unref(); // don't keep the process alive on its own
105
+ scriptTimer.unref();
110
106
 
111
107
  child.on('exit', (code, signal) => {
112
108
  clearTimeout(scriptTimer);
@@ -1,17 +1,9 @@
1
- // Base run(cdp) template. Save task copies in $TMPDIR and run with cdp-sandbox.mjs.
2
1
 
3
2
  export async function run(cdp) {
4
- // Optional: source maps must be registered before navigation.
5
- // const { createSourceMapResolver } = await import(new URL('./sourcemap-resolver.mjs', import.meta.url).href);
6
- // const resolver = await createSourceMapResolver(cdp);
7
3
 
8
4
  await cdp.send('Runtime.enable', {});
9
5
  await cdp.send('Network.enable', {});
10
6
  await cdp.send('Log.enable', {});
11
- // await cdp.send('Page.enable', {});
12
- // await cdp.send('DOM.enable', {});
13
- // await cdp.send('CSS.enable', {});
14
- // await cdp.send('Performance.enable', {});
15
7
 
16
8
  console.log(`[METRIC] Inspecting: ${cdp.targetInfo.url}`);
17
9
  cdp.addReasoningStep?.({
@@ -64,9 +56,8 @@ export async function run(cdp) {
64
56
  console.log(`[LOG:${entry.level.toUpperCase()}] [${entry.source}] ${entry.text}${entry.url ? ` @ ${entry.url}:${entry.lineNumber}` : ''}`);
65
57
  });
66
58
 
67
- // Add task-specific cdp.send() calls here. See SCRIPT_PATTERNS.md.
68
59
 
69
- const MONITOR_MS = 10000; // 3s static, 10s dynamic, 30s long network check
60
+ const MONITOR_MS = 10000;
70
61
  console.log(`[METRIC] Monitoring for ${MONITOR_MS / 1000}s...`);
71
62
  await new Promise(r => setTimeout(r, MONITOR_MS));
72
63
 
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- // Launch Chrome with CDP enabled; tracks isolated sessions for cleanup.
3
2
 
4
3
  import { spawn, execSync, execFileSync } from 'child_process';
5
4
  import { platform, tmpdir } from 'os';
@@ -26,7 +25,6 @@ const CONFIG_PATH = getArg('--config', '');
26
25
 
27
26
  const TMP = tmpdir();
28
27
  const SESSION_FILE = join(TMP, `cdp-session-${PORT}.json`);
29
- // Headless always uses an isolated temp profile.
30
28
  const HEADLESS_PROFILE_DIR = join(TMP, `cdp-chrome-profile-${PORT}`);
31
29
 
32
30
  function ok(payload) { console.log(JSON.stringify(payload)); }
@@ -265,7 +263,6 @@ if (CHROME_PATH && !existsSync(CHROME_PATH)) err(`Chrome not found at --chromePa
265
263
 
266
264
  const HOME = process.env.HOME ?? process.env.USERPROFILE;
267
265
 
268
- // If Chrome is already running without CDP, real-profile launches may hand off to it.
269
266
  function isChromeRunning() {
270
267
  if (platform() === 'darwin') {
271
268
  try { execSync('pgrep -x "Google Chrome" > /dev/null 2>&1'); return true; } catch { return false; }
@@ -1,4 +1,3 @@
1
- // Minimal source-map resolver for CDP scripts; strips sourcesContent.
2
1
 
3
2
  const B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
4
3
  const B64_MAP = new Uint8Array(256).fill(255);
@@ -20,7 +19,6 @@ function decodeVLQList(str) {
20
19
  }
21
20
 
22
21
  function parseMap(mapJson) {
23
- // Never retain original source bodies.
24
22
  delete mapJson.sourcesContent;
25
23
 
26
24
  const sources = mapJson.sources ?? [];
@@ -63,7 +61,6 @@ function originalPositionFor(parsed, genLine, genCol) {
63
61
  const { segments, sources, names } = parsed;
64
62
  if (!segments.length) return null;
65
63
 
66
- // Same-line lookup only; previous-line matches look plausible but are wrong.
67
64
  let lo = 0, hi = segments.length - 1, best = -1;
68
65
 
69
66
  while (lo <= hi) {
@@ -141,7 +138,7 @@ export async function createSourceMapResolver(cdp) {
141
138
  }
142
139
 
143
140
  const mapJson = JSON.parse(mapText);
144
- const parsed = parseMap(mapJson); // strips sourcesContent internally
141
+ const parsed = parseMap(mapJson);
145
142
  parsedMaps.set(scriptId, parsed);
146
143
  stats.loaded++;
147
144
  } catch {
@@ -1,5 +1,3 @@
1
- // Drop-in stealth patches for public sites likely to fingerprint headless Chrome.
2
- // Import from generated scripts before Page.navigate.
3
1
  export async function applyStealthPatches(cdp, opts = {}) {
4
2
  const ua = opts.userAgent ??
5
3
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36';
@@ -68,7 +68,7 @@ Every **non-trivial** task MUST satisfy this contract:
68
68
 
69
69
  ## When To Use It
70
70
 
71
- Use when the user asks to **understand** a codebase/feature end-to-end, **change** unclear/shared/cross-file code, **review** quality/architecture/tech-debt/dead-code/security/build issues, or **decide** architecture and validate RFCs against real behavior. Any language; strongest on Node/TypeScript and Python. For formal RFCs with migration strategy, pair with [octocode-rfc-generator](https://skills.sh/bgauryy/octocode-mcp/octocode-rfc-generator).
71
+ Use when the user asks to **understand** a codebase/feature end-to-end, **change** unclear/shared/cross-file code, **review** quality/architecture/tech-debt/dead-code/security/build issues, or **decide** architecture and validate RFCs against real behavior. Any language; strongest on Node/TypeScript and Python. For architecture options, trade-offs, or migration strategy that need a formal proposal before coding, pair with [octocode-rfc-generator](https://skills.sh/bgauryy/octocode-mcp/octocode-rfc-generator).
72
72
 
73
73
  ## Trivial vs. non-trivial — when the contract binds
74
74
 
@@ -120,12 +120,12 @@ Cover all six on a full review; on a scoped task, cover those the change touches
120
120
  |------|------|-----------------|
121
121
  | Small functions | `scripts/run.js` | `god-function`, `cognitive-complexity`, `halstead-effort`, `excessive-parameters` |
122
122
  | Duplication | `scripts/run.js` | `duplicate-function-body`, `duplicate-flow-structure`, `similar-function-body` |
123
- | Silent failures | `scripts/ast/search.js` | `--preset empty-catch`, `--preset py-bare-except`, `--preset py-pass-except`, `--preset catch-rethrow` |
123
+ | Silent failures | `scripts/ast/search.js` | `--preset empty-catch`, `--preset py-bare-except`, `--preset catch-rethrow` |
124
124
  | Loose types | `scripts/ast/search.js` | `--preset any-type`, `--preset type-assertion`, `--preset non-null-assertion` |
125
125
  | Intent-revealing names | code read + `lspFindReferences` | widely-used cryptic symbols, abbreviations that spread |
126
126
  | Dead / unreachable | scanner + `knip` | `dead-export`, `dead-file`, `unused-import`, `unused-npm-dependency` |
127
127
 
128
- For the full detector catalog, metric definitions, and severity rubric, see [quality-indicators.md](./references/quality-indicators.md).
128
+ Full detector catalog, metric definitions, and severity rubric: [quality-indicators.md](./references/quality-indicators.md).
129
129
 
130
130
  ### Required output: understanding artifact
131
131
 
@@ -260,36 +260,15 @@ Non-trivial tasks follow this arc (recommended, not mandatory): clarify the ques
260
260
 
261
261
  ## Task shapes
262
262
 
263
- Same working order; emphasis differs:
264
-
265
- | Task | Weight on | Notes |
266
- |------|-----------|-------|
267
- | **Code understanding** | steps 3–8 (layout → LSP → AST → scoped scanner → read) | Deliverable is the artifact. |
268
- | **Bug fixing** | Flows + Execution from failing behavior to entry point; adjacent error/retry/contract risk | Fix the smallest layer that solves the root cause; escalate via Smallest-fix vs. safest-fix gate when systemic. |
269
- | **Refactor** | blast radius (`lspFindReferences`), scoped scan, duplication inventory, then plan | Prefer extracting modules, clarifying contracts, simplifying flows over cosmetic reshuffling. Verify per batch. |
270
- | **Architecture review** | scanner `--graph` first, then LSP on candidate modules, then read representatives | Report both local and system-level causes. |
271
- | **RFC / design validation** | map each claim to code ownership; verify flow, contract, and architecture alignment | Mark claims `confirmed|likely|uncertain`; report mismatches as doc or code follow-ups. |
263
+ Same working order; emphasis differs. **Code understanding**: steps 3–8 (layout → LSP → AST → scanner → read), deliverable is the artifact. **Bug fixing**: Flows + Execution from failing behavior inward; fix the smallest responsible layer; escalate at the Smallest-fix gate if systemic. **Refactor**: blast radius first (`lspFindReferences`), then scoped scan + duplication inventory; prefer extracting modules and clarifying contracts over cosmetic reshuffling; verify per batch. **Architecture review**: scanner `--graph` first, then LSP on candidates; report local and system-level causes. **RFC/design validation**: map each claim to code ownership; verify flow, contract, and architecture alignment; mark `confirmed|likely|uncertain`.
272
264
 
273
265
  ## Before / During / After A Change
274
266
 
275
- Operational actions per phase (investigation substance = lenses + artifact):
276
-
277
- ### Before
278
- - Produce the understanding artifact.
279
- - Map design-doc / RFC claims to concrete code ownership when one exists.
280
- - Look for an existing local pattern before inventing a new one.
267
+ **Before**: produce the understanding artifact; map RFC/design-doc claims to code ownership; look for an existing pattern before inventing one.
281
268
 
282
- ### During
283
- - Keep edits in the smallest responsible layer; preserve boundaries unless the plan intentionally changes them.
284
- - Maintain contract/protocol compatibility unless an explicit migration is in scope.
285
- - If root cause turns out structural mid-task, stop and hit the Smallest-fix vs. safest-fix gate instead of continuing with a cosmetic patch.
269
+ **During**: stay in the smallest responsible layer; preserve contract/protocol compatibility unless migration is in scope; if root cause is structural mid-task, stop at the Smallest-fix vs. safest-fix gate.
286
270
 
287
- ### After
288
- - Run tests, lint, and build/type-check.
289
- - Re-check changed symbols with LSP after renames/moves; run a scoped scanner pass for non-trivial changes.
290
- - Run `knip` when the refactor may leave dead artifacts; CSS checks when styles changed.
291
- - Re-validate the artifact's dimensions against the final implementation; note any remaining architectural risk even if the code now works.
292
- - Sync docs / RFC sections touched by the change.
271
+ **After**: run tests, lint, build/type-check; re-check changed symbols with LSP; run scoped scanner pass for non-trivial changes; run `knip` if dead artifacts are likely; sync docs/RFC sections the change touches.
293
272
 
294
273
  ## Confidence Rules
295
274
 
@@ -394,8 +373,3 @@ Fallback applies only when an Octocode tool is truly **unavailable** — not reg
394
373
 
395
374
  **If degraded but completed:** treat the response as valid; on empty/wrong results, retry with a simpler input (drop regex meta-characters, switch to literal search, narrow the path). **Do not** switch to native Claude Code tools — that leaves the skill's evidence model.
396
375
 
397
- ## Companion Skill
398
-
399
- Pair with the RFC skill when architecture options, trade-offs, or migration strategy need a formal proposal before coding:
400
-
401
- - [octocode-rfc-generator](https://skills.sh/bgauryy/octocode-mcp/octocode-rfc-generator) — generate a smart RFC from validated system evidence.
@@ -77,17 +77,11 @@ This skill is private (no `bin` entry) — **do not use `npx`**. `npx` applies o
77
77
 
78
78
  ## Flag Details
79
79
 
80
- `--scope` focuses on specific paths (comma-separated, relative to root). Use `file:symbol` syntax to drill into a specific function or exported variable — only findings whose line range overlaps with that symbol are returned. The full dependency graph is still built so architecture findings involving scoped files are reported. Combinable with `--features`/`--exclude`.
81
-
82
- **Symbol scope fallback**: if the scanner cannot resolve a `file:symbol` target (e.g., the symbol name doesn't match an exported function or the file uses patterns that prevent resolution), it falls back to file-level scope and emits a warning: `"symbol scope could not resolve: <path>. Falling back to file-level scope."` If you see this warning, check the exact exported function name and try again, or use file-level scope directly.
83
-
84
- `--features` and `--exclude` are mutually exclusive. Both accept pillar names (`architecture`, `code-quality`, `dead-code`, `security`, `test-quality`) and individual category names, comma-separated.
85
-
86
- `--semantic` enables TypeChecker + LanguageService analysis (additional categories). Off by default since it adds ~3-5s. Semantic categories require `--semantic` to appear in results.
87
-
88
- `--out` changes the output destination. If the path ends with `.json`, writes a single monolithic file (legacy mode). Otherwise, writes to the given directory instead of the default timestamped directory.
89
-
90
- `--parser` selects the parse engine: `auto` (default — uses tree-sitter with TS fallback), `typescript` (TS compiler only), or `tree-sitter` (tree-sitter only).
80
+ - **`--scope`**: comma-separated paths relative to root. Use `file:symbol` to drill into a specific exported function — only findings overlapping that symbol are returned; the full dependency graph is still built. If `file:symbol` can't resolve (symbol name mismatch), falls back to file-level scope with a warning — check the exact exported name or switch to file-level scope.
81
+ - **`--features` / `--exclude`**: mutually exclusive. Accept pillar names (`architecture`, `code-quality`, `dead-code`, `security`, `test-quality`) and individual category names, comma-separated.
82
+ - **`--semantic`**: enables TypeChecker + LanguageService analysis (~3-5s overhead). Semantic categories only appear in results when this flag is set.
83
+ - **`--out`**: output destination. Path ending in `.json` → single monolithic file (legacy). Otherwise writes to the given directory instead of the default timestamped directory.
84
+ - **`--parser`**: `auto` (default tree-sitter with TS fallback), `typescript` (TS compiler only), or `tree-sitter` (tree-sitter only).
91
85
 
92
86
  ---
93
87
 
@@ -68,9 +68,7 @@ Declarative rule DSL (`forbidden`/`allowed`/`required`). Scanner has 28 built-in
68
68
 
69
69
  ```bash
70
70
  npx depcruise --no-config --output-type err src/
71
- npx depcruise --no-config --output-type metrics src/
72
71
  npx depcruise --no-config --output-type mermaid src/ > deps.md
73
- npx depcruise --no-config --output-type mermaid --focus "^src/session" src/
74
72
  npx depcruise --no-config --output-type err --affected HEAD src/
75
73
  ```
76
74
 
@@ -127,10 +125,8 @@ bandit -r <target> -s B101 # skip specific check (e.g. assert)
127
125
  ### pytest — Test runner
128
126
 
129
127
  ```bash
130
- pytest
131
128
  pytest --tb=short -q
132
129
  pytest --cov=<package> --cov-report=term-missing
133
- pytest -x # stop on first failure
134
130
  ```
135
131
 
136
132
  ---
@@ -91,56 +91,16 @@ The scanner detects quality indicators across 5 pillars: **Architecture**, **Cod
91
91
 
92
92
  ## New Detector Details
93
93
 
94
- ### deep-nesting
95
- - **Threshold**: `deepNestingThreshold` (default: 5)
96
- - **Signal**: `max(maxBranchDepth, maxLoopDepth)` per function
97
- - **Severity mapping**: `≥ threshold+3` high, `≥ threshold+1` → medium, else low
98
- - **Fix strategy**: Guard clauses, early returns, extract to named helpers
99
-
100
- ### multiple-return-paths
101
- - **Threshold**: `multipleReturnThreshold` (default: 6)
102
- - **Signal**: `returns` count per function (includes throw statements)
103
- - **Severity mapping**: `≥ threshold+4` high, `≥ threshold+2` medium, else low
104
- - **Fix strategy**: Single result variable, guard clauses for error paths only
105
-
106
- ### catch-rethrow
107
- - **Signal**: Catch blocks containing a throw statement — candidates for simplification (may include other statements alongside the rethrow)
108
- - **Severity**: Always low (noise reduction)
109
- - **Fix strategy**: Remove the try-catch if only rethrowing, or add logging/wrapping before re-throw
110
-
111
- ### magic-string
112
- - **Threshold**: `magicStringMinOccurrences` (default: 3)
113
- - **Signal**: String literals used in `===`, `!==`, `==`, `!=` comparisons or `case` clauses, appearing ≥ threshold times
114
- - **Severity mapping**: `≥ 8` → high, `≥ 5` → medium, else → low
115
- - **Fix strategy**: Extract to named constant or enum
116
-
117
- ### boolean-parameter-cluster
118
- - **Threshold**: `booleanParamThreshold` (default: 3)
119
- - **Signal**: Functions with ≥ threshold parameters typed as `boolean`
120
- - **Severity**: Always medium
121
- - **Fix strategy**: Replace with options object or split into separate functions
122
-
123
- ### promise-all-unhandled
124
- - **Signal**: `Promise.all/allSettled/race/any` calls without surrounding try-catch or `.catch()` chain
125
- - **Severity**: Always medium
126
- - **Fix strategy**: Wrap in try-catch or chain `.catch()`
127
-
128
- ### export-surface-density
129
- - **Signal**: `exportCount / totalStatements` ratio ≥ 0.5 (modules with ≥ 20 statements)
130
- - **Severity mapping**: `≥ 80%` → high, `≥ 60%` → medium, else → low
131
- - **Fix strategy**: Make non-essential symbols private, split into facade + implementation
132
-
133
- ### change-risk (composite)
134
- - **Signal**: Weighted sum of overlapping quality problems in a single file
135
- - **Components scored**:
136
- - High average complexity → +2
137
- - High cognitive complexity → +2
138
- - Low maintainability functions → +count
139
- - Empty catches → +1
140
- - Unhandled promise combinators → +1
141
- - Excessive exports (>15) → +1
142
- - **Threshold**: Score ≥ 4 triggers finding
143
- - **Severity mapping**: `≥ 8` → critical, `≥ 6` → high, else → medium
94
+ | Category | Threshold flag (default) | Signal | Severity | Fix |
95
+ |----------|--------------------------|--------|----------|-----|
96
+ | `deep-nesting` | `--deep-nesting-threshold N` (5) | `max(maxBranchDepth, maxLoopDepth)` per fn | `≥T+3`→high, `≥T+1`→med, else low | Guard clauses, early returns, extract helpers |
97
+ | `multiple-return-paths` | `--multiple-return-threshold N` (6) | return/throw count per fn | `≥T+4`→high, `≥T+2`→med, else low | Single result var; guard clauses for error paths |
98
+ | `catch-rethrow` | | catch containing a throw (simplification candidates) | always low | Remove try-catch if only re-throwing, or add logging before re-throw |
99
+ | `magic-string` | `--magic-string-min-occurrences N` (3) | string literals in `===`/`!==`/`case` appearing ≥N times | `≥8`→high, `≥5`→med, else low | Extract to named constant or enum |
100
+ | `boolean-parameter-cluster` | `--boolean-param-threshold N` (3) | fns with ≥N `boolean` params | always medium | Options object or split into separate fns |
101
+ | `promise-all-unhandled` | — | `Promise.all/allSettled/race/any` without try-catch or `.catch()` | always medium | Wrap in try-catch or chain `.catch()` |
102
+ | `export-surface-density` | — | `exportCount / totalStatements 0.5` (files with ≥20 stmts) | `≥80%`→high, `≥60%`→med, else low | Make non-essential symbols private; split facade + impl |
103
+ | `change-risk` | | weighted sum: complexity+2, cognitive+2, low-MI+count, empty-catch+1, unhandled-promise+1, exports>15+1; fires at ≥4 | `≥8`→critical, `≥6`→high, else med | Fix overlapping quality signals in the file |
144
104
 
145
105
  ---
146
106
 
@@ -49,16 +49,13 @@ Trace a function: definition → callers → callees.
49
49
  5. **Find callers** — incoming call hierarchy → who depends on this?
50
50
  6. **Find callees** — outgoing call hierarchy → what does this depend on?
51
51
 
52
- ### 3 — Impact Analysis (Pre-Refactor)
52
+ ### 3 — Impact Analysis (Quick Blast Radius)
53
53
 
54
- Assess blast radius before changing a symbol.
54
+ Fast pre-change check. For a full refactoring plan with coupling and cycle analysis, use [Workflow 12](#12--refactoring-plan-safe-restructure).
55
55
 
56
- 1. **Map structural imports** — AST search for import patterns involving the symbol
57
- 2. **Locate the symbol** — text search to get file + lineHint
58
- 3. **Count all consumers** — find references, excluding declaration
59
- 4. **Count test consumers** — find references filtered to test directories only
60
- 5. **Count production consumers** — find references excluding test directories
61
- 6. **Assess safety** — few production refs + high test coverage = safe to change. Many production refs = plan carefully, consider incremental migration.
56
+ 1. **Locate the symbol** — text search to get file + lineHint
57
+ 2. **Count all consumers** — find references, excluding declaration; split test vs production
58
+ 3. **Assess safety** — few production refs + high test coverage = safe to change. Many refs = plan carefully → Workflow 12.
62
59
 
63
60
  ### 4 — Dead Export Validation
64
61
 
@@ -162,17 +159,17 @@ Before writing new code, understand the existing landscape to pick the right loc
162
159
 
163
160
  ### 12 — Refactoring Plan (Safe Restructure)
164
161
 
165
- Plan a multi-file refactor with full blast radius awareness.
162
+ Full blast-radius refactoring plan. Use when Workflow 3 (quick check) reveals high consumer count or cross-package scope.
166
163
 
167
164
  1. **Map all files containing the symbol** — text search with file-list mode
168
165
  2. **Count all consumers** — find references excluding declaration
169
- 3. **Split test vs production consumers** — find references with include/exclude patterns for test dirs
170
- 4. **Map callers and dependencies** — incoming and outgoing call hierarchy
171
- 5. **Check import graph** — AST search for import patterns in the target area
166
+ 3. **Split test vs production consumers** — find references filtered to test dirs; 0 test refs = coverage risk
167
+ 4. **Map structural imports** — AST search for import patterns involving the symbol
168
+ 5. **Map callers and dependencies** — incoming and outgoing call hierarchy
172
169
  6. **Check coupling/cycle risk** — scoped scan with architecture + graph features
173
170
  7. **Assess test quality around target** — scoped scan with test-quality feature
174
171
 
175
- **Output**: file list + consumer count + test coverage + coupling risk = refactoring confidence level.
172
+ **Output**: file list + consumer count (test/prod split) + import graph + coupling risk = refactoring confidence level.
176
173
 
177
174
  ### 13 — Codebase Exploration (New Repo Orientation)
178
175
 
@@ -117,7 +117,7 @@ describe('buildDependencySummary', () => {
117
117
  it('detects test-only modules (no production imports, only test imports)', () => {
118
118
  const state = makeDependencyState();
119
119
  addEdges(state, [
120
- ['src/foo.test.ts', 'src/helper.ts', true], // test imports helper
120
+ ['src/foo.test.ts', 'src/helper.ts', true],
121
121
  ]);
122
122
  const criticality = new Map<string, FileCriticality>();
123
123
  const summary = buildDependencySummary(state, criticality, DEFAULT_OPTS);
@@ -129,7 +129,7 @@ describe('buildDependencySummary', () => {
129
129
  it('excludes test files from test-only modules list', () => {
130
130
  const state = makeDependencyState();
131
131
  addEdges(state, [
132
- ['src/foo.test.ts', 'src/bar.test.ts', true], // test imports test
132
+ ['src/foo.test.ts', 'src/bar.test.ts', true],
133
133
  ]);
134
134
  const criticality = new Map<string, FileCriticality>();
135
135
  const summary = buildDependencySummary(state, criticality, DEFAULT_OPTS);
@@ -150,14 +150,14 @@ describe('collectMetrics', () => {
150
150
  const sf = parse('function foo() { if (a && b) {} }');
151
151
  const fn = firstFn(sf);
152
152
  const m = collectMetrics(fn);
153
- expect(m.complexity).toBe(3); // 1 base + 1 if + 1 &&
153
+ expect(m.complexity).toBe(3);
154
154
  });
155
155
 
156
156
  it('logical || → complexity+1', () => {
157
157
  const sf = parse('function foo() { if (a || b) {} }');
158
158
  const fn = firstFn(sf);
159
159
  const m = collectMetrics(fn);
160
- expect(m.complexity).toBe(3); // 1 base + 1 if + 1 ||
160
+ expect(m.complexity).toBe(3);
161
161
  });
162
162
 
163
163
  it('for-in loop → loops 1', () => {
@@ -1,12 +1,5 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * AST-aware structural code search powered by @ast-grep/napi.
4
- *
5
- * Usage:
6
- * node scripts/ast/search.js --pattern 'console.log($$$ARGS)' --root ./src
7
- * node scripts/ast/search.js --preset empty-catch --root ./packages
8
- * node scripts/ast/search.js --kind function_declaration --root ./src --json
9
- */
2
+
10
3
 
11
4
  import fs from 'node:fs';
12
5
  import { createRequire } from 'node:module';
@@ -16,10 +9,6 @@ import { ALLOWED_EXTS, isPythonFile } from '../types/index.js';
16
9
 
17
10
  import type { NapiConfig, SgNode, SgRoot } from '@ast-grep/napi';
18
11
 
19
- // Require (not static-import) @ast-grep/napi so the resolution happens when this
20
- // module is first evaluated — not when the outer bundle loads. The entry at
21
- // src/ast/search.ts runs the dependency bootstrap before dynamic-importing this
22
- // module, so by the time this line executes the native addon is present.
23
12
  const nodeRequire = createRequire(import.meta.url);
24
13
  const astGrep = nodeRequire('@ast-grep/napi') as typeof import('@ast-grep/napi');
25
14
  const {
@@ -75,7 +64,7 @@ export interface AstSearchResult {
75
64
  totalMatches: number;
76
65
  totalFiles: number;
77
66
  matches: AstMatch[];
78
- /** Source lines keyed by relative file path — only populated when context > 0 */
67
+
79
68
  _sourceByFile?: Map<string, string[]>;
80
69
  }
81
70
 
@@ -272,7 +261,6 @@ export const PRESETS: Record<string, PresetRule> = {
272
261
  description: 'Variable declarations without call expressions (candidates for dead code)',
273
262
  },
274
263
 
275
- // ── Python presets ──────────────────────────────────────────────
276
264
  'py-bare-except': {
277
265
  rule: {
278
266
  kind: 'except_clause',
@@ -846,4 +834,3 @@ export async function main(): Promise<void> {
846
834
  }
847
835
 
848
836
  export { ensurePythonRegistered };
849
- // Direct execution lives in ./search.ts; this file is an internal module.