@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.
Files changed (143) hide show
  1. package/bundled/loop/SKILL.md +2 -1
  2. package/bundled/qc-helper/docs/_meta.ts +1 -0
  3. package/bundled/qc-helper/docs/configuration/auth.md +1 -1
  4. package/bundled/qc-helper/docs/configuration/model-providers.md +12 -5
  5. package/bundled/qc-helper/docs/configuration/settings.md +33 -32
  6. package/bundled/qc-helper/docs/features/approval-mode.md +10 -14
  7. package/bundled/qc-helper/docs/features/commands.md +33 -11
  8. package/bundled/qc-helper/docs/features/dual-output.md +37 -3
  9. package/bundled/qc-helper/docs/features/followup-suggestions.md +2 -2
  10. package/bundled/qc-helper/docs/features/skills.md +29 -3
  11. package/bundled/qc-helper/docs/features/sub-agents.md +34 -12
  12. package/bundled/qc-helper/docs/qwen-serve-deploy-local.md +221 -0
  13. package/bundled/qc-helper/docs/qwen-serve.md +246 -28
  14. package/chunks/{agent-QB7TZ4HW.js → agent-XT7NHZ5H.js} +25 -24
  15. package/chunks/agent-headless-LNRE63ZL.js +51 -0
  16. package/chunks/{anthropicContentGenerator-M45EVVRM.js → anthropicContentGenerator-DCI26OQF.js} +7 -7
  17. package/chunks/{askUserQuestion-WM2KHM3K.js → askUserQuestion-ITYUTWLR.js} +45 -3
  18. package/chunks/{ca-BARBRL6N.js → ca-RK4QPLIX.js} +18 -1
  19. package/chunks/{chunk-CWV3SJZS.js → chunk-3NRO6NHX.js} +2 -2
  20. package/chunks/{chunk-BNESGOSJ.js → chunk-55ZMG67I.js} +1 -1
  21. package/chunks/{chunk-QCG6KPNM.js → chunk-6T7Y7USE.js} +18017 -11621
  22. package/chunks/{chunk-CNHFPN7T.js → chunk-7KPZFE5A.js} +1 -1
  23. package/chunks/{chunk-2ZTWI7KH.js → chunk-A2ZIEEGJ.js} +30 -22
  24. package/chunks/{chunk-JUGRPQAB.js → chunk-B4ZF2KSI.js} +1 -1
  25. package/chunks/chunk-BJ5HQ23U.js +178 -0
  26. package/chunks/{chunk-HXJE7VOG.js → chunk-BXYRCW2C.js} +1074 -144
  27. package/chunks/{chunk-ICOI4E4S.js → chunk-CPVI5J2L.js} +101 -23
  28. package/chunks/{chunk-HV3ZZ7G4.js → chunk-DHZREJTG.js} +2 -2
  29. package/chunks/{chunk-GX7VH5JQ.js → chunk-FIQECJTQ.js} +1 -1
  30. package/chunks/{chunk-SZOEIL6S.js → chunk-H6BD2ELD.js} +1 -0
  31. package/chunks/{chunk-JXAZUMDW.js → chunk-HA2UEYZP.js} +7 -4
  32. package/chunks/{chunk-USE2VQ5P.js → chunk-HED55F43.js} +26 -1
  33. package/chunks/{chunk-PAEBHDIO.js → chunk-HQUWWSSP.js} +1 -1
  34. package/chunks/{chunk-MVIVIPCU.js → chunk-IDYDPBBN.js} +361 -583
  35. package/chunks/{chunk-JVQOQ3OU.js → chunk-IQHSD7K5.js} +1 -1
  36. package/chunks/{chunk-NW5QBUYO.js → chunk-IS7UA4W3.js} +14 -14
  37. package/chunks/{chunk-UAMOBVVW.js → chunk-LXYWINWF.js} +1 -1
  38. package/chunks/{chunk-P4J26VDS.js → chunk-LYRSMKLS.js} +2 -2
  39. package/chunks/{chunk-Y7R6H6FT.js → chunk-LYSND7KR.js} +9 -4
  40. package/chunks/{chunk-LR62TEET.js → chunk-NNIYWQIS.js} +1 -1
  41. package/chunks/chunk-OMX7CUOE.js +356 -0
  42. package/chunks/{chunk-CNSMKPK6.js → chunk-QILTEBWS.js} +1 -1
  43. package/chunks/chunk-QQDPRDVW.js +25 -0
  44. package/chunks/{chunk-ZK4AMNIU.js → chunk-RON7LFNH.js} +1294 -314
  45. package/chunks/chunk-SFRV6BGY.js +243 -0
  46. package/chunks/{chunk-AVW55ZCO.js → chunk-WJ3SND6W.js} +37 -16
  47. package/chunks/{chunk-HGJPQK33.js → chunk-WPTCDQN6.js} +188 -534
  48. package/chunks/{chunk-7YKXFA3D.js → chunk-XZTNBSMW.js} +11 -11
  49. package/chunks/{chunk-C6WMLUNB.js → chunk-Y7KMDUEP.js} +1 -1
  50. package/chunks/{chunk-WFVXF3OM.js → chunk-Z2Z3GUXZ.js} +1 -0
  51. package/chunks/{chunk-KC6ZMJ5X.js → chunk-ZMIBJS45.js} +1 -1
  52. package/chunks/chunk-ZOFNJQNJ.js +607 -0
  53. package/chunks/computer-use-4YX3JGBV.js +2052 -0
  54. package/chunks/contextCommand-KS2H7MW5.js +53 -0
  55. package/chunks/cron-create-CAPUKK7I.js +184 -0
  56. package/chunks/{cron-delete-ZGUXWBTG.js → cron-delete-G3KAR26Q.js} +28 -5
  57. package/chunks/{cron-list-QNNZGMN3.js → cron-list-ZA4ZIUS5.js} +40 -7
  58. package/chunks/{de-YGKK2BC4.js → de-FGPM4KW5.js} +18 -1
  59. package/chunks/{devtools-IXE4UP72.js → devtools-FM6GJPYG.js} +1 -1
  60. package/chunks/{dist-ZMQ4TXD5.js → dist-7YWFWOCJ.js} +2 -2
  61. package/chunks/{dist-R2SXPG74.js → dist-VEGFONCF.js} +2 -2
  62. package/chunks/{dist-TE5QKMGR.js → dist-X4EXN7W6.js} +1 -1
  63. package/chunks/{dist-BXDUQ2QY.js → dist-YLS6NI7H.js} +1 -1
  64. package/chunks/{edit-6UBTS2J5.js → edit-2ARPEO4B.js} +26 -25
  65. package/chunks/{en-HSQQNQUB.js → en-VP6XPGEC.js} +9 -2
  66. package/chunks/{enter-worktree-NN7LIXCM.js → enter-worktree-IXNXNAW5.js} +25 -24
  67. package/chunks/enterPlanMode-TAKAGAYP.js +159 -0
  68. package/chunks/{exit-worktree-GGSS5KIE.js → exit-worktree-LHTRV7ML.js} +25 -24
  69. package/chunks/exitPlanMode-MK5UAITL.js +743 -0
  70. package/chunks/{fr-JXBKPJKQ.js → fr-ATYBVCLT.js} +18 -1
  71. package/chunks/{geminiContentGenerator-I4H2NLJG.js → geminiContentGenerator-HFJIGO77.js} +7 -7
  72. package/chunks/{getMachineId-bsd-F7GNPTER.js → getMachineId-bsd-4CASPIU4.js} +1 -1
  73. package/chunks/{getMachineId-darwin-T73DJL27.js → getMachineId-darwin-HPQPEMZR.js} +1 -1
  74. package/chunks/{getMachineId-linux-MKQTFPQM.js → getMachineId-linux-AUARKYHL.js} +1 -1
  75. package/chunks/{getMachineId-unsupported-MUR5KOQE.js → getMachineId-unsupported-S32ZDA2T.js} +1 -1
  76. package/chunks/{getMachineId-win-CDYFC6ZM.js → getMachineId-win-4EFLHYIJ.js} +1 -1
  77. package/chunks/{glob-OLCX57MD.js → glob-I2USLUSC.js} +25 -24
  78. package/chunks/{grep-7HXIMDOW.js → grep-WBIF7THR.js} +37 -30
  79. package/chunks/{ja-TGPZSP2B.js → ja-W2QEA2OI.js} +18 -1
  80. package/chunks/{keychain-token-storage-LB46DAEK.js → keychain-token-storage-QSTRHKKL.js} +3 -3
  81. package/chunks/{ls-6PEZUK6O.js → ls-2R5RHLX5.js} +4 -4
  82. package/chunks/{lsp-JZSJOVT7.js → lsp-XKH6ZIAN.js} +3 -3
  83. package/chunks/{monitor-SQO7MVAV.js → monitor-WU7UFATU.js} +25 -24
  84. package/chunks/{notebook-edit-72L3EBAL.js → notebook-edit-KUHYPXEM.js} +26 -25
  85. package/chunks/{openaiContentGenerator-FTR7CDWF.js → openaiContentGenerator-5PLHYJQL.js} +15 -15
  86. package/chunks/{pt-TIBG6BIO.js → pt-ZKEWJFBW.js} +18 -1
  87. package/chunks/{qwenContentGenerator-U5UFQ566.js → qwenContentGenerator-TSKW73KY.js} +27 -26
  88. package/chunks/{qwenOAuth2-EFSECGHF.js → qwenOAuth2-KK433U33.js} +6 -5
  89. package/chunks/{read-file-UA64EEQC.js → read-file-VIPF2PS6.js} +11 -11
  90. package/chunks/ripGrep-XLIZTYE7.js +49 -0
  91. package/chunks/{ru-JBCHCK4L.js → ru-VEKTPJ74.js} +18 -1
  92. package/chunks/{scheduler-VBASHOCA.js → scheduler-O66SLJGU.js} +25 -24
  93. package/chunks/{send-message-OYJZ5TPG.js → send-message-CTME7DXD.js} +3 -3
  94. package/chunks/{serve-A7E2OJDR.js → serve-BWOLYT62.js} +13164 -3840
  95. package/chunks/{shell-3NFOT6F5.js → shell-XE7UYKOO.js} +25 -24
  96. package/chunks/{skill-RA5YUREY.js → skill-RZWM6XMC.js} +64 -113
  97. package/chunks/{src-NFCMARMT.js → src-L5P7K4MH.js} +176 -44
  98. package/chunks/{syntheticOutput-DETQ2YM6.js → syntheticOutput-ZJGSU7OQ.js} +4 -4
  99. package/chunks/{task-create-Y3ZKTJIG.js → task-create-EE6JEM7G.js} +8 -7
  100. package/chunks/{task-list-ONXJ3I3A.js → task-list-EESYAC65.js} +7 -6
  101. package/chunks/{task-stop-UHDC4N5B.js → task-stop-XZVCFFYY.js} +3 -3
  102. package/chunks/{task-update-TCNOU3P5.js → task-update-EIO4HNE3.js} +21 -9
  103. package/chunks/{team-create-6SR4OVRG.js → team-create-R2H7Y3SG.js} +28 -26
  104. package/chunks/{team-delete-EJ4U4DDP.js → team-delete-A7LXPGV7.js} +9 -6
  105. package/chunks/{todoWrite-TEYDRS5L.js → todoWrite-VRKSGAWM.js} +5 -5
  106. package/chunks/{tool-search-OD435A3X.js → tool-search-USSQMTMS.js} +11 -11
  107. package/chunks/{web-fetch-6W67H5PO.js → web-fetch-GHAZUA54.js} +5 -5
  108. package/chunks/workflow-5LNNLNUR.js +1414 -0
  109. package/chunks/{write-file-475L5OPP.js → write-file-2I7HP24C.js} +26 -25
  110. package/chunks/{zh-VCLWO26Y.js → zh-OIXDDQHB.js} +10 -3
  111. package/chunks/{zh-TW-G3HFHVVT.js → zh-TW-6YFNCKTA.js} +10 -3
  112. package/cli-entry.js +19 -0
  113. package/cli.js +11064 -6628
  114. package/examples/starter/QWEN.md +30 -0
  115. package/examples/starter/README.md +59 -0
  116. package/examples/starter/agents/diary.md +86 -0
  117. package/examples/starter/commands/writing/polish.md +13 -0
  118. package/examples/starter/example.ts +64 -0
  119. package/examples/starter/package.json +18 -0
  120. package/examples/starter/qwen-extension.json +12 -0
  121. package/examples/starter/skills/synonyms/SKILL.md +48 -0
  122. package/examples/starter/tsconfig.json +13 -0
  123. package/fzfWorker.js +1083 -0
  124. package/locales/ca.js +20 -2
  125. package/locales/de.js +21 -2
  126. package/locales/en.js +13 -4
  127. package/locales/fr.js +22 -2
  128. package/locales/ja.js +22 -2
  129. package/locales/pt.js +21 -2
  130. package/locales/ru.js +20 -2
  131. package/locales/zh-TW.js +11 -4
  132. package/locales/zh.js +11 -4
  133. package/package.json +5 -3
  134. package/chunks/agent-headless-APVHH7QM.js +0 -50
  135. package/chunks/chunk-AJIR24J2.js +0 -59
  136. package/chunks/chunk-SKBPNJEW.js +0 -45
  137. package/chunks/chunk-XBFVXFB2.js +0 -216
  138. package/chunks/computer-use-B7VIUI7F.js +0 -825
  139. package/chunks/contextCommand-63RZ3O5R.js +0 -52
  140. package/chunks/cron-create-FI5LJVUS.js +0 -140
  141. package/chunks/exitPlanMode-H323NHB2.js +0 -235
  142. package/chunks/ripGrep-WSYCWZVK.js +0 -48
  143. package/chunks/workflow-62DHH4EO.js +0 -708
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
  import {
4
4
  ToolNames
5
- } from "./chunk-2ZTWI7KH.js";
5
+ } from "./chunk-A2ZIEEGJ.js";
6
6
  import {
7
7
  init_esbuild_shims
8
8
  } from "./chunk-A4BMJM77.js";
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
  import {
4
4
  createDebugLogger
5
- } from "./chunk-JXAZUMDW.js";
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 built-in but backed by an upstream MCP server.
14885
- // All deferred; revealed only when the user-initiated request triggers
14886
- // a computer-use action. See packages/core/src/tools/computer-use/.
14887
- COMPUTER_USE_LIST_APPS: "computer_use__list_apps",
14888
- COMPUTER_USE_GET_APP_STATE: "computer_use__get_app_state",
14889
- COMPUTER_USE_CLICK: "computer_use__click",
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
- COMPUTER_USE_LIST_APPS: "computer_use__list_apps",
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 = {
@@ -2,7 +2,7 @@
2
2
  "use strict";
3
3
  import {
4
4
  createDebugLogger
5
- } from "./chunk-JXAZUMDW.js";
5
+ } from "./chunk-HA2UEYZP.js";
6
6
  import {
7
7
  init_esbuild_shims
8
8
  } from "./chunk-A4BMJM77.js";
@@ -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
+ };