@visual-z/xeno 0.8.3 → 0.9.0
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/CHANGELOG.md +24 -0
- package/README.md +31 -746
- package/bin/xeno.exe +26 -0
- package/install.cjs +88 -0
- package/package.json +18 -48
- package/docs/app-server.md +0 -115
- package/docs/foundations.md +0 -88
- package/docs/install.md +0 -244
- package/docs/providers.md +0 -172
- package/docs/research/foundation-clients-2026-10-09.md +0 -27
- package/docs/research/foundation-editing-2026-10-09.md +0 -56
- package/docs/research/foundation-network-2026-10-09.md +0 -37
- package/docs/research/foundation-workflow-2026-10-09.md +0 -37
- package/src/apps/acp-server.ts +0 -41
- package/src/apps/agent-profiles.ts +0 -19
- package/src/apps/app-server.ts +0 -30
- package/src/apps/approve.ts +0 -49
- package/src/apps/cli.ts +0 -99
- package/src/apps/commands.ts +0 -319
- package/src/apps/completions.ts +0 -87
- package/src/apps/control-transport.ts +0 -90
- package/src/apps/export-cli.ts +0 -24
- package/src/apps/goal-flow.ts +0 -70
- package/src/apps/image-draft.ts +0 -46
- package/src/apps/input.ts +0 -312
- package/src/apps/model-catalog.ts +0 -69
- package/src/apps/preferences.ts +0 -20
- package/src/apps/project-trust.ts +0 -9
- package/src/apps/provider-connect.ts +0 -346
- package/src/apps/question-ui.ts +0 -27
- package/src/apps/render.ts +0 -181
- package/src/apps/resources.ts +0 -66
- package/src/apps/review.ts +0 -109
- package/src/apps/session-hub.ts +0 -96
- package/src/apps/session-lifecycle.ts +0 -64
- package/src/apps/shell.ts +0 -2066
- package/src/apps/startup-input.ts +0 -135
- package/src/apps/startup.ts +0 -1677
- package/src/apps/ui/app.ts +0 -1713
- package/src/apps/ui/control-model.ts +0 -43
- package/src/apps/ui/extension-host.ts +0 -194
- package/src/apps/ui/image-cache.ts +0 -121
- package/src/apps/ui/palette.ts +0 -88
- package/src/apps/ui/project.ts +0 -127
- package/src/apps/ui/standalone.ts +0 -148
- package/src/apps/ui/status-model.ts +0 -68
- package/src/apps/ui/surface.ts +0 -91
- package/src/apps/ui/theme.ts +0 -86
- package/src/apps/update-check.ts +0 -112
- package/src/apps/workflow.ts +0 -58
- package/src/core/acceptance.ts +0 -139
- package/src/core/action-defaults.ts +0 -58
- package/src/core/activity-status.ts +0 -52
- package/src/core/agent-profile.ts +0 -130
- package/src/core/attachment-input.ts +0 -17
- package/src/core/blind-checks.ts +0 -72
- package/src/core/boundary.ts +0 -174
- package/src/core/branch-receipt.ts +0 -26
- package/src/core/catalog-merge.ts +0 -19
- package/src/core/checkpoints.ts +0 -85
- package/src/core/churn.ts +0 -61
- package/src/core/command-artifacts.ts +0 -94
- package/src/core/command-contract.ts +0 -151
- package/src/core/completion-action.ts +0 -20
- package/src/core/completion-review.ts +0 -98
- package/src/core/context-detail.ts +0 -37
- package/src/core/context-policy.ts +0 -133
- package/src/core/context-window.ts +0 -54
- package/src/core/continuation.ts +0 -130
- package/src/core/control-protocol.ts +0 -69
- package/src/core/control-view.ts +0 -39
- package/src/core/cycle.ts +0 -17
- package/src/core/data-query.ts +0 -201
- package/src/core/deadline.ts +0 -40
- package/src/core/derive.ts +0 -516
- package/src/core/draft-images.ts +0 -56
- package/src/core/edit-plan.ts +0 -200
- package/src/core/environment.ts +0 -181
- package/src/core/event-validation.ts +0 -220
- package/src/core/events.ts +0 -670
- package/src/core/evidence-ladder.ts +0 -62
- package/src/core/evidence-links.ts +0 -68
- package/src/core/evidence.ts +0 -240
- package/src/core/execution.ts +0 -18
- package/src/core/exhaustive.ts +0 -18
- package/src/core/export.ts +0 -179
- package/src/core/extension-flags.ts +0 -14
- package/src/core/external-effects.ts +0 -488
- package/src/core/failure-recovery.ts +0 -173
- package/src/core/file-precondition.ts +0 -78
- package/src/core/file-references.ts +0 -35
- package/src/core/frontmatter.ts +0 -213
- package/src/core/git-status.ts +0 -29
- package/src/core/goal-view.ts +0 -64
- package/src/core/goal.ts +0 -200
- package/src/core/handoff.ts +0 -479
- package/src/core/history-query.ts +0 -139
- package/src/core/history.ts +0 -237
- package/src/core/image-limits.ts +0 -72
- package/src/core/images.ts +0 -46
- package/src/core/integration-health.ts +0 -34
- package/src/core/json-event.ts +0 -131
- package/src/core/json-pointer.ts +0 -46
- package/src/core/keymap.ts +0 -153
- package/src/core/lsp-framing.ts +0 -34
- package/src/core/mcp-config.ts +0 -68
- package/src/core/model-picker.ts +0 -64
- package/src/core/model-preferences.ts +0 -28
- package/src/core/model-replay.ts +0 -22
- package/src/core/model-scope.ts +0 -53
- package/src/core/note-guidance.ts +0 -34
- package/src/core/oauth-fields.ts +0 -44
- package/src/core/observation-view.ts +0 -152
- package/src/core/outcome.ts +0 -44
- package/src/core/overflow.ts +0 -59
- package/src/core/packages.ts +0 -47
- package/src/core/patch.ts +0 -130
- package/src/core/path-suggestions.ts +0 -59
- package/src/core/permissions.ts +0 -410
- package/src/core/process-receipt.ts +0 -105
- package/src/core/process-state.ts +0 -37
- package/src/core/program-status.ts +0 -40
- package/src/core/progress.ts +0 -150
- package/src/core/project.ts +0 -431
- package/src/core/prompt-policy.ts +0 -46
- package/src/core/prompts.ts +0 -111
- package/src/core/question.ts +0 -94
- package/src/core/queue.ts +0 -78
- package/src/core/read-bounds.ts +0 -24
- package/src/core/read-observation.ts +0 -106
- package/src/core/recovery-sources.ts +0 -74
- package/src/core/regex-dialect.ts +0 -25
- package/src/core/request-budget.ts +0 -23
- package/src/core/request-progress.ts +0 -87
- package/src/core/request-state.ts +0 -273
- package/src/core/resource-selection.ts +0 -36
- package/src/core/response-recovery.ts +0 -59
- package/src/core/resume.ts +0 -59
- package/src/core/review.ts +0 -68
- package/src/core/ripgrep-release.ts +0 -64
- package/src/core/runtime-target.ts +0 -94
- package/src/core/scheduling.ts +0 -8
- package/src/core/search-observation.ts +0 -97
- package/src/core/secrets.ts +0 -188
- package/src/core/session-archive.ts +0 -4
- package/src/core/session-browser.ts +0 -82
- package/src/core/session-entry.ts +0 -61
- package/src/core/session-exit.ts +0 -42
- package/src/core/session-format.ts +0 -169
- package/src/core/session-position.ts +0 -26
- package/src/core/session-tree.ts +0 -147
- package/src/core/settings.ts +0 -192
- package/src/core/skills.ts +0 -165
- package/src/core/sql-query.ts +0 -211
- package/src/core/stall.ts +0 -128
- package/src/core/stop-report.ts +0 -68
- package/src/core/text-normalize.ts +0 -81
- package/src/core/theme.ts +0 -166
- package/src/core/thinking.ts +0 -26
- package/src/core/tokens.ts +0 -151
- package/src/core/tool-contract.ts +0 -153
- package/src/core/tool-discovery.ts +0 -87
- package/src/core/tool-failure.ts +0 -81
- package/src/core/tool-input.ts +0 -44
- package/src/core/transcript.ts +0 -108
- package/src/core/tui-mode.ts +0 -29
- package/src/core/update-check.ts +0 -157
- package/src/core/version.ts +0 -55
- package/src/core/web-content.ts +0 -80
- package/src/core/work-state.ts +0 -154
- package/src/core/workflow-mode.ts +0 -34
- package/src/core/working-set.ts +0 -119
- package/src/core/yaml.ts +0 -282
- package/src/runtime/acp-agent.ts +0 -289
- package/src/runtime/agent-profiles.ts +0 -21
- package/src/runtime/auth.ts +0 -367
- package/src/runtime/blind-check.ts +0 -36
- package/src/runtime/branch-jobs.ts +0 -36
- package/src/runtime/catalog.ts +0 -285
- package/src/runtime/clipboard.ts +0 -125
- package/src/runtime/command-artifacts.ts +0 -64
- package/src/runtime/connection-reuse.ts +0 -40
- package/src/runtime/control-client.ts +0 -149
- package/src/runtime/control-connection.ts +0 -139
- package/src/runtime/counter-check.ts +0 -74
- package/src/runtime/environment-tools.ts +0 -60
- package/src/runtime/evidence-notes.ts +0 -35
- package/src/runtime/exec-sessions.ts +0 -456
- package/src/runtime/execution-control.ts +0 -40
- package/src/runtime/extension-loader.ts +0 -37
- package/src/runtime/extension-ui.ts +0 -47
- package/src/runtime/extensions.ts +0 -370
- package/src/runtime/formatter-tool.ts +0 -38
- package/src/runtime/formatter.ts +0 -50
- package/src/runtime/foundation.ts +0 -116
- package/src/runtime/history-cache.ts +0 -57
- package/src/runtime/history-tools.ts +0 -168
- package/src/runtime/images.ts +0 -80
- package/src/runtime/integrations.ts +0 -216
- package/src/runtime/loop.ts +0 -3001
- package/src/runtime/lsp-client.ts +0 -201
- package/src/runtime/mcp-client.ts +0 -264
- package/src/runtime/mcp-oauth.ts +0 -168
- package/src/runtime/mcp-schema.ts +0 -51
- package/src/runtime/model-config.ts +0 -232
- package/src/runtime/model-data.LICENSE +0 -27
- package/src/runtime/model-data.ts +0 -21
- package/src/runtime/model-discovery.ts +0 -208
- package/src/runtime/model-replay.ts +0 -10
- package/src/runtime/model-scope.ts +0 -20
- package/src/runtime/model-sources.ts +0 -151
- package/src/runtime/model.ts +0 -686
- package/src/runtime/models-fetch.ts +0 -57
- package/src/runtime/oauth-device.ts +0 -86
- package/src/runtime/oauth.ts +0 -853
- package/src/runtime/open-image.ts +0 -42
- package/src/runtime/openai-responses.ts +0 -304
- package/src/runtime/openai.ts +0 -697
- package/src/runtime/output-schema.ts +0 -26
- package/src/runtime/package-manager.ts +0 -125
- package/src/runtime/patch-tool.ts +0 -38
- package/src/runtime/permission-resources.ts +0 -18
- package/src/runtime/pi-provider.ts +0 -423
- package/src/runtime/program-status.ts +0 -38
- package/src/runtime/progress.ts +0 -26
- package/src/runtime/provider-access.ts +0 -21
- package/src/runtime/provider-connect.ts +0 -109
- package/src/runtime/provider-presets.ts +0 -98
- package/src/runtime/provider-protocols.ts +0 -29
- package/src/runtime/provider-request.ts +0 -87
- package/src/runtime/provider-tool-policy.ts +0 -33
- package/src/runtime/provider.ts +0 -580
- package/src/runtime/question-tool.ts +0 -62
- package/src/runtime/retry.ts +0 -447
- package/src/runtime/review-tool.ts +0 -48
- package/src/runtime/rich-text.ts +0 -36
- package/src/runtime/runtime-target.ts +0 -149
- package/src/runtime/secrets.ts +0 -79
- package/src/runtime/self-update.ts +0 -74
- package/src/runtime/session-control.ts +0 -265
- package/src/runtime/session-hub.ts +0 -85
- package/src/runtime/stream-idle.ts +0 -80
- package/src/runtime/tool-broker.ts +0 -137
- package/src/runtime/tool-discovery.ts +0 -58
- package/src/runtime/tool-queue.ts +0 -77
- package/src/runtime/tools.ts +0 -1820
- package/src/runtime/turn-effects.ts +0 -31
- package/src/runtime/update-check.ts +0 -48
- package/src/runtime/usage.ts +0 -253
- package/src/runtime/version.ts +0 -12
- package/src/runtime/web-http.ts +0 -56
- package/src/runtime/web-tools.ts +0 -88
- package/src/runtime/working-notes.ts +0 -60
- package/src/runtime/workspace-lifecycle.ts +0 -141
- package/src/store/acceptance.ts +0 -15
- package/src/store/agent-profile-files.ts +0 -13
- package/src/store/atomic.ts +0 -31
- package/src/store/auth-store.ts +0 -50
- package/src/store/blind-checks.ts +0 -32
- package/src/store/blobs.ts +0 -143
- package/src/store/checkpoint-history.ts +0 -32
- package/src/store/command-artifacts.ts +0 -96
- package/src/store/command.ts +0 -111
- package/src/store/config.ts +0 -69
- package/src/store/context-files.ts +0 -436
- package/src/store/file-checkpoints.ts +0 -108
- package/src/store/file-index.ts +0 -174
- package/src/store/foundation-config.ts +0 -24
- package/src/store/git-checkpoints.ts +0 -67
- package/src/store/git-status.ts +0 -15
- package/src/store/history-search.ts +0 -19
- package/src/store/log.ts +0 -725
- package/src/store/lsp-document.ts +0 -30
- package/src/store/mcp-credentials.ts +0 -85
- package/src/store/models.ts +0 -60
- package/src/store/observations.ts +0 -224
- package/src/store/packages.ts +0 -98
- package/src/store/patch.ts +0 -92
- package/src/store/permission-paths.ts +0 -34
- package/src/store/process-receipts.ts +0 -34
- package/src/store/query-source.ts +0 -49
- package/src/store/recovery.ts +0 -44
- package/src/store/replay.ts +0 -76
- package/src/store/resource-index.ts +0 -170
- package/src/store/resources.ts +0 -285
- package/src/store/restore.ts +0 -110
- package/src/store/review.ts +0 -109
- package/src/store/runtime-target.ts +0 -64
- package/src/store/search.ts +0 -728
- package/src/store/secrets.ts +0 -44
- package/src/store/serial.ts +0 -13
- package/src/store/session-archive.ts +0 -165
- package/src/store/session-browser.ts +0 -68
- package/src/store/session-position.ts +0 -27
- package/src/store/sessions.ts +0 -525
- package/src/store/source-cancellation.ts +0 -6
- package/src/store/tool-binaries.ts +0 -90
- package/src/store/trust.ts +0 -82
- package/src/store/update-cache.ts +0 -36
- package/src/store/user-settings.ts +0 -30
- package/src/store/workspace-clone.ts +0 -42
- package/src/store/workspace-observation.ts +0 -113
- package/src/store/workspace.ts +0 -115
- package/src/store/worktree.ts +0 -278
- package/src/tui/ansi-spans.ts +0 -126
- package/src/tui/diff.ts +0 -160
- package/src/tui/exhaustive.ts +0 -14
- package/src/tui/fuzzy.ts +0 -75
- package/src/tui/style.ts +0 -208
- package/src/tui/ui/atomic-draft.ts +0 -121
- package/src/tui/ui/canvas.ts +0 -96
- package/src/tui/ui/colors.ts +0 -70
- package/src/tui/ui/composer.ts +0 -200
- package/src/tui/ui/control-panel.ts +0 -25
- package/src/tui/ui/control-sidebar.ts +0 -49
- package/src/tui/ui/dialog.ts +0 -398
- package/src/tui/ui/draft.ts +0 -23
- package/src/tui/ui/duration.ts +0 -16
- package/src/tui/ui/edge.ts +0 -186
- package/src/tui/ui/image-size.ts +0 -44
- package/src/tui/ui/ink.ts +0 -210
- package/src/tui/ui/items.ts +0 -42
- package/src/tui/ui/keys.ts +0 -40
- package/src/tui/ui/layout.ts +0 -74
- package/src/tui/ui/list-model.ts +0 -86
- package/src/tui/ui/list-view.ts +0 -172
- package/src/tui/ui/mascot.ts +0 -67
- package/src/tui/ui/messages.ts +0 -518
- package/src/tui/ui/motion.ts +0 -28
- package/src/tui/ui/paths.ts +0 -10
- package/src/tui/ui/pictures.ts +0 -108
- package/src/tui/ui/screen.ts +0 -548
- package/src/tui/ui/status.ts +0 -403
- package/src/tui/ui/styled.ts +0 -85
- package/src/tui/ui/tool-card.ts +0 -150
- package/src/tui/width.ts +0 -567
- package/src/vendor/pi-rich/LICENSE.upstream +0 -21
- package/src/vendor/pi-rich/UPSTREAM.json +0 -17
- package/src/vendor/pi-rich/clipboard-command.ts +0 -44
- package/src/vendor/pi-rich/exif-orientation.ts +0 -182
- package/src/vendor/pi-rich/html.ts +0 -51
- package/src/vendor/pi-rich/image-convert.ts +0 -49
- package/src/vendor/pi-rich/image-resize-core.ts +0 -164
- package/src/vendor/pi-rich/image-resize-worker.ts +0 -42
- package/src/vendor/pi-rich/image-resize.ts +0 -123
- package/src/vendor/pi-rich/mime.ts +0 -116
- package/src/vendor/pi-rich/photon.ts +0 -139
- package/src/vendor/pi-rich/syntax-highlight.ts +0 -214
package/src/tui/ui/composer.ts
DELETED
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The one editor (D20). It lives inside the input box at the bottom of the
|
|
3
|
-
* screen and is never recreated: pickers and forms open in the same box
|
|
4
|
-
* above it and give focus back, so the draft, undo history and cursor stay
|
|
5
|
-
* (docs/tasks/refactor-tui-dock-layout.md DoD 1). Typing, undo and paste are
|
|
6
|
-
* OpenTUI's; submission and history are the app's.
|
|
7
|
-
*
|
|
8
|
-
* Completion is state here and drawn by the screen above the box, where it
|
|
9
|
-
* takes layout space instead of covering the transcript.
|
|
10
|
-
*/
|
|
11
|
-
import { BoxRenderable, type CliRenderer } from "@opentui/core";
|
|
12
|
-
import { AtomicDraftArea, type DraftAtom } from "./atomic-draft.ts";
|
|
13
|
-
import { Canvas } from "./canvas.ts";
|
|
14
|
-
import type { UiColors } from "./colors.ts";
|
|
15
|
-
import { draftRows, type DraftRows } from "./draft.ts";
|
|
16
|
-
import type { ListItem } from "./list-model.ts";
|
|
17
|
-
|
|
18
|
-
export interface Completion {
|
|
19
|
-
readonly kind: "command" | "argument" | "path";
|
|
20
|
-
/** Replace text[start, end) with an item's value. */
|
|
21
|
-
readonly start: number;
|
|
22
|
-
readonly end: number;
|
|
23
|
-
readonly items: readonly ListItem[];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* The tallest the draft grows before it scrolls inside the box: a third of
|
|
28
|
-
* the terminal, at least 5 rows. Peers cap by screen fraction rather than a
|
|
29
|
-
* constant (pi 30% min 5, OpenCode ⅓ min 6, Grok ½, Codex ⅔); a third keeps
|
|
30
|
-
* most of the transcript in view while a paragraph still fits.
|
|
31
|
-
*/
|
|
32
|
-
export function draftMaxLines(terminalRows: number): number {
|
|
33
|
-
return Math.max(5, Math.floor(terminalRows / 3));
|
|
34
|
-
}
|
|
35
|
-
const MAX_LINES = 5;
|
|
36
|
-
export const PLACEHOLDER = "What would you like to work on?";
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* The textarea, plus a hook after each of its frames. The editor scrolls to
|
|
40
|
-
* its cursor while it renders, and its own render() skips renderAfter, so
|
|
41
|
-
* this is the one place the visible part of a tall draft is known.
|
|
42
|
-
*/
|
|
43
|
-
export class Composer {
|
|
44
|
-
/** `›` and the editor. Its height is the editor's own measurement of the wrapped draft. */
|
|
45
|
-
readonly row: BoxRenderable;
|
|
46
|
-
readonly area: AtomicDraftArea;
|
|
47
|
-
private draftRevision = 0;
|
|
48
|
-
private readonly prompt: Canvas;
|
|
49
|
-
private completion: Completion | undefined;
|
|
50
|
-
private completionIndex = 0;
|
|
51
|
-
private history: string[] = [];
|
|
52
|
-
private historyAt = -1;
|
|
53
|
-
private historyDraft = "";
|
|
54
|
-
private maxLines = MAX_LINES;
|
|
55
|
-
private shape: DraftRows = { rows: 1, above: 0, below: 0 };
|
|
56
|
-
onChange: ((text: string) => void) | undefined;
|
|
57
|
-
onCursor: (() => void) | undefined;
|
|
58
|
-
/** The row count changed (the box above must re-layout). */
|
|
59
|
-
onResize: (() => void) | undefined;
|
|
60
|
-
/** Rows hidden above or below the visible draft changed (the box edge shows them). */
|
|
61
|
-
onOverflow: (() => void) | undefined;
|
|
62
|
-
|
|
63
|
-
constructor(renderer: CliRenderer, colors: UiColors) {
|
|
64
|
-
this.row = new BoxRenderable(renderer, { id: "composer", flexDirection: "row", flexShrink: 0 });
|
|
65
|
-
this.prompt = new Canvas(renderer, { id: "composer-prompt", width: 2, height: 1, flexShrink: 0, colors });
|
|
66
|
-
this.prompt.setRows([[{ text: "›", role: "accent", bold: true }]]);
|
|
67
|
-
const area = new AtomicDraftArea(renderer, {
|
|
68
|
-
id: "composer-area", flexGrow: 1, minHeight: 1, maxHeight: MAX_LINES, wrapMode: "word",
|
|
69
|
-
textColor: colors.text, focusedTextColor: colors.text, backgroundColor: "transparent", focusedBackgroundColor: "transparent",
|
|
70
|
-
selectionBg: colors.selectionBg, selectionFg: colors.selectionFg,
|
|
71
|
-
placeholder: PLACEHOLDER, placeholderColor: colors.muted,
|
|
72
|
-
// Enter, Shift+Enter, Up/Down are the app's (submit, history); remove them from the textarea.
|
|
73
|
-
keyBindings: [{ name: "return", action: "move-left" }, { name: "_", ctrl: true, action: "undo" }, { name: "/", ctrl: true, action: "undo" }],
|
|
74
|
-
});
|
|
75
|
-
this.area = area;
|
|
76
|
-
// Height comes from the editor's native measurement of its wrapped text, capped by
|
|
77
|
-
// maxHeight (the way OpenCode's prompt grows). Nothing here sets a height, so width
|
|
78
|
-
// changes re-wrap and re-measure on their own (fix-tui-composer-growth).
|
|
79
|
-
this.area.onContentChange = () => { this.draftRevision++; this.onChange?.(this.text); };
|
|
80
|
-
this.area.onCursorChange = () => { this.draftRevision++; this.onCursor?.(); };
|
|
81
|
-
this.area.onSizeChange = () => this.measured();
|
|
82
|
-
// Which rows scrolled out of a tall draft is known only after the editor drew itself.
|
|
83
|
-
area.onRendered = () => this.measured();
|
|
84
|
-
this.row.add(this.prompt); this.row.add(this.area);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
get text(): string { return this.area.plainText; }
|
|
88
|
-
get cursor(): number { return this.area.textCursor; }
|
|
89
|
-
get revision(): number { return this.draftRevision; }
|
|
90
|
-
setAtoms(spans: (text: string) => readonly DraftAtom[]): void { this.area.atoms = spans; }
|
|
91
|
-
get completing(): boolean { return this.completion !== undefined && this.completion.items.length > 0; }
|
|
92
|
-
/** What the completion list shows (screen draws it). */
|
|
93
|
-
get completionView(): { readonly kind: Completion["kind"]; readonly items: readonly ListItem[]; readonly selected: number } | undefined {
|
|
94
|
-
return this.completion ? { kind: this.completion.kind, items: this.completion.items, selected: this.completionIndex } : undefined;
|
|
95
|
-
}
|
|
96
|
-
get historyEntries(): readonly string[] { return this.history; }
|
|
97
|
-
get rows(): number { return Math.max(1, this.area.height); }
|
|
98
|
-
/** Wrapped rows of the draft hidden above / below the box (0 when it all fits). */
|
|
99
|
-
get overflow(): { readonly above: number; readonly below: number } { return { above: this.shape.above, below: this.shape.below }; }
|
|
100
|
-
|
|
101
|
-
setColors(colors: UiColors): void {
|
|
102
|
-
this.area.textColor = colors.text;
|
|
103
|
-
this.area.focusedTextColor = colors.text;
|
|
104
|
-
this.area.placeholderColor = colors.muted;
|
|
105
|
-
this.area.selectionBg = colors.selectionBg;
|
|
106
|
-
this.area.selectionFg = colors.selectionFg;
|
|
107
|
-
this.prompt.setColors(colors);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
setText(text: string): void {
|
|
111
|
-
this.draftRevision++;
|
|
112
|
-
this.area.setText(text);
|
|
113
|
-
this.area.gotoBufferEnd();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
insert(text: string): void { this.draftRevision++; this.area.insertText(text); }
|
|
117
|
-
removeAtom(label: string): void { this.draftRevision++; this.area.replaceText(this.text.split(label).join("")); }
|
|
118
|
-
resetDraft(project: (text: string) => string): void {
|
|
119
|
-
this.history = this.history.map(project).filter(Boolean);
|
|
120
|
-
this.historyAt = -1; this.historyDraft = ""; this.area.clearKilledText(); this.setText("");
|
|
121
|
-
}
|
|
122
|
-
focus(): void { this.area.focus(); }
|
|
123
|
-
|
|
124
|
-
remember(entry: string): void {
|
|
125
|
-
if (!entry.trim()) return;
|
|
126
|
-
if (this.history[0] !== entry) this.history.unshift(entry);
|
|
127
|
-
this.history = this.history.slice(0, 200);
|
|
128
|
-
this.historyAt = -1;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** Up/Down walk history only when the cursor is on the first/last line, so multi-line drafts stay editable. */
|
|
132
|
-
historyStep(direction: -1 | 1): boolean {
|
|
133
|
-
const text = this.area.plainText;
|
|
134
|
-
const offset = this.area.cursorOffset;
|
|
135
|
-
const firstLine = !text.slice(0, offset).includes("\n");
|
|
136
|
-
const lastLine = !text.slice(offset).includes("\n");
|
|
137
|
-
if (direction < 0 && !firstLine) return false;
|
|
138
|
-
if (direction > 0 && !lastLine) return false;
|
|
139
|
-
if (direction < 0) {
|
|
140
|
-
if (this.historyAt + 1 >= this.history.length) return true;
|
|
141
|
-
if (this.historyAt === -1) this.historyDraft = text;
|
|
142
|
-
this.historyAt++;
|
|
143
|
-
this.setText(this.history[this.historyAt]!);
|
|
144
|
-
return true;
|
|
145
|
-
}
|
|
146
|
-
if (this.historyAt < 0) return false;
|
|
147
|
-
this.historyAt--;
|
|
148
|
-
this.setText(this.historyAt < 0 ? this.historyDraft : this.history[this.historyAt]!);
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
setCompletion(completion: Completion | undefined): void {
|
|
153
|
-
const next = completion && completion.items.length ? completion : undefined;
|
|
154
|
-
if (!next && !this.completion) return;
|
|
155
|
-
this.completion = next;
|
|
156
|
-
this.completionIndex = 0;
|
|
157
|
-
this.onResize?.();
|
|
158
|
-
}
|
|
159
|
-
moveCompletion(delta: number): void {
|
|
160
|
-
if (!this.completion) return;
|
|
161
|
-
const n = this.completion.items.length;
|
|
162
|
-
this.completionIndex = (this.completionIndex + delta + n) % n;
|
|
163
|
-
this.onResize?.();
|
|
164
|
-
}
|
|
165
|
-
/** Apply the selected completion; returns the applied item. */
|
|
166
|
-
acceptCompletion(): ListItem | undefined {
|
|
167
|
-
const completion = this.completion;
|
|
168
|
-
const item = completion?.items[this.completionIndex];
|
|
169
|
-
if (!completion || !item) return undefined;
|
|
170
|
-
const text = this.area.plainText;
|
|
171
|
-
this.area.setText(text.slice(0, completion.start) + item.value + text.slice(completion.end));
|
|
172
|
-
this.area.cursorOffset = completion.start + item.value.length;
|
|
173
|
-
this.setCompletion(undefined);
|
|
174
|
-
return item;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/** The tallest the draft may grow, so the box never pushes the transcript off a short screen. */
|
|
178
|
-
/** The screen's limit for this terminal size (draftMaxLines, then whatever space is left). */
|
|
179
|
-
setMaxLines(lines: number): void {
|
|
180
|
-
const next = Math.max(1, Math.floor(lines));
|
|
181
|
-
if (next === this.maxLines) return;
|
|
182
|
-
this.maxLines = next;
|
|
183
|
-
this.area.maxHeight = next;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* After layout or a frame: report a new height and what scrolled out of
|
|
188
|
-
* view. `virtualLineCount` is only the viewport's visible rows (always 1 in
|
|
189
|
-
* a one-row box, which is how the box used to stay one row); the editor
|
|
190
|
-
* view's total is the whole wrapped draft. Writes only on change, so a
|
|
191
|
-
* quiet frame costs two native reads.
|
|
192
|
-
*/
|
|
193
|
-
private measured(): void {
|
|
194
|
-
const next = draftRows(this.area.editorView.getTotalVirtualLineCount(), this.area.scrollY, Math.max(1, Math.min(this.maxLines, this.area.height || 1)));
|
|
195
|
-
const previous = this.shape;
|
|
196
|
-
this.shape = next;
|
|
197
|
-
if (next.rows !== previous.rows) this.onResize?.();
|
|
198
|
-
if (next.above !== previous.above || next.below !== previous.below) this.onOverflow?.();
|
|
199
|
-
}
|
|
200
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/** View-only data: apps owns the projection and actions, as required by D20. */
|
|
2
|
-
import { wrapPlain } from "../diff.ts";
|
|
3
|
-
|
|
4
|
-
export type ControlPanelModel = {
|
|
5
|
-
thread: string; turn: string | null; goal: string; status: string; execution: string; gaps: readonly string[];
|
|
6
|
-
progress: readonly { label: string; count: number; sources: readonly string[] }[]; checks: readonly string[];
|
|
7
|
-
context: readonly string[]; omitted: readonly string[]; history: readonly string[];
|
|
8
|
-
};
|
|
9
|
-
export type ControlTab = "goal" | "progress" | "context";
|
|
10
|
-
export type ControlFocus = "messages" | "omitted" | "history";
|
|
11
|
-
|
|
12
|
-
export function controlPanelLines(model: ControlPanelModel, tab: ControlTab, width: number, focus: ControlFocus = "messages"): string[] {
|
|
13
|
-
const lines = tab === "goal" ? [model.goal, `Goal: ${model.status}`, `Execution: ${model.execution}`, "", ...model.gaps,
|
|
14
|
-
...model.checks, "", `Thread ${model.thread}`, `Turn ${model.turn ?? "none"}`]
|
|
15
|
-
: tab === "progress" ? ["Evidence for this request", ...model.progress.map(item => `${item.label}: ${item.count}`), "",
|
|
16
|
-
"Counts describe observations, not a completion percentage.", ...model.checks,
|
|
17
|
-
...model.progress.flatMap(item => item.sources.map(source => `${item.label}: ${source}`))]
|
|
18
|
-
: focus === "messages" ? ["Actual model context · ←/→ change lens", ...model.context]
|
|
19
|
-
: focus === "omitted" ? ["Not replayed as messages · ←/→ change lens", ...(model.omitted.length ? model.omitted : ["No omitted events in this segment."])]
|
|
20
|
-
: ["Handoff retention and recovery · ←/→ change lens", ...(model.history.length ? model.history : ["No carried history in this segment."])];
|
|
21
|
-
// Unlike status chrome, evidence is inspectable content: every character must
|
|
22
|
-
// remain reachable by scrolling, including long source paths and CJK (Q24).
|
|
23
|
-
// A one-cell pane cannot show a wide glyph; its owner shows resize feedback.
|
|
24
|
-
return lines.flatMap(line => wrapPlain(line.replace(/[\x00-\x1f\x7f-\x9f]/g, " "), Math.max(2, width)));
|
|
25
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/** Persistent view state only; the controller supplies evidence and owns actions (D20/Q24). */
|
|
2
|
-
import { controlPanelLines, type ControlFocus, type ControlPanelModel, type ControlTab } from "./control-panel.ts";
|
|
3
|
-
import { clipText } from "./edge.ts";
|
|
4
|
-
import type { Line } from "./status.ts";
|
|
5
|
-
|
|
6
|
-
const TABS: readonly ControlTab[] = ["goal", "progress", "context"];
|
|
7
|
-
const LENSES: readonly ControlFocus[] = ["messages", "omitted", "history"];
|
|
8
|
-
/** Below these assumed view-only limits, show reversible size feedback instead of unreadable controls. */
|
|
9
|
-
const MIN_CONTENT_COLUMNS = 16, MIN_CONTENT_ROWS = 8;
|
|
10
|
-
|
|
11
|
-
export class ControlSidebar {
|
|
12
|
-
model: ControlPanelModel | undefined;
|
|
13
|
-
tab: ControlTab = "goal";
|
|
14
|
-
lens: ControlFocus = "messages";
|
|
15
|
-
private readonly offsets = new Map<string, number>();
|
|
16
|
-
private shownOffset = 0;
|
|
17
|
-
private pageRows = 1;
|
|
18
|
-
private maxOffset = 0;
|
|
19
|
-
|
|
20
|
-
private get page(): string { return this.tab === "context" ? `${this.tab}:${this.lens}` : this.tab; }
|
|
21
|
-
|
|
22
|
-
changeTab(delta: number): void { this.tab = TABS[(TABS.indexOf(this.tab) + delta + TABS.length) % TABS.length]!; }
|
|
23
|
-
changeLens(delta: number): void { this.lens = LENSES[(LENSES.indexOf(this.lens) + delta + LENSES.length) % LENSES.length]!; }
|
|
24
|
-
scroll(delta: number, page = false): void {
|
|
25
|
-
this.offsets.set(this.page, Math.max(0, Math.min(this.maxOffset, this.shownOffset + delta * (page ? this.pageRows : 1))));
|
|
26
|
-
}
|
|
27
|
-
edge(end: boolean): void { this.offsets.set(this.page, end ? this.maxOffset : 0); }
|
|
28
|
-
|
|
29
|
-
rows(width: number, height: number, focused: boolean): readonly Line[] {
|
|
30
|
-
const w = Math.max(0, Math.floor(width)), h = Math.max(0, Math.floor(height));
|
|
31
|
-
if (w === 0 || h === 0) return [];
|
|
32
|
-
const row = (text: string, role: "text" | "muted" | "accent" = "text", bold = false): Line => [{ text: clipText(text, w), role, bold }];
|
|
33
|
-
if (w < MIN_CONTENT_COLUMNS || h < MIN_CONTENT_ROWS) {
|
|
34
|
-
// Do not reset the model, tab or desired scroll position: resize is reversible.
|
|
35
|
-
return [row(w < 6 ? "↔" : "Resize for control", "accent"), row("Esc editor · q close", "muted")].slice(0, h);
|
|
36
|
-
}
|
|
37
|
-
const tabs = TABS.map(tab => `${tab === this.tab ? "●" : "○"} ${tab === "context" ? "Context Lens" : tab === "goal" ? "Goal" : "Progress"}`);
|
|
38
|
-
const heading = [row(`Control panel · ${focused ? "focused" : "F6 focus"}`, "accent", true), row(`${tabs[0]} ${tabs[1]}`), row(tabs[2]!)];
|
|
39
|
-
const hints = ["Tab sections · ←→ lenses", "r refresh · i stop · a accept", "Esc editor · q close · F6"];
|
|
40
|
-
this.pageRows = Math.max(1, h - heading.length - hints.length - 1);
|
|
41
|
-
const body = this.model ? controlPanelLines(this.model, this.tab, w, this.lens) : ["Evidence unavailable.", "Press r to refresh."];
|
|
42
|
-
this.maxOffset = Math.max(0, body.length - this.pageRows);
|
|
43
|
-
this.shownOffset = Math.min(this.maxOffset, this.offsets.get(this.page) ?? 0);
|
|
44
|
-
const shown = body.slice(this.shownOffset, this.shownOffset + this.pageRows).map(text => row(text));
|
|
45
|
-
while (shown.length < this.pageRows) shown.push(row(""));
|
|
46
|
-
const range = `${this.shownOffset + 1}–${Math.min(body.length, this.shownOffset + this.pageRows)}/${body.length}`;
|
|
47
|
-
return [...heading, ...shown, row(`↑↓ PgUp/PgDn · ${range}`, "muted"), ...hints.map(text => row(text, "muted"))];
|
|
48
|
-
}
|
|
49
|
-
}
|