agent-office 0.4.9 → 0.6.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.
Files changed (189) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +259 -228
  3. package/dist/commands/cron-requests.d.ts +7 -0
  4. package/dist/commands/cron-requests.d.ts.map +1 -0
  5. package/dist/commands/cron-requests.js +31 -0
  6. package/dist/commands/cron-requests.js.map +1 -0
  7. package/dist/commands/crons.d.ts +10 -0
  8. package/dist/commands/crons.d.ts.map +1 -0
  9. package/dist/commands/crons.js +45 -0
  10. package/dist/commands/crons.js.map +1 -0
  11. package/dist/commands/hello.d.ts +5 -0
  12. package/dist/commands/hello.d.ts.map +1 -0
  13. package/dist/commands/hello.js +4 -0
  14. package/dist/commands/hello.js.map +1 -0
  15. package/dist/commands/messages.d.ts +5 -0
  16. package/dist/commands/messages.d.ts.map +1 -0
  17. package/dist/commands/messages.js +18 -0
  18. package/dist/commands/messages.js.map +1 -0
  19. package/dist/commands/sessions.d.ts +13 -0
  20. package/dist/commands/sessions.d.ts.map +1 -0
  21. package/dist/commands/sessions.js +58 -0
  22. package/dist/commands/sessions.js.map +1 -0
  23. package/dist/commands/task-columns.d.ts +2 -0
  24. package/dist/commands/task-columns.d.ts.map +1 -0
  25. package/dist/commands/task-columns.js +13 -0
  26. package/dist/commands/task-columns.js.map +1 -0
  27. package/dist/commands/tasks.d.ts +11 -0
  28. package/dist/commands/tasks.d.ts.map +1 -0
  29. package/dist/commands/tasks.js +75 -0
  30. package/dist/commands/tasks.js.map +1 -0
  31. package/dist/config.test.d.ts +2 -0
  32. package/dist/config.test.d.ts.map +1 -0
  33. package/dist/config.test.js +50 -0
  34. package/dist/config.test.js.map +1 -0
  35. package/dist/db/index.d.ts +6 -70
  36. package/dist/db/index.d.ts.map +1 -0
  37. package/dist/db/index.js +4 -11
  38. package/dist/db/index.js.map +1 -0
  39. package/dist/db/mock-storage.d.ts +79 -0
  40. package/dist/db/mock-storage.d.ts.map +1 -0
  41. package/dist/db/mock-storage.js +381 -0
  42. package/dist/db/mock-storage.js.map +1 -0
  43. package/dist/db/mock-storage.test.d.ts +2 -0
  44. package/dist/db/mock-storage.test.d.ts.map +1 -0
  45. package/dist/db/mock-storage.test.js +234 -0
  46. package/dist/db/mock-storage.test.js.map +1 -0
  47. package/dist/db/postgresql-storage.d.ts +10 -8
  48. package/dist/db/postgresql-storage.d.ts.map +1 -0
  49. package/dist/db/postgresql-storage.js +76 -42
  50. package/dist/db/postgresql-storage.js.map +1 -0
  51. package/dist/db/sqlite-storage.d.ts +9 -8
  52. package/dist/db/sqlite-storage.d.ts.map +1 -0
  53. package/dist/db/sqlite-storage.js +75 -41
  54. package/dist/db/sqlite-storage.js.map +1 -0
  55. package/dist/db/storage-base.d.ts +7 -8
  56. package/dist/db/storage-base.d.ts.map +1 -0
  57. package/dist/db/storage-base.js +3 -2
  58. package/dist/db/storage-base.js.map +1 -0
  59. package/dist/db/storage.d.ts +12 -12
  60. package/dist/db/storage.d.ts.map +1 -0
  61. package/dist/db/storage.js +1 -0
  62. package/dist/db/storage.js.map +1 -0
  63. package/dist/db/types.d.ts +67 -0
  64. package/dist/db/types.d.ts.map +1 -0
  65. package/dist/db/types.js +2 -0
  66. package/dist/db/types.js.map +1 -0
  67. package/dist/index.d.ts +2 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +397 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/index.test.d.ts +2 -0
  72. package/dist/index.test.d.ts.map +1 -0
  73. package/dist/index.test.js +49 -0
  74. package/dist/index.test.js.map +1 -0
  75. package/dist/lib/output.d.ts +2 -0
  76. package/dist/lib/output.d.ts.map +1 -0
  77. package/dist/lib/output.js +8 -0
  78. package/dist/lib/output.js.map +1 -0
  79. package/dist/services/cron-service.constraints.test.d.ts +2 -0
  80. package/dist/services/cron-service.constraints.test.d.ts.map +1 -0
  81. package/dist/services/cron-service.constraints.test.js +90 -0
  82. package/dist/services/cron-service.constraints.test.js.map +1 -0
  83. package/dist/services/cron-service.d.ts +45 -0
  84. package/dist/services/cron-service.d.ts.map +1 -0
  85. package/dist/services/cron-service.js +157 -0
  86. package/dist/services/cron-service.js.map +1 -0
  87. package/dist/services/cron-service.test.d.ts +2 -0
  88. package/dist/services/cron-service.test.d.ts.map +1 -0
  89. package/dist/services/cron-service.test.js +280 -0
  90. package/dist/services/cron-service.test.js.map +1 -0
  91. package/dist/services/index.d.ts +5 -0
  92. package/dist/services/index.d.ts.map +1 -0
  93. package/dist/services/index.js +5 -0
  94. package/dist/services/index.js.map +1 -0
  95. package/dist/services/message-service.d.ts +16 -0
  96. package/dist/services/message-service.d.ts.map +1 -0
  97. package/dist/services/message-service.js +39 -0
  98. package/dist/services/message-service.js.map +1 -0
  99. package/dist/services/message-service.test.d.ts +2 -0
  100. package/dist/services/message-service.test.d.ts.map +1 -0
  101. package/dist/services/message-service.test.js +145 -0
  102. package/dist/services/message-service.test.js.map +1 -0
  103. package/dist/services/session-service.constraints.test.d.ts +2 -0
  104. package/dist/services/session-service.constraints.test.d.ts.map +1 -0
  105. package/dist/services/session-service.constraints.test.js +34 -0
  106. package/dist/services/session-service.constraints.test.js.map +1 -0
  107. package/dist/services/session-service.d.ts +27 -0
  108. package/dist/services/session-service.d.ts.map +1 -0
  109. package/dist/services/session-service.js +55 -0
  110. package/dist/services/session-service.js.map +1 -0
  111. package/dist/services/session-service.test.d.ts +2 -0
  112. package/dist/services/session-service.test.d.ts.map +1 -0
  113. package/dist/services/session-service.test.js +87 -0
  114. package/dist/services/session-service.test.js.map +1 -0
  115. package/dist/services/task-service.d.ts +25 -0
  116. package/dist/services/task-service.d.ts.map +1 -0
  117. package/dist/services/task-service.js +87 -0
  118. package/dist/services/task-service.js.map +1 -0
  119. package/dist/services/task-service.test.d.ts +2 -0
  120. package/dist/services/task-service.test.d.ts.map +1 -0
  121. package/dist/services/task-service.test.js +180 -0
  122. package/dist/services/task-service.test.js.map +1 -0
  123. package/package.json +40 -42
  124. package/dist/cli.d.ts +0 -2
  125. package/dist/cli.js +0 -317
  126. package/dist/commands/communicator.d.ts +0 -9
  127. package/dist/commands/communicator.js +0 -2231
  128. package/dist/commands/manage.d.ts +0 -5
  129. package/dist/commands/manage.js +0 -20
  130. package/dist/commands/notifier.d.ts +0 -11
  131. package/dist/commands/notifier.js +0 -100
  132. package/dist/commands/screensaver.d.ts +0 -8
  133. package/dist/commands/screensaver.js +0 -1280
  134. package/dist/commands/serve.d.ts +0 -13
  135. package/dist/commands/serve.js +0 -95
  136. package/dist/commands/task-board.d.ts +0 -29
  137. package/dist/commands/task-board.js +0 -251
  138. package/dist/commands/worker.d.ts +0 -16
  139. package/dist/commands/worker.js +0 -145
  140. package/dist/db/migrate.d.ts +0 -2
  141. package/dist/db/migrate.js +0 -3
  142. package/dist/lib/agentic-coding-server.d.ts +0 -66
  143. package/dist/lib/agentic-coding-server.js +0 -7
  144. package/dist/lib/notifier.d.ts +0 -18
  145. package/dist/lib/notifier.js +0 -15
  146. package/dist/lib/opencode-coding-server.d.ts +0 -11
  147. package/dist/lib/opencode-coding-server.js +0 -66
  148. package/dist/lib/pi-coding-server.d.ts +0 -20
  149. package/dist/lib/pi-coding-server.js +0 -162
  150. package/dist/manage/app.d.ts +0 -6
  151. package/dist/manage/app.js +0 -128
  152. package/dist/manage/components/AgentCode.d.ts +0 -8
  153. package/dist/manage/components/AgentCode.js +0 -73
  154. package/dist/manage/components/CreateSession.d.ts +0 -8
  155. package/dist/manage/components/CreateSession.js +0 -37
  156. package/dist/manage/components/CronList.d.ts +0 -9
  157. package/dist/manage/components/CronList.js +0 -321
  158. package/dist/manage/components/CronRequests.d.ts +0 -8
  159. package/dist/manage/components/CronRequests.js +0 -181
  160. package/dist/manage/components/DeleteSession.d.ts +0 -7
  161. package/dist/manage/components/DeleteSession.js +0 -55
  162. package/dist/manage/components/InjectText.d.ts +0 -8
  163. package/dist/manage/components/InjectText.js +0 -51
  164. package/dist/manage/components/ItemSelector.d.ts +0 -7
  165. package/dist/manage/components/ItemSelector.js +0 -20
  166. package/dist/manage/components/MenuSelect.d.ts +0 -13
  167. package/dist/manage/components/MenuSelect.js +0 -22
  168. package/dist/manage/components/MyMail.d.ts +0 -9
  169. package/dist/manage/components/MyMail.js +0 -143
  170. package/dist/manage/components/Profile.d.ts +0 -8
  171. package/dist/manage/components/Profile.js +0 -60
  172. package/dist/manage/components/ReadMail.d.ts +0 -8
  173. package/dist/manage/components/ReadMail.js +0 -110
  174. package/dist/manage/components/SendMessage.d.ts +0 -9
  175. package/dist/manage/components/SendMessage.js +0 -79
  176. package/dist/manage/components/SessionList.d.ts +0 -9
  177. package/dist/manage/components/SessionList.js +0 -608
  178. package/dist/manage/components/SessionSidebar.d.ts +0 -6
  179. package/dist/manage/components/SessionSidebar.js +0 -24
  180. package/dist/manage/components/TailMessages.d.ts +0 -8
  181. package/dist/manage/components/TailMessages.js +0 -126
  182. package/dist/manage/hooks/useApi.d.ts +0 -147
  183. package/dist/manage/hooks/useApi.js +0 -181
  184. package/dist/server/cron.d.ts +0 -25
  185. package/dist/server/cron.js +0 -107
  186. package/dist/server/index.d.ts +0 -4
  187. package/dist/server/index.js +0 -22
  188. package/dist/server/routes.d.ts +0 -13
  189. package/dist/server/routes.js +0 -1396
