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.
Files changed (81) hide show
  1. package/CHANGELOG.md +34 -1
  2. package/README.md +138 -38
  3. package/dist/agent-skills.d.ts +77 -0
  4. package/dist/agent-skills.d.ts.map +1 -0
  5. package/dist/agent-skills.js +468 -0
  6. package/dist/agent-skills.js.map +1 -0
  7. package/dist/catalog.d.ts.map +1 -1
  8. package/dist/catalog.js +38 -5
  9. package/dist/catalog.js.map +1 -1
  10. package/dist/cli-help.d.ts +8 -8
  11. package/dist/cli-help.d.ts.map +1 -1
  12. package/dist/cli-help.js +15 -3
  13. package/dist/cli-help.js.map +1 -1
  14. package/dist/commands/bom.d.ts +7 -0
  15. package/dist/commands/bom.d.ts.map +1 -1
  16. package/dist/commands/bom.js +24 -13
  17. package/dist/commands/bom.js.map +1 -1
  18. package/dist/commands/graph.d.ts +2 -1
  19. package/dist/commands/graph.d.ts.map +1 -1
  20. package/dist/commands/graph.js +3 -0
  21. package/dist/commands/graph.js.map +1 -1
  22. package/dist/commands/scaffold.d.ts.map +1 -1
  23. package/dist/commands/scaffold.js +45 -14
  24. package/dist/commands/scaffold.js.map +1 -1
  25. package/dist/commands/suggest-metadata.d.ts +3 -1
  26. package/dist/commands/suggest-metadata.d.ts.map +1 -1
  27. package/dist/commands/suggest-metadata.js +179 -6
  28. package/dist/commands/suggest-metadata.js.map +1 -1
  29. package/dist/diagnostic-ids.d.ts +29 -0
  30. package/dist/diagnostic-ids.d.ts.map +1 -1
  31. package/dist/diagnostic-ids.js +28 -0
  32. package/dist/diagnostic-ids.js.map +1 -1
  33. package/dist/discovery.d.ts +22 -0
  34. package/dist/discovery.d.ts.map +1 -1
  35. package/dist/discovery.js +124 -21
  36. package/dist/discovery.js.map +1 -1
  37. package/dist/metadata.d.ts +3 -1
  38. package/dist/metadata.d.ts.map +1 -1
  39. package/dist/metadata.js +166 -29
  40. package/dist/metadata.js.map +1 -1
  41. package/dist/model.d.ts +1 -0
  42. package/dist/model.d.ts.map +1 -1
  43. package/dist/report.d.ts.map +1 -1
  44. package/dist/report.js +16 -1
  45. package/dist/report.js.map +1 -1
  46. package/dist/repository-evidence.d.ts +11 -1
  47. package/dist/repository-evidence.d.ts.map +1 -1
  48. package/dist/repository-evidence.js +22 -2
  49. package/dist/repository-evidence.js.map +1 -1
  50. package/dist/repository-paths.d.ts +6 -0
  51. package/dist/repository-paths.d.ts.map +1 -0
  52. package/dist/repository-paths.js +62 -0
  53. package/dist/repository-paths.js.map +1 -0
  54. package/dist/rules.d.ts +6 -1
  55. package/dist/rules.d.ts.map +1 -1
  56. package/dist/rules.js +111 -97
  57. package/dist/rules.js.map +1 -1
  58. package/dist/scanner.d.ts +7 -1
  59. package/dist/scanner.d.ts.map +1 -1
  60. package/dist/scanner.js +29 -29
  61. package/dist/scanner.js.map +1 -1
  62. package/dist/security-diagnostics.d.ts.map +1 -1
  63. package/dist/security-diagnostics.js +98 -35
  64. package/dist/security-diagnostics.js.map +1 -1
  65. package/dist/security-policy-inventory.js +11 -4
  66. package/dist/security-policy-inventory.js.map +1 -1
  67. package/dist/security-policy.d.ts +27 -1
  68. package/dist/security-policy.d.ts.map +1 -1
  69. package/dist/security-policy.js +247 -34
  70. package/dist/security-policy.js.map +1 -1
  71. package/dist/skill-migration.d.ts +30 -0
  72. package/dist/skill-migration.d.ts.map +1 -0
  73. package/dist/skill-migration.js +566 -0
  74. package/dist/skill-migration.js.map +1 -0
  75. package/dist/types.d.ts +2 -0
  76. package/dist/types.d.ts.map +1 -1
  77. package/dist/yaml-frontmatter.d.ts +26 -0
  78. package/dist/yaml-frontmatter.d.ts.map +1 -0
  79. package/dist/yaml-frontmatter.js +114 -0
  80. package/dist/yaml-frontmatter.js.map +1 -0
  81. 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;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,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,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,eAAoB,GAC9B,OAAO,CAAC,kBAAkB,CAAC,CAoB7B"}
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
- ...diagnostics,
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;AAa9C,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,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACzE,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;IAE7E,OAAO;QACL,IAAI;QACJ,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,gBAAgB,EAAE,SAAS,CAAC,MAAM;QAClC,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,WAAW,EAAE,WAAW,CAAC,OAAO;QAChC,WAAW,EAAE;YACX,GAAG,WAAW;YACd,GAAG,KAAK,CAAC,WAAW;YACpB,GAAG,WAAW,CAAC,WAAW;SAC3B;KACF,CAAC;AACJ,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
@@ -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;AASpE,OAAO,KAAK,EAEV,OAAO,EAEP,cAAc,EACd,UAAU,EACV,QAAQ,EACT,MAAM,YAAY,CAAC;AA2IpB,8EAA8E;AAC9E,wBAAgB,QAAQ,CACtB,SAAS,EAAE,cAAc,EAAE,EAC3B,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,EAAE,CAOX;AA6kBD,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAQ3E"}
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, RULES, catalog, config);
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
- const RULES = [
131
- {
132
- id: "strict-layout-policy",
133
- run: (context) => strictLayoutPolicyFindings(context.documents, context.config, context.catalog),
134
- },
135
- {
136
- id: "security",
137
- run: ({ documents }) => documents.flatMap((document) => [
138
- ...secretFindings(document),
139
- ...commandFindings(document),
140
- ]),
141
- },
142
- {
143
- id: "shape",
144
- run: ({ documents }) => documents.flatMap((document) => [
145
- ...shapeFindings(document),
146
- ...contextBudgetFindings(document),
147
- ...profileFindings(document),
148
- ]),
149
- },
150
- {
151
- id: "skill-local-support-reachability",
152
- run: ({ documents }) => skillLocalSupportReachabilityFindings(documents),
153
- },
154
- {
155
- id: "support-asset-shared-context-candidate",
156
- run: ({ documents }) => documents.flatMap((document) => supportSharedContextCandidateFindings(document)),
157
- },
158
- {
159
- id: "context-path-non-semantic",
160
- run: ({ documents }) => documents.flatMap((document) => contextPathNonSemanticFindings(document)),
161
- },
162
- {
163
- id: "skill-context-reference-not-declared",
164
- run: ({ documents }) => documents.flatMap((document) => skillContextReferenceNotDeclaredFindings(document)),
165
- },
166
- {
167
- id: "skill-references-superseded-asset",
168
- run: ({ documents }) => skillReferencesSupersededAssetFindings(documents),
169
- },
170
- {
171
- id: "asset-references-superseded-asset",
172
- run: ({ documents }) => assetReferencesSupersededAssetFindings(documents),
173
- },
174
- {
175
- id: "catalog-declared-reference-governance",
176
- run: ({ catalog }) => catalogDeclaredReferenceGovernanceFindings(catalog),
177
- },
178
- ];
179
- function catalogDeclaredReferenceGovernanceFindings(catalog) {
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 skill with requires_lens or optional_lens. If it is not ready or no longer needed, update its lifecycle status after review.",
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 skills that should declare "${entry.id}" in requires_lens or optional_lens. Do not add runtime selection logic or prompt assembly.`,
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.metadata.description ?? "";
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 declaredContexts = new Set(listMetadataValue(document.metadata.requires_context));
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 the skill metadata using requires_context, or remove the prose reference if it is no longer needed.",
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 skill body and add them to requires_context using the metadata syntax currently supported by Renma. Missing declaration: ${referencedPath}`,
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: metadataText(document.metadata.id) ?? document.artifact.path,
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: metadataText(skill.metadata.id) ?? skill.artifact.path,
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
- ...listMetadataValue(document.metadata.superseded_by),
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
- canonicalTargets: sharedContextTargets(document),
1075
- }))
1076
- .filter(({ document, canonicalTargets }) => metadataText(document.metadata.status) === "deprecated" ||
1077
- metadataText(document.metadata.status) === "archived" ||
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
- return supersededAssets.flatMap(({ document, canonicalTargets }) => {
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: metadataText(referencingDocument.metadata.id) ??
1128
- referencingDocument.artifact.path,
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: metadataText(document.metadata.status),
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 root = repositoryRoot(documents);
1327
- const paths = new Set(documents.map((document) => document.artifact.path));
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, root, paths, config));
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, root));
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 requires_context or optional_context references, and keep SKILL.md focused on when to use or not use the skill.",
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, root, paths, config) {
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, root) {
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) && !(root && existsSync(path.join(root, 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 requires_context or optional_context values to canonical repo-root paths.",
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),