upstream-radar 0.33.7 → 0.33.9

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.md CHANGED
@@ -91,7 +91,7 @@ The useful part is the exact path and project-specific next step—not another g
91
91
  Want to try it on a real published DSH plugin immediately?
92
92
 
93
93
  ```bash
94
- npx --yes upstream-radar@0.33.7 inspect dsh-feishu-bot@0.15.4 --deep
94
+ npx --yes upstream-radar@0.33.9 inspect dsh-feishu-bot@0.15.4 --deep
95
95
  ```
96
96
 
97
97
  This runs from an otherwise empty directory and returns a short admission,
@@ -101,7 +101,7 @@ Want to see a real author-actionable result? This exact published DSH plugin
101
101
  currently cannot produce a complete dependency graph in a clean npm resolver:
102
102
 
103
103
  ```bash
104
- npx --yes upstream-radar@0.33.7 inspect \
104
+ npx --yes upstream-radar@0.33.9 inspect \
105
105
  @sanqi-normal/dsh-webui-market-plugin@0.5.4 \
106
106
  --deep --fail-on never
107
107
  ```
@@ -279,7 +279,7 @@ since then.
279
279
  ```text
280
280
  targets.yml
281
281
 
282
- GitHub commit + npm package metadata + optional lockfile
282
+ GitHub commit + npm package metadata + auto-detected or explicit lockfile
283
283
 
284
284
  observations.json
285
285
 
@@ -303,11 +303,36 @@ targets:
303
303
  lockfileType: pnpm
304
304
  ```
305
305
 
306
+ For one public repository, skip YAML and pass its GitHub URL directly. The
307
+ first run creates a baseline; later runs compare the ref you provide. The
308
+ observer automatically looks for `pnpm-lock.yaml` or `package-lock.json` and
309
+ uses the real committed graph. Add `--package-path` for a nested plugin,
310
+ `--package` when the npm name differs from the source manifest, or
311
+ `--lockfile` when you want to choose a particular lockfile:
312
+
313
+ ```bash
314
+ npx --yes upstream-radar@0.33.9 observe \
315
+ https://github.com/PlutoKeating/dsh-lark-bot \
316
+ --state ./observations.json --report ./upstream-radar-observer.md
317
+ ```
318
+
319
+ The public example below supplies `--package` because this repository's source
320
+ manifest is `dsh-lark-bot`, while its published npm package is
321
+ `dsh-feishu-bot`:
322
+
323
+ ```bash
324
+ npx --yes upstream-radar@0.33.9 observe \
325
+ https://github.com/PlutoKeating/dsh-lark-bot \
326
+ --package dsh-feishu-bot \
327
+ --lockfile pnpm-lock.yaml --lockfile-type pnpm \
328
+ --state ./observations.json --report ./upstream-radar-observer.md
329
+ ```
330
+
306
331
  Then run one cycle:
307
332
 
308
333
  ```bash
309
334
  export GITHUB_TOKEN='a read-only GitHub token'
310
- npx --yes upstream-radar@0.33.7 observe \
335
+ npx --yes upstream-radar@0.33.9 observe \
311
336
  ./targets.yml \
312
337
  --state ./observations.json \
313
338
  --report ./upstream-radar-observer.md
@@ -319,7 +344,8 @@ This uses the published CLI; pin the exact version in CI rather than relying on
319
344
  - the source commit and changed files;
320
345
  - the published npm version and integrity value;
321
346
  - the package entrypoint, exports, Node requirement, DSH bundle metadata and dependency declarations;
322
- - the real npm or pnpm lockfile graph, when a lockfile is configured.
347
+ - the real npm or pnpm lockfile graph, when a supported lockfile is committed;
348
+ the selected path is recorded in the observation state.
323
349
 
324
350
  README/docs/tests-only changes advance the observation point without waking the
325
351
  Agent. Runtime source, DSH bundle, package entry, dependency graph, npm version,
@@ -555,7 +581,7 @@ cd my-dsh-plugin
555
581
  pnpm install --ignore-scripts
556
582
 
557
583
  # Read the exact graph before adding the plugin to a DSH profile.
558
- pnpm dlx --package=upstream-radar@0.33.7 upstream-radar graph pnpm-lock pnpm-lock.yaml --json
584
+ pnpm dlx --package=upstream-radar@0.33.9 upstream-radar graph pnpm-lock pnpm-lock.yaml --json
559
585
  ```
