@disclosureos/cli 1.0.0 → 1.1.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/index.js +160 -11
  3. package/package.json +7 -6
package/CHANGELOG.md CHANGED
@@ -4,11 +4,49 @@ All notable changes to `@disclosureos/cli` are documented here. The format is ba
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to
5
5
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## 1.1.0
8
+
9
+ ### Minor Changes
10
+
11
+ - e6ff99c: Add the instruments layer: the UAP Sensor Manifest standard
12
+ (`@disclosureos/instruments@1.0.0`, first published alongside this release —
13
+ see its own changelog).
14
+
15
+ - **`@disclosureos/records`** — `SensorReading` gains optional `sensorRef`
16
+ (`"<org-slug>:<sensor-id>"`, with `sensorRef`/`isSensorRef`/`parseSensorRef`
17
+ helpers in `records/shared`); `SensorType` gains 18 instrument classes
18
+ (infrasonic/ultrasonic sensors, ADS-B receiver, RF spectrum analyzer, passive
19
+ radar, particle detector, atomic clock, GNSS receiver, fluxgate magnetometer,
20
+ air-quality sensor, barometer, lightning detector, IMU, EEG, GSR, pulse
21
+ oximeter, pupillometer, hardware RNG); `DetectionMethod` gains 7 methods
22
+ (particle, gnss, time_reference, chemical, inertial, physiological, pressure).
23
+ Records schema artifact bumped to `1.1.0`.
24
+ - **`@disclosureos/schema`** — composed enriched-observation artifact re-emitted
25
+ at `1.1.0` to carry the records changes.
26
+ - **`@disclosureos/cli`** — new `disclosureos manifest validate <path...>`
27
+ command (`--recursive`, `--json`) delegating to `validateSensorManifest`.
28
+
29
+ ### Patch Changes
30
+
31
+ - c351793: `disclosureos validate` now warns when a `SensorReading.sensorRef` does not
32
+ match the `"<org-slug>:<sensor-id>"` manifest convention — mirroring the
33
+ existing malformed/dangling warnings for claim `evidenceRefs`.
34
+ - Updated dependencies [b373962]
35
+ - Updated dependencies [e6ff99c]
36
+ - Updated dependencies [19bad3d]
37
+ - @disclosureos/instruments@1.0.0
38
+ - @disclosureos/records@1.1.0
39
+ - @disclosureos/schema@1.1.0
40
+ - @disclosureos/scoring@1.1.0
41
+ - @disclosureos/observables@1.0.1
42
+ - @disclosureos/origins@1.0.1
43
+
7
44
  ## 1.0.0
8
45
 
9
46
  Initial public release — developer tools for the DisclosureOS ecosystem.
10
47
 
11
48
  ### Added
49
+
12
50
  - `scaffold` — generate typed observation/data-structure templates.
13
51
  - `validate` — validate observation JSON files through `parseEnrichedObservation`;
14
52
  warns on dangling `evidenceRefs`.
package/dist/index.js CHANGED
@@ -395,7 +395,7 @@ Generate typed templates for DisclosureOS data structures.
395
395
  }
396
396
 
397
397
  // src/commands/validate.ts
398
- import { parseEvidenceRef } from "@disclosureos/records/shared";
398
+ import { parseEvidenceRef, isSensorRef } from "@disclosureos/records/shared";
399
399
  import { parseEnrichedObservation } from "@disclosureos/schema";
