@crouton-kit/crouter 0.3.28 → 0.3.29
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 +4 -2
- 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 +3 -3
- 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 +1 -1
- 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__/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 +262 -840
- 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 +13 -50
- package/dist/core/runtime/tmux.js +33 -87
- 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,165 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* Canvas Dashboard — the TUI presenter (`render` + `keymap`) for the `canvas`
|
|
4
|
+
* view. Node-only (it uses the host's `Draw` API + the `_lib/states.mjs` draw
|
|
5
|
+
* helpers).
|
|
6
|
+
*
|
|
7
|
+
* `render` is a pure read of state; keystrokes map to named intents through
|
|
8
|
+
* `keymap`. All state + data logic lives in `core.mjs`.
|
|
9
|
+
*
|
|
10
|
+
* VISUAL LANGUAGE (crtr-views-visual-design §2/§3/§4): hierarchy is carried by
|
|
11
|
+
* weight + hue + position, never boxes. The status glyph hues match `canvas
|
|
12
|
+
* browse`'s authoritative palette (active=green, idle=yellow, done=cyan,
|
|
13
|
+
* dead=red, canceled=grey; asks=bright-yellow) — "not a recolor." Per-row
|
|
14
|
+
* metadata (the relative age) is right-flushed via `ListItemRow.right`; secondary
|
|
15
|
+
* text recedes via grey+dim so it survives NO_COLOR. The four standard states
|
|
16
|
+
* come from `_lib/states.mjs`.
|
|
17
|
+
*
|
|
18
|
+
* @module canvas/tui
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { relAge } from './core.mjs';
|
|
22
|
+
import { loadingState, emptyState, notReadyState } from '../_lib/states.mjs';
|
|
23
|
+
|
|
24
|
+
/** @typedef {import('./core.mjs').CanvasState} CanvasState */
|
|
25
|
+
/** @typedef {import('./core.mjs').TreeRow} TreeRow */
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Load-bearing status hue — NUMERIC SGR codes, matching `canvas browse`'s
|
|
29
|
+
* STATUS_COLOR exactly (active=green, idle=yellow, done=cyan, dead=red,
|
|
30
|
+
* canceled=grey). The design is explicit: keep these, "this is not a recolor."
|
|
31
|
+
* @type {Record<string,string>}
|
|
32
|
+
*/
|
|
33
|
+
const STATUS_FG = {
|
|
34
|
+
active: '32', // green
|
|
35
|
+
idle: '33', // yellow
|
|
36
|
+
done: '36', // cyan
|
|
37
|
+
dead: '31', // red
|
|
38
|
+
canceled: '90', // grey
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/** @param {string} status @returns {import('../../core/tui/draw.js').Style|undefined} */
|
|
42
|
+
function glyphStyle(status) {
|
|
43
|
+
const fg = STATUS_FG[status];
|
|
44
|
+
return fg ? { fg } : undefined; // hue only — the glyph SHAPE is the mono carrier
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Name weight = hierarchy (design §2 "weight creates hierarchy"): live work
|
|
49
|
+
* (active) LEADS in bold; terminal nodes (done/dead/canceled) recede dim; idle
|
|
50
|
+
* stays default weight (readable, not shouting). Mono-safe (weight, not hue).
|
|
51
|
+
* @param {string} status @returns {import('../../core/tui/draw.js').Style|undefined}
|
|
52
|
+
*/
|
|
53
|
+
function nameStyle(status) {
|
|
54
|
+
if (status === 'active') return { bold: true };
|
|
55
|
+
if (status === 'done' || status === 'dead' || status === 'canceled') return { dim: true };
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ── Row → ListItemRow (left spans + right-flushed age) ─────────────────────────
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Build one list row: a 1-cell left gutter (§2), the tree prefix (dim), the
|
|
63
|
+
* status glyph (hue), the name (weight = status), the dim `[kind/mode]` cue, and
|
|
64
|
+
* a bright-yellow `⚑N` attention flag when blocked — with the relative age
|
|
65
|
+
* RIGHT-FLUSHED into a clean scannable column via `ListItemRow.right`.
|
|
66
|
+
* @param {TreeRow} r @param {number} now
|
|
67
|
+
* @returns {import('../../core/tui/draw.js').ListItemRow}
|
|
68
|
+
*/
|
|
69
|
+
function rowToItem(r, now) {
|
|
70
|
+
/** @type {import('../../core/tui/draw.js').Span[]} */
|
|
71
|
+
const spans = [{ text: ' ', style: undefined }]; // 1-cell gutter (rides the cursor bg)
|
|
72
|
+
if (r.prefix) spans.push({ text: r.prefix, style: { dim: true } });
|
|
73
|
+
spans.push({ text: r.glyph, style: glyphStyle(r.status) });
|
|
74
|
+
spans.push({ text: ' ', style: undefined });
|
|
75
|
+
spans.push({ text: r.name, style: nameStyle(r.status) });
|
|
76
|
+
spans.push({ text: ` [${r.kind}/${r.mode}]`, style: { fg: '90', dim: true } }); // muted: grey + dim (mono-safe)
|
|
77
|
+
if (r.blocked) spans.push({ text: ` ⚑${r.askCount}`, style: { fg: '93', bold: true } }); // attention
|
|
78
|
+
|
|
79
|
+
const age = relAge(r.created, now);
|
|
80
|
+
if (age) {
|
|
81
|
+
return { spans, right: [{ text: age, style: { fg: '90', dim: true } }] };
|
|
82
|
+
}
|
|
83
|
+
return { spans };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── render ─────────────────────────────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Paint the forest, or one of the four standard states. Pure (reads state,
|
|
90
|
+
* calls draw.*); the only state write is storing draw.list's adjusted scroll
|
|
91
|
+
* back, per the Draw contract.
|
|
92
|
+
* @param {CanvasState} state
|
|
93
|
+
* @param {import('../../core/tui/draw.js').Draw} draw
|
|
94
|
+
* @param {import('../../core/tui/draw.js').Rect} content
|
|
95
|
+
*/
|
|
96
|
+
export function render(state, draw, content) {
|
|
97
|
+
if (content.width <= 0 || content.height <= 0) return;
|
|
98
|
+
|
|
99
|
+
if (state.rows.length === 0) {
|
|
100
|
+
// Hard not-ready: the data source is down and there is nothing to keep — a
|
|
101
|
+
// guided takeover owns the whole content rect (design §4/§5). The copy comes
|
|
102
|
+
// from the typed SourceError's `display` VERBATIM (the contract display/kind
|
|
103
|
+
// split — we never branch on `kind`); only the glyph + hue are a presentation
|
|
104
|
+
// map off `display.level` (error → ⚠ red, action → ⊙ yellow).
|
|
105
|
+
if (state.sourceError) {
|
|
106
|
+
const d = state.sourceError.display;
|
|
107
|
+
const g = d.level === 'action' ? { glyph: '⊙', fg: '33' } : { glyph: '⚠', fg: '31' };
|
|
108
|
+
notReadyState(draw, content, {
|
|
109
|
+
glyph: g.glyph,
|
|
110
|
+
glyphFg: g.fg,
|
|
111
|
+
headline: d.headline,
|
|
112
|
+
explanation: d.explanation,
|
|
113
|
+
nextStep: d.nextStep,
|
|
114
|
+
});
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
// First load in flight — a skeleton, not a blank screen.
|
|
118
|
+
if (state.lastFetch === 0) {
|
|
119
|
+
loadingState(draw, content, { rows: Math.min(5, content.height), label: 'Loading the canvas…' });
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// Loaded, nothing to render — the reward state, two flavors.
|
|
123
|
+
if (state.totalNodes === 0) {
|
|
124
|
+
emptyState(draw, content, {
|
|
125
|
+
headline: 'No nodes on the canvas',
|
|
126
|
+
secondary: ['Spawn one with `crtr node new`.', 'Press g to refresh.'],
|
|
127
|
+
});
|
|
128
|
+
} else {
|
|
129
|
+
emptyState(draw, content, {
|
|
130
|
+
headline: 'All caught up',
|
|
131
|
+
secondary: [`${state.totalNodes} node${state.totalNodes === 1 ? '' : 's'} finished — none active.`, 'Press g to refresh.'],
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// The forest. A 1-row section gap below the header (§2 rhythm) when there is
|
|
138
|
+
// room; full-width list so the cursor highlight + age column reach the edges.
|
|
139
|
+
const now = Date.now();
|
|
140
|
+
const gap = content.height > 4 ? 1 : 0;
|
|
141
|
+
const listRect = {
|
|
142
|
+
row: content.row + gap,
|
|
143
|
+
col: content.col,
|
|
144
|
+
width: content.width,
|
|
145
|
+
height: content.height - gap,
|
|
146
|
+
};
|
|
147
|
+
const items = state.rows.map((r) => rowToItem(r, now));
|
|
148
|
+
const res = draw.list(listRect, items, state.cursor, state.scroll);
|
|
149
|
+
state.scroll = res.scroll; // store adjusted scroll back (Draw.list contract)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ── keymap ───────────────────────────────────────────────────────────────
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Read-only navigation: j/k move the cursor, g refreshes, q quits. No async
|
|
156
|
+
* actions from input — this is a monitor, not a controller. Footer hints come
|
|
157
|
+
* from these bindings' `hint` fields (the single source of truth).
|
|
158
|
+
* @type {import('../../core/view/contract.js').KeyBinding<CanvasState>[]}
|
|
159
|
+
*/
|
|
160
|
+
export const keymap = [
|
|
161
|
+
{ keys: ['j', 'down'], intent: 'cursorDown', hint: { keys: 'j/k', label: 'move' } },
|
|
162
|
+
{ keys: ['k', 'up'], intent: 'cursorUp' },
|
|
163
|
+
{ keys: ['g'], intent: 'refresh', hint: { keys: 'g', label: 'refresh' } },
|
|
164
|
+
{ keys: ['q'], intent: 'quit', hint: { keys: 'q', label: 'quit' } },
|
|
165
|
+
];
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* Canvas Dashboard — the WEB presenter for the `canvas` view (React + Tailwind).
|
|
4
|
+
* Browser-only: consumed solely by the web serve path (Vite owns JSX +
|
|
5
|
+
* Tailwind); NEVER Node-imported. The default export is a pure function of
|
|
6
|
+
* `state`; DOM events call `dispatch(intentName, payload?)`.
|
|
7
|
+
*
|
|
8
|
+
* Same logical model as the TUI presenter (`state.rows` + `state.cursor`) read
|
|
9
|
+
* from the SAME portable `core.mjs` — zero shared rendering code with `tui.mjs`
|
|
10
|
+
* (the contract's accepted hard fork: `draw.*` has no web analog). The ASCII
|
|
11
|
+
* forest becomes a DOM tree, but the branch-prefix art is preserved verbatim in
|
|
12
|
+
* a monospace column so the hierarchy reads identically. The outer chrome (title
|
|
13
|
+
* / status / banner / state chip) is rendered by `<ViewChrome>`, which wraps this
|
|
14
|
+
* component — so do NOT render it here.
|
|
15
|
+
*
|
|
16
|
+
* VISUAL LANGUAGE (the web analog of tui.mjs's NUMERIC-SGR maps): the status hue
|
|
17
|
+
* matches `canvas browse`'s palette (active=green, idle=amber, done=cyan,
|
|
18
|
+
* dead=red, canceled=slate); live work LEADS in bold, terminal nodes recede;
|
|
19
|
+
* the ⚑N attention flag is bright yellow.
|
|
20
|
+
*
|
|
21
|
+
* @module canvas/web
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { relAge } from './core.mjs';
|
|
25
|
+
import { Loading, Empty, ErrorState, NotReady } from '@crouton-kit/crouter/web';
|
|
26
|
+
|
|
27
|
+
/** @typedef {import('./core.mjs').CanvasState} CanvasState */
|
|
28
|
+
/** @typedef {import('./core.mjs').TreeRow} TreeRow */
|
|
29
|
+
|
|
30
|
+
// ── Status vocabulary (the web analog of tui.mjs's STATUS_FG / nameStyle) ──────
|
|
31
|
+
|
|
32
|
+
/** @type {Record<string,string>} */
|
|
33
|
+
const STATUS_CLS = {
|
|
34
|
+
active: 'text-green-600',
|
|
35
|
+
idle: 'text-amber-600',
|
|
36
|
+
done: 'text-cyan-700',
|
|
37
|
+
dead: 'text-red-600',
|
|
38
|
+
canceled: 'text-slate-400',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/** @param {string} status @returns {string} */
|
|
42
|
+
function nameCls(status) {
|
|
43
|
+
if (status === 'active') return 'font-bold';
|
|
44
|
+
if (status === 'done' || status === 'dead' || status === 'canceled') return 'text-slate-400';
|
|
45
|
+
return '';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ── Tree rows (the web analog of tui.mjs's rowToItem) ──────────────────────────
|
|
49
|
+
|
|
50
|
+
/** @param {{ row: TreeRow, selected: boolean, onClick: () => void }} props */
|
|
51
|
+
function TreeRowItem({ row, selected, onClick }) {
|
|
52
|
+
const now = Date.now();
|
|
53
|
+
const age = relAge(row.created, now);
|
|
54
|
+
return (
|
|
55
|
+
<li
|
|
56
|
+
className={`flex items-baseline gap-1.5 rounded px-2 py-0.5 ${selected ? 'bg-slate-200' : ''}`}
|
|
57
|
+
onClick={onClick}
|
|
58
|
+
>
|
|
59
|
+
{row.prefix ? <span className="whitespace-pre text-slate-400">{row.prefix}</span> : null}
|
|
60
|
+
<span className={STATUS_CLS[row.status] || 'text-slate-400'}>{row.glyph}</span>
|
|
61
|
+
<span className={nameCls(row.status)}>{row.name}</span>
|
|
62
|
+
<span className="text-slate-400">[{row.kind}/{row.mode}]</span>
|
|
63
|
+
{row.blocked ? <span className="font-bold text-yellow-500">⚑{row.askCount}</span> : null}
|
|
64
|
+
{age ? <span className="ml-auto shrink-0 text-slate-400">{age}</span> : null}
|
|
65
|
+
</li>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ── The view ───────────────────────────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @param {import('../../core/view/contract.js').ViewProps<CanvasState>} props
|
|
73
|
+
*/
|
|
74
|
+
export default function Canvas({ state, dispatch }) {
|
|
75
|
+
// ── Whole-view takeovers (no forest to render). When the data source is down
|
|
76
|
+
// and there is nothing to keep, the copy comes from the typed SourceError's
|
|
77
|
+
// `display` VERBATIM (the contract display/kind split — we never branch on
|
|
78
|
+
// `kind`); only the four-state component is a presentation map off
|
|
79
|
+
// `display.level` so the hue matches the TUI (error → red ErrorState,
|
|
80
|
+
// action → amber NotReady). ──
|
|
81
|
+
if (state.rows.length === 0) {
|
|
82
|
+
if (state.sourceError) {
|
|
83
|
+
const d = state.sourceError.display;
|
|
84
|
+
const Takeover = d.level === 'error' ? ErrorState : NotReady;
|
|
85
|
+
return (
|
|
86
|
+
<Takeover
|
|
87
|
+
headline={d.headline}
|
|
88
|
+
explanation={d.explanation}
|
|
89
|
+
nextStep={d.nextStep}
|
|
90
|
+
onRetry={() => dispatch('refresh')}
|
|
91
|
+
/>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
if (state.lastFetch === 0) {
|
|
95
|
+
return <Loading label="Loading the canvas…" />;
|
|
96
|
+
}
|
|
97
|
+
if (state.totalNodes === 0) {
|
|
98
|
+
return <Empty label="No nodes on the canvas — spawn one with `crtr node new`." />;
|
|
99
|
+
}
|
|
100
|
+
return <Empty label={`All caught up — ${state.totalNodes} node${state.totalNodes === 1 ? '' : 's'} finished, none active.`} />;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<div
|
|
105
|
+
className="font-mono text-sm outline-none"
|
|
106
|
+
tabIndex={0}
|
|
107
|
+
onKeyDown={(e) => {
|
|
108
|
+
if (e.key === 'j' || e.key === 'ArrowDown') { dispatch('cursorDown'); e.preventDefault(); }
|
|
109
|
+
else if (e.key === 'k' || e.key === 'ArrowUp') { dispatch('cursorUp'); e.preventDefault(); }
|
|
110
|
+
else if (e.key === 'g') { dispatch('refresh'); }
|
|
111
|
+
}}
|
|
112
|
+
>
|
|
113
|
+
<ul>
|
|
114
|
+
{state.rows.map((row, i) => (
|
|
115
|
+
<TreeRowItem key={row.nodeId || i} row={row} selected={i === state.cursor} onClick={() => dispatch('activate', { nodeId: row.nodeId })} />
|
|
116
|
+
))}
|
|
117
|
+
</ul>
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
}
|