560
586
 
561
587
  The graph includes the exact DSH package versions and keeps unresolved optional peers visible. It does not load the generated plugin or run lifecycle scripts. After reviewing it, copy this complete workflow into `.github/workflows/upstream-radar.yml`:
@@ -577,7 +603,7 @@ jobs:
577
603
  runs-on: ubuntu-latest
578
604
  steps:
579
605
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
580
- - uses: MicroMilo/upstream-radar@v0.33.7
606
+ - uses: MicroMilo/upstream-radar@v0.33.9
581
607
  with:
582
608
  fail-on: high
583
609
  fail-on-compatibility: breaking
@@ -588,7 +614,7 @@ The Action auto-detects the one `pnpm-lock.yaml`, checks the same exact graph, a
588
614
  To check a real published DSH artifact directly, run one command:
589
615
 
590
616
  ```bash
591
- npx --yes upstream-radar@0.33.7 inspect dsh-feishu-bot@0.15.4 --deep
617
+ npx --yes upstream-radar@0.33.9 inspect dsh-feishu-bot@0.15.4 --deep
592
618
  ```
593
619
 
594
620
  The checked result is `REVIEW`: registry integrity, signature, provenance, and
@@ -745,7 +771,7 @@ To see the two-source vulnerability contract without contacting the network, run
745
771
  Before wiring a project into a compatibility gate, run the offline rule benchmark:
746
772
 
747
773
  ```bash
748
- pnpm dlx --package=upstream-radar@0.33.7 upstream-radar benchmark compatibility
774
+ pnpm dlx --package=upstream-radar@0.33.9 upstream-radar benchmark compatibility
749
775
  ```
750
776
 
751
777
  It covers six contracts: a safe patch, a change that only needs project analysis, an incompatible DSH peer, a publisher-declared breaking release, a vulnerable candidate dependency, and an incomplete candidate graph. The command does not access the network, install a package, load a plugin, or start DSH. It checks the behavior of Radar's deterministic rules and the `breaking`/`any` gates; it is not a runtime compatibility proof.
@@ -758,7 +784,7 @@ When you have an exact plugin artifact and want to know whether one exact DSH re
758
784
  # Pack an exact npm release without running its lifecycle scripts.
759
785
  npm pack --ignore-scripts dsh-plugin@1.2.3
760
786
 
761
- pnpm dlx --package=upstream-radar@0.33.7 upstream-radar probe dsh-load \
787
+ pnpm dlx --package=upstream-radar@0.33.9 upstream-radar probe dsh-load \
762
788
  ./dsh-plugin-1.2.3.tgz \
763
789
  --dsh-version 0.1.0-rc.6
764
790
  ```
@@ -784,7 +810,7 @@ It exercises a loadable bundle, a bundle patch DSH rejects, and a package that r
784
810
  To compare a plugin against more than one DSH release, use the matrix form:
785
811
 
786
812
  ```bash
787
- pnpm dlx --package=upstream-radar@0.33.7 upstream-radar probe dsh-matrix \
813
+ pnpm dlx --package=upstream-radar@0.33.9 upstream-radar probe dsh-matrix \
788
814
  ./dsh-plugin-1.2.3.tgz \
789
815
  --dsh-version 0.1.0-rc.3 \
790
816
  --dsh-version 0.1.0-rc.6 \
@@ -800,7 +826,7 @@ If your team wants the shortest scheduled CI gate before wiring a machine to a l
800
826
  ```yaml
801
827
  steps:
802
828
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
803
- - uses: MicroMilo/upstream-radar@v0.33.7
829
+ - uses: MicroMilo/upstream-radar@v0.33.9
804
830
  with:
805
831
  fail-on: high
806
832
  # Optional: also fail on deterministic DSH/plugin compatibility breaks.
@@ -809,12 +835,12 @@ steps:
809
835
  threat-intel: true
810
836
  ```
