@nebulacomponents/citable 1.13.1 → 1.15.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 +312 -0
- package/README.md +44 -6
- package/dist/universal/.agents/skills/citable/SKILL.md +22 -8
- 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/README.md +4 -1
- package/dist/universal/.agents/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.agents/skills/citable/commands/observe-and-act.md +62 -8
- package/dist/universal/.agents/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.agents/skills/citable/commands/reporting.md +57 -0
- package/dist/universal/.agents/skills/citable/manifest.json +29 -16
- 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/schedule.schema.json +1 -1
- 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 +22 -8
- 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/README.md +4 -1
- package/dist/universal/.claude/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.claude/skills/citable/commands/observe-and-act.md +62 -8
- package/dist/universal/.claude/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.claude/skills/citable/commands/reporting.md +57 -0
- package/dist/universal/.claude/skills/citable/manifest.json +34 -16
- 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/schedule.schema.json +1 -1
- 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 +22 -8
- 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/README.md +4 -1
- package/dist/universal/.cursor/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.cursor/skills/citable/commands/observe-and-act.md +62 -8
- package/dist/universal/.cursor/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.cursor/skills/citable/commands/reporting.md +57 -0
- package/dist/universal/.cursor/skills/citable/manifest.json +29 -16
- 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/schedule.schema.json +1 -1
- 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 +22 -8
- 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/README.md +4 -1
- package/dist/universal/.gemini/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.gemini/skills/citable/commands/observe-and-act.md +62 -8
- package/dist/universal/.gemini/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.gemini/skills/citable/commands/reporting.md +57 -0
- package/dist/universal/.gemini/skills/citable/manifest.json +29 -16
- 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/schedule.schema.json +1 -1
- 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 +22 -8
- 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/README.md +4 -1
- package/dist/universal/.github/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.github/skills/citable/commands/observe-and-act.md +62 -8
- package/dist/universal/.github/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.github/skills/citable/commands/reporting.md +57 -0
- package/dist/universal/.github/skills/citable/manifest.json +29 -16
- 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/schedule.schema.json +1 -1
- 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 +22 -8
- 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/README.md +4 -1
- package/dist/universal/.kiro/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.kiro/skills/citable/commands/observe-and-act.md +62 -8
- package/dist/universal/.kiro/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.kiro/skills/citable/commands/reporting.md +57 -0
- package/dist/universal/.kiro/skills/citable/manifest.json +29 -16
- 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/schedule.schema.json +1 -1
- 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 +22 -8
- 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/README.md +4 -1
- package/dist/universal/.opencode/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.opencode/skills/citable/commands/observe-and-act.md +62 -8
- package/dist/universal/.opencode/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.opencode/skills/citable/commands/reporting.md +57 -0
- package/dist/universal/.opencode/skills/citable/manifest.json +29 -16
- 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/schedule.schema.json +1 -1
- 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 +22 -8
- 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/README.md +4 -1
- 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 +62 -8
- package/dist/universal/.pi/agent/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.pi/agent/skills/citable/commands/reporting.md +57 -0
- package/dist/universal/.pi/agent/skills/citable/manifest.json +29 -16
- 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/schedule.schema.json +1 -1
- 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 +22 -8
- 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/README.md +4 -1
- package/dist/universal/.qoder/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.qoder/skills/citable/commands/observe-and-act.md +62 -8
- package/dist/universal/.qoder/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.qoder/skills/citable/commands/reporting.md +57 -0
- package/dist/universal/.qoder/skills/citable/manifest.json +29 -16
- 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/schedule.schema.json +1 -1
- 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 +22 -8
- 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/README.md +4 -1
- package/dist/universal/.rovodev/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.rovodev/skills/citable/commands/observe-and-act.md +62 -8
- package/dist/universal/.rovodev/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.rovodev/skills/citable/commands/reporting.md +57 -0
- package/dist/universal/.rovodev/skills/citable/manifest.json +29 -16
- 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/schedule.schema.json +1 -1
- 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 +22 -8
- 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/README.md +4 -1
- package/dist/universal/.trae/skills/citable/commands/action-findings.md +9 -1
- package/dist/universal/.trae/skills/citable/commands/observe-and-act.md +62 -8
- package/dist/universal/.trae/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.trae/skills/citable/commands/reporting.md +57 -0
- package/dist/universal/.trae/skills/citable/manifest.json +29 -16
- 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/schedule.schema.json +1 -1
- 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 +22 -8
- 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/README.md +4 -1
- 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 +62 -8
- package/dist/universal/.trae-cn/skills/citable/commands/plan-audit.md +35 -0
- package/dist/universal/.trae-cn/skills/citable/commands/reporting.md +57 -0
- package/dist/universal/.trae-cn/skills/citable/manifest.json +29 -16
- 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/schedule.schema.json +1 -1
- 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 +306 -195
- 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/schedule.schema.json +1 -1
- package/schemas/source-identity-chain.schema.json +83 -0
- package/scripts/build-dist.js +36 -3
- package/skill/SKILL.md +22 -8
- package/skill/agents/citable-auditor.md +64 -0
- package/skill/agents/citable-semantic-reviewer.md +66 -0
- package/skill/commands/README.md +4 -1
- package/skill/commands/action-findings.md +9 -1
- package/skill/commands/observe-and-act.md +62 -8
- package/skill/commands/plan-audit.md +35 -0
- package/skill/commands/reporting.md +57 -0
- package/src/cli/index.js +115 -15
- package/src/commands/actionPlan.js +12 -1
- package/src/commands/audit.js +4 -0
- package/src/commands/connect.js +29 -0
- package/src/commands/context.js +15 -0
- package/src/commands/delivery.js +86 -2
- 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/monitor.js +35 -0
- package/src/commands/observe.js +315 -15
- package/src/commands/planAudit.js +151 -0
- package/src/commands/reportDashboard.js +21 -0
- package/src/commands/reportShareOfVoice.js +60 -0
- package/src/commands/schemaCmd.js +5 -1
- package/src/commands/substantiate.js +22 -10
- package/src/connectors/http.js +6 -3
- package/src/connectors/index.js +3 -1
- package/src/connectors/webflow.js +224 -0
- package/src/connectors/wordpress.js +226 -0
- package/src/crawler/fetch.js +34 -6
- package/src/detectors/geoReco.js +101 -0
- package/src/extractor/page.js +17 -0
- package/src/installer/index.js +282 -28
- package/src/installer/providers.js +11 -0
- package/src/monitoring/alertDelivery.js +98 -0
- package/src/observations/browserJourney.js +15 -7
- package/src/observations/claimDiff.js +83 -0
- package/src/observations/common.js +25 -0
- package/src/observations/entityGraph.js +89 -0
- package/src/observations/renderParity.js +49 -0
- package/src/observations/sourceIdentity.js +62 -0
- package/src/observations/stance.js +261 -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/reporting/dashboard.js +254 -0
- package/src/reporting/shareOfVoice.js +362 -0
- package/src/shared/checklist.js +19 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { envelope, observationRun, readInput } from './common.js';
|
|
2
|
+
import { loadRegistries } from '../registries/index.js';
|
|
3
|
+
import { sha256 } from '../shared/io.js';
|
|
4
|
+
|
|
5
|
+
const FAVORABLE_MARKERS = [
|
|
6
|
+
/\b(?:highly\s+)?recommended\b/i,
|
|
7
|
+
/\bindustry\s+standard\b/i,
|
|
8
|
+
/\bmarket\s+leader\b/i,
|
|
9
|
+
/\bbest(?:-in-class)?\b/i,
|
|
10
|
+
/\btop(?:\s+choice|\s+tier|\s+rated)?\b/i,
|
|
11
|
+
/\bpreferred\s+(?:solution|option|tool|platform)\b/i,
|
|
12
|
+
/\breliable\b/i,
|
|
13
|
+
/\brobust\b/i,
|
|
14
|
+
/\bsecure\b/i,
|
|
15
|
+
/\bperformant\b/i,
|
|
16
|
+
/\befficient\b/i,
|
|
17
|
+
/\bcomprehensive\b/i,
|
|
18
|
+
/\btrusted\b/i,
|
|
19
|
+
/\bintuitive\b/i,
|
|
20
|
+
/\bexcellent\b/i,
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const UNFAVORABLE_MARKERS = [
|
|
24
|
+
/\bcriticized\s+for\b/i,
|
|
25
|
+
/\bexpensive\b/i,
|
|
26
|
+
/\boverpriced\b/i,
|
|
27
|
+
/\bunreliable\b/i,
|
|
28
|
+
/\boutdated\b/i,
|
|
29
|
+
/\blegacy\b/i,
|
|
30
|
+
/\bslow\b/i,
|
|
31
|
+
/\bbuggy\b/i,
|
|
32
|
+
/\bunstable\b/i,
|
|
33
|
+
/\bvulnerabilit(?:y|ies)\b/i,
|
|
34
|
+
/\bsecurity\s+flaw[s]?\b/i,
|
|
35
|
+
/\bsecurity\s+issue[s]?\b/i,
|
|
36
|
+
/\bbreach(?:es)?\b/i,
|
|
37
|
+
/\blacks?\s+(?:critical|essential|basic|key)\b/i,
|
|
38
|
+
/\bmissing\s+(?:critical|essential|key)\b/i,
|
|
39
|
+
/\bpoor\s+(?:performance|support|usability|documentation)\b/i,
|
|
40
|
+
/\bavoid\b/i,
|
|
41
|
+
/\bnot\s+recommended\b/i,
|
|
42
|
+
/\binferior\b/i,
|
|
43
|
+
/\bworst\b/i,
|
|
44
|
+
/\bsteep\s+learning\s+curve\b/i,
|
|
45
|
+
/\bfrustrating\b/i,
|
|
46
|
+
/\bfrequent\s+(?:downtime|crashes|errors|failures)\b/i,
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
function escapeRegex(text) {
|
|
50
|
+
return String(text).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Extract sentences from text.
|
|
55
|
+
*/
|
|
56
|
+
function splitSentences(text) {
|
|
57
|
+
if (!text) return [];
|
|
58
|
+
return String(text)
|
|
59
|
+
.replace(/([.?!])\s+/g, '$1|§|')
|
|
60
|
+
.split('|§|')
|
|
61
|
+
.map((s) => s.trim())
|
|
62
|
+
.filter(Boolean);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Classify tone / stance towards a specific entity within an answer text.
|
|
67
|
+
* Stance categories: 'favorable', 'neutral', 'unfavorable', 'mixed', 'ambiguous'.
|
|
68
|
+
*/
|
|
69
|
+
export function classifyAnswerStance(answerText, entity, { reviewer = null, manualStance = null } = {}) {
|
|
70
|
+
const entityId = entity?.entity_id || 'unknown';
|
|
71
|
+
const canonicalName = entity?.canonical_name || entityId;
|
|
72
|
+
const names = [canonicalName, ...(entity?.aliases || [])].filter(Boolean);
|
|
73
|
+
|
|
74
|
+
if (!names.length || !answerText) {
|
|
75
|
+
return {
|
|
76
|
+
entity_id: entityId,
|
|
77
|
+
canonical_name: canonicalName,
|
|
78
|
+
mentioned: false,
|
|
79
|
+
stance: 'not_mentioned',
|
|
80
|
+
confidence: 'confirmed',
|
|
81
|
+
evidence_passages: [],
|
|
82
|
+
favorable_markers: [],
|
|
83
|
+
unfavorable_markers: [],
|
|
84
|
+
tone_summary: 'Entity not mentioned in text',
|
|
85
|
+
reviewer,
|
|
86
|
+
review_required: false,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Check if any alias / canonical name is mentioned
|
|
91
|
+
const namePatterns = names.map((n) => new RegExp(`\\b${escapeRegex(n)}\\b`, 'i'));
|
|
92
|
+
const isMentioned = namePatterns.some((pattern) => pattern.test(answerText));
|
|
93
|
+
|
|
94
|
+
if (!isMentioned) {
|
|
95
|
+
return {
|
|
96
|
+
entity_id: entityId,
|
|
97
|
+
canonical_name: canonicalName,
|
|
98
|
+
mentioned: false,
|
|
99
|
+
stance: 'not_mentioned',
|
|
100
|
+
confidence: 'confirmed',
|
|
101
|
+
evidence_passages: [],
|
|
102
|
+
favorable_markers: [],
|
|
103
|
+
unfavorable_markers: [],
|
|
104
|
+
tone_summary: 'Entity not mentioned in text',
|
|
105
|
+
reviewer,
|
|
106
|
+
review_required: false,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// If a manual stance from a human reviewer is already recorded, honor it directly
|
|
111
|
+
if (manualStance && ['favorable', 'neutral', 'unfavorable', 'mixed', 'ambiguous'].includes(manualStance)) {
|
|
112
|
+
return {
|
|
113
|
+
entity_id: entityId,
|
|
114
|
+
canonical_name: canonicalName,
|
|
115
|
+
mentioned: true,
|
|
116
|
+
stance: manualStance,
|
|
117
|
+
confidence: reviewer ? 'confirmed' : 'high',
|
|
118
|
+
evidence_passages: [answerText.slice(0, 300)],
|
|
119
|
+
favorable_markers: [],
|
|
120
|
+
unfavorable_markers: [],
|
|
121
|
+
tone_summary: `Human-adjudicated stance: ${manualStance}`,
|
|
122
|
+
reviewer,
|
|
123
|
+
review_required: !reviewer,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Find sentences mentioning the entity
|
|
128
|
+
const sentences = splitSentences(answerText);
|
|
129
|
+
const matchedIndices = new Set();
|
|
130
|
+
sentences.forEach((sentence, idx) => {
|
|
131
|
+
if (namePatterns.some((p) => p.test(sentence))) {
|
|
132
|
+
matchedIndices.add(idx);
|
|
133
|
+
// include adjacent sentence context if available
|
|
134
|
+
if (idx > 0) matchedIndices.add(idx - 1);
|
|
135
|
+
if (idx < sentences.length - 1) matchedIndices.add(idx + 1);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const contextSentences = [...matchedIndices].sort((a, b) => a - b).map((idx) => sentences[idx]);
|
|
140
|
+
const contextText = contextSentences.join(' ');
|
|
141
|
+
|
|
142
|
+
const favorableHits = [];
|
|
143
|
+
for (const rx of FAVORABLE_MARKERS) {
|
|
144
|
+
const m = contextText.match(rx);
|
|
145
|
+
if (m) favorableHits.push(m[0].toLowerCase());
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const unfavorableHits = [];
|
|
149
|
+
for (const rx of UNFAVORABLE_MARKERS) {
|
|
150
|
+
const m = contextText.match(rx);
|
|
151
|
+
if (m) unfavorableHits.push(m[0].toLowerCase());
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let stance = 'neutral';
|
|
155
|
+
if (unfavorableHits.length > 0 && favorableHits.length > 0) {
|
|
156
|
+
stance = 'mixed';
|
|
157
|
+
} else if (unfavorableHits.length > 0) {
|
|
158
|
+
stance = 'unfavorable';
|
|
159
|
+
} else if (favorableHits.length > 0) {
|
|
160
|
+
stance = 'favorable';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const toneSummary = stance === 'unfavorable'
|
|
164
|
+
? `Unfavorable tone detected with markers: ${unfavorableHits.join(', ')}`
|
|
165
|
+
: stance === 'favorable'
|
|
166
|
+
? `Favorable tone detected with markers: ${favorableHits.join(', ')}`
|
|
167
|
+
: stance === 'mixed'
|
|
168
|
+
? `Mixed tone detected (favorable: ${favorableHits.join(', ')}; unfavorable: ${unfavorableHits.join(', ')})`
|
|
169
|
+
: 'Neutral / descriptive tone without evaluative polarity';
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
entity_id: entityId,
|
|
173
|
+
canonical_name: canonicalName,
|
|
174
|
+
mentioned: true,
|
|
175
|
+
stance,
|
|
176
|
+
confidence: reviewer ? 'confirmed' : 'medium',
|
|
177
|
+
evidence_passages: contextSentences.slice(0, 3),
|
|
178
|
+
favorable_markers: [...new Set(favorableHits)],
|
|
179
|
+
unfavorable_markers: [...new Set(unfavorableHits)],
|
|
180
|
+
tone_summary: toneSummary,
|
|
181
|
+
reviewer,
|
|
182
|
+
review_required: !reviewer,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Execute `citable observe stance`.
|
|
188
|
+
*/
|
|
189
|
+
export async function observeStance(root, options = {}) {
|
|
190
|
+
const input = readInput(options.input);
|
|
191
|
+
const { registries, problems } = loadRegistries(root);
|
|
192
|
+
if (problems.length) throw new Error(`registry validation failed: ${problems.join('; ')}`);
|
|
193
|
+
|
|
194
|
+
const entities = (registries.entities?.entries || []).filter((e) => e.status !== 'retired');
|
|
195
|
+
if (!entities.length) throw new Error('no active entities found in entity registry');
|
|
196
|
+
|
|
197
|
+
const targetEntities = options.entity
|
|
198
|
+
? entities.filter((e) => e.entity_id === options.entity || e.canonical_name.toLowerCase() === options.entity.toLowerCase())
|
|
199
|
+
: entities;
|
|
200
|
+
|
|
201
|
+
if (options.entity && !targetEntities.length) {
|
|
202
|
+
throw new Error(`entity not found: ${options.entity}`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Parse candidate items from input
|
|
206
|
+
const doc = input.value;
|
|
207
|
+
const items = Array.isArray(doc)
|
|
208
|
+
? doc
|
|
209
|
+
: doc.observations || doc.items || doc.answers || doc.prompts || [doc];
|
|
210
|
+
|
|
211
|
+
const observations = [];
|
|
212
|
+
for (const item of items) {
|
|
213
|
+
const answerText = item.answer_text || item.answer || item.text || item.data?.answer_text || '';
|
|
214
|
+
if (!answerText) continue;
|
|
215
|
+
|
|
216
|
+
const promptId = item.prompt_id || item.data?.prompt_id || 'unknown';
|
|
217
|
+
const promptText = item.prompt_text || item.data?.prompt_text || null;
|
|
218
|
+
const engine = item.provider || item.engine || item.data?.provider || item.data?.engine || 'unknown';
|
|
219
|
+
const reviewer = options.reviewer || item.reviewer || item.evaluator || null;
|
|
220
|
+
|
|
221
|
+
for (const entity of targetEntities) {
|
|
222
|
+
const classification = classifyAnswerStance(answerText, entity, {
|
|
223
|
+
reviewer,
|
|
224
|
+
manualStance: item.stance || item.sentiment,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
if (!classification.mentioned) continue;
|
|
228
|
+
|
|
229
|
+
const data = {
|
|
230
|
+
prompt_id: promptId,
|
|
231
|
+
prompt_text: promptText,
|
|
232
|
+
engine,
|
|
233
|
+
entity_id: entity.entity_id,
|
|
234
|
+
canonical_name: entity.canonical_name,
|
|
235
|
+
stance: classification.stance,
|
|
236
|
+
evidence_passages: classification.evidence_passages,
|
|
237
|
+
favorable_markers: classification.favorable_markers,
|
|
238
|
+
unfavorable_markers: classification.unfavorable_markers,
|
|
239
|
+
tone_summary: classification.tone_summary,
|
|
240
|
+
reviewer: classification.reviewer,
|
|
241
|
+
review_required: classification.review_required,
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const raw = JSON.stringify({ item, classification });
|
|
245
|
+
observations.push(envelope('stance', data, {
|
|
246
|
+
method: reviewer ? 'human_review' : 'static_analysis',
|
|
247
|
+
source: input.file,
|
|
248
|
+
state: classification.review_required ? 'review_required' : 'observed',
|
|
249
|
+
confidence: classification.confidence,
|
|
250
|
+
raw,
|
|
251
|
+
limitations: classification.review_required
|
|
252
|
+
? ['Automated stance classification is an evidence-backed semantic finding; authoritative determination requires a named human reviewer per the narrative-accuracy rubric.']
|
|
253
|
+
: [],
|
|
254
|
+
}));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return observationRun(root, 'observe stance', input.file, observations, {
|
|
259
|
+
rawInputs: { stance_input: input.raw },
|
|
260
|
+
});
|
|
261
|
+
}
|
|
@@ -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,254 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { readJson } from '../shared/io.js';
|
|
4
|
+
|
|
5
|
+
const POSTURE_CLASS = {
|
|
6
|
+
pass: 'posture-pass',
|
|
7
|
+
partial: 'posture-partial',
|
|
8
|
+
fail: 'posture-fail',
|
|
9
|
+
not_established: 'posture-unknown',
|
|
10
|
+
observed: 'posture-pass',
|
|
11
|
+
not_evidenced: 'posture-unknown',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const NO_GUARANTEE = 'This dashboard renders values already recorded by each audit run. It derives no new findings, combines nothing into an AI visibility score, and guarantees no crawling, indexing, ranking, citation, recommendation, or conversion outcome.';
|
|
15
|
+
|
|
16
|
+
function isAuditSummary(summary) {
|
|
17
|
+
return Boolean(summary) && typeof summary === 'object' && Boolean(summary.by_severity) && Boolean(summary.posture);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Load every audit run that recorded a summary.json, oldest first. Run IDs are
|
|
22
|
+
* `<ISO-timestamp>-<command>-<rand>`, so a lexicographic sort is chronological.
|
|
23
|
+
* A run whose evidence cannot be read is reported in `skipped`, never dropped
|
|
24
|
+
* silently and never thrown.
|
|
25
|
+
*/
|
|
26
|
+
export function loadRunHistory(root, { since, last } = {}) {
|
|
27
|
+
const runsDir = path.join(root, '.citable', 'runs');
|
|
28
|
+
const included = [];
|
|
29
|
+
const skipped = [];
|
|
30
|
+
if (!fs.existsSync(runsDir)) return { included, skipped };
|
|
31
|
+
let runIds = fs.readdirSync(runsDir)
|
|
32
|
+
.filter((runId) => fs.existsSync(path.join(runsDir, runId, 'summary.json')))
|
|
33
|
+
.sort();
|
|
34
|
+
if (since) runIds = runIds.filter((runId) => runId >= since);
|
|
35
|
+
for (const runId of runIds) {
|
|
36
|
+
const dir = path.join(runsDir, runId);
|
|
37
|
+
try {
|
|
38
|
+
const summary = readJson(path.join(dir, 'summary.json'));
|
|
39
|
+
if (!isAuditSummary(summary)) {
|
|
40
|
+
skipped.push({ run_id: runId, reason: 'summary.json records no by_severity or posture; observation runs are not part of the audit trend' });
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
included.push({ run_id: runId, manifest: readJson(path.join(dir, 'manifest.json')), summary });
|
|
44
|
+
} catch (err) {
|
|
45
|
+
skipped.push({ run_id: runId, reason: err.message });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// `last` counts audit runs that carry usable evidence, so an unreadable or
|
|
49
|
+
// observation-only run cannot silently consume the requested window. Skipped
|
|
50
|
+
// runs are reported unless `last` moved the window past them; `since` has
|
|
51
|
+
// already bounded them above.
|
|
52
|
+
const windowed = Number.isInteger(last) && last > 0 ? included.slice(-last) : included;
|
|
53
|
+
const truncated = windowed.length < included.length && windowed.length > 0;
|
|
54
|
+
return {
|
|
55
|
+
included: windowed,
|
|
56
|
+
skipped: truncated ? skipped.filter((item) => item.run_id >= windowed[0].run_id) : skipped,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Project the loaded runs into parallel, run-aligned series. */
|
|
61
|
+
export function buildTimeSeries(included) {
|
|
62
|
+
return {
|
|
63
|
+
run_ids: included.map((run) => run.run_id),
|
|
64
|
+
timestamps: included.map((run) => run.manifest?.timestamp ?? null),
|
|
65
|
+
by_severity_series: included.map((run) => run.summary.by_severity ?? {}),
|
|
66
|
+
retrieval_eligibility_series: included.map((run) => run.summary.posture?.retrieval_eligibility?.result ?? null),
|
|
67
|
+
source_extraction_series: included.map((run) => run.summary.posture?.source_extraction_and_support?.result ?? null),
|
|
68
|
+
citation_presence_rate_series: included.map((run) => run.summary.posture?.observed_citation_behavior?.citation_presence_rate ?? null),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function severityCount(bySeverity, severity) {
|
|
73
|
+
return bySeverity?.[severity] ?? 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function formatRate(rate) {
|
|
77
|
+
return rate == null ? 'not evidenced' : `${(rate * 100).toFixed(1)}%`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function formatPosture(result) {
|
|
81
|
+
return result ?? 'not recorded';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function formatTimestamp(timestamp) {
|
|
85
|
+
return timestamp ?? 'not recorded';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function renderDashboardMarkdown(series, skipped = []) {
|
|
89
|
+
const lines = [];
|
|
90
|
+
const runCount = series.run_ids.length;
|
|
91
|
+
lines.push(`# Citable evidence dashboard`);
|
|
92
|
+
lines.push('');
|
|
93
|
+
lines.push(`- Audit runs included: ${runCount}`);
|
|
94
|
+
lines.push(`- Runs skipped: ${skipped.length}`);
|
|
95
|
+
if (runCount) lines.push(`- Window: \`${series.run_ids[0]}\` → \`${series.run_ids[runCount - 1]}\``);
|
|
96
|
+
lines.push('');
|
|
97
|
+
lines.push(`> ${NO_GUARANTEE}`);
|
|
98
|
+
lines.push('');
|
|
99
|
+
if (runCount < 2) {
|
|
100
|
+
lines.push('## Insufficient history');
|
|
101
|
+
lines.push('');
|
|
102
|
+
lines.push(runCount === 0
|
|
103
|
+
? 'No audit run in `.citable/runs/` recorded a summary. No trend is established. Run `citable audit` to record comparable evidence.'
|
|
104
|
+
: 'Only one audit run is available. A single point establishes no trend, no direction, and no rate of change. Record at least two comparable runs before reading movement into these values.');
|
|
105
|
+
lines.push('');
|
|
106
|
+
}
|
|
107
|
+
if (runCount) {
|
|
108
|
+
lines.push('## Run history');
|
|
109
|
+
lines.push('');
|
|
110
|
+
lines.push('| Run | Timestamp | Critical | High | Medium | Retrieval eligibility | Source extraction | Citation presence rate |');
|
|
111
|
+
lines.push('| --- | --- | --- | --- | --- | --- | --- | --- |');
|
|
112
|
+
for (let i = 0; i < runCount; i++) {
|
|
113
|
+
const sev = series.by_severity_series[i];
|
|
114
|
+
lines.push(`| \`${series.run_ids[i]}\` | ${formatTimestamp(series.timestamps[i])} | ${severityCount(sev, 'critical')} | ${severityCount(sev, 'high')} | ${severityCount(sev, 'medium')} | ${formatPosture(series.retrieval_eligibility_series[i])} | ${formatPosture(series.source_extraction_series[i])} | ${formatRate(series.citation_presence_rate_series[i])} |`);
|
|
115
|
+
}
|
|
116
|
+
lines.push('');
|
|
117
|
+
lines.push('Counts come from each run\'s own recorded summary. A lower count is an observed difference between runs, not proof that a condition was fixed — see `citable compare-snapshots` for run comparability.');
|
|
118
|
+
lines.push('');
|
|
119
|
+
}
|
|
120
|
+
if (skipped.length) {
|
|
121
|
+
lines.push('## Skipped runs');
|
|
122
|
+
lines.push('');
|
|
123
|
+
for (const item of skipped) lines.push(`- \`${item.run_id}\`: ${item.reason}`);
|
|
124
|
+
lines.push('');
|
|
125
|
+
}
|
|
126
|
+
return lines.join('\n');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function escapeHtml(value) {
|
|
130
|
+
return String(value)
|
|
131
|
+
.replace(/&/g, '&')
|
|
132
|
+
.replace(/</g, '<')
|
|
133
|
+
.replace(/>/g, '>')
|
|
134
|
+
.replace(/"/g, '"')
|
|
135
|
+
.replace(/'/g, ''');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Map run-aligned values to `<polyline points>` coordinates. Non-numeric entries
|
|
140
|
+
* (a run with no evidenced value) are omitted rather than interpolated, and
|
|
141
|
+
* fewer than two numeric points yields no line at all.
|
|
142
|
+
*/
|
|
143
|
+
function sparklinePath(values, { width = 480, height = 80 } = {}) {
|
|
144
|
+
const pad = 3;
|
|
145
|
+
const points = values.map((value, index) => ({ value, index })).filter((point) => Number.isFinite(point.value));
|
|
146
|
+
if (points.length < 2) return '';
|
|
147
|
+
const min = Math.min(...points.map((point) => point.value));
|
|
148
|
+
const max = Math.max(...points.map((point) => point.value));
|
|
149
|
+
const span = max - min;
|
|
150
|
+
const steps = Math.max(values.length - 1, 1);
|
|
151
|
+
return points.map((point) => {
|
|
152
|
+
const x = pad + (point.index / steps) * (width - pad * 2);
|
|
153
|
+
const y = span === 0 ? height / 2 : (height - pad) - ((point.value - min) / span) * (height - pad * 2);
|
|
154
|
+
return `${x.toFixed(1)},${y.toFixed(1)}`;
|
|
155
|
+
}).join(' ');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function renderSparkline(title, values, format) {
|
|
159
|
+
const points = sparklinePath(values);
|
|
160
|
+
const numeric = values.filter((value) => Number.isFinite(value));
|
|
161
|
+
const html = [];
|
|
162
|
+
html.push('<section class="chart">');
|
|
163
|
+
html.push(`<h3>${escapeHtml(title)}</h3>`);
|
|
164
|
+
if (!points) {
|
|
165
|
+
html.push(`<p class="note">Fewer than two runs recorded a numeric value for this series (${numeric.length} of ${values.length}). No trend line is drawn.</p>`);
|
|
166
|
+
} else {
|
|
167
|
+
html.push(`<svg viewBox="0 0 480 80" width="480" height="80" role="img" aria-label="${escapeHtml(title)}">`);
|
|
168
|
+
html.push(`<polyline points="${points}" fill="none" stroke="#2f6f4f" stroke-width="2" />`);
|
|
169
|
+
html.push('</svg>');
|
|
170
|
+
html.push(`<p class="note">Range across ${numeric.length} run(s) with a recorded value: ${escapeHtml(format(Math.min(...numeric)))} to ${escapeHtml(format(Math.max(...numeric)))}. The vertical axis is scaled to this range only; runs without a recorded value are omitted, not interpolated.</p>`);
|
|
171
|
+
}
|
|
172
|
+
html.push('</section>');
|
|
173
|
+
return html.join('\n');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function renderPostureRow(label, results, runIds) {
|
|
177
|
+
const cells = results.map((result, index) => `<span class="posture ${POSTURE_CLASS[result] ?? 'posture-unknown'}" title="${escapeHtml(runIds[index])}">${escapeHtml(formatPosture(result))}</span>`).join('');
|
|
178
|
+
return `<section class="chart"><h3>${escapeHtml(label)}</h3><div class="posture-row">${cells}</div><p class="note">Categorical states in run order. These are not plotted as numbers because they have no defined numeric distance.</p></section>`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function renderDashboardHtml(series, skipped = []) {
|
|
182
|
+
const runCount = series.run_ids.length;
|
|
183
|
+
const criticalHigh = series.by_severity_series.map((sev) => severityCount(sev, 'critical') + severityCount(sev, 'high'));
|
|
184
|
+
const html = [];
|
|
185
|
+
html.push('<!doctype html>');
|
|
186
|
+
html.push('<html lang="en">');
|
|
187
|
+
html.push('<head>');
|
|
188
|
+
html.push('<meta charset="utf-8" />');
|
|
189
|
+
html.push('<meta name="viewport" content="width=device-width, initial-scale=1" />');
|
|
190
|
+
html.push('<title>Citable evidence dashboard</title>');
|
|
191
|
+
html.push('<style>');
|
|
192
|
+
html.push('body { font: 16px/1.5 system-ui, sans-serif; margin: 2rem auto; max-width: 60rem; padding: 0 1rem; color: #1c1c1c; }');
|
|
193
|
+
html.push('table { border-collapse: collapse; width: 100%; font-size: 0.875rem; }');
|
|
194
|
+
html.push('th, td { border: 1px solid #d4d4d4; padding: 0.375rem 0.5rem; text-align: left; }');
|
|
195
|
+
html.push('th { background: #f3f3f3; }');
|
|
196
|
+
html.push('code { font-size: 0.8125rem; }');
|
|
197
|
+
html.push('blockquote { border-left: 4px solid #999; margin: 0 0 1.5rem; padding: 0.25rem 1rem; color: #333; }');
|
|
198
|
+
html.push('.note { color: #555; font-size: 0.8125rem; }');
|
|
199
|
+
html.push('.chart { margin: 1.5rem 0; }');
|
|
200
|
+
html.push('.chart svg { background: #fafafa; border: 1px solid #e4e4e4; }');
|
|
201
|
+
html.push('.posture-row { display: flex; flex-wrap: wrap; gap: 0.25rem; }');
|
|
202
|
+
html.push('.posture { border-radius: 3px; font-size: 0.75rem; padding: 0.125rem 0.375rem; }');
|
|
203
|
+
html.push('.posture-pass { background: #e2f2e6; color: #1d5c33; }');
|
|
204
|
+
html.push('.posture-partial { background: #fbf1d8; color: #7a5510; }');
|
|
205
|
+
html.push('.posture-fail { background: #fbe0e0; color: #8c1f1f; }');
|
|
206
|
+
html.push('.posture-unknown { background: #ececec; color: #4a4a4a; }');
|
|
207
|
+
html.push('.insufficient { background: #fbf1d8; border: 1px solid #e2c98a; padding: 0.75rem 1rem; }');
|
|
208
|
+
html.push('</style>');
|
|
209
|
+
html.push('</head>');
|
|
210
|
+
html.push('<body>');
|
|
211
|
+
html.push('<h1>Citable evidence dashboard</h1>');
|
|
212
|
+
html.push('<ul>');
|
|
213
|
+
html.push(`<li>Audit runs included: ${runCount}</li>`);
|
|
214
|
+
html.push(`<li>Runs skipped: ${skipped.length}</li>`);
|
|
215
|
+
if (runCount) html.push(`<li>Window: <code>${escapeHtml(series.run_ids[0])}</code> to <code>${escapeHtml(series.run_ids[runCount - 1])}</code></li>`);
|
|
216
|
+
html.push('</ul>');
|
|
217
|
+
html.push(`<blockquote>${escapeHtml(NO_GUARANTEE)}</blockquote>`);
|
|
218
|
+
if (runCount < 2) {
|
|
219
|
+
html.push('<section class="insufficient">');
|
|
220
|
+
html.push('<h2>Insufficient history</h2>');
|
|
221
|
+
html.push(`<p>${runCount === 0
|
|
222
|
+
? 'No audit run in <code>.citable/runs/</code> recorded a summary. No trend is established. Run <code>citable audit</code> to record comparable evidence.'
|
|
223
|
+
: 'Only one audit run is available. A single point establishes no trend, no direction, and no rate of change. Record at least two comparable runs before reading movement into these values.'}</p>`);
|
|
224
|
+
html.push('</section>');
|
|
225
|
+
}
|
|
226
|
+
if (runCount) {
|
|
227
|
+
html.push('<h2>Trends</h2>');
|
|
228
|
+
html.push(renderSparkline('Critical and high findings per run', criticalHigh, (value) => String(value)));
|
|
229
|
+
html.push(renderSparkline('Observed citation presence rate per run', series.citation_presence_rate_series, formatRate));
|
|
230
|
+
html.push(renderPostureRow('Retrieval eligibility per run', series.retrieval_eligibility_series, series.run_ids));
|
|
231
|
+
html.push(renderPostureRow('Source extraction and support per run', series.source_extraction_series, series.run_ids));
|
|
232
|
+
html.push('<h2>Run history</h2>');
|
|
233
|
+
html.push('<table>');
|
|
234
|
+
html.push('<thead><tr><th>Run</th><th>Timestamp</th><th>Critical</th><th>High</th><th>Medium</th><th>Retrieval eligibility</th><th>Source extraction</th><th>Citation presence rate</th></tr></thead>');
|
|
235
|
+
html.push('<tbody>');
|
|
236
|
+
for (let i = 0; i < runCount; i++) {
|
|
237
|
+
const sev = series.by_severity_series[i];
|
|
238
|
+
html.push(`<tr><td><code>${escapeHtml(series.run_ids[i])}</code></td><td>${escapeHtml(formatTimestamp(series.timestamps[i]))}</td><td>${severityCount(sev, 'critical')}</td><td>${severityCount(sev, 'high')}</td><td>${severityCount(sev, 'medium')}</td><td>${escapeHtml(formatPosture(series.retrieval_eligibility_series[i]))}</td><td>${escapeHtml(formatPosture(series.source_extraction_series[i]))}</td><td>${escapeHtml(formatRate(series.citation_presence_rate_series[i]))}</td></tr>`);
|
|
239
|
+
}
|
|
240
|
+
html.push('</tbody>');
|
|
241
|
+
html.push('</table>');
|
|
242
|
+
html.push('<p class="note">Counts come from each run's own recorded summary. A lower count is an observed difference between runs, not proof that a condition was fixed.</p>');
|
|
243
|
+
}
|
|
244
|
+
if (skipped.length) {
|
|
245
|
+
html.push('<h2>Skipped runs</h2>');
|
|
246
|
+
html.push('<ul>');
|
|
247
|
+
for (const item of skipped) html.push(`<li><code>${escapeHtml(item.run_id)}</code>: ${escapeHtml(item.reason)}</li>`);
|
|
248
|
+
html.push('</ul>');
|
|
249
|
+
}
|
|
250
|
+
html.push('</body>');
|
|
251
|
+
html.push('</html>');
|
|
252
|
+
html.push('');
|
|
253
|
+
return html.join('\n');
|
|
254
|
+
}
|