upstream-radar 0.43.4 → 0.44.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.
- package/README-zh-CN.md +92 -77
- package/README.md +125 -94
- package/dist/src/cli.js +177 -5
- package/dist/src/cli.js.map +1 -1
- package/dist/src/dsh-compatibility-ledger.d.ts +2 -0
- package/dist/src/dsh-compatibility-ledger.d.ts.map +1 -1
- package/dist/src/dsh-compatibility-ledger.js +5 -0
- package/dist/src/dsh-compatibility-ledger.js.map +1 -1
- package/dist/src/dsh-directory-feed.d.ts +7 -3
- package/dist/src/dsh-directory-feed.d.ts.map +1 -1
- package/dist/src/dsh-directory-feed.js +59 -25
- package/dist/src/dsh-directory-feed.js.map +1 -1
- package/dist/src/dsh-headless-agent-plan.d.ts +7 -0
- package/dist/src/dsh-headless-agent-plan.d.ts.map +1 -1
- package/dist/src/dsh-headless-agent-plan.js +20 -1
- package/dist/src/dsh-headless-agent-plan.js.map +1 -1
- package/dist/src/dsh-install-observation.d.ts +6 -0
- package/dist/src/dsh-install-observation.d.ts.map +1 -1
- package/dist/src/dsh-install-observation.js +2 -2
- package/dist/src/dsh-install-observation.js.map +1 -1
- package/dist/src/dsh-install-plan.d.ts +7 -0
- package/dist/src/dsh-install-plan.d.ts.map +1 -1
- package/dist/src/dsh-install-plan.js +8 -2
- package/dist/src/dsh-install-plan.js.map +1 -1
- package/dist/src/dsh-surface-observation.d.ts +160 -0
- package/dist/src/dsh-surface-observation.d.ts.map +1 -0
- package/dist/src/dsh-surface-observation.js +1031 -0
- package/dist/src/dsh-surface-observation.js.map +1 -0
- package/dist/src/dsh-surface.d.ts +127 -0
- package/dist/src/dsh-surface.d.ts.map +1 -0
- package/dist/src/dsh-surface.js +667 -0
- package/dist/src/dsh-surface.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/upstream-observer.d.ts +6 -0
- package/dist/src/upstream-observer.d.ts.map +1 -1
- package/dist/src/upstream-observer.js +206 -127
- package/dist/src/upstream-observer.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/docs/README.zh-CN.md +19 -19
- package/package.json +1 -1
|
@@ -404,6 +404,13 @@ function parsePackageObservation(value, label) {
|
|
|
404
404
|
const distTag = optionalBoundedString(source.distTag, `${label}.distTag`, 128);
|
|
405
405
|
if (distTag !== undefined && !SAFE_NPM_DIST_TAG.test(distTag))
|
|
406
406
|
throw new Error(`${label}.distTag is invalid`);
|
|
407
|
+
const rawMigration = source.migration === undefined ? undefined : asRecord(source.migration);
|
|
408
|
+
if (source.migration !== undefined && rawMigration === undefined)
|
|
409
|
+
throw new Error(`${label}.migration must be an object`);
|
|
410
|
+
const migrationTo = rawMigration === undefined ? undefined : boundedString(rawMigration.to, `${label}.migration.to`, 214);
|
|
411
|
+
if (migrationTo !== undefined && !EXACT_NPM_PACKAGE_NAME.test(migrationTo))
|
|
412
|
+
throw new Error(`${label}.migration.to is not an npm package name`);
|
|
413
|
+
const migrationSince = rawMigration === undefined ? undefined : optionalBoundedString(rawMigration.since, `${label}.migration.since`, 128);
|
|
407
414
|
return {
|
|
408
415
|
name,
|
|
409
416
|
version,
|
|
@@ -412,6 +419,12 @@ function parsePackageObservation(value, label) {
|
|
|
412
419
|
...(optionalBoundedString(source.tarball, `${label}.tarball`, 4_096) === undefined ? {} : { tarball: source.tarball }),
|
|
413
420
|
...(optionalBoundedString(source.repository, `${label}.repository`, 4_096) === undefined ? {} : { repository: source.repository }),
|
|
414
421
|
...(optionalBoundedString(source.publishedAt, `${label}.publishedAt`, 128) === undefined ? {} : { publishedAt: source.publishedAt }),
|
|
422
|
+
...(migrationTo === undefined ? {} : {
|
|
423
|
+
migration: {
|
|
424
|
+
to: migrationTo,
|
|
425
|
+
...(migrationSince === undefined ? {} : { since: migrationSince }),
|
|
426
|
+
},
|
|
427
|
+
}),
|
|
415
428
|
};
|
|
416
429
|
}
|
|
417
430
|
function parseSnapshot(value, label) {
|
|
@@ -836,7 +849,10 @@ export class UpstreamObserverClient {
|
|
|
836
849
|
async fetchNpmObservation(name, distTag = 'latest') {
|
|
837
850
|
const url = new URL(encodeURIComponent(name), this.registry);
|
|
838
851
|
const response = await this.fetchWithRetry(url, {
|
|
839
|
-
|
|
852
|
+
// The abbreviated install-v1 packument deliberately drops custom DSH
|
|
853
|
+
// metadata such as dsh.migrate. The observer needs the published package
|
|
854
|
+
// contract so package moves become explicit Agent evidence.
|
|
855
|
+
headers: { accept: 'application/json', 'user-agent': 'upstream-radar/upstream-observer' },
|
|
840
856
|
redirect: 'follow',
|
|
841
857
|
});
|
|
842
858
|
if (response.status === 404)
|
|
@@ -854,6 +870,13 @@ export class UpstreamObserverClient {
|
|
|
854
870
|
const repository = typeof manifest.repository === 'string'
|
|
855
871
|
? manifest.repository
|
|
856
872
|
: typeof asRecord(manifest.repository)?.url === 'string' ? asRecord(manifest.repository)?.url : undefined;
|
|
873
|
+
const rawMigration = asRecord(asRecord(manifest.dsh)?.migrate);
|
|
874
|
+
const migrationTo = typeof rawMigration?.to === 'string' && EXACT_NPM_PACKAGE_NAME.test(rawMigration.to)
|
|
875
|
+
? rawMigration.to
|
|
876
|
+
: undefined;
|
|
877
|
+
const migrationSince = typeof rawMigration?.since === 'string' && rawMigration.since.length <= 128
|
|
878
|
+
? rawMigration.since
|
|
879
|
+
: undefined;
|
|
857
880
|
return {
|
|
858
881
|
name,
|
|
859
882
|
version: selectedVersion,
|
|
@@ -862,6 +885,12 @@ export class UpstreamObserverClient {
|
|
|
862
885
|
...(typeof dist?.tarball === 'string' ? { tarball: dist.tarball } : {}),
|
|
863
886
|
...(repository === undefined ? {} : { repository: repository.slice(0, 4_096) }),
|
|
864
887
|
...(typeof times?.[selectedVersion] === 'string' ? { publishedAt: times[selectedVersion] } : {}),
|
|
888
|
+
...(migrationTo === undefined ? {} : {
|
|
889
|
+
migration: {
|
|
890
|
+
to: migrationTo,
|
|
891
|
+
...(migrationSince === undefined ? {} : { since: migrationSince }),
|
|
892
|
+
},
|
|
893
|
+
}),
|
|
865
894
|
};
|
|
866
895
|
}
|
|
867
896
|
async observe(targetValue, now) {
|
|
@@ -1180,7 +1209,8 @@ function reverseDependencyChanges(before, after) {
|
|
|
1180
1209
|
function packageChanged(before, after) {
|
|
1181
1210
|
if (before.package?.name !== after.package?.name || before.package?.version !== after.package?.version)
|
|
1182
1211
|
return true;
|
|
1183
|
-
return before.package?.integrity !== after.package?.integrity
|
|
1212
|
+
return before.package?.integrity !== after.package?.integrity
|
|
1213
|
+
|| JSON.stringify(before.package?.migration) !== JSON.stringify(after.package?.migration);
|
|
1184
1214
|
}
|
|
1185
1215
|
function sourcePublishedVersionDrift(snapshot) {
|
|
1186
1216
|
if (snapshot.package === undefined || snapshot.manifest.version === snapshot.package.version)
|
|
@@ -1203,8 +1233,14 @@ function graphChanged(before, after) {
|
|
|
1203
1233
|
function meaningfulChange(sourceChange, before, after) {
|
|
1204
1234
|
const reasons = [];
|
|
1205
1235
|
const manifest = manifestChanges(before.manifest, after.manifest);
|
|
1206
|
-
if (
|
|
1236
|
+
if (before.package?.name !== after.package?.name
|
|
1237
|
+
|| before.package?.version !== after.package?.version
|
|
1238
|
+
|| before.package?.integrity !== after.package?.integrity) {
|
|
1207
1239
|
reasons.push('npm package version or integrity changed');
|
|
1240
|
+
}
|
|
1241
|
+
if (JSON.stringify(before.package?.migration) !== JSON.stringify(after.package?.migration) && after.package?.migration !== undefined) {
|
|
1242
|
+
reasons.push(`npm package migration declared: ${after.package.name} → ${after.package.migration.to}${after.package.migration.since === undefined ? '' : ` since ${after.package.migration.since}`}`);
|
|
1243
|
+
}
|
|
1208
1244
|
if (graphChanged(before, after))
|
|
1209
1245
|
reasons.push('dependency graph changed or became unavailable');
|
|
1210
1246
|
if (manifest.fields.length > 0)
|
|
@@ -1490,55 +1526,96 @@ export async function runOpenAiCompatibleAgent(task, prompt, options) {
|
|
|
1490
1526
|
};
|
|
1491
1527
|
}
|
|
1492
1528
|
const endpoints = llmCompletionEndpoints(baseUrl);
|
|
1493
|
-
|
|
1529
|
+
const systemPrompt = [
|
|
1530
|
+
'只返回一个严格 JSON 对象。不要输出 Markdown、解释、前缀或后缀;输出必须以 { 开始并以 } 结束。',
|
|
1531
|
+
'Every response must contain exactly the eight fields shown below and no others.',
|
|
1532
|
+
'EXAMPLE JSON OUTPUT:',
|
|
1533
|
+
JSON.stringify({
|
|
1534
|
+
impact: 'unknown',
|
|
1535
|
+
confidence: 'low',
|
|
1536
|
+
evidence: ['State an exact repository path or explicitly name the missing evidence.'],
|
|
1537
|
+
breaking_change: 'unknown',
|
|
1538
|
+
dependency_risk: 'unknown',
|
|
1539
|
+
recommended_action: 'Review the changed runtime paths before upgrading.',
|
|
1540
|
+
urgency: 'monitor',
|
|
1541
|
+
reasoning_summary: 'Separate observed facts from model judgment.',
|
|
1542
|
+
}, null, 2),
|
|
1543
|
+
].join('\n');
|
|
1544
|
+
endpointLoop: for (let index = 0; index < endpoints.length; index += 1) {
|
|
1494
1545
|
const endpoint = endpoints[index];
|
|
1495
|
-
|
|
1496
|
-
const
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1546
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
1547
|
+
const repairAttempt = attempt === 1;
|
|
1548
|
+
try {
|
|
1549
|
+
const response = await fetch(endpoint, {
|
|
1550
|
+
method: 'POST',
|
|
1551
|
+
headers: {
|
|
1552
|
+
authorization: `Bearer ${apiKey}`,
|
|
1553
|
+
'content-type': 'application/json',
|
|
1554
|
+
},
|
|
1555
|
+
body: JSON.stringify({
|
|
1556
|
+
model,
|
|
1557
|
+
messages: [
|
|
1558
|
+
{
|
|
1559
|
+
role: 'system',
|
|
1560
|
+
content: repairAttempt
|
|
1561
|
+
? `The previous JSON-mode response was empty or invalid. Return the example shape now.\n\n${systemPrompt}`
|
|
1562
|
+
: systemPrompt,
|
|
1563
|
+
},
|
|
1564
|
+
{ role: 'user', content: prompt },
|
|
1565
|
+
],
|
|
1566
|
+
temperature: 0,
|
|
1567
|
+
// DeepSeek V4 enables thinking by default. For this machine-readable
|
|
1568
|
+
// contract, disable it so the output budget is reserved for the JSON
|
|
1569
|
+
// conclusion instead of an optional reasoning stream.
|
|
1570
|
+
...(isDeepSeekJsonModel(baseUrl, model) ? { thinking: { type: 'disabled' } } : {}),
|
|
1571
|
+
// DeepSeek documents that JSON Output may occasionally return an
|
|
1572
|
+
// empty content field. Retry once without provider JSON mode; the
|
|
1573
|
+
// same exact local schema validator still gates the conclusion.
|
|
1574
|
+
...(repairAttempt ? {} : { response_format: { type: 'json_object' } }),
|
|
1575
|
+
// Keep an explicit output budget so the JSON conclusion is not
|
|
1576
|
+
// truncated by a provider default.
|
|
1577
|
+
max_tokens: DEFAULT_LLM_MAX_TOKENS,
|
|
1578
|
+
}),
|
|
1579
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
1580
|
+
});
|
|
1581
|
+
if (response.status === 404)
|
|
1582
|
+
continue endpointLoop;
|
|
1583
|
+
if (!response.ok) {
|
|
1584
|
+
return {
|
|
1585
|
+
taskId: task.id,
|
|
1586
|
+
status: 'failed',
|
|
1587
|
+
error: `LLM endpoint returned HTTP ${response.status}: ${safeLlmEndpoint(endpoint)}`,
|
|
1588
|
+
};
|
|
1589
|
+
}
|
|
1590
|
+
const body = await response.json();
|
|
1591
|
+
const content = body.choices?.[0]?.message?.content;
|
|
1592
|
+
let conclusionError;
|
|
1593
|
+
if (typeof content !== 'string') {
|
|
1594
|
+
conclusionError = 'LLM response had no message content';
|
|
1595
|
+
}
|
|
1596
|
+
else {
|
|
1597
|
+
try {
|
|
1598
|
+
const parsed = parseAgentOutput(extractJsonObject(content));
|
|
1599
|
+
if (parsed.value !== undefined) {
|
|
1600
|
+
return { taskId: task.id, status: 'succeeded', parsedOutput: parsed.value };
|
|
1601
|
+
}
|
|
1602
|
+
conclusionError = parsed.error ?? 'LLM returned an invalid conclusion';
|
|
1603
|
+
}
|
|
1604
|
+
catch (error) {
|
|
1605
|
+
conclusionError = safeError(error);
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
if (!repairAttempt)
|
|
1609
|
+
continue;
|
|
1523
1610
|
return {
|
|
1524
1611
|
taskId: task.id,
|
|
1525
1612
|
status: 'failed',
|
|
1526
|
-
error: `LLM
|
|
1613
|
+
error: `LLM returned no valid conclusion after JSON-mode and plain-text attempts at ${safeLlmEndpoint(endpoint)}: ${conclusionError}`,
|
|
1527
1614
|
};
|
|
1528
1615
|
}
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
if (typeof content !== 'string') {
|
|
1532
|
-
return { taskId: task.id, status: 'failed', error: `LLM response had no message content: ${safeLlmEndpoint(endpoint)}` };
|
|
1533
|
-
}
|
|
1534
|
-
const parsed = parseAgentOutput(extractJsonObject(content));
|
|
1535
|
-
if (parsed.value === undefined) {
|
|
1536
|
-
return { taskId: task.id, status: 'failed', error: parsed.error ?? 'LLM returned an invalid conclusion' };
|
|
1616
|
+
catch (error) {
|
|
1617
|
+
return { taskId: task.id, status: 'failed', error: `LLM request failed at ${safeLlmEndpoint(endpoint)}: ${safeError(error)}` };
|
|
1537
1618
|
}
|
|
1538
|
-
return { taskId: task.id, status: 'succeeded', parsedOutput: parsed.value };
|
|
1539
|
-
}
|
|
1540
|
-
catch (error) {
|
|
1541
|
-
return { taskId: task.id, status: 'failed', error: `LLM request failed at ${safeLlmEndpoint(endpoint)}: ${safeError(error)}` };
|
|
1542
1619
|
}
|
|
1543
1620
|
}
|
|
1544
1621
|
return {
|
|
@@ -1621,92 +1698,94 @@ export async function runObserver(config, previousState, options = {}) {
|
|
|
1621
1698
|
const alignmentFindings = [];
|
|
1622
1699
|
const errors = [];
|
|
1623
1700
|
const newTasks = [];
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
// checkedAt belongs in the run report. Keep the durable observation point
|
|
1636
|
-
// byte-stable when its evidence did not change, so a no-op cron run does
|
|
1637
|
-
// not manufacture a commit from a fresh timestamp alone.
|
|
1638
|
-
nextTargets[configuredTarget.id] = snapshotEvidenceSignature(before) === snapshotEvidenceSignature(current)
|
|
1639
|
-
? before
|
|
1640
|
-
: current;
|
|
1641
|
-
if (before.alignment === undefined && current.alignment !== undefined) {
|
|
1642
|
-
// Upgrade legacy state into the IR and show its first finding once.
|
|
1643
|
-
// This is evidence for the author, not a fake upstream change and not
|
|
1644
|
-
// a reason to wake the Agent on every subsequent scheduled run.
|
|
1645
|
-
alignmentFindings.push({ targetId: configuredTarget.id, alignment: structuredClone(current.alignment) });
|
|
1646
|
-
}
|
|
1647
|
-
const sourceChange = before.source.commit === current.source.commit
|
|
1648
|
-
? {
|
|
1649
|
-
beforeCommit: before.source.commit,
|
|
1650
|
-
afterCommit: current.source.commit,
|
|
1651
|
-
comparison: 'complete',
|
|
1652
|
-
changedFiles: [],
|
|
1653
|
-
runtimeFiles: [],
|
|
1654
|
-
nonRuntimeFiles: [],
|
|
1701
|
+
if (options.retryPendingOnly !== true) {
|
|
1702
|
+
for (const configuredTarget of config.targets) {
|
|
1703
|
+
try {
|
|
1704
|
+
const current = await source.observe(configuredTarget, checkedAt);
|
|
1705
|
+
const before = previousState.targets[configuredTarget.id];
|
|
1706
|
+
if (before === undefined) {
|
|
1707
|
+
nextTargets[configuredTarget.id] = current;
|
|
1708
|
+
baselineTargets.push(configuredTarget.id);
|
|
1709
|
+
if (current.alignment !== undefined)
|
|
1710
|
+
alignmentFindings.push({ targetId: configuredTarget.id, alignment: structuredClone(current.alignment) });
|
|
1711
|
+
continue;
|
|
1655
1712
|
}
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
};
|
|
1713
|
+
// checkedAt belongs in the run report. Keep the durable observation point
|
|
1714
|
+
// byte-stable when its evidence did not change, so a no-op cron run does
|
|
1715
|
+
// not manufacture a commit from a fresh timestamp alone.
|
|
1716
|
+
nextTargets[configuredTarget.id] = snapshotEvidenceSignature(before) === snapshotEvidenceSignature(current)
|
|
1717
|
+
? before
|
|
1718
|
+
: current;
|
|
1719
|
+
if (before.alignment === undefined && current.alignment !== undefined) {
|
|
1720
|
+
// Upgrade legacy state into the IR and show its first finding once.
|
|
1721
|
+
// This is evidence for the author, not a fake upstream change and not
|
|
1722
|
+
// a reason to wake the Agent on every subsequent scheduled run.
|
|
1723
|
+
alignmentFindings.push({ targetId: configuredTarget.id, alignment: structuredClone(current.alignment) });
|
|
1668
1724
|
}
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1725
|
+
const sourceChange = before.source.commit === current.source.commit
|
|
1726
|
+
? {
|
|
1727
|
+
beforeCommit: before.source.commit,
|
|
1728
|
+
afterCommit: current.source.commit,
|
|
1729
|
+
comparison: 'complete',
|
|
1730
|
+
changedFiles: [],
|
|
1731
|
+
runtimeFiles: [],
|
|
1732
|
+
nonRuntimeFiles: [],
|
|
1733
|
+
}
|
|
1734
|
+
: await source.compare(current.source.repository, before.source.commit, current.source.commit);
|
|
1735
|
+
const change = createChange(configuredTarget, before, current, sourceChange, options.reverseDependencyIndex);
|
|
1736
|
+
if (change.reasons.length === 0)
|
|
1737
|
+
continue;
|
|
1738
|
+
let reviewedChange = change;
|
|
1739
|
+
if (change.meaningful && current.package !== undefined && options.artifactReviewer !== undefined) {
|
|
1740
|
+
const packageSpec = `npm:${current.package.name}@${current.package.version}`;
|
|
1741
|
+
try {
|
|
1742
|
+
reviewedChange = {
|
|
1743
|
+
...change,
|
|
1744
|
+
artifactReview: await options.artifactReviewer(packageSpec, configuredTarget),
|
|
1745
|
+
};
|
|
1746
|
+
}
|
|
1747
|
+
catch (error) {
|
|
1748
|
+
// Artifact review is useful evidence, but it must not turn a valid
|
|
1749
|
+
// source observation into a source-observation error. Keep the
|
|
1750
|
+
// change and make the incomplete review explicit for the author and
|
|
1751
|
+
// for a later retry of the whole scheduled run.
|
|
1752
|
+
reviewedChange = {
|
|
1753
|
+
...change,
|
|
1754
|
+
artifactReview: {
|
|
1755
|
+
spec: packageSpec,
|
|
1756
|
+
verdict: 'review',
|
|
1757
|
+
riskVerdict: 'review',
|
|
1758
|
+
coverageVerdict: 'incomplete',
|
|
1759
|
+
artifactIntegrity: 'not-checked',
|
|
1760
|
+
registrySignature: 'not-checked',
|
|
1761
|
+
provenance: 'not-checked',
|
|
1762
|
+
dependencyResolution: 'manifest-only',
|
|
1763
|
+
dependencyAuditStatus: 'failed',
|
|
1764
|
+
packages: null,
|
|
1765
|
+
unresolved: 0,
|
|
1766
|
+
vulnerabilities: null,
|
|
1767
|
+
installScriptPackages: [],
|
|
1768
|
+
installScriptDetails: [],
|
|
1769
|
+
findings: [],
|
|
1770
|
+
error: safeError(error),
|
|
1771
|
+
},
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1695
1774
|
}
|
|
1775
|
+
changes.push(reviewedChange);
|
|
1776
|
+
if (!reviewedChange.meaningful || reviewedChange.taskId === undefined)
|
|
1777
|
+
continue;
|
|
1778
|
+
const task = createUpstreamChangeTask(configuredTarget, reviewedChange, checkedAt);
|
|
1779
|
+
newTasks.push(task);
|
|
1780
|
+
if (!taskAlreadyPending(pendingTasks, task.id))
|
|
1781
|
+
pendingTasks.push(task);
|
|
1782
|
+
}
|
|
1783
|
+
catch (error) {
|
|
1784
|
+
errors.push({ targetId: configuredTarget.id, message: safeError(error) });
|
|
1696
1785
|
}
|
|
1697
|
-
changes.push(reviewedChange);
|
|
1698
|
-
if (!reviewedChange.meaningful || reviewedChange.taskId === undefined)
|
|
1699
|
-
continue;
|
|
1700
|
-
const task = createUpstreamChangeTask(configuredTarget, reviewedChange, checkedAt);
|
|
1701
|
-
newTasks.push(task);
|
|
1702
|
-
if (!taskAlreadyPending(pendingTasks, task.id))
|
|
1703
|
-
pendingTasks.push(task);
|
|
1704
|
-
}
|
|
1705
|
-
catch (error) {
|
|
1706
|
-
errors.push({ targetId: configuredTarget.id, message: safeError(error) });
|
|
1707
1786
|
}
|
|
1708
1787
|
}
|
|
1709
|
-
const pendingToRetry = options.retryPending === true
|
|
1788
|
+
const pendingToRetry = options.retryPending === true || options.retryPendingOnly === true
|
|
1710
1789
|
? pendingTasks.filter(task => !newTasks.some(current => current.id === task.id))
|
|
1711
1790
|
: [];
|
|
1712
1791
|
const tasksToInvoke = [...newTasks, ...pendingToRetry];
|
|
@@ -1721,7 +1800,7 @@ export async function runObserver(config, previousState, options = {}) {
|
|
|
1721
1800
|
const report = {
|
|
1722
1801
|
schema: OBSERVER_REPORT_SCHEMA,
|
|
1723
1802
|
checkedAt,
|
|
1724
|
-
targetsChecked: config.targets.length,
|
|
1803
|
+
targetsChecked: options.retryPendingOnly === true ? 0 : config.targets.length,
|
|
1725
1804
|
baselineTargets,
|
|
1726
1805
|
alignmentFindings,
|
|
1727
1806
|
...(options.reverseDependencyIndex === undefined ? {} : {
|
|
@@ -1764,7 +1843,7 @@ export function observerExitCode(report) {
|
|
|
1764
1843
|
function displayPackage(value) {
|
|
1765
1844
|
return value === undefined
|
|
1766
1845
|
? 'not observed'
|
|
1767
|
-
: `${value.name}@${value.version}${value.distTag === undefined ? '' : ` via npm tag ${value.distTag}`}`;
|
|
1846
|
+
: `${value.name}@${value.version}${value.distTag === undefined ? '' : ` via npm tag ${value.distTag}`}${value.migration === undefined ? '' : `; migrates to ${value.migration.to}${value.migration.since === undefined ? '' : ` since ${value.migration.since}`}`}`;
|
|
1768
1847
|
}
|
|
1769
1848
|
function displayGraph(value) {
|
|
1770
1849
|
return value === undefined ? 'not observed' : `${value.nodes} nodes, ${value.edges} edges${value.unresolved === 0 ? '' : `, ${value.unresolved} unresolved`}`;
|