811
837
 
812
- The Action is a thin wrapper around `radar check --frozen --state :memory: --fail-on high --json`; when the optional compatibility input is enabled, it also passes `--fail-on-compatibility breaking` or `any`. `--frozen` is deliberate: it uses the graph in the reviewed config and does not try to read a developer's local DSH profile. `threat-intel` is false by default so an ordinary CI gate stays lean; set it to `true` when the Job Summary and raw JSON should include CISA KEV and FIRST EPSS prioritization evidence. Each run is independent, exits `2` when an active vulnerability or opted-in compatibility change meets its threshold, and exits `1` for an operational or source error. `breaking` catches confirmed or strong incompatibility signals; `any` catches every active compatibility event. The default is `never`, so vulnerability-only behavior stays unchanged. In addition to the raw JSON log, the Action writes a short escaped summary to the GitHub Job Summary so a scheduled failure immediately shows the affected package, exact path, published fix version when available, one-line priority evidence, and a suggested next step. The Action does not deliver a DSH Agent task or modify a branch; the native DSH bundle remains the always-on analysis path. Pin the Action to a release tag such as `v0.33.7`, and pin the checkout Action in your workflow according to your repository's policy.
838
+ The Action is a thin wrapper around `radar check --frozen --state :memory: --fail-on high --json`; when the optional compatibility input is enabled, it also passes `--fail-on-compatibility breaking` or `any`. `--frozen` is deliberate: it uses the graph in the reviewed config and does not try to read a developer's local DSH profile. `threat-intel` is false by default so an ordinary CI gate stays lean; set it to `true` when the Job Summary and raw JSON should include CISA KEV and FIRST EPSS prioritization evidence. Each run is independent, exits `2` when an active vulnerability or opted-in compatibility change meets its threshold, and exits `1` for an operational or source error. `breaking` catches confirmed or strong incompatibility signals; `any` catches every active compatibility event. The default is `never`, so vulnerability-only behavior stays unchanged. In addition to the raw JSON log, the Action writes a short escaped summary to the GitHub Job Summary so a scheduled failure immediately shows the affected package, exact path, published fix version when available, one-line priority evidence, and a suggested next step. The Action does not deliver a DSH Agent task or modify a branch; the native DSH bundle remains the always-on analysis path. Pin the Action to a release tag such as `v0.33.9`, and pin the checkout Action in your workflow according to your repository's policy.
813
839
 
814
840
  If the repository has no committed Radar config yet, the smallest setup is to omit `config`, `pnpm-lock`, and `npm-lock`. After checkout, the Action automatically uses the only one of `pnpm-lock.yaml` or `package-lock.json` that exists, generates a temporary reviewed config, and runs the same frozen check:
815
841
 
816
842
  ```yaml
817
- - uses: MicroMilo/upstream-radar@v0.33.7
843
+ - uses: MicroMilo/upstream-radar@v0.33.9
818
844
  with:
819
845
  fail-on: high
820
846
  ```
@@ -824,7 +850,7 @@ An existing `config` wins over auto-detection. If both lockfiles exist, or neith
824
850
  To review the exact plugin artifact before it enters DSH, add `inspect-package`:
825
851
 
826
852
  ```yaml
827
- - uses: MicroMilo/upstream-radar@v0.33.7
853
+ - uses: MicroMilo/upstream-radar@v0.33.9
828
854
  with:
829
855
  inspect-package: dsh-cloudflare-browser-run@0.1.1
830
856
  # review is the safe default; use block only when incomplete coverage may pass.
@@ -836,7 +862,7 @@ This downloads that exact npm tarball, verifies the registry integrity/signature
836
862
  If the repository has a pnpm lockfile but no committed Radar config yet, the Action can generate the config in the same job. See the [copyable pnpm workflow](examples/github-actions/upstream-radar-pnpm.yml):
837
863
 
838
864
  ```yaml
