@askdkc/kiokuko 0.1.17 → 0.1.19
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/README.ja.md +91 -112
- package/README.ko.md +90 -102
- package/README.md +103 -262
- package/README.zh-CN.md +88 -102
- package/dist/agent-file/atomic-write.d.ts +90 -3
- package/dist/agent-file/atomic-write.d.ts.map +1 -1
- package/dist/agent-file/atomic-write.js +990 -14
- package/dist/agent-file/atomic-write.js.map +1 -1
- package/dist/agent-file/managed-block.d.ts +12 -1
- package/dist/agent-file/managed-block.d.ts.map +1 -1
- package/dist/agent-file/managed-block.js +49 -4
- package/dist/agent-file/managed-block.js.map +1 -1
- package/dist/agent-file/render.d.ts +1 -1
- package/dist/agent-file/render.d.ts.map +1 -1
- package/dist/agent-file/render.js +10 -7
- package/dist/agent-file/render.js.map +1 -1
- package/dist/akinator/agent-task.d.ts +11 -22
- package/dist/akinator/agent-task.d.ts.map +1 -1
- package/dist/akinator/agent-task.js +454 -99
- package/dist/akinator/agent-task.js.map +1 -1
- package/dist/akinator/capabilities.d.ts +18 -6
- package/dist/akinator/capabilities.d.ts.map +1 -1
- package/dist/akinator/capabilities.js +72 -35
- package/dist/akinator/capabilities.js.map +1 -1
- package/dist/akinator/capability-binding.d.ts +11 -0
- package/dist/akinator/capability-binding.d.ts.map +1 -0
- package/dist/akinator/capability-binding.js +56 -0
- package/dist/akinator/capability-binding.js.map +1 -0
- package/dist/akinator/domain.js +2 -2
- package/dist/akinator/domain.js.map +1 -1
- package/dist/akinator/knowledge-path.d.ts.map +1 -1
- package/dist/akinator/knowledge-path.js +409 -39
- package/dist/akinator/knowledge-path.js.map +1 -1
- package/dist/akinator/orchestrator.d.ts +3 -4
- package/dist/akinator/orchestrator.d.ts.map +1 -1
- package/dist/akinator/orchestrator.js +1 -4
- package/dist/akinator/orchestrator.js.map +1 -1
- package/dist/akinator/service.d.ts +0 -4
- package/dist/akinator/service.d.ts.map +1 -1
- package/dist/akinator/service.js +19 -35
- package/dist/akinator/service.js.map +1 -1
- package/dist/akinator/skill-discovery-attempt.d.ts +20 -0
- package/dist/akinator/skill-discovery-attempt.d.ts.map +1 -0
- package/dist/akinator/skill-discovery-attempt.js +390 -0
- package/dist/akinator/skill-discovery-attempt.js.map +1 -0
- package/dist/akinator/store.d.ts.map +1 -1
- package/dist/akinator/store.js +107 -52
- package/dist/akinator/store.js.map +1 -1
- package/dist/akinator/types.d.ts +0 -12
- package/dist/akinator/types.d.ts.map +1 -1
- package/dist/bin/kiokuko.js +0 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +534 -148
- package/dist/cli.js.map +1 -1
- package/dist/client/server-client.d.ts +5 -3
- package/dist/client/server-client.d.ts.map +1 -1
- package/dist/client/server-client.js +486 -181
- package/dist/client/server-client.js.map +1 -1
- package/dist/commands/agent.d.ts +2 -0
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +861 -86
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/backup.d.ts +2 -1
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +64 -8
- package/dist/commands/backup.js.map +1 -1
- package/dist/commands/doctor.d.ts +5 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +70 -26
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/export.d.ts +0 -4
- package/dist/commands/export.d.ts.map +1 -1
- package/dist/commands/export.js +191 -32
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/import.d.ts +10 -1
- package/dist/commands/import.d.ts.map +1 -1
- package/dist/commands/import.js +592 -113
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/init.d.ts +19 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +569 -22
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/purge.d.ts.map +1 -1
- package/dist/commands/purge.js +3 -0
- package/dist/commands/purge.js.map +1 -1
- package/dist/commands/setup.d.ts +34 -8
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +418 -86
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/skills.d.ts +9 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +317 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/use.d.ts +10 -2
- package/dist/commands/use.d.ts.map +1 -1
- package/dist/commands/use.js +851 -73
- package/dist/commands/use.js.map +1 -1
- package/dist/config/paths.d.ts +11 -1
- package/dist/config/paths.d.ts.map +1 -1
- package/dist/config/paths.js +64 -29
- package/dist/config/paths.js.map +1 -1
- package/dist/config/project-config.d.ts +1 -0
- package/dist/config/project-config.d.ts.map +1 -1
- package/dist/config/project-config.js +70 -32
- package/dist/config/project-config.js.map +1 -1
- package/dist/context/broker.d.ts +28 -14
- package/dist/context/broker.d.ts.map +1 -1
- package/dist/context/broker.js +604 -145
- package/dist/context/broker.js.map +1 -1
- package/dist/context/delivery.d.ts +6 -21
- package/dist/context/delivery.d.ts.map +1 -1
- package/dist/context/delivery.js +196 -147
- package/dist/context/delivery.js.map +1 -1
- package/dist/context/feedback.d.ts +11 -12
- package/dist/context/feedback.d.ts.map +1 -1
- package/dist/context/feedback.js +229 -261
- package/dist/context/feedback.js.map +1 -1
- package/dist/context/ranking.d.ts +1 -12
- package/dist/context/ranking.d.ts.map +1 -1
- package/dist/context/ranking.js +13 -4
- package/dist/context/ranking.js.map +1 -1
- package/dist/context/recommendations.d.ts +0 -5
- package/dist/context/recommendations.d.ts.map +1 -1
- package/dist/context/recommendations.js +0 -1
- package/dist/context/recommendations.js.map +1 -1
- package/dist/context/run-state.d.ts +26 -0
- package/dist/context/run-state.d.ts.map +1 -0
- package/dist/context/run-state.js +399 -0
- package/dist/context/run-state.js.map +1 -0
- package/dist/context/scoped-broker.d.ts +17 -5
- package/dist/context/scoped-broker.d.ts.map +1 -1
- package/dist/context/scoped-broker.js +512 -106
- package/dist/context/scoped-broker.js.map +1 -1
- package/dist/context/selection-state.d.ts +19 -0
- package/dist/context/selection-state.d.ts.map +1 -0
- package/dist/context/selection-state.js +250 -0
- package/dist/context/selection-state.js.map +1 -0
- package/dist/db/adapter.d.ts +5 -3
- package/dist/db/adapter.d.ts.map +1 -1
- package/dist/db/adapter.js +6 -3
- package/dist/db/adapter.js.map +1 -1
- package/dist/db/capabilities.d.ts.map +1 -1
- package/dist/db/capabilities.js +34 -16
- package/dist/db/capabilities.js.map +1 -1
- package/dist/db/connection.d.ts +8 -0
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +55 -26
- package/dist/db/connection.js.map +1 -1
- package/dist/db/migrate.d.ts +28 -7
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +106 -78
- package/dist/db/migrate.js.map +1 -1
- package/dist/db/sqlite-retry.d.ts +11 -0
- package/dist/db/sqlite-retry.d.ts.map +1 -0
- package/dist/db/sqlite-retry.js +66 -0
- package/dist/db/sqlite-retry.js.map +1 -0
- package/dist/db/transaction.d.ts +13 -0
- package/dist/db/transaction.d.ts.map +1 -1
- package/dist/db/transaction.js +53 -24
- package/dist/db/transaction.js.map +1 -1
- package/dist/db/upgrade-backup.d.ts +58 -2
- package/dist/db/upgrade-backup.d.ts.map +1 -1
- package/dist/db/upgrade-backup.js +757 -28
- package/dist/db/upgrade-backup.js.map +1 -1
- package/dist/errors.js +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/gateway/agent-service.d.ts +4 -1
- package/dist/gateway/agent-service.d.ts.map +1 -1
- package/dist/gateway/agent-service.js +71 -58
- package/dist/gateway/agent-service.js.map +1 -1
- package/dist/gateway/checkpoint-service.d.ts +1 -0
- package/dist/gateway/checkpoint-service.d.ts.map +1 -1
- package/dist/gateway/checkpoint-service.js +47 -24
- package/dist/gateway/checkpoint-service.js.map +1 -1
- package/dist/ledger/archive.d.ts +1 -4
- package/dist/ledger/archive.d.ts.map +1 -1
- package/dist/ledger/archive.js +77 -39
- package/dist/ledger/archive.js.map +1 -1
- package/dist/ledger/maintenance.d.ts +0 -11
- package/dist/ledger/maintenance.d.ts.map +1 -1
- package/dist/ledger/maintenance.js +24 -40
- package/dist/ledger/maintenance.js.map +1 -1
- package/dist/ledger/projection.d.ts +0 -1
- package/dist/ledger/projection.d.ts.map +1 -1
- package/dist/ledger/projection.js.map +1 -1
- package/dist/ledger/promotion.d.ts +0 -9
- package/dist/ledger/promotion.d.ts.map +1 -1
- package/dist/ledger/promotion.js.map +1 -1
- package/dist/ledger/query.d.ts +1 -15
- package/dist/ledger/query.d.ts.map +1 -1
- package/dist/ledger/query.js.map +1 -1
- package/dist/ledger/store.d.ts +0 -1
- package/dist/ledger/store.d.ts.map +1 -1
- package/dist/ledger/store.js +11 -8
- package/dist/ledger/store.js.map +1 -1
- package/dist/ledger/types.d.ts +0 -4
- package/dist/ledger/types.d.ts.map +1 -1
- package/dist/ledger/types.js.map +1 -1
- package/dist/ledger/validate.d.ts.map +1 -1
- package/dist/ledger/validate.js +0 -5
- package/dist/ledger/validate.js.map +1 -1
- package/dist/mcp/server.d.ts +4 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +105 -54
- package/dist/mcp/server.js.map +1 -1
- package/dist/memory/audit.d.ts +0 -1
- package/dist/memory/audit.d.ts.map +1 -1
- package/dist/memory/audit.js +0 -1
- package/dist/memory/audit.js.map +1 -1
- package/dist/memory/curator.d.ts.map +1 -1
- package/dist/memory/curator.js +172 -96
- package/dist/memory/curator.js.map +1 -1
- package/dist/memory/entries.d.ts +12 -2
- package/dist/memory/entries.d.ts.map +1 -1
- package/dist/memory/entries.js +198 -114
- package/dist/memory/entries.js.map +1 -1
- package/dist/memory/federated-retrieval.d.ts +12 -1
- package/dist/memory/federated-retrieval.d.ts.map +1 -1
- package/dist/memory/federated-retrieval.js +183 -70
- package/dist/memory/federated-retrieval.js.map +1 -1
- package/dist/memory/hybrid-retrieval.d.ts +5 -11
- package/dist/memory/hybrid-retrieval.d.ts.map +1 -1
- package/dist/memory/hybrid-retrieval.js +78 -58
- package/dist/memory/hybrid-retrieval.js.map +1 -1
- package/dist/memory/lifecycle.d.ts.map +1 -1
- package/dist/memory/lifecycle.js +17 -13
- package/dist/memory/lifecycle.js.map +1 -1
- package/dist/memory/rebuild-search.d.ts +5 -0
- package/dist/memory/rebuild-search.d.ts.map +1 -1
- package/dist/memory/rebuild-search.js +101 -76
- package/dist/memory/rebuild-search.js.map +1 -1
- package/dist/memory/retrieval-query.d.ts +0 -5
- package/dist/memory/retrieval-query.d.ts.map +1 -1
- package/dist/memory/retrieval-query.js +0 -5
- package/dist/memory/retrieval-query.js.map +1 -1
- package/dist/memory/retrieval.d.ts.map +1 -1
- package/dist/memory/retrieval.js +25 -131
- package/dist/memory/retrieval.js.map +1 -1
- package/dist/memory/revisions.d.ts +76 -1
- package/dist/memory/revisions.d.ts.map +1 -1
- package/dist/memory/revisions.js +539 -35
- package/dist/memory/revisions.js.map +1 -1
- package/dist/memory/scoped-memory.d.ts +16 -1
- package/dist/memory/scoped-memory.d.ts.map +1 -1
- package/dist/memory/scoped-memory.js +240 -107
- package/dist/memory/scoped-memory.js.map +1 -1
- package/dist/memory/secrets.d.ts +2 -0
- package/dist/memory/secrets.d.ts.map +1 -1
- package/dist/memory/secrets.js +36 -0
- package/dist/memory/secrets.js.map +1 -1
- package/dist/memory/structured-memory.d.ts +3 -2
- package/dist/memory/structured-memory.d.ts.map +1 -1
- package/dist/memory/structured-memory.js +54 -22
- package/dist/memory/structured-memory.js.map +1 -1
- package/dist/memory/workspaces.d.ts +9 -0
- package/dist/memory/workspaces.d.ts.map +1 -1
- package/dist/memory/workspaces.js +67 -0
- package/dist/memory/workspaces.js.map +1 -1
- package/dist/package-version.d.ts +2 -0
- package/dist/package-version.d.ts.map +1 -0
- package/dist/package-version.js +7 -0
- package/dist/package-version.js.map +1 -0
- package/dist/repository/binding.d.ts +5 -0
- package/dist/repository/binding.d.ts.map +1 -1
- package/dist/repository/binding.js +117 -17
- package/dist/repository/binding.js.map +1 -1
- package/dist/repository/framework-version.d.ts +8 -0
- package/dist/repository/framework-version.d.ts.map +1 -0
- package/dist/repository/framework-version.js +29 -0
- package/dist/repository/framework-version.js.map +1 -0
- package/dist/repository/identity-value.d.ts +4 -0
- package/dist/repository/identity-value.d.ts.map +1 -0
- package/dist/repository/identity-value.js +24 -0
- package/dist/repository/identity-value.js.map +1 -0
- package/dist/repository/identity.d.ts.map +1 -1
- package/dist/repository/identity.js +2 -0
- package/dist/repository/identity.js.map +1 -1
- package/dist/repository/project-fingerprint.d.ts +14 -2
- package/dist/repository/project-fingerprint.d.ts.map +1 -1
- package/dist/repository/project-fingerprint.js +312 -33
- package/dist/repository/project-fingerprint.js.map +1 -1
- package/dist/repository/remote-url.d.ts +0 -1
- package/dist/repository/remote-url.d.ts.map +1 -1
- package/dist/repository/remote-url.js +0 -1
- package/dist/repository/remote-url.js.map +1 -1
- package/dist/runtime-version.d.ts +2 -1
- package/dist/runtime-version.d.ts.map +1 -1
- package/dist/runtime-version.js +21 -4
- package/dist/runtime-version.js.map +1 -1
- package/dist/serialization/boundary-json.d.ts +20 -0
- package/dist/serialization/boundary-json.d.ts.map +1 -0
- package/dist/serialization/boundary-json.js +129 -0
- package/dist/serialization/boundary-json.js.map +1 -0
- package/dist/serialization/envelope.js +1 -1
- package/dist/serialization/envelope.js.map +1 -1
- package/dist/serialization/validate.d.ts +7 -0
- package/dist/serialization/validate.d.ts.map +1 -1
- package/dist/serialization/validate.js +53 -13
- package/dist/serialization/validate.js.map +1 -1
- package/dist/server/app.js +1 -1
- package/dist/server/app.js.map +1 -1
- package/dist/server/http.d.ts +4 -3
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +90 -50
- package/dist/server/http.js.map +1 -1
- package/dist/server/idempotency.d.ts +0 -6
- package/dist/server/idempotency.d.ts.map +1 -1
- package/dist/server/idempotency.js.map +1 -1
- package/dist/server/router.d.ts.map +1 -1
- package/dist/server/router.js +21 -4
- package/dist/server/router.js.map +1 -1
- package/dist/server/routes/agent-capability-gate.d.ts +40 -0
- package/dist/server/routes/agent-capability-gate.d.ts.map +1 -0
- package/dist/server/routes/agent-capability-gate.js +182 -0
- package/dist/server/routes/agent-capability-gate.js.map +1 -0
- package/dist/server/routes/agent-events.d.ts.map +1 -1
- package/dist/server/routes/agent-events.js +8 -1
- package/dist/server/routes/agent-events.js.map +1 -1
- package/dist/server/routes/agent-intake.d.ts.map +1 -1
- package/dist/server/routes/agent-intake.js +10 -2
- package/dist/server/routes/agent-intake.js.map +1 -1
- package/dist/server/routes/agent-promotions.d.ts.map +1 -1
- package/dist/server/routes/agent-promotions.js +5 -2
- package/dist/server/routes/agent-promotions.js.map +1 -1
- package/dist/server/routes/agent-runs.d.ts.map +1 -1
- package/dist/server/routes/agent-runs.js +18 -4
- package/dist/server/routes/agent-runs.js.map +1 -1
- package/dist/server/routes/request-binding.d.ts +5 -0
- package/dist/server/routes/request-binding.d.ts.map +1 -0
- package/dist/server/routes/request-binding.js +49 -0
- package/dist/server/routes/request-binding.js.map +1 -0
- package/dist/server/routes/task5-support.d.ts +1 -8
- package/dist/server/routes/task5-support.d.ts.map +1 -1
- package/dist/server/routes/task5-support.js +1 -17
- package/dist/server/routes/task5-support.js.map +1 -1
- package/dist/server/routes/task5.d.ts.map +1 -1
- package/dist/server/routes/task5.js +106 -36
- package/dist/server/routes/task5.js.map +1 -1
- package/dist/server/write-queue.js +2 -2
- package/dist/server/write-queue.js.map +1 -1
- package/dist/setup/claude-config.d.ts +2 -1
- package/dist/setup/claude-config.d.ts.map +1 -1
- package/dist/setup/claude-config.js +54 -4
- package/dist/setup/claude-config.js.map +1 -1
- package/dist/setup/client-detection.d.ts +7 -2
- package/dist/setup/client-detection.d.ts.map +1 -1
- package/dist/setup/client-detection.js +27 -9
- package/dist/setup/client-detection.js.map +1 -1
- package/dist/setup/hermes-config.d.ts +2 -1
- package/dist/setup/hermes-config.d.ts.map +1 -1
- package/dist/setup/hermes-config.js +53 -12
- package/dist/setup/hermes-config.js.map +1 -1
- package/dist/setup/legacy-client-cleanup.d.ts +6 -0
- package/dist/setup/legacy-client-cleanup.d.ts.map +1 -0
- package/dist/setup/legacy-client-cleanup.js +152 -0
- package/dist/setup/legacy-client-cleanup.js.map +1 -0
- package/dist/setup/managed-text.d.ts.map +1 -1
- package/dist/setup/managed-text.js +11 -1
- package/dist/setup/managed-text.js.map +1 -1
- package/dist/setup/opencode-config.d.ts +2 -1
- package/dist/setup/opencode-config.d.ts.map +1 -1
- package/dist/setup/opencode-config.js +57 -5
- package/dist/setup/opencode-config.js.map +1 -1
- package/dist/setup/render.d.ts +2 -1
- package/dist/setup/render.d.ts.map +1 -1
- package/dist/setup/render.js +91 -17
- package/dist/setup/render.js.map +1 -1
- package/dist/setup/standard-skills.d.ts +16 -2
- package/dist/setup/standard-skills.d.ts.map +1 -1
- package/dist/setup/standard-skills.js +37 -13
- package/dist/setup/standard-skills.js.map +1 -1
- package/dist/setup/strict-json.d.ts +7 -0
- package/dist/setup/strict-json.d.ts.map +1 -0
- package/dist/setup/strict-json.js +98 -0
- package/dist/setup/strict-json.js.map +1 -0
- package/dist/setup/strict-toml.d.ts +7 -0
- package/dist/setup/strict-toml.d.ts.map +1 -0
- package/dist/setup/strict-toml.js +470 -0
- package/dist/setup/strict-toml.js.map +1 -0
- package/dist/skills/cache.d.ts +15 -0
- package/dist/skills/cache.d.ts.map +1 -0
- package/dist/skills/cache.js +19 -0
- package/dist/skills/cache.js.map +1 -0
- package/dist/skills/candidate-ranking.d.ts +15 -0
- package/dist/skills/candidate-ranking.d.ts.map +1 -0
- package/dist/skills/candidate-ranking.js +52 -0
- package/dist/skills/candidate-ranking.js.map +1 -0
- package/dist/skills/chunking.d.ts +11 -0
- package/dist/skills/chunking.d.ts.map +1 -0
- package/dist/skills/chunking.js +291 -0
- package/dist/skills/chunking.js.map +1 -0
- package/dist/skills/config.d.ts +19 -0
- package/dist/skills/config.d.ts.map +1 -0
- package/dist/skills/config.js +103 -0
- package/dist/skills/config.js.map +1 -0
- package/dist/skills/discovery-service.d.ts +26 -0
- package/dist/skills/discovery-service.d.ts.map +1 -0
- package/dist/skills/discovery-service.js +921 -0
- package/dist/skills/discovery-service.js.map +1 -0
- package/dist/skills/external-transport.d.ts +2 -0
- package/dist/skills/external-transport.d.ts.map +1 -0
- package/dist/skills/external-transport.js +30 -0
- package/dist/skills/external-transport.js.map +1 -0
- package/dist/skills/find.d.ts +16 -0
- package/dist/skills/find.d.ts.map +1 -0
- package/dist/skills/find.js +58 -0
- package/dist/skills/find.js.map +1 -0
- package/dist/skills/gap-detection.d.ts +23 -0
- package/dist/skills/gap-detection.d.ts.map +1 -0
- package/dist/skills/gap-detection.js +62 -0
- package/dist/skills/gap-detection.js.map +1 -0
- package/dist/skills/import-preparation.d.ts +4 -0
- package/dist/skills/import-preparation.d.ts.map +1 -0
- package/dist/skills/import-preparation.js +20 -0
- package/dist/skills/import-preparation.js.map +1 -0
- package/dist/skills/materialization-authority.d.ts +11 -0
- package/dist/skills/materialization-authority.d.ts.map +1 -0
- package/dist/skills/materialization-authority.js +92 -0
- package/dist/skills/materialization-authority.js.map +1 -0
- package/dist/skills/materialization-service.d.ts +22 -0
- package/dist/skills/materialization-service.d.ts.map +1 -0
- package/dist/skills/materialization-service.js +101 -0
- package/dist/skills/materialization-service.js.map +1 -0
- package/dist/skills/official-catalog.d.ts +31 -0
- package/dist/skills/official-catalog.d.ts.map +1 -0
- package/dist/skills/official-catalog.js +110 -0
- package/dist/skills/official-catalog.js.map +1 -0
- package/dist/skills/providers/schema.d.ts +30 -0
- package/dist/skills/providers/schema.d.ts.map +1 -0
- package/dist/skills/providers/schema.js +354 -0
- package/dist/skills/providers/schema.js.map +1 -0
- package/dist/skills/providers/skills-sh-compat.d.ts +17 -0
- package/dist/skills/providers/skills-sh-compat.d.ts.map +1 -0
- package/dist/skills/providers/skills-sh-compat.js +71 -0
- package/dist/skills/providers/skills-sh-compat.js.map +1 -0
- package/dist/skills/providers/skills-sh-v1.d.ts +23 -0
- package/dist/skills/providers/skills-sh-v1.d.ts.map +1 -0
- package/dist/skills/providers/skills-sh-v1.js +134 -0
- package/dist/skills/providers/skills-sh-v1.js.map +1 -0
- package/dist/skills/query-builder.d.ts +18 -0
- package/dist/skills/query-builder.d.ts.map +1 -0
- package/dist/skills/query-builder.js +93 -0
- package/dist/skills/query-builder.js.map +1 -0
- package/dist/skills/source/errors.d.ts +9 -0
- package/dist/skills/source/errors.d.ts.map +1 -0
- package/dist/skills/source/errors.js +15 -0
- package/dist/skills/source/errors.js.map +1 -0
- package/dist/skills/source/frontmatter.d.ts +9 -0
- package/dist/skills/source/frontmatter.d.ts.map +1 -0
- package/dist/skills/source/frontmatter.js +77 -0
- package/dist/skills/source/frontmatter.js.map +1 -0
- package/dist/skills/source/github-fetcher.d.ts +20 -0
- package/dist/skills/source/github-fetcher.d.ts.map +1 -0
- package/dist/skills/source/github-fetcher.js +292 -0
- package/dist/skills/source/github-fetcher.js.map +1 -0
- package/dist/skills/source/snapshot-validator.d.ts +28 -0
- package/dist/skills/source/snapshot-validator.d.ts.map +1 -0
- package/dist/skills/source/snapshot-validator.js +186 -0
- package/dist/skills/source/snapshot-validator.js.map +1 -0
- package/dist/skills/store.d.ts +181 -0
- package/dist/skills/store.d.ts.map +1 -0
- package/dist/skills/store.js +1710 -0
- package/dist/skills/store.js.map +1 -0
- package/dist/skills/types.d.ts +169 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +2 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/web/i18n.d.ts +32 -0
- package/dist/web/i18n.d.ts.map +1 -1
- package/dist/web/i18n.js +128 -0
- package/dist/web/i18n.js.map +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +386 -38
- package/dist/web/server.js.map +1 -1
- package/dist/web/ui.d.ts +4 -0
- package/dist/web/ui.d.ts.map +1 -1
- package/dist/web/ui.js +382 -6
- package/dist/web/ui.js.map +1 -1
- package/migrations/009_external_skill_discovery.sql +126 -0
- package/package.json +4 -3
- package/skills/kiokuko-single-purpose-functions/SKILL.md +288 -0
- package/skills/kiokuko-single-purpose-functions/references/kiokuko-patterns.md +344 -0
- package/skills/kiokuko-single-purpose-functions/references/review-checklist.md +97 -0
- package/skills/kiokuko-ui-design-soul/SKILL.md +1186 -28
- package/templates/AGENTS.md +8 -7
- package/dist/client/runtime-discovery.d.ts +0 -15
- package/dist/client/runtime-discovery.d.ts.map +0 -1
- package/dist/client/runtime-discovery.js +0 -45
- package/dist/client/runtime-discovery.js.map +0 -1
- package/dist/commands/call.d.ts +0 -7
- package/dist/commands/call.d.ts.map +0 -1
- package/dist/commands/call.js +0 -10
- package/dist/commands/call.js.map +0 -1
- package/dist/commands/link.d.ts +0 -6
- package/dist/commands/link.d.ts.map +0 -1
- package/dist/commands/link.js +0 -6
- package/dist/commands/link.js.map +0 -1
- package/dist/commands/promote.d.ts +0 -6
- package/dist/commands/promote.d.ts.map +0 -1
- package/dist/commands/promote.js +0 -6
- package/dist/commands/promote.js.map +0 -1
- package/dist/commands/read.d.ts +0 -6
- package/dist/commands/read.d.ts.map +0 -1
- package/dist/commands/read.js +0 -4
- package/dist/commands/read.js.map +0 -1
- package/dist/commands/recall.d.ts +0 -6
- package/dist/commands/recall.d.ts.map +0 -1
- package/dist/commands/recall.js +0 -4
- package/dist/commands/recall.js.map +0 -1
- package/dist/commands/record.d.ts +0 -6
- package/dist/commands/record.d.ts.map +0 -1
- package/dist/commands/record.js +0 -4
- package/dist/commands/record.js.map +0 -1
- package/dist/commands/search.d.ts +0 -6
- package/dist/commands/search.d.ts.map +0 -1
- package/dist/commands/search.js +0 -4
- package/dist/commands/search.js.map +0 -1
- package/dist/commands/supersede.d.ts +0 -6
- package/dist/commands/supersede.d.ts.map +0 -1
- package/dist/commands/supersede.js +0 -6
- package/dist/commands/supersede.js.map +0 -1
- package/dist/knowledge/sources.d.ts +0 -72
- package/dist/knowledge/sources.d.ts.map +0 -1
- package/dist/knowledge/sources.js +0 -388
- package/dist/knowledge/sources.js.map +0 -1
- package/dist/setup/opencode-evidence.d.ts +0 -37
- package/dist/setup/opencode-evidence.d.ts.map +0 -1
- package/dist/setup/opencode-evidence.js +0 -58
- package/dist/setup/opencode-evidence.js.map +0 -1
- package/dist/setup/opencode-loop-guard.d.ts +0 -9
- package/dist/setup/opencode-loop-guard.d.ts.map +0 -1
- package/dist/setup/opencode-loop-guard.js +0 -248
- package/dist/setup/opencode-loop-guard.js.map +0 -1
package/dist/memory/revisions.js
CHANGED
|
@@ -1,16 +1,272 @@
|
|
|
1
1
|
import { KiokukoError } from '../errors.js';
|
|
2
|
-
import { canonicalContentHash, canonicalJson, requireWorkspace, validateRecordInput, } from '../serialization/validate.js';
|
|
3
|
-
|
|
2
|
+
import { canonicalContentHash, canonicalEntryRevisionContentHash, canonicalJson, ENTRY_STATUSES, requireWorkspace, TRUST_LEVELS, validateRecordInput, } from '../serialization/validate.js';
|
|
3
|
+
import { buildStructuredScope, } from './structured-memory.js';
|
|
4
|
+
const SQLITE_CONSTRAINT_PRIMARY_KEY = 1_555;
|
|
5
|
+
const SQLITE_CONSTRAINT_UNIQUE = 2_067;
|
|
6
|
+
const REVISION_UNIQUENESS_FAILURES = new Set([
|
|
7
|
+
'UNIQUE constraint failed: entry_revisions.entry_id, entry_revisions.revision',
|
|
8
|
+
'UNIQUE constraint failed: entry_revisions.workspace, entry_revisions.content_hash',
|
|
9
|
+
]);
|
|
10
|
+
function isExpectedRevisionConflict(error) {
|
|
11
|
+
if (!(error instanceof Error))
|
|
12
|
+
return false;
|
|
13
|
+
const failure = error;
|
|
14
|
+
return failure.code === 'ERR_SQLITE_ERROR'
|
|
15
|
+
&& (failure.errcode === SQLITE_CONSTRAINT_PRIMARY_KEY || failure.errcode === SQLITE_CONSTRAINT_UNIQUE)
|
|
16
|
+
&& REVISION_UNIQUENESS_FAILURES.has(failure.message);
|
|
17
|
+
}
|
|
18
|
+
function storedIntegrity() {
|
|
19
|
+
throw new KiokukoError('INTEGRITY_ERROR', 'Stored entry or revision is invalid');
|
|
20
|
+
}
|
|
21
|
+
function isPlainObject(value) {
|
|
22
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
23
|
+
return false;
|
|
24
|
+
const prototype = Object.getPrototypeOf(value);
|
|
25
|
+
return prototype === Object.prototype || prototype === null;
|
|
26
|
+
}
|
|
27
|
+
function hasOwn(value, field) {
|
|
28
|
+
return Object.prototype.hasOwnProperty.call(value, field);
|
|
29
|
+
}
|
|
30
|
+
function storedNonEmptyString(value) {
|
|
31
|
+
if (typeof value !== 'string' || value.trim().length === 0)
|
|
32
|
+
storedIntegrity();
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
function canonicalTimestamp(value) {
|
|
36
|
+
if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/u.test(value))
|
|
37
|
+
return false;
|
|
38
|
+
const milliseconds = Date.parse(value);
|
|
39
|
+
return Number.isFinite(milliseconds) && new Date(milliseconds).toISOString() === value;
|
|
40
|
+
}
|
|
41
|
+
function parseStoredObject(value) {
|
|
42
|
+
if (typeof value !== 'string')
|
|
43
|
+
storedIntegrity();
|
|
44
|
+
let parsed;
|
|
45
|
+
try {
|
|
46
|
+
parsed = JSON.parse(value);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (error instanceof SyntaxError)
|
|
50
|
+
storedIntegrity();
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
if (!isPlainObject(parsed))
|
|
54
|
+
storedIntegrity();
|
|
55
|
+
try {
|
|
56
|
+
if (canonicalJson(parsed) !== value)
|
|
57
|
+
storedIntegrity();
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
if (error instanceof KiokukoError && error.code === 'VALIDATION_ERROR')
|
|
61
|
+
storedIntegrity();
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
return parsed;
|
|
65
|
+
}
|
|
66
|
+
function exactLegacyFrameworkOrder(scope, normalized) {
|
|
67
|
+
if (!isPlainObject(scope.applicability) || !isPlainObject(normalized.applicability))
|
|
68
|
+
return false;
|
|
69
|
+
const storedFrameworks = scope.applicability.frameworks;
|
|
70
|
+
const normalizedFrameworks = normalized.applicability.frameworks;
|
|
71
|
+
if (!Array.isArray(storedFrameworks) || !Array.isArray(normalizedFrameworks)
|
|
72
|
+
|| storedFrameworks.length !== normalizedFrameworks.length)
|
|
73
|
+
return false;
|
|
74
|
+
let storedMembers;
|
|
75
|
+
let normalizedMembers;
|
|
76
|
+
try {
|
|
77
|
+
storedMembers = storedFrameworks.map((framework) => canonicalJson(framework));
|
|
78
|
+
normalizedMembers = normalizedFrameworks.map((framework) => canonicalJson(framework));
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (error instanceof KiokukoError && error.code === 'VALIDATION_ERROR')
|
|
82
|
+
return false;
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
const sortedStoredMembers = [...storedMembers].sort();
|
|
86
|
+
const sortedNormalizedMembers = [...normalizedMembers].sort();
|
|
87
|
+
if (new Set(storedMembers).size !== storedMembers.length
|
|
88
|
+
|| new Set(normalizedMembers).size !== normalizedMembers.length
|
|
89
|
+
|| sortedStoredMembers.some((member, index) => member !== sortedNormalizedMembers[index]))
|
|
90
|
+
return false;
|
|
91
|
+
const reconstructed = {
|
|
92
|
+
...normalized,
|
|
93
|
+
applicability: { ...normalized.applicability, frameworks: storedFrameworks },
|
|
94
|
+
};
|
|
95
|
+
return canonicalJson(reconstructed) === canonicalJson(scope);
|
|
96
|
+
}
|
|
97
|
+
/** Normalize caller-supplied structured scope before it is persisted. */
|
|
98
|
+
export function normalizeStructuredScopeInput(scope) {
|
|
99
|
+
if (!hasOwn(scope, 'schemaVersion')) {
|
|
100
|
+
return scope;
|
|
101
|
+
}
|
|
102
|
+
const allowed = new Set([
|
|
103
|
+
'schemaVersion', 'visibility', 'retrievalScope', 'repositoryId', 'memoryClass',
|
|
104
|
+
'applicability', 'signals', 'portableReason',
|
|
105
|
+
]);
|
|
106
|
+
if (Object.keys(scope).some((field) => !allowed.has(field))) {
|
|
107
|
+
throw new KiokukoError('VALIDATION_ERROR', 'Structured memory scope contains an unknown field');
|
|
108
|
+
}
|
|
109
|
+
if (scope.schemaVersion !== 2 && scope.schemaVersion !== 3) {
|
|
110
|
+
throw new KiokukoError('VALIDATION_ERROR', 'Structured memory scope schemaVersion is unsupported');
|
|
111
|
+
}
|
|
112
|
+
const schemaVersion = scope.schemaVersion;
|
|
113
|
+
if (schemaVersion === 2 && hasOwn(scope, 'retrievalScope')) {
|
|
114
|
+
throw new KiokukoError('VALIDATION_ERROR', 'Structured memory scope schemaVersion 2 cannot contain retrievalScope');
|
|
115
|
+
}
|
|
116
|
+
let normalized = buildStructuredScope({
|
|
117
|
+
visibility: scope.visibility,
|
|
118
|
+
...(schemaVersion === 3 && hasOwn(scope, 'retrievalScope') ? { retrievalScope: scope.retrievalScope } : {}),
|
|
119
|
+
...(hasOwn(scope, 'repositoryId') ? { repositoryId: scope.repositoryId } : {}),
|
|
120
|
+
...(hasOwn(scope, 'memoryClass') ? { memoryClass: scope.memoryClass } : {}),
|
|
121
|
+
...(hasOwn(scope, 'applicability') ? { applicability: scope.applicability } : {}),
|
|
122
|
+
...(hasOwn(scope, 'signals') ? { signals: scope.signals } : {}),
|
|
123
|
+
...(hasOwn(scope, 'portableReason') ? { portableReason: scope.portableReason } : {}),
|
|
124
|
+
});
|
|
125
|
+
if (schemaVersion === 2)
|
|
126
|
+
normalized = { ...normalized, schemaVersion: 2 };
|
|
127
|
+
return normalized;
|
|
128
|
+
}
|
|
129
|
+
function normalizeStoredStructuredScope(scope, required) {
|
|
130
|
+
if (required && scope.schemaVersion !== 3)
|
|
131
|
+
storedIntegrity();
|
|
4
132
|
try {
|
|
5
|
-
|
|
6
|
-
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
|
|
7
|
-
throw new Error('not object');
|
|
8
|
-
return parsed;
|
|
133
|
+
return normalizeStructuredScopeInput(scope);
|
|
9
134
|
}
|
|
10
|
-
catch {
|
|
11
|
-
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (error instanceof KiokukoError && (error.code === 'VALIDATION_ERROR' || error.code === 'SECURITY_REJECTION'))
|
|
137
|
+
storedIntegrity();
|
|
138
|
+
throw error;
|
|
12
139
|
}
|
|
13
140
|
}
|
|
141
|
+
/** Decode only the canonical persisted structured-scope representation. */
|
|
142
|
+
export function decodeStoredStructuredScope(scope, required = false) {
|
|
143
|
+
const normalized = normalizeStoredStructuredScope(scope, required);
|
|
144
|
+
if (canonicalJson(normalized) !== canonicalJson(scope))
|
|
145
|
+
storedIntegrity();
|
|
146
|
+
return { scope: normalized, canonicalScope: normalized };
|
|
147
|
+
}
|
|
148
|
+
function decodeMigratableStoredStructuredScope(scope) {
|
|
149
|
+
const normalized = normalizeStoredStructuredScope(scope, false);
|
|
150
|
+
if (canonicalJson(normalized) !== canonicalJson(scope) && !exactLegacyFrameworkOrder(scope, normalized))
|
|
151
|
+
storedIntegrity();
|
|
152
|
+
return { scope: normalized, canonicalScope: normalized, persistedScope: scope };
|
|
153
|
+
}
|
|
154
|
+
function normalizedStoredRecord(input, tags, options) {
|
|
155
|
+
const entryId = storedNonEmptyString(input.entryId);
|
|
156
|
+
const createdBy = storedNonEmptyString(input.createdBy);
|
|
157
|
+
const createdAt = storedNonEmptyString(input.createdAt);
|
|
158
|
+
if (!canonicalTimestamp(createdAt)
|
|
159
|
+
|| !Number.isSafeInteger(input.revision) || Number(input.revision) < 1
|
|
160
|
+
|| input.summary !== null && typeof input.summary !== 'string'
|
|
161
|
+
|| !Array.isArray(tags))
|
|
162
|
+
storedIntegrity();
|
|
163
|
+
const decodedScope = decodeStoredStructuredScope(parseStoredObject(input.scopeJson), options.requireStructuredScope === true);
|
|
164
|
+
const scope = decodedScope.canonicalScope;
|
|
165
|
+
const provenance = parseStoredObject(input.provenanceJson);
|
|
166
|
+
let validated;
|
|
167
|
+
try {
|
|
168
|
+
validated = validateRecordInput({
|
|
169
|
+
workspace: input.workspace,
|
|
170
|
+
kind: input.kind,
|
|
171
|
+
status: 'candidate',
|
|
172
|
+
title: input.title,
|
|
173
|
+
body: input.body,
|
|
174
|
+
summary: input.summary,
|
|
175
|
+
scope,
|
|
176
|
+
provenance,
|
|
177
|
+
trustLevel: 'user_asserted',
|
|
178
|
+
confidence: 1,
|
|
179
|
+
tags,
|
|
180
|
+
createdBy,
|
|
181
|
+
actor: createdBy,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
if (error instanceof KiokukoError && (error.code === 'VALIDATION_ERROR' || error.code === 'SECURITY_REJECTION'))
|
|
186
|
+
storedIntegrity();
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
if (validated.tags.length !== tags.length)
|
|
190
|
+
storedIntegrity();
|
|
191
|
+
const hashInput = {
|
|
192
|
+
kind: validated.kind,
|
|
193
|
+
title: validated.title,
|
|
194
|
+
body: validated.body,
|
|
195
|
+
summary: validated.summary,
|
|
196
|
+
scope: validated.scope,
|
|
197
|
+
provenance: validated.provenance,
|
|
198
|
+
tags: validated.tags,
|
|
199
|
+
};
|
|
200
|
+
const contentHash = canonicalEntryRevisionContentHash(hashInput);
|
|
201
|
+
if (input.contentHash !== contentHash)
|
|
202
|
+
storedIntegrity();
|
|
203
|
+
return {
|
|
204
|
+
entryId,
|
|
205
|
+
workspace: validated.workspace,
|
|
206
|
+
revision: Number(input.revision),
|
|
207
|
+
kind: validated.kind,
|
|
208
|
+
title: validated.title,
|
|
209
|
+
body: validated.body,
|
|
210
|
+
summary: validated.summary,
|
|
211
|
+
scope: decodedScope.canonicalScope,
|
|
212
|
+
provenance: validated.provenance,
|
|
213
|
+
tags: validated.tags,
|
|
214
|
+
contentHash,
|
|
215
|
+
createdBy,
|
|
216
|
+
createdAt,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function decodedStoredEntry(input, revision) {
|
|
220
|
+
const id = storedNonEmptyString(input.id);
|
|
221
|
+
const workspace = storedNonEmptyString(input.workspace);
|
|
222
|
+
const createdBy = storedNonEmptyString(input.createdBy);
|
|
223
|
+
const createdAt = storedNonEmptyString(input.createdAt);
|
|
224
|
+
const updatedAt = storedNonEmptyString(input.updatedAt);
|
|
225
|
+
if (id !== revision.entryId || workspace !== revision.workspace
|
|
226
|
+
|| !Number.isSafeInteger(input.currentRevision) || input.currentRevision !== revision.revision
|
|
227
|
+
|| input.minRevision !== 1
|
|
228
|
+
|| !Number.isSafeInteger(input.maxRevision) || input.currentRevision !== input.maxRevision
|
|
229
|
+
|| !Number.isSafeInteger(input.revisionCount) || input.revisionCount !== input.maxRevision
|
|
230
|
+
|| input.invalidRevisionCount !== 0
|
|
231
|
+
|| typeof input.status !== 'string' || !ENTRY_STATUSES.includes(input.status)
|
|
232
|
+
|| typeof input.trustLevel !== 'string' || !TRUST_LEVELS.includes(input.trustLevel)
|
|
233
|
+
|| typeof input.confidence !== 'number' || !Number.isFinite(input.confidence) || input.confidence < 0 || input.confidence > 1
|
|
234
|
+
|| input.supersededBy !== null && (typeof input.supersededBy !== 'string' || input.supersededBy.trim().length === 0)
|
|
235
|
+
|| input.verifiedAt !== null && (typeof input.verifiedAt !== 'string' || input.verifiedAt.trim().length === 0))
|
|
236
|
+
storedIntegrity();
|
|
237
|
+
const status = input.status;
|
|
238
|
+
const supersededBy = input.supersededBy;
|
|
239
|
+
const verifiedAt = input.verifiedAt;
|
|
240
|
+
if ((status === 'superseded') !== (supersededBy !== null)
|
|
241
|
+
|| status === 'candidate' && verifiedAt !== null
|
|
242
|
+
|| status === 'verified' && verifiedAt === null
|
|
243
|
+
|| !canonicalTimestamp(createdAt) || !canonicalTimestamp(updatedAt)
|
|
244
|
+
|| verifiedAt !== null && !canonicalTimestamp(verifiedAt)
|
|
245
|
+
|| createdAt > revision.createdAt || revision.createdAt > updatedAt
|
|
246
|
+
|| createdAt > updatedAt
|
|
247
|
+
|| verifiedAt !== null && (verifiedAt < createdAt || verifiedAt > updatedAt))
|
|
248
|
+
storedIntegrity();
|
|
249
|
+
return {
|
|
250
|
+
id,
|
|
251
|
+
workspace,
|
|
252
|
+
status,
|
|
253
|
+
trustLevel: input.trustLevel,
|
|
254
|
+
confidence: input.confidence,
|
|
255
|
+
currentRevision: input.currentRevision,
|
|
256
|
+
supersededBy,
|
|
257
|
+
createdBy,
|
|
258
|
+
createdAt,
|
|
259
|
+
updatedAt,
|
|
260
|
+
verifiedAt,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
/** Decode persisted entry/revision data without trusting TypeScript row casts. */
|
|
264
|
+
export function decodeStoredMemoryRow(input) {
|
|
265
|
+
const revision = normalizedStoredRecord(input.revision, input.tags, input.options ?? {});
|
|
266
|
+
if (input.entry === undefined)
|
|
267
|
+
return { revision };
|
|
268
|
+
return { revision, entry: decodedStoredEntry(input.entry, revision) };
|
|
269
|
+
}
|
|
14
270
|
function revisionKey(input) {
|
|
15
271
|
if (typeof input.entryId !== 'string' || input.entryId.length === 0) {
|
|
16
272
|
throw new KiokukoError('VALIDATION_ERROR', 'entryId must be a non-empty string');
|
|
@@ -20,37 +276,267 @@ function revisionKey(input) {
|
|
|
20
276
|
throw new KiokukoError('VALIDATION_ERROR', 'revision must be a positive integer');
|
|
21
277
|
}
|
|
22
278
|
}
|
|
279
|
+
function completeRevisionChain(row) {
|
|
280
|
+
return Number.isSafeInteger(row.current_revision)
|
|
281
|
+
&& row.min_revision === 1
|
|
282
|
+
&& Number.isSafeInteger(row.max_revision)
|
|
283
|
+
&& row.current_revision === row.max_revision
|
|
284
|
+
&& Number.isSafeInteger(row.revision_count)
|
|
285
|
+
&& row.revision_count === row.max_revision
|
|
286
|
+
&& row.invalid_revision_count === 0;
|
|
287
|
+
}
|
|
288
|
+
function ownerRevisionChain(database, entryId) {
|
|
289
|
+
return database.prepare(`
|
|
290
|
+
SELECT e.workspace, e.current_revision,
|
|
291
|
+
MIN(r.revision) AS min_revision,
|
|
292
|
+
MAX(r.revision) AS max_revision,
|
|
293
|
+
COUNT(r.revision) AS revision_count,
|
|
294
|
+
COUNT(CASE
|
|
295
|
+
WHEN r.revision IS NOT NULL
|
|
296
|
+
AND (typeof(r.revision) <> 'integer' OR r.revision < 1)
|
|
297
|
+
THEN 1
|
|
298
|
+
END) AS invalid_revision_count
|
|
299
|
+
FROM entries AS e
|
|
300
|
+
LEFT JOIN entry_revisions AS r ON r.entry_id = e.id
|
|
301
|
+
WHERE e.id = ?
|
|
302
|
+
GROUP BY e.id
|
|
303
|
+
`).get(entryId);
|
|
304
|
+
}
|
|
305
|
+
const REVISION_HASH_ALGORITHM = 'canonical-json-utf16-tags-v1';
|
|
306
|
+
const REVISION_IMMUTABILITY_TRIGGER_SQL = `CREATE TRIGGER entry_revisions_immutable_update
|
|
307
|
+
BEFORE UPDATE ON entry_revisions
|
|
308
|
+
BEGIN
|
|
309
|
+
SELECT RAISE(ABORT, 'entry_revisions are immutable');
|
|
310
|
+
END`;
|
|
311
|
+
function migratableRevision(database, row) {
|
|
312
|
+
const entryId = storedNonEmptyString(row.entry_id);
|
|
313
|
+
const createdBy = storedNonEmptyString(row.created_by);
|
|
314
|
+
const createdAt = storedNonEmptyString(row.created_at);
|
|
315
|
+
if (!canonicalTimestamp(createdAt)
|
|
316
|
+
|| !Number.isSafeInteger(row.revision) || Number(row.revision) < 1
|
|
317
|
+
|| row.summary !== null && typeof row.summary !== 'string')
|
|
318
|
+
storedIntegrity();
|
|
319
|
+
const revision = Number(row.revision);
|
|
320
|
+
const owner = ownerRevisionChain(database, entryId);
|
|
321
|
+
if (owner === undefined || owner.workspace !== row.workspace || !completeRevisionChain(owner))
|
|
322
|
+
storedIntegrity();
|
|
323
|
+
const persistedScope = parseStoredObject(row.scope_json);
|
|
324
|
+
const decodedScope = decodeMigratableStoredStructuredScope(persistedScope);
|
|
325
|
+
const provenance = parseStoredObject(row.provenance_json);
|
|
326
|
+
const persistedTags = database
|
|
327
|
+
.prepare('SELECT tag FROM entry_revision_tags WHERE entry_id = ? AND revision = ? ORDER BY rowid ASC')
|
|
328
|
+
.all(entryId, revision)
|
|
329
|
+
.map((tag) => tag.tag);
|
|
330
|
+
let validated;
|
|
331
|
+
try {
|
|
332
|
+
validated = validateRecordInput({
|
|
333
|
+
workspace: row.workspace,
|
|
334
|
+
kind: row.kind,
|
|
335
|
+
status: 'candidate',
|
|
336
|
+
title: row.title,
|
|
337
|
+
body: row.body,
|
|
338
|
+
summary: row.summary,
|
|
339
|
+
scope: decodedScope.canonicalScope,
|
|
340
|
+
provenance,
|
|
341
|
+
trustLevel: 'user_asserted',
|
|
342
|
+
confidence: 1,
|
|
343
|
+
tags: persistedTags,
|
|
344
|
+
createdBy,
|
|
345
|
+
actor: createdBy,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
catch (error) {
|
|
349
|
+
if (error instanceof KiokukoError && (error.code === 'VALIDATION_ERROR' || error.code === 'SECURITY_REJECTION'))
|
|
350
|
+
storedIntegrity();
|
|
351
|
+
throw error;
|
|
352
|
+
}
|
|
353
|
+
if (validated.tags.length !== persistedTags.length
|
|
354
|
+
|| persistedTags.some((tag) => typeof tag !== 'string'))
|
|
355
|
+
storedIntegrity();
|
|
356
|
+
const hashInput = {
|
|
357
|
+
kind: validated.kind,
|
|
358
|
+
title: validated.title,
|
|
359
|
+
body: validated.body,
|
|
360
|
+
summary: validated.summary,
|
|
361
|
+
scope: validated.scope,
|
|
362
|
+
provenance: validated.provenance,
|
|
363
|
+
tags: validated.tags,
|
|
364
|
+
};
|
|
365
|
+
const canonicalHash = canonicalEntryRevisionContentHash(hashInput);
|
|
366
|
+
const previousHash = row.content_hash;
|
|
367
|
+
if (typeof previousHash !== 'string' || !/^[0-9a-f]{64}$/u.test(previousHash))
|
|
368
|
+
storedIntegrity();
|
|
369
|
+
if (previousHash !== canonicalHash) {
|
|
370
|
+
const legacyPayload = {
|
|
371
|
+
kind: hashInput.kind,
|
|
372
|
+
title: hashInput.title,
|
|
373
|
+
body: hashInput.body,
|
|
374
|
+
summary: hashInput.summary,
|
|
375
|
+
provenance: hashInput.provenance,
|
|
376
|
+
tags: persistedTags,
|
|
377
|
+
};
|
|
378
|
+
const canonicalScopeLegacyHash = canonicalContentHash({
|
|
379
|
+
...legacyPayload,
|
|
380
|
+
scope: hashInput.scope,
|
|
381
|
+
});
|
|
382
|
+
const persistedScopeLegacyHash = canonicalContentHash({
|
|
383
|
+
...legacyPayload,
|
|
384
|
+
scope: decodedScope.persistedScope,
|
|
385
|
+
});
|
|
386
|
+
if (previousHash !== canonicalScopeLegacyHash && previousHash !== persistedScopeLegacyHash)
|
|
387
|
+
storedIntegrity();
|
|
388
|
+
}
|
|
389
|
+
return {
|
|
390
|
+
entryId,
|
|
391
|
+
workspace: validated.workspace,
|
|
392
|
+
revision,
|
|
393
|
+
previousScopeJson: row.scope_json,
|
|
394
|
+
previousHash,
|
|
395
|
+
canonicalScopeJson: canonicalJson(validated.scope),
|
|
396
|
+
canonicalHash,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* One-time migration operation for migration 009. This is the only place that
|
|
401
|
+
* recognizes the released locale-dependent hash preimage. The caller must own
|
|
402
|
+
* the migration transaction; any invalid preimage or canonical collision
|
|
403
|
+
* aborts the whole schema upgrade.
|
|
404
|
+
*/
|
|
405
|
+
export function canonicalizeEntryRevisionHashesInMigration(database) {
|
|
406
|
+
const formatTable = database.prepare(`
|
|
407
|
+
SELECT type
|
|
408
|
+
FROM sqlite_schema
|
|
409
|
+
WHERE name = 'entry_revision_hash_format'
|
|
410
|
+
`).get();
|
|
411
|
+
const existingFormat = formatTable?.type === 'table'
|
|
412
|
+
? database.prepare('SELECT singleton, algorithm FROM entry_revision_hash_format').all()
|
|
413
|
+
: [];
|
|
414
|
+
if (formatTable?.type !== 'table' || existingFormat.length !== 0)
|
|
415
|
+
storedIntegrity();
|
|
416
|
+
const trigger = database.prepare(`
|
|
417
|
+
SELECT sql
|
|
418
|
+
FROM sqlite_schema
|
|
419
|
+
WHERE type = 'trigger' AND name = 'entry_revisions_immutable_update'
|
|
420
|
+
`).get();
|
|
421
|
+
if (trigger?.sql !== REVISION_IMMUTABILITY_TRIGGER_SQL)
|
|
422
|
+
storedIntegrity();
|
|
423
|
+
const rows = database.prepare(`
|
|
424
|
+
SELECT entry_id, workspace, revision, kind, title, body, summary,
|
|
425
|
+
scope_json, provenance_json, content_hash, created_by, created_at
|
|
426
|
+
FROM entry_revisions
|
|
427
|
+
ORDER BY entry_id, revision
|
|
428
|
+
`).all();
|
|
429
|
+
const entries = database.prepare('SELECT id, workspace FROM entries ORDER BY id')
|
|
430
|
+
.all();
|
|
431
|
+
for (const entry of entries) {
|
|
432
|
+
const entryId = storedNonEmptyString(entry.id);
|
|
433
|
+
const workspace = storedNonEmptyString(entry.workspace);
|
|
434
|
+
const owner = ownerRevisionChain(database, entryId);
|
|
435
|
+
if (owner === undefined || owner.workspace !== workspace || !completeRevisionChain(owner))
|
|
436
|
+
storedIntegrity();
|
|
437
|
+
}
|
|
438
|
+
const updates = rows.map((row) => migratableRevision(database, row));
|
|
439
|
+
const canonicalIdentities = new Set();
|
|
440
|
+
for (const update of updates) {
|
|
441
|
+
const identity = `${update.workspace}\u0000${update.canonicalHash}`;
|
|
442
|
+
if (canonicalIdentities.has(identity)) {
|
|
443
|
+
throw new KiokukoError('INTEGRITY_ERROR', 'Stored revisions collide under the canonical revision hash');
|
|
444
|
+
}
|
|
445
|
+
canonicalIdentities.add(identity);
|
|
446
|
+
}
|
|
447
|
+
const changed = updates.filter((update) => update.previousHash !== update.canonicalHash
|
|
448
|
+
|| update.previousScopeJson !== update.canonicalScopeJson);
|
|
449
|
+
if (changed.length > 0) {
|
|
450
|
+
database.exec('DROP TRIGGER entry_revisions_immutable_update');
|
|
451
|
+
const park = database.prepare(`
|
|
452
|
+
UPDATE entry_revisions
|
|
453
|
+
SET content_hash = ?
|
|
454
|
+
WHERE entry_id = ? AND revision = ? AND scope_json = ? AND content_hash = ?
|
|
455
|
+
`);
|
|
456
|
+
const install = database.prepare(`
|
|
457
|
+
UPDATE entry_revisions
|
|
458
|
+
SET scope_json = ?, content_hash = ?
|
|
459
|
+
WHERE entry_id = ? AND revision = ? AND content_hash = ?
|
|
460
|
+
`);
|
|
461
|
+
for (const [index, update] of changed.entries()) {
|
|
462
|
+
const temporaryHash = `migration-009:${index}`;
|
|
463
|
+
park.run(temporaryHash, update.entryId, update.revision, update.previousScopeJson, update.previousHash);
|
|
464
|
+
if (database.prepare('SELECT changes() AS changes').get()?.changes !== 1)
|
|
465
|
+
storedIntegrity();
|
|
466
|
+
}
|
|
467
|
+
for (const [index, update] of changed.entries()) {
|
|
468
|
+
install.run(update.canonicalScopeJson, update.canonicalHash, update.entryId, update.revision, `migration-009:${index}`);
|
|
469
|
+
if (database.prepare('SELECT changes() AS changes').get()?.changes !== 1)
|
|
470
|
+
storedIntegrity();
|
|
471
|
+
}
|
|
472
|
+
database.exec(REVISION_IMMUTABILITY_TRIGGER_SQL);
|
|
473
|
+
}
|
|
474
|
+
database.prepare('INSERT INTO entry_revision_hash_format (singleton, algorithm) VALUES (1, ?)')
|
|
475
|
+
.run(REVISION_HASH_ALGORITHM);
|
|
476
|
+
return { inspected: updates.length, rewritten: changed.length };
|
|
477
|
+
}
|
|
23
478
|
function tagsFor(database, entryId, revision) {
|
|
24
479
|
return database
|
|
25
480
|
.prepare('SELECT tag FROM entry_revision_tags WHERE entry_id = ? AND revision = ? ORDER BY tag ASC')
|
|
26
481
|
.all(entryId, revision)
|
|
27
482
|
.map((row) => row.tag);
|
|
28
483
|
}
|
|
29
|
-
function rowToRevision(database, row) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
484
|
+
function rowToRevision(database, row, checkOwnerChronology = true) {
|
|
485
|
+
const entryId = storedNonEmptyString(row.entry_id);
|
|
486
|
+
if (!Number.isSafeInteger(row.revision))
|
|
487
|
+
storedIntegrity();
|
|
488
|
+
const tags = tagsFor(database, entryId, Number(row.revision));
|
|
489
|
+
const decoded = decodeStoredMemoryRow({
|
|
490
|
+
revision: {
|
|
491
|
+
entryId,
|
|
492
|
+
workspace: row.workspace,
|
|
493
|
+
revision: row.revision,
|
|
494
|
+
kind: row.kind,
|
|
495
|
+
title: row.title,
|
|
496
|
+
body: row.body,
|
|
497
|
+
summary: row.summary,
|
|
498
|
+
scopeJson: row.scope_json,
|
|
499
|
+
provenanceJson: row.provenance_json,
|
|
500
|
+
contentHash: row.content_hash,
|
|
501
|
+
createdBy: row.created_by,
|
|
502
|
+
createdAt: row.created_at,
|
|
503
|
+
},
|
|
504
|
+
tags,
|
|
505
|
+
}).revision;
|
|
506
|
+
if (checkOwnerChronology) {
|
|
507
|
+
const owner = database.prepare(`
|
|
508
|
+
SELECT e.created_at, e.updated_at, e.current_revision,
|
|
509
|
+
(SELECT MIN(all_revisions.revision)
|
|
510
|
+
FROM entry_revisions AS all_revisions
|
|
511
|
+
WHERE all_revisions.entry_id = e.id) AS min_revision,
|
|
512
|
+
(SELECT MAX(all_revisions.revision)
|
|
513
|
+
FROM entry_revisions AS all_revisions
|
|
514
|
+
WHERE all_revisions.entry_id = e.id) AS max_revision,
|
|
515
|
+
(SELECT COUNT(all_revisions.revision)
|
|
516
|
+
FROM entry_revisions AS all_revisions
|
|
517
|
+
WHERE all_revisions.entry_id = e.id) AS revision_count,
|
|
518
|
+
(SELECT COUNT(*)
|
|
519
|
+
FROM entry_revisions AS all_revisions
|
|
520
|
+
WHERE all_revisions.entry_id = e.id
|
|
521
|
+
AND (typeof(all_revisions.revision) <> 'integer' OR all_revisions.revision < 1)) AS invalid_revision_count
|
|
522
|
+
FROM entries AS e
|
|
523
|
+
WHERE e.id = ? AND e.workspace = ?
|
|
524
|
+
`).get(decoded.entryId, decoded.workspace);
|
|
525
|
+
if (owner === undefined || !canonicalTimestamp(owner.created_at) || !canonicalTimestamp(owner.updated_at)
|
|
526
|
+
|| !completeRevisionChain({ workspace: decoded.workspace, ...owner })
|
|
527
|
+
|| owner.created_at > decoded.createdAt || decoded.createdAt > owner.updated_at)
|
|
528
|
+
storedIntegrity();
|
|
529
|
+
}
|
|
530
|
+
return decoded;
|
|
45
531
|
}
|
|
46
|
-
function selectRevision(database, input) {
|
|
532
|
+
function selectRevision(database, input, checkOwnerChronology = true) {
|
|
47
533
|
const row = database.prepare(`
|
|
48
534
|
SELECT entry_id, workspace, revision, kind, title, body, summary,
|
|
49
535
|
scope_json, provenance_json, content_hash, created_by, created_at
|
|
50
536
|
FROM entry_revisions
|
|
51
537
|
WHERE entry_id = ? AND workspace = ? AND revision = ?
|
|
52
538
|
`).get(input.entryId, input.workspace, input.revision);
|
|
53
|
-
return row === undefined ? undefined : rowToRevision(database, row);
|
|
539
|
+
return row === undefined ? undefined : rowToRevision(database, row, checkOwnerChronology);
|
|
54
540
|
}
|
|
55
541
|
export function readEntryRevision(database, input) {
|
|
56
542
|
revisionKey(input);
|
|
@@ -68,11 +554,28 @@ export function insertEntryRevisionInTransaction(database, input) {
|
|
|
68
554
|
if (typeof input.createdBy !== 'string' || input.createdBy.length === 0 || typeof input.createdAt !== 'string' || input.createdAt.length === 0) {
|
|
69
555
|
throw new KiokukoError('VALIDATION_ERROR', 'Revision creator and timestamp are required');
|
|
70
556
|
}
|
|
71
|
-
const owner = database
|
|
557
|
+
const owner = ownerRevisionChain(database, input.entryId);
|
|
72
558
|
if (owner === undefined)
|
|
73
559
|
throw new KiokukoError('NOT_FOUND', 'Entry not found');
|
|
74
560
|
if (owner.workspace !== input.workspace)
|
|
75
561
|
throw new KiokukoError('NOT_FOUND', 'Entry does not belong to workspace');
|
|
562
|
+
let nextRevision;
|
|
563
|
+
if (owner.revision_count === 0) {
|
|
564
|
+
if (owner.min_revision !== null || owner.max_revision !== null || owner.current_revision !== 1)
|
|
565
|
+
storedIntegrity();
|
|
566
|
+
nextRevision = 1;
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
if (!completeRevisionChain(owner))
|
|
570
|
+
storedIntegrity();
|
|
571
|
+
nextRevision = Number(owner.max_revision) + 1;
|
|
572
|
+
}
|
|
573
|
+
if (input.revision !== nextRevision) {
|
|
574
|
+
throw new KiokukoError('CONFLICT', 'Entry revision must be the exact next revision', {
|
|
575
|
+
expectedRevision: nextRevision,
|
|
576
|
+
actualRevision: input.revision,
|
|
577
|
+
});
|
|
578
|
+
}
|
|
76
579
|
const validated = validateRecordInput({
|
|
77
580
|
workspace: input.workspace,
|
|
78
581
|
kind: input.kind,
|
|
@@ -85,12 +588,13 @@ export function insertEntryRevisionInTransaction(database, input) {
|
|
|
85
588
|
createdBy: input.createdBy,
|
|
86
589
|
actor: input.createdBy,
|
|
87
590
|
});
|
|
88
|
-
const
|
|
591
|
+
const canonicalScope = normalizeStructuredScopeInput(validated.scope);
|
|
592
|
+
const contentHash = canonicalEntryRevisionContentHash({
|
|
89
593
|
kind: validated.kind,
|
|
90
594
|
title: validated.title,
|
|
91
595
|
body: validated.body,
|
|
92
596
|
summary: validated.summary,
|
|
93
|
-
scope:
|
|
597
|
+
scope: canonicalScope,
|
|
94
598
|
provenance: validated.provenance,
|
|
95
599
|
tags: validated.tags,
|
|
96
600
|
});
|
|
@@ -103,18 +607,18 @@ export function insertEntryRevisionInTransaction(database, input) {
|
|
|
103
607
|
entry_id, workspace, revision, kind, title, body, summary, scope_json,
|
|
104
608
|
provenance_json, content_hash, created_by, created_at
|
|
105
609
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
106
|
-
`).run(input.entryId, input.workspace, input.revision, validated.kind, validated.title, validated.body, validated.summary, canonicalJson(
|
|
107
|
-
for (const tag of validated.tags) {
|
|
108
|
-
database.prepare('INSERT INTO entry_revision_tags (entry_id, revision, tag) VALUES (?, ?, ?)').run(input.entryId, input.revision, tag);
|
|
109
|
-
}
|
|
610
|
+
`).run(input.entryId, input.workspace, input.revision, validated.kind, validated.title, validated.body, validated.summary, canonicalJson(canonicalScope), canonicalJson(validated.provenance), contentHash, input.createdBy, input.createdAt);
|
|
110
611
|
}
|
|
111
612
|
catch (error) {
|
|
112
|
-
if (
|
|
613
|
+
if (isExpectedRevisionConflict(error)) {
|
|
113
614
|
throw new KiokukoError('CONFLICT', 'Entry revision or content already exists');
|
|
114
615
|
}
|
|
115
616
|
throw error;
|
|
116
617
|
}
|
|
117
|
-
const
|
|
618
|
+
for (const tag of validated.tags) {
|
|
619
|
+
database.prepare('INSERT INTO entry_revision_tags (entry_id, revision, tag) VALUES (?, ?, ?)').run(input.entryId, input.revision, tag);
|
|
620
|
+
}
|
|
621
|
+
const result = selectRevision(database, input, false);
|
|
118
622
|
if (result === undefined)
|
|
119
623
|
throw new KiokukoError('INTEGRITY_ERROR', 'Inserted entry revision could not be read back');
|
|
120
624
|
return result;
|