conexus 3.2.2__tar.gz → 3.2.4__tar.gz
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.
- {conexus-3.2.2 → conexus-3.2.4}/.claude-plugin/marketplace.json +2 -2
- {conexus-3.2.2 → conexus-3.2.4}/CHANGELOG.md +10 -0
- {conexus-3.2.2 → conexus-3.2.4}/CLAUDE.md +10 -9
- {conexus-3.2.2 → conexus-3.2.4}/PKG-INFO +1 -1
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/README.md +1 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-006-chunk-size-configuration.md +1 -1
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-048-streaming-pdf-pipeline.md +1 -1
- conexus-3.2.4/docs/rdr/rdr-054-chunk-boundary-equation-splitting.md +128 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/.claude-plugin/plugin.json +1 -1
- {conexus-3.2.2 → conexus-3.2.4}/nx/CHANGELOG.md +8 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/subagent-start.sh +3 -0
- {conexus-3.2.2 → conexus-3.2.4}/pyproject.toml +1 -1
- {conexus-3.2.2 → conexus-3.2.4}/sn/.claude-plugin/plugin.json +1 -1
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/catalog.py +19 -6
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/mcp_server.py +70 -14
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/md_chunker.py +24 -11
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/pdf_chunker.py +1 -1
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_md_chunker.py +95 -1
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_chunker.py +11 -0
- {conexus-3.2.2 → conexus-3.2.4}/uv.lock +1 -1
- {conexus-3.2.2 → conexus-3.2.4}/.beads/.gitignore +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.beads/README.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.beads/config.yaml +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.beads/hooks/post-checkout +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.beads/hooks/post-merge +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.beads/hooks/pre-commit +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.beads/hooks/pre-push +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.beads/hooks/prepare-commit-msg +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.beads/interactions.jsonl +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.beads/issues.jsonl +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.beads/metadata.json +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.claude/skills/release.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.devcontainer/Dockerfile +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.devcontainer/devcontainer.json +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.dockerignore +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.env.example +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.gitattributes +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.github/workflows/ci.yml +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.github/workflows/release.yml +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.gitignore +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/.markdownlint.json +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/AGENTS.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/Formula/nx.rb +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/LICENSE +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/README.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/README.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/architecture.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/catalog.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/cli-reference.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/configuration.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/contributing.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/getting-started.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/historical.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/memory-and-tasks.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/postmortem/2026-03-23-pdf-index-collection-mismatch.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/postmortem/2026-03-24-pdf-index-fix-not-applied.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/querying-guide.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/001-rdr-process-validation.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/002-t2-status-synchronization.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/010-t1-http-server.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/011-pdf-ingest-test-coverage.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/012-pdfplumber-extraction-tier.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/014-knowledge-base-retrieval-quality.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/015-indexing-pipeline-rethink.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/016-ast-chunk-line-range-bug.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/017-indexing-progress-reporting.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/018-replace-serve-with-git-hooks.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/023-agent-tool-permissions-audit.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/024-rdr-process-guardrails.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/028-language-registry-unification.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/029-pipeline-versioning.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/049-git-backed-catalog.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/050-catalog-query-integration.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/051-link-lifecycle.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/052-catalog-first-query-routing.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/053-xanadu-fidelity.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/post-mortem/cce-query-model-mismatch.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-001-rdr-process-validation.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-002-t2-status-synchronization.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-004-four-store-architecture.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-005-chromadb-cloud-quota-enforcement.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-007-claude-adoption-session-context-and-search-guidance.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-008-nx-workflow-integration.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-009-remove-agentic-and-answer-flags.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-010-t1-scratch-persistent-bounded-store.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-011-pdf-ingest-test-coverage.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-012-pdfplumber-extraction-tier.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-013-remove-nx-pm-layer.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-014-knowledge-base-retrieval-quality.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-015-indexing-pipeline-rethink.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-016-ast-chunk-line-range-bug.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-017-indexing-progress-reporting.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-018-replace-serve-with-git-hooks.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-019-chromadb-transient-retry.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-020-voyage-chromadb-read-timeout.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-021-docling-pdf-extraction.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-022-memory-delete-command.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-023-agent-tool-permissions-audit.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-024-rdr-process-guardrails.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-025-language-agnostic-agents.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-026-hybrid-search-fusion.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-027-search-results-ux.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-028-code-search-recall.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-029-pipeline-versioning.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-030-reliability-hardening.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-031-collection-portability.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-032-indexer-decomposition.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-033-pdf-agent-nx-index-alignment.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-034-mcp-server-agent-storage.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-035-plugin-agent-mcp-tool-access.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-036-post-accept-planning-workflow.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-037-t3-database-consolidation.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-038-local-t3-backend.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-039-claude-code-framework-alignment.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-040-cce-postmortem-gaps-mcp-enhancement.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-040-developer-agent-circuit-breaker.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-041-t1-scratch-inter-agent-context.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-042-agenticscholar-enhancements.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-043-plan-enricher-scope.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-044-math-aware-pdf-extraction.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-045-post-implementation-verification.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-046-mineru-server-backed-extraction.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-047-large-pdf-extraction-resilience.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-049-consolidation-plan.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-049-git-backed-catalog.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-050-knowledge-graph-query-planning.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-051-link-lifecycle.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-052-catalog-first-query-routing.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr/rdr-053-xanadu-fidelity.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr-nexus-integration.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr-overview.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr-templates.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/rdr-workflow.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/repo-indexing.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/storage-tiers.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/docs/xanadu-in-nexus.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/.mcp.json +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/README.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/_shared/CONTEXT_PROTOCOL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/_shared/ERROR_HANDLING.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/_shared/MAINTENANCE.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/_shared/README.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/_shared/RELAY_TEMPLATE.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/analytical-operator.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/architect-planner.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/code-review-expert.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/codebase-deep-analyzer.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/debugger.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/deep-analyst.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/deep-research-synthesizer.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/developer.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/knowledge-tidier.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/orchestrator.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/pdf-chromadb-processor.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/plan-auditor.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/plan-enricher.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/query-planner.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/strategic-planner.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/substantive-critic.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/agents/test-validator.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/analyze-code.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/architecture.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/create-plan.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/debug.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/deep-analysis.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/enrich-plan.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/implement.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/knowledge-tidy.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/nx-preflight.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/pdf-process.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/plan-audit.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/rdr-accept.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/rdr-close.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/rdr-create.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/rdr-gate.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/rdr-list.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/rdr-research.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/rdr-show.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/research.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/review-code.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/substantive-critique.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/commands/test-validate.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/hooks.json +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/auto-approve-nx-mcp.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/post_compact_hook.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/pre_close_verification_hook.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/rdr_hook.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/read_verification_config.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/session_start_hook.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/stop_failure_hook.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/stop_verification_hook.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/hooks/scripts/t2_prefix_scan.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/registry.yaml +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/resources/rdr/README-TEMPLATE.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/resources/rdr/TEMPLATE.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/resources/rdr/post-mortem/TEMPLATE.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/architecture/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/brainstorming-gate/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/cli-controller/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/code-review/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/codebase-analysis/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/debugging/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/deep-analysis/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/development/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/enrich-plan/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/finishing-branch/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/git-worktrees/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/knowledge-tidying/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/nexus/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/nexus/reference.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/orchestration/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/pdf-processing/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/plan-validation/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/query/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/rdr-accept/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/rdr-close/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/rdr-create/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/rdr-gate/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/rdr-list/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/rdr-research/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/rdr-show/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/receiving-review/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/research-synthesis/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/serena-code-nav/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/strategic-planning/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/substantive-critique/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/test-validation/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/using-nx-skills/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/nx/skills/writing-nx-skills/SKILL.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/scripts/reinstall-tool.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/sn/.mcp.json +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/sn/README.md +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/sn/hooks/hooks.json +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/sn/hooks/scripts/auto-approve-sn-mcp.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/sn/hooks/scripts/mcp-inject.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/sn/hooks/scripts/session-start.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/__init__.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/bib_enricher.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/catalog/__init__.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/catalog/auto_linker.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/catalog/catalog.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/catalog/catalog_db.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/catalog/consolidation.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/catalog/link_generator.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/catalog/tumbler.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/checkpoint.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/chunker.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/classifier.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/cli.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/code_indexer.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/__init__.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/_helpers.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/_provision.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/collection.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/config_cmd.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/doctor.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/enrich.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/hook.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/hooks.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/index.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/memory.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/mineru.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/scratch.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/search_cmd.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/commands/store.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/config.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/corpus.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/db/__init__.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/db/chroma_quotas.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/db/local_ef.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/db/t1.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/db/t2.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/db/t3.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/doc_indexer.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/errors.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/exporter.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/formatters.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/frecency.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/hooks.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/index_context.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/indexer.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/indexer_utils.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/languages.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/pdf_extractor.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/pipeline_buffer.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/pipeline_stages.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/prose_indexer.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/registry.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/retry.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/ripgrep_cache.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/scoring.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/search_engine.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/session.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/ttl.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/src/nexus/types.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/__init__.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/__snapshots__/test_search_snapshot.ambr +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/benchmarks/__init__.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/benchmarks/corpus.json +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/benchmarks/queries.json +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/benchmarks/test_retrieval_ndcg.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/conftest.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/auth-login.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/lib.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/run.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/sandbox.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/scenarios/00_debug_load.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/scenarios/01_smoke.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/scenarios/02_sequential_thinking.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/e2e/scenarios/03_skills.sh +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/__init__.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/test_permission_request_hooks.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/test_post_compact_hook.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/test_pre_close_verification_hook.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/test_read_verification_config.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/test_stop_failure_hook.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/test_stop_verification_hook.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/hooks/test_verification_integration.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_ast_languages.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_auto_linker.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_backfill_hash.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_bib_enricher.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_backfill.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_cli.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_consolidation.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_db.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_e2e.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_git.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_indexer_hook.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_jsonl.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_knowledge_hook.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_link_generation.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_links.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_mcp.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_catalog_pdf_hook.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_checkpoint.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_chroma_quotas.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_chroma_retry.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_chunker.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_chunker_ast_languages.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_classifier.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_collection_cmd.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_config.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_config_cmd.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_corpus.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_doc_indexer.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_doc_indexer_hash_sync.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_doc_indexer_pagination.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_doctor_cmd.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_doctor_integrity.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_e2e.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_enrich_command.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_exporter.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_formatters.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_frecency.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_git_hooks.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_hooks.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_hybrid_boost.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_index_cmd.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_index_lock.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_index_pdf_batch.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_index_rdr_cmd.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_index_reminder.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_indexer.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_indexer_chunk_flow.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_indexer_e2e.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_indexer_modules.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_integration.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_jsonl.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_languages.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_local_mode.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_mcp_concurrency.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_mcp_integration.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_mcp_server.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_mcp_session.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_md_chunker_semantic_integrity.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_md_preservation.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_memory.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_mineru_cmd.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_mineru_extractor.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_minified_chunking.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_p0_regressions.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_chunker_integration.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_e2e.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_extractor.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_extractor_integration.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_extractor_normalization.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_extractor_server.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_normalization.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_pdf_subsystem.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_pipeline_buffer.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_pipeline_stages.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_pipeline_version.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_plan_library.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_plugin.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_plugin_install.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_plugin_structure.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_ppid_chain_hypothesis.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_provision.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_rdr052_verification.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_rdr053_verification.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_registry.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_ripgrep_cache.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_schema.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_scoring.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_scratch.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_scratch_cmd.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_search_cmd.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_search_engine.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_search_modules.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_search_snapshot.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_session.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_session_propagation_hypotheses.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_silent_error_logging.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_sn_plugin.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_store_cmd.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_t1.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_t2.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_t2_prefix_scan.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_t3.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_t3_quota_enforcement.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_table_extraction.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_ttl.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_tumbler.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_tuning_config.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_types_and_errors.py +0 -0
- {conexus-3.2.2 → conexus-3.2.4}/tests/test_voyage_retry.py +0 -0
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
"name": "nx",
|
|
10
10
|
"source": "./nx",
|
|
11
11
|
"description": "Self-hosted three-tier knowledge management with 17 specialized agents, analytical query pipelines, semantic search, and RDR decision tracking for Claude Code.",
|
|
12
|
-
"version": "3.2.
|
|
12
|
+
"version": "3.2.4"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"name": "sn",
|
|
16
16
|
"source": "./sn",
|
|
17
17
|
"description": "Injects Serena and Context7 MCP tool usage guidance into subagents via SubagentStart hook.",
|
|
18
|
-
"version": "3.2.
|
|
18
|
+
"version": "3.2.4"
|
|
19
19
|
}
|
|
20
20
|
]
|
|
21
21
|
}
|
|
@@ -6,6 +6,16 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [3.2.4] - 2026-04-07
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- **Chunk boundary overlap** (RDR-054) — wired dead `overlap_chars` into `SemanticMarkdownChunker._split_large_section`, which previously had zero overlap between sub-chunks. Bumped `PDFChunker` default overlap from 15% to 20% (225 → 300 chars). Fixed header duplication bug when overlap exceeds emitted content length. Guarded Python `[-0:]` edge case.
|
|
13
|
+
|
|
14
|
+
## [3.2.3] - 2026-04-07
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- **Pagination completeness** — all list-returning MCP tools and CLI commands now include pagination footers when results are truncated. Tools fixed: `query`, `scratch` (search/list), `plan_search`, `catalog_search`, `catalog_list`, `catalog_link_query`. CLI commands fixed: `nx catalog list`, `nx catalog search`, `nx catalog links`. Docstrings updated to document pagination behavior.
|
|
18
|
+
|
|
9
19
|
## [3.2.2] - 2026-04-07
|
|
10
20
|
|
|
11
21
|
### Fixed
|
|
@@ -62,15 +62,15 @@ Nexus is a Python 3.12+ CLI + persistent server for semantic search and knowledg
|
|
|
62
62
|
|
|
63
63
|
**Catalog (T3 metadata layer)**: Git-backed document registry that tracks *what* is indexed and *how documents relate*. JSONL files are the source of truth; SQLite + FTS5 is the query cache (rebuilt automatically on mtime change). Tumblers (hierarchical addresses like `1.2.5`) identify documents. Every indexing pathway (`index repo`, `index pdf`, `index rdr`, MCP `store_put`) auto-registers entries. `nx catalog setup` creates and populates the catalog in one step.
|
|
64
64
|
|
|
65
|
-
**Link graph**: Typed edges between documents
|
|
66
|
-
- `cites` — citation (auto from `nx enrich` via Semantic Scholar, or by research agents)
|
|
67
|
-
- `implements-heuristic` — code→RDR (auto from indexer, title substring match)
|
|
68
|
-
- `supersedes` — replacement (by rdr-close, knowledge-tidier)
|
|
69
|
-
- `relates` — related findings (by debugger, deep-analyst, codebase-analyzer, architect-planner)
|
|
70
|
-
- `implements` — manual or by developer agent linking insights to RDRs
|
|
71
|
-
- `created_by` tracks provenance: which agent or user created each link
|
|
65
|
+
**Link graph**: Typed edges between documents (`cites`, `implements`, `implements-heuristic`, `supersedes`, `relates`, or custom). `created_by` tracks provenance. Three creation paths:
|
|
72
66
|
|
|
73
|
-
**
|
|
67
|
+
1. **Post-hoc** (batch, after indexing): `generate_citation_links()`, `generate_code_rdr_links()`, `generate_rdr_filepath_links()` in `link_generator.py`
|
|
68
|
+
2. **Auto-linker** (`auto_linker.py`): fires on every `store_put` MCP call, reads `link-context` from T1 scratch (tag: `link-context`), creates links to seeded targets. Skills seed before dispatch; agents self-seed from their task prompt when no context exists.
|
|
69
|
+
3. **Agent-direct**: agents call `catalog_link` MCP tool during work for precise typed links
|
|
70
|
+
|
|
71
|
+
**Two graph views**: `catalog_links` returns live-document links only. `catalog_link_query` returns all including orphans. The `query` MCP tool has catalog-aware routing (`author`, `content_type`, `subtree`, `follow_links`, `depth`) for scoped search.
|
|
72
|
+
|
|
73
|
+
**Pagination**: All list-returning tools include footers when truncated — `offset=N` for next page.
|
|
74
74
|
|
|
75
75
|
**T3 expire guard**: always filter `ttl_days > 0 AND expires_at != "" AND expires_at < now` — the `expires_at != ""` guard is mandatory: permanent entries use `expires_at=""` which sorts before ISO timestamps and would be incorrectly deleted by a 2-condition guard.
|
|
76
76
|
|
|
@@ -84,7 +84,8 @@ src/nexus/ # Core package
|
|
|
84
84
|
catalog.py # Core: link(), link_query(), graph(), delete_document(), link_audit(), descendants(), resolve_chunk()
|
|
85
85
|
catalog_db.py # SQLite schema + FTS5 + UNIQUE link constraint + descendants() SQL helper
|
|
86
86
|
tumbler.py # Hierarchical addresses (depth, ancestors, lca) + JSONL readers with resilience
|
|
87
|
-
|
|
87
|
+
auto_linker.py # Storage-boundary auto-linking from T1 scratch link-context
|
|
88
|
+
link_generator.py # Post-hoc batch linkers: citation, code-RDR heuristic, RDR file-path
|
|
88
89
|
db/ # t1.py, t2.py, t3.py — tier implementations; local_ef.py — local ONNX embeddings
|
|
89
90
|
indexer.py # Repo indexing pipeline (classify → chunk → embed → store)
|
|
90
91
|
classifier.py # File classification: CODE / PROSE / PDF / SKIP
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: conexus
|
|
3
|
-
Version: 3.2.
|
|
3
|
+
Version: 3.2.4
|
|
4
4
|
Summary: Self-hosted semantic search and knowledge management for LLM-driven development
|
|
5
5
|
Project-URL: Homepage, https://github.com/Hellblazer/nexus
|
|
6
6
|
Project-URL: Repository, https://github.com/Hellblazer/nexus
|
|
@@ -75,6 +75,7 @@ An RDR (Research-Design-Review) is a short document that records a technical dec
|
|
|
75
75
|
| [RDR-051](rdr-051-link-lifecycle.md) | Link Lifecycle: Full CRUD, Queryable Links, Bulk Operations | Architecture | Closed | 2026-04-05 |
|
|
76
76
|
| [RDR-052](rdr-052-catalog-first-query-routing.md) | Catalog-First Query Routing — Push Planning into MCP | Architecture | Closed | 2026-04-05 |
|
|
77
77
|
| [RDR-053](rdr-053-xanadu-fidelity.md) | Xanadu Fidelity — Tumbler Arithmetic and Content-Addressed Spans | Architecture | Closed | 2026-04-05 |
|
|
78
|
+
| [RDR-054](rdr-054-chunk-boundary-equation-splitting.md) | Chunk Boundary Equation Splitting — Information Loss at Chunk Boundaries | Bug | Closed | 2026-04-07 |
|
|
78
79
|
|
|
79
80
|
---
|
|
80
81
|
|
|
@@ -239,7 +239,7 @@ nx index repo PATH
|
|
|
239
239
|
```
|
|
240
240
|
|
|
241
241
|
Markdown prose uses `SemanticMarkdownChunker(chunk_size=512, chunk_overlap=50)` (tokens).
|
|
242
|
-
PDFs use `PDFChunker(chunk_chars=1500, overlap_percent=0.
|
|
242
|
+
PDFs use `PDFChunker(chunk_chars=1500, overlap_percent=0.20)`.
|
|
243
243
|
Both are out of scope — this RDR addresses code files only.
|
|
244
244
|
|
|
245
245
|
### R3: Scope of change (Confirmed)
|
|
@@ -311,7 +311,7 @@ Three concurrent threads need coordinated shutdown when any stage fails. Standar
|
|
|
311
311
|
**Current pipeline memory for 771-page CMRB book**:
|
|
312
312
|
- Extraction: `md_parts` list — 771 page strings, ~2-5 MB total
|
|
313
313
|
- `"\n".join(md_parts)` — creates a second copy, ~2-5 MB
|
|
314
|
-
- `PDFChunker.chunk()` — returns ~2000 `TextChunk` objects, each holding a copy of its text. Total: ~3-5 MB (overlapping chunks mean ~
|
|
314
|
+
- `PDFChunker.chunk()` — returns ~2000 `TextChunk` objects, each holding a copy of its text. Total: ~3-5 MB (overlapping chunks mean ~20% extra text)
|
|
315
315
|
- `_embed_with_fallback` — embedding vectors: 2000 × 1024 floats × 4 bytes = ~8 MB
|
|
316
316
|
- `_index_document` / `_index_pdf_incremental` — IDs, documents, metadatas lists: ~5-10 MB
|
|
317
317
|
- **Peak concurrent**: ~20-30 MB for the 771-page book (extraction + chunks + embeddings all in memory simultaneously before the first upsert)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Chunk Boundary Equation Splitting — Information Loss at Chunk Boundaries"
|
|
3
|
+
id: RDR-054
|
|
4
|
+
type: Bug
|
|
5
|
+
status: closed
|
|
6
|
+
close_reason: implemented
|
|
7
|
+
closed_date: 2026-04-07
|
|
8
|
+
priority: high
|
|
9
|
+
author: Hal Hildebrand
|
|
10
|
+
reviewed-by: self
|
|
11
|
+
created: 2026-04-07
|
|
12
|
+
accepted_date: 2026-04-07
|
|
13
|
+
related_issues: []
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# RDR-054: Chunk Boundary Equation Splitting — Information Loss at Chunk Boundaries
|
|
17
|
+
|
|
18
|
+
> Revise during planning; lock at implementation.
|
|
19
|
+
> If wrong, abandon code and iterate RDR.
|
|
20
|
+
|
|
21
|
+
## Problem Statement
|
|
22
|
+
|
|
23
|
+
When indexing PDF papers with mathematical equations, the chunker splits equation definitions across chunk boundaries such that:
|
|
24
|
+
- Chunk N ends with the prose leading to the definition (e.g., "The sigmoid excitatory feedback signal: f_u(u_ij) =")
|
|
25
|
+
- Chunk N+1 starts with the formula body, WITHOUT the variable name from Chunk N
|
|
26
|
+
|
|
27
|
+
This makes the formula **unsearchable by its variable name**. Searching for "f_u" finds Chunk N (truncated before the formula). Searching for the formula content finds Chunk N+1 but without context about what function it defines.
|
|
28
|
+
|
|
29
|
+
### Reproduction
|
|
30
|
+
|
|
31
|
+
- Paper: GnaGroSovereign2007.pdf (109 pages, 537 chunks, MinerU extractor)
|
|
32
|
+
- Section: Appendix A4.5, Eq.56 (page 88)
|
|
33
|
+
- Search: "sigmoid excitatory feedback signal f_u" → returns chunk ending before the formula
|
|
34
|
+
- Re-indexing with `--extractor mineru --force` produces identical truncation
|
|
35
|
+
|
|
36
|
+
The actual equation (from direct PDF read):
|
|
37
|
+
```
|
|
38
|
+
f_u(u_ij) = α^N · ([u_ij]⁺)^N / (α^N + θ · ([u_ij]⁺)^N)
|
|
39
|
+
where α=1.7, N=5, θ=9.8
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Impact
|
|
43
|
+
|
|
44
|
+
- HIGH for mathematical/scientific papers where equation definitions are primary content
|
|
45
|
+
- The f_u function was a Hill sigmoid, NOT the ([u]⁺)² inferred from analogy. The inference was wrong — 3 independent lines of analogical evidence all pointed to the wrong answer because the actual definition was trapped in a chunk boundary.
|
|
46
|
+
- Multiple parameter values (D₁=18 vs assumed 1.0, S_j={1/6,1/3,1/2} vs assumed {1.0,0.75,0.5}) were also in this truncated region.
|
|
47
|
+
- 17 parallel agents across 4 rounds of deep research (851+ chunk searches) all failed to find this equation via T3 search. Only resolved by reading the PDF directly with the Read tool at the page number.
|
|
48
|
+
|
|
49
|
+
## Proposed Mitigations
|
|
50
|
+
|
|
51
|
+
### M1: Chunk overlap (recommended, general-purpose)
|
|
52
|
+
|
|
53
|
+
**Priority 1 (CRITICAL):** Wire SemanticMarkdownChunker's dead `overlap_chars` (165 chars) into `_split_large_section` which currently has zero overlap. Affects: `md_chunker.py` lines 288–309. Cost: +5-8% corpus-level (only split sections pay).
|
|
54
|
+
|
|
55
|
+
**Priority 2 (HIGH):** Increase PDFChunker overlap from 225→300 chars (15%→20%). Affects: `pdf_chunker.py` line 12 (`_DEFAULT_OVERLAP`). Cost: +6.3% chunks (<$0.001/paper embedding).
|
|
56
|
+
|
|
57
|
+
**Migration cost:** Existing indexed documents retain old chunk boundaries until re-indexed. Full corpus re-indexing (`nx index pdf --force` per paper) required to benefit from the fix. For large corpora, estimate total embedding cost as documents × avg_chunks × embedding_price_per_token before running.
|
|
58
|
+
|
|
59
|
+
300 chars covers all tested equation types including worst case (Long Boltzmann at 202 chars) for the overlap window. However, overlap only ensures the *leading context* is repeated — it does not prevent mid-equation splits for equations longer than the overlap window.
|
|
60
|
+
|
|
61
|
+
### M2: Equation-aware chunking
|
|
62
|
+
|
|
63
|
+
Detect LaTeX equation environments (`\begin{equation}...\end{equation}`, `$$...$$`, `\tag{N}`) and ensure they are never split across chunks.
|
|
64
|
+
|
|
65
|
+
Affects: `pdf_chunker.py` primarily (LaTeX in extracted text).
|
|
66
|
+
|
|
67
|
+
Trade-off: requires equation boundary detection in extracted text, which varies by extractor. **Not yet verified:** whether MinerU output for GnaGroSovereign2007.pdf actually contains `$$`, `\begin{equation}`, or `\tag{N}` markers. If MinerU renders equations as plain text/Unicode, M2's LaTeX boundary detection has zero coverage. Needs an RF verifying the actual extraction format before implementing.
|
|
68
|
+
|
|
69
|
+
### M3: Paragraph-boundary chunking
|
|
70
|
+
|
|
71
|
+
Split only at paragraph boundaries (double newline), never mid-paragraph. The f_u definition was mid-paragraph — M3 addresses this failure mode by construction.
|
|
72
|
+
|
|
73
|
+
Affects: `pdf_chunker.py` (sentence snapper could prefer `\n\n` over `. `), `md_chunker.py`.
|
|
74
|
+
|
|
75
|
+
Trade-off: may produce very large chunks for papers with long prose paragraphs. Needs a max-size fallback. However, scientific appendix equations are typically in short display-math paragraphs — paragraph length distribution in the reproduction document (GnaGroSovereign2007.pdf) should be measured to validate this concern. If equation-bearing paragraphs are short, M3 + max-size fallback may be simpler and more correct than overlap alone.
|
|
76
|
+
|
|
77
|
+
### M4: Post-extraction equation linking
|
|
78
|
+
|
|
79
|
+
After chunking, scan for equation references (e.g., "Eq.56", "\tag{56}") and create cross-references between chunks that reference the same equation. Could use catalog links with `relates` type.
|
|
80
|
+
|
|
81
|
+
Affects: new module or extension to `link_generator.py`.
|
|
82
|
+
|
|
83
|
+
Trade-off: doesn't fix searchability — the equation is still split. But makes it discoverable via link traversal.
|
|
84
|
+
|
|
85
|
+
## Recommendation
|
|
86
|
+
|
|
87
|
+
Start with M1 (chunk overlap) — md_chunker first (CRITICAL: currently zero overlap), then PDFChunker bump to 20%. M1 reduces the probability of context loss at boundaries but does not prevent mid-equation splits for equations longer than ~300 chars. M2 (equation-aware snapper) remains necessary for the elimination case.
|
|
88
|
+
|
|
89
|
+
M3 (paragraph boundaries) deserves evaluation alongside M1 for PDFChunker — it directly addresses the observed failure mode (mid-paragraph split). M4 is independent and complementary.
|
|
90
|
+
|
|
91
|
+
## Key Discoveries
|
|
92
|
+
|
|
93
|
+
### RF-1: Chunker boundary overlap audit (verified, source search)
|
|
94
|
+
|
|
95
|
+
Three distinct overlap gaps identified:
|
|
96
|
+
|
|
97
|
+
1. **PDFChunker** (`pdf_chunker.py`): Has 225-char overlap (15% of 1500), but boundary snapper at lines 59–63 only looks for `. ` (period-space) — no awareness of LaTeX `$$...$$` or equation environments. Will split mid-equation if the equation doesn't end with a sentence period.
|
|
98
|
+
|
|
99
|
+
2. **SemanticMarkdownChunker** (`md_chunker.py`): `_split_large_section()` at lines 261–323 has **zero overlap** between sub-chunks. The `chunk_overlap` / `overlap_chars` fields are defined but never used by the semantic path — dead code. Only the naive fallback path has overlap (165 chars). This is the most significant gap.
|
|
100
|
+
|
|
101
|
+
3. **`_enforce_byte_cap`** (`chunker.py:163–211`): Sub-splits of oversized AST nodes also have zero overlap between sub-chunks. Lower priority since code chunking uses AST boundaries.
|
|
102
|
+
|
|
103
|
+
**Insertion points for fix:**
|
|
104
|
+
- `md_chunker.py:288–309`: Before `chunks.append(...)` at line 288, capture `emitted_text = "\n\n".join(current_parts)`. After the flush, prepend `emitted_text[-overlap_chars:]` to the new `current_parts` (after the header, so section context is preserved). The naive fallback path at lines 354–376 is a working reference implementation — same overlap structure, already tested.
|
|
105
|
+
- `pdf_chunker.py:59–63`: Extend snapper to check for unclosed `$$` in candidate window
|
|
106
|
+
|
|
107
|
+
### RF-2: Prior art — RAG chunking overlap and equation-aware splitting (verified, source search)
|
|
108
|
+
|
|
109
|
+
No mainstream chunking library has equation/math-aware splitting (verified across LlamaIndex, LangChain, Unstructured, Chonkie, semchunk). Default overlaps: LlamaIndex SentenceSplitter ~19.5%, LangChain 200 chars (5%), Unstructured 0. Literature consensus: 10-20% optimal (NVIDIA FinanceBench). Nexus PDFChunker at 15% is already in range — the bug is the sentence snapper and the dead md_chunker overlap code. Equation-boundary snapping would be novel.
|
|
110
|
+
|
|
111
|
+
### RF-3: Storage cost analysis — overlap overhead measured empirically (verified, spike)
|
|
112
|
+
|
|
113
|
+
PDFChunker 225→300 chars: +6.3% chunks, <$0.001/paper. 450 chars (doubled): +21.7% — excessive. md_chunker wiring 165ch overlap: +5-8% corpus-level. 200 chars is NOT enough for multi-line equations (Long Boltzmann at 202ch). 300 chars covers all tested types with margin. md_chunker overlap is CRITICAL priority (currently zero).
|
|
114
|
+
|
|
115
|
+
## Finalization Gate
|
|
116
|
+
|
|
117
|
+
- [x] Overlap size determined: 300 chars PDFChunker, 165 chars md_chunker (RF-3)
|
|
118
|
+
- [x] Storage overhead measured: +6.3% PDF, +5-8% md corpus-level (RF-3)
|
|
119
|
+
- [ ] Impact validated against real-world corpus (post-implementation)
|
|
120
|
+
- [ ] No regression in existing chunker tests (post-implementation)
|
|
121
|
+
- [ ] Search recall improvement measured for boundary-split cases (post-implementation)
|
|
122
|
+
- [ ] MinerU extraction format verified for equation markers (RF needed for M2)
|
|
123
|
+
|
|
124
|
+
## Revision History
|
|
125
|
+
|
|
126
|
+
- 2026-04-07: Gate PASSED. 2 criticals resolved in-gate (insertion point corrected, overlap limitation acknowledged), 3 significants addressed (migration cost, M3 evaluation, M2 feasibility).
|
|
127
|
+
- 2026-04-07: RF-1 (code audit), RF-2 (prior art), RF-3 (cost analysis) — all verified.
|
|
128
|
+
- 2026-04-07: Created from T2 issue report (nexus_issues/chunker-splits-equations-at-boundary). Source: RDR-068 research session where 17 parallel agents failed to find f_u equation definition.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nx",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.3",
|
|
4
4
|
"description": "Self-hosted three-tier knowledge management with specialized agents, analytical query pipelines, semantic search, and RDR decision tracking for Claude Code.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Hal Hildebrand",
|
|
@@ -6,6 +6,14 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [3.2.4] - 2026-04-07
|
|
10
|
+
|
|
11
|
+
Plugin version aligned with Nexus CLI 3.2.4. No plugin-level functional changes.
|
|
12
|
+
|
|
13
|
+
## [3.2.3] - 2026-04-07
|
|
14
|
+
|
|
15
|
+
Plugin version aligned with Nexus CLI 3.2.3. No plugin-level functional changes.
|
|
16
|
+
|
|
9
17
|
## [3.2.2] - 2026-04-07
|
|
10
18
|
|
|
11
19
|
### Fixed
|
|
@@ -109,6 +109,9 @@ T3 knowledge — permanent, semantic search:
|
|
|
109
109
|
store_get(doc_id="...", collection="knowledge")
|
|
110
110
|
Tool: mcp__plugin_nx_nexus__store_put
|
|
111
111
|
store_put(content="...", collection="knowledge", title="...", tags="...")
|
|
112
|
+
AUTO-LINKING: store_put checks T1 scratch for link-context (tag: "link-context") and auto-creates catalog links.
|
|
113
|
+
If no link-context in scratch, self-seed: catalog_search your task references → scratch put with targets.
|
|
114
|
+
You MUST call store_put before returning — findings not stored are findings lost.
|
|
112
115
|
Tool: mcp__plugin_nx_nexus__store_delete
|
|
113
116
|
store_delete(doc_id="...", collection="knowledge")
|
|
114
117
|
Tool: mcp__plugin_nx_nexus__collection_list
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "conexus"
|
|
7
|
-
version = "3.2.
|
|
7
|
+
version = "3.2.4"
|
|
8
8
|
description = "Self-hosted semantic search and knowledge management for LLM-driven development"
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
requires-python = ">=3.12,<3.14"
|
|
@@ -300,23 +300,27 @@ def setup_cmd(remote: str) -> None:
|
|
|
300
300
|
@click.option("--owner", default="")
|
|
301
301
|
@click.option("--type", "content_type", default="")
|
|
302
302
|
@click.option("--limit", "-n", default=50)
|
|
303
|
+
@click.option("--offset", default=0)
|
|
303
304
|
@click.option("--json", "as_json", is_flag=True)
|
|
304
|
-
def list_cmd(owner: str, content_type: str, limit: int, as_json: bool) -> None:
|
|
305
|
+
def list_cmd(owner: str, content_type: str, limit: int, offset: int, as_json: bool) -> None:
|
|
305
306
|
"""List catalog entries."""
|
|
306
307
|
cat = _get_catalog()
|
|
307
308
|
if owner:
|
|
308
309
|
entries = cat.by_owner(Tumbler.parse(owner))
|
|
309
310
|
else:
|
|
310
|
-
entries = cat.all_documents(limit=limit)
|
|
311
|
+
entries = cat.all_documents(limit=limit + offset + 1)
|
|
311
312
|
if content_type:
|
|
312
313
|
entries = [e for e in entries if e.content_type == content_type]
|
|
313
|
-
|
|
314
|
+
total = len(entries)
|
|
315
|
+
entries = entries[offset:offset + limit]
|
|
314
316
|
|
|
315
317
|
if as_json:
|
|
316
318
|
click.echo(json.dumps([_entry_to_dict(e) for e in entries], indent=2))
|
|
317
319
|
else:
|
|
318
320
|
for e in entries:
|
|
319
321
|
click.echo(f"{str(e.tumbler):<12} {e.content_type:<10} {e.title}")
|
|
322
|
+
if offset + limit < total:
|
|
323
|
+
click.echo(f"\n Next page: --offset {offset + limit}")
|
|
320
324
|
|
|
321
325
|
|
|
322
326
|
@catalog.command("show")
|
|
@@ -378,15 +382,18 @@ def show_cmd(tumbler_or_title: str, as_json: bool) -> None:
|
|
|
378
382
|
@catalog.command("search")
|
|
379
383
|
@click.argument("query")
|
|
380
384
|
@click.option("--limit", "-n", default=20)
|
|
385
|
+
@click.option("--offset", default=0)
|
|
381
386
|
@click.option("--json", "as_json", is_flag=True)
|
|
382
|
-
def search_cmd(query: str, limit: int, as_json: bool) -> None:
|
|
387
|
+
def search_cmd(query: str, limit: int, offset: int, as_json: bool) -> None:
|
|
383
388
|
"""Find documents by title, author, corpus, or file path.
|
|
384
389
|
|
|
385
390
|
Uses full-text search across document metadata. Faster than T3 semantic
|
|
386
391
|
search for exact metadata lookups. Returns tumbler, type, and title.
|
|
387
392
|
"""
|
|
388
393
|
cat = _get_catalog()
|
|
389
|
-
|
|
394
|
+
all_results = cat.find(query)
|
|
395
|
+
total = len(all_results)
|
|
396
|
+
results = all_results[offset:offset + limit]
|
|
390
397
|
if as_json:
|
|
391
398
|
click.echo(json.dumps([_entry_to_dict(e) for e in results], indent=2))
|
|
392
399
|
else:
|
|
@@ -395,6 +402,8 @@ def search_cmd(query: str, limit: int, as_json: bool) -> None:
|
|
|
395
402
|
return
|
|
396
403
|
for e in results:
|
|
397
404
|
click.echo(f"{str(e.tumbler):<12} {e.content_type:<10} {e.title}")
|
|
405
|
+
if offset + limit < total:
|
|
406
|
+
click.echo(f"\n Next page: --offset {offset + limit}")
|
|
398
407
|
|
|
399
408
|
|
|
400
409
|
@catalog.command("register", hidden=True)
|
|
@@ -599,8 +608,10 @@ def links_cmd(
|
|
|
599
608
|
links = cat.link_query(
|
|
600
609
|
from_t=resolved_from, to_t=resolved_to,
|
|
601
610
|
link_type=link_type, created_by=created_by,
|
|
602
|
-
limit=limit, offset=offset,
|
|
611
|
+
limit=limit + 1, offset=offset,
|
|
603
612
|
)
|
|
613
|
+
has_more = len(links) > limit
|
|
614
|
+
links = links[:limit]
|
|
604
615
|
if as_json:
|
|
605
616
|
click.echo(json.dumps([_link_to_dict(lnk) for lnk in links], indent=2))
|
|
606
617
|
else:
|
|
@@ -609,6 +620,8 @@ def links_cmd(
|
|
|
609
620
|
return
|
|
610
621
|
for edge in links:
|
|
611
622
|
click.echo(f"{edge.from_tumbler} → {edge.to_tumbler} ({edge.link_type}) by {edge.created_by}")
|
|
623
|
+
if has_more:
|
|
624
|
+
click.echo(f"\n Next page: --offset {offset + limit}")
|
|
612
625
|
|
|
613
626
|
|
|
614
627
|
@catalog.command("link-bulk-delete", hidden=True)
|
|
@@ -391,6 +391,9 @@ def query(
|
|
|
391
391
|
) -> str:
|
|
392
392
|
"""Document-level semantic search for analytical questions.
|
|
393
393
|
|
|
394
|
+
Results are capped at ``limit``. When more documents match, a footer line shows
|
|
395
|
+
the total count. Increase ``limit`` to see more.
|
|
396
|
+
|
|
394
397
|
Unlike ``search`` which returns individual chunks, ``query`` groups results
|
|
395
398
|
by source document and returns the best-matching snippet per document along
|
|
396
399
|
with full metadata (title, year, citations, page count, extraction method).
|
|
@@ -558,7 +561,9 @@ def query(
|
|
|
558
561
|
docs[doc_key]["snippet"] = r.content[:300].replace("\n", " ")
|
|
559
562
|
|
|
560
563
|
# Sort by best match distance, limit
|
|
561
|
-
|
|
564
|
+
all_docs = sorted(docs.values(), key=lambda d: d["distance"])
|
|
565
|
+
sorted_docs = all_docs[:limit]
|
|
566
|
+
total = len(all_docs)
|
|
562
567
|
|
|
563
568
|
header = f"Found {len(sorted_docs)} documents (from {len(results)} chunks across {len(target)} collections)"
|
|
564
569
|
lines: list[str] = [f"{routing_note}\n{header}" if routing_note else header]
|
|
@@ -598,6 +603,9 @@ def query(
|
|
|
598
603
|
lines.append(f" {d['snippet']}")
|
|
599
604
|
lines.append("")
|
|
600
605
|
|
|
606
|
+
if total > limit:
|
|
607
|
+
lines.append(f"\n--- showing 1-{len(sorted_docs)} of {total} documents. Results are capped at limit={limit}.")
|
|
608
|
+
|
|
601
609
|
return "\n".join(lines)
|
|
602
610
|
except Exception as e:
|
|
603
611
|
return f"Error: {e}"
|
|
@@ -936,6 +944,9 @@ def scratch(
|
|
|
936
944
|
) -> str:
|
|
937
945
|
"""T1 session scratch pad — ephemeral within-session storage.
|
|
938
946
|
|
|
947
|
+
For ``search`` and ``list``, results are capped at ``limit``. A footer
|
|
948
|
+
indicates when more entries exist.
|
|
949
|
+
|
|
939
950
|
Args:
|
|
940
951
|
action: One of "put", "search", "list", "get", "delete"
|
|
941
952
|
content: Content to store (for "put")
|
|
@@ -964,17 +975,23 @@ def scratch(
|
|
|
964
975
|
for r in results:
|
|
965
976
|
snippet = r["content"][:200].replace("\n", " ")
|
|
966
977
|
lines.append(f"{prefix}[{r['id'][:12]}] {snippet}")
|
|
978
|
+
if len(results) >= limit:
|
|
979
|
+
lines.append(f"\n--- showing {len(results)} results (limit={limit}). Increase limit to see more.")
|
|
967
980
|
return "\n".join(lines)
|
|
968
981
|
|
|
969
982
|
elif action == "list":
|
|
970
983
|
entries = t1.list_entries()
|
|
971
984
|
if not entries:
|
|
972
985
|
return f"{prefix}No scratch entries."
|
|
986
|
+
total = len(entries)
|
|
987
|
+
entries = entries[:limit]
|
|
973
988
|
lines = []
|
|
974
989
|
for e in entries:
|
|
975
990
|
snippet = e["content"][:80].replace("\n", " ")
|
|
976
991
|
tags_str = f" [{e.get('tags', '')}]" if e.get("tags") else ""
|
|
977
992
|
lines.append(f"{prefix}[{e['id'][:12]}] {snippet}{tags_str}")
|
|
993
|
+
if total > limit:
|
|
994
|
+
lines.append(f"\n--- showing {limit} of {total} entries. Increase limit to see all.")
|
|
978
995
|
return "\n".join(lines)
|
|
979
996
|
|
|
980
997
|
elif action == "get":
|
|
@@ -1159,17 +1176,25 @@ def plan_save(
|
|
|
1159
1176
|
|
|
1160
1177
|
|
|
1161
1178
|
@mcp.tool()
|
|
1162
|
-
def plan_search(query: str, project: str = "", limit: int = 5) -> str:
|
|
1179
|
+
def plan_search(query: str, project: str = "", limit: int = 5, offset: int = 0) -> str:
|
|
1163
1180
|
"""Search the T2 plan library for similar query plans.
|
|
1164
1181
|
|
|
1182
|
+
Results are paged. Response footer shows ``offset=N`` for next page.
|
|
1183
|
+
|
|
1165
1184
|
Args:
|
|
1166
1185
|
query: Search query (matched against plan query text and tags)
|
|
1167
1186
|
project: Optional project filter (e.g. "nexus")
|
|
1168
|
-
limit: Maximum results to return
|
|
1187
|
+
limit: Maximum results to return (default 5)
|
|
1188
|
+
offset: Skip this many results (default 0). Use for pagination.
|
|
1169
1189
|
"""
|
|
1170
1190
|
try:
|
|
1171
1191
|
with _t2_ctx() as db:
|
|
1172
|
-
|
|
1192
|
+
# Over-fetch by 1 to detect if there are more
|
|
1193
|
+
results = db.search_plans(query, limit=limit + 1, project=project)
|
|
1194
|
+
if offset:
|
|
1195
|
+
results = results[offset:]
|
|
1196
|
+
has_more = len(results) > limit
|
|
1197
|
+
results = results[:limit]
|
|
1173
1198
|
if not results:
|
|
1174
1199
|
return "No matching plans."
|
|
1175
1200
|
lines: list[str] = []
|
|
@@ -1180,6 +1205,9 @@ def plan_search(query: str, project: str = "", limit: int = 5) -> str:
|
|
|
1180
1205
|
f" outcome={r['outcome']} tags={r['tags']}\n"
|
|
1181
1206
|
f" plan: {plan_preview}..."
|
|
1182
1207
|
)
|
|
1208
|
+
shown_end = offset + len(results)
|
|
1209
|
+
if has_more:
|
|
1210
|
+
lines.append(f"\n--- showing {offset + 1}-{shown_end}. may have more: offset={shown_end}")
|
|
1183
1211
|
return "\n\n".join(lines)
|
|
1184
1212
|
except Exception as e:
|
|
1185
1213
|
return f"Error: {e}"
|
|
@@ -1205,11 +1233,15 @@ def catalog_search(
|
|
|
1205
1233
|
owner: str = "",
|
|
1206
1234
|
file_path: str = "",
|
|
1207
1235
|
limit: int = 20,
|
|
1236
|
+
offset: int = 0,
|
|
1208
1237
|
) -> list[dict]:
|
|
1209
1238
|
"""Find documents by metadata (title, author, corpus, file path).
|
|
1210
1239
|
|
|
1240
|
+
Results are paged. When results are truncated, a ``_pagination`` entry appears
|
|
1241
|
+
at the end with ``next_offset``. Pass that value as ``offset`` to get the next page.
|
|
1242
|
+
|
|
1211
1243
|
Returns catalog entries with tumbler, physical_collection, and metadata — NOT document
|
|
1212
|
-
content. Use the
|
|
1244
|
+
content. Use the ``search`` tool for semantic content search within collections.
|
|
1213
1245
|
Use catalog_search first to discover WHICH collections to search, then search for content.
|
|
1214
1246
|
|
|
1215
1247
|
Filters: query (free-text), author, corpus, owner, file_path, content_type (exact match).
|
|
@@ -1246,9 +1278,9 @@ def catalog_search(
|
|
|
1246
1278
|
sql = (
|
|
1247
1279
|
"SELECT tumbler, title, author, year, content_type, file_path, "
|
|
1248
1280
|
"corpus, physical_collection, chunk_count, head_hash, indexed_at, metadata "
|
|
1249
|
-
f"FROM documents WHERE {' AND '.join(conditions)} LIMIT ?"
|
|
1281
|
+
f"FROM documents WHERE {' AND '.join(conditions)} LIMIT ? OFFSET ?"
|
|
1250
1282
|
)
|
|
1251
|
-
params.
|
|
1283
|
+
params.extend([limit + 1, offset])
|
|
1252
1284
|
rows = cat._db.execute(sql, params).fetchall()
|
|
1253
1285
|
from nexus.catalog.catalog import CatalogEntry
|
|
1254
1286
|
entries = [
|
|
@@ -1260,7 +1292,12 @@ def catalog_search(
|
|
|
1260
1292
|
)
|
|
1261
1293
|
for r in rows
|
|
1262
1294
|
]
|
|
1263
|
-
|
|
1295
|
+
has_more = len(entries) > limit
|
|
1296
|
+
entries = entries[:limit]
|
|
1297
|
+
result = [_entry_to_dict(e) for e in entries]
|
|
1298
|
+
if has_more:
|
|
1299
|
+
result.append({"_pagination": {"next_offset": offset + limit, "limit": limit}})
|
|
1300
|
+
return result
|
|
1264
1301
|
|
|
1265
1302
|
# FTS5 free-text search (append author to query if both provided)
|
|
1266
1303
|
fts_query = query
|
|
@@ -1268,8 +1305,12 @@ def catalog_search(
|
|
|
1268
1305
|
fts_query = f"{query} {author}"
|
|
1269
1306
|
if not fts_query.strip():
|
|
1270
1307
|
return [{"error": "query or at least one filter required"}]
|
|
1271
|
-
|
|
1272
|
-
|
|
1308
|
+
all_results = cat.find(fts_query, content_type=content_type or None)
|
|
1309
|
+
page = all_results[offset:offset + limit]
|
|
1310
|
+
result = [_entry_to_dict(e) for e in page]
|
|
1311
|
+
if offset + limit < len(all_results):
|
|
1312
|
+
result.append({"_pagination": {"next_offset": offset + limit, "limit": limit}})
|
|
1313
|
+
return result
|
|
1273
1314
|
except Exception as e:
|
|
1274
1315
|
return [{"error": str(e)}]
|
|
1275
1316
|
|
|
@@ -1315,7 +1356,10 @@ def catalog_list(
|
|
|
1315
1356
|
limit: int = 50,
|
|
1316
1357
|
offset: int = 0,
|
|
1317
1358
|
) -> list[dict]:
|
|
1318
|
-
"""List catalog entries with optional filters.
|
|
1359
|
+
"""List catalog entries with optional filters.
|
|
1360
|
+
|
|
1361
|
+
Results are paged. When truncated, a ``_pagination`` entry appears at the end
|
|
1362
|
+
with ``next_offset``. Pass that as ``offset`` to get the next page."""
|
|
1319
1363
|
cat, err = _require_catalog()
|
|
1320
1364
|
if err:
|
|
1321
1365
|
return [{"error": err}]
|
|
@@ -1347,7 +1391,11 @@ def catalog_list(
|
|
|
1347
1391
|
]
|
|
1348
1392
|
if content_type:
|
|
1349
1393
|
entries = [e for e in entries if e.content_type == content_type]
|
|
1350
|
-
|
|
1394
|
+
page = entries[:limit]
|
|
1395
|
+
result = [_entry_to_dict(e) for e in page]
|
|
1396
|
+
if len(entries) > limit:
|
|
1397
|
+
result.append({"_pagination": {"next_offset": offset + limit, "limit": limit}})
|
|
1398
|
+
return result
|
|
1351
1399
|
except Exception as e:
|
|
1352
1400
|
return [{"error": str(e)}]
|
|
1353
1401
|
|
|
@@ -1592,6 +1640,9 @@ def catalog_link_query(
|
|
|
1592
1640
|
) -> list[dict]:
|
|
1593
1641
|
"""Query links by any combination of filters. For admin/audit use.
|
|
1594
1642
|
|
|
1643
|
+
Results are paged. When truncated, a ``_pagination`` entry appears at the end
|
|
1644
|
+
with ``next_offset``. Pass that as ``offset`` to get the next page.
|
|
1645
|
+
|
|
1595
1646
|
NOT a query-planner step — use catalog_links for graph traversal.
|
|
1596
1647
|
Use for: audit by creator, find all links of a type, count generator output.
|
|
1597
1648
|
created_at_before: ISO timestamp — only links created before this time.
|
|
@@ -1606,9 +1657,14 @@ def catalog_link_query(
|
|
|
1606
1657
|
from_t=from_tumbler, to_t=to_tumbler, link_type=link_type,
|
|
1607
1658
|
created_by=created_by, direction=direction, tumbler=tumbler,
|
|
1608
1659
|
created_at_before=created_at_before,
|
|
1609
|
-
limit=limit, offset=offset,
|
|
1660
|
+
limit=limit + 1, offset=offset,
|
|
1610
1661
|
)
|
|
1611
|
-
|
|
1662
|
+
has_more = len(links) > limit
|
|
1663
|
+
links = links[:limit]
|
|
1664
|
+
result = [_link_to_dict(l) for l in links]
|
|
1665
|
+
if has_more:
|
|
1666
|
+
result.append({"_pagination": {"next_offset": offset + limit, "limit": limit}})
|
|
1667
|
+
return result
|
|
1612
1668
|
except Exception as e:
|
|
1613
1669
|
return [{"error": str(e)}]
|
|
1614
1670
|
|
|
@@ -284,10 +284,18 @@ class SemanticMarkdownChunker:
|
|
|
284
284
|
current_tokens += part_tokens
|
|
285
285
|
current_end_char = part_end_char
|
|
286
286
|
else:
|
|
287
|
+
is_code = part.get("is_code_block", False)
|
|
288
|
+
if self.preserve_code_blocks and is_code:
|
|
289
|
+
# Emit code blocks atomically — never truncate, even if oversized.
|
|
290
|
+
pass
|
|
291
|
+
elif len(part_text) > self.max_chars:
|
|
292
|
+
# Truncate oversized non-code parts to prevent unbounded chunk sizes.
|
|
293
|
+
part_text = part_text[: self.max_chars]
|
|
287
294
|
if current_parts:
|
|
295
|
+
emitted_text = "\n\n".join(current_parts)
|
|
288
296
|
chunks.append(
|
|
289
297
|
self._make_chunk(
|
|
290
|
-
|
|
298
|
+
emitted_text,
|
|
291
299
|
chunk_index,
|
|
292
300
|
base_metadata,
|
|
293
301
|
section["header_path"],
|
|
@@ -297,16 +305,21 @@ class SemanticMarkdownChunker:
|
|
|
297
305
|
)
|
|
298
306
|
chunk_index += 1
|
|
299
307
|
section_start_char = current_end_char
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
308
|
+
if self.overlap_chars > 0:
|
|
309
|
+
# Compute overlap from content only (skip header) to
|
|
310
|
+
# avoid duplicating the header when emitted_text is
|
|
311
|
+
# shorter than overlap_chars.
|
|
312
|
+
content_text = "\n\n".join(current_parts[1:]) if header_text else emitted_text
|
|
313
|
+
overlap_tail = content_text[-self.overlap_chars:] if content_text else ""
|
|
314
|
+
if header_text:
|
|
315
|
+
current_parts = [header_text, overlap_tail, part_text]
|
|
316
|
+
else:
|
|
317
|
+
current_parts = [overlap_tail, part_text]
|
|
318
|
+
else:
|
|
319
|
+
current_parts = [header_text, part_text] if header_text else [part_text]
|
|
320
|
+
else:
|
|
321
|
+
current_parts = [header_text, part_text] if header_text else [part_text]
|
|
322
|
+
current_tokens = sum(len(p) for p in current_parts) / _CHARS_PER_TOKEN
|
|
310
323
|
current_end_char = part_end_char
|
|
311
324
|
|
|
312
325
|
if current_parts:
|