@devinnn/docdrift 0.1.2 → 0.1.4

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,87 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.fetchSpec = fetchSpec;
7
+ exports.fetchSpecPost = fetchSpecPost;
8
+ const node_https_1 = __importDefault(require("node:https"));
9
+ const node_http_1 = __importDefault(require("node:http"));
10
+ const TIMEOUT_MS = 30_000;
11
+ function getAgent(_url) {
12
+ const proxy = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
13
+ if (proxy) {
14
+ try {
15
+ const { HttpsProxyAgent } = require("https-proxy-agent");
16
+ return new HttpsProxyAgent(proxy);
17
+ }
18
+ catch {
19
+ // Optional dependency not installed
20
+ }
21
+ }
22
+ return undefined;
23
+ }
24
+ /**
25
+ * Fetch a URL and return the response body as string.
26
+ * Respects HTTP_PROXY, HTTPS_PROXY; 30s timeout; follows redirects.
27
+ */
28
+ async function fetchSpec(url) {
29
+ const parsed = new URL(url);
30
+ const isHttps = parsed.protocol === "https:";
31
+ const agent = getAgent(url);
32
+ return new Promise((resolve, reject) => {
33
+ const req = (isHttps ? node_https_1.default : node_http_1.default).get(url, { agent: agent ?? undefined, timeout: TIMEOUT_MS }, (res) => {
34
+ const redirect = res.headers.location;
35
+ if (redirect && [301, 302, 307, 308].includes(res.statusCode ?? 0)) {
36
+ req.destroy();
37
+ fetchSpec(new URL(redirect, url).href).then(resolve).catch(reject);
38
+ return;
39
+ }
40
+ const chunks = [];
41
+ res.on("data", (chunk) => chunks.push(chunk));
42
+ res.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
43
+ res.on("error", reject);
44
+ });
45
+ req.on("timeout", () => {
46
+ req.destroy();
47
+ reject(new Error(`Fetch timeout after ${TIMEOUT_MS}ms`));
48
+ });
49
+ req.on("error", reject);
50
+ });
51
+ }
52
+ /**
53
+ * POST to a URL with JSON body (e.g. GraphQL introspection).
54
+ */
55
+ async function fetchSpecPost(url, body) {
56
+ const parsed = new URL(url);
57
+ const isHttps = parsed.protocol === "https:";
58
+ const agent = getAgent(url);
59
+ const bodyStr = JSON.stringify(body);
60
+ return new Promise((resolve, reject) => {
61
+ const options = {
62
+ hostname: parsed.hostname,
63
+ port: parsed.port || (isHttps ? 443 : 80),
64
+ path: parsed.pathname + parsed.search,
65
+ method: "POST",
66
+ headers: {
67
+ "Content-Type": "application/json",
68
+ "Content-Length": Buffer.byteLength(bodyStr),
69
+ },
70
+ ...(agent && { agent }),
71
+ timeout: TIMEOUT_MS,
72
+ };
73
+ const req = (isHttps ? node_https_1.default : node_http_1.default).request(options, (res) => {
74
+ const chunks = [];
75
+ res.on("data", (chunk) => chunks.push(chunk));
76
+ res.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
77
+ res.on("error", reject);
78
+ });
79
+ req.on("timeout", () => {
80
+ req.destroy();
81
+ reject(new Error(`Fetch timeout after ${TIMEOUT_MS}ms`));
82
+ });
83
+ req.on("error", reject);
84
+ req.write(bodyStr);
85
+ req.end();
86
+ });
87
+ }
@@ -1,9 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveDefaultBaseHead = resolveDefaultBaseHead;
3
4
  exports.gitChangedPaths = gitChangedPaths;
4
5
  exports.gitDiffSummary = gitDiffSummary;
5
6
  exports.gitCommitList = gitCommitList;
6
7
  const exec_1 = require("./exec");
