opencode-subagent-magazine 1.7.1 → 1.7.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/_version.d.ts +1 -1
- package/dist/tui.js +1 -1
- package/dist/v2.js +1 -1
- package/package.json +17 -4
- package/dist/_version.js +0 -2
- package/dist/clipboard.js +0 -85
- package/dist/core/color.js +0 -68
- package/dist/core/format.js +0 -113
- package/dist/core/index.js +0 -6
- package/dist/core/kv.js +0 -64
- package/dist/core/state-machine.js +0 -27
- package/dist/core/types.js +0 -9
- package/dist/core/usage.js +0 -1
- package/dist/i18n.js +0 -353
- package/dist/index.js +0 -528
- package/dist/panel/SubAgentPanel.js +0 -1644
- package/dist/panel/entry-map.js +0 -99
- package/dist/panel/panel-api.js +0 -1
- package/dist/panel/session-routing.js +0 -4
- package/dist/panel/store.js +0 -5
- package/dist/server.js +0 -14
- package/dist/v2/commands.js +0 -434
- package/dist/v2/db.js +0 -341
- package/dist/v2/index.js +0 -85
- package/dist/v2/settings-menu.js +0 -242
- package/dist/v2/theme.js +0 -12
- package/dist/v2/types.js +0 -6
- package/dist/v2/v2-panel-api.js +0 -623
- package/src/_version.ts +0 -2
- package/src/clipboard.ts +0 -134
- package/src/core/color.ts +0 -70
- package/src/core/format.ts +0 -105
- package/src/core/index.ts +0 -6
- package/src/core/kv.ts +0 -78
- package/src/core/state-machine.ts +0 -46
- package/src/core/types.ts +0 -85
- package/src/core/usage.ts +0 -16
- package/src/i18n.ts +0 -365
- package/src/index.tsx +0 -584
- package/src/panel/SubAgentPanel.tsx +0 -1877
- package/src/panel/entry-map.ts +0 -116
- package/src/panel/panel-api.ts +0 -100
- package/src/panel/session-routing.ts +0 -10
- package/src/panel/store.ts +0 -8
- package/src/server.ts +0 -19
- package/src/v2/commands.ts +0 -422
- package/src/v2/db.ts +0 -346
- package/src/v2/index.tsx +0 -149
- package/src/v2/settings-menu.ts +0 -259
- package/src/v2/theme.ts +0 -14
- package/src/v2/types.ts +0 -167
- package/src/v2/v2-panel-api.ts +0 -520
package/dist/_version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PLUGIN_VERSION = "1.7.
|
|
1
|
+
export declare const PLUGIN_VERSION = "1.7.2";
|
package/dist/tui.js
CHANGED
package/dist/v2.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-subagent-magazine",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.2",
|
|
4
4
|
"description": "OpenCode TUI plugin monitoring sub-agent invocation status in real time",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"dist",
|
|
18
|
-
"src",
|
|
19
18
|
"tui",
|
|
20
19
|
"install.mjs",
|
|
21
20
|
"README.md"
|
|
@@ -24,12 +23,12 @@
|
|
|
24
23
|
"opencode-subagent-magazine": "install.mjs"
|
|
25
24
|
},
|
|
26
25
|
"scripts": {
|
|
27
|
-
"build": "tsc && node build.tui.mjs",
|
|
26
|
+
"build": "tsc --emitDeclarationOnly && node build.tui.mjs",
|
|
28
27
|
"build:tui": "node build.tui.mjs",
|
|
29
28
|
"typecheck": "tsc --noEmit",
|
|
30
29
|
"test": "tsx --test tests/*.test.ts",
|
|
31
30
|
"version": "node -e \"require('fs').writeFileSync('src/_version.ts','// auto-generated\\nexport const PLUGIN_VERSION='+JSON.stringify(require('./package.json').version)+';\\n')\"",
|
|
32
|
-
"prepublishOnly": "tsc"
|
|
31
|
+
"prepublishOnly": "tsc --noEmit"
|
|
33
32
|
},
|
|
34
33
|
"keywords": [
|
|
35
34
|
"opencode",
|
|
@@ -54,9 +53,23 @@
|
|
|
54
53
|
"peerDependenciesMeta": {
|
|
55
54
|
"@opencode/plugin": {
|
|
56
55
|
"optional": true
|
|
56
|
+
},
|
|
57
|
+
"@opencode-ai/plugin": {
|
|
58
|
+
"optional": true
|
|
59
|
+
},
|
|
60
|
+
"@opencode-ai/sdk": {
|
|
61
|
+
"optional": true
|
|
62
|
+
},
|
|
63
|
+
"@opentui/core": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"@opentui/solid": {
|
|
67
|
+
"optional": true
|
|
57
68
|
}
|
|
58
69
|
},
|
|
59
70
|
"devDependencies": {
|
|
71
|
+
"@opentui/core": "^0.5.8",
|
|
72
|
+
"@opentui/solid": "^0.5.8",
|
|
60
73
|
"@opencode-ai/plugin": "^1.14.50",
|
|
61
74
|
"@opencode-ai/sdk": "^1.14.50",
|
|
62
75
|
"@types/node": "^22.0.0",
|
package/dist/_version.js
DELETED
package/dist/clipboard.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import { platform, release } from "node:os";
|
|
3
|
-
function runWithInput(command, args, input) {
|
|
4
|
-
return new Promise((resolve, reject) => {
|
|
5
|
-
const child = spawn(command, args, {
|
|
6
|
-
stdio: ["pipe", "ignore", "ignore"],
|
|
7
|
-
windowsHide: true,
|
|
8
|
-
});
|
|
9
|
-
child.once("error", reject);
|
|
10
|
-
child.once("close", (code) => {
|
|
11
|
-
if (code === 0)
|
|
12
|
-
resolve();
|
|
13
|
-
else
|
|
14
|
-
reject(new Error(`${command} exited with code ${code}`));
|
|
15
|
-
});
|
|
16
|
-
child.stdin?.end(input);
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
function writeOsc52(text) {
|
|
20
|
-
if (!process.stdout.isTTY)
|
|
21
|
-
return false;
|
|
22
|
-
const payload = Buffer.from(text, "utf8").toString("base64");
|
|
23
|
-
const sequence = `\x1b]52;c;${payload}\x07`;
|
|
24
|
-
const wrapped = process.env.TMUX || process.env.STY
|
|
25
|
-
? `\x1bPtmux;\x1b${sequence}\x1b\\`
|
|
26
|
-
: sequence;
|
|
27
|
-
process.stdout.write(wrapped);
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
async function tryCommand(method, command, args, text) {
|
|
31
|
-
try {
|
|
32
|
-
await runWithInput(command, args, text);
|
|
33
|
-
return { copied: true, method };
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
return undefined;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
export async function copyText(text) {
|
|
40
|
-
if (!text)
|
|
41
|
-
return { copied: false, method: "none", error: "empty_text" };
|
|
42
|
-
const os = platform();
|
|
43
|
-
const isWsl = release().toLowerCase().includes("microsoft");
|
|
44
|
-
const attempts = [];
|
|
45
|
-
if (os === "darwin") {
|
|
46
|
-
attempts.push(() => tryCommand("pbcopy", "pbcopy", [], text));
|
|
47
|
-
attempts.push(() => tryCommand("osascript", "osascript", ["-e", "set the clipboard to (read (POSIX file \"/dev/stdin\") as text)"], text));
|
|
48
|
-
}
|
|
49
|
-
if (os === "linux" && isWsl) {
|
|
50
|
-
attempts.push(() => tryCommand("powershell", "powershell.exe", [
|
|
51
|
-
"-NonInteractive",
|
|
52
|
-
"-NoProfile",
|
|
53
|
-
"-Command",
|
|
54
|
-
"[Console]::InputEncoding=[Text.Encoding]::UTF8; Set-Clipboard ([Console]::In.ReadToEnd())",
|
|
55
|
-
], text));
|
|
56
|
-
}
|
|
57
|
-
else if (os === "linux") {
|
|
58
|
-
if (process.env.WAYLAND_DISPLAY) {
|
|
59
|
-
attempts.push(() => tryCommand("wl-copy", "wl-copy", [], text));
|
|
60
|
-
}
|
|
61
|
-
attempts.push(() => tryCommand("xclip", "xclip", ["-selection", "clipboard"], text));
|
|
62
|
-
attempts.push(() => tryCommand("xsel", "xsel", ["--clipboard", "--input"], text));
|
|
63
|
-
}
|
|
64
|
-
if (os === "win32") {
|
|
65
|
-
attempts.push(() => tryCommand("powershell", "powershell.exe", [
|
|
66
|
-
"-NonInteractive",
|
|
67
|
-
"-NoProfile",
|
|
68
|
-
"-Command",
|
|
69
|
-
"[Console]::InputEncoding=[Text.Encoding]::UTF8; Set-Clipboard ([Console]::In.ReadToEnd())",
|
|
70
|
-
], text));
|
|
71
|
-
}
|
|
72
|
-
for (const attempt of attempts) {
|
|
73
|
-
const result = await attempt();
|
|
74
|
-
if (result)
|
|
75
|
-
return result;
|
|
76
|
-
}
|
|
77
|
-
try {
|
|
78
|
-
if (writeOsc52(text))
|
|
79
|
-
return { copied: true, method: "osc52" };
|
|
80
|
-
}
|
|
81
|
-
catch {
|
|
82
|
-
// Continue to the explicit failure result.
|
|
83
|
-
}
|
|
84
|
-
return { copied: false, method: "none", error: "clipboard_unavailable" };
|
|
85
|
-
}
|
package/dist/core/color.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/** Morandi palette helpers — desaturate any theme color toward a muted fallback. */
|
|
2
|
-
export function rgb(raw) {
|
|
3
|
-
if (typeof raw === "string" && raw.startsWith("#")) {
|
|
4
|
-
const h = raw.slice(1);
|
|
5
|
-
return {
|
|
6
|
-
r: parseInt(h.slice(0, 2), 16),
|
|
7
|
-
g: parseInt(h.slice(2, 4), 16),
|
|
8
|
-
b: parseInt(h.slice(4, 6), 16),
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
if (raw && typeof raw === "object") {
|
|
12
|
-
const o = raw;
|
|
13
|
-
if (typeof o.r === "number" && typeof o.g === "number" && typeof o.b === "number") {
|
|
14
|
-
const scale = o.r > 1 || o.g > 1 || o.b > 1 ? 1 : 255;
|
|
15
|
-
return { r: Math.round(o.r * scale), g: Math.round(o.g * scale), b: Math.round(o.b * scale) };
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
export function saturation(r, g, b) {
|
|
21
|
-
const max = Math.max(r, g, b) / 255;
|
|
22
|
-
const min = Math.min(r, g, b) / 255;
|
|
23
|
-
const delta = max - min;
|
|
24
|
-
if (delta === 0)
|
|
25
|
-
return 0;
|
|
26
|
-
const L = (max + min) / 2;
|
|
27
|
-
return L <= 0.5 ? delta / (max + min) : delta / (2 - max - min);
|
|
28
|
-
}
|
|
29
|
-
function desaturateTo(raw, maxSat, fallback) {
|
|
30
|
-
const c = rgb(raw);
|
|
31
|
-
if (!c)
|
|
32
|
-
return fallback;
|
|
33
|
-
const sat = saturation(c.r, c.g, c.b);
|
|
34
|
-
if (sat <= maxSat) {
|
|
35
|
-
return "#" + [c.r, c.g, c.b].map((v) => v.toString(16).padStart(2, "0")).join("");
|
|
36
|
-
}
|
|
37
|
-
const luma = c.r * 0.299 + c.g * 0.587 + c.b * 0.114;
|
|
38
|
-
let lo = 0, hi = 1;
|
|
39
|
-
for (let i = 0; i < 12; i++) {
|
|
40
|
-
const mid = (lo + hi) / 2;
|
|
41
|
-
const nr = Math.round(c.r + (luma - c.r) * mid);
|
|
42
|
-
const ng = Math.round(c.g + (luma - c.g) * mid);
|
|
43
|
-
const nb = Math.round(c.b + (luma - c.b) * mid);
|
|
44
|
-
if (saturation(nr, ng, nb) > maxSat)
|
|
45
|
-
lo = mid;
|
|
46
|
-
else
|
|
47
|
-
hi = mid;
|
|
48
|
-
}
|
|
49
|
-
const nr = Math.round(c.r + (luma - c.r) * hi);
|
|
50
|
-
const ng = Math.round(c.g + (luma - c.g) * hi);
|
|
51
|
-
const nb = Math.round(c.b + (luma - c.b) * hi);
|
|
52
|
-
return "#" + [nr, ng, nb].map((v) => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join("");
|
|
53
|
-
}
|
|
54
|
-
function dimColor(hex, factor = 0.5) {
|
|
55
|
-
const c = rgb(hex);
|
|
56
|
-
if (!c)
|
|
57
|
-
return hex;
|
|
58
|
-
const r = Math.round(c.r * factor);
|
|
59
|
-
const g = Math.round(c.g * factor);
|
|
60
|
-
const b = Math.round(c.b * factor);
|
|
61
|
-
return "#" + [r, g, b].map((v) => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join("");
|
|
62
|
-
}
|
|
63
|
-
export const FALLBACK = {
|
|
64
|
-
primary: "#8B9DAF", text: "#C5C5BB", muted: "#7A7A72",
|
|
65
|
-
success: "#9CAF8B", warning: "#C5B88D", error: "#B08A8A", border: "#6B6B63",
|
|
66
|
-
};
|
|
67
|
-
export const MAX_SAT = 0.28;
|
|
68
|
-
export { desaturateTo, dimColor };
|
package/dist/core/format.js
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
/** Visual width of a single character (CJK/wide chars count as 2). */
|
|
2
|
-
function charColumns(c) {
|
|
3
|
-
const code = c.codePointAt(0) ?? 0;
|
|
4
|
-
if (code < 0x20)
|
|
5
|
-
return 0;
|
|
6
|
-
if (code < 0x7f)
|
|
7
|
-
return 1;
|
|
8
|
-
if (code < 0xa0)
|
|
9
|
-
return 0;
|
|
10
|
-
if ((code >= 0x1100 && code <= 0x115f) ||
|
|
11
|
-
(code >= 0x2e80 && code <= 0xa4cf) ||
|
|
12
|
-
(code >= 0xac00 && code <= 0xd7a3) ||
|
|
13
|
-
(code >= 0xf900 && code <= 0xfaff) ||
|
|
14
|
-
(code >= 0xfe10 && code <= 0xfe6f) ||
|
|
15
|
-
(code >= 0xff01 && code <= 0xff60) ||
|
|
16
|
-
(code >= 0xffe0 && code <= 0xffe6) ||
|
|
17
|
-
(code >= 0x1f300 && code <= 0x1f64f) ||
|
|
18
|
-
(code >= 0x20000 && code <= 0x3fffd))
|
|
19
|
-
return 2;
|
|
20
|
-
return 1;
|
|
21
|
-
}
|
|
22
|
-
export function visualWidth(s) {
|
|
23
|
-
let w = 0;
|
|
24
|
-
for (const c of s)
|
|
25
|
-
w += charColumns(c);
|
|
26
|
-
return w;
|
|
27
|
-
}
|
|
28
|
-
export function truncate(text, maxCols) {
|
|
29
|
-
if (visualWidth(text) <= maxCols)
|
|
30
|
-
return text;
|
|
31
|
-
let cols = 0;
|
|
32
|
-
let i = 0;
|
|
33
|
-
for (const c of text) {
|
|
34
|
-
const w = charColumns(c);
|
|
35
|
-
if (cols + w > maxCols - 1)
|
|
36
|
-
break;
|
|
37
|
-
cols += w;
|
|
38
|
-
i += c.length;
|
|
39
|
-
}
|
|
40
|
-
return text.slice(0, i) + "\u2026";
|
|
41
|
-
}
|
|
42
|
-
export function fmtDurationShort(ms, running) {
|
|
43
|
-
if (running && ms < 2000)
|
|
44
|
-
return "";
|
|
45
|
-
if (ms < 1000)
|
|
46
|
-
return (ms / 1000).toFixed(2) + "s";
|
|
47
|
-
if (ms < 60000)
|
|
48
|
-
return (ms / 1000).toFixed(2) + "s";
|
|
49
|
-
const m = Math.floor(ms / 60000);
|
|
50
|
-
const s = Math.round((ms % 60000) / 1000);
|
|
51
|
-
return `${m}m${s}s`;
|
|
52
|
-
}
|
|
53
|
-
/** All supported elapsed-time display modes, in picker order. */
|
|
54
|
-
export const TIME_FORMATS = ["short", "decimal", "clock", "compact", "seconds"];
|
|
55
|
-
/** Neutral samples shown in the time-format picker (language independent). */
|
|
56
|
-
export const TIME_FORMAT_SAMPLES = {
|
|
57
|
-
decimal: "45.3s · 9.5m · 1.9h",
|
|
58
|
-
short: "45.32s · 112m35s",
|
|
59
|
-
clock: "0:45 · 1:52:35",
|
|
60
|
-
compact: "45s · 1h52m",
|
|
61
|
-
seconds: "45s · 6755s",
|
|
62
|
-
};
|
|
63
|
-
/** Formats elapsed milliseconds using the configured display mode. */
|
|
64
|
-
export function fmtDuration(ms, running, mode = "short") {
|
|
65
|
-
if (running && ms < 2000)
|
|
66
|
-
return "";
|
|
67
|
-
const t = Number.isFinite(ms) && ms > 0 ? ms : 0;
|
|
68
|
-
switch (mode) {
|
|
69
|
-
case "short":
|
|
70
|
-
return fmtDurationShort(t, false);
|
|
71
|
-
case "compact": {
|
|
72
|
-
if (t < 60000)
|
|
73
|
-
return `${Math.floor(t / 1000)}s`;
|
|
74
|
-
if (t < 3600000)
|
|
75
|
-
return `${Math.floor(t / 60000)}m${Math.floor((t % 60000) / 1000)}s`;
|
|
76
|
-
return `${Math.floor(t / 3600000)}h${Math.floor((t % 3600000) / 60000)}m`;
|
|
77
|
-
}
|
|
78
|
-
case "clock": {
|
|
79
|
-
const s = Math.floor((t % 60000) / 1000);
|
|
80
|
-
if (t < 3600000)
|
|
81
|
-
return `${Math.floor(t / 60000)}:${String(s).padStart(2, "0")}`;
|
|
82
|
-
const m = Math.floor((t % 3600000) / 60000);
|
|
83
|
-
return `${Math.floor(t / 3600000)}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
|
|
84
|
-
}
|
|
85
|
-
case "seconds":
|
|
86
|
-
return `${Math.floor(t / 1000)}s`;
|
|
87
|
-
case "decimal":
|
|
88
|
-
default: {
|
|
89
|
-
// Promote units when rounding would show "60.0s" / "60.0m".
|
|
90
|
-
if (t < 59950)
|
|
91
|
-
return `${(t / 1000).toFixed(1)}s`;
|
|
92
|
-
if (t < 3597000)
|
|
93
|
-
return `${(t / 60000).toFixed(1)}m`;
|
|
94
|
-
return `${(t / 3600000).toFixed(1)}h`;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
export function fmtTokens(n) {
|
|
99
|
-
if (n < 1000)
|
|
100
|
-
return `${n}`;
|
|
101
|
-
if (n < 1000000)
|
|
102
|
-
return `${(n / 1000).toFixed(1)}k`;
|
|
103
|
-
return `${(n / 1000000).toFixed(1)}M`;
|
|
104
|
-
}
|
|
105
|
-
export function safeErrorMsg(err) {
|
|
106
|
-
if (!err)
|
|
107
|
-
return "";
|
|
108
|
-
if (typeof err === "string")
|
|
109
|
-
return err;
|
|
110
|
-
if (typeof err === "object")
|
|
111
|
-
return String(err.message || err.code || "");
|
|
112
|
-
return "";
|
|
113
|
-
}
|
package/dist/core/index.js
DELETED
package/dist/core/kv.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
export const KV_PREFIX = "subagent_magazine";
|
|
2
|
-
export const SESSION_DATA_KEY = `${KV_PREFIX}.session_data`;
|
|
3
|
-
/** Setting keys shared by V1/V2 (values are raw strings in KV). */
|
|
4
|
-
export const SETTING_KEYS = {
|
|
5
|
-
lang: `${KV_PREFIX}.lang`,
|
|
6
|
-
maxEntries: `${KV_PREFIX}.max_entries`,
|
|
7
|
-
order: `${KV_PREFIX}.order`,
|
|
8
|
-
scrollMode: `${KV_PREFIX}.scroll_mode`,
|
|
9
|
-
open: `${KV_PREFIX}.open`,
|
|
10
|
-
ttlDays: `${KV_PREFIX}.ttl_days`,
|
|
11
|
-
border: `${KV_PREFIX}.border`,
|
|
12
|
-
showEntryCost: `${KV_PREFIX}.show_entry_cost`,
|
|
13
|
-
showEntryTime: `${KV_PREFIX}.show_entry_time`,
|
|
14
|
-
showEntryTokens: `${KV_PREFIX}.show_entry_tokens`,
|
|
15
|
-
timeFormat: `${KV_PREFIX}.time_format`,
|
|
16
|
-
showOrigin: `${KV_PREFIX}.show_origin`,
|
|
17
|
-
dbSync: `${KV_PREFIX}.db_sync`,
|
|
18
|
-
};
|
|
19
|
-
export function loadSessionData(kv) {
|
|
20
|
-
try {
|
|
21
|
-
const raw = kv.get(SESSION_DATA_KEY, "{}");
|
|
22
|
-
return JSON.parse(String(raw));
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
return {};
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Atomic read-merge-write of the session store.
|
|
30
|
-
*
|
|
31
|
-
* `mutator` receives the latest persisted map (read under the host lock when
|
|
32
|
-
* `kv.update` is available) and may mutate it freely; the result is written
|
|
33
|
-
* back. Every writer must go through here: writing a whole in-memory snapshot
|
|
34
|
-
* directly would silently drop entries created by the other TUIs.
|
|
35
|
-
*/
|
|
36
|
-
export function updateSessionData(kv, mutator) {
|
|
37
|
-
try {
|
|
38
|
-
if (typeof kv.update === "function") {
|
|
39
|
-
return kv.update(SESSION_DATA_KEY, (raw) => {
|
|
40
|
-
const data = parseSessionData(raw);
|
|
41
|
-
mutator(data);
|
|
42
|
-
return JSON.stringify(data);
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
// Fallback (V1 hosts without atomic update): read-modify-write. The window
|
|
46
|
-
// is small and the mutation is merged against the value we just read.
|
|
47
|
-
const data = loadSessionData(kv);
|
|
48
|
-
mutator(data);
|
|
49
|
-
kv.set(SESSION_DATA_KEY, JSON.stringify(data));
|
|
50
|
-
}
|
|
51
|
-
catch { }
|
|
52
|
-
}
|
|
53
|
-
function parseSessionData(raw) {
|
|
54
|
-
try {
|
|
55
|
-
return JSON.parse(String(raw ?? "{}"));
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
return {};
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
export function readTTLDays(kv) {
|
|
62
|
-
const ttlDaysRaw = parseInt(String(kv.get(SETTING_KEYS.ttlDays, "3")), 10);
|
|
63
|
-
return Number.isNaN(ttlDaysRaw) ? 3 : ttlDaysRaw;
|
|
64
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/** Final status decision when a child session settles (V1 `session.idle` semantics). */
|
|
2
|
-
export function settleOnIdle(entry) {
|
|
3
|
-
if (entry.status === "cancel_requested" && entry.abortAccepted)
|
|
4
|
-
return "cancelled";
|
|
5
|
-
return "done";
|
|
6
|
-
}
|
|
7
|
-
/** Agent-name normalization used by the fallback matching chain. */
|
|
8
|
-
export function normalizeAgent(s) {
|
|
9
|
-
return s.toLowerCase().replace(/[^a-z0-9-]/g, "");
|
|
10
|
-
}
|
|
11
|
-
/** Apply a settled status + usage backfill onto an entry (no-op preserving already-settled). */
|
|
12
|
-
export function settleEntry(entry, targetStatus, nowTs, snap, errorMsg) {
|
|
13
|
-
const alreadySettled = entry.status !== "running" && entry.status !== "cancel_requested";
|
|
14
|
-
const finalStatus = targetStatus === "error" ? "error" : settleOnIdle(entry);
|
|
15
|
-
return {
|
|
16
|
-
...entry,
|
|
17
|
-
...(alreadySettled ? {} : { status: finalStatus, endedAt: nowTs }),
|
|
18
|
-
tokens: entry.tokens ?? snap.tokens,
|
|
19
|
-
cost: entry.cost ?? snap.cost,
|
|
20
|
-
model: entry.model ?? snap.model,
|
|
21
|
-
todoTotal: entry.todoTotal ?? snap.todo?.total,
|
|
22
|
-
todoDone: entry.todoDone ?? snap.todo?.done,
|
|
23
|
-
error: errorMsg || entry.error,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
/** Time-based scan heuristic: how old must a running entry be before assuming completion. */
|
|
27
|
-
export const STALE_RUNNING_MS = 30 * 60 * 1000;
|
package/dist/core/types.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/** OpenCode built-in tool names that spawn sub-agents or delegate tasks. */
|
|
2
|
-
export const SUBAGENT_TOOLS = new Set(["task", "subagent", "delegate", "call_omo_agent"]);
|
|
3
|
-
/** 工具输入是否声明后台执行(V1/V2 两种字段名)。 */
|
|
4
|
-
export function isBackgroundInput(input) {
|
|
5
|
-
if (!input || typeof input !== "object")
|
|
6
|
-
return false;
|
|
7
|
-
const i = input;
|
|
8
|
-
return i.background === true || i.run_in_background === true;
|
|
9
|
-
}
|
package/dist/core/usage.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|