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.
- 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 +40 -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 -2231
- 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,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Concrete AgenticCodingServer backed by an OpenCode server
|
|
3
|
-
* via the @opencode-ai/sdk.
|
|
4
|
-
*/
|
|
5
|
-
import { createOpencodeClient } from "@opencode-ai/sdk";
|
|
6
|
-
export class OpenCodeCodingServer {
|
|
7
|
-
client;
|
|
8
|
-
baseURL;
|
|
9
|
-
constructor(opencodeUrl) {
|
|
10
|
-
this.baseURL = opencodeUrl;
|
|
11
|
-
this.client = createOpencodeClient({
|
|
12
|
-
baseUrl: opencodeUrl,
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
async createSession(title) {
|
|
16
|
-
if (!this.client)
|
|
17
|
-
throw new Error("Internal error: OpenCode client not initialized");
|
|
18
|
-
const { data: session } = await this.client.session.create({ title });
|
|
19
|
-
if (!session)
|
|
20
|
-
throw new Error("OpenCode returned no session");
|
|
21
|
-
return session.id;
|
|
22
|
-
}
|
|
23
|
-
async deleteSession(sessionID) {
|
|
24
|
-
if (!this.client)
|
|
25
|
-
throw new Error("Internal error: OpenCode client not initialized");
|
|
26
|
-
await this.client.session.delete({ path: { id: sessionID } });
|
|
27
|
-
}
|
|
28
|
-
async sendMessage(sessionID, text, agent, system) {
|
|
29
|
-
if (!this.client)
|
|
30
|
-
throw new Error("Internal error: OpenCode client not initialized");
|
|
31
|
-
await this.client.session.promptAsync({
|
|
32
|
-
path: { id: sessionID },
|
|
33
|
-
body: {
|
|
34
|
-
parts: [{ type: "text", text }],
|
|
35
|
-
agent,
|
|
36
|
-
system,
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
async getMessages(sessionID, limit) {
|
|
41
|
-
if (!this.client)
|
|
42
|
-
throw new Error("Internal error: OpenCode client not initialized");
|
|
43
|
-
const { data: messages } = await this.client.session.messages({
|
|
44
|
-
path: { id: sessionID },
|
|
45
|
-
...(limit != null ? { query: { limit } } : {}),
|
|
46
|
-
});
|
|
47
|
-
return (messages ?? []).map((m) => ({
|
|
48
|
-
id: m.info.id,
|
|
49
|
-
role: m.info.role,
|
|
50
|
-
parts: m.parts,
|
|
51
|
-
}));
|
|
52
|
-
}
|
|
53
|
-
async getAgentModes() {
|
|
54
|
-
if (!this.client)
|
|
55
|
-
throw new Error("Internal error: OpenCode client not initialized");
|
|
56
|
-
const { data: config } = await this.client.config.get();
|
|
57
|
-
const agent = config?.agent ?? {};
|
|
58
|
-
return Object.entries(agent)
|
|
59
|
-
.filter(([, val]) => val != null)
|
|
60
|
-
.map(([name, val]) => ({
|
|
61
|
-
name,
|
|
62
|
-
description: val.description ?? "",
|
|
63
|
-
model: val.model ?? "",
|
|
64
|
-
}));
|
|
65
|
-
}
|
|
66
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { AgenticCodingServer, SessionMessage, AgentMode } from "./agentic-coding-server.js";
|
|
2
|
-
export declare class PiCodingServer implements AgenticCodingServer {
|
|
3
|
-
private sessions;
|
|
4
|
-
private authStorage;
|
|
5
|
-
private modelRegistry;
|
|
6
|
-
private selectedModel;
|
|
7
|
-
private vendor;
|
|
8
|
-
private modelName;
|
|
9
|
-
constructor(vendor: string, model: string, apiKey: string);
|
|
10
|
-
/** Shared creation logic (no duplication) */
|
|
11
|
-
private createSessionInternal;
|
|
12
|
-
/** Fallback helper: returns cached session OR creates new one with the exact provided ID */
|
|
13
|
-
private ensureSession;
|
|
14
|
-
createSession(_title: string): Promise<string>;
|
|
15
|
-
deleteSession(sessionID: string): Promise<void>;
|
|
16
|
-
sendMessage(sessionID: string, text: string, agent: string, system: string): Promise<void>;
|
|
17
|
-
getMessages(sessionID: string, limit?: number): Promise<SessionMessage[]>;
|
|
18
|
-
revertSession(sessionID: string, messageID: string): Promise<void>;
|
|
19
|
-
getAgentModes(): Promise<AgentMode[]>;
|
|
20
|
-
}
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { createAgentSession, SessionManager, AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
import { getModel } from "@mariozechner/pi-ai";
|
|
3
|
-
import crypto from "crypto";
|
|
4
|
-
import path from "path";
|
|
5
|
-
import fs from "fs/promises";
|
|
6
|
-
export class PiCodingServer {
|
|
7
|
-
sessions = new Map();
|
|
8
|
-
authStorage;
|
|
9
|
-
modelRegistry;
|
|
10
|
-
selectedModel;
|
|
11
|
-
vendor;
|
|
12
|
-
modelName;
|
|
13
|
-
constructor(vendor, model, apiKey) {
|
|
14
|
-
if (!vendor || !model || !apiKey?.trim()) {
|
|
15
|
-
throw new Error("vendor, model, and apiKey are all required and must not be empty");
|
|
16
|
-
}
|
|
17
|
-
this.vendor = vendor.trim().toLowerCase();
|
|
18
|
-
this.modelName = model.trim();
|
|
19
|
-
this.authStorage = AuthStorage.create();
|
|
20
|
-
this.authStorage.setRuntimeApiKey(this.vendor, apiKey);
|
|
21
|
-
this.modelRegistry = new ModelRegistry(this.authStorage);
|
|
22
|
-
this.selectedModel = getModel(this.vendor, this.modelName);
|
|
23
|
-
if (!this.selectedModel) {
|
|
24
|
-
throw new Error(`Model '${this.modelName}' not found for provider '${this.vendor}'. ` +
|
|
25
|
-
`Check spelling or run 'pi /model' in a terminal.`);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
/** Shared creation logic (no duplication) */
|
|
29
|
-
async createSessionInternal(sessionID) {
|
|
30
|
-
const workspace = path.join(process.cwd(), "workspaces", sessionID);
|
|
31
|
-
await fs.mkdir(workspace, { recursive: true });
|
|
32
|
-
const sessionManager = SessionManager.create(workspace);
|
|
33
|
-
const { session } = await createAgentSession({
|
|
34
|
-
cwd: workspace,
|
|
35
|
-
model: this.selectedModel,
|
|
36
|
-
thinkingLevel: "medium",
|
|
37
|
-
sessionManager,
|
|
38
|
-
authStorage: this.authStorage,
|
|
39
|
-
modelRegistry: this.modelRegistry,
|
|
40
|
-
});
|
|
41
|
-
return session;
|
|
42
|
-
}
|
|
43
|
-
/** Fallback helper: returns cached session OR creates new one with the exact provided ID */
|
|
44
|
-
async ensureSession(sessionID) {
|
|
45
|
-
let session = this.sessions.get(sessionID);
|
|
46
|
-
if (!session) {
|
|
47
|
-
session = await this.createSessionInternal(sessionID);
|
|
48
|
-
this.sessions.set(sessionID, session);
|
|
49
|
-
}
|
|
50
|
-
return session;
|
|
51
|
-
}
|
|
52
|
-
async createSession(_title) {
|
|
53
|
-
const sessionID = crypto.randomUUID();
|
|
54
|
-
const session = await this.createSessionInternal(sessionID);
|
|
55
|
-
this.sessions.set(sessionID, session);
|
|
56
|
-
return sessionID;
|
|
57
|
-
}
|
|
58
|
-
async deleteSession(sessionID) {
|
|
59
|
-
const session = this.sessions.get(sessionID);
|
|
60
|
-
if (session) {
|
|
61
|
-
session.dispose?.();
|
|
62
|
-
this.sessions.delete(sessionID);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
async sendMessage(sessionID, text, agent, system) {
|
|
66
|
-
const session = await this.ensureSession(sessionID);
|
|
67
|
-
const prefix = agent ? `[Message from coworker ${agent}]: ` : "";
|
|
68
|
-
const message = `${prefix}${text}`;
|
|
69
|
-
// Set the system prompt if provided
|
|
70
|
-
if (system && system.trim()) {
|
|
71
|
-
session.agent.setSystemPrompt(system);
|
|
72
|
-
}
|
|
73
|
-
// Create a promise that resolves when the agent finishes processing
|
|
74
|
-
const completionPromise = new Promise((resolve) => {
|
|
75
|
-
const unsubscribe = session.subscribe((event) => {
|
|
76
|
-
if (event.type === "agent_end") {
|
|
77
|
-
unsubscribe();
|
|
78
|
-
resolve();
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
// Timeout after 5 minutes in case agent never finishes
|
|
82
|
-
setTimeout(() => {
|
|
83
|
-
unsubscribe();
|
|
84
|
-
resolve();
|
|
85
|
-
}, 5 * 60 * 1000);
|
|
86
|
-
});
|
|
87
|
-
// Send the prompt
|
|
88
|
-
await session.prompt(message);
|
|
89
|
-
// Wait for processing to complete
|
|
90
|
-
await completionPromise;
|
|
91
|
-
}
|
|
92
|
-
async getMessages(sessionID, limit = 100) {
|
|
93
|
-
const session = await this.ensureSession(sessionID);
|
|
94
|
-
const msgs = session.messages || [];
|
|
95
|
-
return msgs.slice(-limit).map((m) => {
|
|
96
|
-
let role = "assistant";
|
|
97
|
-
let parts = [];
|
|
98
|
-
if (m.role === "user") {
|
|
99
|
-
role = "user";
|
|
100
|
-
// User message content can be string or array
|
|
101
|
-
if (typeof m.content === "string") {
|
|
102
|
-
parts = [{ type: "text", text: m.content }];
|
|
103
|
-
}
|
|
104
|
-
else if (Array.isArray(m.content)) {
|
|
105
|
-
parts = m.content.map((c) => {
|
|
106
|
-
if (c.type === "text")
|
|
107
|
-
return { type: "text", text: c.text };
|
|
108
|
-
return { type: c.type || "text", text: JSON.stringify(c) };
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
parts = [{ type: "text", text: JSON.stringify(m.content) }];
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
else if (m.role === "assistant") {
|
|
116
|
-
role = "assistant";
|
|
117
|
-
// Assistant message content is always an array of TextContent | ThinkingContent | ToolCall
|
|
118
|
-
if (Array.isArray(m.content)) {
|
|
119
|
-
parts = m.content.map((c) => {
|
|
120
|
-
if (c.type === "text")
|
|
121
|
-
return { type: "text", text: c.text };
|
|
122
|
-
if (c.type === "thinking")
|
|
123
|
-
return { type: "thinking", text: c.thinking };
|
|
124
|
-
if (c.type === "toolCall")
|
|
125
|
-
return { type: "toolCall", text: `[Tool: ${c.name}]` };
|
|
126
|
-
return { type: c.type || "text", text: JSON.stringify(c) };
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
else if (typeof m.content === "string") {
|
|
130
|
-
parts = [{ type: "text", text: m.content }];
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
// toolResult or other custom types
|
|
135
|
-
parts = [{ type: "text", text: JSON.stringify(m.content) }];
|
|
136
|
-
}
|
|
137
|
-
return {
|
|
138
|
-
id: m.id || m.entryId || crypto.randomUUID(),
|
|
139
|
-
role,
|
|
140
|
-
parts,
|
|
141
|
-
};
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
async revertSession(sessionID, messageID) {
|
|
145
|
-
const session = await this.ensureSession(sessionID);
|
|
146
|
-
try {
|
|
147
|
-
await session.navigateTree(messageID, { summarize: true });
|
|
148
|
-
}
|
|
149
|
-
catch (err) {
|
|
150
|
-
// Graceful: new/empty sessions can't revert → still succeed the call
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
async getAgentModes() {
|
|
154
|
-
return [
|
|
155
|
-
{
|
|
156
|
-
name: "coworker",
|
|
157
|
-
description: `${this.vendor.toUpperCase()} ${this.modelName} – fast agentic coding coworker`,
|
|
158
|
-
model: this.modelName,
|
|
159
|
-
},
|
|
160
|
-
];
|
|
161
|
-
}
|
|
162
|
-
}
|
package/dist/manage/app.d.ts
DELETED
package/dist/manage/app.js
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useEffect, useRef } from "react";
|
|
3
|
-
import { Box, Text, useApp, useStdout, useInput } from "ink";
|
|
4
|
-
import { Spinner } from "@inkjs/ui";
|
|
5
|
-
import { useApi } from "./hooks/useApi.js";
|
|
6
|
-
import { SessionList } from "./components/SessionList.js";
|
|
7
|
-
import { SendMessage } from "./components/SendMessage.js";
|
|
8
|
-
import { Profile } from "./components/Profile.js";
|
|
9
|
-
import { MyMail } from "./components/MyMail.js";
|
|
10
|
-
import { SessionSidebar } from "./components/SessionSidebar.js";
|
|
11
|
-
import { MenuSelect } from "./components/MenuSelect.js";
|
|
12
|
-
import { CronList } from "./components/CronList.js";
|
|
13
|
-
import { CronRequests } from "./components/CronRequests.js";
|
|
14
|
-
const MENU_OPTIONS = [
|
|
15
|
-
{ label: "Send message", value: "send-message" },
|
|
16
|
-
{ label: "My mail", value: "my-mail" },
|
|
17
|
-
{ label: "Coworkers", value: "list" },
|
|
18
|
-
{ label: "Cron jobs", value: "cron" },
|
|
19
|
-
{ label: "Cron requests", value: "cron-requests" },
|
|
20
|
-
{ label: "My profile", value: "profile" },
|
|
21
|
-
{ label: "Quit", value: "quit" },
|
|
22
|
-
];
|
|
23
|
-
const SUB_SCREENS = ["list", "send-message", "my-mail", "profile", "cron", "cron-requests"];
|
|
24
|
-
const FOOTER_HINTS = {
|
|
25
|
-
connecting: "",
|
|
26
|
-
"auth-error": "",
|
|
27
|
-
menu: "↑↓ navigate · Enter select · q quit",
|
|
28
|
-
list: "↑↓ navigate · c create · d delete · r reveal code · g regen · x revert · X revert-all · t tail · i inject · m mail · M memories · Esc back",
|
|
29
|
-
"send-message": "Enter submit · Esc back to menu",
|
|
30
|
-
"my-mail": "↑↓ select message · r reply · m mark read · a mark all read · s sent tab · Esc back",
|
|
31
|
-
"profile": "Enter submit · Esc back to menu",
|
|
32
|
-
cron: "↑↓ navigate · c create · d delete · e enable/disable · h history · Esc back",
|
|
33
|
-
"cron-requests": "↑↓ navigate · a approve · r reject · v view · f filter · Esc back",
|
|
34
|
-
};
|
|
35
|
-
function Header({ serverUrl, unreadCount }) {
|
|
36
|
-
return (_jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, justifyContent: "space-between", children: [_jsx(Text, { bold: true, color: "cyan", children: "agent-office" }), _jsxs(Box, { gap: 2, children: [unreadCount > 0 && (_jsxs(Text, { color: "yellow", bold: true, children: ["\u2709 ", unreadCount, " unread"] })), _jsx(Text, { dimColor: true, children: serverUrl })] })] }));
|
|
37
|
-
}
|
|
38
|
-
function Footer({ hint }) {
|
|
39
|
-
return (_jsx(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, children: _jsx(Text, { dimColor: true, children: hint }) }));
|
|
40
|
-
}
|
|
41
|
-
export function App({ serverUrl, password }) {
|
|
42
|
-
const { exit } = useApp();
|
|
43
|
-
const { stdout } = useStdout();
|
|
44
|
-
const { checkHealth, getConfig, getMailMessages } = useApi(serverUrl, password);
|
|
45
|
-
const [screen, setScreen] = useState("connecting");
|
|
46
|
-
const [termHeight, setTermHeight] = useState(stdout?.rows ?? 24);
|
|
47
|
-
const [termWidth, setTermWidth] = useState(stdout?.columns ?? 80);
|
|
48
|
-
const [unreadCount, setUnreadCount] = useState(0);
|
|
49
|
-
const [replyTo, setReplyTo] = useState(null);
|
|
50
|
-
const [subViewActive, setSubViewActive] = useState(false);
|
|
51
|
-
const humanNameRef = useRef("Human");
|
|
52
|
-
// Track terminal size
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
const update = () => {
|
|
55
|
-
setTermHeight(stdout?.rows ?? 24);
|
|
56
|
-
setTermWidth(stdout?.columns ?? 80);
|
|
57
|
-
};
|
|
58
|
-
stdout?.on("resize", update);
|
|
59
|
-
return () => { stdout?.off("resize", update); };
|
|
60
|
-
}, [stdout]);
|
|
61
|
-
// Health check on mount
|
|
62
|
-
useEffect(() => {
|
|
63
|
-
checkHealth().then((ok) => {
|
|
64
|
-
setScreen(ok ? "menu" : "auth-error");
|
|
65
|
-
});
|
|
66
|
-
}, []);
|
|
67
|
-
// Resolve human name once, then poll unread mail every 15s
|
|
68
|
-
useEffect(() => {
|
|
69
|
-
const fetchUnread = async () => {
|
|
70
|
-
try {
|
|
71
|
-
const msgs = await getMailMessages(humanNameRef.current, { unreadOnly: true });
|
|
72
|
-
setUnreadCount(msgs.length);
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
// ignore poll errors silently
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
getConfig().then((cfg) => {
|
|
79
|
-
humanNameRef.current = cfg.human_name ?? "Human";
|
|
80
|
-
fetchUnread();
|
|
81
|
-
}).catch(() => { });
|
|
82
|
-
const timer = setInterval(fetchUnread, 15_000);
|
|
83
|
-
return () => clearInterval(timer);
|
|
84
|
-
}, []);
|
|
85
|
-
useInput((input, key) => {
|
|
86
|
-
if (key.escape && SUB_SCREENS.includes(screen) && !subViewActive) {
|
|
87
|
-
setScreen("menu");
|
|
88
|
-
}
|
|
89
|
-
if (input === "q" && screen === "menu") {
|
|
90
|
-
exit();
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
const goBack = () => setScreen("menu");
|
|
94
|
-
const handleMenuSelect = (value) => {
|
|
95
|
-
if (value === "quit") {
|
|
96
|
-
exit();
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
if (value === "my-mail")
|
|
100
|
-
setUnreadCount(0);
|
|
101
|
-
setScreen(value);
|
|
102
|
-
};
|
|
103
|
-
// content area = terminal height minus header (3 rows) and footer (3 rows)
|
|
104
|
-
const contentHeight = Math.max(4, termHeight - 6);
|
|
105
|
-
const renderContent = () => {
|
|
106
|
-
switch (screen) {
|
|
107
|
-
case "connecting":
|
|
108
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: `Connecting to ${serverUrl}...` }) }));
|
|
109
|
-
case "auth-error":
|
|
110
|
-
return (_jsxs(Box, { height: contentHeight, flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 1, children: [_jsx(Text, { color: "red", bold: true, children: "Connection failed" }), _jsxs(Text, { children: ["Could not reach ", _jsx(Text, { color: "cyan", children: serverUrl })] }), _jsx(Text, { dimColor: true, children: "Check that agent-office serve is running and your --password is correct." })] }));
|
|
111
|
-
case "menu":
|
|
112
|
-
return (_jsxs(Box, { height: contentHeight, flexDirection: "row", flexGrow: 1, children: [_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, flexGrow: 1, children: [_jsx(Text, { bold: true, children: "Main Menu" }), _jsx(MenuSelect, { options: MENU_OPTIONS, onChange: handleMenuSelect, badges: unreadCount > 0 ? { "my-mail": `(${unreadCount})` } : {} })] }), _jsx(SessionSidebar, { serverUrl: serverUrl, password: password })] }));
|
|
113
|
-
case "list":
|
|
114
|
-
return (_jsx(Box, { height: contentHeight, flexDirection: "column", paddingX: 2, paddingY: 1, children: _jsx(SessionList, { serverUrl: serverUrl, password: password, onBack: goBack, contentHeight: contentHeight - 2, onSubViewChange: setSubViewActive }) }));
|
|
115
|
-
case "send-message":
|
|
116
|
-
return (_jsx(Box, { height: contentHeight, flexDirection: "column", paddingX: 2, paddingY: 1, children: _jsx(SendMessage, { serverUrl: serverUrl, password: password, onBack: () => { setReplyTo(null); goBack(); }, contentHeight: contentHeight - 2, initialRecipient: replyTo ?? undefined }) }));
|
|
117
|
-
case "profile":
|
|
118
|
-
return (_jsx(Box, { height: contentHeight, flexDirection: "column", paddingX: 2, paddingY: 1, children: _jsx(Profile, { serverUrl: serverUrl, password: password, onBack: goBack, contentHeight: contentHeight - 2 }) }));
|
|
119
|
-
case "my-mail":
|
|
120
|
-
return (_jsx(Box, { height: contentHeight, flexDirection: "column", paddingX: 2, paddingY: 1, children: _jsx(MyMail, { serverUrl: serverUrl, password: password, onBack: goBack, contentHeight: contentHeight - 2, onReply: (name) => { setReplyTo(name); setScreen("send-message"); } }) }));
|
|
121
|
-
case "cron":
|
|
122
|
-
return (_jsx(Box, { height: contentHeight, flexDirection: "column", paddingX: 2, paddingY: 1, children: _jsx(CronList, { serverUrl: serverUrl, password: password, onBack: goBack, contentHeight: contentHeight - 2 }) }));
|
|
123
|
-
case "cron-requests":
|
|
124
|
-
return (_jsx(Box, { height: contentHeight, flexDirection: "column", paddingX: 2, paddingY: 1, children: _jsx(CronRequests, { serverUrl: serverUrl, password: password, onBack: goBack, contentHeight: contentHeight - 2 }) }));
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
return (_jsxs(Box, { flexDirection: "column", width: termWidth, children: [_jsx(Header, { serverUrl: serverUrl, unreadCount: unreadCount }), renderContent(), screen !== "connecting" && (_jsx(Footer, { hint: FOOTER_HINTS[screen] }))] }));
|
|
128
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
interface AgentCodeProps {
|
|
2
|
-
serverUrl: string;
|
|
3
|
-
password: string;
|
|
4
|
-
onBack: () => void;
|
|
5
|
-
contentHeight: number;
|
|
6
|
-
}
|
|
7
|
-
export declare function AgentCode({ serverUrl, password, onBack, contentHeight }: AgentCodeProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
-
export {};
|
|
@@ -1,73 +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, ConfirmInput } from "@inkjs/ui";
|
|
5
|
-
import { useApi, useAsyncState } from "../hooks/useApi.js";
|
|
6
|
-
const MASKED = "••••••••-••••-••••-••••-••••••••••••";
|
|
7
|
-
export function AgentCode({ serverUrl, password, onBack, contentHeight }) {
|
|
8
|
-
const { listSessions, regenerateCode } = useApi(serverUrl, password);
|
|
9
|
-
const { run: runList } = useAsyncState();
|
|
10
|
-
const [sessions, setSessions] = useState([]);
|
|
11
|
-
const [stage, setStage] = useState("loading-sessions");
|
|
12
|
-
const [selected, setSelected] = useState(null);
|
|
13
|
-
const [revealed, setRevealed] = useState(false);
|
|
14
|
-
const [error, setError] = useState(null);
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
runList(listSessions).then((rows) => {
|
|
17
|
-
setSessions(rows ?? []);
|
|
18
|
-
setStage("select");
|
|
19
|
-
});
|
|
20
|
-
}, []);
|
|
21
|
-
// r = reveal/hide, g = trigger regenerate, when viewing
|
|
22
|
-
useInput((input) => {
|
|
23
|
-
if (stage !== "view")
|
|
24
|
-
return;
|
|
25
|
-
if (input === "r")
|
|
26
|
-
setRevealed((v) => !v);
|
|
27
|
-
if (input === "g")
|
|
28
|
-
setStage("confirm-regen");
|
|
29
|
-
});
|
|
30
|
-
const handleSelect = (name) => {
|
|
31
|
-
const session = sessions.find((s) => s.name === name) ?? null;
|
|
32
|
-
setSelected(session);
|
|
33
|
-
setRevealed(false);
|
|
34
|
-
setStage("view");
|
|
35
|
-
};
|
|
36
|
-
const handleConfirmRegen = async (confirmed) => {
|
|
37
|
-
if (!confirmed || !selected) {
|
|
38
|
-
setStage("view");
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
setStage("regenerating");
|
|
42
|
-
try {
|
|
43
|
-
const updated = await regenerateCode(selected.name);
|
|
44
|
-
setSelected(updated);
|
|
45
|
-
setRevealed(true); // auto-reveal the new code
|
|
46
|
-
setStage("view");
|
|
47
|
-
}
|
|
48
|
-
catch (err) {
|
|
49
|
-
setError(err instanceof Error ? err.message : String(err));
|
|
50
|
-
setStage("error");
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
if (stage === "loading-sessions") {
|
|
54
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Loading sessions..." }) }));
|
|
55
|
-
}
|
|
56
|
-
if (stage === "regenerating") {
|
|
57
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Spinner, { label: "Generating new agent code..." }) }));
|
|
58
|
-
}
|
|
59
|
-
if (stage === "error") {
|
|
60
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Agent Code" }), _jsxs(Text, { color: "red", children: ["Error: ", error] }), _jsx(Text, { dimColor: true, children: "Press Esc to go back" })] }));
|
|
61
|
-
}
|
|
62
|
-
if (stage === "select") {
|
|
63
|
-
if (sessions.length === 0) {
|
|
64
|
-
return (_jsx(Box, { height: contentHeight, alignItems: "center", justifyContent: "center", children: _jsx(Text, { dimColor: true, children: "No sessions yet. Create one first." }) }));
|
|
65
|
-
}
|
|
66
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Agent Code" }), _jsx(Text, { dimColor: true, children: "Select a session to view its agent code:" }), _jsx(Select, { options: sessions.map((s) => ({ label: s.name, value: s.name })), onChange: handleSelect })] }));
|
|
67
|
-
}
|
|
68
|
-
if (stage === "confirm-regen" && selected) {
|
|
69
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Agent Code" }), _jsxs(Text, { children: ["Regenerate code for ", _jsx(Text, { color: "cyan", bold: true, children: selected.name }), "?", " ", _jsx(Text, { dimColor: true, children: "The old code will stop working immediately." })] }), _jsx(ConfirmInput, { defaultChoice: "cancel", onConfirm: () => void handleConfirmRegen(true), onCancel: () => void handleConfirmRegen(false) })] }));
|
|
70
|
-
}
|
|
71
|
-
// stage === "view"
|
|
72
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Agent Code" }), _jsx(Text, { color: "cyan", children: selected?.name })] }), _jsxs(Box, { gap: 2, marginY: 1, children: [_jsx(Text, { bold: true, children: "Code:" }), revealed ? (_jsx(Text, { color: "yellow", children: selected?.agent_code })) : (_jsx(Text, { dimColor: true, children: MASKED }))] }), _jsxs(Box, { gap: 2, children: [_jsx(Text, { dimColor: true, children: "Clock-in format:" }), _jsxs(Text, { dimColor: true, children: [revealed ? selected?.agent_code : MASKED, "@<server-url>"] })] }), _jsxs(Box, { flexDirection: "column", marginTop: 1, gap: 0, children: [_jsxs(Text, { dimColor: true, children: ["r ", revealed ? "hide" : "reveal", " code"] }), _jsx(Text, { dimColor: true, children: "g regenerate code" }), _jsx(Text, { dimColor: true, children: "Esc back to menu" })] })] }));
|
|
73
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
interface CreateSessionProps {
|
|
2
|
-
serverUrl: string;
|
|
3
|
-
password: string;
|
|
4
|
-
agent: string;
|
|
5
|
-
onBack: () => void;
|
|
6
|
-
}
|
|
7
|
-
export declare function CreateSession({ serverUrl, password, agent, onBack }: CreateSessionProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
-
export {};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useEffect } from "react";
|
|
3
|
-
import { Box, Text } from "ink";
|
|
4
|
-
import { TextInput, Spinner } from "@inkjs/ui";
|
|
5
|
-
import { useApi, useAsyncState } from "../hooks/useApi.js";
|
|
6
|
-
export function CreateSession({ serverUrl, password, agent, onBack }) {
|
|
7
|
-
const { createSession } = useApi(serverUrl, password);
|
|
8
|
-
const { loading, error, run } = useAsyncState();
|
|
9
|
-
const [created, setCreated] = useState(null);
|
|
10
|
-
const [submitted, setSubmitted] = useState(false);
|
|
11
|
-
// Auto-return to menu 1.5s after success or error
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
if (created || error) {
|
|
14
|
-
const timer = setTimeout(onBack, 1500);
|
|
15
|
-
return () => clearTimeout(timer);
|
|
16
|
-
}
|
|
17
|
-
}, [created, error, onBack]);
|
|
18
|
-
const handleSubmit = async (name) => {
|
|
19
|
-
const trimmed = name.trim();
|
|
20
|
-
if (!trimmed)
|
|
21
|
-
return;
|
|
22
|
-
setSubmitted(true);
|
|
23
|
-
const result = await run(() => createSession(trimmed, agent));
|
|
24
|
-
if (result)
|
|
25
|
-
setCreated(result);
|
|
26
|
-
};
|
|
27
|
-
if (loading) {
|
|
28
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Create Session" }), _jsx(Spinner, { label: "Creating session on OpenCode..." })] }));
|
|
29
|
-
}
|
|
30
|
-
if (created) {
|
|
31
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Create Session" }), _jsx(Text, { color: "green", children: "Session created!" }), _jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "Name:" }), _jsx(Text, { color: "cyan", children: created.name })] }), _jsxs(Box, { gap: 2, children: [_jsx(Text, { bold: true, children: "OpenCode ID:" }), _jsx(Text, { dimColor: true, children: created.session_id })] }), _jsx(Text, { dimColor: true, children: "Returning to menu..." })] }));
|
|
32
|
-
}
|
|
33
|
-
if (error) {
|
|
34
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Create Session" }), _jsxs(Text, { color: "red", children: ["Error: ", error] }), _jsx(Text, { dimColor: true, children: "Returning to menu..." })] }));
|
|
35
|
-
}
|
|
36
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, children: "Create Session" }), _jsxs(Box, { gap: 1, children: [_jsx(Text, { children: "Name: " }), !submitted && (_jsx(TextInput, { placeholder: "e.g. john", onSubmit: handleSubmit }))] })] }));
|
|
37
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
interface CronListProps {
|
|
2
|
-
serverUrl: string;
|
|
3
|
-
password: string;
|
|
4
|
-
onBack: () => void;
|
|
5
|
-
contentHeight: number;
|
|
6
|
-
sessionName?: string | null;
|
|
7
|
-
}
|
|
8
|
-
export declare function CronList({ serverUrl, password, onBack, contentHeight, sessionName: initialSessionName }: CronListProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
-
export {};
|