@tenphi/akno-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +83 -0
- package/README.md +26 -0
- package/config/default.jsonc +548 -0
- package/dist/bench/answer-corpus.d.ts +48 -0
- package/dist/bench/answer-corpus.d.ts.map +1 -0
- package/dist/bench/answer-corpus.js +491 -0
- package/dist/bench/answer-corpus.js.map +1 -0
- package/dist/bench/answer.d.ts +156 -0
- package/dist/bench/answer.d.ts.map +1 -0
- package/dist/bench/answer.js +608 -0
- package/dist/bench/answer.js.map +1 -0
- package/dist/bench/auto-recall-answer-corpus.d.ts +21 -0
- package/dist/bench/auto-recall-answer-corpus.d.ts.map +1 -0
- package/dist/bench/auto-recall-answer-corpus.js +245 -0
- package/dist/bench/auto-recall-answer-corpus.js.map +1 -0
- package/dist/bench/auto-recall-answer.d.ts +198 -0
- package/dist/bench/auto-recall-answer.d.ts.map +1 -0
- package/dist/bench/auto-recall-answer.js +720 -0
- package/dist/bench/auto-recall-answer.js.map +1 -0
- package/dist/bench/auto-recall-corpus.d.ts +45 -0
- package/dist/bench/auto-recall-corpus.d.ts.map +1 -0
- package/dist/bench/auto-recall-corpus.js +221 -0
- package/dist/bench/auto-recall-corpus.js.map +1 -0
- package/dist/bench/auto-recall.d.ts +171 -0
- package/dist/bench/auto-recall.d.ts.map +1 -0
- package/dist/bench/auto-recall.js +651 -0
- package/dist/bench/auto-recall.js.map +1 -0
- package/dist/bench/entity-resolution.d.ts +37 -0
- package/dist/bench/entity-resolution.d.ts.map +1 -0
- package/dist/bench/entity-resolution.js +121 -0
- package/dist/bench/entity-resolution.js.map +1 -0
- package/dist/bench/graph.d.ts +57 -0
- package/dist/bench/graph.d.ts.map +1 -0
- package/dist/bench/graph.js +573 -0
- package/dist/bench/graph.js.map +1 -0
- package/dist/bench/llm-ranking-probe.d.ts +27 -0
- package/dist/bench/llm-ranking-probe.d.ts.map +1 -0
- package/dist/bench/llm-ranking-probe.js +105 -0
- package/dist/bench/llm-ranking-probe.js.map +1 -0
- package/dist/bench/merge-discovery-corpus.d.ts +26 -0
- package/dist/bench/merge-discovery-corpus.d.ts.map +1 -0
- package/dist/bench/merge-discovery-corpus.js +114 -0
- package/dist/bench/merge-discovery-corpus.js.map +1 -0
- package/dist/bench/merge-discovery-review.d.ts +81 -0
- package/dist/bench/merge-discovery-review.d.ts.map +1 -0
- package/dist/bench/merge-discovery-review.js +149 -0
- package/dist/bench/merge-discovery-review.js.map +1 -0
- package/dist/bench/merge-discovery.d.ts +122 -0
- package/dist/bench/merge-discovery.d.ts.map +1 -0
- package/dist/bench/merge-discovery.js +390 -0
- package/dist/bench/merge-discovery.js.map +1 -0
- package/dist/bench/mixed-retrieval.d.ts +35 -0
- package/dist/bench/mixed-retrieval.d.ts.map +1 -0
- package/dist/bench/mixed-retrieval.js +355 -0
- package/dist/bench/mixed-retrieval.js.map +1 -0
- package/dist/bench/ranking-corpus.d.ts +29 -0
- package/dist/bench/ranking-corpus.d.ts.map +1 -0
- package/dist/bench/ranking-corpus.js +514 -0
- package/dist/bench/ranking-corpus.js.map +1 -0
- package/dist/bench/ranking-end-to-end.d.ts +112 -0
- package/dist/bench/ranking-end-to-end.d.ts.map +1 -0
- package/dist/bench/ranking-end-to-end.js +479 -0
- package/dist/bench/ranking-end-to-end.js.map +1 -0
- package/dist/bench/ranking-latency.d.ts +71 -0
- package/dist/bench/ranking-latency.d.ts.map +1 -0
- package/dist/bench/ranking-latency.js +130 -0
- package/dist/bench/ranking-latency.js.map +1 -0
- package/dist/bench/ranking-matrix.d.ts +141 -0
- package/dist/bench/ranking-matrix.d.ts.map +1 -0
- package/dist/bench/ranking-matrix.js +526 -0
- package/dist/bench/ranking-matrix.js.map +1 -0
- package/dist/bench/ranking-review.d.ts +93 -0
- package/dist/bench/ranking-review.d.ts.map +1 -0
- package/dist/bench/ranking-review.js +249 -0
- package/dist/bench/ranking-review.js.map +1 -0
- package/dist/bench/ranking.d.ts +122 -0
- package/dist/bench/ranking.d.ts.map +1 -0
- package/dist/bench/ranking.js +547 -0
- package/dist/bench/ranking.js.map +1 -0
- package/dist/bench.d.ts +60 -0
- package/dist/bench.d.ts.map +1 -0
- package/dist/bench.js +167 -0
- package/dist/bench.js.map +1 -0
- package/dist/config/jsonc.d.ts +8 -0
- package/dist/config/jsonc.d.ts.map +1 -0
- package/dist/config/jsonc.js +85 -0
- package/dist/config/jsonc.js.map +1 -0
- package/dist/config/load.d.ts +43 -0
- package/dist/config/load.d.ts.map +1 -0
- package/dist/config/load.js +608 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/paths.d.ts +10 -0
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +38 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/schema.d.ts +698 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +394 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/write-rules.d.ts +41 -0
- package/dist/config/write-rules.d.ts.map +1 -0
- package/dist/config/write-rules.js +225 -0
- package/dist/config/write-rules.js.map +1 -0
- package/dist/config/write-setup.d.ts +42 -0
- package/dist/config/write-setup.d.ts.map +1 -0
- package/dist/config/write-setup.js +358 -0
- package/dist/config/write-setup.js.map +1 -0
- package/dist/context.d.ts +64 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +14 -0
- package/dist/context.js.map +1 -0
- package/dist/doctor.d.ts +115 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +388 -0
- package/dist/doctor.js.map +1 -0
- package/dist/index/chunk.d.ts +62 -0
- package/dist/index/chunk.d.ts.map +1 -0
- package/dist/index/chunk.js +307 -0
- package/dist/index/chunk.js.map +1 -0
- package/dist/index/defer.d.ts +32 -0
- package/dist/index/defer.d.ts.map +1 -0
- package/dist/index/defer.js +66 -0
- package/dist/index/defer.js.map +1 -0
- package/dist/index/derive.d.ts +99 -0
- package/dist/index/derive.d.ts.map +1 -0
- package/dist/index/derive.js +378 -0
- package/dist/index/derive.js.map +1 -0
- package/dist/index/entity-resolution.d.ts +68 -0
- package/dist/index/entity-resolution.d.ts.map +1 -0
- package/dist/index/entity-resolution.js +305 -0
- package/dist/index/entity-resolution.js.map +1 -0
- package/dist/index/graph.d.ts +46 -0
- package/dist/index/graph.d.ts.map +1 -0
- package/dist/index/graph.js +618 -0
- package/dist/index/graph.js.map +1 -0
- package/dist/index/indexer.d.ts +301 -0
- package/dist/index/indexer.d.ts.map +1 -0
- package/dist/index/indexer.js +1398 -0
- package/dist/index/indexer.js.map +1 -0
- package/dist/index/revision-barrier.d.ts +30 -0
- package/dist/index/revision-barrier.d.ts.map +1 -0
- package/dist/index/revision-barrier.js +140 -0
- package/dist/index/revision-barrier.js.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest/adoption-eligibility.d.ts +4 -0
- package/dist/ingest/adoption-eligibility.d.ts.map +1 -0
- package/dist/ingest/adoption-eligibility.js +18 -0
- package/dist/ingest/adoption-eligibility.js.map +1 -0
- package/dist/ingest/availability.d.ts +15 -0
- package/dist/ingest/availability.d.ts.map +1 -0
- package/dist/ingest/availability.js +37 -0
- package/dist/ingest/availability.js.map +1 -0
- package/dist/ingest/extract.d.ts +58 -0
- package/dist/ingest/extract.d.ts.map +1 -0
- package/dist/ingest/extract.js +255 -0
- package/dist/ingest/extract.js.map +1 -0
- package/dist/ingest/fetch.d.ts +35 -0
- package/dist/ingest/fetch.d.ts.map +1 -0
- package/dist/ingest/fetch.js +142 -0
- package/dist/ingest/fetch.js.map +1 -0
- package/dist/ingest/inbox.d.ts +53 -0
- package/dist/ingest/inbox.d.ts.map +1 -0
- package/dist/ingest/inbox.js +110 -0
- package/dist/ingest/inbox.js.map +1 -0
- package/dist/ingest/name.d.ts +72 -0
- package/dist/ingest/name.d.ts.map +1 -0
- package/dist/ingest/name.js +208 -0
- package/dist/ingest/name.js.map +1 -0
- package/dist/ingest/parts.d.ts +78 -0
- package/dist/ingest/parts.d.ts.map +1 -0
- package/dist/ingest/parts.js +52 -0
- package/dist/ingest/parts.js.map +1 -0
- package/dist/ingest/rendition.d.ts +75 -0
- package/dist/ingest/rendition.d.ts.map +1 -0
- package/dist/ingest/rendition.js +92 -0
- package/dist/ingest/rendition.js.map +1 -0
- package/dist/ingest/store.d.ts +66 -0
- package/dist/ingest/store.d.ts.map +1 -0
- package/dist/ingest/store.js +92 -0
- package/dist/ingest/store.js.map +1 -0
- package/dist/kb/folders.d.ts +37 -0
- package/dist/kb/folders.d.ts.map +1 -0
- package/dist/kb/folders.js +133 -0
- package/dist/kb/folders.js.map +1 -0
- package/dist/kb/frontmatter.d.ts +91 -0
- package/dist/kb/frontmatter.d.ts.map +1 -0
- package/dist/kb/frontmatter.js +274 -0
- package/dist/kb/frontmatter.js.map +1 -0
- package/dist/kb/line-facts.d.ts +29 -0
- package/dist/kb/line-facts.d.ts.map +1 -0
- package/dist/kb/line-facts.js +23 -0
- package/dist/kb/line-facts.js.map +1 -0
- package/dist/kb/page.d.ts +92 -0
- package/dist/kb/page.d.ts.map +1 -0
- package/dist/kb/page.js +243 -0
- package/dist/kb/page.js.map +1 -0
- package/dist/kb/scan.d.ts +38 -0
- package/dist/kb/scan.d.ts.map +1 -0
- package/dist/kb/scan.js +109 -0
- package/dist/kb/scan.js.map +1 -0
- package/dist/kb/words.d.ts +30 -0
- package/dist/kb/words.d.ts.map +1 -0
- package/dist/kb/words.js +107 -0
- package/dist/kb/words.js.map +1 -0
- package/dist/maintenance/adopt.d.ts +65 -0
- package/dist/maintenance/adopt.d.ts.map +1 -0
- package/dist/maintenance/adopt.js +238 -0
- package/dist/maintenance/adopt.js.map +1 -0
- package/dist/maintenance/budget.d.ts +55 -0
- package/dist/maintenance/budget.d.ts.map +1 -0
- package/dist/maintenance/budget.js +61 -0
- package/dist/maintenance/budget.js.map +1 -0
- package/dist/maintenance/conflicts.d.ts +105 -0
- package/dist/maintenance/conflicts.d.ts.map +1 -0
- package/dist/maintenance/conflicts.js +368 -0
- package/dist/maintenance/conflicts.js.map +1 -0
- package/dist/maintenance/contradictions.d.ts +34 -0
- package/dist/maintenance/contradictions.d.ts.map +1 -0
- package/dist/maintenance/contradictions.js +199 -0
- package/dist/maintenance/contradictions.js.map +1 -0
- package/dist/maintenance/curate.d.ts +156 -0
- package/dist/maintenance/curate.d.ts.map +1 -0
- package/dist/maintenance/curate.js +2070 -0
- package/dist/maintenance/curate.js.map +1 -0
- package/dist/maintenance/dream.d.ts +139 -0
- package/dist/maintenance/dream.d.ts.map +1 -0
- package/dist/maintenance/dream.js +1632 -0
- package/dist/maintenance/dream.js.map +1 -0
- package/dist/maintenance/graph-candidates.d.ts +19 -0
- package/dist/maintenance/graph-candidates.d.ts.map +1 -0
- package/dist/maintenance/graph-candidates.js +120 -0
- package/dist/maintenance/graph-candidates.js.map +1 -0
- package/dist/maintenance/housekeeping.d.ts +81 -0
- package/dist/maintenance/housekeeping.d.ts.map +1 -0
- package/dist/maintenance/housekeeping.js +281 -0
- package/dist/maintenance/housekeeping.js.map +1 -0
- package/dist/maintenance/link-repairs.d.ts +58 -0
- package/dist/maintenance/link-repairs.d.ts.map +1 -0
- package/dist/maintenance/link-repairs.js +281 -0
- package/dist/maintenance/link-repairs.js.map +1 -0
- package/dist/maintenance/log.d.ts +41 -0
- package/dist/maintenance/log.d.ts.map +1 -0
- package/dist/maintenance/log.js +72 -0
- package/dist/maintenance/log.js.map +1 -0
- package/dist/maintenance/managed-item-routing.d.ts +48 -0
- package/dist/maintenance/managed-item-routing.d.ts.map +1 -0
- package/dist/maintenance/managed-item-routing.js +281 -0
- package/dist/maintenance/managed-item-routing.js.map +1 -0
- package/dist/maintenance/managed-item-sources.d.ts +38 -0
- package/dist/maintenance/managed-item-sources.d.ts.map +1 -0
- package/dist/maintenance/managed-item-sources.js +324 -0
- package/dist/maintenance/managed-item-sources.js.map +1 -0
- package/dist/maintenance/managed-items.d.ts +162 -0
- package/dist/maintenance/managed-items.d.ts.map +1 -0
- package/dist/maintenance/managed-items.js +1329 -0
- package/dist/maintenance/managed-items.js.map +1 -0
- package/dist/maintenance/merge-classifier.d.ts +19 -0
- package/dist/maintenance/merge-classifier.d.ts.map +1 -0
- package/dist/maintenance/merge-classifier.js +49 -0
- package/dist/maintenance/merge-classifier.js.map +1 -0
- package/dist/maintenance/model-telemetry.d.ts +45 -0
- package/dist/maintenance/model-telemetry.d.ts.map +1 -0
- package/dist/maintenance/model-telemetry.js +107 -0
- package/dist/maintenance/model-telemetry.js.map +1 -0
- package/dist/maintenance/observe.d.ts +72 -0
- package/dist/maintenance/observe.d.ts.map +1 -0
- package/dist/maintenance/observe.js +265 -0
- package/dist/maintenance/observe.js.map +1 -0
- package/dist/maintenance/path-policy.d.ts +83 -0
- package/dist/maintenance/path-policy.d.ts.map +1 -0
- package/dist/maintenance/path-policy.js +360 -0
- package/dist/maintenance/path-policy.js.map +1 -0
- package/dist/maintenance/plans.d.ts +366 -0
- package/dist/maintenance/plans.d.ts.map +1 -0
- package/dist/maintenance/plans.js +4060 -0
- package/dist/maintenance/plans.js.map +1 -0
- package/dist/maintenance/profile.d.ts +33 -0
- package/dist/maintenance/profile.d.ts.map +1 -0
- package/dist/maintenance/profile.js +99 -0
- package/dist/maintenance/profile.js.map +1 -0
- package/dist/maintenance/recovery.d.ts +38 -0
- package/dist/maintenance/recovery.d.ts.map +1 -0
- package/dist/maintenance/recovery.js +217 -0
- package/dist/maintenance/recovery.js.map +1 -0
- package/dist/maintenance/repair.d.ts +37 -0
- package/dist/maintenance/repair.d.ts.map +1 -0
- package/dist/maintenance/repair.js +183 -0
- package/dist/maintenance/repair.js.map +1 -0
- package/dist/maintenance/rule-drift.d.ts +104 -0
- package/dist/maintenance/rule-drift.d.ts.map +1 -0
- package/dist/maintenance/rule-drift.js +507 -0
- package/dist/maintenance/rule-drift.js.map +1 -0
- package/dist/maintenance/run-verification.d.ts +44 -0
- package/dist/maintenance/run-verification.d.ts.map +1 -0
- package/dist/maintenance/run-verification.js +253 -0
- package/dist/maintenance/run-verification.js.map +1 -0
- package/dist/maintenance/runs.d.ts +142 -0
- package/dist/maintenance/runs.d.ts.map +1 -0
- package/dist/maintenance/runs.js +439 -0
- package/dist/maintenance/runs.js.map +1 -0
- package/dist/maintenance/semantic-merge-discovery.d.ts +54 -0
- package/dist/maintenance/semantic-merge-discovery.d.ts.map +1 -0
- package/dist/maintenance/semantic-merge-discovery.js +308 -0
- package/dist/maintenance/semantic-merge-discovery.js.map +1 -0
- package/dist/maintenance/temporal.d.ts +44 -0
- package/dist/maintenance/temporal.d.ts.map +1 -0
- package/dist/maintenance/temporal.js +295 -0
- package/dist/maintenance/temporal.js.map +1 -0
- package/dist/models/client.d.ts +214 -0
- package/dist/models/client.d.ts.map +1 -0
- package/dist/models/client.js +904 -0
- package/dist/models/client.js.map +1 -0
- package/dist/models/provider-api.d.ts +28 -0
- package/dist/models/provider-api.d.ts.map +1 -0
- package/dist/models/provider-api.js +320 -0
- package/dist/models/provider-api.js.map +1 -0
- package/dist/open.d.ts +163 -0
- package/dist/open.d.ts.map +1 -0
- package/dist/open.js +382 -0
- package/dist/open.js.map +1 -0
- package/dist/ops/adopt.d.ts +12 -0
- package/dist/ops/adopt.d.ts.map +1 -0
- package/dist/ops/adopt.js +138 -0
- package/dist/ops/adopt.js.map +1 -0
- package/dist/ops/answer.d.ts +29 -0
- package/dist/ops/answer.d.ts.map +1 -0
- package/dist/ops/answer.js +557 -0
- package/dist/ops/answer.js.map +1 -0
- package/dist/ops/context.d.ts +18 -0
- package/dist/ops/context.d.ts.map +1 -0
- package/dist/ops/context.js +713 -0
- package/dist/ops/context.js.map +1 -0
- package/dist/ops/folder.d.ts +23 -0
- package/dist/ops/folder.d.ts.map +1 -0
- package/dist/ops/folder.js +130 -0
- package/dist/ops/folder.js.map +1 -0
- package/dist/ops/forget.d.ts +14 -0
- package/dist/ops/forget.d.ts.map +1 -0
- package/dist/ops/forget.js +212 -0
- package/dist/ops/forget.js.map +1 -0
- package/dist/ops/graph.d.ts +10 -0
- package/dist/ops/graph.d.ts.map +1 -0
- package/dist/ops/graph.js +480 -0
- package/dist/ops/graph.js.map +1 -0
- package/dist/ops/ingest.d.ts +40 -0
- package/dist/ops/ingest.d.ts.map +1 -0
- package/dist/ops/ingest.js +434 -0
- package/dist/ops/ingest.js.map +1 -0
- package/dist/ops/list.d.ts +9 -0
- package/dist/ops/list.d.ts.map +1 -0
- package/dist/ops/list.js +217 -0
- package/dist/ops/list.js.map +1 -0
- package/dist/ops/move.d.ts +20 -0
- package/dist/ops/move.d.ts.map +1 -0
- package/dist/ops/move.js +173 -0
- package/dist/ops/move.js.map +1 -0
- package/dist/ops/read.d.ts +9 -0
- package/dist/ops/read.d.ts.map +1 -0
- package/dist/ops/read.js +271 -0
- package/dist/ops/read.js.map +1 -0
- package/dist/ops/recall.d.ts +13 -0
- package/dist/ops/recall.d.ts.map +1 -0
- package/dist/ops/recall.js +297 -0
- package/dist/ops/recall.js.map +1 -0
- package/dist/ops/remember.d.ts +34 -0
- package/dist/ops/remember.d.ts.map +1 -0
- package/dist/ops/remember.js +660 -0
- package/dist/ops/remember.js.map +1 -0
- package/dist/ops/timeline.d.ts +11 -0
- package/dist/ops/timeline.d.ts.map +1 -0
- package/dist/ops/timeline.js +111 -0
- package/dist/ops/timeline.js.map +1 -0
- package/dist/ops/undo.d.ts +9 -0
- package/dist/ops/undo.d.ts.map +1 -0
- package/dist/ops/undo.js +38 -0
- package/dist/ops/undo.js.map +1 -0
- package/dist/ops/write.d.ts +55 -0
- package/dist/ops/write.d.ts.map +1 -0
- package/dist/ops/write.js +463 -0
- package/dist/ops/write.js.map +1 -0
- package/dist/recall/assemble.d.ts +81 -0
- package/dist/recall/assemble.d.ts.map +1 -0
- package/dist/recall/assemble.js +603 -0
- package/dist/recall/assemble.js.map +1 -0
- package/dist/recall/expand.d.ts +55 -0
- package/dist/recall/expand.d.ts.map +1 -0
- package/dist/recall/expand.js +282 -0
- package/dist/recall/expand.js.map +1 -0
- package/dist/recall/graph-arm.d.ts +17 -0
- package/dist/recall/graph-arm.d.ts.map +1 -0
- package/dist/recall/graph-arm.js +227 -0
- package/dist/recall/graph-arm.js.map +1 -0
- package/dist/recall/llm-rerank.d.ts +55 -0
- package/dist/recall/llm-rerank.d.ts.map +1 -0
- package/dist/recall/llm-rerank.js +213 -0
- package/dist/recall/llm-rerank.js.map +1 -0
- package/dist/recall/reranker-calibration.d.ts +23 -0
- package/dist/recall/reranker-calibration.d.ts.map +1 -0
- package/dist/recall/reranker-calibration.js +161 -0
- package/dist/recall/reranker-calibration.js.map +1 -0
- package/dist/recall/search.d.ts +107 -0
- package/dist/recall/search.d.ts.map +1 -0
- package/dist/recall/search.js +530 -0
- package/dist/recall/search.js.map +1 -0
- package/dist/reserved.d.ts +39 -0
- package/dist/reserved.d.ts.map +1 -0
- package/dist/reserved.js +63 -0
- package/dist/reserved.js.map +1 -0
- package/dist/rules/compile.d.ts +27 -0
- package/dist/rules/compile.d.ts.map +1 -0
- package/dist/rules/compile.js +105 -0
- package/dist/rules/compile.js.map +1 -0
- package/dist/setup/model-free.d.ts +15 -0
- package/dist/setup/model-free.d.ts.map +1 -0
- package/dist/setup/model-free.js +26 -0
- package/dist/setup/model-free.js.map +1 -0
- package/dist/setup/openai.d.ts +46 -0
- package/dist/setup/openai.d.ts.map +1 -0
- package/dist/setup/openai.js +165 -0
- package/dist/setup/openai.js.map +1 -0
- package/dist/store/db.d.ts +61 -0
- package/dist/store/db.d.ts.map +1 -0
- package/dist/store/db.js +265 -0
- package/dist/store/db.js.map +1 -0
- package/dist/store/ids.d.ts +29 -0
- package/dist/store/ids.d.ts.map +1 -0
- package/dist/store/ids.js +0 -0
- package/dist/store/ids.js.map +1 -0
- package/dist/store/migrations.d.ts +54 -0
- package/dist/store/migrations.d.ts.map +1 -0
- package/dist/store/migrations.js +923 -0
- package/dist/store/migrations.js.map +1 -0
- package/dist/store/vectors.d.ts +34 -0
- package/dist/store/vectors.d.ts.map +1 -0
- package/dist/store/vectors.js +158 -0
- package/dist/store/vectors.js.map +1 -0
- package/dist/timeline/documents.d.ts +23 -0
- package/dist/timeline/documents.d.ts.map +1 -0
- package/dist/timeline/documents.js +262 -0
- package/dist/timeline/documents.js.map +1 -0
- package/dist/watch/watcher.d.ts +43 -0
- package/dist/watch/watcher.d.ts.map +1 -0
- package/dist/watch/watcher.js +143 -0
- package/dist/watch/watcher.js.map +1 -0
- package/dist/write/atomic.d.ts +34 -0
- package/dist/write/atomic.d.ts.map +1 -0
- package/dist/write/atomic.js +58 -0
- package/dist/write/atomic.js.map +1 -0
- package/dist/write/conflict.d.ts +43 -0
- package/dist/write/conflict.d.ts.map +1 -0
- package/dist/write/conflict.js +149 -0
- package/dist/write/conflict.js.map +1 -0
- package/dist/write/edit.d.ts +59 -0
- package/dist/write/edit.d.ts.map +1 -0
- package/dist/write/edit.js +231 -0
- package/dist/write/edit.js.map +1 -0
- package/dist/write/gate.d.ts +59 -0
- package/dist/write/gate.d.ts.map +1 -0
- package/dist/write/gate.js +99 -0
- package/dist/write/gate.js.map +1 -0
- package/dist/write/journal.d.ts +90 -0
- package/dist/write/journal.d.ts.map +1 -0
- package/dist/write/journal.js +187 -0
- package/dist/write/journal.js.map +1 -0
- package/dist/write/ledger.d.ts +28 -0
- package/dist/write/ledger.d.ts.map +1 -0
- package/dist/write/ledger.js +141 -0
- package/dist/write/ledger.js.map +1 -0
- package/dist/write/placement.d.ts +29 -0
- package/dist/write/placement.d.ts.map +1 -0
- package/dist/write/placement.js +140 -0
- package/dist/write/placement.js.map +1 -0
- package/dist/write/remember-fallback.d.ts +18 -0
- package/dist/write/remember-fallback.d.ts.map +1 -0
- package/dist/write/remember-fallback.js +48 -0
- package/dist/write/remember-fallback.js.map +1 -0
- package/dist/write/retain.d.ts +61 -0
- package/dist/write/retain.d.ts.map +1 -0
- package/dist/write/retain.js +272 -0
- package/dist/write/retain.js.map +1 -0
- package/package.json +50 -0
- package/swift/extract.swift +232 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import fsp from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { AknoError } from '@tenphi/akno-protocol';
|
|
4
|
+
import { newPrefixedId } from "../store/ids.js";
|
|
5
|
+
import { restoreFile } from "./atomic.js";
|
|
6
|
+
export class Journal {
|
|
7
|
+
#store;
|
|
8
|
+
#aknoPath;
|
|
9
|
+
#trashDir;
|
|
10
|
+
constructor(store, aknoPath, trashDir) {
|
|
11
|
+
this.#store = store;
|
|
12
|
+
this.#aknoPath = aknoPath;
|
|
13
|
+
this.#trashDir = trashDir;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Records a change that has already been applied to disk. Deliberately after
|
|
17
|
+
* the fact: a journal entry for a write that then failed is a lie in the one
|
|
18
|
+
* table that has to be trustworthy, and the failure mode of recording late (a
|
|
19
|
+
* crash between write and journal leaves an un-undoable change) is both rarer
|
|
20
|
+
* and far less confusing than the reverse.
|
|
21
|
+
*/
|
|
22
|
+
record(input) {
|
|
23
|
+
const changeId = newPrefixedId('chg');
|
|
24
|
+
const now = new Date().toISOString();
|
|
25
|
+
this.#store.transaction(() => {
|
|
26
|
+
this.#store.db
|
|
27
|
+
.prepare('INSERT INTO changes(id, at, actor, op, summary, status) VALUES(?, ?, ?, ?, ?, ?)')
|
|
28
|
+
.run(changeId, now, input.actor, input.op, input.summary, 'applied');
|
|
29
|
+
const insert = this.#store.db.prepare(`INSERT INTO change_files(change_id, ord, rel_path, action, before, after, snapshot, moved_to)
|
|
30
|
+
VALUES(?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
31
|
+
input.files.forEach((file, index) => {
|
|
32
|
+
insert.run(changeId, index, file.relPath, file.action, file.before, file.after, file.snapshot ?? null, file.movedTo ?? null);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
return changeId;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Reverses a change: every file back to its previous bytes, in reverse order.
|
|
39
|
+
*
|
|
40
|
+
* Reverse order matters for a move — the change created the destination and
|
|
41
|
+
* deleted the source, so undoing destination-first leaves the source free to be
|
|
42
|
+
* recreated. Forward order would try to recreate the source while the
|
|
43
|
+
* destination still holds it.
|
|
44
|
+
*/
|
|
45
|
+
async undo(changeId) {
|
|
46
|
+
const change = this.#store.db.prepare('SELECT * FROM changes WHERE id = ?').get(changeId);
|
|
47
|
+
if (!change)
|
|
48
|
+
throw new AknoError('not_found', `no change with id ${changeId}`);
|
|
49
|
+
if (change.status === 'undone') {
|
|
50
|
+
throw new AknoError('invalid', `${changeId} has already been undone`);
|
|
51
|
+
}
|
|
52
|
+
const files = this.#store.db
|
|
53
|
+
.prepare('SELECT * FROM change_files WHERE change_id = ? ORDER BY ord DESC')
|
|
54
|
+
.all(changeId);
|
|
55
|
+
const restored = [];
|
|
56
|
+
const removed = [];
|
|
57
|
+
const reversedMoves = [];
|
|
58
|
+
for (const file of files) {
|
|
59
|
+
if (file.moved_to) {
|
|
60
|
+
// The change was a rename, so its reversal is the rename back. Nothing was created
|
|
61
|
+
// and nothing was destroyed, which is why this case cannot go through `restoreFile`.
|
|
62
|
+
const from = path.join(this.#aknoPath, file.moved_to);
|
|
63
|
+
const target = path.join(this.#aknoPath, file.rel_path);
|
|
64
|
+
await fsp.mkdir(path.dirname(target), { recursive: true });
|
|
65
|
+
let reversed = true;
|
|
66
|
+
await fsp.rename(from, target).catch(async (err) => {
|
|
67
|
+
// Already gone is not a reason to abandon the rest of the reversal — the file was
|
|
68
|
+
// moved again, or removed, since. Everything else still goes back.
|
|
69
|
+
if (err.code !== 'ENOENT')
|
|
70
|
+
throw err;
|
|
71
|
+
reversed = false;
|
|
72
|
+
});
|
|
73
|
+
if (reversed)
|
|
74
|
+
reversedMoves.push({ from: file.moved_to, to: file.rel_path });
|
|
75
|
+
restored.push(file.rel_path);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (file.snapshot) {
|
|
79
|
+
// A binary: the bytes are in trash, not in the journal.
|
|
80
|
+
const source = path.join(this.#trashDir, file.snapshot);
|
|
81
|
+
const target = path.join(this.#aknoPath, file.rel_path);
|
|
82
|
+
await fsp.mkdir(path.dirname(target), { recursive: true });
|
|
83
|
+
await fsp.copyFile(source, target);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
await restoreFile(this.#aknoPath, file.rel_path, file.before);
|
|
87
|
+
}
|
|
88
|
+
// No prior content and no snapshot means the change created this file, so putting it
|
|
89
|
+
// back is deleting it. Two opposite outcomes reported under one word is one of them
|
|
90
|
+
// being reported wrongly.
|
|
91
|
+
if (!file.snapshot && file.before === null)
|
|
92
|
+
removed.push(file.rel_path);
|
|
93
|
+
else
|
|
94
|
+
restored.push(file.rel_path);
|
|
95
|
+
}
|
|
96
|
+
// A document row carries retained extraction and provenance that a structural re-index cannot
|
|
97
|
+
// always reproduce without another model call. Follow successful attachment renames back before
|
|
98
|
+
// the scanner runs, just as the forward move follows them, rather than deleting and recreating
|
|
99
|
+
// the row from its content-derived id.
|
|
100
|
+
if (reversedMoves.length > 0) {
|
|
101
|
+
this.#store.transaction(() => {
|
|
102
|
+
const moveDocument = this.#store.db.prepare('UPDATE OR IGNORE documents SET rel_path = ? WHERE rel_path = ?');
|
|
103
|
+
const moveRenders = this.#store.db.prepare('UPDATE documents SET renders = ? WHERE renders = ?');
|
|
104
|
+
const moveGroup = this.#store.db.prepare('UPDATE documents SET group_key = ? WHERE group_key = ?');
|
|
105
|
+
for (const move of reversedMoves)
|
|
106
|
+
moveDocument.run(move.to, move.from);
|
|
107
|
+
for (const move of reversedMoves) {
|
|
108
|
+
moveRenders.run(move.to, move.from);
|
|
109
|
+
moveGroup.run(move.to, move.from);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
this.#store.db
|
|
114
|
+
.prepare("UPDATE changes SET status = 'undone', undone_at = ? WHERE id = ?")
|
|
115
|
+
.run(new Date().toISOString(), changeId);
|
|
116
|
+
return { restored, removed, summary: change.summary };
|
|
117
|
+
}
|
|
118
|
+
list(limit = 20) {
|
|
119
|
+
// By rowid, not by `at`: two changes in the same millisecond have identical
|
|
120
|
+
// timestamps, and "the most recent change" then depends on SQLite's scan order.
|
|
121
|
+
// `undo --list` showing them out of order is how you undo the wrong one.
|
|
122
|
+
const rows = this.#store.db.prepare('SELECT * FROM changes ORDER BY rowid DESC LIMIT ?').all(limit);
|
|
123
|
+
const filesFor = this.#store.db.prepare('SELECT rel_path, action FROM change_files WHERE change_id = ? ORDER BY ord');
|
|
124
|
+
return rows.map((row) => ({
|
|
125
|
+
...row,
|
|
126
|
+
files: filesFor.all(row.id).map((file) => ({
|
|
127
|
+
relPath: file.rel_path,
|
|
128
|
+
action: file.action,
|
|
129
|
+
})),
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Moves a file into `trash/<change>/` and returns the snapshot path:
|
|
134
|
+
* `forget({slug})` moves a whole page to trash and stays undoable for the
|
|
135
|
+
* retention window — deleting outright would make "reversible" a lie.
|
|
136
|
+
*/
|
|
137
|
+
async trash(relPath, changeToken) {
|
|
138
|
+
const snapshot = path.join(changeToken, relPath);
|
|
139
|
+
const target = path.join(this.#trashDir, snapshot);
|
|
140
|
+
await fsp.mkdir(path.dirname(target), { recursive: true });
|
|
141
|
+
await fsp.rename(path.join(this.#aknoPath, relPath), target).catch(async (err) => {
|
|
142
|
+
// A rename across devices fails; trash may sit on a different volume.
|
|
143
|
+
if (err.code !== 'EXDEV')
|
|
144
|
+
throw err;
|
|
145
|
+
await fsp.copyFile(path.join(this.#aknoPath, relPath), target);
|
|
146
|
+
await fsp.rm(path.join(this.#aknoPath, relPath));
|
|
147
|
+
});
|
|
148
|
+
return snapshot;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Drops trashed files past the retention window. Called from the maintenance
|
|
152
|
+
* path, never from a write — a delete that also expires somebody else's older
|
|
153
|
+
* delete is a surprise nobody asked for.
|
|
154
|
+
*/
|
|
155
|
+
async expireTrash(retentionDays) {
|
|
156
|
+
if (retentionDays <= 0)
|
|
157
|
+
return 0;
|
|
158
|
+
const cutoff = Date.now() - retentionDays * 86_400_000;
|
|
159
|
+
let removed = 0;
|
|
160
|
+
let entries;
|
|
161
|
+
try {
|
|
162
|
+
entries = await fsp.readdir(this.#trashDir);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return 0;
|
|
166
|
+
}
|
|
167
|
+
for (const entry of entries) {
|
|
168
|
+
const abs = path.join(this.#trashDir, entry);
|
|
169
|
+
const stat = await fsp.stat(abs).catch(() => null);
|
|
170
|
+
if (!stat || stat.mtimeMs > cutoff)
|
|
171
|
+
continue;
|
|
172
|
+
await fsp.rm(abs, { recursive: true, force: true });
|
|
173
|
+
removed++;
|
|
174
|
+
}
|
|
175
|
+
return removed;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/** Convenience: turn an atomic write result into the journal's shape. */
|
|
179
|
+
export function fileEntry(result) {
|
|
180
|
+
return {
|
|
181
|
+
relPath: result.relPath,
|
|
182
|
+
action: result.created ? 'created' : 'modified',
|
|
183
|
+
before: result.before,
|
|
184
|
+
after: result.after,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=journal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal.js","sourceRoot":"","sources":["../../src/write/journal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface LedgerEvent {
|
|
2
|
+
date: string;
|
|
3
|
+
summary: string;
|
|
4
|
+
/** The page holding the detail. Plenty of events will never have one. */
|
|
5
|
+
slug?: string | null;
|
|
6
|
+
}
|
|
7
|
+
export interface LedgerInsert {
|
|
8
|
+
content: string;
|
|
9
|
+
/** 1-based line the new event landed on, so it can be cited as `timeline:47`. */
|
|
10
|
+
line: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function formatEventLine(event: LedgerEvent): string;
|
|
13
|
+
/**
|
|
14
|
+
* Inserts an event under its year heading, creating the heading if the year is new.
|
|
15
|
+
*
|
|
16
|
+
* Placement within a year is newest-first, but only among lines Akno can read as
|
|
17
|
+
* events — an unparseable line a human wrote is stepped over, never reordered
|
|
18
|
+
* around. If the year heading is absent it is added in the right place among the
|
|
19
|
+
* other year headings, so a ledger stays readable without anything being rewritten.
|
|
20
|
+
*/
|
|
21
|
+
export declare function insertEvent(content: string, event: LedgerEvent): LedgerInsert;
|
|
22
|
+
/**
|
|
23
|
+
* The header a ledger gets when a write has to create it. Startup creates this on
|
|
24
|
+
* startup only when asked; an event write creates it because the caller asked for
|
|
25
|
+
* an event and there is nowhere else to put it.
|
|
26
|
+
*/
|
|
27
|
+
export declare function newLedger(year: string): string;
|
|
28
|
+
//# sourceMappingURL=ledger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/write/ledger.ts"],"names":[],"mappings":"AA0BA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;CACd;AAKD,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAM1D;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,YAAY,CAiF7E;AASD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAU9C"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The event ledger.
|
|
3
|
+
*
|
|
4
|
+
* **The ledger is a source file, not a rendered view.** Generating it from the
|
|
5
|
+
* events index would always be tidy and correctly sorted, and it is rejected: a
|
|
6
|
+
* rendered file silently discards hand edits, and the whole point of a Markdown
|
|
7
|
+
* knowledge base is that hand edits are legitimate.
|
|
8
|
+
*
|
|
9
|
+
* So Akno maintains it **by appending only** — inserting under the right year
|
|
10
|
+
* heading and never rewriting or reordering what is already there. No edit a human
|
|
11
|
+
* made can be lost, and a hand-written line is indexed exactly like a generated
|
|
12
|
+
* one. Automatic upkeep without the destructive part.
|
|
13
|
+
*
|
|
14
|
+
* Nothing about this line syntax ever reaches a prompt: there is no
|
|
15
|
+
* `add_event` op). A caller hands over `{date, summary}`.
|
|
16
|
+
*/
|
|
17
|
+
import { saysTheSame } from "../kb/words.js";
|
|
18
|
+
/** The summary out of a formatted event line, without the date marker or the citation. */
|
|
19
|
+
function summaryOf(line) {
|
|
20
|
+
return line
|
|
21
|
+
.replace(EVENT_DATE, '')
|
|
22
|
+
.replace(/\[\[[^\]]*\]\]/g, '')
|
|
23
|
+
.trim();
|
|
24
|
+
}
|
|
25
|
+
/** The same shape the indexer matches, used here to read dates already in place. */
|
|
26
|
+
const EVENT_DATE = /^\s*[-*]\s+\*\*(\d{4}-\d{2}-\d{2})\*\*\s*\|/;
|
|
27
|
+
export function formatEventLine(event) {
|
|
28
|
+
const summary = event.summary.trim().replace(/\s+/g, ' ');
|
|
29
|
+
const link = event.slug ? ` [[${event.slug}]]` : '';
|
|
30
|
+
// The bold date and the `|` are what make a line an event: the indexer matches
|
|
31
|
+
// that exact shape, and prose it cannot match is invisible to search.
|
|
32
|
+
return `- **${event.date}** | ${summary}${link}`;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Inserts an event under its year heading, creating the heading if the year is new.
|
|
36
|
+
*
|
|
37
|
+
* Placement within a year is newest-first, but only among lines Akno can read as
|
|
38
|
+
* events — an unparseable line a human wrote is stepped over, never reordered
|
|
39
|
+
* around. If the year heading is absent it is added in the right place among the
|
|
40
|
+
* other year headings, so a ledger stays readable without anything being rewritten.
|
|
41
|
+
*/
|
|
42
|
+
export function insertEvent(content, event) {
|
|
43
|
+
const line = formatEventLine(event);
|
|
44
|
+
const lines = content.length === 0 ? [] : content.replace(/\n$/, '').split('\n');
|
|
45
|
+
const year = event.date.slice(0, 4);
|
|
46
|
+
// Already present, byte for byte: appending it twice is not append-only upkeep,
|
|
47
|
+
// it is duplication. The index collapses duplicates; this avoids making
|
|
48
|
+
// one in the file.
|
|
49
|
+
const existing = lines.indexOf(line);
|
|
50
|
+
if (existing !== -1)
|
|
51
|
+
return { content, line: existing + 1 };
|
|
52
|
+
// Already present in different words. Two callers describing one day's event will not agree on
|
|
53
|
+
// the wording — `They watched "Wicked: For Good"` and `The user watched "Wicked: For Good"` are
|
|
54
|
+
// one event and two strings, and the byte comparison above sees only the strings.
|
|
55
|
+
//
|
|
56
|
+
// Scoped to the date, which is what makes it safe: a ledger is full of events that resemble each
|
|
57
|
+
// other across days — a weekly delivery, a monthly payment — and those are genuinely separate
|
|
58
|
+
// things that happened. Two similar summaries on *one* day are almost always one thing described
|
|
59
|
+
// twice.
|
|
60
|
+
const sameDay = lines.findIndex((text) => {
|
|
61
|
+
const date = EVENT_DATE.exec(text)?.[1];
|
|
62
|
+
if (date !== event.date)
|
|
63
|
+
return false;
|
|
64
|
+
// A shared subject, place and date are not enough: scheduling something and later doing it
|
|
65
|
+
// are separate events whose nouns can overlap heavily. The default 0.7 containment boundary
|
|
66
|
+
// collapsed exactly that transition. Ledger deduplication is intentionally stricter because
|
|
67
|
+
// an extra line is visible and repairable, while a missing completion event is silent loss.
|
|
68
|
+
return saysTheSame(summaryOf(text), event.summary, 0.8);
|
|
69
|
+
});
|
|
70
|
+
if (sameDay !== -1)
|
|
71
|
+
return { content, line: sameDay + 1 };
|
|
72
|
+
const headings = lines
|
|
73
|
+
.map((text, index) => ({ text, index, year: /^##\s+(\d{4})\s*$/.exec(text)?.[1] }))
|
|
74
|
+
.filter((entry) => Boolean(entry.year));
|
|
75
|
+
const target = headings.find((heading) => heading.year === year);
|
|
76
|
+
if (target) {
|
|
77
|
+
// The block ends at the next heading, but its *content* ends before the blank
|
|
78
|
+
// line that separates the years. Inserting after that blank puts the line under
|
|
79
|
+
// the next year's heading as far as any reader is concerned.
|
|
80
|
+
const nextHeading = nextHeadingIndex(lines, target.index);
|
|
81
|
+
let blockEnd = nextHeading;
|
|
82
|
+
while (blockEnd > target.index + 1 && lines[blockEnd - 1].trim().length === 0)
|
|
83
|
+
blockEnd--;
|
|
84
|
+
let at = target.index + 1;
|
|
85
|
+
while (at < blockEnd && lines[at].trim().length === 0)
|
|
86
|
+
at++;
|
|
87
|
+
// Newest first, by date, among the lines Akno can read as events. A
|
|
88
|
+
// backdated entry — last week's appointment recorded today — belongs below
|
|
89
|
+
// the newer ones, and putting it at the top would make the ledger wrong in a
|
|
90
|
+
// way nobody notices until they read it.
|
|
91
|
+
//
|
|
92
|
+
// Still pure insertion: an unparseable line a human wrote is stepped over,
|
|
93
|
+
// never moved, so "never rewrites or reorders" holds.
|
|
94
|
+
for (let i = at; i < blockEnd; i++) {
|
|
95
|
+
const existingDate = EVENT_DATE.exec(lines[i])?.[1];
|
|
96
|
+
if (existingDate && existingDate < event.date) {
|
|
97
|
+
at = i;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
if (i === blockEnd - 1)
|
|
101
|
+
at = blockEnd;
|
|
102
|
+
}
|
|
103
|
+
lines.splice(at, 0, line);
|
|
104
|
+
return { content: `${lines.join('\n')}\n`, line: at + 1 };
|
|
105
|
+
}
|
|
106
|
+
// A new year. Newer years go above older ones, matching newest-first.
|
|
107
|
+
const laterHeading = headings.find((heading) => heading.year < year);
|
|
108
|
+
const insertAt = laterHeading ? laterHeading.index : lines.length;
|
|
109
|
+
const block = [`## ${year}`, line];
|
|
110
|
+
// Keep one blank line between year blocks, and none at the very top of a file
|
|
111
|
+
// that is only a header.
|
|
112
|
+
const needsGapBefore = insertAt > 0 && lines[insertAt - 1].trim().length > 0;
|
|
113
|
+
const needsGapAfter = insertAt < lines.length;
|
|
114
|
+
lines.splice(insertAt, 0, ...(needsGapBefore ? [''] : []), ...block, ...(needsGapAfter ? [''] : []));
|
|
115
|
+
return {
|
|
116
|
+
content: `${lines.join('\n')}\n`,
|
|
117
|
+
line: insertAt + (needsGapBefore ? 1 : 0) + 2,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function nextHeadingIndex(lines, from) {
|
|
121
|
+
for (let i = from + 1; i < lines.length; i++) {
|
|
122
|
+
if (/^##?\s+/.test(lines[i]))
|
|
123
|
+
return i;
|
|
124
|
+
}
|
|
125
|
+
return lines.length;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The header a ledger gets when a write has to create it. Startup creates this on
|
|
129
|
+
* startup only when asked; an event write creates it because the caller asked for
|
|
130
|
+
* an event and there is nowhere else to put it.
|
|
131
|
+
*/
|
|
132
|
+
export function newLedger(year) {
|
|
133
|
+
return (`---\ntype: timeline\ntitle: Timeline\n---\n\n# Timeline\n\n` +
|
|
134
|
+
`What actually happened, newest first. One line per event; the detail lives on the linked\n` +
|
|
135
|
+
`page, so this stays an index and never a second copy of a fact.\n\n` +
|
|
136
|
+
`Append-only: never edit or remove a line, correct it with a new one. Each line reads\n` +
|
|
137
|
+
`\`- **YYYY-MM-DD** | what happened. [[page/with/detail]]\` — that exact shape is what\n` +
|
|
138
|
+
`makes a line an event, and prose Akno cannot match is invisible to search.\n\n` +
|
|
139
|
+
`## ${year}\n`);
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../src/write/ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type ModelClient } from '../models/client.ts';
|
|
3
|
+
export interface ManagedItem {
|
|
4
|
+
id: string;
|
|
5
|
+
text: string;
|
|
6
|
+
source: string;
|
|
7
|
+
origin: 'user' | 'assistant' | 'unknown';
|
|
8
|
+
}
|
|
9
|
+
export interface PlacementResult {
|
|
10
|
+
content: string;
|
|
11
|
+
unsorted: string[];
|
|
12
|
+
error: string | null;
|
|
13
|
+
}
|
|
14
|
+
/** `id` is checked against the supplied set afterwards — a grammar can require a string
|
|
15
|
+
* there, not that it is one of the ids the model was actually given. */
|
|
16
|
+
export declare const PLACEMENT_SCHEMA: z.ZodObject<{
|
|
17
|
+
placements: z.ZodArray<z.ZodObject<{
|
|
18
|
+
id: z.ZodString;
|
|
19
|
+
heading: z.ZodString;
|
|
20
|
+
}, z.core.$strip>>;
|
|
21
|
+
}, z.core.$strip>;
|
|
22
|
+
/**
|
|
23
|
+
* One model call places all managed items bound for a page. The model chooses only section names;
|
|
24
|
+
* deterministic code performs the edit and preserves every existing byte outside the insertion.
|
|
25
|
+
*/
|
|
26
|
+
export declare function placeManagedItems(content: string, items: ManagedItem[], model: ModelClient): Promise<PlacementResult>;
|
|
27
|
+
/** Return the exact source label that survives the bounded marker encoding. */
|
|
28
|
+
export declare function managedSourceReference(value: string): string;
|
|
29
|
+
//# sourceMappingURL=placement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"placement.d.ts","sourceRoot":"","sources":["../../src/write/placement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvE,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;CAC1C;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAYD;yEACyE;AACzE,eAAO,MAAM,gBAAgB;;;;;iBAE3B,CAAC;AAEH;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,WAAW,EAAE,EACpB,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,eAAe,CAAC,CA8C1B;AAwCD,+EAA+E;AAC/E,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAS5D"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { parseFrontmatter } from "../kb/frontmatter.js";
|
|
3
|
+
import { parseJsonLoose } from "../models/client.js";
|
|
4
|
+
const SYSTEM = `You place durable knowledge into one Markdown page.
|
|
5
|
+
|
|
6
|
+
Reply with JSON only:
|
|
7
|
+
{"placements":[{"id":"exact supplied id","heading":"exact existing ## heading, or a concise new heading"}]}
|
|
8
|
+
|
|
9
|
+
Choose the most specific semantically correct section for every item. Reuse an existing ## heading
|
|
10
|
+
when one fits. A new heading is allowed when it materially improves the page. Do not rewrite,
|
|
11
|
+
rephrase, merge or omit items. Do not use the title as a heading. Never return "Unsorted"; the
|
|
12
|
+
caller owns that fallback.`;
|
|
13
|
+
/** `id` is checked against the supplied set afterwards — a grammar can require a string
|
|
14
|
+
* there, not that it is one of the ids the model was actually given. */
|
|
15
|
+
export const PLACEMENT_SCHEMA = z.object({
|
|
16
|
+
placements: z.array(z.object({ id: z.string(), heading: z.string() })),
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* One model call places all managed items bound for a page. The model chooses only section names;
|
|
20
|
+
* deterministic code performs the edit and preserves every existing byte outside the insertion.
|
|
21
|
+
*/
|
|
22
|
+
export async function placeManagedItems(content, items, model) {
|
|
23
|
+
if (items.length === 0)
|
|
24
|
+
return { content, unsorted: [], error: null };
|
|
25
|
+
const frontmatter = parseFrontmatter(content);
|
|
26
|
+
const body = content.slice(frontmatter.bodyOffset);
|
|
27
|
+
const existing = secondLevelHeadings(body);
|
|
28
|
+
let chosen = new Map();
|
|
29
|
+
let error = null;
|
|
30
|
+
if (model.available) {
|
|
31
|
+
const result = await model.chat([
|
|
32
|
+
{ role: 'system', content: SYSTEM },
|
|
33
|
+
{
|
|
34
|
+
role: 'user',
|
|
35
|
+
content: `Page:\n${body.slice(0, 24_000)}\n\nExisting ## headings: ${JSON.stringify(existing)}\n\n` +
|
|
36
|
+
`Items:\n${JSON.stringify(items.map(({ id, text }) => ({ id, text })))}`,
|
|
37
|
+
},
|
|
38
|
+
], { schema: PLACEMENT_SCHEMA, maxTokens: Math.min(1600, 200 + items.length * 100) });
|
|
39
|
+
if (result.ok && result.value) {
|
|
40
|
+
const parsed = parseJsonLoose(result.value);
|
|
41
|
+
chosen = cleanPlacements(parsed?.placements, new Set(items.map((item) => item.id)));
|
|
42
|
+
if (chosen.size !== items.length)
|
|
43
|
+
error = 'placement omitted or invalidated one or more items';
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
error = result.error ?? 'placement failed';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
error = model.unavailableReason ?? 'placement model unavailable';
|
|
51
|
+
}
|
|
52
|
+
let nextBody = body;
|
|
53
|
+
const unsorted = [];
|
|
54
|
+
for (const item of items) {
|
|
55
|
+
const heading = chosen.get(item.id) ?? 'Unsorted';
|
|
56
|
+
if (heading === 'Unsorted')
|
|
57
|
+
unsorted.push(item.id);
|
|
58
|
+
nextBody = appendManagedBlock(nextBody, heading, managedBlock(item));
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
content: content.slice(0, frontmatter.bodyOffset) + nextBody,
|
|
62
|
+
unsorted,
|
|
63
|
+
error,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function cleanPlacements(value, itemIds) {
|
|
67
|
+
const out = new Map();
|
|
68
|
+
if (!Array.isArray(value))
|
|
69
|
+
return out;
|
|
70
|
+
for (const entry of value) {
|
|
71
|
+
if (!entry || typeof entry !== 'object')
|
|
72
|
+
continue;
|
|
73
|
+
const record = entry;
|
|
74
|
+
if (typeof record.id !== 'string' || !itemIds.has(record.id) || out.has(record.id))
|
|
75
|
+
continue;
|
|
76
|
+
if (typeof record.heading !== 'string')
|
|
77
|
+
continue;
|
|
78
|
+
const heading = cleanHeading(record.heading);
|
|
79
|
+
if (heading)
|
|
80
|
+
out.set(record.id, heading);
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
function cleanHeading(raw) {
|
|
85
|
+
const heading = raw
|
|
86
|
+
.replace(/^#+\s*/, '')
|
|
87
|
+
.replace(/[\r\n[\]<>]/g, '')
|
|
88
|
+
.trim();
|
|
89
|
+
if (heading.length === 0 || heading.length > 80 || heading.toLowerCase() === 'unsorted')
|
|
90
|
+
return null;
|
|
91
|
+
return heading;
|
|
92
|
+
}
|
|
93
|
+
function secondLevelHeadings(body) {
|
|
94
|
+
return body
|
|
95
|
+
.split('\n')
|
|
96
|
+
.map((line) => /^##\s+(.+?)\s*$/.exec(line)?.[1]?.trim())
|
|
97
|
+
.filter((heading) => Boolean(heading));
|
|
98
|
+
}
|
|
99
|
+
function managedBlock(item) {
|
|
100
|
+
return `<!-- akno:item ${item.id} source=${encodeMarker(item.source)} origin=${item.origin} -->\n${item.text.trim()}`;
|
|
101
|
+
}
|
|
102
|
+
function encodeMarker(value) {
|
|
103
|
+
return encodeURIComponent(managedSourceReference(value));
|
|
104
|
+
}
|
|
105
|
+
/** Return the exact source label that survives the bounded marker encoding. */
|
|
106
|
+
export function managedSourceReference(value) {
|
|
107
|
+
const cleaned = value.replace(/-->/g, '') || 'remember';
|
|
108
|
+
let bounded = '';
|
|
109
|
+
for (const character of cleaned) {
|
|
110
|
+
const candidate = bounded + character;
|
|
111
|
+
if (encodeURIComponent(candidate).length > 300)
|
|
112
|
+
break;
|
|
113
|
+
bounded = candidate;
|
|
114
|
+
}
|
|
115
|
+
return bounded || 'remember';
|
|
116
|
+
}
|
|
117
|
+
function appendManagedBlock(body, heading, block) {
|
|
118
|
+
const lines = body.replace(/\s+$/, '').split('\n');
|
|
119
|
+
const wanted = heading.toLowerCase();
|
|
120
|
+
const matches = lines
|
|
121
|
+
.map((line, index) => ({ index, match: /^##\s+(.+?)\s*$/.exec(line) }))
|
|
122
|
+
.filter((entry) => entry.match?.[1]?.trim().toLowerCase() === wanted);
|
|
123
|
+
if (matches.length !== 1) {
|
|
124
|
+
const gap = lines.length === 1 && lines[0] === '' ? [] : ['', ''];
|
|
125
|
+
return `${[...lines, ...gap, `## ${heading}`, '', block].join('\n').replace(/^\n+/, '')}\n`;
|
|
126
|
+
}
|
|
127
|
+
const start = matches[0].index;
|
|
128
|
+
let end = lines.length;
|
|
129
|
+
for (let index = start + 1; index < lines.length; index++) {
|
|
130
|
+
if (/^#{1,2}\s+/.test(lines[index])) {
|
|
131
|
+
end = index;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
while (end > start + 1 && lines[end - 1].trim() === '')
|
|
136
|
+
end--;
|
|
137
|
+
lines.splice(end, 0, '', block);
|
|
138
|
+
return `${lines.join('\n').replace(/\n{3,}/g, '\n\n')}\n`;
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=placement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"placement.js","sourceRoot":"","sources":["../../src/write/placement.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AknoContext } from '../context.ts';
|
|
2
|
+
import { type FolderCatalogEntry } from '../kb/folders.ts';
|
|
3
|
+
type RememberFallbackUnavailableReason = 'reserved_path' | 'existing_page_not_admitted' | 'unindexed_page_exists' | 'folder_not_admitted';
|
|
4
|
+
export type RememberFallbackResolution = {
|
|
5
|
+
slug: string;
|
|
6
|
+
status: 'existing_page' | 'new_page';
|
|
7
|
+
} | {
|
|
8
|
+
slug: string;
|
|
9
|
+
status: 'unavailable';
|
|
10
|
+
reason: RememberFallbackUnavailableReason;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the explicit catch-all independently of semantic routing. Configuration names one exact page;
|
|
14
|
+
* admission still comes from the page or its parent folder, so this option cannot grant itself write authority.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveRememberFallback(ctx: AknoContext, catalog?: FolderCatalogEntry[]): Promise<RememberFallbackResolution | null>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=remember-fallback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remember-fallback.d.ts","sourceRoot":"","sources":["../../src/write/remember-fallback.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAiB,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAG1E,KAAK,iCAAiC,GACpC,eAAe,GAAG,4BAA4B,GAAG,uBAAuB,GAAG,qBAAqB,CAAC;AAEnG,MAAM,MAAM,0BAA0B,GAClC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,eAAe,GAAG,UAAU,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,iCAAiC,CAAA;CAAE,CAAC;AAEvF;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,WAAW,EAChB,OAAO,GAAE,kBAAkB,EAAyC,GACnE,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC,CA8B5C"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import fsp from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { folderCatalog } from "../kb/folders.js";
|
|
4
|
+
import { isReserved } from "../reserved.js";
|
|
5
|
+
/**
|
|
6
|
+
* Resolve the explicit catch-all independently of semantic routing. Configuration names one exact page;
|
|
7
|
+
* admission still comes from the page or its parent folder, so this option cannot grant itself write authority.
|
|
8
|
+
*/
|
|
9
|
+
export async function resolveRememberFallback(ctx, catalog = folderCatalog(ctx.config, ctx.store)) {
|
|
10
|
+
const slug = ctx.config.maintenance.retain.fallbackPage;
|
|
11
|
+
if (!slug)
|
|
12
|
+
return null;
|
|
13
|
+
if (isReserved(slug, ctx.config))
|
|
14
|
+
return { slug, status: 'unavailable', reason: 'reserved_path' };
|
|
15
|
+
const row = ctx.store.db.prepare('SELECT role, remember_management FROM pages WHERE slug = ?').get(slug);
|
|
16
|
+
if (row) {
|
|
17
|
+
return row.role === 'knowledge' && row.remember_management === 'integrate'
|
|
18
|
+
? { slug, status: 'existing_page' }
|
|
19
|
+
: { slug, status: 'unavailable', reason: 'existing_page_not_admitted' };
|
|
20
|
+
}
|
|
21
|
+
// An indexed page has policy metadata. Existing bytes without an index row do not, and treating them as a
|
|
22
|
+
// new managed page would overwrite user-authored content before Akno had classified it.
|
|
23
|
+
if (await fallbackFileExists(ctx, slug)) {
|
|
24
|
+
return { slug, status: 'unavailable', reason: 'unindexed_page_exists' };
|
|
25
|
+
}
|
|
26
|
+
const parent = slug.slice(0, slug.lastIndexOf('/'));
|
|
27
|
+
const admitted = catalog.some((folder) => folder.path === parent &&
|
|
28
|
+
folder.role === 'knowledge' &&
|
|
29
|
+
folder.remember === 'integrate' &&
|
|
30
|
+
folder.creatable);
|
|
31
|
+
return admitted
|
|
32
|
+
? { slug, status: 'new_page' }
|
|
33
|
+
: { slug, status: 'unavailable', reason: 'folder_not_admitted' };
|
|
34
|
+
}
|
|
35
|
+
async function fallbackFileExists(ctx, slug) {
|
|
36
|
+
for (const extension of ctx.config.pageExtensions) {
|
|
37
|
+
try {
|
|
38
|
+
if ((await fsp.stat(path.join(ctx.config.aknoPath, `${slug}${extension}`))).isFile())
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (error.code !== 'ENOENT')
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=remember-fallback.js.map
|