8
+ /** Resolve default base/head when not provided. Uses GITHUB_* in CI, else merge-base(main, headRef)..headRef. */
9
+ async function resolveDefaultBaseHead(headRef = process.env.GITHUB_SHA ?? "HEAD") {
10
+ const headSha = headRef;
11
+ const baseSha = process.env.GITHUB_BASE_SHA;
12
+ if (baseSha) {
13
+ return { baseSha, headSha };
14
+ }
15
+ for (const branch of ["origin/main", "origin/master", "main", "master"]) {
16
+ const res = await (0, exec_1.execCommand)(`git merge-base ${branch} ${headRef}`);
17
+ if (res.exitCode === 0 && res.stdout.trim()) {
18
+ return { baseSha: res.stdout.trim(), headSha };
19
+ }
20
+ }
21
+ const fallback = await (0, exec_1.execCommand)(`git rev-parse ${headRef}^`);
22
+ if (fallback.exitCode === 0 && fallback.stdout.trim()) {
23
+ return { baseSha: fallback.stdout.trim(), headSha };
24
+ }
25
+ return { baseSha: headSha, headSha };
26
+ }
7
27
  async function gitChangedPaths(baseSha, headSha) {
8
28
  const res = await (0, exec_1.execCommand)(`git diff --name-only ${baseSha} ${headSha}`);
9
29
  if (res.exitCode !== 0) {
@@ -0,0 +1,438 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://github.com/devinnn/docdrift/docdrift.schema.json",
4
+ "title": "DocDrift Configuration",
5
+ "description": "Repository-local config for docdrift (detect and remediate documentation drift with Devin). See docdrift-yml.md for full reference.",
6
+ "type": "object",
7
+ "properties": {
8
+ "version": {
9
+ "type": "number",
10
+ "enum": [
11
+ 1,
12
+ 2
13
+ ]
14
+ },
15
+ "specProviders": {
16
+ "type": "array",
17
+ "items": {
18
+ "type": "object",
19
+ "properties": {
20
+ "format": {
21
+ "type": "string",
22
+ "enum": [
23
+ "openapi3",
24
+ "swagger2",
25
+ "graphql",
26
+ "fern",
27
+ "postman"
28
+ ]
29
+ },
30
+ "current": {
31
+ "anyOf": [
32
+ {
33
+ "type": "object",
34
+ "properties": {
35
+ "type": {
36
+ "type": "string",
37
+ "const": "url"
38
+ },
39
+ "url": {
40
+ "type": "string",
41
+ "format": "uri"
42
+ }
43
+ },
44
+ "required": [
45
+ "type",
46
+ "url"
47
+ ],
48
+ "additionalProperties": false
49
+ },
50
+ {
51
+ "type": "object",
52
+ "properties": {
53
+ "type": {
54
+ "type": "string",
55
+ "const": "local"
56
+ },
57
+ "path": {
58
+ "type": "string",
59
+ "minLength": 1
60
+ }
61
+ },
62
+ "required": [
63
+ "type",
64
+ "path"
65
+ ],
66
+ "additionalProperties": false
67
+ },
68
+ {
69
+ "type": "object",
70
+ "properties": {
71
+ "type": {
72
+ "type": "string",
73
+ "const": "export"
74
+ },
75
+ "command": {
76
+ "type": "string",
77
+ "minLength": 1
78
+ },
79
+ "outputPath": {
80
+ "type": "string",
81
+ "minLength": 1
82
+ }
83
+ },
84
+ "required": [
85
+ "type",
86
+ "command",
87
+ "outputPath"
88
+ ],
89
+ "additionalProperties": false
90
+ }
91
+ ]
92
+ },
93
+ "published": {
94
+ "type": "string",
95
+ "minLength": 1
96
+ }
97
+ },
98
+ "required": [
99
+ "format",
100
+ "current",
101
+ "published"
102
+ ],
103
+ "additionalProperties": false
104
+ }
105
+ },
106
+ "openapi": {
107
+ "type": "object",
108
+ "properties": {
109
+ "export": {
110
+ "type": "string",
111
+ "minLength": 1
112
+ },
113
+ "generated": {
114
+ "type": "string",
115
+ "minLength": 1
116
+ },
117
+ "published": {
118
+ "type": "string",
119
+ "minLength": 1
120
+ }
121
+ },
122
+ "required": [
123
+ "export",
124
+ "generated",
125
+ "published"
126
+ ],
127
+ "additionalProperties": false
128
+ },
129
+ "docsite": {
130
+ "anyOf": [
131
+ {
132
+ "type": "string",
133
+ "minLength": 1
134
+ },
135
+ {
136
+ "type": "array",
137
+ "items": {
138
+ "type": "string",
139
+ "minLength": 1
140
+ }
141
+ }
142
+ ]
143
+ },
144
+ "exclude": {
145
+ "type": "array",
146
+ "items": {
147
+ "type": "string",
148
+ "minLength": 1
149
+ },
150
+ "default": []
151
+ },
152
+ "requireHumanReview": {
153
+ "type": "array",
154
+ "items": {
155
+ "type": "string",
156
+ "minLength": 1
157
+ },
158
+ "default": []
159
+ },
160
+ "pathMappings": {
161
+ "type": "array",
162
+ "items": {
163
+ "type": "object",
164
+ "properties": {
165
+ "match": {
166
+ "type": "string",
167
+ "minLength": 1
168
+ },
169
+ "impacts": {
170
+ "type": "array",
171
+ "items": {
172
+ "type": "string",
173
+ "minLength": 1
174
+ },
175
+ "minItems": 1
176
+ }
177
+ },
178
+ "required": [
179
+ "match",
180
+ "impacts"
181
+ ],
182
+ "additionalProperties": false
183
+ },
184
+ "default": []
185
+ },
186
+ "allowConceptualOnlyRun": {
187
+ "type": "boolean",
188
+ "default": false
189
+ },
190
+ "inferMode": {
191
+ "type": "boolean",
192
+ "default": true
193
+ },
194
+ "devin": {
195
+ "type": "object",
196
+ "properties": {
197
+ "apiVersion": {
198
+ "type": "string",
199
+ "const": "v1"
200
+ },
201
+ "unlisted": {
202
+ "type": "boolean",
203
+ "default": true
204
+ },
205
+ "maxAcuLimit": {
206
+ "type": "integer",
207
+ "exclusiveMinimum": 0,
208
+ "default": 2
209
+ },
210
+ "tags": {
211
+ "type": "array",
212
+ "items": {
213
+ "type": "string",
214
+ "minLength": 1
215
+ },
216
+ "default": [
217
+ "docdrift"
218
+ ]
219
+ },
220
+ "customInstructions": {
221
+ "type": "array",
222
+ "items": {
223
+ "type": "string",
224
+ "minLength": 1
225
+ }
226
+ },
227
+ "customInstructionContent": {
228
+ "type": "string"
229
+ }
230
+ },
231
+ "required": [
232
+ "apiVersion"
233
+ ],
234
+ "additionalProperties": false
235
+ },
236
+ "policy": {
237
+ "type": "object",
238
+ "properties": {
239
+ "prCaps": {
240
+ "type": "object",
241
+ "properties": {
242
+ "maxPrsPerDay": {
243
+ "type": "integer",
244
+ "exclusiveMinimum": 0,
245
+ "default": 1
246
+ },
247
+ "maxFilesTouched": {
248
+ "type": "integer",
249
+ "exclusiveMinimum": 0,
250
+ "default": 12
251
+ }
252
+ },
253
+ "additionalProperties": false
254
+ },
255
+ "confidence": {
256
+ "type": "object",
257
+ "properties": {
258
+ "autopatchThreshold": {
259
+ "type": "number",
260
+ "minimum": 0,
261
+ "maximum": 1,
262
+ "default": 0.8
263
+ }
264
+ },
265
+ "additionalProperties": false
266
+ },
267
+ "allowlist": {
268
+ "type": "array",
269
+ "items": {
270
+ "type": "string",
271
+ "minLength": 1
272
+ },
273
+ "minItems": 1
274
+ },
275
+ "verification": {
276
+ "type": "object",
277
+ "properties": {
278
+ "commands": {
279
+ "type": "array",
280
+ "items": {
281
+ "type": "string",
282
+ "minLength": 1
283
+ },
284
+ "minItems": 1
285
+ }
286
+ },
287
+ "required": [
288
+ "commands"
289
+ ],
290
+ "additionalProperties": false
291
+ },
292
+ "slaDays": {
293
+ "type": "integer",
294
+ "minimum": 0,
295
+ "default": 7
296
+ },
297
+ "slaLabel": {
298
+ "type": "string",
299
+ "minLength": 1,
300
+ "default": "docdrift"
301
+ },
302
+ "allowNewFiles": {
303
+ "type": "boolean",
304
+ "default": false
305
+ }
306
+ },
307
+ "required": [
308
+ "prCaps",
309
+ "confidence",
310
+ "allowlist",
311
+ "verification"
312
+ ],
313
+ "additionalProperties": false
314
+ },
315
+ "docAreas": {
316
+ "type": "array",
317
+ "items": {
318
+ "type": "object",
319
+ "properties": {
320
+ "name": {
321
+ "type": "string",
322
+ "minLength": 1
323
+ },
324
+ "mode": {
325
+ "type": "string",
326
+ "enum": [
327
+ "autogen",
328
+ "conceptual"
329
+ ]
330
+ },
331
+ "owners": {
332
+ "type": "object",
333
+ "properties": {
334
+ "reviewers": {
335
+ "type": "array",
336
+ "items": {
337
+ "type": "string",
338
+ "minLength": 1
339
+ },
340
+ "minItems": 1
341
+ }
342
+ },
343
+ "required": [
344
+ "reviewers"
345
+ ],
346
+ "additionalProperties": false
347
+ },
348
+ "detect": {
349
+ "type": "object",
350
+ "properties": {
351
+ "openapi": {
352
+ "type": "object",
353
+ "properties": {
354
+ "exportCmd": {
355
+ "type": "string",
356
+ "minLength": 1
357
+ },
358
+ "generatedPath": {
359
+ "type": "string",
360
+ "minLength": 1
361
+ },
362
+ "publishedPath": {
363
+ "type": "string",
364
+ "minLength": 1
365
+ }
366
+ },
367
+ "required": [
368
+ "exportCmd",
369
+ "generatedPath",
370
+ "publishedPath"
371
+ ],
372
+ "additionalProperties": false
373
+ },
374
+ "paths": {
375
+ "type": "array",
376
+ "items": {
377
+ "type": "object",
378
+ "properties": {
379
+ "match": {
380
+ "type": "string",
381
+ "minLength": 1
382
+ },
383
+ "impacts": {
384
+ "type": "array",
385
+ "items": {
386
+ "type": "string",
387
+ "minLength": 1
388
+ },
389
+ "minItems": 1
390
+ }
391
+ },
392
+ "required": [
393
+ "match",
394
+ "impacts"
395
+ ],
396
+ "additionalProperties": false
397
+ }
398
+ }
399
+ },
400
+ "additionalProperties": false
401
+ },
402
+ "patch": {
403
+ "type": "object",
404
+ "properties": {
405
+ "targets": {
406
+ "type": "array",
407
+ "items": {
408
+ "type": "string",
409
+ "minLength": 1
410
+ }
411
+ },
412
+ "requireHumanConfirmation": {
413
+ "type": "boolean",
414
+ "default": false
415
+ }
416
+ },
417
+ "additionalProperties": false
418
+ }
419
+ },
420
+ "required": [
421
+ "name",
422
+ "mode",
423
+ "owners",
424
+ "detect",
425
+ "patch"
426
+ ],
427
+ "additionalProperties": false
428
+ },
429
+ "default": []
430
+ }
431
+ },
432
+ "required": [
433
+ "version",
434
+ "devin",
435
+ "policy"
436
+ ],
437
+ "additionalProperties": false
438
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devinnn/docdrift",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "private": false,
5
5
  "description": "Detect and remediate documentation drift with Devin sessions",
6
6
  "main": "dist/src/index.js",
@@ -12,7 +12,8 @@
12
12
  "node": ">=20"
13
13
  },
14
14
  "files": [
15
- "dist/src"
15
+ "dist/src",
16
+ "docdrift.schema.json"
16
17
  ],
17
18
  "repository": {
18
19
  "type": "git",
@@ -35,10 +36,17 @@
35
36
  "docs:gen": "npm run --prefix apps/docs-site docusaurus -- gen-api-docs api",
36
37
  "docs:build": "npm run --prefix apps/docs-site build",
37
38
  "docs:serve": "npm run --prefix apps/docs-site start",
38
- "docdrift": "tsx src/cli.ts"
39
+ "docdrift": "tsx src/cli.ts",
40
+ "schema:generate": "tsx scripts/generate-schema.ts",
41
+ "prebuild": "npm run schema:generate",
42
+ "prepublishOnly": "npm run build"
39
43
  },
40
44
  "dependencies": {
45
+ "@ai-sdk/gateway": "^1.0.0",
46
+ "@inquirer/prompts": "^7.2.0",
41
47
  "@octokit/rest": "^21.1.1",
48
+ "ai": "^4.0.0",
49
+ "dotenv": "^16.4.5",
42
50
  "fastify": "^5.2.1",
43
51
  "js-yaml": "^4.1.0",
44
52
  "zod": "^3.24.1"
@@ -50,6 +58,7 @@
50
58
  "prettier": "^3.5.0",
51
59
  "tsx": "^4.19.2",
52
60
  "typescript": "^5.7.3",
53
- "vitest": "^3.0.5"
61
+ "vitest": "^3.0.5",
62
+ "zod-to-json-schema": "^3.25.1"
54
63
  }
55
- }
64
+ }