@letterblack/lbe-core 1.3.3 → 1.3.5

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.
@@ -0,0 +1,110 @@
1
+ # LBE Release Workspace Rules
2
+
3
+ This file defines what can and cannot be used as LBE release proof.
4
+
5
+ ## Release authority boundary
6
+
7
+ Only the designated LBE release workspace may certify LBE release safety.
8
+
9
+ A downstream project, integration lab, copied repository, downloaded folder, worktree, or consumer app is not release authority for LBE.
10
+
11
+ Consumer projects may prove only their own integration behavior with the installed LBE package.
12
+
13
+ They must not claim:
14
+
15
+ - LBE release-ready
16
+ - LBE published
17
+ - full LBE proof passed
18
+ - npm/GitHub release alignment
19
+ - package release correctness
20
+
21
+ ## Consumer dependency rule
22
+
23
+ Other projects must consume LBE as an installed package dependency from the public registry.
24
+
25
+ Allowed consumer model:
26
+
27
+ ```bash
28
+ npm install @letterblack/lbe-core
29
+ npx lbe init
30
+ npx lbe status
31
+ npx lbe proof --public
32
+ ```
33
+
34
+ Do not use a copied LBE source tree as the authority for consumer projects.
35
+
36
+ Do not point consumer projects at LBE through:
37
+
38
+ - `file:`
39
+ - `link:`
40
+ - `workspace:`
41
+ - `git+`
42
+ - `github:`
43
+ - local relative paths
44
+ - local absolute paths
45
+ - symlinked `node_modules` packages
46
+
47
+ ## assert-consumer rule
48
+
49
+ `npx lbe assert-consumer` is a downstream consumer-safety guard.
50
+
51
+ It answers:
52
+
53
+ - Is this project using `@letterblack/lbe-core` as an installed dependency?
54
+ - Is this project accidentally pointing at a copied source tree, workspace link, git dependency, local path, or symlink?
55
+
56
+ It must always report consumer status only.
57
+
58
+ It is not release proof.
59
+
60
+ It is not package provenance proof.
61
+
62
+ It is not a substitute for:
63
+
64
+ - full test suite
65
+ - `npm run proof`
66
+ - package runtime verification
67
+ - packed tarball inspection
68
+ - npm `gitHead` check
69
+ - GitHub tag alignment
70
+ - GitHub Release verification
71
+ - fresh install smoke from the registry
72
+
73
+ Expected classification for a valid consumer project:
74
+
75
+ ```txt
76
+ consumer-project-using-installed-registry-dependency
77
+ releaseClaimsAllowed: false
78
+ ```
79
+
80
+ If a project passes `assert-consumer`, the only valid conclusion is:
81
+
82
+ ```txt
83
+ This project consumes LBE from an installed package dependency.
84
+ This does not certify LBE release safety.
85
+ ```
86
+
87
+ ## Hard stop conditions
88
+
89
+ Stop and report if:
90
+
91
+ - a consumer project is used to certify an LBE release
92
+ - focused integration tests are used as release proof
93
+ - a copied/lab workspace is treated as package authority
94
+ - local path, git, workspace, or symlink dependencies are used for LBE in a consumer project
95
+ - release claims are made without npm/GitHub/package provenance checks
96
+
97
+ ## Agent report format
98
+
99
+ Before making any LBE-related release claim, report:
100
+
101
+ ```txt
102
+ Workspace classification:
103
+ - Path:
104
+ - Type: LBE release workspace / consumer project / local lab / copied workspace / unknown
105
+ - npm run proof available: yes/no
106
+ - full suite exit code:
107
+ - release claims allowed: yes/no
108
+ ```
109
+
110
+ If the workspace is a consumer project, local lab, copied workspace, or unknown, release claims are not allowed.
package/dist/cli/lbe.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli/main.js
4
- import fs29 from "fs";
5
- import path35 from "path";
4
+ import fs30 from "fs";
5
+ import path36 from "path";
6
6
  import { fileURLToPath as fileURLToPath3 } from "url";
