@nebulacomponents/citable 1.13.1 → 1.14.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 +246 -0
- package/README.md +43 -5
- package/dist/universal/.agents/skills/citable/SKILL.md +13 -4
- package/dist/universal/.agents/skills/citable/VERSION +1 -1
- package/dist/universal/.agents/skills/citable/agents/citable-auditor.md +64 -0
- package/dist/universal/.agents/skills/citable/agents/citable-semantic-reviewer.md +66 -0
- package/dist/universal/.agents/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.agents/skills/citable/commands/observe-and-act.md +50 -3
- package/dist/universal/.agents/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.agents/skills/citable/manifest.json +26 -14
- package/dist/universal/.agents/skills/citable/schemas/action-plan.schema.json +13 -0
- package/dist/universal/.agents/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
- package/dist/universal/.agents/skills/citable/schemas/canonical-index-import.schema.json +30 -0
- package/dist/universal/.agents/skills/citable/schemas/common.defs.json +12 -1
- package/dist/universal/.agents/skills/citable/schemas/corroboration-import.schema.json +48 -0
- package/dist/universal/.agents/skills/citable/schemas/entity-graph.schema.json +75 -0
- package/dist/universal/.agents/skills/citable/schemas/entity.schema.json +13 -0
- package/dist/universal/.agents/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.agents/skills/citable/schemas/page.schema.json +3 -0
- package/dist/universal/.agents/skills/citable/schemas/regional-network-import.schema.json +55 -0
- package/dist/universal/.agents/skills/citable/schemas/source-identity-chain.schema.json +83 -0
- package/dist/universal/.agents/skills/citable/scripts/README.md +3 -1
- package/dist/universal/.claude/agents/citable/citable-auditor.md +64 -0
- package/dist/universal/.claude/agents/citable/citable-semantic-reviewer.md +66 -0
- package/dist/universal/.claude/agents/citable/manifest.json +12 -0
- package/dist/universal/.claude/skills/citable/SKILL.md +13 -4
- package/dist/universal/.claude/skills/citable/VERSION +1 -1
- package/dist/universal/.claude/skills/citable/agents/citable-auditor.md +64 -0
- package/dist/universal/.claude/skills/citable/agents/citable-semantic-reviewer.md +66 -0
- package/dist/universal/.claude/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.claude/skills/citable/commands/observe-and-act.md +50 -3
- package/dist/universal/.claude/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.claude/skills/citable/manifest.json +31 -14
- package/dist/universal/.claude/skills/citable/schemas/action-plan.schema.json +13 -0
- package/dist/universal/.claude/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
- package/dist/universal/.claude/skills/citable/schemas/canonical-index-import.schema.json +30 -0
- package/dist/universal/.claude/skills/citable/schemas/common.defs.json +12 -1
- package/dist/universal/.claude/skills/citable/schemas/corroboration-import.schema.json +48 -0
- package/dist/universal/.claude/skills/citable/schemas/entity-graph.schema.json +75 -0
- package/dist/universal/.claude/skills/citable/schemas/entity.schema.json +13 -0
- package/dist/universal/.claude/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.claude/skills/citable/schemas/page.schema.json +3 -0
- package/dist/universal/.claude/skills/citable/schemas/regional-network-import.schema.json +55 -0
- package/dist/universal/.claude/skills/citable/schemas/source-identity-chain.schema.json +83 -0
- package/dist/universal/.claude/skills/citable/scripts/README.md +3 -1
- package/dist/universal/.cursor/skills/citable/SKILL.md +13 -4
- package/dist/universal/.cursor/skills/citable/VERSION +1 -1
- package/dist/universal/.cursor/skills/citable/agents/citable-auditor.md +64 -0
- package/dist/universal/.cursor/skills/citable/agents/citable-semantic-reviewer.md +66 -0
- package/dist/universal/.cursor/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.cursor/skills/citable/commands/observe-and-act.md +50 -3
- package/dist/universal/.cursor/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.cursor/skills/citable/manifest.json +26 -14
- package/dist/universal/.cursor/skills/citable/schemas/action-plan.schema.json +13 -0
- package/dist/universal/.cursor/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
- package/dist/universal/.cursor/skills/citable/schemas/canonical-index-import.schema.json +30 -0
- package/dist/universal/.cursor/skills/citable/schemas/common.defs.json +12 -1
- package/dist/universal/.cursor/skills/citable/schemas/corroboration-import.schema.json +48 -0
- package/dist/universal/.cursor/skills/citable/schemas/entity-graph.schema.json +75 -0
- package/dist/universal/.cursor/skills/citable/schemas/entity.schema.json +13 -0
- package/dist/universal/.cursor/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.cursor/skills/citable/schemas/page.schema.json +3 -0
- package/dist/universal/.cursor/skills/citable/schemas/regional-network-import.schema.json +55 -0
- package/dist/universal/.cursor/skills/citable/schemas/source-identity-chain.schema.json +83 -0
- package/dist/universal/.cursor/skills/citable/scripts/README.md +3 -1
- package/dist/universal/.gemini/skills/citable/SKILL.md +13 -4
- package/dist/universal/.gemini/skills/citable/VERSION +1 -1
- package/dist/universal/.gemini/skills/citable/agents/citable-auditor.md +64 -0
- package/dist/universal/.gemini/skills/citable/agents/citable-semantic-reviewer.md +66 -0
- package/dist/universal/.gemini/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.gemini/skills/citable/commands/observe-and-act.md +50 -3
- package/dist/universal/.gemini/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.gemini/skills/citable/manifest.json +26 -14
- package/dist/universal/.gemini/skills/citable/schemas/action-plan.schema.json +13 -0
- package/dist/universal/.gemini/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
- package/dist/universal/.gemini/skills/citable/schemas/canonical-index-import.schema.json +30 -0
- package/dist/universal/.gemini/skills/citable/schemas/common.defs.json +12 -1
- package/dist/universal/.gemini/skills/citable/schemas/corroboration-import.schema.json +48 -0
- package/dist/universal/.gemini/skills/citable/schemas/entity-graph.schema.json +75 -0
- package/dist/universal/.gemini/skills/citable/schemas/entity.schema.json +13 -0
- package/dist/universal/.gemini/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.gemini/skills/citable/schemas/page.schema.json +3 -0
- package/dist/universal/.gemini/skills/citable/schemas/regional-network-import.schema.json +55 -0
- package/dist/universal/.gemini/skills/citable/schemas/source-identity-chain.schema.json +83 -0
- package/dist/universal/.gemini/skills/citable/scripts/README.md +3 -1
- package/dist/universal/.github/skills/citable/SKILL.md +13 -4
- package/dist/universal/.github/skills/citable/VERSION +1 -1
- package/dist/universal/.github/skills/citable/agents/citable-auditor.md +64 -0
- package/dist/universal/.github/skills/citable/agents/citable-semantic-reviewer.md +66 -0
- package/dist/universal/.github/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.github/skills/citable/commands/observe-and-act.md +50 -3
- package/dist/universal/.github/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.github/skills/citable/manifest.json +26 -14
- package/dist/universal/.github/skills/citable/schemas/action-plan.schema.json +13 -0
- package/dist/universal/.github/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
- package/dist/universal/.github/skills/citable/schemas/canonical-index-import.schema.json +30 -0
- package/dist/universal/.github/skills/citable/schemas/common.defs.json +12 -1
- package/dist/universal/.github/skills/citable/schemas/corroboration-import.schema.json +48 -0
- package/dist/universal/.github/skills/citable/schemas/entity-graph.schema.json +75 -0
- package/dist/universal/.github/skills/citable/schemas/entity.schema.json +13 -0
- package/dist/universal/.github/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.github/skills/citable/schemas/page.schema.json +3 -0
- package/dist/universal/.github/skills/citable/schemas/regional-network-import.schema.json +55 -0
- package/dist/universal/.github/skills/citable/schemas/source-identity-chain.schema.json +83 -0
- package/dist/universal/.github/skills/citable/scripts/README.md +3 -1
- package/dist/universal/.kiro/skills/citable/SKILL.md +13 -4
- package/dist/universal/.kiro/skills/citable/VERSION +1 -1
- package/dist/universal/.kiro/skills/citable/agents/citable-auditor.md +64 -0
- package/dist/universal/.kiro/skills/citable/agents/citable-semantic-reviewer.md +66 -0
- package/dist/universal/.kiro/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.kiro/skills/citable/commands/observe-and-act.md +50 -3
- package/dist/universal/.kiro/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.kiro/skills/citable/manifest.json +26 -14
- package/dist/universal/.kiro/skills/citable/schemas/action-plan.schema.json +13 -0
- package/dist/universal/.kiro/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
- package/dist/universal/.kiro/skills/citable/schemas/canonical-index-import.schema.json +30 -0
- package/dist/universal/.kiro/skills/citable/schemas/common.defs.json +12 -1
- package/dist/universal/.kiro/skills/citable/schemas/corroboration-import.schema.json +48 -0
- package/dist/universal/.kiro/skills/citable/schemas/entity-graph.schema.json +75 -0
- package/dist/universal/.kiro/skills/citable/schemas/entity.schema.json +13 -0
- package/dist/universal/.kiro/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.kiro/skills/citable/schemas/page.schema.json +3 -0
- package/dist/universal/.kiro/skills/citable/schemas/regional-network-import.schema.json +55 -0
- package/dist/universal/.kiro/skills/citable/schemas/source-identity-chain.schema.json +83 -0
- package/dist/universal/.kiro/skills/citable/scripts/README.md +3 -1
- package/dist/universal/.opencode/skills/citable/SKILL.md +13 -4
- package/dist/universal/.opencode/skills/citable/VERSION +1 -1
- package/dist/universal/.opencode/skills/citable/agents/citable-auditor.md +64 -0
- package/dist/universal/.opencode/skills/citable/agents/citable-semantic-reviewer.md +66 -0
- package/dist/universal/.opencode/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.opencode/skills/citable/commands/observe-and-act.md +50 -3
- package/dist/universal/.opencode/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.opencode/skills/citable/manifest.json +26 -14
- package/dist/universal/.opencode/skills/citable/schemas/action-plan.schema.json +13 -0
- package/dist/universal/.opencode/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
- package/dist/universal/.opencode/skills/citable/schemas/canonical-index-import.schema.json +30 -0
- package/dist/universal/.opencode/skills/citable/schemas/common.defs.json +12 -1
- package/dist/universal/.opencode/skills/citable/schemas/corroboration-import.schema.json +48 -0
- package/dist/universal/.opencode/skills/citable/schemas/entity-graph.schema.json +75 -0
- package/dist/universal/.opencode/skills/citable/schemas/entity.schema.json +13 -0
- package/dist/universal/.opencode/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.opencode/skills/citable/schemas/page.schema.json +3 -0
- package/dist/universal/.opencode/skills/citable/schemas/regional-network-import.schema.json +55 -0
- package/dist/universal/.opencode/skills/citable/schemas/source-identity-chain.schema.json +83 -0
- package/dist/universal/.opencode/skills/citable/scripts/README.md +3 -1
- package/dist/universal/.pi/agent/skills/citable/SKILL.md +13 -4
- package/dist/universal/.pi/agent/skills/citable/VERSION +1 -1
- package/dist/universal/.pi/agent/skills/citable/agents/citable-auditor.md +64 -0
- package/dist/universal/.pi/agent/skills/citable/agents/citable-semantic-reviewer.md +66 -0
- package/dist/universal/.pi/agent/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.pi/agent/skills/citable/commands/observe-and-act.md +50 -3
- package/dist/universal/.pi/agent/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.pi/agent/skills/citable/manifest.json +26 -14
- package/dist/universal/.pi/agent/skills/citable/schemas/action-plan.schema.json +13 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/canonical-index-import.schema.json +30 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/common.defs.json +12 -1
- package/dist/universal/.pi/agent/skills/citable/schemas/corroboration-import.schema.json +48 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/entity-graph.schema.json +75 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/entity.schema.json +13 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.pi/agent/skills/citable/schemas/page.schema.json +3 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/regional-network-import.schema.json +55 -0
- package/dist/universal/.pi/agent/skills/citable/schemas/source-identity-chain.schema.json +83 -0
- package/dist/universal/.pi/agent/skills/citable/scripts/README.md +3 -1
- package/dist/universal/.qoder/skills/citable/SKILL.md +13 -4
- package/dist/universal/.qoder/skills/citable/VERSION +1 -1
- package/dist/universal/.qoder/skills/citable/agents/citable-auditor.md +64 -0
- package/dist/universal/.qoder/skills/citable/agents/citable-semantic-reviewer.md +66 -0
- package/dist/universal/.qoder/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.qoder/skills/citable/commands/observe-and-act.md +50 -3
- package/dist/universal/.qoder/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.qoder/skills/citable/manifest.json +26 -14
- package/dist/universal/.qoder/skills/citable/schemas/action-plan.schema.json +13 -0
- package/dist/universal/.qoder/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
- package/dist/universal/.qoder/skills/citable/schemas/canonical-index-import.schema.json +30 -0
- package/dist/universal/.qoder/skills/citable/schemas/common.defs.json +12 -1
- package/dist/universal/.qoder/skills/citable/schemas/corroboration-import.schema.json +48 -0
- package/dist/universal/.qoder/skills/citable/schemas/entity-graph.schema.json +75 -0
- package/dist/universal/.qoder/skills/citable/schemas/entity.schema.json +13 -0
- package/dist/universal/.qoder/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.qoder/skills/citable/schemas/page.schema.json +3 -0
- package/dist/universal/.qoder/skills/citable/schemas/regional-network-import.schema.json +55 -0
- package/dist/universal/.qoder/skills/citable/schemas/source-identity-chain.schema.json +83 -0
- package/dist/universal/.qoder/skills/citable/scripts/README.md +3 -1
- package/dist/universal/.rovodev/skills/citable/SKILL.md +13 -4
- package/dist/universal/.rovodev/skills/citable/VERSION +1 -1
- package/dist/universal/.rovodev/skills/citable/agents/citable-auditor.md +64 -0
- package/dist/universal/.rovodev/skills/citable/agents/citable-semantic-reviewer.md +66 -0
- package/dist/universal/.rovodev/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.rovodev/skills/citable/commands/observe-and-act.md +50 -3
- package/dist/universal/.rovodev/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.rovodev/skills/citable/manifest.json +26 -14
- package/dist/universal/.rovodev/skills/citable/schemas/action-plan.schema.json +13 -0
- package/dist/universal/.rovodev/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
- package/dist/universal/.rovodev/skills/citable/schemas/canonical-index-import.schema.json +30 -0
- package/dist/universal/.rovodev/skills/citable/schemas/common.defs.json +12 -1
- package/dist/universal/.rovodev/skills/citable/schemas/corroboration-import.schema.json +48 -0
- package/dist/universal/.rovodev/skills/citable/schemas/entity-graph.schema.json +75 -0
- package/dist/universal/.rovodev/skills/citable/schemas/entity.schema.json +13 -0
- package/dist/universal/.rovodev/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.rovodev/skills/citable/schemas/page.schema.json +3 -0
- package/dist/universal/.rovodev/skills/citable/schemas/regional-network-import.schema.json +55 -0
- package/dist/universal/.rovodev/skills/citable/schemas/source-identity-chain.schema.json +83 -0
- package/dist/universal/.rovodev/skills/citable/scripts/README.md +3 -1
- package/dist/universal/.trae/skills/citable/SKILL.md +13 -4
- package/dist/universal/.trae/skills/citable/VERSION +1 -1
- package/dist/universal/.trae/skills/citable/agents/citable-auditor.md +64 -0
- package/dist/universal/.trae/skills/citable/agents/citable-semantic-reviewer.md +66 -0
- package/dist/universal/.trae/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.trae/skills/citable/commands/observe-and-act.md +50 -3
- package/dist/universal/.trae/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.trae/skills/citable/manifest.json +26 -14
- package/dist/universal/.trae/skills/citable/schemas/action-plan.schema.json +13 -0
- package/dist/universal/.trae/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
- package/dist/universal/.trae/skills/citable/schemas/canonical-index-import.schema.json +30 -0
- package/dist/universal/.trae/skills/citable/schemas/common.defs.json +12 -1
- package/dist/universal/.trae/skills/citable/schemas/corroboration-import.schema.json +48 -0
- package/dist/universal/.trae/skills/citable/schemas/entity-graph.schema.json +75 -0
- package/dist/universal/.trae/skills/citable/schemas/entity.schema.json +13 -0
- package/dist/universal/.trae/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.trae/skills/citable/schemas/page.schema.json +3 -0
- package/dist/universal/.trae/skills/citable/schemas/regional-network-import.schema.json +55 -0
- package/dist/universal/.trae/skills/citable/schemas/source-identity-chain.schema.json +83 -0
- package/dist/universal/.trae/skills/citable/scripts/README.md +3 -1
- package/dist/universal/.trae-cn/skills/citable/SKILL.md +13 -4
- package/dist/universal/.trae-cn/skills/citable/VERSION +1 -1
- package/dist/universal/.trae-cn/skills/citable/agents/citable-auditor.md +64 -0
- package/dist/universal/.trae-cn/skills/citable/agents/citable-semantic-reviewer.md +66 -0
- package/dist/universal/.trae-cn/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.trae-cn/skills/citable/commands/observe-and-act.md +50 -3
- package/dist/universal/.trae-cn/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.trae-cn/skills/citable/manifest.json +26 -14
- package/dist/universal/.trae-cn/skills/citable/schemas/action-plan.schema.json +13 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/browser-evidence-plan.schema.json +14 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/canonical-index-import.schema.json +30 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/common.defs.json +12 -1
- package/dist/universal/.trae-cn/skills/citable/schemas/corroboration-import.schema.json +48 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/entity-graph.schema.json +75 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/entity.schema.json +13 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/observation.schema.json +1 -1
- package/dist/universal/.trae-cn/skills/citable/schemas/page.schema.json +3 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/regional-network-import.schema.json +55 -0
- package/dist/universal/.trae-cn/skills/citable/schemas/source-identity-chain.schema.json +83 -0
- package/dist/universal/.trae-cn/skills/citable/scripts/README.md +3 -1
- package/dist/universal/manifest.json +270 -171
- package/package.json +1 -1
- package/schemas/action-plan.schema.json +13 -0
- package/schemas/browser-evidence-plan.schema.json +14 -0
- package/schemas/canonical-index-import.schema.json +30 -0
- package/schemas/common.defs.json +12 -1
- package/schemas/corroboration-import.schema.json +48 -0
- package/schemas/entity-graph.schema.json +75 -0
- package/schemas/entity.schema.json +13 -0
- package/schemas/observation.schema.json +1 -1
- package/schemas/page.schema.json +3 -0
- package/schemas/regional-network-import.schema.json +55 -0
- package/schemas/source-identity-chain.schema.json +83 -0
- package/scripts/build-dist.js +36 -3
- package/skill/SKILL.md +13 -4
- package/skill/agents/citable-auditor.md +64 -0
- package/skill/agents/citable-semantic-reviewer.md +66 -0
- package/skill/commands/action-findings.md +9 -1
- package/skill/commands/observe-and-act.md +50 -3
- package/skill/commands/plan-audit.md +35 -0
- package/src/cli/index.js +38 -5
- package/src/commands/actionPlan.js +12 -1
- package/src/commands/audit.js +4 -0
- package/src/commands/demo.js +36 -0
- package/src/commands/fixtures/demo/.citable/claims.yaml +27 -0
- package/src/commands/fixtures/demo/.citable/competitors.yaml +3 -0
- package/src/commands/fixtures/demo/.citable/config.yaml +18 -0
- package/src/commands/fixtures/demo/.citable/crawlers.yaml +30 -0
- package/src/commands/fixtures/demo/.citable/entities.yaml +28 -0
- package/src/commands/fixtures/demo/.citable/evidence.yaml +19 -0
- package/src/commands/fixtures/demo/.citable/experiments.yaml +3 -0
- package/src/commands/fixtures/demo/.citable/pages.yaml +54 -0
- package/src/commands/fixtures/demo/.citable/prompts.yaml +11 -0
- package/src/commands/fixtures/demo/.citable/queries.yaml +10 -0
- package/src/commands/fixtures/demo/site/index.html +12 -0
- package/src/commands/fixtures/demo/site/learn/execution-governance/index.html +14 -0
- package/src/commands/fixtures/demo/site/pricing/index.html +10 -0
- package/src/commands/fixtures/demo/site/products/gatekeeper/index.html +15 -0
- package/src/commands/fixtures/demo/site/robots.txt +7 -0
- package/src/commands/fixtures/demo/site/sitemap.xml +7 -0
- package/src/commands/init.js +5 -2
- package/src/commands/observe.js +313 -15
- package/src/commands/planAudit.js +151 -0
- package/src/commands/schemaCmd.js +5 -1
- package/src/commands/substantiate.js +22 -10
- package/src/crawler/fetch.js +34 -6
- package/src/extractor/page.js +17 -0
- package/src/installer/index.js +282 -28
- package/src/installer/providers.js +11 -0
- package/src/observations/browserJourney.js +15 -7
- package/src/observations/claimDiff.js +83 -0
- package/src/observations/common.js +15 -0
- package/src/observations/entityGraph.js +89 -0
- package/src/observations/renderParity.js +49 -0
- package/src/observations/sourceIdentity.js +62 -0
- package/src/registries/seed.js +95 -0
- package/src/registries/seeds/saas-pricing/claims.yaml +18 -0
- package/src/registries/seeds/saas-pricing/entities.yaml +20 -0
- package/src/registries/seeds/saas-pricing/seed.json +6 -0
- package/src/shared/checklist.js +19 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { sha256 } from '../shared/io.js';
|
|
2
|
+
import { validateAgainst } from '../shared/schemaValidator.js';
|
|
3
|
+
|
|
4
|
+
const list = (value) => Array.isArray(value) ? value : value == null ? [] : [value];
|
|
5
|
+
|
|
6
|
+
function visibleSupport(node, page) {
|
|
7
|
+
const candidates = [
|
|
8
|
+
...list(node.name).map((value) => ['name', value]),
|
|
9
|
+
...list(node.headline).map((value) => ['headline', value]),
|
|
10
|
+
...list(node.description).map((value) => ['description', value]),
|
|
11
|
+
].filter(([, value]) => typeof value === 'string' && value.trim());
|
|
12
|
+
if (!candidates.length) return { status: 'not_testable', matched_fields: [] };
|
|
13
|
+
const visible = `${page.title || ''} ${page.text || ''}`.toLocaleLowerCase();
|
|
14
|
+
const matchedFields = [...new Set(candidates
|
|
15
|
+
.filter(([, value]) => visible.includes(value.trim().toLocaleLowerCase()))
|
|
16
|
+
.map(([field]) => field))].sort();
|
|
17
|
+
return { status: matchedFields.length ? 'supported' : 'not_observed', matched_fields: matchedFields };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function referencedIds(value, relation, out = []) {
|
|
21
|
+
if (Array.isArray(value)) {
|
|
22
|
+
for (const item of value) referencedIds(item, relation, out);
|
|
23
|
+
} else if (value && typeof value === 'object') {
|
|
24
|
+
if (typeof value['@id'] === 'string') out.push({ relation, target_id: value['@id'] });
|
|
25
|
+
else for (const [key, nested] of Object.entries(value)) referencedIds(nested, key, out);
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function buildEntityGraph(pages) {
|
|
31
|
+
const nodeMap = new Map();
|
|
32
|
+
const pendingEdges = [];
|
|
33
|
+
const parseFailures = [];
|
|
34
|
+
for (const page of pages) {
|
|
35
|
+
for (const script of page.jsonLd) {
|
|
36
|
+
if (script.parseError) {
|
|
37
|
+
parseFailures.push({ url: page.url, error: script.parseError, raw_hash: sha256(script.raw) });
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
for (const block of script.blocks) {
|
|
41
|
+
if (!block || typeof block !== 'object' || Array.isArray(block)) continue;
|
|
42
|
+
const blockHash = sha256(JSON.stringify(block));
|
|
43
|
+
const nodeId = typeof block['@id'] === 'string' && block['@id'].trim()
|
|
44
|
+
? block['@id']
|
|
45
|
+
: `urn:citable:jsonld:${blockHash}`;
|
|
46
|
+
const prior = nodeMap.get(nodeId) || {
|
|
47
|
+
node_id: nodeId, types: [], names: [], source_blocks: [],
|
|
48
|
+
visible_support: { status: 'not_testable', matched_fields: [] },
|
|
49
|
+
};
|
|
50
|
+
prior.types = [...new Set([...prior.types, ...list(block['@type']).filter((value) => typeof value === 'string')])].sort();
|
|
51
|
+
prior.names = [...new Set([...prior.names, ...list(block.name).filter((value) => typeof value === 'string' && value.trim())])].sort();
|
|
52
|
+
prior.source_blocks.push({ url: page.url, block_hash: blockHash });
|
|
53
|
+
const support = visibleSupport(block, page);
|
|
54
|
+
prior.visible_support = {
|
|
55
|
+
status: prior.visible_support.status === 'supported' || support.status === 'supported'
|
|
56
|
+
? 'supported'
|
|
57
|
+
: prior.visible_support.status === 'not_observed' || support.status === 'not_observed'
|
|
58
|
+
? 'not_observed'
|
|
59
|
+
: 'not_testable',
|
|
60
|
+
matched_fields: [...new Set([...prior.visible_support.matched_fields, ...support.matched_fields])].sort(),
|
|
61
|
+
};
|
|
62
|
+
nodeMap.set(nodeId, prior);
|
|
63
|
+
for (const [relation, value] of Object.entries(block)) {
|
|
64
|
+
if (relation.startsWith('@')) continue;
|
|
65
|
+
for (const ref of referencedIds(value, relation)) {
|
|
66
|
+
pendingEdges.push({ source_id: nodeId, relation: ref.relation, target_id: ref.target_id, source_url: page.url });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const nodes = [...nodeMap.values()].sort((a, b) => a.node_id.localeCompare(b.node_id));
|
|
73
|
+
const nodeIds = new Set(nodes.map((node) => node.node_id));
|
|
74
|
+
const allEdges = pendingEdges.map((edge) => ({ ...edge, target_declared: nodeIds.has(edge.target_id) }))
|
|
75
|
+
.sort((a, b) => `${a.source_id}:${a.relation}:${a.target_id}`.localeCompare(`${b.source_id}:${b.relation}:${b.target_id}`));
|
|
76
|
+
const graph = {
|
|
77
|
+
version: 1,
|
|
78
|
+
nodes,
|
|
79
|
+
edges: allEdges.filter((edge) => edge.target_declared),
|
|
80
|
+
unresolved_references: allEdges.filter((edge) => !edge.target_declared),
|
|
81
|
+
parse_failures: parseFailures,
|
|
82
|
+
limitations: [
|
|
83
|
+
'Normalization reports declared JSON-LD structure and literal visible-text matches; it does not establish semantic correctness, eligibility, search-engine recognition, or ranking impact.',
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
const check = validateAgainst('entity-graph.schema.json', graph);
|
|
87
|
+
if (!check.valid) throw new Error(`entity graph violates contract: ${check.errors.join('; ')}`);
|
|
88
|
+
return graph;
|
|
89
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { parse } from 'node-html-parser';
|
|
2
|
+
import { sha256 } from '../shared/io.js';
|
|
3
|
+
|
|
4
|
+
function profile(html) {
|
|
5
|
+
const root = parse(String(html || ''));
|
|
6
|
+
for (const node of root.querySelectorAll('script,style,noscript,nav,footer,header[role=banner]')) node.remove();
|
|
7
|
+
const text = root.textContent.replace(/\s+/g, ' ').trim();
|
|
8
|
+
const tokens = new Set(text.toLocaleLowerCase().split(/\s+/).filter(Boolean));
|
|
9
|
+
const headings = root.querySelectorAll('h1,h2,h3,h4,h5,h6').map((node) => node.text.replace(/\s+/g, ' ').trim()).filter(Boolean).sort();
|
|
10
|
+
const links = root.querySelectorAll('a[href]').map((node) => node.getAttribute('href')).filter(Boolean).sort();
|
|
11
|
+
const structuredData = parse(String(html || '')).querySelectorAll('script[type="application/ld+json"]').map((node) => sha256(node.text)).sort();
|
|
12
|
+
return { text, tokens, headings, links, structuredData };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const missing = (before, after) => before.filter((value) => !after.includes(value));
|
|
16
|
+
|
|
17
|
+
export function analyzeRenderParity(initialHtml, renderedHtml, policy = null) {
|
|
18
|
+
const initial = profile(initialHtml);
|
|
19
|
+
const rendered = profile(renderedHtml);
|
|
20
|
+
const retained = [...initial.tokens].filter((token) => rendered.tokens.has(token)).length;
|
|
21
|
+
const textRetentionRatio = initial.tokens.size ? Number((retained / initial.tokens.size).toFixed(3)) : null;
|
|
22
|
+
const removedHeadings = missing(initial.headings, rendered.headings);
|
|
23
|
+
const removedLinks = missing(initial.links, rendered.links);
|
|
24
|
+
const structuredDataMatches = JSON.stringify(initial.structuredData) === JSON.stringify(rendered.structuredData);
|
|
25
|
+
const violations = [];
|
|
26
|
+
if (policy) {
|
|
27
|
+
if (textRetentionRatio != null && textRetentionRatio < policy.min_text_retention_ratio) {
|
|
28
|
+
violations.push({ check: 'text_retention', observed: textRetentionRatio, required: policy.min_text_retention_ratio });
|
|
29
|
+
}
|
|
30
|
+
if (policy.require_heading_parity && removedHeadings.length) violations.push({ check: 'heading_parity', observed: removedHeadings.length, required: 0 });
|
|
31
|
+
if (policy.require_link_parity && removedLinks.length) violations.push({ check: 'link_parity', observed: removedLinks.length, required: 0 });
|
|
32
|
+
if (policy.require_structured_data_parity && !structuredDataMatches) violations.push({ check: 'structured_data_parity', observed: false, required: true });
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
policy_id: policy?.policy_id || null,
|
|
36
|
+
review_owner: policy?.review_owner || null,
|
|
37
|
+
initial_text_hash: sha256(initial.text),
|
|
38
|
+
rendered_text_hash: sha256(rendered.text),
|
|
39
|
+
text_retention_ratio: textRetentionRatio,
|
|
40
|
+
removed_headings: removedHeadings,
|
|
41
|
+
added_headings: missing(rendered.headings, initial.headings),
|
|
42
|
+
removed_links: removedLinks,
|
|
43
|
+
added_links: missing(rendered.links, initial.links),
|
|
44
|
+
structured_data_matches: structuredDataMatches,
|
|
45
|
+
policy_violations: violations,
|
|
46
|
+
semantic_review_status: policy ? 'review_required' : 'not_evidenced',
|
|
47
|
+
interpretation_boundary: 'Deterministic parity and policy checks do not establish semantic, retrieval, citation, ranking, or business impact.',
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { validateAgainst } from '../shared/schemaValidator.js';
|
|
2
|
+
|
|
3
|
+
export function buildSourceIdentityChain(registries) {
|
|
4
|
+
const entities = new Map((registries.entities?.entries || []).map((item) => [item.entity_id, item]));
|
|
5
|
+
const evidence = new Map((registries.evidence?.entries || []).map((item) => [item.evidence_id, item]));
|
|
6
|
+
const pages = (registries.pages?.entries || []).map((page) => {
|
|
7
|
+
const publisherEntity = entities.get(page.publisher_entity);
|
|
8
|
+
const publisher = publisherEntity ? {
|
|
9
|
+
entity_id: publisherEntity.entity_id,
|
|
10
|
+
name: publisherEntity.canonical_name,
|
|
11
|
+
canonical_url: publisherEntity.canonical_url || null,
|
|
12
|
+
status: publisherEntity.status,
|
|
13
|
+
} : null;
|
|
14
|
+
const authors = (page.author_entities || []).map((id) => {
|
|
15
|
+
const entity = entities.get(id);
|
|
16
|
+
return entity ? {
|
|
17
|
+
entity_id: entity.entity_id,
|
|
18
|
+
name: entity.canonical_name,
|
|
19
|
+
canonical_url: entity.canonical_url || null,
|
|
20
|
+
affiliations: (entity.affiliations || []).map((affiliation) => ({
|
|
21
|
+
...affiliation,
|
|
22
|
+
entity_name: entities.get(affiliation.entity_id)?.canonical_name || null,
|
|
23
|
+
})),
|
|
24
|
+
status: entity.status,
|
|
25
|
+
} : { entity_id: id, name: null, canonical_url: null, affiliations: [], status: 'missing' };
|
|
26
|
+
});
|
|
27
|
+
const evidenceOwners = (page.evidence_references || []).map((id) => {
|
|
28
|
+
const item = evidence.get(id);
|
|
29
|
+
return { evidence_id: id, owner: item?.source_owner || null, verification_status: item?.verification_status || 'missing' };
|
|
30
|
+
});
|
|
31
|
+
const missing = [];
|
|
32
|
+
if (!publisher) missing.push('publisher_entity');
|
|
33
|
+
if (!authors.length) missing.push('author_entities');
|
|
34
|
+
else if (authors.some((author) => !author.affiliations.length)) missing.push('author_affiliations');
|
|
35
|
+
if (!page.content_owner) missing.push('content_owner');
|
|
36
|
+
if (!page.factual_reviewer) missing.push('factual_reviewer');
|
|
37
|
+
if (!page.correction_path) missing.push('correction_path');
|
|
38
|
+
if (evidenceOwners.some((item) => !item.owner)) missing.push('evidence_owner');
|
|
39
|
+
return {
|
|
40
|
+
page_id: page.page_id,
|
|
41
|
+
url: page.url,
|
|
42
|
+
publisher,
|
|
43
|
+
authors,
|
|
44
|
+
content_owner: page.content_owner || null,
|
|
45
|
+
factual_reviewer: page.factual_reviewer || null,
|
|
46
|
+
evidence_owners: evidenceOwners,
|
|
47
|
+
correction_path: page.correction_path || null,
|
|
48
|
+
status: missing.length ? 'incomplete' : 'complete',
|
|
49
|
+
missing_fields: [...new Set(missing)].sort(),
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
const chain = {
|
|
53
|
+
version: 1,
|
|
54
|
+
pages,
|
|
55
|
+
limitations: [
|
|
56
|
+
'Registry linkage records declared identity and governance relationships; it does not establish that disclosures are visible, current, independent, or recognized by external systems.',
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
const check = validateAgainst('source-identity-chain.schema.json', chain);
|
|
60
|
+
if (!check.valid) throw new Error(`source identity chain violates contract: ${check.errors.join('; ')}`);
|
|
61
|
+
return chain;
|
|
62
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { readYaml, nowIso, sha256 } from '../shared/io.js';
|
|
5
|
+
import { loadRegistries, saveRegistry, REGISTRY_SPECS } from './index.js';
|
|
6
|
+
|
|
7
|
+
const SEEDS_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), 'seeds');
|
|
8
|
+
|
|
9
|
+
export function listSeeds(seedsDir = SEEDS_DIR) {
|
|
10
|
+
if (!fs.existsSync(seedsDir)) return [];
|
|
11
|
+
return fs.readdirSync(seedsDir).filter((name) => fs.existsSync(path.join(seedsDir, name, 'seed.json')));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function loadSeedManifest(name, seedsDir) {
|
|
15
|
+
const dir = path.join(seedsDir, name);
|
|
16
|
+
const manifestFile = path.join(dir, 'seed.json');
|
|
17
|
+
if (!fs.existsSync(manifestFile)) {
|
|
18
|
+
throw new Error(`unknown seed: ${name}; available seeds: ${listSeeds(seedsDir).join(', ') || 'none bundled'}`);
|
|
19
|
+
}
|
|
20
|
+
return { dir, manifest: JSON.parse(fs.readFileSync(manifestFile, 'utf8')) };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Deterministic, key-order-independent serialization for content fingerprinting. */
|
|
24
|
+
function stableStringify(value) {
|
|
25
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`;
|
|
26
|
+
if (value && typeof value === 'object') {
|
|
27
|
+
return `{${Object.keys(value).sort().map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`).join(',')}}`;
|
|
28
|
+
}
|
|
29
|
+
return JSON.stringify(value);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Fingerprint an entry's content, excluding provenance (which carries the fingerprint itself). */
|
|
33
|
+
function contentFingerprint(entry) {
|
|
34
|
+
const { provenance, ...rest } = entry;
|
|
35
|
+
return sha256(stableStringify(rest));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Overlay a bundled starter registry seed onto the caller's `.citable/` registries.
|
|
40
|
+
*
|
|
41
|
+
* Fail-closed guarantees, enforced in code (never trusted from the seed file itself):
|
|
42
|
+
* - every written entry is stamped `status: unverified` unconditionally, regardless of
|
|
43
|
+
* what status the seed bundle declares (candidate, active, verified — all forced);
|
|
44
|
+
* - an existing entry is only ever refreshed (even with `force`) if its current content
|
|
45
|
+
* still matches the fingerprint recorded at seed time — `provenance.seededFrom` being
|
|
46
|
+
* present is not by itself proof the entry is unedited, since a user can edit a field
|
|
47
|
+
* while leaving provenance untouched; a fingerprint mismatch means the owner changed
|
|
48
|
+
* it, and a seed can never clobber that edit.
|
|
49
|
+
*/
|
|
50
|
+
export function applySeed(root, name, { force = false, seedsDir = SEEDS_DIR } = {}) {
|
|
51
|
+
const { dir, manifest } = loadSeedManifest(name, seedsDir);
|
|
52
|
+
const { registries } = loadRegistries(root);
|
|
53
|
+
const appliedAt = nowIso();
|
|
54
|
+
const result = { seedName: name, seedVersion: manifest.version, appliedAt, registriesTouched: {}, warnings: [] };
|
|
55
|
+
|
|
56
|
+
for (const kind of manifest.registries) {
|
|
57
|
+
const spec = REGISTRY_SPECS.find((s) => s.kind === kind);
|
|
58
|
+
if (!spec) { result.warnings.push(`seed "${name}" references unknown registry kind "${kind}"; skipped`); continue; }
|
|
59
|
+
const seedFile = path.join(dir, spec.file);
|
|
60
|
+
if (!fs.existsSync(seedFile)) continue;
|
|
61
|
+
const seedRegistry = readYaml(seedFile);
|
|
62
|
+
const existing = registries[kind];
|
|
63
|
+
const existingById = new Map(existing.entries.map((e) => [e[spec.idField], e]));
|
|
64
|
+
let added = 0;
|
|
65
|
+
let skipped = 0;
|
|
66
|
+
|
|
67
|
+
for (const entry of seedRegistry.entries) {
|
|
68
|
+
const id = entry[spec.idField];
|
|
69
|
+
const already = existingById.get(id);
|
|
70
|
+
if (already) {
|
|
71
|
+
const seededFrom = already.provenance?.seededFrom;
|
|
72
|
+
const unedited = seededFrom && seededFrom.contentFingerprint === contentFingerprint(already);
|
|
73
|
+
if (!force || !unedited) { skipped++; continue; }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (entry.status !== 'unverified') {
|
|
77
|
+
result.warnings.push(`${kind}/${id}: seed attempted status "${entry.status}"; forced to "unverified"`);
|
|
78
|
+
entry.status = 'unverified';
|
|
79
|
+
}
|
|
80
|
+
entry.provenance = {
|
|
81
|
+
...(entry.provenance || {}),
|
|
82
|
+
seededFrom: { seedName: name, seedVersion: manifest.version, importedAt: appliedAt, contentFingerprint: contentFingerprint(entry) },
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
if (already) Object.assign(already, entry);
|
|
86
|
+
else existing.entries.push(entry);
|
|
87
|
+
added++;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
saveRegistry(root, kind, existing);
|
|
91
|
+
result.registriesTouched[kind] = { added, skipped };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
kind: claims
|
|
3
|
+
entries:
|
|
4
|
+
- claim_id: CLAIM-SEED-PRICING-TRANSPARENCY
|
|
5
|
+
claim: >
|
|
6
|
+
Placeholder: replace with a specific, evidenced pricing claim for your
|
|
7
|
+
product (e.g. published starting price, billing unit, plan boundaries).
|
|
8
|
+
claim_type: commercial
|
|
9
|
+
entity: ENT-SEED-PRODUCT
|
|
10
|
+
publication_surfaces: ["/pricing/"]
|
|
11
|
+
status: unverified
|
|
12
|
+
- claim_id: CLAIM-SEED-FEATURE-SCOPE
|
|
13
|
+
claim: >
|
|
14
|
+
Placeholder: replace with a specific, evidenced capability claim and its
|
|
15
|
+
scope/exclusions (what the product does and explicitly does not do).
|
|
16
|
+
claim_type: capability
|
|
17
|
+
entity: ENT-SEED-PRODUCT
|
|
18
|
+
status: unverified
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
kind: entities
|
|
3
|
+
entries:
|
|
4
|
+
- entity_id: ENT-SEED-VENDOR
|
|
5
|
+
canonical_name: (your company name)
|
|
6
|
+
entity_type: organization
|
|
7
|
+
category: SaaS vendor
|
|
8
|
+
definition: >
|
|
9
|
+
Replace with your organization's own definition. Seeded as a starting
|
|
10
|
+
shape only — not a fact about your company.
|
|
11
|
+
status: unverified
|
|
12
|
+
- entity_id: ENT-SEED-PRODUCT
|
|
13
|
+
canonical_name: (your product name)
|
|
14
|
+
entity_type: product
|
|
15
|
+
owner_entity: ENT-SEED-VENDOR
|
|
16
|
+
category: SaaS product
|
|
17
|
+
definition: >
|
|
18
|
+
Replace with your product's own definition. Seeded as a starting shape
|
|
19
|
+
only — not a fact about your product.
|
|
20
|
+
status: unverified
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared required-input checklist item builder used by substantiate, schemaCmd,
|
|
3
|
+
* and actionPlan so the three no longer maintain independent literal-string lists.
|
|
4
|
+
* Callers still serialize to array<string> via toStringArray — no consumer-facing
|
|
5
|
+
* shape changes.
|
|
6
|
+
*/
|
|
7
|
+
export function checklistItem(id, label, note) {
|
|
8
|
+
return { id, label, satisfied: false, note: note ?? null };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Render one item (or an already-plain string) down to its display label. */
|
|
12
|
+
export function toLabel(item) {
|
|
13
|
+
return typeof item === 'string' ? item : item.label;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Serialize a list of items (or plain strings) to array<string>. */
|
|
17
|
+
export function toStringArray(items) {
|
|
18
|
+
return items.map(toLabel);
|
|
19
|
+
}
|