loop-task 1.5.5 → 2.0.1
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/README.md +127 -21
- package/dist/board/App.js +1 -1
- package/dist/board/components/ActionButtons.js +1 -1
- package/dist/board/components/BoardButton.js +1 -1
- package/dist/board/components/ConfirmModal.js +1 -1
- package/dist/board/components/ContextHelpModal.js +1 -1
- package/dist/board/components/CreateForm.js +1 -1
- package/dist/board/components/CreateProjectModal.js +1 -1
- package/dist/board/components/DeleteProjectConfirm.js +1 -1
- package/dist/board/components/DetailView.js +1 -1
- package/dist/board/components/EditProjectModal.js +1 -1
- package/dist/board/components/FilterBar.js +1 -1
- package/dist/board/components/Footer.js +1 -1
- package/dist/board/components/Header.js +1 -1
- package/dist/board/components/HelpModal.js +1 -1
- package/dist/board/components/Inspector.js +1 -1
- package/dist/board/components/LogModal.js +1 -1
- package/dist/board/components/Navigator.js +1 -1
- package/dist/board/components/ProjectsModal.js +1 -1
- package/dist/board/components/ProjectsPage.js +1 -1
- package/dist/board/components/RunHistory.js +1 -1
- package/dist/board/components/SearchBox.js +1 -1
- package/dist/board/components/SearchSelect.js +1 -1
- package/dist/board/components/TaskBrowser.js +1 -1
- package/dist/board/components/TaskFilterBar.js +1 -1
- package/dist/board/components/TaskForm.js +1 -1
- package/dist/board/components/Timeline.js +1 -1
- package/dist/board/focus-context.js +1 -1
- package/dist/board/format.js +15 -6
- package/dist/board/index.js +1 -1
- package/dist/board/toast.js +1 -1
- package/dist/cli/import-validator.js +151 -0
- package/dist/cli/import-writer.js +77 -0
- package/dist/cli.js +111 -17
- package/dist/config/constants.js +52 -0
- package/dist/daemon/file-watcher.js +171 -0
- package/dist/daemon/http-server.js +605 -0
- package/dist/daemon/index.js +36 -6
- package/dist/daemon/manager.js +94 -13
- package/dist/daemon/projects.js +10 -0
- package/dist/daemon/server.js +21 -0
- package/dist/daemon/task-manager.js +7 -0
- package/dist/esm-loader.js +4 -1
- package/dist/hooks/useLoopFormValidation.js +140 -0
- package/dist/i18n/en.json +237 -17
- package/dist/shared/fs-utils.js +34 -1
- package/dist/tui/app.js +675 -151
- package/dist/tui/commands.js +114 -0
- package/dist/tui/components/ActionButtons.js +49 -0
- package/dist/tui/components/Button.js +18 -0
- package/dist/tui/components/ChainEditor.js +112 -0
- package/dist/tui/components/CommandBuilderField.js +143 -0
- package/dist/tui/components/CommandEditorModal.js +159 -0
- package/dist/tui/components/CommandInput.js +303 -0
- package/dist/tui/components/CommandsBrowserModal.js +77 -0
- package/dist/tui/components/ConfirmModal.js +9 -0
- package/dist/tui/components/ContextHelpModal.js +8 -0
- package/dist/tui/components/CreateForm.js +223 -0
- package/dist/tui/components/DebugPanel.js +8 -0
- package/dist/tui/components/ExportModal.js +37 -0
- package/dist/tui/components/FilterBar.js +13 -0
- package/dist/tui/components/FocusableButton.js +16 -0
- package/dist/tui/components/FocusableInput.js +69 -0
- package/dist/tui/components/FocusableList.js +46 -0
- package/dist/tui/components/FocusableSearchSelect.js +82 -0
- package/dist/tui/components/Footer.js +42 -0
- package/dist/tui/components/Header.js +40 -0
- package/dist/tui/components/HelpGuideModal.js +21 -0
- package/dist/tui/components/HelpModal.js +59 -0
- package/dist/tui/components/InlineCommandEditor.js +143 -0
- package/dist/tui/components/Inspector.js +31 -0
- package/dist/tui/components/LeftPanel.js +33 -0
- package/dist/tui/components/LogModal.js +121 -0
- package/dist/tui/components/Modal.js +11 -0
- package/dist/tui/components/Navigator.js +68 -0
- package/dist/tui/components/PatchEditForm.js +78 -0
- package/dist/tui/components/ProjectForm.js +64 -0
- package/dist/tui/components/ProjectsModal.js +40 -0
- package/dist/tui/components/ProjectsPage.js +99 -0
- package/dist/tui/components/RightPanel.js +34 -0
- package/dist/tui/components/RunHistory.js +108 -0
- package/dist/tui/components/SearchSelect.js +67 -0
- package/dist/tui/components/SelectModal.js +76 -0
- package/dist/tui/components/TabBar.js +20 -0
- package/dist/tui/components/TaskBrowser.js +96 -0
- package/dist/tui/components/TaskFilterBar.js +9 -0
- package/dist/tui/components/TaskForm.js +134 -0
- package/dist/tui/components/TaskPickerModal.js +60 -0
- package/dist/tui/components/Toast.js +37 -0
- package/dist/tui/components/WelcomeScreen.js +70 -0
- package/dist/tui/components/WizardForm.js +178 -0
- package/dist/tui/daemon.js +142 -0
- package/dist/tui/format.js +111 -0
- package/dist/tui/hooks/useBreakpoint.js +7 -0
- package/dist/tui/hooks/useHoverState.js +11 -0
- package/dist/tui/hooks/useLogStream.js +32 -0
- package/dist/tui/hooks/useLoopPolling.js +28 -0
- package/dist/tui/index.js +24 -0
- package/dist/tui/router.js +16 -0
- package/dist/tui/state.js +175 -0
- package/dist/tui/theme.js +96 -0
- package/dist/tui/types.js +1 -0
- package/dist/tui/utils/paste.js +10 -0
- package/dist/tui/utils/validation.js +56 -0
- package/package.json +13 -8
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
export const defaultFilters = {
|
|
2
|
+
status: "all",
|
|
3
|
+
intervalBucket: "all",
|
|
4
|
+
recentActivity: "all",
|
|
5
|
+
query: "",
|
|
6
|
+
};
|
|
7
|
+
const statusOrder = {
|
|
8
|
+
running: 0,
|
|
9
|
+
waiting: 1,
|
|
10
|
+
paused: 2,
|
|
11
|
+
idle: 3,
|
|
12
|
+
stopped: 4,
|
|
13
|
+
};
|
|
14
|
+
function intervalBucketOf(interval) {
|
|
15
|
+
if (interval <= 60_000)
|
|
16
|
+
return "short";
|
|
17
|
+
if (interval <= 3_600_000)
|
|
18
|
+
return "medium";
|
|
19
|
+
return "long";
|
|
20
|
+
}
|
|
21
|
+
function activityBucketOf(loop) {
|
|
22
|
+
const baseline = loop.lastRunAt ?? loop.createdAt;
|
|
23
|
+
const ageMs = Date.now() - new Date(baseline).getTime();
|
|
24
|
+
return ageMs <= 15 * 60_000 ? "active" : "stale";
|
|
25
|
+
}
|
|
26
|
+
function matches(loop, filters) {
|
|
27
|
+
if (filters.status !== "all" && loop.status !== filters.status) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
if (filters.intervalBucket !== "all" &&
|
|
31
|
+
intervalBucketOf(loop.interval) !== filters.intervalBucket) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
if (filters.recentActivity !== "all" &&
|
|
35
|
+
activityBucketOf(loop) !== filters.recentActivity) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const query = filters.query.trim().toLowerCase();
|
|
39
|
+
if (!query) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
const haystack = [
|
|
43
|
+
loop.id,
|
|
44
|
+
loop.command,
|
|
45
|
+
...loop.commandArgs,
|
|
46
|
+
loop.description ?? "",
|
|
47
|
+
loop.status,
|
|
48
|
+
loop.intervalHuman,
|
|
49
|
+
]
|
|
50
|
+
.join(" ")
|
|
51
|
+
.toLowerCase();
|
|
52
|
+
return haystack.includes(query);
|
|
53
|
+
}
|
|
54
|
+
function describeLoop(loop) {
|
|
55
|
+
return loop.description?.trim() || [loop.command, ...loop.commandArgs].join(" ").trim();
|
|
56
|
+
}
|
|
57
|
+
function compare(left, right, sort) {
|
|
58
|
+
if (sort === "description") {
|
|
59
|
+
return describeLoop(left).localeCompare(describeLoop(right));
|
|
60
|
+
}
|
|
61
|
+
if (sort === "created") {
|
|
62
|
+
return right.createdAt.localeCompare(left.createdAt);
|
|
63
|
+
}
|
|
64
|
+
if (sort === "recent") {
|
|
65
|
+
return (right.lastRunAt ?? right.createdAt).localeCompare(left.lastRunAt ?? left.createdAt);
|
|
66
|
+
}
|
|
67
|
+
const byStatus = statusOrder[left.status] - statusOrder[right.status];
|
|
68
|
+
if (byStatus !== 0) {
|
|
69
|
+
return byStatus;
|
|
70
|
+
}
|
|
71
|
+
const leftNext = left.nextRunAt ?? left.lastRunAt ?? left.createdAt;
|
|
72
|
+
const rightNext = right.nextRunAt ?? right.lastRunAt ?? right.createdAt;
|
|
73
|
+
return rightNext.localeCompare(leftNext);
|
|
74
|
+
}
|
|
75
|
+
export function applyLoopFilters(loops, filters, sort) {
|
|
76
|
+
return loops
|
|
77
|
+
.filter((loop) => matches(loop, filters))
|
|
78
|
+
.sort((left, right) => compare(left, right, sort));
|
|
79
|
+
}
|
|
80
|
+
const SORT_CYCLE = {
|
|
81
|
+
description: "status",
|
|
82
|
+
status: "recent",
|
|
83
|
+
recent: "created",
|
|
84
|
+
created: "description",
|
|
85
|
+
};
|
|
86
|
+
export function cycleSortMode(mode) {
|
|
87
|
+
return SORT_CYCLE[mode];
|
|
88
|
+
}
|
|
89
|
+
const STATUS_CYCLE = {
|
|
90
|
+
all: "running",
|
|
91
|
+
running: "waiting",
|
|
92
|
+
waiting: "paused",
|
|
93
|
+
paused: "idle",
|
|
94
|
+
idle: "stopped",
|
|
95
|
+
stopped: "all",
|
|
96
|
+
};
|
|
97
|
+
export function cycleStatusFilter(status) {
|
|
98
|
+
return STATUS_CYCLE[status];
|
|
99
|
+
}
|
|
100
|
+
export const defaultProjectFilters = {
|
|
101
|
+
query: "",
|
|
102
|
+
hasLoops: "all",
|
|
103
|
+
isSystem: "all",
|
|
104
|
+
sort: "name",
|
|
105
|
+
};
|
|
106
|
+
export function applyProjectFilters(projects, loops, filters) {
|
|
107
|
+
const filtered = projects.filter((project) => {
|
|
108
|
+
if (filters.hasLoops === "with-loops") {
|
|
109
|
+
const count = loops.filter((l) => (l.projectId ?? "default") === project.id).length;
|
|
110
|
+
if (count === 0)
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
if (filters.hasLoops === "empty") {
|
|
114
|
+
const count = loops.filter((l) => (l.projectId ?? "default") === project.id).length;
|
|
115
|
+
if (count > 0)
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
if (filters.isSystem === "system" && !project.isSystem)
|
|
119
|
+
return false;
|
|
120
|
+
if (filters.isSystem === "user" && project.isSystem)
|
|
121
|
+
return false;
|
|
122
|
+
const query = filters.query.trim().toLowerCase();
|
|
123
|
+
if (query && !project.name.toLowerCase().includes(query))
|
|
124
|
+
return false;
|
|
125
|
+
return true;
|
|
126
|
+
});
|
|
127
|
+
return filtered.sort((a, b) => {
|
|
128
|
+
if (filters.sort === "name") {
|
|
129
|
+
return a.name.localeCompare(b.name, undefined, { sensitivity: "base" });
|
|
130
|
+
}
|
|
131
|
+
if (filters.sort === "loop-count") {
|
|
132
|
+
const ca = loops.filter((l) => (l.projectId ?? "default") === a.id).length;
|
|
133
|
+
const cb = loops.filter((l) => (l.projectId ?? "default") === b.id).length;
|
|
134
|
+
if (cb !== ca)
|
|
135
|
+
return cb - ca;
|
|
136
|
+
return a.name.localeCompare(b.name, undefined, { sensitivity: "base" });
|
|
137
|
+
}
|
|
138
|
+
const da = a.createdAt;
|
|
139
|
+
const db = b.createdAt;
|
|
140
|
+
if (da !== db)
|
|
141
|
+
return db.localeCompare(da);
|
|
142
|
+
return a.name.localeCompare(b.name, undefined, { sensitivity: "base" });
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
const PROJECT_SORT_CYCLE = {
|
|
146
|
+
name: "loop-count",
|
|
147
|
+
"loop-count": "created-date",
|
|
148
|
+
"created-date": "name",
|
|
149
|
+
};
|
|
150
|
+
export function cycleProjectSortMode(mode) {
|
|
151
|
+
return PROJECT_SORT_CYCLE[mode];
|
|
152
|
+
}
|
|
153
|
+
const PROJECT_HAS_LOOPS_CYCLE = {
|
|
154
|
+
all: "with-loops",
|
|
155
|
+
"with-loops": "empty",
|
|
156
|
+
empty: "all",
|
|
157
|
+
};
|
|
158
|
+
export function cycleProjectHasLoopsFilter(filter) {
|
|
159
|
+
return PROJECT_HAS_LOOPS_CYCLE[filter];
|
|
160
|
+
}
|
|
161
|
+
const PROJECT_IS_SYSTEM_CYCLE = {
|
|
162
|
+
all: "system",
|
|
163
|
+
system: "user",
|
|
164
|
+
user: "all",
|
|
165
|
+
};
|
|
166
|
+
export function cycleProjectIsSystemFilter(filter) {
|
|
167
|
+
return PROJECT_IS_SYSTEM_CYCLE[filter];
|
|
168
|
+
}
|
|
169
|
+
export function resolveInputOwner(state) {
|
|
170
|
+
if (state.modalOpen)
|
|
171
|
+
return "modal";
|
|
172
|
+
if (state.commandBarHasText || state.commandBarDropdownOpen)
|
|
173
|
+
return "commandBar";
|
|
174
|
+
return "panel";
|
|
175
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export const darkTheme = {
|
|
2
|
+
bg: {
|
|
3
|
+
base: "#0a0e14",
|
|
4
|
+
surface: "#111827",
|
|
5
|
+
elevated: "#1e293b",
|
|
6
|
+
hover: "#1e3a5f",
|
|
7
|
+
active: "#1e3a8a", // loop selection (blue)
|
|
8
|
+
activeTask: "#3b1f6e", // task selection (purple)
|
|
9
|
+
activeProject: "#0f3d2e", // project selection (green)
|
|
10
|
+
input: "#0f172a",
|
|
11
|
+
},
|
|
12
|
+
text: {
|
|
13
|
+
primary: "#e5e7eb",
|
|
14
|
+
secondary: "#9ca3af",
|
|
15
|
+
muted: "#6b7280",
|
|
16
|
+
inverse: "#ffffff",
|
|
17
|
+
},
|
|
18
|
+
accent: {
|
|
19
|
+
brand: "#fbbf24",
|
|
20
|
+
loop: "#38bdf8",
|
|
21
|
+
task: "#a78bfa",
|
|
22
|
+
project: "#34d399",
|
|
23
|
+
},
|
|
24
|
+
semantic: {
|
|
25
|
+
success: "#4ade80",
|
|
26
|
+
warning: "#facc15",
|
|
27
|
+
danger: "#f87171",
|
|
28
|
+
idle: "#fb923c",
|
|
29
|
+
},
|
|
30
|
+
border: {
|
|
31
|
+
default: "#1e293b",
|
|
32
|
+
dim: "#374151",
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
export const lightTheme = {
|
|
36
|
+
bg: {
|
|
37
|
+
base: "#f8fafc",
|
|
38
|
+
surface: "#f1f5f9",
|
|
39
|
+
elevated: "#e2e8f0",
|
|
40
|
+
hover: "#cbd5e1",
|
|
41
|
+
active: "#93c5fd",
|
|
42
|
+
input: "#f1f5f9",
|
|
43
|
+
},
|
|
44
|
+
text: {
|
|
45
|
+
primary: "#1e293b",
|
|
46
|
+
secondary: "#475569",
|
|
47
|
+
muted: "#94a3b8",
|
|
48
|
+
inverse: "#0f172a",
|
|
49
|
+
},
|
|
50
|
+
accent: {
|
|
51
|
+
brand: "#d97706",
|
|
52
|
+
loop: "#0284c7",
|
|
53
|
+
task: "#7c3aed",
|
|
54
|
+
project: "#059669",
|
|
55
|
+
},
|
|
56
|
+
semantic: {
|
|
57
|
+
success: "#16a34a",
|
|
58
|
+
warning: "#ca8a04",
|
|
59
|
+
danger: "#dc2626",
|
|
60
|
+
idle: "#ea580c",
|
|
61
|
+
},
|
|
62
|
+
border: {
|
|
63
|
+
default: "#cbd5e1",
|
|
64
|
+
dim: "#94a3b8",
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
export const space = {
|
|
68
|
+
0: 0,
|
|
69
|
+
1: 1,
|
|
70
|
+
2: 2,
|
|
71
|
+
3: 3,
|
|
72
|
+
4: 4,
|
|
73
|
+
};
|
|
74
|
+
export const ENTITY_COLORS = {
|
|
75
|
+
loop: "#38bdf8",
|
|
76
|
+
task: "#a78bfa",
|
|
77
|
+
project: "#34d399",
|
|
78
|
+
};
|
|
79
|
+
export const STATUS_COLORS = {
|
|
80
|
+
running: "#4ade80",
|
|
81
|
+
waiting: "#6b7280",
|
|
82
|
+
paused: "#facc15",
|
|
83
|
+
idle: "#fb923c",
|
|
84
|
+
stopped: "#f87171",
|
|
85
|
+
};
|
|
86
|
+
export function statusColor(status) {
|
|
87
|
+
return STATUS_COLORS[status] ?? "#9ca3af";
|
|
88
|
+
}
|
|
89
|
+
export function tabAccentColor(tab) {
|
|
90
|
+
const map = {
|
|
91
|
+
loops: darkTheme.accent.loop,
|
|
92
|
+
tasks: darkTheme.accent.task,
|
|
93
|
+
projects: darkTheme.accent.project,
|
|
94
|
+
};
|
|
95
|
+
return map[tab] ?? darkTheme.accent.brand;
|
|
96
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PASTE_MAX_CHARS } from "../../config/constants.js";
|
|
2
|
+
// Turn a raw paste (possibly bracketed, multi-line, with stray control chars)
|
|
3
|
+
// into a single-line insertable string. Exported for tests.
|
|
4
|
+
export function sanitizePaste(raw) {
|
|
5
|
+
return raw
|
|
6
|
+
.replace(/\x1b\[20[01]~/g, "") // strip bracketed-paste markers ESC[200~/ESC[201~
|
|
7
|
+
.replace(/[\r\n]+/g, " ") // command bar is single-line: newlines -> space
|
|
8
|
+
.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "") // drop remaining control chars
|
|
9
|
+
.slice(0, PASTE_MAX_CHARS);
|
|
10
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { parseDuration } from "../../duration.js";
|
|
3
|
+
import { parseMaxRuns } from "../../loop-config.js";
|
|
4
|
+
import { t } from "../../i18n/index.js";
|
|
5
|
+
const validators = {
|
|
6
|
+
name(value) {
|
|
7
|
+
if (!value.trim())
|
|
8
|
+
return t("errors.commandEmpty");
|
|
9
|
+
return null;
|
|
10
|
+
},
|
|
11
|
+
interval(value) {
|
|
12
|
+
if (!value.trim())
|
|
13
|
+
return null;
|
|
14
|
+
try {
|
|
15
|
+
parseDuration(value);
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
return err instanceof Error ? err.message : t("wizard.validationError");
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
command(value, options) {
|
|
23
|
+
if (options?.taskMode === "existing")
|
|
24
|
+
return null;
|
|
25
|
+
if (!value.trim())
|
|
26
|
+
return t("errors.commandEmpty");
|
|
27
|
+
return null;
|
|
28
|
+
},
|
|
29
|
+
description(value) {
|
|
30
|
+
if (!value.trim())
|
|
31
|
+
return null;
|
|
32
|
+
return null;
|
|
33
|
+
},
|
|
34
|
+
maxRuns(value) {
|
|
35
|
+
if (!value.trim())
|
|
36
|
+
return null;
|
|
37
|
+
try {
|
|
38
|
+
parseMaxRuns(value);
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
return err instanceof Error ? err.message : t("wizard.validationError");
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
cwd(value) {
|
|
46
|
+
if (!value.trim())
|
|
47
|
+
return null;
|
|
48
|
+
if (!fs.existsSync(value))
|
|
49
|
+
return t("board.cwdMissing", { cwd: value });
|
|
50
|
+
return null;
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
export function validateField(key, value, options) {
|
|
54
|
+
const fn = validators[key];
|
|
55
|
+
return fn ? fn(value, options) : null;
|
|
56
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loop-task",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Loop engineering toolkit. Run any command on a cadence, in the background, managed from a terminal board. Schedule tests, builds, syncs, or agent prompts.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -38,20 +38,24 @@
|
|
|
38
38
|
"license": "MIT",
|
|
39
39
|
"repository": {
|
|
40
40
|
"type": "git",
|
|
41
|
-
"url": "https://github.com/CKGrafico/loop-
|
|
41
|
+
"url": "https://github.com/CKGrafico/loop-task.git"
|
|
42
42
|
},
|
|
43
|
-
"homepage": "https://github.com/CKGrafico/loop-
|
|
43
|
+
"homepage": "https://github.com/CKGrafico/loop-task",
|
|
44
44
|
"bugs": {
|
|
45
|
-
"url": "https://github.com/CKGrafico/loop-
|
|
45
|
+
"url": "https://github.com/CKGrafico/loop-task/issues"
|
|
46
46
|
},
|
|
47
47
|
"engines": {
|
|
48
48
|
"node": ">=20.0.0"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@opentui/core": "^0.4.1",
|
|
52
|
-
"@opentui/react": "^0.4.1",
|
|
53
51
|
"commander": "^13.1.0",
|
|
54
52
|
"execa": "^9.6.0",
|
|
53
|
+
"ink": "^7.1.0",
|
|
54
|
+
"ink-combobox": "^0.2.0",
|
|
55
|
+
"ink-scroll-list": "^0.4.1",
|
|
56
|
+
"ink-select-input": "^6.2.0",
|
|
57
|
+
"ink-spinner": "^5.0.0",
|
|
58
|
+
"ink-text-input": "^6.0.0",
|
|
55
59
|
"ms": "^2.1.3",
|
|
56
60
|
"react": "^19.2.7"
|
|
57
61
|
},
|
|
@@ -61,6 +65,7 @@
|
|
|
61
65
|
"@types/react": "^19.2.17",
|
|
62
66
|
"@vitest/coverage-v8": "^3.1.0",
|
|
63
67
|
"eslint": "^9.25.0",
|
|
68
|
+
"ink-testing-library": "^4.0.0",
|
|
64
69
|
"tsx": "^4.19.0",
|
|
65
70
|
"typescript": "^5.8.0",
|
|
66
71
|
"typescript-eslint": "^8.30.0",
|
|
@@ -69,8 +74,8 @@
|
|
|
69
74
|
"scripts": {
|
|
70
75
|
"build": "tsc -p tsconfig.build.json && node -e \"require('fs').copyFileSync('src/entry.js','dist/entry.js'); require('fs').copyFileSync('src/esm-loader.js','dist/esm-loader.js')\"",
|
|
71
76
|
"start": "node dist/entry.js",
|
|
72
|
-
"dev": "
|
|
73
|
-
"dev:watch": "
|
|
77
|
+
"dev": "tsx src/cli.ts",
|
|
78
|
+
"dev:watch": "tsx --watch src/cli.ts",
|
|
74
79
|
"board": "node dist/entry.js",
|
|
75
80
|
"test": "vitest run --exclude '**/background-cli.test.ts'",
|
|
76
81
|
"test:all": "vitest run",
|