@north-light/crouter 0.3.227 → 0.3.229
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/dist/api/client.d.ts +5 -5
- package/dist/api/client.js +3 -3
- package/dist/api/dto/broker-ops.d.ts +8 -0
- package/dist/api/dto/memory.d.ts +8 -7
- package/dist/api/dto/memory.js +2 -2
- package/dist/builtin-memory/04-base-worker.md +1 -1
- package/dist/builtin-memory/insights/init.md +5 -5
- package/dist/builtin-memory/internal/INDEX.md +1 -1
- package/dist/builtin-memory/internal/agent-shaping.md +11 -11
- package/dist/builtin-memory/internal/examples/INDEX.md +1 -1
- package/dist/builtin-memory/internal/memory-loading.md +6 -6
- package/dist/builtin-memory/internal/plugins.md +1 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +50 -37
- package/dist/clients/attach/__tests__/pane-tag-successor.test.js +56 -0
- package/dist/clients/attach/__tests__/profile-files.test.js +21 -0
- package/dist/clients/attach/chrome/inbox-strip.js +11 -7
- package/dist/clients/attach/session/pane-tag.d.ts +28 -2
- package/dist/clients/attach/session/pane-tag.js +48 -22
- package/dist/clients/attach/session/profile-files.d.ts +6 -0
- package/dist/clients/attach/session/profile-files.js +44 -11
- package/dist/clients/attach/slash/dispatch.js +4 -7
- package/dist/clients/attach/viewer.js +588 -596
- package/dist/commands/__tests__/surface-reload-target.test.js +21 -0
- package/dist/commands/api-client.d.ts +3 -7
- package/dist/commands/api-client.js +7 -12
- package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +292 -0
- package/dist/commands/memory/__tests__/repository-root-lint.test.js +146 -0
- package/dist/commands/memory/delete.js +51 -24
- package/dist/commands/memory/edit.js +50 -10
- package/dist/commands/memory/find.js +105 -56
- package/dist/commands/memory/history.js +51 -31
- package/dist/commands/memory/lint.d.ts +0 -9
- package/dist/commands/memory/lint.js +78 -322
- package/dist/commands/memory/list.d.ts +12 -4
- package/dist/commands/memory/list.js +64 -25
- package/dist/commands/memory/move.js +103 -73
- package/dist/commands/memory/origin.js +35 -5
- package/dist/commands/memory/read.d.ts +4 -0
- package/dist/commands/memory/read.js +132 -80
- package/dist/commands/memory/shared.d.ts +115 -25
- package/dist/commands/memory/shared.js +331 -74
- package/dist/commands/memory/write.js +72 -21
- package/dist/commands/memory.js +2 -2
- package/dist/commands/node/create.d.ts +1 -1
- package/dist/commands/node/create.js +1 -1
- package/dist/commands/node/inspect.js +1 -1
- package/dist/commands/node/lifecycle.js +5 -5
- package/dist/commands/pkg/market-manage.js +25 -24
- package/dist/commands/pkg/plugin-manage.d.ts +22 -6
- package/dist/commands/pkg/plugin-manage.js +118 -25
- package/dist/commands/pkg/shared.d.ts +8 -0
- package/dist/commands/pkg/shared.js +23 -20
- package/dist/commands/surface-reload.d.ts +5 -0
- package/dist/commands/surface-reload.js +9 -1
- package/dist/commands/sys/__tests__/migrate.test.js +1140 -22
- package/dist/commands/sys/__tests__/sync-project-guidance.test.js +218 -0
- package/dist/commands/sys/migrate.js +126 -140
- package/dist/commands/sys/panels/profiles-panel.d.ts +66 -0
- package/dist/commands/sys/panels/profiles-panel.js +599 -0
- package/dist/commands/sys/settings-shell.d.ts +4 -2
- package/dist/commands/sys/settings-shell.js +35 -4
- package/dist/commands/sys/settings.js +21 -5
- package/dist/commands/sys/sync-deps.d.ts +2 -0
- package/dist/commands/sys/sync-deps.js +26 -15
- package/dist/commands/sys/sync-project-guidance.js +228 -145
- package/dist/commands/sys/sync-skills.js +28 -17
- package/dist/commands/sys/update.js +11 -3
- package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +15 -2
- package/dist/core/__tests__/config-change-delta.test.js +106 -0
- package/dist/core/__tests__/context-intro.test.js +13 -9
- package/dist/core/__tests__/daemon-boot.test.js +22 -16
- package/dist/core/__tests__/fixtures/memory-slash-live-probe.js +5 -1
- package/dist/core/__tests__/human-deliver.test.js +19 -0
- package/dist/core/__tests__/inline-memory-refs.test.js +50 -46
- package/dist/core/__tests__/{serial → integration}/broker-fork-seam.test.js +1 -1
- package/dist/core/__tests__/{serial → integration}/broker-sdk-wiring.test.js +1 -1
- package/dist/core/__tests__/{serial → integration}/broker-snapshot-history.test.js +1 -1
- package/dist/core/__tests__/{serial → integration}/command-plugins.test.js +94 -3
- package/dist/core/__tests__/{serial → integration}/deferred-no-wake.test.js +1 -1
- package/dist/core/__tests__/{serial → integration}/flagship-lifecycle.test.js +13 -27
- package/dist/core/__tests__/{serial → integration}/host-teardown-process-group.test.js +1 -1
- package/dist/core/__tests__/{serial → integration}/human-deliver-e2e.test.js +1 -1
- package/dist/core/__tests__/{live-mutation-verbs.test.js → integration/live-mutation-verbs.test.js} +22 -33
- package/dist/core/__tests__/{serial → integration}/live-mutation.test.js +21 -41
- package/dist/core/__tests__/integration/refresh-stall-recycle.test.d.ts +1 -0
- package/dist/core/__tests__/{serial → integration}/refresh-stall-recycle.test.js +1 -1
- package/dist/core/__tests__/integration/revive.test.d.ts +1 -0
- package/dist/core/__tests__/{serial → integration}/revive.test.js +38 -19
- package/dist/core/__tests__/integration/spawn-root.test.d.ts +1 -0
- package/dist/core/__tests__/{serial → integration}/spawn-root.test.js +104 -1
- package/dist/core/__tests__/integration/subscription-delivery.test.d.ts +1 -0
- package/dist/core/__tests__/{serial → integration}/subscription-delivery.test.js +1 -1
- package/dist/core/__tests__/integration/tmux-surface.test.d.ts +1 -0
- package/dist/core/__tests__/{serial → integration}/tmux-surface.test.js +1 -1
- package/dist/core/__tests__/integration/worktree-land.test.d.ts +1 -0
- package/dist/core/__tests__/integration/worktree-land.test.js +400 -0
- package/dist/core/__tests__/integration/worktree-reap.test.d.ts +1 -0
- package/dist/core/__tests__/{serial/worktree.test.js → integration/worktree-reap.test.js} +6 -338
- package/dist/core/__tests__/kickoff.test.js +16 -5
- package/dist/core/__tests__/memory-resolver-precedence.test.js +122 -91
- package/dist/core/__tests__/nested-store-discovery.test.js +5 -3
- package/dist/core/__tests__/on-read-crouter-home-fence.test.js +2 -1
- package/dist/core/__tests__/on-read-dedup-resume.test.js +39 -27
- package/dist/core/__tests__/on-read-nested-store.test.js +19 -13
- package/dist/core/__tests__/profile-project-memory-delivery.test.js +138 -44
- package/dist/core/__tests__/repository-association.test.d.ts +1 -0
- package/dist/core/__tests__/repository-association.test.js +153 -0
- package/dist/core/__tests__/repository-root-identity.test.d.ts +1 -0
- package/dist/core/__tests__/repository-root-identity.test.js +219 -0
- package/dist/core/__tests__/review-model-floor.test.js +12 -4
- package/dist/core/__tests__/seam/memory-slash-node-relative-inventory.test.js +27 -11
- package/dist/core/__tests__/warm-claim-preference-snapshot.test.d.ts +1 -0
- package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +40 -0
- package/dist/core/canvas/canvas.d.ts +3 -0
- package/dist/core/canvas/canvas.js +30 -10
- package/dist/core/canvas/db.js +28 -1
- package/dist/core/canvas/paths.d.ts +4 -6
- package/dist/core/canvas/paths.js +8 -6
- package/dist/core/canvas/render-source.js +2 -2
- package/dist/core/canvas/types.d.ts +9 -13
- package/dist/core/config.d.ts +3 -3
- package/dist/core/config.js +3 -3
- package/dist/core/exclusive-lock.d.ts +2 -0
- package/dist/core/exclusive-lock.js +21 -0
- package/dist/core/git.d.ts +0 -1
- package/dist/core/git.js +0 -3
- package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +1 -0
- package/dist/core/human/feedback-companion.js +3 -0
- package/dist/core/human/scan.js +8 -1
- package/dist/core/keybindings/catalog.d.ts +2 -2
- package/dist/core/keybindings/catalog.js +2 -1
- package/dist/core/memory/doc-link-grammar.js +2 -2
- package/dist/core/memory/history.d.ts +24 -0
- package/dist/core/memory/history.js +66 -1
- package/dist/core/memory/identity.d.ts +65 -0
- package/dist/core/memory/identity.js +185 -0
- package/dist/core/memory/inline-ref-guidance.d.ts +1 -1
- package/dist/core/memory/inline-ref-guidance.js +1 -1
- package/dist/core/memory/inline-ref-inventory.d.ts +3 -10
- package/dist/core/memory/inline-ref-inventory.js +30 -62
- package/dist/core/memory/lint.d.ts +129 -0
- package/dist/core/memory/lint.js +517 -0
- package/dist/core/memory/project-namespace.d.ts +31 -0
- package/dist/core/memory/project-namespace.js +85 -0
- package/dist/core/memory/repository-association.d.ts +31 -0
- package/dist/core/memory/repository-association.js +129 -0
- package/dist/core/memory/tree.d.ts +39 -0
- package/dist/core/memory/tree.js +93 -0
- package/dist/core/memory-resolver.d.ts +193 -90
- package/dist/core/memory-resolver.js +461 -375
- package/dist/core/nested-stores.js +6 -13
- package/dist/core/profiles/select.d.ts +4 -1
- package/dist/core/profiles/select.js +108 -48
- package/dist/core/review/__tests__/capture-origin.test.js +2 -2
- package/dist/core/review/__tests__/stage-identity.test.js +2 -2
- package/dist/core/review/companion.js +11 -2
- package/dist/core/runtime/bearings.d.ts +2 -2
- package/dist/core/runtime/bearings.js +3 -3
- package/dist/core/runtime/broker/daemon-ops.d.ts +2 -2
- package/dist/core/runtime/broker/rebind.js +5 -0
- package/dist/core/runtime/broker-extension-render.d.ts +7 -3
- package/dist/core/runtime/broker-extension-render.js +10 -5
- package/dist/core/runtime/broker-persona-guidance.d.ts +19 -5
- package/dist/core/runtime/broker-persona-guidance.js +122 -27
- package/dist/core/runtime/deliver-live.d.ts +16 -4
- package/dist/core/runtime/deliver-live.js +29 -15
- package/dist/core/runtime/kickoff.d.ts +3 -3
- package/dist/core/runtime/kickoff.js +8 -16
- package/dist/core/runtime/launch.js +1 -1
- package/dist/core/runtime/lifecycle.js +2 -3
- package/dist/core/runtime/nodes.d.ts +3 -4
- package/dist/core/runtime/nodes.js +3 -4
- package/dist/core/runtime/persona.d.ts +8 -12
- package/dist/core/runtime/persona.js +24 -96
- package/dist/core/runtime/promote.d.ts +2 -2
- package/dist/core/runtime/promote.js +8 -21
- package/dist/core/runtime/revive.js +20 -17
- package/dist/core/runtime/spawn.js +18 -7
- package/dist/core/runtime/tmux-bindings.js +2 -3
- package/dist/core/runtime/warm-pool.js +3 -4
- package/dist/core/scope.js +2 -0
- package/dist/core/self-update.d.ts +0 -2
- package/dist/core/self-update.js +2 -35
- package/dist/core/substrate/__tests__/surface-match-memory-read.test.d.ts +1 -0
- package/dist/core/substrate/__tests__/surface-match-memory-read.test.js +28 -0
- package/dist/core/substrate/index.d.ts +2 -2
- package/dist/core/substrate/index.js +1 -1
- package/dist/core/substrate/injected-store.d.ts +43 -27
- package/dist/core/substrate/injected-store.js +208 -104
- package/dist/core/substrate/listings.d.ts +19 -12
- package/dist/core/substrate/listings.js +75 -52
- package/dist/core/substrate/on-read-node.d.ts +4 -7
- package/dist/core/substrate/on-read-node.js +6 -8
- package/dist/core/substrate/on-read.d.ts +22 -25
- package/dist/core/substrate/on-read.js +103 -147
- package/dist/core/substrate/render-node.d.ts +4 -7
- package/dist/core/substrate/render-node.js +5 -7
- package/dist/core/substrate/render.d.ts +21 -3
- package/dist/core/substrate/render.js +291 -223
- package/dist/core/substrate/schema.d.ts +1 -13
- package/dist/core/substrate/schema.js +5 -40
- package/dist/core/substrate/session-cache.d.ts +14 -4
- package/dist/core/substrate/session-cache.js +40 -22
- package/dist/core/substrate/surface-match.d.ts +9 -7
- package/dist/core/substrate/surface-match.js +26 -25
- package/dist/daemon/__tests__/helpers/source-daemon.d.ts +30 -0
- package/dist/daemon/__tests__/helpers/source-daemon.js +174 -0
- package/dist/daemon/__tests__/integration/migration-startup.test.d.ts +1 -0
- package/dist/daemon/__tests__/integration/migration-startup.test.js +97 -0
- package/dist/daemon/api/__tests__/bridge-heartbeat.test.js +21 -5
- package/dist/daemon/api/handlers/broker-ops.js +21 -16
- package/dist/daemon/api/handlers/memory.js +2 -0
- package/dist/daemon/crtrd.js +2 -0
- package/dist/daemon/human/finish.js +8 -1
- package/dist/daemon/manage.d.ts +0 -1
- package/dist/daemon/manage.js +7 -16
- package/dist/daemon/startup-policy.d.ts +1 -0
- package/dist/daemon/startup-policy.js +1 -0
- package/dist/migrations/001-surfaces-frontmatter.js +21 -109
- package/dist/migrations/002-profile-project-memory.js +1 -0
- package/dist/migrations/003-repository-root-memory-identity/front-door.d.ts +26 -0
- package/dist/migrations/003-repository-root-memory-identity/front-door.js +231 -0
- package/dist/migrations/003-repository-root-memory-identity/index.d.ts +2 -0
- package/dist/migrations/003-repository-root-memory-identity/index.js +513 -0
- package/dist/migrations/003-repository-root-memory-identity/references.d.ts +95 -0
- package/dist/migrations/003-repository-root-memory-identity/references.js +469 -0
- package/dist/migrations/003-repository-root-memory-identity/repository-facts.d.ts +39 -0
- package/dist/migrations/003-repository-root-memory-identity/repository-facts.js +349 -0
- package/dist/migrations/__tests__/activation-concurrency.test.d.ts +1 -0
- package/dist/migrations/__tests__/activation-concurrency.test.js +145 -0
- package/dist/migrations/__tests__/activation.test.d.ts +1 -0
- package/dist/migrations/__tests__/activation.test.js +149 -0
- package/dist/migrations/__tests__/deletion-and-root-declaration.test.d.ts +1 -0
- package/dist/migrations/__tests__/deletion-and-root-declaration.test.js +149 -0
- package/dist/migrations/activation.d.ts +16 -0
- package/dist/migrations/activation.js +78 -0
- package/dist/migrations/convergent.d.ts +14 -3
- package/dist/migrations/convergent.js +21 -10
- package/dist/migrations/corpus.d.ts +78 -0
- package/dist/migrations/corpus.js +497 -0
- package/dist/migrations/frontmatter-splice.d.ts +15 -0
- package/dist/migrations/frontmatter-splice.js +176 -0
- package/dist/migrations/registry.d.ts +6 -1
- package/dist/migrations/registry.js +7 -2
- package/dist/migrations/runner.d.ts +41 -0
- package/dist/migrations/runner.js +81 -0
- package/dist/migrations/types.d.ts +148 -9
- package/dist/migrations/types.js +9 -2
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +225 -17
- package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +11 -3
- package/dist/pi-extensions/canvas-context-intro.d.ts +3 -5
- package/dist/pi-extensions/canvas-context-intro.js +50 -46
- package/dist/pi-extensions/canvas-doc-substrate.d.ts +1 -8
- package/dist/pi-extensions/canvas-doc-substrate.js +55 -122
- package/dist/pi-extensions/canvas-stophook.js +6 -13
- package/dist/shared/generated-context.d.ts +0 -3
- package/dist/shared/generated-context.js +0 -57
- package/dist/shared/tool-groups.js +2 -3
- package/dist/types.d.ts +8 -11
- package/dist/types.js +4 -31
- package/package.json +5 -4
- package/runtime.lock.json +2 -2
- package/dist/builtin-memory/05-kinds/design/00-base.md +0 -17
- package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +0 -15
- package/dist/builtin-memory/05-kinds/design/design-contract.md +0 -19
- package/dist/builtin-memory/05-kinds/developer/00-base.md +0 -17
- package/dist/builtin-memory/05-kinds/developer/01-orchestrator.md +0 -15
- package/dist/builtin-memory/05-kinds/plan/00-base.md +0 -17
- package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +0 -17
- package/dist/builtin-memory/05-kinds/plan/plan-contract.md +0 -28
- package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +0 -15
- package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +0 -15
- package/dist/builtin-memory/05-kinds/plan/reviewers/lens-contract.md +0 -13
- package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +0 -17
- package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +0 -17
- package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +0 -17
- package/dist/builtin-memory/05-kinds/spec/00-base.md +0 -17
- package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +0 -15
- package/dist/builtin-memory/05-kinds/spec/requirements.md +0 -15
- package/dist/builtin-memory/design/guide.md +0 -35
- package/dist/builtin-memory/design/roadmap.md +0 -21
- package/dist/builtin-memory/development.md +0 -113
- package/dist/builtin-memory/plan/roadmap.md +0 -25
- package/dist/builtin-memory/spec/guide.md +0 -53
- package/dist/builtin-memory/spec/requirements.md +0 -29
- package/dist/builtin-memory/spec/roadmap.md +0 -36
- package/dist/builtin-memory/testing.md +0 -39
- /package/dist/api/__tests__/{serial → integration}/client.test.d.ts +0 -0
- /package/dist/api/__tests__/{serial → integration}/client.test.js +0 -0
- /package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/{serial → integration}/provider-rotation.test.ts +0 -0
- /package/dist/clients/{inbox/__tests__/serial/inbox-controller.test.d.ts → attach/__tests__/pane-tag-successor.test.d.ts} +0 -0
- /package/dist/clients/{inbox/__tests__/serial/mount-panel.test.d.ts → attach/__tests__/profile-files.test.d.ts} +0 -0
- /package/dist/{core/__tests__/live-mutation-verbs.test.d.ts → clients/inbox/__tests__/integration/inbox-controller.test.d.ts} +0 -0
- /package/dist/clients/inbox/__tests__/{serial → integration}/inbox-controller.test.js +0 -0
- /package/dist/{core/__tests__/serial/broker-fork-seam.test.d.ts → clients/inbox/__tests__/integration/mount-panel.test.d.ts} +0 -0
- /package/dist/clients/inbox/__tests__/{serial → integration}/mount-panel.test.js +0 -0
- /package/dist/{core/__tests__/serial/broker-sdk-wiring.test.d.ts → commands/__tests__/surface-reload-target.test.d.ts} +0 -0
- /package/dist/{core/__tests__/serial/broker-snapshot-history.test.d.ts → commands/memory/__tests__/command-selector-and-mutation-guards.test.d.ts} +0 -0
- /package/dist/{core/__tests__/serial/command-plugins.test.d.ts → commands/memory/__tests__/repository-root-lint.test.d.ts} +0 -0
- /package/dist/{core/__tests__/serial/deferred-no-wake.test.d.ts → commands/sys/__tests__/sync-project-guidance.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/flagship-lifecycle.test.d.ts → config-change-delta.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/host-teardown-process-group.test.d.ts → integration/broker-fork-seam.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/human-deliver-e2e.test.d.ts → integration/broker-sdk-wiring.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/live-mutation.test.d.ts → integration/broker-snapshot-history.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/refresh-stall-recycle.test.d.ts → integration/command-plugins.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/revive.test.d.ts → integration/deferred-no-wake.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/spawn-root.test.d.ts → integration/flagship-lifecycle.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/subscription-delivery.test.d.ts → integration/host-teardown-process-group.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/tmux-surface.test.d.ts → integration/human-deliver-e2e.test.d.ts} +0 -0
- /package/dist/core/__tests__/{serial/worktree.test.d.ts → integration/live-mutation-verbs.test.d.ts} +0 -0
- /package/dist/core/{human/__tests__/serial/inbox-core.test.d.ts → __tests__/integration/live-mutation.test.d.ts} +0 -0
- /package/dist/core/human/__tests__/{serial → integration}/inbox-core.test.js +0 -0
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { CrtrClient } from '../../api/index.js';
|
|
2
2
|
import { interpolateNodePaths } from '../../core/canvas/paths.js';
|
|
3
3
|
import { defineLeaf } from '../../core/command.js';
|
|
4
|
-
import { CrtrError
|
|
4
|
+
import { CrtrError } from '../../core/errors.js';
|
|
5
5
|
import { memoryExtensionEffectiveCatalog, projectEffectiveMemoryExtensions } from '../../core/memory/extensions.js';
|
|
6
6
|
import { readText, realpathOrSelf } from '../../core/fs-utils.js';
|
|
7
7
|
import { parseFrontmatterGeneric } from '../../core/frontmatter.js';
|
|
8
8
|
import { docLinkNames } from '../../core/memory/doc-link-grammar.js';
|
|
9
|
-
import { createMemoryDocSnapshot, listAllMemoryDocs,
|
|
9
|
+
import { createMemoryDocSnapshot, listAllMemoryDocs, loadMemoryStoreView, resolveMemoryCandidates, resolveMemoryDocs, } from '../../core/memory-resolver.js';
|
|
10
10
|
import { expandShellBlocks, hasShellBlocks, makeNodeShellRunner } from '../../core/runtime/shell-expansion.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { emptyContextExposureState, exposedAtOrAbove, exposureTarget, loadContextExposureState, registerDocumentExposure, registerExposure, saveContextExposureState, } from '../../core/substrate/injected-store.js';
|
|
12
|
+
import { dirDedupKey, docListingDirs, docsByName, isDirName, renderDirListing } from '../../core/substrate/listings.js';
|
|
13
13
|
import { memoryReadDocBlocks } from '../../core/substrate/on-read.js';
|
|
14
14
|
import { renderResult } from '../../core/render.js';
|
|
15
|
-
import { effectiveDocKind
|
|
16
|
-
import {
|
|
15
|
+
import { effectiveDocKind } from '../../core/substrate/schema.js';
|
|
16
|
+
import { canonicalSegments } from '../../core/memory/identity.js';
|
|
17
|
+
import { MEMORY_KINDS, requireMountedStore, resolveReadSelector, selectorParam } from './shared.js';
|
|
17
18
|
export { createMemoryDocSnapshot, resolveMemoryDocs };
|
|
18
19
|
/** Load the body at an already-resolved memory path with the same frontmatter
|
|
19
20
|
* stripping and in-node path interpolation as `memory read`. Callers that
|
|
@@ -48,6 +49,17 @@ function corpusDocs() {
|
|
|
48
49
|
return [];
|
|
49
50
|
}
|
|
50
51
|
}
|
|
52
|
+
/** One physical document sharing a canonical identity, as the path-aware
|
|
53
|
+
* surfaces report it. `--dir <its project>` is how a non-winner is reached. */
|
|
54
|
+
export function candidateRow(doc, winner) {
|
|
55
|
+
return {
|
|
56
|
+
winner: doc === winner,
|
|
57
|
+
scope: doc.scope,
|
|
58
|
+
store_root: doc.root,
|
|
59
|
+
physical_relative_path: doc.physicalRelativePath,
|
|
60
|
+
path: doc.path,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
51
63
|
function attr(s) {
|
|
52
64
|
return s
|
|
53
65
|
.replace(/&/g, '&')
|
|
@@ -58,25 +70,32 @@ function attr(s) {
|
|
|
58
70
|
export const readLeaf = defineLeaf({
|
|
59
71
|
name: 'read',
|
|
60
72
|
description: 'load a memory document body by name',
|
|
61
|
-
whenToUse: 'a task in front of you matches a stored document and you already know its name — read it before improvising.
|
|
73
|
+
whenToUse: 'a task in front of you matches a stored document and you already know its canonical name — read it before improvising. Resolution is exact and takes the full canonical name (a project document is `<namespace>/<local name>`); among documents sharing one name the winner is the nearest scope (node > project stack > profile > user > builtin). A directory name is a valid target too: it answers with that directory\u2019s own document, when it has one, together with its immediate listing, and walking directories is the sanctioned browse move. You name the document by its crtr identifier, never a file path — do not cat or find the markdown off disk. Reach for `crtr memory find` first when you do not yet know which document applies.',
|
|
62
74
|
help: {
|
|
63
75
|
name: 'memory read',
|
|
64
|
-
summary: 'resolve
|
|
76
|
+
summary: 'resolve an exact canonical name to its document body (frontmatter stripped unless --frontmatter), plus the directory listing when that name has members',
|
|
65
77
|
params: [
|
|
66
|
-
{ kind: 'positional', name: 'name', required: true, constraint: '
|
|
78
|
+
{ kind: 'positional', name: 'name', required: true, constraint: 'Full canonical memory name — a project document is `<namespace>/<local name>`, every other store\u2019s local names are already canonical, where a nested store\'s namespace includes its path under the repository root. Resolution is exact: a file path, a bare leaf, a `<scope>/<name>` spelling, and a trailing `/INDEX` all fail. A name that carries members returns its listing alongside its body; a name that is only a directory returns the listing alone.' },
|
|
67
79
|
{ kind: 'flag', name: 'kind', type: 'enum', choices: [...MEMORY_KINDS], required: false, constraint: 'Narrows resolution when the name is ambiguous across kinds.' },
|
|
68
80
|
{ kind: 'flag', name: 'frontmatter', type: 'bool', required: false, constraint: 'When present, includes the YAML frontmatter in the returned body. Off by default — only the body is returned.' },
|
|
81
|
+
selectorParam('scope-read'),
|
|
82
|
+
selectorParam('dir', {}, 'Reads that store alone: the name resolves against its documents only, and the listing shows its members only.'),
|
|
69
83
|
],
|
|
70
84
|
output: [
|
|
71
|
-
{ name: 'name', type: 'string', required: true, constraint: 'Resolved document name, or the directory name on a directory read.' },
|
|
85
|
+
{ name: 'name', type: 'string', required: true, constraint: 'Resolved canonical document name, or the directory name on a directory read.' },
|
|
86
|
+
{ name: 'local_name', type: 'string', required: false, constraint: 'Store-local identity, before the store namespace composed the canonical name. Absent on a directory read.' },
|
|
72
87
|
{ name: 'kind', type: 'string', required: false, constraint: 'Resolved kind: knowledge or preference. Absent on a directory read.' },
|
|
73
88
|
{ name: 'scope', type: 'string', required: false, constraint: 'Scope the document was resolved from: node, project, profile, user, or builtin. Absent on a directory read.' },
|
|
74
89
|
{ name: 'path', type: 'string', required: false, constraint: 'Absolute path to the document on disk. Revise it with `crtr memory edit`, never by editing this file — an edit records why the change happened and lands in the doc’s revision history. Absent on a directory read.' },
|
|
90
|
+
{ name: 'store_root', type: 'string', required: false, constraint: 'Absolute memory store root the document loaded from. Absent on a directory read.' },
|
|
91
|
+
{ name: 'physical_relative_path', type: 'string', required: false, constraint: 'Store-relative physical markdown path, ordering prefixes and any `INDEX.md` kept. Absent on a directory read.' },
|
|
92
|
+
{ name: 'representation', type: 'string', required: false, constraint: 'Physical representation of this identity: leaf-file or directory-index. Absent on a directory read.' },
|
|
93
|
+
{ name: 'candidates', type: 'object[]', required: false, constraint: 'Present only when several physical documents share this canonical name: one row per candidate in source order, {winner, scope, store_root, physical_relative_path, path}. The winner is what this read returned; reach a non-winning one with `--dir <its project>`.' },
|
|
75
94
|
{ name: 'content', type: 'string', required: false, constraint: 'Document body. Frontmatter stripped unless --frontmatter is set. A document may embed shell as `!`cmd`` or a ```! fenced block; each runs once per read, in the current working directory, and is replaced by its output. Read `path` off disk when you need the literal unexecuted text. May be preceded by one `<auto-loaded-context>` block carrying the doc\u2019s neighborhood listings and any docs routed to this read. Absent on a directory read.' },
|
|
76
|
-
{ name: 'listing', type: 'string[]', required: false, constraint: 'Present
|
|
95
|
+
{ name: 'listing', type: 'string[]', required: false, constraint: 'Present when the name has members — a directory document returns its body AND this listing, a bare directory returns the listing alone: one `[[name]]: <when-and-why>` line per member doc, one bare `[[name]]` per subdirectory. Follow any line with `crtr memory read <name>`.' },
|
|
77
96
|
{ name: 'extensions', type: 'object', required: false, constraint: 'Effective valid plugin-owned metadata, keyed by plugin namespace then field. Includes enabled declaration defaults without writing them to frontmatter; disabled and unresolved namespaces are omitted. Present only on a document read.' },
|
|
78
97
|
{ name: 'links', type: 'string[]', required: false, constraint: 'Canonical names this document links to via `[[name]]` that resolve in the current corpus — further reading, loaded only on demand with `crtr memory read <name>`. A directory link returns that directory\u2019s listing. Omitted when the body carries no resolvable links.' },
|
|
79
|
-
{ name: 'follow_up', type: 'string', required: false, constraint: 'Present
|
|
98
|
+
{ name: 'follow_up', type: 'string', required: false, constraint: 'Present whenever the read returned a listing or resolvable body links.' },
|
|
80
99
|
],
|
|
81
100
|
outputKind: 'object',
|
|
82
101
|
effects: [
|
|
@@ -88,34 +107,64 @@ export const readLeaf = defineLeaf({
|
|
|
88
107
|
const nameRaw = input['name'];
|
|
89
108
|
const kindFilter = input['kind'];
|
|
90
109
|
const includeFrontmatter = input['frontmatter'];
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
110
|
+
// The selector decides the corpus: a scope filter over the target view, or
|
|
111
|
+
// the one exact store `--dir` names. --kind is threaded INTO resolution
|
|
112
|
+
// (not a post-filter): a nearer wrong-kind doc is skipped so a farther
|
|
113
|
+
// matching-kind doc is found instead of shadowing it into a false
|
|
114
|
+
// not_found.
|
|
115
|
+
const selector = resolveReadSelector({
|
|
116
|
+
scope: input['scope'],
|
|
117
|
+
dir: input['dir'],
|
|
118
|
+
});
|
|
119
|
+
const kindOpts = kindFilter === undefined ? {} : { kind: kindFilter };
|
|
120
|
+
let set = null;
|
|
121
|
+
// Re-runs the throwing resolve when nothing answered, so the canonical
|
|
122
|
+
// not-found (with its spelling guidance) is the resolver's, not a copy.
|
|
123
|
+
let fail;
|
|
124
|
+
let listingByName;
|
|
125
|
+
let linkByName;
|
|
126
|
+
if (selector.store !== null) {
|
|
127
|
+
// `--dir` reads ONE exact store: its documents alone decide what resolves
|
|
128
|
+
// and what the listings show. Links stay corpus-wide — a body legitimately
|
|
129
|
+
// points at another store — with the selected store first so it wins its
|
|
130
|
+
// own names.
|
|
131
|
+
const view = loadMemoryStoreView(requireMountedStore(selector.store), true);
|
|
132
|
+
listingByName = docsByName(view.docs);
|
|
133
|
+
linkByName = docsByName([...view.docs, ...corpusDocs()]);
|
|
134
|
+
set = view.candidates(nameRaw, kindOpts);
|
|
135
|
+
fail = () => view.resolve(nameRaw, kindOpts);
|
|
100
136
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
137
|
+
else {
|
|
138
|
+
const resolveOpts = {
|
|
139
|
+
...kindOpts,
|
|
140
|
+
...(selector.scope === undefined ? {} : { scope: selector.scope }),
|
|
141
|
+
includeDescendants: true,
|
|
142
|
+
};
|
|
143
|
+
listingByName = linkByName = docsByName(listAllMemoryDocs(selector.scope, false, true));
|
|
144
|
+
try {
|
|
145
|
+
set = resolveMemoryCandidates(nameRaw, resolveOpts);
|
|
146
|
+
}
|
|
147
|
+
catch (e) {
|
|
148
|
+
if (!(e instanceof CrtrError && e.code === 'not_found'))
|
|
149
|
+
throw e;
|
|
150
|
+
}
|
|
151
|
+
fail = () => resolveMemoryCandidates(nameRaw, resolveOpts);
|
|
104
152
|
}
|
|
105
153
|
const nodeId = process.env['CRTR_NODE_ID'] || undefined;
|
|
106
|
-
if (
|
|
107
|
-
// No
|
|
108
|
-
//
|
|
109
|
-
// excluded), never dedup-filtered;
|
|
110
|
-
// preview so unsolicited channels stay
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
if (dirName !== '' && isDirName(
|
|
114
|
-
const
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
154
|
+
if (set === null) {
|
|
155
|
+
// No document answers this name — a directory with no document of its own
|
|
156
|
+
// still does, through its listing. An explicit dir read is a deliberate
|
|
157
|
+
// act, so every line renders (unlisted excluded), never dedup-filtered;
|
|
158
|
+
// rendered members still record at preview so unsolicited channels stay
|
|
159
|
+
// quiet about them later.
|
|
160
|
+
const dirName = canonicalSegments(nameRaw.trim()).join('/');
|
|
161
|
+
if (dirName !== '' && isDirName(listingByName, dirName)) {
|
|
162
|
+
const contextExposure = nodeId !== undefined ? loadContextExposureState(nodeId) : null;
|
|
163
|
+
const target = contextExposure === null ? null : exposureTarget(contextExposure, 'transcript');
|
|
164
|
+
const listing = renderDirListing(listingByName, dirName, target, false);
|
|
165
|
+
if (nodeId !== undefined && contextExposure !== null && target !== null) {
|
|
166
|
+
registerExposure(target, dirDedupKey(dirName), 'preview');
|
|
167
|
+
saveContextExposureState(nodeId, contextExposure);
|
|
119
168
|
}
|
|
120
169
|
return {
|
|
121
170
|
name: dirName,
|
|
@@ -123,11 +172,9 @@ export const readLeaf = defineLeaf({
|
|
|
123
172
|
follow_up: 'Each line is readable with `crtr memory read <name>` — a `[[name]]: <line>` entry is a doc, a bare `[[name]]` is a subdirectory whose read browses deeper. Browse the whole inventory with `crtr memory list`.',
|
|
124
173
|
};
|
|
125
174
|
}
|
|
126
|
-
|
|
127
|
-
memory: nameRaw,
|
|
128
|
-
next: 'Run `crtr memory find <query>` to discover documents, or `crtr memory list` to browse the inventory.',
|
|
129
|
-
});
|
|
175
|
+
fail();
|
|
130
176
|
}
|
|
177
|
+
const doc = set.winner;
|
|
131
178
|
const kind = effectiveDocKind(doc);
|
|
132
179
|
const raw = readMemoryDocContent(doc.path, includeFrontmatter);
|
|
133
180
|
// A read is an explicit act by an agent that can already run shell, so a
|
|
@@ -137,71 +184,76 @@ export const readLeaf = defineLeaf({
|
|
|
137
184
|
const content = hasShellBlocks(raw)
|
|
138
185
|
? await expandShellBlocks(raw, makeNodeShellRunner({ cwd: process.cwd() }))
|
|
139
186
|
: raw;
|
|
140
|
-
const byName = docsByName(corpusDocs());
|
|
141
187
|
// `[[name]]` doc links are pointers, never transclusion: surface which
|
|
142
188
|
// linked names actually resolve so the reader can follow one when the
|
|
143
189
|
// task needs that depth, without ever auto-loading a linked body. A link
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return true;
|
|
148
|
-
try {
|
|
149
|
-
// `resolveMemoryDoc` permits leaf-name fallback for interactive reads;
|
|
150
|
-
// a stored graph edge does not. Compare the resolved canonical name
|
|
151
|
-
// so an old shorthand never masquerades as a first-class doc link.
|
|
152
|
-
return resolveMemoryDoc(linkName, { includeDescendants: true }).name === linkName;
|
|
153
|
-
}
|
|
154
|
-
catch {
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
|
-
});
|
|
190
|
+
// is an exact canonical address — a directory name included, which browses
|
|
191
|
+
// to its listing.
|
|
192
|
+
const links = docLinkNames(doc.body).filter((linkName) => linkByName.has(linkName) || isDirName(linkByName, linkName));
|
|
158
193
|
// Reading a doc discloses where it sits (its directory's listing and each
|
|
159
|
-
// ancestor's, once per
|
|
194
|
+
// ancestor's, once per loaded context) and fires the memory-read event
|
|
160
195
|
// (corpus docs whose `memory-read` entries match the resolved name).
|
|
161
196
|
// Both prepend in one <auto-loaded-context> block. Without a node
|
|
162
197
|
// identity the call is stateless: listings render undeduped and nothing
|
|
163
198
|
// records.
|
|
164
|
-
const
|
|
199
|
+
const contextExposure = nodeId !== undefined
|
|
200
|
+
? loadContextExposureState(nodeId)
|
|
201
|
+
: emptyContextExposureState();
|
|
202
|
+
const target = exposureTarget(contextExposure, 'transcript');
|
|
165
203
|
const subject = await fetchSubject(nodeId);
|
|
166
204
|
const excludeReal = realpathOrSelf(doc.path);
|
|
167
205
|
// The explicit read IS a content delivery: record it first so unsolicited
|
|
168
206
|
// channels (including this doc's own line in its directory listing) stay
|
|
169
207
|
// quiet about a doc whose full body is already in the transcript.
|
|
170
|
-
|
|
171
|
-
recordDelivery(seen, excludeReal, 'content');
|
|
208
|
+
registerDocumentExposure(target, doc.path, doc.body, 'content');
|
|
172
209
|
const blocks = [];
|
|
173
|
-
|
|
174
|
-
|
|
210
|
+
// A doc that fronts a directory carries its members with its body: that
|
|
211
|
+
// listing is part of the deliberate read (every line renders) and returns
|
|
212
|
+
// as `listing`, while the ancestors above it stay unsolicited neighborhood
|
|
213
|
+
// context. The node's own document is never among its children, so nothing
|
|
214
|
+
// repeats.
|
|
215
|
+
const dirs = docListingDirs(listingByName, doc.name);
|
|
216
|
+
const ownDir = dirs[0] === doc.name;
|
|
217
|
+
let listing;
|
|
218
|
+
if (ownDir) {
|
|
219
|
+
listing = renderDirListing(listingByName, doc.name, target, false);
|
|
220
|
+
registerExposure(target, dirDedupKey(doc.name), 'preview');
|
|
221
|
+
}
|
|
222
|
+
for (const dir of ownDir ? dirs.slice(1) : dirs) {
|
|
223
|
+
if (exposedAtOrAbove(contextExposure, dirDedupKey(dir), 'preview'))
|
|
175
224
|
continue;
|
|
176
|
-
const lines = renderDirListing(
|
|
177
|
-
|
|
178
|
-
recordDelivery(seen, dirDedupKey(dir), 'preview');
|
|
225
|
+
const lines = renderDirListing(listingByName, dir, target, true);
|
|
226
|
+
registerExposure(target, dirDedupKey(dir), 'preview');
|
|
179
227
|
if (lines.length > 0)
|
|
180
228
|
blocks.push(`<memory-listing dir="${attr(dir)}">\n${lines.join('\n')}\n</memory-listing>`);
|
|
181
229
|
}
|
|
182
|
-
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
if (slash > 0)
|
|
186
|
-
targetNames.push(doc.name.slice(slash + 1));
|
|
187
|
-
}
|
|
188
|
-
blocks.push(...memoryReadDocBlocks(subject, excludeReal, targetNames, seen ?? new Map()));
|
|
189
|
-
if (nodeId !== undefined && seen !== null)
|
|
190
|
-
saveInjectedDocs(nodeId, seen);
|
|
230
|
+
blocks.push(...memoryReadDocBlocks(subject, excludeReal, doc.name, target));
|
|
231
|
+
if (nodeId !== undefined)
|
|
232
|
+
saveContextExposureState(nodeId, contextExposure);
|
|
191
233
|
const finalContent = blocks.length === 0 ? content : `<auto-loaded-context>\n${blocks.join('\n')}\n</auto-loaded-context>\n\n${content}`;
|
|
234
|
+
const hasListing = listing !== undefined && listing.length > 0;
|
|
235
|
+
const followUp = hasListing
|
|
236
|
+
? links.length > 0
|
|
237
|
+
? 'Each `[[name]]` line in `listing` is one of this directory’s immediate members, and the `[[name]]` links in the body are further reading — follow either with `crtr memory read <name>` only when the task needs that depth.'
|
|
238
|
+
: 'Each `[[name]]` line in `listing` is one of this directory’s immediate members, readable with `crtr memory read <name>` — follow one only when the task needs that depth.'
|
|
239
|
+
: links.length > 0
|
|
240
|
+
? 'The `[[name]]` links in the body are further reading — follow one with `crtr memory read <name>` only when the task needs that depth.'
|
|
241
|
+
: null;
|
|
192
242
|
return {
|
|
193
243
|
name: doc.name,
|
|
244
|
+
local_name: doc.localName,
|
|
194
245
|
kind,
|
|
195
246
|
scope: doc.scope,
|
|
196
247
|
path: doc.path,
|
|
248
|
+
store_root: doc.root,
|
|
249
|
+
physical_relative_path: doc.physicalRelativePath,
|
|
250
|
+
representation: doc.representation,
|
|
251
|
+
...(set.candidates.length > 1 ? { candidates: set.candidates.map((c) => candidateRow(c, doc)) } : {}),
|
|
197
252
|
content: finalContent,
|
|
253
|
+
...(hasListing ? { listing } : {}),
|
|
198
254
|
extensions: projectEffectiveMemoryExtensions(doc.frontmatter?.['extensions'], memoryExtensionEffectiveCatalog(doc)),
|
|
199
|
-
...(links.length > 0
|
|
200
|
-
|
|
201
|
-
links,
|
|
202
|
-
follow_up: 'The `[[name]]` links in the body are further reading — follow one with `crtr memory read <name>` only when the task needs that depth.',
|
|
203
|
-
}
|
|
204
|
-
: {}),
|
|
255
|
+
...(links.length > 0 ? { links } : {}),
|
|
256
|
+
...(followUp === null ? {} : { follow_up: followUp }),
|
|
205
257
|
};
|
|
206
258
|
},
|
|
207
259
|
render: (result) => {
|
|
@@ -1,40 +1,122 @@
|
|
|
1
1
|
import { type FlagParam } from '../../core/help.js';
|
|
2
|
-
import type
|
|
2
|
+
import { type MemoryCandidateSet, type MemoryDoc, type MemoryScope, type MemoryStoreDescriptor } from '../../core/memory-resolver.js';
|
|
3
|
+
import { type DocRepresentation } from '../../core/memory/identity.js';
|
|
3
4
|
import { type MemoryExtensionCatalog } from '../../core/memory/extensions.js';
|
|
4
5
|
import type { MemoryExtensionScalar } from '../../types.js';
|
|
5
6
|
export declare const MEMORY_KINDS: readonly ["knowledge", "preference"];
|
|
7
|
+
export declare const MEMORY_READ_SCOPES: readonly ["user", "project", "profile", "node", "builtin"];
|
|
8
|
+
export declare const MEMORY_WRITE_SCOPES: readonly ["user", "project", "profile", "node"];
|
|
6
9
|
export declare const MEMORY_SCOPES: readonly ["user", "project", "profile", "node"];
|
|
7
10
|
/** Scope sort weight matching resolution precedence (node > project stack >
|
|
8
11
|
* profile > user > builtin). Used by `list` for its "scope then kind then
|
|
9
12
|
* name" ordering. */
|
|
10
13
|
export declare function scopeRank(scope: MemoryScope): number;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
export declare function registerMemoryListingExposure(identity: string): void;
|
|
15
|
+
/** The raw selector flags a memory leaf accepts. */
|
|
16
|
+
export interface MemorySelectorInput {
|
|
17
|
+
scope?: string | undefined;
|
|
18
|
+
dir?: string | undefined;
|
|
19
|
+
profile?: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
export interface MemoryReadSelector {
|
|
22
|
+
/** Source-stack filter for a target view, absent when unfiltered. */
|
|
23
|
+
scope?: MemoryScope;
|
|
24
|
+
/** The one exact store `--dir` selected, or null for a target view. Returned
|
|
25
|
+
* whatever its mount status: lint inspects a store the runtime refuses to
|
|
26
|
+
* mount, everything else calls `requireMountedStore` first. */
|
|
27
|
+
store: MemoryStoreDescriptor | null;
|
|
28
|
+
}
|
|
29
|
+
export interface MemoryWriteSelector {
|
|
30
|
+
scope: MemoryScope;
|
|
31
|
+
/** Absolute `<root>/memory` dir the document is written under. */
|
|
32
|
+
memoryDir: string;
|
|
33
|
+
/** The store its canonical name composes under. */
|
|
34
|
+
store: MemoryStoreDescriptor;
|
|
35
|
+
}
|
|
36
|
+
/** Resolve the read selection: a scope filter, or the exact store `--dir`
|
|
37
|
+
* names. */
|
|
38
|
+
export declare function resolveReadSelector(input: MemorySelectorInput): MemoryReadSelector;
|
|
39
|
+
/** Resolve the one store a mutation writes to. Default: project when a project
|
|
40
|
+
* scope exists for the cwd, else user. An explicit `--scope project` with no
|
|
41
|
+
* project scope yet scaffolds one (`ensureProjectScopeRoot`). `--scope
|
|
42
|
+
* profile` is NEVER a default — it requires a selected profile, from
|
|
43
|
+
* `--profile <id-or-name>` or else the process's `CRTR_PROFILE_ID`, resolved
|
|
44
|
+
* through the centralized `loadProfileManifest` (never a raw path join).
|
|
45
|
+
* `--scope node` targets the this-node store
|
|
46
|
+
* (`nodes/<CRTR_NODE_ID>/context/memory/`) and requires a running node. */
|
|
47
|
+
export declare function resolveWriteSelector(input: MemorySelectorInput): MemoryWriteSelector;
|
|
48
|
+
/** The scope + memory dir a write lands in. Retained for the leaves that still
|
|
49
|
+
* place documents by path alone; they cut over to `resolveWriteSelector` and
|
|
50
|
+
* `planNewDocumentPlacement` in their own phases. */
|
|
25
51
|
export declare function resolveWriteTarget(scopeArg: string | undefined, profileArg?: string, dirArg?: string): {
|
|
26
52
|
scope: MemoryScope;
|
|
27
53
|
memoryDir: string;
|
|
28
54
|
};
|
|
55
|
+
/** Refuse a project store the runtime will not resolve through. A project
|
|
56
|
+
* repository-root store carries the identity every canonical name in it composes under, so
|
|
57
|
+
* without a valid declaration no name can be validated, stripped, or placed;
|
|
58
|
+
* user, profile, and node stores have no declaration and always pass, even
|
|
59
|
+
* before their directory exists. */
|
|
60
|
+
export declare function requireMountedStore(store: MemoryStoreDescriptor): MemoryStoreDescriptor;
|
|
61
|
+
/** Normalize and validate a full canonical name: ordering prefixes are
|
|
62
|
+
* physical-path-only, a trailing `INDEX` is never an address, and the segment
|
|
63
|
+
* charset is fixed. */
|
|
64
|
+
export declare function requireCanonicalName(rawName: string): string;
|
|
65
|
+
/** The store-local name a full canonical name has inside one exact store, or a
|
|
66
|
+
* usage error when it falls outside that store's namespace. `''` names the
|
|
67
|
+
* store's own root document — a project store answers at its namespace. */
|
|
68
|
+
export declare function requireLocalNameInStore(store: MemoryStoreDescriptor, rawName: string): string;
|
|
69
|
+
export interface MemoryPlacement {
|
|
70
|
+
store: MemoryStoreDescriptor;
|
|
71
|
+
/** Full canonical name — the address the document answers at. */
|
|
72
|
+
canonicalName: string;
|
|
73
|
+
/** Store-local name, `''` for the store's own root document. */
|
|
74
|
+
localName: string;
|
|
75
|
+
representation: DocRepresentation;
|
|
76
|
+
/** Store-relative markdown path. */
|
|
77
|
+
physicalRelativePath: string;
|
|
78
|
+
/** Absolute path of the `.md` file. */
|
|
79
|
+
path: string;
|
|
80
|
+
}
|
|
81
|
+
/** Where a NEW document (a `write`, a `move` destination) physically lands in
|
|
82
|
+
* one exact store, after proving the canonical identity is free.
|
|
83
|
+
*
|
|
84
|
+
* Both physical forms carry the same identity, so occupancy is checked against
|
|
85
|
+
* the loaded identities AND both `<local>.md` and `<local>/INDEX.md` — a file
|
|
86
|
+
* whose explicit `name:` points elsewhere still owns its path. The chosen form
|
|
87
|
+
* is `<local>/INDEX.md` when the canonical directory already has descendants
|
|
88
|
+
* in this store (the document fronts a directory that exists), else
|
|
89
|
+
* `<local>.md`; descendants created later never relocate it, because either
|
|
90
|
+
* form validly owns the identity. Pass `storeDocs` when the caller already
|
|
91
|
+
* loaded the store, and `source` when planning a move, whose own identity and
|
|
92
|
+
* file are being vacated. */
|
|
93
|
+
export declare function planNewDocumentPlacement(store: MemoryStoreDescriptor, rawName: string, storeDocs?: readonly MemoryDoc[], source?: MemoryDoc): MemoryPlacement;
|
|
94
|
+
/** The document a mutation acts on, refusing an identity two files in ONE
|
|
95
|
+
* store both own. Reads stay answerable (`<name>/INDEX.md` deterministically
|
|
96
|
+
* wins), but a mutation would silently pick one of two files, so it stops with
|
|
97
|
+
* both paths. Candidates in OTHER stores are ordinary alternates — precedence
|
|
98
|
+
* picked the winner and `--dir` reaches the rest. */
|
|
99
|
+
export declare function requireUnambiguousDoc(set: MemoryCandidateSet): MemoryDoc;
|
|
100
|
+
/** Move and delete are the only mutation recovery path for a same-store
|
|
101
|
+
* collision. The exact-store winner remains the ordinary target; only the
|
|
102
|
+
* selected store's candidates are ordered by their physical path. */
|
|
103
|
+
export interface MutationDocSelection {
|
|
104
|
+
doc: MemoryDoc;
|
|
105
|
+
collisionPaths: readonly string[];
|
|
106
|
+
}
|
|
107
|
+
export declare function selectMutationDoc(set: MemoryCandidateSet): MutationDocSelection;
|
|
29
108
|
/** Remove a just-removed file's now-empty parent directories up to (never
|
|
30
|
-
* including) its
|
|
31
|
-
* prefix does not orphan an empty directory.
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* `.history/<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
109
|
+
* including) its store root, so removing the last entry under an `area/`
|
|
110
|
+
* prefix does not orphan an empty directory. `pathSegments` counts the
|
|
111
|
+
* PHYSICAL store-relative path (`doc.physicalRelativePath.split('/').length`),
|
|
112
|
+
* never the canonical name, which carries the store's namespace on top of it —
|
|
113
|
+
* the same count addresses a `.history/<path>.jsonl` sidecar. Stops at the
|
|
114
|
+
* first non-empty ancestor. */
|
|
115
|
+
export declare function pruneEmptyParents(filePath: string, pathSegments: number): void;
|
|
116
|
+
/** Map a STORE-LOCAL name (`topic`, `area/topic`, `INDEX`) to its file path
|
|
117
|
+
* under a memory dir, guarding against traversal/absolute escapes. Physical
|
|
118
|
+
* mapping only: it composes no namespace and collapses no `INDEX`, so a
|
|
119
|
+
* canonical name reaches it through `planNewDocumentPlacement`. */
|
|
38
120
|
export declare function memoryFilePath(memoryDir: string, name: string): string;
|
|
39
121
|
export declare function coerceGate(raw: string): Record<string, unknown>;
|
|
40
122
|
/** Coerce one `--surface` value into a validated surfaces entry. Strict where
|
|
@@ -96,6 +178,13 @@ export declare function applyExtensionChanges(frontmatter: Record<string, unknow
|
|
|
96
178
|
/** The frontmatter-overlay flags, keyed by flag name, carrying the prose true
|
|
97
179
|
* on BOTH leaves. `write` appends its creation clauses with `withConstraint`;
|
|
98
180
|
* neither leaf restates the other's rules. */
|
|
181
|
+
/** The selector flags, keyed by flag name, carrying the prose true on every
|
|
182
|
+
* leaf that accepts them. A leaf appends its own clause with `selectorParam`;
|
|
183
|
+
* none of them restates the shared rules. */
|
|
184
|
+
export declare const SELECTOR_PARAMS: Record<string, FlagParam>;
|
|
185
|
+
/** One selector flag, with leaf-specific prose appended to the shared
|
|
186
|
+
* constraint and any leaf-specific schema override applied. */
|
|
187
|
+
export declare function selectorParam(name: string, overrides?: Partial<FlagParam>, extraConstraint?: string): FlagParam;
|
|
99
188
|
export declare const FRONTMATTER_OVERLAY_PARAMS: Record<string, FlagParam>;
|
|
100
189
|
/** One overlay flag, with leaf-specific prose appended to the shared
|
|
101
190
|
* constraint and any leaf-specific schema override applied. */
|
|
@@ -105,8 +194,9 @@ export declare function overlayParam(name: string, overrides?: Partial<FlagParam
|
|
|
105
194
|
* `--doc-rationale`, because `--rationale` there means why THIS REVISION is
|
|
106
195
|
* happening. Same field, same prose, two flag names that cannot be confused. */
|
|
107
196
|
export declare const DOC_RATIONALE_CONSTRAINT = "Frontmatter rationale \u2014 the observed agent failure that made this doc necessary. Maintainer-facing only: never ships in any delivered surface (boot render, on-read injection, `memory read` content), visible only via `memory read --frontmatter`. Omitting the flag preserves an existing rationale unchanged.";
|
|
108
|
-
export declare const GUIDE_SURFACES = "Every doc appears in its directory\u2019s listing by default (suppress with --unlisted); everything beyond the listing is explicit `surfaces` routing \u2014 entries declaring WHEN the doc delivers and how much. Events: `boot` delivers in the boot catalog every agent sees; `workspace-open` delivers in first-message context when cwd/profile mounts the doc\u2019s project store (project stores only); `read` fires when the agent reads a matching file (globs vs the file\u2019s absolute path and basename, `./`-anchored globs vs its path relative to the store\u2019s owning repo dir, `match-frontmatter` predicates over the read file\u2019s own YAML frontmatter); `memory-read` fires when another memory doc is read (globs vs that doc\u2019s canonical name, `./` anchored to this doc\u2019s own name directory); `command` fires when a matching shell command runs (globs vs the whole command string, `*` crossing `/`). An entry may also carry `gate`, a node-config predicate using the same vocabulary as the document-level `gate`: event constraints and entry gate both must match, then all participating entries fold to the highest `at` (`content` > `preview` > `name`), with no cross-entry deny precedence. The document-level `gate` remains the hard eligibility check: when it fails, no automatic surface can deliver the document. `at` sets how much delivers: `name` the bare tag, `preview` the routing line, `content` the whole body. Explicit `memory read` and listings remain deliberate access and ignore gates/rungs; only companion docs routed by their `memory-read` entries use entry gates. Each entry is paid by every future agent it fires on, so default down: no surfaces at all is correct for reference depth reached through listings and [[links]], and when a doc fits in a single sentence, deliver `content` directly \u2014 a `preview` routing line would run longer than the doc itself. Sentence-length `content` docs are correct; never pad a memory to be more verbose than the rule or fact it carries.";
|
|
197
|
+
export declare const GUIDE_SURFACES = "Every doc appears in its directory\u2019s listing by default (suppress with --unlisted); everything beyond the listing is explicit `surfaces` routing \u2014 entries declaring WHEN the doc delivers and how much. Events: `boot` delivers in the boot catalog every agent sees; `workspace-open` delivers in first-message context when cwd/profile mounts the doc\u2019s project store (project stores only); `read` fires when the agent reads a matching file (globs vs the file\u2019s absolute path and basename, `./`-anchored globs vs its path relative to the store\u2019s owning repo dir, `match-frontmatter` predicates over the read file\u2019s own YAML frontmatter); `memory-read` fires when another memory doc is read (globs vs that doc\u2019s canonical name, `./` anchored to this doc\u2019s routing anchor \u2014 its own canonical name when it is its directory\u2019s document, otherwise the canonical directory it sits in); `command` fires when a matching shell command runs (globs vs the whole command string, `*` crossing `/`). An entry may also carry `gate`, a node-config predicate using the same vocabulary as the document-level `gate`: event constraints and entry gate both must match, then all participating entries fold to the highest `at` (`content` > `preview` > `name`), with no cross-entry deny precedence. The document-level `gate` remains the hard eligibility check: when it fails, no automatic surface can deliver the document. `at` sets how much delivers: `name` the bare tag, `preview` the routing line, `content` the whole body. Explicit `memory read` and listings remain deliberate access and ignore gates/rungs; only companion docs routed by their `memory-read` entries use entry gates. Each entry is paid by every future agent it fires on, so default down: no surfaces at all is correct for reference depth reached through listings and [[links]], and when a doc fits in a single sentence, deliver `content` directly \u2014 a `preview` routing line would run longer than the doc itself. Sentence-length `content` docs are correct; never pad a memory to be more verbose than the rule or fact it carries.";
|
|
109
198
|
export declare const GUIDE_ROUTING_LINE = "The routing line (--when-and-why-to-read) is the only text an agent reads before deciding to load the doc. The test for its when-clause: it names an observable circumstance in the reader\u2019s current work, not the doc\u2019s topic reworded as an activity. If the WHEN can be inferred from the title alone, it is not a real trigger. Bad on a todo list: \"When planning or prioritizing work across this profile.\" Good: \"When the user mentions something from their todos, or asks what is still outstanding across this profile.\" The test for its because-clause: if it can be derived by paraphrasing the doc\u2019s advice, it is a restatement, not a payoff \u2014 a real payoff names a consequence in the reader\u2019s world that the document itself never asserts. Bad: \"because only genuine first principles belong in taste memory.\" Bad: \"because keeping the test loop fast and free of speculative tests protects the development pace\" \u2014 the doc\u2019s rule as an outcome, derivable straight from its advice. Good: \"because identifying throughlines in user taste lets future decisions be made faster and with less re-litigation.\" Someone mid-task who has not read the doc must be able to decide from this line alone whether the read is worth it. If you cannot name the concrete situation that triggers it, you do not yet understand the memory \u2014 ask the user one sharp question instead of improvising.";
|
|
110
199
|
export declare const GUIDE_PREDICATE_VOCABULARY = "Document gates, surface-entry gates, and match-frontmatter share the same predicate language: a field map is AND-ed across fields; dotted fields resolve nested values; field matchers may be scalar, array, or object. Scalar matchers do exact equality, with arrays matching any element. Array matchers do membership or intersection. Object matchers accept `eq`, `ne`, `in`, `nin`, `exists`, `contains`, `containsAll`, `containsAny`, `matches`, `imatches`, `gt`, `gte`, `lt`, and `lte`. Combinators are `all`, `any`, and `not`; sibling field matchers next to them are AND-ed in. An empty condition is inert. An unknown op never matches.";
|
|
111
|
-
export declare const GUIDE_DOC_LINKS = "Link related docs with `[[canonical/name]]`. A doc link in any body is a first-class cross-reference to another memory document by its exact canonical name \u2014 the same identifier `crtr memory read` takes. A bare directory name is a valid link too: following it returns that directory\u2019s
|
|
200
|
+
export declare const GUIDE_DOC_LINKS = "Link related docs with `[[canonical/name]]`. A doc link in any body is a first-class cross-reference to another memory document by its exact canonical name \u2014 the same identifier `crtr memory read` takes, namespace included for a project document. A bare directory name is a valid link too: following it returns that directory\u2019s own document when it has one, plus the directory listing. Links are pointers, never transclusion: the linked body is loaded only when a reader follows it, so a link costs nothing until needed. `crtr memory lint` fails on a link that resolves to no document or directory, and `crtr memory read` lists a doc\u2019s resolvable links alongside its body. There is no alias, label, or old-name form \u2014 a renamed target needs its links rewritten.";
|
|
201
|
+
export declare const GUIDE_CANONICAL_NAMES = "A document has exactly one address: its canonical name, the store\u2019s namespace composed with the document\u2019s store-local name. A repository declares its namespace once, as `namespace:` on the root `INDEX.md` of `<repository root>/.crouter/memory/`; a store nested inside that repository composes under the repository namespace plus its own directory path relative to the repository root, and declares nothing itself. An installed plugin\u2019s store mounts under the plugin\u2019s own name; user, profile, node, and builtin stores have no namespace, so their local names are already canonical. A local doc `unit-tests` in a store that declares `namespace: acme/core` therefore answers only at `acme/core/unit-tests`, and the store\u2019s root document answers at `acme/core`; a store at `packages/api/.crouter/memory/` in a repository declaring `namespace: acme` answers under `acme/packages/api`. A non-root explicit `name:` in frontmatter is store-LOCAL \u2014 it never carries the namespace, and composition is unconditional, so a name that merely looks prefixed is prefixed again. The namespace itself is immutable through the memory commands: `crtr memory write <namespace> --dir <repository root>` declares it once in an empty repository-root store, `crtr sys migrate --dir <repository root>` converts a legacy one, and nothing else rewrites it. A trailing `INDEX` is never part of an address in any store: `area/INDEX.md` is the document attached to directory `area`, so it answers at `area` and reading `area` returns that body together with the directory\u2019s immediate listing. Resolution is exact \u2014 a file path, a bare leaf, a `<scope>/<name>` spelling, and a trailing `/INDEX` all fail \u2014 so run `crtr memory find <leaf>` when you do not know the canonical name.";
|
|
112
202
|
export {};
|