co-maintainer 0.4.10 → 0.4.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "co-maintainer",
3
- "version": "0.4.10",
3
+ "version": "0.4.11",
4
4
  "description": "Analyzes a GitHub repository and writes repository-specific contribution guidance.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -4,4 +4,4 @@ export type ValidationResult = {
4
4
  errors: string[];
5
5
  warnings: string[];
6
6
  };
7
- export declare function validateSkill(markdown: string, outputDirectory: string, source?: Source, referenceIssues?: "error" | "warning"): Promise<ValidationResult>;
7
+ export declare function validateSkill(markdown: string, source?: Source, referenceIssues?: "error" | "warning"): Promise<ValidationResult>;
@@ -1,5 +1,4 @@
1
- import { stat } from "../util/runtime.js";
2
- export async function validateSkill(markdown, outputDirectory, source, referenceIssues = "error") {
1
+ export async function validateSkill(markdown, source, referenceIssues = "error") {
3
2
  const errors = [];
4
3
  const warnings = [];
5
4
  const referenceProblems = referenceIssues === "error" ? errors : warnings;
@@ -33,54 +32,6 @@ export async function validateSkill(markdown, outputDirectory, source, reference
33
32
  if (source) {
34
33
  const paths = new Set([...source.tree, ...Object.keys(source.files)]);
35
34
  const repositoryName = String(source.repo.full_name ?? "");
36
- const commands = new Set();
37
- for (const [path, content] of Object.entries(source.files)) {
38
- if (path.endsWith("package.json")) {
39
- try {
40
- const scripts = JSON.parse(content)
41
- .scripts ?? {};
42
- const prefix = source.tree.some((item) => /pnpm-lock\.yaml$/.test(item))
43
- ? "pnpm"
44
- : source.tree.some((item) => /yarn\.lock$/.test(item))
45
- ? "yarn"
46
- : "npm";
47
- for (const name of Object.keys(scripts)) {
48
- commands.add(`${prefix} ${name}`);
49
- commands.add(`${prefix} run ${name}`);
50
- commands.add(String(scripts[name]));
51
- }
52
- }
53
- catch {
54
- // Ignore malformed manifests; syntax validation is outside this gate.
55
- }
56
- }
57
- if (/deno\.jsonc?$/.test(path)) {
58
- try {
59
- const tasks = JSON.parse(content).tasks ??
60
- {};
61
- for (const [name, task] of Object.entries(tasks)) {
62
- commands.add(`deno task ${name}`);
63
- commands.add(String(task));
64
- }
65
- }
66
- catch {
67
- // Ignore malformed manifests; syntax validation is outside this gate.
68
- }
69
- }
70
- for (const match of content.matchAll(/^\s*run:\s*([^\s#].*?)\s*$/gm)) {
71
- commands.add(match[1].replace(/^['"]|['"]$/g, ""));
72
- }
73
- for (const match of content.matchAll(/`((?:npm|pnpm|yarn|bun|deno|cargo|make|go|python|node|git)\s+[^`\n]+)`/g)) {
74
- commands.add(match[1]);
75
- }
76
- for (const match of content.matchAll(/^\s*((?:npm|pnpm|yarn|bun|deno|cargo|make|go|python|node|git)\s+[^\n`]+)$/gm)) {
77
- commands.add(match[1].trim());
78
- }
79
- }
80
- if (source.tree.some((path) => /Cargo\.toml$/.test(path))) {
81
- commands.add("cargo test");
82
- commands.add("cargo build");
83
- }
84
35
  const references = [...markdown.matchAll(/`([^`\n]+)`/g)].map((match) => match[1]);
85
36
  for (const reference of references) {
86
37
  const isQualifier = /^[a-z][a-z\d_-]*:/i.test(reference);
@@ -109,27 +60,14 @@ export async function validateSkill(markdown, outputDirectory, source, reference
109
60
  referenceProblems.push(`referenced path is absent from source: ${reference}`);
110
61
  }
111
62
  }
112
- if (/^(?:npm|pnpm|yarn|bun|deno|cargo|make|go|python|node|git)\s/.test(reference) &&
113
- ![...commands].some((command) => reference === command ||
114
- reference.startsWith(`${command} `) ||
115
- command.startsWith(`${reference} `))) {
116
- referenceProblems.push(`referenced command is absent from source: ${reference}`);
117
- }
118
63
  }
119
64
  }
120
- const links = [...markdown.matchAll(/\[[^\]]+\]\(([^)]+)\)/g)].map((match) => match[1]);
121
- for (const link of links) {
122
- if (/^[a-z][a-z\d+.-]*:/i.test(link) ||
123
- link.startsWith("/") ||
124
- link.includes("..")) {
125
- errors.push(`link is not relative: ${link}`);
126
- continue;
127
- }
128
- try {
129
- await stat(`${outputDirectory}/${link}`);
130
- }
131
- catch {
132
- errors.push(`linked file does not exist: ${link}`);
65
+ for (const link of markdown.matchAll(/\[[^\]]+\]\(([^)]+)\)/g)) {
66
+ const target = link[1];
67
+ if (/^[a-z][a-z\d+.-]*:/i.test(target) ||
68
+ target.startsWith("/") ||
69
+ target.includes("..")) {
70
+ errors.push(`link is not relative: ${target}`);
133
71
  }
134
72
  }
135
73
  return { valid: errors.length === 0, errors, warnings };
@@ -204,19 +204,19 @@ export async function runInitOrRemake(options) {
204
204
  let result = await timed("assemble skill", options.logTime, () => assembleSkill(options.repo, facts, previousMarkdown, previous?.sectionHashes ?? {}, overrides));
205
205
  const reviewDocuments = buildReviewDocuments(facts);
206
206
  result.markdown = addReviewLink(result.markdown, reviewDocuments);
207
- const validation = await timed("validate skill", options.logTime, () => validateSkill(result.markdown, `${reposDir()}/${options.repo}`, source));
207
+ const validation = await timed("validate skill", options.logTime, () => validateSkill(result.markdown, source));
208
208
  if (!validation.valid && Object.keys(overrides).length) {
209
209
  log("validate", `AI output rejected: ${validation.errors.join("; ")}`);
210
210
  overrides = {};
211
211
  result = await timed("reassemble valid skill", options.logTime, () => assembleSkill(options.repo, facts, previousMarkdown, previous?.sectionHashes ?? {}, overrides));
212
212
  result.markdown = addReviewLink(result.markdown, reviewDocuments);
213
213
  }
214
- const finalValidation = await timed("final skill validation", options.logTime, () => validateSkill(result.markdown, `${reposDir()}/${options.repo}`, source, "warning"));
214
+ const finalValidation = await timed("final skill validation", options.logTime, () => validateSkill(result.markdown, source, "warning"));
215
215
  if (finalValidation.warnings.length) {
216
216
  log("validate", `stale references kept: ${finalValidation.warnings.join(", ")}`);
217
217
  }
218
218
  if (!finalValidation.valid) {
219
- throw new Error(`generated skill is invalid: ${finalValidation.errors.join("; ")}`);
219
+ log("validate", `skill problems kept: ${finalValidation.errors.join("; ")}`);
220
220
  }
221
221
  await timed("write skill and state", options.logTime, async () => {
222
222
  const { withKnowledgeLock } = await import("../review/guides.js");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "co-maintainer",
3
- "version": "0.4.10",
3
+ "version": "0.4.11",
4
4
  "description": "Analyzes a GitHub repository and writes repository-specific contribution guidance.",
5
5
  "license": "MIT",
6
6
  "repository": {