839
- - uses: MicroMilo/upstream-radar@v0.33.7
865
+ - uses: MicroMilo/upstream-radar@v0.33.9
840
866
  with:
841
867
  pnpm-lock: pnpm-lock.yaml
842
868
  fail-on: high
@@ -850,7 +876,7 @@ See the [copyable npm workflow](examples/github-actions/upstream-radar-npm.yml)
850
876
  The Action requires the caller to check out the repository first. It does not install the project's dependencies or run their lifecycle scripts; it only reads the committed graph and queries the configured upstream sources. For a fully explicit, lower-level invocation, the equivalent command is:
851
877
 
852
878
  ```bash
853
- pnpm dlx --package=upstream-radar@0.33.7 upstream-radar radar check \
879
+ pnpm dlx --package=upstream-radar@0.33.9 upstream-radar radar check \
854
880
  ./upstream-radar.config.json --frozen --state :memory: --fail-on high \
855
881
  --fail-on-compatibility breaking --json
856
882
  ```
@@ -858,7 +884,7 @@ pnpm dlx --package=upstream-radar@0.33.7 upstream-radar radar check \
858
884
  To add the optional DSH load matrix for a published plugin, provide an exact npm package and at least two exact DSH versions:
859
885
 
860
886
  ```yaml
861
- - uses: MicroMilo/upstream-radar@v0.33.7
887
+ - uses: MicroMilo/upstream-radar@v0.33.9
862
888
  id: radar
863
889
  with:
864
890
  config: upstream-radar.config.json
package/dist/src/cli.js CHANGED
@@ -29,10 +29,10 @@ import { createRadarHistory, renderRadarHistory } from './radar-history.js';
29
29
  import { loadRadarState, saveRadarState } from './radar-state.js';
30
30
  import { createRadarNext, createRadarStatus, renderRadarNext, renderRadarStatus } from './radar-status.js';
31
31
  import { renderTextReport } from './render.js';
32
- import { materializeGitHubRepository } from './repository.js';
32
+ import { materializeGitHubRepository, parseGitHubRepositoryUrl } from './repository.js';
33
33
  import { scanDirectory } from './scan.js';
34
34
  import { CisaKevClient, EpssClient } from './threat-intel.js';
35
- import { loadObservationState, parseObserverConfigText, renderObserverReport, runDshAgentCommand, runOpenAiCompatibleAgent, runObserver, saveObservationState, UpstreamObserverClient, } from './upstream-observer.js';
35
+ import { loadObservationState, OBSERVER_TARGETS_SCHEMA, parseObserverConfig, parseObserverConfigText, renderObserverReport, runDshAgentCommand, runOpenAiCompatibleAgent, runObserver, saveObservationState, UpstreamObserverClient, } from './upstream-observer.js';
36
36
  import { TOOL_VERSION } from './version.js';
37
37
  import { eventsForRadarWebhookTarget, markRadarWebhookEventsDelivered, markRadarWebhookEventsDeliveredForRoute, normalizeRadarWebhookUrl, queueRadarWebhookEvents, queueRadarWebhookEventsForRoute, resolveRadarWebhookTargets, sendRadarWebhook, undeliveredRadarWebhookEvents, undeliveredRadarWebhookEventsForRoute, } from './webhook.js';
38
38
  const VALID_THRESHOLDS = new Set(['warn', 'review', 'block', 'never']);
@@ -197,14 +197,22 @@ should remain visible without failing CI.
197
197
  observe: `Upstream Radar — watch DSH plugin repositories and packages for meaningful upstream changes
198
198
 
199
199
  Usage:
200
- upstream-radar observe <targets.yml> [--state <observations.json>]
200
+ upstream-radar observe <targets.yml|github-url> [--state <observations.json>]
201
201
  [--report <report.md>] [--dsh-agent-command <executable>]
202
- [--dsh-agent-arg <argument>] [--llm-env-file <path>] [--retry-pending] [--json]
202
+ [--dsh-agent-arg <argument>] [--llm-env-file <path>] [--retry-pending]
203
+ [--ecosystem <dsh|codex|pi>] [--id <id>] [--package <name>]
204
+ [--package-path <path>] [--lockfile <path>] [--lockfile-type <npm|pnpm>]
205
+ [--ref <branch>] [--json]
203
206
 
