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.
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 +41 -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 -2232
  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,7 +0,0 @@
1
- interface ItemSelectorProps {
2
- items: string[];
3
- onSelect: (value: string) => void;
4
- onCancel?: () => void;
5
- }
6
- export declare function ItemSelector({ items, onSelect, onCancel }: ItemSelectorProps): import("react/jsx-runtime").JSX.Element;
7
- export {};
@@ -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 {};