@@ -1,321 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useEffect, useState, useCallback } from "react";
3
- import { Box, Text, useInput } from "ink";
4
- import { TextInput, Spinner, ConfirmInput } from "@inkjs/ui";
5
- import { useApi, useAsyncState } from "../hooks/useApi.js";
6
- const NEXT_RUN_PADDING = 22;
7
- export function CronList({ serverUrl, password, onBack, contentHeight, sessionName: initialSessionName }) {
8
- const { listCrons, createCron, deleteCron, enableCron, disableCron, getCronHistory, listSessions } = useApi(serverUrl, password);
9
- const { data: crons, loading, error: loadError, run } = useAsyncState();
10
- const { data: sessions, run: runSessions } = useAsyncState();
11
- const [cursor, setCursor] = useState(0);
12
- const [mode, setMode] = useState("list");
13
- const [actionMsg, setActionMsg] = useState(null);
14
- const [actionError, setActionError] = useState(null);
15
- const [selectedSession, setSelectedSession] = useState(initialSessionName ?? null);
16
- const [createData, setCreateData] = useState({
17
- name: "",
18
- schedule: "",
19
- message: "",
20
- });
21
- const [selectedSessionCursor, setSelectedSessionCursor] = useState(0);
22
- const [history, setHistory] = useState([]);
23
- const [historyLoading, setHistoryLoading] = useState(false);
24
- const filteredCrons = crons?.filter((c) => (selectedSession ? c.session_name === selectedSession : true)) ?? [];
25
- const reload = () => {
26
- void run(listCrons);
27
- void runSessions(() => listSessions());
28
- };
29
- useEffect(() => {
30
- reload();
31
- }, []);
32
- useEffect(() => {
33
- if (filteredCrons.length > 0) {
34
- setCursor((c) => Math.min(c, filteredCrons.length - 1));
35
- }
36
- }, [filteredCrons.length]);
37
- useInput((input, key) => {
38
- if (key.escape && mode === "list") {
39
- onBack();
40
- return;
41
- }
42
- if (key.escape && (mode === "confirm-delete" || mode === "confirm-enable" || mode === "confirm-disable" || mode === "history" || mode === "view-message")) {
43
- setMode("list");
44
- return;
45
- }
46
- if (key.escape && (mode === "create-name" || mode === "create-schedule" || mode === "create-message" || mode === "create-timezone")) {
47
- setMode("list");
48
- setCreateData({ name: "", schedule: "", message: "" });
49
- return;
50
- }
51
- if (loading)
52
- return;
53
- if (mode === "list") {
54
- if (key.upArrow)
55
- setCursor((c) => Math.max(0, c - 1));
56
- if (key.downArrow)
57
- setCursor((c) => Math.min(filteredCrons.length - 1, c + 1));
58
- if (input === "c") {
59
- setActionError(null);
60
- setActionMsg(null);
61
- setCreateData({ name: "", schedule: "", message: "", timezone: "" });
62
- setSelectedSessionCursor(0);
63
- setMode("create-select-session");
64
- }
65
- if (input === "f" && filteredCrons.length > 0) {
66
- setSelectedSession((prev) => (prev ? null : filteredCrons[0]?.session_name ?? null));
67
- }
68
- if (filteredCrons.length > 0) {
69
- const selected = filteredCrons[cursor];
70
- if (input === "d") {
71
- setActionError(null);
72
- setActionMsg(null);
73
- setMode("confirm-delete");
74
- }
75
- if (input === "e") {
76
- setActionError(null);
77
- setActionMsg(null);
78
- setMode(selected?.enabled ? "confirm-disable" : "confirm-enable");
79
- }
80
- if (input === "h") {
81
- setActionError(null);
82
- loadHistory(selected.id);
83
- }
84
- if (input === "v") {
85
- setMode("view-message");
86
- }
87
- }
88
- }
89
- if (mode === "confirm-delete" || mode === "confirm-enable" || mode === "confirm-disable") {
90
- if (key.return || input === "y") {
91
- if (mode === "confirm-delete") {
92
- handleDelete();
93
- }
94
- else if (mode === "confirm-enable") {
95
- handleEnable();
96
- }
97
- else if (mode === "confirm-disable") {
98
- handleDisable();
99
- }
100
- }
101
- if (input === "n" || key.escape) {
102
- setMode("list");
103
- }
104
- return;
105
- }
106
- if (mode === "create-select-session") {
107
- if (key.upArrow)
108
- setSelectedSessionCursor((c) => Math.max(0, c - 1));
109
- if (key.downArrow)
110
- setSelectedSessionCursor((c) => Math.min((sessions ?? []).length - 1, c + 1));
111
- if (key.return) {
112
- const selected = sessions?.[selectedSessionCursor];
113
- if (selected) {
114
- setSelectedSession(selected.name);
115
- setMode("create-name");
116
- }
117
- }
118
- if (key.escape) {
119
- setCreateData({ name: "", schedule: "", message: "" });
120
- setSelectedSession(null);
121
- setMode("list");
122
- }
123
- }
124
- });
125
- const loadHistory = useCallback(async (cronId) => {
126
- setHistoryLoading(true);
127
- try {
128
- const entries = await getCronHistory(cronId, 10);
129
- setHistory(entries);
130
- setMode("history");
131
- }
132
- catch (err) {
133
- setActionError(err instanceof Error ? err.message : String(err));
134
- }
135
- finally {
136
- setHistoryLoading(false);
137
- }
138
- }, [getCronHistory]);
139
- const handleDelete = async () => {
140
- const selected = filteredCrons[cursor];
141
- if (!selected)
142
- return;
143
- setMode("deleting");
144
- try {
145
- await deleteCron(selected.id);
146
- setActionMsg(`Cron job "${selected.name}" deleted.`);
147
- setMode("list");
148
- reload();
149
- }
150
- catch (err) {
151
- setActionError(err instanceof Error ? err.message : String(err));
152
- setMode("list");
153
- }
154
- };
155
- const handleEnable = async () => {
156
- const selected = filteredCrons[cursor];
157
- if (!selected)
158
- return;
159
- setMode("toggling");
160
- try {
161
- await enableCron(selected.id);
162
- setActionMsg(`Cron job "${selected.name}" enabled.`);
163
- setMode("list");
164
- reload();
165
- }
166
- catch (err) {
167
- setActionError(err instanceof Error ? err.message : String(err));
168
- setMode("list");
169
- }
170
- };
171
- const handleDisable = async () => {
172
- const selected = filteredCrons[cursor];
173
- if (!selected)
174
- return;
175
- setMode("toggling");
176
- try {
177
- await disableCron(selected.id);
178
- setActionMsg(`Cron job "${selected.name}" disabled.`);
179
- setMode("list");
180
- reload();
181
- }
182
- catch (err) {
183
- setActionError(err instanceof Error ? err.message : String(err));
184
- setMode("list");
185
- }
186
- };
187
- const handleCreate = async () => {
188
- if (!createData.name.trim() || !createData.schedule.trim() || !createData.message.trim())
189
- return;
190
- if (!selectedSession)
191
- return;
192
- setMode("creating");
193
- try {
194
- await createCron({
195
- name: createData.name.trim(),
196
- session_name: selectedSession,
197
- schedule: createData.schedule.trim(),
198
- message: createData.message.trim(),
199
- timezone: createData.timezone,
200
- });
201
- setActionMsg(`Cron job "${createData.name.trim()}" created.`);
202
- setMode("list");
203
- setCreateData({ name: "", schedule: "", message: "", timezone: "" });
204
- reload();
205
- }
206
- catch (err) {
207
- setActionError(err instanceof Error ? err.message : String(err));
208
- setMode("list");
209
- setCreateData({ name: "", schedule: "", message: "", timezone: "" });
210
- }
211
- };
212
- const formatNextRun = (nextRun) => {
213
- if (!nextRun)
214
- return "—";
215
- try {
216
- const date = new Date(nextRun);
217
- return date.toLocaleString();
218
- }
219
- catch {
220
- return nextRun;
221
- }
222
- };
223
- const formatLastRun = (lastRun) => {
224
- if (!lastRun)
225
- return "never";
226
- try {
227
- const date = new Date(lastRun);
228
- return date.toLocaleString();
229
- }
230
- catch {
231
- return lastRun;
232
- }
233
- };
234
- if (loading && filteredCrons.length === 0) {
235
- return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Loading cron jobs..." }) }));
236
- }
237
- if (loadError) {
238
- return (_jsxs(Box, { height: contentHeight, flexDirection: "column", gap: 1, children: [_jsx(Text, { color: "red", bold: true, children: "Error" }), _jsx(Text, { children: loadError })] }));
239
- }
240
- const renderActionPanel = () => {
241
- if (mode === "deleting") {
242
- return (_jsx(Box, { borderStyle: "round", borderColor: "red", paddingX: 1, marginBottom: 1, children: _jsx(Spinner, { label: `Deleting "${filteredCrons[cursor]?.name}"...` }) }));
243
- }
244
- if (mode === "toggling") {
245
- return (_jsx(Box, { borderStyle: "round", borderColor: "yellow", paddingX: 1, marginBottom: 1, children: _jsx(Spinner, { label: "Updating cron job..." }) }));
246
- }
247
- if (mode === "confirm-delete" && filteredCrons[cursor]) {
248
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "red", children: "Delete Cron Job" }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: ["Delete ", _jsx(Text, { color: "yellow", bold: true, children: filteredCrons[cursor].name }), "? This cannot be undone."] }) }), _jsx(Box, { marginTop: 1, children: _jsx(ConfirmInput, { defaultChoice: "cancel", onConfirm: () => void handleDelete(), onCancel: () => setMode("list") }) })] }));
249
- }
250
- if (mode === "confirm-enable" && filteredCrons[cursor]) {
251
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "green", children: "Enable Cron Job" }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: ["Enable ", _jsx(Text, { color: "cyan", bold: true, children: filteredCrons[cursor].name }), "?"] }) }), _jsx(Box, { marginTop: 1, children: _jsx(ConfirmInput, { defaultChoice: "cancel", onConfirm: () => void handleEnable(), onCancel: () => setMode("list") }) })] }));
252
- }
253
- if (mode === "confirm-disable" && filteredCrons[cursor]) {
254
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "Disable Cron Job" }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { children: ["Disable ", _jsx(Text, { color: "cyan", bold: true, children: filteredCrons[cursor].name }), "?"] }) }), _jsx(Box, { marginTop: 1, children: _jsx(ConfirmInput, { defaultChoice: "cancel", onConfirm: () => void handleDisable(), onCancel: () => setMode("list") }) })] }));
255
- }
256
- return null;
257
- };
258
- const renderCreateSelectSession = () => {
259
- if (mode !== "create-select-session")
260
- return null;
261
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Box, { gap: 2, children: _jsx(Text, { bold: true, children: "Select Coworker" }) }), (sessions ?? []).map((s, i) => {
262
- const sel = i === selectedSessionCursor;
263
- return (_jsxs(Box, { gap: 2, children: [_jsx(Text, { color: sel ? "cyan" : undefined, bold: sel, children: sel ? "▶ " : " " }), _jsx(Text, { color: sel ? "cyan" : undefined, bold: sel, children: s.name })] }, s.id));
264
- }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate \u00B7 Enter select \u00B7 Esc cancel" }) })] }));
265
- };
266
- const renderCreateFields = () => {
267
- if (mode === "create-name") {
268
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Create Cron Job" }), _jsx(Text, { dimColor: true, children: selectedSession })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Name: " }), _jsx(TextInput, { placeholder: "e.g. daily-standup", onSubmit: (v) => {
269
- setCreateData({ ...createData, name: v });
270
- setMode("create-schedule");
271
- } }, "create-name")] })] }));
272
- }
273
- if (mode === "create-schedule") {
274
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Create Cron Job" }), _jsx(Text, { dimColor: true, children: createData.name ?? "" })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Schedule (cron expr): " }), _jsx(TextInput, { placeholder: "e.g. 0 9 * * *", onSubmit: (v) => {
275
- setCreateData({ ...createData, schedule: v });
276
- setMode("create-message");
277
- } }, "create-schedule")] }), _jsx(Text, { dimColor: true, children: "Example: \"0 9 * * *\" = daily at 9am, \"*/30 * * * *\" = every 30 minutes" })] }));
278
- }
279
- if (mode === "create-message") {
280
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Create Cron Job" }), _jsx(Text, { dimColor: true, children: createData.schedule ?? "" })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Message: " }), _jsx(TextInput, { placeholder: "Message to inject", onSubmit: (v) => {
281
- setCreateData({ ...createData, message: v });
282
- setMode("create-timezone");
283
- } }, "create-message")] })] }));
284
- }
285
- if (mode === "create-timezone") {
286
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Create Cron Job" }), _jsxs(Text, { dimColor: true, children: [createData.message.slice(0, 40), "..."] })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Timezone (optional, ENTER to skip): " }), _jsx(TextInput, { placeholder: "e.g. America/New_York", onSubmit: (v) => {
287
- setCreateData({ ...createData, timezone: v || "" });
288
- handleCreate();
289
- } }, "create-timezone")] }), _jsx(Text, { dimColor: true, children: "Leave empty for system timezone" })] }));
290
- }
291
- if (mode === "creating") {
292
- return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Creating cron job..." }) }));
293
- }
294
- return null;
295
- };
296
- const renderViewMessage = () => {
297
- if (mode !== "view-message")
298
- return null;
299
- const selected = filteredCrons[cursor];
300
- if (!selected)
301
- return null;
302
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Message Preview" }), _jsx(Text, { dimColor: true, children: selected.name })] }), _jsx(Box, { borderStyle: "round", borderColor: "cyan", paddingX: 1, paddingY: 0, flexDirection: "column", children: _jsx(Text, { wrap: "wrap", children: selected.message }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Esc back" }) })] }));
303
- };
304
- const renderHistory = () => {
305
- if (mode !== "history")
306
- return null;
307
- if (historyLoading) {
308
- return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Loading history..." }) }));
309
- }
310
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "History" }), _jsx(Text, { dimColor: true, children: "Press any key to go back" })] }), history.length === 0 ? (_jsx(Text, { dimColor: true, children: "No execution history yet." })) : (_jsx(Box, { flexDirection: "column", children: history.map((entry) => (_jsxs(Box, { gap: 2, children: [_jsx(Text, { color: entry.success ? "green" : "red", children: entry.success ? "✓" : "✗" }), _jsx(Text, { children: new Date(entry.executed_at).toLocaleString() }), !entry.success && entry.error_message && (_jsx(Text, { color: "red", children: entry.error_message }))] }, entry.id))) }))] }));
311
- };
312
- const actionPanel = renderActionPanel();
313
- const panelHeight = actionPanel ? 5 : 0;
314
- const tableHeight = contentHeight - panelHeight - 5;
315
- return (_jsxs(Box, { flexDirection: "column", gap: 0, children: [renderCreateSelectSession(), renderCreateFields(), renderViewMessage(), renderHistory(), (mode === "list" || mode === "confirm-delete" || mode === "confirm-enable" || mode === "confirm-disable" || mode === "deleting" || mode === "toggling" || mode === "view-message") && (_jsxs(_Fragment, { children: [_jsxs(Box, { gap: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Cron Jobs" }), selectedSession ? (_jsxs(Text, { color: "cyan", dimColor: true, children: ["[", filteredCrons.length, " jobs for ", selectedSession, "]"] })) : (_jsxs(Text, { dimColor: true, children: ["[", filteredCrons.length, " total]"] })), loading && _jsx(Spinner, {})] }), actionPanel, filteredCrons.length === 0 ? (_jsx(Box, { height: tableHeight, alignItems: "center", justifyContent: "center", children: _jsx(Text, { dimColor: true, children: selectedSession
316
- ? `No cron jobs for ${selectedSession}. Press c to create one.`
317
- : "No cron jobs yet. Press c to create one." }) })) : (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { gap: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: " NAME".padEnd(20) }), _jsx(Text, { bold: true, color: "cyan", children: "COWORKER".padEnd(15) }), _jsx(Text, { bold: true, color: "cyan", children: "SCHEDULE".padEnd(20) }), _jsx(Text, { bold: true, color: "cyan", children: "NEXT RUN".padEnd(NEXT_RUN_PADDING) }), _jsx(Text, { bold: true, color: "cyan", children: "STATUS" })] }), filteredCrons.map((job, idx) => {
318
- const selected = idx === cursor;
319
- return (_jsxs(Box, { gap: 2, children: [_jsxs(Box, { width: 20, children: [_jsx(Text, { color: selected ? "cyan" : undefined, children: selected ? "▶ " : " " }), _jsx(Text, { color: selected ? "cyan" : "green", bold: selected, children: job.name })] }), _jsx(Box, { width: 15, children: _jsx(Text, { color: selected ? "magenta" : undefined, dimColor: !selected, children: job.session_name.padEnd(15) }) }), _jsx(Box, { width: 20, children: _jsx(Text, { dimColor: !selected, children: job.schedule.padEnd(20) }) }), _jsx(Box, { width: NEXT_RUN_PADDING, children: _jsx(Text, { color: job.enabled ? (selected ? "cyan" : "green") : "gray", dimColor: !selected, children: job.enabled ? formatNextRun(job.next_run).padEnd(NEXT_RUN_PADDING) : "DISABLED".padEnd(NEXT_RUN_PADDING) }) }), _jsx(Text, { color: job.enabled ? "green" : "gray", dimColor: !selected, children: job.enabled ? "enabled" : "disabled" })] }, job.id));
320
- })] })), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["c create \u00B7 d delete \u00B7 e enable/disable \u00B7 h history \u00B7 v view message \u00B7 f", " ", selectedSession ? "show all" : "filter by coworker", " \u00B7 Esc back"] }) })] }))] }));
321
- }
@@ -1,8 +0,0 @@
1
- interface CronRequestsProps {
2
- serverUrl: string;
3
- password: string;
4
- onBack: () => void;
5
- contentHeight: number;
6
- }
7
- export declare function CronRequests({ serverUrl, password, onBack, contentHeight }: CronRequestsProps): import("react/jsx-runtime").JSX.Element;
8
- export {};
@@ -1,181 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useEffect, useState, useCallback } from "react";
3
- import { Box, Text, useInput } from "ink";
4
- import { TextInput, Spinner, ConfirmInput } from "@inkjs/ui";
5
- import { useApi, useAsyncState } from "../hooks/useApi.js";
6
- export function CronRequests({ serverUrl, password, onBack, contentHeight }) {
7
- const { listCronRequests, approveCronRequest, rejectCronRequest } = useApi(serverUrl, password);
8
- const { data: requests, loading, error: loadError, run } = useAsyncState();
9
- const [cursor, setCursor] = useState(0);
10
- const [mode, setMode] = useState("list");
11
- const [actionMsg, setActionMsg] = useState(null);
12
- const [actionError, setActionError] = useState(null);
13
- const [rejectNotes, setRejectNotes] = useState("");
14
- const [showAll, setShowAll] = useState(false);
15
- const filteredRequests = (requests ?? []).filter((r) => showAll || r.status === "pending");
16
- const reload = useCallback(() => {
17
- void run(() => listCronRequests(showAll ? undefined : { status: "pending" }));
18
- }, [showAll]);
19
- useEffect(() => {
20
- reload();
21
- }, [showAll]);
22
- useEffect(() => {
23
- if (filteredRequests.length > 0) {
24
- setCursor((c) => Math.min(c, filteredRequests.length - 1));
25
- }
26
- }, [filteredRequests.length]);
27
- useInput((input, key) => {
28
- if (key.escape && mode === "list") {
29
- onBack();
30
- return;
31
- }
32
- if (key.escape && (mode === "confirm-approve" || mode === "confirm-reject" || mode === "reject-notes" || mode === "view-message")) {
33
- setMode("list");
34
- setRejectNotes("");
35
- return;
36
- }
37
- if (loading)
38
- return;
39
- if (mode === "list") {
40
- if (key.upArrow)
41
- setCursor((c) => Math.max(0, c - 1));
42
- if (key.downArrow)
43
- setCursor((c) => Math.min(filteredRequests.length - 1, c + 1));
44
- if (filteredRequests.length > 0) {
45
- const selected = filteredRequests[cursor];
46
- if (input === "a" && selected?.status === "pending") {
47
- setActionError(null);
48
- setActionMsg(null);
49
- setMode("confirm-approve");
50
- }
51
- if (input === "r" && selected?.status === "pending") {
52
- setActionError(null);
53
- setActionMsg(null);
54
- setRejectNotes("");
55
- setMode("reject-notes");
56
- }
57
- if (input === "v") {
58
- setMode("view-message");
59
- }
60
- }
61
- if (input === "f") {
62
- setShowAll((prev) => !prev);
63
- }
64
- }
65
- if (mode === "confirm-approve") {
66
- if (key.return || input === "y") {
67
- handleApprove();
68
- }
69
- if (input === "n" || key.escape) {
70
- setMode("list");
71
- }
72
- return;
73
- }
74
- if (mode === "confirm-reject") {
75
- if (key.return || input === "y") {
76
- handleReject();
77
- }
78
- if (input === "n" || key.escape) {
79
- setMode("list");
80
- setRejectNotes("");
81
- }
82
- return;
83
- }
84
- });
85
- const handleApprove = async () => {
86
- const selected = filteredRequests[cursor];
87
- if (!selected)
88
- return;
89
- setMode("approving");
90
- try {
91
- await approveCronRequest(selected.id);
92
- setActionMsg(`Cron request "${selected.name}" approved and scheduled.`);
93
- setMode("list");
94
- reload();
95
- }
96
- catch (err) {
97
- setActionError(err instanceof Error ? err.message : String(err));
98
- setMode("list");
99
- }
100
- };
101
- const handleReject = async () => {
102
- const selected = filteredRequests[cursor];
103
- if (!selected)
104
- return;
105
- setMode("rejecting");
106
- try {
107
- await rejectCronRequest(selected.id, rejectNotes || undefined);
108
- setActionMsg(`Cron request "${selected.name}" rejected.`);
109
- setMode("list");
110
- setRejectNotes("");
111
- reload();
112
- }
113
- catch (err) {
114
- setActionError(err instanceof Error ? err.message : String(err));
115
- setMode("list");
116
- setRejectNotes("");
117
- }
118
- };
119
- const formatDate = (dateStr) => {
120
- try {
121
- return new Date(dateStr).toLocaleString();
122
- }
123
- catch {
124
- return dateStr;
125
- }
126
- };
127
- const statusColor = (status) => {
128
- switch (status) {
129
- case "pending": return "yellow";
130
- case "approved": return "green";
131
- case "rejected": return "red";
132
- default: return "white";
133
- }
134
- };
135
- if (loading && filteredRequests.length === 0) {
136
- return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Loading cron requests..." }) }));
137
- }
138
- if (loadError) {
139
- return (_jsxs(Box, { height: contentHeight, flexDirection: "column", gap: 1, children: [_jsx(Text, { color: "red", bold: true, children: "Error" }), _jsx(Text, { children: loadError })] }));
140
- }
141
- const renderActionPanel = () => {
142
- if (mode === "approving") {
143
- return (_jsx(Box, { borderStyle: "round", borderColor: "green", paddingX: 1, marginBottom: 1, children: _jsx(Spinner, { label: `Approving "${filteredRequests[cursor]?.name}"...` }) }));
144
- }
145
- if (mode === "rejecting") {
146
- return (_jsx(Box, { borderStyle: "round", borderColor: "red", paddingX: 1, marginBottom: 1, children: _jsx(Spinner, { label: `Rejecting "${filteredRequests[cursor]?.name}"...` }) }));
147
- }
148
- if (mode === "confirm-approve" && filteredRequests[cursor]) {
149
- const req = filteredRequests[cursor];
150
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "green", children: "Approve Cron Request" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { children: ["Approve ", _jsx(Text, { color: "cyan", bold: true, children: req.name }), " from ", _jsx(Text, { color: "magenta", children: req.session_name }), "?"] }), _jsxs(Text, { dimColor: true, children: ["Schedule: ", req.schedule] })] }), _jsx(Box, { marginTop: 1, children: _jsx(ConfirmInput, { defaultChoice: "cancel", onConfirm: () => void handleApprove(), onCancel: () => setMode("list") }) })] }));
151
- }
152
- if (mode === "confirm-reject" && filteredRequests[cursor]) {
153
- const req = filteredRequests[cursor];
154
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "red", paddingX: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "red", children: "Reject Cron Request" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { children: ["Reject ", _jsx(Text, { color: "cyan", bold: true, children: req.name }), " from ", _jsx(Text, { color: "magenta", children: req.session_name }), "?"] }), rejectNotes && _jsxs(Text, { dimColor: true, children: ["Notes: ", rejectNotes] })] }), _jsx(Box, { marginTop: 1, children: _jsx(ConfirmInput, { defaultChoice: "cancel", onConfirm: () => void handleReject(), onCancel: () => { setMode("list"); setRejectNotes(""); } }) })] }));
155
- }
156
- return null;
157
- };
158
- const renderRejectNotes = () => {
159
- if (mode !== "reject-notes")
160
- return null;
161
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, color: "red", children: "Reject Cron Request" }), _jsx(Text, { dimColor: true, children: filteredRequests[cursor]?.name })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Reason (optional, Enter to skip): " }), _jsx(TextInput, { placeholder: "e.g. Schedule too frequent", onSubmit: (v) => {
162
- setRejectNotes(v);
163
- setMode("confirm-reject");
164
- } }, "reject-notes")] }), _jsx(Text, { dimColor: true, children: "Esc cancel" })] }));
165
- };
166
- const renderViewMessage = () => {
167
- if (mode !== "view-message")
168
- return null;
169
- const selected = filteredRequests[cursor];
170
- if (!selected)
171
- return null;
172
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Request Details" }), _jsx(Text, { dimColor: true, children: selected.name })] }), _jsxs(Box, { borderStyle: "round", borderColor: "cyan", paddingX: 1, paddingY: 0, flexDirection: "column", children: [_jsxs(Text, { children: ["From: ", _jsx(Text, { color: "magenta", bold: true, children: selected.session_name })] }), _jsxs(Text, { children: ["Schedule: ", _jsx(Text, { bold: true, children: selected.schedule })] }), selected.timezone && _jsxs(Text, { children: ["Timezone: ", selected.timezone] }), _jsxs(Text, { children: ["Status: ", _jsx(Text, { color: statusColor(selected.status), bold: true, children: selected.status })] }), _jsxs(Text, { children: ["Requested: ", formatDate(selected.requested_at)] }), selected.reviewed_at && _jsxs(Text, { children: ["Reviewed: ", formatDate(selected.reviewed_at), " by ", selected.reviewed_by] }), selected.reviewer_notes && _jsxs(Text, { children: ["Notes: ", selected.reviewer_notes] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { bold: true, children: "Message:" }) }), _jsx(Text, { wrap: "wrap", children: selected.message })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Esc back" }) })] }));
173
- };
174
- const actionPanel = renderActionPanel();
175
- const panelHeight = actionPanel ? 5 : 0;
176
- const tableHeight = contentHeight - panelHeight - 5;
177
- return (_jsxs(Box, { flexDirection: "column", gap: 0, children: [renderRejectNotes(), renderViewMessage(), (mode === "list" || mode === "confirm-approve" || mode === "confirm-reject" || mode === "approving" || mode === "rejecting") && (_jsxs(_Fragment, { children: [_jsxs(Box, { gap: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Cron Requests" }), _jsxs(Text, { dimColor: true, children: ["[", filteredRequests.length, " ", showAll ? "total" : "pending", "]"] }), loading && _jsx(Spinner, {})] }), actionMsg && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "green", children: actionMsg }) })), actionError && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "red", children: actionError }) })), actionPanel, filteredRequests.length === 0 ? (_jsx(Box, { height: tableHeight, alignItems: "center", justifyContent: "center", children: _jsx(Text, { dimColor: true, children: showAll ? "No cron requests found." : "No pending cron requests. Press f to show all." }) })) : (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { gap: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: " NAME".padEnd(20) }), _jsx(Text, { bold: true, color: "cyan", children: "COWORKER".padEnd(15) }), _jsx(Text, { bold: true, color: "cyan", children: "SCHEDULE".padEnd(20) }), _jsx(Text, { bold: true, color: "cyan", children: "REQUESTED".padEnd(22) }), _jsx(Text, { bold: true, color: "cyan", children: "STATUS" })] }), filteredRequests.map((req, idx) => {
178
- const selected = idx === cursor;
179
- return (_jsxs(Box, { gap: 2, children: [_jsxs(Box, { width: 20, children: [_jsx(Text, { color: selected ? "cyan" : undefined, children: selected ? "▶ " : " " }), _jsx(Text, { color: selected ? "cyan" : "green", bold: selected, children: req.name })] }), _jsx(Box, { width: 15, children: _jsx(Text, { color: selected ? "magenta" : undefined, dimColor: !selected, children: req.session_name.padEnd(15) }) }), _jsx(Box, { width: 20, children: _jsx(Text, { dimColor: !selected, children: req.schedule.padEnd(20) }) }), _jsx(Box, { width: 22, children: _jsx(Text, { dimColor: !selected, children: formatDate(req.requested_at).padEnd(22) }) }), _jsx(Text, { color: statusColor(req.status), bold: selected, children: req.status })] }, req.id));
180
- })] })), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["a approve \u00B7 r reject \u00B7 v view details \u00B7 f ", showAll ? "show pending only" : "show all", " \u00B7 Esc back"] }) })] }))] }));
181
- }
@@ -1,7 +0,0 @@
1
- interface DeleteSessionProps {
2
- serverUrl: string;
3
- password: string;
4
- onBack: () => void;
5
- }
6
- export declare function DeleteSession({ serverUrl, password, onBack }: DeleteSessionProps): import("react/jsx-runtime").JSX.Element;
7
- export {};
@@ -1,55 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useState } from "react";
3
- import { Box, Text } from "ink";
4
- import { Select, Spinner, ConfirmInput } from "@inkjs/ui";
5
- import { useApi, useAsyncState } from "../hooks/useApi.js";
6
- export function DeleteSession({ serverUrl, password, onBack }) {
7
- const { listSessions, deleteSession } = useApi(serverUrl, password);
8
- const { run } = useAsyncState();
9
- const [sessions, setSessions] = useState([]);
10
- const [stage, setStage] = useState("loading");
11
- const [selected, setSelected] = useState(null);
12
- const [error, setError] = useState(null);
13
- useEffect(() => {
14
- void run(listSessions).then((rows) => {
15
- if (rows && rows.length > 0) {
16
- setSessions(rows);
17
- setStage("select");
18
- }
19
- else if (rows) {
20
- setError("No sessions to delete.");
21
- setStage("error");
22
- }
23
- });
24
- }, []);
25
- // Auto-return to menu 1.5s after done or error
26
- useEffect(() => {
27
- if (stage === "done" || stage === "error") {
28
- const timer = setTimeout(onBack, 1500);
29
- return () => clearTimeout(timer);
30
- }
31
- }, [stage, onBack]);
32
- const handleSelect = (name) => {
33
- setSelected(name);
34
- setStage("confirm");
35
- };
36
- const handleConfirm = async (confirmed) => {
37
- if (!confirmed || !selected) {
38
- onBack();
39
- return;
40
- }
41
- setStage("deleting");
42
- try {
43
- await deleteSession(selected);
44
- setStage("done");
45
- }
46
- catch (err) {
47
- setError(err instanceof Error ? err.message : String(err));
48
- setStage("error");
49
- }
50
- };
51
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Delete Session" }), stage === "loading" && (_jsx(Spinner, { label: "Loading sessions..." })), stage === "select" && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: "Select a session to delete:" }), _jsx(Select, { options: sessions.map((s) => ({
52
- label: `${s.name} ${s.session_id.slice(0, 8)}...`,
53
- value: s.name,
54
- })), onChange: handleSelect })] })), stage === "confirm" && selected && (_jsxs(_Fragment, { children: [_jsxs(Text, { children: ["Delete ", _jsx(Text, { color: "yellow", bold: true, children: selected }), "?", " ", _jsx(Text, { dimColor: true, children: "This also deletes the OpenCode session." })] }), _jsx(ConfirmInput, { defaultChoice: "cancel", onConfirm: () => void handleConfirm(true), onCancel: () => void handleConfirm(false) })] })), stage === "deleting" && (_jsx(Spinner, { label: `Deleting "${selected}"...` })), stage === "done" && (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "green", children: ["Session \"", selected, "\" deleted."] }), _jsx(Text, { dimColor: true, children: "Returning to menu..." })] })), stage === "error" && (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "red", children: ["Error: ", error] }), _jsx(Text, { dimColor: true, children: "Returning to menu..." })] }))] }));
55
- }
@@ -1,8 +0,0 @@
1
- interface InjectTextProps {
2
- serverUrl: string;
3
- password: string;
4
- onBack: () => void;
5
- contentHeight: number;
6
- }
7
- export declare function InjectText({ serverUrl, password, onBack, contentHeight }: InjectTextProps): import("react/jsx-runtime").JSX.Element;
8
- export {};
@@ -1,51 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useState } from "react";
3
- import { Box, Text } from "ink";
4
- import { Select, Spinner, TextInput } from "@inkjs/ui";
5
- import { useApi, useAsyncState } from "../hooks/useApi.js";
6
- export function InjectText({ serverUrl, password, onBack, contentHeight }) {
7
- const { listSessions, injectText } = useApi(serverUrl, password);
8
- const { run: runList } = useAsyncState();
9
- const [sessions, setSessions] = useState([]);
10
- const [sessionsLoading, setSessionsLoading] = useState(true);
11
- const [stage, setStage] = useState("select");
12
- const [selectedName, setSelectedName] = useState(null);
13
- const [error, setError] = useState(null);
14
- const [submitted, setSubmitted] = useState(false);
15
- useEffect(() => {
16
- runList(listSessions).then((rows) => {
17
- setSessions(rows ?? []);
18
- setSessionsLoading(false);
19
- });
20
- }, []);
21
- // Auto-return after done or error
22
- useEffect(() => {
23
- if (stage === "done" || stage === "error") {
24
- const timer = setTimeout(onBack, 2000);
25
- return () => clearTimeout(timer);
26
- }
27
- }, [stage, onBack]);
28
- const handleSessionSelect = (name) => {
29
- setSelectedName(name);
30
- setStage("input");
31
- };
32
- const handleTextSubmit = async (text) => {
33
- const trimmed = text.trim();
34
- if (!trimmed || !selectedName)
35
- return;
36
- setSubmitted(true);
37
- setStage("submitting");
38
- try {
39
- await injectText(selectedName, trimmed);
40
- setStage("done");
41
- }
42
- catch (err) {
43
- setError(err instanceof Error ? err.message : String(err));
44
- setStage("error");
45
- }
46
- };
47
- if (sessionsLoading) {
48
- return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Loading sessions..." }) }));
49
- }
50
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Inject Text" }), stage === "select" && sessions.length === 0 && (_jsx(Box, { height: contentHeight - 2, alignItems: "center", justifyContent: "center", children: _jsx(Text, { dimColor: true, children: "No sessions yet. Create one first." }) })), stage === "select" && sessions.length > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: "Select a session to inject into:" }), _jsx(Select, { options: sessions.map((s) => ({ label: s.name, value: s.name })), onChange: handleSessionSelect })] })), stage === "input" && (_jsxs(_Fragment, { children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Session: " }), _jsx(Text, { color: "cyan", children: selectedName })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Text: " }), !submitted && (_jsx(TextInput, { placeholder: "Type your message...", onSubmit: handleTextSubmit }))] })] })), stage === "submitting" && (_jsx(Spinner, { label: `Injecting into "${selectedName}"...` })), stage === "done" && (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "green", children: ["Message injected into \"", selectedName, "\"."] }), _jsx(Text, { dimColor: true, children: "Returning to menu..." })] })), stage === "error" && (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "red", children: ["Error: ", error] }), _jsx(Text, { dimColor: true, children: "Returning to menu..." })] }))] }));
51
- }