204
207
  The first run creates a baseline. Later runs compare source commits, published
205
208
  npm metadata, package manifests, and an optional npm/pnpm dependency graph. A
206
209
  DSH Agent is called only for meaningful changes. Safety: does not install packages, run lifecycle scripts, load plugin code, or invoke a shell.
207
210
 
211
+ When the target is an HTTPS GitHub repository URL, Radar builds one target in
212
+ memory and does not require a targets.yml file. The default package path is
213
+ package.json; pass --package-path for a nested plugin and --lockfile to include
214
+ the committed npm/pnpm graph.
215
+
208
216
  The Agent executable receives one read-only task prompt on stdin and should
209
217
  return one JSON conclusion on stdout. If it is not configured, the task stays
210
218
  in observations.json for a later explicit retry. As a simpler alternative,
@@ -410,7 +418,7 @@ Usage:
410
418
  upstream-radar doctor [config.json] [options]
411
419
  upstream-radar scan <directory-or-github-url> [--json] [--fail-on <warn|review|block|never>]
412
420
  upstream-radar inspect [npm:]<package>@<exact-version> [--deep] [--json] [--fail-on <warn|review|block|never>]
413
- upstream-radar observe <targets.yml> [--state <observations.json>] [--report <report.md>] [--dsh-agent-command <executable>] [--dsh-agent-arg <argument>] [--llm-env-file <path>] [--retry-pending] [--json]
421
+ upstream-radar observe <targets.yml|github-url> [--state <observations.json>] [--report <report.md>] [--dsh-agent-command <executable>] [--dsh-agent-arg <argument>] [--llm-env-file <path>] [--retry-pending] [--ecosystem <dsh|codex|pi>] [--id <id>] [--package <name>] [--package-path <path>] [--lockfile <path>] [--lockfile-type <npm|pnpm>] [--ref <branch>] [--json]
414
422
  upstream-radar graph <npm-lock|pnpm-lock> <lockfile> [--root <package>@<exact-version>] [--json]
415
423
  upstream-radar profile-check [profile-directory] [--patch <path>] [--report <path>] [--summary] [--json]
416
424
  upstream-radar probe dsh-load <package.tgz> [--dsh-version <exact-version>] [--timeout <seconds>] [--keep-profile] [--json]
