@qwen-code/qwen-code 0.18.0-preview.2 → 0.18.1
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/bundled/loop/SKILL.md +2 -1
- package/bundled/qc-helper/docs/_meta.ts +1 -0
- package/bundled/qc-helper/docs/configuration/auth.md +1 -1
- package/bundled/qc-helper/docs/configuration/model-providers.md +12 -5
- package/bundled/qc-helper/docs/configuration/settings.md +33 -32
- package/bundled/qc-helper/docs/features/approval-mode.md +10 -14
- package/bundled/qc-helper/docs/features/commands.md +33 -11
- package/bundled/qc-helper/docs/features/dual-output.md +37 -3
- package/bundled/qc-helper/docs/features/followup-suggestions.md +2 -2
- package/bundled/qc-helper/docs/features/skills.md +29 -3
- package/bundled/qc-helper/docs/features/sub-agents.md +34 -12
- package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +221 -0
- package/bundled/qc-helper/docs/qwen-serve.md +246 -28
- package/chunks/{agent-QB7TZ4HW.js → agent-XT7NHZ5H.js} +25 -24
- package/chunks/agent-headless-LNRE63ZL.js +51 -0
- package/chunks/{anthropicContentGenerator-M45EVVRM.js → anthropicContentGenerator-DCI26OQF.js} +7 -7
- package/chunks/{askUserQuestion-WM2KHM3K.js → askUserQuestion-ITYUTWLR.js} +45 -3
- package/chunks/{ca-BARBRL6N.js → ca-RK4QPLIX.js} +18 -1
- package/chunks/{chunk-CWV3SJZS.js → chunk-3NRO6NHX.js} +2 -2
- package/chunks/{chunk-BNESGOSJ.js → chunk-55ZMG67I.js} +1 -1
- package/chunks/{chunk-QCG6KPNM.js → chunk-6T7Y7USE.js} +18017 -11621
- package/chunks/{chunk-CNHFPN7T.js → chunk-7KPZFE5A.js} +1 -1
- package/chunks/{chunk-2ZTWI7KH.js → chunk-A2ZIEEGJ.js} +30 -22
- package/chunks/{chunk-JUGRPQAB.js → chunk-B4ZF2KSI.js} +1 -1
- package/chunks/chunk-BJ5HQ23U.js +178 -0
- package/chunks/{chunk-HXJE7VOG.js → chunk-BXYRCW2C.js} +1074 -144
- package/chunks/{chunk-ICOI4E4S.js → chunk-CPVI5J2L.js} +101 -23
- package/chunks/{chunk-HV3ZZ7G4.js → chunk-DHZREJTG.js} +2 -2
- package/chunks/{chunk-GX7VH5JQ.js → chunk-FIQECJTQ.js} +1 -1
- package/chunks/{chunk-SZOEIL6S.js → chunk-H6BD2ELD.js} +1 -0
- package/chunks/{chunk-JXAZUMDW.js → chunk-HA2UEYZP.js} +7 -4
- package/chunks/{chunk-USE2VQ5P.js → chunk-HED55F43.js} +26 -1
- package/chunks/{chunk-PAEBHDIO.js → chunk-HQUWWSSP.js} +1 -1
- package/chunks/{chunk-MVIVIPCU.js → chunk-IDYDPBBN.js} +361 -583
- package/chunks/{chunk-JVQOQ3OU.js → chunk-IQHSD7K5.js} +1 -1
- package/chunks/{chunk-NW5QBUYO.js → chunk-IS7UA4W3.js} +14 -14
- package/chunks/{chunk-UAMOBVVW.js → chunk-LXYWINWF.js} +1 -1
- package/chunks/{chunk-P4J26VDS.js → chunk-LYRSMKLS.js} +2 -2
- package/chunks/{chunk-Y7R6H6FT.js → chunk-LYSND7KR.js} +9 -4
- package/chunks/{chunk-LR62TEET.js → chunk-NNIYWQIS.js} +1 -1
- package/chunks/chunk-OMX7CUOE.js +356 -0
- package/chunks/{chunk-CNSMKPK6.js → chunk-QILTEBWS.js} +1 -1
- package/chunks/chunk-QQDPRDVW.js +25 -0
- package/chunks/{chunk-ZK4AMNIU.js → chunk-RON7LFNH.js} +1294 -314
- package/chunks/chunk-SFRV6BGY.js +243 -0
- package/chunks/{chunk-AVW55ZCO.js → chunk-WJ3SND6W.js} +37 -16
- package/chunks/{chunk-HGJPQK33.js → chunk-WPTCDQN6.js} +188 -534
- package/chunks/{chunk-7YKXFA3D.js → chunk-XZTNBSMW.js} +11 -11
- package/chunks/{chunk-C6WMLUNB.js → chunk-Y7KMDUEP.js} +1 -1
- package/chunks/{chunk-WFVXF3OM.js → chunk-Z2Z3GUXZ.js} +1 -0
- package/chunks/{chunk-KC6ZMJ5X.js → chunk-ZMIBJS45.js} +1 -1
- package/chunks/chunk-ZOFNJQNJ.js +607 -0
- package/chunks/computer-use-4YX3JGBV.js +2052 -0
- package/chunks/contextCommand-KS2H7MW5.js +53 -0
- package/chunks/cron-create-CAPUKK7I.js +184 -0
- package/chunks/{cron-delete-ZGUXWBTG.js → cron-delete-G3KAR26Q.js} +28 -5
- package/chunks/{cron-list-QNNZGMN3.js → cron-list-ZA4ZIUS5.js} +40 -7
- package/chunks/{de-YGKK2BC4.js → de-FGPM4KW5.js} +18 -1
- package/chunks/{devtools-IXE4UP72.js → devtools-FM6GJPYG.js} +1 -1
- package/chunks/{dist-ZMQ4TXD5.js → dist-7YWFWOCJ.js} +2 -2
- package/chunks/{dist-R2SXPG74.js → dist-VEGFONCF.js} +2 -2
- package/chunks/{dist-TE5QKMGR.js → dist-X4EXN7W6.js} +1 -1
- package/chunks/{dist-BXDUQ2QY.js → dist-YLS6NI7H.js} +1 -1
- package/chunks/{edit-6UBTS2J5.js → edit-2ARPEO4B.js} +26 -25
- package/chunks/{en-HSQQNQUB.js → en-VP6XPGEC.js} +9 -2
- package/chunks/{enter-worktree-NN7LIXCM.js → enter-worktree-IXNXNAW5.js} +25 -24
- package/chunks/enterPlanMode-TAKAGAYP.js +159 -0
- package/chunks/{exit-worktree-GGSS5KIE.js → exit-worktree-LHTRV7ML.js} +25 -24
- package/chunks/exitPlanMode-MK5UAITL.js +743 -0
- package/chunks/{fr-JXBKPJKQ.js → fr-ATYBVCLT.js} +18 -1
- package/chunks/{geminiContentGenerator-I4H2NLJG.js → geminiContentGenerator-HFJIGO77.js} +7 -7
- package/chunks/{getMachineId-bsd-F7GNPTER.js → getMachineId-bsd-4CASPIU4.js} +1 -1
- package/chunks/{getMachineId-darwin-T73DJL27.js → getMachineId-darwin-HPQPEMZR.js} +1 -1
- package/chunks/{getMachineId-linux-MKQTFPQM.js → getMachineId-linux-AUARKYHL.js} +1 -1
- package/chunks/{getMachineId-unsupported-MUR5KOQE.js → getMachineId-unsupported-S32ZDA2T.js} +1 -1
- package/chunks/{getMachineId-win-CDYFC6ZM.js → getMachineId-win-4EFLHYIJ.js} +1 -1
- package/chunks/{glob-OLCX57MD.js → glob-I2USLUSC.js} +25 -24
- package/chunks/{grep-7HXIMDOW.js → grep-WBIF7THR.js} +37 -30
- package/chunks/{ja-TGPZSP2B.js → ja-W2QEA2OI.js} +18 -1
- package/chunks/{keychain-token-storage-LB46DAEK.js → keychain-token-storage-QSTRHKKL.js} +3 -3
- package/chunks/{ls-6PEZUK6O.js → ls-2R5RHLX5.js} +4 -4
- package/chunks/{lsp-JZSJOVT7.js → lsp-XKH6ZIAN.js} +3 -3
- package/chunks/{monitor-SQO7MVAV.js → monitor-WU7UFATU.js} +25 -24
- package/chunks/{notebook-edit-72L3EBAL.js → notebook-edit-KUHYPXEM.js} +26 -25
- package/chunks/{openaiContentGenerator-FTR7CDWF.js → openaiContentGenerator-5PLHYJQL.js} +15 -15
- package/chunks/{pt-TIBG6BIO.js → pt-ZKEWJFBW.js} +18 -1
- package/chunks/{qwenContentGenerator-U5UFQ566.js → qwenContentGenerator-TSKW73KY.js} +27 -26
- package/chunks/{qwenOAuth2-EFSECGHF.js → qwenOAuth2-KK433U33.js} +6 -5
- package/chunks/{read-file-UA64EEQC.js → read-file-VIPF2PS6.js} +11 -11
- package/chunks/ripGrep-XLIZTYE7.js +49 -0
- package/chunks/{ru-JBCHCK4L.js → ru-VEKTPJ74.js} +18 -1
- package/chunks/{scheduler-VBASHOCA.js → scheduler-O66SLJGU.js} +25 -24
- package/chunks/{send-message-OYJZ5TPG.js → send-message-CTME7DXD.js} +3 -3
- package/chunks/{serve-A7E2OJDR.js → serve-BWOLYT62.js} +13164 -3840
- package/chunks/{shell-3NFOT6F5.js → shell-XE7UYKOO.js} +25 -24
- package/chunks/{skill-RA5YUREY.js → skill-RZWM6XMC.js} +64 -113
- package/chunks/{src-NFCMARMT.js → src-L5P7K4MH.js} +176 -44
- package/chunks/{syntheticOutput-DETQ2YM6.js → syntheticOutput-ZJGSU7OQ.js} +4 -4
- package/chunks/{task-create-Y3ZKTJIG.js → task-create-EE6JEM7G.js} +8 -7
- package/chunks/{task-list-ONXJ3I3A.js → task-list-EESYAC65.js} +7 -6
- package/chunks/{task-stop-UHDC4N5B.js → task-stop-XZVCFFYY.js} +3 -3
- package/chunks/{task-update-TCNOU3P5.js → task-update-EIO4HNE3.js} +21 -9
- package/chunks/{team-create-6SR4OVRG.js → team-create-R2H7Y3SG.js} +28 -26
- package/chunks/{team-delete-EJ4U4DDP.js → team-delete-A7LXPGV7.js} +9 -6
- package/chunks/{todoWrite-TEYDRS5L.js → todoWrite-VRKSGAWM.js} +5 -5
- package/chunks/{tool-search-OD435A3X.js → tool-search-USSQMTMS.js} +11 -11
- package/chunks/{web-fetch-6W67H5PO.js → web-fetch-GHAZUA54.js} +5 -5
- package/chunks/workflow-5LNNLNUR.js +1414 -0
- package/chunks/{write-file-475L5OPP.js → write-file-2I7HP24C.js} +26 -25
- package/chunks/{zh-VCLWO26Y.js → zh-OIXDDQHB.js} +10 -3
- package/chunks/{zh-TW-G3HFHVVT.js → zh-TW-6YFNCKTA.js} +10 -3
- package/cli-entry.js +19 -0
- package/cli.js +11064 -6628
- 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 +20 -2
- package/locales/de.js +21 -2
- package/locales/en.js +13 -4
- package/locales/fr.js +22 -2
- package/locales/ja.js +22 -2
- package/locales/pt.js +21 -2
- package/locales/ru.js +20 -2
- package/locales/zh-TW.js +11 -4
- package/locales/zh.js +11 -4
- package/package.json +5 -3
- package/chunks/agent-headless-APVHH7QM.js +0 -50
- package/chunks/chunk-AJIR24J2.js +0 -59
- package/chunks/chunk-SKBPNJEW.js +0 -45
- package/chunks/chunk-XBFVXFB2.js +0 -216
- package/chunks/computer-use-B7VIUI7F.js +0 -825
- package/chunks/contextCommand-63RZ3O5R.js +0 -52
- package/chunks/cron-create-FI5LJVUS.js +0 -140
- package/chunks/exitPlanMode-H323NHB2.js +0 -235
- package/chunks/ripGrep-WSYCWZVK.js +0 -48
- package/chunks/workflow-62DHH4EO.js +0 -708
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
import {
|
|
4
4
|
createDebugLogger
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-HA2UEYZP.js";
|
|
6
6
|
import {
|
|
7
7
|
init_esbuild_shims
|
|
8
8
|
} from "./chunk-A4BMJM77.js";
|
|
@@ -14623,6 +14623,25 @@ var DeclarativeTool = class {
|
|
|
14623
14623
|
parametersJsonSchema: this.parameterSchema
|
|
14624
14624
|
};
|
|
14625
14625
|
}
|
|
14626
|
+
/**
|
|
14627
|
+
* Max model-facing characters for this tool's output before the scheduler
|
|
14628
|
+
* spills it to disk (mirrors Claude Code's per-tool `maxResultSizeChars`).
|
|
14629
|
+
* - `undefined` → use the global truncation threshold.
|
|
14630
|
+
* - `Infinity` → self-managed (the tool does its own size control, e.g.
|
|
14631
|
+
* ReadFile's line-based paging), exempt from scheduler char truncation.
|
|
14632
|
+
* Override in subclasses to opt into a per-tool budget.
|
|
14633
|
+
*/
|
|
14634
|
+
get maxOutputChars() {
|
|
14635
|
+
return void 0;
|
|
14636
|
+
}
|
|
14637
|
+
/**
|
|
14638
|
+
* Direction kept when this tool's oversized output is truncated: `'head'`
|
|
14639
|
+
* (beginning, e.g. shell), `'tail'` (end, e.g. background agents), or
|
|
14640
|
+
* `'both'` (first + last, the default).
|
|
14641
|
+
*/
|
|
14642
|
+
get truncateKeep() {
|
|
14643
|
+
return "both";
|
|
14644
|
+
}
|
|
14626
14645
|
/**
|
|
14627
14646
|
* Projects tool params for the AUTO approval mode classifier.
|
|
14628
14647
|
*
|
|
@@ -14832,6 +14851,7 @@ var Kind = /* @__PURE__ */ ((Kind2) => {
|
|
|
14832
14851
|
Kind2["Execute"] = "execute";
|
|
14833
14852
|
Kind2["Think"] = "think";
|
|
14834
14853
|
Kind2["Fetch"] = "fetch";
|
|
14854
|
+
Kind2["Agent"] = "agent";
|
|
14835
14855
|
Kind2["Other"] = "other";
|
|
14836
14856
|
return Kind2;
|
|
14837
14857
|
})(Kind || {});
|
|
@@ -14861,6 +14881,7 @@ var ToolNames = {
|
|
|
14861
14881
|
AGENT: "agent",
|
|
14862
14882
|
SKILL: "skill",
|
|
14863
14883
|
EXIT_PLAN_MODE: "exit_plan_mode",
|
|
14884
|
+
ENTER_PLAN_MODE: "enter_plan_mode",
|
|
14864
14885
|
WEB_FETCH: "web_fetch",
|
|
14865
14886
|
LS: "list_directory",
|
|
14866
14887
|
LSP: "lsp",
|
|
@@ -14881,18 +14902,12 @@ var ToolNames = {
|
|
|
14881
14902
|
TOOL_SEARCH: "tool_search",
|
|
14882
14903
|
ENTER_WORKTREE: "enter_worktree",
|
|
14883
14904
|
EXIT_WORKTREE: "exit_worktree",
|
|
14884
|
-
// Computer Use tools
|
|
14885
|
-
//
|
|
14886
|
-
//
|
|
14887
|
-
|
|
14888
|
-
|
|
14889
|
-
|
|
14890
|
-
COMPUTER_USE_PERFORM_SECONDARY_ACTION: "computer_use__perform_secondary_action",
|
|
14891
|
-
COMPUTER_USE_SCROLL: "computer_use__scroll",
|
|
14892
|
-
COMPUTER_USE_DRAG: "computer_use__drag",
|
|
14893
|
-
COMPUTER_USE_TYPE_TEXT: "computer_use__type_text",
|
|
14894
|
-
COMPUTER_USE_PRESS_KEY: "computer_use__press_key",
|
|
14895
|
-
COMPUTER_USE_SET_VALUE: "computer_use__set_value",
|
|
14905
|
+
// Computer Use tools (computer_use__*) are intentionally NOT enumerated here.
|
|
14906
|
+
// Their full 35-tool surface is generated into computer-use/schemas.ts and
|
|
14907
|
+
// registered via computer-use/index.ts (cast to ToolName). Duplicating a
|
|
14908
|
+
// subset here only goes stale on every cua-driver version bump — review
|
|
14909
|
+
// round 1 removed the old ocu-era 9-name list, which still carried
|
|
14910
|
+
// `get_app_state` / `perform_secondary_action` that no longer exist.
|
|
14896
14911
|
WORKFLOW: "workflow"
|
|
14897
14912
|
};
|
|
14898
14913
|
var ToolDisplayNames = {
|
|
@@ -14907,6 +14922,7 @@ var ToolDisplayNames = {
|
|
|
14907
14922
|
AGENT: "Agent",
|
|
14908
14923
|
SKILL: "Skill",
|
|
14909
14924
|
EXIT_PLAN_MODE: "ExitPlanMode",
|
|
14925
|
+
ENTER_PLAN_MODE: "EnterPlanMode",
|
|
14910
14926
|
WEB_FETCH: "WebFetch",
|
|
14911
14927
|
LS: "ListFiles",
|
|
14912
14928
|
LSP: "Lsp",
|
|
@@ -14927,15 +14943,7 @@ var ToolDisplayNames = {
|
|
|
14927
14943
|
TOOL_SEARCH: "ToolSearch",
|
|
14928
14944
|
ENTER_WORKTREE: "EnterWorktree",
|
|
14929
14945
|
EXIT_WORKTREE: "ExitWorktree",
|
|
14930
|
-
|
|
14931
|
-
COMPUTER_USE_GET_APP_STATE: "computer_use__get_app_state",
|
|
14932
|
-
COMPUTER_USE_CLICK: "computer_use__click",
|
|
14933
|
-
COMPUTER_USE_PERFORM_SECONDARY_ACTION: "computer_use__perform_secondary_action",
|
|
14934
|
-
COMPUTER_USE_SCROLL: "computer_use__scroll",
|
|
14935
|
-
COMPUTER_USE_DRAG: "computer_use__drag",
|
|
14936
|
-
COMPUTER_USE_TYPE_TEXT: "computer_use__type_text",
|
|
14937
|
-
COMPUTER_USE_PRESS_KEY: "computer_use__press_key",
|
|
14938
|
-
COMPUTER_USE_SET_VALUE: "computer_use__set_value",
|
|
14946
|
+
// computer_use__* display names are not enumerated here (see ToolNames).
|
|
14939
14947
|
WORKFLOW: "Workflow"
|
|
14940
14948
|
};
|
|
14941
14949
|
var ToolNamesMigration = {
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// Force strict mode and setup for ESM
|
|
2
|
+
"use strict";
|
|
3
|
+
import {
|
|
4
|
+
Mutex
|
|
5
|
+
} from "./chunk-OMX7CUOE.js";
|
|
6
|
+
import {
|
|
7
|
+
atomicWriteJSON
|
|
8
|
+
} from "./chunk-LXYWINWF.js";
|
|
9
|
+
import {
|
|
10
|
+
Storage,
|
|
11
|
+
createDebugLogger,
|
|
12
|
+
getProjectHash
|
|
13
|
+
} from "./chunk-HA2UEYZP.js";
|
|
14
|
+
import {
|
|
15
|
+
init_esbuild_shims
|
|
16
|
+
} from "./chunk-A4BMJM77.js";
|
|
17
|
+
import {
|
|
18
|
+
__name
|
|
19
|
+
} from "./chunk-J2S4EL5Y.js";
|
|
20
|
+
|
|
21
|
+
// packages/core/src/services/cronTasksFile.ts
|
|
22
|
+
init_esbuild_shims();
|
|
23
|
+
import * as fs from "node:fs/promises";
|
|
24
|
+
import * as path from "node:path";
|
|
25
|
+
var debugLogger = createDebugLogger("CRON_TASKS_FILE");
|
|
26
|
+
var TASKS_FILENAME = "scheduled_tasks.json";
|
|
27
|
+
var CRON_TASKS_DISPLAY_PATH = `~/.qwen/tmp/<project-hash>/${TASKS_FILENAME}`;
|
|
28
|
+
var UPDATE_LOCK_RETRY_MS = 15;
|
|
29
|
+
var UPDATE_LOCK_STALE_MS = 2e3;
|
|
30
|
+
var UPDATE_LOCK_TIMEOUT_MS = 3e3;
|
|
31
|
+
var updateStaleSeq = 0;
|
|
32
|
+
var updateMutexes = /* @__PURE__ */ new Map();
|
|
33
|
+
function getUpdateMutex(filePath) {
|
|
34
|
+
let mutex = updateMutexes.get(filePath);
|
|
35
|
+
if (!mutex) {
|
|
36
|
+
mutex = new Mutex();
|
|
37
|
+
updateMutexes.set(filePath, mutex);
|
|
38
|
+
}
|
|
39
|
+
return mutex;
|
|
40
|
+
}
|
|
41
|
+
__name(getUpdateMutex, "getUpdateMutex");
|
|
42
|
+
function getCronFilePath(projectRoot) {
|
|
43
|
+
return path.join(
|
|
44
|
+
Storage.getGlobalTempDir(),
|
|
45
|
+
getProjectHash(projectRoot),
|
|
46
|
+
TASKS_FILENAME
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
__name(getCronFilePath, "getCronFilePath");
|
|
50
|
+
async function readCronTasks(projectRoot) {
|
|
51
|
+
const filePath = getCronFilePath(projectRoot);
|
|
52
|
+
let raw;
|
|
53
|
+
try {
|
|
54
|
+
raw = await fs.readFile(filePath, "utf-8");
|
|
55
|
+
} catch (err) {
|
|
56
|
+
if (err.code === "ENOENT") return [];
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
let parsed;
|
|
60
|
+
try {
|
|
61
|
+
parsed = JSON.parse(raw);
|
|
62
|
+
} catch {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`Malformed JSON in ${filePath} \u2014 fix or delete the file; refusing to treat it as an empty schedule.`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
if (!Array.isArray(parsed)) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Expected a JSON array in ${filePath} \u2014 fix or delete the file; refusing to treat it as an empty schedule.`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
const valid = parsed.filter(isValidTask);
|
|
73
|
+
if (valid.length !== parsed.length) {
|
|
74
|
+
debugLogger.warn(
|
|
75
|
+
`Dropped ${parsed.length - valid.length} invalid task entr${parsed.length - valid.length === 1 ? "y" : "ies"} from ${filePath}; a later write will persist without ${parsed.length - valid.length === 1 ? "it" : "them"}.`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return valid;
|
|
79
|
+
}
|
|
80
|
+
__name(readCronTasks, "readCronTasks");
|
|
81
|
+
async function writeCronTasks(projectRoot, tasks) {
|
|
82
|
+
const filePath = getCronFilePath(projectRoot);
|
|
83
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
84
|
+
await atomicWriteJSON(filePath, tasks, { noFollow: true });
|
|
85
|
+
}
|
|
86
|
+
__name(writeCronTasks, "writeCronTasks");
|
|
87
|
+
async function acquireUpdateLock(filePath) {
|
|
88
|
+
const lockPath = `${filePath}.lock`;
|
|
89
|
+
await fs.mkdir(path.dirname(lockPath), { recursive: true });
|
|
90
|
+
const deadline = Date.now() + UPDATE_LOCK_TIMEOUT_MS;
|
|
91
|
+
for (; ; ) {
|
|
92
|
+
if (Date.now() > deadline) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Timed out waiting for scheduled-tasks lock (${lockPath})`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
await fs.writeFile(lockPath, String(process.pid), { flag: "wx" });
|
|
99
|
+
return async () => {
|
|
100
|
+
await fs.unlink(lockPath).catch(() => {
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
} catch (err) {
|
|
104
|
+
if (err.code !== "EEXIST") throw err;
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const stat2 = await fs.stat(lockPath);
|
|
108
|
+
if (Date.now() - stat2.mtimeMs > UPDATE_LOCK_STALE_MS) {
|
|
109
|
+
const stalePath = `${lockPath}.stale.${process.pid}.${updateStaleSeq++}`;
|
|
110
|
+
try {
|
|
111
|
+
await fs.rename(lockPath, stalePath);
|
|
112
|
+
} catch {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const moved = await fs.stat(stalePath).catch(() => null);
|
|
116
|
+
if (moved && Date.now() - moved.mtimeMs <= UPDATE_LOCK_STALE_MS) {
|
|
117
|
+
await fs.link(stalePath, lockPath).catch(() => {
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
await fs.unlink(stalePath).catch(() => {
|
|
121
|
+
});
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
} catch {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
await new Promise((resolve) => setTimeout(resolve, UPDATE_LOCK_RETRY_MS));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
__name(acquireUpdateLock, "acquireUpdateLock");
|
|
131
|
+
async function updateCronTasks(projectRoot, mutate) {
|
|
132
|
+
const filePath = getCronFilePath(projectRoot);
|
|
133
|
+
return getUpdateMutex(filePath).runExclusive(async () => {
|
|
134
|
+
const release = await acquireUpdateLock(filePath);
|
|
135
|
+
try {
|
|
136
|
+
const tasks = await readCronTasks(projectRoot);
|
|
137
|
+
const next = mutate(tasks);
|
|
138
|
+
if (next !== tasks) {
|
|
139
|
+
await writeCronTasks(projectRoot, next);
|
|
140
|
+
}
|
|
141
|
+
} finally {
|
|
142
|
+
await release();
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
__name(updateCronTasks, "updateCronTasks");
|
|
147
|
+
async function addCronTask(projectRoot, task) {
|
|
148
|
+
await updateCronTasks(projectRoot, (tasks) => [...tasks, task]);
|
|
149
|
+
}
|
|
150
|
+
__name(addCronTask, "addCronTask");
|
|
151
|
+
async function removeCronTasks(projectRoot, ids) {
|
|
152
|
+
const idSet = new Set(ids);
|
|
153
|
+
const current = await readCronTasks(projectRoot);
|
|
154
|
+
if (!current.some((t) => idSet.has(t.id))) return 0;
|
|
155
|
+
let removed = 0;
|
|
156
|
+
await updateCronTasks(projectRoot, (tasks) => {
|
|
157
|
+
const remaining = tasks.filter((t) => !idSet.has(t.id));
|
|
158
|
+
removed = tasks.length - remaining.length;
|
|
159
|
+
return removed === 0 ? tasks : remaining;
|
|
160
|
+
});
|
|
161
|
+
return removed;
|
|
162
|
+
}
|
|
163
|
+
__name(removeCronTasks, "removeCronTasks");
|
|
164
|
+
function isValidTask(value) {
|
|
165
|
+
if (typeof value !== "object" || value === null) return false;
|
|
166
|
+
const obj = value;
|
|
167
|
+
return typeof obj["id"] === "string" && typeof obj["cron"] === "string" && typeof obj["prompt"] === "string" && typeof obj["recurring"] === "boolean" && typeof obj["createdAt"] === "number" && (obj["lastFiredAt"] === null || typeof obj["lastFiredAt"] === "number");
|
|
168
|
+
}
|
|
169
|
+
__name(isValidTask, "isValidTask");
|
|
170
|
+
|
|
171
|
+
export {
|
|
172
|
+
CRON_TASKS_DISPLAY_PATH,
|
|
173
|
+
getCronFilePath,
|
|
174
|
+
readCronTasks,
|
|
175
|
+
updateCronTasks,
|
|
176
|
+
addCronTask,
|
|
177
|
+
removeCronTasks
|
|
178
|
+
};
|