@ploaness/cli 1.1.0 → 1.3.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/dist/checks/assets.d.ts +12 -0
- package/dist/checks/assets.d.ts.map +1 -1
- package/dist/checks/assets.js +27 -4
- package/dist/checks/assets.js.map +1 -1
- package/dist/checks/blocklist.d.ts +8 -0
- package/dist/checks/blocklist.d.ts.map +1 -0
- package/dist/checks/blocklist.js +106 -0
- package/dist/checks/blocklist.js.map +1 -0
- package/dist/checks/container-run.d.ts +23 -0
- package/dist/checks/container-run.d.ts.map +1 -0
- package/dist/checks/container-run.js +55 -0
- package/dist/checks/container-run.js.map +1 -0
- package/dist/checks/containers.d.ts.map +1 -1
- package/dist/checks/containers.js +2 -32
- package/dist/checks/containers.js.map +1 -1
- package/dist/checks/dependencies.d.ts.map +1 -1
- package/dist/checks/dependencies.js +75 -52
- package/dist/checks/dependencies.js.map +1 -1
- package/dist/checks/editorconfig.js +6 -5
- package/dist/checks/editorconfig.js.map +1 -1
- package/dist/checks/environment.d.ts +3 -3
- package/dist/checks/environment.d.ts.map +1 -1
- package/dist/checks/environment.js +29 -14
- package/dist/checks/environment.js.map +1 -1
- package/dist/checks/infra.d.ts +5 -0
- package/dist/checks/infra.d.ts.map +1 -0
- package/dist/checks/infra.js +185 -0
- package/dist/checks/infra.js.map +1 -0
- package/dist/checks/install.d.ts +2 -0
- package/dist/checks/install.d.ts.map +1 -1
- package/dist/checks/install.js +10 -1
- package/dist/checks/install.js.map +1 -1
- package/dist/checks/oxlint.d.ts +5 -0
- package/dist/checks/oxlint.d.ts.map +1 -0
- package/dist/checks/oxlint.js +85 -0
- package/dist/checks/oxlint.js.map +1 -0
- package/dist/checks/payload.d.ts +11 -0
- package/dist/checks/payload.d.ts.map +1 -1
- package/dist/checks/payload.js +130 -9
- package/dist/checks/payload.js.map +1 -1
- package/dist/checks/shell.d.ts +5 -0
- package/dist/checks/shell.d.ts.map +1 -0
- package/dist/checks/shell.js +78 -0
- package/dist/checks/shell.js.map +1 -0
- package/dist/checks/suppressions.d.ts +2 -2
- package/dist/checks/suppressions.d.ts.map +1 -1
- package/dist/checks/suppressions.js +31 -11
- package/dist/checks/suppressions.js.map +1 -1
- package/dist/checks/tree.d.ts +1 -1
- package/dist/checks/tree.d.ts.map +1 -1
- package/dist/checks/tree.js +6 -26
- package/dist/checks/tree.js.map +1 -1
- package/dist/checks/wiring.d.ts +10 -0
- package/dist/checks/wiring.d.ts.map +1 -1
- package/dist/checks/wiring.js +16 -4
- package/dist/checks/wiring.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +1 -3
- package/dist/commands/init.js.map +1 -1
- package/dist/context.d.ts +1 -23
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +16 -33
- package/dist/context.js.map +1 -1
- package/dist/gates.d.ts.map +1 -1
- package/dist/gates.js +54 -13
- package/dist/gates.js.map +1 -1
- package/dist/probes/payload-defaults.probe.d.ts +2 -0
- package/dist/probes/payload-defaults.probe.d.ts.map +1 -0
- package/dist/probes/payload-defaults.probe.js +116 -0
- package/dist/probes/payload-defaults.probe.js.map +1 -0
- package/dist/source-comments.d.ts +9 -0
- package/dist/source-comments.d.ts.map +1 -0
- package/dist/source-comments.js +54 -0
- package/dist/source-comments.js.map +1 -0
- package/dist/working-tree.d.ts +5 -0
- package/dist/working-tree.d.ts.map +1 -0
- package/dist/working-tree.js +36 -0
- package/dist/working-tree.js.map +1 -0
- package/package.json +6 -5
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// The half of the `payload-defaults` gate that runs inside the project: it imports the project's built
|
|
2
|
+
// Payload configuration and reports which operations of which entities still carry Payload's own
|
|
3
|
+
// `defaultAccess`. It is spawned by the gate through tsx, with the project root as its working directory
|
|
4
|
+
// so that `payload` and the configuration's own imports resolve from the project, and it prints one
|
|
5
|
+
// marker-prefixed JSON line that the gate parses. What the report MEANS is decided in
|
|
6
|
+
// `@ploaness/governance`; this file only reads.
|
|
7
|
+
//
|
|
8
|
+
// It also asks every drafts-enabled entity's read rule what it answers a caller with no credentials.
|
|
9
|
+
// That is the one place the harness CALLS a project's function rather than inspecting it, and it is
|
|
10
|
+
// deliberate: the constraint a read returns is the half `/api/access` reports and the anonymous sweep
|
|
11
|
+
// never opens, so there is nowhere else to see it. The call is confined to entities that keep drafts,
|
|
12
|
+
// it is awaited so a legitimately asynchronous rule is not punished for being one, and a rule that
|
|
13
|
+
// throws is reported as undecidable rather than assumed safe. The harness already requires an access
|
|
14
|
+
// decision to be a pure function of the values it is handed, which is the shape this relies on.
|
|
15
|
+
//
|
|
16
|
+
// Two arguments, both absolute: the configuration file, and Payload's `dist/auth/defaultAccess.js`.
|
|
17
|
+
// Identity is judged by reference first and by source text second, because a loader can register the
|
|
18
|
+
// same module twice under two URLs and a project function cannot be byte-identical to Payload's by
|
|
19
|
+
// accident. Nothing here imports `payload` by name: the harness never depends on it, and the copy that
|
|
20
|
+
// matters is the one the project installed.
|
|
21
|
+
import { pathToFileURL } from 'node:url';
|
|
22
|
+
import { accessOperationsFor, INHERITED_ACCESS_REPORT_MARKER, isArray, isRecord, QUERY_PRESETS_SLUG, readKey, } from '@ploaness/governance';
|
|
23
|
+
// node, the probe, then the two paths.
|
|
24
|
+
const ARGUMENT_OFFSET = 2;
|
|
25
|
+
const [configFile, defaultAccessFile] = process.argv.slice(ARGUMENT_OFFSET);
|
|
26
|
+
if (configFile === undefined || defaultAccessFile === undefined) {
|
|
27
|
+
throw new Error('usage: payload-defaults.probe.js <payload.config.ts> <defaultAccess.js>');
|
|
28
|
+
}
|
|
29
|
+
const defaultAccessModule = await import(pathToFileURL(defaultAccessFile).href);
|
|
30
|
+
const defaultAccess = readKey(defaultAccessModule, 'defaultAccess');
|
|
31
|
+
if (typeof defaultAccess !== 'function') {
|
|
32
|
+
throw new TypeError(`Payload's default access could not be established from ${defaultAccessFile}`);
|
|
33
|
+
}
|
|
34
|
+
const defaultAccessSource = String(defaultAccess);
|
|
35
|
+
// Undeclared counts as inherited, and not only as a convenience. `executeAccess` runs the rule it is
|
|
36
|
+
// given and, handed nothing, falls through to `if (req.user) return true` - so a missing rule is not an
|
|
37
|
+
// absent permission but an open one, indistinguishable at runtime from Payload's own default. Payload
|
|
38
|
+
// fills every operation but `readVersions` in during sanitisation, which is the one this reaches.
|
|
39
|
+
const isInherited = (rule) => rule === undefined ||
|
|
40
|
+
rule === defaultAccess ||
|
|
41
|
+
(typeof rule === 'function' && String(rule) === defaultAccessSource);
|
|
42
|
+
const configModule = await import(pathToFileURL(configFile).href);
|
|
43
|
+
// Awaited either way: `buildConfig` returns a promise, and a configuration handed over as a plain
|
|
44
|
+
// object is read the same.
|
|
45
|
+
const config = await readKey(configModule, 'default');
|
|
46
|
+
const collections = readKey(config, 'collections');
|
|
47
|
+
const globals = readKey(config, 'globals');
|
|
48
|
+
if (!(isArray(collections) && isArray(globals))) {
|
|
49
|
+
throw new Error(`the default export of ${configFile} is not a built Payload configuration`);
|
|
50
|
+
}
|
|
51
|
+
// Which operations an entity owes depends on what it is, and sanitisation is what makes that legible:
|
|
52
|
+
// `auth` survives as an object on an auth collection and as `false` elsewhere, and `versions` survives
|
|
53
|
+
// as an object where it is enabled and is deleted where it is not. Both reads are therefore about the
|
|
54
|
+
// built object rather than the source the project wrote.
|
|
55
|
+
// The access a project decided, which for one collection is not the access the collection carries.
|
|
56
|
+
// Payload builds the query-presets collection's rules itself, wrapping each operation in a closure that
|
|
57
|
+
// falls back to its own default, so the wrapper is never the default this probe recognises; the block
|
|
58
|
+
// the project wrote sits on the configuration instead. See QUERY_PRESETS_SLUG for what that hides.
|
|
59
|
+
const accessOf = (entity, slug) => readKey(slug === QUERY_PRESETS_SLUG ? readKey(config, 'queryPresets') : entity, 'access');
|
|
60
|
+
const entryOf = (entity, kind) => {
|
|
61
|
+
const slug = String(readKey(entity, 'slug'));
|
|
62
|
+
const access = accessOf(entity, slug);
|
|
63
|
+
const operations = accessOperationsFor({
|
|
64
|
+
kind,
|
|
65
|
+
hasAuth: Boolean(readKey(entity, 'auth')),
|
|
66
|
+
hasVersions: Boolean(readKey(entity, 'versions')),
|
|
67
|
+
});
|
|
68
|
+
return {
|
|
69
|
+
slug,
|
|
70
|
+
inherited: operations.filter((operation) => isInherited(readKey(access, operation))),
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
const hasDrafts = (entity) => Boolean(readKey(readKey(entity, 'versions'), 'drafts'));
|
|
74
|
+
// A predicate rather than an assertion, for the reason `isArray` is one: calling a value narrowed only
|
|
75
|
+
// to `Function` hands back `any`, and an assertion is what type coverage counts against the harness.
|
|
76
|
+
const isAccessRule = (value) => typeof value === 'function';
|
|
77
|
+
const anonymousReadOf = async (entity) => {
|
|
78
|
+
const rule = readKey(readKey(entity, 'access'), 'read');
|
|
79
|
+
if (!isAccessRule(rule)) {
|
|
80
|
+
// An undeclared read is Payload's own default, which the inherited half of this report names.
|
|
81
|
+
return { kind: 'denied' };
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const answer = await rule({ req: { user: null } });
|
|
85
|
+
if (answer === true) {
|
|
86
|
+
return { kind: 'open' };
|
|
87
|
+
}
|
|
88
|
+
return isRecord(answer) ? { kind: 'filtered', where: answer } : { kind: 'denied' };
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
return {
|
|
92
|
+
kind: 'undecidable',
|
|
93
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const draftReadsOf = async (entities, kind) => await Promise.all(entities
|
|
98
|
+
.filter((entity) => hasDrafts(entity))
|
|
99
|
+
.map(async (entity) => {
|
|
100
|
+
const anonymousRead = await anonymousReadOf(entity);
|
|
101
|
+
return { kind, slug: String(readKey(entity, 'slug')), anonymousRead };
|
|
102
|
+
}));
|
|
103
|
+
const report = {
|
|
104
|
+
collections: collections.map((collection) => entryOf(collection, 'collection')),
|
|
105
|
+
draftReads: [
|
|
106
|
+
...(await draftReadsOf(collections, 'collection')),
|
|
107
|
+
...(await draftReadsOf(globals, 'global')),
|
|
108
|
+
],
|
|
109
|
+
globals: globals.map((global) => entryOf(global, 'global')),
|
|
110
|
+
};
|
|
111
|
+
process.stdout.write(`${INHERITED_ACCESS_REPORT_MARKER}${JSON.stringify(report)}\n`);
|
|
112
|
+
// The exit code rather than `process.exit()`, for the reason bin.ts states: the report is flushed
|
|
113
|
+
// before the process ends. A plugin that keeps a handle open after import holds the process until the
|
|
114
|
+
// gate's own timeout, which then reports it as a build that did not finish rather than as a pass.
|
|
115
|
+
process.exitCode = 0;
|
|
116
|
+
//# sourceMappingURL=payload-defaults.probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payload-defaults.probe.js","sourceRoot":"","sources":["../../src/probes/payload-defaults.probe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SourceComment } from '@ploaness/governance';
|
|
2
|
+
/**
|
|
3
|
+
* Read actual source comments without mistaking strings, regular expressions, or JSX text for directives.
|
|
4
|
+
* @param text the source being checked.
|
|
5
|
+
* @param file the filename, which determines whether angle brackets are types or JSX.
|
|
6
|
+
* @returns comments once each, located at their original source lines.
|
|
7
|
+
*/
|
|
8
|
+
export declare const sourceComments: (text: string, file?: string) => readonly SourceComment[];
|
|
9
|
+
//# sourceMappingURL=source-comments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-comments.d.ts","sourceRoot":"","sources":["../src/source-comments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAqCzD;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GACzB,MAAM,MAAM,EACZ,OAAM,MAAqB,KAC1B,SAAS,aAAa,EAuBxB,CAAA"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
const LITERAL_KINDS = new Set([
|
|
3
|
+
ts.SyntaxKind.JsxText,
|
|
4
|
+
ts.SyntaxKind.StringLiteral,
|
|
5
|
+
ts.SyntaxKind.RegularExpressionLiteral,
|
|
6
|
+
ts.SyntaxKind.NoSubstitutionTemplateLiteral,
|
|
7
|
+
ts.SyntaxKind.TemplateHead,
|
|
8
|
+
ts.SyntaxKind.TemplateMiddle,
|
|
9
|
+
ts.SyntaxKind.TemplateTail,
|
|
10
|
+
]);
|
|
11
|
+
const literalRangesOf = (node, source) => [
|
|
12
|
+
...(LITERAL_KINDS.has(node.kind)
|
|
13
|
+
? [
|
|
14
|
+
{
|
|
15
|
+
pos: node.kind === ts.SyntaxKind.JsxText ? node.pos : node.getStart(source),
|
|
16
|
+
end: node.end,
|
|
17
|
+
},
|
|
18
|
+
]
|
|
19
|
+
: []),
|
|
20
|
+
...node
|
|
21
|
+
.getChildren(source)
|
|
22
|
+
.flatMap((child) => literalRangesOf(child, source)),
|
|
23
|
+
];
|
|
24
|
+
const rangesOf = (node, source) => [
|
|
25
|
+
...(node.kind === ts.SyntaxKind.JsxText
|
|
26
|
+
? []
|
|
27
|
+
: (ts.getLeadingCommentRanges(source.text, node.getFullStart()) ?? [])),
|
|
28
|
+
...(ts.getTrailingCommentRanges(source.text, node.end) ?? []),
|
|
29
|
+
...node
|
|
30
|
+
.getChildren(source)
|
|
31
|
+
.flatMap((child) => rangesOf(child, source)),
|
|
32
|
+
];
|
|
33
|
+
/**
|
|
34
|
+
* Read actual source comments without mistaking strings, regular expressions, or JSX text for directives.
|
|
35
|
+
* @param text the source being checked.
|
|
36
|
+
* @param file the filename, which determines whether angle brackets are types or JSX.
|
|
37
|
+
* @returns comments once each, located at their original source lines.
|
|
38
|
+
*/
|
|
39
|
+
export const sourceComments = (text, file = 'source.tsx') => {
|
|
40
|
+
const source = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true);
|
|
41
|
+
const ranges = new Map(rangesOf(source, source).map((range) => [
|
|
42
|
+
range.pos,
|
|
43
|
+
range,
|
|
44
|
+
]));
|
|
45
|
+
const literals = literalRangesOf(source, source);
|
|
46
|
+
return [...ranges.values()]
|
|
47
|
+
.filter((range) => !literals.some((literal) => range.pos >= literal.pos && range.pos < literal.end))
|
|
48
|
+
.toSorted((left, right) => left.pos - right.pos)
|
|
49
|
+
.map((range) => ({
|
|
50
|
+
line: source.getLineAndCharacterOfPosition(range.pos).line + 1,
|
|
51
|
+
text: text.slice(range.pos, range.end),
|
|
52
|
+
}));
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=source-comments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-comments.js","sourceRoot":"","sources":["../src/source-comments.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Enumerate tracked and non-ignored untracked paths on each call, including indexed deletions. */
|
|
2
|
+
export declare const workingTreeFiles: (root: string) => readonly string[];
|
|
3
|
+
/** Fingerprint paths, file kinds, modes, and bytes without following symbolic links. */
|
|
4
|
+
export declare const workingTreeFingerprint: (root: string) => string;
|
|
5
|
+
//# sourceMappingURL=working-tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"working-tree.d.ts","sourceRoot":"","sources":["../src/working-tree.ts"],"names":[],"mappings":"AASA,mGAAmG;AACnG,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG,SAAS,MAAM,EAYuB,CAAA;AAgBtF,wFAAwF;AACxF,eAAO,MAAM,sBAAsB,GAAI,MAAM,MAAM,KAAG,MASpC,CAAA"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { lstatSync, readFileSync, readlinkSync } from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
const BYTES_PER_KIB = 1024;
|
|
6
|
+
const KIB_PER_MIB = 1024;
|
|
7
|
+
const MAX_OUTPUT_MIB = 64;
|
|
8
|
+
/** Enumerate tracked and non-ignored untracked paths on each call, including indexed deletions. */
|
|
9
|
+
export const workingTreeFiles = (root) => [
|
|
10
|
+
...new Set(execFileSync('git', ['ls-files', '-z', '--cached', '--others', '--exclude-standard'], {
|
|
11
|
+
cwd: root,
|
|
12
|
+
encoding: 'utf8',
|
|
13
|
+
maxBuffer: MAX_OUTPUT_MIB * KIB_PER_MIB * BYTES_PER_KIB,
|
|
14
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
15
|
+
})
|
|
16
|
+
.split('\0')
|
|
17
|
+
.filter((file) => file !== '')),
|
|
18
|
+
].toSorted((left, right) => left.localeCompare(right, 'en'));
|
|
19
|
+
const fileState = (root, file) => {
|
|
20
|
+
const full = path.join(root, file);
|
|
21
|
+
const stat = lstatSync(full, { throwIfNoEntry: false });
|
|
22
|
+
if (stat === undefined) {
|
|
23
|
+
return [file, 'absent'];
|
|
24
|
+
}
|
|
25
|
+
if (stat.isSymbolicLink()) {
|
|
26
|
+
return [file, 'symlink', readlinkSync(full)];
|
|
27
|
+
}
|
|
28
|
+
return stat.isFile()
|
|
29
|
+
? [file, 'file', stat.mode, createHash('sha256').update(readFileSync(full)).digest('hex')]
|
|
30
|
+
: [file, 'directory'];
|
|
31
|
+
};
|
|
32
|
+
/** Fingerprint paths, file kinds, modes, and bytes without following symbolic links. */
|
|
33
|
+
export const workingTreeFingerprint = (root) => createHash('sha256')
|
|
34
|
+
.update(JSON.stringify(workingTreeFiles(root).map((file) => fileState(root, file))))
|
|
35
|
+
.digest('hex');
|
|
36
|
+
//# sourceMappingURL=working-tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"working-tree.js","sourceRoot":"","sources":["../src/working-tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC/D,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,MAAM,aAAa,GAAW,IAAI,CAAA;AAClC,MAAM,WAAW,GAAW,IAAI,CAAA;AAChC,MAAM,cAAc,GAAW,EAAE,CAAA;AAEjC,mGAAmG;AACnG,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAqB,EAAE,CAClE;IACE,GAAG,IAAI,GAAG,CACR,YAAY,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,oBAAoB,CAAC,EAAE;QACpF,GAAG,EAAE,IAAI;QACT,QAAQ,EAAE,MAAM;QAChB,SAAS,EAAE,cAAc,GAAG,WAAW,GAAG,aAAa;QACvD,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;KAClC,CAAC;SACC,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,CAAC,IAAY,EAAW,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAClD;CACF,CAAC,QAAQ,CAAC,CAAC,IAAY,EAAE,KAAa,EAAU,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAA;AAEtF,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,IAAY,EAAgC,EAAE;IAC7E,MAAM,IAAI,GAAW,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAC1C,MAAM,IAAI,GAA6C,SAAS,CAAC,IAAI,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAA;IACjG,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IACzB,CAAC;IACD,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;QAC1B,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAA;IAC9C,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,EAAE;QAClB,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1F,CAAC,CAAC,CAAC,IAAI,EAAE,WAAW,CAAC,CAAA;AACzB,CAAC,CAAA;AAED,wFAAwF;AACxF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,IAAY,EAAU,EAAE,CAC7D,UAAU,CAAC,QAAQ,CAAC;KACjB,MAAM,CACL,IAAI,CAAC,SAAS,CACZ,gBAAgB,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAY,EAAgC,EAAE,CACxE,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CACtB,CACF,CACF;KACA,MAAM,CAAC,KAAK,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ploaness/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "The executable half of ploaness: the verification gates and the commands that run them.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Herman Ciechanowiec <herman@ciechanowiec.eu>",
|
|
@@ -32,13 +32,14 @@
|
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@biomejs/biome": "2.5.11",
|
|
35
|
-
"@ploaness/assets": "1.
|
|
36
|
-
"@ploaness/config": "1.
|
|
37
|
-
"@ploaness/governance": "1.
|
|
35
|
+
"@ploaness/assets": "1.3.0",
|
|
36
|
+
"@ploaness/config": "1.3.0",
|
|
37
|
+
"@ploaness/governance": "1.3.0",
|
|
38
38
|
"@vitest/coverage-v8": "4.1.11",
|
|
39
39
|
"dependency-cruiser": "18.2.0",
|
|
40
40
|
"eslint": "10.9.1",
|
|
41
41
|
"knip": "6.34.0",
|
|
42
|
+
"oxlint": "1.81.0",
|
|
42
43
|
"stylelint": "17.14.1",
|
|
43
44
|
"tsx": "4.23.13",
|
|
44
45
|
"type-coverage": "2.30.1",
|
|
@@ -52,7 +53,7 @@
|
|
|
52
53
|
"access": "public"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
|
-
"@types/node": "26.4.
|
|
56
|
+
"@types/node": "26.4.1"
|
|
56
57
|
},
|
|
57
58
|
"scripts": {
|
|
58
59
|
"build": "tsc --build"
|