renma 0.15.1 → 0.16.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/CHANGELOG.md +34 -1
- package/README.md +138 -38
- package/dist/agent-skills.d.ts +77 -0
- package/dist/agent-skills.d.ts.map +1 -0
- package/dist/agent-skills.js +468 -0
- package/dist/agent-skills.js.map +1 -0
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +38 -5
- package/dist/catalog.js.map +1 -1
- package/dist/cli-help.d.ts +8 -8
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +15 -3
- package/dist/cli-help.js.map +1 -1
- package/dist/commands/bom.d.ts +7 -0
- package/dist/commands/bom.d.ts.map +1 -1
- package/dist/commands/bom.js +24 -13
- package/dist/commands/bom.js.map +1 -1
- package/dist/commands/graph.d.ts +2 -1
- package/dist/commands/graph.d.ts.map +1 -1
- package/dist/commands/graph.js +3 -0
- package/dist/commands/graph.js.map +1 -1
- package/dist/commands/scaffold.d.ts.map +1 -1
- package/dist/commands/scaffold.js +45 -14
- package/dist/commands/scaffold.js.map +1 -1
- package/dist/commands/suggest-metadata.d.ts +3 -1
- package/dist/commands/suggest-metadata.d.ts.map +1 -1
- package/dist/commands/suggest-metadata.js +179 -6
- package/dist/commands/suggest-metadata.js.map +1 -1
- package/dist/diagnostic-ids.d.ts +29 -0
- package/dist/diagnostic-ids.d.ts.map +1 -1
- package/dist/diagnostic-ids.js +28 -0
- package/dist/diagnostic-ids.js.map +1 -1
- package/dist/discovery.d.ts +22 -0
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +124 -21
- package/dist/discovery.js.map +1 -1
- package/dist/metadata.d.ts +3 -1
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +166 -29
- package/dist/metadata.js.map +1 -1
- package/dist/model.d.ts +1 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +16 -1
- package/dist/report.js.map +1 -1
- package/dist/repository-evidence.d.ts +11 -1
- package/dist/repository-evidence.d.ts.map +1 -1
- package/dist/repository-evidence.js +22 -2
- package/dist/repository-evidence.js.map +1 -1
- package/dist/repository-paths.d.ts +6 -0
- package/dist/repository-paths.d.ts.map +1 -0
- package/dist/repository-paths.js +62 -0
- package/dist/repository-paths.js.map +1 -0
- package/dist/rules.d.ts +6 -1
- package/dist/rules.d.ts.map +1 -1
- package/dist/rules.js +111 -97
- package/dist/rules.js.map +1 -1
- package/dist/scanner.d.ts +7 -1
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +29 -29
- package/dist/scanner.js.map +1 -1
- package/dist/security-diagnostics.d.ts.map +1 -1
- package/dist/security-diagnostics.js +98 -35
- package/dist/security-diagnostics.js.map +1 -1
- package/dist/security-policy-inventory.js +11 -4
- package/dist/security-policy-inventory.js.map +1 -1
- package/dist/security-policy.d.ts +27 -1
- package/dist/security-policy.d.ts.map +1 -1
- package/dist/security-policy.js +247 -34
- package/dist/security-policy.js.map +1 -1
- package/dist/skill-migration.d.ts +30 -0
- package/dist/skill-migration.d.ts.map +1 -0
- package/dist/skill-migration.js +566 -0
- package/dist/skill-migration.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/yaml-frontmatter.d.ts +26 -0
- package/dist/yaml-frontmatter.d.ts.map +1 -0
- package/dist/yaml-frontmatter.js +114 -0
- package/dist/yaml-frontmatter.js.map +1 -0
- package/package.json +4 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ConfigOverrides } from "./config.js";
|
|
2
2
|
import { type ContextLensSummary } from "./context-lens.js";
|
|
3
3
|
import type { Catalog } from "./model.js";
|
|
4
|
-
import type { Diagnostic } from "./types.js";
|
|
4
|
+
import type { Artifact, Diagnostic, ParsedDocument, ScanConfig } from "./types.js";
|
|
5
5
|
export interface RepositoryEvidence {
|
|
6
6
|
root: string;
|
|
7
7
|
configPath?: string;
|
|
@@ -10,5 +10,15 @@ export interface RepositoryEvidence {
|
|
|
10
10
|
contextLens: ContextLensSummary;
|
|
11
11
|
diagnostics: Diagnostic[];
|
|
12
12
|
}
|
|
13
|
+
export interface RepositorySnapshot extends RepositoryEvidence {
|
|
14
|
+
config: ScanConfig;
|
|
15
|
+
artifacts: Artifact[];
|
|
16
|
+
documents: ParsedDocument[];
|
|
17
|
+
repositoryPaths: ReadonlySet<string>;
|
|
18
|
+
discoveryDiagnostics: Diagnostic[];
|
|
19
|
+
catalogDiagnostics: Diagnostic[];
|
|
20
|
+
contextLensDiagnostics: Diagnostic[];
|
|
21
|
+
}
|
|
13
22
|
export declare function collectRepositoryEvidence(targetPath: string, overrides?: ConfigOverrides): Promise<RepositoryEvidence>;
|
|
23
|
+
export declare function collectRepositorySnapshot(targetPath: string, overrides?: ConfigOverrides): Promise<RepositorySnapshot>;
|
|
14
24
|
//# sourceMappingURL=repository-evidence.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository-evidence.d.ts","sourceRoot":"","sources":["../src/repository-evidence.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"repository-evidence.d.ts","sourceRoot":"","sources":["../src/repository-evidence.ts"],"names":[],"mappings":"AAEA,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,cAAc,EACd,UAAU,EACX,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,kBAAkB,CAAC;IAChC,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAmB,SAAQ,kBAAkB;IAC5D,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,oBAAoB,EAAE,UAAU,EAAE,CAAC;IACnC,kBAAkB,EAAE,UAAU,EAAE,CAAC;IACjC,sBAAsB,EAAE,UAAU,EAAE,CAAC;CACtC;AAED,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,eAAoB,GAC9B,OAAO,CAAC,kBAAkB,CAAC,CAU7B;AAED,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,eAAoB,GAC9B,OAAO,CAAC,kBAAkB,CAAC,CAkC7B"}
|
|
@@ -4,21 +4,41 @@ import { loadConfig } from "./config.js";
|
|
|
4
4
|
import { summarizeContextLensGovernance, } from "./context-lens.js";
|
|
5
5
|
import { discoverArtifacts } from "./discovery.js";
|
|
6
6
|
import { parseDocument } from "./markdown.js";
|
|
7
|
+
import { collectRepositoryPaths } from "./repository-paths.js";
|
|
7
8
|
export async function collectRepositoryEvidence(targetPath, overrides = {}) {
|
|
9
|
+
const snapshot = await collectRepositorySnapshot(targetPath, overrides);
|
|
10
|
+
return {
|
|
11
|
+
root: snapshot.root,
|
|
12
|
+
...(snapshot.configPath ? { configPath: snapshot.configPath } : {}),
|
|
13
|
+
scannedFileCount: snapshot.scannedFileCount,
|
|
14
|
+
catalog: snapshot.catalog,
|
|
15
|
+
contextLens: snapshot.contextLens,
|
|
16
|
+
diagnostics: snapshot.diagnostics,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export async function collectRepositorySnapshot(targetPath, overrides = {}) {
|
|
8
20
|
const root = path.resolve(targetPath);
|
|
9
21
|
const { config, configPath } = await loadConfig(root, overrides);
|
|
10
|
-
const { artifacts, diagnostics } = await discoverArtifacts(root, config);
|
|
22
|
+
const { artifacts, diagnostics: discoveryDiagnostics } = await discoverArtifacts(root, config);
|
|
11
23
|
const documents = artifacts.map(parseDocument);
|
|
12
24
|
const built = buildCatalog(documents);
|
|
13
25
|
const contextLens = summarizeContextLensGovernance(documents, built.catalog);
|
|
26
|
+
const repositoryPaths = await collectRepositoryPaths(root, artifacts, documents, built.catalog);
|
|
14
27
|
return {
|
|
15
28
|
root,
|
|
16
29
|
...(configPath ? { configPath } : {}),
|
|
30
|
+
config,
|
|
31
|
+
artifacts,
|
|
32
|
+
documents,
|
|
33
|
+
repositoryPaths,
|
|
17
34
|
scannedFileCount: artifacts.length,
|
|
18
35
|
catalog: built.catalog,
|
|
19
36
|
contextLens: contextLens.summary,
|
|
37
|
+
discoveryDiagnostics,
|
|
38
|
+
catalogDiagnostics: built.diagnostics,
|
|
39
|
+
contextLensDiagnostics: contextLens.diagnostics,
|
|
20
40
|
diagnostics: [
|
|
21
|
-
...
|
|
41
|
+
...discoveryDiagnostics,
|
|
22
42
|
...built.diagnostics,
|
|
23
43
|
...contextLens.diagnostics,
|
|
24
44
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository-evidence.js","sourceRoot":"","sources":["../src/repository-evidence.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAwB,MAAM,aAAa,CAAC;AAC/D,OAAO,EACL,8BAA8B,GAE/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"repository-evidence.js","sourceRoot":"","sources":["../src/repository-evidence.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAwB,MAAM,aAAa,CAAC;AAC/D,OAAO,EACL,8BAA8B,GAE/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AA2B/D,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,UAAkB,EAClB,YAA6B,EAAE;IAE/B,MAAM,QAAQ,GAAG,MAAM,yBAAyB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IACxE,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;QAC3C,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,WAAW,EAAE,QAAQ,CAAC,WAAW;KAClC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,UAAkB,EAClB,YAA6B,EAAE;IAE/B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACjE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,oBAAoB,EAAE,GACpD,MAAM,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IACtC,MAAM,WAAW,GAAG,8BAA8B,CAAC,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7E,MAAM,eAAe,GAAG,MAAM,sBAAsB,CAClD,IAAI,EACJ,SAAS,EACT,SAAS,EACT,KAAK,CAAC,OAAO,CACd,CAAC;IAEF,OAAO;QACL,IAAI;QACJ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,MAAM;QACN,SAAS;QACT,SAAS;QACT,eAAe;QACf,gBAAgB,EAAE,SAAS,CAAC,MAAM;QAClC,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,WAAW,EAAE,WAAW,CAAC,OAAO;QAChC,oBAAoB;QACpB,kBAAkB,EAAE,KAAK,CAAC,WAAW;QACrC,sBAAsB,EAAE,WAAW,CAAC,WAAW;QAC/C,WAAW,EAAE;YACX,GAAG,oBAAoB;YACvB,GAAG,KAAK,CAAC,WAAW;YACpB,GAAG,WAAW,CAAC,WAAW;SAC3B;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Catalog } from "./model.js";
|
|
2
|
+
import type { Artifact, ParsedDocument } from "./types.js";
|
|
3
|
+
/** Collect immutable repository-relative path existence evidence for rules. */
|
|
4
|
+
export declare function collectRepositoryPaths(root: string, artifacts: Artifact[], documents: ParsedDocument[], catalog: Catalog): Promise<ReadonlySet<string>>;
|
|
5
|
+
export declare function helperScriptPath(command: string): string | undefined;
|
|
6
|
+
//# sourceMappingURL=repository-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-paths.d.ts","sourceRoot":"","sources":["../src/repository-paths.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE3D,+EAA+E;AAC/E,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,QAAQ,EAAE,EACrB,SAAS,EAAE,cAAc,EAAE,EAC3B,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAa9B;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKpE"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
/** Collect immutable repository-relative path existence evidence for rules. */
|
|
4
|
+
export async function collectRepositoryPaths(root, artifacts, documents, catalog) {
|
|
5
|
+
const paths = new Set(artifacts
|
|
6
|
+
.map((artifact) => normalizeRepositoryPath(artifact.path))
|
|
7
|
+
.filter((candidate) => candidate !== undefined));
|
|
8
|
+
for (const candidate of repositoryPathCandidates(documents, catalog)) {
|
|
9
|
+
if (paths.has(candidate))
|
|
10
|
+
continue;
|
|
11
|
+
if (await repositoryPathExists(root, candidate))
|
|
12
|
+
paths.add(candidate);
|
|
13
|
+
}
|
|
14
|
+
return paths;
|
|
15
|
+
}
|
|
16
|
+
export function helperScriptPath(command) {
|
|
17
|
+
const parts = command.split(/\s+/).slice(1);
|
|
18
|
+
return parts.find((part) => /(?:^|\/)scripts\/.+\.(?:mjs|js|cjs|sh|bash|py)$/.test(part));
|
|
19
|
+
}
|
|
20
|
+
function repositoryPathCandidates(documents, catalog) {
|
|
21
|
+
return [
|
|
22
|
+
...helperCommandPathCandidates(documents),
|
|
23
|
+
...catalog.dependencies
|
|
24
|
+
.map((dependency) => dependency.to)
|
|
25
|
+
.map(normalizeRepositoryPath)
|
|
26
|
+
.filter((candidate) => candidate !== undefined)
|
|
27
|
+
.filter(isRepoPathLike),
|
|
28
|
+
].filter((candidate, index, candidates) => candidates.indexOf(candidate) === index);
|
|
29
|
+
}
|
|
30
|
+
function helperCommandPathCandidates(documents) {
|
|
31
|
+
return documents.flatMap((document) => document.codeFences.flatMap((fence) => fence.content
|
|
32
|
+
.split(/\r?\n/)
|
|
33
|
+
.map((line) => line.trim())
|
|
34
|
+
.filter((command) => /^(node|bash|sh|python|python3)\s+/.test(command))
|
|
35
|
+
.map(helperScriptPath)
|
|
36
|
+
.map((candidate) => candidate ? normalizeRepositoryPath(candidate) : undefined)
|
|
37
|
+
.filter((candidate) => candidate !== undefined)));
|
|
38
|
+
}
|
|
39
|
+
function normalizeRepositoryPath(value) {
|
|
40
|
+
const normalized = value.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
41
|
+
if (!normalized ||
|
|
42
|
+
path.posix.isAbsolute(normalized) ||
|
|
43
|
+
normalized === ".." ||
|
|
44
|
+
normalized.startsWith("../") ||
|
|
45
|
+
normalized.split("/").includes("..")) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
return normalized;
|
|
49
|
+
}
|
|
50
|
+
async function repositoryPathExists(root, relativePath) {
|
|
51
|
+
try {
|
|
52
|
+
await access(path.join(root, relativePath));
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function isRepoPathLike(value) {
|
|
60
|
+
return /^[A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)+$/.test(value);
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=repository-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository-paths.js","sourceRoot":"","sources":["../src/repository-paths.ts"],"names":[],"mappings":"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"}
|
package/dist/rules.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { Catalog } from "./model.js";
|
|
2
2
|
import type { Finding, ParsedDocument, ScanConfig, Severity } from "./types.js";
|
|
3
|
+
interface RuleOptions {
|
|
4
|
+
evaluationDate?: Date | string;
|
|
5
|
+
repositoryPaths?: ReadonlySet<string>;
|
|
6
|
+
}
|
|
3
7
|
/** Run all deterministic rules and return findings in stable source order. */
|
|
4
|
-
export declare function runRules(documents: ParsedDocument[], config: ScanConfig, catalog?: Catalog): Finding[];
|
|
8
|
+
export declare function runRules(documents: ParsedDocument[], config: ScanConfig, catalog?: Catalog, options?: RuleOptions): Finding[];
|
|
5
9
|
/** Return whether a severity is at least as severe as a configured threshold. */
|
|
6
10
|
export declare function severityMeets(value: Severity, threshold: Severity): boolean;
|
|
11
|
+
export {};
|
|
7
12
|
//# sourceMappingURL=rules.d.ts.map
|
package/dist/rules.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAA4B,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAA4B,MAAM,YAAY,CAAC;AAWpE,OAAO,KAAK,EAEV,OAAO,EAEP,cAAc,EACd,UAAU,EACV,QAAQ,EACT,MAAM,YAAY,CAAC;AAcpB,UAAU,WAAW;IACnB,cAAc,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IAC/B,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACvC;AA+HD,8EAA8E;AAC9E,wBAAgB,QAAQ,CACtB,SAAS,EAAE,cAAc,EAAE,EAC3B,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE,OAAO,EACjB,OAAO,GAAE,WAAgB,GACxB,OAAO,EAAE,CAeX;AAmmBD,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAQ3E"}
|
package/dist/rules.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
1
|
import path from "node:path";
|
|
2
|
+
import { resolvedAgentSkillDescription } from "./agent-skills.js";
|
|
3
3
|
import { addDaysIsoDate, isIsoDate, parseDayDuration, todayIsoDate, } from "./freshness.js";
|
|
4
4
|
import { DIAGNOSTIC_IDS } from "./diagnostic-ids.js";
|
|
5
|
+
import { helperScriptPath } from "./repository-paths.js";
|
|
6
|
+
import { parseAssetMetadata } from "./metadata.js";
|
|
5
7
|
import { runRuleRegistry } from "./rule-engine.js";
|
|
6
8
|
const SECRET_PATTERN = /\b(?:password|passwd|token|api[_-]?key|secret|credential|private[_-]?key)\b\s*[:=]\s*["']?([A-Za-z0-9_./+=-]{8,})/i;
|
|
7
9
|
const PRIVATE_KEY_PATTERN = /-----BEGIN (?:RSA |OPENSSH |EC |DSA )?PRIVATE KEY-----/;
|
|
@@ -118,8 +120,8 @@ const CONTEXT_TOKEN_LIMITS = {
|
|
|
118
120
|
example: 800,
|
|
119
121
|
};
|
|
120
122
|
/** Run all deterministic rules and return findings in stable source order. */
|
|
121
|
-
export function runRules(documents, config, catalog) {
|
|
122
|
-
const findings = runRuleRegistry(documents,
|
|
123
|
+
export function runRules(documents, config, catalog, options = {}) {
|
|
124
|
+
const findings = runRuleRegistry(documents, rulesForEvaluationDate(evaluationDay(options.evaluationDate), options.repositoryPaths), catalog, config);
|
|
123
125
|
return findings.sort((a, b) => {
|
|
124
126
|
const byPath = a.evidence.path.localeCompare(b.evidence.path);
|
|
125
127
|
if (byPath !== 0)
|
|
@@ -127,56 +129,71 @@ export function runRules(documents, config, catalog) {
|
|
|
127
129
|
return a.evidence.startLine - b.evidence.startLine;
|
|
128
130
|
});
|
|
129
131
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
132
|
+
function rulesForEvaluationDate(evaluationDate, repositoryPaths) {
|
|
133
|
+
return [
|
|
134
|
+
{
|
|
135
|
+
id: "strict-layout-policy",
|
|
136
|
+
run: (context) => strictLayoutPolicyFindings(context.documents, context.config, context.catalog, repositoryPaths),
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
id: "security",
|
|
140
|
+
run: ({ documents }) => documents.flatMap((document) => [
|
|
141
|
+
...secretFindings(document),
|
|
142
|
+
...commandFindings(document),
|
|
143
|
+
]),
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
id: "shape",
|
|
147
|
+
run: ({ documents }) => documents.flatMap((document) => [
|
|
148
|
+
...shapeFindings(document),
|
|
149
|
+
...contextBudgetFindings(document),
|
|
150
|
+
...profileFindings(document),
|
|
151
|
+
]),
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
id: "skill-local-support-reachability",
|
|
155
|
+
run: ({ documents }) => skillLocalSupportReachabilityFindings(documents),
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
id: "support-asset-shared-context-candidate",
|
|
159
|
+
run: ({ documents }) => documents.flatMap((document) => supportSharedContextCandidateFindings(document)),
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
id: "context-path-non-semantic",
|
|
163
|
+
run: ({ documents }) => documents.flatMap((document) => contextPathNonSemanticFindings(document)),
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
id: "skill-context-reference-not-declared",
|
|
167
|
+
run: ({ documents }) => documents.flatMap((document) => skillContextReferenceNotDeclaredFindings(document)),
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
id: "skill-references-superseded-asset",
|
|
171
|
+
run: ({ documents }) => skillReferencesSupersededAssetFindings(documents),
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
id: "asset-references-superseded-asset",
|
|
175
|
+
run: ({ documents }) => assetReferencesSupersededAssetFindings(documents),
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: "catalog-declared-reference-governance",
|
|
179
|
+
run: ({ catalog }) => catalogDeclaredReferenceGovernanceFindings(catalog, evaluationDate),
|
|
180
|
+
},
|
|
181
|
+
];
|
|
182
|
+
}
|
|
183
|
+
function evaluationDay(value) {
|
|
184
|
+
if (value === undefined)
|
|
185
|
+
return todayIsoDate();
|
|
186
|
+
if (value instanceof Date)
|
|
187
|
+
return todayIsoDate(value);
|
|
188
|
+
if (isIsoDate(value))
|
|
189
|
+
return value;
|
|
190
|
+
const parsed = new Date(value);
|
|
191
|
+
if (Number.isNaN(parsed.getTime())) {
|
|
192
|
+
throw new Error(`Invalid internal evaluation date: ${value}`);
|
|
193
|
+
}
|
|
194
|
+
return todayIsoDate(parsed);
|
|
195
|
+
}
|
|
196
|
+
function catalogDeclaredReferenceGovernanceFindings(catalog, today) {
|
|
180
197
|
if (!catalog)
|
|
181
198
|
return [];
|
|
182
199
|
const resolver = createCatalogReferenceResolver(catalog.entries);
|
|
@@ -187,7 +204,7 @@ function catalogDeclaredReferenceGovernanceFindings(catalog) {
|
|
|
187
204
|
...orphanedContextAssetFindings(catalog.entries, catalog.dependencies, resolver),
|
|
188
205
|
...orphanedContextLensFindings(catalog.entries, resolver),
|
|
189
206
|
...contextLensAppliesToInactiveContextFindings(catalog.dependencies, resolver),
|
|
190
|
-
...freshnessGovernanceFindings(catalog.entries),
|
|
207
|
+
...freshnessGovernanceFindings(catalog.entries, today),
|
|
191
208
|
];
|
|
192
209
|
return findings;
|
|
193
210
|
}
|
|
@@ -419,7 +436,7 @@ function orphanedContextLensFindings(entries, resolver) {
|
|
|
419
436
|
confidence: "medium",
|
|
420
437
|
evidence: metadataFindingEvidence(entry.sourcePath, "Active context lens has no incoming requires_lens or optional_lens references from skills."),
|
|
421
438
|
whyItMatters: "Context lenses are easier to review when a skill declares how the purpose-oriented interpretation is used. An unreferenced active lens may be newly created, intentionally staged, or stale.",
|
|
422
|
-
remediation: "If the lens should be used, reference it from a
|
|
439
|
+
remediation: "If the lens should be used, reference it from a canonical Skill with metadata.renma.requires-lens or metadata.renma.optional-lens JSON-array metadata. Pre-0.16-only Skills use requires_lens or optional_lens only during migration. If the lens is not ready or no longer needed, update its lifecycle status after review.",
|
|
423
440
|
constraints: [
|
|
424
441
|
"Do not make Renma select runtime lenses.",
|
|
425
442
|
"Do not rank or retrieve lenses semantically.",
|
|
@@ -431,7 +448,7 @@ function orphanedContextLensFindings(entries, resolver) {
|
|
|
431
448
|
"Run renma catalog.",
|
|
432
449
|
"Run renma graph focused on the lens or owning skill.",
|
|
433
450
|
],
|
|
434
|
-
llmHint: `Search for
|
|
451
|
+
llmHint: `Search for Skills that should declare "${entry.id}" as a required or optional lens. For canonical Skills, update metadata.renma.requires-lens or metadata.renma.optional-lens as a JSON-array string; use requires_lens or optional_lens only for pre-0.16 migration inputs. Do not add runtime selection logic or prompt assembly.`,
|
|
435
452
|
details: {
|
|
436
453
|
assetId: entry.id,
|
|
437
454
|
sourcePath: entry.sourcePath,
|
|
@@ -625,7 +642,9 @@ function shapeFindings(document) {
|
|
|
625
642
|
return [];
|
|
626
643
|
const text = document.artifact.content.toLowerCase();
|
|
627
644
|
const findings = [];
|
|
628
|
-
const description = document.
|
|
645
|
+
const description = document.artifact.kind === "skill"
|
|
646
|
+
? (resolvedAgentSkillDescription(document) ?? "")
|
|
647
|
+
: (document.metadata.description ?? "");
|
|
629
648
|
const tokenCount = approximateTokenCount(document.artifact.content);
|
|
630
649
|
if (!description) {
|
|
631
650
|
findings.push(documentFinding(document, DIAGNOSTIC_IDS.QUAL_MISSING_DESCRIPTION, "Skill is missing an explicit description", "quality", "medium", "Add frontmatter description so agents can route to the skill intentionally."));
|
|
@@ -921,7 +940,8 @@ function contextPathNonSemanticFindings(document) {
|
|
|
921
940
|
function skillContextReferenceNotDeclaredFindings(document) {
|
|
922
941
|
if (document.artifact.kind !== "skill")
|
|
923
942
|
return [];
|
|
924
|
-
const
|
|
943
|
+
const operationalMetadata = parseAssetMetadata(document).metadata;
|
|
944
|
+
const declaredContexts = new Set(operationalMetadata.requiresContext);
|
|
925
945
|
const bodyLineIndexes = markdownBodyLineIndexes(document);
|
|
926
946
|
const matches = new Map();
|
|
927
947
|
for (const index of bodyLineIndexes) {
|
|
@@ -946,7 +966,7 @@ function skillContextReferenceNotDeclaredFindings(document) {
|
|
|
946
966
|
confidence: "high",
|
|
947
967
|
evidence: evidence(document, match.line, match.text),
|
|
948
968
|
whyItMatters: "Declared context references make skill/context relationships visible to catalog, graph, and validation reports. If a skill only mentions a context in prose, humans may see the dependency but repository tooling cannot validate it.",
|
|
949
|
-
remediation: "Add the referenced shared context asset to
|
|
969
|
+
remediation: "Add the referenced shared context asset to metadata.renma.requires-context as a JSON-array string, or remove the prose reference if it is no longer needed. Pre-0.16 requires_context is migration input only and is not operational in Renma 0.16.0.",
|
|
950
970
|
constraints: [
|
|
951
971
|
"Do not select runtime context.",
|
|
952
972
|
"Do not assemble prompt packages.",
|
|
@@ -958,9 +978,9 @@ function skillContextReferenceNotDeclaredFindings(document) {
|
|
|
958
978
|
"Run renma catalog.",
|
|
959
979
|
"Confirm the skill/context relationship appears in metadata and catalog output.",
|
|
960
980
|
],
|
|
961
|
-
llmHint: `Find context paths mentioned in the
|
|
981
|
+
llmHint: `Find context paths mentioned in the Skill body and add the missing declaration using metadata.renma.requires-context as a JSON-array string. Pre-0.16 requires_context is accepted only by suggest-metadata and is not operational. Missing declaration: ${referencedPath}`,
|
|
962
982
|
details: {
|
|
963
|
-
source:
|
|
983
|
+
source: operationalMetadata.id ?? document.artifact.path,
|
|
964
984
|
target: referencedPath,
|
|
965
985
|
referenceKind: "requires_context",
|
|
966
986
|
sourcePath: document.artifact.path,
|
|
@@ -987,6 +1007,7 @@ function skillReferencesSupersededAssetFindings(documents) {
|
|
|
987
1007
|
const skill = skillsByPath.get(skillPath);
|
|
988
1008
|
if (!skill)
|
|
989
1009
|
return [];
|
|
1010
|
+
const skillMetadata = parseAssetMetadata(skill).metadata;
|
|
990
1011
|
const referencedFrom = skillReferenceLine(skill, document.artifact.path);
|
|
991
1012
|
if (!referencedFrom)
|
|
992
1013
|
return [];
|
|
@@ -1027,7 +1048,7 @@ function skillReferencesSupersededAssetFindings(documents) {
|
|
|
1027
1048
|
],
|
|
1028
1049
|
llmHint: "Inspect the deprecated local support file and its superseded_by or canonical_context metadata. If the shared context asset is now canonical, update skill guidance and metadata to reference the shared context directly. Keep the local reference only if it contains truly local notes or is intentionally preserved as a compatibility shim.",
|
|
1029
1050
|
details: {
|
|
1030
|
-
source:
|
|
1051
|
+
source: skillMetadata.id ?? skill.artifact.path,
|
|
1031
1052
|
target: metadataText(document.metadata.id) ?? document.artifact.path,
|
|
1032
1053
|
referenceKind: "body_reference",
|
|
1033
1054
|
sourcePath: skill.artifact.path,
|
|
@@ -1044,8 +1065,9 @@ function isSkillLocalReference(document) {
|
|
|
1044
1065
|
/^skills\/[^/]+\/references\/.+\.md$/u.test(document.artifact.path));
|
|
1045
1066
|
}
|
|
1046
1067
|
function sharedContextTargets(document) {
|
|
1068
|
+
const operationalMetadata = parseAssetMetadata(document).metadata;
|
|
1047
1069
|
return [
|
|
1048
|
-
...
|
|
1070
|
+
...operationalMetadata.supersededBy,
|
|
1049
1071
|
...listMetadataValue(document.metadata.canonical_context),
|
|
1050
1072
|
].filter((target, index, targets) => /^contexts?\//u.test(target) && targets.indexOf(target) === index);
|
|
1051
1073
|
}
|
|
@@ -1069,18 +1091,23 @@ function skillReferenceLine(skill, referencePath) {
|
|
|
1069
1091
|
}
|
|
1070
1092
|
function assetReferencesSupersededAssetFindings(documents) {
|
|
1071
1093
|
const supersededAssets = documents
|
|
1072
|
-
.map((document) =>
|
|
1073
|
-
document
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1094
|
+
.map((document) => {
|
|
1095
|
+
const metadata = parseAssetMetadata(document).metadata;
|
|
1096
|
+
return {
|
|
1097
|
+
document,
|
|
1098
|
+
metadata,
|
|
1099
|
+
canonicalTargets: sharedContextTargets(document),
|
|
1100
|
+
};
|
|
1101
|
+
})
|
|
1102
|
+
.filter(({ metadata, canonicalTargets }) => metadata.status === "deprecated" ||
|
|
1103
|
+
metadata.status === "archived" ||
|
|
1078
1104
|
canonicalTargets.length > 0)
|
|
1079
1105
|
.filter(({ canonicalTargets }) => canonicalTargets.length > 0);
|
|
1080
1106
|
return documents.flatMap((referencingDocument) => {
|
|
1081
1107
|
if (referencingDocument.artifact.kind === "skill")
|
|
1082
1108
|
return [];
|
|
1083
|
-
|
|
1109
|
+
const referencingMetadata = parseAssetMetadata(referencingDocument).metadata;
|
|
1110
|
+
return supersededAssets.flatMap(({ document, metadata, canonicalTargets }) => {
|
|
1084
1111
|
if (document.artifact.path === referencingDocument.artifact.path) {
|
|
1085
1112
|
return [];
|
|
1086
1113
|
}
|
|
@@ -1124,13 +1151,12 @@ function assetReferencesSupersededAssetFindings(documents) {
|
|
|
1124
1151
|
],
|
|
1125
1152
|
llmHint: "Inspect the referenced deprecated asset and its superseded_by or canonical context metadata. If the canonical shared context is the intended source of truth, update this asset to reference that context directly. Keep the superseded file only when it serves a deliberate compatibility or migration role.",
|
|
1126
1153
|
details: {
|
|
1127
|
-
source:
|
|
1128
|
-
|
|
1129
|
-
target: metadataText(document.metadata.id) ?? document.artifact.path,
|
|
1154
|
+
source: referencingMetadata.id ?? referencingDocument.artifact.path,
|
|
1155
|
+
target: metadata.id ?? document.artifact.path,
|
|
1130
1156
|
referenceKind: "body_reference",
|
|
1131
1157
|
sourcePath: referencingDocument.artifact.path,
|
|
1132
1158
|
targetPath: document.artifact.path,
|
|
1133
|
-
targetStatus:
|
|
1159
|
+
targetStatus: metadata.status,
|
|
1134
1160
|
replacementTargets: canonicalTargets,
|
|
1135
1161
|
},
|
|
1136
1162
|
},
|
|
@@ -1321,20 +1347,20 @@ function matchingLineFindings(document, matcher) {
|
|
|
1321
1347
|
];
|
|
1322
1348
|
});
|
|
1323
1349
|
}
|
|
1324
|
-
function strictLayoutPolicyFindings(documents, config, catalog) {
|
|
1350
|
+
function strictLayoutPolicyFindings(documents, config, catalog, repositoryPaths) {
|
|
1325
1351
|
const findings = [];
|
|
1326
|
-
const
|
|
1327
|
-
|
|
1352
|
+
const paths = repositoryPaths ??
|
|
1353
|
+
new Set(documents.map((document) => document.artifact.path));
|
|
1328
1354
|
for (const document of documents) {
|
|
1329
1355
|
findings.push(...disallowedSkillAssetFindings(document, config));
|
|
1330
1356
|
findings.push(...thinSkillLayoutFindings(document));
|
|
1331
|
-
findings.push(...helperCommandFindings(document,
|
|
1357
|
+
findings.push(...helperCommandFindings(document, paths, config));
|
|
1332
1358
|
findings.push(...layoutConsistencyFindings(document));
|
|
1333
1359
|
findings.push(...contextRootFindings(document));
|
|
1334
1360
|
findings.push(...helperRootFindings(document));
|
|
1335
1361
|
}
|
|
1336
1362
|
if (catalog) {
|
|
1337
|
-
findings.push(...declaredDependencyLayoutFindings(catalog, paths
|
|
1363
|
+
findings.push(...declaredDependencyLayoutFindings(catalog, paths));
|
|
1338
1364
|
}
|
|
1339
1365
|
return findings;
|
|
1340
1366
|
}
|
|
@@ -1381,7 +1407,7 @@ function thinSkillLayoutFindings(document) {
|
|
|
1381
1407
|
"Confirm SKILL.md contains routing guidance and required context references only.",
|
|
1382
1408
|
"Run renma readiness and check layout.skills_thin.",
|
|
1383
1409
|
],
|
|
1384
|
-
llmHint: "Extract long procedure sections into contexts/**, add
|
|
1410
|
+
llmHint: "Extract long procedure sections into contexts/**, add metadata.renma.requires-context or metadata.renma.optional-context JSON-array strings, and keep SKILL.md focused on when to use or not use the Skill. Pre-0.16 top-level references are migration input only.",
|
|
1385
1411
|
}));
|
|
1386
1412
|
}
|
|
1387
1413
|
const command = firstExecutableCommand(document);
|
|
@@ -1396,7 +1422,7 @@ function thinSkillLayoutFindings(document) {
|
|
|
1396
1422
|
}
|
|
1397
1423
|
return findings;
|
|
1398
1424
|
}
|
|
1399
|
-
function helperCommandFindings(document,
|
|
1425
|
+
function helperCommandFindings(document, paths, config) {
|
|
1400
1426
|
const findings = [];
|
|
1401
1427
|
for (const command of executableCommands(document)) {
|
|
1402
1428
|
const scriptPath = helperScriptPath(command.command);
|
|
@@ -1418,9 +1444,7 @@ function helperCommandFindings(document, root, paths, config) {
|
|
|
1418
1444
|
}));
|
|
1419
1445
|
continue;
|
|
1420
1446
|
}
|
|
1421
|
-
if (scriptPath.startsWith("tools/") &&
|
|
1422
|
-
!paths.has(scriptPath) &&
|
|
1423
|
-
!(root && existsSync(path.join(root, scriptPath)))) {
|
|
1447
|
+
if (scriptPath.startsWith("tools/") && !paths.has(scriptPath)) {
|
|
1424
1448
|
findings.push(findingAt(document, DIAGNOSTIC_IDS.PATH_HELPER_COMMAND_UNRESOLVED, "Helper command target does not resolve", "structure", "medium", command.line, command.command, `Create \`${scriptPath}\` or update this command to the correct tools/** helper path.`, {
|
|
1425
1449
|
whyItMatters: "Agents need helper commands in markdown procedures to resolve deterministically before running them.",
|
|
1426
1450
|
}));
|
|
@@ -1488,13 +1512,13 @@ function helperRootFindings(document) {
|
|
|
1488
1512
|
}
|
|
1489
1513
|
return [];
|
|
1490
1514
|
}
|
|
1491
|
-
function declaredDependencyLayoutFindings(catalog, paths
|
|
1515
|
+
function declaredDependencyLayoutFindings(catalog, paths) {
|
|
1492
1516
|
const findings = [];
|
|
1493
1517
|
for (const dependency of catalog.dependencies) {
|
|
1494
1518
|
const target = dependency.to;
|
|
1495
1519
|
if (!isRepoPathLike(target))
|
|
1496
1520
|
continue;
|
|
1497
|
-
if (!paths.has(target)
|
|
1521
|
+
if (!paths.has(target)) {
|
|
1498
1522
|
continue;
|
|
1499
1523
|
}
|
|
1500
1524
|
if (target.startsWith("contexts/") ||
|
|
@@ -1513,7 +1537,7 @@ function declaredDependencyLayoutFindings(catalog, paths, root) {
|
|
|
1513
1537
|
confidence: "medium",
|
|
1514
1538
|
evidence: metadataFindingEvidence(source.sourcePath, target),
|
|
1515
1539
|
whyItMatters: "Declared context references should resolve through canonical contexts/**, skills/**, or tools/** repo paths.",
|
|
1516
|
-
remediation: "Rewrite declared
|
|
1540
|
+
remediation: "Rewrite declared required or optional context dependency values to canonical repo-root paths without changing the Skill's operational metadata format.",
|
|
1517
1541
|
verificationSteps: ["Run renma graph and confirm all edges resolve."],
|
|
1518
1542
|
details: {
|
|
1519
1543
|
source: dependency.from,
|
|
@@ -1537,10 +1561,6 @@ function executableCommands(document) {
|
|
|
1537
1561
|
function firstExecutableCommand(document) {
|
|
1538
1562
|
return executableCommands(document)[0];
|
|
1539
1563
|
}
|
|
1540
|
-
function helperScriptPath(command) {
|
|
1541
|
-
const parts = command.split(/\s+/).slice(1);
|
|
1542
|
-
return parts.find((part) => /(?:^|\/)scripts\/.+\.(?:mjs|js|cjs|sh|bash|py)$/.test(part));
|
|
1543
|
-
}
|
|
1544
1564
|
function canonicalHelperTarget(config, scriptPath) {
|
|
1545
1565
|
const parts = scriptPath.split("/");
|
|
1546
1566
|
const skillName = parts[1] ?? "unknown";
|
|
@@ -1563,12 +1583,6 @@ function helperAssetPath(config, workflow, rest) {
|
|
|
1563
1583
|
function isCanonicalSkillEntrypoint(pathValue) {
|
|
1564
1584
|
return /^skills\/[^/]+\/SKILL\.md$/.test(pathValue);
|
|
1565
1585
|
}
|
|
1566
|
-
function repositoryRoot(documents) {
|
|
1567
|
-
const document = documents[0];
|
|
1568
|
-
if (!document)
|
|
1569
|
-
return undefined;
|
|
1570
|
-
return document.artifact.absolutePath.slice(0, document.artifact.absolutePath.length - document.artifact.path.length);
|
|
1571
|
-
}
|
|
1572
1586
|
function findingAt(document, id, title, category, severity, line, snippet, remediation, details = {}) {
|
|
1573
1587
|
return {
|
|
1574
1588
|
...finding(id, title, category, severity, document, remediation, details),
|