@crouton-kit/crouter 0.3.17 → 0.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-root.js +6 -0
- package/dist/builtin-memory/crouter-development/marketplaces.md +164 -0
- package/dist/builtin-memory/crouter-development/personas/base-prompt.md +58 -0
- package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +60 -0
- package/dist/builtin-memory/crouter-development/personas.md +117 -0
- package/dist/builtin-memory/crouter-development/plugins.md +163 -0
- package/dist/builtin-memory/design.md +60 -0
- package/dist/builtin-memory/development.md +116 -0
- package/dist/builtin-memory/planning.md +66 -0
- package/dist/builtin-memory/spec.md +99 -0
- package/dist/builtin-personas/design/{base.md → PERSONA.md} +4 -0
- package/dist/builtin-personas/design/orchestrator.md +1 -1
- package/dist/builtin-personas/developer/{base.md → PERSONA.md} +4 -0
- package/dist/builtin-personas/developer/orchestrator.md +1 -1
- package/dist/builtin-personas/explore/{base.md → PERSONA.md} +4 -0
- package/dist/builtin-personas/general/{base.md → PERSONA.md} +4 -0
- package/dist/builtin-personas/lifecycle/resident.md +1 -1
- package/dist/builtin-personas/lifecycle/terminal.md +5 -2
- package/dist/builtin-personas/orchestration-kernel.md +15 -24
- package/dist/builtin-personas/plan/{base.md → PERSONA.md} +4 -0
- package/dist/builtin-personas/plan/orchestrator.md +1 -1
- package/dist/builtin-personas/plan/reviewers/architecture-fit/{base.md → PERSONA.md} +1 -1
- package/dist/builtin-personas/plan/reviewers/code-smells/{base.md → PERSONA.md} +1 -1
- package/dist/builtin-personas/plan/reviewers/pattern-consistency/{base.md → PERSONA.md} +1 -1
- package/dist/builtin-personas/plan/reviewers/requirements-coverage/{base.md → PERSONA.md} +1 -1
- package/dist/builtin-personas/plan/reviewers/security/{base.md → PERSONA.md} +1 -1
- package/dist/builtin-personas/review/{base.md → PERSONA.md} +4 -0
- package/dist/builtin-personas/runtime-base.md +6 -3
- package/dist/builtin-personas/spec/{base.md → PERSONA.md} +4 -0
- package/dist/builtin-personas/spec/orchestrator.md +1 -1
- package/dist/builtin-personas/waiting.md +8 -0
- package/dist/builtin-skills/skills/crouter-development/personas/SKILL.md +24 -14
- package/dist/builtin-skills/skills/crouter-development/personas/base-prompt/SKILL.md +4 -4
- package/dist/builtin-skills/skills/crouter-development/personas/orchestrator-prompt/SKILL.md +1 -1
- package/dist/builtin-skills/skills/crouter-development/plugins/SKILL.md +2 -2
- package/dist/builtin-views/_lib/states.mjs +161 -0
- package/dist/builtin-views/canvas/client.mjs +303 -0
- package/dist/builtin-views/canvas/view.mjs +576 -0
- package/dist/builtin-views/git-pr/client.mjs +440 -0
- package/dist/builtin-views/git-pr/view.mjs +675 -0
- package/dist/builtin-views/inbox/_lib/render.mjs +177 -0
- package/dist/builtin-views/inbox/sources/gmail.mjs +965 -0
- package/dist/builtin-views/inbox/sources/linkedin.mjs +427 -0
- package/dist/builtin-views/inbox/view.mjs +889 -0
- package/dist/builtin-views/linkedin/client.mjs +610 -0
- package/dist/builtin-views/linkedin/view.mjs +1171 -0
- package/dist/clients/attach/attach-cmd.d.ts +2 -0
- package/dist/clients/attach/attach-cmd.js +354 -0
- package/dist/clients/attach/chat-view.d.ts +77 -0
- package/dist/clients/attach/chat-view.js +450 -0
- package/dist/clients/attach/clipboard-image.d.ts +16 -0
- package/dist/clients/attach/clipboard-image.js +113 -0
- package/dist/clients/attach/config-load.d.ts +31 -0
- package/dist/clients/attach/config-load.js +113 -0
- package/dist/clients/attach/extension-dialogs.d.ts +29 -0
- package/dist/clients/attach/extension-dialogs.js +101 -0
- package/dist/clients/attach/input-controller.d.ts +54 -0
- package/dist/clients/attach/input-controller.js +204 -0
- package/dist/clients/attach/slash-commands.d.ts +36 -0
- package/dist/clients/attach/slash-commands.js +200 -0
- package/dist/clients/attach/view-socket.d.ts +48 -0
- package/dist/clients/attach/view-socket.js +126 -0
- package/dist/commands/attention.js +3 -3
- package/dist/commands/canvas-prune.js +1 -1
- package/dist/commands/daemon.js +4 -3
- package/dist/commands/human/prompts.js +4 -10
- package/dist/commands/human/queue.js +43 -8
- package/dist/commands/human/shared.d.ts +28 -1
- package/dist/commands/human/shared.js +48 -10
- package/dist/commands/memory/find.d.ts +1 -0
- package/dist/commands/memory/find.js +180 -0
- package/dist/commands/memory/lint.d.ts +1 -0
- package/dist/commands/memory/lint.js +140 -0
- package/dist/commands/memory/list.d.ts +1 -0
- package/dist/commands/memory/list.js +79 -0
- package/dist/commands/memory/read.js +103 -0
- package/dist/commands/memory/shared.d.ts +30 -0
- package/dist/commands/memory/shared.js +122 -0
- package/dist/commands/memory/write.d.ts +1 -0
- package/dist/commands/memory/write.js +85 -0
- package/dist/commands/memory.d.ts +2 -0
- package/dist/commands/memory.js +27 -0
- package/dist/commands/node.d.ts +3 -2
- package/dist/commands/node.js +660 -65
- package/dist/commands/pkg/market-manage.js +1 -1
- package/dist/commands/push.js +6 -6
- package/dist/commands/revive.js +1 -1
- package/dist/commands/skill/author.js +1 -1
- package/dist/commands/skill/shared.d.ts +1 -8
- package/dist/commands/skill/shared.js +2 -55
- package/dist/commands/skill.js +9 -14
- package/dist/commands/sys/doctor.js +1 -1
- package/dist/commands/sys/update.js +1 -1
- package/dist/commands/view-cycle.d.ts +2 -0
- package/dist/commands/view-cycle.js +125 -0
- package/dist/commands/view-list.d.ts +2 -0
- package/dist/commands/view-list.js +66 -0
- package/dist/commands/view-new.d.ts +2 -0
- package/dist/commands/view-new.js +70 -0
- package/dist/commands/view-pick.d.ts +2 -0
- package/dist/commands/view-pick.js +119 -0
- package/dist/commands/view-run.d.ts +2 -0
- package/dist/commands/view-run.js +191 -0
- package/dist/commands/view.d.ts +2 -0
- package/dist/commands/view.js +29 -0
- package/dist/core/__tests__/broker-lifecycle.test.d.ts +1 -0
- package/dist/core/__tests__/broker-lifecycle.test.js +677 -0
- package/dist/core/__tests__/broker-sdk-wiring.test.d.ts +1 -0
- package/dist/core/__tests__/broker-sdk-wiring.test.js +166 -0
- package/dist/core/__tests__/cascade-close.test.js +12 -2
- package/dist/core/__tests__/child-death-wake.test.d.ts +1 -0
- package/dist/core/__tests__/child-death-wake.test.js +245 -0
- package/dist/core/__tests__/context-intro.test.js +76 -62
- package/dist/core/__tests__/daemon-boot.test.js +14 -5
- package/dist/core/__tests__/daemon-liveness.test.js +34 -9
- package/dist/core/__tests__/detach-focus.test.d.ts +1 -0
- package/dist/core/__tests__/detach-focus.test.js +206 -0
- package/dist/core/__tests__/draw-style.test.d.ts +1 -0
- package/dist/core/__tests__/draw-style.test.js +258 -0
- package/dist/core/__tests__/fixtures/c3-custom-provider-ext.d.ts +2 -0
- package/dist/core/__tests__/fixtures/c3-custom-provider-ext.js +18 -0
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +138 -0
- package/dist/core/__tests__/fixtures/fake-engine.js +614 -0
- package/dist/core/__tests__/fixtures/fake-pi-host.js +1 -0
- package/dist/core/__tests__/flagship-lifecycle.test.js +7 -1
- package/dist/core/__tests__/frame-decoder-perf.test.d.ts +1 -0
- package/dist/core/__tests__/frame-decoder-perf.test.js +198 -0
- package/dist/core/__tests__/helpers/harness.d.ts +9 -0
- package/dist/core/__tests__/helpers/harness.js +111 -1
- package/dist/core/__tests__/home-session.test.js +41 -8
- package/dist/core/__tests__/human-new-window-regression.test.d.ts +1 -0
- package/dist/core/__tests__/human-new-window-regression.test.js +101 -0
- package/dist/core/__tests__/human-surface-target.test.d.ts +1 -0
- package/dist/core/__tests__/human-surface-target.test.js +98 -0
- package/dist/core/__tests__/kickoff.test.js +37 -3
- package/dist/core/__tests__/live-mutation.test.js +50 -33
- package/dist/core/__tests__/memory.test.js +23 -115
- package/dist/core/__tests__/persona-subkind.test.js +18 -15
- package/dist/core/__tests__/placement-focus.test.js +5 -0
- package/dist/core/__tests__/placement-teardown.test.js +54 -11
- package/dist/core/__tests__/relaunch.test.js +4 -3
- package/dist/core/__tests__/review-render-pane-regression.test.d.ts +1 -0
- package/dist/core/__tests__/review-render-pane-regression.test.js +133 -0
- package/dist/core/__tests__/spawn-root.test.js +10 -0
- package/dist/core/__tests__/spike-harness.test.js +1 -0
- package/dist/core/__tests__/wake-bearings.test.d.ts +1 -0
- package/dist/core/__tests__/wake-bearings.test.js +156 -0
- package/dist/core/__tests__/wake-origin.test.d.ts +1 -0
- package/dist/core/__tests__/wake-origin.test.js +110 -0
- package/dist/core/bootstrap.js +1 -1
- package/dist/core/canvas/browse/__tests__/render.test.js +1 -0
- package/dist/core/canvas/browse/app.js +24 -2
- package/dist/core/canvas/browse/model.d.ts +38 -2
- package/dist/core/canvas/browse/model.js +134 -10
- package/dist/core/canvas/browse/render.d.ts +6 -12
- package/dist/core/canvas/browse/render.js +72 -104
- package/dist/core/canvas/canvas.js +15 -22
- package/dist/core/canvas/db.js +46 -0
- package/dist/core/canvas/index.d.ts +1 -0
- package/dist/core/canvas/index.js +1 -0
- package/dist/core/canvas/paths.d.ts +4 -1
- package/dist/core/canvas/paths.js +10 -4
- package/dist/core/canvas/pid.d.ts +4 -0
- package/dist/core/canvas/pid.js +23 -0
- package/dist/core/canvas/render.d.ts +11 -2
- package/dist/core/canvas/render.js +69 -0
- package/dist/core/canvas/types.d.ts +85 -3
- package/dist/core/canvas/types.js +2 -2
- package/dist/core/canvas/wakeups.d.ts +76 -0
- package/dist/core/canvas/wakeups.js +185 -0
- package/dist/core/config.js +4 -1
- package/dist/core/frontmatter.js +37 -124
- package/dist/core/help.d.ts +6 -0
- package/dist/core/help.js +7 -0
- package/dist/core/memory-resolver.d.ts +49 -0
- package/dist/core/memory-resolver.js +141 -0
- package/dist/core/personas/index.d.ts +4 -3
- package/dist/core/personas/index.js +3 -2
- package/dist/core/personas/loader.d.ts +41 -16
- package/dist/core/personas/loader.js +133 -29
- package/dist/core/personas/resolve.d.ts +4 -4
- package/dist/core/personas/resolve.js +28 -16
- package/dist/core/predicate.d.ts +63 -0
- package/dist/core/predicate.js +189 -0
- package/dist/core/resolver.js +26 -5
- package/dist/core/runtime/bearings.d.ts +53 -12
- package/dist/core/runtime/bearings.js +132 -59
- package/dist/core/runtime/broker-cli.d.ts +1 -0
- package/dist/core/runtime/broker-cli.js +46 -0
- package/dist/core/runtime/broker-protocol.d.ts +332 -0
- package/dist/core/runtime/broker-protocol.js +153 -0
- package/dist/core/runtime/broker-sdk.d.ts +48 -0
- package/dist/core/runtime/broker-sdk.js +72 -0
- package/dist/core/runtime/broker.d.ts +55 -0
- package/dist/core/runtime/broker.js +1128 -0
- package/dist/core/runtime/close.js +35 -6
- package/dist/core/runtime/host.d.ts +53 -0
- package/dist/core/runtime/host.js +186 -0
- package/dist/core/runtime/kickoff.d.ts +2 -1
- package/dist/core/runtime/kickoff.js +91 -5
- package/dist/core/runtime/launch.d.ts +45 -2
- package/dist/core/runtime/launch.js +65 -2
- package/dist/core/runtime/lifecycle.js +23 -6
- package/dist/core/runtime/memory.d.ts +2 -42
- package/dist/core/runtime/memory.js +11 -162
- package/dist/core/runtime/nodes.d.ts +33 -0
- package/dist/core/runtime/nodes.js +59 -1
- package/dist/core/runtime/persona.js +21 -11
- package/dist/core/runtime/pi-vendored.d.ts +18 -0
- package/dist/core/runtime/pi-vendored.js +49 -0
- package/dist/core/runtime/placement.d.ts +42 -14
- package/dist/core/runtime/placement.js +228 -38
- package/dist/core/runtime/promote.d.ts +0 -6
- package/dist/core/runtime/promote.js +1 -12
- package/dist/core/runtime/{demote.d.ts → recycle.d.ts} +5 -5
- package/dist/core/runtime/{demote.js → recycle.js} +27 -11
- package/dist/core/runtime/reset.js +8 -6
- package/dist/core/runtime/revive.d.ts +2 -0
- package/dist/core/runtime/revive.js +34 -34
- package/dist/core/runtime/spawn.d.ts +19 -0
- package/dist/core/runtime/spawn.js +75 -22
- package/dist/core/runtime/stop-guard.d.ts +1 -1
- package/dist/core/runtime/stop-guard.js +6 -1
- package/dist/core/runtime/tmux-chrome.d.ts +1 -1
- package/dist/core/runtime/tmux-chrome.js +1 -1
- package/dist/core/runtime/tmux.d.ts +28 -0
- package/dist/core/runtime/tmux.js +80 -6
- package/dist/core/scope.d.ts +11 -0
- package/dist/core/scope.js +39 -0
- package/dist/core/spawn.d.ts +25 -1
- package/dist/core/spawn.js +72 -7
- package/dist/core/substrate/gate.d.ts +13 -0
- package/dist/core/substrate/gate.js +21 -0
- package/dist/core/substrate/index.d.ts +7 -0
- package/dist/core/substrate/index.js +18 -0
- package/dist/core/substrate/on-read.d.ts +14 -0
- package/dist/core/substrate/on-read.js +292 -0
- package/dist/core/substrate/render.d.ts +25 -0
- package/dist/core/substrate/render.js +256 -0
- package/dist/core/substrate/schema.d.ts +76 -0
- package/dist/core/substrate/schema.js +124 -0
- package/dist/core/substrate/session-cache.d.ts +30 -0
- package/dist/core/substrate/session-cache.js +77 -0
- package/dist/core/substrate/subject.d.ts +41 -0
- package/dist/core/substrate/subject.js +54 -0
- package/dist/core/tui/contract.d.ts +83 -0
- package/dist/core/tui/contract.js +8 -0
- package/dist/core/tui/draw.d.ts +96 -0
- package/dist/core/tui/draw.js +339 -0
- package/dist/core/tui/host.d.ts +29 -0
- package/dist/core/tui/host.js +379 -0
- package/dist/core/tui/loader.d.ts +16 -0
- package/dist/core/tui/loader.js +94 -0
- package/dist/core/{canvas/browse → tui}/terminal.js +7 -6
- package/dist/core/wake.d.ts +86 -0
- package/dist/core/wake.js +308 -0
- package/dist/daemon/crtrd.d.ts +29 -4
- package/dist/daemon/crtrd.js +662 -46
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.d.ts +1 -0
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +171 -0
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +19 -12
- package/dist/pi-extensions/canvas-commands.d.ts +3 -0
- package/dist/pi-extensions/canvas-commands.js +10 -0
- package/dist/pi-extensions/canvas-context-intro.d.ts +17 -0
- package/dist/pi-extensions/canvas-context-intro.js +55 -15
- package/dist/pi-extensions/canvas-doc-substrate.d.ts +44 -0
- package/dist/pi-extensions/canvas-doc-substrate.js +112 -0
- package/dist/pi-extensions/canvas-nav.d.ts +3 -0
- package/dist/pi-extensions/canvas-nav.js +145 -34
- package/dist/pi-extensions/canvas-stophook.js +17 -8
- package/dist/pi-extensions/canvas-view.d.ts +21 -0
- package/dist/pi-extensions/canvas-view.js +75 -0
- package/dist/prompts/skill.js +19 -26
- package/dist/prompts/view.d.ts +7 -0
- package/dist/prompts/view.js +101 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.js +1 -0
- package/package.json +9 -4
- package/dist/commands/skill/find.d.ts +0 -4
- package/dist/commands/skill/find.js +0 -257
- package/dist/commands/skill/read.js +0 -91
- /package/dist/commands/{skill → memory}/read.d.ts +0 -0
- /package/dist/core/{canvas/browse → tui}/terminal.d.ts +0 -0
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* Resolution order (highest → lowest precedence): project > user > builtin.
|
|
6
6
|
*
|
|
7
7
|
* Layout on disk:
|
|
8
|
-
* <root>/personas/<kind>/
|
|
8
|
+
* <root>/personas/<kind>/PERSONA.md
|
|
9
9
|
* <root>/personas/<kind>/orchestrator.md
|
|
10
10
|
* <root>/personas/orchestration-kernel.md
|
|
11
|
+
* <root>/personas/<kind>/<...>/PERSONA.md (nested sub-personas)
|
|
11
12
|
*
|
|
12
13
|
* The builtin root is src/builtin-personas (or dist/builtin-personas in the
|
|
13
14
|
* compiled build), resolved relative to this module — mirrors the pattern used
|
|
@@ -38,6 +39,13 @@ export declare function loadKernel(): string;
|
|
|
38
39
|
* live in their own fragments, loaded below.
|
|
39
40
|
*/
|
|
40
41
|
export declare function loadRuntimeBase(): string;
|
|
42
|
+
/**
|
|
43
|
+
* Load the waiting fragment — the cross-kind "waiting is a way to end a turn"
|
|
44
|
+
* operating posture (arm a wake + go dormant instead of busy-looping or
|
|
45
|
+
* finishing-to-stop). Spliced into every node's baked prompt immediately after
|
|
46
|
+
* the lifecycle fragment (resolve.ts). Returns '' if the fragment is missing.
|
|
47
|
+
*/
|
|
48
|
+
export declare function loadWaitingFragment(): string;
|
|
41
49
|
/**
|
|
42
50
|
* Load the lifecycle fragment — the "how you end" contract, keyed on the node's
|
|
43
51
|
* lifecycle axis: `terminal` (drive to done + `push final`) or `resident`
|
|
@@ -55,29 +63,46 @@ export declare function loadLifecycleFragment(lifecycle: 'terminal' | 'resident'
|
|
|
55
63
|
*/
|
|
56
64
|
export declare function loadSpineFragment(hasManager: boolean): string;
|
|
57
65
|
/**
|
|
58
|
-
* Enumerate the kinds with at least one persona file (
|
|
66
|
+
* Enumerate the kinds with at least one persona file (PERSONA.md or
|
|
59
67
|
* orchestrator.md) across all scope roots (project/user/builtin). Used to
|
|
60
|
-
* validate a requested `--kind` and to list the valid choices.
|
|
68
|
+
* validate a requested `--kind` and to list the valid choices. Only the
|
|
69
|
+
* IMMEDIATE children of each root count — nested sub-personas never pollute
|
|
70
|
+
* the global kind list (see subPersonasFor).
|
|
61
71
|
*/
|
|
62
72
|
export declare function availableKinds(): string[];
|
|
63
|
-
|
|
73
|
+
/**
|
|
74
|
+
* The one-line "when to use this node type" gloss for `kind`, read from its
|
|
75
|
+
* `<kind>/PERSONA.md` `whenToUse` frontmatter (resolved project > user >
|
|
76
|
+
* builtin). Returns '' when the kind has no PERSONA.md or no `whenToUse`.
|
|
77
|
+
* Drives the dynamic kind list in `node new -h` / `node promote -h`.
|
|
78
|
+
*/
|
|
79
|
+
export declare function kindWhenToUse(kind: string): string;
|
|
80
|
+
export interface SubPersona {
|
|
64
81
|
/** Full kind string to spawn, e.g. 'plan/reviewers/security'. */
|
|
65
82
|
kind: string;
|
|
66
83
|
/** Leaf name, e.g. 'security'. */
|
|
67
84
|
name: string;
|
|
68
|
-
/** One-line "
|
|
69
|
-
|
|
85
|
+
/** One-line "when to use", from the sub-persona PERSONA.md `whenToUse` frontmatter (or ''). */
|
|
86
|
+
whenToUse: string;
|
|
70
87
|
}
|
|
71
88
|
/**
|
|
72
|
-
* Enumerate the
|
|
73
|
-
* personas
|
|
74
|
-
*
|
|
89
|
+
* Enumerate the sub-personas AVAILABLE TO `kind` — the nested specialist
|
|
90
|
+
* personas (e.g. `plan/reviewers/security`) a `kind` node may spawn, surfaced
|
|
91
|
+
* in its composed prompt (resolve.ts) and nowhere else.
|
|
92
|
+
*
|
|
93
|
+
* A sub-persona is any descendant dir (ANY depth) under a top-level kind dir
|
|
94
|
+
* that holds a PERSONA.md, EXCLUDING the top-level PERSONA.md itself. Its
|
|
95
|
+
* availability is its `availableTo` frontmatter: an explicit list of kind
|
|
96
|
+
* strings, or the wildcard `"*"`/`"all"` (visible to every kind); absent, it
|
|
97
|
+
* defaults to its own top-level ancestor kind. So the five `plan/reviewers/*`
|
|
98
|
+
* (no `availableTo`) are visible only to `plan`, while a sub-persona under
|
|
99
|
+
* `developer/` can declare `availableTo: [plan]` to surface in plan's menu —
|
|
100
|
+
* which is why ALL top-level kinds' descendants are scanned, not just `<kind>/`.
|
|
75
101
|
*
|
|
76
|
-
* Sub-
|
|
77
|
-
* immediate children of each
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* `<kind>/reviewers/<name>/base.md` — no code change.
|
|
102
|
+
* Sub-personas are intentionally NOT global kinds: `availableKinds()` scans only
|
|
103
|
+
* the immediate children of each root, so a nested sub-persona never leaks into
|
|
104
|
+
* the global list; it is reachable only by its full kind string. Precedence is
|
|
105
|
+
* project > user > builtin keyed on the FULL kind string — the highest root that
|
|
106
|
+
* defines a given kind string wins (and owns its `availableTo`).
|
|
82
107
|
*/
|
|
83
|
-
export declare function
|
|
108
|
+
export declare function subPersonasFor(kind: string): SubPersona[];
|
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* Resolution order (highest → lowest precedence): project > user > builtin.
|
|
6
6
|
*
|
|
7
7
|
* Layout on disk:
|
|
8
|
-
* <root>/personas/<kind>/
|
|
8
|
+
* <root>/personas/<kind>/PERSONA.md
|
|
9
9
|
* <root>/personas/<kind>/orchestrator.md
|
|
10
10
|
* <root>/personas/orchestration-kernel.md
|
|
11
|
+
* <root>/personas/<kind>/<...>/PERSONA.md (nested sub-personas)
|
|
11
12
|
*
|
|
12
13
|
* The builtin root is src/builtin-personas (or dist/builtin-personas in the
|
|
13
14
|
* compiled build), resolved relative to this module — mirrors the pattern used
|
|
@@ -55,11 +56,28 @@ function personaSearchRoots() {
|
|
|
55
56
|
return roots;
|
|
56
57
|
}
|
|
57
58
|
// ---------------------------------------------------------------------------
|
|
59
|
+
// Frontmatter scalar coercion
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
/** Coerce a frontmatter scalar to its string form, matching the legacy
|
|
62
|
+
* hand-rolled parser (which stringified every scalar). Strings pass through;
|
|
63
|
+
* number/boolean coerce via String(); null/undefined and non-scalars
|
|
64
|
+
* (objects/arrays) are dropped (→ null). The `yaml` package returns native
|
|
65
|
+
* scalar types, so without this a `typeof === 'string'` guard would silently
|
|
66
|
+
* DROP a numeric/boolean frontmatter value (e.g. blanking a menu line) where
|
|
67
|
+
* the old parser kept its stringified form. */
|
|
68
|
+
function scalarToString(v) {
|
|
69
|
+
if (typeof v === 'string')
|
|
70
|
+
return v;
|
|
71
|
+
if (typeof v === 'number' || typeof v === 'boolean')
|
|
72
|
+
return String(v);
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
58
76
|
// File resolution helpers
|
|
59
77
|
// ---------------------------------------------------------------------------
|
|
60
78
|
/**
|
|
61
79
|
* Find the first existing file across the scope roots.
|
|
62
|
-
* `relativePath` is relative to each root (e.g. 'general/
|
|
80
|
+
* `relativePath` is relative to each root (e.g. 'general/PERSONA.md').
|
|
63
81
|
*/
|
|
64
82
|
function resolveFile(relativePath) {
|
|
65
83
|
for (const root of personaSearchRoots()) {
|
|
@@ -92,6 +110,11 @@ function inlineIncludes(body) {
|
|
|
92
110
|
return kernelBody.trim();
|
|
93
111
|
});
|
|
94
112
|
}
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// Public API
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
/** The role-body filename for every kind/sub-persona (replaces legacy base.md). */
|
|
117
|
+
const PERSONA_FILE = 'PERSONA.md';
|
|
95
118
|
/**
|
|
96
119
|
* Load and parse a persona file for the given `kind` and `mode`.
|
|
97
120
|
*
|
|
@@ -99,7 +122,8 @@ function inlineIncludes(body) {
|
|
|
99
122
|
* On success, `@include` directives in the body are resolved and inlined.
|
|
100
123
|
*/
|
|
101
124
|
export function loadPersona(kind, mode) {
|
|
102
|
-
|
|
125
|
+
// base → PERSONA.md (the role body); orchestrator → its sibling orchestrator.md.
|
|
126
|
+
const relativePath = mode === 'orchestrator' ? `${kind}/orchestrator.md` : `${kind}/PERSONA.md`;
|
|
103
127
|
const filePath = resolveFile(relativePath);
|
|
104
128
|
if (!filePath)
|
|
105
129
|
return null;
|
|
@@ -136,6 +160,19 @@ export function loadRuntimeBase() {
|
|
|
136
160
|
const { body } = parseFrontmatterGeneric(src);
|
|
137
161
|
return body.trim();
|
|
138
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Load the waiting fragment — the cross-kind "waiting is a way to end a turn"
|
|
165
|
+
* operating posture (arm a wake + go dormant instead of busy-looping or
|
|
166
|
+
* finishing-to-stop). Spliced into every node's baked prompt immediately after
|
|
167
|
+
* the lifecycle fragment (resolve.ts). Returns '' if the fragment is missing.
|
|
168
|
+
*/
|
|
169
|
+
export function loadWaitingFragment() {
|
|
170
|
+
const filePath = resolveFile('waiting.md');
|
|
171
|
+
if (!filePath)
|
|
172
|
+
return '';
|
|
173
|
+
const { body } = parseFrontmatterGeneric(readFileSync(filePath, 'utf8'));
|
|
174
|
+
return body.trim();
|
|
175
|
+
}
|
|
139
176
|
/**
|
|
140
177
|
* Load the lifecycle fragment — the "how you end" contract, keyed on the node's
|
|
141
178
|
* lifecycle axis: `terminal` (drive to done + `push final`) or `resident`
|
|
@@ -165,9 +202,11 @@ export function loadSpineFragment(hasManager) {
|
|
|
165
202
|
return body.trim();
|
|
166
203
|
}
|
|
167
204
|
/**
|
|
168
|
-
* Enumerate the kinds with at least one persona file (
|
|
205
|
+
* Enumerate the kinds with at least one persona file (PERSONA.md or
|
|
169
206
|
* orchestrator.md) across all scope roots (project/user/builtin). Used to
|
|
170
|
-
* validate a requested `--kind` and to list the valid choices.
|
|
207
|
+
* validate a requested `--kind` and to list the valid choices. Only the
|
|
208
|
+
* IMMEDIATE children of each root count — nested sub-personas never pollute
|
|
209
|
+
* the global kind list (see subPersonasFor).
|
|
171
210
|
*/
|
|
172
211
|
export function availableKinds() {
|
|
173
212
|
const kinds = new Set();
|
|
@@ -178,42 +217,107 @@ export function availableKinds() {
|
|
|
178
217
|
if (!entry.isDirectory())
|
|
179
218
|
continue;
|
|
180
219
|
const dir = join(root, entry.name);
|
|
181
|
-
if (existsSync(join(dir,
|
|
220
|
+
if (existsSync(join(dir, PERSONA_FILE)) || existsSync(join(dir, 'orchestrator.md'))) {
|
|
182
221
|
kinds.add(entry.name);
|
|
183
222
|
}
|
|
184
223
|
}
|
|
185
224
|
}
|
|
186
225
|
return [...kinds].sort();
|
|
187
226
|
}
|
|
188
|
-
const REVIEWERS_SUBDIR = 'reviewers';
|
|
189
227
|
/**
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
228
|
+
* The one-line "when to use this node type" gloss for `kind`, read from its
|
|
229
|
+
* `<kind>/PERSONA.md` `whenToUse` frontmatter (resolved project > user >
|
|
230
|
+
* builtin). Returns '' when the kind has no PERSONA.md or no `whenToUse`.
|
|
231
|
+
* Drives the dynamic kind list in `node new -h` / `node promote -h`.
|
|
232
|
+
*/
|
|
233
|
+
export function kindWhenToUse(kind) {
|
|
234
|
+
const filePath = resolveFile(`${kind}/${PERSONA_FILE}`);
|
|
235
|
+
if (!filePath)
|
|
236
|
+
return '';
|
|
237
|
+
const { data } = parseFrontmatterGeneric(readFileSync(filePath, 'utf8'));
|
|
238
|
+
return scalarToString(data?.['whenToUse']) ?? '';
|
|
239
|
+
}
|
|
240
|
+
/** Recursively yield every dir under `dir` (inclusive) that holds a PERSONA.md,
|
|
241
|
+
* with `relKind` = the dir's path relative to the scope root (slash-joined).
|
|
242
|
+
* Dirs WITHOUT a PERSONA.md (e.g. a `reviewers/` grouping namespace) are
|
|
243
|
+
* transparent — they yield nothing themselves but are still descended into,
|
|
244
|
+
* so `plan/reviewers/security` keeps that exact kind string. */
|
|
245
|
+
function* walkPersonaDirs(dir, relParts) {
|
|
246
|
+
const file = join(dir, PERSONA_FILE);
|
|
247
|
+
if (existsSync(file))
|
|
248
|
+
yield { relKind: relParts.join('/'), file };
|
|
249
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
250
|
+
if (entry.isDirectory())
|
|
251
|
+
yield* walkPersonaDirs(join(dir, entry.name), [...relParts, entry.name]);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/** Parse a sub-persona's `availableTo` frontmatter into its availability set.
|
|
255
|
+
* Returns the wildcard sentinel `'*'` for `"*"`/`"all"` (scalar or in an
|
|
256
|
+
* array), an explicit list of kind strings when present, else the default
|
|
257
|
+
* `[topKind]` (the top-level ancestor kind). */
|
|
258
|
+
function parseAvailableTo(data, topKind) {
|
|
259
|
+
const isWild = (s) => {
|
|
260
|
+
const t = s.trim().toLowerCase();
|
|
261
|
+
return t === '*' || t === 'all';
|
|
262
|
+
};
|
|
263
|
+
const v = data ? data['availableTo'] : undefined;
|
|
264
|
+
if (v === undefined)
|
|
265
|
+
return [topKind];
|
|
266
|
+
const scalar = scalarToString(v);
|
|
267
|
+
if (scalar !== null)
|
|
268
|
+
return isWild(scalar) ? '*' : [scalar];
|
|
269
|
+
if (Array.isArray(v)) {
|
|
270
|
+
const arr = v.map(scalarToString).filter((x) => x !== null);
|
|
271
|
+
if (arr.some(isWild))
|
|
272
|
+
return '*';
|
|
273
|
+
return arr.length > 0 ? arr : [topKind];
|
|
274
|
+
}
|
|
275
|
+
return [topKind];
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Enumerate the sub-personas AVAILABLE TO `kind` — the nested specialist
|
|
279
|
+
* personas (e.g. `plan/reviewers/security`) a `kind` node may spawn, surfaced
|
|
280
|
+
* in its composed prompt (resolve.ts) and nowhere else.
|
|
193
281
|
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
282
|
+
* A sub-persona is any descendant dir (ANY depth) under a top-level kind dir
|
|
283
|
+
* that holds a PERSONA.md, EXCLUDING the top-level PERSONA.md itself. Its
|
|
284
|
+
* availability is its `availableTo` frontmatter: an explicit list of kind
|
|
285
|
+
* strings, or the wildcard `"*"`/`"all"` (visible to every kind); absent, it
|
|
286
|
+
* defaults to its own top-level ancestor kind. So the five `plan/reviewers/*`
|
|
287
|
+
* (no `availableTo`) are visible only to `plan`, while a sub-persona under
|
|
288
|
+
* `developer/` can declare `availableTo: [plan]` to surface in plan's menu —
|
|
289
|
+
* which is why ALL top-level kinds' descendants are scanned, not just `<kind>/`.
|
|
290
|
+
*
|
|
291
|
+
* Sub-personas are intentionally NOT global kinds: `availableKinds()` scans only
|
|
292
|
+
* the immediate children of each root, so a nested sub-persona never leaks into
|
|
293
|
+
* the global list; it is reachable only by its full kind string. Precedence is
|
|
294
|
+
* project > user > builtin keyed on the FULL kind string — the highest root that
|
|
295
|
+
* defines a given kind string wins (and owns its `availableTo`).
|
|
200
296
|
*/
|
|
201
|
-
export function
|
|
202
|
-
const
|
|
297
|
+
export function subPersonasFor(kind) {
|
|
298
|
+
const seen = new Set(); // full kind strings already resolved (higher root won)
|
|
299
|
+
const out = [];
|
|
203
300
|
for (const root of personaSearchRoots()) {
|
|
204
|
-
|
|
205
|
-
if (!existsSync(dir))
|
|
301
|
+
if (!existsSync(root))
|
|
206
302
|
continue;
|
|
207
|
-
for (const
|
|
208
|
-
if (!
|
|
209
|
-
continue; // higher root already won
|
|
210
|
-
const baseFile = join(dir, entry.name, 'base.md');
|
|
211
|
-
if (!existsSync(baseFile))
|
|
303
|
+
for (const top of readdirSync(root, { withFileTypes: true })) {
|
|
304
|
+
if (!top.isDirectory())
|
|
212
305
|
continue;
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
|
|
306
|
+
const topKind = top.name;
|
|
307
|
+
for (const { relKind, file } of walkPersonaDirs(join(root, topKind), [topKind])) {
|
|
308
|
+
if (relKind === topKind)
|
|
309
|
+
continue; // the top-level PERSONA.md is the kind itself, not a sub-persona
|
|
310
|
+
if (seen.has(relKind))
|
|
311
|
+
continue; // a higher root already resolved this kind string
|
|
312
|
+
seen.add(relKind);
|
|
313
|
+
const { data } = parseFrontmatterGeneric(readFileSync(file, 'utf8'));
|
|
314
|
+
const availableTo = parseAvailableTo(data, topKind);
|
|
315
|
+
if (availableTo !== '*' && !availableTo.includes(kind))
|
|
316
|
+
continue;
|
|
317
|
+
const whenToUse = scalarToString(data?.['whenToUse']) ?? '';
|
|
318
|
+
out.push({ kind: relKind, name: relKind.split('/').pop(), whenToUse });
|
|
319
|
+
}
|
|
216
320
|
}
|
|
217
321
|
}
|
|
218
|
-
return
|
|
322
|
+
return out.sort((a, b) => a.kind.localeCompare(b.kind));
|
|
219
323
|
}
|
|
@@ -4,17 +4,17 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Composition rules:
|
|
6
6
|
* mode==='base'
|
|
7
|
-
* → load <kind>/
|
|
7
|
+
* → load <kind>/PERSONA.md; if missing fall back to general defaults.
|
|
8
8
|
*
|
|
9
9
|
* mode==='orchestrator'
|
|
10
10
|
* → prefer <kind>/orchestrator.md (which must embed the kernel via
|
|
11
11
|
* @include orchestration-kernel.md — inlined by the loader).
|
|
12
12
|
* If no orchestrator.md exists for this kind, compose:
|
|
13
|
-
* <kind>/
|
|
14
|
-
* If even the
|
|
13
|
+
* <kind>/PERSONA.md body + '\n\n' + kernel body
|
|
14
|
+
* If even the PERSONA.md is missing, fall back to general defaults + kernel.
|
|
15
15
|
*
|
|
16
16
|
* Frontmatter from whichever file is the primary source (orchestrator.md >
|
|
17
|
-
*
|
|
17
|
+
* PERSONA.md) supplies model/skills/extensions/tools. Lifecycle and spine position
|
|
18
18
|
* are INPUTS (the caller decides them — root/child, terminal/resident), not
|
|
19
19
|
* derived here; they select the lifecycle/spine protocol fragments spliced
|
|
20
20
|
* ahead of the persona body.
|
|
@@ -4,32 +4,41 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Composition rules:
|
|
6
6
|
* mode==='base'
|
|
7
|
-
* → load <kind>/
|
|
7
|
+
* → load <kind>/PERSONA.md; if missing fall back to general defaults.
|
|
8
8
|
*
|
|
9
9
|
* mode==='orchestrator'
|
|
10
10
|
* → prefer <kind>/orchestrator.md (which must embed the kernel via
|
|
11
11
|
* @include orchestration-kernel.md — inlined by the loader).
|
|
12
12
|
* If no orchestrator.md exists for this kind, compose:
|
|
13
|
-
* <kind>/
|
|
14
|
-
* If even the
|
|
13
|
+
* <kind>/PERSONA.md body + '\n\n' + kernel body
|
|
14
|
+
* If even the PERSONA.md is missing, fall back to general defaults + kernel.
|
|
15
15
|
*
|
|
16
16
|
* Frontmatter from whichever file is the primary source (orchestrator.md >
|
|
17
|
-
*
|
|
17
|
+
* PERSONA.md) supplies model/skills/extensions/tools. Lifecycle and spine position
|
|
18
18
|
* are INPUTS (the caller decides them — root/child, terminal/resident), not
|
|
19
19
|
* derived here; they select the lifecycle/spine protocol fragments spliced
|
|
20
20
|
* ahead of the persona body.
|
|
21
21
|
*/
|
|
22
|
-
import { loadPersona, loadKernel, loadRuntimeBase, loadSpineFragment, loadLifecycleFragment,
|
|
22
|
+
import { loadPersona, loadKernel, loadRuntimeBase, loadSpineFragment, loadLifecycleFragment, loadWaitingFragment, subPersonasFor } from './loader.js';
|
|
23
23
|
// ---------------------------------------------------------------------------
|
|
24
24
|
// Helpers
|
|
25
25
|
// ---------------------------------------------------------------------------
|
|
26
26
|
function toStringArray(v) {
|
|
27
27
|
if (!Array.isArray(v))
|
|
28
28
|
return [];
|
|
29
|
-
|
|
29
|
+
// yaml.parse coerces scalars to native types; the persona prompt needs strings,
|
|
30
|
+
// so coerce each scalar element (dropping nested objects/arrays/null) — this
|
|
31
|
+
// mirrors the prior hand-rolled parser, which returned every scalar as a string.
|
|
32
|
+
return v.filter((x) => x != null && typeof x !== 'object').map((x) => String(x));
|
|
30
33
|
}
|
|
31
34
|
function toOptionalString(v) {
|
|
32
|
-
|
|
35
|
+
if (typeof v === 'string')
|
|
36
|
+
return v;
|
|
37
|
+
// Preserve the legacy parser's string-typed contract for native scalars
|
|
38
|
+
// (e.g. `model: 4` must compose as "4", not be dropped as a non-string).
|
|
39
|
+
if (typeof v === 'number' || typeof v === 'boolean')
|
|
40
|
+
return String(v);
|
|
41
|
+
return undefined;
|
|
33
42
|
}
|
|
34
43
|
/** The bare-minimum system prompt used when no persona file is found at all. */
|
|
35
44
|
function fallbackBasePrompt(kind) {
|
|
@@ -40,29 +49,32 @@ function fallbackBasePrompt(kind) {
|
|
|
40
49
|
* fragment (report-up vs. silent, keyed on whether the node has a manager),
|
|
41
50
|
* then the lifecycle fragment (finish-with-`push final` vs. dormant/wake). The
|
|
42
51
|
* kind×mode persona body follows after a rule. Empty fragments drop out. */
|
|
43
|
-
/** Render the "sub-
|
|
44
|
-
* Returns '' when
|
|
45
|
-
* spawn string + its `
|
|
46
|
-
|
|
47
|
-
|
|
52
|
+
/** Render the "sub-personas you may spawn" menu for a kind that has any
|
|
53
|
+
* available to it. Returns '' when none are. Data-driven: one line per
|
|
54
|
+
* sub-persona, its spawn string + its `whenToUse`. A sub-persona surfaces here
|
|
55
|
+
* for a kind when its `availableTo` includes that kind (default: its own
|
|
56
|
+
* top-level ancestor) or is the wildcard. */
|
|
57
|
+
function renderSubPersonaMenu(kind) {
|
|
58
|
+
const subs = subPersonasFor(kind);
|
|
48
59
|
if (subs.length === 0)
|
|
49
60
|
return '';
|
|
50
|
-
const lines = subs.map((s) => `- \`${s.kind}\` — ${s.
|
|
61
|
+
const lines = subs.map((s) => `- \`${s.kind}\` — ${s.whenToUse}`);
|
|
51
62
|
return [
|
|
52
|
-
'##
|
|
63
|
+
'## Sub-personas you may spawn',
|
|
53
64
|
'',
|
|
54
|
-
`These specialist
|
|
65
|
+
`These specialist sub-personas are available to the ${kind} kind. Spawn one with \`crtr node new --kind <sub> "<scope>"\`, giving it only its scope, never your suspicions: a reviewer handed a hint anchors on it instead of finding problems independently.`,
|
|
55
66
|
'',
|
|
56
67
|
...lines,
|
|
57
68
|
].join('\n');
|
|
58
69
|
}
|
|
59
70
|
function composeProtocol(personaPrompt, kind, lifecycle, hasManager) {
|
|
60
|
-
const menu =
|
|
71
|
+
const menu = renderSubPersonaMenu(kind);
|
|
61
72
|
const body = menu ? `${personaPrompt}\n\n${menu}` : personaPrompt;
|
|
62
73
|
const protocol = [
|
|
63
74
|
loadRuntimeBase(),
|
|
64
75
|
loadSpineFragment(hasManager),
|
|
65
76
|
loadLifecycleFragment(lifecycle),
|
|
77
|
+
loadWaitingFragment(),
|
|
66
78
|
]
|
|
67
79
|
.filter((s) => s.length > 0)
|
|
68
80
|
.join('\n\n');
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Predicate matcher engine — vendored verbatim from pi's frontmatter-rules
|
|
3
|
+
* extension.
|
|
4
|
+
*
|
|
5
|
+
* Source: pi-personal-extensions/extensions/frontmatter-rules/index.ts
|
|
6
|
+
* (the "Condition language" block, functions `asArray` … `evalCondition`).
|
|
7
|
+
*
|
|
8
|
+
* The unified document substrate uses this to evaluate a document's `gate`
|
|
9
|
+
* predicate against a node-config subject (e.g. `orchestration.depth: { gte: 2 }`).
|
|
10
|
+
*
|
|
11
|
+
* This is intentionally a COPY, not an import: the source lives in a separate,
|
|
12
|
+
* private, unpublished repo that crtr cannot depend on. The functions are pure
|
|
13
|
+
* TS over `unknown` / `Record<string, unknown>` with zero external imports, so
|
|
14
|
+
* vendoring them keeps this module standalone and dependency-free. Keep it in
|
|
15
|
+
* sync with the source by hand if the matcher language ever changes.
|
|
16
|
+
*
|
|
17
|
+
* Condition language (evaluated against the subject object):
|
|
18
|
+
* A condition is a map of <field> -> <matcher>, AND-ed across fields.
|
|
19
|
+
* `field` may be dotted to reach nested values (e.g. `orchestration.depth`).
|
|
20
|
+
*
|
|
21
|
+
* Matcher forms:
|
|
22
|
+
* scalar (string/number/bool/null)
|
|
23
|
+
* field === value, OR (if the field is an array) the array includes value
|
|
24
|
+
* array [a, b, c]
|
|
25
|
+
* membership/intersection: field is one of these, OR the field array
|
|
26
|
+
* shares any element with these
|
|
27
|
+
* object { <op>: <arg>, ... } (multiple ops AND together)
|
|
28
|
+
* eq equals (scalar or array-includes)
|
|
29
|
+
* ne not eq
|
|
30
|
+
* in [..] — field (or any of its array elements) is in the list
|
|
31
|
+
* nin not in
|
|
32
|
+
* exists true|false — field is present / absent
|
|
33
|
+
* contains field array includes this value
|
|
34
|
+
* containsAll [..] — field array includes all of these
|
|
35
|
+
* containsAny [..] — field array includes any of these
|
|
36
|
+
* matches regex string, case-sensitive (tests String(field); arrays: any)
|
|
37
|
+
* imatches regex string, case-insensitive
|
|
38
|
+
* gt gte lt lte numeric comparison
|
|
39
|
+
*
|
|
40
|
+
* Combinators (reserved keys at any condition level):
|
|
41
|
+
* all: [ {..}, {..} ] every sub-condition true (AND)
|
|
42
|
+
* any: [ {..}, {..} ] at least one true (OR)
|
|
43
|
+
* not: { .. } sub-condition false
|
|
44
|
+
* Sibling field matchers next to combinators are AND-ed in.
|
|
45
|
+
*
|
|
46
|
+
* Two load-bearing edge cases preserved from the source:
|
|
47
|
+
* - An empty condition (`{}`) is INERT: it returns false, NOT match-all.
|
|
48
|
+
* - An unknown op never matches.
|
|
49
|
+
*/
|
|
50
|
+
export declare function asArray(v: unknown): unknown[];
|
|
51
|
+
export declare function scalarEq(a: unknown, b: unknown): boolean;
|
|
52
|
+
export declare function getField(subject: unknown, key: string): unknown;
|
|
53
|
+
export declare function toRegExp(arg: unknown, flags: string): RegExp | null;
|
|
54
|
+
export declare function applyOp(op: string, value: unknown, arg: unknown): boolean;
|
|
55
|
+
export declare function matchField(value: unknown, matcher: unknown): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Evaluate a `gate` predicate against a subject object.
|
|
58
|
+
*
|
|
59
|
+
* This is the one function consumers call. Returns true iff `condition`
|
|
60
|
+
* matches `subject`. A null/non-object condition and an empty object both
|
|
61
|
+
* return false (inert), never match-all.
|
|
62
|
+
*/
|
|
63
|
+
export declare function evalCondition(condition: unknown, subject: Record<string, unknown>): boolean;
|