@mascaro101/autodoc 1.0.0

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.
@@ -0,0 +1,6 @@
1
+ {
2
+ "provider": "gemini",
3
+ "model": "gemini-2.0-flash",
4
+ "apiKey": "your-api-key-here",
5
+ "docFile": "./docs/doc.md"
6
+ }
@@ -0,0 +1,30 @@
1
+ <svg width="612" height="616" viewBox="0 0 612 616" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <ellipse cx="300.846" cy="314.242" rx="161" ry="166" fill="#373737"/>
3
+ <g filter="url(#filter0_d_2005_137)">
4
+ <path d="M296.846 102C303.822 102 310.729 102.344 317.55 103.02L314.2 136.854L314.199 136.856C314.122 136.849 314.046 136.842 313.969 136.835C325.764 137.987 337.218 140.316 348.216 143.705L348.219 143.702L348.322 143.365L358.231 111.21C371.596 115.329 384.387 120.753 396.457 127.328L388.323 142.256L388.324 142.257L380.191 157.185L380.189 157.187C390.398 162.748 400.003 169.298 408.876 176.712L430.679 150.623C441.267 159.471 450.975 169.344 459.657 180.091L446.433 190.773L433.209 201.457L433.206 201.458C440.456 210.433 446.858 220.136 452.286 230.443H452.289L453.719 229.69L482.372 214.601C488.746 226.705 493.995 239.51 497.975 252.871L465.39 262.577H465.387C468.648 273.525 470.895 284.917 472.017 296.643H472.02L505.865 293.404C506.515 300.19 506.846 307.061 506.846 314C506.846 320.939 506.515 327.81 505.865 334.596L472.02 331.357L472.016 331.356C470.894 343.082 468.648 354.474 465.387 365.422L465.39 365.423L497.975 375.129C493.995 388.49 488.746 401.295 482.372 413.399L452.289 397.557L452.286 397.555C446.858 407.863 440.457 417.566 433.206 426.541L433.209 426.543L459.657 447.909C450.975 458.656 441.267 468.529 430.679 477.377L408.877 451.287L408.876 451.286C400.003 458.701 390.399 465.251 380.189 470.812L380.191 470.815L387.72 484.635L396.457 500.672C384.387 507.247 371.596 512.672 358.231 516.79L353.225 500.543L348.219 484.298L348.217 484.294C337.29 487.661 325.914 489.983 314.199 491.143L314.2 491.146L317.55 524.98C310.729 525.656 303.822 526 296.846 526C289.869 526 282.962 525.656 276.142 524.98L279.491 491.146V491.143C267.777 489.983 256.4 487.661 245.474 484.294L245.473 484.298L240.467 500.544L240.466 500.543L235.46 516.79C222.095 512.671 209.304 507.247 197.234 500.672L213.5 470.815L213.501 470.812C203.292 465.251 193.687 458.701 184.814 451.286V451.287L163.013 477.377C152.425 468.529 142.716 458.656 134.034 447.909L160.482 426.543L160.484 426.541C153.672 418.108 147.608 409.032 142.397 399.415L141.404 397.555L141.402 397.557L111.319 413.399C104.945 401.295 99.6967 388.49 95.7168 375.129L128.302 365.423L128.304 365.422C128.321 365.48 128.339 365.538 128.356 365.596C125.067 354.594 122.802 343.144 121.674 331.356L121.672 331.357L87.8262 334.596C87.1769 327.81 86.8457 320.939 86.8457 314C86.8457 307.061 87.1769 300.19 87.8262 293.404L121.672 296.643H121.675C122.806 284.824 125.079 273.345 128.382 262.317C128.356 262.404 128.33 262.491 128.304 262.577H128.302L125.587 261.769L95.7168 252.871C99.6967 239.51 104.945 226.705 111.319 214.601L141.402 230.443H141.403C146.832 220.136 153.233 210.432 160.483 201.457H160.482L147.258 190.774V190.773L134.034 180.091C142.716 169.344 152.425 159.471 163.013 150.623L184.814 176.713C193.727 169.265 203.378 162.69 213.639 157.112C213.593 157.137 213.547 157.162 213.501 157.187L213.5 157.185L205.367 142.257V142.256L197.234 127.328C209.304 120.753 222.095 115.329 235.46 111.21L245.369 143.365L245.473 143.702L245.474 143.705C245.456 143.711 245.438 143.716 245.42 143.722C256.443 140.321 267.925 137.985 279.749 136.832C279.663 136.84 279.577 136.848 279.491 136.856V136.854L276.142 103.02C282.962 102.344 289.869 102 296.846 102ZM294.652 491.986L296.846 492C296.101 492 295.358 491.995 294.615 491.985C294.628 491.986 294.64 491.986 294.652 491.986ZM296.846 158.242C211.794 158.242 142.846 227.862 142.846 313.742C142.846 399.622 211.794 469.242 296.846 469.242C381.898 469.242 450.846 399.622 450.846 313.742C450.846 227.862 381.898 158.242 296.846 158.242Z" fill="#4D4D4D"/>
5
+ </g>
6
+ <path d="M408.846 227.589V414.242C408.846 433.02 393.623 448.242 374.846 448.242H225.846C207.068 448.242 191.846 433.02 191.846 414.242V214.242C191.846 195.465 207.068 180.242 225.846 180.242H361.499L408.846 227.589Z" fill="#D9D9D9"/>
7
+ <path d="M408.499 227.242H361.846V180.589L408.499 227.242Z" fill="#797979"/>
8
+ <rect x="224.846" y="249.242" width="151" height="13" rx="6.5" fill="#797979"/>
9
+ <rect x="224.846" y="354.242" width="151" height="13" rx="6.5" fill="#797979"/>
10
+ <rect x="224.846" y="389.242" width="151" height="13" rx="6.5" fill="#797979"/>
11
+ <rect x="224.846" y="319.242" width="151" height="13" rx="6.5" fill="#797979"/>
12
+ <rect x="224.846" y="284.242" width="151" height="13" rx="6.5" fill="#797979"/>
13
+ <mask id="path-10-inside-1_2005_137" fill="white">
14
+ <ellipse cx="299.637" cy="316.229" rx="213.108" ry="215.096" transform="rotate(-53.541 299.637 316.229)"/>
15
+ </mask>
16
+ <path d="M439.944 126.332C430.832 138.664 421.72 150.996 412.608 163.329C429.026 174.975 443.604 189.107 455.692 205.228C505.138 269.431 507.92 366.702 458.761 433.799C400.237 520.768 266.307 543.042 179.832 478.379C90.4359 418.227 64.681 280.985 131.264 191.826C181.201 119.343 281.317 86.5026 366.54 114.847C387.792 121.629 407.993 131.789 426.276 144.83C408.449 131.173 388.512 120.255 367.277 112.668C282.311 81.0528 177.485 110.28 122.014 184.992C48.4371 276.404 69.0995 426.291 166.164 496.877C259.43 572.046 413.598 554.349 486.509 454.3C547.089 377.402 549.001 260.541 491.142 179.675C477.014 159.404 459.654 141.36 439.944 126.332ZM412.608 163.329L439.944 126.332L426.276 144.83L412.608 163.329Z" fill="#D9D9D9" mask="url(#path-10-inside-1_2005_137)"/>
17
+ <path d="M380.583 128.876C379.382 126.605 381.404 123.973 383.908 124.549L439.182 137.272C441.311 137.762 442.219 140.291 440.887 142.024L412.137 179.436C410.806 181.169 408.128 180.943 407.107 179.011L380.583 128.876Z" fill="#D9D9D9"/>
18
+ <defs>
19
+ <filter id="filter0_d_2005_137" x="82.8457" y="102" width="428" height="432" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
20
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
21
+ <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
22
+ <feOffset dy="4"/>
23
+ <feGaussianBlur stdDeviation="2"/>
24
+ <feComposite in2="hardAlpha" operator="out"/>
25
+ <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
26
+ <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2005_137"/>
27
+ <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2005_137" result="shape"/>
28
+ </filter>
29
+ </defs>
30
+ </svg>
@@ -0,0 +1,31 @@
1
+ <svg width="1151" height="616" viewBox="0 0 1151 616" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <ellipse cx="304.761" cy="315" rx="161" ry="166" fill="#373737"/>
3
+ <g filter="url(#filter0_d_2003_244)">
4
+ <path d="M300.761 102.758C307.737 102.758 314.645 103.102 321.465 103.778L318.116 137.613L318.115 137.615C318.038 137.607 317.961 137.601 317.884 137.593C329.679 138.745 341.133 141.074 352.131 144.463L352.134 144.46L352.238 144.123L362.147 111.968C375.511 116.087 388.302 121.511 400.372 128.086L392.239 143.014L392.24 143.015L384.107 157.943L384.105 157.945C394.314 163.506 403.918 170.056 412.791 177.47L434.594 151.381C445.182 160.229 454.891 170.102 463.573 180.849L450.348 191.531L437.124 202.215L437.121 202.216C444.372 211.191 450.773 220.894 456.201 231.201H456.204L457.634 230.448L486.287 215.359C492.662 227.463 497.91 240.268 501.89 253.629L469.305 263.335H469.302C472.563 274.283 474.81 285.675 475.932 297.401H475.935L509.781 294.162C510.43 300.948 510.761 307.819 510.761 314.758C510.761 321.697 510.43 328.568 509.781 335.354L475.935 332.115L475.931 332.115C474.809 343.84 472.563 355.232 469.302 366.18L469.305 366.181L501.89 375.887C497.91 389.248 492.662 402.053 486.287 414.157L456.204 398.315L456.201 398.313C450.773 408.621 444.372 418.324 437.121 427.299L437.124 427.301L463.573 448.667C454.891 459.414 445.182 469.287 434.594 478.135L412.792 452.045L412.791 452.044C403.918 459.459 394.314 466.009 384.105 471.571L384.107 471.573L391.635 485.393L400.372 501.43C388.302 508.005 375.511 513.43 362.147 517.548L357.14 501.301L352.134 485.056L352.132 485.052C341.206 488.419 329.829 490.741 318.115 491.901L318.116 491.904L321.465 525.739C314.645 526.414 307.737 526.758 300.761 526.758C293.785 526.758 286.877 526.414 280.057 525.739L283.407 491.904V491.901C271.692 490.741 260.316 488.419 249.389 485.052L249.388 485.056L244.382 501.302L244.381 501.301L239.375 517.548C226.011 513.43 213.22 508.005 201.15 501.43L217.415 471.573L217.416 471.571C207.207 466.009 197.603 459.459 188.73 452.044V452.045L166.928 478.135C156.34 469.287 146.631 459.414 137.95 448.667L164.398 427.301L164.4 427.299C157.587 418.866 151.523 409.79 146.313 400.173L145.32 398.313L145.318 398.315L115.235 414.157C108.86 402.053 103.612 389.248 99.6321 375.887L132.217 366.181L132.219 366.18C132.236 366.238 132.254 366.296 132.272 366.354C128.983 355.352 126.717 343.902 125.589 332.115L125.587 332.115L91.7415 335.354C91.0922 328.568 90.7611 321.697 90.761 314.758C90.761 307.819 91.0922 300.948 91.7415 294.162L125.587 297.401H125.59C126.721 285.582 128.994 274.103 132.297 263.075C132.271 263.162 132.245 263.249 132.219 263.335H132.217L129.502 262.527L99.6321 253.629C103.612 240.268 108.86 227.463 115.235 215.359L145.318 231.201H145.319C150.747 220.894 157.148 211.19 164.399 202.215H164.398L151.173 191.532V191.531L137.95 180.849C146.631 170.102 156.34 160.229 166.928 151.381L188.73 177.471C197.642 170.023 207.294 163.448 217.554 157.87C217.508 157.895 217.462 157.92 217.416 157.945L217.415 157.943L209.283 143.015V143.014L201.15 128.086C213.22 121.511 226.011 116.087 239.375 111.968L249.284 144.123L249.388 144.46L249.389 144.463C249.371 144.469 249.353 144.474 249.335 144.48C260.358 141.079 271.84 138.743 283.664 137.59C283.578 137.598 283.492 137.606 283.407 137.615V137.613L280.057 103.778C286.877 103.102 293.785 102.758 300.761 102.758ZM298.568 492.744L300.761 492.758C300.016 492.758 299.273 492.753 298.531 492.743C298.543 492.744 298.555 492.744 298.568 492.744ZM300.761 159C215.709 159 146.761 228.62 146.761 314.5C146.761 400.381 215.709 470 300.761 470C385.813 470 454.761 400.381 454.761 314.5C454.761 228.62 385.813 159 300.761 159Z" fill="#4D4D4D"/>
5
+ </g>
6
+ <path d="M412.761 228.347V415C412.761 433.778 397.539 449 378.761 449H229.761C210.983 449 195.761 433.778 195.761 415V215C195.761 196.223 210.983 181 229.761 181H365.414L412.761 228.347Z" fill="#D9D9D9"/>
7
+ <path d="M412.414 228H365.761V181.347L412.414 228Z" fill="#797979"/>
8
+ <rect x="228.761" y="250" width="151" height="13" rx="6.5" fill="#797979"/>
9
+ <rect x="228.761" y="355" width="151" height="13" rx="6.5" fill="#797979"/>
10
+ <rect x="228.761" y="390" width="151" height="13" rx="6.5" fill="#797979"/>
11
+ <rect x="228.761" y="320" width="151" height="13" rx="6.5" fill="#797979"/>
12
+ <rect x="228.761" y="285" width="151" height="13" rx="6.5" fill="#797979"/>
13
+ <path d="M620.898 342H599.807L631.943 248.909H657.307L689.398 342H668.307L644.989 270.182H644.261L620.898 342ZM619.579 305.409H669.398V320.773H619.579V305.409ZM745.011 312.273V272.182H764.375V342H745.784V329.319H745.057C743.481 333.409 740.86 336.697 737.193 339.182C733.557 341.667 729.117 342.909 723.875 342.909C719.208 342.909 715.102 341.849 711.557 339.728C708.011 337.606 705.239 334.591 703.239 330.682C701.269 326.773 700.269 322.091 700.239 316.637V272.182H719.602V313.182C719.632 317.303 720.739 320.561 722.92 322.955C725.102 325.349 728.026 326.546 731.693 326.546C734.026 326.546 736.208 326.016 738.239 324.955C740.269 323.864 741.905 322.258 743.148 320.137C744.42 318.016 745.042 315.394 745.011 312.273ZM817 272.182V286.728H774.954V272.182H817ZM784.5 255.455H803.864V320.546C803.864 322.334 804.136 323.728 804.682 324.728C805.227 325.697 805.985 326.379 806.954 326.773C807.954 327.167 809.106 327.364 810.409 327.364C811.318 327.364 812.227 327.288 813.136 327.137C814.045 326.955 814.742 326.819 815.227 326.728L818.273 341.137C817.303 341.44 815.939 341.788 814.182 342.182C812.424 342.606 810.288 342.864 807.773 342.955C803.106 343.137 799.015 342.516 795.5 341.091C792.015 339.667 789.303 337.455 787.364 334.455C785.424 331.455 784.47 327.667 784.5 323.091V255.455ZM860.409 343.364C853.348 343.364 847.242 341.864 842.091 338.864C836.97 335.834 833.015 331.622 830.227 326.228C827.439 320.803 826.045 314.516 826.045 307.364C826.045 300.152 827.439 293.849 830.227 288.455C833.015 283.031 836.97 278.819 842.091 275.819C847.242 272.788 853.348 271.273 860.409 271.273C867.47 271.273 873.56 272.788 878.682 275.819C883.833 278.819 887.803 283.031 890.591 288.455C893.379 293.849 894.773 300.152 894.773 307.364C894.773 314.516 893.379 320.803 890.591 326.228C887.803 331.622 883.833 335.834 878.682 338.864C873.56 341.864 867.47 343.364 860.409 343.364ZM860.5 328.364C863.712 328.364 866.394 327.455 868.545 325.637C870.697 323.788 872.318 321.273 873.409 318.091C874.53 314.909 875.091 311.288 875.091 307.228C875.091 303.167 874.53 299.546 873.409 296.364C872.318 293.182 870.697 290.667 868.545 288.819C866.394 286.97 863.712 286.046 860.5 286.046C857.257 286.046 854.53 286.97 852.318 288.819C850.136 290.667 848.485 293.182 847.364 296.364C846.273 299.546 845.727 303.167 845.727 307.228C845.727 311.288 846.273 314.909 847.364 318.091C848.485 321.273 850.136 323.788 852.318 325.637C854.53 327.455 857.257 328.364 860.5 328.364ZM940.727 342H907.727V248.909H941C950.364 248.909 958.424 250.773 965.182 254.5C971.939 258.197 977.136 263.516 980.773 270.455C984.439 277.394 986.273 285.697 986.273 295.364C986.273 305.061 984.439 313.394 980.773 320.364C977.136 327.334 971.909 332.682 965.091 336.409C958.303 340.137 950.182 342 940.727 342ZM927.409 325.137H939.909C945.727 325.137 950.621 324.106 954.591 322.046C958.591 319.955 961.591 316.728 963.591 312.364C965.621 307.97 966.636 302.303 966.636 295.364C966.636 288.485 965.621 282.864 963.591 278.5C961.591 274.137 958.606 270.925 954.636 268.864C950.667 266.803 945.773 265.773 939.954 265.773H927.409V325.137ZM1032.03 343.364C1024.97 343.364 1018.87 341.864 1013.72 338.864C1008.59 335.834 1004.64 331.622 1001.85 326.228C999.064 320.803 997.67 314.516 997.67 307.364C997.67 300.152 999.064 293.849 1001.85 288.455C1004.64 283.031 1008.59 278.819 1013.72 275.819C1018.87 272.788 1024.97 271.273 1032.03 271.273C1039.09 271.273 1045.19 272.788 1050.31 275.819C1055.46 278.819 1059.43 283.031 1062.22 288.455C1065 293.849 1066.4 300.152 1066.4 307.364C1066.4 314.516 1065 320.803 1062.22 326.228C1059.43 331.622 1055.46 335.834 1050.31 338.864C1045.19 341.864 1039.09 343.364 1032.03 343.364ZM1032.12 328.364C1035.34 328.364 1038.02 327.455 1040.17 325.637C1042.32 323.788 1043.94 321.273 1045.03 318.091C1046.16 314.909 1046.72 311.288 1046.72 307.228C1046.72 303.167 1046.16 299.546 1045.03 296.364C1043.94 293.182 1042.32 290.667 1040.17 288.819C1038.02 286.97 1035.34 286.046 1032.12 286.046C1028.88 286.046 1026.16 286.97 1023.94 288.819C1021.76 290.667 1020.11 293.182 1018.99 296.364C1017.9 299.546 1017.35 303.167 1017.35 307.228C1017.35 311.288 1017.9 314.909 1018.99 318.091C1020.11 321.273 1021.76 323.788 1023.94 325.637C1026.16 327.455 1028.88 328.364 1032.12 328.364ZM1110.53 343.364C1103.38 343.364 1097.23 341.849 1092.08 338.819C1086.96 335.758 1083.02 331.516 1080.26 326.091C1077.53 320.667 1076.17 314.425 1076.17 307.364C1076.17 300.212 1077.55 293.94 1080.31 288.546C1083.09 283.122 1087.05 278.894 1092.17 275.864C1097.29 272.803 1103.38 271.273 1110.44 271.273C1116.53 271.273 1121.87 272.379 1126.44 274.591C1131.02 276.803 1134.64 279.909 1137.31 283.909C1139.97 287.909 1141.44 292.606 1141.72 298H1123.44C1122.93 294.516 1121.56 291.712 1119.35 289.591C1117.17 287.44 1114.31 286.364 1110.76 286.364C1107.76 286.364 1105.14 287.182 1102.9 288.819C1100.69 290.425 1098.96 292.773 1097.72 295.864C1096.47 298.955 1095.85 302.697 1095.85 307.091C1095.85 311.546 1096.46 315.334 1097.67 318.455C1098.91 321.576 1100.66 323.955 1102.9 325.591C1105.14 327.228 1107.76 328.046 1110.76 328.046C1112.97 328.046 1114.96 327.591 1116.72 326.682C1118.5 325.773 1119.97 324.455 1121.12 322.728C1122.31 320.97 1123.08 318.864 1123.44 316.409H1141.72C1141.41 321.743 1139.96 326.44 1137.35 330.5C1134.78 334.531 1131.22 337.682 1126.67 339.955C1122.12 342.228 1116.75 343.364 1110.53 343.364Z" fill="white"/>
14
+ <mask id="path-11-inside-1_2003_244" fill="white">
15
+ <ellipse cx="299.674" cy="316.226" rx="213.041" ry="215.192" transform="rotate(-53.541 299.674 316.226)"/>
16
+ </mask>
17
+ <path d="M439.941 126.383C430.829 138.716 421.717 151.048 412.605 163.38C429.026 175.029 443.61 189.161 455.704 205.281C505.179 269.474 508.037 366.753 458.875 433.853C400.343 520.83 266.382 542.989 179.909 478.322C90.5123 418.173 64.6337 280.944 131.224 191.766C181.166 119.273 281.325 86.5091 366.537 114.886C387.789 121.676 407.989 131.839 426.273 144.882C408.445 131.223 388.509 120.301 367.275 112.707C282.323 81.0606 177.456 110.205 121.974 184.932C48.3824 276.372 69.1884 426.25 166.241 496.82C259.488 571.98 413.682 554.43 486.623 454.355C547.219 377.437 549.03 260.55 491.146 179.716C477.012 159.451 459.65 141.411 439.941 126.383ZM412.605 163.38L439.941 126.383L426.273 144.882L412.605 163.38Z" fill="#D9D9D9" mask="url(#path-11-inside-1_2003_244)"/>
18
+ <path d="M380.568 128.914C379.365 126.643 381.389 124.01 383.893 124.587L439.181 137.329C441.31 137.82 442.217 140.348 440.886 142.081L412.144 179.481C410.813 181.213 408.136 180.988 407.114 179.057L380.568 128.914Z" fill="#D9D9D9"/>
19
+ <defs>
20
+ <filter id="filter0_d_2003_244" x="86.761" y="102.758" width="428" height="432" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
21
+ <feFlood flood-opacity="0" result="BackgroundImageFix"/>
22
+ <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
23
+ <feOffset dy="4"/>
24
+ <feGaussianBlur stdDeviation="2"/>
25
+ <feComposite in2="hardAlpha" operator="out"/>
26
+ <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
27
+ <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_2003_244"/>
28
+ <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_2003_244" result="shape"/>
29
+ </filter>
30
+ </defs>
31
+ </svg>
package/README.md ADDED
@@ -0,0 +1,117 @@
1
+ <p align="center"><img src="AutoDocTextLogo.svg" alt="AutoDoc" width="260" /></p>
2
+
3
+ Keep your documentation in sync with your code. AutoDoc diffs your staged changes, asks an AI what docs need updating, shows you exactly what will change, and writes the file only after you approve.
4
+
5
+ ---
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g autodoc-cli
11
+ ```
12
+
13
+ Requires Node 18+.
14
+
15
+ ---
16
+
17
+ ## Quick start
18
+
19
+ ```bash
20
+ # 1. Set up autodoc in your project
21
+ cd your-project
22
+ autodoc init
23
+
24
+ # 2. Make code changes, stage them
25
+ git add .
26
+
27
+ # 3. Update the docs
28
+ autodoc build
29
+
30
+ # 4. Commit everything
31
+ git add docs/doc.md && git commit -m "..."
32
+ ```
33
+
34
+ ---
35
+
36
+ ## How it works
37
+
38
+ `autodoc build` runs before you commit:
39
+
40
+ 1. Reads your staged diff (`git diff --staged`)
41
+ 2. Sends the diff + your current doc file to the AI
42
+ 3. Prints a summary of what needs to change and why
43
+ 4. Asks for confirmation
44
+ 5. Writes the updated doc file
45
+
46
+ Nothing is written without your approval.
47
+
48
+ ---
49
+
50
+ ## Commands
51
+
52
+ ### `autodoc init`
53
+
54
+ Interactive setup. Creates a `.autodocrc` in the current directory.
55
+
56
+ ### `autodoc build`
57
+
58
+ Analyze changes and update documentation.
59
+
60
+ | Flag | Description |
61
+ |---|---|
62
+ | `-y, --yes` | Skip the confirmation prompt |
63
+ | `--diff <type>` | `staged` (default), `last-commit`, or `working` |
64
+ | `--doc <path>` | Override the doc file from config |
65
+
66
+ ---
67
+
68
+ ## Configuration
69
+
70
+ `autodoc init` creates a `.autodocrc` file:
71
+
72
+ ```json
73
+ {
74
+ "provider": "gemini",
75
+ "model": "gemini-2.0-flash",
76
+ "apiKey": "your-key",
77
+ "docFile": "./docs/doc.md"
78
+ }
79
+ ```
80
+
81
+ **Keeping your key out of the config** set an environment variable instead and leave `apiKey` out of `.autodocrc`:
82
+
83
+ | Provider | Environment variable |
84
+ |---|---|
85
+ | Gemini | `GEMINI_API_KEY` |
86
+ | Groq | `GROQ_API_KEY` |
87
+ | OpenAI | `OPENAI_API_KEY` |
88
+ | Anthropic | `ANTHROPIC_API_KEY` |
89
+
90
+ Or use `AUTODOC_API_KEY` for any provider.
91
+
92
+ Add `.autodocrc` to your `.gitignore` if the key is stored in it.
93
+
94
+ ---
95
+
96
+ ## Providers
97
+
98
+ | Provider | Free tier | Default model |
99
+ |---|---|---|
100
+ | **Gemini** | Yes [aistudio.google.com](https://aistudio.google.com) | `gemini-2.0-flash` |
101
+ | **Groq** | Yes [console.groq.com](https://console.groq.com) | `llama-3.1-8b-instant` |
102
+ | **OpenAI** | No | `gpt-4o-mini` |
103
+ | **Anthropic** | No | `claude-haiku-4-5-20251001` |
104
+
105
+ Override the model in `.autodocrc` or during `autodoc init`.
106
+
107
+ ---
108
+
109
+ ## Adding to an existing project
110
+
111
+ ```bash
112
+ npm install --save-dev autodoc-cli
113
+ autodoc init
114
+ echo ".autodocrc" >> .gitignore
115
+ ```
116
+
117
+ The `.autodocrc` walks up parent directories, so a monorepo can share one config at the root.
package/bin/autodoc.js ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { program } = require('commander');
4
+ const pkg = require('../package.json');
5
+
6
+ program
7
+ .name('autodoc')
8
+ .description('Auto-generate documentation from git changes using AI')
9
+ .version(pkg.version);
10
+
11
+ program
12
+ .command('init')
13
+ .description('Initialize AutoDoc in the current project')
14
+ .action(() => require('../src/commands/init').runInit());
15
+
16
+ program
17
+ .command('build')
18
+ .description('Analyze staged changes and update documentation')
19
+ .option('-y, --yes', 'Auto-approve all changes without prompting')
20
+ .option('--diff <type>', 'What to diff: staged (default), last-commit, or working', 'staged')
21
+ .option('--doc <path>', 'Override the doc file path from config')
22
+ .action((options) => require('../src/commands/build').runBuild(options));
23
+
24
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "@mascaro101/autodoc",
3
+ "version": "1.0.0",
4
+ "description": "Auto-generate and maintain documentation from git diffs using AI",
5
+ "license": "MIT",
6
+ "bin": {
7
+ "autodoc": "./bin/autodoc.js"
8
+ },
9
+ "engines": {
10
+ "node": ">=18.0.0"
11
+ },
12
+ "keywords": ["documentation", "ai", "git", "cli", "automation"],
13
+ "dependencies": {
14
+ "chalk": "^4.1.2",
15
+ "commander": "^11.1.0",
16
+ "inquirer": "^8.2.6"
17
+ }
18
+ }
@@ -0,0 +1,135 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+ const inquirer = require('inquirer');
5
+ const { getConfig } = require('../config');
6
+ const { getDiff, getStagedFiles, isGitRepo } = require('../git');
7
+ const { getProvider } = require('../providers');
8
+ const { log } = require('../ui');
9
+
10
+ async function runBuild(options = {}) {
11
+ if (!isGitRepo()) {
12
+ log.error('Not a git repository. AutoDoc requires git.');
13
+ process.exit(1);
14
+ }
15
+
16
+ let config;
17
+ try {
18
+ config = getConfig();
19
+ } catch (err) {
20
+ log.error(err.message);
21
+ process.exit(1);
22
+ }
23
+
24
+ // Doc file: CLI flag overrides config
25
+ const docFilePath = options.doc
26
+ ? path.resolve(process.cwd(), options.doc)
27
+ : path.resolve(process.cwd(), config.docFile);
28
+
29
+ if (!fs.existsSync(docFilePath)) {
30
+ log.error(`Doc file not found: ${options.doc || config.docFile}`);
31
+ log.info('Run `autodoc init` to create it, or pass --doc <path>.');
32
+ process.exit(1);
33
+ }
34
+
35
+ if (!config.apiKey) {
36
+ log.error('No API key found.');
37
+ log.info(
38
+ `Set it in .autodocrc (apiKey) or via an environment variable (AUTODOC_API_KEY or provider-specific).`
39
+ );
40
+ process.exit(1);
41
+ }
42
+
43
+ // Get diff
44
+ const diffType = options.diff || 'staged';
45
+ log.info(`Checking ${diffType} changes...`);
46
+
47
+ let diff;
48
+ try {
49
+ diff = getDiff(diffType);
50
+ } catch (err) {
51
+ log.error(err.message);
52
+ process.exit(1);
53
+ }
54
+
55
+ if (!diff.trim()) {
56
+ if (diffType === 'staged') {
57
+ log.warn('No staged changes. Run `git add <files>` before `autodoc build`.');
58
+ } else {
59
+ log.warn(`No ${diffType} changes found.`);
60
+ }
61
+ process.exit(0);
62
+ }
63
+
64
+ // Show changed file count for staged
65
+ if (diffType === 'staged') {
66
+ const files = getStagedFiles();
67
+ log.info(`Found ${files.length} changed file(s) to analyze.`);
68
+ }
69
+
70
+ const currentDoc = fs.readFileSync(docFilePath, 'utf8');
71
+
72
+ // Run AI analysis
73
+ const provider = getProvider(config.provider);
74
+ console.log(chalk.dim(`\n Sending to ${config.provider} (${config.model})...\n`));
75
+
76
+ let result;
77
+ try {
78
+ result = await provider.analyze(config.apiKey, config.model, currentDoc, diff);
79
+ } catch (err) {
80
+ log.error(`AI analysis failed: ${err.message}`);
81
+ process.exit(1);
82
+ }
83
+
84
+ if (!result.hasChanges) {
85
+ log.success('Documentation is already up to date. No changes needed.');
86
+ return;
87
+ }
88
+
89
+ // Display proposed changes
90
+ log.section('Documentation Changes Detected');
91
+
92
+ console.log(` ${chalk.bold('Summary:')} ${result.summary}\n`);
93
+
94
+ if (result.sections?.length) {
95
+ console.log(chalk.bold(' Proposed changes:'));
96
+ for (const s of result.sections) {
97
+ log.change(s.type, s.section, s.reason);
98
+ }
99
+ console.log('');
100
+ }
101
+
102
+ // Confirm
103
+ let approved = !!options.yes;
104
+ if (!approved) {
105
+ const { confirm } = await inquirer.prompt([
106
+ {
107
+ type: 'confirm',
108
+ name: 'confirm',
109
+ message: `Apply these changes to ${options.doc || config.docFile}?`,
110
+ default: true,
111
+ },
112
+ ]);
113
+ approved = confirm;
114
+ }
115
+
116
+ if (!approved) {
117
+ log.info('Changes not applied.');
118
+ return;
119
+ }
120
+
121
+ // Write updated doc
122
+ if (typeof result.updatedDoc !== 'string' || !result.updatedDoc.trim()) {
123
+ log.error('AI returned an empty document. Aborting to avoid overwriting your file.');
124
+ process.exit(1);
125
+ }
126
+
127
+ fs.writeFileSync(docFilePath, result.updatedDoc);
128
+ log.success(`Updated ${options.doc || config.docFile}`);
129
+
130
+ const docRelative = options.doc || config.docFile;
131
+ console.log(chalk.dim('\n Next: commit your changes including the updated doc.'));
132
+ console.log(chalk.dim(` git add ${docRelative} && git commit -m "docs: update documentation"\n`));
133
+ }
134
+
135
+ module.exports = { runBuild };
@@ -0,0 +1,147 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+ const inquirer = require('inquirer');
5
+ const { saveConfig, loadConfig, CONFIG_FILE } = require('../config');
6
+ const { PROVIDER_META, PROVIDERS } = require('../providers');
7
+ const { log } = require('../ui');
8
+
9
+ async function runInit() {
10
+ console.log(chalk.bold.cyan('\n AutoDoc — Init\n'));
11
+
12
+ const existing = loadConfig();
13
+ if (existing) {
14
+ const { overwrite } = await inquirer.prompt([
15
+ {
16
+ type: 'confirm',
17
+ name: 'overwrite',
18
+ message: `${CONFIG_FILE} already exists. Overwrite?`,
19
+ default: false,
20
+ },
21
+ ]);
22
+ if (!overwrite) {
23
+ log.info('Init cancelled.');
24
+ return;
25
+ }
26
+ }
27
+
28
+ const answers = await inquirer.prompt([
29
+ {
30
+ type: 'list',
31
+ name: 'provider',
32
+ message: 'Which AI provider?',
33
+ choices: Object.entries(PROVIDER_META).map(([value, { label }]) => ({
34
+ name: label,
35
+ value,
36
+ })),
37
+ },
38
+ {
39
+ type: 'input',
40
+ name: 'model',
41
+ message: (a) => `Model (default: ${PROVIDERS[a.provider].DEFAULT_MODEL}):`,
42
+ default: (a) => PROVIDERS[a.provider].DEFAULT_MODEL,
43
+ },
44
+ {
45
+ type: 'password',
46
+ name: 'apiKey',
47
+ message: 'API key (leave blank to use an environment variable):',
48
+ mask: '*',
49
+ },
50
+ {
51
+ type: 'input',
52
+ name: 'docFile',
53
+ message: 'Path to your documentation file:',
54
+ default: './docs/doc.md',
55
+ validate: (v) => (v.trim() ? true : 'Path is required'),
56
+ },
57
+ {
58
+ type: 'confirm',
59
+ name: 'createDoc',
60
+ message: (a) => `${a.docFile} does not exist. Create it with a starter template?`,
61
+ default: true,
62
+ when: (a) => !fs.existsSync(path.resolve(process.cwd(), a.docFile)),
63
+ },
64
+ ]);
65
+
66
+ const config = {
67
+ provider: answers.provider,
68
+ model: answers.model,
69
+ docFile: answers.docFile,
70
+ };
71
+
72
+ if (answers.apiKey) {
73
+ config.apiKey = answers.apiKey;
74
+ }
75
+
76
+ // Create doc file if requested
77
+ if (answers.createDoc) {
78
+ const docPath = path.resolve(process.cwd(), answers.docFile);
79
+ fs.mkdirSync(path.dirname(docPath), { recursive: true });
80
+ fs.writeFileSync(
81
+ docPath,
82
+ [
83
+ '# Project Documentation',
84
+ '',
85
+ '> Maintained by [AutoDoc](https://github.com/your-org/autodoc-cli).',
86
+ '',
87
+ '## Overview',
88
+ '',
89
+ 'Describe your project here.',
90
+ '',
91
+ '## Installation',
92
+ '',
93
+ '```bash',
94
+ '# installation steps',
95
+ '```',
96
+ '',
97
+ '## Usage',
98
+ '',
99
+ 'Describe how to use the project.',
100
+ '',
101
+ '## API',
102
+ '',
103
+ 'Document your API, functions, or configuration options here.',
104
+ '',
105
+ '## Changelog',
106
+ '',
107
+ '- Initial documentation.',
108
+ '',
109
+ ].join('\n')
110
+ );
111
+ log.success(`Created ${answers.docFile}`);
112
+ }
113
+
114
+ const configPath = saveConfig(config);
115
+ log.success(`Config saved → ${configPath}`);
116
+
117
+ // Warn if API key is stored in config (gitignore reminder)
118
+ if (answers.apiKey) {
119
+ console.log('');
120
+ log.warn(`Your API key is stored in ${CONFIG_FILE}.`);
121
+ console.log(
122
+ chalk.dim(` Add ${CONFIG_FILE} to .gitignore to avoid committing it:\n`) +
123
+ chalk.dim(` echo ".autodocrc" >> .gitignore\n`) +
124
+ chalk.dim(` Or remove "apiKey" from .autodocrc and set the env var instead:\n`) +
125
+ chalk.dim(` export ${getEnvKey(answers.provider)}=your_key`)
126
+ );
127
+ }
128
+
129
+ console.log('');
130
+ console.log(chalk.bold(' Next steps:'));
131
+ console.log(chalk.dim(' 1. Make your code changes'));
132
+ console.log(chalk.dim(' 2. Stage them with: git add .'));
133
+ console.log(chalk.dim(' 3. Run: autodoc build'));
134
+ console.log(chalk.dim(' 4. Approve the doc changes, then commit & push\n'));
135
+ }
136
+
137
+ function getEnvKey(provider) {
138
+ const map = {
139
+ gemini: 'GEMINI_API_KEY',
140
+ groq: 'GROQ_API_KEY',
141
+ openai: 'OPENAI_API_KEY',
142
+ anthropic: 'ANTHROPIC_API_KEY',
143
+ };
144
+ return map[provider] || 'AUTODOC_API_KEY';
145
+ }
146
+
147
+ module.exports = { runInit };
package/src/config.js ADDED
@@ -0,0 +1,55 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const CONFIG_FILE = '.autodocrc';
5
+
6
+ const ENV_KEYS = {
7
+ gemini: 'GEMINI_API_KEY',
8
+ groq: 'GROQ_API_KEY',
9
+ openai: 'OPENAI_API_KEY',
10
+ anthropic: 'ANTHROPIC_API_KEY',
11
+ };
12
+
13
+ function findConfigPath(dir = process.cwd()) {
14
+ const candidate = path.join(dir, CONFIG_FILE);
15
+ if (fs.existsSync(candidate)) return candidate;
16
+ const parent = path.dirname(dir);
17
+ if (parent === dir) return null;
18
+ return findConfigPath(parent);
19
+ }
20
+
21
+ function loadConfig() {
22
+ const configPath = findConfigPath();
23
+ if (!configPath) return null;
24
+ try {
25
+ return { ...JSON.parse(fs.readFileSync(configPath, 'utf8')), _path: configPath };
26
+ } catch {
27
+ throw new Error(`Failed to parse ${configPath} — is it valid JSON?`);
28
+ }
29
+ }
30
+
31
+ function saveConfig(config, dir = process.cwd()) {
32
+ const configPath = path.join(dir, CONFIG_FILE);
33
+ const { _path, ...clean } = config;
34
+ fs.writeFileSync(configPath, JSON.stringify(clean, null, 2) + '\n');
35
+ return configPath;
36
+ }
37
+
38
+ function getConfig() {
39
+ const config = loadConfig();
40
+ if (!config) {
41
+ throw new Error('No .autodocrc found. Run `autodoc init` first.');
42
+ }
43
+
44
+ // Resolve API key from env if not in config
45
+ if (!config.apiKey) {
46
+ config.apiKey =
47
+ process.env.AUTODOC_API_KEY ||
48
+ (config.provider && process.env[ENV_KEYS[config.provider]]) ||
49
+ null;
50
+ }
51
+
52
+ return config;
53
+ }
54
+
55
+ module.exports = { loadConfig, saveConfig, getConfig, CONFIG_FILE };
package/src/git.js ADDED
@@ -0,0 +1,44 @@
1
+ const { execSync } = require('child_process');
2
+
3
+ function exec(cmd) {
4
+ return execSync(cmd, { encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 });
5
+ }
6
+
7
+ function isGitRepo() {
8
+ try {
9
+ exec('git rev-parse --git-dir');
10
+ return true;
11
+ } catch {
12
+ return false;
13
+ }
14
+ }
15
+
16
+ function getDiff(type = 'staged') {
17
+ const cmds = {
18
+ staged: 'git diff --staged',
19
+ 'last-commit': 'git diff HEAD~1 HEAD',
20
+ working: 'git diff',
21
+ };
22
+
23
+ const cmd = cmds[type];
24
+ if (!cmd) throw new Error(`Unknown diff type: "${type}". Use: staged, last-commit, working`);
25
+
26
+ try {
27
+ return exec(cmd);
28
+ } catch (err) {
29
+ if (err.message.includes('not a git repository')) {
30
+ throw new Error('Not a git repository. AutoDoc requires git.');
31
+ }
32
+ // last-commit fails on repos with only one commit
33
+ if (type === 'last-commit' && err.message.includes('unknown revision')) {
34
+ throw new Error('No previous commit to diff against. Try --diff working');
35
+ }
36
+ throw err;
37
+ }
38
+ }
39
+
40
+ function getStagedFiles() {
41
+ return exec('git diff --staged --name-only').trim().split('\n').filter(Boolean);
42
+ }
43
+
44
+ module.exports = { isGitRepo, getDiff, getStagedFiles };
@@ -0,0 +1,31 @@
1
+ const { buildPrompt, parseResponse } = require('./common');
2
+
3
+ const DEFAULT_MODEL = 'claude-haiku-4-5-20251001';
4
+
5
+ async function analyze(apiKey, model, currentDoc, diff) {
6
+ const res = await fetch('https://api.anthropic.com/v1/messages', {
7
+ method: 'POST',
8
+ headers: {
9
+ 'x-api-key': apiKey,
10
+ 'anthropic-version': '2023-06-01',
11
+ 'Content-Type': 'application/json',
12
+ },
13
+ body: JSON.stringify({
14
+ model,
15
+ max_tokens: 8192,
16
+ messages: [{ role: 'user', content: buildPrompt(currentDoc, diff) }],
17
+ }),
18
+ });
19
+
20
+ if (!res.ok) {
21
+ const body = await res.json().catch(() => ({}));
22
+ throw new Error(`Anthropic error ${res.status}: ${body.error?.message || res.statusText}`);
23
+ }
24
+
25
+ const data = await res.json();
26
+ const text = data.content?.[0]?.text;
27
+ if (!text) throw new Error('Empty response from Anthropic');
28
+ return parseResponse(text);
29
+ }
30
+
31
+ module.exports = { analyze, DEFAULT_MODEL };
@@ -0,0 +1,43 @@
1
+ function buildPrompt(currentDoc, diff) {
2
+ return `Update the documentation to reflect the code changes in the diff.
3
+
4
+ Current documentation:
5
+ ===
6
+ ${currentDoc}
7
+ ===
8
+
9
+ Git diff:
10
+ ===
11
+ ${diff}
12
+ ===
13
+
14
+ Return JSON only, no extra text:
15
+ {
16
+ "hasChanges": <true if anything needs updating, false otherwise>,
17
+ "summary": "<what specifically changed, e.g. 'renamed login() to authenticate(), added optional timeout param'>",
18
+ "sections": [
19
+ {
20
+ "type": "<update | add | remove>",
21
+ "section": "<section heading>",
22
+ "reason": "<what changed and why the docs need to reflect it, e.g. 'config.port was renamed to config.serverPort'>"
23
+ }
24
+ ],
25
+ "updatedDoc": "<full updated markdown doc>"
26
+ }`;
27
+ }
28
+
29
+ function parseResponse(raw) {
30
+ // Strip accidental code block wrapping from models that ignore instructions
31
+ const text = raw
32
+ .replace(/^```(?:json)?\s*/i, '')
33
+ .replace(/\s*```\s*$/, '')
34
+ .trim();
35
+
36
+ try {
37
+ return JSON.parse(text);
38
+ } catch {
39
+ throw new Error(`AI returned non-JSON response:\n${raw.slice(0, 300)}`);
40
+ }
41
+ }
42
+
43
+ module.exports = { buildPrompt, parseResponse };
@@ -0,0 +1,28 @@
1
+ const { buildPrompt, parseResponse } = require('./common');
2
+
3
+ const DEFAULT_MODEL = 'gemini-2.0-flash';
4
+
5
+ async function analyze(apiKey, model, currentDoc, diff) {
6
+ const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${apiKey}`;
7
+
8
+ const res = await fetch(url, {
9
+ method: 'POST',
10
+ headers: { 'Content-Type': 'application/json' },
11
+ body: JSON.stringify({
12
+ contents: [{ parts: [{ text: buildPrompt(currentDoc, diff) }] }],
13
+ generationConfig: { temperature: 0.1 },
14
+ }),
15
+ });
16
+
17
+ if (!res.ok) {
18
+ const body = await res.json().catch(() => ({}));
19
+ throw new Error(`Gemini error ${res.status}: ${body.error?.message || res.statusText}`);
20
+ }
21
+
22
+ const data = await res.json();
23
+ const text = data.candidates?.[0]?.content?.parts?.[0]?.text;
24
+ if (!text) throw new Error('Empty response from Gemini');
25
+ return parseResponse(text);
26
+ }
27
+
28
+ module.exports = { analyze, DEFAULT_MODEL };
@@ -0,0 +1,30 @@
1
+ const { buildPrompt, parseResponse } = require('./common');
2
+
3
+ const DEFAULT_MODEL = 'llama-3.1-8b-instant';
4
+
5
+ async function analyze(apiKey, model, currentDoc, diff) {
6
+ const res = await fetch('https://api.groq.com/openai/v1/chat/completions', {
7
+ method: 'POST',
8
+ headers: {
9
+ Authorization: `Bearer ${apiKey}`,
10
+ 'Content-Type': 'application/json',
11
+ },
12
+ body: JSON.stringify({
13
+ model,
14
+ messages: [{ role: 'user', content: buildPrompt(currentDoc, diff) }],
15
+ temperature: 0.1,
16
+ }),
17
+ });
18
+
19
+ if (!res.ok) {
20
+ const body = await res.json().catch(() => ({}));
21
+ throw new Error(`Groq error ${res.status}: ${body.error?.message || res.statusText}`);
22
+ }
23
+
24
+ const data = await res.json();
25
+ const text = data.choices?.[0]?.message?.content;
26
+ if (!text) throw new Error('Empty response from Groq');
27
+ return parseResponse(text);
28
+ }
29
+
30
+ module.exports = { analyze, DEFAULT_MODEL };
@@ -0,0 +1,25 @@
1
+ const PROVIDERS = {
2
+ gemini: require('./gemini'),
3
+ groq: require('./groq'),
4
+ openai: require('./openai'),
5
+ anthropic: require('./anthropic'),
6
+ };
7
+
8
+ function getProvider(name) {
9
+ const provider = PROVIDERS[name];
10
+ if (!provider) {
11
+ throw new Error(
12
+ `Unknown provider: "${name}". Supported: ${Object.keys(PROVIDERS).join(', ')}`
13
+ );
14
+ }
15
+ return provider;
16
+ }
17
+
18
+ const PROVIDER_META = {
19
+ gemini: { label: 'Google Gemini (free tier available)' },
20
+ groq: { label: 'Groq (free tier available)' },
21
+ openai: { label: 'OpenAI' },
22
+ anthropic: { label: 'Anthropic Claude' },
23
+ };
24
+
25
+ module.exports = { getProvider, PROVIDER_META, PROVIDERS };
@@ -0,0 +1,31 @@
1
+ const { buildPrompt, parseResponse } = require('./common');
2
+
3
+ const DEFAULT_MODEL = 'gpt-4o-mini';
4
+
5
+ async function analyze(apiKey, model, currentDoc, diff) {
6
+ const res = await fetch('https://api.openai.com/v1/chat/completions', {
7
+ method: 'POST',
8
+ headers: {
9
+ Authorization: `Bearer ${apiKey}`,
10
+ 'Content-Type': 'application/json',
11
+ },
12
+ body: JSON.stringify({
13
+ model,
14
+ messages: [{ role: 'user', content: buildPrompt(currentDoc, diff) }],
15
+ temperature: 0.1,
16
+ response_format: { type: 'json_object' },
17
+ }),
18
+ });
19
+
20
+ if (!res.ok) {
21
+ const body = await res.json().catch(() => ({}));
22
+ throw new Error(`OpenAI error ${res.status}: ${body.error?.message || res.statusText}`);
23
+ }
24
+
25
+ const data = await res.json();
26
+ const text = data.choices?.[0]?.message?.content;
27
+ if (!text) throw new Error('Empty response from OpenAI');
28
+ return parseResponse(text);
29
+ }
30
+
31
+ module.exports = { analyze, DEFAULT_MODEL };
package/src/ui.js ADDED
@@ -0,0 +1,30 @@
1
+ const chalk = require('chalk');
2
+
3
+ const ICONS = { info: 'ℹ', success: '✓', warn: '⚠', error: '✗' };
4
+
5
+ const log = {
6
+ info: (msg) => console.log(chalk.blue(ICONS.info), msg),
7
+ success: (msg) => console.log(chalk.green(ICONS.success), msg),
8
+ warn: (msg) => console.log(chalk.yellow(ICONS.warn), msg),
9
+ error: (msg) => console.error(chalk.red(ICONS.error), msg),
10
+
11
+ section(title) {
12
+ const bar = chalk.bold.cyan('─'.repeat(52));
13
+ console.log(`\n${bar}`);
14
+ console.log(chalk.bold.cyan(` ${title}`));
15
+ console.log(`${bar}\n`);
16
+ },
17
+
18
+ change(type, section, reason) {
19
+ const styles = {
20
+ add: { icon: '+', color: chalk.green, label: 'ADD' },
21
+ remove: { icon: '-', color: chalk.red, label: 'REMOVE' },
22
+ update: { icon: '~', color: chalk.yellow, label: 'UPDATE' },
23
+ };
24
+ const s = styles[type] || styles.update;
25
+ console.log(` ${s.color(s.icon)} ${s.color.bold(`[${s.label}]`)} ${chalk.bold(section)}`);
26
+ console.log(` ${chalk.dim(reason)}`);
27
+ },
28
+ };
29
+
30
+ module.exports = { log };