@maintainabilityai/research-runner 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +82 -0
- package/bin/research-runner.js +2 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +209 -0
- package/dist/llm/anthropic-client.d.ts +39 -0
- package/dist/llm/anthropic-client.js +74 -0
- package/dist/llm/github-models-client.d.ts +46 -0
- package/dist/llm/github-models-client.js +78 -0
- package/dist/llm/llm-router.d.ts +46 -0
- package/dist/llm/llm-router.js +60 -0
- package/dist/mesh/get-mesh-sha.d.ts +1 -0
- package/dist/mesh/get-mesh-sha.js +27 -0
- package/dist/mesh/mesh-reader.d.ts +14 -0
- package/dist/mesh/mesh-reader.js +392 -0
- package/dist/mesh/prompt-loader.d.ts +22 -0
- package/dist/mesh/prompt-loader.js +119 -0
- package/dist/mesh/threat-model-reader.d.ts +33 -0
- package/dist/mesh/threat-model-reader.js +123 -0
- package/dist/runner/archeologist.d.ts +39 -0
- package/dist/runner/archeologist.js +620 -0
- package/dist/runner/audit-emitter.d.ts +62 -0
- package/dist/runner/audit-emitter.js +210 -0
- package/dist/runner/hatters-tag-builder.d.ts +52 -0
- package/dist/runner/hatters-tag-builder.js +40 -0
- package/dist/runner/nodes/analyze-architecture.d.ts +10 -0
- package/dist/runner/nodes/analyze-architecture.js +447 -0
- package/dist/runner/nodes/arxiv-search.d.ts +12 -0
- package/dist/runner/nodes/arxiv-search.js +52 -0
- package/dist/runner/nodes/clone-and-index.d.ts +32 -0
- package/dist/runner/nodes/clone-and-index.js +158 -0
- package/dist/runner/nodes/dedupe-and-rank.d.ts +27 -0
- package/dist/runner/nodes/dedupe-and-rank.js +98 -0
- package/dist/runner/nodes/deterministic-review.d.ts +55 -0
- package/dist/runner/nodes/deterministic-review.js +206 -0
- package/dist/runner/nodes/expert-review.d.ts +68 -0
- package/dist/runner/nodes/expert-review.js +197 -0
- package/dist/runner/nodes/gap-analysis.d.ts +48 -0
- package/dist/runner/nodes/gap-analysis.js +153 -0
- package/dist/runner/nodes/generate-prd-manifest.d.ts +53 -0
- package/dist/runner/nodes/generate-prd-manifest.js +209 -0
- package/dist/runner/nodes/hackernews-search.d.ts +12 -0
- package/dist/runner/nodes/hackernews-search.js +63 -0
- package/dist/runner/nodes/identify-gaps.d.ts +33 -0
- package/dist/runner/nodes/identify-gaps.js +185 -0
- package/dist/runner/nodes/plan-queries.d.ts +28 -0
- package/dist/runner/nodes/plan-queries.js +120 -0
- package/dist/runner/nodes/prd-validator.d.ts +51 -0
- package/dist/runner/nodes/prd-validator.js +203 -0
- package/dist/runner/nodes/synthesis-archaeology-validator.d.ts +22 -0
- package/dist/runner/nodes/synthesis-archaeology-validator.js +131 -0
- package/dist/runner/nodes/synthesis-validator.d.ts +51 -0
- package/dist/runner/nodes/synthesis-validator.js +185 -0
- package/dist/runner/nodes/synthesize-prd.d.ts +84 -0
- package/dist/runner/nodes/synthesize-prd.js +202 -0
- package/dist/runner/nodes/synthesize-report.d.ts +53 -0
- package/dist/runner/nodes/synthesize-report.js +188 -0
- package/dist/runner/nodes/tavily-search.d.ts +21 -0
- package/dist/runner/nodes/tavily-search.js +57 -0
- package/dist/runner/nodes/uspto-search.d.ts +13 -0
- package/dist/runner/nodes/uspto-search.js +62 -0
- package/dist/runner/nodes/verify-grounding.d.ts +54 -0
- package/dist/runner/nodes/verify-grounding.js +134 -0
- package/dist/runner/prd.d.ts +28 -0
- package/dist/runner/prd.js +494 -0
- package/dist/schemas/audit-event.d.ts +1151 -0
- package/dist/schemas/audit-event.js +141 -0
- package/dist/schemas/index.d.ts +17 -0
- package/dist/schemas/index.js +33 -0
- package/dist/schemas/mesh-context.d.ts +415 -0
- package/dist/schemas/mesh-context.js +95 -0
- package/dist/schemas/observed-architecture.d.ts +262 -0
- package/dist/schemas/observed-architecture.js +90 -0
- package/dist/schemas/prd-brief.d.ts +111 -0
- package/dist/schemas/prd-brief.js +37 -0
- package/dist/schemas/prd-doc.d.ts +249 -0
- package/dist/schemas/prd-doc.js +42 -0
- package/dist/schemas/prd-manifest.d.ts +171 -0
- package/dist/schemas/prd-manifest.js +73 -0
- package/dist/schemas/primitives.d.ts +47 -0
- package/dist/schemas/primitives.js +41 -0
- package/dist/schemas/query-plan.d.ts +33 -0
- package/dist/schemas/query-plan.js +25 -0
- package/dist/schemas/ranked-source.d.ts +82 -0
- package/dist/schemas/ranked-source.js +29 -0
- package/dist/schemas/research-brief.d.ts +114 -0
- package/dist/schemas/research-brief.js +49 -0
- package/dist/schemas/research-doc.d.ts +104 -0
- package/dist/schemas/research-doc.js +37 -0
- package/dist/search/arxiv-client.d.ts +41 -0
- package/dist/search/arxiv-client.js +88 -0
- package/dist/search/hackernews-client.d.ts +33 -0
- package/dist/search/hackernews-client.js +44 -0
- package/dist/search/provider-result.d.ts +25 -0
- package/dist/search/provider-result.js +2 -0
- package/dist/search/tavily-client.d.ts +38 -0
- package/dist/search/tavily-client.js +53 -0
- package/dist/search/uspto-client.d.ts +50 -0
- package/dist/search/uspto-client.js +112 -0
- package/dist/utils/run-id.d.ts +2 -0
- package/dist/utils/run-id.js +22 -0
- package/package.json +53 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tavily-client — minimal `fetch`-based wrapper around Tavily's `/search`
|
|
3
|
+
* endpoint. Returns normalized results the dedupe_and_rank node can score.
|
|
4
|
+
*/
|
|
5
|
+
export interface TavilySearchOpts {
|
|
6
|
+
apiKey: string;
|
|
7
|
+
query: string;
|
|
8
|
+
/** 1..20. Tavily default is 5. */
|
|
9
|
+
maxResults?: number;
|
|
10
|
+
/** "basic" (cheap, fast) or "advanced" (better quality, slower). */
|
|
11
|
+
searchDepth?: 'basic' | 'advanced';
|
|
12
|
+
/** Whether to include domains-only filter etc. — pass through to Tavily. */
|
|
13
|
+
includeDomains?: string[];
|
|
14
|
+
excludeDomains?: string[];
|
|
15
|
+
/** Test injection point; defaults to globalThis.fetch. */
|
|
16
|
+
fetchImpl?: typeof fetch;
|
|
17
|
+
/** Abort timeout (ms). Default 30s. */
|
|
18
|
+
timeoutMs?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface TavilyResult {
|
|
21
|
+
title: string;
|
|
22
|
+
url: string;
|
|
23
|
+
/** Snippet/excerpt that matched the query. */
|
|
24
|
+
content: string;
|
|
25
|
+
/** Tavily relevance score 0..1. */
|
|
26
|
+
score: number;
|
|
27
|
+
/** Publication date if Tavily resolved one (ISO). */
|
|
28
|
+
publishedDate?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface TavilySearchResult {
|
|
31
|
+
query: string;
|
|
32
|
+
results: TavilyResult[];
|
|
33
|
+
/** Total response bytes (for audit). */
|
|
34
|
+
responseBytes: number;
|
|
35
|
+
/** HTTP status. */
|
|
36
|
+
httpStatus: number;
|
|
37
|
+
}
|
|
38
|
+
export declare function tavilySearch(opts: TavilySearchOpts): Promise<TavilySearchResult>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* tavily-client — minimal `fetch`-based wrapper around Tavily's `/search`
|
|
4
|
+
* endpoint. Returns normalized results the dedupe_and_rank node can score.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.tavilySearch = tavilySearch;
|
|
8
|
+
async function tavilySearch(opts) {
|
|
9
|
+
if (!opts.apiKey) {
|
|
10
|
+
throw new Error('TAVILY_API_KEY missing — set the env var or pass apiKey directly');
|
|
11
|
+
}
|
|
12
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
13
|
+
const controller = new AbortController();
|
|
14
|
+
const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? 30_000);
|
|
15
|
+
let response;
|
|
16
|
+
try {
|
|
17
|
+
response = await fetchImpl('https://api.tavily.com/search', {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
headers: { 'content-type': 'application/json' },
|
|
20
|
+
body: JSON.stringify({
|
|
21
|
+
api_key: opts.apiKey,
|
|
22
|
+
query: opts.query,
|
|
23
|
+
max_results: opts.maxResults ?? 5,
|
|
24
|
+
search_depth: opts.searchDepth ?? 'basic',
|
|
25
|
+
...(opts.includeDomains?.length ? { include_domains: opts.includeDomains } : {}),
|
|
26
|
+
...(opts.excludeDomains?.length ? { exclude_domains: opts.excludeDomains } : {}),
|
|
27
|
+
}),
|
|
28
|
+
signal: controller.signal,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
clearTimeout(timer);
|
|
33
|
+
}
|
|
34
|
+
const httpStatus = response.status;
|
|
35
|
+
const rawText = await response.text();
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
throw new Error(`Tavily returned ${httpStatus}: ${rawText.slice(0, 400)}`);
|
|
38
|
+
}
|
|
39
|
+
const data = JSON.parse(rawText);
|
|
40
|
+
const results = (data.results ?? []).map(r => ({
|
|
41
|
+
title: r.title ?? '',
|
|
42
|
+
url: r.url ?? '',
|
|
43
|
+
content: r.content ?? '',
|
|
44
|
+
score: typeof r.score === 'number' ? r.score : 0,
|
|
45
|
+
publishedDate: r.published_date,
|
|
46
|
+
})).filter(r => r.url.length > 0);
|
|
47
|
+
return {
|
|
48
|
+
query: opts.query,
|
|
49
|
+
results,
|
|
50
|
+
responseBytes: Buffer.byteLength(rawText, 'utf8'),
|
|
51
|
+
httpStatus,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* uspto-client — query USPTO's Open Data Portal for patents related to the
|
|
3
|
+
* research topic, then enrich each hit with its abstract by following the
|
|
4
|
+
* grant / pre-grant publication XML URI.
|
|
5
|
+
*
|
|
6
|
+
* Two-stage pipeline (mirrors the NCMS archeologist_agent.py reference at
|
|
7
|
+
* github.com/AliceNN-ucdenver/ncms/.../archeologist_agent.py#L810):
|
|
8
|
+
*
|
|
9
|
+
* 1. GET https://api.uspto.gov/api/v1/patent/applications/search
|
|
10
|
+
* ?q=<urlencoded-AND-joined-terms>&limit=<n>&offset=0
|
|
11
|
+
* Headers: X-API-Key: <USPTO_API_KEY>, Accept: application/json
|
|
12
|
+
* Returns { patentFileWrapperDataBag: [{ applicationMetaData, grantDocumentMetaData, pgpubDocumentMetaData, ... }] }
|
|
13
|
+
*
|
|
14
|
+
* 2. For each hit, follow `grantDocumentMetaData.fileLocationURI` (or
|
|
15
|
+
* `pgpubDocumentMetaData.fileLocationURI` as fallback) and parse the
|
|
16
|
+
* <abstract> element out of the XML. Stage 2 is best-effort —
|
|
17
|
+
* a missing/failed abstract just leaves abstract: '' on the result
|
|
18
|
+
* and the synthesis prompt falls back on the title alone.
|
|
19
|
+
*
|
|
20
|
+
* Migrated from the deprecated PatentsView v1 endpoint
|
|
21
|
+
* (https://search.patentsview.org/api/v1/patent/) — USPTO has consolidated
|
|
22
|
+
* onto the Open Data Portal at api.uspto.gov. The PatentsView endpoint may
|
|
23
|
+
* still respond intermittently but is no longer the recommended path.
|
|
24
|
+
*
|
|
25
|
+
* Get a key at https://data.uspto.gov/apis/getting-started (USPTO ODP).
|
|
26
|
+
*/
|
|
27
|
+
export interface UsptoResult {
|
|
28
|
+
patentNumber: string;
|
|
29
|
+
title: string;
|
|
30
|
+
/** Best abstract / first claim summary, fetched in stage 2. Empty when stage 2 fails. */
|
|
31
|
+
abstract: string;
|
|
32
|
+
url: string;
|
|
33
|
+
grantedAt: string;
|
|
34
|
+
inventors: string[];
|
|
35
|
+
}
|
|
36
|
+
export interface UsptoSearchOpts {
|
|
37
|
+
apiKey: string;
|
|
38
|
+
query: string;
|
|
39
|
+
maxResults?: number;
|
|
40
|
+
fetchImpl?: typeof fetch;
|
|
41
|
+
timeoutMs?: number;
|
|
42
|
+
endpoint?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface UsptoSearchResult {
|
|
45
|
+
query: string;
|
|
46
|
+
results: UsptoResult[];
|
|
47
|
+
responseBytes: number;
|
|
48
|
+
httpStatus: number;
|
|
49
|
+
}
|
|
50
|
+
export declare function usptoSearch(opts: UsptoSearchOpts): Promise<UsptoSearchResult>;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* uspto-client — query USPTO's Open Data Portal for patents related to the
|
|
4
|
+
* research topic, then enrich each hit with its abstract by following the
|
|
5
|
+
* grant / pre-grant publication XML URI.
|
|
6
|
+
*
|
|
7
|
+
* Two-stage pipeline (mirrors the NCMS archeologist_agent.py reference at
|
|
8
|
+
* github.com/AliceNN-ucdenver/ncms/.../archeologist_agent.py#L810):
|
|
9
|
+
*
|
|
10
|
+
* 1. GET https://api.uspto.gov/api/v1/patent/applications/search
|
|
11
|
+
* ?q=<urlencoded-AND-joined-terms>&limit=<n>&offset=0
|
|
12
|
+
* Headers: X-API-Key: <USPTO_API_KEY>, Accept: application/json
|
|
13
|
+
* Returns { patentFileWrapperDataBag: [{ applicationMetaData, grantDocumentMetaData, pgpubDocumentMetaData, ... }] }
|
|
14
|
+
*
|
|
15
|
+
* 2. For each hit, follow `grantDocumentMetaData.fileLocationURI` (or
|
|
16
|
+
* `pgpubDocumentMetaData.fileLocationURI` as fallback) and parse the
|
|
17
|
+
* <abstract> element out of the XML. Stage 2 is best-effort —
|
|
18
|
+
* a missing/failed abstract just leaves abstract: '' on the result
|
|
19
|
+
* and the synthesis prompt falls back on the title alone.
|
|
20
|
+
*
|
|
21
|
+
* Migrated from the deprecated PatentsView v1 endpoint
|
|
22
|
+
* (https://search.patentsview.org/api/v1/patent/) — USPTO has consolidated
|
|
23
|
+
* onto the Open Data Portal at api.uspto.gov. The PatentsView endpoint may
|
|
24
|
+
* still respond intermittently but is no longer the recommended path.
|
|
25
|
+
*
|
|
26
|
+
* Get a key at https://data.uspto.gov/apis/getting-started (USPTO ODP).
|
|
27
|
+
*/
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.usptoSearch = usptoSearch;
|
|
30
|
+
const DEFAULT_ENDPOINT = 'https://api.uspto.gov/api/v1/patent/applications/search';
|
|
31
|
+
async function usptoSearch(opts) {
|
|
32
|
+
if (!opts.apiKey) {
|
|
33
|
+
throw new Error('USPTO_API_KEY missing — request one at https://data.uspto.gov/apis/getting-started');
|
|
34
|
+
}
|
|
35
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
36
|
+
const endpoint = opts.endpoint ?? DEFAULT_ENDPOINT;
|
|
37
|
+
const size = Math.min(Math.max(1, opts.maxResults ?? 5), 20);
|
|
38
|
+
// The api.uspto.gov endpoint takes free-text queries with AND operators
|
|
39
|
+
// directly in the q= param (URL-encoded). No JSON DSL.
|
|
40
|
+
const url = `${endpoint}?q=${encodeURIComponent(opts.query)}&limit=${size}&offset=0`;
|
|
41
|
+
const controller = new AbortController();
|
|
42
|
+
const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? 30_000);
|
|
43
|
+
let response;
|
|
44
|
+
try {
|
|
45
|
+
response = await fetchImpl(url, {
|
|
46
|
+
method: 'GET',
|
|
47
|
+
headers: {
|
|
48
|
+
accept: 'application/json',
|
|
49
|
+
'X-API-Key': opts.apiKey,
|
|
50
|
+
},
|
|
51
|
+
signal: controller.signal,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
}
|
|
57
|
+
const httpStatus = response.status;
|
|
58
|
+
const rawText = await response.text();
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
throw new Error(`USPTO ODP returned ${httpStatus}: ${rawText.slice(0, 400)}`);
|
|
61
|
+
}
|
|
62
|
+
const data = JSON.parse(rawText);
|
|
63
|
+
const records = data.patentFileWrapperDataBag ?? [];
|
|
64
|
+
const stage1 = records.map(r => {
|
|
65
|
+
const meta = r.applicationMetaData ?? {};
|
|
66
|
+
const xmlUri = r.grantDocumentMetaData?.fileLocationURI
|
|
67
|
+
|| r.pgpubDocumentMetaData?.fileLocationURI
|
|
68
|
+
|| '';
|
|
69
|
+
const num = meta.patentNumber || meta.earliestPublicationNumber || '';
|
|
70
|
+
return {
|
|
71
|
+
patentNumber: num,
|
|
72
|
+
title: meta.inventionTitle ?? '',
|
|
73
|
+
abstract: '',
|
|
74
|
+
url: num ? `https://patents.google.com/patent/US${num}` : '',
|
|
75
|
+
grantedAt: meta.grantDate || meta.filingDate || meta.effectiveFilingDate || '',
|
|
76
|
+
inventors: meta.firstInventorName ? [meta.firstInventorName] : [],
|
|
77
|
+
_xmlUri: xmlUri,
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
// Stage 2: parallel best-effort abstract fetch. The full-text XML carries
|
|
81
|
+
// the <abstract> element; we regex it out rather than parsing the whole
|
|
82
|
+
// document (the XML is large and we only want the abstract).
|
|
83
|
+
await Promise.all(stage1.map(async (r) => {
|
|
84
|
+
if (!r._xmlUri) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const xmlRes = await fetchImpl(r._xmlUri, {
|
|
89
|
+
method: 'GET',
|
|
90
|
+
headers: { 'X-API-Key': opts.apiKey, accept: 'application/xml' },
|
|
91
|
+
});
|
|
92
|
+
if (!xmlRes.ok) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const xml = await xmlRes.text();
|
|
96
|
+
const m = xml.match(/<abstract[^>]*>([\s\S]*?)<\/abstract>/i);
|
|
97
|
+
if (m) {
|
|
98
|
+
const stripped = m[1].replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
|
|
99
|
+
r.abstract = stripped.slice(0, 1000);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch { /* ignore — best-effort */ }
|
|
103
|
+
}));
|
|
104
|
+
// Drop the internal _xmlUri marker before returning.
|
|
105
|
+
const results = stage1.map(({ _xmlUri: _ignored, ...rest }) => rest);
|
|
106
|
+
return {
|
|
107
|
+
query: opts.query,
|
|
108
|
+
results,
|
|
109
|
+
responseBytes: rawText.length,
|
|
110
|
+
httpStatus,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateRunId = generateRunId;
|
|
4
|
+
/**
|
|
5
|
+
* run-id — generate stable, sortable, low-collision run identifiers.
|
|
6
|
+
*
|
|
7
|
+
* Format: `<KIND>-YYYY-MM-DD-<8 hex chars>`
|
|
8
|
+
* KIND ∈ {RES, PRD}
|
|
9
|
+
*
|
|
10
|
+
* The date is the run's UTC start day; the 8-hex tail is the first 4 bytes
|
|
11
|
+
* of a crypto.randomBytes call. 32 bits gives birthday-collision probability
|
|
12
|
+
* around 1 in 65,536 for the same date — more than enough for human-scale
|
|
13
|
+
* mesh-wide audit.
|
|
14
|
+
*/
|
|
15
|
+
const node_crypto_1 = require("node:crypto");
|
|
16
|
+
function generateRunId(kind, now = new Date()) {
|
|
17
|
+
const yyyy = now.getUTCFullYear();
|
|
18
|
+
const mm = String(now.getUTCMonth() + 1).padStart(2, '0');
|
|
19
|
+
const dd = String(now.getUTCDate()).padStart(2, '0');
|
|
20
|
+
const tail = (0, node_crypto_1.randomBytes)(4).toString('hex');
|
|
21
|
+
return `${kind}-${yyyy}-${mm}-${dd}-${tail}`;
|
|
22
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@maintainabilityai/research-runner",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Research + PRD agent runner — orchestrates the Archeologist and PRD pipelines for the MaintainabilityAI governance mesh",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "MaintainabilityAI",
|
|
7
|
+
"homepage": "https://maintainability.ai",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/AliceNN-ucdenver/MaintainabilityAI",
|
|
11
|
+
"directory": "packages/research-runner"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/AliceNN-ucdenver/MaintainabilityAI/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"research",
|
|
18
|
+
"prd",
|
|
19
|
+
"governance",
|
|
20
|
+
"calm",
|
|
21
|
+
"ai-agents",
|
|
22
|
+
"tavily",
|
|
23
|
+
"anthropic"
|
|
24
|
+
],
|
|
25
|
+
"bin": {
|
|
26
|
+
"research-runner": "./bin/research-runner.js"
|
|
27
|
+
},
|
|
28
|
+
"main": "./dist/cli.js",
|
|
29
|
+
"files": [
|
|
30
|
+
"bin/",
|
|
31
|
+
"dist/",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
34
|
+
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=20"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsc -p tsconfig.json",
|
|
40
|
+
"test": "node --test --import tsx 'src/**/*.test.ts'",
|
|
41
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"js-yaml": "^4.1.0",
|
|
45
|
+
"zod": "^3.25.76"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/js-yaml": "^4.0.9",
|
|
49
|
+
"@types/node": "^20.11.0",
|
|
50
|
+
"tsx": "^4.19.0",
|
|
51
|
+
"typescript": "^5.5.0"
|
|
52
|
+
}
|
|
53
|
+
}
|