7
7
 
8
8
  // src/cli/parseArgs.js
@@ -67,6 +67,7 @@ COMMANDS:
67
67
  logs Print recent entries from central event log
68
68
  open-state Open the central state directory in the file manager
69
69
  proof Show latest proof result (--json for raw JSON, --public for redacted)
70
+ assert-consumer Verify this project consumes LBE as an installed registry dependency
70
71
  help Show this help message
71
72
 
72
73
  OPTIONS:
@@ -4143,6 +4144,160 @@ LBE Proof \u2014 ${workspace}`);
4143
4144
  return { found: true, result: proof.result, profile: proof.profile };
4144
4145
  }
4145
4146
 
4147
+ // src/cli/commands/assertConsumer.js
4148
+ import fs29 from "fs";
4149
+ import path35 from "path";
4150
+ import { createRequire } from "module";
4151
+ var PACKAGE_NAME = "@letterblack/lbe-core";
4152
+ var DEP_SECTIONS = [
4153
+ "dependencies",
4154
+ "devDependencies",
4155
+ "optionalDependencies",
4156
+ "peerDependencies"
4157
+ ];
4158
+ function readJson(filePath) {
4159
+ try {
4160
+ return JSON.parse(fs29.readFileSync(filePath, "utf-8"));
4161
+ } catch {
4162
+ return null;
4163
+ }
4164
+ }
4165
+ function addCheck2(checks, name, ok, details = {}) {
4166
+ checks.push({ name, ok, ...details });
4167
+ return ok;
4168
+ }
4169
+ function findDependencySpec(packageJson2) {
4170
+ if (!packageJson2 || typeof packageJson2 !== "object") return null;
4171
+ for (const section of DEP_SECTIONS) {
4172
+ const value = packageJson2[section]?.[PACKAGE_NAME];
4173
+ if (value !== void 0) {
4174
+ return { section, spec: String(value) };
4175
+ }
4176
+ }
4177
+ return null;
4178
+ }
4179
+ function classifyDependencySpec(spec) {
4180
+ const raw = String(spec || "").trim();
4181
+ const lower = raw.toLowerCase();
4182
+ if (!raw) {
4183
+ return { ok: false, reason: "EMPTY_DEPENDENCY_SPEC" };
4184
+ }
4185
+ const blockedPrefixes = [
4186
+ "file:",
4187
+ "link:",
4188
+ "workspace:",
4189
+ "git+",
4190
+ "github:",
4191
+ "git://",
4192
+ "ssh://"
4193
+ ];
4194
+ for (const prefix of blockedPrefixes) {
4195
+ if (lower.startsWith(prefix)) {
4196
+ return { ok: false, reason: "LOCAL_OR_GIT_DEPENDENCY_SPEC", prefix };
4197
+ }
4198
+ }
4199
+ if (/^[a-z]:[\\/]/i.test(raw) || raw.startsWith("./") || raw.startsWith("../")) {
4200
+ return { ok: false, reason: "PATH_DEPENDENCY_SPEC" };
4201
+ }
4202
+ return { ok: true };
4203
+ }
4204
+ function findPackageRoot(startFile) {
4205
+ let dir = fs29.statSync(startFile).isDirectory() ? startFile : path35.dirname(startFile);
4206
+ while (true) {
4207
+ const candidate = path35.join(dir, "package.json");
4208
+ const pkg = readJson(candidate);
4209
+ if (pkg?.name === PACKAGE_NAME) return dir;
4210
+ const parent = path35.dirname(dir);
4211
+ if (parent === dir) return null;
4212
+ dir = parent;
4213
+ }
4214
+ }
4215
+ function inspectPackageLock(root) {
4216
+ const lockPath = path35.join(root, "package-lock.json");
4217
+ const lock = readJson(lockPath);
4218
+ if (!lock) return { present: false };
4219
+ const packageEntry = lock.packages?.[`node_modules/${PACKAGE_NAME}`];
4220
+ if (!packageEntry) return { present: true, packageEntryPresent: false };
4221
+ const resolved = String(packageEntry.resolved || "");
4222
+ const blockedResolved = packageEntry.link === true || resolved.startsWith("file:") || resolved.startsWith("git+") || resolved.startsWith("github:") || resolved.startsWith("ssh://") || /^[a-z]:[\\/]/i.test(resolved);
4223
+ return {
4224
+ present: true,
4225
+ packageEntryPresent: true,
4226
+ link: packageEntry.link === true,
4227
+ resolved: resolved || null,
4228
+ blockedResolved
4229
+ };
4230
+ }
4231
+ function getInstalledPackagePath(root) {
4232
+ return path35.join(root, "node_modules", ...PACKAGE_NAME.split("/"));
4233
+ }
4234
+ async function assertConsumerCommand(opts = {}) {
4235
+ const root = path35.resolve(opts.root || process.cwd());
4236
+ const packageJsonPath2 = path35.join(root, "package.json");
4237
+ const packageJson2 = readJson(packageJsonPath2);
4238
+ const checks = [];
4239
+ addCheck2(checks, "project-package-json-present", Boolean(packageJson2), { path: packageJsonPath2 });
4240
+ const dependency = findDependencySpec(packageJson2);
4241
+ addCheck2(checks, "declares-lbe-package-dependency", Boolean(dependency), dependency || {});
4242
+ const specCheck = dependency ? classifyDependencySpec(dependency.spec) : { ok: false, reason: "DEPENDENCY_NOT_DECLARED" };
4243
+ addCheck2(checks, "dependency-spec-is-registry-package", specCheck.ok, {
4244
+ spec: dependency?.spec || null,
4245
+ reason: specCheck.reason || null,
4246
+ blockedPrefix: specCheck.prefix || null
4247
+ });
4248
+ let resolvedEntry = null;
4249
+ let resolvedRoot = null;
4250
+ try {
4251
+ const req = createRequire(path35.join(root, "package.json"));
4252
+ resolvedEntry = req.resolve(PACKAGE_NAME);
4253
+ resolvedRoot = findPackageRoot(resolvedEntry);
4254
+ } catch (error) {
4255
+ addCheck2(checks, "lbe-package-resolves-from-project", false, { message: error.message });
4256
+ }
4257
+ if (resolvedEntry) {
4258
+ addCheck2(checks, "lbe-package-resolves-from-project", true, { resolvedEntry });
4259
+ }
4260
+ if (resolvedRoot) {
4261
+ const stat = fs29.lstatSync(resolvedRoot);
4262
+ addCheck2(checks, "lbe-package-is-not-symlink", !stat.isSymbolicLink(), { resolvedRoot });
4263
+ } else {
4264
+ addCheck2(checks, "lbe-package-is-not-symlink", false, { reason: "PACKAGE_ROOT_NOT_FOUND" });
4265
+ }
4266
+ const installedPackagePath = getInstalledPackagePath(root);
4267
+ if (fs29.existsSync(installedPackagePath)) {
4268
+ const installedStat = fs29.lstatSync(installedPackagePath);
4269
+ addCheck2(checks, "installed-node_modules-package-is-not-symlink", !installedStat.isSymbolicLink(), {
4270
+ installedPackagePath
4271
+ });
4272
+ } else {
4273
+ addCheck2(checks, "installed-node_modules-package-is-not-symlink", false, {
4274
+ installedPackagePath,
4275
+ reason: "PACKAGE_NOT_INSTALLED_LOCALLY"
4276
+ });
4277
+ }
4278
+ const lockInfo = inspectPackageLock(root);
4279
+ if (lockInfo.present && lockInfo.packageEntryPresent) {
4280
+ addCheck2(checks, "package-lock-does-not-link-local-lbe", !lockInfo.blockedResolved, lockInfo);
4281
+ } else {
4282
+ addCheck2(checks, "package-lock-does-not-link-local-lbe", true, lockInfo);
4283
+ }
4284
+ const ok = checks.every((check) => check.ok);
4285
+ const result = {
4286
+ ok,
4287
+ command: "assert-consumer",
4288
+ package: PACKAGE_NAME,
4289
+ root,
4290
+ classification: ok ? "consumer-project-using-installed-registry-dependency" : "not-proven-consumer-installed-dependency",
4291
+ releaseClaimsAllowed: false,
4292
+ message: ok ? "This project consumes LBE as an installed package dependency. This does not certify LBE release safety." : "This project is not proven to consume LBE only as an installed registry dependency.",
4293
+ checks
4294
+ };
4295
+ console.log(JSON.stringify(result, null, 2));
4296
+ if (!ok) {
4297
+ process.exitCode = 7;
4298
+ }
4299
+ }
4300
+
4146
4301
  // src/cli/main.js
4147
4302
  function toBoolean4(value, defaultValue = false) {
4148
4303
  if (value === void 0) return defaultValue;
@@ -4152,9 +4307,9 @@ function toBoolean4(value, defaultValue = false) {
4152
4307
  if (normalized === "false" || normalized === "0" || normalized === "no") return false;
4153
4308
  return defaultValue;
4154
4309
  }
4155
- var __dirname2 = path35.dirname(fileURLToPath3(import.meta.url));
4156
- var packageJsonPath = path35.join(__dirname2, "../../package.json");
4157
- var packageJson = JSON.parse(fs29.readFileSync(packageJsonPath, "utf-8"));
4310
+ var __dirname2 = path36.dirname(fileURLToPath3(import.meta.url));
4311
+ var packageJsonPath = path36.join(__dirname2, "../../package.json");
4312
+ var packageJson = JSON.parse(fs30.readFileSync(packageJsonPath, "utf-8"));
4158
4313
  async function main() {
4159
4314
  const argv = process.argv.slice(2);
4160
4315
  if (argv.includes("--version")) {
@@ -4177,7 +4332,7 @@ async function main() {
4177
4332
  try {
4178
4333
  if (opts["pub-key-file"]) {
4179
4334
  try {
4180
- opts["pub-key"] = fs29.readFileSync(path35.resolve(opts["pub-key-file"]), "utf-8").trim();
4335
+ opts["pub-key"] = fs30.readFileSync(path36.resolve(opts["pub-key-file"]), "utf-8").trim();
4181
4336
  } catch (error) {
4182
4337
  console.error(`Error reading public key file: ${error.message}`);
4183
4338
  process.exit(1);
@@ -4185,7 +4340,7 @@ async function main() {
4185
4340
  }
4186
4341
  if (["verify", "dryrun", "run"].includes(command)) {
4187
4342
  const integrityStrict = toBoolean4(opts["integrity-strict"], false);
4188
- const integrityManifestPath = path35.resolve(opts["integrity-manifest"] || ".lbe/config/integrity.manifest.json");
4343
+ const integrityManifestPath = path36.resolve(opts["integrity-manifest"] || ".lbe/config/integrity.manifest.json");
4189
4344
  const integrityResult = await performIntegrityCheck({
4190
4345
  strict: integrityStrict,
4191
4346
  manifestPath: integrityManifestPath
@@ -4246,6 +4401,9 @@ async function main() {
4246
4401
  case "proof":
4247
4402
  await proofCommand(opts);
4248
4403
  break;
4404
+ case "assert-consumer":
4405
+ await assertConsumerCommand(opts);
4406
+ break;
4249
4407
  default:
4250
4408
  console.error(`Unknown command: ${command}`);
4251
4409
  printHelp(packageJson.version);
Binary file
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
- "name": "@letterblack/lbe-core",
3
- "version": "1.3.3",
2
+ "name": "@letterblack/lbe-core",
3
+ "version": "1.3.5",
4
4
  "description": "Local-first execution governance SDK for AI agents. Agents propose → Controller validates → Adapters execute.",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "types": "types.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./types.d.ts",
11
- "default": "./index.js"
12
- },
13
- "./engine": "./runtime/engine.js",
14
- "./adapters": "./src/adapters/index.js",
15
- "./exec": "./exec/index.js",
16
- "./hooks/register.cjs": "./dist/hooks/register.cjs"
17
- },
8
+ "exports": {
9
+ ".": {
10
+ "types": "./types.d.ts",
11
+ "default": "./index.js"
12
+ },
13
+ "./engine": "./runtime/engine.js",
14
+ "./adapters": "./src/adapters/index.js",
15
+ "./exec": "./exec/index.js",
16
+ "./hooks/register.cjs": "./dist/hooks/register.cjs"
17
+ },
18
18
  "bin": {
19
19
  "lbe": "bin/lbe.js"
20
20
  },
@@ -29,24 +29,25 @@
29
29
  "health": "node bin/lbe.js health --json true",
30
30
  "integrity:generate": "node bin/lbe.js integrity-generate",
31
31
  "integrity:check": "node bin/lbe.js integrity-check",
32
- "build:engine": "node scripts/build-engine.js",
33
- "build:public-sdk": "node scripts/build-public-sdk.mjs",
34
- "build:public-exec": "node scripts/build-public-exec.mjs",
35
- "build:package-runtime": "node scripts/build-package-runtime.mjs",
36
- "proof": "node _proof.mjs",
37
- "audit:public-docs": "node scripts/audit-public-docs.mjs",
38
- "verify:package-runtime": "node scripts/verify-package-runtime.mjs",
39
- "verify:public-exec": "npm run proof && npm run build:public-exec && node scripts/check-public-exec.mjs && cd release-exec && npm pack --dry-run",
40
- "verify:public-sdk": "npm run build:public-sdk && node scripts/check-public-artifact.mjs && cd release-public && npm pack --dry-run",
41
- "engine:check": "node scripts/check-engine.js",
42
- "pack:check": "npm pack --dry-run",
43
- "audit:verify": "node bin/lbe.js audit-verify",
44
- "guard:mainhead": "node scripts/mainhead-guard.mjs",
45
- "hooks:install": "node scripts/install-git-hooks.mjs",
46
- "prepack": "npm run build:package-runtime",
47
- "validate:all": "npm run guard:mainhead && npm run engine:check && npm run lint && npm run test",
48
- "publish:release": "node scripts/publish.mjs"
49
- },
32
+ "build:engine": "node scripts/build-engine.js",
33
+ "build:public-sdk": "node scripts/build-public-sdk.mjs",
34
+ "build:public-exec": "node scripts/build-public-exec.mjs",
35
+ "build:package-runtime": "node scripts/build-package-runtime.mjs",
36
+ "proof": "node _proof.mjs",
37
+ "audit:public-docs": "node scripts/audit-public-docs.mjs",
38
+ "verify:package-runtime": "node scripts/verify-package-runtime.mjs",
39
+ "assert-consumer": "node bin/lbe.js assert-consumer",
40
+ "verify:public-exec": "npm run proof && npm run build:public-exec && node scripts/check-public-exec.mjs && cd release-exec && npm pack --dry-run",
41
+ "verify:public-sdk": "npm run build:public-sdk && node scripts/check-public-artifact.mjs && cd release-public && npm pack --dry-run",
42
+ "engine:check": "node scripts/check-engine.js",
43
+ "pack:check": "npm pack --dry-run",
44
+ "audit:verify": "node bin/lbe.js audit-verify",
45
+ "guard:mainhead": "node scripts/mainhead-guard.mjs",
46
+ "hooks:install": "node scripts/install-git-hooks.mjs",
47
+ "prepack": "npm run build:package-runtime",
48
+ "validate:all": "npm run guard:mainhead && npm run engine:check && npm run lint && npm run test",
49
+ "publish:release": "node scripts/publish.mjs"
50
+ },
50
51
  "keywords": [
51
52
  "ai-governance",
52
53
  "execution-governance",
@@ -0,0 +1,198 @@
1
+ // src/cli/commands/assertConsumer.js
2
+ // Guard that proves a consuming project is using LBE as an installed package,
3
+ // not treating a copied/source repository as release authority.
4
+
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import { createRequire } from 'module';
8
+
9
+ const PACKAGE_NAME = '@letterblack/lbe-core';
10
+ const DEP_SECTIONS = [
11
+ 'dependencies',
12
+ 'devDependencies',
13
+ 'optionalDependencies',
14
+ 'peerDependencies'
15
+ ];
16
+
17
+ function readJson(filePath) {
18
+ try {
19
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+
25
+ function addCheck(checks, name, ok, details = {}) {
26
+ checks.push({ name, ok, ...details });
27
+ return ok;
28
+ }
29
+
30
+ function findDependencySpec(packageJson) {
31
+ if (!packageJson || typeof packageJson !== 'object') return null;
32
+
33
+ for (const section of DEP_SECTIONS) {
34
+ const value = packageJson[section]?.[PACKAGE_NAME];
35
+ if (value !== undefined) {
36
+ return { section, spec: String(value) };
37
+ }
38
+ }
39
+
40
+ return null;
41
+ }
42
+
43
+ function classifyDependencySpec(spec) {
44
+ const raw = String(spec || '').trim();
45
+ const lower = raw.toLowerCase();
46
+
47
+ if (!raw) {
48
+ return { ok: false, reason: 'EMPTY_DEPENDENCY_SPEC' };
49
+ }
50
+
51
+ const blockedPrefixes = [
52
+ 'file:',
53
+ 'link:',
54
+ 'workspace:',
55
+ 'git+',
56
+ 'github:',
57
+ 'git://',
58
+ 'ssh://'
59
+ ];
60
+
61
+ for (const prefix of blockedPrefixes) {
62
+ if (lower.startsWith(prefix)) {
63
+ return { ok: false, reason: 'LOCAL_OR_GIT_DEPENDENCY_SPEC', prefix };
64
+ }
65
+ }
66
+
67
+ if (/^[a-z]:[\\/]/i.test(raw) || raw.startsWith('./') || raw.startsWith('../')) {
68
+ return { ok: false, reason: 'PATH_DEPENDENCY_SPEC' };
69
+ }
70
+
71
+ return { ok: true };
72
+ }
73
+
74
+ function findPackageRoot(startFile) {
75
+ let dir = fs.statSync(startFile).isDirectory() ? startFile : path.dirname(startFile);
76
+
77
+ while (true) {
78
+ const candidate = path.join(dir, 'package.json');
79
+ const pkg = readJson(candidate);
80
+ if (pkg?.name === PACKAGE_NAME) return dir;
81
+
82
+ const parent = path.dirname(dir);
83
+ if (parent === dir) return null;
84
+ dir = parent;
85
+ }
86
+ }
87
+
88
+ function inspectPackageLock(root) {
89
+ const lockPath = path.join(root, 'package-lock.json');
90
+ const lock = readJson(lockPath);
91
+ if (!lock) return { present: false };
92
+
93
+ const packageEntry = lock.packages?.[`node_modules/${PACKAGE_NAME}`];
94
+ if (!packageEntry) return { present: true, packageEntryPresent: false };
95
+
96
+ const resolved = String(packageEntry.resolved || '');
97
+ const blockedResolved =
98
+ packageEntry.link === true ||
99
+ resolved.startsWith('file:') ||
100
+ resolved.startsWith('git+') ||
101
+ resolved.startsWith('github:') ||
102
+ resolved.startsWith('ssh://') ||
103
+ /^[a-z]:[\\/]/i.test(resolved);
104
+
105
+ return {
106
+ present: true,
107
+ packageEntryPresent: true,
108
+ link: packageEntry.link === true,
109
+ resolved: resolved || null,
110
+ blockedResolved
111
+ };
112
+ }
113
+
114
+ function getInstalledPackagePath(root) {
115
+ return path.join(root, 'node_modules', ...PACKAGE_NAME.split('/'));
116
+ }
117
+
118
+ export async function assertConsumerCommand(opts = {}) {
119
+ const root = path.resolve(opts.root || process.cwd());
120
+ const packageJsonPath = path.join(root, 'package.json');
121
+ const packageJson = readJson(packageJsonPath);
122
+ const checks = [];
123
+
124
+ addCheck(checks, 'project-package-json-present', Boolean(packageJson), { path: packageJsonPath });
125
+
126
+ const dependency = findDependencySpec(packageJson);
127
+ addCheck(checks, 'declares-lbe-package-dependency', Boolean(dependency), dependency || {});
128
+
129
+ const specCheck = dependency ? classifyDependencySpec(dependency.spec) : { ok: false, reason: 'DEPENDENCY_NOT_DECLARED' };
130
+ addCheck(checks, 'dependency-spec-is-registry-package', specCheck.ok, {
131
+ spec: dependency?.spec || null,
132
+ reason: specCheck.reason || null,
133
+ blockedPrefix: specCheck.prefix || null
134
+ });
135
+
136
+ let resolvedEntry = null;
137
+ let resolvedRoot = null;
138
+ try {
139
+ const req = createRequire(path.join(root, 'package.json'));
140
+ resolvedEntry = req.resolve(PACKAGE_NAME);
141
+ resolvedRoot = findPackageRoot(resolvedEntry);
142
+ } catch (error) {
143
+ addCheck(checks, 'lbe-package-resolves-from-project', false, { message: error.message });
144
+ }
145
+
146
+ if (resolvedEntry) {
147
+ addCheck(checks, 'lbe-package-resolves-from-project', true, { resolvedEntry });
148
+ }
149
+
150
+ if (resolvedRoot) {
151
+ const stat = fs.lstatSync(resolvedRoot);
152
+ addCheck(checks, 'lbe-package-is-not-symlink', !stat.isSymbolicLink(), { resolvedRoot });
153
+ } else {
154
+ addCheck(checks, 'lbe-package-is-not-symlink', false, { reason: 'PACKAGE_ROOT_NOT_FOUND' });
155
+ }
156
+
157
+ const installedPackagePath = getInstalledPackagePath(root);
158
+ if (fs.existsSync(installedPackagePath)) {
159
+ const installedStat = fs.lstatSync(installedPackagePath);
160
+ addCheck(checks, 'installed-node_modules-package-is-not-symlink', !installedStat.isSymbolicLink(), {
161
+ installedPackagePath
162
+ });
163
+ } else {
164
+ addCheck(checks, 'installed-node_modules-package-is-not-symlink', false, {
165
+ installedPackagePath,
166
+ reason: 'PACKAGE_NOT_INSTALLED_LOCALLY'
167
+ });
168
+ }
169
+
170
+ const lockInfo = inspectPackageLock(root);
171
+ if (lockInfo.present && lockInfo.packageEntryPresent) {
172
+ addCheck(checks, 'package-lock-does-not-link-local-lbe', !lockInfo.blockedResolved, lockInfo);
173
+ } else {
174
+ addCheck(checks, 'package-lock-does-not-link-local-lbe', true, lockInfo);
175
+ }
176
+
177
+ const ok = checks.every((check) => check.ok);
178
+ const result = {
179
+ ok,
180
+ command: 'assert-consumer',
181
+ package: PACKAGE_NAME,
182
+ root,
183
+ classification: ok
184
+ ? 'consumer-project-using-installed-registry-dependency'
185
+ : 'not-proven-consumer-installed-dependency',
186
+ releaseClaimsAllowed: false,
187
+ message: ok
188
+ ? 'This project consumes LBE as an installed package dependency. This does not certify LBE release safety.'
189
+ : 'This project is not proven to consume LBE only as an installed registry dependency.',
190
+ checks
191
+ };
192
+
193
+ console.log(JSON.stringify(result, null, 2));
194
+
195
+ if (!ok) {
196
+ process.exitCode = 7;
197
+ }
198
+ }