@mmmbuto/qwen-code-termux 0.16.1-termux → 0.18.0-termux
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/README.md +79 -109
- package/bundled/new-app/SKILL.md +22 -0
- package/bundled/qc-helper/SKILL.md +29 -24
- package/bundled/qc-helper/docs/_meta.ts +1 -0
- package/bundled/qc-helper/docs/configuration/_meta.ts +0 -3
- package/bundled/qc-helper/docs/configuration/settings.md +37 -31
- package/bundled/qc-helper/docs/configuration/themes.md +39 -0
- package/bundled/qc-helper/docs/features/_meta.ts +1 -3
- package/bundled/qc-helper/docs/features/approval-mode.md +35 -35
- package/bundled/qc-helper/docs/features/auto-mode.md +54 -9
- package/bundled/qc-helper/docs/features/channels/_meta.ts +1 -0
- package/bundled/qc-helper/docs/features/channels/feishu.md +170 -0
- package/bundled/qc-helper/docs/features/commands.md +115 -35
- package/bundled/qc-helper/docs/features/followup-suggestions.md +2 -2
- package/bundled/qc-helper/docs/features/headless.md +32 -0
- package/bundled/qc-helper/docs/features/markdown-rendering.md +21 -1
- package/bundled/qc-helper/docs/features/memory.md +22 -5
- package/bundled/qc-helper/docs/features/scheduled-tasks.md +1 -1
- package/bundled/qc-helper/docs/features/status-line.md +168 -32
- package/bundled/qc-helper/docs/features/sub-agents.md +60 -0
- package/bundled/qc-helper/docs/features/worktree.md +345 -0
- package/bundled/qc-helper/docs/overview.md +4 -4
- package/bundled/qc-helper/docs/quickstart.md +4 -4
- package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +221 -0
- package/bundled/qc-helper/docs/qwen-serve.md +234 -24
- package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +16 -0
- package/bundled/qc-helper/docs/support/Uninstall.md +19 -1
- package/bundled/qc-helper/docs/support/troubleshooting.md +2 -1
- package/bundled/simplify/SKILL.md +123 -0
- package/chunks/agent-IDS4HMOX.js +56 -0
- package/chunks/agent-headless-5Q2EUSPS.js +50 -0
- package/chunks/{anthropicContentGenerator-SSGKR6DO.js → anthropicContentGenerator-2HBRNQ3B.js} +52 -9
- package/chunks/{askUserQuestion-PJWUUXKN.js → askUserQuestion-75TDJVK2.js} +45 -3
- package/chunks/{ca-UZ7BANMN.js → ca-BARBRL6N.js} +89 -5
- package/chunks/{chunk-GGNTZ2NH.js → chunk-2Y5SYSD3.js} +368 -597
- package/chunks/{chunk-2LA2TREA.js → chunk-3AA2DK35.js} +1448 -207
- package/chunks/{chunk-I2V5WXHJ.js → chunk-3AUHFMSK.js} +80 -38
- package/chunks/chunk-3DHXZ6EV.js +241 -0
- package/chunks/{chunk-PR4T27R7.js → chunk-3HTIVKZE.js} +42 -8
- package/chunks/chunk-3HX5LZ6R.js +1798 -0
- package/chunks/chunk-3PJXIDKI.js +2517 -0
- package/chunks/{chunk-MYAKAFEC.js → chunk-55ZMG67I.js} +7451 -3517
- package/chunks/{chunk-66CXYE4B.js → chunk-5IFG2VC4.js} +293 -242
- package/chunks/chunk-64WXLC72.js +98 -0
- package/chunks/{chunk-C6WMLUNB.js → chunk-72LDN5PP.js} +1 -1
- package/chunks/{chunk-F23NCRJ2.js → chunk-A7B4ISQP.js} +1 -1
- package/chunks/chunk-B7HXHOHU.js +393 -0
- package/chunks/{chunk-XEGHDASV.js → chunk-D3RHSPAS.js} +435 -540
- package/chunks/{chunk-XKS5KBFJ.js → chunk-EYENRK4D.js} +694 -384
- package/chunks/chunk-H6BD2ELD.js +36 -0
- package/chunks/{chunk-XP27SJMH.js → chunk-HR7SV7AY.js} +79 -48
- package/chunks/{chunk-D5NTAHYL.js → chunk-IDX6COTE.js} +7 -2
- package/chunks/{chunk-SHT4VJWU.js → chunk-IWKSG2AR.js} +2 -2
- package/chunks/chunk-J37FGIOA.js +1623 -0
- package/chunks/chunk-J5MDQKJL.js +2230 -0
- package/chunks/{chunk-USE2VQ5P.js → chunk-JTQAQBTV.js} +21 -0
- package/chunks/{chunk-NCTLV2NB.js → chunk-KQJMQJPI.js} +1 -1
- package/chunks/{chunk-5FBA5XC2.js → chunk-KRIHGKNA.js} +1 -1
- package/chunks/chunk-LD2XBG6Z.js +102 -0
- package/chunks/{chunk-MAY32HXD.js → chunk-M6VTDSVR.js} +3 -1
- package/chunks/chunk-MRO43B25.js +30 -0
- package/chunks/{chunk-N4WOREMD.js → chunk-NVFMZBX2.js} +43 -3
- package/chunks/chunk-OHEGWO4L.js +264 -0
- package/chunks/{chunk-K6O2NBMF.js → chunk-OQ7NJIY7.js} +4604 -6397
- package/chunks/chunk-QQDPRDVW.js +25 -0
- package/chunks/{chunk-KXZ4TJB4.js → chunk-SEGYWKIH.js} +1 -1
- package/chunks/chunk-SKBPNJEW.js +45 -0
- package/chunks/{chunk-4AOCVI6J.js → chunk-SNGELLWX.js} +52 -6
- package/chunks/{chunk-3OCRHZA3.js → chunk-TD4OPI4T.js} +56742 -44104
- package/chunks/{chunk-DQ4QTG7E.js → chunk-VV4F63BD.js} +11 -11
- package/chunks/chunk-XBY7E2FX.js +605 -0
- package/chunks/{chunk-JKMBWLFB.js → chunk-YILFYI5W.js} +48 -26
- package/chunks/chunk-YOGAOMYB.js +159 -0
- package/chunks/{chunk-QWSRH265.js → chunk-Z2Z3GUXZ.js} +777 -776
- package/chunks/{chunk-SDHRQFOS.js → chunk-ZTZ4DDQE.js} +2 -2
- package/chunks/computer-use-W2TYQNEE.js +825 -0
- package/chunks/contextCommand-6FGX3A7J.js +52 -0
- package/chunks/{cron-create-3ZBBN7WB.js → cron-create-APL5LU6I.js} +3 -3
- package/chunks/{cron-delete-NAGKKIIG.js → cron-delete-4SBJSCN4.js} +3 -3
- package/chunks/{cron-list-PAGRXNAI.js → cron-list-2AMGOMVO.js} +3 -3
- package/chunks/{de-V4IE2OOZ.js → de-YGKK2BC4.js} +89 -5
- package/chunks/{devtools-TWVXEJQB.js → devtools-FM6GJPYG.js} +2 -1
- package/chunks/{dist-4L54HRX2.js → dist-4LXD6L6X.js} +24 -5
- package/chunks/dist-H6ONXVLG.js +94146 -0
- package/chunks/{dist-XKWIWPWQ.js → dist-KAZ3SEBX.js} +1083 -3856
- package/chunks/{dist-BXDUQ2QY.js → dist-PK7DFCAW.js} +1 -1
- package/chunks/{edit-NVO3FOAK.js → edit-ZCEZC264.js} +30 -22
- package/chunks/{en-HGJ2SPLM.js → en-DHGYHIHX.js} +127 -6
- package/chunks/{enter-worktree-UEBG4WFC.js → enter-worktree-BBHCFCHG.js} +30 -20
- package/chunks/enterPlanMode-3M6KTD3B.js +158 -0
- package/chunks/{exit-worktree-UZ3MAQZN.js → exit-worktree-73YPIEQO.js} +27 -19
- package/chunks/exitPlanMode-TYZM6BAE.js +703 -0
- package/chunks/{fr-CJULI7ZX.js → fr-JXBKPJKQ.js} +89 -5
- package/chunks/{geminiContentGenerator-3UZFXGNT.js → geminiContentGenerator-7N2V3VW2.js} +8 -6
- package/chunks/{getMachineId-bsd-JXOSIJV2.js → getMachineId-bsd-4CASPIU4.js} +4 -4
- package/chunks/{getMachineId-darwin-TE4QRR42.js → getMachineId-darwin-HPQPEMZR.js} +4 -4
- package/chunks/{getMachineId-linux-S3OL52XK.js → getMachineId-linux-AUARKYHL.js} +3 -3
- package/chunks/{getMachineId-unsupported-DWUSBAPX.js → getMachineId-unsupported-S32ZDA2T.js} +3 -3
- package/chunks/{getMachineId-win-AAC5P3AP.js → getMachineId-win-4EFLHYIJ.js} +4 -4
- package/chunks/{glob-KNHSFFFG.js → glob-5XBCPQ2A.js} +27 -19
- package/chunks/{grep-LACWDZW4.js → grep-VIUU3A7X.js} +30 -19
- package/chunks/{ja-L7CHRQEW.js → ja-TGPZSP2B.js} +89 -5
- package/chunks/{keychain-token-storage-335UOLJ6.js → keychain-token-storage-6IU6ORQN.js} +3 -3
- package/chunks/{ls-AGXQOKSG.js → ls-JRGYIGLY.js} +4 -4
- package/chunks/{lsp-UDMUHNPA.js → lsp-SHMKFOAC.js} +3 -3
- package/chunks/{monitor-ETKWPJEH.js → monitor-6R4LIJL5.js} +40 -25
- package/chunks/{multipart-parser-3QWGTLK3.js → multipart-parser-AJ4WASWR.js} +2 -2
- package/chunks/{notebook-edit-QJJLPNYT.js → notebook-edit-5E7ULDVQ.js} +28 -20
- package/chunks/{openaiContentGenerator-CNNN424U.js → openaiContentGenerator-ZVHFKM3O.js} +17 -14
- package/chunks/{pt-M6JULLEQ.js → pt-TIBG6BIO.js} +89 -5
- package/chunks/{qwenContentGenerator-BOLCGK3R.js → qwenContentGenerator-B2VTVSPJ.js} +31 -23
- package/chunks/{qwenOAuth2-EEJGROP7.js → qwenOAuth2-2KCKWDCF.js} +6 -4
- package/chunks/read-file-GIT7BCDR.js +27 -0
- package/chunks/ripGrep-MWKFVYMS.js +48 -0
- package/chunks/{ru-QILM4HBC.js → ru-JBCHCK4L.js} +89 -5
- package/chunks/scheduler-5VOOYGBH.js +308 -0
- package/chunks/send-message-4QNWQJF4.js +244 -0
- package/chunks/{serve-OLSI7WSR.js → serve-MN6HZBWN.js} +14262 -7414
- package/chunks/shell-NQZQGFM2.js +56 -0
- package/chunks/{skill-D6YRHTTI.js → skill-WCFW4644.js} +145 -119
- package/chunks/{src-TMOD5X6F.js → src-7XL4G4DC.js} +88 -46
- package/chunks/{src-4QH4FZ6I.js → src-IHA6DTUV.js} +452 -62
- package/chunks/{syntheticOutput-5PVFDDJ4.js → syntheticOutput-YTYS2ZMQ.js} +4 -4
- package/chunks/task-create-MPORPYN6.js +19 -0
- package/chunks/task-list-R2YDYPZT.js +151 -0
- package/chunks/{task-stop-AJKPSR6R.js → task-stop-SYWJYBCM.js} +3 -3
- package/chunks/task-update-E4NSLKMQ.js +408 -0
- package/chunks/team-create-7R7KA5IP.js +314 -0
- package/chunks/team-delete-25OIWUPN.js +116 -0
- package/chunks/{todoWrite-VLAUG4CA.js → todoWrite-4YHMIF4X.js} +16 -5
- package/chunks/{tool-search-MZGHUUKD.js → tool-search-YBRVZCLI.js} +29 -11
- package/chunks/{tts-notification-K3X7X7MN.js → tts-notification-7SOEMQK4.js} +5 -4
- package/chunks/{web-fetch-OILB464A.js → web-fetch-MFIRHIHI.js} +5 -5
- package/chunks/workflow-5RIKVCIE.js +960 -0
- package/chunks/{write-file-BIQAA57V.js → write-file-DMQTJZOM.js} +32 -24
- package/chunks/{zh-PWL2NKY3.js → zh-7H5OQC4I.js} +135 -11
- package/chunks/{zh-TW-S3YGWICZ.js → zh-TW-P4IDHD3M.js} +128 -11
- package/cli.js +45402 -20570
- package/examples/agent/agents/diary.md +86 -0
- package/examples/agent/qwen-extension.json +5 -0
- package/examples/commands/commands/fs/grep-code.md +3 -0
- package/examples/commands/qwen-extension.json +5 -0
- package/examples/context/QWEN.md +8 -0
- package/examples/context/qwen-extension.json +5 -0
- package/examples/mcp-server/example.ts +60 -0
- package/examples/mcp-server/package.json +18 -0
- package/examples/mcp-server/qwen-extension.json +12 -0
- package/examples/mcp-server/tsconfig.json +13 -0
- package/examples/skills/qwen-extension.json +5 -0
- package/examples/skills/skills/synonyms/SKILL.md +48 -0
- package/examples/starter/QWEN.md +30 -0
- package/examples/starter/README.md +59 -0
- package/examples/starter/agents/diary.md +86 -0
- package/examples/starter/commands/writing/polish.md +13 -0
- package/examples/starter/example.ts +64 -0
- package/examples/starter/package.json +18 -0
- package/examples/starter/qwen-extension.json +12 -0
- package/examples/starter/skills/synonyms/SKILL.md +48 -0
- package/examples/starter/tsconfig.json +13 -0
- package/fzfWorker.js +1083 -0
- package/locales/ca.js +118 -5
- package/locales/de.js +117 -5
- package/locales/en.js +169 -7
- package/locales/fr.js +119 -5
- package/locales/ja.js +114 -5
- package/locales/pt.js +117 -5
- package/locales/ru.js +116 -5
- package/locales/zh-TW.js +161 -12
- package/locales/zh.js +169 -12
- package/package.json +4 -2
- package/scripts/postinstall.cjs +2 -1
- package/bundled/qc-helper/docs/features/checkpointing.md +0 -77
- package/chunks/agent-7ZN3CRHR.js +0 -48
- package/chunks/chunk-6PCB2DEF.js +0 -434
- package/chunks/chunk-EM6ETG2K.js +0 -60
- package/chunks/chunk-G7YTSRES.js +0 -150
- package/chunks/contextCommand-7IBASARL.js +0 -44
- package/chunks/exitPlanMode-PZAMWIRW.js +0 -227
- package/chunks/multipart-parser-IXGBIOIN.js +0 -384
- package/chunks/read-file-CCUEUFG2.js +0 -24
- package/chunks/ripGrep-TADOH2HK.js +0 -40
- package/chunks/send-message-YL44UZFC.js +0 -151
- package/chunks/shell-7KKKC5G7.js +0 -48
- package/chunks/src-IPWIHNMI.js +0 -1406
- package/chunks/undici-F6ZOXSS5.js +0 -8
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
import {
|
|
4
4
|
resolveBundleDir
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-TD4OPI4T.js";
|
|
6
6
|
import {
|
|
7
7
|
Storage
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-HR7SV7AY.js";
|
|
9
9
|
import {
|
|
10
10
|
init_esbuild_shims
|
|
11
11
|
} from "./chunk-A4BMJM77.js";
|
|
@@ -169,15 +169,15 @@ init_esbuild_shims();
|
|
|
169
169
|
|
|
170
170
|
// import("./locales/**/*.js") in packages/cli/src/i18n/index.ts
|
|
171
171
|
var globImport_locales_js = __glob({
|
|
172
|
-
"./locales/ca.js": () => import("./ca-
|
|
173
|
-
"./locales/de.js": () => import("./de-
|
|
174
|
-
"./locales/en.js": () => import("./en-
|
|
175
|
-
"./locales/fr.js": () => import("./fr-
|
|
176
|
-
"./locales/ja.js": () => import("./ja-
|
|
177
|
-
"./locales/pt.js": () => import("./pt-
|
|
178
|
-
"./locales/ru.js": () => import("./ru-
|
|
179
|
-
"./locales/zh-TW.js": () => import("./zh-TW-
|
|
180
|
-
"./locales/zh.js": () => import("./zh-
|
|
172
|
+
"./locales/ca.js": () => import("./ca-BARBRL6N.js"),
|
|
173
|
+
"./locales/de.js": () => import("./de-YGKK2BC4.js"),
|
|
174
|
+
"./locales/en.js": () => import("./en-DHGYHIHX.js"),
|
|
175
|
+
"./locales/fr.js": () => import("./fr-JXBKPJKQ.js"),
|
|
176
|
+
"./locales/ja.js": () => import("./ja-TGPZSP2B.js"),
|
|
177
|
+
"./locales/pt.js": () => import("./pt-TIBG6BIO.js"),
|
|
178
|
+
"./locales/ru.js": () => import("./ru-JBCHCK4L.js"),
|
|
179
|
+
"./locales/zh-TW.js": () => import("./zh-TW-P4IDHD3M.js"),
|
|
180
|
+
"./locales/zh.js": () => import("./zh-7H5OQC4I.js")
|
|
181
181
|
});
|
|
182
182
|
|
|
183
183
|
// packages/cli/src/i18n/index.ts
|
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
// Force strict mode and setup for ESM
|
|
2
|
+
"use strict";
|
|
3
|
+
import {
|
|
4
|
+
Mutex,
|
|
5
|
+
getTasksDir,
|
|
6
|
+
require_proper_lockfile
|
|
7
|
+
} from "./chunk-J5MDQKJL.js";
|
|
8
|
+
import {
|
|
9
|
+
atomicWriteJSON
|
|
10
|
+
} from "./chunk-B7HXHOHU.js";
|
|
11
|
+
import {
|
|
12
|
+
createDebugLogger,
|
|
13
|
+
isNodeError
|
|
14
|
+
} from "./chunk-HR7SV7AY.js";
|
|
15
|
+
import {
|
|
16
|
+
init_esbuild_shims
|
|
17
|
+
} from "./chunk-A4BMJM77.js";
|
|
18
|
+
import {
|
|
19
|
+
__name,
|
|
20
|
+
__toESM
|
|
21
|
+
} from "./chunk-J2S4EL5Y.js";
|
|
22
|
+
|
|
23
|
+
// packages/core/src/agents/team/tasks.ts
|
|
24
|
+
init_esbuild_shims();
|
|
25
|
+
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
26
|
+
import * as fs from "node:fs/promises";
|
|
27
|
+
import { constants as fsConstants } from "node:fs";
|
|
28
|
+
import * as path from "node:path";
|
|
29
|
+
var debug = createDebugLogger("AGENTS_TEAM_TASKS");
|
|
30
|
+
var MAX_METADATA_BYTES = 32768;
|
|
31
|
+
var MAX_PARALLEL_TASK_READS = 16;
|
|
32
|
+
function assertMetadataWithinLimit(metadata) {
|
|
33
|
+
if (!metadata) return;
|
|
34
|
+
const size = Buffer.byteLength(JSON.stringify(metadata), "utf-8");
|
|
35
|
+
if (size > MAX_METADATA_BYTES) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`Task metadata is too large (${size} bytes; max ${MAX_METADATA_BYTES}). Trim the payload or store the bulk content elsewhere.`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
__name(assertMetadataWithinLimit, "assertMetadataWithinLimit");
|
|
42
|
+
var LOCK_OPTIONS = {
|
|
43
|
+
retries: {
|
|
44
|
+
retries: 30,
|
|
45
|
+
minTimeout: 5,
|
|
46
|
+
maxTimeout: 100,
|
|
47
|
+
factor: 2,
|
|
48
|
+
// Jitter the backoff so in-process and cross-process contenders
|
|
49
|
+
// don't retry in lockstep (thundering herd) and starve each other
|
|
50
|
+
// out of the retry budget — mirrors mailbox.ts. The most acute case
|
|
51
|
+
// is scanIdleAgentsForTasks racing up to MAX_TEAMMATES claimants at
|
|
52
|
+
// the same first-pending task file.
|
|
53
|
+
randomize: true
|
|
54
|
+
},
|
|
55
|
+
stale: 5e3,
|
|
56
|
+
onCompromised: /* @__PURE__ */ __name((err) => {
|
|
57
|
+
debug.warn("task lock compromised:", err?.message ?? err);
|
|
58
|
+
}, "onCompromised")
|
|
59
|
+
};
|
|
60
|
+
var taskFileLocks = /* @__PURE__ */ new Map();
|
|
61
|
+
function getTaskFileLock(taskPath) {
|
|
62
|
+
let lock = taskFileLocks.get(taskPath);
|
|
63
|
+
if (!lock) {
|
|
64
|
+
lock = new Mutex();
|
|
65
|
+
taskFileLocks.set(taskPath, lock);
|
|
66
|
+
}
|
|
67
|
+
return lock;
|
|
68
|
+
}
|
|
69
|
+
__name(getTaskFileLock, "getTaskFileLock");
|
|
70
|
+
async function withTaskFileLock(taskPath, fn, onMissing) {
|
|
71
|
+
return getTaskFileLock(taskPath).runExclusive(async () => {
|
|
72
|
+
let release;
|
|
73
|
+
try {
|
|
74
|
+
release = await import_proper_lockfile.default.lock(taskPath, LOCK_OPTIONS);
|
|
75
|
+
} catch (err) {
|
|
76
|
+
if (isNodeError(err) && err.code === "ENOENT") return onMissing();
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
return await fn();
|
|
81
|
+
} finally {
|
|
82
|
+
await release();
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
__name(withTaskFileLock, "withTaskFileLock");
|
|
87
|
+
var RECIPROCAL_CALLER = "__reciprocal__";
|
|
88
|
+
var agentClaimLocks = /* @__PURE__ */ new Map();
|
|
89
|
+
function getAgentClaimLock(agentId) {
|
|
90
|
+
let lock = agentClaimLocks.get(agentId);
|
|
91
|
+
if (!lock) {
|
|
92
|
+
lock = new Mutex();
|
|
93
|
+
agentClaimLocks.set(agentId, lock);
|
|
94
|
+
}
|
|
95
|
+
return lock;
|
|
96
|
+
}
|
|
97
|
+
__name(getAgentClaimLock, "getAgentClaimLock");
|
|
98
|
+
function assertValidTaskId(taskId) {
|
|
99
|
+
if (!/^[1-9]\d*$/.test(taskId)) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`Invalid task ID "${taskId}". Task IDs must be positive integers.`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
__name(assertValidTaskId, "assertValidTaskId");
|
|
106
|
+
function getTaskPath(teamName, taskId) {
|
|
107
|
+
assertValidTaskId(taskId);
|
|
108
|
+
return path.join(getTasksDir(teamName), `${taskId}.json`);
|
|
109
|
+
}
|
|
110
|
+
__name(getTaskPath, "getTaskPath");
|
|
111
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
112
|
+
function onTasksUpdated(listener) {
|
|
113
|
+
listeners.add(listener);
|
|
114
|
+
return () => {
|
|
115
|
+
listeners.delete(listener);
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
__name(onTasksUpdated, "onTasksUpdated");
|
|
119
|
+
function notifyTasksUpdated(teamName) {
|
|
120
|
+
for (const listener of listeners) {
|
|
121
|
+
try {
|
|
122
|
+
listener(teamName);
|
|
123
|
+
} catch (err) {
|
|
124
|
+
debug.warn(`task update listener failed: ${err}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
__name(notifyTasksUpdated, "notifyTasksUpdated");
|
|
129
|
+
async function createTask(teamName, opts) {
|
|
130
|
+
assertMetadataWithinLimit(opts.metadata);
|
|
131
|
+
const dir = getTasksDir(teamName);
|
|
132
|
+
await fs.mkdir(dir, { recursive: true });
|
|
133
|
+
const MAX_RETRIES = 15;
|
|
134
|
+
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
135
|
+
const nextId = await getNextTaskId(dir);
|
|
136
|
+
const task = {
|
|
137
|
+
id: nextId,
|
|
138
|
+
subject: opts.subject,
|
|
139
|
+
description: opts.description,
|
|
140
|
+
activeForm: opts.activeForm,
|
|
141
|
+
owner: opts.owner,
|
|
142
|
+
status: "pending",
|
|
143
|
+
blocks: [],
|
|
144
|
+
blockedBy: [],
|
|
145
|
+
metadata: opts.metadata
|
|
146
|
+
};
|
|
147
|
+
const taskPath = path.join(dir, `${nextId}.json`);
|
|
148
|
+
try {
|
|
149
|
+
const handle = await fs.open(
|
|
150
|
+
taskPath,
|
|
151
|
+
fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL
|
|
152
|
+
);
|
|
153
|
+
await handle.close();
|
|
154
|
+
} catch (err) {
|
|
155
|
+
if (isNodeError(err) && err.code === "EEXIST") {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
throw err;
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
await atomicWriteJSON(taskPath, task);
|
|
162
|
+
} catch (err) {
|
|
163
|
+
await fs.unlink(taskPath).catch(() => {
|
|
164
|
+
});
|
|
165
|
+
throw err;
|
|
166
|
+
}
|
|
167
|
+
notifyTasksUpdated(teamName);
|
|
168
|
+
return task;
|
|
169
|
+
}
|
|
170
|
+
throw new Error(
|
|
171
|
+
`Failed to create task after ${MAX_RETRIES} attempts (ID contention).`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
__name(createTask, "createTask");
|
|
175
|
+
async function getTask(teamName, taskId) {
|
|
176
|
+
const taskPath = getTaskPath(teamName, taskId);
|
|
177
|
+
try {
|
|
178
|
+
const raw = await fs.readFile(taskPath, "utf-8");
|
|
179
|
+
return JSON.parse(raw);
|
|
180
|
+
} catch (err) {
|
|
181
|
+
if (isNodeError(err) && err.code === "ENOENT") return void 0;
|
|
182
|
+
throw err;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
__name(getTask, "getTask");
|
|
186
|
+
var TaskOwnershipError = class extends Error {
|
|
187
|
+
constructor(taskId, callerName, actualOwner) {
|
|
188
|
+
super(
|
|
189
|
+
`Task #${taskId} is owned by "${actualOwner}". Only the leader or the owner can change status / owner / subject / description / blocks.`
|
|
190
|
+
);
|
|
191
|
+
this.taskId = taskId;
|
|
192
|
+
this.callerName = callerName;
|
|
193
|
+
this.actualOwner = actualOwner;
|
|
194
|
+
this.name = "TaskOwnershipError";
|
|
195
|
+
}
|
|
196
|
+
static {
|
|
197
|
+
__name(this, "TaskOwnershipError");
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
async function updateTask(teamName, taskId, updates, opts) {
|
|
201
|
+
const taskPath = getTaskPath(teamName, taskId);
|
|
202
|
+
return withTaskFileLock(
|
|
203
|
+
taskPath,
|
|
204
|
+
async () => {
|
|
205
|
+
let raw;
|
|
206
|
+
try {
|
|
207
|
+
raw = await fs.readFile(taskPath, "utf-8");
|
|
208
|
+
} catch (err) {
|
|
209
|
+
if (isNodeError(err) && err.code === "ENOENT") return void 0;
|
|
210
|
+
throw err;
|
|
211
|
+
}
|
|
212
|
+
const task = JSON.parse(raw);
|
|
213
|
+
if (opts?.callerName !== void 0 && opts.callerName !== RECIPROCAL_CALLER) {
|
|
214
|
+
const restrictsOwnership = updates.status !== void 0 || updates.owner !== void 0 || updates.subject !== void 0 || updates.description !== void 0 || (updates.addBlocks?.length ?? 0) > 0 || (updates.addBlockedBy?.length ?? 0) > 0;
|
|
215
|
+
if (restrictsOwnership && task.owner && task.owner !== opts.callerName) {
|
|
216
|
+
throw new TaskOwnershipError(taskId, opts.callerName, task.owner);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (updates.addBlocks?.length) {
|
|
220
|
+
const blockSet = new Set(task.blocks);
|
|
221
|
+
for (const id of updates.addBlocks) blockSet.add(id);
|
|
222
|
+
task.blocks = Array.from(blockSet);
|
|
223
|
+
}
|
|
224
|
+
if (updates.addBlockedBy?.length) {
|
|
225
|
+
const blockedBySet = new Set(task.blockedBy);
|
|
226
|
+
for (const id of updates.addBlockedBy) blockedBySet.add(id);
|
|
227
|
+
task.blockedBy = Array.from(blockedBySet);
|
|
228
|
+
}
|
|
229
|
+
if (updates.status !== void 0) {
|
|
230
|
+
task.status = updates.status;
|
|
231
|
+
if (updates.status === "completed" && task.blocks.length > 0) {
|
|
232
|
+
await unblockDependents(teamName, taskId, task.blocks);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (updates.owner !== void 0) {
|
|
236
|
+
task.owner = updates.owner ? updates.owner : void 0;
|
|
237
|
+
}
|
|
238
|
+
if (updates.subject !== void 0) {
|
|
239
|
+
task.subject = updates.subject;
|
|
240
|
+
}
|
|
241
|
+
if (updates.description !== void 0) {
|
|
242
|
+
task.description = updates.description;
|
|
243
|
+
}
|
|
244
|
+
if (updates.activeForm !== void 0) {
|
|
245
|
+
task.activeForm = updates.activeForm ?? void 0;
|
|
246
|
+
}
|
|
247
|
+
if (updates.metadata !== void 0) {
|
|
248
|
+
task.metadata = task.metadata ?? {};
|
|
249
|
+
for (const [key, value] of Object.entries(updates.metadata)) {
|
|
250
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (value === null) {
|
|
254
|
+
delete task.metadata[key];
|
|
255
|
+
} else {
|
|
256
|
+
task.metadata[key] = value;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (Object.keys(task.metadata).length === 0) {
|
|
260
|
+
task.metadata = void 0;
|
|
261
|
+
}
|
|
262
|
+
assertMetadataWithinLimit(task.metadata);
|
|
263
|
+
}
|
|
264
|
+
await atomicWriteJSON(taskPath, task);
|
|
265
|
+
notifyTasksUpdated(teamName);
|
|
266
|
+
return task;
|
|
267
|
+
},
|
|
268
|
+
() => void 0
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
__name(updateTask, "updateTask");
|
|
272
|
+
async function deleteTask(teamName, taskId, opts) {
|
|
273
|
+
const taskPath = getTaskPath(teamName, taskId);
|
|
274
|
+
const dependentIds = await withTaskFileLock(
|
|
275
|
+
taskPath,
|
|
276
|
+
async () => {
|
|
277
|
+
let task;
|
|
278
|
+
try {
|
|
279
|
+
const raw = await fs.readFile(taskPath, "utf-8");
|
|
280
|
+
task = JSON.parse(raw);
|
|
281
|
+
} catch (err) {
|
|
282
|
+
if (isNodeError(err) && err.code === "ENOENT") return null;
|
|
283
|
+
throw err;
|
|
284
|
+
}
|
|
285
|
+
if (opts?.callerName !== void 0 && task.owner && task.owner !== opts.callerName) {
|
|
286
|
+
throw new TaskOwnershipError(taskId, opts.callerName, task.owner);
|
|
287
|
+
}
|
|
288
|
+
const deps = /* @__PURE__ */ new Set([...task.blocks, ...task.blockedBy]);
|
|
289
|
+
deps.delete(taskId);
|
|
290
|
+
try {
|
|
291
|
+
await fs.unlink(taskPath);
|
|
292
|
+
} catch (err) {
|
|
293
|
+
if (isNodeError(err) && err.code === "ENOENT") return null;
|
|
294
|
+
throw err;
|
|
295
|
+
}
|
|
296
|
+
return deps;
|
|
297
|
+
},
|
|
298
|
+
() => null
|
|
299
|
+
);
|
|
300
|
+
if (dependentIds === null) return false;
|
|
301
|
+
const results = await Promise.allSettled(
|
|
302
|
+
Array.from(dependentIds).map(
|
|
303
|
+
(depId) => removeEdgesReferencing(teamName, depId, taskId)
|
|
304
|
+
)
|
|
305
|
+
);
|
|
306
|
+
for (const r of results) {
|
|
307
|
+
if (r.status === "rejected") {
|
|
308
|
+
debug.warn(`deleteTask(${taskId}): edge cleanup failed: ${r.reason}`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
notifyTasksUpdated(teamName);
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
__name(deleteTask, "deleteTask");
|
|
315
|
+
async function removeEdgesReferencing(teamName, targetId, referencedId) {
|
|
316
|
+
const depPath = getTaskPath(teamName, targetId);
|
|
317
|
+
await withTaskFileLock(
|
|
318
|
+
depPath,
|
|
319
|
+
async () => {
|
|
320
|
+
try {
|
|
321
|
+
const raw = await fs.readFile(depPath, "utf-8");
|
|
322
|
+
const task = JSON.parse(raw);
|
|
323
|
+
const beforeBlocks = task.blocks.length;
|
|
324
|
+
const beforeBlockedBy = task.blockedBy.length;
|
|
325
|
+
task.blocks = task.blocks.filter((id) => id !== referencedId);
|
|
326
|
+
task.blockedBy = task.blockedBy.filter((id) => id !== referencedId);
|
|
327
|
+
if (task.blocks.length === beforeBlocks && task.blockedBy.length === beforeBlockedBy) {
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
await atomicWriteJSON(depPath, task);
|
|
331
|
+
} catch (err) {
|
|
332
|
+
if (isNodeError(err) && err.code === "ENOENT") return;
|
|
333
|
+
throw err;
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
() => void 0
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
__name(removeEdgesReferencing, "removeEdgesReferencing");
|
|
340
|
+
async function listTasks(teamName, filters) {
|
|
341
|
+
const dir = getTasksDir(teamName);
|
|
342
|
+
let entries;
|
|
343
|
+
try {
|
|
344
|
+
entries = await fs.readdir(dir);
|
|
345
|
+
} catch (err) {
|
|
346
|
+
if (isNodeError(err) && err.code === "ENOENT") return [];
|
|
347
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
348
|
+
debug.warn(`Failed to list tasks dir ${dir}: ${errMsg}`);
|
|
349
|
+
throw err instanceof Error ? err : new Error(errMsg);
|
|
350
|
+
}
|
|
351
|
+
const jsonEntries = entries.filter((e) => e.endsWith(".json"));
|
|
352
|
+
const reads = [];
|
|
353
|
+
for (let i = 0; i < jsonEntries.length; i += MAX_PARALLEL_TASK_READS) {
|
|
354
|
+
const batch = jsonEntries.slice(i, i + MAX_PARALLEL_TASK_READS);
|
|
355
|
+
const batchReads = await Promise.all(
|
|
356
|
+
batch.map(async (entry) => {
|
|
357
|
+
const filePath = path.join(dir, entry);
|
|
358
|
+
let raw;
|
|
359
|
+
try {
|
|
360
|
+
raw = await fs.readFile(filePath, "utf-8");
|
|
361
|
+
} catch (err) {
|
|
362
|
+
if (isNodeError(err) && err.code === "ENOENT") return void 0;
|
|
363
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
364
|
+
debug.warn(`Failed to read task file ${filePath}: ${errMsg}`);
|
|
365
|
+
return void 0;
|
|
366
|
+
}
|
|
367
|
+
if (raw.trim() === "") {
|
|
368
|
+
return void 0;
|
|
369
|
+
}
|
|
370
|
+
try {
|
|
371
|
+
return JSON.parse(raw);
|
|
372
|
+
} catch (err) {
|
|
373
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
374
|
+
debug.warn(`Quarantining corrupt task file ${filePath}: ${errMsg}`);
|
|
375
|
+
const quarantined = `${filePath}.corrupt-${Date.now()}`;
|
|
376
|
+
try {
|
|
377
|
+
await fs.rename(filePath, quarantined);
|
|
378
|
+
} catch (renameErr) {
|
|
379
|
+
const renameMsg = renameErr instanceof Error ? renameErr.message : String(renameErr);
|
|
380
|
+
debug.warn(`Failed to quarantine ${filePath}: ${renameMsg}`);
|
|
381
|
+
}
|
|
382
|
+
return void 0;
|
|
383
|
+
}
|
|
384
|
+
})
|
|
385
|
+
);
|
|
386
|
+
reads.push(...batchReads);
|
|
387
|
+
}
|
|
388
|
+
const tasks = reads.filter((t) => t !== void 0);
|
|
389
|
+
tasks.sort((a, b) => Number(a.id) - Number(b.id));
|
|
390
|
+
if (!filters) return tasks;
|
|
391
|
+
return tasks.filter((t) => {
|
|
392
|
+
if (filters.status !== void 0 && t.status !== filters.status) {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
if (filters.owner !== void 0 && t.owner !== filters.owner) {
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
398
|
+
if (filters.blockedBy !== void 0 && !t.blockedBy.includes(filters.blockedBy)) {
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
return true;
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
__name(listTasks, "listTasks");
|
|
405
|
+
async function resetTaskList(teamName) {
|
|
406
|
+
const dir = getTasksDir(teamName);
|
|
407
|
+
await fs.rm(dir, { recursive: true, force: true });
|
|
408
|
+
notifyTasksUpdated(teamName);
|
|
409
|
+
}
|
|
410
|
+
__name(resetTaskList, "resetTaskList");
|
|
411
|
+
async function unblockDependents(teamName, completedId, dependentIds) {
|
|
412
|
+
const results = await Promise.allSettled(
|
|
413
|
+
dependentIds.map(async (depId) => {
|
|
414
|
+
const depPath = getTaskPath(teamName, depId);
|
|
415
|
+
await withTaskFileLock(
|
|
416
|
+
depPath,
|
|
417
|
+
async () => {
|
|
418
|
+
let raw;
|
|
419
|
+
try {
|
|
420
|
+
raw = await fs.readFile(depPath, "utf-8");
|
|
421
|
+
} catch (err) {
|
|
422
|
+
if (isNodeError(err) && err.code === "ENOENT") return;
|
|
423
|
+
throw err;
|
|
424
|
+
}
|
|
425
|
+
const task = JSON.parse(raw);
|
|
426
|
+
const before = task.blockedBy.length;
|
|
427
|
+
task.blockedBy = task.blockedBy.filter((id) => id !== completedId);
|
|
428
|
+
if (task.blockedBy.length === before) return;
|
|
429
|
+
await atomicWriteJSON(depPath, task);
|
|
430
|
+
},
|
|
431
|
+
() => void 0
|
|
432
|
+
);
|
|
433
|
+
})
|
|
434
|
+
);
|
|
435
|
+
for (const r of results) {
|
|
436
|
+
if (r.status === "rejected") {
|
|
437
|
+
debug.warn(`unblockDependents(${completedId}): ${r.reason}`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
notifyTasksUpdated(teamName);
|
|
441
|
+
}
|
|
442
|
+
__name(unblockDependents, "unblockDependents");
|
|
443
|
+
async function blockTask(teamName, fromId, toId) {
|
|
444
|
+
await updateTask(teamName, fromId, { addBlocks: [toId] });
|
|
445
|
+
await updateTask(teamName, toId, { addBlockedBy: [fromId] });
|
|
446
|
+
}
|
|
447
|
+
__name(blockTask, "blockTask");
|
|
448
|
+
async function claimTask(teamName, taskId, agentId, opts) {
|
|
449
|
+
if (opts?.checkAgentBusy) {
|
|
450
|
+
return getAgentClaimLock(agentId).runExclusive(
|
|
451
|
+
() => claimTaskLocked(teamName, taskId, agentId, opts, true)
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
return claimTaskLocked(teamName, taskId, agentId, opts, false);
|
|
455
|
+
}
|
|
456
|
+
__name(claimTask, "claimTask");
|
|
457
|
+
async function claimTaskLocked(teamName, taskId, agentId, opts, checkBusy) {
|
|
458
|
+
if (checkBusy) {
|
|
459
|
+
const busy = await isAgentBusy(teamName, agentId);
|
|
460
|
+
if (busy) return void 0;
|
|
461
|
+
}
|
|
462
|
+
const taskPath = getTaskPath(teamName, taskId);
|
|
463
|
+
return withTaskFileLock(
|
|
464
|
+
taskPath,
|
|
465
|
+
async () => {
|
|
466
|
+
let raw;
|
|
467
|
+
try {
|
|
468
|
+
raw = await fs.readFile(taskPath, "utf-8");
|
|
469
|
+
} catch (err) {
|
|
470
|
+
if (isNodeError(err) && err.code === "ENOENT") return void 0;
|
|
471
|
+
throw err;
|
|
472
|
+
}
|
|
473
|
+
const task = JSON.parse(raw);
|
|
474
|
+
if (task.status !== "pending") return void 0;
|
|
475
|
+
if (task.owner) return void 0;
|
|
476
|
+
task.owner = opts?.ownerName ?? agentId;
|
|
477
|
+
task.status = "in_progress";
|
|
478
|
+
await atomicWriteJSON(taskPath, task);
|
|
479
|
+
notifyTasksUpdated(teamName);
|
|
480
|
+
return task;
|
|
481
|
+
},
|
|
482
|
+
() => void 0
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
__name(claimTaskLocked, "claimTaskLocked");
|
|
486
|
+
async function isAgentBusy(teamName, agentId) {
|
|
487
|
+
const inProgress = await listTasks(teamName, {
|
|
488
|
+
status: "in_progress"
|
|
489
|
+
});
|
|
490
|
+
const bareName = agentId.split("@")[0];
|
|
491
|
+
return inProgress.some((t) => t.owner === agentId || t.owner === bareName);
|
|
492
|
+
}
|
|
493
|
+
__name(isAgentBusy, "isAgentBusy");
|
|
494
|
+
async function releaseOwnedTask(teamName, taskId, expectedOwner) {
|
|
495
|
+
const taskPath = getTaskPath(teamName, taskId);
|
|
496
|
+
return withTaskFileLock(
|
|
497
|
+
taskPath,
|
|
498
|
+
async () => {
|
|
499
|
+
let raw;
|
|
500
|
+
try {
|
|
501
|
+
raw = await fs.readFile(taskPath, "utf-8");
|
|
502
|
+
} catch (err) {
|
|
503
|
+
if (isNodeError(err) && err.code === "ENOENT") return false;
|
|
504
|
+
throw err;
|
|
505
|
+
}
|
|
506
|
+
const task = JSON.parse(raw);
|
|
507
|
+
if (task.status !== "in_progress") return false;
|
|
508
|
+
if (task.owner !== expectedOwner) return false;
|
|
509
|
+
task.owner = void 0;
|
|
510
|
+
task.status = "pending";
|
|
511
|
+
await atomicWriteJSON(taskPath, task);
|
|
512
|
+
return true;
|
|
513
|
+
},
|
|
514
|
+
() => false
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
__name(releaseOwnedTask, "releaseOwnedTask");
|
|
518
|
+
async function unassignTeammateTasks(teamName, agentId) {
|
|
519
|
+
const bareName = agentId.split("@")[0];
|
|
520
|
+
const inProgress = await listTasks(teamName, {
|
|
521
|
+
status: "in_progress"
|
|
522
|
+
});
|
|
523
|
+
const owned = inProgress.filter(
|
|
524
|
+
(task) => task.owner === agentId || task.owner === bareName
|
|
525
|
+
);
|
|
526
|
+
const results = await Promise.allSettled(
|
|
527
|
+
owned.map((task) => releaseOwnedTask(teamName, task.id, task.owner))
|
|
528
|
+
);
|
|
529
|
+
const failed = results.filter((r) => r.status === "rejected");
|
|
530
|
+
if (failed.length > 0) {
|
|
531
|
+
debug.warn(
|
|
532
|
+
`unassignTeammateTasks: ${failed.length}/${owned.length} task(s) failed to unassign for ${agentId}`
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
const released = results.filter(
|
|
536
|
+
(r) => r.status === "fulfilled" && r.value === true
|
|
537
|
+
).length;
|
|
538
|
+
if (released > 0) {
|
|
539
|
+
notifyTasksUpdated(teamName);
|
|
540
|
+
}
|
|
541
|
+
return released;
|
|
542
|
+
}
|
|
543
|
+
__name(unassignTeammateTasks, "unassignTeammateTasks");
|
|
544
|
+
async function getAgentStatuses(teamName) {
|
|
545
|
+
const tasks = await listTasks(teamName);
|
|
546
|
+
const statuses = /* @__PURE__ */ new Map();
|
|
547
|
+
for (const task of tasks) {
|
|
548
|
+
if (!task.owner) continue;
|
|
549
|
+
const entry = statuses.get(task.owner) ?? {
|
|
550
|
+
inProgress: 0,
|
|
551
|
+
completed: 0
|
|
552
|
+
};
|
|
553
|
+
if (task.status === "in_progress") {
|
|
554
|
+
entry.inProgress++;
|
|
555
|
+
} else if (task.status === "completed") {
|
|
556
|
+
entry.completed++;
|
|
557
|
+
}
|
|
558
|
+
statuses.set(task.owner, entry);
|
|
559
|
+
}
|
|
560
|
+
return statuses;
|
|
561
|
+
}
|
|
562
|
+
__name(getAgentStatuses, "getAgentStatuses");
|
|
563
|
+
async function getNextTaskId(dir) {
|
|
564
|
+
let entries;
|
|
565
|
+
try {
|
|
566
|
+
entries = await fs.readdir(dir);
|
|
567
|
+
} catch {
|
|
568
|
+
return "1";
|
|
569
|
+
}
|
|
570
|
+
let maxId = 0;
|
|
571
|
+
for (const entry of entries) {
|
|
572
|
+
if (!entry.endsWith(".json")) continue;
|
|
573
|
+
const num = parseInt(entry.replace(".json", ""), 10);
|
|
574
|
+
if (!isNaN(num) && num > maxId) {
|
|
575
|
+
maxId = num;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
return String(maxId + 1);
|
|
579
|
+
}
|
|
580
|
+
__name(getNextTaskId, "getNextTaskId");
|
|
581
|
+
|
|
582
|
+
export {
|
|
583
|
+
RECIPROCAL_CALLER,
|
|
584
|
+
assertValidTaskId,
|
|
585
|
+
getTaskPath,
|
|
586
|
+
onTasksUpdated,
|
|
587
|
+
notifyTasksUpdated,
|
|
588
|
+
createTask,
|
|
589
|
+
getTask,
|
|
590
|
+
TaskOwnershipError,
|
|
591
|
+
updateTask,
|
|
592
|
+
deleteTask,
|
|
593
|
+
listTasks,
|
|
594
|
+
resetTaskList,
|
|
595
|
+
blockTask,
|
|
596
|
+
claimTask,
|
|
597
|
+
releaseOwnedTask,
|
|
598
|
+
unassignTeammateTasks,
|
|
599
|
+
getAgentStatuses
|
|
600
|
+
};
|
|
601
|
+
/**
|
|
602
|
+
* @license
|
|
603
|
+
* Copyright 2025 Qwen
|
|
604
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
605
|
+
*/
|