400
400
  function validate(args2) {
401
401
  if (args2.flags["help"]) {
@@ -503,7 +503,7 @@ function validateFileStructured(filePath, strict) {
503
503
  const obs = data;
504
504
  const structuralErrors = parseEnrichedObservation(obs).issues;
505
505
  const semanticErrors = validateSemantics(obs);
506
- const warnings = [...validateEvidenceRefs(obs), ...strict ? validateStrict(obs) : []];
506
+ const warnings = [...validateEvidenceRefs(obs), ...validateSensorRefs(obs), ...strict ? validateStrict(obs) : []];
507
507
  const allErrors = [...structuralErrors, ...semanticErrors];
508
508
  return {
509
509
  file: filePath,
@@ -527,7 +527,7 @@ function validateFile(filePath, strict) {
527
527
  const obs = data;
528
528
  const structuralErrors = parseEnrichedObservation(obs).issues;
529
529
  const semanticErrors = validateSemantics(obs);
530
- const warnings = [...validateEvidenceRefs(obs), ...strict ? validateStrict(obs) : []];
530
+ const warnings = [...validateEvidenceRefs(obs), ...validateSensorRefs(obs), ...strict ? validateStrict(obs) : []];
531
531
  const allErrors = [...structuralErrors, ...semanticErrors];
532
532
  if (allErrors.length > 0 || warnings.length > 0) {
533
533
  console.log(`
@@ -628,6 +628,25 @@ function validateEvidenceRefs(obs) {
628
628
  }
629
629
  return warnings;
630
630
  }
631
+ function validateSensorRefs(obs) {
632
+ const warnings = [];
633
+ const sensorEvidence = obs["sensorEvidence"];
634
+ if (!sensorEvidence || typeof sensorEvidence !== "object") return warnings;
635
+ const sensors = sensorEvidence["sensors"];
636
+ if (!Array.isArray(sensors)) return warnings;
637
+ sensors.forEach((sensor, i) => {
638
+ if (!sensor || typeof sensor !== "object") return;
639
+ const ref = sensor["sensorRef"];
640
+ if (ref === void 0) return;
641
+ if (typeof ref !== "string" || !isSensorRef(ref)) {
642
+ warnings.push({
643
+ path: `sensorEvidence.sensors[${i}].sensorRef`,
644
+ message: `malformed sensor ref ${JSON.stringify(ref)} (expected "<org-slug>:<sensor-id>", e.g. "eldaeon:dionysus-passive-radar")`
645
+ });
646
+ }
647
+ });
648
+ return warnings;
649
+ }
631
650
  function validateStrict(obs) {
632
651
  const warnings = [];
633
652
  const recommended = ["summary", "description", "objectCharacteristics", "sourceData", "witnesses"];
@@ -679,6 +698,7 @@ Validate observation JSON files against the full schema.
679
698
  console.log(` \u2022 OCS node IDs in origin classifications (if present)`);
680
699
  console.log(` \u2022 Unknown top-level keys rejected (third-party data belongs under "extensions")`);
681
700
  console.log(` \u2022 Evidence refs on claims resolve to in-record evidence (warns on dangling)`);
701
+ console.log(` \u2022 Sensor refs follow the "<org-slug>:<sensor-id>" manifest convention (warns on malformed)`);
682
702
  console.log(` \u2022 Semantic sanity (non-negative duration, speed, counts)
683
703
  `);
684
704
  console.log(`${dim("Examples:")}`);
@@ -690,17 +710,142 @@ Validate observation JSON files against the full schema.
690
710
  `);
691
711
  }
692
712
 
713
+ // src/commands/manifest.ts
714
+ import { validateSensorManifest } from "@disclosureos/instruments";
715
+ function manifest(args2) {
716
+ if (args2.flags["help"] || args2.subcommand !== "validate") {
717
+ printUsage3();
718
+ if (!args2.flags["help"] && args2.subcommand !== void 0 && args2.subcommand !== "validate") {
719
+ process.exit(1);
720
+ }
721
+ return;
722
+ }
723
+ const targets = args2.positional.filter((t) => !!t);
724
+ if (targets.length === 0) {
725
+ printUsage3();
726
+ return;
727
+ }
728
+ const recursive = !!args2.flags["recursive"];
729
+ const jsonMode = !!args2.flags["json"];
730
+ const files = [...new Set(targets.flatMap((target) => findJSONFiles(target, recursive)))];
731
+ if (files.length === 0) {
732
+ console.log(error(`No JSON files found at: ${targets.join(", ")}`));
733
+ process.exit(1);
734
+ }
735
+ const results = files.map(validateManifestFile);
736
+ if (jsonMode) {
737
+ const valid = results.every((result) => result.valid);
738
+ console.log(JSON.stringify({ files: results, valid }, null, 2));
739
+ if (!valid) process.exit(1);
740
+ return;
741
+ }
742
+ let failed = false;
743
+ for (const result of results) {
744
+ if (!result.valid) {
745
+ failed = true;
746
+ console.log(`
747
+ ${error(`${result.file} INVALID`)}`);
748
+ for (const issue of result.errors) {
749
+ console.log(` ${error(`${issue.path}: ${issue.message}`)}`);
750
+ }
751
+ continue;
752
+ }
753
+ const summary = result.summary;
754
+ console.log(`
755
+ ${success(`${result.file}`)}`);
756
+ console.log(` ${dim(formatManifestLine(summary))}`);
757
+ console.log(` ${dim("by modality:")} ${Object.entries(summary.byModality).map(([m, n]) => `${m} ${n}`).join(", ")}`);
758
+ if (summary.proposedSensorTypes.length > 0) {
759
+ console.log(` ${dim(`proposed sensor types (${summary.proposedSensorTypes.length}):`)} ${summary.proposedSensorTypes.join(", ")}`);
760
+ }
761
+ if (summary.proposedDetectionMethods.length > 0) {
762
+ console.log(` ${dim(`proposed detection methods (${summary.proposedDetectionMethods.length}):`)} ${summary.proposedDetectionMethods.join(", ")}`);
763
+ }
764
+ }
765
+ console.log("");
766
+ if (failed) {
767
+ console.log(error(`Validation failed`));
768
+ process.exit(1);
769
+ }
770
+ console.log(success(`All ${files.length} manifest(s) valid`));
771
+ }
772
+ function formatManifestLine(summary) {
773
+ return `${summary.org} (${summary.orgSlug}) \u2014 ${summary.sensors} sensors, ${summary.futureUpgrades} future upgrades`;
774
+ }
775
+ function validateManifestFile(file) {
776
+ let data;
777
+ try {
778
+ data = readJSON(file);
779
+ } catch {
780
+ return { file, valid: false, errors: [{ path: "", message: "Failed to parse JSON" }] };
781
+ }
782
+ const issues = validateSensorManifest(data);
783
+ if (issues.length > 0) {
784
+ return { file, valid: false, errors: issues };
785
+ }
786
+ const parsed = data;
787
+ const byModality = {};
788
+ const proposedSensorTypes = [];
789
+ const proposedDetectionMethods = [];
790
+ for (const sensor of parsed.sensors) {
791
+ byModality[sensor.modality] = (byModality[sensor.modality] ?? 0) + 1;
792
+ if (sensor.recordsMapping?.proposedSensorType && sensor.recordsMapping.sensorType) {
793
+ proposedSensorTypes.push(sensor.recordsMapping.sensorType);
794
+ }
795
+ if (sensor.recordsMapping?.proposedDetectionMethod && sensor.recordsMapping.detectionMethod) {
796
+ proposedDetectionMethods.push(sensor.recordsMapping.detectionMethod);
797
+ }
798
+ }
799
+ return {
800
+ file,
801
+ valid: true,
802
+ errors: [],
803
+ summary: {
804
+ org: parsed.org,
805
+ orgSlug: parsed.orgSlug,
806
+ sensors: parsed.sensors.length,
807
+ byModality,
808
+ proposedSensorTypes,
809
+ proposedDetectionMethods,
810
+ futureUpgrades: parsed.futureUpgrades?.length ?? 0
811
+ }
812
+ };
813
+ }
814
+ function printUsage3() {
815
+ console.log(heading(`${BRAND} manifest`));
816
+ console.log(`
817
+ Validate sensor-manifest JSON files (@disclosureos/instruments).
818
+ `);
819
+ console.log(`${dim("Usage:")}`);
820
+ console.log(` disclosureos manifest validate <path...> [options]
821
+ `);
822
+ console.log(`${dim("Options:")}`);
823
+ console.log(` --recursive, -r Validate all JSON files in directories recursively`);
824
+ console.log(` --json, -j Output results as structured JSON (for CI and scripts)`);
825
+ console.log(` --help, -h Show this help message
826
+ `);
827
+ console.log(`${dim("Validation checks:")}`);
828
+ console.log(` \u2022 Manifest structure (org, orgSlug, sensors, calibration, timing, measurements)`);
829
+ console.log(` \u2022 Sensor ids unique and kebab-case`);
830
+ console.log(` \u2022 recordsMapping values exist in the records enums or carry proposed* flags
831
+ `);
832
+ console.log(`${dim("Examples:")}`);
833
+ console.log(` disclosureos manifest validate ./manifests/eldaeon-sensors.json`);
834
+ console.log(` disclosureos manifest validate ./manifests/ --recursive --json
835
+ `);
836
+ }
837
+
693
838
  // src/commands/completeness.ts
694
839
  import { parseEnrichedObservation as parseEnrichedObservation2 } from "@disclosureos/schema";
695
840
  import { getCompleteness } from "@disclosureos/scoring";
696
841
  function completeness(args2) {
697
842
  if (args2.flags["help"]) {
698
- printUsage3();
843
+ printUsage4();
699
844
  return;
700
845
  }
701
846
  const targets = [args2.subcommand, ...args2.positional].filter((t) => !!t);
702
847
  if (targets.length === 0) {
703
- printUsage3();
848
+ printUsage4();
704
849
  return;
705
850
  }
706
851
  const recursive = !!args2.flags["recursive"];
@@ -866,7 +1011,7 @@ function scoreFileQuiet(filePath) {
866
1011
  missing: comp.missing
867
1012
  };
868
1013
  }
869
- function printUsage3() {
1014
+ function printUsage4() {
870
1015
  console.log(heading(`${BRAND} completeness`));
871
1016
  console.log(`
872
1017
  Measure how fully observation JSON files populate the records schema.
@@ -916,7 +1061,7 @@ import {
916
1061
  } from "@disclosureos/origins";
917
1062
  function registry(args2) {
918
1063
  if (args2.flags["help"]) {
919
- printUsage4();
1064
+ printUsage5();
920
1065
  return;
921
1066
  }
922
1067
  const sub = args2.subcommand;
@@ -931,7 +1076,7 @@ function registry(args2) {
931
1076
  registryOrigins(args2);
932
1077
  break;
933
1078
  default:
934
- printUsage4();
1079
+ printUsage5();
935
1080
  }
936
1081
  }
937
1082
  function registryFields(args2) {
@@ -1070,7 +1215,7 @@ ${label("ID", node.id)}`);
1070
1215
  }
1071
1216
  console.log("");
1072
1217
  }
1073
- function printUsage4() {
1218
+ function printUsage5() {
1074
1219
  console.log(heading(`${BRAND} registry`));
1075
1220
  console.log(`
1076
1221
  Introspect DisclosureOS field, observable, and origin registries.
@@ -1110,7 +1255,7 @@ import {
1110
1255
  var FIELD_PATH_COUNT = deriveFieldPaths2().length;
1111
1256
  function info(args2) {
1112
1257
  if (args2.flags["help"]) {
1113
- printUsage5();
1258
+ printUsage6();
1114
1259
  return;
1115
1260
  }
1116
1261
  const sub = args2.subcommand;
@@ -1257,7 +1402,7 @@ ${label("ID", node.id)}`);
1257
1402
  }
1258
1403
  console.log("");
1259
1404
  }
1260
- function printUsage5() {
1405
+ function printUsage6() {
1261
1406
  console.log(heading(`${BRAND} info`));
1262
1407
  console.log(`
1263
1408
  Quick reference for DisclosureOS types and definitions.
@@ -1291,6 +1436,9 @@ if (args.flags["version"]) {
1291
1436
  case "validate":
1292
1437
  validate(args);
1293
1438
  break;
1439
+ case "manifest":
1440
+ manifest(args);
1441
+ break;
1294
1442
  case "completeness":
1295
1443
  completeness(args);
1296
1444
  break;
@@ -1322,6 +1470,7 @@ function printHelp() {
1322
1470
  console.log(`${dim("Commands:")}`);
1323
1471
  console.log(` scaffold Generate typed data structure templates`);
1324
1472
  console.log(` validate Validate observation JSON files`);
1473
+ console.log(` manifest Validate sensor-manifest JSON files`);
1325
1474
  console.log(` completeness Measure how fully observations populate the schema`);
1326
1475
  console.log(` registry Introspect field, observable, and origin registries`);
1327
1476
  console.log(` info Quick reference for types and definitions`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@disclosureos/cli",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Developer tools for the DisclosureOS ecosystem — scaffold, validate, and inspect observations",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -42,11 +42,12 @@
42
42
  ],
43
43
  "dependencies": {
44
44
  "picocolors": "^1.1.1",
45
- "@disclosureos/records": "1.0.0",
46
- "@disclosureos/observables": "1.0.0",
47
- "@disclosureos/origins": "1.0.0",
48
- "@disclosureos/schema": "1.0.0",
49
- "@disclosureos/scoring": "1.0.0"
45
+ "@disclosureos/records": "1.1.0",
46
+ "@disclosureos/instruments": "1.0.0",
47
+ "@disclosureos/observables": "1.0.1",
48
+ "@disclosureos/scoring": "1.1.0",
49
+ "@disclosureos/origins": "1.0.1",
50
+ "@disclosureos/schema": "1.1.0"
50
51
  },
51
52
  "devDependencies": {
52
53
  "@types/node": "^20",