@nebulacomponents/citable 0.1.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 +26 -0
- package/LICENSE +201 -0
- package/README.md +150 -0
- package/cli/bin/citable.js +5 -0
- package/dist/universal/.agents/skills/citable/SKILL.md +137 -0
- package/dist/universal/.agents/skills/citable/VERSION +1 -0
- package/dist/universal/.agents/skills/citable/commands/README.md +36 -0
- package/dist/universal/.agents/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.agents/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.agents/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.agents/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.agents/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.agents/skills/citable/manifest.json +54 -0
- package/dist/universal/.agents/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.agents/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.agents/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.agents/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.agents/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.agents/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.agents/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.agents/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.agents/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.agents/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.agents/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.agents/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.agents/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.agents/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.agents/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.agents/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.agents/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.agents/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.agents/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.agents/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.agents/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.agents/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.agents/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.agents/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.agents/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.agents/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.agents/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.agents/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.agents/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.agents/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.agents/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.agents/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.agents/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.claude/skills/citable/SKILL.md +137 -0
- package/dist/universal/.claude/skills/citable/VERSION +1 -0
- package/dist/universal/.claude/skills/citable/commands/README.md +36 -0
- package/dist/universal/.claude/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.claude/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.claude/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.claude/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.claude/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.claude/skills/citable/manifest.json +54 -0
- package/dist/universal/.claude/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.claude/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.claude/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.claude/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.claude/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.claude/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.claude/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.claude/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.claude/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.claude/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.claude/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.claude/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.claude/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.claude/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.claude/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.claude/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.claude/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.claude/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.claude/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.claude/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.claude/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.claude/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.claude/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.claude/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.claude/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.claude/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.claude/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.claude/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.claude/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.claude/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.claude/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.claude/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.claude/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.cursor/skills/citable/SKILL.md +137 -0
- package/dist/universal/.cursor/skills/citable/VERSION +1 -0
- package/dist/universal/.cursor/skills/citable/commands/README.md +36 -0
- package/dist/universal/.cursor/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.cursor/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.cursor/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.cursor/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.cursor/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.cursor/skills/citable/manifest.json +54 -0
- package/dist/universal/.cursor/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.cursor/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.cursor/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.cursor/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.cursor/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.cursor/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.cursor/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.cursor/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.cursor/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.cursor/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.cursor/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.cursor/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.cursor/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.cursor/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.cursor/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.cursor/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.cursor/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.cursor/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.cursor/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.cursor/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.cursor/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.cursor/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.cursor/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.cursor/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.cursor/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.cursor/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.cursor/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.cursor/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.cursor/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.cursor/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.cursor/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.cursor/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.cursor/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.gemini/skills/citable/SKILL.md +137 -0
- package/dist/universal/.gemini/skills/citable/VERSION +1 -0
- package/dist/universal/.gemini/skills/citable/commands/README.md +36 -0
- package/dist/universal/.gemini/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.gemini/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.gemini/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.gemini/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.gemini/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.gemini/skills/citable/manifest.json +54 -0
- package/dist/universal/.gemini/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.gemini/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.gemini/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.gemini/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.gemini/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.gemini/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.gemini/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.gemini/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.gemini/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.gemini/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.gemini/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.gemini/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.gemini/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.gemini/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.gemini/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.gemini/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.gemini/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.gemini/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.gemini/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.gemini/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.gemini/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.gemini/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.gemini/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.gemini/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.gemini/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.gemini/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.gemini/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.gemini/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.gemini/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.gemini/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.gemini/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.gemini/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.gemini/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.github/skills/citable/SKILL.md +137 -0
- package/dist/universal/.github/skills/citable/VERSION +1 -0
- package/dist/universal/.github/skills/citable/commands/README.md +36 -0
- package/dist/universal/.github/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.github/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.github/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.github/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.github/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.github/skills/citable/manifest.json +54 -0
- package/dist/universal/.github/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.github/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.github/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.github/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.github/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.github/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.github/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.github/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.github/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.github/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.github/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.github/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.github/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.github/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.github/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.github/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.github/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.github/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.github/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.github/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.github/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.github/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.github/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.github/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.github/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.github/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.github/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.github/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.github/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.github/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.github/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.github/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.github/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.kiro/skills/citable/SKILL.md +137 -0
- package/dist/universal/.kiro/skills/citable/VERSION +1 -0
- package/dist/universal/.kiro/skills/citable/commands/README.md +36 -0
- package/dist/universal/.kiro/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.kiro/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.kiro/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.kiro/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.kiro/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.kiro/skills/citable/manifest.json +54 -0
- package/dist/universal/.kiro/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.kiro/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.kiro/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.kiro/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.kiro/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.kiro/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.kiro/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.kiro/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.kiro/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.kiro/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.kiro/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.kiro/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.kiro/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.kiro/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.kiro/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.kiro/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.kiro/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.kiro/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.kiro/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.kiro/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.kiro/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.kiro/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.kiro/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.kiro/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.kiro/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.kiro/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.kiro/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.kiro/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.kiro/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.kiro/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.kiro/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.kiro/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.kiro/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.opencode/skills/citable/SKILL.md +137 -0
- package/dist/universal/.opencode/skills/citable/VERSION +1 -0
- package/dist/universal/.opencode/skills/citable/commands/README.md +36 -0
- package/dist/universal/.opencode/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.opencode/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.opencode/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.opencode/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.opencode/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.opencode/skills/citable/manifest.json +54 -0
- package/dist/universal/.opencode/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.opencode/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.opencode/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.opencode/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.opencode/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.opencode/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.opencode/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.opencode/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.opencode/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.opencode/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.opencode/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.opencode/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.opencode/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.opencode/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.opencode/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.opencode/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.opencode/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.opencode/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.opencode/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.opencode/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.opencode/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.opencode/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.opencode/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.opencode/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.opencode/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.opencode/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.opencode/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.opencode/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.opencode/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.opencode/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.opencode/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.opencode/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.opencode/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.pi/agent/skills/citable/SKILL.md +137 -0
- package/dist/universal/.pi/agent/skills/citable/VERSION +1 -0
- package/dist/universal/.pi/agent/skills/citable/commands/README.md +36 -0
- package/dist/universal/.pi/agent/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.pi/agent/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.pi/agent/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.pi/agent/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.pi/agent/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.pi/agent/skills/citable/manifest.json +54 -0
- package/dist/universal/.pi/agent/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.pi/agent/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.pi/agent/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.pi/agent/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.pi/agent/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.qoder/skills/citable/SKILL.md +137 -0
- package/dist/universal/.qoder/skills/citable/VERSION +1 -0
- package/dist/universal/.qoder/skills/citable/commands/README.md +36 -0
- package/dist/universal/.qoder/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.qoder/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.qoder/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.qoder/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.qoder/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.qoder/skills/citable/manifest.json +54 -0
- package/dist/universal/.qoder/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.qoder/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.qoder/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.qoder/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.qoder/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.qoder/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.qoder/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.qoder/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.qoder/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.qoder/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.qoder/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.qoder/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.qoder/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.qoder/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.qoder/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.qoder/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.qoder/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.qoder/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.qoder/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.qoder/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.qoder/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.qoder/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.qoder/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.qoder/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.qoder/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.qoder/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.qoder/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.qoder/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.qoder/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.qoder/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.qoder/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.qoder/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.qoder/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.rovodev/skills/citable/SKILL.md +137 -0
- package/dist/universal/.rovodev/skills/citable/VERSION +1 -0
- package/dist/universal/.rovodev/skills/citable/commands/README.md +36 -0
- package/dist/universal/.rovodev/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.rovodev/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.rovodev/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.rovodev/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.rovodev/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.rovodev/skills/citable/manifest.json +54 -0
- package/dist/universal/.rovodev/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.rovodev/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.rovodev/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.rovodev/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.rovodev/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.rovodev/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.rovodev/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.rovodev/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.rovodev/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.rovodev/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.rovodev/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.rovodev/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.rovodev/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.rovodev/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.rovodev/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.rovodev/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.rovodev/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.rovodev/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.rovodev/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.rovodev/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.rovodev/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.trae/skills/citable/SKILL.md +137 -0
- package/dist/universal/.trae/skills/citable/VERSION +1 -0
- package/dist/universal/.trae/skills/citable/commands/README.md +36 -0
- package/dist/universal/.trae/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.trae/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.trae/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.trae/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.trae/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.trae/skills/citable/manifest.json +54 -0
- package/dist/universal/.trae/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.trae/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.trae/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.trae/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.trae/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.trae/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.trae/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.trae/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.trae/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.trae/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.trae/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.trae/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.trae/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.trae/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.trae/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.trae/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.trae/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.trae/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.trae/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.trae/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.trae/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.trae/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.trae/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.trae/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.trae/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.trae/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.trae/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.trae/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.trae/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.trae/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.trae/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.trae/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.trae/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/.trae-cn/skills/citable/SKILL.md +137 -0
- package/dist/universal/.trae-cn/skills/citable/VERSION +1 -0
- package/dist/universal/.trae-cn/skills/citable/commands/README.md +36 -0
- package/dist/universal/.trae-cn/skills/citable/commands/ingest.md +44 -0
- package/dist/universal/.trae-cn/skills/citable/commands/measurement.md +49 -0
- package/dist/universal/.trae-cn/skills/citable/commands/optimize-page.md +53 -0
- package/dist/universal/.trae-cn/skills/citable/commands/page-work.md +48 -0
- package/dist/universal/.trae-cn/skills/citable/commands/validate-render.md +24 -0
- package/dist/universal/.trae-cn/skills/citable/manifest.json +54 -0
- package/dist/universal/.trae-cn/skills/citable/policies/crawler-policy-template.md +47 -0
- package/dist/universal/.trae-cn/skills/citable/references/anti-patterns.md +61 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/README.md +30 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/answer-extractability.md +44 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/claim-boundedness.md +36 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/comparison-fairness.md +30 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/conversion-alignment.md +37 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/entity-clarity.md +41 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/evidence-strength.md +53 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/information-gain.md +33 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/intent-alignment.md +41 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/narrative-accuracy.md +46 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/recommendation-eligibility.md +36 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/semantic-clarity.md +42 -0
- package/dist/universal/.trae-cn/skills/citable/rubrics/source-authority.md +37 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/claim.schema.json +53 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/common.defs.json +33 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/competitor.schema.json +28 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/config.schema.json +41 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/crawler.schema.json +33 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/detector-quality.schema.json +39 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/entity.schema.json +39 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/evidence.schema.json +41 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/experiment.schema.json +37 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/finding.schema.json +101 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/page.schema.json +40 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/project.schema.json +29 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/prompt-result.schema.json +37 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/prompt.schema.json +41 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/query.schema.json +43 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/run.schema.json +36 -0
- package/dist/universal/.trae-cn/skills/citable/scripts/README.md +4 -0
- package/dist/universal/.trae-cn/skills/citable/templates/finding-review.md +54 -0
- package/dist/universal/manifest.json +598 -0
- package/package.json +89 -0
- package/schemas/claim.schema.json +53 -0
- package/schemas/common.defs.json +33 -0
- package/schemas/competitor.schema.json +28 -0
- package/schemas/config.schema.json +41 -0
- package/schemas/crawler.schema.json +33 -0
- package/schemas/detector-quality.schema.json +39 -0
- package/schemas/entity.schema.json +39 -0
- package/schemas/evidence.schema.json +41 -0
- package/schemas/experiment.schema.json +37 -0
- package/schemas/finding.schema.json +101 -0
- package/schemas/page.schema.json +40 -0
- package/schemas/project.schema.json +29 -0
- package/schemas/prompt-result.schema.json +37 -0
- package/schemas/prompt.schema.json +41 -0
- package/schemas/query.schema.json +43 -0
- package/schemas/run.schema.json +36 -0
- package/scripts/build-dist.js +143 -0
- package/skill/SKILL.md +137 -0
- package/skill/commands/README.md +36 -0
- package/skill/commands/ingest.md +44 -0
- package/skill/commands/measurement.md +49 -0
- package/skill/commands/optimize-page.md +53 -0
- package/skill/commands/page-work.md +48 -0
- package/skill/commands/validate-render.md +24 -0
- package/skill/policies/crawler-policy-template.md +47 -0
- package/skill/references/anti-patterns.md +61 -0
- package/skill/rubrics/README.md +30 -0
- package/skill/rubrics/answer-extractability.md +44 -0
- package/skill/rubrics/claim-boundedness.md +36 -0
- package/skill/rubrics/comparison-fairness.md +30 -0
- package/skill/rubrics/conversion-alignment.md +37 -0
- package/skill/rubrics/entity-clarity.md +41 -0
- package/skill/rubrics/evidence-strength.md +53 -0
- package/skill/rubrics/information-gain.md +33 -0
- package/skill/rubrics/intent-alignment.md +41 -0
- package/skill/rubrics/narrative-accuracy.md +46 -0
- package/skill/rubrics/recommendation-eligibility.md +36 -0
- package/skill/rubrics/semantic-clarity.md +42 -0
- package/skill/rubrics/source-authority.md +37 -0
- package/skill/templates/finding-review.md +54 -0
- package/src/cli/index.js +135 -0
- package/src/commands/audit.js +111 -0
- package/src/commands/compareSnapshots.js +48 -0
- package/src/commands/context.js +62 -0
- package/src/commands/init.js +111 -0
- package/src/commands/inspect.js +61 -0
- package/src/commands/mapClaims.js +89 -0
- package/src/commands/schemaCmd.js +71 -0
- package/src/commands/substantiate.js +121 -0
- package/src/commands/validate.js +27 -0
- package/src/crawler/fetch.js +31 -0
- package/src/crawler/robots.js +67 -0
- package/src/crawler/sitemap.js +25 -0
- package/src/detectors/ans.js +219 -0
- package/src/detectors/arch.js +154 -0
- package/src/detectors/claim.js +230 -0
- package/src/detectors/crawl.js +143 -0
- package/src/detectors/entity.js +202 -0
- package/src/detectors/evd.js +164 -0
- package/src/detectors/framework.js +137 -0
- package/src/detectors/geoReco.js +218 -0
- package/src/detectors/index.js +50 -0
- package/src/detectors/lifeMeas.js +212 -0
- package/src/detectors/link.js +121 -0
- package/src/detectors/page.js +202 -0
- package/src/detectors/schemaData.js +249 -0
- package/src/detectors/tech.js +397 -0
- package/src/evidence/run.js +88 -0
- package/src/extractor/page.js +125 -0
- package/src/extractor/site.js +175 -0
- package/src/installer/index.js +1117 -0
- package/src/installer/providers.js +164 -0
- package/src/registries/index.js +127 -0
- package/src/reporting/report.js +82 -0
- package/src/shared/io.js +56 -0
- package/src/shared/schemaValidator.js +29 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { buildContext } from './context.js';
|
|
2
|
+
import { loadRegistries, saveRegistry, diffRegistries } from '../registries/index.js';
|
|
3
|
+
import { nowIso } from '../shared/io.js';
|
|
4
|
+
|
|
5
|
+
const PATTERNS = [
|
|
6
|
+
{ rx: /\b(the (best|leading|top|fastest|most \w+)|#1|number one|industry[- ]leading|world[- ]class|first and only|unmatched|unrivalled|unrivaled)\b/i, type: 'comparative', why: 'superlative / market-position language' },
|
|
7
|
+
{ rx: /\b\d+(\.\d+)?\s*(%|percent|x|times)\b/i, type: 'performance', why: 'quantitative assertion' },
|
|
8
|
+
{ rx: /\b(guarantee[ds]?|ensures?|always|never fails?|zero (downtime|risk)|100%)\b/i, type: 'performance', why: 'absolute or guarantee language' },
|
|
9
|
+
{ rx: /\b(compliant|certified|SOC ?2|ISO ?\d+|GDPR|HIPAA|PCI[- ]DSS|FedRAMP|accredited)\b/i, type: 'legal_regulatory', why: 'compliance / certification assertion' },
|
|
10
|
+
{ rx: /\b(secure|encrypt(s|ed|ion)|zero[- ]trust|penetration[- ]tested|audited)\b/i, type: 'security', why: 'security capability assertion' },
|
|
11
|
+
{ rx: /\b(only (platform|solution|product|vendor)|unlike (any|all) (other|competitors))\b/i, type: 'comparative', why: 'exclusivity assertion' },
|
|
12
|
+
{ rx: /\b(trusted by|used by|customers? (include|like)|deployed (at|by))\b/i, type: 'commercial', why: 'customer / adoption assertion' },
|
|
13
|
+
{ rx: /\b(integrates? with|supports? (over )?\d+|compatible with)\b/i, type: 'capability', why: 'capability / integration assertion' },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
const REVIEW_TYPES = new Set(['legal_regulatory', 'security', 'commercial']);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* `citable map-claims` — extract MATERIAL claim candidates from page text.
|
|
20
|
+
* Candidates are never marked verified; regulated types are flagged review_required.
|
|
21
|
+
* Writes to the claim registry only when `write: true`.
|
|
22
|
+
*/
|
|
23
|
+
export async function mapClaims(root, { target, baseUrl, write = false, refDate } = {}) {
|
|
24
|
+
const ctx = await buildContext(root, { target, baseUrl, refDate });
|
|
25
|
+
if (!ctx.site) throw new Error('map-claims requires a site target (built output directory or URL)');
|
|
26
|
+
|
|
27
|
+
const existing = new Set((ctx.registries.claims?.entries || []).map((c) => normalizeText(c.claim)));
|
|
28
|
+
const candidates = [];
|
|
29
|
+
for (const p of ctx.site.pages) {
|
|
30
|
+
if (p.status !== 200) continue;
|
|
31
|
+
const sentences = p.paragraphs.flatMap((para) => para.split(/(?<=[.!?])\s+(?=[A-Z])/));
|
|
32
|
+
for (const s of sentences) {
|
|
33
|
+
if (s.length < 25 || s.length > 400) continue; // not every sentence is a strategic claim
|
|
34
|
+
for (const pat of PATTERNS) {
|
|
35
|
+
if (pat.rx.test(s)) {
|
|
36
|
+
if (existing.has(normalizeText(s))) break;
|
|
37
|
+
candidates.push({
|
|
38
|
+
claim: s.trim(),
|
|
39
|
+
claim_type: pat.type,
|
|
40
|
+
reason: pat.why,
|
|
41
|
+
source_location: `${p.sourceFile ?? p.url}`,
|
|
42
|
+
page_url: p.url,
|
|
43
|
+
review_required: REVIEW_TYPES.has(pat.type),
|
|
44
|
+
});
|
|
45
|
+
break; // one classification per sentence
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Deduplicate by normalized text
|
|
52
|
+
const seen = new Set();
|
|
53
|
+
const unique = candidates.filter((c) => {
|
|
54
|
+
const k = normalizeText(c.claim);
|
|
55
|
+
if (seen.has(k)) return false;
|
|
56
|
+
seen.add(k);
|
|
57
|
+
return true;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
let registryDiff = null;
|
|
61
|
+
if (write && unique.length) {
|
|
62
|
+
const { registries } = loadRegistries(root);
|
|
63
|
+
const before = JSON.parse(JSON.stringify(registries.claims));
|
|
64
|
+
let n = registries.claims.entries.length;
|
|
65
|
+
for (const c of unique) {
|
|
66
|
+
n += 1;
|
|
67
|
+
registries.claims.entries.push({
|
|
68
|
+
claim_id: `CLAIM-${String(n).padStart(4, '0')}`,
|
|
69
|
+
claim: c.claim,
|
|
70
|
+
claim_type: c.claim_type,
|
|
71
|
+
entity: undefined,
|
|
72
|
+
evidence: [],
|
|
73
|
+
publication_surfaces: [c.page_url],
|
|
74
|
+
source_location: c.source_location,
|
|
75
|
+
status: c.review_required ? 'review_required' : 'candidate',
|
|
76
|
+
legal_status: c.review_required ? 'review_required' : 'not_assessed',
|
|
77
|
+
provenance: { created: nowIso(), created_by: 'citable map-claims', source: c.reason },
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
saveRegistry(root, 'claims', registries.claims);
|
|
81
|
+
registryDiff = diffRegistries(before, registries.claims, 'claim_id');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return { candidates: unique, written: write ? unique.length : 0, registryDiff };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function normalizeText(s) {
|
|
88
|
+
return String(s).toLowerCase().replace(/\s+/g, ' ').trim();
|
|
89
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { buildContext } from './context.js';
|
|
2
|
+
import { selectDetectors } from '../detectors/index.js';
|
|
3
|
+
import { runDetectors, sitePageFor } from '../detectors/framework.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `citable schema` — derive JSON-LD proposals from registry data and validate deployed schema.
|
|
7
|
+
*
|
|
8
|
+
* Generation is registry-driven: schema is only proposed for entities that exist in the
|
|
9
|
+
* entity registry with a canonical URL. Nothing is fabricated; missing fields are listed
|
|
10
|
+
* as required_input instead of being invented.
|
|
11
|
+
*/
|
|
12
|
+
export async function schemaCommand(root, { target, baseUrl, refDate } = {}) {
|
|
13
|
+
const ctx = await buildContext(root, { target, baseUrl, refDate });
|
|
14
|
+
|
|
15
|
+
// 1. Validate deployed schema via SCHEMA + ENTITY detectors (needs a site)
|
|
16
|
+
let findings = [];
|
|
17
|
+
if (ctx.site) {
|
|
18
|
+
const res = runDetectors(selectDetectors({ namespaces: ['SCHEMA', 'ENTITY'] }).filter((d) => !d.requires || d.requires.every((r) => ctx[r])), ctx);
|
|
19
|
+
findings = res.findings;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// 2. Propose JSON-LD from registry entities
|
|
23
|
+
const proposals = [];
|
|
24
|
+
const blocked = [];
|
|
25
|
+
const base = ctx.config?.site?.base_url;
|
|
26
|
+
for (const e of (ctx.registries.entities?.entries || []).filter((e) => e.status !== 'retired')) {
|
|
27
|
+
const missing = [];
|
|
28
|
+
if (!e.canonical_url) missing.push('canonical_url');
|
|
29
|
+
if (!e.definition && ['proprietary_concept', 'category'].includes(e.entity_type)) missing.push('definition');
|
|
30
|
+
if (missing.length) {
|
|
31
|
+
blocked.push({ entity_id: e.entity_id, status: 'blocked', reason: 'entity record incomplete; schema would require invented facts', required_input: missing });
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const id = `${e.canonical_url}#${e.entity_type}`;
|
|
35
|
+
const typeMap = {
|
|
36
|
+
organization: 'Organization', legal_entity: 'Organization', person: 'Person', author: 'Person',
|
|
37
|
+
product: 'SoftwareApplication', product_family: 'SoftwareApplication', service: 'Service',
|
|
38
|
+
category: 'DefinedTerm', proprietary_concept: 'DefinedTerm', methodology: 'DefinedTerm',
|
|
39
|
+
research_artifact: 'Report', dataset: 'Dataset', location: 'Place', partnership: 'Organization', case_study: 'Article',
|
|
40
|
+
};
|
|
41
|
+
const block = {
|
|
42
|
+
'@context': 'https://schema.org',
|
|
43
|
+
'@type': (e.schema_types && e.schema_types[0]) || typeMap[e.entity_type] || 'Thing',
|
|
44
|
+
'@id': id,
|
|
45
|
+
name: e.canonical_name,
|
|
46
|
+
url: e.canonical_url,
|
|
47
|
+
};
|
|
48
|
+
if (e.definition) block.description = e.definition;
|
|
49
|
+
if (e.aliases?.length) block.alternateName = e.aliases;
|
|
50
|
+
if ((e.authoritative_profiles || []).length) block.sameAs = e.authoritative_profiles;
|
|
51
|
+
if (e.owner_entity) {
|
|
52
|
+
const owner = (ctx.registries.entities?.entries || []).find((o) => o.entity_id === e.owner_entity);
|
|
53
|
+
if (owner?.canonical_url) block.publisher = { '@id': `${owner.canonical_url}#${owner.entity_type}` };
|
|
54
|
+
}
|
|
55
|
+
// consistency: schema must not exceed the registry — no ratings, prices, or claims added here
|
|
56
|
+
proposals.push({ entity_id: e.entity_id, target_url: e.canonical_url, jsonld: block });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 3. Detect registry entities whose canonical page carries no schema at all
|
|
60
|
+
const missingDeployment = [];
|
|
61
|
+
if (ctx.site) {
|
|
62
|
+
for (const p of proposals) {
|
|
63
|
+
const page = sitePageFor(ctx, { url: p.target_url });
|
|
64
|
+
if (page && page.jsonLd.length === 0) {
|
|
65
|
+
missingDeployment.push({ entity_id: p.entity_id, url: p.target_url, note: 'canonical page has no JSON-LD; proposal available' });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { findings, proposals, blocked, missingDeployment };
|
|
71
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { loadRegistries, saveRegistry, diffRegistries } from '../registries/index.js';
|
|
2
|
+
import { isPastDate, nowIso } from '../shared/io.js';
|
|
3
|
+
|
|
4
|
+
const REGULATED = new Set(['legal_regulatory', 'security', 'commercial']);
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `citable substantiate` — deterministic claim/evidence assessment.
|
|
8
|
+
*
|
|
9
|
+
* Outcomes per claim (spec §8.5): verified · verified_narrowed · insufficient_evidence ·
|
|
10
|
+
* contradicted · expired · prohibited · review_required.
|
|
11
|
+
*
|
|
12
|
+
* This command performs the *deterministic* portion: evidence linkage, validity dates,
|
|
13
|
+
* type adequacy, contradiction records, and legal-review gating. It never invents evidence
|
|
14
|
+
* and never upgrades a claim to verified on its own — upgrades require existing verified
|
|
15
|
+
* evidence in the registry. Semantic adequacy (does the evidence actually support the
|
|
16
|
+
* wording?) is a human/rubric task: see skill/rubrics/evidence-strength.md.
|
|
17
|
+
*/
|
|
18
|
+
export function substantiate(root, { write = false, refDate } = {}) {
|
|
19
|
+
const { registries, problems } = loadRegistries(root);
|
|
20
|
+
const ref = refDate ? new Date(refDate) : new Date();
|
|
21
|
+
const evidence = new Map(registries.evidence.entries.map((e) => [e.evidence_id, e]));
|
|
22
|
+
const before = JSON.parse(JSON.stringify(registries.claims));
|
|
23
|
+
const assessments = [];
|
|
24
|
+
|
|
25
|
+
for (const c of registries.claims.entries) {
|
|
26
|
+
const a = { claim_id: c.claim_id, previous_status: c.status, outcome: null, reasons: [], required_input: [] };
|
|
27
|
+
|
|
28
|
+
if (c.legal_status === 'prohibited') {
|
|
29
|
+
a.outcome = 'prohibited';
|
|
30
|
+
a.reasons.push('legal_status is prohibited');
|
|
31
|
+
} else if (isPastDate(c.expires, ref)) {
|
|
32
|
+
a.outcome = 'expired';
|
|
33
|
+
a.reasons.push(`claim expiry ${c.expires} has passed`);
|
|
34
|
+
} else if ((c.contradictory_sources || []).length > 0) {
|
|
35
|
+
a.outcome = 'contradicted';
|
|
36
|
+
a.reasons.push(`contradictory sources recorded: ${c.contradictory_sources.join(', ')}`);
|
|
37
|
+
} else if (REGULATED.has(c.claim_type) && (!c.legal_status || c.legal_status === 'not_assessed')) {
|
|
38
|
+
a.outcome = 'review_required';
|
|
39
|
+
a.reasons.push(`${c.claim_type} claim requires legal/SME review before any verified status`);
|
|
40
|
+
a.required_input.push('legal or subject-matter review decision');
|
|
41
|
+
} else if (['opinion', 'position', 'aspirational'].includes(c.claim_type)) {
|
|
42
|
+
// Opinions and aspirations are positions, not verifiable facts; they never enter the verified track.
|
|
43
|
+
a.outcome = c.status === 'candidate' ? 'candidate' : 'unverified';
|
|
44
|
+
a.reasons.push(`${c.claim_type} claims are positions, not verifiable facts; keep them out of the verified track`);
|
|
45
|
+
} else {
|
|
46
|
+
const evs = (c.evidence || []).map((id) => evidence.get(id)).filter(Boolean);
|
|
47
|
+
const missing = (c.evidence || []).filter((id) => !evidence.has(id));
|
|
48
|
+
const live = evs.filter((e) => !isPastDate(e.valid_until, ref) && ['verified', 'reviewed'].includes(e.verification_status));
|
|
49
|
+
if (missing.length) a.reasons.push(`dangling evidence references: ${missing.join(', ')}`);
|
|
50
|
+
if (evs.length === 0) {
|
|
51
|
+
a.outcome = 'insufficient_evidence';
|
|
52
|
+
a.reasons.push('no resolvable evidence attached');
|
|
53
|
+
a.required_input.push(...requiredInputFor(c));
|
|
54
|
+
} else if (live.length === 0) {
|
|
55
|
+
a.outcome = 'insufficient_evidence';
|
|
56
|
+
a.reasons.push('all attached evidence is expired, unverified, revoked, or inaccessible');
|
|
57
|
+
a.required_input.push('current, verified evidence');
|
|
58
|
+
} else if (['performance', 'comparative', 'security'].includes(c.claim_type) && live.every((e) => e.primary_or_secondary === 'secondary')) {
|
|
59
|
+
a.outcome = 'insufficient_evidence';
|
|
60
|
+
a.reasons.push(`${c.claim_type} claims require primary evidence; only secondary evidence attached`);
|
|
61
|
+
a.required_input.push('primary evidence (test result, benchmark, specification, certification)');
|
|
62
|
+
} else if (['performance'].includes(c.claim_type) && live.every((e) => !e.methodology)) {
|
|
63
|
+
a.outcome = 'insufficient_evidence';
|
|
64
|
+
a.reasons.push('performance evidence lacks methodology');
|
|
65
|
+
a.required_input.push('methodology', 'test conditions', 'measurement period');
|
|
66
|
+
} else if ((c.scope || []).length === 0 && ['capability', 'performance', 'comparative'].includes(c.claim_type)) {
|
|
67
|
+
a.outcome = 'verified_narrowed';
|
|
68
|
+
a.reasons.push('evidence exists but claim declares no scope; treat as verified only with narrowed scope pending scope definition');
|
|
69
|
+
a.required_input.push('explicit scope and exclusions');
|
|
70
|
+
} else {
|
|
71
|
+
// Deterministic conditions passed. Verified status additionally requires a recorded
|
|
72
|
+
// semantic support assessment (entailment) by a named assessor — evidence linkage
|
|
73
|
+
// alone does not establish that the wording matches what the evidence proves.
|
|
74
|
+
const sa = c.support_assessment;
|
|
75
|
+
if (sa?.status === 'contradicted') {
|
|
76
|
+
a.outcome = 'contradicted';
|
|
77
|
+
a.reasons.push('support assessment records the evidence as contradicting the claim wording');
|
|
78
|
+
} else if (['verified', 'verified_narrowed'].includes(c.status)) {
|
|
79
|
+
if (sa && ['directly_supported', 'partially_supported'].includes(sa.status) && sa.assessor) {
|
|
80
|
+
a.outcome = sa.status === 'partially_supported' ? 'verified_narrowed' : c.status;
|
|
81
|
+
a.reasons.push(`deterministic conditions hold; support assessment ${sa.status} by ${sa.assessor}`);
|
|
82
|
+
} else {
|
|
83
|
+
a.outcome = 'review_required';
|
|
84
|
+
a.reasons.push('verified status held without an adequate semantic support assessment; entailment review required (evidence-strength rubric)');
|
|
85
|
+
a.required_input.push('support_assessment with named assessor');
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
a.outcome = 'review_required';
|
|
89
|
+
a.reasons.push('deterministic conditions hold; semantic adequacy review required before marking verified (see evidence-strength rubric)');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
assessments.push(a);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let registryDiff = null;
|
|
97
|
+
if (write) {
|
|
98
|
+
for (const a of assessments) {
|
|
99
|
+
const c = registries.claims.entries.find((x) => x.claim_id === a.claim_id);
|
|
100
|
+
if (a.outcome && a.outcome !== c.status && a.outcome !== 'candidate') {
|
|
101
|
+
// Never silently upgrade to verified; only downgrades/lateral moves are automated.
|
|
102
|
+
const upgrade = ['verified', 'verified_narrowed'].includes(a.outcome) && !['verified', 'verified_narrowed'].includes(c.status);
|
|
103
|
+
if (!upgrade) {
|
|
104
|
+
c.status = a.outcome;
|
|
105
|
+
c.provenance = { ...(c.provenance || {}), updated: nowIso(), source: `citable substantiate: ${a.reasons[0]}` };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
saveRegistry(root, 'claims', registries.claims);
|
|
110
|
+
registryDiff = diffRegistries(before, registries.claims, 'claim_id');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return { assessments, problems, registryDiff };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function requiredInputFor(c) {
|
|
117
|
+
if (c.claim_type === 'performance') return ['baseline', 'measurement period', 'test population/conditions', 'methodology', 'result source'];
|
|
118
|
+
if (c.claim_type === 'comparative') return ['comparison set', 'comparison criteria', 'evidence for each compared dimension'];
|
|
119
|
+
if (c.claim_type === 'security') return ['test report, certification, or architecture evidence'];
|
|
120
|
+
return ['supporting evidence with an accountable owner'];
|
|
121
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { loadRegistries, checkReferentialIntegrity } from '../registries/index.js';
|
|
2
|
+
import { audit } from './audit.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `citable validate` — schema-validate all registries plus referential integrity.
|
|
6
|
+
* `citable validate-claims|validate-evidence|validate-schema|validate-links` narrow to the
|
|
7
|
+
* relevant detector scope (these require a site target for page-level checks).
|
|
8
|
+
*/
|
|
9
|
+
export async function validate(root, { mode = 'registries', target, baseUrl, refDate } = {}) {
|
|
10
|
+
const { problems } = loadRegistries(root);
|
|
11
|
+
const { registries } = loadRegistries(root);
|
|
12
|
+
const integrity = checkReferentialIntegrity(registries);
|
|
13
|
+
const structural = [...problems, ...integrity];
|
|
14
|
+
|
|
15
|
+
if (mode === 'registries') {
|
|
16
|
+
return { ok: structural.length === 0, problems: structural, findings: [] };
|
|
17
|
+
}
|
|
18
|
+
const scopeMap = { claims: 'claims', evidence: 'evidence', schema: 'schema', links: 'technical', regression: null };
|
|
19
|
+
const result = await audit(root, { target, scope: scopeMap[mode] ?? undefined, baseUrl, refDate });
|
|
20
|
+
return {
|
|
21
|
+
ok: structural.length === 0 && result.findings.filter((f) => ['critical', 'high'].includes(f.classification.severity)).length === 0,
|
|
22
|
+
problems: structural,
|
|
23
|
+
findings: result.findings,
|
|
24
|
+
runId: result.runId,
|
|
25
|
+
dir: result.dir,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch a URL capturing status, headers, body, and redirect chain.
|
|
3
|
+
* Used only when the operator supplies a deployed target and fetching is permitted.
|
|
4
|
+
*/
|
|
5
|
+
export async function fetchUrl(url, { userAgent = 'CitableAudit/0.1', maxRedirects = 10, timeoutMs = 20000 } = {}) {
|
|
6
|
+
const chain = [];
|
|
7
|
+
let current = url;
|
|
8
|
+
for (let i = 0; i <= maxRedirects; i++) {
|
|
9
|
+
const controller = new AbortController();
|
|
10
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
11
|
+
let res;
|
|
12
|
+
try {
|
|
13
|
+
res = await fetch(current, {
|
|
14
|
+
redirect: 'manual',
|
|
15
|
+
headers: { 'user-agent': userAgent },
|
|
16
|
+
signal: controller.signal,
|
|
17
|
+
});
|
|
18
|
+
} finally {
|
|
19
|
+
clearTimeout(timer);
|
|
20
|
+
}
|
|
21
|
+
const headers = Object.fromEntries(res.headers.entries());
|
|
22
|
+
if (res.status >= 300 && res.status < 400 && headers.location) {
|
|
23
|
+
chain.push({ url: current, status: res.status, location: headers.location });
|
|
24
|
+
current = new URL(headers.location, current).href;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const body = await res.text();
|
|
28
|
+
return { url: current, requestedUrl: url, status: res.status, headers, body, redirectChain: chain };
|
|
29
|
+
}
|
|
30
|
+
throw new Error(`redirect chain exceeded ${maxRedirects} hops for ${url}`);
|
|
31
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/** Minimal robots.txt parser sufficient for governance checks. */
|
|
2
|
+
export function parseRobots(text) {
|
|
3
|
+
const groups = [];
|
|
4
|
+
let current = null;
|
|
5
|
+
const sitemaps = [];
|
|
6
|
+
const errors = [];
|
|
7
|
+
const lines = String(text ?? '').split(/\r?\n/);
|
|
8
|
+
lines.forEach((line, i) => {
|
|
9
|
+
const noComment = line.replace(/#.*$/, '').trim();
|
|
10
|
+
if (!noComment) return;
|
|
11
|
+
const m = noComment.match(/^([A-Za-z-]+)\s*:\s*(.*)$/);
|
|
12
|
+
if (!m) {
|
|
13
|
+
errors.push(`line ${i + 1}: unparseable: "${line.trim()}"`);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const key = m[1].toLowerCase();
|
|
17
|
+
const value = m[2].trim();
|
|
18
|
+
if (key === 'user-agent') {
|
|
19
|
+
if (!current || current.rulesStarted) {
|
|
20
|
+
current = { agents: [], rules: [], rulesStarted: false };
|
|
21
|
+
groups.push(current);
|
|
22
|
+
}
|
|
23
|
+
current.agents.push(value.toLowerCase());
|
|
24
|
+
} else if (key === 'allow' || key === 'disallow') {
|
|
25
|
+
if (!current) {
|
|
26
|
+
errors.push(`line ${i + 1}: ${key} before any User-agent`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
current.rulesStarted = true;
|
|
30
|
+
current.rules.push({ type: key, path: value });
|
|
31
|
+
} else if (key === 'sitemap') {
|
|
32
|
+
sitemaps.push(value);
|
|
33
|
+
} else if (key === 'crawl-delay') {
|
|
34
|
+
if (current) { current.rulesStarted = true; current.rules.push({ type: 'crawl-delay', path: value }); }
|
|
35
|
+
} else {
|
|
36
|
+
errors.push(`line ${i + 1}: unknown directive "${m[1]}"`);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
return { groups, sitemaps, errors };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function ruleMatches(rulePath, urlPath) {
|
|
43
|
+
if (rulePath === '') return false; // empty disallow = allow all
|
|
44
|
+
let re = rulePath.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
|
|
45
|
+
if (re.endsWith('\\$')) re = re.slice(0, -2) + '$';
|
|
46
|
+
return new RegExp('^' + re).test(urlPath);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Decide whether userAgent may fetch urlPath under parsed robots. */
|
|
50
|
+
export function isAllowed(parsed, userAgent, urlPath) {
|
|
51
|
+
const ua = userAgent.toLowerCase();
|
|
52
|
+
let group =
|
|
53
|
+
parsed.groups.find((g) => g.agents.some((a) => a !== '*' && ua.includes(a))) ||
|
|
54
|
+
parsed.groups.find((g) => g.agents.includes('*'));
|
|
55
|
+
if (!group) return { allowed: true, rule: null };
|
|
56
|
+
let best = null;
|
|
57
|
+
for (const r of group.rules) {
|
|
58
|
+
if (r.type !== 'allow' && r.type !== 'disallow') continue;
|
|
59
|
+
if (ruleMatches(r.path, urlPath)) {
|
|
60
|
+
if (!best || r.path.length > best.path.length || (r.path.length === best.path.length && r.type === 'allow')) {
|
|
61
|
+
best = r;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (!best) return { allowed: true, rule: null };
|
|
66
|
+
return { allowed: best.type === 'allow', rule: `${best.type}: ${best.path}` };
|
|
67
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Minimal XML sitemap parser (urlset + sitemapindex). */
|
|
2
|
+
export function parseSitemap(xml) {
|
|
3
|
+
const text = String(xml ?? '');
|
|
4
|
+
const errors = [];
|
|
5
|
+
const urls = [];
|
|
6
|
+
const children = [];
|
|
7
|
+
const isIndex = /<sitemapindex[\s>]/i.test(text);
|
|
8
|
+
const blockRe = isIndex ? /<sitemap[\s>]([\s\S]*?)<\/sitemap>/gi : /<url[\s>]([\s\S]*?)<\/url>/gi;
|
|
9
|
+
let m;
|
|
10
|
+
while ((m = blockRe.exec(text)) !== null) {
|
|
11
|
+
const block = m[1];
|
|
12
|
+
const loc = block.match(/<loc>\s*([\s\S]*?)\s*<\/loc>/i)?.[1]?.trim();
|
|
13
|
+
const lastmod = block.match(/<lastmod>\s*([\s\S]*?)\s*<\/lastmod>/i)?.[1]?.trim() ?? null;
|
|
14
|
+
if (!loc) {
|
|
15
|
+
errors.push('entry missing <loc>');
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (isIndex) children.push({ loc, lastmod });
|
|
19
|
+
else urls.push({ loc, lastmod });
|
|
20
|
+
}
|
|
21
|
+
if (!isIndex && !/<urlset[\s>]/i.test(text) && urls.length === 0) {
|
|
22
|
+
errors.push('document contains no <urlset> or entries');
|
|
23
|
+
}
|
|
24
|
+
return { isIndex, urls, children, errors };
|
|
25
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { defineDetector, indexTargets, registryPageFor, pageSubject } from './framework.js';
|
|
2
|
+
|
|
3
|
+
const D = [];
|
|
4
|
+
|
|
5
|
+
const PREAMBLE_RX = /\b(in today'?s (rapidly |ever[- ])?(evolving|changing)|in the (modern|current|digital) (era|age|landscape|world)|now more than ever|as (technology|ai) continues to (evolve|advance)|in an increasingly)\b/i;
|
|
6
|
+
|
|
7
|
+
D.push(defineDetector({
|
|
8
|
+
id: 'ANS-001', name: 'Generic preamble before answer', namespace: 'ANS',
|
|
9
|
+
description: 'The opening paragraph uses generic scene-setting boilerplate instead of answering the page’s question.',
|
|
10
|
+
discipline: ['aeo', 'geo'], severity: 'medium', deterministic: false, requires: ['site'],
|
|
11
|
+
impact: { citation: 'medium', representation: 'low' },
|
|
12
|
+
applicable_requirement: 'AEO §4 direct answer block in first 50–100 words; GEO §5 avoid "in today\'s rapidly evolving..." openings; anti-pattern: generic AI introductions',
|
|
13
|
+
remediation: 'Replace the opening with a direct answer to the principal question in the first 50–100 words.',
|
|
14
|
+
verification: 'Re-inspect the first paragraph for a direct answer.',
|
|
15
|
+
check(ctx) {
|
|
16
|
+
return indexTargets(ctx)
|
|
17
|
+
.filter((p) => p.status === 200 && p.paragraphs.length > 0 && PREAMBLE_RX.test(p.paragraphs[0]))
|
|
18
|
+
.map((p) => ({
|
|
19
|
+
subject: pageSubject(p),
|
|
20
|
+
summary: 'Opening paragraph is generic preamble, not a direct answer',
|
|
21
|
+
evidence: [`first paragraph: "${p.paragraphs[0].slice(0, 160)}..."`],
|
|
22
|
+
confidence: 'high',
|
|
23
|
+
}));
|
|
24
|
+
},
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
D.push(defineDetector({
|
|
28
|
+
id: 'ANS-002', name: 'Question heading without direct answer', namespace: 'ANS',
|
|
29
|
+
description: 'A heading phrased as a question is not followed by prose before the next heading.',
|
|
30
|
+
discipline: ['aeo'], severity: 'medium', deterministic: true, requires: ['site'],
|
|
31
|
+
impact: { citation: 'medium' },
|
|
32
|
+
applicable_requirement: 'AEO §4 answer extractability; anti-pattern: question headings created only for formatting',
|
|
33
|
+
remediation: 'Answer the question directly in the text immediately after the heading, or remove the decorative question heading.',
|
|
34
|
+
verification: 'Confirm prose follows each question heading.',
|
|
35
|
+
check(ctx) {
|
|
36
|
+
const hits = [];
|
|
37
|
+
for (const p of indexTargets(ctx)) {
|
|
38
|
+
if (p.status !== 200) continue;
|
|
39
|
+
const html = p.rawHtml;
|
|
40
|
+
const rx = /<h([2-4])[^>]*>([^<]*\?)\s*<\/h\1>\s*(<h[1-6]|<\/section|<\/article|<\/body|$)/gi;
|
|
41
|
+
let m;
|
|
42
|
+
while ((m = rx.exec(html)) !== null) {
|
|
43
|
+
hits.push({
|
|
44
|
+
subject: pageSubject(p),
|
|
45
|
+
summary: `Question heading "${m[2].trim().slice(0, 80)}" has no answering prose before the next heading`,
|
|
46
|
+
evidence: [`heading: ${m[2].trim()}`],
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return hits;
|
|
51
|
+
},
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
D.push(defineDetector({
|
|
55
|
+
id: 'ANS-003', name: 'Circular definition', namespace: 'ANS',
|
|
56
|
+
description: 'A definitional sentence defines a term using the term itself as the definition head.',
|
|
57
|
+
discipline: ['aeo', 'geo'], severity: 'medium', deterministic: false, requires: ['site'],
|
|
58
|
+
impact: { citation: 'medium', representation: 'medium' },
|
|
59
|
+
applicable_requirement: 'AEO §4 explicit definitions; anti-pattern: circular definitions',
|
|
60
|
+
false_positive_conditions: ['legitimate genus-differentia definitions repeating one word of a compound term'],
|
|
61
|
+
remediation: 'Rewrite as “[Term] is [genus] that [differentia]”, then state exclusions.',
|
|
62
|
+
verification: 'Re-inspect the definition sentence.',
|
|
63
|
+
check(ctx) {
|
|
64
|
+
const hits = [];
|
|
65
|
+
for (const p of indexTargets(ctx)) {
|
|
66
|
+
if (p.status !== 200) continue;
|
|
67
|
+
for (const para of p.paragraphs.slice(0, 12)) {
|
|
68
|
+
const m = para.match(/^([A-Z][A-Za-z0-9 -]{2,60}?)\s+(?:is|are|refers to|means)\s+(.{3,120})/);
|
|
69
|
+
if (!m) continue;
|
|
70
|
+
const term = m[1].trim().toLowerCase().replace(/^(the|a|an)\s+/, '');
|
|
71
|
+
const defHead = m[2].trim().toLowerCase().replace(/^(the|a|an|simply|just|basically)\s+/, '');
|
|
72
|
+
if (term.split(' ').length >= 2 && defHead.startsWith(term)) {
|
|
73
|
+
hits.push({
|
|
74
|
+
subject: pageSubject(p),
|
|
75
|
+
summary: `Circular definition: "${m[1].trim()}" is defined as itself`,
|
|
76
|
+
evidence: [`sentence: "${para.slice(0, 160)}"`],
|
|
77
|
+
confidence: 'high',
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return hits;
|
|
83
|
+
},
|
|
84
|
+
}));
|
|
85
|
+
|
|
86
|
+
D.push(defineDetector({
|
|
87
|
+
id: 'ANS-004', name: 'Deictic dependency in answer text', namespace: 'ANS',
|
|
88
|
+
description: 'Answer-bearing prose depends on preceding visual context ("as shown above", "in the diagram below"), which breaks when extracted.',
|
|
89
|
+
discipline: ['aeo'], severity: 'low', deterministic: true, requires: ['site'],
|
|
90
|
+
impact: { citation: 'medium' },
|
|
91
|
+
applicable_requirement: 'AEO §4: extracted passage must not distort or lose meaning; GEO §5 decomposable content',
|
|
92
|
+
remediation: 'Make the passage self-contained: name the referent explicitly instead of pointing at it.',
|
|
93
|
+
verification: 'Search page text for deictic references.',
|
|
94
|
+
check(ctx) {
|
|
95
|
+
const rx = /\b(as (shown|seen|described|illustrated|mentioned) (above|below|earlier|previously)|the (diagram|table|figure|chart|image) (above|below)|see (above|below))\b/i;
|
|
96
|
+
return indexTargets(ctx)
|
|
97
|
+
.filter((p) => p.status === 200)
|
|
98
|
+
.flatMap((p) => {
|
|
99
|
+
const matches = p.paragraphs.filter((t) => rx.test(t));
|
|
100
|
+
return matches.length ? [{
|
|
101
|
+
subject: pageSubject(p),
|
|
102
|
+
summary: `${matches.length} passage(s) depend on preceding visual context`,
|
|
103
|
+
evidence: matches.slice(0, 3).map((t) => `"${t.slice(0, 120)}"`),
|
|
104
|
+
}] : [];
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
}));
|
|
108
|
+
|
|
109
|
+
D.push(defineDetector({
|
|
110
|
+
id: 'ANS-005', name: 'Relative quantity without baseline or timeframe', namespace: 'ANS',
|
|
111
|
+
description: 'Text asserts a relative numeric improvement ("3x faster", "50% reduction") without a nearby baseline, unit, or timeframe.',
|
|
112
|
+
discipline: ['aeo', 'geo'], severity: 'medium', deterministic: false, requires: ['site'],
|
|
113
|
+
impact: { citation: 'medium', legal: 'medium', reputational: 'medium' },
|
|
114
|
+
applicable_requirement: 'AEO §4 atomic factual claims with measurement conditions; detector spec: numerical claim without unit or timeframe; anti-pattern: false precision',
|
|
115
|
+
false_positive_conditions: ['numbers whose baseline is stated in an adjacent sentence outside the matched window'],
|
|
116
|
+
remediation: 'State the baseline, measurement period, and test conditions adjacent to the number, or remove the figure.',
|
|
117
|
+
verification: 'Confirm baseline/conditions appear adjacent to each relative quantity.',
|
|
118
|
+
check(ctx) {
|
|
119
|
+
const numRx = /\b(\d+(?:\.\d+)?)\s*(x|times)\s+(faster|slower|better|cheaper|more|fewer|higher|lower)|\b(\d+(?:\.\d+)?)%\s+(reduction|increase|improvement|faster|savings|growth|decrease)/i;
|
|
120
|
+
const contextRx = /\b(compared (to|with)|versus|vs\.?|baseline|benchmark|measured|test(ed)? (under|conditions|over|during|in)|between \d{4}|in (q[1-4] )?\d{4}|over (a|the) (period|quarter|year|month)|methodology)\b/i;
|
|
121
|
+
const hits = [];
|
|
122
|
+
for (const p of indexTargets(ctx)) {
|
|
123
|
+
if (p.status !== 200) continue;
|
|
124
|
+
for (const para of p.paragraphs) {
|
|
125
|
+
if (numRx.test(para) && !contextRx.test(para)) {
|
|
126
|
+
hits.push({
|
|
127
|
+
subject: pageSubject(p),
|
|
128
|
+
summary: 'Relative quantity asserted without baseline or timeframe in the same passage',
|
|
129
|
+
evidence: [`passage: "${para.slice(0, 160)}"`],
|
|
130
|
+
confidence: 'medium',
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return hits;
|
|
136
|
+
},
|
|
137
|
+
}));
|
|
138
|
+
|
|
139
|
+
D.push(defineDetector({
|
|
140
|
+
id: 'ANS-006', name: 'Procedure content without ordered steps', namespace: 'ANS',
|
|
141
|
+
description: 'A page registered as implementation/how-to content contains no ordered list or numbered steps.',
|
|
142
|
+
discipline: ['aeo'], severity: 'low', deterministic: true, requires: ['site', 'registries'],
|
|
143
|
+
impact: { citation: 'medium' },
|
|
144
|
+
applicable_requirement: 'AEO §4 procedures: provide explicit steps',
|
|
145
|
+
remediation: 'Express the procedure as explicit ordered steps.',
|
|
146
|
+
verification: 'Confirm an ordered list or numbered step structure exists.',
|
|
147
|
+
check(ctx) {
|
|
148
|
+
const hits = [];
|
|
149
|
+
for (const p of indexTargets(ctx)) {
|
|
150
|
+
const reg = registryPageFor(ctx, p);
|
|
151
|
+
if (!reg || reg.page_type !== 'implementation' || p.status !== 200) continue;
|
|
152
|
+
const numbered = /(^|\s)(step\s+\d|1\.\s+\S+[\s\S]{0,400}2\.\s+\S+)/i.test(p.text);
|
|
153
|
+
if (p.orderedLists === 0 && !numbered) {
|
|
154
|
+
hits.push({
|
|
155
|
+
subject: pageSubject(p),
|
|
156
|
+
summary: `Implementation page ${reg.page_id} has no ordered steps`,
|
|
157
|
+
evidence: ['0 <ol> elements; no numbered step pattern in text'],
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return hits;
|
|
162
|
+
},
|
|
163
|
+
}));
|
|
164
|
+
|
|
165
|
+
D.push(defineDetector({
|
|
166
|
+
id: 'ANS-007', name: 'Comparison without explicit basis', namespace: 'ANS',
|
|
167
|
+
description: 'A comparison page has neither a comparison table nor prose stating the comparison criteria.',
|
|
168
|
+
discipline: ['aeo', 'geo'], severity: 'medium', deterministic: true, requires: ['site', 'registries'],
|
|
169
|
+
impact: { citation: 'medium', representation: 'medium' },
|
|
170
|
+
applicable_requirement: 'AEO §4 comparison tables with prose; detector spec: comparison without explicit comparison basis',
|
|
171
|
+
remediation: 'State the comparison dimensions explicitly and support them with a table plus prose.',
|
|
172
|
+
verification: 'Confirm comparison criteria appear in table or prose.',
|
|
173
|
+
check(ctx) {
|
|
174
|
+
const basisRx = /\b(differs? (from|in)|difference between|compared (on|across|by)|criteria|dimension|whereas|in contrast|unlike)\b/i;
|
|
175
|
+
const hits = [];
|
|
176
|
+
for (const p of indexTargets(ctx)) {
|
|
177
|
+
const reg = registryPageFor(ctx, p);
|
|
178
|
+
if (!reg || reg.page_type !== 'comparison' || p.status !== 200) continue;
|
|
179
|
+
if (p.tables === 0 && !basisRx.test(p.text)) {
|
|
180
|
+
hits.push({
|
|
181
|
+
subject: pageSubject(p),
|
|
182
|
+
summary: `Comparison page ${reg.page_id} states no explicit comparison basis`,
|
|
183
|
+
evidence: ['0 tables; no comparison-basis phrasing found in text'],
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return hits;
|
|
188
|
+
},
|
|
189
|
+
}));
|
|
190
|
+
|
|
191
|
+
D.push(defineDetector({
|
|
192
|
+
id: 'ANS-008', name: 'Missing scope or limitations on answer page', namespace: 'ANS',
|
|
193
|
+
description: 'A definition/comparison/recommendation page never states scope boundaries, exclusions, or limitations.',
|
|
194
|
+
discipline: ['aeo', 'geo'], severity: 'medium', deterministic: false, requires: ['site', 'registries'],
|
|
195
|
+
impact: { citation: 'medium', legal: 'medium', representation: 'medium' },
|
|
196
|
+
applicable_requirement: 'AEO §4 boundary conditions; GEO §5 scope boundaries; acceptance standard: limitations disclosed',
|
|
197
|
+
false_positive_conditions: ['limitations expressed with vocabulary outside the matched set'],
|
|
198
|
+
remediation: 'Add explicit "when this applies / when it does not / limitations" content.',
|
|
199
|
+
verification: 'Confirm boundary-condition language exists on the page.',
|
|
200
|
+
check(ctx) {
|
|
201
|
+
const rx = /\b(limitation|does not (apply|include|cover|solve|support)|not (intended|suitable|designed) for|out of scope|exclusion|caveat|constraint|boundary condition|when (this|it) (does not|doesn'?t) apply)\b/i;
|
|
202
|
+
const hits = [];
|
|
203
|
+
for (const p of indexTargets(ctx)) {
|
|
204
|
+
const reg = registryPageFor(ctx, p);
|
|
205
|
+
if (!reg || !['definition', 'comparison', 'recommendation', 'product'].includes(reg.page_type) || p.status !== 200) continue;
|
|
206
|
+
if (!rx.test(p.text)) {
|
|
207
|
+
hits.push({
|
|
208
|
+
subject: pageSubject(p),
|
|
209
|
+
summary: `${reg.page_type} page ${reg.page_id} states no scope boundaries or limitations`,
|
|
210
|
+
evidence: ['no limitation/exclusion/scope-boundary phrasing found in page text'],
|
|
211
|
+
confidence: 'medium',
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return hits;
|
|
216
|
+
},
|
|
217
|
+
}));
|
|
218
|
+
|
|
219
|
+
export default D;
|