pybao-cli 1.4.49 → 1.4.51
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/REPL-6YEOSMEP.js +47 -0
- package/dist/{acp-FGRNDOS5.js → acp-2C774HUW.js} +31 -31
- package/dist/{agentsValidate-7CRDPNQ6.js → agentsValidate-RCXZBOU3.js} +7 -7
- package/dist/{ask-IR5W5M66.js → ask-EIO3Q6ED.js} +30 -30
- package/dist/{autoUpdater-MAEQZPST.js → autoUpdater-IIJMDPJE.js} +3 -3
- package/dist/{chunk-SHIPHOMT.js → chunk-5RX62PWR.js} +1 -1
- package/dist/{chunk-XHGUMYRL.js → chunk-6MFZG46W.js} +1 -1
- package/dist/{chunk-IQ3KORSP.js → chunk-DCSAQNHW.js} +4 -4
- package/dist/{chunk-YFBIVUDT.js → chunk-ESKTQXW6.js} +27 -3
- package/dist/chunk-ESKTQXW6.js.map +7 -0
- package/dist/{chunk-QW4VX3FW.js → chunk-G2FI43IB.js} +2 -2
- package/dist/{chunk-4Z6CCSED.js → chunk-GLS3ZXCS.js} +3 -3
- package/dist/{chunk-DEQQW4H6.js → chunk-GTP62T63.js} +3 -3
- package/dist/{chunk-UUGWQSET.js → chunk-HJDETBB6.js} +1 -1
- package/dist/{chunk-55QJI7OQ.js → chunk-HY24VLOS.js} +1 -1
- package/dist/{chunk-LZT5LZKG.js → chunk-KDKXQODT.js} +2 -2
- package/dist/{chunk-HFL2SOFQ.js → chunk-KNOCJVE6.js} +1 -1
- package/dist/{chunk-MCP52ZSD.js → chunk-L2FQX7IL.js} +419 -244
- package/dist/chunk-L2FQX7IL.js.map +7 -0
- package/dist/{chunk-6Y4OSP3J.js → chunk-LAFEZLTD.js} +307 -218
- package/dist/chunk-LAFEZLTD.js.map +7 -0
- package/dist/{chunk-EXEPX5H2.js → chunk-LAQQRRQR.js} +4 -4
- package/dist/{chunk-2U747SA5.js → chunk-LEQNJ73H.js} +3 -3
- package/dist/{chunk-NZTVG7YS.js → chunk-MZ6UJROW.js} +4 -4
- package/dist/{chunk-MLCISJKM.js → chunk-N6DXTYLR.js} +3 -3
- package/dist/{chunk-JF4AMPKU.js → chunk-OBFMPMGW.js} +2 -2
- package/dist/{chunk-A7VN6YXZ.js → chunk-OYCMMRZV.js} +1 -1
- package/dist/{chunk-XZNXY65J.js → chunk-PKAVBIO7.js} +1 -1
- package/dist/{chunk-S2AJAM6R.js → chunk-SNKLRBWT.js} +2 -2
- package/dist/{chunk-6GOKZQDV.js → chunk-SQJJRPIY.js} +5 -5
- package/dist/{chunk-72SGZIMD.js → chunk-TMFNSMVV.js} +6 -6
- package/dist/{chunk-D3Q32IUW.js → chunk-U7MPXQO4.js} +3 -3
- package/dist/{chunk-3P2EGWMK.js → chunk-VUILI5ED.js} +2 -2
- package/dist/{chunk-7FNDFUQH.js → chunk-WCKPMAYX.js} +1 -1
- package/dist/{chunk-PSI4PJ2H.js → chunk-WSN5UCPE.js} +1 -1
- package/dist/{chunk-AWML3QPK.js → chunk-YNVGW5VZ.js} +7 -7
- package/dist/{chunk-I5H5PGD5.js → chunk-YTUV273Y.js} +50 -122
- package/dist/{chunk-I5H5PGD5.js.map → chunk-YTUV273Y.js.map} +2 -2
- package/dist/{chunk-GFDV6FUG.js → chunk-ZQAKMVXR.js} +3 -3
- package/dist/{cli-PCLH664O.js → cli-JPS6PPHH.js} +91 -89
- package/dist/{cli-PCLH664O.js.map → cli-JPS6PPHH.js.map} +2 -2
- package/dist/commands-3IJYY2KF.js +51 -0
- package/dist/{config-EBW7GI65.js → config-7RFJBYCF.js} +4 -4
- package/dist/{context-4BILE3LL.js → context-L6IDU4ZF.js} +6 -6
- package/dist/{customCommands-GDDHYRJR.js → customCommands-2ZLDKEPS.js} +4 -4
- package/dist/{env-7V57CD26.js → env-KKHHZ47D.js} +2 -2
- package/dist/{file-3W4M7RXM.js → file-QGJRLWJ7.js} +4 -4
- package/dist/index.js +3 -3
- package/dist/{llm-PIRKDSMO.js → llm-HHSKS5JE.js} +31 -31
- package/dist/{llmLazy-HWKMKZ5M.js → llmLazy-YV33JO4W.js} +1 -1
- package/dist/{loader-GYFX3MOO.js → loader-YCEP5CYE.js} +4 -4
- package/dist/{lsp-BDQVEVFK.js → lsp-TG3EZZOU.js} +6 -6
- package/dist/{lspAnchor-S45W3FAI.js → lspAnchor-T3544E7J.js} +6 -6
- package/dist/{mcp-ZHLSRCM5.js → mcp-SWYFI5FF.js} +7 -7
- package/dist/{mentionProcessor-GOS6BB64.js → mentionProcessor-IP6FAEXL.js} +7 -6
- package/dist/{mentionProcessor-GOS6BB64.js.map → mentionProcessor-IP6FAEXL.js.map} +1 -1
- package/dist/{messages-AX4MWPK5.js → messages-3B2ZJJKW.js} +1 -1
- package/dist/{model-QDQAUOQ6.js → model-HDJXCBKD.js} +5 -5
- package/dist/{openai-IBJPYBTX.js → openai-DF2BQT7X.js} +5 -5
- package/dist/{outputStyles-UNAE3KVB.js → outputStyles-GWUBSKDY.js} +4 -4
- package/dist/{pluginRuntime-QP6HTJ6Y.js → pluginRuntime-LKAAMJH2.js} +6 -6
- package/dist/{pluginValidation-C66MGV4E.js → pluginValidation-7GJA32YV.js} +6 -6
- package/dist/prompts-DB772NLS.js +53 -0
- package/dist/{pybAgentSessionLoad-GJQQFHVS.js → pybAgentSessionLoad-BGIX7L4O.js} +4 -4
- package/dist/{pybAgentSessionResume-2ZNOOEVX.js → pybAgentSessionResume-VKK6VZSA.js} +4 -4
- package/dist/{pybAgentStreamJsonSession-PE2K75QJ.js → pybAgentStreamJsonSession-HDXJ4F5W.js} +1 -1
- package/dist/{pybHooks-22R4DOTT.js → pybHooks-LEIAZ7D6.js} +5 -5
- package/dist/query-LVPGQYDL.js +55 -0
- package/dist/{registry-ES4KTNF7.js → registry-C4V5AZ6N.js} +5 -5
- package/dist/{ripgrep-7BPG53S4.js → ripgrep-PWIRRS2Q.js} +3 -3
- package/dist/{skillMarketplace-O5TAM4G6.js → skillMarketplace-GZN6RWUY.js} +3 -3
- package/dist/{state-3OM3WWZ2.js → state-T7WQKFBG.js} +2 -2
- package/dist/{theme-7MFSQQ5Z.js → theme-CLYLDSCI.js} +5 -5
- package/dist/{toolPermissionSettings-KKMWAVTJ.js → toolPermissionSettings-UYHSUTC5.js} +6 -6
- package/dist/tools-SEWCFM5P.js +52 -0
- package/dist/{userInput-3BYMTC52.js → userInput-KZXH5O7V.js} +32 -32
- package/package.json +27 -3
- package/dist/REPL-PRQAXE32.js +0 -47
- package/dist/chunk-6Y4OSP3J.js.map +0 -7
- package/dist/chunk-MCP52ZSD.js.map +0 -7
- package/dist/chunk-YFBIVUDT.js.map +0 -7
- package/dist/commands-Y7GVRV66.js +0 -51
- package/dist/prompts-LNJ2SJQ7.js +0 -53
- package/dist/query-2ZFLZTV6.js +0 -55
- package/dist/tools-ME4EX5CM.js +0 -52
- /package/dist/{REPL-PRQAXE32.js.map → REPL-6YEOSMEP.js.map} +0 -0
- /package/dist/{acp-FGRNDOS5.js.map → acp-2C774HUW.js.map} +0 -0
- /package/dist/{agentsValidate-7CRDPNQ6.js.map → agentsValidate-RCXZBOU3.js.map} +0 -0
- /package/dist/{ask-IR5W5M66.js.map → ask-EIO3Q6ED.js.map} +0 -0
- /package/dist/{autoUpdater-MAEQZPST.js.map → autoUpdater-IIJMDPJE.js.map} +0 -0
- /package/dist/{chunk-SHIPHOMT.js.map → chunk-5RX62PWR.js.map} +0 -0
- /package/dist/{chunk-XHGUMYRL.js.map → chunk-6MFZG46W.js.map} +0 -0
- /package/dist/{chunk-IQ3KORSP.js.map → chunk-DCSAQNHW.js.map} +0 -0
- /package/dist/{chunk-QW4VX3FW.js.map → chunk-G2FI43IB.js.map} +0 -0
- /package/dist/{chunk-4Z6CCSED.js.map → chunk-GLS3ZXCS.js.map} +0 -0
- /package/dist/{chunk-DEQQW4H6.js.map → chunk-GTP62T63.js.map} +0 -0
- /package/dist/{chunk-UUGWQSET.js.map → chunk-HJDETBB6.js.map} +0 -0
- /package/dist/{chunk-55QJI7OQ.js.map → chunk-HY24VLOS.js.map} +0 -0
- /package/dist/{chunk-LZT5LZKG.js.map → chunk-KDKXQODT.js.map} +0 -0
- /package/dist/{chunk-HFL2SOFQ.js.map → chunk-KNOCJVE6.js.map} +0 -0
- /package/dist/{chunk-EXEPX5H2.js.map → chunk-LAQQRRQR.js.map} +0 -0
- /package/dist/{chunk-2U747SA5.js.map → chunk-LEQNJ73H.js.map} +0 -0
- /package/dist/{chunk-NZTVG7YS.js.map → chunk-MZ6UJROW.js.map} +0 -0
- /package/dist/{chunk-MLCISJKM.js.map → chunk-N6DXTYLR.js.map} +0 -0
- /package/dist/{chunk-JF4AMPKU.js.map → chunk-OBFMPMGW.js.map} +0 -0
- /package/dist/{chunk-A7VN6YXZ.js.map → chunk-OYCMMRZV.js.map} +0 -0
- /package/dist/{chunk-XZNXY65J.js.map → chunk-PKAVBIO7.js.map} +0 -0
- /package/dist/{chunk-S2AJAM6R.js.map → chunk-SNKLRBWT.js.map} +0 -0
- /package/dist/{chunk-6GOKZQDV.js.map → chunk-SQJJRPIY.js.map} +0 -0
- /package/dist/{chunk-72SGZIMD.js.map → chunk-TMFNSMVV.js.map} +0 -0
- /package/dist/{chunk-D3Q32IUW.js.map → chunk-U7MPXQO4.js.map} +0 -0
- /package/dist/{chunk-3P2EGWMK.js.map → chunk-VUILI5ED.js.map} +0 -0
- /package/dist/{chunk-7FNDFUQH.js.map → chunk-WCKPMAYX.js.map} +0 -0
- /package/dist/{chunk-PSI4PJ2H.js.map → chunk-WSN5UCPE.js.map} +0 -0
- /package/dist/{chunk-AWML3QPK.js.map → chunk-YNVGW5VZ.js.map} +0 -0
- /package/dist/{chunk-GFDV6FUG.js.map → chunk-ZQAKMVXR.js.map} +0 -0
- /package/dist/{commands-Y7GVRV66.js.map → commands-3IJYY2KF.js.map} +0 -0
- /package/dist/{config-EBW7GI65.js.map → config-7RFJBYCF.js.map} +0 -0
- /package/dist/{context-4BILE3LL.js.map → context-L6IDU4ZF.js.map} +0 -0
- /package/dist/{customCommands-GDDHYRJR.js.map → customCommands-2ZLDKEPS.js.map} +0 -0
- /package/dist/{env-7V57CD26.js.map → env-KKHHZ47D.js.map} +0 -0
- /package/dist/{file-3W4M7RXM.js.map → file-QGJRLWJ7.js.map} +0 -0
- /package/dist/{llm-PIRKDSMO.js.map → llm-HHSKS5JE.js.map} +0 -0
- /package/dist/{llmLazy-HWKMKZ5M.js.map → llmLazy-YV33JO4W.js.map} +0 -0
- /package/dist/{loader-GYFX3MOO.js.map → loader-YCEP5CYE.js.map} +0 -0
- /package/dist/{lsp-BDQVEVFK.js.map → lsp-TG3EZZOU.js.map} +0 -0
- /package/dist/{lspAnchor-S45W3FAI.js.map → lspAnchor-T3544E7J.js.map} +0 -0
- /package/dist/{mcp-ZHLSRCM5.js.map → mcp-SWYFI5FF.js.map} +0 -0
- /package/dist/{messages-AX4MWPK5.js.map → messages-3B2ZJJKW.js.map} +0 -0
- /package/dist/{model-QDQAUOQ6.js.map → model-HDJXCBKD.js.map} +0 -0
- /package/dist/{openai-IBJPYBTX.js.map → openai-DF2BQT7X.js.map} +0 -0
- /package/dist/{outputStyles-UNAE3KVB.js.map → outputStyles-GWUBSKDY.js.map} +0 -0
- /package/dist/{pluginRuntime-QP6HTJ6Y.js.map → pluginRuntime-LKAAMJH2.js.map} +0 -0
- /package/dist/{pluginValidation-C66MGV4E.js.map → pluginValidation-7GJA32YV.js.map} +0 -0
- /package/dist/{prompts-LNJ2SJQ7.js.map → prompts-DB772NLS.js.map} +0 -0
- /package/dist/{pybAgentSessionLoad-GJQQFHVS.js.map → pybAgentSessionLoad-BGIX7L4O.js.map} +0 -0
- /package/dist/{pybAgentSessionResume-2ZNOOEVX.js.map → pybAgentSessionResume-VKK6VZSA.js.map} +0 -0
- /package/dist/{pybAgentStreamJsonSession-PE2K75QJ.js.map → pybAgentStreamJsonSession-HDXJ4F5W.js.map} +0 -0
- /package/dist/{pybHooks-22R4DOTT.js.map → pybHooks-LEIAZ7D6.js.map} +0 -0
- /package/dist/{query-2ZFLZTV6.js.map → query-LVPGQYDL.js.map} +0 -0
- /package/dist/{registry-ES4KTNF7.js.map → registry-C4V5AZ6N.js.map} +0 -0
- /package/dist/{ripgrep-7BPG53S4.js.map → ripgrep-PWIRRS2Q.js.map} +0 -0
- /package/dist/{skillMarketplace-O5TAM4G6.js.map → skillMarketplace-GZN6RWUY.js.map} +0 -0
- /package/dist/{state-3OM3WWZ2.js.map → state-T7WQKFBG.js.map} +0 -0
- /package/dist/{theme-7MFSQQ5Z.js.map → theme-CLYLDSCI.js.map} +0 -0
- /package/dist/{toolPermissionSettings-KKMWAVTJ.js.map → toolPermissionSettings-UYHSUTC5.js.map} +0 -0
- /package/dist/{tools-ME4EX5CM.js.map → tools-SEWCFM5P.js.map} +0 -0
- /package/dist/{userInput-3BYMTC52.js.map → userInput-KZXH5O7V.js.map} +0 -0
|
@@ -4,18 +4,21 @@ import {
|
|
|
4
4
|
getSessionState,
|
|
5
5
|
setSessionState
|
|
6
6
|
} from "./chunk-ERMQRV55.js";
|
|
7
|
+
import {
|
|
8
|
+
getPybAgentSessionId
|
|
9
|
+
} from "./chunk-B6IMQJZM.js";
|
|
7
10
|
import {
|
|
8
11
|
getCurrentProjectConfig,
|
|
9
12
|
getGlobalConfig
|
|
10
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-LEQNJ73H.js";
|
|
11
14
|
import {
|
|
12
15
|
debug
|
|
13
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-6MFZG46W.js";
|
|
14
17
|
import {
|
|
15
18
|
getCwd,
|
|
16
19
|
logError,
|
|
17
20
|
resolveXdgDataPath
|
|
18
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-HJDETBB6.js";
|
|
19
22
|
|
|
20
23
|
// src/utils/agent/storage.ts
|
|
21
24
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
@@ -81,16 +84,153 @@ function generateAgentId() {
|
|
|
81
84
|
// src/utils/session/taskStore.ts
|
|
82
85
|
import {
|
|
83
86
|
existsSync as existsSync2,
|
|
87
|
+
closeSync,
|
|
84
88
|
mkdirSync as mkdirSync2,
|
|
89
|
+
openSync,
|
|
85
90
|
readFileSync as readFileSync2,
|
|
86
91
|
readdirSync,
|
|
92
|
+
renameSync,
|
|
87
93
|
rmSync,
|
|
88
94
|
writeFileSync as writeFileSync2
|
|
89
95
|
} from "fs";
|
|
90
96
|
import { join as join2 } from "path";
|
|
91
97
|
import { homedir } from "os";
|
|
92
|
-
import {
|
|
93
|
-
|
|
98
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
99
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
100
|
+
|
|
101
|
+
// src/utils/session/taskLockNative.ts
|
|
102
|
+
import { createRequire } from "module";
|
|
103
|
+
var require2 = createRequire(import.meta.url);
|
|
104
|
+
var getLinuxVariant = (report) => {
|
|
105
|
+
const glibc = report?.getReport?.()?.header?.glibcVersionRuntime;
|
|
106
|
+
return glibc ? "gnu" : "musl";
|
|
107
|
+
};
|
|
108
|
+
var resolveNativeLockPackage = (options) => {
|
|
109
|
+
const platform = options?.platform ?? process.platform;
|
|
110
|
+
const arch = options?.arch ?? process.arch;
|
|
111
|
+
const report = options?.report ?? process.report;
|
|
112
|
+
if (platform === "win32" && arch === "x64") {
|
|
113
|
+
return "@pyb/lock-win32-x64-msvc";
|
|
114
|
+
}
|
|
115
|
+
if (platform === "win32" && arch === "arm64") {
|
|
116
|
+
return "@pyb/lock-win32-arm64-msvc";
|
|
117
|
+
}
|
|
118
|
+
if (platform === "darwin" && arch === "x64") {
|
|
119
|
+
return "@pyb/lock-darwin-x64";
|
|
120
|
+
}
|
|
121
|
+
if (platform === "darwin" && arch === "arm64") {
|
|
122
|
+
return "@pyb/lock-darwin-arm64";
|
|
123
|
+
}
|
|
124
|
+
if (platform === "linux" && arch === "x64") {
|
|
125
|
+
const variant = getLinuxVariant(report);
|
|
126
|
+
return variant === "musl" ? "@pyb/lock-linux-x64-musl" : "@pyb/lock-linux-x64-gnu";
|
|
127
|
+
}
|
|
128
|
+
if (platform === "linux" && arch === "arm64") {
|
|
129
|
+
return "@pyb/lock-linux-arm64-gnu";
|
|
130
|
+
}
|
|
131
|
+
if (platform === "linux" && arch === "arm") {
|
|
132
|
+
return "@pyb/lock-linux-armv7-gnueabihf";
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
};
|
|
136
|
+
var cachedLock;
|
|
137
|
+
var loadNativeTaskLock = () => {
|
|
138
|
+
const globalLock = globalThis.__PYB_NATIVE_TASK_LOCK__;
|
|
139
|
+
if (globalLock) {
|
|
140
|
+
cachedLock = globalLock;
|
|
141
|
+
return cachedLock;
|
|
142
|
+
}
|
|
143
|
+
if (cachedLock !== void 0) return cachedLock;
|
|
144
|
+
const envPath = process.env.PYB_NATIVE_LOCK_NODE_PATH;
|
|
145
|
+
if (envPath) {
|
|
146
|
+
try {
|
|
147
|
+
const mod = require2(envPath);
|
|
148
|
+
const candidate = mod?.default ?? mod;
|
|
149
|
+
if (candidate && typeof candidate.lockExclusive === "function" && typeof candidate.tryLockExclusive === "function" && typeof candidate.unlock === "function") {
|
|
150
|
+
cachedLock = candidate;
|
|
151
|
+
return cachedLock;
|
|
152
|
+
}
|
|
153
|
+
} catch {
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const packageName = resolveNativeLockPackage();
|
|
157
|
+
if (!packageName) {
|
|
158
|
+
cachedLock = null;
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
const mod = require2(packageName);
|
|
163
|
+
const candidate = mod?.default ?? mod;
|
|
164
|
+
if (candidate && typeof candidate.lockExclusive === "function" && typeof candidate.tryLockExclusive === "function" && typeof candidate.unlock === "function") {
|
|
165
|
+
cachedLock = candidate;
|
|
166
|
+
return cachedLock;
|
|
167
|
+
}
|
|
168
|
+
} catch {
|
|
169
|
+
}
|
|
170
|
+
cachedLock = null;
|
|
171
|
+
return null;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// src/utils/session/taskStore.ts
|
|
175
|
+
var taskListIdStorage = new AsyncLocalStorage();
|
|
176
|
+
var taskListEnvStorage = new AsyncLocalStorage();
|
|
177
|
+
var nativeLock = null;
|
|
178
|
+
var nativeLockResolved = false;
|
|
179
|
+
function getNativeLock() {
|
|
180
|
+
const globalLock = globalThis.__PYB_NATIVE_TASK_LOCK__;
|
|
181
|
+
if (globalLock) {
|
|
182
|
+
nativeLock = globalLock;
|
|
183
|
+
nativeLockResolved = true;
|
|
184
|
+
return nativeLock;
|
|
185
|
+
}
|
|
186
|
+
if (nativeLockResolved) return nativeLock;
|
|
187
|
+
nativeLockResolved = true;
|
|
188
|
+
nativeLock = loadNativeTaskLock();
|
|
189
|
+
return nativeLock;
|
|
190
|
+
}
|
|
191
|
+
function generateTaskListId() {
|
|
192
|
+
return randomUUID2();
|
|
193
|
+
}
|
|
194
|
+
function runWithTaskListId(listId, handler) {
|
|
195
|
+
return taskListIdStorage.run(listId, () => {
|
|
196
|
+
const result = handler();
|
|
197
|
+
const asyncIterator = result && typeof result[Symbol.asyncIterator] === "function" ? result : null;
|
|
198
|
+
if (!asyncIterator) return result;
|
|
199
|
+
return {
|
|
200
|
+
[Symbol.asyncIterator]() {
|
|
201
|
+
const iterator = asyncIterator[Symbol.asyncIterator]();
|
|
202
|
+
return {
|
|
203
|
+
next: (value) => taskListIdStorage.run(listId, () => iterator.next(value)),
|
|
204
|
+
return: iterator.return ? (value) => taskListIdStorage.run(listId, () => iterator.return(value)) : void 0,
|
|
205
|
+
throw: iterator.throw ? (err) => taskListIdStorage.run(listId, () => iterator.throw(err)) : void 0
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
function runWithTaskListEnv(env, handler) {
|
|
212
|
+
return taskListEnvStorage.run(env, () => {
|
|
213
|
+
const result = handler();
|
|
214
|
+
const asyncIterator = result && typeof result[Symbol.asyncIterator] === "function" ? result : null;
|
|
215
|
+
if (!asyncIterator) return result;
|
|
216
|
+
return {
|
|
217
|
+
[Symbol.asyncIterator]() {
|
|
218
|
+
const iterator = asyncIterator[Symbol.asyncIterator]();
|
|
219
|
+
return {
|
|
220
|
+
next: (value) => taskListEnvStorage.run(env, () => iterator.next(value)),
|
|
221
|
+
return: iterator.return ? (value) => taskListEnvStorage.run(env, () => iterator.return(value)) : void 0,
|
|
222
|
+
throw: iterator.throw ? (err) => taskListEnvStorage.run(env, () => iterator.throw(err)) : void 0
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
var taskListLocks = /* @__PURE__ */ new Map();
|
|
229
|
+
var taskLockWaitBuffer = new Int32Array(new SharedArrayBuffer(4));
|
|
230
|
+
var DEFAULT_LOCK_TIMEOUT_MS = Number(
|
|
231
|
+
process.env.PYB_TASK_LOCK_TIMEOUT_MS ?? 5e3
|
|
232
|
+
);
|
|
233
|
+
var DEFAULT_LOCK_RETRY_MS = Number(process.env.PYB_TASK_LOCK_RETRY_MS ?? 50);
|
|
94
234
|
var TaskStoreLockError = class extends Error {
|
|
95
235
|
code = "TASK_STORE_LOCKED";
|
|
96
236
|
constructor(message) {
|
|
@@ -114,7 +254,7 @@ var TaskStoreConflictError = class extends Error {
|
|
|
114
254
|
}
|
|
115
255
|
};
|
|
116
256
|
function getDefaultTaskListId(cwd) {
|
|
117
|
-
return
|
|
257
|
+
return getPybAgentSessionId();
|
|
118
258
|
}
|
|
119
259
|
function resolveGlobalTaskRootDir() {
|
|
120
260
|
const override = process.env.PYB_CONFIG_DIR ?? process.env.CLAUDE_CONFIG_DIR;
|
|
@@ -133,12 +273,13 @@ function findBaseDirWithList(listId, candidates) {
|
|
|
133
273
|
return null;
|
|
134
274
|
}
|
|
135
275
|
function getTaskListContext(options) {
|
|
136
|
-
const env = options?.env ?? process.env;
|
|
276
|
+
const env = options?.env ?? taskListEnvStorage.getStore() ?? process.env;
|
|
137
277
|
const globalConfig = options?.globalConfig ?? getGlobalConfig();
|
|
138
278
|
const projectConfig = options?.projectConfig ?? getCurrentProjectConfig();
|
|
139
279
|
const cwd = options?.cwd ?? getCwd();
|
|
140
280
|
const defaultId = getDefaultTaskListId(cwd);
|
|
141
281
|
const inputListId = options?.listId?.trim();
|
|
282
|
+
const contextListId = taskListIdStorage.getStore()?.trim();
|
|
142
283
|
const envId = env.PYB_TASK_LIST_ID?.trim() || env.CLAUDE_CODE_TASK_LIST_ID?.trim();
|
|
143
284
|
const globalId = globalConfig?.taskListId?.trim();
|
|
144
285
|
const projectId = projectConfig?.taskListId?.trim();
|
|
@@ -151,6 +292,9 @@ function getTaskListContext(options) {
|
|
|
151
292
|
}
|
|
152
293
|
return { listId: inputListId, scope: "project", source: "input" };
|
|
153
294
|
}
|
|
295
|
+
if (contextListId) {
|
|
296
|
+
return { listId: contextListId, scope: "project", source: "context" };
|
|
297
|
+
}
|
|
154
298
|
if (envId) return { listId: envId, scope: "global", source: "env" };
|
|
155
299
|
if (globalId) return { listId: globalId, scope: "global", source: "global" };
|
|
156
300
|
if (projectId) return { listId: projectId, scope: "project", source: "project" };
|
|
@@ -182,24 +326,92 @@ function resolveTaskBaseDir(context, cwd) {
|
|
|
182
326
|
const candidates = [...globalCandidates, resolveXdgDataPath("tasks")];
|
|
183
327
|
return findBaseDirWithList(context.listId, candidates) ?? defaultBaseDir;
|
|
184
328
|
}
|
|
185
|
-
function
|
|
186
|
-
const
|
|
187
|
-
const cwd = getCwd();
|
|
188
|
-
const baseDir = resolveTaskBaseDir(context, cwd);
|
|
189
|
-
const listDir = join2(baseDir, context.listId);
|
|
329
|
+
function buildTaskListPaths(baseDir, listId) {
|
|
330
|
+
const listDir = join2(baseDir, listId);
|
|
190
331
|
return {
|
|
191
|
-
listId
|
|
332
|
+
listId,
|
|
192
333
|
baseDir,
|
|
193
334
|
listDir,
|
|
194
335
|
tasksDir: listDir,
|
|
195
|
-
indexPath: join2(listDir, "index.json"),
|
|
196
|
-
metaPath: join2(listDir, "meta.json"),
|
|
197
336
|
lockPath: join2(listDir, ".lock"),
|
|
198
|
-
|
|
337
|
+
highwatermarkPath: join2(listDir, ".highwatermark")
|
|
199
338
|
};
|
|
200
339
|
}
|
|
340
|
+
function getTaskListPaths(listId) {
|
|
341
|
+
const context = getTaskListContext({ listId });
|
|
342
|
+
const cwd = getCwd();
|
|
343
|
+
const baseDir = resolveTaskBaseDir(context, cwd);
|
|
344
|
+
return buildTaskListPaths(baseDir, context.listId);
|
|
345
|
+
}
|
|
346
|
+
function initTaskListLockFile(options) {
|
|
347
|
+
const paths = getTaskListPaths(options?.listId);
|
|
348
|
+
ensureTaskListDirs(paths);
|
|
349
|
+
}
|
|
350
|
+
function sortReadPaths(paths) {
|
|
351
|
+
const priority = { pyb: 0, claude: 1, other: 2 };
|
|
352
|
+
return [...paths].sort((a, b) => priority[a.source] - priority[b.source]);
|
|
353
|
+
}
|
|
354
|
+
function resolveSourceForBaseDir(baseDir) {
|
|
355
|
+
if (baseDir.includes(`${join2(".pyb", "tasks")}`)) return "pyb";
|
|
356
|
+
if (baseDir.includes(`${join2(".claude", "tasks")}`)) return "claude";
|
|
357
|
+
if (baseDir.includes(`${join2(".pyb")}`)) return "pyb";
|
|
358
|
+
if (baseDir.includes(`${join2(".claude")}`)) return "claude";
|
|
359
|
+
return "other";
|
|
360
|
+
}
|
|
361
|
+
function getTaskListReadPaths(listId) {
|
|
362
|
+
const context = getTaskListContext({ listId });
|
|
363
|
+
const cwd = getCwd();
|
|
364
|
+
const projectPyb = join2(cwd, ".pyb", "tasks");
|
|
365
|
+
const projectClaude = join2(cwd, ".claude", "tasks");
|
|
366
|
+
if (context.scope === "project") {
|
|
367
|
+
const existing2 = [];
|
|
368
|
+
if (existsSync2(join2(projectPyb, context.listId))) {
|
|
369
|
+
existing2.push({
|
|
370
|
+
...buildTaskListPaths(projectPyb, context.listId),
|
|
371
|
+
source: "pyb"
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
if (existsSync2(join2(projectClaude, context.listId))) {
|
|
375
|
+
existing2.push({
|
|
376
|
+
...buildTaskListPaths(projectClaude, context.listId),
|
|
377
|
+
source: "claude"
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
if (existing2.length > 0) return sortReadPaths(existing2);
|
|
381
|
+
}
|
|
382
|
+
const override = process.env.PYB_CONFIG_DIR ?? process.env.CLAUDE_CONFIG_DIR;
|
|
383
|
+
const globalCandidates = override ? [
|
|
384
|
+
{
|
|
385
|
+
baseDir: join2(override, "tasks"),
|
|
386
|
+
source: resolveSourceForBaseDir(join2(override, "tasks"))
|
|
387
|
+
}
|
|
388
|
+
] : [
|
|
389
|
+
{ baseDir: join2(homedir(), ".pyb", "tasks"), source: "pyb" },
|
|
390
|
+
{ baseDir: join2(homedir(), ".claude", "tasks"), source: "claude" }
|
|
391
|
+
];
|
|
392
|
+
const candidates = [
|
|
393
|
+
...globalCandidates,
|
|
394
|
+
{ baseDir: resolveXdgDataPath("tasks"), source: "other" }
|
|
395
|
+
];
|
|
396
|
+
const existing = candidates.filter((candidate) => existsSync2(join2(candidate.baseDir, context.listId))).map((candidate) => ({
|
|
397
|
+
...buildTaskListPaths(candidate.baseDir, context.listId),
|
|
398
|
+
source: candidate.source
|
|
399
|
+
}));
|
|
400
|
+
if (existing.length > 0) return sortReadPaths(existing);
|
|
401
|
+
const baseDir = resolveTaskBaseDir(context, cwd);
|
|
402
|
+
return [
|
|
403
|
+
{
|
|
404
|
+
...buildTaskListPaths(baseDir, context.listId),
|
|
405
|
+
source: resolveSourceForBaseDir(baseDir)
|
|
406
|
+
}
|
|
407
|
+
];
|
|
408
|
+
}
|
|
201
409
|
function ensureTaskListDirs(paths) {
|
|
202
410
|
mkdirSync2(paths.listDir, { recursive: true });
|
|
411
|
+
if (!existsSync2(paths.lockPath)) {
|
|
412
|
+
writeFileSync2(paths.lockPath, "");
|
|
413
|
+
}
|
|
414
|
+
cleanupLegacyFiles(paths);
|
|
203
415
|
}
|
|
204
416
|
function readJson(path) {
|
|
205
417
|
if (!existsSync2(path)) return null;
|
|
@@ -213,78 +425,27 @@ function readJson(path) {
|
|
|
213
425
|
function writeJson(path, value) {
|
|
214
426
|
writeFileSync2(path, JSON.stringify(value, null, 2), "utf8");
|
|
215
427
|
}
|
|
216
|
-
function
|
|
217
|
-
|
|
218
|
-
writeFileSync2(
|
|
219
|
-
|
|
220
|
-
encoding: "utf8",
|
|
221
|
-
flag: "a"
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
function readTaskEventLog(listId, offset = 0) {
|
|
225
|
-
const paths = getTaskListPaths(listId);
|
|
226
|
-
if (!existsSync2(paths.eventsPath)) {
|
|
227
|
-
return { events: [], nextOffset: 0 };
|
|
228
|
-
}
|
|
229
|
-
const buffer = readFileSync2(paths.eventsPath);
|
|
230
|
-
const nextOffset = buffer.length;
|
|
231
|
-
if (offset >= nextOffset) {
|
|
232
|
-
return { events: [], nextOffset };
|
|
233
|
-
}
|
|
234
|
-
const chunk = buffer.toString("utf8", offset);
|
|
235
|
-
const events = [];
|
|
236
|
-
for (const line of chunk.split("\n")) {
|
|
237
|
-
if (!line.trim()) continue;
|
|
238
|
-
try {
|
|
239
|
-
const parsed = JSON.parse(line);
|
|
240
|
-
if (parsed.listId && parsed.taskId && parsed.type && parsed.timestamp) {
|
|
241
|
-
events.push(parsed);
|
|
242
|
-
}
|
|
243
|
-
} catch {
|
|
244
|
-
continue;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
return { events, nextOffset };
|
|
248
|
-
}
|
|
249
|
-
function readIndex(paths) {
|
|
250
|
-
const index = readJson(paths.indexPath);
|
|
251
|
-
if (index && typeof index.nextId === "number" && index.nextId >= 1) {
|
|
252
|
-
const byStatus = index.byStatus ?? {};
|
|
253
|
-
const pending = typeof byStatus.pending === "number" ? byStatus.pending : typeof byStatus.open === "number" ? byStatus.open : 0;
|
|
254
|
-
return {
|
|
255
|
-
nextId: index.nextId,
|
|
256
|
-
total: typeof index.total === "number" ? index.total : 0,
|
|
257
|
-
byStatus: {
|
|
258
|
-
pending,
|
|
259
|
-
in_progress: typeof byStatus.in_progress === "number" ? byStatus.in_progress : 0,
|
|
260
|
-
blocked: typeof byStatus.blocked === "number" ? byStatus.blocked : 0,
|
|
261
|
-
done: typeof byStatus.done === "number" ? byStatus.done : 0,
|
|
262
|
-
archived: typeof byStatus.archived === "number" ? byStatus.archived : 0
|
|
263
|
-
},
|
|
264
|
-
lastUpdated: typeof index.lastUpdated === "number" ? index.lastUpdated : Date.now()
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
return recoverIndex(paths);
|
|
428
|
+
function writeJsonAtomic(path, value) {
|
|
429
|
+
const tempPath = `${path}.${randomUUID2()}.tmp`;
|
|
430
|
+
writeFileSync2(tempPath, JSON.stringify(value, null, 2), "utf8");
|
|
431
|
+
renameSync(tempPath, path);
|
|
268
432
|
}
|
|
269
|
-
function
|
|
270
|
-
|
|
433
|
+
function readHighwatermark(paths) {
|
|
434
|
+
if (!existsSync2(paths.highwatermarkPath)) return null;
|
|
435
|
+
const raw = readFileSync2(paths.highwatermarkPath, "utf8").trim();
|
|
436
|
+
const value = Number(raw);
|
|
437
|
+
if (!Number.isFinite(value) || value < 0) return null;
|
|
438
|
+
return value;
|
|
271
439
|
}
|
|
272
|
-
function
|
|
440
|
+
function writeHighwatermark(paths, value) {
|
|
273
441
|
ensureTaskListDirs(paths);
|
|
274
|
-
|
|
275
|
-
if (meta && meta.listId) return meta;
|
|
276
|
-
const now = Date.now();
|
|
277
|
-
const created = {
|
|
278
|
-
listId: paths.listId,
|
|
279
|
-
createdAt: now,
|
|
280
|
-
updatedAt: now
|
|
281
|
-
};
|
|
282
|
-
writeJson(paths.metaPath, created);
|
|
283
|
-
return created;
|
|
442
|
+
writeFileSync2(paths.highwatermarkPath, String(value), "utf8");
|
|
284
443
|
}
|
|
285
|
-
function
|
|
286
|
-
|
|
287
|
-
|
|
444
|
+
function updateHighwatermark(paths, value) {
|
|
445
|
+
if (!Number.isFinite(value) || value < 0) return;
|
|
446
|
+
const current = readHighwatermark(paths);
|
|
447
|
+
const next = current !== null ? Math.max(current, value) : value;
|
|
448
|
+
writeHighwatermark(paths, next);
|
|
288
449
|
}
|
|
289
450
|
function readTaskFile(path) {
|
|
290
451
|
const data = readJson(path);
|
|
@@ -358,6 +519,7 @@ function areBlocksEqual(a, b) {
|
|
|
358
519
|
return true;
|
|
359
520
|
}
|
|
360
521
|
function readTasksFromDisk(paths) {
|
|
522
|
+
if (!existsSync2(paths.tasksDir)) return [];
|
|
361
523
|
const files = readdirSync(paths.tasksDir).filter((file) => file.endsWith(".json"));
|
|
362
524
|
return files.map((file) => readTaskFile(join2(paths.tasksDir, file))).filter(Boolean);
|
|
363
525
|
}
|
|
@@ -390,71 +552,123 @@ function rebuildBlocksForPaths(paths) {
|
|
|
390
552
|
const updated = persistBlocksMap(paths, map);
|
|
391
553
|
return { tasks: applyBlocksMap(tasks, map), updated };
|
|
392
554
|
}
|
|
393
|
-
|
|
394
|
-
|
|
555
|
+
var legacyFiles = ["index.json", "meta.json", "events.jsonl"];
|
|
556
|
+
function cleanupLegacyFiles(paths) {
|
|
557
|
+
for (const file of legacyFiles) {
|
|
558
|
+
const path = join2(paths.listDir, file);
|
|
559
|
+
if (existsSync2(path)) {
|
|
560
|
+
rmSync(path, { force: true });
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
function getMaxIdFromTasksDir(paths) {
|
|
565
|
+
if (!existsSync2(paths.tasksDir)) return 0;
|
|
395
566
|
const files = readdirSync(paths.tasksDir).filter((file) => file.endsWith(".json"));
|
|
396
|
-
const tasks = files.map((file) => readTaskFile(join2(paths.tasksDir, file))).filter(Boolean);
|
|
397
|
-
const byStatus = {
|
|
398
|
-
pending: 0,
|
|
399
|
-
in_progress: 0,
|
|
400
|
-
blocked: 0,
|
|
401
|
-
done: 0,
|
|
402
|
-
archived: 0
|
|
403
|
-
};
|
|
404
567
|
let maxId = 0;
|
|
405
|
-
for (const
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
maxId = Math.max(maxId, numericId);
|
|
568
|
+
for (const file of files) {
|
|
569
|
+
const numeric = Number(file.replace(/\.json$/, ""));
|
|
570
|
+
if (Number.isFinite(numeric)) {
|
|
571
|
+
maxId = Math.max(maxId, numeric);
|
|
410
572
|
}
|
|
411
573
|
}
|
|
412
|
-
|
|
413
|
-
nextId: Math.max(1, maxId + 1),
|
|
414
|
-
total: tasks.length,
|
|
415
|
-
byStatus,
|
|
416
|
-
lastUpdated: Date.now()
|
|
417
|
-
};
|
|
418
|
-
writeIndex(paths, index);
|
|
419
|
-
return index;
|
|
420
|
-
}
|
|
421
|
-
function readLock(path) {
|
|
422
|
-
const lock = readJson(path);
|
|
423
|
-
if (!lock || !lock.createdAt || !lock.expiresAt) return null;
|
|
424
|
-
return lock;
|
|
574
|
+
return maxId;
|
|
425
575
|
}
|
|
426
|
-
function
|
|
427
|
-
|
|
576
|
+
function getNextTaskId(paths) {
|
|
577
|
+
const highwatermark = readHighwatermark(paths) ?? 0;
|
|
578
|
+
const maxId = getMaxIdFromTasksDir(paths);
|
|
579
|
+
return Math.max(highwatermark, maxId) + 1;
|
|
428
580
|
}
|
|
429
581
|
function acquireLock(paths) {
|
|
430
582
|
ensureTaskListDirs(paths);
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
583
|
+
const start = Date.now();
|
|
584
|
+
while (taskListLocks.has(paths.lockPath)) {
|
|
585
|
+
const elapsed = Date.now() - start;
|
|
586
|
+
if (elapsed >= DEFAULT_LOCK_TIMEOUT_MS) {
|
|
587
|
+
throw new TaskStoreLockError("Task list is locked");
|
|
588
|
+
}
|
|
589
|
+
Atomics.wait(taskLockWaitBuffer, 0, 0, DEFAULT_LOCK_RETRY_MS);
|
|
437
590
|
}
|
|
438
|
-
const
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
),
|
|
450
|
-
{ encoding: "utf8", flag: "wx" }
|
|
591
|
+
const native = getNativeLock();
|
|
592
|
+
if (!native) {
|
|
593
|
+
const platformLabel = `${process.platform}-${process.arch}`;
|
|
594
|
+
const packageName = resolveNativeLockPackage();
|
|
595
|
+
if (packageName) {
|
|
596
|
+
throw new TaskStoreLockError(
|
|
597
|
+
`Native lock unavailable. Missing package ${packageName} for ${platformLabel}`
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
throw new TaskStoreLockError(
|
|
601
|
+
`Native lock unavailable. Unsupported platform ${platformLabel}`
|
|
451
602
|
);
|
|
452
|
-
}
|
|
453
|
-
|
|
603
|
+
}
|
|
604
|
+
if (native.tryLockExclusivePath && native.unlockHandle) {
|
|
605
|
+
const lockKey = paths.lockPath;
|
|
606
|
+
while (true) {
|
|
607
|
+
try {
|
|
608
|
+
const handle = native.tryLockExclusivePath(lockKey);
|
|
609
|
+
if (handle > 0) {
|
|
610
|
+
taskListLocks.set(paths.lockPath, { handle, mode: "nativeHandle" });
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
} catch {
|
|
614
|
+
}
|
|
615
|
+
const elapsed = Date.now() - start;
|
|
616
|
+
if (elapsed >= DEFAULT_LOCK_TIMEOUT_MS) {
|
|
617
|
+
throw new TaskStoreLockError("Task list is locked");
|
|
618
|
+
}
|
|
619
|
+
Atomics.wait(taskLockWaitBuffer, 0, 0, DEFAULT_LOCK_RETRY_MS);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
while (true) {
|
|
623
|
+
const handle = openSync(paths.lockPath, "r+");
|
|
624
|
+
try {
|
|
625
|
+
const ok = native.tryLockExclusive(handle);
|
|
626
|
+
if (ok) {
|
|
627
|
+
taskListLocks.set(paths.lockPath, { handle, mode: "fd" });
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
try {
|
|
631
|
+
closeSync(handle);
|
|
632
|
+
} catch {
|
|
633
|
+
}
|
|
634
|
+
const elapsed = Date.now() - start;
|
|
635
|
+
if (elapsed >= DEFAULT_LOCK_TIMEOUT_MS) {
|
|
636
|
+
throw new TaskStoreLockError("Task list is locked");
|
|
637
|
+
}
|
|
638
|
+
Atomics.wait(taskLockWaitBuffer, 0, 0, DEFAULT_LOCK_RETRY_MS);
|
|
639
|
+
} catch {
|
|
640
|
+
try {
|
|
641
|
+
closeSync(handle);
|
|
642
|
+
} catch {
|
|
643
|
+
}
|
|
644
|
+
const elapsed = Date.now() - start;
|
|
645
|
+
if (elapsed >= DEFAULT_LOCK_TIMEOUT_MS) {
|
|
646
|
+
throw new TaskStoreLockError("Task list is locked");
|
|
647
|
+
}
|
|
648
|
+
Atomics.wait(taskLockWaitBuffer, 0, 0, DEFAULT_LOCK_RETRY_MS);
|
|
649
|
+
}
|
|
454
650
|
}
|
|
455
651
|
}
|
|
456
652
|
function releaseLock(paths) {
|
|
457
|
-
|
|
653
|
+
const lock = taskListLocks.get(paths.lockPath);
|
|
654
|
+
if (lock !== void 0) {
|
|
655
|
+
const native = getNativeLock();
|
|
656
|
+
if (native && lock.mode === "nativeHandle" && native.unlockHandle) {
|
|
657
|
+
try {
|
|
658
|
+
native.unlockHandle(lock.handle);
|
|
659
|
+
} catch {
|
|
660
|
+
}
|
|
661
|
+
} else {
|
|
662
|
+
if (native) {
|
|
663
|
+
try {
|
|
664
|
+
native.unlock(lock.handle);
|
|
665
|
+
} catch {
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
closeSync(lock.handle);
|
|
669
|
+
}
|
|
670
|
+
taskListLocks.delete(paths.lockPath);
|
|
671
|
+
}
|
|
458
672
|
}
|
|
459
673
|
function withTaskListLock(paths, handler) {
|
|
460
674
|
acquireLock(paths);
|
|
@@ -464,6 +678,18 @@ function withTaskListLock(paths, handler) {
|
|
|
464
678
|
releaseLock(paths);
|
|
465
679
|
}
|
|
466
680
|
}
|
|
681
|
+
function mergeMetadata(existing, updates) {
|
|
682
|
+
if (!updates) return existing;
|
|
683
|
+
const next = { ...existing ?? {} };
|
|
684
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
685
|
+
if (value === null) {
|
|
686
|
+
delete next[key];
|
|
687
|
+
} else {
|
|
688
|
+
next[key] = value;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
return Object.keys(next).length > 0 ? next : void 0;
|
|
692
|
+
}
|
|
467
693
|
function applyTaskUpdates(task, updates, nextBaseVersion) {
|
|
468
694
|
const now = updates.updatedAt ?? Date.now();
|
|
469
695
|
const subject = updates.subject ?? task.subject;
|
|
@@ -479,7 +705,7 @@ function applyTaskUpdates(task, updates, nextBaseVersion) {
|
|
|
479
705
|
status,
|
|
480
706
|
tags: updates.tags ?? task.tags,
|
|
481
707
|
assignee: updates.assignee ?? task.assignee,
|
|
482
|
-
metadata:
|
|
708
|
+
metadata: mergeMetadata(task.metadata, updates.metadata),
|
|
483
709
|
archived: updates.archived ?? task.archived,
|
|
484
710
|
blocks: task.blocks ?? [],
|
|
485
711
|
blockedBy,
|
|
@@ -498,16 +724,12 @@ function createTask(input, options) {
|
|
|
498
724
|
const paths = getTaskListPaths(options?.listId);
|
|
499
725
|
return withTaskListLock(paths, () => {
|
|
500
726
|
ensureTaskListDirs(paths);
|
|
501
|
-
const
|
|
502
|
-
const id = String(index.nextId);
|
|
727
|
+
const id = String(getNextTaskId(paths));
|
|
503
728
|
const now = Date.now();
|
|
504
729
|
const subject = input.subject;
|
|
505
730
|
if (!subject) {
|
|
506
731
|
throw new Error("Task subject is required");
|
|
507
732
|
}
|
|
508
|
-
if (!input.activeForm) {
|
|
509
|
-
throw new Error("Task activeForm is required");
|
|
510
|
-
}
|
|
511
733
|
const activeForm = input.activeForm;
|
|
512
734
|
const status = input.status ?? "pending";
|
|
513
735
|
if (status === "open") {
|
|
@@ -534,50 +756,55 @@ function createTask(input, options) {
|
|
|
534
756
|
legacyTodoId: input.legacyTodoId
|
|
535
757
|
};
|
|
536
758
|
writeJson(join2(paths.tasksDir, `${id}.json`), record);
|
|
537
|
-
|
|
538
|
-
index.total += 1;
|
|
539
|
-
index.byStatus[record.status] += 1;
|
|
540
|
-
index.lastUpdated = Date.now();
|
|
541
|
-
writeIndex(paths, index);
|
|
542
|
-
const meta = readMeta(paths);
|
|
543
|
-
meta.updatedAt = Date.now();
|
|
544
|
-
writeMeta(paths, meta);
|
|
545
|
-
appendTaskEvent(paths, {
|
|
546
|
-
listId: paths.listId,
|
|
547
|
-
taskId: record.id,
|
|
548
|
-
type: "task.created",
|
|
549
|
-
timestamp: Date.now()
|
|
550
|
-
});
|
|
759
|
+
updateHighwatermark(paths, Number(id));
|
|
551
760
|
const { tasks } = rebuildBlocksForPaths(paths);
|
|
552
761
|
const refreshed = tasks.find((task) => task.id === record.id);
|
|
553
762
|
return refreshed ?? record;
|
|
554
763
|
});
|
|
555
764
|
}
|
|
556
765
|
function getTask(id, options) {
|
|
557
|
-
const
|
|
558
|
-
|
|
766
|
+
const pathsList = getTaskListReadPaths(options?.listId);
|
|
767
|
+
for (const paths of pathsList) {
|
|
768
|
+
const taskPath = join2(paths.tasksDir, `${id}.json`);
|
|
769
|
+
if (!existsSync2(taskPath)) continue;
|
|
770
|
+
const task = readTaskFile(taskPath);
|
|
771
|
+
if (task) return task;
|
|
772
|
+
}
|
|
773
|
+
return null;
|
|
559
774
|
}
|
|
560
775
|
function listTasks(options) {
|
|
561
|
-
const
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
776
|
+
const pathsList = getTaskListReadPaths(options?.listId);
|
|
777
|
+
const merged = /* @__PURE__ */ new Map();
|
|
778
|
+
for (const paths of pathsList) {
|
|
779
|
+
const tasks = readTasksFromDisk(paths);
|
|
780
|
+
const map = deriveBlocks(tasks);
|
|
781
|
+
const derived = applyBlocksMap(tasks, map);
|
|
782
|
+
const needsPersist = tasks.some((task) => {
|
|
783
|
+
const nextBlocks = map.get(task.id) ?? [];
|
|
784
|
+
return !areBlocksEqual(task.blocks, nextBlocks);
|
|
785
|
+
});
|
|
786
|
+
const ready = needsPersist ? withTaskListLock(paths, () => rebuildBlocksForPaths(paths).tasks) : derived;
|
|
787
|
+
for (const task of ready) {
|
|
788
|
+
if (!merged.has(task.id)) {
|
|
789
|
+
merged.set(task.id, task);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
return Array.from(merged.values()).sort((a, b) => Number(a.id) - Number(b.id));
|
|
573
794
|
}
|
|
574
795
|
function updateTask(id, updates, options) {
|
|
575
796
|
if (updates.status === "open") {
|
|
576
797
|
throw new Error("Task status open is not supported");
|
|
577
798
|
}
|
|
578
|
-
const
|
|
579
|
-
|
|
580
|
-
|
|
799
|
+
const pathsList = getTaskListReadPaths(options?.listId);
|
|
800
|
+
const target = pathsList.find(
|
|
801
|
+
(paths) => existsSync2(join2(paths.tasksDir, `${id}.json`))
|
|
802
|
+
);
|
|
803
|
+
if (!target) {
|
|
804
|
+
throw new Error(`Task ${id} not found`);
|
|
805
|
+
}
|
|
806
|
+
return withTaskListLock(target, () => {
|
|
807
|
+
const existing = readTaskFile(join2(target.tasksDir, `${id}.json`));
|
|
581
808
|
if (!existing) {
|
|
582
809
|
throw new Error(`Task ${id} not found`);
|
|
583
810
|
}
|
|
@@ -598,27 +825,8 @@ function updateTask(id, updates, options) {
|
|
|
598
825
|
}
|
|
599
826
|
const nextBaseVersion = existing.baseVersion + 1;
|
|
600
827
|
const updated = applyTaskUpdates(existing, updates, nextBaseVersion);
|
|
601
|
-
|
|
602
|
-
const
|
|
603
|
-
if (updated.status !== existing.status) {
|
|
604
|
-
index.byStatus[existing.status] = Math.max(
|
|
605
|
-
0,
|
|
606
|
-
index.byStatus[existing.status] - 1
|
|
607
|
-
);
|
|
608
|
-
index.byStatus[updated.status] += 1;
|
|
609
|
-
}
|
|
610
|
-
index.lastUpdated = Date.now();
|
|
611
|
-
writeIndex(paths, index);
|
|
612
|
-
const meta = readMeta(paths);
|
|
613
|
-
meta.updatedAt = Date.now();
|
|
614
|
-
writeMeta(paths, meta);
|
|
615
|
-
appendTaskEvent(paths, {
|
|
616
|
-
listId: paths.listId,
|
|
617
|
-
taskId: updated.id,
|
|
618
|
-
type: "task.updated",
|
|
619
|
-
timestamp: Date.now()
|
|
620
|
-
});
|
|
621
|
-
const { tasks } = rebuildBlocksForPaths(paths);
|
|
828
|
+
writeJsonAtomic(join2(target.tasksDir, `${id}.json`), updated);
|
|
829
|
+
const { tasks } = rebuildBlocksForPaths(target);
|
|
622
830
|
const refreshed = tasks.find((task) => task.id === updated.id);
|
|
623
831
|
return { task: refreshed ?? updated, conflict: hasConflict };
|
|
624
832
|
});
|
|
@@ -626,26 +834,16 @@ function updateTask(id, updates, options) {
|
|
|
626
834
|
function rebuildTaskBlocks(options) {
|
|
627
835
|
const paths = getTaskListPaths(options?.listId);
|
|
628
836
|
return withTaskListLock(paths, () => {
|
|
629
|
-
readIndex(paths);
|
|
630
837
|
ensureTaskListDirs(paths);
|
|
631
838
|
const { tasks, updated } = rebuildBlocksForPaths(paths);
|
|
632
839
|
return { updated, total: tasks.length };
|
|
633
840
|
});
|
|
634
841
|
}
|
|
635
|
-
function getTaskListMeta(options) {
|
|
636
|
-
const paths = getTaskListPaths(options?.listId);
|
|
637
|
-
return readMeta(paths);
|
|
638
|
-
}
|
|
639
|
-
function updateTaskListMeta(meta, options) {
|
|
640
|
-
const paths = getTaskListPaths(options?.listId);
|
|
641
|
-
const updated = { ...meta, updatedAt: Date.now() };
|
|
642
|
-
writeMeta(paths, updated);
|
|
643
|
-
return updated;
|
|
644
|
-
}
|
|
645
842
|
|
|
646
843
|
// src/utils/session/todoStorage.ts
|
|
647
844
|
var TODO_STORAGE_KEY = "todos";
|
|
648
845
|
var TODO_CONFIG_KEY = "todoConfig";
|
|
846
|
+
var TODO_MIGRATION_KEY = "todoMigration";
|
|
649
847
|
var DEFAULT_CONFIG = {
|
|
650
848
|
maxTodos: 100,
|
|
651
849
|
autoArchiveCompleted: false,
|
|
@@ -710,22 +908,24 @@ function syncTodosToTasks(todos, options) {
|
|
|
710
908
|
}
|
|
711
909
|
function migrateTodosToTasks(options) {
|
|
712
910
|
const { listId } = getTaskListPaths(options?.listId);
|
|
713
|
-
const
|
|
714
|
-
|
|
911
|
+
const migrationKey = `${listId}:${options?.agentId ?? "default"}`;
|
|
912
|
+
const sessionState = getSessionState();
|
|
913
|
+
const migrationState = sessionState[TODO_MIGRATION_KEY] ?? {};
|
|
914
|
+
if (migrationState[migrationKey]?.completedAt) {
|
|
715
915
|
return { listId, migrated: false, created: 0 };
|
|
716
916
|
}
|
|
717
917
|
const todos = getTodos(options?.agentId);
|
|
718
918
|
const result = syncTodosToTasks(todos, { listId });
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
919
|
+
setSessionState({
|
|
920
|
+
...sessionState,
|
|
921
|
+
[TODO_MIGRATION_KEY]: {
|
|
922
|
+
...migrationState,
|
|
923
|
+
[migrationKey]: {
|
|
723
924
|
completedAt: Date.now(),
|
|
724
925
|
sourceCount: todos.length
|
|
725
926
|
}
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
);
|
|
927
|
+
}
|
|
928
|
+
});
|
|
729
929
|
return { listId, migrated: true, created: result.created };
|
|
730
930
|
}
|
|
731
931
|
function invalidateCache() {
|
|
@@ -903,38 +1103,10 @@ var SystemReminderService = class {
|
|
|
903
1103
|
"todo",
|
|
904
1104
|
"task",
|
|
905
1105
|
"medium",
|
|
906
|
-
"This is a reminder that your task list is currently empty. DO NOT mention this to the user explicitly because they are already aware. If you are working on tasks that would benefit from a structured plan, use TaskCreate to
|
|
1106
|
+
"This is a reminder that your task list is currently empty. DO NOT mention this to the user explicitly because they are already aware. If you are working on tasks that would benefit from a structured plan, use TaskCreate once to provide a complete task list (no dependencies); the tool will finalize dependencies internally. Use TaskList to review readiness. If not, please feel free to ignore. Again do not mention this message to the user.",
|
|
907
1107
|
currentTime
|
|
908
1108
|
);
|
|
909
1109
|
}
|
|
910
|
-
if (todos.length > 0) {
|
|
911
|
-
const reminderKey = `todo_updated_${agentKey}_${todos.length}_${this.getTodoStateHash(todos)}`;
|
|
912
|
-
if (this.reminderCache.has(reminderKey)) {
|
|
913
|
-
return this.reminderCache.get(reminderKey);
|
|
914
|
-
}
|
|
915
|
-
if (!this.sessionState.remindersSent.has(reminderKey)) {
|
|
916
|
-
this.sessionState.remindersSent.add(reminderKey);
|
|
917
|
-
this.clearTodoReminders(agentKey);
|
|
918
|
-
const todoContent = JSON.stringify(
|
|
919
|
-
todos.map((todo) => ({
|
|
920
|
-
content: todo.content.length > 100 ? todo.content.substring(0, 100) + "..." : todo.content,
|
|
921
|
-
status: todo.status,
|
|
922
|
-
activeForm: todo.activeForm && todo.activeForm.length > 100 ? todo.activeForm.substring(0, 100) + "..." : todo.activeForm || todo.content
|
|
923
|
-
}))
|
|
924
|
-
);
|
|
925
|
-
const reminder = this.createReminderMessage(
|
|
926
|
-
"todo",
|
|
927
|
-
"task",
|
|
928
|
-
"medium",
|
|
929
|
-
`Your task items have changed. DO NOT mention this explicitly to the user. Here are the latest contents of your tracked items:
|
|
930
|
-
|
|
931
|
-
${todoContent}. Use TaskList to review readiness and TaskUpdate to adjust status if needed.`,
|
|
932
|
-
currentTime
|
|
933
|
-
);
|
|
934
|
-
this.reminderCache.set(reminderKey, reminder);
|
|
935
|
-
return reminder;
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
1110
|
return null;
|
|
939
1111
|
}
|
|
940
1112
|
dispatchSecurityEvent() {
|
|
@@ -1357,9 +1529,12 @@ var resetReminderSession = () => systemReminderService.resetSession();
|
|
|
1357
1529
|
export {
|
|
1358
1530
|
getAgentFilePath,
|
|
1359
1531
|
generateAgentId,
|
|
1532
|
+
generateTaskListId,
|
|
1533
|
+
runWithTaskListId,
|
|
1534
|
+
runWithTaskListEnv,
|
|
1360
1535
|
TaskStoreConflictError,
|
|
1361
1536
|
getTaskListPaths,
|
|
1362
|
-
|
|
1537
|
+
initTaskListLockFile,
|
|
1363
1538
|
createTask,
|
|
1364
1539
|
getTask,
|
|
1365
1540
|
listTasks,
|