oh-my-second-brain 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +89 -0
- package/README.ko.md +127 -0
- package/README.md +128 -0
- package/adapters/README.md +8 -8
- package/adapters/claude-code/.claude-plugin/plugin.json +3 -2
- package/adapters/claude-code/.mcp.json +8 -0
- package/adapters/claude-code/CLAUDE.md +5 -6
- package/adapters/claude-code/skills/compile/SKILL.md +10 -35
- package/adapters/claude-code/skills/distill/SKILL.md +6 -26
- package/adapters/claude-code/skills/link/SKILL.md +87 -0
- package/adapters/claude-code/skills/retrieve/SKILL.md +4 -7
- package/adapters/claude-code/skills/setup/SKILL.md +5 -6
- package/adapters/claude-code/skills/uninstall/SKILL.md +1 -1
- package/adapters/claude-code/skills/wiki/SKILL.md +49 -24
- package/adapters/claude-code/skills/write/SKILL.md +16 -0
- package/adapters/codex/.codex-plugin/plugin.json +1 -1
- package/adapters/codex/AGENTS.md +2 -2
- package/adapters/codex/rules/oms.md +1 -1
- package/adapters/codex/skills/oms-compile/SKILL.md +7 -9
- package/adapters/codex/skills/oms-distill/SKILL.md +4 -9
- package/adapters/codex/skills/oms-link/SKILL.md +35 -0
- package/adapters/codex/skills/oms-retrieve/SKILL.md +5 -6
- package/adapters/codex/skills/oms-wiki/SKILL.md +28 -8
- package/adapters/codex/skills/oms-write/SKILL.md +10 -0
- package/adapters/hermes/README.md +3 -1
- package/adapters/hermes/SOUL.md +2 -3
- package/adapters/hermes/manifest.json +1 -1
- package/adapters/hermes/skills/compile/SKILL.md +5 -7
- package/adapters/hermes/skills/distill/SKILL.md +1 -3
- package/adapters/hermes/skills/link/SKILL.md +18 -0
- package/adapters/hermes/skills/retrieve/SKILL.md +5 -6
- package/adapters/hermes/skills/setup/SKILL.md +5 -2
- package/adapters/hermes/skills/wiki/SKILL.md +4 -2
- package/adapters/hermes/skills/write/SKILL.md +10 -0
- package/core/AGENTS.md +4 -2
- package/core/agents/librarian.md +3 -2
- package/core/ontology/concepts/term.yaml +12 -0
- package/core/ontology/taxonomy.yaml +3 -0
- package/core/skills/compile/SKILL.md +19 -18
- package/core/skills/distill/SKILL.md +13 -24
- package/core/skills/link/SKILL.md +130 -0
- package/core/skills/retrieve/SKILL.md +0 -1
- package/core/skills/setup/SKILL.md +12 -14
- package/core/skills/vault-lint/SKILL.md +1 -1
- package/core/skills/wiki/SKILL.md +109 -30
- package/core/skills/write/SKILL.md +15 -0
- package/dist/capture/safe.d.ts +61 -1
- package/dist/capture/safe.js +489 -66
- package/dist/capture/safe.js.map +1 -1
- package/dist/cli/args.d.ts +29 -0
- package/dist/cli/args.js +156 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/audit.d.ts +6 -0
- package/dist/cli/audit.js +93 -0
- package/dist/cli/audit.js.map +1 -0
- package/dist/cli/claude-install-plan.d.ts +10 -0
- package/dist/cli/claude-install-plan.js +26 -0
- package/dist/cli/claude-install-plan.js.map +1 -0
- package/dist/cli/doctor-lint.d.ts +11 -0
- package/dist/cli/doctor-lint.js +86 -0
- package/dist/cli/doctor-lint.js.map +1 -0
- package/dist/cli/global-writeback.d.ts +31 -0
- package/dist/cli/global-writeback.js +73 -0
- package/dist/cli/global-writeback.js.map +1 -0
- package/dist/cli/host-commands.d.ts +30 -0
- package/dist/cli/host-commands.js +89 -0
- package/dist/cli/host-commands.js.map +1 -0
- package/dist/cli/link-command.d.ts +9 -0
- package/dist/cli/link-command.js +47 -0
- package/dist/cli/link-command.js.map +1 -0
- package/dist/cli/linkify.d.ts +23 -0
- package/dist/cli/linkify.js +118 -0
- package/dist/cli/linkify.js.map +1 -0
- package/dist/cli/oms.d.ts +8 -32
- package/dist/cli/oms.js +100 -703
- package/dist/cli/oms.js.map +1 -1
- package/dist/cli/semantic-args.d.ts +1 -2
- package/dist/cli/semantic-args.js +4 -7
- package/dist/cli/semantic-args.js.map +1 -1
- package/dist/cli/semantic-http.d.ts +0 -3
- package/dist/cli/semantic-http.js +40 -45
- package/dist/cli/semantic-http.js.map +1 -1
- package/dist/cli/semantic-usage.js +10 -9
- package/dist/cli/semantic-usage.js.map +1 -1
- package/dist/cli/semantic.js +99 -137
- package/dist/cli/semantic.js.map +1 -1
- package/dist/cli/setup-command.d.ts +11 -0
- package/dist/cli/setup-command.js +196 -0
- package/dist/cli/setup-command.js.map +1 -0
- package/dist/cli/setup-documents.d.ts +15 -0
- package/dist/cli/setup-documents.js +149 -0
- package/dist/cli/setup-documents.js.map +1 -0
- package/dist/cli/update-notice.d.ts +10 -0
- package/dist/cli/update-notice.js +42 -0
- package/dist/cli/update-notice.js.map +1 -0
- package/dist/cli/usage.d.ts +4 -0
- package/dist/cli/usage.js +102 -0
- package/dist/cli/usage.js.map +1 -0
- package/dist/conventions/lint.js +12 -33
- package/dist/conventions/lint.js.map +1 -1
- package/dist/conventions/report.d.ts +62 -0
- package/dist/conventions/report.js +217 -0
- package/dist/conventions/report.js.map +1 -0
- package/dist/conventions/validate.d.ts +1 -1
- package/dist/conventions/vault-walk.d.ts +38 -0
- package/dist/conventions/vault-walk.js +80 -0
- package/dist/conventions/vault-walk.js.map +1 -0
- package/dist/conventions/write-contract.d.ts +27 -0
- package/dist/conventions/write-contract.js +91 -0
- package/dist/conventions/write-contract.js.map +1 -0
- package/dist/conventions/write-protocol.d.ts +39 -0
- package/dist/conventions/write-protocol.js +44 -0
- package/dist/conventions/write-protocol.js.map +1 -0
- package/dist/core/ontology/loader.d.ts +2 -0
- package/dist/{ontology → core/ontology}/loader.js +11 -20
- package/dist/core/ontology/loader.js.map +1 -0
- package/dist/core/ontology/resolver.d.ts +2 -0
- package/dist/{ontology → core/ontology}/resolver.js +1 -15
- package/dist/core/ontology/resolver.js.map +1 -0
- package/dist/core/ontology/types.d.ts +47 -0
- package/dist/core/ontology/types.js +2 -0
- package/dist/core/ontology/types.js.map +1 -0
- package/dist/core/runtime/assets.d.ts +20 -0
- package/dist/core/runtime/assets.js +66 -0
- package/dist/core/runtime/assets.js.map +1 -0
- package/dist/engine/assemble.d.ts +28 -72
- package/dist/engine/assemble.js +77 -61
- package/dist/engine/assemble.js.map +1 -1
- package/dist/engine/conventions/vault-lint.d.ts +30 -2
- package/dist/engine/conventions/vault-lint.js +93 -97
- package/dist/engine/conventions/vault-lint.js.map +1 -1
- package/dist/engine/embed/deferred.d.ts +3 -4
- package/dist/engine/embed/deferred.js +10 -7
- package/dist/engine/embed/deferred.js.map +1 -1
- package/dist/engine/embed/identity.d.ts +11 -0
- package/dist/engine/embed/identity.js +15 -0
- package/dist/engine/embed/identity.js.map +1 -0
- package/dist/engine/embed/provider.d.ts +12 -13
- package/dist/engine/embed/provider.js +30 -27
- package/dist/engine/embed/provider.js.map +1 -1
- package/dist/engine/embed/store.d.ts +48 -27
- package/dist/engine/embed/store.js +281 -98
- package/dist/engine/embed/store.js.map +1 -1
- package/dist/engine/embed/sync.d.ts +17 -47
- package/dist/engine/embed/sync.js +233 -69
- package/dist/engine/embed/sync.js.map +1 -1
- package/dist/engine/graph/builder.d.ts +1 -1
- package/dist/engine/graph/builder.js +1 -1
- package/dist/engine/graph/explore.d.ts +2 -2
- package/dist/engine/graph/explore.js +0 -0
- package/dist/engine/graph/resolver.d.ts +17 -0
- package/dist/engine/graph/resolver.js +46 -11
- package/dist/engine/graph/resolver.js.map +1 -1
- package/dist/engine/linkify/apply.d.ts +56 -0
- package/dist/engine/linkify/apply.js +65 -0
- package/dist/engine/linkify/apply.js.map +1 -0
- package/dist/engine/linkify/josa.d.ts +58 -0
- package/dist/engine/linkify/josa.js +133 -0
- package/dist/engine/linkify/josa.js.map +1 -0
- package/dist/engine/linkify/mask.d.ts +29 -0
- package/dist/engine/linkify/mask.js +173 -0
- package/dist/engine/linkify/mask.js.map +1 -0
- package/dist/engine/linkify/suggest.d.ts +52 -0
- package/dist/engine/linkify/suggest.js +181 -0
- package/dist/engine/linkify/suggest.js.map +1 -0
- package/dist/engine/linkify/types.d.ts +68 -0
- package/dist/engine/linkify/types.js +12 -0
- package/dist/engine/linkify/types.js.map +1 -0
- package/dist/engine/mcp/facade.d.ts +12 -18
- package/dist/engine/mcp/facade.js +30 -80
- package/dist/engine/mcp/facade.js.map +1 -1
- package/dist/engine/mcp/op-mappers.d.ts +3 -9
- package/dist/engine/mcp/op-mappers.js +2 -30
- package/dist/engine/mcp/op-mappers.js.map +1 -1
- package/dist/engine/mcp/types.d.ts +5 -29
- package/dist/engine/tracer.js +6 -2
- package/dist/engine/tracer.js.map +1 -1
- package/dist/engine/types.d.ts +8 -3
- package/dist/graph/cache.d.ts +1 -11
- package/dist/graph/cache.js +1 -44
- package/dist/graph/cache.js.map +1 -1
- package/dist/graph/explore.js +88 -137
- package/dist/graph/explore.js.map +1 -1
- package/dist/harness/surface-registry.d.ts +56 -0
- package/dist/harness/surface-registry.js +397 -0
- package/dist/harness/surface-registry.js.map +1 -0
- package/dist/harness/validation.d.ts +9 -0
- package/dist/harness/validation.js +201 -0
- package/dist/harness/validation.js.map +1 -0
- package/dist/hook/post-tool-use.js +2 -2
- package/dist/hook/post-tool-use.js.map +1 -1
- package/dist/index.d.ts +7 -5
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/install/adapter-source.d.ts +14 -0
- package/dist/install/adapter-source.js +45 -0
- package/dist/install/adapter-source.js.map +1 -0
- package/dist/install/claude-hooks.d.ts +13 -0
- package/dist/install/claude-hooks.js +411 -0
- package/dist/install/claude-hooks.js.map +1 -0
- package/dist/install/claude-marketplace.d.ts +44 -0
- package/dist/install/claude-marketplace.js +89 -0
- package/dist/install/claude-marketplace.js.map +1 -0
- package/dist/install/claude.d.ts +4 -0
- package/dist/install/claude.js +216 -0
- package/dist/install/claude.js.map +1 -0
- package/dist/install/codex.d.ts +24 -0
- package/dist/install/codex.js +193 -0
- package/dist/install/codex.js.map +1 -0
- package/dist/install/common.d.ts +34 -0
- package/dist/install/common.js +122 -0
- package/dist/install/common.js.map +1 -0
- package/dist/install/hermes.d.ts +4 -0
- package/dist/install/hermes.js +78 -0
- package/dist/install/hermes.js.map +1 -0
- package/dist/install/hosts.d.ts +6 -56
- package/dist/install/hosts.js +65 -610
- package/dist/install/hosts.js.map +1 -1
- package/dist/install/types.d.ts +34 -0
- package/dist/install/types.js +2 -0
- package/dist/install/types.js.map +1 -0
- package/dist/link/convention-note.d.ts +10 -0
- package/dist/link/convention-note.js +59 -0
- package/dist/link/convention-note.js.map +1 -0
- package/dist/link/global-config.d.ts +22 -0
- package/dist/link/global-config.js +69 -0
- package/dist/link/global-config.js.map +1 -0
- package/dist/link/link.d.ts +101 -0
- package/dist/link/link.js +265 -0
- package/dist/link/link.js.map +1 -0
- package/dist/mcp/engine-morning-backend.d.ts +12 -17
- package/dist/mcp/engine-morning-backend.js +25 -131
- package/dist/mcp/engine-morning-backend.js.map +1 -1
- package/dist/mcp/link-tools.d.ts +81 -0
- package/dist/mcp/link-tools.js +157 -0
- package/dist/mcp/link-tools.js.map +1 -0
- package/dist/mcp/semantic-engine.d.ts +32 -0
- package/dist/mcp/semantic-engine.js +52 -0
- package/dist/mcp/semantic-engine.js.map +1 -0
- package/dist/mcp/semantic-retrieve-args.d.ts +1 -5
- package/dist/mcp/semantic-retrieve-args.js +1 -26
- package/dist/mcp/semantic-retrieve-args.js.map +1 -1
- package/dist/mcp/semantic-retrieve-schema.d.ts +0 -14
- package/dist/mcp/semantic-retrieve-schema.js +0 -5
- package/dist/mcp/semantic-retrieve-schema.js.map +1 -1
- package/dist/mcp/semantic-retrieve.d.ts +12 -18
- package/dist/mcp/semantic-retrieve.js +40 -71
- package/dist/mcp/semantic-retrieve.js.map +1 -1
- package/dist/mcp/semantic-tool-schemas.js +7 -24
- package/dist/mcp/semantic-tool-schemas.js.map +1 -1
- package/dist/mcp/server.d.ts +7 -0
- package/dist/mcp/server.js +224 -162
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/update-notice.d.ts +51 -0
- package/dist/mcp/update-notice.js +196 -0
- package/dist/mcp/update-notice.js.map +1 -0
- package/dist/ontology/active.d.ts +7 -0
- package/dist/ontology/active.js +41 -0
- package/dist/ontology/active.js.map +1 -0
- package/dist/retrieve/morning.d.ts +10 -18
- package/dist/retrieve/morning.js +2 -26
- package/dist/retrieve/morning.js.map +1 -1
- package/dist/retrieve/semantic-contract.d.ts +10 -0
- package/dist/retrieve/semantic-contract.js +2 -0
- package/dist/retrieve/semantic-contract.js.map +1 -0
- package/dist/setup/axis.d.ts +22 -3
- package/dist/setup/axis.js +82 -35
- package/dist/setup/axis.js.map +1 -1
- package/dist/update/update.d.ts +12 -0
- package/dist/update/update.js +2 -2
- package/dist/update/update.js.map +1 -1
- package/docs/install.md +43 -7
- package/docs/release.md +109 -17
- package/package.json +11 -3
- package/scripts/install.sh +1 -1
- package/adapters/claude-code/skills/capture/SKILL.md +0 -50
- package/adapters/codex/skills/oms-capture/SKILL.md +0 -16
- package/adapters/hermes/skills/capture/SKILL.md +0 -16
- package/core/skills/capture/SKILL.md +0 -50
- package/dist/adapt/HostAdapter.d.ts +0 -21
- package/dist/adapt/HostAdapter.js +0 -10
- package/dist/adapt/HostAdapter.js.map +0 -1
- package/dist/adapt/claudeCode.d.ts +0 -9
- package/dist/adapt/claudeCode.js +0 -15
- package/dist/adapt/claudeCode.js.map +0 -1
- package/dist/adapt/codex.d.ts +0 -9
- package/dist/adapt/codex.js +0 -15
- package/dist/adapt/codex.js.map +0 -1
- package/dist/adapt/hermes.d.ts +0 -9
- package/dist/adapt/hermes.js +0 -15
- package/dist/adapt/hermes.js.map +0 -1
- package/dist/cli/semantic-metadata-commands.d.ts +0 -3
- package/dist/cli/semantic-metadata-commands.js +0 -115
- package/dist/cli/semantic-metadata-commands.js.map +0 -1
- package/dist/engine/compile/cascade.d.ts +0 -35
- package/dist/engine/compile/cascade.js +0 -59
- package/dist/engine/compile/cascade.js.map +0 -1
- package/dist/engine/compile/cot.d.ts +0 -30
- package/dist/engine/compile/cot.js +0 -153
- package/dist/engine/compile/cot.js.map +0 -1
- package/dist/engine/compile/phases.d.ts +0 -47
- package/dist/engine/compile/phases.js +0 -101
- package/dist/engine/compile/phases.js.map +0 -1
- package/dist/engine/compile/provenance.d.ts +0 -45
- package/dist/engine/compile/provenance.js +0 -103
- package/dist/engine/compile/provenance.js.map +0 -1
- package/dist/engine/compile/sha-cache.d.ts +0 -42
- package/dist/engine/compile/sha-cache.js +0 -86
- package/dist/engine/compile/sha-cache.js.map +0 -1
- package/dist/engine/compile/types.d.ts +0 -71
- package/dist/engine/compile/types.js +0 -9
- package/dist/engine/compile/types.js.map +0 -1
- package/dist/engine/compile/worker.d.ts +0 -47
- package/dist/engine/compile/worker.js +0 -75
- package/dist/engine/compile/worker.js.map +0 -1
- package/dist/engine/distill/analyzer.d.ts +0 -51
- package/dist/engine/distill/analyzer.js +0 -279
- package/dist/engine/distill/analyzer.js.map +0 -1
- package/dist/engine/distill/clean-room.d.ts +0 -46
- package/dist/engine/distill/clean-room.js +0 -131
- package/dist/engine/distill/clean-room.js.map +0 -1
- package/dist/engine/distill/report.d.ts +0 -23
- package/dist/engine/distill/report.js +0 -107
- package/dist/engine/distill/report.js.map +0 -1
- package/dist/engine/distill/types.d.ts +0 -89
- package/dist/engine/distill/types.js +0 -9
- package/dist/engine/distill/types.js.map +0 -1
- package/dist/engine/embed/pull.d.ts +0 -51
- package/dist/engine/embed/pull.js +0 -90
- package/dist/engine/embed/pull.js.map +0 -1
- package/dist/engine/graph/community.d.ts +0 -38
- package/dist/engine/graph/community.js +0 -122
- package/dist/engine/graph/community.js.map +0 -1
- package/dist/engine/index.d.ts +0 -5
- package/dist/engine/index.js +0 -2
- package/dist/engine/index.js.map +0 -1
- package/dist/engine/mcp/index.d.ts +0 -15
- package/dist/engine/mcp/index.js +0 -19
- package/dist/engine/mcp/index.js.map +0 -1
- package/dist/engine/mcp/retrieve-mapper.d.ts +0 -38
- package/dist/engine/mcp/retrieve-mapper.js +0 -96
- package/dist/engine/mcp/retrieve-mapper.js.map +0 -1
- package/dist/engine/setup/ambiguity.d.ts +0 -39
- package/dist/engine/setup/ambiguity.js +0 -50
- package/dist/engine/setup/ambiguity.js.map +0 -1
- package/dist/engine/setup/types.d.ts +0 -71
- package/dist/engine/setup/types.js +0 -22
- package/dist/engine/setup/types.js.map +0 -1
- package/dist/engine/setup/writer.d.ts +0 -32
- package/dist/engine/setup/writer.js +0 -77
- package/dist/engine/setup/writer.js.map +0 -1
- package/dist/engine/wiki/collection.d.ts +0 -91
- package/dist/engine/wiki/collection.js +0 -188
- package/dist/engine/wiki/collection.js.map +0 -1
- package/dist/engine/wiki/ledger.d.ts +0 -59
- package/dist/engine/wiki/ledger.js +0 -130
- package/dist/engine/wiki/ledger.js.map +0 -1
- package/dist/engine/wiki/lint.d.ts +0 -38
- package/dist/engine/wiki/lint.js +0 -186
- package/dist/engine/wiki/lint.js.map +0 -1
- package/dist/engine/wiki/navigation.d.ts +0 -40
- package/dist/engine/wiki/navigation.js +0 -83
- package/dist/engine/wiki/navigation.js.map +0 -1
- package/dist/engine/wiki/types.d.ts +0 -54
- package/dist/engine/wiki/types.js +0 -7
- package/dist/engine/wiki/types.js.map +0 -1
- package/dist/ontology/loader.d.ts +0 -13
- package/dist/ontology/loader.js.map +0 -1
- package/dist/ontology/resolver.d.ts +0 -13
- package/dist/ontology/resolver.js.map +0 -1
- package/dist/ontology/types.d.ts +0 -72
- package/dist/ontology/types.js +0 -12
- package/dist/ontology/types.js.map +0 -1
- package/dist/retrieve/embedding-sync.d.ts +0 -3
- package/dist/retrieve/embedding-sync.js +0 -21
- package/dist/retrieve/embedding-sync.js.map +0 -1
- package/dist/runtime/assets.d.ts +0 -7
- package/dist/runtime/assets.js +0 -13
- package/dist/runtime/assets.js.map +0 -1
- package/dist/search/semantic-collections.d.ts +0 -32
- package/dist/search/semantic-collections.js +0 -68
- package/dist/search/semantic-collections.js.map +0 -1
- package/dist/search/semantic-contexts.d.ts +0 -21
- package/dist/search/semantic-contexts.js +0 -28
- package/dist/search/semantic-contexts.js.map +0 -1
- package/dist/search/semantic-diagnostics.d.ts +0 -16
- package/dist/search/semantic-diagnostics.js +0 -110
- package/dist/search/semantic-diagnostics.js.map +0 -1
- package/dist/search/semantic-documents.d.ts +0 -3
- package/dist/search/semantic-documents.js +0 -150
- package/dist/search/semantic-documents.js.map +0 -1
- package/dist/search/semantic-embedding-hash.d.ts +0 -3
- package/dist/search/semantic-embedding-hash.js +0 -30
- package/dist/search/semantic-embedding-hash.js.map +0 -1
- package/dist/search/semantic-embedding-provider.d.ts +0 -9
- package/dist/search/semantic-embedding-provider.js +0 -58
- package/dist/search/semantic-embedding-provider.js.map +0 -1
- package/dist/search/semantic-index-build.d.ts +0 -13
- package/dist/search/semantic-index-build.js +0 -101
- package/dist/search/semantic-index-build.js.map +0 -1
- package/dist/search/semantic-index-core.d.ts +0 -21
- package/dist/search/semantic-index-core.js +0 -106
- package/dist/search/semantic-index-core.js.map +0 -1
- package/dist/search/semantic-index-io.d.ts +0 -19
- package/dist/search/semantic-index-io.js +0 -214
- package/dist/search/semantic-index-io.js.map +0 -1
- package/dist/search/semantic-index-types.d.ts +0 -50
- package/dist/search/semantic-index-types.js +0 -2
- package/dist/search/semantic-index-types.js.map +0 -1
- package/dist/search/semantic-index.d.ts +0 -4
- package/dist/search/semantic-index.js +0 -4
- package/dist/search/semantic-index.js.map +0 -1
- package/dist/search/semantic-listing.d.ts +0 -12
- package/dist/search/semantic-listing.js +0 -64
- package/dist/search/semantic-listing.js.map +0 -1
- package/dist/search/semantic-maintenance-shared.d.ts +0 -15
- package/dist/search/semantic-maintenance-shared.js +0 -43
- package/dist/search/semantic-maintenance-shared.js.map +0 -1
- package/dist/search/semantic-maintenance-types.d.ts +0 -103
- package/dist/search/semantic-maintenance-types.js +0 -2
- package/dist/search/semantic-maintenance-types.js.map +0 -1
- package/dist/search/semantic-maintenance.d.ts +0 -4
- package/dist/search/semantic-maintenance.js +0 -5
- package/dist/search/semantic-maintenance.js.map +0 -1
- package/dist/search/semantic-provider-types.d.ts +0 -34
- package/dist/search/semantic-provider-types.js +0 -2
- package/dist/search/semantic-provider-types.js.map +0 -1
- package/dist/search/semantic-query-types.d.ts +0 -83
- package/dist/search/semantic-query-types.js +0 -2
- package/dist/search/semantic-query-types.js.map +0 -1
- package/dist/search/semantic-query.d.ts +0 -2
- package/dist/search/semantic-query.js +0 -188
- package/dist/search/semantic-query.js.map +0 -1
- package/dist/search/semantic-sqlite-db.d.ts +0 -18
- package/dist/search/semantic-sqlite-db.js +0 -87
- package/dist/search/semantic-sqlite-db.js.map +0 -1
- package/dist/search/semantic-sqlite-query.d.ts +0 -2
- package/dist/search/semantic-sqlite-query.js +0 -128
- package/dist/search/semantic-sqlite-query.js.map +0 -1
- package/dist/search/semantic-sqlite-read.d.ts +0 -5
- package/dist/search/semantic-sqlite-read.js +0 -104
- package/dist/search/semantic-sqlite-read.js.map +0 -1
- package/dist/search/semantic-sqlite-write.d.ts +0 -7
- package/dist/search/semantic-sqlite-write.js +0 -66
- package/dist/search/semantic-sqlite-write.js.map +0 -1
- package/dist/search/semantic-store.d.ts +0 -15
- package/dist/search/semantic-store.js +0 -17
- package/dist/search/semantic-store.js.map +0 -1
- package/dist/search/semantic-sync-types.d.ts +0 -47
- package/dist/search/semantic-sync-types.js +0 -2
- package/dist/search/semantic-sync-types.js.map +0 -1
- package/dist/search/semantic-sync.d.ts +0 -13
- package/dist/search/semantic-sync.js +0 -131
- package/dist/search/semantic-sync.js.map +0 -1
- package/dist/search/semantic-test-fixtures.d.ts +0 -1
- package/dist/search/semantic-test-fixtures.js +0 -38
- package/dist/search/semantic-test-fixtures.js.map +0 -1
- package/dist/search/semantic-token.d.ts +0 -25
- package/dist/search/semantic-token.js +0 -114
- package/dist/search/semantic-token.js.map +0 -1
- package/dist/search/semantic-types.d.ts +0 -5
- package/dist/search/semantic-types.js +0 -2
- package/dist/search/semantic-types.js.map +0 -1
- package/dist/search/semantic.d.ts +0 -6
- package/dist/search/semantic.js +0 -6
- package/dist/search/semantic.js.map +0 -1
package/dist/capture/safe.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { mkdir, readFile,
|
|
1
|
+
import { access, appendFile, mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { stringify as yamlStringify } from "yaml";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { parseNote } from "../conventions/frontmatter.js";
|
|
5
|
+
import { evaluateWriteContract, routingLawStrictFolders, writeFieldDescriptors, } from "../conventions/write-contract.js";
|
|
6
|
+
import { rejection, } from "../conventions/write-protocol.js";
|
|
7
|
+
import { resolveConcept } from "../core/ontology/resolver.js";
|
|
6
8
|
function slugify(value) {
|
|
7
9
|
const slug = value
|
|
8
10
|
.toLowerCase()
|
|
@@ -26,12 +28,84 @@ function defaultInboxFolder(ontology) {
|
|
|
26
28
|
const inboxConcept = ontology.concepts.get("inbox");
|
|
27
29
|
return inboxConcept?.folder ?? "inbox";
|
|
28
30
|
}
|
|
29
|
-
function
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
function mergeFrontmatter(base, patch) {
|
|
32
|
+
return { ...base, ...patch };
|
|
33
|
+
}
|
|
34
|
+
function emptyWriteFields() {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
function contractFields(concept) {
|
|
38
|
+
return concept ? writeFieldDescriptors(concept) : emptyWriteFields();
|
|
39
|
+
}
|
|
40
|
+
function writeResult(partial) {
|
|
41
|
+
return partial;
|
|
42
|
+
}
|
|
43
|
+
function inboxResult(mode, ontology, filename, frontmatter, reason) {
|
|
44
|
+
const inbox = defaultInboxFolder(ontology);
|
|
45
|
+
const inboxConcept = findConcept(ontology, "inbox");
|
|
46
|
+
return writeResult({
|
|
47
|
+
status: "inbox",
|
|
48
|
+
mode,
|
|
49
|
+
notePath: `${inbox}/${filename}`,
|
|
50
|
+
concept: "inbox",
|
|
51
|
+
folder: inbox,
|
|
52
|
+
fields: contractFields(inboxConcept),
|
|
53
|
+
frontmatter,
|
|
54
|
+
missingFields: [],
|
|
55
|
+
violations: [],
|
|
56
|
+
reason,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function pathUnsafeRejection(reason) {
|
|
60
|
+
return rejection("admission", "path-unsafe", reason, "pass a vault-relative `notePath` ending in .md that stays inside the vault and avoids hidden or internal folders");
|
|
61
|
+
}
|
|
62
|
+
function conceptUnboundRejection() {
|
|
63
|
+
return rejection("admission", "concept-unbound", "Cannot commit capture: notePath does not resolve to a concept binding", "move the note into a folder bound to a concept in taxonomy.yaml, or target an existing bound note");
|
|
64
|
+
}
|
|
65
|
+
function rejectedResult(mode, notePath, concept, frontmatter, violations, reason, rejectionPayload) {
|
|
66
|
+
return writeResult({
|
|
67
|
+
status: "rejected",
|
|
68
|
+
mode,
|
|
69
|
+
notePath,
|
|
70
|
+
concept: concept?.concept ?? null,
|
|
71
|
+
folder: notePath.split("/")[0] ?? "",
|
|
72
|
+
fields: contractFields(concept),
|
|
73
|
+
frontmatter,
|
|
74
|
+
missingFields: violations.map((violation) => violation.field),
|
|
75
|
+
violations,
|
|
76
|
+
reason,
|
|
77
|
+
...(rejectionPayload ? { rejection: rejectionPayload } : {}),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function askResult(mode, notePath, concept, frontmatter, violations) {
|
|
81
|
+
return writeResult({
|
|
82
|
+
status: "ask",
|
|
83
|
+
mode,
|
|
84
|
+
notePath,
|
|
85
|
+
concept: concept.concept,
|
|
86
|
+
folder: notePath.split("/")[0] ?? concept.folder,
|
|
87
|
+
fields: contractFields(concept),
|
|
88
|
+
frontmatter,
|
|
89
|
+
missingFields: violations.map((violation) => violation.field),
|
|
90
|
+
violations,
|
|
91
|
+
rejection: rejection("admission", "contract-violation", "Capture does not satisfy the concept contract yet", `provide or correct these fields, then retry: ${violations
|
|
92
|
+
.map((violation) => violation.field)
|
|
93
|
+
.join(", ")}`),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function writtenResult(mode, notePath, concept, frontmatter, receipt) {
|
|
97
|
+
return writeResult({
|
|
98
|
+
status: "written",
|
|
99
|
+
mode,
|
|
100
|
+
notePath,
|
|
101
|
+
concept: concept?.concept ?? null,
|
|
102
|
+
folder: notePath.split("/")[0] ?? "",
|
|
103
|
+
fields: contractFields(concept),
|
|
104
|
+
frontmatter,
|
|
105
|
+
missingFields: [],
|
|
106
|
+
violations: [],
|
|
107
|
+
...(receipt ? { receipt } : {}),
|
|
108
|
+
});
|
|
35
109
|
}
|
|
36
110
|
export function safeVaultNotePath(vault, notePath) {
|
|
37
111
|
if (path.isAbsolute(notePath)) {
|
|
@@ -55,6 +129,22 @@ export function safeVaultNotePath(vault, notePath) {
|
|
|
55
129
|
}
|
|
56
130
|
return resolved;
|
|
57
131
|
}
|
|
132
|
+
function trySafeNotePath(vault, notePath) {
|
|
133
|
+
try {
|
|
134
|
+
const fullPath = safeVaultNotePath(vault, notePath);
|
|
135
|
+
return {
|
|
136
|
+
ok: true,
|
|
137
|
+
fullPath,
|
|
138
|
+
normalized: path.relative(vault, fullPath).replace(/\\/g, "/"),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
return {
|
|
143
|
+
ok: false,
|
|
144
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
58
148
|
function safeCaptureFilename(requested, title) {
|
|
59
149
|
if (!requested) {
|
|
60
150
|
return {
|
|
@@ -72,96 +162,429 @@ function safeCaptureFilename(requested, title) {
|
|
|
72
162
|
safe,
|
|
73
163
|
};
|
|
74
164
|
}
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
const resolvedConcept = requestedConcept ?? findConcept(input.ontology, folderConcepts[0]);
|
|
165
|
+
function planCreatePlacement(ontology, conceptName, folderName, filename, frontmatter) {
|
|
166
|
+
const requestedConcept = findConcept(ontology, conceptName);
|
|
167
|
+
const folder = folderName ?? requestedConcept?.folder ?? defaultInboxFolder(ontology);
|
|
168
|
+
const folderConcepts = conceptsForFolder(ontology, folder);
|
|
169
|
+
const resolvedConcept = requestedConcept ?? findConcept(ontology, folderConcepts[0]);
|
|
81
170
|
const titleValue = frontmatter["title"];
|
|
82
171
|
const title = typeof titleValue === "string" ? titleValue : "untitled";
|
|
83
|
-
const filenamePlan = safeCaptureFilename(
|
|
84
|
-
const filename = filenamePlan.filename;
|
|
85
|
-
const notePath = `${folder}/${filename}`;
|
|
172
|
+
const filenamePlan = safeCaptureFilename(filename, title);
|
|
86
173
|
if (!filenamePlan.safe) {
|
|
87
|
-
|
|
174
|
+
return {
|
|
175
|
+
kind: "inbox",
|
|
176
|
+
notePath: `${defaultInboxFolder(ontology)}/${filenamePlan.filename}`,
|
|
177
|
+
concept: findConcept(ontology, "inbox"),
|
|
178
|
+
folder: defaultInboxFolder(ontology),
|
|
179
|
+
filename: filenamePlan.filename,
|
|
180
|
+
reason: "Requested filename was unsafe; planned a safe inbox capture path.",
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
if (!resolvedConcept || !folderConcepts.includes(resolvedConcept.concept)) {
|
|
184
|
+
return {
|
|
185
|
+
kind: "inbox",
|
|
186
|
+
notePath: `${defaultInboxFolder(ontology)}/${filenamePlan.filename}`,
|
|
187
|
+
concept: findConcept(ontology, "inbox"),
|
|
188
|
+
folder: defaultInboxFolder(ontology),
|
|
189
|
+
filename: filenamePlan.filename,
|
|
190
|
+
reason: "No safe folder/concept binding matched the requested capture.",
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
kind: "bound",
|
|
195
|
+
notePath: `${folder}/${filenamePlan.filename}`,
|
|
196
|
+
concept: resolvedConcept,
|
|
197
|
+
folder,
|
|
198
|
+
filename: filenamePlan.filename,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function formatNote(frontmatter, body) {
|
|
202
|
+
return `---\n${yamlStringify(frontmatter).trimEnd()}\n---\n\n${body.trim()}\n`;
|
|
203
|
+
}
|
|
204
|
+
function hasErrorCode(error, code) {
|
|
205
|
+
return error instanceof Error && "code" in error && error.code === code;
|
|
206
|
+
}
|
|
207
|
+
async function fileExists(fullPath) {
|
|
208
|
+
try {
|
|
209
|
+
await access(fullPath);
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
if (hasErrorCode(error, "ENOENT")) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async function isDirectory(fullPath) {
|
|
220
|
+
try {
|
|
221
|
+
return (await stat(fullPath)).isDirectory();
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
if (hasErrorCode(error, "ENOENT") || hasErrorCode(error, "ENOTDIR")) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
export function prepareCapture(input) {
|
|
231
|
+
const frontmatter = input.frontmatter ?? {};
|
|
232
|
+
const planned = planCreatePlacement(input.ontology, input.concept, input.folder, input.filename, frontmatter);
|
|
233
|
+
if (planned.kind === "inbox") {
|
|
88
234
|
return {
|
|
89
235
|
action: "route-to-inbox",
|
|
90
236
|
concept: "inbox",
|
|
91
|
-
folder:
|
|
92
|
-
notePath:
|
|
237
|
+
folder: planned.folder,
|
|
238
|
+
notePath: planned.notePath,
|
|
93
239
|
missingFields: [],
|
|
94
240
|
frontmatter,
|
|
95
|
-
|
|
241
|
+
fields: contractFields(planned.concept),
|
|
242
|
+
violations: [],
|
|
243
|
+
reason: planned.reason,
|
|
96
244
|
};
|
|
97
245
|
}
|
|
98
|
-
|
|
99
|
-
|
|
246
|
+
const concept = planned.concept;
|
|
247
|
+
if (!concept) {
|
|
100
248
|
return {
|
|
101
249
|
action: "route-to-inbox",
|
|
102
250
|
concept: "inbox",
|
|
103
|
-
folder:
|
|
104
|
-
notePath:
|
|
251
|
+
folder: defaultInboxFolder(input.ontology),
|
|
252
|
+
notePath: planned.notePath,
|
|
105
253
|
missingFields: [],
|
|
106
254
|
frontmatter,
|
|
255
|
+
fields: [],
|
|
256
|
+
violations: [],
|
|
107
257
|
reason: "No safe folder/concept binding matched the requested capture.",
|
|
108
258
|
};
|
|
109
259
|
}
|
|
110
|
-
const
|
|
260
|
+
const contract = evaluateWriteContract(frontmatter, concept, planned.notePath, routingLawStrictFolders(input.ontology));
|
|
111
261
|
return {
|
|
112
|
-
action:
|
|
113
|
-
concept:
|
|
114
|
-
folder,
|
|
115
|
-
notePath,
|
|
116
|
-
missingFields,
|
|
262
|
+
action: contract.valid ? "ready" : "ask-missing-fields",
|
|
263
|
+
concept: concept.concept,
|
|
264
|
+
folder: planned.folder,
|
|
265
|
+
notePath: planned.notePath,
|
|
266
|
+
missingFields: contract.violations.map((violation) => violation.field),
|
|
117
267
|
frontmatter,
|
|
268
|
+
fields: contractFields(concept),
|
|
269
|
+
violations: contract.violations,
|
|
118
270
|
};
|
|
119
271
|
}
|
|
120
|
-
|
|
121
|
-
|
|
272
|
+
/**
|
|
273
|
+
* Admission Rules - target verification.
|
|
274
|
+
*
|
|
275
|
+
* Runs before ANY disk mutation. `cwd` resolution is unverified for the write
|
|
276
|
+
* surface (the process may have booted anywhere). A `global` registry pointer
|
|
277
|
+
* must still point at a real `.oms` ontology; every other source is trusted
|
|
278
|
+
* without an ontology presence check so the bundled-ontology fallback keeps
|
|
279
|
+
* working.
|
|
280
|
+
*/
|
|
281
|
+
async function admitTarget(target) {
|
|
282
|
+
if (target.source === "cwd") {
|
|
283
|
+
return rejection("admission", "target-unverified", `Refusing to write: the target vault was inferred from the current directory (${target.vault}), which is not a verified Oh My Second Brain vault`, "run `oms setup` in your Obsidian vault (or set OMS_VAULT / register the vault in ~/.oms/config.yaml), then retry");
|
|
284
|
+
}
|
|
285
|
+
if (target.source === "global") {
|
|
286
|
+
const hasOntology = (await isDirectory(path.join(target.vault, ".oms", "concepts"))) ||
|
|
287
|
+
(await fileExists(path.join(target.vault, ".oms", "taxonomy.yaml")));
|
|
288
|
+
if (!hasOntology) {
|
|
289
|
+
return rejection("admission", "target-invalid", `Refusing to write: the registered global vault target has no .oms ontology: ${target.vault}`, "update ~/.oms/config.yaml to point at your vault, or run `oms setup` in that vault, then retry");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return undefined;
|
|
122
293
|
}
|
|
123
|
-
function
|
|
124
|
-
return
|
|
294
|
+
function targetRejectedResult(mode, input, frontmatter, rejectionPayload) {
|
|
295
|
+
return rejectedResult(mode, input.notePath ?? "", undefined, frontmatter, [], rejectionPayload.message, rejectionPayload);
|
|
125
296
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
297
|
+
/**
|
|
298
|
+
* Acceptance Criteria - staged evaluation (pre-persist).
|
|
299
|
+
*
|
|
300
|
+
* Parses the note content that is ABOUT to be written and re-runs the kernel
|
|
301
|
+
* write contract against the RENDERED frontmatter. This catches divergence
|
|
302
|
+
* between the caller-supplied frontmatter and what actually lands on disk
|
|
303
|
+
* (yaml round-trip artifacts such as `NaN` rendering as `.nan` and parsing
|
|
304
|
+
* back as `null`).
|
|
305
|
+
*/
|
|
306
|
+
export function evaluateStagedNote(stagedContent, concept, notePath, strictZones) {
|
|
307
|
+
const parsed = parseNote(stagedContent);
|
|
308
|
+
const contract = evaluateWriteContract(parsed.frontmatter, concept, notePath, strictZones);
|
|
309
|
+
return {
|
|
310
|
+
ok: contract.valid,
|
|
311
|
+
violations: contract.violations,
|
|
312
|
+
frontmatter: parsed.frontmatter,
|
|
313
|
+
body: parsed.body,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function sameViolationSet(left, right) {
|
|
317
|
+
if (left.length !== right.length) {
|
|
318
|
+
return false;
|
|
132
319
|
}
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
320
|
+
const key = (violation) => `${violation.field}\u0000${violation.rule}\u0000${violation.message}`;
|
|
321
|
+
const leftKeys = left.map(key).sort();
|
|
322
|
+
const rightKeys = right.map(key).sort();
|
|
323
|
+
return leftKeys.every((entry, index) => entry === rightKeys[index]);
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Acceptance rejection for a staged render that diverges from the (already
|
|
327
|
+
* passing) input evaluation. Callers only reach this when the input-level
|
|
328
|
+
* contract check passed, so the violation is a genuine render divergence.
|
|
329
|
+
*/
|
|
330
|
+
function stagedRejectedResult(mode, notePath, concept, frontmatter, violations) {
|
|
331
|
+
const fields = violations.map((violation) => violation.field).join(", ");
|
|
332
|
+
return rejectedResult(mode, notePath, concept, frontmatter, violations, "Cannot write: the rendered note violates the concept contract", rejection("acceptance", "contract-violation", `Staged note render violates the concept contract (${fields})`, `these values do not survive the note render unchanged - correct them, then retry: ${fields}`));
|
|
333
|
+
}
|
|
334
|
+
function stagedBodyMissingResult(mode, notePath, concept, frontmatter) {
|
|
335
|
+
return rejectedResult(mode, notePath, concept, frontmatter, [], "create requires a body", rejection("acceptance", "body-missing", "Staged note render carries no body content", "pass a non-empty `body` for the note, then retry"));
|
|
336
|
+
}
|
|
337
|
+
function postconditionRejectedResult(mode, notePath, fullPath, concept, frontmatter, violations, detail) {
|
|
338
|
+
return rejectedResult(mode, notePath, concept, frontmatter, violations, `Postcondition failed after writing ${notePath}: ${detail}`, rejection("acceptance", "postcondition-failed", `Postcondition failed after writing ${notePath}: ${detail}`, `inspect the persisted file at ${fullPath} (it was NOT removed) and repair or delete it before retrying`));
|
|
339
|
+
}
|
|
340
|
+
function receiptFor(input, mode, notePath, concept) {
|
|
341
|
+
return {
|
|
342
|
+
resolvedVault: input.target.vault,
|
|
343
|
+
resolutionSource: input.target.source,
|
|
344
|
+
notePath,
|
|
345
|
+
mode,
|
|
346
|
+
concept: concept?.concept ?? null,
|
|
347
|
+
postconditionVerified: true,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function normalizeBody(body) {
|
|
351
|
+
return body.replace(/\s+$/, "");
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Acceptance Criteria - postcondition (post-persist).
|
|
355
|
+
*
|
|
356
|
+
* Re-reads the persisted note through the `readBack` seam, re-runs the write
|
|
357
|
+
* contract on what is actually on disk, and asserts the intended body content
|
|
358
|
+
* landed. The persisted file is never auto-deleted on failure.
|
|
359
|
+
*/
|
|
360
|
+
async function verifyPostcondition(input, fullPath, notePath, concept, strictZones, expectation) {
|
|
361
|
+
const read = input.readBack ?? ((target) => readFile(target, "utf-8"));
|
|
362
|
+
const persisted = await read(fullPath);
|
|
363
|
+
const parsed = parseNote(persisted);
|
|
364
|
+
const contract = evaluateWriteContract(parsed.frontmatter, concept, notePath, strictZones);
|
|
365
|
+
if (!contract.valid) {
|
|
366
|
+
return {
|
|
367
|
+
ok: false,
|
|
368
|
+
violations: contract.violations,
|
|
369
|
+
detail: `persisted frontmatter violates the concept contract (${contract.violations
|
|
370
|
+
.map((violation) => violation.field)
|
|
371
|
+
.join(", ")})`,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
const bodyOk = expectation.kind === "full"
|
|
375
|
+
? normalizeBody(parsed.body) === normalizeBody(expectation.body)
|
|
376
|
+
: normalizeBody(persisted).endsWith(expectation.body.trim());
|
|
377
|
+
if (!bodyOk) {
|
|
378
|
+
return { ok: false, violations: [], detail: "persisted body does not match the staged content" };
|
|
379
|
+
}
|
|
380
|
+
return { ok: true, violations: [], detail: "" };
|
|
381
|
+
}
|
|
382
|
+
export async function writeNote(input) {
|
|
383
|
+
const frontmatter = input.frontmatter ?? {};
|
|
384
|
+
const strictZones = routingLawStrictFolders(input.ontology);
|
|
385
|
+
const targetRejection = await admitTarget(input.target);
|
|
386
|
+
if (targetRejection) {
|
|
387
|
+
return targetRejectedResult(input.mode, input, frontmatter, targetRejection);
|
|
388
|
+
}
|
|
389
|
+
if (input.mode === "update") {
|
|
390
|
+
return writeUpdate(input, frontmatter, strictZones);
|
|
137
391
|
}
|
|
138
|
-
await mkdir(path.dirname(fullPath), { recursive: true });
|
|
139
392
|
if (input.mode === "append") {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
393
|
+
return writeAppend(input, frontmatter, strictZones);
|
|
394
|
+
}
|
|
395
|
+
return writeCreate(input, frontmatter, strictZones);
|
|
396
|
+
}
|
|
397
|
+
async function writeCreate(input, frontmatter, strictZones) {
|
|
398
|
+
let notePath;
|
|
399
|
+
let concept;
|
|
400
|
+
if (input.notePath) {
|
|
401
|
+
const safe = trySafeNotePath(input.target.vault, input.notePath);
|
|
402
|
+
if (!safe.ok) {
|
|
403
|
+
return rejectedResult("create", input.notePath, undefined, frontmatter, [], safe.reason, pathUnsafeRejection(safe.reason));
|
|
143
404
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
405
|
+
notePath = safe.normalized;
|
|
406
|
+
concept = resolveConcept(input.ontology, notePath);
|
|
407
|
+
if (!concept) {
|
|
408
|
+
const filename = path.posix.basename(notePath);
|
|
409
|
+
return inboxResult("create", input.ontology, filename, frontmatter, "No safe folder/concept binding matched the requested capture.");
|
|
149
410
|
}
|
|
150
411
|
}
|
|
151
412
|
else {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
flag: "wx",
|
|
156
|
-
});
|
|
413
|
+
const planned = planCreatePlacement(input.ontology, input.concept, input.folder, input.filename, frontmatter);
|
|
414
|
+
if (planned.kind === "inbox") {
|
|
415
|
+
return inboxResult("create", input.ontology, planned.filename, frontmatter, planned.reason ?? "No safe folder/concept binding matched the requested capture.");
|
|
157
416
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
417
|
+
notePath = planned.notePath;
|
|
418
|
+
concept = planned.concept;
|
|
419
|
+
}
|
|
420
|
+
if (!concept) {
|
|
421
|
+
return inboxResult("create", input.ontology, path.posix.basename(notePath), frontmatter, "No safe folder/concept binding matched the requested capture.");
|
|
422
|
+
}
|
|
423
|
+
const contract = evaluateWriteContract(frontmatter, concept, notePath, strictZones);
|
|
424
|
+
if (!contract.valid) {
|
|
425
|
+
return askResult("create", notePath, concept, frontmatter, contract.violations);
|
|
426
|
+
}
|
|
427
|
+
if (input.body === undefined) {
|
|
428
|
+
return rejectedResult("create", notePath, concept, frontmatter, [], "create requires a body", rejection("admission", "body-missing", "create requires a body", "pass a non-empty `body` for the note, then retry"));
|
|
429
|
+
}
|
|
430
|
+
const safe = trySafeNotePath(input.target.vault, notePath);
|
|
431
|
+
if (!safe.ok) {
|
|
432
|
+
return rejectedResult("create", notePath, concept, frontmatter, [], safe.reason, pathUnsafeRejection(safe.reason));
|
|
433
|
+
}
|
|
434
|
+
if (await fileExists(safe.fullPath)) {
|
|
435
|
+
return rejectedResult("create", notePath, concept, frontmatter, [], "Cannot create capture: target note already exists", rejection("admission", "note-exists", "Cannot create capture: target note already exists", "use mode `append` or `update` for an existing note, or choose a different filename"));
|
|
436
|
+
}
|
|
437
|
+
// Write Attempt: build the staged note in memory.
|
|
438
|
+
const staged = formatNote(frontmatter, input.body);
|
|
439
|
+
// Evaluation (pre-persist): the staged render is a second gate that only
|
|
440
|
+
// fires on divergence from the input evaluation, which already passed above.
|
|
441
|
+
const stagedEvaluation = evaluateStagedNote(staged, concept, notePath, strictZones);
|
|
442
|
+
if (!stagedEvaluation.ok && !sameViolationSet(stagedEvaluation.violations, contract.violations)) {
|
|
443
|
+
return stagedRejectedResult("create", notePath, concept, frontmatter, stagedEvaluation.violations);
|
|
444
|
+
}
|
|
445
|
+
if (stagedEvaluation.body.trim() === "") {
|
|
446
|
+
return stagedBodyMissingResult("create", notePath, concept, frontmatter);
|
|
447
|
+
}
|
|
448
|
+
if (input.dryRun) {
|
|
449
|
+
return writtenResult("create", notePath, concept, frontmatter);
|
|
450
|
+
}
|
|
451
|
+
// Persist.
|
|
452
|
+
await mkdir(path.dirname(safe.fullPath), { recursive: true });
|
|
453
|
+
await writeFile(safe.fullPath, staged, {
|
|
454
|
+
encoding: "utf-8",
|
|
455
|
+
flag: "wx",
|
|
456
|
+
});
|
|
457
|
+
// Postcondition.
|
|
458
|
+
const postcondition = await verifyPostcondition(input, safe.fullPath, notePath, concept, strictZones, { kind: "full", body: stagedEvaluation.body });
|
|
459
|
+
if (!postcondition.ok) {
|
|
460
|
+
return postconditionRejectedResult("create", notePath, safe.fullPath, concept, frontmatter, postcondition.violations, postcondition.detail);
|
|
461
|
+
}
|
|
462
|
+
return writtenResult("create", notePath, concept, frontmatter, receiptFor(input, "create", notePath, concept));
|
|
463
|
+
}
|
|
464
|
+
async function writeAppend(input, frontmatter, strictZones) {
|
|
465
|
+
if (!input.notePath) {
|
|
466
|
+
return rejectedResult("append", "", undefined, frontmatter, [], "append requires notePath", rejection("admission", "args-invalid", "append requires notePath", "pass the vault-relative `notePath` of the note to append to, then retry"));
|
|
467
|
+
}
|
|
468
|
+
if (input.body === undefined) {
|
|
469
|
+
return rejectedResult("append", input.notePath, undefined, frontmatter, [], "append requires a body", rejection("admission", "body-missing", "append requires a body", "pass a non-empty `body` to append, then retry"));
|
|
470
|
+
}
|
|
471
|
+
const safe = trySafeNotePath(input.target.vault, input.notePath);
|
|
472
|
+
if (!safe.ok) {
|
|
473
|
+
return rejectedResult("append", input.notePath, undefined, frontmatter, [], safe.reason, pathUnsafeRejection(safe.reason));
|
|
474
|
+
}
|
|
475
|
+
const exists = await fileExists(safe.fullPath);
|
|
476
|
+
if (!exists) {
|
|
477
|
+
const created = await writeCreate({
|
|
478
|
+
target: input.target,
|
|
479
|
+
ontology: input.ontology,
|
|
480
|
+
mode: "create",
|
|
481
|
+
dryRun: input.dryRun,
|
|
482
|
+
notePath: safe.normalized,
|
|
483
|
+
frontmatter,
|
|
484
|
+
body: input.body,
|
|
485
|
+
}, frontmatter, strictZones);
|
|
486
|
+
if (created.status !== "written") {
|
|
487
|
+
return created;
|
|
163
488
|
}
|
|
489
|
+
return writeResult({
|
|
490
|
+
...created,
|
|
491
|
+
mode: "append",
|
|
492
|
+
...(created.receipt ? { receipt: { ...created.receipt, mode: "append" } } : {}),
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
const raw = await readFile(safe.fullPath, "utf-8");
|
|
496
|
+
const parsed = parseNote(raw);
|
|
497
|
+
const concept = resolveConcept(input.ontology, safe.normalized);
|
|
498
|
+
if (!concept) {
|
|
499
|
+
return rejectedResult("append", safe.normalized, undefined, parsed.frontmatter, [], "Cannot commit capture: notePath does not resolve to a concept binding", conceptUnboundRejection());
|
|
500
|
+
}
|
|
501
|
+
const contract = evaluateWriteContract(parsed.frontmatter, concept, safe.normalized, strictZones);
|
|
502
|
+
if (!contract.valid) {
|
|
503
|
+
return rejectedResult("append", safe.normalized, concept, parsed.frontmatter, contract.violations, "Cannot append: existing frontmatter violates the concept contract");
|
|
504
|
+
}
|
|
505
|
+
// Write Attempt: the staged note is exactly what the file will hold after the
|
|
506
|
+
// append (current content + the appended block).
|
|
507
|
+
const appended = `\n\n${input.body.trim()}\n`;
|
|
508
|
+
const staged = `${raw}${appended}`;
|
|
509
|
+
// Evaluation (pre-persist).
|
|
510
|
+
const stagedEvaluation = evaluateStagedNote(staged, concept, safe.normalized, strictZones);
|
|
511
|
+
if (!stagedEvaluation.ok && !sameViolationSet(stagedEvaluation.violations, contract.violations)) {
|
|
512
|
+
return stagedRejectedResult("append", safe.normalized, concept, parsed.frontmatter, stagedEvaluation.violations);
|
|
513
|
+
}
|
|
514
|
+
if (input.dryRun) {
|
|
515
|
+
return writtenResult("append", safe.normalized, concept, parsed.frontmatter);
|
|
516
|
+
}
|
|
517
|
+
// Persist.
|
|
518
|
+
await appendFile(safe.fullPath, appended, "utf-8");
|
|
519
|
+
// Postcondition.
|
|
520
|
+
const postcondition = await verifyPostcondition(input, safe.fullPath, safe.normalized, concept, strictZones, { kind: "suffix", body: input.body });
|
|
521
|
+
if (!postcondition.ok) {
|
|
522
|
+
return postconditionRejectedResult("append", safe.normalized, safe.fullPath, concept, parsed.frontmatter, postcondition.violations, postcondition.detail);
|
|
523
|
+
}
|
|
524
|
+
return writtenResult("append", safe.normalized, concept, parsed.frontmatter, receiptFor(input, "append", safe.normalized, concept));
|
|
525
|
+
}
|
|
526
|
+
async function writeUpdate(input, frontmatter, strictZones) {
|
|
527
|
+
if (!input.notePath) {
|
|
528
|
+
return rejectedResult("update", "", undefined, frontmatter, [], "update requires notePath", rejection("admission", "args-invalid", "update requires notePath", "pass the vault-relative `notePath` of the note to update, then retry"));
|
|
529
|
+
}
|
|
530
|
+
if (input.frontmatter === undefined && input.body === undefined) {
|
|
531
|
+
return rejectedResult("update", input.notePath, undefined, frontmatter, [], "update requires frontmatter or body", rejection("admission", "args-invalid", "update requires frontmatter or body", "pass `frontmatter`, `body`, or both, then retry"));
|
|
532
|
+
}
|
|
533
|
+
const safe = trySafeNotePath(input.target.vault, input.notePath);
|
|
534
|
+
if (!safe.ok) {
|
|
535
|
+
return rejectedResult("update", input.notePath, undefined, frontmatter, [], safe.reason, pathUnsafeRejection(safe.reason));
|
|
536
|
+
}
|
|
537
|
+
if (!(await fileExists(safe.fullPath))) {
|
|
538
|
+
return rejectedResult("update", safe.normalized, undefined, frontmatter, [], "Cannot update capture: target note does not exist", rejection("admission", "note-missing", "Cannot update capture: target note does not exist", "create the note first (mode `create`) or correct `notePath`, then retry"));
|
|
539
|
+
}
|
|
540
|
+
const raw = await readFile(safe.fullPath, "utf-8");
|
|
541
|
+
const parsed = parseNote(raw);
|
|
542
|
+
const merged = input.frontmatter === undefined ? parsed.frontmatter : mergeFrontmatter(parsed.frontmatter, frontmatter);
|
|
543
|
+
const body = input.body === undefined ? parsed.body : input.body;
|
|
544
|
+
const concept = resolveConcept(input.ontology, safe.normalized);
|
|
545
|
+
if (!concept) {
|
|
546
|
+
return rejectedResult("update", safe.normalized, undefined, merged, [], "Cannot commit capture: notePath does not resolve to a concept binding", conceptUnboundRejection());
|
|
547
|
+
}
|
|
548
|
+
const contract = evaluateWriteContract(merged, concept, safe.normalized, strictZones);
|
|
549
|
+
if (!contract.valid) {
|
|
550
|
+
return rejectedResult("update", safe.normalized, concept, merged, contract.violations, "Cannot update capture: resulting frontmatter violates the concept contract");
|
|
551
|
+
}
|
|
552
|
+
// Write Attempt: build the staged note in memory.
|
|
553
|
+
const staged = formatNote(merged, body);
|
|
554
|
+
// Evaluation (pre-persist).
|
|
555
|
+
const stagedEvaluation = evaluateStagedNote(staged, concept, safe.normalized, strictZones);
|
|
556
|
+
if (!stagedEvaluation.ok && !sameViolationSet(stagedEvaluation.violations, contract.violations)) {
|
|
557
|
+
return stagedRejectedResult("update", safe.normalized, concept, merged, stagedEvaluation.violations);
|
|
558
|
+
}
|
|
559
|
+
if (input.dryRun) {
|
|
560
|
+
return writtenResult("update", safe.normalized, concept, merged);
|
|
561
|
+
}
|
|
562
|
+
// Persist.
|
|
563
|
+
await writeFile(safe.fullPath, staged, "utf-8");
|
|
564
|
+
// Postcondition.
|
|
565
|
+
const postcondition = await verifyPostcondition(input, safe.fullPath, safe.normalized, concept, strictZones, { kind: "full", body: stagedEvaluation.body });
|
|
566
|
+
if (!postcondition.ok) {
|
|
567
|
+
return postconditionRejectedResult("update", safe.normalized, safe.fullPath, concept, merged, postcondition.violations, postcondition.detail);
|
|
568
|
+
}
|
|
569
|
+
return writtenResult("update", safe.normalized, concept, merged, receiptFor(input, "update", safe.normalized, concept));
|
|
570
|
+
}
|
|
571
|
+
export async function commitCapture(input) {
|
|
572
|
+
const result = await writeNote({
|
|
573
|
+
target: { vault: input.vault, source: input.source },
|
|
574
|
+
ontology: input.ontology,
|
|
575
|
+
mode: input.mode,
|
|
576
|
+
dryRun: false,
|
|
577
|
+
notePath: input.notePath,
|
|
578
|
+
frontmatter: input.frontmatter,
|
|
579
|
+
body: input.body,
|
|
580
|
+
});
|
|
581
|
+
if (result.status === "written") {
|
|
582
|
+
return { written: true, mode: input.mode, notePath: result.notePath };
|
|
583
|
+
}
|
|
584
|
+
if (result.violations.length > 0) {
|
|
585
|
+
const fields = result.violations.map((violation) => violation.field).join(", ");
|
|
586
|
+
throw new Error(`Cannot commit capture: frontmatter violates the concept contract (${fields})`);
|
|
164
587
|
}
|
|
165
|
-
|
|
588
|
+
throw new Error(result.reason ?? "Cannot commit capture");
|
|
166
589
|
}
|
|
167
590
|
//# sourceMappingURL=safe.js.map
|