@dex-ai/coding-agent 0.1.92

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.
Files changed (70) hide show
  1. package/bin/dex.ts +402 -0
  2. package/package.json +45 -0
  3. package/src/__tests__/command-validation.test.ts +205 -0
  4. package/src/__tests__/history.test.ts +183 -0
  5. package/src/cli-extension.ts +153 -0
  6. package/src/commands/extension-loader.ts +399 -0
  7. package/src/commands/extension.ts +924 -0
  8. package/src/commands/update.ts +419 -0
  9. package/src/env.d.ts +5 -0
  10. package/src/extensions/cli-tui-components/ActivityPanel.vue +24 -0
  11. package/src/extensions/cli-tui-components/ActivityPanel.vue.compiled.ts +96 -0
  12. package/src/extensions/cli-tui-components/App.vue +127 -0
  13. package/src/extensions/cli-tui-components/App.vue.compiled.ts +374 -0
  14. package/src/extensions/cli-tui-components/ApprovalPrompt.vue +30 -0
  15. package/src/extensions/cli-tui-components/ApprovalPrompt.vue.compiled.ts +72 -0
  16. package/src/extensions/cli-tui-components/AskPanel.vue +228 -0
  17. package/src/extensions/cli-tui-components/AskPanel.vue.compiled.ts +419 -0
  18. package/src/extensions/cli-tui-components/CommandPalette.vue +19 -0
  19. package/src/extensions/cli-tui-components/CommandPalette.vue.compiled.ts +65 -0
  20. package/src/extensions/cli-tui-components/ConfirmModal.vue +29 -0
  21. package/src/extensions/cli-tui-components/ConfirmModal.vue.compiled.ts +72 -0
  22. package/src/extensions/cli-tui-components/DiffView.vue +139 -0
  23. package/src/extensions/cli-tui-components/DiffView.vue.compiled.ts +274 -0
  24. package/src/extensions/cli-tui-components/FormModal.vue +58 -0
  25. package/src/extensions/cli-tui-components/FormModal.vue.compiled.ts +156 -0
  26. package/src/extensions/cli-tui-components/Header.vue +13 -0
  27. package/src/extensions/cli-tui-components/Header.vue.compiled.ts +42 -0
  28. package/src/extensions/cli-tui-components/InputArea.vue +202 -0
  29. package/src/extensions/cli-tui-components/InputArea.vue.compiled.ts +243 -0
  30. package/src/extensions/cli-tui-components/InteractivePanel.vue +32 -0
  31. package/src/extensions/cli-tui-components/InteractivePanel.vue.compiled.ts +103 -0
  32. package/src/extensions/cli-tui-components/ListModal.vue +58 -0
  33. package/src/extensions/cli-tui-components/ListModal.vue.compiled.ts +130 -0
  34. package/src/extensions/cli-tui-components/MarkdownContent.ts +54 -0
  35. package/src/extensions/cli-tui-components/Messages.vue +68 -0
  36. package/src/extensions/cli-tui-components/Messages.vue.compiled.ts +253 -0
  37. package/src/extensions/cli-tui-components/Modal.vue +56 -0
  38. package/src/extensions/cli-tui-components/Modal.vue.compiled.ts +61 -0
  39. package/src/extensions/cli-tui-components/SettingsPanel.vue +178 -0
  40. package/src/extensions/cli-tui-components/SettingsPanel.vue.compiled.ts +359 -0
  41. package/src/extensions/cli-tui-components/Spinner.vue +19 -0
  42. package/src/extensions/cli-tui-components/Spinner.vue.compiled.ts +42 -0
  43. package/src/extensions/cli-tui-components/StatusBar.vue +45 -0
  44. package/src/extensions/cli-tui-components/StatusBar.vue.compiled.ts +106 -0
  45. package/src/extensions/cli-tui-components/SteeringPreview.vue +11 -0
  46. package/src/extensions/cli-tui-components/SteeringPreview.vue.compiled.ts +38 -0
  47. package/src/extensions/cli-tui-components/ThinkingBlock.vue +40 -0
  48. package/src/extensions/cli-tui-components/ThinkingBlock.vue.compiled.ts +82 -0
  49. package/src/extensions/cli-tui-components/ToolCall.vue +114 -0
  50. package/src/extensions/cli-tui-components/ToolCall.vue.compiled.ts +319 -0
  51. package/src/extensions/cli-tui-components/UserMessage.vue +40 -0
  52. package/src/extensions/cli-tui-components/UserMessage.vue.compiled.ts +148 -0
  53. package/src/extensions/cli-tui-components/ask-panel-controller.ts +573 -0
  54. package/src/extensions/cli-tui-components/settings-panel-controller.ts +958 -0
  55. package/src/extensions/cli-tui.ts +2349 -0
  56. package/src/extensions/debug.ts +46 -0
  57. package/src/extensions/headless.ts +55 -0
  58. package/src/extensions/modal-system.ts +719 -0
  59. package/src/host.ts +505 -0
  60. package/src/index.ts +9 -0
  61. package/src/input/history.ts +233 -0
  62. package/src/input/index.ts +6 -0
  63. package/src/panels/dynamic-panel.ts +5 -0
  64. package/src/panels/index.ts +43 -0
  65. package/src/panels/state.ts +73 -0
  66. package/src/panels/types.ts +79 -0
  67. package/src/panels/widget.ts +25 -0
  68. package/src/provider-registry.ts +44 -0
  69. package/src/stderr-capture.ts +248 -0
  70. package/src/types.ts +20 -0
