@crouton-kit/crouter 0.3.28 → 0.3.30
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.d.ts +15 -7
- package/dist/build-root.js +48 -34
- package/dist/builtin-memory/crouter-development/marketplaces.md +7 -6
- package/dist/builtin-memory/crouter-development/personas/base-prompt.md +1 -1
- package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +1 -1
- package/dist/builtin-memory/crouter-development/personas.md +1 -1
- package/dist/builtin-memory/crouter-development/plugins.md +20 -18
- package/dist/builtin-memory/design.md +1 -1
- package/dist/builtin-memory/development.md +1 -1
- package/dist/builtin-memory/internal/INDEX.md +1 -1
- package/dist/builtin-memory/internal/examples/INDEX.md +1 -1
- package/dist/builtin-memory/internal/examples/imessage-assistant.md +2 -2
- package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
- package/dist/builtin-memory/internal/storage-tiers.md +1 -1
- package/dist/builtin-memory/planning.md +1 -1
- package/dist/builtin-memory/spec.md +6 -4
- package/dist/builtin-personas/orchestration-kernel.md +4 -5
- package/dist/builtin-personas/runtime-base.md +5 -4
- package/dist/builtin-personas/spec/PERSONA.md +8 -4
- package/dist/builtin-personas/spec/orchestrator.md +5 -3
- package/dist/builtin-personas/spec/requirements/PERSONA.md +10 -0
- package/dist/builtin-views/canvas/core.mjs +586 -0
- package/dist/builtin-views/canvas/text.mjs +58 -0
- package/dist/builtin-views/canvas/tui.mjs +165 -0
- package/dist/builtin-views/canvas/web.jsx +120 -0
- package/dist/builtin-views/git-pr/core.mjs +673 -0
- package/dist/builtin-views/git-pr/text.mjs +84 -0
- package/dist/builtin-views/git-pr/tui.mjs +302 -0
- package/dist/builtin-views/git-pr/web.jsx +216 -0
- package/dist/builtin-views/inbox/_lib/render.mjs +1 -3
- package/dist/builtin-views/inbox/core.mjs +1273 -0
- package/dist/builtin-views/inbox/text.mjs +73 -0
- package/dist/builtin-views/inbox/tui.mjs +312 -0
- package/dist/builtin-views/inbox/web.jsx +188 -0
- package/dist/builtin-views/linkedin/core.mjs +906 -0
- package/dist/builtin-views/linkedin/text.mjs +69 -0
- package/dist/builtin-views/linkedin/tui.mjs +427 -0
- package/dist/builtin-views/linkedin/web.jsx +206 -0
- package/dist/builtin-views/workspace-sidebar/core.mjs +621 -0
- package/dist/builtin-views/workspace-sidebar/text.mjs +53 -0
- package/dist/builtin-views/workspace-sidebar/tui.mjs +142 -0
- package/dist/builtin-views/workspace-sidebar/web.jsx +109 -0
- package/dist/cli.js +22 -17
- package/dist/clients/attach/__tests__/action-parity.test.js +48 -0
- package/dist/clients/attach/__tests__/clipboard-image.test.js +76 -0
- package/dist/clients/attach/__tests__/editor-newline.test.js +57 -0
- package/dist/clients/attach/__tests__/git-info.test.js +31 -0
- package/dist/clients/attach/__tests__/onrequest-wired.test.js +20 -0
- package/dist/clients/attach/__tests__/slash-quit-copy.test.js +42 -0
- package/dist/clients/attach/__tests__/titled-editor.test.js +39 -0
- package/dist/clients/attach/attach-cmd.js +282 -46
- package/dist/clients/attach/auth-pickers.d.ts +9 -0
- package/dist/clients/attach/auth-pickers.js +194 -0
- package/dist/clients/attach/canvas-panels.d.ts +4 -2
- package/dist/clients/attach/canvas-panels.js +45 -17
- package/dist/clients/attach/chat-view.d.ts +27 -2
- package/dist/clients/attach/chat-view.js +98 -9
- package/dist/clients/attach/clipboard-image.d.ts +47 -8
- package/dist/clients/attach/clipboard-image.js +150 -26
- package/dist/clients/attach/clipboard-text.d.ts +3 -0
- package/dist/clients/attach/clipboard-text.js +39 -0
- package/dist/clients/attach/config-load.d.ts +54 -7
- package/dist/clients/attach/config-load.js +99 -3
- package/dist/clients/attach/context-message.d.ts +12 -0
- package/dist/clients/attach/context-message.js +72 -0
- package/dist/clients/attach/git-info.d.ts +20 -0
- package/dist/clients/attach/git-info.js +44 -0
- package/dist/clients/attach/graph-overlay.d.ts +13 -4
- package/dist/clients/attach/graph-overlay.js +59 -19
- package/dist/clients/attach/input-controller.d.ts +75 -13
- package/dist/clients/attach/input-controller.js +305 -67
- package/dist/clients/attach/pickers.d.ts +58 -0
- package/dist/clients/attach/pickers.js +171 -0
- package/dist/clients/attach/slash-commands.d.ts +22 -0
- package/dist/clients/attach/slash-commands.js +91 -25
- package/dist/clients/attach/titled-editor.d.ts +33 -0
- package/dist/clients/attach/titled-editor.js +84 -0
- package/dist/clients/attach/view-socket.d.ts +18 -1
- package/dist/clients/attach/view-socket.js +70 -1
- package/dist/clients/web/dev-server.d.ts +7 -0
- package/dist/clients/web/dev-server.js +59 -0
- package/dist/clients/web/events.d.ts +14 -0
- package/dist/clients/web/events.js +151 -0
- package/dist/clients/web/server.d.ts +18 -0
- package/dist/clients/web/server.js +450 -0
- package/dist/clients/web/web-cmd.d.ts +2 -0
- package/dist/clients/web/web-cmd.js +120 -0
- package/dist/commands/canvas.js +1 -2
- package/dist/commands/chord.js +4 -25
- package/dist/commands/dashboard.js +5 -1
- package/dist/commands/memory/__tests__/lint-schema.test.js +6 -6
- package/dist/commands/memory/lint.js +14 -2
- package/dist/commands/memory/read.js +2 -2
- package/dist/commands/memory/shared.d.ts +7 -1
- package/dist/commands/memory/shared.js +18 -3
- package/dist/commands/memory/write.js +8 -4
- package/dist/commands/memory.js +4 -4
- package/dist/commands/node.d.ts +1 -1
- package/dist/commands/node.js +64 -65
- package/dist/commands/pkg.js +1 -2
- package/dist/commands/revive.js +11 -3
- package/dist/commands/sys/sync.d.ts +1 -0
- package/dist/commands/sys/sync.js +187 -0
- package/dist/commands/sys.js +3 -2
- package/dist/commands/view-cycle.js +2 -2
- package/dist/commands/view-list.js +8 -8
- package/dist/commands/view-new.js +21 -17
- package/dist/commands/view-pick.js +1 -1
- package/dist/commands/view-run.js +35 -14
- package/dist/commands/view.js +8 -6
- package/dist/commands/workspace.d.ts +2 -0
- package/dist/commands/workspace.js +161 -0
- package/dist/core/__tests__/broker-double-spawn.test.d.ts +1 -0
- package/dist/core/__tests__/broker-double-spawn.test.js +143 -0
- package/dist/core/__tests__/broker-fork-seam.test.d.ts +1 -0
- package/dist/core/__tests__/broker-fork-seam.test.js +102 -0
- package/dist/core/__tests__/broker-sdk-wiring.test.js +2 -0
- package/dist/core/__tests__/child-death-wake.test.js +56 -111
- package/dist/core/__tests__/close.test.js +14 -20
- package/dist/core/__tests__/context-intro.test.js +19 -19
- package/dist/core/__tests__/daemon-boot.test.js +30 -23
- package/dist/core/__tests__/draw-style.test.js +1 -1
- package/dist/core/__tests__/error-stall-recycle.test.d.ts +1 -0
- package/dist/core/__tests__/error-stall-recycle.test.js +141 -0
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +17 -1
- package/dist/core/__tests__/fixtures/fake-engine.js +22 -2
- package/dist/core/__tests__/fixtures/fake-pi-host.js +2 -2
- package/dist/core/__tests__/focuses.test.js +25 -13
- package/dist/core/__tests__/fork.test.js +22 -5
- package/dist/core/__tests__/full/broker-control-preempt.test.d.ts +1 -0
- package/dist/core/__tests__/full/broker-control-preempt.test.js +61 -0
- package/dist/core/__tests__/full/broker-model-changed-broadcast.test.d.ts +1 -0
- package/dist/core/__tests__/full/broker-model-changed-broadcast.test.js +57 -0
- package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.d.ts +1 -0
- package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.js +80 -0
- package/dist/core/__tests__/full/broker-pane-resolution.test.js +90 -0
- package/dist/core/__tests__/full/cascade-close.test.js +22 -8
- package/dist/core/__tests__/full/detach-focus.test.js +66 -169
- package/dist/core/__tests__/helpers/harness.d.ts +6 -9
- package/dist/core/__tests__/helpers/harness.js +19 -36
- package/dist/core/__tests__/human-node-not-supervised.test.d.ts +1 -0
- package/dist/core/__tests__/human-node-not-supervised.test.js +83 -0
- package/dist/core/__tests__/lifecycle.test.js +1 -19
- package/dist/core/__tests__/listing-completeness.test.js +2 -2
- package/dist/core/__tests__/live-mutation-verbs.test.js +5 -5
- package/dist/core/__tests__/memory-resolver.test.js +1 -1
- package/dist/core/__tests__/on-read-dedup-resume.test.js +2 -2
- package/dist/core/__tests__/refresh-stall-recycle.test.d.ts +1 -0
- package/dist/core/__tests__/refresh-stall-recycle.test.js +88 -0
- package/dist/core/__tests__/relaunch-root.test.d.ts +1 -0
- package/dist/core/__tests__/relaunch-root.test.js +114 -0
- package/dist/core/__tests__/reset.test.js +19 -79
- package/dist/core/__tests__/steer-note.test.js +9 -7
- package/dist/core/__tests__/tmux-surface.test.js +13 -7
- package/dist/core/bootstrap.d.ts +0 -3
- package/dist/core/bootstrap.js +1 -143
- package/dist/core/canvas/browse/__tests__/model.test.js +86 -1
- package/dist/core/canvas/browse/__tests__/render.test.js +2 -1
- package/dist/core/canvas/browse/app.js +131 -8
- package/dist/core/canvas/browse/model.d.ts +23 -5
- package/dist/core/canvas/browse/model.js +68 -13
- package/dist/core/canvas/browse/render.d.ts +7 -1
- package/dist/core/canvas/browse/render.js +178 -47
- package/dist/core/canvas/canvas.js +1 -1
- package/dist/core/canvas/focuses.d.ts +4 -4
- package/dist/core/canvas/focuses.js +7 -7
- package/dist/core/canvas/nav-model.js +8 -7
- package/dist/core/canvas/render.d.ts +68 -9
- package/dist/core/canvas/render.js +195 -61
- package/dist/core/canvas/types.d.ts +16 -23
- package/dist/core/config.js +1 -4
- package/dist/core/memory-resolver.js +43 -5
- package/dist/core/runtime/bearings.d.ts +1 -1
- package/dist/core/runtime/bearings.js +8 -8
- package/dist/core/runtime/branded-host.d.ts +16 -0
- package/dist/core/runtime/branded-host.js +127 -0
- package/dist/core/runtime/broker-protocol.d.ts +212 -6
- package/dist/core/runtime/broker.d.ts +4 -1
- package/dist/core/runtime/broker.js +494 -58
- package/dist/core/runtime/close.d.ts +12 -2
- package/dist/core/runtime/close.js +37 -16
- package/dist/core/runtime/front-door.js +6 -14
- package/dist/core/runtime/host.d.ts +14 -34
- package/dist/core/runtime/host.js +14 -50
- package/dist/core/runtime/launch.d.ts +12 -9
- package/dist/core/runtime/launch.js +27 -15
- package/dist/core/runtime/lifecycle.d.ts +1 -1
- package/dist/core/runtime/lifecycle.js +15 -19
- package/dist/core/runtime/nodes.d.ts +0 -55
- package/dist/core/runtime/nodes.js +6 -74
- package/dist/core/runtime/placement.d.ts +91 -335
- package/dist/core/runtime/placement.js +291 -858
- package/dist/core/runtime/promote.d.ts +2 -0
- package/dist/core/runtime/promote.js +24 -6
- package/dist/core/runtime/recap.d.ts +8 -0
- package/dist/core/runtime/recap.js +107 -0
- package/dist/core/runtime/recycle.js +25 -61
- package/dist/core/runtime/reset.d.ts +43 -37
- package/dist/core/runtime/reset.js +131 -218
- package/dist/core/runtime/revive.d.ts +9 -29
- package/dist/core/runtime/revive.js +40 -139
- package/dist/core/runtime/spawn.d.ts +15 -16
- package/dist/core/runtime/spawn.js +165 -194
- package/dist/core/runtime/surface-bg.d.ts +11 -0
- package/dist/core/runtime/surface-bg.js +68 -0
- package/dist/core/runtime/tmux.d.ts +15 -52
- package/dist/core/runtime/tmux.js +35 -99
- package/dist/core/scope.d.ts +1 -2
- package/dist/core/scope.js +1 -5
- package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.d.ts +1 -0
- package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.js +57 -0
- package/dist/core/skill-sync/builtins.d.ts +42 -0
- package/dist/core/skill-sync/builtins.js +112 -0
- package/dist/core/skill-sync/claude-plugins.d.ts +23 -0
- package/dist/core/skill-sync/claude-plugins.js +71 -0
- package/dist/core/skill-sync/engine.d.ts +42 -0
- package/dist/core/skill-sync/engine.js +633 -0
- package/dist/core/skill-sync/export.d.ts +23 -0
- package/dist/core/skill-sync/export.js +86 -0
- package/dist/core/skill-sync/manifest.d.ts +64 -0
- package/dist/core/skill-sync/manifest.js +181 -0
- package/dist/core/skill-sync/profile.d.ts +76 -0
- package/dist/core/skill-sync/profile.js +173 -0
- package/dist/core/skill-sync/snapshot.d.ts +57 -0
- package/dist/core/skill-sync/snapshot.js +120 -0
- package/dist/core/substrate/index.d.ts +1 -1
- package/dist/core/substrate/index.js +1 -1
- package/dist/core/substrate/injected-store.js +3 -3
- package/dist/core/substrate/on-read.js +68 -6
- package/dist/core/substrate/render.d.ts +8 -11
- package/dist/core/substrate/render.js +29 -43
- package/dist/core/substrate/schema.d.ts +10 -3
- package/dist/core/substrate/schema.js +6 -3
- package/dist/core/tui/host.d.ts +12 -4
- package/dist/core/tui/host.js +280 -149
- package/dist/core/view/bridge.d.ts +10 -0
- package/dist/core/view/bridge.js +31 -0
- package/dist/core/view/chrome.d.ts +9 -0
- package/dist/core/view/chrome.js +22 -0
- package/dist/core/view/contract.d.ts +171 -0
- package/dist/core/view/contract.js +23 -0
- package/dist/core/view/loader.d.ts +31 -0
- package/dist/core/view/loader.js +188 -0
- package/dist/core/view/transport-local.d.ts +7 -0
- package/dist/core/view/transport-local.js +70 -0
- package/dist/core/view/transport.d.ts +4 -0
- package/dist/core/view/transport.js +15 -0
- package/dist/daemon/crtrd.d.ts +38 -27
- package/dist/daemon/crtrd.js +303 -376
- package/dist/daemon/manage.js +6 -1
- package/dist/index.js +1 -1
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +28 -20
- package/dist/pi-extensions/canvas-context-intro.js +4 -4
- package/dist/pi-extensions/canvas-doc-substrate.js +16 -16
- package/dist/pi-extensions/canvas-nav.js +5 -0
- package/dist/pi-extensions/canvas-recap.d.ts +37 -0
- package/dist/pi-extensions/canvas-recap.js +236 -0
- package/dist/pi-extensions/canvas-resume.js +2 -1
- package/dist/pi-extensions/canvas-stophook.d.ts +14 -12
- package/dist/pi-extensions/canvas-stophook.js +87 -101
- package/dist/pi-extensions/canvas-view.js +2 -1
- package/dist/pi-extensions/widget-order-bus.d.ts +6 -0
- package/dist/pi-extensions/widget-order-bus.js +34 -0
- package/dist/prompts/view.d.ts +2 -2
- package/dist/prompts/view.js +145 -73
- package/dist/types.d.ts +1 -6
- package/dist/types.js +1 -3
- package/dist/web/ViewChrome.d.ts +7 -0
- package/dist/web/ViewChrome.js +28 -0
- package/dist/web/ViewPane.d.ts +39 -0
- package/dist/web/ViewPane.js +48 -0
- package/dist/web/index.d.ts +6 -0
- package/dist/web/index.js +16 -0
- package/dist/web/runtime.d.ts +39 -0
- package/dist/web/runtime.js +133 -0
- package/dist/web/states.d.ts +24 -0
- package/dist/web/states.js +24 -0
- package/dist/web/transport-http.d.ts +5 -0
- package/dist/web/transport-http.js +28 -0
- package/dist/web-client/assets/index-BUvQb4hR.css +2 -0
- package/dist/web-client/assets/index-ClLQXYAE.js +10 -0
- package/dist/web-client/index.html +13 -0
- package/package.json +20 -6
- package/dist/builtin-views/canvas/client.mjs +0 -303
- package/dist/builtin-views/canvas/view.mjs +0 -576
- package/dist/builtin-views/git-pr/client.mjs +0 -440
- package/dist/builtin-views/git-pr/view.mjs +0 -675
- package/dist/builtin-views/inbox/sources/gmail.mjs +0 -965
- package/dist/builtin-views/inbox/sources/linkedin.mjs +0 -427
- package/dist/builtin-views/inbox/view.mjs +0 -889
- package/dist/builtin-views/linkedin/client.mjs +0 -610
- package/dist/builtin-views/linkedin/view.mjs +0 -1171
- package/dist/commands/pkg/bridge.d.ts +0 -1
- package/dist/commands/pkg/bridge.js +0 -137
- package/dist/commands/skill/author.d.ts +0 -3
- package/dist/commands/skill/author.js +0 -140
- package/dist/commands/skill/shared.d.ts +0 -3
- package/dist/commands/skill/shared.js +0 -19
- package/dist/commands/skill.d.ts +0 -2
- package/dist/commands/skill.js +0 -21
- package/dist/commands/tmux-spread.d.ts +0 -2
- package/dist/commands/tmux-spread.js +0 -144
- package/dist/core/__tests__/full/daemon-liveness-pane.full.test.js +0 -292
- package/dist/core/__tests__/full/placement-focus.test.js +0 -309
- package/dist/core/__tests__/full/placement-reconcile.test.js +0 -212
- package/dist/core/__tests__/full/placement-revive.test.js +0 -238
- package/dist/core/__tests__/full/placement-teardown.test.js +0 -297
- package/dist/core/__tests__/home-session.test.js +0 -186
- package/dist/core/__tests__/relaunch.test.js +0 -335
- package/dist/core/bridge-map.d.ts +0 -19
- package/dist/core/bridge-map.js +0 -73
- package/dist/core/tui/contract.d.ts +0 -83
- package/dist/core/tui/contract.js +0 -8
- package/dist/core/tui/loader.d.ts +0 -16
- package/dist/core/tui/loader.js +0 -94
- package/dist/prompts/skill.d.ts +0 -2
- package/dist/prompts/skill.js +0 -650
- /package/dist/{core/__tests__/full/daemon-liveness-pane.full.test.d.ts → clients/attach/__tests__/action-parity.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/placement-focus.test.d.ts → clients/attach/__tests__/clipboard-image.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/placement-reconcile.test.d.ts → clients/attach/__tests__/editor-newline.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/placement-revive.test.d.ts → clients/attach/__tests__/git-info.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/placement-teardown.test.d.ts → clients/attach/__tests__/onrequest-wired.test.d.ts} +0 -0
- /package/dist/{core/__tests__/home-session.test.d.ts → clients/attach/__tests__/slash-quit-copy.test.d.ts} +0 -0
- /package/dist/{core/__tests__/relaunch.test.d.ts → clients/attach/__tests__/titled-editor.test.d.ts} +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-pair merge-base snapshot store + conflict-report helpers.
|
|
3
|
+
*
|
|
4
|
+
* All machine-local skill-sync I/O lives here. Nothing in this module is
|
|
5
|
+
* committed: everything is rooted under `~/.crouter/skill-sync/` (R-U9), which
|
|
6
|
+
* is the machine-local, uncommitted tier — never a scope's committed dirs.
|
|
7
|
+
*
|
|
8
|
+
* snapshots/<pair-id>/body.md merge base, frontmatter stripped (R-I3)
|
|
9
|
+
* snapshots/<pair-id>/assets/… byte-for-byte base of every non-SKILL.md
|
|
10
|
+
* file, mirroring subdir structure (R-I3)
|
|
11
|
+
* snapshots/<pair-id>/meta.json { syncedAt, crtrFrontmatter, claudeFrontmatter }
|
|
12
|
+
* conflicts/<pair-id>.md current conflict report, if any (R-E6/OD-4)
|
|
13
|
+
*
|
|
14
|
+
* The snapshot is the SOLE change-detector (R-U4): the engine diffs body/assets
|
|
15
|
+
* against `body.md`/`assets/`, and each frontmatter value against the recorded
|
|
16
|
+
* `meta.json` value — no mtime, no fingerprint, no stamp file.
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, } from 'node:fs';
|
|
19
|
+
import { dirname, join, relative, sep } from 'node:path';
|
|
20
|
+
import { userScopeRoot } from '../scope.js';
|
|
21
|
+
// ── Path roots ───────────────────────────────────────────────────────────────
|
|
22
|
+
/** `~/.crouter/skill-sync/` — the machine-local, uncommitted root (R-U9). */
|
|
23
|
+
export function skillSyncRoot() {
|
|
24
|
+
return join(userScopeRoot(), 'skill-sync');
|
|
25
|
+
}
|
|
26
|
+
function snapshotsRoot() {
|
|
27
|
+
return join(skillSyncRoot(), 'snapshots');
|
|
28
|
+
}
|
|
29
|
+
function conflictsRoot() {
|
|
30
|
+
return join(skillSyncRoot(), 'conflicts');
|
|
31
|
+
}
|
|
32
|
+
/** `~/.crouter/skill-sync/snapshots/<id>/`. */
|
|
33
|
+
export function snapshotDir(id) {
|
|
34
|
+
return join(snapshotsRoot(), id);
|
|
35
|
+
}
|
|
36
|
+
/** `~/.crouter/skill-sync/conflicts/<id>.md`. */
|
|
37
|
+
export function conflictReportPath(id) {
|
|
38
|
+
return join(conflictsRoot(), `${id}.md`);
|
|
39
|
+
}
|
|
40
|
+
// ── Asset helpers ────────────────────────────────────────────────────────────
|
|
41
|
+
/** Recursively read every file under `dir`, keyed by POSIX relpath. */
|
|
42
|
+
function readAssetTree(dir) {
|
|
43
|
+
const out = new Map();
|
|
44
|
+
if (!existsSync(dir))
|
|
45
|
+
return out;
|
|
46
|
+
const walk = (cur) => {
|
|
47
|
+
for (const entry of readdirSync(cur, { withFileTypes: true })) {
|
|
48
|
+
const full = join(cur, entry.name);
|
|
49
|
+
if (entry.isDirectory()) {
|
|
50
|
+
walk(full);
|
|
51
|
+
}
|
|
52
|
+
else if (entry.isFile()) {
|
|
53
|
+
const rel = relative(dir, full).split(sep).join('/');
|
|
54
|
+
out.set(rel, readFileSync(full));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
walk(dir);
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
// ── Snapshot read / write ────────────────────────────────────────────────────
|
|
62
|
+
/**
|
|
63
|
+
* Load the merge base for `id`, or `null` when the snapshot dir is absent
|
|
64
|
+
* (no prior sync — the engine seeds on first reconcile, R-S1/R-S3).
|
|
65
|
+
*/
|
|
66
|
+
export function readSnapshot(id) {
|
|
67
|
+
const dir = snapshotDir(id);
|
|
68
|
+
if (!existsSync(dir))
|
|
69
|
+
return null;
|
|
70
|
+
const bodyPath = join(dir, 'body.md');
|
|
71
|
+
const body = existsSync(bodyPath) ? readFileSync(bodyPath, 'utf8') : '';
|
|
72
|
+
const assets = readAssetTree(join(dir, 'assets'));
|
|
73
|
+
const metaPath = join(dir, 'meta.json');
|
|
74
|
+
const meta = existsSync(metaPath)
|
|
75
|
+
? JSON.parse(readFileSync(metaPath, 'utf8'))
|
|
76
|
+
: { syncedAt: '', crtrFrontmatter: {}, claudeFrontmatter: {} };
|
|
77
|
+
return { body, assets, meta };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Write the merge base for `id` byte-for-byte. The snapshot dir is rebuilt
|
|
81
|
+
* from scratch so stale assets from a prior base never linger — the on-disk
|
|
82
|
+
* `assets/` always mirrors exactly the passed `assets` map (R-U5/R-I3).
|
|
83
|
+
*/
|
|
84
|
+
export function writeSnapshot(id, snapshot) {
|
|
85
|
+
const dir = snapshotDir(id);
|
|
86
|
+
rmSync(dir, { recursive: true, force: true });
|
|
87
|
+
mkdirSync(dir, { recursive: true });
|
|
88
|
+
writeFileSync(join(dir, 'body.md'), snapshot.body, 'utf8');
|
|
89
|
+
const assetsDir = join(dir, 'assets');
|
|
90
|
+
mkdirSync(assetsDir, { recursive: true });
|
|
91
|
+
for (const [rel, buf] of snapshot.assets) {
|
|
92
|
+
const full = join(assetsDir, ...rel.split('/'));
|
|
93
|
+
mkdirSync(dirname(full), { recursive: true });
|
|
94
|
+
writeFileSync(full, buf);
|
|
95
|
+
}
|
|
96
|
+
writeFileSync(join(dir, 'meta.json'), `${JSON.stringify(snapshot.meta, null, 2)}\n`, 'utf8');
|
|
97
|
+
}
|
|
98
|
+
// ── Conflict-report helpers (R-E6 / OD-4) ────────────────────────────────────
|
|
99
|
+
/**
|
|
100
|
+
* Write the current conflict report for `id` to `conflicts/<id>.md`. The engine
|
|
101
|
+
* calls this on any true conflict (overlapping body/asset merge or both-sides
|
|
102
|
+
* non-equivalent frontmatter) after deciding to write nothing for the pair.
|
|
103
|
+
*/
|
|
104
|
+
export function writeConflictReport(id, text) {
|
|
105
|
+
const path = conflictReportPath(id);
|
|
106
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
107
|
+
writeFileSync(path, text, 'utf8');
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Delete a stale `conflicts/<id>.md` once the pair reconciles cleanly or
|
|
111
|
+
* becomes a no-op (OD-4). No-op if absent — never throws on a missing report.
|
|
112
|
+
*/
|
|
113
|
+
export function clearConflictReport(id) {
|
|
114
|
+
rmSync(conflictReportPath(id), { force: true });
|
|
115
|
+
}
|
|
116
|
+
/** True iff a conflict report currently exists for `id`. */
|
|
117
|
+
export function hasConflictReport(id) {
|
|
118
|
+
const path = conflictReportPath(id);
|
|
119
|
+
return existsSync(path) && statSync(path).isFile();
|
|
120
|
+
}
|
|
@@ -5,5 +5,5 @@ export type { NodeConfigSubject } from './subject.js';
|
|
|
5
5
|
export { gatePasses } from './gate.js';
|
|
6
6
|
export { INDEX_NAME, isIndexName, indexDirOf, displayName, buildCeilingIndex, effectiveRung, } from './ceiling.js';
|
|
7
7
|
export type { Surface } from './ceiling.js';
|
|
8
|
-
export {
|
|
8
|
+
export { renderPreferencesSection, renderKnowledgeBlock, renderMemoryGuidance, } from './render.js';
|
|
9
9
|
export { renderOnReadDocs } from './on-read.js';
|
|
@@ -15,5 +15,5 @@ parseSubstrateFrontmatter, parseSubstrateDoc, previewLine, } from './schema.js';
|
|
|
15
15
|
export { scopeForCwd, spineDepth, assembleNodeSubject } from './subject.js';
|
|
16
16
|
export { gatePasses } from './gate.js';
|
|
17
17
|
export { INDEX_NAME, isIndexName, indexDirOf, displayName, buildCeilingIndex, effectiveRung, } from './ceiling.js';
|
|
18
|
-
export {
|
|
18
|
+
export { renderPreferencesSection, renderKnowledgeBlock, renderMemoryGuidance, } from './render.js';
|
|
19
19
|
export { renderOnReadDocs } from './on-read.js';
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
//
|
|
12
12
|
// This module persists the set to `nodes/<id>/injected-docs.json` so the resumed
|
|
13
13
|
// process rehydrates it and skips docs already present in the transcript. The
|
|
14
|
-
// launch
|
|
15
|
-
//
|
|
16
|
-
//
|
|
14
|
+
// one launch path that begins a FRESH transcript (reviveNode with resume=false,
|
|
15
|
+
// in runtime/revive.ts) calls clearInjectedDocs(), so a new conversation starts
|
|
16
|
+
// with an empty set.
|
|
17
17
|
//
|
|
18
18
|
// All ops are best-effort: a failed read/write degrades to a possible re-inject,
|
|
19
19
|
// never a crash — a dedup miss must never break a read or a revive.
|
|
@@ -3,16 +3,25 @@
|
|
|
3
3
|
// When a `read` tool call returns, the canvas-doc-substrate pi extension calls
|
|
4
4
|
// renderOnReadDocs() to surface the substrate docs that should appear ALONGSIDE
|
|
5
5
|
// the file just read — each at its FILE-READ-VISIBILITY rung (NOT the
|
|
6
|
-
// system-prompt rung the boot render uses).
|
|
7
|
-
//
|
|
6
|
+
// system-prompt rung the boot render uses). Three triggers decide which docs
|
|
7
|
+
// surface (design §4/§6; Stream A native rules):
|
|
8
8
|
//
|
|
9
9
|
// • POSITIONAL — walk the read file's ancestor dirs; any doc living in an
|
|
10
10
|
// ancestor's `.crouter/memory/` surfaces (a doc surfaces when a file
|
|
11
|
-
// beside/under its own scope dir is read)
|
|
12
|
-
//
|
|
11
|
+
// beside/under its own scope dir is read), UNLESS it carries an explicit
|
|
12
|
+
// read-trigger (see D5 below). This mirrors nested-context's `.claude/rules`
|
|
13
|
+
// ancestor walk, but keyed on `.crouter/memory/`.
|
|
13
14
|
// • applies-to GLOB — any RESOLVED substrate doc (user/project/builtin scope)
|
|
14
15
|
// whose `appliesTo` glob matches the read file path surfaces, regardless of
|
|
15
16
|
// where the read file sits relative to the doc.
|
|
17
|
+
// • read-when FRONTMATTER (Stream A) — any RESOLVED doc whose `readWhen`
|
|
18
|
+
// condition matches the READ FILE's own parsed frontmatter (markdown only),
|
|
19
|
+
// via `evalCondition` against that YAML rather than the node subject.
|
|
20
|
+
//
|
|
21
|
+
// D5 — an EXPLICIT read-trigger (applies-to OR read-when) SUPPRESSES the
|
|
22
|
+
// positional default for that doc: an author who declared a trigger meant it, so
|
|
23
|
+
// the doc fires only on its trigger, never positionally on every read under its
|
|
24
|
+
// scope. The two explicit triggers compose by OR.
|
|
16
25
|
//
|
|
17
26
|
// Each candidate runs the substrate pipeline at its fileReadVisibility rung:
|
|
18
27
|
// parse → gatePasses(doc, assembleNodeSubject(nodeId)) → render
|
|
@@ -35,6 +44,7 @@ import { basename, dirname, join, matchesGlob, parse, relative, sep } from 'node
|
|
|
35
44
|
import { CRTR_DIR_NAME } from '../../types.js';
|
|
36
45
|
import { pathExists, readText, walkFiles } from '../fs-utils.js';
|
|
37
46
|
import { parseFrontmatterGeneric } from '../frontmatter.js';
|
|
47
|
+
import { evalCondition } from '../predicate.js';
|
|
38
48
|
import { listAllMemoryDocs } from '../memory-resolver.js';
|
|
39
49
|
import { assembleNodeSubject, buildCeilingIndex, displayName, effectiveRung, gatePasses, parseSubstrateDoc, parseSubstrateFrontmatter, previewLine, } from './index.js';
|
|
40
50
|
import { cachedSubstrateDocs } from './session-cache.js';
|
|
@@ -117,6 +127,12 @@ function safeWalkMd(dir) {
|
|
|
117
127
|
return [];
|
|
118
128
|
}
|
|
119
129
|
}
|
|
130
|
+
/** Does the doc declare an EXPLICIT read-trigger? (applies-to glob OR read-when
|
|
131
|
+
* frontmatter condition). D5: an explicit trigger SUPPRESSES the positional
|
|
132
|
+
* default — such a doc fires only on its declared trigger, never positionally. */
|
|
133
|
+
function hasExplicitTrigger(doc) {
|
|
134
|
+
return (doc.appliesTo !== undefined && doc.appliesTo.length > 0) || doc.readWhen !== undefined;
|
|
135
|
+
}
|
|
120
136
|
/** POSITIONAL trigger: every substrate doc in an ancestor dir's
|
|
121
137
|
* `.crouter/memory/`, walking from the read file up to $HOME (or the
|
|
122
138
|
* filesystem root for a read outside $HOME), skipping junk ancestors. */
|
|
@@ -138,7 +154,9 @@ function positionalCandidates(absReadFile) {
|
|
|
138
154
|
continue;
|
|
139
155
|
seenDocPaths.add(real);
|
|
140
156
|
const doc = loadPositionalDoc(file, memDir, scope);
|
|
141
|
-
|
|
157
|
+
// D5: a doc with an explicit read-trigger (applies-to/read-when) does
|
|
158
|
+
// NOT fire positionally — it surfaces only via that trigger.
|
|
159
|
+
if (doc && !hasExplicitTrigger(doc))
|
|
142
160
|
out.push({ doc, realpath: real, order: depth });
|
|
143
161
|
}
|
|
144
162
|
}
|
|
@@ -204,6 +222,49 @@ function appliesToCandidates(absReadFile, taken) {
|
|
|
204
222
|
}
|
|
205
223
|
return out;
|
|
206
224
|
}
|
|
225
|
+
/** Parse the READ FILE's own YAML frontmatter once (markdown only), the subject
|
|
226
|
+
* a `read-when` condition is evaluated against. Non-markdown reads (and any
|
|
227
|
+
* unreadable / frontmatter-less file) yield `{}` — no `read-when` rule can then
|
|
228
|
+
* match (mirrors pi's frontmatter-rules, which only consider .md/.mdx/.markdown). */
|
|
229
|
+
function readFileFrontmatter(absReadFile) {
|
|
230
|
+
if (!/\.(md|mdx|markdown)$/i.test(absReadFile))
|
|
231
|
+
return {};
|
|
232
|
+
try {
|
|
233
|
+
return parseFrontmatterGeneric(readText(absReadFile)).data ?? {};
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
return {};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/** read-when FRONTMATTER trigger (Stream A): every RESOLVED substrate doc whose
|
|
240
|
+
* `readWhen` condition matches the read file's own frontmatter. `taken` carries
|
|
241
|
+
* the realpaths already claimed by earlier passes so a doc is not double-counted.
|
|
242
|
+
* Uses the per-session cache (same corpus the glob pass walks). Returns [] when
|
|
243
|
+
* the read file has no frontmatter — no condition can match an empty subject. */
|
|
244
|
+
function readWhenCandidates(readFileFm, taken) {
|
|
245
|
+
if (Object.keys(readFileFm).length === 0)
|
|
246
|
+
return [];
|
|
247
|
+
let docs;
|
|
248
|
+
try {
|
|
249
|
+
docs = cachedSubstrateDocs(listAllMemoryDocs, parseSubstrateDoc);
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
return [];
|
|
253
|
+
}
|
|
254
|
+
const out = [];
|
|
255
|
+
for (const doc of docs) {
|
|
256
|
+
if (doc.readWhen === undefined)
|
|
257
|
+
continue;
|
|
258
|
+
const real = realpathOrSelf(doc.path);
|
|
259
|
+
if (taken.has(real))
|
|
260
|
+
continue;
|
|
261
|
+
if (!evalCondition(doc.readWhen, readFileFm))
|
|
262
|
+
continue;
|
|
263
|
+
taken.add(real);
|
|
264
|
+
out.push({ doc, realpath: real, order: -1 });
|
|
265
|
+
}
|
|
266
|
+
return out;
|
|
267
|
+
}
|
|
207
268
|
// ---------------------------------------------------------------------------
|
|
208
269
|
// Per-doc envelope render.
|
|
209
270
|
// ---------------------------------------------------------------------------
|
|
@@ -256,7 +317,8 @@ export function renderOnReadDocs(nodeId, readFilePath, seen = new Set()) {
|
|
|
256
317
|
const positional = positionalCandidates(absReadFile);
|
|
257
318
|
const taken = new Set(positional.map((c) => c.realpath));
|
|
258
319
|
const byGlob = appliesToCandidates(absReadFile, taken);
|
|
259
|
-
|
|
320
|
+
const byReadWhen = readWhenCandidates(readFileFrontmatter(absReadFile), taken);
|
|
321
|
+
candidates = [...positional, ...byGlob, ...byReadWhen];
|
|
260
322
|
}
|
|
261
323
|
catch {
|
|
262
324
|
return '';
|
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
/** The `<skills>` system-prompt block: every eligible `kind: skill` doc placed
|
|
2
|
-
* in one tree at its effective rung. Plugin skills (`<plugin>/…` names) fall out
|
|
3
|
-
* naturally as dirs. Returns '' when nothing is eligible. */
|
|
4
|
-
export declare function renderSkillsSection(nodeId: string): string;
|
|
5
1
|
/** The `<preferences>` system-prompt block: every eligible `kind: preference`
|
|
6
2
|
* doc in one tree at its effective rung (the preference default rung is
|
|
7
3
|
* `preview` → the routing line). Returns '' when nothing is eligible. */
|
|
8
4
|
export declare function renderPreferencesSection(nodeId: string): string;
|
|
9
|
-
/** The `<
|
|
5
|
+
/** The `<knowledge>` block embedded INSIDE the `<crtr-context>` session_start
|
|
10
6
|
* message (bearings.ts pushes the returned string into the block, or drops it
|
|
11
|
-
* when '').
|
|
12
|
-
* rung (
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
7
|
+
* when ''). The consultable catalog: every eligible `kind: knowledge` resolver
|
|
8
|
+
* doc at its effective rung (most surface only as `[+N more]` counts unless
|
|
9
|
+
* author-promoted) PLUS the node-local memory docs (any kind), the latter
|
|
10
|
+
* floored to `name` so a `none`-rung node-local doc still shows its name rather
|
|
11
|
+
* than collapsing into a count. Procedural skills and factual references both
|
|
12
|
+
* live here now — they merged into the one `knowledge` kind. Returns '' when
|
|
16
13
|
* nothing is eligible. */
|
|
17
|
-
export declare function
|
|
14
|
+
export declare function renderKnowledgeBlock(nodeId: string): string;
|
|
18
15
|
/** The memory-hygiene directive spliced into the system prompt after the
|
|
19
16
|
* preferences block. ALWAYS present for a canvas node (the memory system always
|
|
20
17
|
* exists), so the system-prompt splice stays non-empty even when both trees are
|
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
// line; content → the full body indented beneath the entry); hidden (`none`-rung)
|
|
7
7
|
// docs leak only a `[+N more]` count under their dir, never a name.
|
|
8
8
|
//
|
|
9
|
-
// • the SYSTEM-PROMPT half — `<
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// • the `<crtr-context>` half — `<
|
|
14
|
-
//
|
|
9
|
+
// • the SYSTEM-PROMPT half — `<preferences>` (renderPreferencesSection) +
|
|
10
|
+
// `<memory-guidance>` (renderMemoryGuidance) — strings the
|
|
11
|
+
// canvas-doc-substrate `before_agent_start` extension splices into the
|
|
12
|
+
// system prompt before the `\n\nGuidelines:` anchor;
|
|
13
|
+
// • the `<crtr-context>` half — `<knowledge>` (renderKnowledgeBlock) — the
|
|
14
|
+
// consultable catalog (every `kind: knowledge` doc ∪ node-local) the string
|
|
15
|
+
// bearings.ts embeds in the session_start message.
|
|
15
16
|
//
|
|
16
17
|
// Every doc flows through the same pipeline: MemoryDoc → parseSubstrateDoc →
|
|
17
18
|
// (null-filter non-substrate) → ceiling-capped effective rung → gatePasses →
|
|
@@ -73,11 +74,11 @@ function scopeRank(scope) {
|
|
|
73
74
|
* parseSubstrateFrontmatter (mirroring the resolver pipeline), then gate-passed.
|
|
74
75
|
* Non-substrate files (those with no `kind`) parse to null and drop out.
|
|
75
76
|
* Returned across ALL kinds — node-local is the catch-all this-node store and
|
|
76
|
-
* rides into the
|
|
77
|
+
* rides into the knowledge block.
|
|
77
78
|
*
|
|
78
79
|
* IMPORTANT: node-local docs are NOT filtered or capped by rung. Their contract
|
|
79
|
-
* is "node-local rides into
|
|
80
|
-
* node-local
|
|
80
|
+
* is "node-local rides into knowledge" without qualification, so a `none`-rung
|
|
81
|
+
* node-local doc must still surface — the caller floors it to `name` so it
|
|
81
82
|
* renders its name (never collapsing into a hidden count). Only gate evaluation
|
|
82
83
|
* removes a node-local doc from the block. */
|
|
83
84
|
function nodeLocalDocs(nodeId, subject) {
|
|
@@ -276,20 +277,17 @@ function buildTree(docs, rootLabel) {
|
|
|
276
277
|
// ---------------------------------------------------------------------------
|
|
277
278
|
const READ_LEGEND = 'Each %s below shows either its full content (indented beneath its name), a ' +
|
|
278
279
|
'`# read when:` line telling you when to read the full document, or simply its name.';
|
|
279
|
-
const SKILLS_INTRO = 'Skills contain procedural knowledge — playbooks and techniques for how to do things. ' +
|
|
280
|
-
'To read a skill, run `crtr memory read <name>`. Reach for a matching skill before ' +
|
|
281
|
-
'improvising. ' +
|
|
282
|
-
READ_LEGEND.replace('%s', 'skill');
|
|
283
|
-
const SKILLS_OUTRO = 'If you learn a better way to do something a skill covers, update the skill.';
|
|
284
280
|
const PREFERENCES_INTRO = 'Preferences are how the user wants you to behave — standing directives and corrections. ' +
|
|
285
281
|
'To read a preference, run `crtr memory read <name>`. ' +
|
|
286
282
|
READ_LEGEND.replace('%s', 'preference');
|
|
287
283
|
const PREFERENCES_OUTRO = 'If the user corrects you in a way that contradicts a preference, update the preference.';
|
|
288
|
-
const
|
|
289
|
-
'To read
|
|
284
|
+
const KNOWLEDGE_INTRO = 'Knowledge documents are what you consult — playbooks and techniques for how to do things, and ' +
|
|
285
|
+
'references on the user, projects, and this node. To read one, run `crtr memory read <name>`. ' +
|
|
286
|
+
'Reach for a matching document before improvising, and read one when it seems relevant to the ' +
|
|
290
287
|
'task at hand. ' +
|
|
291
|
-
READ_LEGEND.replace('%s', '
|
|
292
|
-
const
|
|
288
|
+
READ_LEGEND.replace('%s', 'document');
|
|
289
|
+
const KNOWLEDGE_OUTRO = 'If you learn a better way to do something a document covers, or gain information that ' +
|
|
290
|
+
'contradicts one, update that document.';
|
|
293
291
|
/** Wrap an intro + tree + outro in a kind-named block, or '' when the tree is
|
|
294
292
|
* empty (the whole block is dropped). */
|
|
295
293
|
function wrapBlock(tag, intro, tree, outro) {
|
|
@@ -298,20 +296,7 @@ function wrapBlock(tag, intro, tree, outro) {
|
|
|
298
296
|
return `<${tag}>\n${intro}\n\n${tree}\n\n${outro}\n</${tag}>`;
|
|
299
297
|
}
|
|
300
298
|
// ---------------------------------------------------------------------------
|
|
301
|
-
// 1.
|
|
302
|
-
// ---------------------------------------------------------------------------
|
|
303
|
-
/** The `<skills>` system-prompt block: every eligible `kind: skill` doc placed
|
|
304
|
-
* in one tree at its effective rung. Plugin skills (`<plugin>/…` names) fall out
|
|
305
|
-
* naturally as dirs. Returns '' when nothing is eligible. */
|
|
306
|
-
export function renderSkillsSection(nodeId) {
|
|
307
|
-
const subject = cachedNodeSubject(nodeId, assembleNodeSubject);
|
|
308
|
-
if (subject === null)
|
|
309
|
-
return '';
|
|
310
|
-
const tree = buildTree(effectiveDocs(subject, 'skill'), 'skills');
|
|
311
|
-
return wrapBlock('skills', SKILLS_INTRO, tree, SKILLS_OUTRO);
|
|
312
|
-
}
|
|
313
|
-
// ---------------------------------------------------------------------------
|
|
314
|
-
// 2. Preferences — `<preferences>` (system prompt).
|
|
299
|
+
// 1. Preferences — `<preferences>` (system prompt).
|
|
315
300
|
// ---------------------------------------------------------------------------
|
|
316
301
|
/** The `<preferences>` system-prompt block: every eligible `kind: preference`
|
|
317
302
|
* doc in one tree at its effective rung (the preference default rung is
|
|
@@ -324,28 +309,29 @@ export function renderPreferencesSection(nodeId) {
|
|
|
324
309
|
return wrapBlock('preferences', PREFERENCES_INTRO, tree, PREFERENCES_OUTRO);
|
|
325
310
|
}
|
|
326
311
|
// ---------------------------------------------------------------------------
|
|
327
|
-
//
|
|
312
|
+
// 2. Knowledge — `<knowledge>` (inside the <crtr-context> message).
|
|
328
313
|
// ---------------------------------------------------------------------------
|
|
329
|
-
/** The `<
|
|
314
|
+
/** The `<knowledge>` block embedded INSIDE the `<crtr-context>` session_start
|
|
330
315
|
* message (bearings.ts pushes the returned string into the block, or drops it
|
|
331
|
-
* when '').
|
|
332
|
-
* rung (
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
*
|
|
316
|
+
* when ''). The consultable catalog: every eligible `kind: knowledge` resolver
|
|
317
|
+
* doc at its effective rung (most surface only as `[+N more]` counts unless
|
|
318
|
+
* author-promoted) PLUS the node-local memory docs (any kind), the latter
|
|
319
|
+
* floored to `name` so a `none`-rung node-local doc still shows its name rather
|
|
320
|
+
* than collapsing into a count. Procedural skills and factual references both
|
|
321
|
+
* live here now — they merged into the one `knowledge` kind. Returns '' when
|
|
336
322
|
* nothing is eligible. */
|
|
337
|
-
export function
|
|
323
|
+
export function renderKnowledgeBlock(nodeId) {
|
|
338
324
|
const subject = cachedNodeSubject(nodeId, assembleNodeSubject);
|
|
339
325
|
if (subject === null)
|
|
340
326
|
return '';
|
|
341
327
|
const nodeLocal = nodeLocalDocs(nodeId, subject).map((d) => rungRank(d.systemPromptVisibility) >= rungRank('name')
|
|
342
328
|
? d
|
|
343
329
|
: { ...d, systemPromptVisibility: 'name' });
|
|
344
|
-
const tree = buildTree([...effectiveDocs(subject, '
|
|
345
|
-
return wrapBlock('
|
|
330
|
+
const tree = buildTree([...effectiveDocs(subject, 'knowledge'), ...nodeLocal], 'knowledge');
|
|
331
|
+
return wrapBlock('knowledge', KNOWLEDGE_INTRO, tree, KNOWLEDGE_OUTRO);
|
|
346
332
|
}
|
|
347
333
|
// ---------------------------------------------------------------------------
|
|
348
|
-
//
|
|
334
|
+
// 3. Memory-saving hygiene guidance — `<memory-guidance>` (system prompt).
|
|
349
335
|
// ---------------------------------------------------------------------------
|
|
350
336
|
/** The memory-hygiene directive spliced into the system prompt after the
|
|
351
337
|
* preferences block. ALWAYS present for a canvas node (the memory system always
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Scope } from '../../types.js';
|
|
2
2
|
import type { MemoryDoc } from '../memory-resolver.js';
|
|
3
|
-
export declare const KINDS: readonly ["
|
|
3
|
+
export declare const KINDS: readonly ["knowledge", "preference"];
|
|
4
4
|
export type DocKind = (typeof KINDS)[number];
|
|
5
|
-
/** Is `v` one of the
|
|
5
|
+
/** Is `v` one of the two valid document kinds? */
|
|
6
6
|
export declare function isDocKind(v: unknown): v is DocKind;
|
|
7
7
|
export declare const RUNGS: readonly ["none", "name", "preview", "content"];
|
|
8
8
|
export type Rung = (typeof RUNGS)[number];
|
|
@@ -21,7 +21,7 @@ export type GatePredicate = Record<string, unknown>;
|
|
|
21
21
|
* defaults applied. Required fields (`kind`/`when-and-why-to-read`) and
|
|
22
22
|
* optionals all resolved to concrete typed values. */
|
|
23
23
|
export interface SubstrateSchema {
|
|
24
|
-
/** Which of the
|
|
24
|
+
/** Which of the two semantic kinds (knowledge | preference). */
|
|
25
25
|
kind: DocKind;
|
|
26
26
|
/** The read-routing line — a single sentence answering WHEN to read this doc
|
|
27
27
|
* and WHY it is worth the read: "When <circumstance>, this <kind> should be
|
|
@@ -43,6 +43,13 @@ export interface SubstrateSchema {
|
|
|
43
43
|
/** Optional glob list narrowing the on-read trigger to matching read files.
|
|
44
44
|
* Absent ⇒ positional trigger only. A single glob is normalized to a 1-list. */
|
|
45
45
|
appliesTo?: string[];
|
|
46
|
+
/** Optional condition over the READ FILE's own frontmatter — the on-read
|
|
47
|
+
* frontmatter trigger (Stream A native rules). Same coercion + predicate
|
|
48
|
+
* vocabulary as `gate` (non-null non-array object carried; empty `{}` inert),
|
|
49
|
+
* but evaluated by `evalCondition` against the read file's parsed YAML rather
|
|
50
|
+
* than the node subject. Absent ⇒ no frontmatter trigger. Frontmatter key
|
|
51
|
+
* `read-when`. */
|
|
52
|
+
readWhen?: GatePredicate;
|
|
46
53
|
}
|
|
47
54
|
/** A fully-resolved substrate document: the parsed schema PLUS the resolver's
|
|
48
55
|
* path-derived identity and body. This single object flows through the whole
|
|
@@ -12,10 +12,12 @@
|
|
|
12
12
|
// floor `none` — a malformed doc renders invisible rather than crashing, and
|
|
13
13
|
// lint flags it. Valid docs never hit the fallback.
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
|
-
// Kinds — the
|
|
15
|
+
// Kinds — the two semantic kinds (design §3): `knowledge` (consult — procedural
|
|
16
|
+
// playbooks + factual references merged) vs `preference` (behave — standing
|
|
17
|
+
// directives). `kind` is a load-bearing binary, not a content taxonomy.
|
|
16
18
|
// ---------------------------------------------------------------------------
|
|
17
|
-
export const KINDS = ['
|
|
18
|
-
/** Is `v` one of the
|
|
19
|
+
export const KINDS = ['knowledge', 'preference'];
|
|
20
|
+
/** Is `v` one of the two valid document kinds? */
|
|
19
21
|
export function isDocKind(v) {
|
|
20
22
|
return typeof v === 'string' && KINDS.includes(v);
|
|
21
23
|
}
|
|
@@ -66,6 +68,7 @@ export function parseSubstrateFrontmatter(fm) {
|
|
|
66
68
|
fileReadVisibility: parseRung(fm['file-read-visibility'], FALLBACK_RUNG),
|
|
67
69
|
gate: parseGate(fm.gate),
|
|
68
70
|
appliesTo: parseAppliesTo(fm['applies-to']),
|
|
71
|
+
readWhen: parseGate(fm['read-when']),
|
|
69
72
|
};
|
|
70
73
|
}
|
|
71
74
|
/** Parse a resolved MemoryDoc into a fully-typed SubstrateDoc (schema + the
|
package/dist/core/tui/host.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Draw, type Rect, type Size } from './draw.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ViewCore, TuiPresenter, TextPresenter, KeyHint, BannerLevel } from '../view/contract.js';
|
|
3
3
|
export interface RunViewOptions {
|
|
4
4
|
/** CLI flags forwarded verbatim to the view via host.options. */
|
|
5
5
|
options?: Record<string, string>;
|
|
@@ -19,11 +19,19 @@ export interface Chrome {
|
|
|
19
19
|
subtitle: string | null;
|
|
20
20
|
mode: string | null;
|
|
21
21
|
}
|
|
22
|
+
/** The slice of a view's manifest that drawChrome reads (title + subtitle), plus
|
|
23
|
+
* the footer hints lifted from the TuiPresenter's keymap bindings. */
|
|
24
|
+
export interface ChromeManifest {
|
|
25
|
+
title: string;
|
|
26
|
+
subtitle?: string;
|
|
27
|
+
keymap?: KeyHint[];
|
|
28
|
+
}
|
|
22
29
|
/** Draw the host chrome into `draw` and return the content Rect for the view.
|
|
23
30
|
* Three zones: title row (state rail + title/subtitle + state chip + liveness),
|
|
24
31
|
* a hairline, and a footer (status left, keymap right) with a severity banner
|
|
25
32
|
* on the row above it when set. */
|
|
26
|
-
declare function drawChrome(draw: Draw, size: Size, manifest:
|
|
33
|
+
declare function drawChrome(draw: Draw, size: Size, manifest: ChromeManifest, c: Chrome, now?: number): Rect;
|
|
27
34
|
export { drawChrome };
|
|
28
|
-
/** Host a
|
|
29
|
-
|
|
35
|
+
/** Host a dual-target ViewCore + TuiPresenter in the alt screen until it quits
|
|
36
|
+
* (or Ctrl-C). `text` is the optional text presenter for the piped path. */
|
|
37
|
+
export declare function runCoreView<S>(core: ViewCore<S>, tui: TuiPresenter<S>, text: TextPresenter<S> | null, opts?: RunViewOptions): Promise<void>;
|