agent-office 0.5.0 → 0.6.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/LICENSE +1 -1
- package/README.md +259 -228
- package/dist/commands/cron-requests.d.ts +7 -0
- package/dist/commands/cron-requests.d.ts.map +1 -0
- package/dist/commands/cron-requests.js +31 -0
- package/dist/commands/cron-requests.js.map +1 -0
- package/dist/commands/crons.d.ts +10 -0
- package/dist/commands/crons.d.ts.map +1 -0
- package/dist/commands/crons.js +45 -0
- package/dist/commands/crons.js.map +1 -0
- package/dist/commands/hello.d.ts +5 -0
- package/dist/commands/hello.d.ts.map +1 -0
- package/dist/commands/hello.js +4 -0
- package/dist/commands/hello.js.map +1 -0
- package/dist/commands/messages.d.ts +5 -0
- package/dist/commands/messages.d.ts.map +1 -0
- package/dist/commands/messages.js +18 -0
- package/dist/commands/messages.js.map +1 -0
- package/dist/commands/sessions.d.ts +13 -0
- package/dist/commands/sessions.d.ts.map +1 -0
- package/dist/commands/sessions.js +58 -0
- package/dist/commands/sessions.js.map +1 -0
- package/dist/commands/task-columns.d.ts +2 -0
- package/dist/commands/task-columns.d.ts.map +1 -0
- package/dist/commands/task-columns.js +13 -0
- package/dist/commands/task-columns.js.map +1 -0
- package/dist/commands/tasks.d.ts +11 -0
- package/dist/commands/tasks.d.ts.map +1 -0
- package/dist/commands/tasks.js +75 -0
- package/dist/commands/tasks.js.map +1 -0
- package/dist/config.test.d.ts +2 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +50 -0
- package/dist/config.test.js.map +1 -0
- package/dist/db/index.d.ts +6 -70
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +4 -11
- package/dist/db/index.js.map +1 -0
- package/dist/db/mock-storage.d.ts +79 -0
- package/dist/db/mock-storage.d.ts.map +1 -0
- package/dist/db/mock-storage.js +381 -0
- package/dist/db/mock-storage.js.map +1 -0
- package/dist/db/mock-storage.test.d.ts +2 -0
- package/dist/db/mock-storage.test.d.ts.map +1 -0
- package/dist/db/mock-storage.test.js +234 -0
- package/dist/db/mock-storage.test.js.map +1 -0
- package/dist/db/postgresql-storage.d.ts +10 -8
- package/dist/db/postgresql-storage.d.ts.map +1 -0
- package/dist/db/postgresql-storage.js +76 -42
- package/dist/db/postgresql-storage.js.map +1 -0
- package/dist/db/sqlite-storage.d.ts +9 -8
- package/dist/db/sqlite-storage.d.ts.map +1 -0
- package/dist/db/sqlite-storage.js +75 -41
- package/dist/db/sqlite-storage.js.map +1 -0
- package/dist/db/storage-base.d.ts +7 -8
- package/dist/db/storage-base.d.ts.map +1 -0
- package/dist/db/storage-base.js +3 -2
- package/dist/db/storage-base.js.map +1 -0
- package/dist/db/storage.d.ts +12 -12
- package/dist/db/storage.d.ts.map +1 -0
- package/dist/db/storage.js +1 -0
- package/dist/db/storage.js.map +1 -0
- package/dist/db/types.d.ts +67 -0
- package/dist/db/types.d.ts.map +1 -0
- package/dist/db/types.js +2 -0
- package/dist/db/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +397 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/index.test.js +49 -0
- package/dist/index.test.js.map +1 -0
- package/dist/lib/output.d.ts +2 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +8 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/services/cron-service.constraints.test.d.ts +2 -0
- package/dist/services/cron-service.constraints.test.d.ts.map +1 -0
- package/dist/services/cron-service.constraints.test.js +90 -0
- package/dist/services/cron-service.constraints.test.js.map +1 -0
- package/dist/services/cron-service.d.ts +45 -0
- package/dist/services/cron-service.d.ts.map +1 -0
- package/dist/services/cron-service.js +157 -0
- package/dist/services/cron-service.js.map +1 -0
- package/dist/services/cron-service.test.d.ts +2 -0
- package/dist/services/cron-service.test.d.ts.map +1 -0
- package/dist/services/cron-service.test.js +280 -0
- package/dist/services/cron-service.test.js.map +1 -0
- package/dist/services/index.d.ts +5 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +5 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/message-service.d.ts +16 -0
- package/dist/services/message-service.d.ts.map +1 -0
- package/dist/services/message-service.js +39 -0
- package/dist/services/message-service.js.map +1 -0
- package/dist/services/message-service.test.d.ts +2 -0
- package/dist/services/message-service.test.d.ts.map +1 -0
- package/dist/services/message-service.test.js +145 -0
- package/dist/services/message-service.test.js.map +1 -0
- package/dist/services/session-service.constraints.test.d.ts +2 -0
- package/dist/services/session-service.constraints.test.d.ts.map +1 -0
- package/dist/services/session-service.constraints.test.js +34 -0
- package/dist/services/session-service.constraints.test.js.map +1 -0
- package/dist/services/session-service.d.ts +27 -0
- package/dist/services/session-service.d.ts.map +1 -0
- package/dist/services/session-service.js +55 -0
- package/dist/services/session-service.js.map +1 -0
- package/dist/services/session-service.test.d.ts +2 -0
- package/dist/services/session-service.test.d.ts.map +1 -0
- package/dist/services/session-service.test.js +87 -0
- package/dist/services/session-service.test.js.map +1 -0
- package/dist/services/task-service.d.ts +25 -0
- package/dist/services/task-service.d.ts.map +1 -0
- package/dist/services/task-service.js +87 -0
- package/dist/services/task-service.js.map +1 -0
- package/dist/services/task-service.test.d.ts +2 -0
- package/dist/services/task-service.test.d.ts.map +1 -0
- package/dist/services/task-service.test.js +180 -0
- package/dist/services/task-service.test.js.map +1 -0
- package/package.json +41 -42
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -317
- package/dist/commands/communicator.d.ts +0 -9
- package/dist/commands/communicator.js +0 -2232
- package/dist/commands/manage.d.ts +0 -5
- package/dist/commands/manage.js +0 -20
- package/dist/commands/notifier.d.ts +0 -11
- package/dist/commands/notifier.js +0 -100
- package/dist/commands/screensaver.d.ts +0 -8
- package/dist/commands/screensaver.js +0 -1280
- package/dist/commands/serve.d.ts +0 -13
- package/dist/commands/serve.js +0 -95
- package/dist/commands/task-board.d.ts +0 -29
- package/dist/commands/task-board.js +0 -251
- package/dist/commands/worker.d.ts +0 -16
- package/dist/commands/worker.js +0 -145
- package/dist/db/migrate.d.ts +0 -2
- package/dist/db/migrate.js +0 -3
- package/dist/lib/agentic-coding-server.d.ts +0 -66
- package/dist/lib/agentic-coding-server.js +0 -7
- package/dist/lib/notifier.d.ts +0 -18
- package/dist/lib/notifier.js +0 -15
- package/dist/lib/opencode-coding-server.d.ts +0 -11
- package/dist/lib/opencode-coding-server.js +0 -66
- package/dist/lib/pi-coding-server.d.ts +0 -20
- package/dist/lib/pi-coding-server.js +0 -162
- package/dist/manage/app.d.ts +0 -6
- package/dist/manage/app.js +0 -128
- package/dist/manage/components/AgentCode.d.ts +0 -8
- package/dist/manage/components/AgentCode.js +0 -73
- package/dist/manage/components/CreateSession.d.ts +0 -8
- package/dist/manage/components/CreateSession.js +0 -37
- package/dist/manage/components/CronList.d.ts +0 -9
- package/dist/manage/components/CronList.js +0 -321
- package/dist/manage/components/CronRequests.d.ts +0 -8
- package/dist/manage/components/CronRequests.js +0 -181
- package/dist/manage/components/DeleteSession.d.ts +0 -7
- package/dist/manage/components/DeleteSession.js +0 -55
- package/dist/manage/components/InjectText.d.ts +0 -8
- package/dist/manage/components/InjectText.js +0 -51
- package/dist/manage/components/ItemSelector.d.ts +0 -7
- package/dist/manage/components/ItemSelector.js +0 -20
- package/dist/manage/components/MenuSelect.d.ts +0 -13
- package/dist/manage/components/MenuSelect.js +0 -22
- package/dist/manage/components/MyMail.d.ts +0 -9
- package/dist/manage/components/MyMail.js +0 -143
- package/dist/manage/components/Profile.d.ts +0 -8
- package/dist/manage/components/Profile.js +0 -60
- package/dist/manage/components/ReadMail.d.ts +0 -8
- package/dist/manage/components/ReadMail.js +0 -110
- package/dist/manage/components/SendMessage.d.ts +0 -9
- package/dist/manage/components/SendMessage.js +0 -79
- package/dist/manage/components/SessionList.d.ts +0 -9
- package/dist/manage/components/SessionList.js +0 -608
- package/dist/manage/components/SessionSidebar.d.ts +0 -6
- package/dist/manage/components/SessionSidebar.js +0 -24
- package/dist/manage/components/TailMessages.d.ts +0 -8
- package/dist/manage/components/TailMessages.js +0 -126
- package/dist/manage/hooks/useApi.d.ts +0 -147
- package/dist/manage/hooks/useApi.js +0 -181
- package/dist/server/cron.d.ts +0 -25
- package/dist/server/cron.js +0 -107
- package/dist/server/index.d.ts +0 -4
- package/dist/server/index.js +0 -22
- package/dist/server/routes.d.ts +0 -13
- package/dist/server/routes.js +0 -1396
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import { Box, Text, useInput } from "ink";
|
|
4
|
-
export function ItemSelector({ items, onSelect, onCancel }) {
|
|
5
|
-
const [cursor, setCursor] = useState(0);
|
|
6
|
-
useInput((_input, key) => {
|
|
7
|
-
if (key.upArrow)
|
|
8
|
-
setCursor((c) => Math.max(0, c - 1));
|
|
9
|
-
if (key.downArrow)
|
|
10
|
-
setCursor((c) => Math.min(items.length - 1, c + 1));
|
|
11
|
-
if (key.return && items[cursor] != null)
|
|
12
|
-
onSelect(items[cursor]);
|
|
13
|
-
if (key.escape)
|
|
14
|
-
onCancel?.();
|
|
15
|
-
});
|
|
16
|
-
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [items.map((item, i) => {
|
|
17
|
-
const sel = i === cursor;
|
|
18
|
-
return (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: sel ? "cyan" : undefined, bold: sel, children: sel ? "▶" : " " }), _jsx(Text, { color: sel ? "cyan" : undefined, bold: sel, children: item })] }, item));
|
|
19
|
-
}), _jsx(Text, { dimColor: true, children: "\u2191\u2193 navigate \u00B7 Enter select \u00B7 Esc cancel" })] }));
|
|
20
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export interface MenuOption {
|
|
2
|
-
label: string;
|
|
3
|
-
value: string;
|
|
4
|
-
hint?: string;
|
|
5
|
-
}
|
|
6
|
-
interface MenuSelectProps {
|
|
7
|
-
options: MenuOption[];
|
|
8
|
-
onChange: (value: string) => void;
|
|
9
|
-
/** Optional badge text shown next to a specific option value */
|
|
10
|
-
badges?: Record<string, string>;
|
|
11
|
-
}
|
|
12
|
-
export declare function MenuSelect({ options, onChange, badges }: MenuSelectProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
-
export {};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from "react";
|
|
3
|
-
import { Box, Text, useInput } from "ink";
|
|
4
|
-
export function MenuSelect({ options, onChange, badges = {} }) {
|
|
5
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
6
|
-
useInput((input, key) => {
|
|
7
|
-
if (key.upArrow) {
|
|
8
|
-
setSelectedIndex((i) => (i - 1 + options.length) % options.length);
|
|
9
|
-
}
|
|
10
|
-
if (key.downArrow) {
|
|
11
|
-
setSelectedIndex((i) => (i + 1) % options.length);
|
|
12
|
-
}
|
|
13
|
-
if (key.return) {
|
|
14
|
-
onChange(options[selectedIndex].value);
|
|
15
|
-
}
|
|
16
|
-
});
|
|
17
|
-
return (_jsx(Box, { flexDirection: "column", marginTop: 1, children: options.map((opt, i) => {
|
|
18
|
-
const isSelected = i === selectedIndex;
|
|
19
|
-
const badge = badges[opt.value];
|
|
20
|
-
return (_jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: isSelected ? "cyan" : undefined, bold: isSelected, children: isSelected ? "▶" : " " }), _jsx(Text, { color: isSelected ? "cyan" : undefined, bold: isSelected, children: opt.label }), badge ? (_jsx(Text, { color: "yellow", bold: true, children: badge })) : null] }, opt.value));
|
|
21
|
-
}) }));
|
|
22
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
interface MyMailProps {
|
|
2
|
-
serverUrl: string;
|
|
3
|
-
password: string;
|
|
4
|
-
onBack: () => void;
|
|
5
|
-
contentHeight: number;
|
|
6
|
-
onReply: (toName: string) => void;
|
|
7
|
-
}
|
|
8
|
-
export declare function MyMail({ serverUrl, password, onBack, contentHeight, onReply }: MyMailProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
-
export {};
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState, useRef } from "react";
|
|
3
|
-
import { Box, Text, useInput } from "ink";
|
|
4
|
-
import { Spinner } from "@inkjs/ui";
|
|
5
|
-
import { useApi } from "../hooks/useApi.js";
|
|
6
|
-
export function MyMail({ serverUrl, password, onBack, contentHeight, onReply }) {
|
|
7
|
-
const { getConfig, getMailMessages, markMessageRead } = useApi(serverUrl, password);
|
|
8
|
-
const [humanName, setHumanName] = useState("Human");
|
|
9
|
-
const [viewTab, setViewTab] = useState("received");
|
|
10
|
-
const [messages, setMessages] = useState([]);
|
|
11
|
-
const [error, setError] = useState(null);
|
|
12
|
-
const [selectedMsgIndex, setSelectedMsgIndex] = useState(0);
|
|
13
|
-
const [marking, setMarking] = useState(false);
|
|
14
|
-
const humanNameRef = useRef("Human");
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
getConfig().then((config) => {
|
|
17
|
-
const name = config.human_name ?? "Human";
|
|
18
|
-
setHumanName(name);
|
|
19
|
-
humanNameRef.current = name;
|
|
20
|
-
loadMessages(name, "received");
|
|
21
|
-
}).catch((err) => {
|
|
22
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
23
|
-
});
|
|
24
|
-
}, []);
|
|
25
|
-
const loadMessages = async (name, tab) => {
|
|
26
|
-
try {
|
|
27
|
-
const msgs = await getMailMessages(name, { sent: tab === "sent" });
|
|
28
|
-
setMessages(msgs);
|
|
29
|
-
setSelectedMsgIndex(0);
|
|
30
|
-
}
|
|
31
|
-
catch (err) {
|
|
32
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
const handleTabSwitch = (newTab) => {
|
|
36
|
-
setViewTab(newTab);
|
|
37
|
-
loadMessages(humanNameRef.current, newTab);
|
|
38
|
-
};
|
|
39
|
-
const handleMarkRead = async () => {
|
|
40
|
-
const msg = messages[selectedMsgIndex];
|
|
41
|
-
if (!msg || msg.read || viewTab !== "received")
|
|
42
|
-
return;
|
|
43
|
-
setMarking(true);
|
|
44
|
-
try {
|
|
45
|
-
await markMessageRead(msg.id);
|
|
46
|
-
setMessages((prev) => prev.map((m) => (m.id === msg.id ? { ...m, read: true } : m)));
|
|
47
|
-
}
|
|
48
|
-
catch (err) {
|
|
49
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
50
|
-
}
|
|
51
|
-
finally {
|
|
52
|
-
setMarking(false);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
const handleMarkAllRead = async () => {
|
|
56
|
-
if (viewTab !== "received")
|
|
57
|
-
return;
|
|
58
|
-
const unread = messages.filter((m) => !m.read);
|
|
59
|
-
if (unread.length === 0)
|
|
60
|
-
return;
|
|
61
|
-
setMarking(true);
|
|
62
|
-
try {
|
|
63
|
-
await Promise.all(unread.map((m) => markMessageRead(m.id)));
|
|
64
|
-
setMessages((prev) => prev.map((m) => ({ ...m, read: true })));
|
|
65
|
-
}
|
|
66
|
-
catch (err) {
|
|
67
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
68
|
-
}
|
|
69
|
-
finally {
|
|
70
|
-
setMarking(false);
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
useInput((input, key) => {
|
|
74
|
-
if (marking)
|
|
75
|
-
return;
|
|
76
|
-
if (key.upArrow) {
|
|
77
|
-
setSelectedMsgIndex((i) => Math.max(0, i - 1));
|
|
78
|
-
}
|
|
79
|
-
if (key.downArrow) {
|
|
80
|
-
setSelectedMsgIndex((i) => Math.min(messages.length - 1, i + 1));
|
|
81
|
-
}
|
|
82
|
-
if (input === "r") {
|
|
83
|
-
if (viewTab === "received") {
|
|
84
|
-
const msg = messages[selectedMsgIndex];
|
|
85
|
-
if (msg)
|
|
86
|
-
onReply(msg.from_name);
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
handleTabSwitch("received");
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (input === "m" && viewTab === "received") {
|
|
93
|
-
handleMarkRead();
|
|
94
|
-
}
|
|
95
|
-
if (input === "s" && viewTab !== "sent") {
|
|
96
|
-
handleTabSwitch("sent");
|
|
97
|
-
}
|
|
98
|
-
if (input === "a" && viewTab === "received") {
|
|
99
|
-
handleMarkAllRead();
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
const renderMessages = () => {
|
|
103
|
-
const viewHeight = contentHeight - 8;
|
|
104
|
-
if (messages.length === 0) {
|
|
105
|
-
return (_jsx(Box, { flexDirection: "column", height: viewHeight, children: _jsx(Text, { dimColor: true, children: "No messages." }) }));
|
|
106
|
-
}
|
|
107
|
-
const allLines = [];
|
|
108
|
-
const msgStartLine = [];
|
|
109
|
-
for (let mi = 0; mi < messages.length; mi++) {
|
|
110
|
-
const msg = messages[mi];
|
|
111
|
-
const isSelected = mi === selectedMsgIndex;
|
|
112
|
-
const timestamp = new Date(msg.created_at).toLocaleString();
|
|
113
|
-
const accentColor = isSelected ? "cyan" : "gray";
|
|
114
|
-
msgStartLine.push(allLines.length);
|
|
115
|
-
allLines.push({ text: isSelected ? "▶ ──────────────────────────" : " ──────────────────────────", color: accentColor, bold: isSelected, msgIndex: mi });
|
|
116
|
-
allLines.push({
|
|
117
|
-
text: ` ${msg.from_name} → ${msg.to_name}`,
|
|
118
|
-
color: isSelected ? "cyan" : undefined,
|
|
119
|
-
bold: isSelected,
|
|
120
|
-
msgIndex: mi,
|
|
121
|
-
});
|
|
122
|
-
allLines.push({ text: ` ${timestamp}`, color: "gray", msgIndex: mi });
|
|
123
|
-
if (!msg.read) {
|
|
124
|
-
allLines.push({ text: " [unread]", color: "yellow", bold: true, msgIndex: mi });
|
|
125
|
-
}
|
|
126
|
-
allLines.push({ text: "", msgIndex: mi });
|
|
127
|
-
for (const line of msg.body.split("\n")) {
|
|
128
|
-
allLines.push({ text: ` ${line}`, msgIndex: mi });
|
|
129
|
-
}
|
|
130
|
-
allLines.push({ text: "", msgIndex: mi });
|
|
131
|
-
}
|
|
132
|
-
// Auto-scroll: keep selected message's first line in view
|
|
133
|
-
const selStart = msgStartLine[selectedMsgIndex] ?? 0;
|
|
134
|
-
const maxOffset = Math.max(0, allLines.length - viewHeight);
|
|
135
|
-
// Prefer showing the selected message near the top, but clamp to bounds
|
|
136
|
-
const rawOffset = Math.max(0, selStart - 1);
|
|
137
|
-
const scrollOffset = Math.min(rawOffset, maxOffset);
|
|
138
|
-
const visible = allLines.slice(scrollOffset, scrollOffset + viewHeight);
|
|
139
|
-
return (_jsx(Box, { flexDirection: "column", height: viewHeight, overflow: "hidden", children: visible.map((line, i) => (_jsx(Text, { color: line.color, bold: line.bold, children: line.text }, i))) }));
|
|
140
|
-
};
|
|
141
|
-
const unreadCount = messages.filter((m) => !m.read).length;
|
|
142
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 0, children: [_jsxs(Box, { gap: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, children: "My Mail" }), _jsx(Text, { color: "cyan", children: humanName }), _jsxs(Text, { dimColor: true, children: ["(", messages.length, " ", viewTab] }), viewTab === "received" && unreadCount > 0 && (_jsxs(Text, { color: "yellow", bold: true, children: ["\u00B7 ", unreadCount, " unread"] })), _jsx(Text, { dimColor: true, children: ")" }), marking && _jsx(Spinner, { label: "saving..." })] }), _jsxs(Box, { gap: 2, marginBottom: 1, children: [viewTab === "received" ? (_jsx(Text, { bold: true, color: "green", children: "[Received]" })) : (_jsx(Text, { dimColor: true, children: "Received (press r)" })), viewTab === "sent" ? (_jsx(Text, { bold: true, color: "yellow", children: "[Sent]" })) : (_jsx(Text, { dimColor: true, children: "Sent (s)" }))] }), error ? (_jsx(Text, { color: "red", children: error })) : (renderMessages())] }));
|
|
143
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
interface ProfileProps {
|
|
2
|
-
serverUrl: string;
|
|
3
|
-
password: string;
|
|
4
|
-
onBack: () => void;
|
|
5
|
-
contentHeight: number;
|
|
6
|
-
}
|
|
7
|
-
export declare function Profile({ serverUrl, password, onBack, contentHeight }: ProfileProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
-
export {};
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
import { Spinner, TextInput } from "@inkjs/ui";
|
|
5
|
-
import { useApi } from "../hooks/useApi.js";
|
|
6
|
-
export function Profile({ serverUrl, password, onBack, contentHeight }) {
|
|
7
|
-
const { getConfig, setConfig } = useApi(serverUrl, password);
|
|
8
|
-
const [name, setName] = useState("");
|
|
9
|
-
const [description, setDescription] = useState("");
|
|
10
|
-
const [stage, setStage] = useState("loading");
|
|
11
|
-
const [error, setError] = useState(null);
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
getConfig()
|
|
14
|
-
.then((config) => {
|
|
15
|
-
setName(config.human_name ?? "Human");
|
|
16
|
-
setDescription(config.human_description ?? "");
|
|
17
|
-
setStage("editing-name");
|
|
18
|
-
})
|
|
19
|
-
.catch((err) => {
|
|
20
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
21
|
-
setStage("error");
|
|
22
|
-
});
|
|
23
|
-
}, []);
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
if (stage === "done" || stage === "error") {
|
|
26
|
-
const timer = setTimeout(onBack, 1500);
|
|
27
|
-
return () => clearTimeout(timer);
|
|
28
|
-
}
|
|
29
|
-
}, [stage, onBack]);
|
|
30
|
-
const handleNameSubmit = (newName) => {
|
|
31
|
-
setName(newName);
|
|
32
|
-
setStage("editing-description");
|
|
33
|
-
};
|
|
34
|
-
const handleDescriptionSubmit = async (newDesc) => {
|
|
35
|
-
setDescription(newDesc);
|
|
36
|
-
setStage("saving");
|
|
37
|
-
try {
|
|
38
|
-
await setConfig("human_name", name);
|
|
39
|
-
await setConfig("human_description", newDesc);
|
|
40
|
-
setStage("done");
|
|
41
|
-
}
|
|
42
|
-
catch (err) {
|
|
43
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
44
|
-
setStage("error");
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
if (stage === "loading") {
|
|
48
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Loading profile..." }) }));
|
|
49
|
-
}
|
|
50
|
-
if (stage === "error") {
|
|
51
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "My Profile" }), _jsxs(Text, { color: "red", children: ["Error: ", error] }), _jsx(Text, { dimColor: true, children: "Returning to menu..." })] }));
|
|
52
|
-
}
|
|
53
|
-
if (stage === "saving") {
|
|
54
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Saving profile..." }) }));
|
|
55
|
-
}
|
|
56
|
-
if (stage === "done") {
|
|
57
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "My Profile" }), _jsx(Text, { color: "green", children: "Profile saved successfully!" }), _jsx(Text, { dimColor: true, children: "Returning to menu..." })] }));
|
|
58
|
-
}
|
|
59
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "My Profile" }), _jsx(Text, { dimColor: true, children: "Configure your name and description (visible to agents)" }), _jsxs(Box, { flexDirection: "column", gap: 1, marginTop: 1, children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { bold: true, children: "Name:" }), stage === "editing-name" ? (_jsx(TextInput, { placeholder: name || "Your name", onSubmit: handleNameSubmit })) : (_jsx(Text, { color: "cyan", children: name }))] }), stage === "editing-description" && (_jsxs(Box, { gap: 1, children: [_jsx(Text, { bold: true, children: "Description:" }), _jsx(TextInput, { placeholder: description || "Optional description", onSubmit: handleDescriptionSubmit })] }))] }), stage === "editing-name" && (_jsx(Text, { dimColor: true, children: "Enter to continue \u00B7 Esc to cancel" })), stage === "editing-description" && (_jsx(Text, { dimColor: true, children: "Enter to save \u00B7 Esc to cancel" }))] }));
|
|
60
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
interface ReadMailProps {
|
|
2
|
-
serverUrl: string;
|
|
3
|
-
password: string;
|
|
4
|
-
onBack: () => void;
|
|
5
|
-
contentHeight: number;
|
|
6
|
-
}
|
|
7
|
-
export declare function ReadMail({ serverUrl, password, onBack, contentHeight }: ReadMailProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
-
export {};
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
|
-
import { Box, Text, useInput } from "ink";
|
|
4
|
-
import { Select, Spinner } from "@inkjs/ui";
|
|
5
|
-
import { useApi, useAsyncState } from "../hooks/useApi.js";
|
|
6
|
-
export function ReadMail({ serverUrl, password, onBack, contentHeight }) {
|
|
7
|
-
const { listSessions, getMailMessages, markMessageRead } = 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-session");
|
|
12
|
-
const [selectedName, setSelectedName] = useState(null);
|
|
13
|
-
const [viewTab, setViewTab] = useState("received");
|
|
14
|
-
const [messages, setMessages] = useState([]);
|
|
15
|
-
const [error, setError] = useState(null);
|
|
16
|
-
const [scrollOffset, setScrollOffset] = useState(0);
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
runList(listSessions).then((rows) => {
|
|
19
|
-
setSessions(rows ?? []);
|
|
20
|
-
setSessionsLoading(false);
|
|
21
|
-
});
|
|
22
|
-
}, []);
|
|
23
|
-
const loadMessages = async (name) => {
|
|
24
|
-
setSelectedName(name);
|
|
25
|
-
setStage("loading");
|
|
26
|
-
try {
|
|
27
|
-
const msgs = await getMailMessages(name, { sent: false });
|
|
28
|
-
setMessages(msgs);
|
|
29
|
-
setScrollOffset(0);
|
|
30
|
-
setStage("view-received");
|
|
31
|
-
}
|
|
32
|
-
catch (err) {
|
|
33
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
34
|
-
setStage("error");
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
const handleTabSwitch = async (newTab) => {
|
|
38
|
-
if (!selectedName)
|
|
39
|
-
return;
|
|
40
|
-
setStage("loading");
|
|
41
|
-
setViewTab(newTab);
|
|
42
|
-
setScrollOffset(0);
|
|
43
|
-
try {
|
|
44
|
-
const msgs = await getMailMessages(selectedName, { sent: newTab === "sent" });
|
|
45
|
-
setMessages(msgs);
|
|
46
|
-
setStage(newTab === "sent" ? "view-sent" : "view-received");
|
|
47
|
-
}
|
|
48
|
-
catch (err) {
|
|
49
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
50
|
-
setStage("error");
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
useInput((input, key) => {
|
|
54
|
-
if ((stage === "view-received" || stage === "view-sent")) {
|
|
55
|
-
if (key.upArrow)
|
|
56
|
-
setScrollOffset((o) => Math.max(0, o - 1));
|
|
57
|
-
if (key.downArrow)
|
|
58
|
-
setScrollOffset((o) => o + 1);
|
|
59
|
-
if (input === "r" && stage === "view-received") {
|
|
60
|
-
handleTabSwitch("received");
|
|
61
|
-
}
|
|
62
|
-
if (input === "s" && stage === "view-received") {
|
|
63
|
-
handleTabSwitch("sent");
|
|
64
|
-
}
|
|
65
|
-
if (input === "r" && stage === "view-sent") {
|
|
66
|
-
handleTabSwitch("received");
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
if (sessionsLoading) {
|
|
71
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Loading sessions..." }) }));
|
|
72
|
-
}
|
|
73
|
-
if (stage === "select-session") {
|
|
74
|
-
if (sessions.length === 0) {
|
|
75
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Text, { dimColor: true, children: "No sessions yet. Create one first." }) }));
|
|
76
|
-
}
|
|
77
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Coworker Mail" }), _jsx(Text, { dimColor: true, children: "Select a session:" }), _jsx(Select, { options: sessions.map((s) => ({ label: s.name, value: s.name })), onChange: loadMessages })] }));
|
|
78
|
-
}
|
|
79
|
-
if (stage === "loading") {
|
|
80
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: `Loading ${viewTab} messages...` }) }));
|
|
81
|
-
}
|
|
82
|
-
if (stage === "error") {
|
|
83
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Coworker Mail" }), _jsxs(Text, { color: "red", children: ["Error: ", error] })] }));
|
|
84
|
-
}
|
|
85
|
-
const renderMessages = () => {
|
|
86
|
-
if (messages.length === 0) {
|
|
87
|
-
return (_jsx(Box, { height: contentHeight - 6, alignItems: "center", justifyContent: "center", children: _jsxs(Text, { dimColor: true, children: ["No ", viewTab, " messages."] }) }));
|
|
88
|
-
}
|
|
89
|
-
const lines = [];
|
|
90
|
-
const maxNameLen = Math.max(...messages.map((m) => m.from_name.length));
|
|
91
|
-
for (const msg of messages) {
|
|
92
|
-
const timestamp = new Date(msg.created_at).toLocaleString();
|
|
93
|
-
lines.push({ text: `─`, color: "gray" });
|
|
94
|
-
lines.push({ text: `${msg.from_name.padEnd(maxNameLen)} → ${msg.to_name}`, color: "cyan" });
|
|
95
|
-
lines.push({ text: `${timestamp}`, color: "gray" });
|
|
96
|
-
lines.push({ text: msg.read ? "" : " [unread]" });
|
|
97
|
-
lines.push({ text: "" });
|
|
98
|
-
for (const line of msg.body.split("\n")) {
|
|
99
|
-
lines.push({ text: ` ${line}` });
|
|
100
|
-
}
|
|
101
|
-
lines.push({ text: "" });
|
|
102
|
-
}
|
|
103
|
-
const viewHeight = contentHeight - 6;
|
|
104
|
-
const maxOffset = Math.max(0, lines.length - viewHeight);
|
|
105
|
-
const clampedOffset = Math.min(scrollOffset, maxOffset);
|
|
106
|
-
const visible = lines.slice(clampedOffset, clampedOffset + viewHeight);
|
|
107
|
-
return (_jsx(Box, { flexDirection: "column", height: viewHeight, overflow: "hidden", children: visible.map((line, i) => (_jsx(Text, { color: line.color, children: line.text }, i))) }));
|
|
108
|
-
};
|
|
109
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 0, children: [_jsxs(Box, { gap: 2, marginBottom: 1, children: [_jsx(Text, { bold: true, children: "Coworker Mail" }), _jsx(Text, { color: "cyan", children: selectedName }), _jsxs(Text, { dimColor: true, children: ["(", messages.length, " ", viewTab, " messages)"] })] }), _jsxs(Box, { gap: 2, marginBottom: 1, children: [viewTab === "received" ? (_jsx(Text, { bold: true, color: "green", children: "[Received]" })) : (_jsx(Text, { dimColor: true, children: "Received (press r)" })), viewTab === "sent" ? (_jsx(Text, { bold: true, color: "yellow", children: "[Sent]" })) : (_jsx(Text, { dimColor: true, children: "Sent (press s)" }))] }), renderMessages()] }));
|
|
110
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
interface SendMessageProps {
|
|
2
|
-
serverUrl: string;
|
|
3
|
-
password: string;
|
|
4
|
-
onBack: () => void;
|
|
5
|
-
contentHeight: number;
|
|
6
|
-
initialRecipient?: string;
|
|
7
|
-
}
|
|
8
|
-
export declare function SendMessage({ serverUrl, password, onBack, contentHeight, initialRecipient }: SendMessageProps): import("react/jsx-runtime").JSX.Element | null;
|
|
9
|
-
export {};
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
import { Spinner, TextInput } from "@inkjs/ui";
|
|
5
|
-
import { ItemSelector } from "./ItemSelector.js";
|
|
6
|
-
import { useApi, useAsyncState } from "../hooks/useApi.js";
|
|
7
|
-
export function SendMessage({ serverUrl, password, onBack, contentHeight, initialRecipient }) {
|
|
8
|
-
const { listSessions, sendMailMessage, getConfig } = useApi(serverUrl, password);
|
|
9
|
-
const { run: runList } = useAsyncState();
|
|
10
|
-
const [sessions, setSessions] = useState([]);
|
|
11
|
-
const [sessionsLoading, setSessionsLoading] = useState(!initialRecipient);
|
|
12
|
-
const [stage, setStage] = useState(initialRecipient ? "enter-body" : "select-recipients");
|
|
13
|
-
const [recipients, setRecipients] = useState(initialRecipient ? [initialRecipient] : []);
|
|
14
|
-
const [messageBody, setMessageBody] = useState("");
|
|
15
|
-
const [error, setError] = useState(null);
|
|
16
|
-
const [submitted, setSubmitted] = useState(false);
|
|
17
|
-
const [senderName, setSenderName] = useState("Human");
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
getConfig().then((config) => {
|
|
20
|
-
setSenderName(config.human_name ?? "Human");
|
|
21
|
-
});
|
|
22
|
-
}, [getConfig]);
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
if (initialRecipient)
|
|
25
|
-
return; // no need to load sessions list when replying
|
|
26
|
-
runList(listSessions).then((rows) => {
|
|
27
|
-
setSessions(rows ?? []);
|
|
28
|
-
setSessionsLoading(false);
|
|
29
|
-
});
|
|
30
|
-
}, []);
|
|
31
|
-
useEffect(() => {
|
|
32
|
-
if (stage === "done" || stage === "error") {
|
|
33
|
-
const timer = setTimeout(onBack, 1500);
|
|
34
|
-
return () => clearTimeout(timer);
|
|
35
|
-
}
|
|
36
|
-
}, [stage, onBack]);
|
|
37
|
-
const handleRecipientSelect = (value) => {
|
|
38
|
-
setRecipients([value]);
|
|
39
|
-
setStage("enter-body");
|
|
40
|
-
};
|
|
41
|
-
const handleBodySubmit = async (body) => {
|
|
42
|
-
const trimmed = body.trim();
|
|
43
|
-
if (!trimmed || recipients.length === 0)
|
|
44
|
-
return;
|
|
45
|
-
setSubmitted(true);
|
|
46
|
-
setMessageBody(trimmed);
|
|
47
|
-
setStage("sending");
|
|
48
|
-
try {
|
|
49
|
-
await sendMailMessage(senderName, recipients, trimmed);
|
|
50
|
-
setStage("done");
|
|
51
|
-
}
|
|
52
|
-
catch (err) {
|
|
53
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
54
|
-
setStage("error");
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
if (sessionsLoading) {
|
|
58
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Loading sessions..." }) }));
|
|
59
|
-
}
|
|
60
|
-
if (stage === "select-recipients") {
|
|
61
|
-
if (sessions.length === 0) {
|
|
62
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Text, { dimColor: true, children: "No sessions yet. Create one first." }) }));
|
|
63
|
-
}
|
|
64
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Send Message" }), _jsx(Text, { dimColor: true, children: "Select a recipient agent:" }), _jsx(ItemSelector, { items: sessions.map((s) => s.name), onSelect: handleRecipientSelect, onCancel: onBack })] }));
|
|
65
|
-
}
|
|
66
|
-
if (stage === "enter-body" && !submitted) {
|
|
67
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Send Message" }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "From: " }), _jsx(Text, { color: "cyan", children: senderName })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "To: " }), _jsx(Text, { color: "cyan", children: recipients[0] })] }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Body: " }), _jsx(TextInput, { placeholder: "Type your message...", onSubmit: handleBodySubmit })] })] }));
|
|
68
|
-
}
|
|
69
|
-
if (stage === "sending") {
|
|
70
|
-
return (_jsx(Spinner, { label: "Sending message..." }));
|
|
71
|
-
}
|
|
72
|
-
if (stage === "done") {
|
|
73
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Send Message" }), _jsx(Text, { color: "green", children: "Message sent!" }), _jsx(Text, { dimColor: true, children: "Returning to menu..." })] }));
|
|
74
|
-
}
|
|
75
|
-
if (stage === "error") {
|
|
76
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Send Message" }), _jsxs(Text, { color: "red", children: ["Error: ", error] }), _jsx(Text, { dimColor: true, children: "Returning to menu..." })] }));
|
|
77
|
-
}
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
interface SessionListProps {
|
|
2
|
-
serverUrl: string;
|
|
3
|
-
password: string;
|
|
4
|
-
onBack: () => void;
|
|
5
|
-
contentHeight: number;
|
|
6
|
-
onSubViewChange?: (active: boolean) => void;
|
|
7
|
-
}
|
|
8
|
-
export declare function SessionList({ serverUrl, password, contentHeight, onSubViewChange }: SessionListProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
-
export {};
|