@@ -0,0 +1,139 @@
1
+ <template>
2
+ <stack v-if="hunks.length > 0">
3
+ <line>
4
+ <text color="subtle" :style="{ paddingLeft: 2 }">└ {{ summary }}</text>
5
+ </line>
6
+ <template v-for="(hunk, hi) in hunks" :key="hi">
7
+ <line v-if="hi > 0">
8
+ <text color="subtle" :style="{ paddingLeft: 4 }">...</text>
9
+ </line>
10
+ <template v-for="(line, li) in hunk.lines" :key="`${hi}-${li}`">
11
+ <line>
12
+ <text
13
+ :color="line.type === 'add' ? 'diff-add' : line.type === 'del' ? 'diff-del' : 'subtle'"
14
+ dim
15
+ :style="{ paddingLeft: 4, paddingRight: 1 }"
16
+ >{{ line.lineNo }}</text>
17
+ <text
18
+ v-if="line.type === 'add' || line.type === 'del'"
19
+ :color="line.type === 'add' ? 'diff-add' : 'diff-del'"
20
+ :bg="line.type === 'add' ? 'bg-diff-add' : 'bg-diff-del'"
21
+ >{{ line.text }}</text>
22
+ <text
23
+ v-else
24
+ color="subtle"
25
+ >{{ line.text }}</text>
26
+ </line>
27
+ </template>
28
+ </template>
29
+ </stack>
30
+ </template>
31
+
32
+ <script setup lang="ts">
33
+ import { computed } from "@vue/runtime-core";
34
+
35
+ interface DisplayLine {
36
+ type: "add" | "del" | "ctx";
37
+ lineNo: string;
38
+ text: string;
39
+ }
40
+
41
+ interface DisplayHunk {
42
+ lines: DisplayLine[];
43
+ }
44
+
45
+ const props = defineProps<{
46
+ diff: string;
47
+ }>();
48
+
49
+ const hunks = computed((): DisplayHunk[] => {
50
+ if (!props.diff) return [];
51
+
52
+ const result: DisplayHunk[] = [];
53
+ let currentHunk: DisplayLine[] = [];
54
+ let oldLine = 0;
55
+ let newLine = 0;
56
+ let maxLineNo = 0;
57
+
58
+ // First pass: find max line number for padding
59
+ for (const raw of props.diff.split("\n")) {
60
+ if (raw.startsWith("@@")) {
61
+ const match = raw.match(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
62
+ if (match) {
63
+ const oldStart = parseInt(match[1]!, 10);
64
+ const oldCount = parseInt(match[2] ?? "1", 10);
65
+ const newStart = parseInt(match[3]!, 10);
66
+ const newCount = parseInt(match[4] ?? "1", 10);
67
+ maxLineNo = Math.max(maxLineNo, oldStart + oldCount, newStart + newCount);
68
+ }
69
+ }
70
+ }
71
+ const pad = Math.max(String(maxLineNo).length, 2);
72
+
73
+ // Second pass: build display lines
74
+ for (const raw of props.diff.split("\n")) {
75
+ if (raw.startsWith("@@")) {
76
+ // Save previous hunk if non-empty
77
+ if (currentHunk.length > 0) {
78
+ result.push({ lines: currentHunk });
79
+ currentHunk = [];
80
+ }
81
+ const match = raw.match(/@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
82
+ if (match) {
83
+ oldLine = parseInt(match[1]!, 10);
84
+ newLine = parseInt(match[2]!, 10);
85
+ }
86
+ continue;
87
+ }
88
+ if (raw.startsWith("--- ") || raw.startsWith("+++ ")) continue;
89
+
90
+ if (raw.startsWith("+")) {
91
+ currentHunk.push({
92
+ type: "add",
93
+ lineNo: String(newLine).padStart(pad) + "+",
94
+ text: raw.slice(1).replace(/\t/g, " "),
95
+ });
96
+ newLine++;
97
+ } else if (raw.startsWith("-")) {
98
+ currentHunk.push({
99
+ type: "del",
100
+ lineNo: String(oldLine).padStart(pad) + "-",
101
+ text: raw.slice(1).replace(/\t/g, " "),
102
+ });
103
+ oldLine++;
104
+ } else {
105
+ // Context line (starts with space or is empty)
106
+ const text = (raw.startsWith(" ") ? raw.slice(1) : raw).replace(/\t/g, " ");
107
+ currentHunk.push({
108
+ type: "ctx",
109
+ lineNo: String(newLine).padStart(pad) + " ",
110
+ text,
111
+ });
112
+ oldLine++;
113
+ newLine++;
114
+ }
115
+ }
116
+
117
+ // Push final hunk
118
+ if (currentHunk.length > 0) {
119
+ result.push({ lines: currentHunk });
120
+ }
121
+
122
+ return result;
123
+ });
124
+
125
+ const summary = computed(() => {
126
+ let additions = 0;
127
+ let deletions = 0;
128
+ for (const hunk of hunks.value) {
129
+ for (const line of hunk.lines) {
130
+ if (line.type === "add") additions++;
131
+ else if (line.type === "del") deletions++;
132
+ }
133
+ }
134
+ const parts: string[] = [];
135
+ if (additions > 0) parts.push(`Added ${additions} line${additions !== 1 ? "s" : ""}`);
136
+ if (deletions > 0) parts.push(`removed ${deletions} line${deletions !== 1 ? "s" : ""}`);
137
+ return parts.join(", ");
138
+ });
139
+ </script>
@@ -0,0 +1,274 @@
1
+ import * as _Vue from "@vue/runtime-core";
2
+ const {
3
+ h: _h,
4
+ toDisplayString: _toDisplayString,
5
+ openBlock: _openBlock,
6
+ createElementBlock: _createElementBlock,
7
+ createElementVNode: _createElementVNode,
8
+ createVNode: _createVNode,
9
+ createBlock: _createBlock,
10
+ createCommentVNode: _createCommentVNode,
11
+ Fragment: _Fragment,
12
+ renderList: _renderList,
13
+ withCtx: _withCtx,
14
+ createTextVNode: _createTextVNode,
15
+ resolveComponent: _resolveComponent,
16
+ normalizeStyle: _normalizeStyle,
17
+ normalizeClass: _normalizeClass,
18
+ normalizeProps: _normalizeProps,
19
+ guardReactiveProps: _guardReactiveProps,
20
+ mergeProps: _mergeProps,
21
+ withDirectives: _withDirectives,
22
+ resolveDynamicComponent: _resolveDynamicComponent,
23
+ } = _Vue;
24
+
25
+ import { defineComponent as _defineComponent } from "@vue/runtime-core";
26
+ import { computed } from "@vue/runtime-core";
27
+
28
+ interface DisplayLine {
29
+ type: "add" | "del" | "ctx";
30
+ lineNo: string;
31
+ marker: string;
32
+ text: string;
33
+ }
34
+
35
+ interface DisplayHunk {
36
+ lines: DisplayLine[];
37
+ }
38
+
39
+ const __sfc_main = /*@__PURE__*/ _defineComponent({
40
+ __name: "DiffView",
41
+ props: {
42
+ diff: { type: String, required: true },
43
+ },
44
+ setup(__props: any, { expose: __expose }) {
45
+ __expose();
46
+
47
+ const props = __props;
48
+
49
+ const hunks = computed((): DisplayHunk[] => {
50
+ if (!props.diff) return [];
51
+
52
+ const result: DisplayHunk[] = [];
53
+ let currentHunk: DisplayLine[] = [];
54
+ let oldLine = 0;
55
+ let newLine = 0;
56
+ let maxLineNo = 0;
57
+
58
+ // First pass: find max line number for padding
59
+ for (const raw of props.diff.split("\n")) {
60
+ if (raw.startsWith("@@")) {
61
+ const match = raw.match(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
62
+ if (match) {
63
+ const oldStart = parseInt(match[1]!, 10);
64
+ const oldCount = parseInt(match[2] ?? "1", 10);
65
+ const newStart = parseInt(match[3]!, 10);
66
+ const newCount = parseInt(match[4] ?? "1", 10);
67
+ maxLineNo = Math.max(
68
+ maxLineNo,
69
+ oldStart + oldCount,
70
+ newStart + newCount,
71
+ );
72
+ }
73
+ }
74
+ }
75
+ const pad = Math.max(String(maxLineNo).length, 3);
76
+
77
+ // Second pass: build display lines
78
+ for (const raw of props.diff.split("\n")) {
79
+ if (raw.startsWith("@@")) {
80
+ // Save previous hunk if non-empty
81
+ if (currentHunk.length > 0) {
82
+ result.push({ lines: currentHunk });
83
+ currentHunk = [];
84
+ }
85
+ const match = raw.match(/@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
86
+ if (match) {
87
+ oldLine = parseInt(match[1]!, 10);
88
+ newLine = parseInt(match[2]!, 10);
89
+ }
90
+ continue;
91
+ }
92
+ if (raw.startsWith("--- ") || raw.startsWith("+++ ")) continue;
93
+
94
+ if (raw.startsWith("+")) {
95
+ currentHunk.push({
96
+ type: "add",
97
+ lineNo: String(newLine).padStart(pad) + " +",
98
+ marker: "",
99
+ text: raw.slice(1),
100
+ });
101
+ newLine++;
102
+ } else if (raw.startsWith("-")) {
103
+ currentHunk.push({
104
+ type: "del",
105
+ lineNo: String(oldLine).padStart(pad) + " -",
106
+ marker: "",
107
+ text: raw.slice(1),
108
+ });
109
+ oldLine++;
110
+ } else {
111
+ // Context line (starts with space or is empty)
112
+ const text = raw.startsWith(" ") ? raw.slice(1) : raw;
113
+ currentHunk.push({
114
+ type: "ctx",
115
+ lineNo: String(newLine).padStart(pad) + " ",
116
+ marker: "",
117
+ text,
118
+ });
119
+ oldLine++;
120
+ newLine++;
121
+ }
122
+ }
123
+
124
+ // Push final hunk
125
+ if (currentHunk.length > 0) {
126
+ result.push({ lines: currentHunk });
127
+ }
128
+
129
+ return result;
130
+ });
131
+
132
+ const summary = computed(() => {
133
+ let additions = 0;
134
+ let deletions = 0;
135
+ for (const hunk of hunks.value) {
136
+ for (const line of hunk.lines) {
137
+ if (line.type === "add") additions++;
138
+ else if (line.type === "del") deletions++;
139
+ }
140
+ }
141
+ const parts: string[] = [];
142
+ if (additions > 0)
143
+ parts.push(`Added ${additions} line${additions !== 1 ? "s" : ""}`);
144
+ if (deletions > 0)
145
+ parts.push(`removed ${deletions} line${deletions !== 1 ? "s" : ""}`);
146
+ return parts.join(", ");
147
+ });
148
+
149
+ const __returned__ = { props, hunks, summary };
150
+ Object.defineProperty(__returned__, "__isScriptSetup", {
151
+ enumerable: false,
152
+ value: true,
153
+ });
154
+ return __returned__;
155
+ },
156
+ });
157
+
158
+ const _hoisted_1 = { key: 0 };
159
+
160
+ const render = (
161
+ _ctx: any,
162
+ _cache: any,
163
+ $props: any,
164
+ $setup: any,
165
+ $data: any,
166
+ $options: any,
167
+ ) =>
168
+ $setup.hunks.length > 0
169
+ ? (_openBlock(),
170
+ _createElementBlock("stack", _hoisted_1, [
171
+ _createElementVNode("line", null, [
172
+ _createElementVNode(
173
+ "text",
174
+ {
175
+ color: "subtle",
176
+ style: { paddingLeft: 2 },
177
+ },
178
+ _toDisplayString("└ " + $setup.summary),
179
+ 1 /* TEXT */,
180
+ ),
181
+ ]),
182
+ (_openBlock(true),
183
+ _createElementBlock(
184
+ _Fragment,
185
+ null,
186
+ _renderList($setup.hunks, (hunk: any, hi: number) => {
187
+ return (
188
+ _openBlock(),
189
+ _createElementBlock(
190
+ _Fragment,
191
+ { key: hi },
192
+ [
193
+ hi > 0
194
+ ? (_openBlock(),
195
+ _createElementBlock("line", { key: 0 }, [
196
+ _createElementVNode(
197
+ "text",
198
+ {
199
+ color: "subtle",
200
+ style: { paddingLeft: 4 },
201
+ },
202
+ "...",
203
+ ),
204
+ ]))
205
+ : _createCommentVNode("v-if", true),
206
+ (_openBlock(true),
207
+ _createElementBlock(
208
+ _Fragment,
209
+ null,
210
+ _renderList(hunk.lines, (line: any, li: number) => {
211
+ return (
212
+ _openBlock(),
213
+ _createElementBlock("line", { key: `${hi}-${li}` }, [
214
+ _createElementVNode(
215
+ "text",
216
+ {
217
+ color:
218
+ line.type === "add"
219
+ ? "diff-add"
220
+ : line.type === "del"
221
+ ? "diff-del"
222
+ : "subtle",
223
+ dim: "",
224
+ style: { paddingLeft: 4, paddingRight: 1 },
225
+ },
226
+ _toDisplayString(line.lineNo),
227
+ 9 /* TEXT, PROPS */,
228
+ ),
229
+ line.type === "add" || line.type === "del"
230
+ ? (_openBlock(),
231
+ _createElementBlock(
232
+ "text",
233
+ {
234
+ key: 0,
235
+ color:
236
+ line.type === "add"
237
+ ? "diff-add"
238
+ : "diff-del",
239
+ bg:
240
+ line.type === "add"
241
+ ? "bg-diff-add"
242
+ : "bg-diff-del",
243
+ },
244
+ _toDisplayString(line.text),
245
+ 9 /* TEXT, PROPS */,
246
+ ))
247
+ : (_openBlock(),
248
+ _createElementBlock(
249
+ "text",
250
+ {
251
+ key: 1,
252
+ color: "subtle",
253
+ },
254
+ _toDisplayString(line.text),
255
+ 1 /* TEXT */,
256
+ )),
257
+ ])
258
+ );
259
+ }),
260
+ 128 /* KEYED_FRAGMENT */,
261
+ )),
262
+ ],
263
+ 64 /* STABLE_FRAGMENT */,
264
+ )
265
+ );
266
+ }),
267
+ 128 /* KEYED_FRAGMENT */,
268
+ )),
269
+ ]))
270
+ : _createCommentVNode("v-if", true);
271
+
272
+ __sfc_main.render = render;
273
+
274
+ export default __sfc_main;
@@ -0,0 +1,58 @@
1
+ <template>
2
+ <stack>
3
+ <line borderTop="solid" :style="{ borderTopColor: 'accent' }">
4
+ <text bold color="accent"> {{ title }} </text>
5
+ </line>
6
+ <line v-for="(field, i) in fields" :key="field.key">
7
+ <text :color="i === focusedIndex ? 'accent' : 'muted'" :style="{ paddingLeft: 1, fontWeight: i === focusedIndex ? 'bold' : 'normal' }">{{ i === focusedIndex ? '❯' : ' ' }}</text>
8
+ <text :style="{ paddingLeft: 1 }" :color="i === focusedIndex ? 'text' : 'muted'">{{ field.label }}</text>
9
+ <text v-if="field.required && !field.readonly && !values[field.key]" color="warn" :style="{ paddingLeft: 1 }">*</text>
10
+ <text muted :style="{ paddingLeft: 1 }">│</text>
11
+ <text v-if="field.readonly && values[field.key]" dim :style="{ paddingLeft: 1 }">{{ values[field.key] }}</text>
12
+ <text v-else-if="field.readonly" dim :style="{ paddingLeft: 1 }">—</text>
13
+ <text v-else-if="i === focusedIndex && editing" color="accent" :style="{ paddingLeft: 1 }">{{ editBuffer }}▏</text>
14
+ <text v-else-if="field.type === 'password' && values[field.key]" :style="{ paddingLeft: 1 }">{{ maskValue(values[field.key]!) }}</text>
15
+ <text v-else-if="values[field.key]" :style="{ paddingLeft: 1 }">{{ values[field.key] }}</text>
16
+ <text v-else-if="field.placeholder" dim :style="{ paddingLeft: 1 }">{{ field.placeholder }}</text>
17
+ </line>
18
+ <line v-if="error">
19
+ <text color="error" :style="{ paddingLeft: 2 }">⚠ {{ error }}</text>
20
+ </line>
21
+ <line borderBottom="solid" :style="{ borderBottomColor: 'subtle' }">
22
+ <text muted>{{ editing ? 'enter/tab confirm · esc revert' : hasEditableFields ? 'tab/enter edit · ↑↓ fields · ctrl+s save · esc cancel' : '↑↓ navigate · esc close' }}</text>
23
+ </line>
24
+ </stack>
25
+ </template>
26
+
27
+ <script setup lang="ts">
28
+ import { computed } from "@vue/runtime-core";
29
+
30
+ export interface FormFieldDef {
31
+ key: string;
32
+ label: string;
33
+ type: 'text' | 'password' | 'select';
34
+ value?: string;
35
+ placeholder?: string;
36
+ hint?: string;
37
+ required?: boolean;
38
+ readonly?: boolean;
39
+ options?: string[];
40
+ }
41
+
42
+ const props = defineProps<{
43
+ title: string;
44
+ fields: FormFieldDef[];
45
+ values: Record<string, string>;
46
+ focusedIndex: number;
47
+ editing: boolean;
48
+ editBuffer: string;
49
+ error: string;
50
+ }>();
51
+
52
+ const hasEditableFields = computed(() => props.fields.some(f => !f.readonly));
53
+
54
+ function maskValue(val: string): string {
55
+ if (val.length <= 4) return '••••';
56
+ return '••••••••' + val.slice(-4);
57
+ }
58
+ </script>
@@ -0,0 +1,156 @@
1
+ import * as _Vue from "@vue/runtime-core";
2
+ const { h: _h, toDisplayString: _toDisplayString, openBlock: _openBlock, createElementBlock: _createElementBlock, createElementVNode: _createElementVNode, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode, Fragment: _Fragment, renderList: _renderList, withCtx: _withCtx, createTextVNode: _createTextVNode, resolveComponent: _resolveComponent, normalizeStyle: _normalizeStyle, normalizeClass: _normalizeClass, normalizeProps: _normalizeProps, guardReactiveProps: _guardReactiveProps, mergeProps: _mergeProps, withDirectives: _withDirectives, resolveDynamicComponent: _resolveDynamicComponent } = _Vue;
3
+
4
+ import { defineComponent as _defineComponent } from "@vue/runtime-core"
5
+ import { computed } from "@vue/runtime-core";
6
+
7
+ export interface FormFieldDef {
8
+ key: string;
9
+ label: string;
10
+ type: 'text' | 'password' | 'select';
11
+ value?: string;
12
+ placeholder?: string;
13
+ hint?: string;
14
+ required?: boolean;
15
+ readonly?: boolean;
16
+ options?: string[];
17
+ }
18
+
19
+
20
+ const __sfc_main = /*@__PURE__*/_defineComponent({
21
+ __name: 'FormModal',
22
+ props: {
23
+ title: { type: String, required: true },
24
+ fields: { type: Array, required: true },
25
+ values: { type: Object, required: true },
26
+ focusedIndex: { type: Number, required: true },
27
+ editing: { type: Boolean, required: true },
28
+ editBuffer: { type: String, required: true },
29
+ error: { type: String, required: true }
30
+ },
31
+ setup(__props: any, { expose: __expose }) {
32
+ __expose();
33
+
34
+ const props = __props;
35
+
36
+ const hasEditableFields = computed(() => props.fields.some(f => !f.readonly));
37
+
38
+ function maskValue(val: string): string {
39
+ if (val.length <= 4) return '••••';
40
+ return '••••••••' + val.slice(-4);
41
+ }
42
+
43
+ const __returned__ = { props, hasEditableFields, maskValue }
44
+ Object.defineProperty(__returned__, '__isScriptSetup', { enumerable: false, value: true })
45
+ return __returned__
46
+ }
47
+
48
+ })
49
+
50
+ const _hoisted_1 = {
51
+ borderTop: "solid",
52
+ style: { borderTopColor: 'accent' }
53
+ }
54
+ const _hoisted_2 = {
55
+ bold: "",
56
+ color: "accent"
57
+ }
58
+ const _hoisted_3 = ["color"]
59
+ const _hoisted_4 = ["color"]
60
+ const _hoisted_5 = {
61
+ key: 0,
62
+ color: "warn",
63
+ style: { paddingLeft: 1 }
64
+ }
65
+ const _hoisted_6 = {
66
+ key: 1,
67
+ dim: "",
68
+ style: { paddingLeft: 1 }
69
+ }
70
+ const _hoisted_7 = {
71
+ key: 2,
72
+ dim: "",
73
+ style: { paddingLeft: 1 }
74
+ }
75
+ const _hoisted_8 = {
76
+ key: 3,
77
+ color: "accent",
78
+ style: { paddingLeft: 1 }
79
+ }
80
+ const _hoisted_9 = {
81
+ key: 4,
82
+ style: { paddingLeft: 1 }
83
+ }
84
+ const _hoisted_10 = {
85
+ key: 5,
86
+ style: { paddingLeft: 1 }
87
+ }
88
+ const _hoisted_11 = {
89
+ key: 6,
90
+ dim: "",
91
+ style: { paddingLeft: 1 }
92
+ }
93
+ const _hoisted_12 = { key: 0 }
94
+ const _hoisted_13 = {
95
+ color: "error",
96
+ style: { paddingLeft: 2 }
97
+ }
98
+ const _hoisted_14 = {
99
+ borderBottom: "solid",
100
+ style: { borderBottomColor: 'subtle' }
101
+ }
102
+ const _hoisted_15 = { muted: "" }
103
+
104
+ const render = function(_ctx, _cache, $props, $setup, $data, $options) {
105
+ return (_openBlock(), _createElementBlock("stack", null, [
106
+ _createElementVNode("line", _hoisted_1, [
107
+ _createElementVNode("text", _hoisted_2, _toDisplayString($props.title), 1 /* TEXT */)
108
+ ]),
109
+ (_openBlock(true), _createElementBlock(_Fragment, null, _renderList($props.fields, (field, i) => {
110
+ return (_openBlock(), _createElementBlock("line", {
111
+ key: field.key
112
+ }, [
113
+ _createElementVNode("text", {
114
+ color: i === $props.focusedIndex ? 'accent' : 'muted',
115
+ style: _normalizeStyle({ paddingLeft: 1, fontWeight: i === $props.focusedIndex ? 'bold' : 'normal' })
116
+ }, _toDisplayString(i === $props.focusedIndex ? '❯' : ' '), 13 /* TEXT, STYLE, PROPS */, _hoisted_3),
117
+ _createElementVNode("text", {
118
+ style: { paddingLeft: 1 },
119
+ color: i === $props.focusedIndex ? 'text' : 'muted'
120
+ }, _toDisplayString(field.label), 9 /* TEXT, PROPS */, _hoisted_4),
121
+ (field.required && !field.readonly && !$props.values[field.key])
122
+ ? (_openBlock(), _createElementBlock("text", _hoisted_5, "*"))
123
+ : _createCommentVNode("v-if", true),
124
+ _cache[0] || (_cache[0] = _createElementVNode("text", {
125
+ muted: "",
126
+ style: { paddingLeft: 1 }
127
+ }, "│", -1 /* CACHED */)),
128
+ (field.readonly && $props.values[field.key])
129
+ ? (_openBlock(), _createElementBlock("text", _hoisted_6, _toDisplayString($props.values[field.key]), 1 /* TEXT */))
130
+ : (field.readonly)
131
+ ? (_openBlock(), _createElementBlock("text", _hoisted_7, "—"))
132
+ : (i === $props.focusedIndex && $props.editing)
133
+ ? (_openBlock(), _createElementBlock("text", _hoisted_8, _toDisplayString($props.editBuffer) + "▏", 1 /* TEXT */))
134
+ : (field.type === 'password' && $props.values[field.key])
135
+ ? (_openBlock(), _createElementBlock("text", _hoisted_9, _toDisplayString($setup.maskValue($props.values[field.key]!)), 1 /* TEXT */))
136
+ : ($props.values[field.key])
137
+ ? (_openBlock(), _createElementBlock("text", _hoisted_10, _toDisplayString($props.values[field.key]), 1 /* TEXT */))
138
+ : (field.placeholder)
139
+ ? (_openBlock(), _createElementBlock("text", _hoisted_11, _toDisplayString(field.placeholder), 1 /* TEXT */))
140
+ : _createCommentVNode("v-if", true)
141
+ ]))
142
+ }), 128 /* KEYED_FRAGMENT */)),
143
+ ($props.error)
144
+ ? (_openBlock(), _createElementBlock("line", _hoisted_12, [
145
+ _createElementVNode("text", _hoisted_13, "⚠ " + _toDisplayString($props.error), 1 /* TEXT */)
146
+ ]))
147
+ : _createCommentVNode("v-if", true),
148
+ _createElementVNode("line", _hoisted_14, [
149
+ _createElementVNode("text", _hoisted_15, _toDisplayString($props.editing ? 'enter confirm · esc revert' : $setup.hasEditableFields ? '↑↓ fields · enter edit · ctrl+s save · esc cancel' : '↑↓ navigate · esc close'), 1 /* TEXT */)
150
+ ])
151
+ ]))
152
+ }
153
+
154
+ __sfc_main.render = render;
155
+
156
+ export default __sfc_main;
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <line>
3
+ <text color="accent" bold>{{ title }}</text>
4
+ <text dim :style="{ paddingLeft: 1 }">{{ subtitle }}</text>
5
+ </line>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ defineProps<{
10
+ title: string;
11
+ subtitle: string;
12
+ }>();
13
+ </script>
@@ -0,0 +1,42 @@
1
+ import * as _Vue from "@vue/runtime-core";
2
+ const { h: _h, toDisplayString: _toDisplayString, openBlock: _openBlock, createElementBlock: _createElementBlock, createElementVNode: _createElementVNode, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode, Fragment: _Fragment, renderList: _renderList, withCtx: _withCtx, createTextVNode: _createTextVNode, resolveComponent: _resolveComponent, normalizeStyle: _normalizeStyle, normalizeClass: _normalizeClass, normalizeProps: _normalizeProps, guardReactiveProps: _guardReactiveProps, mergeProps: _mergeProps, withDirectives: _withDirectives, resolveDynamicComponent: _resolveDynamicComponent } = _Vue;
3
+
4
+ import { defineComponent as _defineComponent } from "@vue/runtime-core"
5
+
6
+ const __sfc_main = /*@__PURE__*/_defineComponent({
7
+ __name: 'Header',
8
+ props: {
9
+ title: { type: String, required: true },
10
+ subtitle: { type: String, required: true }
11
+ },
12
+ setup(__props: any, { expose: __expose }) {
13
+ __expose();
14
+
15
+
16
+
17
+ const __returned__ = { }
18
+ Object.defineProperty(__returned__, '__isScriptSetup', { enumerable: false, value: true })
19
+ return __returned__
20
+ }
21
+
22
+ })
23
+
24
+ const _hoisted_1 = {
25
+ color: "accent",
26
+ bold: ""
27
+ }
28
+ const _hoisted_2 = {
29
+ dim: "",
30
+ style: { paddingLeft: 1 }
31
+ }
32
+
33
+ const render = function(_ctx, _cache, $props, $setup, $data, $options) {
34
+ return (_openBlock(), _createElementBlock("line", null, [
35
+ _createElementVNode("text", _hoisted_1, _toDisplayString($props.title), 1 /* TEXT */),
36
+ _createElementVNode("text", _hoisted_2, _toDisplayString($props.subtitle), 1 /* TEXT */)
37
+ ]))
38
+ }
39
+
40
+ __sfc_main.render = render;
41
+
42
+ export default __sfc_main;