workspacecord 1.0.2 → 1.1.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/dist/archive-manager-KMNAWQIN.js +21 -0
- package/dist/attachment-cli-QEF7IZBI.js +62 -0
- package/dist/{chunk-OKI4UVGY.js → chunk-52OOARML.js} +65 -2
- package/dist/{chunk-NIXZJTOZ.js → chunk-7KESUGJP.js} +3 -46
- package/dist/chunk-CBNENUW6.js +55 -0
- package/dist/{chunk-2LBNM64L.js → chunk-D6J3X35H.js} +23 -11
- package/dist/{bot-B5HN4ZW6.js → chunk-G6CCOBUY.js} +6556 -5956
- package/dist/{chunk-TSBM3BNT.js → chunk-IFSOU4XI.js} +393 -140
- package/dist/chunk-PUKMHDXS.js +196 -0
- package/dist/chunk-Q2AJ4UEK.js +199 -0
- package/dist/cli-framework-KMQXM2PO.js +17 -0
- package/dist/cli.js +20 -68
- package/dist/{codex-launcher-IF2IPLBP.js → codex-launcher-OOF2WYQF.js} +1 -1
- package/dist/{codex-provider-7CI5W34X.js → codex-provider-P7TDYK6B.js} +2 -2
- package/dist/{config-cli-F2B5SYHJ.js → config-cli-YSKOXADF.js} +2 -2
- package/dist/{project-cli-FEMPZIRQ.js → project-cli-QW5QYT6A.js} +2 -1
- package/dist/{project-registry-DQT5ORUU.js → project-registry-LL75XEUV.js} +2 -1
- package/dist/{setup-TKOVXSME.js → setup-QJ4HVVCU.js} +1 -1
- package/dist/{thread-manager-5T46QTZF.js → thread-manager-DRWNFXXY.js} +17 -7
- package/package.json +7 -2
- package/dist/chunk-WE4X3JB3.js +0 -130
- package/dist/utils-72GMT2X5.js +0 -36
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
endSession,
|
|
4
|
+
getAllSessions,
|
|
5
|
+
getProject,
|
|
6
|
+
setHistoryChannelId
|
|
7
|
+
} from "./chunk-IFSOU4XI.js";
|
|
8
|
+
import {
|
|
9
|
+
config
|
|
10
|
+
} from "./chunk-D6J3X35H.js";
|
|
11
|
+
import {
|
|
12
|
+
Store
|
|
13
|
+
} from "./chunk-CBNENUW6.js";
|
|
14
|
+
|
|
15
|
+
// src/archive-manager.ts
|
|
16
|
+
import { ChannelType, EmbedBuilder } from "discord.js";
|
|
17
|
+
var archiveStore = new Store("archived.json");
|
|
18
|
+
var archived = [];
|
|
19
|
+
async function loadArchived() {
|
|
20
|
+
archived = await archiveStore.read() || [];
|
|
21
|
+
}
|
|
22
|
+
async function saveArchived() {
|
|
23
|
+
await archiveStore.write(archived);
|
|
24
|
+
}
|
|
25
|
+
function getArchivedSessions(categoryId) {
|
|
26
|
+
return archived.filter((a) => a.categoryId === categoryId);
|
|
27
|
+
}
|
|
28
|
+
function isArchivedProviderSession(provider, providerSessionId) {
|
|
29
|
+
if (!providerSessionId) return false;
|
|
30
|
+
return archived.some(
|
|
31
|
+
(record) => record.provider === provider && record.providerSessionId === providerSessionId
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
async function ensureHistoryChannel(guild, categoryId) {
|
|
35
|
+
const project = getProject(categoryId);
|
|
36
|
+
if (!project) return null;
|
|
37
|
+
if (project.historyChannelId) {
|
|
38
|
+
const existing2 = guild.channels.cache.get(project.historyChannelId);
|
|
39
|
+
if (existing2?.type === ChannelType.GuildForum) {
|
|
40
|
+
return existing2;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const existing = guild.channels.cache.find(
|
|
44
|
+
(ch) => ch.parentId === categoryId && ch.name === "history" && ch.type === ChannelType.GuildForum
|
|
45
|
+
);
|
|
46
|
+
if (existing?.type === ChannelType.GuildForum) {
|
|
47
|
+
setHistoryChannelId(categoryId, existing.id);
|
|
48
|
+
return existing;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const forum = await guild.channels.create({
|
|
52
|
+
name: "history",
|
|
53
|
+
type: ChannelType.GuildForum,
|
|
54
|
+
parent: categoryId,
|
|
55
|
+
topic: "Archived agent sessions for this project",
|
|
56
|
+
reason: "Auto-created by workspacecord for session archiving"
|
|
57
|
+
});
|
|
58
|
+
setHistoryChannelId(categoryId, forum.id);
|
|
59
|
+
return forum;
|
|
60
|
+
} catch (err) {
|
|
61
|
+
console.error(`[archive-manager] Failed to create #history forum: ${err.message}`);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function archiveSession(session, guild, summary) {
|
|
66
|
+
const historyForum = await ensureHistoryChannel(guild, session.categoryId);
|
|
67
|
+
const record = {
|
|
68
|
+
id: session.id,
|
|
69
|
+
categoryId: session.categoryId,
|
|
70
|
+
agentLabel: session.agentLabel,
|
|
71
|
+
provider: session.provider,
|
|
72
|
+
providerSessionId: session.providerSessionId,
|
|
73
|
+
directory: session.directory,
|
|
74
|
+
mode: session.mode,
|
|
75
|
+
createdAt: session.createdAt,
|
|
76
|
+
archivedAt: Date.now(),
|
|
77
|
+
messageCount: session.messageCount,
|
|
78
|
+
totalCost: session.totalCost,
|
|
79
|
+
summary: summary || session.workflowState.lastWorkerSummary
|
|
80
|
+
};
|
|
81
|
+
if (historyForum) {
|
|
82
|
+
try {
|
|
83
|
+
const date = new Date(session.createdAt).toISOString().slice(0, 10);
|
|
84
|
+
const postName = `[${session.provider}] ${session.agentLabel} \xB7 ${date}`.slice(0, 100);
|
|
85
|
+
const embed = new EmbedBuilder().setColor(9807270).setTitle(`Archived: ${session.agentLabel}`).addFields(
|
|
86
|
+
{ name: "Provider", value: session.provider, inline: true },
|
|
87
|
+
{ name: "Mode", value: session.mode, inline: true },
|
|
88
|
+
{ name: "Messages", value: `${session.messageCount}`, inline: true },
|
|
89
|
+
{ name: "Directory", value: `\`${session.directory}\``, inline: false },
|
|
90
|
+
{
|
|
91
|
+
name: "Active",
|
|
92
|
+
value: `${formatDuration(record.archivedAt - record.createdAt)}`,
|
|
93
|
+
inline: true
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "Cost",
|
|
97
|
+
value: session.totalCost > 0 ? `$${session.totalCost.toFixed(4)}` : "N/A",
|
|
98
|
+
inline: true
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
if (record.summary) {
|
|
102
|
+
embed.addFields({ name: "Last Summary", value: record.summary.slice(0, 1e3) });
|
|
103
|
+
}
|
|
104
|
+
const post = await historyForum.threads.create({
|
|
105
|
+
name: postName,
|
|
106
|
+
message: { embeds: [embed] },
|
|
107
|
+
reason: `Session archived by workspacecord`
|
|
108
|
+
});
|
|
109
|
+
record.forumPostId = post.id;
|
|
110
|
+
} catch (err) {
|
|
111
|
+
console.error(`[archive-manager] Failed to create forum post: ${err.message}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (session.type === "persistent") {
|
|
115
|
+
try {
|
|
116
|
+
const channel = guild.channels.cache.get(session.channelId);
|
|
117
|
+
if (channel) {
|
|
118
|
+
await channel.delete(`Session archived by workspacecord`);
|
|
119
|
+
}
|
|
120
|
+
} catch (err) {
|
|
121
|
+
console.error(
|
|
122
|
+
`[archive-manager] Failed to delete session channel: ${err.message}`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
await endSession(session.id);
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
archived.push(record);
|
|
131
|
+
await saveArchived();
|
|
132
|
+
return record;
|
|
133
|
+
}
|
|
134
|
+
async function checkAutoArchive(guild) {
|
|
135
|
+
if (!config.autoArchiveDays && !config.maxActiveSessionsPerProject) return;
|
|
136
|
+
const now = Date.now();
|
|
137
|
+
const inactiveThreshold = config.autoArchiveDays ? config.autoArchiveDays * 24 * 60 * 60 * 1e3 : 0;
|
|
138
|
+
const byCategory = /* @__PURE__ */ new Map();
|
|
139
|
+
for (const session of getAllSessions()) {
|
|
140
|
+
if (session.type !== "persistent") continue;
|
|
141
|
+
if (session.isGenerating) continue;
|
|
142
|
+
const list = byCategory.get(session.categoryId) ?? [];
|
|
143
|
+
list.push(session);
|
|
144
|
+
byCategory.set(session.categoryId, list);
|
|
145
|
+
}
|
|
146
|
+
for (const [categoryId, categorySessions] of byCategory) {
|
|
147
|
+
const toArchive = /* @__PURE__ */ new Set();
|
|
148
|
+
if (inactiveThreshold > 0) {
|
|
149
|
+
for (const s of categorySessions) {
|
|
150
|
+
if (now - s.lastActivity > inactiveThreshold) {
|
|
151
|
+
toArchive.add(s.id);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const maxActive = config.maxActiveSessionsPerProject;
|
|
156
|
+
if (maxActive > 0 && categorySessions.length > maxActive) {
|
|
157
|
+
const sorted = [...categorySessions].sort((a, b) => a.lastActivity - b.lastActivity);
|
|
158
|
+
const excess = categorySessions.length - maxActive;
|
|
159
|
+
for (let i = 0; i < excess; i++) {
|
|
160
|
+
toArchive.add(sorted[i].id);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
for (const sessionId of toArchive) {
|
|
164
|
+
const session = categorySessions.find((s) => s.id === sessionId);
|
|
165
|
+
if (!session) continue;
|
|
166
|
+
console.log(
|
|
167
|
+
`[archive-manager] Auto-archiving session "${session.agentLabel}" (inactive: ${Math.round((now - session.lastActivity) / 864e5)}d)`
|
|
168
|
+
);
|
|
169
|
+
await archiveSession(
|
|
170
|
+
session,
|
|
171
|
+
guild,
|
|
172
|
+
"Auto-archived due to inactivity or session limit."
|
|
173
|
+
).catch(
|
|
174
|
+
(err) => console.error(
|
|
175
|
+
`[archive-manager] Auto-archive failed for "${session.agentLabel}": ${err.message}`
|
|
176
|
+
)
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function formatDuration(ms) {
|
|
182
|
+
const d = Math.floor(ms / 864e5);
|
|
183
|
+
const h = Math.floor(ms % 864e5 / 36e5);
|
|
184
|
+
const m = Math.floor(ms % 36e5 / 6e4);
|
|
185
|
+
if (d > 0) return `${d}d ${h}h`;
|
|
186
|
+
if (h > 0) return `${h}h ${m}m`;
|
|
187
|
+
return `${m}m`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export {
|
|
191
|
+
loadArchived,
|
|
192
|
+
getArchivedSessions,
|
|
193
|
+
isArchivedProviderSession,
|
|
194
|
+
archiveSession,
|
|
195
|
+
checkAutoArchive
|
|
196
|
+
};
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
Store,
|
|
4
|
+
getDataDir
|
|
5
|
+
} from "./chunk-CBNENUW6.js";
|
|
6
|
+
|
|
7
|
+
// src/discord/attachment-inbox.ts
|
|
8
|
+
import { basename, extname, join } from "path";
|
|
9
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
10
|
+
var attachmentStore = new Store("attachment-inbox.json");
|
|
11
|
+
var attachmentAuditStore = new Store("attachment-download-audit.json");
|
|
12
|
+
var MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024;
|
|
13
|
+
var MAX_TOTAL_DOWNLOAD_BYTES = 100 * 1024 * 1024;
|
|
14
|
+
var FETCH_TIMEOUT_MS = (() => {
|
|
15
|
+
const env = Number(process.env.WORKSPACECORD_ATTACHMENT_FETCH_TIMEOUT_MS ?? "");
|
|
16
|
+
if (Number.isFinite(env) && env > 0) {
|
|
17
|
+
return env;
|
|
18
|
+
}
|
|
19
|
+
return 15e3;
|
|
20
|
+
})();
|
|
21
|
+
var ALLOWED_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
|
|
22
|
+
function makeKey(sessionId, messageId) {
|
|
23
|
+
return `${sessionId}:${messageId}`;
|
|
24
|
+
}
|
|
25
|
+
function normalizeAttachment(attachment, messageId, index) {
|
|
26
|
+
return {
|
|
27
|
+
attachmentId: attachment.id ?? `${messageId}-${index}`,
|
|
28
|
+
name: attachment.name ?? `attachment-${index + 1}`,
|
|
29
|
+
contentType: attachment.contentType ?? null,
|
|
30
|
+
sizeBytes: attachment.size ?? 0,
|
|
31
|
+
url: attachment.url ?? ""
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function sanitizeFilename(name, attachmentId) {
|
|
35
|
+
const safeBase = basename(name).replace(/[^a-zA-Z0-9._-]/g, "_").replace(/_+/g, "_");
|
|
36
|
+
const ext = extname(safeBase);
|
|
37
|
+
const stem = safeBase.slice(0, ext ? -ext.length : void 0) || attachmentId;
|
|
38
|
+
const normalizedExt = ext.replace(/[^a-zA-Z0-9.]/g, "") || ".bin";
|
|
39
|
+
return `${stem}-${attachmentId}${normalizedExt}`;
|
|
40
|
+
}
|
|
41
|
+
async function readIndex() {
|
|
42
|
+
return await attachmentStore.read() ?? {};
|
|
43
|
+
}
|
|
44
|
+
async function writeIndex(index) {
|
|
45
|
+
await attachmentStore.write(index);
|
|
46
|
+
}
|
|
47
|
+
async function appendAudit(entry) {
|
|
48
|
+
const existing = await attachmentAuditStore.read() ?? [];
|
|
49
|
+
existing.push(entry);
|
|
50
|
+
await attachmentAuditStore.write(existing);
|
|
51
|
+
}
|
|
52
|
+
async function registerMessageAttachments(sessionId, messageId, attachments) {
|
|
53
|
+
const index = await readIndex();
|
|
54
|
+
const records = attachments.map((attachment, idx) => normalizeAttachment(attachment, messageId, idx));
|
|
55
|
+
index[makeKey(sessionId, messageId)] = records;
|
|
56
|
+
await writeIndex(index);
|
|
57
|
+
return records;
|
|
58
|
+
}
|
|
59
|
+
async function getMessageAttachments(sessionId, messageId, attachmentId) {
|
|
60
|
+
const index = await readIndex();
|
|
61
|
+
const records = index[makeKey(sessionId, messageId)] ?? [];
|
|
62
|
+
if (!attachmentId) return records;
|
|
63
|
+
return records.filter((record) => record.attachmentId === attachmentId);
|
|
64
|
+
}
|
|
65
|
+
async function fetchRegisteredAttachments(options) {
|
|
66
|
+
if (!options.currentSessionId) {
|
|
67
|
+
throw new Error("currentSessionId is required: session context must be provided for attachment downloads");
|
|
68
|
+
}
|
|
69
|
+
if (options.currentSessionId !== options.sessionId) {
|
|
70
|
+
throw new Error("current session mismatch: cross-session attachment download is not allowed");
|
|
71
|
+
}
|
|
72
|
+
const records = await getMessageAttachments(
|
|
73
|
+
options.sessionId,
|
|
74
|
+
options.messageId,
|
|
75
|
+
options.all ? void 0 : options.attachmentId
|
|
76
|
+
);
|
|
77
|
+
if (!options.all && !options.attachmentId) {
|
|
78
|
+
throw new Error("attachmentId is required unless --all is set");
|
|
79
|
+
}
|
|
80
|
+
if (records.length === 0) {
|
|
81
|
+
throw new Error("No registered attachments found for the requested message");
|
|
82
|
+
}
|
|
83
|
+
if (records.some((record) => !record.url)) {
|
|
84
|
+
throw new Error("Missing download URL for one or more attachments");
|
|
85
|
+
}
|
|
86
|
+
if (options.all) {
|
|
87
|
+
const totalBytes = records.reduce((sum, record) => sum + record.sizeBytes, 0);
|
|
88
|
+
if (totalBytes > MAX_TOTAL_DOWNLOAD_BYTES) {
|
|
89
|
+
throw new Error("Total attachment size exceeds --all limit");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const inboxDir = join(getDataDir(), "inbox", options.sessionId);
|
|
93
|
+
await mkdir(inboxDir, { recursive: true });
|
|
94
|
+
const downloaded = [];
|
|
95
|
+
for (const record of records) {
|
|
96
|
+
assertHttpUrl(record.url);
|
|
97
|
+
if (record.sizeBytes > MAX_ATTACHMENT_BYTES) {
|
|
98
|
+
throw new Error(`Attachment exceeds 25MB limit: ${record.name}`);
|
|
99
|
+
}
|
|
100
|
+
const response = await fetchWithTimeout(record.url, record);
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
throw new Error(`Failed to download attachment: ${record.name}`);
|
|
103
|
+
}
|
|
104
|
+
const bytes = Buffer.from(await readArrayBufferWithTimeout(response, record));
|
|
105
|
+
const filename = sanitizeFilename(record.name, record.attachmentId);
|
|
106
|
+
const path = join(inboxDir, filename);
|
|
107
|
+
await writeFile(path, bytes);
|
|
108
|
+
downloaded.push({
|
|
109
|
+
attachmentId: record.attachmentId,
|
|
110
|
+
name: record.name,
|
|
111
|
+
contentType: record.contentType,
|
|
112
|
+
sizeBytes: record.sizeBytes,
|
|
113
|
+
path
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
await appendAudit({
|
|
117
|
+
sessionId: options.sessionId,
|
|
118
|
+
messageId: options.messageId,
|
|
119
|
+
attachmentId: options.attachmentId,
|
|
120
|
+
all: options.all === true,
|
|
121
|
+
downloadedPaths: downloaded.map((item) => item.path),
|
|
122
|
+
timestampIso: (/* @__PURE__ */ new Date()).toISOString()
|
|
123
|
+
});
|
|
124
|
+
return downloaded;
|
|
125
|
+
}
|
|
126
|
+
function assertHttpUrl(rawUrl) {
|
|
127
|
+
let parsed;
|
|
128
|
+
try {
|
|
129
|
+
parsed = new URL(rawUrl);
|
|
130
|
+
} catch {
|
|
131
|
+
throw new Error(`Invalid attachment URL: ${rawUrl}`);
|
|
132
|
+
}
|
|
133
|
+
if (!ALLOWED_PROTOCOLS.has(parsed.protocol)) {
|
|
134
|
+
throw new Error(`Attachment URL must use http or https: ${rawUrl}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async function readArrayBufferWithTimeout(response, record) {
|
|
138
|
+
let timer;
|
|
139
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
140
|
+
timer = setTimeout(() => {
|
|
141
|
+
reject(new Error(`Attachment download timed out: ${record.name}`));
|
|
142
|
+
}, FETCH_TIMEOUT_MS);
|
|
143
|
+
});
|
|
144
|
+
try {
|
|
145
|
+
return await Promise.race([readResponseBody(response, record), timeoutPromise]);
|
|
146
|
+
} finally {
|
|
147
|
+
if (timer) clearTimeout(timer);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function fetchWithTimeout(url, record) {
|
|
151
|
+
const controller = new AbortController();
|
|
152
|
+
let timer;
|
|
153
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
154
|
+
timer = setTimeout(() => {
|
|
155
|
+
controller.abort();
|
|
156
|
+
reject(new Error(`Attachment download timed out: ${record.name}`));
|
|
157
|
+
}, FETCH_TIMEOUT_MS);
|
|
158
|
+
});
|
|
159
|
+
try {
|
|
160
|
+
return await Promise.race([fetch(url, { signal: controller.signal }), timeoutPromise]);
|
|
161
|
+
} finally {
|
|
162
|
+
if (timer) clearTimeout(timer);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async function readResponseBody(response, record) {
|
|
166
|
+
const reader = response.body?.getReader();
|
|
167
|
+
if (!reader) {
|
|
168
|
+
const bytes = Buffer.from(await response.arrayBuffer());
|
|
169
|
+
if (bytes.byteLength > MAX_ATTACHMENT_BYTES) {
|
|
170
|
+
throw new Error(`Attachment exceeds 25MB limit: ${record.name}`);
|
|
171
|
+
}
|
|
172
|
+
return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
173
|
+
}
|
|
174
|
+
const chunks = [];
|
|
175
|
+
let totalBytes = 0;
|
|
176
|
+
while (true) {
|
|
177
|
+
const { done, value } = await reader.read();
|
|
178
|
+
if (done) break;
|
|
179
|
+
if (!value) continue;
|
|
180
|
+
totalBytes += value.byteLength;
|
|
181
|
+
if (totalBytes > MAX_ATTACHMENT_BYTES) {
|
|
182
|
+
await reader.cancel("attachment too large");
|
|
183
|
+
throw new Error(`Attachment exceeds 25MB limit: ${record.name}`);
|
|
184
|
+
}
|
|
185
|
+
chunks.push(value);
|
|
186
|
+
}
|
|
187
|
+
const combined = new Uint8Array(totalBytes);
|
|
188
|
+
let offset = 0;
|
|
189
|
+
for (const chunk of chunks) {
|
|
190
|
+
combined.set(chunk, offset);
|
|
191
|
+
offset += chunk.byteLength;
|
|
192
|
+
}
|
|
193
|
+
return combined.buffer;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export {
|
|
197
|
+
registerMessageAttachments,
|
|
198
|
+
fetchRegisteredAttachments
|
|
199
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
runCli,
|
|
4
|
+
startBot
|
|
5
|
+
} from "./chunk-G6CCOBUY.js";
|
|
6
|
+
import "./chunk-Q2AJ4UEK.js";
|
|
7
|
+
import "./chunk-PUKMHDXS.js";
|
|
8
|
+
import "./chunk-IFSOU4XI.js";
|
|
9
|
+
import "./chunk-D6J3X35H.js";
|
|
10
|
+
import "./chunk-7KESUGJP.js";
|
|
11
|
+
import "./chunk-CBNENUW6.js";
|
|
12
|
+
import "./chunk-52OOARML.js";
|
|
13
|
+
import "./chunk-K3NQKI34.js";
|
|
14
|
+
export {
|
|
15
|
+
runCli,
|
|
16
|
+
startBot
|
|
17
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -1,71 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
runCli,
|
|
4
|
+
startBot
|
|
5
|
+
} from "./chunk-G6CCOBUY.js";
|
|
6
|
+
import "./chunk-Q2AJ4UEK.js";
|
|
7
|
+
import "./chunk-PUKMHDXS.js";
|
|
8
|
+
import "./chunk-IFSOU4XI.js";
|
|
9
|
+
import "./chunk-D6J3X35H.js";
|
|
10
|
+
import "./chunk-7KESUGJP.js";
|
|
11
|
+
import "./chunk-CBNENUW6.js";
|
|
12
|
+
import "./chunk-52OOARML.js";
|
|
13
|
+
import "./chunk-K3NQKI34.js";
|
|
2
14
|
|
|
3
15
|
// src/cli.ts
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const { handleConfig } = await import("./config-cli-F2B5SYHJ.js");
|
|
13
|
-
await handleConfig(process.argv.slice(3));
|
|
14
|
-
break;
|
|
15
|
-
}
|
|
16
|
-
case "start":
|
|
17
|
-
case void 0: {
|
|
18
|
-
const { startBot } = await import("./bot-B5HN4ZW6.js");
|
|
19
|
-
console.log("workspacecord starting...");
|
|
20
|
-
await startBot();
|
|
21
|
-
break;
|
|
22
|
-
}
|
|
23
|
-
case "project": {
|
|
24
|
-
const { handleProject } = await import("./project-cli-FEMPZIRQ.js");
|
|
25
|
-
await handleProject(process.argv.slice(3));
|
|
26
|
-
break;
|
|
27
|
-
}
|
|
28
|
-
case "daemon": {
|
|
29
|
-
const { handleDaemon } = await import("./daemon-NW4WRMQK.js");
|
|
30
|
-
await handleDaemon(process.argv[3]);
|
|
31
|
-
break;
|
|
32
|
-
}
|
|
33
|
-
case "codex": {
|
|
34
|
-
const { handleCodexCommand } = await import("./codex-launcher-IF2IPLBP.js");
|
|
35
|
-
await handleCodexCommand(process.argv.slice(3));
|
|
36
|
-
break;
|
|
37
|
-
}
|
|
38
|
-
case "help":
|
|
39
|
-
case "--help":
|
|
40
|
-
case "-h": {
|
|
41
|
-
console.log(`
|
|
42
|
-
\x1B[1mworkspacecord\x1B[0m \u2014 Discord bot for multi-agent coding sessions
|
|
43
|
-
|
|
44
|
-
\x1B[1mUsage:\x1B[0m
|
|
45
|
-
workspacecord Start the bot
|
|
46
|
-
workspacecord config setup Interactive configuration wizard
|
|
47
|
-
workspacecord config get <key> Read a config value
|
|
48
|
-
workspacecord config set <k> <v> Write a config value
|
|
49
|
-
workspacecord config list List all config values
|
|
50
|
-
workspacecord config path Show config file path
|
|
51
|
-
workspacecord project <subcommand> Manage mounted projects
|
|
52
|
-
workspacecord daemon Manage background service (install/uninstall/status)
|
|
53
|
-
workspacecord codex [options] Launch managed Codex session with remote approval
|
|
54
|
-
workspacecord help Show this help message
|
|
55
|
-
|
|
56
|
-
\x1B[1mQuick start:\x1B[0m
|
|
57
|
-
1. workspacecord config setup Configure Discord app, token, permissions
|
|
58
|
-
2. workspacecord project init Mount a local project
|
|
59
|
-
3. workspacecord Start the bot
|
|
60
|
-
4. /project setup project:<name> Bind a Discord category to the mounted project
|
|
61
|
-
5. /agent spawn label:<task> Create an agent session
|
|
62
|
-
|
|
63
|
-
\x1B[2mhttps://github.com/xuhongbo/WorkspaceCord\x1B[0m
|
|
64
|
-
`);
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
default:
|
|
68
|
-
console.error(`Unknown command: ${command}`);
|
|
69
|
-
console.error("Run \x1B[36mworkspacecord help\x1B[0m for usage.");
|
|
70
|
-
process.exit(1);
|
|
71
|
-
}
|
|
16
|
+
void (async () => {
|
|
17
|
+
const { runCli: runCli2 } = await import("./cli-framework-KMQXM2PO.js");
|
|
18
|
+
await runCli2();
|
|
19
|
+
})();
|
|
20
|
+
export {
|
|
21
|
+
runCli,
|
|
22
|
+
startBot
|
|
23
|
+
};
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
maskSensitive,
|
|
10
10
|
setConfigValue,
|
|
11
11
|
validateConfigValue
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-52OOARML.js";
|
|
13
13
|
import "./chunk-K3NQKI34.js";
|
|
14
14
|
|
|
15
15
|
// src/config-cli.ts
|
|
@@ -33,7 +33,7 @@ async function handleConfig(args) {
|
|
|
33
33
|
const [subcommand, ...rest] = args;
|
|
34
34
|
switch (subcommand) {
|
|
35
35
|
case "setup": {
|
|
36
|
-
const { runSetup } = await import("./setup-
|
|
36
|
+
const { runSetup } = await import("./setup-QJ4HVVCU.js");
|
|
37
37
|
await runSetup();
|
|
38
38
|
break;
|
|
39
39
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
abortSession,
|
|
4
4
|
abortSessionWithReason,
|
|
5
|
+
buildClaudeSubagentProviderSessionId,
|
|
5
6
|
consumeAbortReason,
|
|
6
7
|
continueSession,
|
|
7
8
|
continueSessionWithOverrides,
|
|
@@ -15,13 +16,16 @@ import {
|
|
|
15
16
|
getSessionByChannel,
|
|
16
17
|
getSessionByCodexId,
|
|
17
18
|
getSessionByProviderSession,
|
|
18
|
-
getSessionByProviderSessionId,
|
|
19
19
|
getSessionByThread,
|
|
20
|
+
getSessionPermissionDetails,
|
|
21
|
+
getSessionPermissionSummary,
|
|
20
22
|
getSessionsByCategory,
|
|
21
23
|
loadSessions,
|
|
22
24
|
registerLocalSession,
|
|
23
25
|
resetWorkflowState,
|
|
24
26
|
resolveCodexSessionFromMonitor,
|
|
27
|
+
resolveEffectiveClaudePermissionMode,
|
|
28
|
+
resolveEffectiveCodexOptions,
|
|
25
29
|
sendMonitorPrompt,
|
|
26
30
|
sendPrompt,
|
|
27
31
|
setAgentPersona,
|
|
@@ -33,16 +37,18 @@ import {
|
|
|
33
37
|
setVerbose,
|
|
34
38
|
updateLocalObservation,
|
|
35
39
|
updateSession,
|
|
40
|
+
updateSessionPermissions,
|
|
36
41
|
updateWorkflowState
|
|
37
|
-
} from "./chunk-
|
|
38
|
-
import "./chunk-
|
|
39
|
-
import "./chunk-
|
|
40
|
-
import "./chunk-
|
|
41
|
-
import "./chunk-
|
|
42
|
+
} from "./chunk-IFSOU4XI.js";
|
|
43
|
+
import "./chunk-D6J3X35H.js";
|
|
44
|
+
import "./chunk-7KESUGJP.js";
|
|
45
|
+
import "./chunk-CBNENUW6.js";
|
|
46
|
+
import "./chunk-52OOARML.js";
|
|
42
47
|
import "./chunk-K3NQKI34.js";
|
|
43
48
|
export {
|
|
44
49
|
abortSession,
|
|
45
50
|
abortSessionWithReason,
|
|
51
|
+
buildClaudeSubagentProviderSessionId,
|
|
46
52
|
consumeAbortReason,
|
|
47
53
|
continueSession,
|
|
48
54
|
continueSessionWithOverrides,
|
|
@@ -56,13 +62,16 @@ export {
|
|
|
56
62
|
getSessionByChannel,
|
|
57
63
|
getSessionByCodexId,
|
|
58
64
|
getSessionByProviderSession,
|
|
59
|
-
getSessionByProviderSessionId,
|
|
60
65
|
getSessionByThread,
|
|
66
|
+
getSessionPermissionDetails,
|
|
67
|
+
getSessionPermissionSummary,
|
|
61
68
|
getSessionsByCategory,
|
|
62
69
|
loadSessions,
|
|
63
70
|
registerLocalSession,
|
|
64
71
|
resetWorkflowState,
|
|
65
72
|
resolveCodexSessionFromMonitor,
|
|
73
|
+
resolveEffectiveClaudePermissionMode,
|
|
74
|
+
resolveEffectiveCodexOptions,
|
|
66
75
|
sendMonitorPrompt,
|
|
67
76
|
sendPrompt,
|
|
68
77
|
setAgentPersona,
|
|
@@ -74,5 +83,6 @@ export {
|
|
|
74
83
|
setVerbose,
|
|
75
84
|
updateLocalObservation,
|
|
76
85
|
updateSession,
|
|
86
|
+
updateSessionPermissions,
|
|
77
87
|
updateWorkflowState
|
|
78
88
|
};
|