@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,8 +1,23 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
1
2
|
import { defineLeaf } from '../../core/command.js';
|
|
2
3
|
import { usage } from '../../core/errors.js';
|
|
3
|
-
import {
|
|
4
|
+
import { ensureDir, realpathOrSelf, walkFiles, writeText } from '../../core/fs-utils.js';
|
|
5
|
+
import { associateRepository } from '../../core/memory/repository-association.js';
|
|
4
6
|
import { appendHistoryRecord, buildHistoryRecord, historyLogPathFor, } from '../../core/memory/history.js';
|
|
5
|
-
import { DOC_RATIONALE_CONSTRAINT, GUIDE_DOC_LINKS, GUIDE_PREDICATE_VOCABULARY, GUIDE_ROUTING_LINE, GUIDE_SURFACES,
|
|
7
|
+
import { DOC_RATIONALE_CONSTRAINT, GUIDE_CANONICAL_NAMES, GUIDE_DOC_LINKS, GUIDE_PREDICATE_VOCABULARY, GUIDE_ROUTING_LINE, GUIDE_SURFACES, planNewDocumentPlacement, resolveWriteSelector, requireMountedStore, buildOrigin, coerceGate, coerceSurface, memoryExtensionCatalogForDoc, memoryExtensionFieldCatalogHelp, overlayParam, requireCanonicalName, selectorParam, parseRequestedExtensionChanges, applyExtensionChanges, serializeMemoryDoc, } from './shared.js';
|
|
8
|
+
function emptyMemoryStore(memoryDir) {
|
|
9
|
+
return walkFiles(memoryDir, (name) => name.endsWith('.md') && name !== 'SKILL.md', (name) => name === '.crouter').length === 0;
|
|
10
|
+
}
|
|
11
|
+
function hasWorkspaceFrontDoor(surfaces) {
|
|
12
|
+
const workspaceOpen = surfaces.some((entry) => entry['on'] === 'workspace-open' && entry['at'] === 'content');
|
|
13
|
+
const readEntry = surfaces.some((entry) => {
|
|
14
|
+
if (entry['on'] !== 'read' || entry['at'] !== 'content')
|
|
15
|
+
return false;
|
|
16
|
+
const match = entry['match'];
|
|
17
|
+
return match === './**' || (Array.isArray(match) && match.includes('./**'));
|
|
18
|
+
});
|
|
19
|
+
return workspaceOpen && readEntry;
|
|
20
|
+
}
|
|
6
21
|
// A topic's memory set stays usable only when authors treat cohesion as a creation
|
|
7
22
|
// gate; otherwise small corrections accumulate as overlapping leaves whose routing
|
|
8
23
|
// lines cannot tell a future reader which one owns the topic.
|
|
@@ -12,24 +27,25 @@ export const writeLeaf = defineLeaf({
|
|
|
12
27
|
whenToUse: 'you are recording a new knowledge document or preference that does not exist yet. Creation only — a name already taken at the resolved scope is an error, because revising a stored document goes through `crtr memory edit`, which requires a rationale and records the revision.',
|
|
13
28
|
help: {
|
|
14
29
|
name: 'memory write',
|
|
15
|
-
summary: 'create memory
|
|
30
|
+
summary: 'create a memory document at the resolved store from frontmatter flags + a stdin body',
|
|
16
31
|
guide: 'Every frontmatter flag decides who sees this doc, when, and at what context cost. Each rung up is paid by every future agent at every boot or read, so default each rung down.\n\n' +
|
|
17
32
|
'Pick the kind. knowledge is consulted for facts or procedures; preference directs behavior. The kind choice is about how the doc is used, not about how long it is.\n\n' +
|
|
18
33
|
'Store reusable current truth, not session notes. Useful memories are non-obvious procedures, gotchas, durable preferences, and cross-repo conventions. Do not store chat summaries, implementation history, or facts already recorded in the repo.\n\n' +
|
|
19
34
|
GUIDE_SURFACES + '\n\n' +
|
|
20
35
|
'Choose the scope. `project` is for facts any agent in one repo needs. `user` is for person-wide facts and preferences that should follow the user everywhere. `profile` is for the profile’s bundle of dirs: cross-repo conventions, how the pieces relate, or the user’s stance toward that body of work. `node` is scratch memory only this running node sees; it rides into this node’s knowledge block and dies with the node. When unsure, choose the narrowest scope that will still reach the next agent who needs it.\n\n' +
|
|
21
|
-
'A workspace front door is an ordinary doc carrying the entry pair {on: workspace-open, at: content} plus {on: read, match: "./**", at: content}: it enters first-message context when cwd/profile mounts its project store and fires on any file read beneath the store’s owning dir. Target the exact project with --dir. Keep only the project constraints, key commands, architecture orientation, and conventions that differ from defaults. `crtr memory lint`
|
|
36
|
+
'A workspace front door is an ordinary doc carrying the entry pair {on: workspace-open, at: content} plus {on: read, match: "./**", at: content}: it enters first-message context when cwd/profile mounts its project store and fires on any file read beneath the store’s owning dir. Target the exact project with --dir. Keep only the project constraints, key commands, architecture orientation, and conventions that differ from defaults. `crtr memory lint` requires this front door on the repository-root guide for a repository managed by the selected profile; nested stores may carry ordinary guides without a missing-door finding.\n\n' +
|
|
22
37
|
'Choose the hook — boot vs read. A boot entry rides the boot catalog every agent sees; a read entry fires only when a matching file is actually read. Put code-specific knowledge in the owning project store, give it the narrowest real file glob, and keep it off boot when the file read is the useful trigger. Knowledge about a person or process usually has no file boundary, so skip read entries and route it through boot instead.\n\n' +
|
|
23
38
|
'Write the routing line (--when-and-why-to-read) first, before storing anything. ' + GUIDE_ROUTING_LINE + '\n\n' +
|
|
24
39
|
GUIDE_PREDICATE_VOCABULARY + '\n\n' +
|
|
40
|
+
GUIDE_CANONICAL_NAMES + '\n\n' +
|
|
25
41
|
GUIDE_DOC_LINKS + '\n\n' +
|
|
26
|
-
'When a doc grows long or information-rich, nest it into a graph instead of letting it become a scroll. The main doc at the topic’s path keeps the high-level, most load-bearing information, most important first; depth splits into reference docs under the topic’s directory (`area/topic/...`), each pointed at with a `[[link]]`. Split by subject: a leaf earns its link by covering a different subject a task might need on its own; a leaf of offloaded “further evidence”, examples, or references is never followed, so supporting material either sits in the main doc next to the point it supports or gets cut. The main doc is the entry point a reader can act from alone; a reference leaf is loaded only when the task needs that depth. Give reference leaves no surfaces at all — the directory listing and the link from the main doc are how they are found, so any routing entry just double-charges every boot or read for depth the graph already routes. Keep
|
|
42
|
+
'When a doc grows long or information-rich, nest it into a graph instead of letting it become a scroll. The main doc at the topic’s path keeps the high-level, most load-bearing information, most important first; depth splits into reference docs under the topic’s directory (`area/topic/...`), each pointed at with a `[[link]]`. Split by subject: a leaf earns its link by covering a different subject a task might need on its own; a leaf of offloaded “further evidence”, examples, or references is never followed, so supporting material either sits in the main doc next to the point it supports or gets cut. The main doc is the entry point a reader can act from alone; a reference leaf is loaded only when the task needs that depth. Give reference leaves no surfaces at all — the directory listing and the link from the main doc are how they are found, so any routing entry just double-charges every boot or read for depth the graph already routes. State each fact once. Keep facts that affect action or judgment, including constraints, exceptions, numbers, and exact names. Remove known context, inferable conclusions, filler transitions, and examples that resolve no ambiguity. `crtr memory lint` caps body length by delivery rung and its findings carry the split guidance.\n\n' +
|
|
27
43
|
'A directory needs no index doc: reading a directory name returns its listing — each member’s routing line — so never author a doc that merely lists, fronts, or paraphrases its siblings. Write a directory-level doc only for synthesis: an operating guide or the cluster’s mechanics, ordering, conditions, and relationships, content no single member can carry. Guided entrance into a topic is an ordinary member doc, found through the listing like any other.\n\n' +
|
|
28
44
|
'Find before write. Prefer slightly expanding an existing document with `crtr memory edit`, nesting genuinely separate depth under its topic, and updating the existing `when-and-why-to-read` (plus its INDEX router when present) over creating another similar memory. A new document earns its own identity only when it has a distinct read trigger and a coherent body whose merge into the existing document would make it harder to route or use. Group related docs with path names (area/topic). Provenance is stamped here and preserved by every later revision. Run `crtr memory lint` after authoring.\n\n' +
|
|
29
45
|
'--rationale is the gap this doc exists to close — the observed agent failure that prompted it, captured from user signal (a correction, a mistake you watched happen) rather than inferred from the doc’s own content. If the rationale is guessable from reading the doc, it is not the real one — a guessable gap is one agents do not actually fall into. Omit the flag when you have no observed gap to record.\n\n' +
|
|
30
46
|
'Revise an existing doc with `crtr memory edit`.',
|
|
31
47
|
params: [
|
|
32
|
-
{ kind: 'positional', name: 'name', required: true, constraint: '
|
|
48
|
+
{ kind: 'positional', name: 'name', required: true, constraint: 'Full canonical identity. Project writes require `<namespace>/<local name>`; writing the namespace itself targets the repository-root document. A trailing `/INDEX` is invalid because directory documents answer at the directory name. The identity must be free in the selected exact store.' },
|
|
33
49
|
overlayParam('kind', { required: true }),
|
|
34
50
|
overlayParam('when-and-why-to-read', { required: true }),
|
|
35
51
|
overlayParam('short-form'),
|
|
@@ -39,13 +55,13 @@ export const writeLeaf = defineLeaf({
|
|
|
39
55
|
overlayParam('slash'),
|
|
40
56
|
{ kind: 'flag', name: 'rationale', type: 'string', required: false, constraint: DOC_RATIONALE_CONSTRAINT },
|
|
41
57
|
{ kind: 'flag', name: 'extension', type: 'string', required: false, repeatable: true, constraint: 'Set one declared plugin field as `extensions.<plugin>.<field>=VALUE`. The path is required in full; booleans accept only true or false, numbers require finite numeric syntax, and strings/enums preserve the literal text after the first =. Every requested field validates before the document is written.' },
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
58
|
+
selectorParam('scope-write'),
|
|
59
|
+
selectorParam('dir'),
|
|
60
|
+
selectorParam('profile'),
|
|
45
61
|
{ kind: 'stdin', name: 'body', required: true, constraint: 'Document body (markdown, no frontmatter). Piped on stdin only — this leaf already claims the one positional for NAME, so a second bare argv token is rejected, not silently accepted as the body.' },
|
|
46
62
|
],
|
|
47
63
|
output: [
|
|
48
|
-
{ name: 'name', type: 'string', required: true, constraint: 'The
|
|
64
|
+
{ name: 'name', type: 'string', required: true, constraint: 'The full canonical document name written.' },
|
|
49
65
|
{ name: 'kind', type: 'string', required: true, constraint: 'Kind recorded in frontmatter.' },
|
|
50
66
|
{ name: 'scope', type: 'string', required: true, constraint: 'Scope the document was written to: user, project, profile, or node.' },
|
|
51
67
|
{ name: 'path', type: 'string', required: true, constraint: 'Absolute path to the written document.' },
|
|
@@ -57,7 +73,7 @@ export const writeLeaf = defineLeaf({
|
|
|
57
73
|
outputKind: 'object',
|
|
58
74
|
dynamicState: () => memoryExtensionFieldCatalogHelp('write'),
|
|
59
75
|
effects: [
|
|
60
|
-
'Creates
|
|
76
|
+
'Creates the selected physical memory document with the given frontmatter fields + stdin body, and opens its mirrored `.history` sidecar with a `create` record. An empty repository-root store is initialized at its root namespace only when the ordinary workspace front door surfaces are supplied.'
|
|
61
77
|
],
|
|
62
78
|
},
|
|
63
79
|
run: async (input) => {
|
|
@@ -67,17 +83,41 @@ export const writeLeaf = defineLeaf({
|
|
|
67
83
|
const profileArg = input['profile'];
|
|
68
84
|
const body = input['body'] ?? '';
|
|
69
85
|
const dirArg = input['dir'];
|
|
70
|
-
const { scope
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
86
|
+
const selector = resolveWriteSelector({ scope: scopeArg, profile: profileArg, dir: dirArg });
|
|
87
|
+
const { scope, memoryDir, store } = selector;
|
|
88
|
+
let initializing = false;
|
|
89
|
+
if (scope === 'project' && store.mountStatus !== 'ready' && dirArg !== undefined && emptyMemoryStore(memoryDir)) {
|
|
90
|
+
const association = associateRepository(realpathOrSelf(dirArg));
|
|
91
|
+
if (association.ok) {
|
|
92
|
+
if (association.association.ownerRelativePath !== '') {
|
|
93
|
+
throw usage(`${dirArg} is a nested store in the repository rooted at ${association.association.repositoryRoot}; only the repository root declares a namespace`, {
|
|
94
|
+
next: 'crtr memory write <namespace> --dir <repositoryRoot>, or crtr sys migrate --dir <repositoryRoot>',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
initializing = true;
|
|
98
|
+
}
|
|
99
|
+
else if (association.code === 'no-project-root') {
|
|
100
|
+
initializing = true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (scope === 'project' && store.mountStatus !== 'ready' && !initializing)
|
|
104
|
+
requireMountedStore(store);
|
|
105
|
+
let canonicalName;
|
|
106
|
+
let path;
|
|
107
|
+
if (initializing) {
|
|
108
|
+
canonicalName = requireCanonicalName(name);
|
|
109
|
+
path = join(memoryDir, 'INDEX.md');
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
const placement = planNewDocumentPlacement(store, name);
|
|
113
|
+
canonicalName = placement.canonicalName;
|
|
114
|
+
path = placement.path;
|
|
78
115
|
}
|
|
116
|
+
const extensionChanges = parseRequestedExtensionChanges(input['extension'], undefined, memoryExtensionCatalogForDoc({ scope, path }));
|
|
79
117
|
const frontmatter = {};
|
|
80
118
|
frontmatter['kind'] = kind;
|
|
119
|
+
if (initializing)
|
|
120
|
+
frontmatter['namespace'] = canonicalName;
|
|
81
121
|
// Provenance is runtime-stamped ONCE, here — who/when/where authored this
|
|
82
122
|
// doc. Every later revision preserves it, so it always points at the
|
|
83
123
|
// conversation that created the doc, not the last one to touch it.
|
|
@@ -112,7 +152,17 @@ export const writeLeaf = defineLeaf({
|
|
|
112
152
|
surfacesVal.some((e) => e !== null && typeof e === 'object' && e['on'] === 'workspace-open')) {
|
|
113
153
|
throw usage('a workspace-open surfaces entry is a project-store mount route; user, profile, and node memory cannot carry one — drop the entry or write to a project store');
|
|
114
154
|
}
|
|
155
|
+
if (initializing) {
|
|
156
|
+
const surfaces = Array.isArray(surfacesVal) ? surfacesVal.filter((entry) => entry !== null && typeof entry === 'object') : [];
|
|
157
|
+
if (!hasWorkspaceFrontDoor(surfaces)) {
|
|
158
|
+
throw usage('empty project initialization requires the ordinary workspace front door: --surface \'{on: workspace-open, at: content}\' and --surface \'{on: read, match: "./**", at: content}\'', {
|
|
159
|
+
memory: canonicalName,
|
|
160
|
+
next: `Pass both front-door surfaces when initializing ${canonicalName} with --dir.`,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
115
164
|
const after = serializeMemoryDoc(frontmatter, body);
|
|
165
|
+
ensureDir(memoryDir);
|
|
116
166
|
writeText(path, after);
|
|
117
167
|
const logPath = historyLogPathFor(memoryDir, path);
|
|
118
168
|
appendHistoryRecord(logPath, buildHistoryRecord({ op: 'create', before: '', after }));
|
|
@@ -121,6 +171,7 @@ export const writeLeaf = defineLeaf({
|
|
|
121
171
|
// result or its collapsed viewer preview.
|
|
122
172
|
const selectedKeys = [
|
|
123
173
|
'kind',
|
|
174
|
+
...(initializing ? ['namespace'] : []),
|
|
124
175
|
...(input['whenAndWhyToRead'] !== undefined ? ['when-and-why-to-read'] : []),
|
|
125
176
|
...(input['shortForm'] !== undefined ? ['short-form'] : []),
|
|
126
177
|
...(input['unlisted'] === true ? ['unlisted'] : []),
|
|
@@ -132,14 +183,14 @@ export const writeLeaf = defineLeaf({
|
|
|
132
183
|
];
|
|
133
184
|
const selectedFrontmatter = selectedKeys.map((key) => ({ key, value: frontmatter[key] }));
|
|
134
185
|
return {
|
|
135
|
-
name,
|
|
186
|
+
name: canonicalName,
|
|
136
187
|
kind,
|
|
137
188
|
scope,
|
|
138
189
|
path,
|
|
139
190
|
created: true,
|
|
140
191
|
frontmatter: selectedFrontmatter,
|
|
141
192
|
log_path: logPath,
|
|
142
|
-
follow_up: `Read it back with \`crtr memory read ${
|
|
193
|
+
follow_up: `Read it back with \`crtr memory read ${canonicalName}\`, revise it later with \`crtr memory edit ${canonicalName} --rationale "<why>"\`, or browse the inventory with \`crtr memory list\`.`,
|
|
143
194
|
};
|
|
144
195
|
},
|
|
145
196
|
});
|
package/dist/commands/memory.js
CHANGED
|
@@ -18,12 +18,12 @@ export function registerMemory() {
|
|
|
18
18
|
rootEntry: {
|
|
19
19
|
concept: 'a memory document you read on demand — knowledge or a preference',
|
|
20
20
|
desc: 'list, read, search, and write memory documents',
|
|
21
|
-
useWhen: 'durable knowledge and preferences shared across nodes and sessions — use when prior guidance may apply to the current task, or when a non-obvious reusable truth should outlive this conversation.
|
|
21
|
+
useWhen: 'durable knowledge and preferences shared across nodes and sessions — use when prior guidance may apply to the current task, or when a non-obvious reusable truth should outlive this conversation. Every document has one canonical name, a crtr identifier rather than a file path — read docs through the command surface, never cat or find the markdown off disk.',
|
|
22
22
|
},
|
|
23
23
|
help: {
|
|
24
24
|
name: 'memory',
|
|
25
25
|
summary: 'list, read, search, and write memory documents — knowledge and preferences',
|
|
26
|
-
model: '
|
|
26
|
+
model: 'One address per document: its canonical name, the store’s namespace composed with its store-local name. A repository declares that namespace once, as `namespace:` on the root `INDEX.md` of `<repository root>/.crouter/memory/`, and a store nested inside the repository composes under that namespace plus its own path from the repository root; user, profile, node, and builtin names carry no namespace, and an installed plugin’s documents mount under the plugin’s own name. Resolution is exact — a file path, a bare leaf, a `<scope>/<name>` spelling, and a trailing `/INDEX` all fail — so `find` is the discovery surface when you do not know a name and `list` browses the whole inventory. A trailing `INDEX` is never part of an address, so a directory may carry its own document: reading the directory name returns that body together with the directory’s immediate listing. Precedence — node > project stack > profile > user > builtin — picks the winner among documents sharing ONE canonical name; `--paths` reports every physical candidate behind a name, and `--dir <project>` reaches one exact store. One verb per operation: `write` creates, `edit` revises (every revision carries a rationale and is recorded), `move` relocates or renames a doc and rewrites inbound `[[refs]]` corpus-wide, `delete` removes, and `history` reads how a document reached its current state. Beyond listings, delivery is explicit `surfaces` routing: each entry names the event that fires it (boot, workspace-open, read, memory-read, command) and how much delivers (name, preview, content). A selected profile widens the project stack to every project in its purview, and each of those relationships caps what its stores deliver to the boot and workspace-open events; `read`, find, listings, and file- and command-routed delivery see the full corpus regardless.',
|
|
27
27
|
},
|
|
28
28
|
children: [listLeaf, readLeaf, findLeaf, writeLeaf, editLeaf, moveLeaf, historyLeaf, deleteLeaf, originLeaf, lintLeaf],
|
|
29
29
|
});
|
|
@@ -12,7 +12,7 @@ export declare function assertKind(kind: string): void;
|
|
|
12
12
|
*
|
|
13
13
|
* Keep this block cheap and caller-agnostic: help should not depend on the
|
|
14
14
|
* running node's current persona env, which can lag after polymorph. Sub-kinds
|
|
15
|
-
* (e.g. `
|
|
15
|
+
* (e.g. `audit/security`) are OMITTED here — `KindConfig.availableTo`
|
|
16
16
|
* defaults to the sub-kind's own top-level ancestor, and this generic block has
|
|
17
17
|
* no single ancestor to check against, so only an explicit `availableTo: ['*']`
|
|
18
18
|
* sub-kind (universally available) earns a place in this list. A direct launch
|
|
@@ -40,7 +40,7 @@ export function assertKind(kind) {
|
|
|
40
40
|
*
|
|
41
41
|
* Keep this block cheap and caller-agnostic: help should not depend on the
|
|
42
42
|
* running node's current persona env, which can lag after polymorph. Sub-kinds
|
|
43
|
-
* (e.g. `
|
|
43
|
+
* (e.g. `audit/security`) are OMITTED here — `KindConfig.availableTo`
|
|
44
44
|
* defaults to the sub-kind's own top-level ancestor, and this generic block has
|
|
45
45
|
* no single ancestor to check against, so only an explicit `availableTo: ['*']`
|
|
46
46
|
* sub-kind (universally available) earns a place in this list. A direct launch
|
|
@@ -23,7 +23,7 @@ const nodeList = defineLeaf({
|
|
|
23
23
|
summary: 'list nodes on the canvas, filtered by any combination of attribute slices and a graph-scope (--under) that AND together',
|
|
24
24
|
params: [
|
|
25
25
|
{ kind: 'flag', name: 'status', type: 'string', required: false, constraint: 'Filter status (comma-separated for several; accepted values: active, idle, done, dead, canceled). NOTE: `active` means the engine process is live (never closed), NOT that the node is generating right now — an active node is usually dormant between turns. To tell working-vs-idle, check the pi session-file mtime or CPU, not status.' },
|
|
26
|
-
{ kind: 'flag', name: 'kind', type: 'string', required: false, constraint: 'Filter by persona kind (comma-separated for several). The <kinds> list below names every top-level installable kind; a sub-kind
|
|
26
|
+
{ kind: 'flag', name: 'kind', type: 'string', required: false, constraint: 'Filter by persona kind (comma-separated for several). The <kinds> list below names every top-level installable kind; a registered sub-kind filters too by exact path even though it is not listed.' },
|
|
27
27
|
{ kind: 'flag', name: 'mode', type: 'string', required: false, constraint: 'Filter by mode (comma-separated for several; accepted values: base, orchestrator).' },
|
|
28
28
|
{ kind: 'flag', name: 'lifecycle', type: 'string', required: false, constraint: 'Filter by lifecycle (comma-separated for several; accepted values: terminal, resident).' },
|
|
29
29
|
{ kind: 'flag', name: 'profile', type: 'string', required: false, constraint: 'Filter by profile. On the local canvas, accepts an exact profile id or a unique manifest name from the <profiles> list below. Against a remote canvas, pass the exact profile id carried by its node rows.' },
|
|
@@ -131,7 +131,7 @@ export const nodeConfig = defineLeaf({
|
|
|
131
131
|
{ kind: 'flag', name: 'pane', type: 'string', required: false, constraint: 'tmux pane id to resolve the node from. Defaults to $TMUX_PANE.' },
|
|
132
132
|
{ kind: 'flag', name: 'model', type: 'string', required: false, constraint: 'Model spec: exact provider/id, capability tier (ultra|strong|medium|light), family alias (opus|sonnet|haiku), or a free-text substring when the broker is live. Dormant nodes require a provider/id, tier, or alias.' },
|
|
133
133
|
{ kind: 'flag', name: 'lifecycle', type: 'enum', choices: ['terminal', 'resident'], required: false, constraint: 'Set lifecycle headlessly without closing the viewer. terminal owes a final and reaps when done; resident stays interactable while attached or awaiting something live.' },
|
|
134
|
-
{ kind: 'flag', name: 'kind', type: 'string', required: false, constraint: 'Persona kind. The <kinds> list below names every top-level installable kind and when to use each; a sub-kind
|
|
134
|
+
{ kind: 'flag', name: 'kind', type: 'string', required: false, constraint: 'Persona kind. The <kinds> list below names every top-level installable kind and when to use each; a registered sub-kind is valid too by exact path but not listed here.' },
|
|
135
135
|
{ kind: 'flag', name: 'mode', type: 'enum', choices: ['base', 'orchestrator'], required: false, constraint: 'Set persona mode headlessly. base is hands-on; orchestrator holds a roadmap and delegates. orchestrator seeds a roadmap scaffold if absent.' },
|
|
136
136
|
{ kind: 'flag', name: 'name', type: 'string', required: false, constraint: 'Rename the node; if the node has a live window, also rename that viewer window.' },
|
|
137
137
|
],
|
|
@@ -241,7 +241,7 @@ export const nodePromote = defineLeaf({
|
|
|
241
241
|
name: 'node promote',
|
|
242
242
|
summary: 'promote yourself to an orchestrator when worthwhile parallel delegation should make coordination your primary job; task duration, sequential phases, or one helper do not qualify. Mode only — lifecycle stays as-is unless you pass --resident',
|
|
243
243
|
params: [
|
|
244
|
-
{ kind: 'flag', name: 'kind', type: 'string', required: false, constraint: 'Specialize as this kind of orchestrator. The <kinds> list below names every top-level installable kind and when to use each; a sub-kind
|
|
244
|
+
{ kind: 'flag', name: 'kind', type: 'string', required: false, constraint: 'Specialize as this kind of orchestrator. The <kinds> list below names every top-level installable kind and when to use each; a registered sub-kind is valid too by exact path but not listed here. For an exact composed persona list, use `crtr sys prompt-review --list --kind <kind>` with the target kind. Defaults to your current kind. Promoting from a generic kind? CHOOSE a concrete one — it sets the orchestrator persona you revive into.' },
|
|
245
245
|
{ kind: 'flag', name: 'resident', type: 'bool', required: false, constraint: 'ALSO flip lifecycle→resident: make the node interactable — it is never forced to submit a final, stays wakeable while attached or awaiting something live, and completes after the unattended grace otherwise. Omit to stay terminal/orchestrator (delegates + holds a roadmap, but still owes a final up the spine and reaps when done).' },
|
|
246
246
|
{ kind: 'flag', name: 'model', type: 'enum', choices: ['ultra', 'strong'], required: false, constraint: 'Change the model you run on, by capability tier: `ultra` (frontier — reserve for high-taste judgment or enormous work: speccing, planning something large, e2e-testing something hard to test) or `strong` (opus — regular dev work). Omit to keep your current model. An orchestrator steering work is never weaker than opus, so these are the only two choices; the change is durable across future revives.' },
|
|
247
247
|
{ kind: 'flag', name: 'node', type: 'string', required: false, constraint: 'Node to promote. Defaults to the caller (CRTR_NODE_ID).' },
|
|
@@ -258,7 +258,7 @@ export const nodePromote = defineLeaf({
|
|
|
258
258
|
],
|
|
259
259
|
dynamicState: () => kindsStateBlock(),
|
|
260
260
|
outputKind: 'object',
|
|
261
|
-
effects: ['Flips mode→orchestrator + kind→chosen (lifecycle unchanged unless --resident, which also flips lifecycle→resident); --model durably pins the model tier; rewrites the launch spec to that kind\'s orchestrator persona; seeds context/roadmap.md scaffold if absent.', '
|
|
261
|
+
effects: ['Flips mode→orchestrator + kind→chosen (lifecycle unchanged unless --resident, which also flips lifecycle→resident); --model durably pins the model tier; rewrites the launch spec to that kind\'s orchestrator persona; seeds context/roadmap.md scaffold if absent.', 'The next model request is gated on appending and persisting your new-role guidance. If a fresh context starts first, its rebuilt baseline carries the new role.'],
|
|
262
262
|
},
|
|
263
263
|
run: async (input) => {
|
|
264
264
|
const id = input['node'] ?? process.env['CRTR_NODE_ID'];
|
|
@@ -327,7 +327,7 @@ const nodeDemote = defineLeaf({
|
|
|
327
327
|
{ name: 'detached', type: 'boolean', required: false, constraint: 'True when --detach closed the agent\'s viewer pane (broker keeps running).' },
|
|
328
328
|
],
|
|
329
329
|
outputKind: 'object',
|
|
330
|
-
effects: ['Flips the node\'s lifecycle→terminal and rebuilds its launch spec so a future revive boots terminal — it stays focused and running, now owing a final up the spine.', 'The
|
|
330
|
+
effects: ['Flips the node\'s lifecycle→terminal and rebuilds its launch spec so a future revive boots terminal — it stays focused and running, now owing a final up the spine.', 'The next model request is gated on appending and persisting the role transition. If a fresh context starts first, its rebuilt baseline carries the new lifecycle.', 'With --detach: closes the agent\'s viewer pane WITHOUT touching the broker engine — it keeps generating off-screen, reconnectable by a later `focus`.'],
|
|
331
331
|
},
|
|
332
332
|
run: async (input) => {
|
|
333
333
|
const pane = input['pane'] ?? process.env['TMUX_PANE'];
|
|
@@ -373,7 +373,7 @@ export const nodeYield = defineLeaf({
|
|
|
373
373
|
guide: 'Persist anything needed after refresh and send any pending human question before invoking; in-flight asks survive the refresh.',
|
|
374
374
|
params: [
|
|
375
375
|
{ kind: 'flag', name: 'promote', type: 'bool', required: false, constraint: 'Also become an orchestrator as you refresh. Pass only when (1) the remaining work contains independent units that can run in parallel and (2) the task is large enough that parallel execution will materially improve intelligence, productivity, or elapsed throughput after coordination and synthesis. Task length, context exhaustion, sequential phases, or one helper are not enough; keep hands-on work in base mode and yield again as needed. Promote when coordinating and integrating children becomes your primary job. Already an orchestrator? This is not an error: your mode stays orchestrator and a missing roadmap is seeded.' },
|
|
376
|
-
{ kind: 'flag', name: 'kind', type: 'string', required: false, constraint: 'Respecialize as you refresh. The <kinds> list below names every top-level available kind and when to choose it; a sub-kind
|
|
376
|
+
{ kind: 'flag', name: 'kind', type: 'string', required: false, constraint: 'Respecialize as you refresh. The <kinds> list below names every top-level available kind and when to choose it; a registered sub-kind is valid too by exact path but not listed here. Defaults to your current kind. With --promote it sets the orchestrator kind you become; without --promote it changes the kind while preserving your current mode.' },
|
|
377
377
|
{ kind: 'flag', name: 'model', type: 'enum', choices: ['ultra', 'strong'], required: false, constraint: 'Change the model your fresh revive runs on, by capability tier: `ultra` (frontier — reserve for high-taste judgment or enormous work: speccing, planning something large, e2e-testing something hard to test) or `strong` (opus — regular dev work). Omit to keep your current model. A node steering work is never weaker than opus, so these are the only two choices; the change is durable across future revives.' },
|
|
378
378
|
// Deliberate fail-first contract: builtin orchestration guidance shows bare
|
|
379
379
|
// `crtr node yield`; that invocation fails fast and surfaces yield's full help just in
|
|
@@ -147,11 +147,17 @@ export const marketRemove = defineLeaf({
|
|
|
147
147
|
return { name, removed: true };
|
|
148
148
|
},
|
|
149
149
|
});
|
|
150
|
+
/** Stage a fresh checkout beside the active root. A clone that fails throws
|
|
151
|
+
* the git error: reporting the active revision as current would present a
|
|
152
|
+
* failed refresh as an up-to-date one, which is how a checkout stays pinned
|
|
153
|
+
* to a stale revision with nothing on screen to say so. */
|
|
150
154
|
function stageGitRoot(url, ref, active, candidate) {
|
|
151
|
-
|
|
152
|
-
|
|
155
|
+
try {
|
|
156
|
+
clone(url, candidate, { depth: 1, ref });
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
153
159
|
removePath(candidate);
|
|
154
|
-
|
|
160
|
+
throw error;
|
|
155
161
|
}
|
|
156
162
|
return { active, candidate, previous: `${candidate}.previous` };
|
|
157
163
|
}
|
|
@@ -195,21 +201,17 @@ async function updateMarketplaceTarget(target) {
|
|
|
195
201
|
if (isGitRepo(target.root)) {
|
|
196
202
|
const candidate = join(dirname(target.root), `.${target.name}.${process.pid}.${Date.now()}.candidate`);
|
|
197
203
|
marketplaceCandidate = stageGitRoot(target.url, target.ref, target.root, candidate);
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if (activeManifest === null)
|
|
210
|
-
throw notFound(`marketplace manifest not found after refresh: ${target.root}/.crouter-marketplace/marketplace.json`);
|
|
211
|
-
manifest = activeManifest;
|
|
212
|
-
}
|
|
204
|
+
cleanupRoots.push(candidate);
|
|
205
|
+
const candidateManifest = readMarketplaceManifest(candidate);
|
|
206
|
+
if (candidateManifest === null)
|
|
207
|
+
throw notFound(`marketplace manifest not found in candidate checkout: ${candidate}/.crouter-marketplace/marketplace.json`);
|
|
208
|
+
manifest = candidateManifest;
|
|
209
|
+
// The staged checkout replaces the active root even at an unchanged
|
|
210
|
+
// revision. The tree is package-owned content, not a working copy: an
|
|
211
|
+
// in-place edit to it (a memory migration reaching a plugin through its
|
|
212
|
+
// symlink, a hand edit) otherwise survives every update, and a revision
|
|
213
|
+
// comparison would call that drifted tree current.
|
|
214
|
+
stagedRoots.push(marketplaceCandidate);
|
|
213
215
|
}
|
|
214
216
|
else {
|
|
215
217
|
const activeManifest = readMarketplaceManifest(target.root);
|
|
@@ -221,6 +223,8 @@ async function updateMarketplaceTarget(target) {
|
|
|
221
223
|
if (isSymlink(plugin.root)) {
|
|
222
224
|
if (marketplaceCandidate === undefined)
|
|
223
225
|
continue;
|
|
226
|
+
// A symlinked plugin resolves through the marketplace root, so the root
|
|
227
|
+
// swap above already replaced its content.
|
|
224
228
|
const entry = manifest.plugins.find((candidate) => candidate.name === plugin.name);
|
|
225
229
|
if (entry === undefined || !isMarketplaceRelativeSource(entry.source)) {
|
|
226
230
|
throw general(`marketplace candidate removes relative-source plugin "${plugin.name}" while it is installed`);
|
|
@@ -251,15 +255,12 @@ async function updateMarketplaceTarget(target) {
|
|
|
251
255
|
const candidate = join(scopeRoot, 'tmp', `${plugin.name}.${process.pid}.${Date.now()}.candidate`);
|
|
252
256
|
ensureDir(join(scopeRoot, 'tmp'));
|
|
253
257
|
const staged = stageGitRoot(remote, branch, plugin.root, candidate);
|
|
254
|
-
if (staged === undefined)
|
|
255
|
-
continue;
|
|
256
258
|
cleanupRoots.push(candidate);
|
|
257
259
|
const candidateManifest = readPluginManifest(candidate);
|
|
258
260
|
if (candidateManifest === null)
|
|
259
261
|
throw notFound(`plugin manifest not found in update candidate: ${candidate}/.crouter-plugin/plugin.json`);
|
|
260
262
|
candidates.push(candidatePlugin(plugin, candidate, candidateManifest));
|
|
261
|
-
|
|
262
|
-
stagedRoots.push(staged);
|
|
263
|
+
stagedRoots.push(staged);
|
|
263
264
|
}
|
|
264
265
|
for (const candidate of candidates) {
|
|
265
266
|
await assertPluginCandidateValid(candidate.plugin.manifest, candidate.plugin.root, candidate.plugin.scope, candidate.scopeRoot, `${candidate.plugin.root}/.crouter-plugin/plugin.json`, candidates);
|
|
@@ -294,7 +295,7 @@ async function updateMarketplaceTarget(target) {
|
|
|
294
295
|
}
|
|
295
296
|
export const marketUpdate = defineLeaf({
|
|
296
297
|
name: 'update',
|
|
297
|
-
description: '
|
|
298
|
+
description: 'replace marketplace source with its latest revision',
|
|
298
299
|
whenToUse: 'refreshing one named marketplace source from git, or all registered marketplace sources when no name is given; also updates installed plugins sourced from refreshed marketplaces',
|
|
299
300
|
help: {
|
|
300
301
|
name: 'pkg market update',
|
|
@@ -307,7 +308,7 @@ export const marketUpdate = defineLeaf({
|
|
|
307
308
|
{ name: 'updated', type: 'object[]', required: true, constraint: 'One entry per marketplace processed: {name, updated, sha}.' },
|
|
308
309
|
],
|
|
309
310
|
outputKind: 'object',
|
|
310
|
-
effects: ['Stages and validates marketplace and sourced-plugin revisions before atomically activating them. Updates installed plugin content/version for plugins sourced from refreshed marketplaces.'],
|
|
311
|
+
effects: ['Stages and validates marketplace and sourced-plugin revisions before atomically activating them, replacing each checkout even at an unchanged revision — local modifications inside those directories are discarded. `updated` reports whether the revision moved, not whether the checkout was replaced. Updates installed plugin content/version for plugins sourced from refreshed marketplaces.'],
|
|
311
312
|
},
|
|
312
313
|
run: async (input) => {
|
|
313
314
|
const name = input['name'];
|
|
@@ -4,18 +4,34 @@ interface MarketplaceRef {
|
|
|
4
4
|
marketplace: string;
|
|
5
5
|
plugin: string;
|
|
6
6
|
}
|
|
7
|
+
interface InstallResult {
|
|
8
|
+
name: string;
|
|
9
|
+
scope: Scope;
|
|
10
|
+
path: string;
|
|
11
|
+
memory?: PluginMemoryReport;
|
|
12
|
+
}
|
|
13
|
+
/** Who owns the physical memory corpus a candidate gate converges. A `package`
|
|
14
|
+
* corpus is bytes this command owns — staged, or installed under the scope's
|
|
15
|
+
* plugins dir — so a failed activation still rolls the package back. A `linked`
|
|
16
|
+
* corpus is the caller's own directory the install keeps as a live link: the
|
|
17
|
+
* rewrite lands there, outlives a rejected install, and is never rolled back. */
|
|
18
|
+
type PluginMemoryOwnership = 'package' | 'linked';
|
|
19
|
+
interface PluginMemoryReport extends Record<string, unknown> {
|
|
20
|
+
/** Markdown documents the candidate's memory store holds. */
|
|
21
|
+
docs: number;
|
|
22
|
+
/** Store-relative documents this gate rewrote to reach exact canonical identity. */
|
|
23
|
+
migrated: string[];
|
|
24
|
+
/** The caller-owned directory converged in place, absent for a package corpus. */
|
|
25
|
+
linkedSource?: string;
|
|
26
|
+
}
|
|
7
27
|
/** Validate a package candidate before it gains an active plugin path. The
|
|
8
28
|
* candidate namespace shadows any installed declaration of the same name. */
|
|
9
|
-
export declare function assertPluginCandidateValid(manifest: PluginManifest, root: string, scope: Scope, scopeRootPath: string, where: string, candidates?: readonly HookPluginCandidate[]): Promise<
|
|
29
|
+
export declare function assertPluginCandidateValid(manifest: PluginManifest, root: string, scope: Scope, scopeRootPath: string, where: string, candidates?: readonly HookPluginCandidate[], ownership?: PluginMemoryOwnership): Promise<PluginMemoryReport | undefined>;
|
|
10
30
|
export declare function isMarketplaceRelativeSource(source: string): boolean;
|
|
11
31
|
/** Install one marketplace plugin into a scope. Exported so `sys setup` can
|
|
12
32
|
* install the default plugin set through the same path `pkg plugin install`
|
|
13
33
|
* uses — refresh the source, resolve the entry, link/clone, register. */
|
|
14
|
-
export declare function installFromMarketplace(ref: MarketplaceRef, scope: Scope): Promise<
|
|
15
|
-
name: string;
|
|
16
|
-
scope: Scope;
|
|
17
|
-
path: string;
|
|
18
|
-
}>;
|
|
34
|
+
export declare function installFromMarketplace(ref: MarketplaceRef, scope: Scope): Promise<InstallResult>;
|
|
19
35
|
export declare const pluginInstall: import("../../core/command.js").LeafDef;
|
|
20
36
|
export declare const pluginRemove: import("../../core/command.js").LeafDef;
|
|
21
37
|
export declare const pluginEnable: import("../../core/command.js").LeafDef;
|