oh-my-opencode-cohub 1.10.1 → 1.10.2
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/cli/index.js +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +139 -49
- package/dist/tools/council.d.ts.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +76 -11
- package/dist/utils/log.d.ts +18 -0
- package/dist/utils/log.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAyIlD,QAAA,MAAM,WAAW,EAAE,MAmclB,CAAC;AAEF,eAAO,MAAM,MAAM,QAAc,CAAC;AAClC,eAAe,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -516,7 +516,7 @@ class TaskTracker {
|
|
|
516
516
|
}
|
|
517
517
|
const agent = args.subagent_type ?? "unknown";
|
|
518
518
|
const alias = this.alias(agent);
|
|
519
|
-
const label = typeof args.description === "string" ? args.description : alias;
|
|
519
|
+
const label = typeof args.description === "string" && args.description ? args.description : alias;
|
|
520
520
|
this.jobs.set(alias, {
|
|
521
521
|
alias,
|
|
522
522
|
sessionId: args.task_id ?? "",
|
|
@@ -1101,6 +1101,69 @@ function loadCoHubConfig() {
|
|
|
1101
1101
|
|
|
1102
1102
|
// src/tools/council.ts
|
|
1103
1103
|
import { tool } from "@opencode-ai/plugin";
|
|
1104
|
+
|
|
1105
|
+
// src/utils/log.ts
|
|
1106
|
+
import * as fs2 from "fs/promises";
|
|
1107
|
+
import * as path2 from "path";
|
|
1108
|
+
import * as os2 from "os";
|
|
1109
|
+
var LOG_DIR = path2.join(os2.homedir(), ".local", "share", "opencode", "log");
|
|
1110
|
+
var LOG_PREFIX = "oh-my-opencode-cohub";
|
|
1111
|
+
var KEEP_DAYS = 7;
|
|
1112
|
+
var _today = "";
|
|
1113
|
+
var _logPath = "";
|
|
1114
|
+
var _cleanedToday = false;
|
|
1115
|
+
function getLogPath() {
|
|
1116
|
+
const today = new Date().toISOString().slice(0, 10).replace(/-/g, "");
|
|
1117
|
+
if (today !== _today) {
|
|
1118
|
+
_today = today;
|
|
1119
|
+
_logPath = path2.join(LOG_DIR, `${LOG_PREFIX}.${today}.log`);
|
|
1120
|
+
_cleanedToday = false;
|
|
1121
|
+
}
|
|
1122
|
+
return _logPath;
|
|
1123
|
+
}
|
|
1124
|
+
async function cleanOldLogsOnce() {
|
|
1125
|
+
if (_cleanedToday)
|
|
1126
|
+
return;
|
|
1127
|
+
_cleanedToday = true;
|
|
1128
|
+
try {
|
|
1129
|
+
const cutoff = new Date;
|
|
1130
|
+
cutoff.setUTCDate(cutoff.getUTCDate() - KEEP_DAYS);
|
|
1131
|
+
const cutoffStr = cutoff.toISOString().slice(0, 10).replace(/-/g, "");
|
|
1132
|
+
const files = await fs2.readdir(LOG_DIR);
|
|
1133
|
+
for (const file of files) {
|
|
1134
|
+
if (!file.startsWith(LOG_PREFIX + "."))
|
|
1135
|
+
continue;
|
|
1136
|
+
const escapedPrefix = LOG_PREFIX.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1137
|
+
const match = file.match(new RegExp(`^${escapedPrefix}\\.(\\d{8})\\.log$`));
|
|
1138
|
+
if (!match)
|
|
1139
|
+
continue;
|
|
1140
|
+
if (match[1] < cutoffStr) {
|
|
1141
|
+
await fs2.unlink(path2.join(LOG_DIR, file)).catch(() => {});
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
} catch {}
|
|
1145
|
+
}
|
|
1146
|
+
async function appendLog(tag, message, err) {
|
|
1147
|
+
try {
|
|
1148
|
+
const logPath = getLogPath();
|
|
1149
|
+
await fs2.mkdir(LOG_DIR, { recursive: true });
|
|
1150
|
+
const now = new Date().toISOString();
|
|
1151
|
+
let line = `[${now}] [oh-my-opencode-cohub] [${tag}] ${message}`;
|
|
1152
|
+
if (err instanceof Error) {
|
|
1153
|
+
line += `
|
|
1154
|
+
stack: ${err.stack ?? err.message}`;
|
|
1155
|
+
} else if (err !== undefined) {
|
|
1156
|
+
line += `
|
|
1157
|
+
detail: ${String(err)}`;
|
|
1158
|
+
}
|
|
1159
|
+
line += `
|
|
1160
|
+
`;
|
|
1161
|
+
await fs2.appendFile(logPath, line, "utf-8");
|
|
1162
|
+
await cleanOldLogsOnce();
|
|
1163
|
+
} catch {}
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
// src/tools/council.ts
|
|
1104
1167
|
var z = tool.schema;
|
|
1105
1168
|
|
|
1106
1169
|
class OperationTimeoutError extends Error {
|
|
@@ -1127,14 +1190,16 @@ function parseModelReference(model) {
|
|
|
1127
1190
|
async function abortSession(client, sessionId) {
|
|
1128
1191
|
try {
|
|
1129
1192
|
await client.session.abort({ path: { id: sessionId } });
|
|
1130
|
-
} catch {
|
|
1193
|
+
} catch (err) {
|
|
1194
|
+
appendLog("abortSession", "中止会话失败", err);
|
|
1195
|
+
}
|
|
1131
1196
|
}
|
|
1132
|
-
async function promptWithTimeout(client,
|
|
1133
|
-
const sessionId =
|
|
1197
|
+
async function promptWithTimeout(client, path3, body, timeoutMs, directory) {
|
|
1198
|
+
const sessionId = path3.id;
|
|
1134
1199
|
let timer;
|
|
1135
1200
|
try {
|
|
1136
1201
|
const promptPromise = client.session.prompt({
|
|
1137
|
-
path:
|
|
1202
|
+
path: path3,
|
|
1138
1203
|
body,
|
|
1139
1204
|
query: directory ? { directory } : undefined
|
|
1140
1205
|
});
|
|
@@ -1143,7 +1208,7 @@ async function promptWithTimeout(client, path2, body, timeoutMs, directory) {
|
|
|
1143
1208
|
if (timeoutMs > 0) {
|
|
1144
1209
|
racers.push(new Promise((_, reject) => {
|
|
1145
1210
|
timer = setTimeout(() => {
|
|
1146
|
-
reject(new OperationTimeoutError(`Prompt timed out after ${timeoutMs}ms`));
|
|
1211
|
+
reject(new OperationTimeoutError(`[oh-my-opencode-cohub] Prompt timed out after ${timeoutMs}ms`));
|
|
1147
1212
|
}, timeoutMs);
|
|
1148
1213
|
}));
|
|
1149
1214
|
}
|
|
@@ -1354,7 +1419,7 @@ class CouncilManager {
|
|
|
1354
1419
|
async runAgentSession(options) {
|
|
1355
1420
|
const modelRef = parseModelReference(options.model);
|
|
1356
1421
|
if (!modelRef) {
|
|
1357
|
-
throw new Error(`Invalid model format: ${options.model}`);
|
|
1422
|
+
throw new Error(`[oh-my-opencode-cohub] Invalid model format: ${options.model}`);
|
|
1358
1423
|
}
|
|
1359
1424
|
let sessionId;
|
|
1360
1425
|
try {
|
|
@@ -1366,9 +1431,12 @@ class CouncilManager {
|
|
|
1366
1431
|
query: { directory: this.directory }
|
|
1367
1432
|
});
|
|
1368
1433
|
if (!session.data?.id) {
|
|
1369
|
-
throw new Error("Failed to create session");
|
|
1434
|
+
throw new Error("[oh-my-opencode-cohub] Failed to create session");
|
|
1370
1435
|
}
|
|
1371
1436
|
sessionId = session.data.id;
|
|
1437
|
+
if (!options.promptText) {
|
|
1438
|
+
throw new Error("[oh-my-opencode-cohub] PromptText is empty");
|
|
1439
|
+
}
|
|
1372
1440
|
const promptBody = {
|
|
1373
1441
|
model: modelRef,
|
|
1374
1442
|
tools: {
|
|
@@ -1388,7 +1456,7 @@ class CouncilManager {
|
|
|
1388
1456
|
await promptWithTimeout(this.client, { id: sessionId }, promptBody, options.timeout, this.directory);
|
|
1389
1457
|
const extraction = await extractSessionResult(this.client, sessionId);
|
|
1390
1458
|
if (extraction.empty) {
|
|
1391
|
-
throw new Error("Empty response from provider");
|
|
1459
|
+
throw new Error("[oh-my-opencode-cohub] Empty response from provider");
|
|
1392
1460
|
}
|
|
1393
1461
|
return extraction.text;
|
|
1394
1462
|
} finally {
|
|
@@ -1417,7 +1485,7 @@ function createCouncilTool(ctx, councilManager) {
|
|
|
1417
1485
|
const allowedAgents = ["co-council"];
|
|
1418
1486
|
const callingAgent = toolContext.agent;
|
|
1419
1487
|
if (callingAgent && !allowedAgents.includes(callingAgent)) {
|
|
1420
|
-
throw new Error(`Council sessions can only be invoked by the co-council agent. Current agent: ${callingAgent}`);
|
|
1488
|
+
throw new Error(`[oh-my-opencode-cohub] Council sessions can only be invoked by the co-council agent. Current agent: ${callingAgent}`);
|
|
1421
1489
|
}
|
|
1422
1490
|
const prompt = String(args.prompt);
|
|
1423
1491
|
const preset = typeof args.preset === "string" ? args.preset : undefined;
|
|
@@ -1441,9 +1509,9 @@ function createCouncilTool(ctx, councilManager) {
|
|
|
1441
1509
|
}
|
|
1442
1510
|
|
|
1443
1511
|
// src/index.ts
|
|
1444
|
-
import * as
|
|
1445
|
-
import * as
|
|
1446
|
-
import * as
|
|
1512
|
+
import * as fs3 from "node:fs";
|
|
1513
|
+
import * as path3 from "node:path";
|
|
1514
|
+
import * as os3 from "node:os";
|
|
1447
1515
|
function loadFileOverrides(projectDir) {
|
|
1448
1516
|
const overrides = {};
|
|
1449
1517
|
const agentNames = [
|
|
@@ -1462,22 +1530,26 @@ function loadFileOverrides(projectDir) {
|
|
|
1462
1530
|
];
|
|
1463
1531
|
const searchDirs = [];
|
|
1464
1532
|
if (projectDir) {
|
|
1465
|
-
searchDirs.push(
|
|
1533
|
+
searchDirs.push(path3.join(projectDir, ".opencode", "oh-my-opencode-cohub"));
|
|
1466
1534
|
}
|
|
1467
|
-
searchDirs.push(
|
|
1535
|
+
searchDirs.push(path3.join(os3.homedir(), ".config", "opencode", "oh-my-opencode-cohub"));
|
|
1468
1536
|
for (const agent of agentNames) {
|
|
1469
1537
|
for (const dir of searchDirs) {
|
|
1470
|
-
const replacePath =
|
|
1471
|
-
if (!overrides[agent]?.replace &&
|
|
1538
|
+
const replacePath = path3.join(dir, `${agent}.md`);
|
|
1539
|
+
if (!overrides[agent]?.replace && fs3.existsSync(replacePath)) {
|
|
1472
1540
|
try {
|
|
1473
|
-
overrides[agent] = { ...overrides[agent], replace:
|
|
1474
|
-
} catch {
|
|
1541
|
+
overrides[agent] = { ...overrides[agent], replace: fs3.readFileSync(replacePath, "utf-8") };
|
|
1542
|
+
} catch (err) {
|
|
1543
|
+
appendLog("loadFileOverrides", "读取replace文件失败", err);
|
|
1544
|
+
}
|
|
1475
1545
|
}
|
|
1476
|
-
const appendPath =
|
|
1477
|
-
if (!overrides[agent]?.append &&
|
|
1546
|
+
const appendPath = path3.join(dir, `${agent}_append.md`);
|
|
1547
|
+
if (!overrides[agent]?.append && fs3.existsSync(appendPath)) {
|
|
1478
1548
|
try {
|
|
1479
|
-
overrides[agent] = { ...overrides[agent], append:
|
|
1480
|
-
} catch {
|
|
1549
|
+
overrides[agent] = { ...overrides[agent], append: fs3.readFileSync(appendPath, "utf-8") };
|
|
1550
|
+
} catch (err) {
|
|
1551
|
+
appendLog("loadFileOverrides", "读取append文件失败", err);
|
|
1552
|
+
}
|
|
1481
1553
|
}
|
|
1482
1554
|
}
|
|
1483
1555
|
}
|
|
@@ -1505,26 +1577,26 @@ var CoHubPlugin = async (input, options) => {
|
|
|
1505
1577
|
}
|
|
1506
1578
|
const promptOverrides = { ...configOverrides, ...fileOverrides };
|
|
1507
1579
|
const tracker = new TaskTracker;
|
|
1508
|
-
const STATE_DIR =
|
|
1509
|
-
const STATE_FILE =
|
|
1580
|
+
const STATE_DIR = path3.join(os3.homedir(), ".local", "share", "opencode", "storage", "oh-my-opencode-cohub");
|
|
1581
|
+
const STATE_FILE = path3.join(STATE_DIR, "tracker-state.json");
|
|
1510
1582
|
function syncTrackerState(sessionId) {
|
|
1511
1583
|
try {
|
|
1512
|
-
if (!
|
|
1513
|
-
|
|
1584
|
+
if (!fs3.existsSync(STATE_DIR)) {
|
|
1585
|
+
fs3.mkdirSync(STATE_DIR, { recursive: true });
|
|
1514
1586
|
}
|
|
1515
1587
|
const state = {
|
|
1516
1588
|
updatedAt: Date.now(),
|
|
1517
1589
|
runningAgents: tracker.getRunningAgents(sessionId),
|
|
1518
1590
|
runningCount: tracker.getRunningCount(sessionId)
|
|
1519
1591
|
};
|
|
1520
|
-
|
|
1592
|
+
fs3.writeFileSync(STATE_FILE, JSON.stringify(state), "utf-8");
|
|
1521
1593
|
} catch {}
|
|
1522
1594
|
}
|
|
1523
|
-
const AGENT_CONFIG_FILE =
|
|
1595
|
+
const AGENT_CONFIG_FILE = path3.join(STATE_DIR, "cohub-state.json");
|
|
1524
1596
|
function syncAgentConfig() {
|
|
1525
1597
|
try {
|
|
1526
|
-
if (!
|
|
1527
|
-
|
|
1598
|
+
if (!fs3.existsSync(STATE_DIR)) {
|
|
1599
|
+
fs3.mkdirSync(STATE_DIR, { recursive: true });
|
|
1528
1600
|
}
|
|
1529
1601
|
const configs = agents.map((a) => {
|
|
1530
1602
|
const modelStr = a.config.model;
|
|
@@ -1539,7 +1611,7 @@ var CoHubPlugin = async (input, options) => {
|
|
|
1539
1611
|
provider
|
|
1540
1612
|
};
|
|
1541
1613
|
});
|
|
1542
|
-
|
|
1614
|
+
fs3.writeFileSync(AGENT_CONFIG_FILE, JSON.stringify({ updatedAt: Date.now(), agents: configs }), "utf-8");
|
|
1543
1615
|
} catch {}
|
|
1544
1616
|
}
|
|
1545
1617
|
const agents = [
|
|
@@ -1690,12 +1762,16 @@ var CoHubPlugin = async (input, options) => {
|
|
|
1690
1762
|
const cleanupTimer = setInterval(() => {
|
|
1691
1763
|
try {
|
|
1692
1764
|
tracker.cleanupStaleJobs(STALE_TIMEOUT_MS);
|
|
1693
|
-
} catch {
|
|
1765
|
+
} catch (err) {
|
|
1766
|
+
appendLog("cleanupStaleJobs", "定时清理过期任务失败", err);
|
|
1767
|
+
}
|
|
1694
1768
|
}, 30000);
|
|
1695
1769
|
const contextCleanupTimer = setInterval(() => {
|
|
1696
1770
|
try {
|
|
1697
1771
|
contextEngine.cleanupStaleDependencies();
|
|
1698
|
-
} catch {
|
|
1772
|
+
} catch (err) {
|
|
1773
|
+
appendLog("contextCleanupTimer", "定时清理上下文失败", err);
|
|
1774
|
+
}
|
|
1699
1775
|
}, 60000);
|
|
1700
1776
|
const agentConfigs = {};
|
|
1701
1777
|
for (const agent of agents) {
|
|
@@ -1716,8 +1792,10 @@ var CoHubPlugin = async (input, options) => {
|
|
|
1716
1792
|
c.agent[name] = config;
|
|
1717
1793
|
}
|
|
1718
1794
|
try {
|
|
1719
|
-
|
|
1720
|
-
} catch {
|
|
1795
|
+
fs3.writeFileSync(path3.join(STATE_DIR, "config-hook-ran.json"), JSON.stringify({ ran: true, count: agents.length }));
|
|
1796
|
+
} catch (err) {
|
|
1797
|
+
appendLog("config", "双重注册写入文件失败", err);
|
|
1798
|
+
}
|
|
1721
1799
|
},
|
|
1722
1800
|
"tool.execute.before": async (input2, output) => {
|
|
1723
1801
|
try {
|
|
@@ -1754,19 +1832,19 @@ var CoHubPlugin = async (input, options) => {
|
|
|
1754
1832
|
if (details) {
|
|
1755
1833
|
output.args[targetField] += details;
|
|
1756
1834
|
}
|
|
1757
|
-
const logPath =
|
|
1835
|
+
const logPath = path3.join(os3.tmpdir(), "opencode", "ctx-diag.log");
|
|
1758
1836
|
try {
|
|
1759
|
-
const stat =
|
|
1837
|
+
const stat = fs3.statSync(logPath);
|
|
1760
1838
|
if (stat.size > 50 * 1024) {
|
|
1761
|
-
const lines =
|
|
1839
|
+
const lines = fs3.readFileSync(logPath, "utf-8").trim().split(`
|
|
1762
1840
|
`);
|
|
1763
|
-
|
|
1841
|
+
fs3.writeFileSync(logPath, lines.slice(-30).join(`
|
|
1764
1842
|
`) + `
|
|
1765
1843
|
`);
|
|
1766
1844
|
}
|
|
1767
1845
|
} catch {}
|
|
1768
1846
|
const finalPrompt = typeof output.args?.prompt === "string" ? output.args.prompt : "";
|
|
1769
|
-
|
|
1847
|
+
fs3.appendFileSync(logPath, JSON.stringify({
|
|
1770
1848
|
time: new Date().toISOString(),
|
|
1771
1849
|
session: input2.sessionID?.slice(0, 20) ?? "?",
|
|
1772
1850
|
subagent: subagentType,
|
|
@@ -1782,7 +1860,7 @@ var CoHubPlugin = async (input, options) => {
|
|
|
1782
1860
|
}
|
|
1783
1861
|
}
|
|
1784
1862
|
} catch (err) {
|
|
1785
|
-
|
|
1863
|
+
appendLog("tool.execute.before", "hook 失败", err);
|
|
1786
1864
|
}
|
|
1787
1865
|
},
|
|
1788
1866
|
"tool.execute.after": async (input2, output) => {
|
|
@@ -1799,7 +1877,9 @@ var CoHubPlugin = async (input, options) => {
|
|
|
1799
1877
|
tracker.updateAfterTask(input2.sessionID, "completed", childSessionId);
|
|
1800
1878
|
syncTrackerState(input2.sessionID ?? "");
|
|
1801
1879
|
}
|
|
1802
|
-
} catch {
|
|
1880
|
+
} catch (err) {
|
|
1881
|
+
appendLog("tool.execute.after", "hook 失败", err);
|
|
1882
|
+
}
|
|
1803
1883
|
},
|
|
1804
1884
|
event: async (input2) => {
|
|
1805
1885
|
try {
|
|
@@ -1821,7 +1901,9 @@ var CoHubPlugin = async (input, options) => {
|
|
|
1821
1901
|
tracker.updateByChildSessionId(sessionId, "errored");
|
|
1822
1902
|
syncTrackerState(tracker.currentParentSessionId);
|
|
1823
1903
|
}
|
|
1824
|
-
} catch {
|
|
1904
|
+
} catch (err) {
|
|
1905
|
+
appendLog("event", "事件处理失败", err);
|
|
1906
|
+
}
|
|
1825
1907
|
},
|
|
1826
1908
|
"experimental.chat.messages.transform": async (_input, output) => {
|
|
1827
1909
|
try {
|
|
@@ -1831,7 +1913,7 @@ var CoHubPlugin = async (input, options) => {
|
|
|
1831
1913
|
let sessionID;
|
|
1832
1914
|
for (let i = output.messages.length - 1;i >= 0; i--) {
|
|
1833
1915
|
const m = output.messages[i];
|
|
1834
|
-
if (m.info
|
|
1916
|
+
if (m.info?.role === "user") {
|
|
1835
1917
|
lastUserMsg = m;
|
|
1836
1918
|
sessionID = m.info?.sessionID;
|
|
1837
1919
|
break;
|
|
@@ -1839,12 +1921,14 @@ var CoHubPlugin = async (input, options) => {
|
|
|
1839
1921
|
}
|
|
1840
1922
|
if (!lastUserMsg)
|
|
1841
1923
|
return;
|
|
1924
|
+
if (!lastUserMsg.parts || !Array.isArray(lastUserMsg.parts))
|
|
1925
|
+
return;
|
|
1842
1926
|
const board = tracker.getBoardText();
|
|
1843
1927
|
if (board) {
|
|
1844
1928
|
for (let j = lastUserMsg.parts.length - 1;j >= 0; j--) {
|
|
1845
1929
|
const part = lastUserMsg.parts[j];
|
|
1846
1930
|
if (part.type === "text") {
|
|
1847
|
-
part.text
|
|
1931
|
+
part.text = (part.text || "") + `
|
|
1848
1932
|
|
|
1849
1933
|
` + board;
|
|
1850
1934
|
break;
|
|
@@ -1855,17 +1939,23 @@ var CoHubPlugin = async (input, options) => {
|
|
|
1855
1939
|
for (let k = lastUserMsg.parts.length - 1;k >= 0; k--) {
|
|
1856
1940
|
const part = lastUserMsg.parts[k];
|
|
1857
1941
|
if (part.type === "text") {
|
|
1858
|
-
part.text
|
|
1942
|
+
part.text = (part.text || "") + coreRulesInjectionText;
|
|
1859
1943
|
break;
|
|
1860
1944
|
}
|
|
1861
1945
|
}
|
|
1862
1946
|
}
|
|
1863
1947
|
} catch (err) {
|
|
1864
|
-
|
|
1948
|
+
appendLog("messages.transform", "hook 失败", err);
|
|
1865
1949
|
}
|
|
1866
1950
|
},
|
|
1867
1951
|
"experimental.chat.system.transform": async (input2, output) => {
|
|
1868
|
-
|
|
1952
|
+
try {
|
|
1953
|
+
if (output?.system && Array.isArray(output.system)) {
|
|
1954
|
+
output.system.push(CHINESE_LANGUAGE_INSTRUCTION);
|
|
1955
|
+
}
|
|
1956
|
+
} catch (err) {
|
|
1957
|
+
appendLog("system.transform", "hook 失败", err);
|
|
1958
|
+
}
|
|
1869
1959
|
},
|
|
1870
1960
|
dispose: async () => {
|
|
1871
1961
|
clearInterval(cleanupTimer);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"council.d.ts","sourceRoot":"","sources":["../../src/tools/council.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"council.d.ts","sourceRoot":"","sources":["../../src/tools/council.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAW7D,MAAM,WAAW,gBAAgB;IAC/B,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,CAAC,cAAc,EAAE,MAAM,GAAG,gBAAgB,CAAC;CAC5C;AAED,MAAM,WAAW,aAAa;IAC5B,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACvC,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2CAA2C;IAC3C,yBAAyB,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IAClD,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,uCAAuC;AACvC,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA+OD,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAA0C;IACxD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAgB;gBAG5B,MAAM,EAAE,UAAU,CAAC,OAAO,oBAAoB,CAAC,EAC/C,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,aAAa;IAOvB;;;OAGG;IACG,UAAU,CACd,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;KACvC,CAAC;YA2DY,cAAc;YA8Cd,sBAAsB;YAkDtB,eAAe;CAgF9B;AAMD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,WAAW,EAChB,cAAc,EAAE,cAAc,GAC7B,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAyDzC"}
|
package/dist/tui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../src/tui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AA+E/D,QAAA,MAAM,MAAM,EAAE,eA2Gb,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/tui.js
CHANGED
|
@@ -1,14 +1,77 @@
|
|
|
1
1
|
// src/tui.ts
|
|
2
2
|
import { jsx } from "@opentui/solid/jsx-runtime";
|
|
3
|
-
import * as
|
|
4
|
-
import * as
|
|
5
|
-
import * as
|
|
6
|
-
|
|
3
|
+
import * as fs2 from "node:fs";
|
|
4
|
+
import * as path2 from "node:path";
|
|
5
|
+
import * as os2 from "node:os";
|
|
6
|
+
|
|
7
|
+
// src/utils/log.ts
|
|
8
|
+
import * as fs from "fs/promises";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
import * as os from "os";
|
|
11
|
+
var LOG_DIR = path.join(os.homedir(), ".local", "share", "opencode", "log");
|
|
12
|
+
var LOG_PREFIX = "oh-my-opencode-cohub";
|
|
13
|
+
var KEEP_DAYS = 7;
|
|
14
|
+
var _today = "";
|
|
15
|
+
var _logPath = "";
|
|
16
|
+
var _cleanedToday = false;
|
|
17
|
+
function getLogPath() {
|
|
18
|
+
const today = new Date().toISOString().slice(0, 10).replace(/-/g, "");
|
|
19
|
+
if (today !== _today) {
|
|
20
|
+
_today = today;
|
|
21
|
+
_logPath = path.join(LOG_DIR, `${LOG_PREFIX}.${today}.log`);
|
|
22
|
+
_cleanedToday = false;
|
|
23
|
+
}
|
|
24
|
+
return _logPath;
|
|
25
|
+
}
|
|
26
|
+
async function cleanOldLogsOnce() {
|
|
27
|
+
if (_cleanedToday)
|
|
28
|
+
return;
|
|
29
|
+
_cleanedToday = true;
|
|
30
|
+
try {
|
|
31
|
+
const cutoff = new Date;
|
|
32
|
+
cutoff.setUTCDate(cutoff.getUTCDate() - KEEP_DAYS);
|
|
33
|
+
const cutoffStr = cutoff.toISOString().slice(0, 10).replace(/-/g, "");
|
|
34
|
+
const files = await fs.readdir(LOG_DIR);
|
|
35
|
+
for (const file of files) {
|
|
36
|
+
if (!file.startsWith(LOG_PREFIX + "."))
|
|
37
|
+
continue;
|
|
38
|
+
const escapedPrefix = LOG_PREFIX.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
39
|
+
const match = file.match(new RegExp(`^${escapedPrefix}\\.(\\d{8})\\.log$`));
|
|
40
|
+
if (!match)
|
|
41
|
+
continue;
|
|
42
|
+
if (match[1] < cutoffStr) {
|
|
43
|
+
await fs.unlink(path.join(LOG_DIR, file)).catch(() => {});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} catch {}
|
|
47
|
+
}
|
|
48
|
+
async function appendLog(tag, message, err) {
|
|
49
|
+
try {
|
|
50
|
+
const logPath = getLogPath();
|
|
51
|
+
await fs.mkdir(LOG_DIR, { recursive: true });
|
|
52
|
+
const now = new Date().toISOString();
|
|
53
|
+
let line = `[${now}] [oh-my-opencode-cohub] [${tag}] ${message}`;
|
|
54
|
+
if (err instanceof Error) {
|
|
55
|
+
line += `
|
|
56
|
+
stack: ${err.stack ?? err.message}`;
|
|
57
|
+
} else if (err !== undefined) {
|
|
58
|
+
line += `
|
|
59
|
+
detail: ${String(err)}`;
|
|
60
|
+
}
|
|
61
|
+
line += `
|
|
62
|
+
`;
|
|
63
|
+
await fs.appendFile(logPath, line, "utf-8");
|
|
64
|
+
await cleanOldLogsOnce();
|
|
65
|
+
} catch {}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/tui.ts
|
|
69
|
+
var AGENT_CONFIG_FILE = path2.join(os2.homedir(), ".config", "opencode", "oh-my-opencode-cohub.json");
|
|
7
70
|
function loadAgentConfig() {
|
|
8
71
|
try {
|
|
9
|
-
if (!
|
|
72
|
+
if (!fs2.existsSync(AGENT_CONFIG_FILE))
|
|
10
73
|
return DEFAULT_AGENTS();
|
|
11
|
-
const data = JSON.parse(
|
|
74
|
+
const data = JSON.parse(fs2.readFileSync(AGENT_CONFIG_FILE, "utf-8"));
|
|
12
75
|
const agents = data.agents;
|
|
13
76
|
if (!agents)
|
|
14
77
|
return DEFAULT_AGENTS();
|
|
@@ -25,7 +88,8 @@ function loadAgentConfig() {
|
|
|
25
88
|
provider
|
|
26
89
|
};
|
|
27
90
|
});
|
|
28
|
-
} catch {
|
|
91
|
+
} catch (err) {
|
|
92
|
+
appendLog("tui.loadAgentConfig", "读取代理配置失败,使用默认值", err);
|
|
29
93
|
return DEFAULT_AGENTS();
|
|
30
94
|
}
|
|
31
95
|
}
|
|
@@ -55,14 +119,15 @@ function DEFAULT_AGENTS() {
|
|
|
55
119
|
};
|
|
56
120
|
});
|
|
57
121
|
}
|
|
58
|
-
var STATE_FILE =
|
|
122
|
+
var STATE_FILE = path2.join(os2.homedir(), ".local", "share", "opencode", "storage", "oh-my-opencode-cohub", "tracker-state.json");
|
|
59
123
|
var SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
60
124
|
function readState() {
|
|
61
125
|
try {
|
|
62
|
-
if (!
|
|
126
|
+
if (!fs2.existsSync(STATE_FILE))
|
|
63
127
|
return null;
|
|
64
|
-
return JSON.parse(
|
|
65
|
-
} catch {
|
|
128
|
+
return JSON.parse(fs2.readFileSync(STATE_FILE, "utf-8"));
|
|
129
|
+
} catch (err) {
|
|
130
|
+
appendLog("tui.readState", "读取状态文件失败", err);
|
|
66
131
|
return null;
|
|
67
132
|
}
|
|
68
133
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* oh-my-opencode-cohub 诊断日志工具(按天轮转)
|
|
3
|
+
*
|
|
4
|
+
* 日志路径:~/.local/share/opencode/log/oh-my-opencode-cohub.YYYYMMDD.log
|
|
5
|
+
* 保留天数:7 天(每次切换日期时自动清理过期文件)
|
|
6
|
+
* 格式:[ISO时间] [oh-my-opencode-cohub] [tag] message
|
|
7
|
+
*
|
|
8
|
+
* 内部 try-catch 自保护——日志写入失败不影响主业务。
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* 追加一条诊断日志
|
|
12
|
+
*
|
|
13
|
+
* @param tag 标签(如 hook 名称、函数名)
|
|
14
|
+
* @param message 描述信息
|
|
15
|
+
* @param err 可选,错误对象,存在时会自动追加 err.stack
|
|
16
|
+
*/
|
|
17
|
+
export declare function appendLog(tag: string, message: string, err?: unknown): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/utils/log.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAoDH;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,GAAG,CAAC,EAAE,OAAO,GACZ,OAAO,CAAC,IAAI,CAAC,CAoBf"}
|