opmsec 0.1.51 → 0.1.53
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/package.json +9 -8
- package/packages/cli/src/commands/check.tsx +48 -5
- package/packages/cli/src/commands/fix.tsx +76 -25
- package/packages/cli/src/index.tsx +16 -0
- package/packages/scanner/src/services/openrouter.ts +8 -2
- package/packages/web/.next/BUILD_ID +1 -1
- package/packages/web/.next/build-manifest.json +2 -2
- package/packages/web/.next/prerender-manifest.json +7 -7
- package/packages/web/.next/server/app/_not-found.html +1 -1
- package/packages/web/.next/server/app/_not-found.rsc +1 -1
- package/packages/web/.next/server/app/index.html +2 -2
- package/packages/web/.next/server/app/index.rsc +1 -1
- package/packages/web/.next/server/pages/404.html +1 -1
- package/packages/web/.next/server/pages/500.html +1 -1
- package/packages/web/.next/server/pages-manifest.json +1 -1
- package/packages/web/.next/trace +2 -2
- /package/packages/web/.next/static/{jwpVFtQGO17b1LATsewLl → dQsL29tmXanBGrmJ9Agh2}/_buildManifest.js +0 -0
- /package/packages/web/.next/static/{jwpVFtQGO17b1LATsewLl → dQsL29tmXanBGrmJ9Agh2}/_ssgManifest.js +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opmsec",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.53",
|
|
4
4
|
"private": false,
|
|
5
5
|
"bin": {
|
|
6
6
|
"opm": "packages/cli/src/index.tsx"
|
|
@@ -23,18 +23,19 @@
|
|
|
23
23
|
"chalk": "^5.4.0",
|
|
24
24
|
"ethers": "^6.13.0",
|
|
25
25
|
"ink": "^5.2.1",
|
|
26
|
-
"react": "
|
|
27
|
-
"react-devtools-core": "
|
|
28
|
-
"terminal-image": "
|
|
29
|
-
"viem": "
|
|
26
|
+
"react": "18.3.1",
|
|
27
|
+
"react-devtools-core": "6.1.5",
|
|
28
|
+
"terminal-image": "3.1.1",
|
|
29
|
+
"viem": "2.21.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"bun-types": "latest"
|
|
32
|
+
"bun-types": "latest",
|
|
33
|
+
"react-server-dom-parcel": "19.1.5"
|
|
33
34
|
},
|
|
34
35
|
"opm": {
|
|
35
|
-
"signature": "
|
|
36
|
+
"signature": "0x9483cfcd3b920b1626e8055ca922ba69b04497d9d9234e4b9111439ad36d85b9028965909c76ee9af8bec3c8740575a38f2670bb1ea424210971a29368250fc21c",
|
|
36
37
|
"author": "0x2a3942EbDd8c5ea3E66D3fC4301F56d0F15d4bE2",
|
|
37
38
|
"ensName": "djpaiethg.eth",
|
|
38
|
-
"checksum": "
|
|
39
|
+
"checksum": "0xba72bf9125deddae2758f962c6c62567d6d23b819a1f7d716ba679b19287b4ef"
|
|
39
40
|
}
|
|
40
41
|
}
|
|
@@ -10,6 +10,7 @@ import { resolveAndScanDepGraph } from '../services/dep-graph';
|
|
|
10
10
|
import { queryOSV, getOSVSeverity, getFixedVersion } from '../services/osv';
|
|
11
11
|
import { getPackageInfo } from '../services/contract';
|
|
12
12
|
import { detectTyposquatBatch } from '../services/typosquat';
|
|
13
|
+
import { isENSVersion, resolveVersion } from '../services/version';
|
|
13
14
|
import { callLLMRaw, getAgentConfigs, uploadCheckReportToFileverse } from '@opm/scanner';
|
|
14
15
|
import * as fs from 'fs';
|
|
15
16
|
import * as path from 'path';
|
|
@@ -20,6 +21,8 @@ export function CheckCommand() {
|
|
|
20
21
|
const [phase, setPhase] = useState<Phase>('graph');
|
|
21
22
|
const [graphStatus, setGraphStatus] = useState('Resolving...');
|
|
22
23
|
const [graph, setGraph] = useState<DepGraphResult | null>(null);
|
|
24
|
+
const [scanDetail, setScanDetail] = useState('');
|
|
25
|
+
const [agentLogs, setAgentLogs] = useState<string[]>([]);
|
|
23
26
|
const [report, setReport] = useState<CheckReport | null>(null);
|
|
24
27
|
const [reportLink, setReportLink] = useState<string | null>(null);
|
|
25
28
|
const [uploadError, setUploadError] = useState<string | null>(null);
|
|
@@ -47,10 +50,32 @@ export function CheckCommand() {
|
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
setPhase('scanning');
|
|
50
|
-
const
|
|
51
|
-
...deps.map(([n, v]) => ({ n, v:
|
|
52
|
-
...devDeps.map(([n, v]) => ({ n, v:
|
|
53
|
+
const rawEntries = [
|
|
54
|
+
...deps.map(([n, v]) => ({ n, v: String(v) })),
|
|
55
|
+
...devDeps.map(([n, v]) => ({ n, v: String(v) })),
|
|
53
56
|
];
|
|
57
|
+
|
|
58
|
+
const ensEntries = rawEntries.filter(e => isENSVersion(e.v));
|
|
59
|
+
if (ensEntries.length > 0) {
|
|
60
|
+
setScanDetail(`Resolving ${ensEntries.length} ENS version(s)...`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const allEntries: { n: string; v: string }[] = [];
|
|
64
|
+
for (const entry of rawEntries) {
|
|
65
|
+
if (isENSVersion(entry.v)) {
|
|
66
|
+
try {
|
|
67
|
+
setScanDetail(`ENS: ${entry.v} → ${entry.n}...`);
|
|
68
|
+
const resolved = await resolveVersion(entry.n, entry.v);
|
|
69
|
+
allEntries.push({ n: entry.n, v: resolved.version });
|
|
70
|
+
} catch {
|
|
71
|
+
allEntries.push({ n: entry.n, v: clean(entry.v) });
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
allEntries.push({ n: entry.n, v: clean(entry.v) });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
setScanDetail('Batch querying typosquats + CVEs + on-chain...');
|
|
54
79
|
const allNames = allEntries.map((e) => e.n);
|
|
55
80
|
|
|
56
81
|
const [typosquatResults, ...parallelResults] = await Promise.all([
|
|
@@ -98,18 +123,21 @@ export function CheckCommand() {
|
|
|
98
123
|
let agentResults: CheckAgentResult[] = [];
|
|
99
124
|
try {
|
|
100
125
|
const configs = getAgentConfigs();
|
|
126
|
+
setAgentLogs([`Dispatching ${configs.length} agents...`]);
|
|
101
127
|
const depE: DepEntry[] = deps.map(([n, v]) => ({ name: n, version: clean(v) }));
|
|
102
128
|
const devE: DepEntry[] = devDeps.map(([n, v]) => ({ name: n, version: clean(v) }));
|
|
103
129
|
const prompt = buildCheckPrompt(depE, devE);
|
|
104
130
|
|
|
105
131
|
const runs = await Promise.allSettled(
|
|
106
132
|
configs.map(async (cfg) => {
|
|
133
|
+
setAgentLogs(prev => [...prev, `[${cfg.agentId}] Calling ${cfg.model}...`]);
|
|
107
134
|
const { intelligence, coding } = await getModelRankingFor(cfg.model);
|
|
108
135
|
const res = await callLLMRaw<{
|
|
109
136
|
findings: CheckAgentResult['findings'];
|
|
110
137
|
overall_assessment: string;
|
|
111
138
|
risk_score: number;
|
|
112
139
|
}>(cfg.model, CHECK_SYSTEM_PROMPT, prompt);
|
|
140
|
+
setAgentLogs(prev => [...prev, `[${cfg.agentId}] ✓ ${(res.findings || []).length} findings (score: ${res.risk_score || 0})`]);
|
|
113
141
|
return {
|
|
114
142
|
agentId: cfg.agentId, model: cfg.model,
|
|
115
143
|
intelligence, coding,
|
|
@@ -122,6 +150,13 @@ export function CheckCommand() {
|
|
|
122
150
|
agentResults = runs.filter((r): r is PromiseFulfilledResult<CheckAgentResult> =>
|
|
123
151
|
r.status === 'fulfilled',
|
|
124
152
|
).map((r) => r.value);
|
|
153
|
+
|
|
154
|
+
for (const r of runs) {
|
|
155
|
+
if (r.status === 'rejected') {
|
|
156
|
+
const msg = String(r.reason?.message || r.reason).slice(0, 80);
|
|
157
|
+
setAgentLogs(prev => [...prev, `Agent failed: ${msg}`]);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
125
160
|
} catch { /* no LLM keys — skip */ }
|
|
126
161
|
|
|
127
162
|
const checkReport: CheckReport = {
|
|
@@ -174,13 +209,21 @@ export function CheckCommand() {
|
|
|
174
209
|
{phase !== 'graph' && (
|
|
175
210
|
<StatusLine label={`Scanning ${report?.totalDeps || '...'} direct dependencies`}
|
|
176
211
|
status={phase === 'scanning' ? 'running' : 'done'}
|
|
177
|
-
detail={phase === 'scanning' ?
|
|
212
|
+
detail={phase === 'scanning' ? scanDetail : `${report?.totalDeps} checked`} />
|
|
178
213
|
)}
|
|
179
214
|
|
|
180
215
|
{phase !== 'graph' && phase !== 'scanning' && (
|
|
181
216
|
<StatusLine label="AI agents analyzing dependency tree"
|
|
182
217
|
status={phase === 'agents' ? 'running' : 'done'}
|
|
183
|
-
detail={report?.agents.length ? `${report.agents.length} agents` : undefined} />
|
|
218
|
+
detail={phase === 'agents' && agentLogs.length > 0 ? agentLogs[agentLogs.length - 1] : report?.agents.length ? `${report.agents.length} agents` : undefined} />
|
|
219
|
+
)}
|
|
220
|
+
|
|
221
|
+
{phase === 'agents' && agentLogs.length > 0 && (
|
|
222
|
+
<Box flexDirection="column" marginLeft={4}>
|
|
223
|
+
{agentLogs.slice(-5).map((log, i) => (
|
|
224
|
+
<Text key={i} color="gray">{log}</Text>
|
|
225
|
+
))}
|
|
226
|
+
</Box>
|
|
184
227
|
)}
|
|
185
228
|
|
|
186
229
|
{process.env.FILEVERSE_API_KEY && (phase === 'upload' || phase === 'done') && (
|
|
@@ -7,6 +7,7 @@ import { StatusLine } from '../components/StatusLine';
|
|
|
7
7
|
import { Hyperlink } from '../components/Hyperlink';
|
|
8
8
|
import { queryOSV, getOSVSeverity, getFixedVersion } from '../services/osv';
|
|
9
9
|
import { detectTyposquatBatch } from '../services/typosquat';
|
|
10
|
+
import { isENSVersion, resolveVersion } from '../services/version';
|
|
10
11
|
import { callLLMRaw, getAgentConfigs, uploadCheckReportToFileverse } from '@opm/scanner';
|
|
11
12
|
import * as fs from 'fs';
|
|
12
13
|
import * as path from 'path';
|
|
@@ -20,12 +21,16 @@ interface FixAction {
|
|
|
20
21
|
reason: string;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
type Phase = 'scan' | 'agents' | 'apply' | 'upload' | 'done';
|
|
24
|
+
type Phase = 'ens' | 'scan' | 'agents' | 'apply' | 'upload' | 'done';
|
|
24
25
|
|
|
25
26
|
export function FixCommand() {
|
|
26
|
-
const [phase, setPhase] = useState<Phase>('
|
|
27
|
+
const [phase, setPhase] = useState<Phase>('ens');
|
|
27
28
|
const [fixes, setFixes] = useState<FixAction[]>([]);
|
|
28
29
|
const [total, setTotal] = useState(0);
|
|
30
|
+
const [ensCount, setEnsCount] = useState(0);
|
|
31
|
+
const [ensResolved, setEnsResolved] = useState(0);
|
|
32
|
+
const [scanDetail, setScanDetail] = useState('');
|
|
33
|
+
const [agentLogs, setAgentLogs] = useState<string[]>([]);
|
|
29
34
|
const [applied, setApplied] = useState(false);
|
|
30
35
|
const [reportLink, setReportLink] = useState<string | null>(null);
|
|
31
36
|
const [uploadError, setUploadError] = useState<string | null>(null);
|
|
@@ -44,18 +49,41 @@ export function FixCommand() {
|
|
|
44
49
|
const projectName = pkgJson.name || path.basename(process.cwd());
|
|
45
50
|
const deps = Object.entries(pkgJson.dependencies || {}) as [string, string][];
|
|
46
51
|
const devDeps = Object.entries(pkgJson.devDependencies || {}) as [string, string][];
|
|
47
|
-
const
|
|
48
|
-
...deps.map(([n, v]) => ({ n, v:
|
|
49
|
-
...devDeps.map(([n, v]) => ({ n, v:
|
|
52
|
+
const rawEntries = [
|
|
53
|
+
...deps.map(([n, v]) => ({ n, v: String(v) })),
|
|
54
|
+
...devDeps.map(([n, v]) => ({ n, v: String(v) })),
|
|
50
55
|
];
|
|
51
|
-
setTotal(
|
|
56
|
+
setTotal(rawEntries.length);
|
|
57
|
+
|
|
58
|
+
const ensEntries = rawEntries.filter(e => isENSVersion(e.v));
|
|
59
|
+
setEnsCount(ensEntries.length);
|
|
60
|
+
|
|
61
|
+
const allEntries: { n: string; v: string; ensResolved?: string }[] = [];
|
|
62
|
+
for (const entry of rawEntries) {
|
|
63
|
+
if (isENSVersion(entry.v)) {
|
|
64
|
+
try {
|
|
65
|
+
setScanDetail(`Resolving ${entry.v} for ${entry.n}...`);
|
|
66
|
+
const resolved = await resolveVersion(entry.n, entry.v);
|
|
67
|
+
allEntries.push({ n: entry.n, v: resolved.version, ensResolved: entry.v });
|
|
68
|
+
setEnsResolved(c => c + 1);
|
|
69
|
+
} catch {
|
|
70
|
+
allEntries.push({ n: entry.n, v: clean(entry.v) });
|
|
71
|
+
setEnsResolved(c => c + 1);
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
allEntries.push({ n: entry.n, v: clean(entry.v) });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
52
77
|
|
|
78
|
+
setPhase('scan');
|
|
79
|
+
setScanDetail('Batch querying typosquats + CVEs...');
|
|
53
80
|
const allNames = allEntries.map((e) => e.n);
|
|
54
81
|
const [typosquatResults, ...parallelResults] = await Promise.all([
|
|
55
82
|
detectTyposquatBatch(allNames),
|
|
56
83
|
...allEntries.map(({ n, v }) => queryOSV(n, v).catch(() => [])),
|
|
57
84
|
]);
|
|
58
85
|
|
|
86
|
+
setScanDetail('Analyzing results...');
|
|
59
87
|
const actions: FixAction[] = [];
|
|
60
88
|
const depResults: CheckDepResult[] = [];
|
|
61
89
|
|
|
@@ -107,18 +135,21 @@ export function FixCommand() {
|
|
|
107
135
|
let agentResults: CheckAgentResult[] = [];
|
|
108
136
|
try {
|
|
109
137
|
const configs = getAgentConfigs();
|
|
138
|
+
setAgentLogs([`Dispatching ${configs.length} agents...`]);
|
|
110
139
|
const depE: DepEntry[] = deps.map(([n, v]) => ({ name: n, version: clean(v) }));
|
|
111
140
|
const devE: DepEntry[] = devDeps.map(([n, v]) => ({ name: n, version: clean(v) }));
|
|
112
141
|
const prompt = buildCheckPrompt(depE, devE);
|
|
113
142
|
|
|
114
143
|
const runs = await Promise.allSettled(
|
|
115
144
|
configs.map(async (cfg) => {
|
|
145
|
+
setAgentLogs(prev => [...prev, `[${cfg.agentId}] Calling ${cfg.model}...`]);
|
|
116
146
|
const { intelligence, coding } = await getModelRankingFor(cfg.model);
|
|
117
147
|
const res = await callLLMRaw<{
|
|
118
148
|
findings: CheckAgentResult['findings'];
|
|
119
149
|
overall_assessment: string;
|
|
120
150
|
risk_score: number;
|
|
121
151
|
}>(cfg.model, CHECK_SYSTEM_PROMPT, prompt);
|
|
152
|
+
setAgentLogs(prev => [...prev, `[${cfg.agentId}] Done — ${(res.findings || []).length} findings`]);
|
|
122
153
|
return {
|
|
123
154
|
agentId: cfg.agentId, model: cfg.model,
|
|
124
155
|
intelligence, coding,
|
|
@@ -132,6 +163,13 @@ export function FixCommand() {
|
|
|
132
163
|
.filter((r): r is PromiseFulfilledResult<CheckAgentResult> => r.status === 'fulfilled')
|
|
133
164
|
.map((r) => r.value);
|
|
134
165
|
|
|
166
|
+
for (const r of runs) {
|
|
167
|
+
if (r.status === 'rejected') {
|
|
168
|
+
const msg = String(r.reason?.message || r.reason).slice(0, 80);
|
|
169
|
+
setAgentLogs(prev => [...prev, `Agent failed: ${msg}`]);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
135
173
|
const flagCounts = new Map<string, { count: number; replacement: string | null; version: string | null; reason: string }>();
|
|
136
174
|
for (const agent of agentResults) {
|
|
137
175
|
for (const f of agent.findings) {
|
|
@@ -155,7 +193,7 @@ export function FixCommand() {
|
|
|
155
193
|
actions.push({
|
|
156
194
|
name: pkg, version: entry.v, kind: 'ai',
|
|
157
195
|
newName: validName, newVersion: validVersion,
|
|
158
|
-
reason: `${count}
|
|
196
|
+
reason: `${count}/${configs.length} agents flagged: ${reason.slice(0, 80)}`,
|
|
159
197
|
});
|
|
160
198
|
}
|
|
161
199
|
} catch { /* no LLM keys — skip */ }
|
|
@@ -182,17 +220,15 @@ export function FixCommand() {
|
|
|
182
220
|
setApplied(true);
|
|
183
221
|
}
|
|
184
222
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
setUploadError('FILEVERSE_API_KEY not set');
|
|
195
|
-
} else {
|
|
223
|
+
if (process.env.FILEVERSE_API_KEY) {
|
|
224
|
+
setPhase('upload');
|
|
225
|
+
const checkReport: CheckReport = {
|
|
226
|
+
project: projectName,
|
|
227
|
+
timestamp: new Date().toISOString(),
|
|
228
|
+
totalDeps: allEntries.length,
|
|
229
|
+
deps: depResults,
|
|
230
|
+
agents: agentResults,
|
|
231
|
+
};
|
|
196
232
|
try {
|
|
197
233
|
const uploadResult = await uploadCheckReportToFileverse(checkReport);
|
|
198
234
|
setReportLink(uploadResult.link);
|
|
@@ -209,21 +245,36 @@ export function FixCommand() {
|
|
|
209
245
|
setPhase('done');
|
|
210
246
|
}
|
|
211
247
|
|
|
248
|
+
const hasEns = ensCount > 0;
|
|
249
|
+
|
|
212
250
|
return (
|
|
213
251
|
<Box flexDirection="column">
|
|
214
252
|
<Header subtitle="fix" />
|
|
215
253
|
<Text> </Text>
|
|
216
254
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
255
|
+
{hasEns && (
|
|
256
|
+
<StatusLine label={`Resolving ${ensCount} ENS version${ensCount > 1 ? 's' : ''}`}
|
|
257
|
+
status={phase === 'ens' ? 'running' : 'done'}
|
|
258
|
+
detail={phase === 'ens' ? `${ensResolved}/${ensCount} resolved` : `${ensCount} resolved`} />
|
|
259
|
+
)}
|
|
260
|
+
|
|
261
|
+
<StatusLine label={`Scanning ${total} dependencies`}
|
|
262
|
+
status={phase === 'ens' ? 'pending' : phase === 'scan' ? 'running' : 'done'}
|
|
263
|
+
detail={phase === 'scan' ? scanDetail : phase !== 'ens' ? `${total} scanned` : undefined} />
|
|
220
264
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
265
|
+
<StatusLine label="AI agents analyzing dependency tree"
|
|
266
|
+
status={phase === 'ens' || phase === 'scan' ? 'pending' : phase === 'agents' ? 'running' : 'done'}
|
|
267
|
+
detail={phase === 'agents' ? `${agentLogs.length > 0 ? agentLogs[agentLogs.length - 1] : 'starting...'}` : undefined} />
|
|
268
|
+
|
|
269
|
+
{phase === 'agents' && agentLogs.length > 0 && (
|
|
270
|
+
<Box flexDirection="column" marginLeft={4}>
|
|
271
|
+
{agentLogs.slice(-4).map((log, i) => (
|
|
272
|
+
<Text key={i} color="gray">{log}</Text>
|
|
273
|
+
))}
|
|
274
|
+
</Box>
|
|
224
275
|
)}
|
|
225
276
|
|
|
226
|
-
{(phase === 'upload' || phase === 'done') && (
|
|
277
|
+
{process.env.FILEVERSE_API_KEY && (phase === 'upload' || phase === 'done') && (
|
|
227
278
|
<StatusLine label="Upload report to Fileverse"
|
|
228
279
|
status={phase === 'upload' ? 'running' : reportLink ? 'done' : 'skip'}
|
|
229
280
|
detail={uploadError || undefined} />
|
|
@@ -16,6 +16,19 @@ const args = process.argv.slice(2);
|
|
|
16
16
|
const command = args[0];
|
|
17
17
|
const rest = args.slice(1);
|
|
18
18
|
|
|
19
|
+
if (command === '--version' || command === '-v' || command === '-V' || command === 'version') {
|
|
20
|
+
try {
|
|
21
|
+
const fs = await import('fs');
|
|
22
|
+
const path = await import('path');
|
|
23
|
+
const pkgPath = path.resolve(__dirname, '../../../package.json');
|
|
24
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
25
|
+
console.log(`opm v${pkg.version}`);
|
|
26
|
+
} catch {
|
|
27
|
+
console.log('opm (version unknown)');
|
|
28
|
+
}
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
31
|
+
|
|
19
32
|
function parsePackageArg(pkg?: string) {
|
|
20
33
|
if (!pkg) return {};
|
|
21
34
|
const atIdx = pkg.lastIndexOf('@');
|
|
@@ -138,6 +151,9 @@ function Help() {
|
|
|
138
151
|
<Text color="gray"> view name.eth → author profile + OPM ENS records</Text>
|
|
139
152
|
<Text color="gray"> pkg@name.eth → ENS-resolved safest version by author</Text>
|
|
140
153
|
<Text> </Text>
|
|
154
|
+
<Text color="cyan" bold>Other:</Text>
|
|
155
|
+
<Text> opm --version / -v Show OPM version</Text>
|
|
156
|
+
<Text> </Text>
|
|
141
157
|
<Text color="cyan" bold>Environment (install/audit/info/view need no config):</Text>
|
|
142
158
|
<Text> OPM_SIGNING_KEY Author signing key (for push only)</Text>
|
|
143
159
|
<Text> NPM_TOKEN npm automation token (for push only)</Text>
|
|
@@ -2,6 +2,8 @@ import { OPENROUTER_API_URL, OPENAI_API_URL } from '@opm/core';
|
|
|
2
2
|
import type { AgentScanResult } from '@opm/core';
|
|
3
3
|
import { validateScanResult, normalizeScanResult, safeJsonParse } from '@opm/core';
|
|
4
4
|
|
|
5
|
+
const REASONING_MODELS = /^(o[1-9]|o\d+-)/i;
|
|
6
|
+
|
|
5
7
|
function getProvider(): { apiUrl: string; apiKey: string; kind: 'openai' | 'openrouter' } {
|
|
6
8
|
const forcedProvider = process.env.LLM_PROVIDER;
|
|
7
9
|
|
|
@@ -57,6 +59,8 @@ export async function callLLM(
|
|
|
57
59
|
? { max_completion_tokens: 4096 }
|
|
58
60
|
: { max_tokens: 4096 };
|
|
59
61
|
|
|
62
|
+
const isReasoning = REASONING_MODELS.test(model);
|
|
63
|
+
|
|
60
64
|
const res = await fetch(apiUrl, {
|
|
61
65
|
method: 'POST',
|
|
62
66
|
headers,
|
|
@@ -67,7 +71,7 @@ export async function callLLM(
|
|
|
67
71
|
{ role: 'user', content: userPrompt },
|
|
68
72
|
],
|
|
69
73
|
response_format: { type: 'json_object' },
|
|
70
|
-
temperature: 0.1,
|
|
74
|
+
...(isReasoning ? {} : { temperature: 0.1 }),
|
|
71
75
|
...tokenLimit,
|
|
72
76
|
}),
|
|
73
77
|
});
|
|
@@ -113,6 +117,8 @@ export async function callLLMRaw<T = unknown>(
|
|
|
113
117
|
? { max_completion_tokens: 4096 }
|
|
114
118
|
: { max_tokens: 4096 };
|
|
115
119
|
|
|
120
|
+
const isReasoning = REASONING_MODELS.test(model);
|
|
121
|
+
|
|
116
122
|
const res = await fetch(apiUrl, {
|
|
117
123
|
method: 'POST',
|
|
118
124
|
headers,
|
|
@@ -123,7 +129,7 @@ export async function callLLMRaw<T = unknown>(
|
|
|
123
129
|
{ role: 'user', content: userPrompt },
|
|
124
130
|
],
|
|
125
131
|
response_format: { type: 'json_object' },
|
|
126
|
-
temperature: 0.1,
|
|
132
|
+
...(isReasoning ? {} : { temperature: 0.1 }),
|
|
127
133
|
...tokenLimit,
|
|
128
134
|
}),
|
|
129
135
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
dQsL29tmXanBGrmJ9Agh2
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
"devFiles": [],
|
|
6
6
|
"ampDevFiles": [],
|
|
7
7
|
"lowPriorityFiles": [
|
|
8
|
-
"static/
|
|
9
|
-
"static/
|
|
8
|
+
"static/dQsL29tmXanBGrmJ9Agh2/_buildManifest.js",
|
|
9
|
+
"static/dQsL29tmXanBGrmJ9Agh2/_ssgManifest.js"
|
|
10
10
|
],
|
|
11
11
|
"rootMainFiles": [
|
|
12
12
|
"static/chunks/webpack-0dcd67569eb46132.js",
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 4,
|
|
3
3
|
"routes": {
|
|
4
|
-
"/
|
|
5
|
-
"initialStatus": 404,
|
|
4
|
+
"/": {
|
|
6
5
|
"experimentalBypassFor": [
|
|
7
6
|
{
|
|
8
7
|
"type": "header",
|
|
@@ -15,8 +14,8 @@
|
|
|
15
14
|
}
|
|
16
15
|
],
|
|
17
16
|
"initialRevalidateSeconds": false,
|
|
18
|
-
"srcRoute": "/
|
|
19
|
-
"dataRoute": "/
|
|
17
|
+
"srcRoute": "/",
|
|
18
|
+
"dataRoute": "/index.rsc",
|
|
20
19
|
"allowHeader": [
|
|
21
20
|
"host",
|
|
22
21
|
"x-matched-path",
|
|
@@ -26,7 +25,8 @@
|
|
|
26
25
|
"x-next-revalidate-tag-token"
|
|
27
26
|
]
|
|
28
27
|
},
|
|
29
|
-
"/": {
|
|
28
|
+
"/_not-found": {
|
|
29
|
+
"initialStatus": 404,
|
|
30
30
|
"experimentalBypassFor": [
|
|
31
31
|
{
|
|
32
32
|
"type": "header",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
}
|
|
40
40
|
],
|
|
41
41
|
"initialRevalidateSeconds": false,
|
|
42
|
-
"srcRoute": "/",
|
|
43
|
-
"dataRoute": "/
|
|
42
|
+
"srcRoute": "/_not-found",
|
|
43
|
+
"dataRoute": "/_not-found.rsc",
|
|
44
44
|
"allowHeader": [
|
|
45
45
|
"host",
|
|
46
46
|
"x-matched-path",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
1
|
+
<!DOCTYPE html><!--dQsL29tmXanBGrmJ9Agh2--><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/4cf2300e9c8272f7-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/93f479601ee12b01-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/102562cf2d0ae9b0.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-0dcd67569eb46132.js"/><script src="/_next/static/chunks/4bd1b696-382748cc942d8a14.js" async=""></script><script src="/_next/static/chunks/255-0dc49b7a6e8e5c05.js" async=""></script><script src="/_next/static/chunks/main-app-dd261207182e5a23.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><title>OPM | On-chain Package Manager</title><meta name="description" content="Cryptographically signed, AI-audited, on-chain verified package security for the npm ecosystem."/><meta property="og:title" content="OPM | On-chain Package Manager"/><meta property="og:description" content="Cryptographically signed, AI-audited, on-chain verified package security."/><meta property="og:type" content="website"/><meta name="twitter:card" content="summary"/><meta name="twitter:title" content="OPM | On-chain Package Manager"/><meta name="twitter:description" content="Cryptographically signed, AI-audited, on-chain verified package security."/><link rel="icon" href="/favicon.svg"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body class="font-sans antialiased"><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-0dcd67569eb46132.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[9766,[],\"\"]\n3:I[8924,[],\"\"]\n4:I[4431,[],\"OutletBoundary\"]\n6:I[5278,[],\"AsyncMetadataOutlet\"]\n8:I[4431,[],\"ViewportBoundary\"]\na:I[4431,[],\"MetadataBoundary\"]\nb:\"$Sreact.suspense\"\nd:I[7150,[],\"\"]\n:HL[\"/_next/static/media/4cf2300e9c8272f7-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/93f479601ee12b01-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/css/102562cf2d0ae9b0.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"dQsL29tmXanBGrmJ9Agh2\",\"p\":\"\",\"c\":[\"\",\"_not-found\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/102562cf2d0ae9b0.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[\"$\",\"body\",null,{\"className\":\"font-sans antialiased\",\"children\":[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L4\",null,{\"children\":[\"$L5\",[\"$\",\"$L6\",null,{\"promise\":\"$@7\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$La\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$b\",null,{\"fallback\":null,\"children\":\"$Lc\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$d\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"9:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n5:null\n"])</script><script>self.__next_f.push([1,"e:I[622,[],\"IconMark\"]\n"])</script><script>self.__next_f.push([1,"7:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"OPM | On-chain Package Manager\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Cryptographically signed, AI-audited, on-chain verified package security for the npm ecosystem.\"}],[\"$\",\"meta\",\"2\",{\"property\":\"og:title\",\"content\":\"OPM | On-chain Package Manager\"}],[\"$\",\"meta\",\"3\",{\"property\":\"og:description\",\"content\":\"Cryptographically signed, AI-audited, on-chain verified package security.\"}],[\"$\",\"meta\",\"4\",{\"property\":\"og:type\",\"content\":\"website\"}],[\"$\",\"meta\",\"5\",{\"name\":\"twitter:card\",\"content\":\"summary\"}],[\"$\",\"meta\",\"6\",{\"name\":\"twitter:title\",\"content\":\"OPM | On-chain Package Manager\"}],[\"$\",\"meta\",\"7\",{\"name\":\"twitter:description\",\"content\":\"Cryptographically signed, AI-audited, on-chain verified package security.\"}],[\"$\",\"link\",\"8\",{\"rel\":\"icon\",\"href\":\"/favicon.svg\"}],[\"$\",\"$Le\",\"9\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"c:\"$7:metadata\"\n"])</script></body></html>
|
|
@@ -10,7 +10,7 @@ d:I[7150,[],""]
|
|
|
10
10
|
:HL["/_next/static/media/4cf2300e9c8272f7-s.p.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
|
|
11
11
|
:HL["/_next/static/media/93f479601ee12b01-s.p.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
|
|
12
12
|
:HL["/_next/static/css/102562cf2d0ae9b0.css","style"]
|
|
13
|
-
0:{"P":null,"b":"
|
|
13
|
+
0:{"P":null,"b":"dQsL29tmXanBGrmJ9Agh2","p":"","c":["","_not-found"],"i":false,"f":[[["",{"children":["/_not-found",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/102562cf2d0ae9b0.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"className":"font-sans antialiased","children":["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]}]}]]}],{"children":["/_not-found",["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],null,["$","$L4",null,{"children":["$L5",["$","$L6",null,{"promise":"$@7"}]]}]]}],{},null,false]},null,false]},null,false],["$","$1","h",{"children":[["$","meta",null,{"name":"robots","content":"noindex"}],[["$","$L8",null,{"children":"$L9"}],["$","meta",null,{"name":"next-size-adjust","content":""}]],["$","$La",null,{"children":["$","div",null,{"hidden":true,"children":["$","$b",null,{"fallback":null,"children":"$Lc"}]}]}]]}],false]],"m":"$undefined","G":["$d",[]],"s":false,"S":true}
|
|
14
14
|
9:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
|
15
15
|
5:null
|
|
16
16
|
e:I[622,[],"IconMark"]
|