@pretense/cli 0.6.16 → 0.6.17
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.
|
@@ -17,7 +17,7 @@ function versionFromPackageJson() {
|
|
|
17
17
|
return void 0;
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
var PRETENSE_VERSION = (true ? "0.6.
|
|
20
|
+
var PRETENSE_VERSION = (true ? "0.6.17" : void 0) ?? versionFromPackageJson() ?? "0.0.0-unknown";
|
|
21
21
|
|
|
22
22
|
export {
|
|
23
23
|
PRETENSE_VERSION
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
PRETENSE_VERSION
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-EFDPBFXJ.js";
|
|
5
5
|
import {
|
|
6
6
|
__commonJS,
|
|
7
7
|
__toESM,
|
|
@@ -3892,10 +3892,10 @@ var Minipass = class extends EventEmitter {
|
|
|
3892
3892
|
* Return a void Promise that resolves once the stream ends.
|
|
3893
3893
|
*/
|
|
3894
3894
|
async promise() {
|
|
3895
|
-
return new Promise((
|
|
3895
|
+
return new Promise((resolve8, reject) => {
|
|
3896
3896
|
this.on(DESTROYED, () => reject(new Error("stream destroyed")));
|
|
3897
3897
|
this.on("error", (er) => reject(er));
|
|
3898
|
-
this.on("end", () =>
|
|
3898
|
+
this.on("end", () => resolve8());
|
|
3899
3899
|
});
|
|
3900
3900
|
}
|
|
3901
3901
|
/**
|
|
@@ -3919,7 +3919,7 @@ var Minipass = class extends EventEmitter {
|
|
|
3919
3919
|
return Promise.resolve({ done: false, value: res });
|
|
3920
3920
|
if (this[EOF])
|
|
3921
3921
|
return stop();
|
|
3922
|
-
let
|
|
3922
|
+
let resolve8;
|
|
3923
3923
|
let reject;
|
|
3924
3924
|
const onerr = (er) => {
|
|
3925
3925
|
this.off("data", ondata);
|
|
@@ -3933,19 +3933,19 @@ var Minipass = class extends EventEmitter {
|
|
|
3933
3933
|
this.off("end", onend);
|
|
3934
3934
|
this.off(DESTROYED, ondestroy);
|
|
3935
3935
|
this.pause();
|
|
3936
|
-
|
|
3936
|
+
resolve8({ value, done: !!this[EOF] });
|
|
3937
3937
|
};
|
|
3938
3938
|
const onend = () => {
|
|
3939
3939
|
this.off("error", onerr);
|
|
3940
3940
|
this.off("data", ondata);
|
|
3941
3941
|
this.off(DESTROYED, ondestroy);
|
|
3942
3942
|
stop();
|
|
3943
|
-
|
|
3943
|
+
resolve8({ done: true, value: void 0 });
|
|
3944
3944
|
};
|
|
3945
3945
|
const ondestroy = () => onerr(new Error("stream destroyed"));
|
|
3946
3946
|
return new Promise((res2, rej) => {
|
|
3947
3947
|
reject = rej;
|
|
3948
|
-
|
|
3948
|
+
resolve8 = res2;
|
|
3949
3949
|
this.once(DESTROYED, ondestroy);
|
|
3950
3950
|
this.once("error", onerr);
|
|
3951
3951
|
this.once("end", onend);
|
|
@@ -4917,9 +4917,9 @@ var PathBase = class {
|
|
|
4917
4917
|
if (this.#asyncReaddirInFlight) {
|
|
4918
4918
|
await this.#asyncReaddirInFlight;
|
|
4919
4919
|
} else {
|
|
4920
|
-
let
|
|
4920
|
+
let resolve8 = () => {
|
|
4921
4921
|
};
|
|
4922
|
-
this.#asyncReaddirInFlight = new Promise((res) =>
|
|
4922
|
+
this.#asyncReaddirInFlight = new Promise((res) => resolve8 = res);
|
|
4923
4923
|
try {
|
|
4924
4924
|
for (const e of await this.#fs.promises.readdir(fullpath, {
|
|
4925
4925
|
withFileTypes: true
|
|
@@ -4932,7 +4932,7 @@ var PathBase = class {
|
|
|
4932
4932
|
children.provisional = 0;
|
|
4933
4933
|
}
|
|
4934
4934
|
this.#asyncReaddirInFlight = void 0;
|
|
4935
|
-
|
|
4935
|
+
resolve8();
|
|
4936
4936
|
}
|
|
4937
4937
|
return children.slice(0, children.provisional);
|
|
4938
4938
|
}
|
|
@@ -10413,7 +10413,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
|
|
10413
10413
|
});
|
|
10414
10414
|
if (!chunk) {
|
|
10415
10415
|
if (i === 1) {
|
|
10416
|
-
await new Promise((
|
|
10416
|
+
await new Promise((resolve8) => setTimeout(resolve8));
|
|
10417
10417
|
maxReadCount = 3;
|
|
10418
10418
|
continue;
|
|
10419
10419
|
}
|
|
@@ -14408,7 +14408,7 @@ import { createHmac, hkdfSync, randomBytes as randomBytes2 } from "crypto";
|
|
|
14408
14408
|
import { createHash, randomBytes } from "crypto";
|
|
14409
14409
|
import { readFileSync as readFileSync4, existsSync as existsSync22 } from "fs";
|
|
14410
14410
|
import { homedir as homedir2 } from "os";
|
|
14411
|
-
import { join as join22, dirname, parse } from "path";
|
|
14411
|
+
import { join as join22, dirname, parse, resolve } from "path";
|
|
14412
14412
|
import { chmodSync, existsSync as existsSync4, mkdirSync as mkdirSync2, statSync, writeFileSync as writeFileSync3 } from "fs";
|
|
14413
14413
|
import { homedir } from "os";
|
|
14414
14414
|
import { join as join4 } from "path";
|
|
@@ -14481,6 +14481,7 @@ function tighten(path2, exact, kind) {
|
|
|
14481
14481
|
);
|
|
14482
14482
|
}
|
|
14483
14483
|
}
|
|
14484
|
+
var PROJECT_ROOT_ENV = "PRETENSE_PROJECT_ROOT";
|
|
14484
14485
|
var KEYS_DIR_NAME = join22(".pretense", "keys");
|
|
14485
14486
|
function keysDir() {
|
|
14486
14487
|
return join22(homedir2(), KEYS_DIR_NAME);
|
|
@@ -14503,7 +14504,25 @@ var PROJECT_MARKERS = [
|
|
|
14503
14504
|
".hg",
|
|
14504
14505
|
".svn"
|
|
14505
14506
|
];
|
|
14507
|
+
function markersAt(dir, home) {
|
|
14508
|
+
return dir === home ? PROJECT_MARKERS.filter((m) => m !== ".pretense") : PROJECT_MARKERS;
|
|
14509
|
+
}
|
|
14506
14510
|
function findProjectRoot(filePath) {
|
|
14511
|
+
let dir = dirname(filePath);
|
|
14512
|
+
const { root } = parse(dir);
|
|
14513
|
+
const startDir = dir;
|
|
14514
|
+
const home = homedir2();
|
|
14515
|
+
while (true) {
|
|
14516
|
+
if (markersAt(dir, home).some((m) => existsSync22(join22(dir, m)))) {
|
|
14517
|
+
return dir;
|
|
14518
|
+
}
|
|
14519
|
+
if (dir === root) return startDir;
|
|
14520
|
+
const parent = dirname(dir);
|
|
14521
|
+
if (parent === dir) return startDir;
|
|
14522
|
+
dir = parent;
|
|
14523
|
+
}
|
|
14524
|
+
}
|
|
14525
|
+
function legacyFindProjectRoot(filePath) {
|
|
14507
14526
|
let dir = dirname(filePath);
|
|
14508
14527
|
const { root } = parse(dir);
|
|
14509
14528
|
const startDir = dir;
|
|
@@ -14517,6 +14536,21 @@ function findProjectRoot(filePath) {
|
|
|
14517
14536
|
dir = parent;
|
|
14518
14537
|
}
|
|
14519
14538
|
}
|
|
14539
|
+
function resolveProjectRoot(filePath) {
|
|
14540
|
+
const override2 = process.env[PROJECT_ROOT_ENV];
|
|
14541
|
+
if (override2 && override2.trim()) return resolve(override2.trim());
|
|
14542
|
+
return findProjectRoot(filePath);
|
|
14543
|
+
}
|
|
14544
|
+
function candidateProjectRoots(filePath) {
|
|
14545
|
+
const out = [];
|
|
14546
|
+
const override2 = process.env[PROJECT_ROOT_ENV];
|
|
14547
|
+
if (override2 && override2.trim()) out.push(resolve(override2.trim()));
|
|
14548
|
+
out.push(findProjectRoot(filePath));
|
|
14549
|
+
out.push(dirname(filePath));
|
|
14550
|
+
out.push(legacyFindProjectRoot(filePath));
|
|
14551
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14552
|
+
return out.filter((r) => seen.has(r) ? false : (seen.add(r), true));
|
|
14553
|
+
}
|
|
14520
14554
|
function findProjectRootForDir(dir) {
|
|
14521
14555
|
return findProjectRoot(join22(dir, "__pretense_probe__"));
|
|
14522
14556
|
}
|
|
@@ -16335,7 +16369,7 @@ import { join as join5 } from "path";
|
|
|
16335
16369
|
import { parse as parseYaml } from "yaml";
|
|
16336
16370
|
import { readFileSync as readFileSync23 } from "fs";
|
|
16337
16371
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
16338
|
-
import { dirname as dirname3, join as join23, resolve } from "path";
|
|
16372
|
+
import { dirname as dirname3, join as join23, resolve as resolve2 } from "path";
|
|
16339
16373
|
import https from "https";
|
|
16340
16374
|
|
|
16341
16375
|
// ../packages/tls/dist/index.js
|
|
@@ -16471,7 +16505,7 @@ function versionFromCliPackageJson() {
|
|
|
16471
16505
|
}
|
|
16472
16506
|
} catch {
|
|
16473
16507
|
}
|
|
16474
|
-
const parent =
|
|
16508
|
+
const parent = resolve2(dir, "..");
|
|
16475
16509
|
if (parent === dir) break;
|
|
16476
16510
|
dir = parent;
|
|
16477
16511
|
}
|
|
@@ -16480,11 +16514,11 @@ function versionFromCliPackageJson() {
|
|
|
16480
16514
|
return void 0;
|
|
16481
16515
|
}
|
|
16482
16516
|
function productVersion() {
|
|
16483
|
-
return override ?? (true ? "0.6.
|
|
16517
|
+
return override ?? (true ? "0.6.17" : void 0) ?? versionFromCliPackageJson() ?? "0.0.0-unknown";
|
|
16484
16518
|
}
|
|
16485
16519
|
var UNKNOWN_COMMIT = "unknown";
|
|
16486
16520
|
function bakedCommitSha() {
|
|
16487
|
-
return "
|
|
16521
|
+
return "6f467e565f6f035a63fe420acef1019ddf2455f0".length > 0 ? "6f467e565f6f035a63fe420acef1019ddf2455f0" : UNKNOWN_COMMIT;
|
|
16488
16522
|
}
|
|
16489
16523
|
var FEATURE_TIERS = {
|
|
16490
16524
|
compliance_export: "pro",
|
|
@@ -17989,14 +18023,14 @@ if (isMain) {
|
|
|
17989
18023
|
init_esm_shims();
|
|
17990
18024
|
import net from "net";
|
|
17991
18025
|
function isPortFree(port) {
|
|
17992
|
-
return new Promise((
|
|
18026
|
+
return new Promise((resolve8) => {
|
|
17993
18027
|
const srv = net.createServer();
|
|
17994
18028
|
srv.once("error", () => {
|
|
17995
|
-
srv.close(() =>
|
|
17996
|
-
|
|
18029
|
+
srv.close(() => resolve8(false));
|
|
18030
|
+
resolve8(false);
|
|
17997
18031
|
});
|
|
17998
18032
|
srv.once("listening", () => {
|
|
17999
|
-
srv.close(() =>
|
|
18033
|
+
srv.close(() => resolve8(true));
|
|
18000
18034
|
});
|
|
18001
18035
|
srv.listen(port);
|
|
18002
18036
|
});
|
|
@@ -18662,7 +18696,7 @@ import { Command as Command5, Option, InvalidArgumentError as InvalidArgumentErr
|
|
|
18662
18696
|
import chalk5 from "chalk";
|
|
18663
18697
|
import { readFileSync as readFileSync8, statSync as statSync3, readdirSync as readdirSync2, openSync, readSync, closeSync } from "fs";
|
|
18664
18698
|
import { execSync as execSync3 } from "child_process";
|
|
18665
|
-
import { resolve as
|
|
18699
|
+
import { resolve as resolve3, join as join8, extname as extname2, basename } from "path";
|
|
18666
18700
|
|
|
18667
18701
|
// src/safe-output.ts
|
|
18668
18702
|
init_esm_shims();
|
|
@@ -18789,7 +18823,7 @@ function isBinaryFile(filePath) {
|
|
|
18789
18823
|
}
|
|
18790
18824
|
var SEVERITY_ORDER = { low: 0, medium: 1, high: 2, critical: 3 };
|
|
18791
18825
|
function collectFiles(target) {
|
|
18792
|
-
const abs =
|
|
18826
|
+
const abs = resolve3(target);
|
|
18793
18827
|
let stat;
|
|
18794
18828
|
try {
|
|
18795
18829
|
stat = statSync3(abs);
|
|
@@ -20469,7 +20503,7 @@ import {
|
|
|
20469
20503
|
readFileSync as readFileSync13,
|
|
20470
20504
|
mkdirSync as mkdirSync3
|
|
20471
20505
|
} from "fs";
|
|
20472
|
-
import { join as join15, resolve as
|
|
20506
|
+
import { join as join15, resolve as resolve4 } from "path";
|
|
20473
20507
|
var HOOK_SCRIPTS = {
|
|
20474
20508
|
"pre-commit": `#!/bin/sh
|
|
20475
20509
|
# Pretense AI Firewall \u2014 pre-commit hook
|
|
@@ -20511,7 +20545,7 @@ function installCommand() {
|
|
|
20511
20545
|
"-m, --mode <mode>",
|
|
20512
20546
|
"Hook mode: pre-commit, pre-push (omit to install both)"
|
|
20513
20547
|
).option("-f, --force", "Overwrite existing hooks without prompting", false).option("-d, --dir <path>", "Project directory (defaults to cwd)", ".").action((opts) => {
|
|
20514
|
-
const dir =
|
|
20548
|
+
const dir = resolve4(opts.dir);
|
|
20515
20549
|
const force = opts.force;
|
|
20516
20550
|
const modeArg = opts.mode;
|
|
20517
20551
|
if (modeArg && !VALID_MODES.includes(modeArg)) {
|
|
@@ -20887,7 +20921,7 @@ init_esm_shims();
|
|
|
20887
20921
|
import { Command as Command15 } from "commander";
|
|
20888
20922
|
import chalk14 from "chalk";
|
|
20889
20923
|
import { existsSync as existsSync14, writeFileSync as writeFileSync6 } from "fs";
|
|
20890
|
-
import { join as join17, resolve as
|
|
20924
|
+
import { join as join17, resolve as resolve5 } from "path";
|
|
20891
20925
|
var DEFAULT_CONFIG_YAML = `scan:
|
|
20892
20926
|
secrets: block
|
|
20893
20927
|
pii: redact
|
|
@@ -20914,7 +20948,7 @@ verbose: false
|
|
|
20914
20948
|
`;
|
|
20915
20949
|
function quickstartCommand() {
|
|
20916
20950
|
return new Command15("quickstart").description("One-command setup: init + install hooks + show next steps").option("-d, --dir <path>", "Directory to scan", ".").option("--dry-run", "Print what would be written without writing", false).action(async (opts) => {
|
|
20917
|
-
const dir =
|
|
20951
|
+
const dir = resolve5(opts.dir);
|
|
20918
20952
|
console.log(chalk14.bold.cyan("\n Pretense Quickstart\n"));
|
|
20919
20953
|
console.log(chalk14.dim(" Setting up AI firewall for this project...\n"));
|
|
20920
20954
|
console.log(chalk14.dim(" [1/4] Scanning codebase..."));
|
|
@@ -20971,7 +21005,7 @@ import { Command as Command16, Option as Option2 } from "commander";
|
|
|
20971
21005
|
import chalk16 from "chalk";
|
|
20972
21006
|
import { readFileSync as readFileSync15, writeFileSync as writeFileSync7, chmodSync as chmodSync4, existsSync as existsSync15 } from "fs";
|
|
20973
21007
|
import { createHash as createHash3 } from "crypto";
|
|
20974
|
-
import { resolve as
|
|
21008
|
+
import { resolve as resolve6, extname as extname4 } from "path";
|
|
20975
21009
|
|
|
20976
21010
|
// src/secret-crypto.ts
|
|
20977
21011
|
init_esm_shims();
|
|
@@ -21156,7 +21190,7 @@ function preflightReversalMap(mapPath, absFile, content, contentSha, force) {
|
|
|
21156
21190
|
to overwrite it deliberately.`
|
|
21157
21191
|
};
|
|
21158
21192
|
}
|
|
21159
|
-
const existingFile = existing.file ?
|
|
21193
|
+
const existingFile = existing.file ? resolve6(existing.file) : void 0;
|
|
21160
21194
|
if (existingFile && existingFile !== absFile) {
|
|
21161
21195
|
if (force) {
|
|
21162
21196
|
return { action: "write", generation: 1, supersededSha: existing.originalSha };
|
|
@@ -21326,8 +21360,8 @@ async function runMutate(file, opts = {}) {
|
|
|
21326
21360
|
return 0;
|
|
21327
21361
|
}
|
|
21328
21362
|
reportUnmutatable(unmutatable);
|
|
21329
|
-
const absFile =
|
|
21330
|
-
const projectRoot =
|
|
21363
|
+
const absFile = resolve6(file);
|
|
21364
|
+
const projectRoot = resolveProjectRoot(absFile);
|
|
21331
21365
|
const result = mutateSecrets(content, findings, { projectRoot, keysDir: opts.keysDir });
|
|
21332
21366
|
let effectiveMap;
|
|
21333
21367
|
if (preview) {
|
|
@@ -21480,7 +21514,7 @@ init_esm_shims();
|
|
|
21480
21514
|
import { Command as Command17 } from "commander";
|
|
21481
21515
|
import chalk17 from "chalk";
|
|
21482
21516
|
import { readFileSync as readFileSync16, existsSync as existsSync16, statSync as statSync6 } from "fs";
|
|
21483
|
-
import { resolve as
|
|
21517
|
+
import { resolve as resolve7 } from "path";
|
|
21484
21518
|
import { createHash as createHash4 } from "crypto";
|
|
21485
21519
|
function sha256Hex3(s) {
|
|
21486
21520
|
return createHash4("sha256").update(s, "utf8").digest("hex");
|
|
@@ -21539,7 +21573,7 @@ function loadReversalMap(mapPath) {
|
|
|
21539
21573
|
}
|
|
21540
21574
|
function runReverse(file, opts = {}) {
|
|
21541
21575
|
const reverseStartMs = Date.now();
|
|
21542
|
-
const absPath =
|
|
21576
|
+
const absPath = resolve7(file);
|
|
21543
21577
|
if (!existsSync16(absPath) || !statSync6(absPath).isFile()) {
|
|
21544
21578
|
console.error(chalk17.red(`
|
|
21545
21579
|
x File not found: ${file}
|
|
@@ -21561,30 +21595,41 @@ function runReverse(file, opts = {}) {
|
|
|
21561
21595
|
const mapFile = loadReversalMap(mapPath);
|
|
21562
21596
|
let plainMutations;
|
|
21563
21597
|
if (mapFile.encrypted) {
|
|
21564
|
-
const
|
|
21565
|
-
const
|
|
21566
|
-
|
|
21567
|
-
|
|
21568
|
-
|
|
21569
|
-
|
|
21570
|
-
|
|
21571
|
-
|
|
21572
|
-
|
|
21573
|
-
|
|
21598
|
+
const keySource = mapFile.file ?? absPath;
|
|
21599
|
+
const roots = candidateProjectRoots(keySource);
|
|
21600
|
+
let decrypted;
|
|
21601
|
+
let anyKeyPresent = false;
|
|
21602
|
+
for (const root of roots) {
|
|
21603
|
+
const key = readProjectKey(root, opts.keysDir);
|
|
21604
|
+
if (!key) continue;
|
|
21605
|
+
anyKeyPresent = true;
|
|
21606
|
+
try {
|
|
21607
|
+
decrypted = mapFile.mutations.map((m) => ({
|
|
21608
|
+
original: decryptSecret(m.original, key),
|
|
21609
|
+
replacement: m.replacement
|
|
21610
|
+
}));
|
|
21611
|
+
break;
|
|
21612
|
+
} catch {
|
|
21613
|
+
decrypted = void 0;
|
|
21614
|
+
}
|
|
21574
21615
|
}
|
|
21575
|
-
|
|
21576
|
-
|
|
21577
|
-
original: decryptSecret(m.original, key),
|
|
21578
|
-
replacement: m.replacement
|
|
21579
|
-
}));
|
|
21580
|
-
} catch {
|
|
21616
|
+
if (!decrypted) {
|
|
21617
|
+
const looked = roots.join("\n ");
|
|
21581
21618
|
console.error(
|
|
21582
21619
|
chalk17.red(`
|
|
21583
|
-
x
|
|
21620
|
+
x Encryption key not found for this file \u2014 cannot decrypt the reversal map.`) + (anyKeyPresent ? chalk17.dim(`
|
|
21621
|
+
A key was present but did not decrypt this map (wrong key or corrupt data).`) : chalk17.dim(`
|
|
21622
|
+
No key was found under any known project location for this file.`)) + chalk17.dim(`
|
|
21623
|
+
Looked under these project roots (keys dir ${opts.keysDir ?? "~/.pretense/keys"}):`) + chalk17.dim(`
|
|
21624
|
+
${looked}`) + chalk17.dim(`
|
|
21625
|
+
Run \`reverse\` on the SAME machine and HOME where you mutated the file,`) + chalk17.dim(`
|
|
21626
|
+
or set ${chalk17.cyan("PRETENSE_PROJECT_ROOT")} to the project root used at mutate time.`) + chalk17.dim(`
|
|
21627
|
+
File left untouched.
|
|
21584
21628
|
`)
|
|
21585
21629
|
);
|
|
21586
21630
|
return 1;
|
|
21587
21631
|
}
|
|
21632
|
+
plainMutations = decrypted;
|
|
21588
21633
|
} else {
|
|
21589
21634
|
plainMutations = mapFile.mutations.map((m) => ({ original: m.original, replacement: m.replacement }));
|
|
21590
21635
|
}
|
package/dist/postinstall.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pretense/cli",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.17",
|
|
4
4
|
"description": "Local-first AI firewall that mutates proprietary code before sending to LLM APIs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,15 +23,15 @@
|
|
|
23
23
|
"tsx": "^4.0.0",
|
|
24
24
|
"typescript": "^5.4.0",
|
|
25
25
|
"vitest": "^1.0.0",
|
|
26
|
-
"@pretense/protocol": "0.1.0",
|
|
27
26
|
"@pretense/compliance-engine": "0.1.0",
|
|
28
|
-
"@pretense/
|
|
27
|
+
"@pretense/protocol": "0.1.0",
|
|
28
|
+
"@pretense/billing": "0.1.0",
|
|
29
|
+
"@pretense/learner": "0.2.0",
|
|
29
30
|
"@pretense/mutator": "0.2.0",
|
|
30
|
-
"@pretense/
|
|
31
|
+
"@pretense/proxy": "0.1.0",
|
|
31
32
|
"@pretense/scanner-rs": "0.2.0",
|
|
32
33
|
"@pretense/store": "0.2.0",
|
|
33
|
-
"@pretense/
|
|
34
|
-
"@pretense/learner": "0.2.0"
|
|
34
|
+
"@pretense/scanner": "0.2.0"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public",
|