@@ -1400,7 +1408,7 @@ async function runRadar(args) {
1400
1408
  async function runObserve(args) {
1401
1409
  const targetsPath = args[0];
1402
1410
  if (targetsPath === undefined || targetsPath.startsWith('-'))
1403
- throw new Error('observe requires a targets.yml file');
1411
+ throw new Error('observe requires a targets.yml file or an HTTPS GitHub repository URL');
1404
1412
  let statePath = 'observations.json';
1405
1413
  let reportPath;
1406
1414
  let agentCommand;
@@ -1409,6 +1417,14 @@ async function runObserve(args) {
1409
1417
  let registry;
1410
1418
  let retryPending = false;
1411
1419
  let json = false;
1420
+ let inlineEcosystem;
1421
+ let inlineId;
1422
+ let inlinePackage;
1423
+ let inlinePackagePath;
1424
+ let inlineLockfile;
1425
+ let inlineLockfileType;
1426
+ let inlineRef;
1427
+ let inlineOptionsUsed = false;
1412
1428
  for (let index = 1; index < args.length; index += 1) {
1413
1429
  const argument = args[index];
1414
1430
  if (argument === '--json') {
@@ -1417,11 +1433,25 @@ async function runObserve(args) {
1417
1433
  else if (argument === '--retry-pending') {
1418
1434
  retryPending = true;
1419
1435
  }
1420
- else if (argument === '--state' || argument === '--report' || argument === '--dsh-agent-command' || argument === '--dsh-agent-arg' || argument === '--llm-env-file' || argument === '--registry') {
1436
+ else if (argument === '--ecosystem' || argument === '--id' || argument === '--package' || argument === '--package-path' || argument === '--lockfile' || argument === '--lockfile-type' || argument === '--ref' || argument === '--state' || argument === '--report' || argument === '--dsh-agent-command' || argument === '--dsh-agent-arg' || argument === '--llm-env-file' || argument === '--registry') {
1421
1437
  const value = args[index + 1];
1422
1438
  if (value === undefined || (value.startsWith('-') && argument !== '--dsh-agent-arg'))
1423
1439
  throw new Error(`${argument} requires a value`);
1424
- if (argument === '--state')
1440
+ if (argument === '--ecosystem')
1441
+ inlineEcosystem = value;
1442
+ else if (argument === '--id')
1443
+ inlineId = value;
1444
+ else if (argument === '--package')
1445
+ inlinePackage = value;
1446
+ else if (argument === '--package-path')
1447
+ inlinePackagePath = value;
1448
+ else if (argument === '--lockfile')
1449
+ inlineLockfile = value;
1450
+ else if (argument === '--lockfile-type')
1451
+ inlineLockfileType = value;
1452
+ else if (argument === '--ref')
1453
+ inlineRef = value;
1454
+ else if (argument === '--state')
1425
1455
  statePath = value;
1426
1456
  else if (argument === '--report')
1427
1457
  reportPath = value;
@@ -1433,14 +1463,42 @@ async function runObserve(args) {
1433
1463
  llmEnvFile = value;
1434
1464
  else
1435
1465
  registry = value;
1466
+ if (argument !== '--state' && argument !== '--report' && argument !== '--dsh-agent-command' && argument !== '--dsh-agent-arg' && argument !== '--llm-env-file' && argument !== '--registry')
1467
+ inlineOptionsUsed = true;
1436
1468
  index += 1;
1437
1469
  }
1438
1470
  else {
1439
1471
  throw new Error(`unknown option for observe: ${argument}`);
1440
1472
  }
1441
1473
  }
1442
- const targetText = await readBoundedFile(targetsPath, 256 * 1024);
1443
- const config = parseObserverConfigText(targetText);
1474
+ const githubTarget = parseGitHubRepositoryUrl(targetsPath);
1475
+ let config;
1476
+ if (githubTarget !== undefined) {
1477
+ if (inlineLockfileType !== undefined && inlineLockfile === undefined) {
1478
+ throw new Error('--lockfile-type requires --lockfile when observe receives a GitHub URL');
1479
+ }
1480
+ config = parseObserverConfig({
1481
+ schema: OBSERVER_TARGETS_SCHEMA,
1482
+ targets: [{
1483
+ id: inlineId ?? `${githubTarget.owner}-${githubTarget.repository}`,
1484
+ ecosystem: inlineEcosystem ?? 'dsh',
1485
+ repository: `${githubTarget.owner}/${githubTarget.repository}`,
1486
+ ref: inlineRef ?? 'main',
1487
+ packageName: inlinePackage,
1488
+ packagePath: inlinePackagePath ?? 'package.json',
1489
+ ...(inlineLockfile === undefined ? {} : { lockfile: inlineLockfile }),
1490
+ ...(inlineLockfileType === undefined ? {} : { lockfileType: inlineLockfileType }),
1491
+ }],
1492
+ });
1493
+ }
1494
+ else {
1495
+ if (/^https?:\/\//i.test(targetsPath))
1496
+ throw new Error('observe URL must be an HTTPS GitHub repository URL');
1497
+ if (inlineOptionsUsed)
1498
+ throw new Error('--ecosystem, --id, --package, --package-path, --lockfile, --lockfile-type and --ref require a GitHub URL target');
1499
+ const targetText = await readBoundedFile(targetsPath, 256 * 1024);
1500
+ config = parseObserverConfigText(targetText);
1501
+ }
1444
1502
  const previousState = await loadObservationState(statePath);
1445
1503
  const source = new UpstreamObserverClient({
1446
1504
  ...(process.env.GITHUB_TOKEN === undefined ? {} : { githubToken: process.env.GITHUB_TOKEN }),