@qlingzzy/qling 1.0.0 → 1.1.0

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 (254) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/README.en.md +82 -17
  3. package/README.md +15 -7
  4. package/dist/agent/main-loop.d.ts +120 -0
  5. package/dist/agent/main-loop.d.ts.map +1 -0
  6. package/dist/agent/main-loop.js +279 -0
  7. package/dist/agent/subtask-parallel.d.ts +29 -0
  8. package/dist/agent/subtask-parallel.d.ts.map +1 -0
  9. package/dist/agent/subtask-parallel.js +107 -0
  10. package/dist/agent/subtask.d.ts +13 -0
  11. package/dist/agent/subtask.d.ts.map +1 -1
  12. package/dist/agent/subtask.js +79 -24
  13. package/dist/agent/system-prompt.d.ts +39 -0
  14. package/dist/agent/system-prompt.d.ts.map +1 -0
  15. package/dist/agent/system-prompt.js +89 -0
  16. package/dist/agent/tool-orchestrator.d.ts +66 -0
  17. package/dist/agent/tool-orchestrator.d.ts.map +1 -0
  18. package/dist/agent/tool-orchestrator.js +355 -0
  19. package/dist/agent-loop.d.ts +29 -16
  20. package/dist/agent-loop.d.ts.map +1 -1
  21. package/dist/agent-loop.js +262 -807
  22. package/dist/agents/roles.d.ts +57 -0
  23. package/dist/agents/roles.d.ts.map +1 -0
  24. package/dist/agents/roles.js +198 -0
  25. package/dist/commands/agents.d.ts.map +1 -1
  26. package/dist/commands/agents.js +17 -3
  27. package/dist/commands/claude-style.d.ts.map +1 -1
  28. package/dist/commands/claude-style.js +19 -10
  29. package/dist/commands/help.d.ts.map +1 -1
  30. package/dist/commands/help.js +3 -2
  31. package/dist/commands/index.d.ts.map +1 -1
  32. package/dist/commands/index.js +6 -0
  33. package/dist/commands/mode.d.ts +16 -0
  34. package/dist/commands/mode.d.ts.map +1 -0
  35. package/dist/commands/mode.js +67 -0
  36. package/dist/commands/recover.d.ts +3 -0
  37. package/dist/commands/recover.d.ts.map +1 -0
  38. package/dist/commands/recover.js +69 -0
  39. package/dist/commands/runtime.d.ts +2 -0
  40. package/dist/commands/runtime.d.ts.map +1 -1
  41. package/dist/commands/runtime.js +2 -0
  42. package/dist/commands/trace.d.ts +3 -0
  43. package/dist/commands/trace.d.ts.map +1 -0
  44. package/dist/commands/trace.js +45 -0
  45. package/dist/commands/verify.js +2 -2
  46. package/dist/config-report.d.ts +0 -1
  47. package/dist/config-report.d.ts.map +1 -1
  48. package/dist/config-report.js +1 -2
  49. package/dist/config.d.ts +0 -1
  50. package/dist/config.d.ts.map +1 -1
  51. package/dist/config.js +0 -1
  52. package/dist/context-report.d.ts +13 -7
  53. package/dist/context-report.d.ts.map +1 -1
  54. package/dist/context-report.js +64 -61
  55. package/dist/context-tool-hygiene.d.ts +36 -0
  56. package/dist/context-tool-hygiene.d.ts.map +1 -0
  57. package/dist/context-tool-hygiene.js +125 -0
  58. package/dist/dashboard/client.d.ts +2 -0
  59. package/dist/dashboard/client.d.ts.map +1 -0
  60. package/dist/dashboard/client.js +305 -0
  61. package/dist/dashboard/model.d.ts +13 -0
  62. package/dist/dashboard/model.d.ts.map +1 -0
  63. package/dist/dashboard/model.js +112 -0
  64. package/dist/dashboard/page.d.ts +3 -0
  65. package/dist/dashboard/page.d.ts.map +1 -0
  66. package/dist/dashboard/page.js +204 -0
  67. package/dist/dashboard/types.d.ts +63 -0
  68. package/dist/dashboard/types.d.ts.map +1 -0
  69. package/dist/dashboard/types.js +1 -0
  70. package/dist/dashboard-server.d.ts +24 -4
  71. package/dist/dashboard-server.d.ts.map +1 -1
  72. package/dist/dashboard-server.js +397 -302
  73. package/dist/discovery-registry.d.ts +17 -3
  74. package/dist/discovery-registry.d.ts.map +1 -1
  75. package/dist/discovery-registry.js +78 -3
  76. package/dist/doctor.d.ts +8 -0
  77. package/dist/doctor.d.ts.map +1 -1
  78. package/dist/doctor.js +116 -0
  79. package/dist/eval/llm-tasks.d.ts +5 -0
  80. package/dist/eval/llm-tasks.d.ts.map +1 -0
  81. package/dist/eval/llm-tasks.js +125 -0
  82. package/dist/eval/repo-tasks.d.ts +12 -0
  83. package/dist/eval/repo-tasks.d.ts.map +1 -0
  84. package/dist/eval/repo-tasks.js +220 -0
  85. package/dist/eval/runner.d.ts +3 -1
  86. package/dist/eval/runner.d.ts.map +1 -1
  87. package/dist/eval/runner.js +23 -4
  88. package/dist/eval/tasks.d.ts.map +1 -1
  89. package/dist/eval/tasks.js +186 -0
  90. package/dist/eval/types.d.ts +8 -5
  91. package/dist/eval/types.d.ts.map +1 -1
  92. package/dist/execution/event-bus.d.ts +44 -0
  93. package/dist/execution/event-bus.d.ts.map +1 -0
  94. package/dist/execution/event-bus.js +76 -0
  95. package/dist/execution/failure-classifier.d.ts +11 -0
  96. package/dist/execution/failure-classifier.d.ts.map +1 -0
  97. package/dist/execution/failure-classifier.js +66 -0
  98. package/dist/execution/progress-detector.d.ts +3 -0
  99. package/dist/execution/progress-detector.d.ts.map +1 -0
  100. package/dist/execution/progress-detector.js +23 -0
  101. package/dist/execution/recovery-controller.d.ts +24 -0
  102. package/dist/execution/recovery-controller.d.ts.map +1 -0
  103. package/dist/execution/recovery-controller.js +114 -0
  104. package/dist/execution/recovery-messages.d.ts +24 -0
  105. package/dist/execution/recovery-messages.d.ts.map +1 -0
  106. package/dist/execution/recovery-messages.js +48 -0
  107. package/dist/execution/recovery-metrics.d.ts +16 -0
  108. package/dist/execution/recovery-metrics.d.ts.map +1 -0
  109. package/dist/execution/recovery-metrics.js +73 -0
  110. package/dist/execution/recovery-strategy-planner.d.ts +6 -0
  111. package/dist/execution/recovery-strategy-planner.d.ts.map +1 -0
  112. package/dist/execution/recovery-strategy-planner.js +24 -0
  113. package/dist/execution/run-trace-store.d.ts +29 -0
  114. package/dist/execution/run-trace-store.d.ts.map +1 -0
  115. package/dist/execution/run-trace-store.js +140 -0
  116. package/dist/execution/staged-verifier.d.ts +33 -0
  117. package/dist/execution/staged-verifier.d.ts.map +1 -0
  118. package/dist/execution/staged-verifier.js +39 -0
  119. package/dist/execution/types.d.ts +58 -0
  120. package/dist/execution/types.d.ts.map +1 -0
  121. package/dist/execution/types.js +1 -0
  122. package/dist/execution/verification-loop.d.ts +58 -0
  123. package/dist/execution/verification-loop.d.ts.map +1 -0
  124. package/dist/execution/verification-loop.js +195 -0
  125. package/dist/execution/verification-stages.d.ts +17 -0
  126. package/dist/execution/verification-stages.d.ts.map +1 -0
  127. package/dist/execution/verification-stages.js +102 -0
  128. package/dist/help-topics.d.ts.map +1 -1
  129. package/dist/help-topics.js +11 -0
  130. package/dist/index.js +0 -8
  131. package/dist/lsp/ts-service.d.ts +36 -0
  132. package/dist/lsp/ts-service.d.ts.map +1 -0
  133. package/dist/lsp/ts-service.js +291 -0
  134. package/dist/memory/lifecycle.d.ts +19 -0
  135. package/dist/memory/lifecycle.d.ts.map +1 -0
  136. package/dist/memory/lifecycle.js +53 -0
  137. package/dist/memory.d.ts +0 -16
  138. package/dist/memory.d.ts.map +1 -1
  139. package/dist/memory.js +0 -36
  140. package/dist/metrics/collector.d.ts +7 -0
  141. package/dist/metrics/collector.d.ts.map +1 -1
  142. package/dist/metrics/collector.js +60 -0
  143. package/dist/mission/manager.d.ts +1 -0
  144. package/dist/mission/manager.d.ts.map +1 -1
  145. package/dist/mission/manager.js +9 -0
  146. package/dist/mission/progress-notify.d.ts +39 -0
  147. package/dist/mission/progress-notify.d.ts.map +1 -0
  148. package/dist/mission/progress-notify.js +386 -0
  149. package/dist/pipeline/hooks.d.ts +1 -1
  150. package/dist/pipeline/hooks.d.ts.map +1 -1
  151. package/dist/pipeline/hooks.js +1 -0
  152. package/dist/pipeline/sections.d.ts +8 -4
  153. package/dist/pipeline/sections.d.ts.map +1 -1
  154. package/dist/pipeline/sections.js +70 -27
  155. package/dist/pipeline/verification.d.ts +1 -0
  156. package/dist/pipeline/verification.d.ts.map +1 -1
  157. package/dist/pipeline/verification.js +10 -7
  158. package/dist/providers/llm-client.d.ts +38 -0
  159. package/dist/providers/llm-client.d.ts.map +1 -0
  160. package/dist/providers/llm-client.js +105 -0
  161. package/dist/sdk.d.ts +1 -0
  162. package/dist/sdk.d.ts.map +1 -1
  163. package/dist/sdk.js +1 -0
  164. package/dist/session/durable-session-supervisor.d.ts.map +1 -1
  165. package/dist/session/durable-session-supervisor.js +13 -6
  166. package/dist/session/session-persistence.d.ts +29 -0
  167. package/dist/session/session-persistence.d.ts.map +1 -0
  168. package/dist/session/session-persistence.js +45 -0
  169. package/dist/session/session-scheduler.d.ts +8 -1
  170. package/dist/session/session-scheduler.d.ts.map +1 -1
  171. package/dist/session/session-scheduler.js +33 -4
  172. package/dist/session-task-report.d.ts +1 -0
  173. package/dist/session-task-report.d.ts.map +1 -1
  174. package/dist/session-task-report.js +2 -1
  175. package/dist/shortcuts.d.ts.map +1 -1
  176. package/dist/shortcuts.js +1 -0
  177. package/dist/skills/registry.d.ts.map +1 -1
  178. package/dist/skills/registry.js +10 -0
  179. package/dist/skills/security-scan.d.ts +15 -0
  180. package/dist/skills/security-scan.d.ts.map +1 -0
  181. package/dist/skills/security-scan.js +95 -0
  182. package/dist/skills/types.d.ts +2 -0
  183. package/dist/skills/types.d.ts.map +1 -1
  184. package/dist/statusline.d.ts +3 -3
  185. package/dist/statusline.d.ts.map +1 -1
  186. package/dist/statusline.js +9 -17
  187. package/dist/token-usage.d.ts +27 -0
  188. package/dist/token-usage.d.ts.map +1 -0
  189. package/dist/token-usage.js +107 -0
  190. package/dist/tools/bash.d.ts.map +1 -1
  191. package/dist/tools/bash.js +5 -3
  192. package/dist/tools/browser-act-session.d.ts +48 -0
  193. package/dist/tools/browser-act-session.d.ts.map +1 -0
  194. package/dist/tools/browser-act-session.js +168 -0
  195. package/dist/tools/browser-act.d.ts +14 -0
  196. package/dist/tools/browser-act.d.ts.map +1 -0
  197. package/dist/tools/browser-act.js +297 -0
  198. package/dist/tools/code-symbols.d.ts +35 -0
  199. package/dist/tools/code-symbols.d.ts.map +1 -0
  200. package/dist/tools/code-symbols.js +257 -0
  201. package/dist/tools/index.d.ts +4 -1
  202. package/dist/tools/index.d.ts.map +1 -1
  203. package/dist/tools/index.js +22 -2
  204. package/dist/tools/lsp.d.ts +13 -0
  205. package/dist/tools/lsp.d.ts.map +1 -0
  206. package/dist/tools/lsp.js +136 -0
  207. package/dist/tools/patch.d.ts +5 -0
  208. package/dist/tools/patch.d.ts.map +1 -1
  209. package/dist/tools/patch.js +25 -4
  210. package/dist/tools/search.d.ts +7 -0
  211. package/dist/tools/search.d.ts.map +1 -1
  212. package/dist/tools/search.js +20 -3
  213. package/dist/tools/skill.d.ts +2 -0
  214. package/dist/tools/skill.d.ts.map +1 -1
  215. package/dist/tools/skill.js +47 -14
  216. package/dist/tools/subtask.d.ts +3 -1
  217. package/dist/tools/subtask.d.ts.map +1 -1
  218. package/dist/tools/subtask.js +151 -56
  219. package/dist/tui/shell.d.ts +12 -0
  220. package/dist/tui/shell.d.ts.map +1 -1
  221. package/dist/tui/shell.js +36 -3
  222. package/dist/tui/streaming-repl.d.ts +1 -0
  223. package/dist/tui/streaming-repl.d.ts.map +1 -1
  224. package/dist/tui/streaming-repl.js +27 -4
  225. package/dist/tui/streaming-tui.d.ts +10 -0
  226. package/dist/tui/streaming-tui.d.ts.map +1 -1
  227. package/dist/tui/streaming-tui.js +70 -12
  228. package/dist/types.d.ts +0 -8
  229. package/dist/types.d.ts.map +1 -1
  230. package/dist/workflow-runtime.d.ts.map +1 -1
  231. package/dist/workflow-runtime.js +10 -2
  232. package/dist/workflow-types.d.ts +2 -0
  233. package/dist/workflow-types.d.ts.map +1 -1
  234. package/docs/install.md +29 -8
  235. package/docs/skills.md +56 -7
  236. package/docs/web-routing.md +83 -0
  237. package/package.json +18 -4
  238. package/scripts/dep-layers.mjs +275 -0
  239. package/scripts/eval-llm.mjs +27 -0
  240. package/scripts/eval-recovery.mjs +101 -0
  241. package/scripts/eval-tasks.mjs +20 -0
  242. package/scripts/validate-packaging.mjs +51 -0
  243. package/skills/examples/README.md +23 -0
  244. package/skills/examples/add-function/SKILL.md +31 -0
  245. package/skills/examples/fix-failing-test/SKILL.md +32 -0
  246. package/skills/examples/pr-summary/SKILL.md +34 -0
  247. package/skills/lifecycle-build/SKILL.md +22 -0
  248. package/skills/lifecycle-plan/SKILL.md +32 -0
  249. package/skills/lifecycle-review/SKILL.md +25 -0
  250. package/skills/lifecycle-ship/SKILL.md +22 -0
  251. package/skills/lifecycle-spec/SKILL.md +24 -0
  252. package/skills/lifecycle-test/SKILL.md +21 -0
  253. package/skills/opencli/SKILL.md +222 -0
  254. package/skills/qling.md +14 -3
@@ -1,8 +1,9 @@
1
1
  // ============================================================
2
- // 轻灵 - Verification Agent(精简版)
3
- // - 简单操作跳过 LLM,直接规则判断
4
- // - LLM 输出严格限制在 150 tokens 内
5
- // - 只返回判决 + 一句话说明
2
+ // 轻灵 - Verification Agent(精简版,已 deprecated)
3
+ //
4
+ // 写操作失败恢复闭环请使用 StagedVerifier + resolveVerificationStages。
5
+ // 本类仅作无验证命令时的 advisory 旁路提示,不得驱动 RecoveryController。
6
+ // - 默认规则判断;LLM 路径需 QLING_VERIFY_LLM=1 显式开启
6
7
  // ============================================================
7
8
  const VERIFICATION_PROMPT = `你是轻灵的验证 Agent,负责判断操作是否成功。
8
9
 
@@ -20,6 +21,7 @@ PARTIAL // 部分成功,有警告
20
21
  - PARTIAL: 达到了核心目标,但有小问题
21
22
 
22
23
  请直接返回判决和说明,不要解释验证过程。`;
24
+ /** @deprecated Prefer StagedVerifier for recovery-driving verification. */
23
25
  export class VerificationAgent {
24
26
  apiKey;
25
27
  model;
@@ -28,11 +30,12 @@ export class VerificationAgent {
28
30
  this.model = model;
29
31
  }
30
32
  async verify(operation, expectedOutcome, actualOutput, context) {
31
- // 规则验证(快速路径)
33
+ // 规则验证(快速路径);advisory only — never feeds RecoveryController
32
34
  const ruleResult = this.ruleBasedVerify(operation, expectedOutcome, actualOutput);
33
- // 如果 output 很短(bash 无输出、权限拒绝等),直接用规则结果
35
+ const llmEnabled = ["1", "true", "on", "yes"].includes(String(process.env.QLING_VERIFY_LLM ?? "").trim().toLowerCase());
36
+ // 如果 output 很短且显式开启 LLM 旁路,才调用模型
34
37
  const isSimple = actualOutput.length < 100 || actualOutput.includes("denied") || actualOutput.includes("not found") || actualOutput.includes("Error");
35
- if (isSimple && this.apiKey) {
38
+ if (llmEnabled && isSimple && this.apiKey) {
36
39
  try {
37
40
  const llmResult = await this.verifyWithLLM(operation, actualOutput, ruleResult);
38
41
  return llmResult;
@@ -0,0 +1,38 @@
1
+ import { type ChatUsage } from "../token-usage.js";
2
+ import type { Message, RawToolCall, ToolDefinition } from "../types.js";
3
+ export interface LlmChatOverrides {
4
+ max_tokens?: number;
5
+ temperature?: number;
6
+ [key: string]: unknown;
7
+ }
8
+ export interface LlmChatResponse {
9
+ content: string;
10
+ tool_calls?: RawToolCall[];
11
+ usage?: ChatUsage;
12
+ }
13
+ export interface LlmClientOptions {
14
+ endpoint: string;
15
+ apiKey: string;
16
+ timeoutMs: number;
17
+ provider?: string;
18
+ /** Invoked once per transport retry attempt. */
19
+ onRetry?: () => void;
20
+ }
21
+ export declare class LlmHttpClient {
22
+ private client;
23
+ private provider;
24
+ private onRetry?;
25
+ constructor(options: LlmClientOptions);
26
+ reconfigure(options: LlmClientOptions): void;
27
+ /** Introspection for doctor/tests — request timeout in ms. */
28
+ getTimeoutMs(): number;
29
+ chatCompletions(input: {
30
+ model: string;
31
+ systemPrompt: string;
32
+ messages: Message[];
33
+ tools: ToolDefinition[];
34
+ overrides?: LlmChatOverrides;
35
+ }): Promise<LlmChatResponse>;
36
+ private buildClient;
37
+ }
38
+ //# sourceMappingURL=llm-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-client.d.ts","sourceRoot":"","sources":["../../src/providers/llm-client.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,SAAS,EACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAExE,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,WAAW,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAC,CAAa;gBAEjB,OAAO,EAAE,gBAAgB;IAMrC,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAM5C,8DAA8D;IAC9D,YAAY,IAAI,MAAM;IAKhB,eAAe,CAAC,KAAK,EAAE;QAC3B,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,KAAK,EAAE,cAAc,EAAE,CAAC;QACxB,SAAS,CAAC,EAAE,gBAAgB,CAAC;KAC9B,GAAG,OAAO,CAAC,eAAe,CAAC;IA4D5B,OAAO,CAAC,WAAW;CAkCpB"}
@@ -0,0 +1,105 @@
1
+ // ============================================================
2
+ // 轻灵 — OpenAI 兼容 LLM HTTP 客户端(从 AgentLoop 抽出)
3
+ // foundation 层:仅 axios + token-usage,无业务副作用。
4
+ // ============================================================
5
+ import axios from "axios";
6
+ import { extractProviderUsage, } from "../token-usage.js";
7
+ export class LlmHttpClient {
8
+ client;
9
+ provider;
10
+ onRetry;
11
+ constructor(options) {
12
+ this.provider = options.provider ?? "unknown";
13
+ this.onRetry = options.onRetry;
14
+ this.client = this.buildClient(options);
15
+ }
16
+ reconfigure(options) {
17
+ this.provider = options.provider ?? this.provider;
18
+ this.onRetry = options.onRetry ?? this.onRetry;
19
+ this.client = this.buildClient(options);
20
+ }
21
+ /** Introspection for doctor/tests — request timeout in ms. */
22
+ getTimeoutMs() {
23
+ const t = this.client.defaults.timeout;
24
+ return typeof t === "number" ? t : 0;
25
+ }
26
+ async chatCompletions(input) {
27
+ const systemMsg = { role: "system", content: input.systemPrompt };
28
+ const payload = {
29
+ model: input.model,
30
+ messages: [systemMsg, ...input.messages],
31
+ tools: input.tools.map((t) => ({
32
+ type: "function",
33
+ function: {
34
+ name: t.name,
35
+ description: t.description,
36
+ parameters: t.parameters,
37
+ },
38
+ })),
39
+ stream: false,
40
+ ...(input.overrides ?? {}),
41
+ };
42
+ let resp;
43
+ try {
44
+ resp = await this.client.post("/chat/completions", payload);
45
+ }
46
+ catch (err) {
47
+ const e = err;
48
+ const detail = JSON.stringify(e.response?.data ?? {}).slice(0, 500);
49
+ throw new Error(`${this.provider} API error: ` + detail);
50
+ }
51
+ const choice = resp.data.choices?.[0];
52
+ if (!choice) {
53
+ throw new Error(`${this.provider} API error: ` + JSON.stringify(resp.data));
54
+ }
55
+ const msg = choice.message;
56
+ let rawToolCalls;
57
+ if (msg.tool_calls && msg.tool_calls.length > 0) {
58
+ rawToolCalls = msg.tool_calls.map((tc) => ({
59
+ id: tc.id,
60
+ type: "function",
61
+ function: {
62
+ name: tc.function.name,
63
+ arguments: typeof tc.function.arguments === "string"
64
+ ? tc.function.arguments
65
+ : JSON.stringify(tc.function.arguments),
66
+ },
67
+ }));
68
+ }
69
+ const usage = extractProviderUsage(resp.data?.usage) ?? extractProviderUsage(resp.data);
70
+ return {
71
+ content: msg.content ?? "",
72
+ tool_calls: rawToolCalls,
73
+ usage,
74
+ };
75
+ }
76
+ buildClient(options) {
77
+ const client = axios.create({
78
+ baseURL: options.endpoint,
79
+ headers: {
80
+ Authorization: "Bearer " + options.apiKey,
81
+ "Content-Type": "application/json",
82
+ },
83
+ timeout: options.timeoutMs,
84
+ });
85
+ client.interceptors.response.use((response) => response, async (err) => {
86
+ const cfg = err.config;
87
+ if (!cfg)
88
+ return Promise.reject(err);
89
+ const maxRetries = 3;
90
+ cfg.__retryCount = cfg.__retryCount ?? 0;
91
+ const status = err.response?.status;
92
+ const shouldRetry = (!err.response || status === 429 || (status >= 500 && status <= 503)) &&
93
+ cfg.__retryCount < maxRetries;
94
+ if (shouldRetry) {
95
+ cfg.__retryCount++;
96
+ this.onRetry?.();
97
+ const delay = Math.min(1000 * Math.pow(2, cfg.__retryCount - 1), 10_000);
98
+ await new Promise((r) => setTimeout(r, delay));
99
+ return client(cfg);
100
+ }
101
+ return Promise.reject(err);
102
+ });
103
+ return client;
104
+ }
105
+ }
package/dist/sdk.d.ts CHANGED
@@ -6,6 +6,7 @@ export { addMcpPresetToStore, loadMcpStore, saveMcpStore, defaultMcpStorePath, t
6
6
  export { getRuntimeRootsFromEnv, isPathAllowedForWrite, checkSensitiveWriteTarget, resolveWriteSandboxMode, type RuntimeRoots, type WriteSandboxMode, } from "./runtime-paths.js";
7
7
  export { runEvalSuite, formatEvalReport, type RunEvalOptions, } from "./eval/runner.js";
8
8
  export { buildEvalSmokeTasks } from "./eval/tasks.js";
9
+ export { buildEvalRepoTasks, materializeBrokenFixture } from "./eval/repo-tasks.js";
9
10
  export { ALL_TOOLS, buildToolRegistry, dispatch } from "./tools/index.js";
10
11
  export { getPackageVersion, formatCliVersion, formatDaemonVersion, } from "./package-version.js";
11
12
  export type { AgentConfig, Message, ToolDefinition, ToolResult } from "./types.js";
package/dist/sdk.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,YAAY,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,KAAK,cAAc,GACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,YAAY,EACZ,cAAc,EACd,KAAK,SAAS,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,KAAK,YAAY,GAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,KAAK,YAAY,EACjB,KAAK,gBAAgB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,YAAY,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,KAAK,cAAc,GACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,YAAY,EACZ,cAAc,EACd,KAAK,SAAS,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,KAAK,YAAY,GAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,yBAAyB,EACzB,uBAAuB,EACvB,KAAK,YAAY,EACjB,KAAK,gBAAgB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,KAAK,cAAc,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACpF,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
package/dist/sdk.js CHANGED
@@ -14,5 +14,6 @@ export { addMcpPresetToStore, loadMcpStore, saveMcpStore, defaultMcpStorePath, }
14
14
  export { getRuntimeRootsFromEnv, isPathAllowedForWrite, checkSensitiveWriteTarget, resolveWriteSandboxMode, } from "./runtime-paths.js";
15
15
  export { runEvalSuite, formatEvalReport, } from "./eval/runner.js";
16
16
  export { buildEvalSmokeTasks } from "./eval/tasks.js";
17
+ export { buildEvalRepoTasks, materializeBrokenFixture } from "./eval/repo-tasks.js";
17
18
  export { ALL_TOOLS, buildToolRegistry, dispatch } from "./tools/index.js";
18
19
  export { getPackageVersion, formatCliVersion, formatDaemonVersion, } from "./package-version.js";
@@ -1 +1 @@
1
- {"version":3,"file":"durable-session-supervisor.d.ts","sourceRoot":"","sources":["../../src/session/durable-session-supervisor.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA4B;IAChD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,+BAA+B;IAMpD,KAAK,IAAI,IAAI;IAQP,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAOb,IAAI;YAoBJ,iBAAiB;YAcjB,iBAAiB;YAiBjB,sBAAsB;YA+BtB,cAAc;YAoCd,iBAAiB;YAyBjB,WAAW;CA+B1B"}
1
+ {"version":3,"file":"durable-session-supervisor.d.ts","sourceRoot":"","sources":["../../src/session/durable-session-supervisor.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA4B;IAChD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqB;IACrD,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,+BAA+B;IAMpD,KAAK,IAAI,IAAI;IAQP,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAOb,IAAI;YAyBJ,iBAAiB;YAcjB,iBAAiB;YAiBjB,sBAAsB;YAiCtB,cAAc;YAoCd,iBAAiB;YAyBjB,WAAW;CA8B1B"}
@@ -43,11 +43,17 @@ export class DurableSessionSupervisor {
43
43
  if (this.runningSessions.has(sessionId)) {
44
44
  continue;
45
45
  }
46
- const handledGoal = await this.tryRunDurableGoal(sessionId);
47
- if (handledGoal) {
48
- continue;
46
+ try {
47
+ const handledGoal = await this.tryRunDurableGoal(sessionId);
48
+ if (handledGoal) {
49
+ continue;
50
+ }
51
+ await this.tryRunDurableLoopTasks(sessionId);
52
+ }
53
+ catch (error) {
54
+ const message = error instanceof Error ? error.message : String(error);
55
+ this.log(`[durable-session] session=${sessionId} failed: ${message.slice(0, 500)}`);
49
56
  }
50
- await this.tryRunDurableLoopTasks(sessionId);
51
57
  }
52
58
  }
53
59
  finally {
@@ -100,7 +106,9 @@ export class DurableSessionSupervisor {
100
106
  const hasDue = tasks.some((task) => task.runner === "daemon" &&
101
107
  task.status !== "canceled" &&
102
108
  task.status !== "completed" &&
103
- (task.pending || task.nextRunAt <= now));
109
+ task.status !== "failed" &&
110
+ task.status !== "blocked" &&
111
+ (task.pending || (task.nextRunAt <= now && (task.backoffUntil ?? 0) <= now)));
104
112
  if (!hasDue) {
105
113
  return false;
106
114
  }
@@ -184,7 +192,6 @@ export class DurableSessionSupervisor {
184
192
  fileStateDir: this.stateDir,
185
193
  maxSteps: config.runtime.max_steps,
186
194
  parseRetries: config.runtime.parse_retries,
187
- maxTokenBudget: config.runtime.max_token_budget,
188
195
  toolRepeatLimit: config.runtime.tool_repeat_limit,
189
196
  timeoutMs: config.runtime.timeout_ms,
190
197
  },
@@ -0,0 +1,29 @@
1
+ import type { Message } from "../types.js";
2
+ import type { SavedSessionSnapshot, SavedSessionSummary } from "./session-registry.js";
3
+ export interface SessionLiveFields {
4
+ sessionId: string;
5
+ sessionCreatedAt: string;
6
+ messages: Message[];
7
+ turnCount: number;
8
+ sessionTokens: number;
9
+ compactionCount: number;
10
+ workspaceDir: string | null;
11
+ }
12
+ /** Fields AgentLoop should write back after restore. */
13
+ export interface SessionRestorePatch {
14
+ messages: Message[];
15
+ turnCount: number;
16
+ sessionTokens: number;
17
+ sessionPromptTokens: number;
18
+ sessionCompletionTokens: number;
19
+ tokenUsageSource: "provider" | "unknown";
20
+ compactionCount: number;
21
+ sessionId: string;
22
+ sessionCreatedAt: string;
23
+ workspaceDir: string | null;
24
+ summary: SavedSessionSummary;
25
+ }
26
+ export declare function buildSessionSnapshot(name: string, fields: SessionLiveFields): Omit<SavedSessionSnapshot, "version">;
27
+ export declare function applySessionSnapshot(snapshot: SavedSessionSnapshot): SessionRestorePatch;
28
+ export declare function defaultSessionSaveName(now?: Date): string;
29
+ //# sourceMappingURL=session-persistence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-persistence.d.ts","sourceRoot":"","sources":["../../src/session/session-persistence.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEvF,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,wDAAwD;AACxD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,uBAAuB,EAAE,MAAM,CAAC;IAChC,gBAAgB,EAAE,UAAU,GAAG,SAAS,CAAC;IACzC,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,mBAAmB,CAAC;CAC9B;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,iBAAiB,GACxB,IAAI,CAAC,oBAAoB,EAAE,SAAS,CAAC,CAYvC;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,mBAAmB,CAwBxF;AAED,wBAAgB,sBAAsB,CAAC,GAAG,OAAa,GAAG,MAAM,CAE/D"}
@@ -0,0 +1,45 @@
1
+ // ============================================================
2
+ // Session 快照构建 / 应用(从 AgentLoop 抽出)
3
+ // domain 层:纯数据结构,不依赖 AgentLoop 实例
4
+ // ============================================================
5
+ export function buildSessionSnapshot(name, fields) {
6
+ return {
7
+ name,
8
+ sessionId: fields.sessionId,
9
+ workspaceDir: fields.workspaceDir,
10
+ createdAt: fields.sessionCreatedAt,
11
+ updatedAt: new Date().toISOString(),
12
+ messages: fields.messages.map((message) => ({ ...message })),
13
+ turnCount: fields.turnCount,
14
+ sessionTokens: fields.sessionTokens,
15
+ compactionCount: fields.compactionCount,
16
+ };
17
+ }
18
+ export function applySessionSnapshot(snapshot) {
19
+ return {
20
+ messages: snapshot.messages.map((message) => ({ ...message })),
21
+ turnCount: snapshot.turnCount,
22
+ sessionTokens: snapshot.sessionTokens,
23
+ sessionPromptTokens: 0,
24
+ sessionCompletionTokens: 0,
25
+ tokenUsageSource: "unknown",
26
+ compactionCount: snapshot.compactionCount,
27
+ sessionId: snapshot.sessionId,
28
+ sessionCreatedAt: snapshot.createdAt,
29
+ workspaceDir: snapshot.workspaceDir,
30
+ summary: {
31
+ name: snapshot.name,
32
+ sessionId: snapshot.sessionId,
33
+ workspaceDir: snapshot.workspaceDir,
34
+ createdAt: snapshot.createdAt,
35
+ updatedAt: snapshot.updatedAt,
36
+ turnCount: snapshot.turnCount,
37
+ messageCount: snapshot.messages.length,
38
+ sessionTokens: snapshot.sessionTokens,
39
+ compactionCount: snapshot.compactionCount,
40
+ },
41
+ };
42
+ }
43
+ export function defaultSessionSaveName(now = new Date()) {
44
+ return "session-" + now.toISOString().replace(/[:.]/g, "-");
45
+ }
@@ -1,6 +1,6 @@
1
1
  export type SessionTaskKind = "loop";
2
2
  export type SessionTaskMode = "fixed" | "default";
3
- export type SessionTaskStatus = "active" | "running" | "completed" | "canceled";
3
+ export type SessionTaskStatus = "active" | "running" | "blocked" | "failed" | "completed" | "canceled";
4
4
  export type SessionTaskRunner = "session" | "daemon";
5
5
  export interface SessionTask {
6
6
  id: string;
@@ -15,6 +15,13 @@ export interface SessionTask {
15
15
  updatedAt: number;
16
16
  lastRunAt?: number;
17
17
  nextRunAt: number;
18
+ attemptCount?: number;
19
+ consecutiveFailures?: number;
20
+ lastError?: {
21
+ message: string;
22
+ timestamp: number;
23
+ };
24
+ backoffUntil?: number;
18
25
  }
19
26
  export interface SessionSchedulerOptions {
20
27
  stateDir: string;
@@ -1 +1 @@
1
- {"version":3,"file":"session-scheduler.d.ts","sourceRoot":"","sources":["../../src/session/session-scheduler.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC;AACrC,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,CAAC;AAClD,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;AAChF,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,QAAQ,CAAC;AAErD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuC;IAC7D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IACxD,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,KAAK,CAA+C;gBAEhD,OAAO,EAAE,uBAAuB;IAStC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,KAAK,IAAI,IAAI;IAOP,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAIvB,cAAc,CAAC,OAAO,EAAE;QAC5B,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,eAAe,CAAC;QACtB,MAAM,CAAC,EAAE,iBAAiB,CAAC;KAC5B,GAAG,OAAO,CAAC,WAAW,CAAC;IAqBlB,SAAS,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAOnC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAU5C,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAiBjC,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC;IAqD9C,OAAO,CAAC,cAAc;YAQR,SAAS;YAaT,SAAS;CAMxB"}
1
+ {"version":3,"file":"session-scheduler.d.ts","sourceRoot":"","sources":["../../src/session/session-scheduler.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC;AACrC,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,CAAC;AAClD,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,GAAG,UAAU,CAAC;AACvG,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,QAAQ,CAAC;AAErD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuC;IAC7D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IACxD,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,KAAK,CAA+C;gBAEhD,OAAO,EAAE,uBAAuB;IAStC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,KAAK,IAAI,IAAI;IAOP,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAIvB,cAAc,CAAC,OAAO,EAAE;QAC5B,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,eAAe,CAAC;QACtB,MAAM,CAAC,EAAE,iBAAiB,CAAC;KAC5B,GAAG,OAAO,CAAC,WAAW,CAAC;IAqBlB,SAAS,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAOnC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAU5C,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAiBjC,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC;IA4E9C,OAAO,CAAC,cAAc;YAQR,SAAS;YAaT,SAAS;CAMxB"}
@@ -100,13 +100,13 @@ export class SessionScheduler {
100
100
  let dirty = false;
101
101
  const tasks = Array.from(this.tasks.values()).sort((a, b) => a.nextRunAt - b.nextRunAt);
102
102
  for (const task of tasks) {
103
- if (task.status === "canceled" || task.status === "completed") {
103
+ if (["canceled", "completed", "failed", "blocked"].includes(task.status)) {
104
104
  continue;
105
105
  }
106
106
  if ((task.runner ?? "session") !== this.runner) {
107
107
  continue;
108
108
  }
109
- const isDue = task.pending || task.nextRunAt <= now;
109
+ const isDue = task.pending || (task.nextRunAt <= now && (task.backoffUntil ?? 0) <= now);
110
110
  if (!isDue)
111
111
  continue;
112
112
  if (this.busy) {
@@ -119,20 +119,45 @@ export class SessionScheduler {
119
119
  }
120
120
  task.pending = false;
121
121
  task.status = "running";
122
+ task.attemptCount = (task.attemptCount ?? 0) + 1;
122
123
  task.updatedAt = now;
123
124
  await this.saveTasks();
124
125
  try {
125
126
  await this.onDue(cloneTask(task));
126
127
  triggered++;
127
- }
128
- finally {
129
128
  const currentTask = this.tasks.get(task.id);
130
129
  if (currentTask && currentTask.status !== "canceled") {
131
130
  currentTask.status = "active";
131
+ currentTask.consecutiveFailures = 0;
132
+ currentTask.lastError = undefined;
133
+ currentTask.backoffUntil = undefined;
132
134
  currentTask.lastRunAt = now;
133
135
  currentTask.nextRunAt = now + currentTask.intervalMs;
134
136
  currentTask.updatedAt = this.clock();
135
137
  }
138
+ }
139
+ catch (error) {
140
+ const currentTask = this.tasks.get(task.id);
141
+ if (currentTask && currentTask.status !== "canceled") {
142
+ const failures = (currentTask.consecutiveFailures ?? 0) + 1;
143
+ const failedAt = this.clock();
144
+ currentTask.consecutiveFailures = failures;
145
+ currentTask.lastError = { message: sanitizeError(error), timestamp: failedAt };
146
+ currentTask.lastRunAt = now;
147
+ currentTask.updatedAt = failedAt;
148
+ if (failures >= 4) {
149
+ currentTask.status = "failed";
150
+ currentTask.backoffUntil = undefined;
151
+ }
152
+ else {
153
+ const delay = Math.min(60_000, 1_000 * 2 ** (failures - 1));
154
+ currentTask.status = "active";
155
+ currentTask.backoffUntil = failedAt + delay;
156
+ currentTask.nextRunAt = currentTask.backoffUntil;
157
+ }
158
+ }
159
+ }
160
+ finally {
136
161
  await this.saveTasks();
137
162
  }
138
163
  }
@@ -168,3 +193,7 @@ export class SessionScheduler {
168
193
  await fs.writeFile(this.stateFile, JSON.stringify(payload, null, 2), "utf-8");
169
194
  }
170
195
  }
196
+ function sanitizeError(error) {
197
+ const message = error instanceof Error ? error.message : String(error);
198
+ return message.replace(/\b(?:sk|api)[-_][a-z0-9_-]{8,}\b/gi, "[redacted]").slice(0, 500);
199
+ }
@@ -14,6 +14,7 @@ export interface SessionTaskReport {
14
14
  export declare function parseSessionTaskCount(value?: string): number;
15
15
  export declare function listLocalSessionTasks(stateDir: string, options?: {
16
16
  count?: number;
17
+ maxCount?: number;
17
18
  }): Promise<SessionTaskReport>;
18
19
  export declare function cancelLocalSessionTask(stateDir: string, taskId: string, options?: {
19
20
  clock?: () => number;
@@ -1 +1 @@
1
- {"version":3,"file":"session-task-report.d.ts","sourceRoot":"","sources":["../src/session-task-report.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAKlE,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAK5D;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CA8D5B;AAED,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO,GACrC,OAAO,CAAC,gBAAgB,CAAC,CA0C3B;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAkC3E;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAY1E"}
1
+ {"version":3,"file":"session-task-report.d.ts","sourceRoot":"","sources":["../src/session-task-report.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAKlE,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAK5D;AAED,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,OAAO,CAAC,iBAAiB,CAAC,CA+D5B;AAED,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,MAAM,CAAA;CAAO,GACrC,OAAO,CAAC,gBAAgB,CAAC,CA0C3B;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,EAAE,CAkC3E;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAY1E"}
@@ -13,7 +13,8 @@ export function parseSessionTaskCount(value) {
13
13
  }
14
14
  export async function listLocalSessionTasks(stateDir, options = {}) {
15
15
  const tasksDir = path.join(stateDir, "session-tasks");
16
- const count = Math.min(Math.max(1, Math.floor(options.count ?? DEFAULT_TASK_COUNT)), MAX_TASK_COUNT);
16
+ const maxCount = Math.max(1, Math.floor(options.maxCount ?? MAX_TASK_COUNT));
17
+ const count = Math.min(Math.max(1, Math.floor(options.count ?? DEFAULT_TASK_COUNT)), maxCount);
17
18
  const warnings = [];
18
19
  if (!existsSync(tasksDir)) {
19
20
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"shortcuts.d.ts","sourceRoot":"","sources":["../src/shortcuts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,UA+B1B,CAAC"}
1
+ {"version":3,"file":"shortcuts.d.ts","sourceRoot":"","sources":["../src/shortcuts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc,UAgC1B,CAAC"}
package/dist/shortcuts.js CHANGED
@@ -5,6 +5,7 @@ export const SHORTCUT_LINES = [
5
5
  "界面入口 : /help slash 查看本地命令;/privacy 查看边界;/context 查看上下文;/statusline 查看状态线;Tab agents 打开本地 agents 视图",
6
6
  "Enter : 发送当前输入",
7
7
  "Tab : 空输入时打开本地 /agents mission 视图;slash 前缀补全最佳命令;其他非空输入会保留草稿并提示补全未启用",
8
+ "Shift+Tab: 循环 Agent/ask → Plan → Agent/allow (Always Agree) → Agent/ask;保留当前草稿",
8
9
  "Slash : 输入 / 或 /sk 显示本地命令候选,Tab 补全最佳候选,不自动执行",
9
10
  "Ctrl+N : 插入换行,继续编辑多行 prompt",
10
11
  "Ctrl+R : 用当前输入搜索本会话内历史;未命中会提示并保留草稿",
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/skills/registry.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAS5C,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAYxE;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAErE;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAStF;AA+BD,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAoBhF;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,CAiCzE;AAED,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/skills/registry.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAS5C,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAYxE;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAErE;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAStF;AA+BD,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAoBhF;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,CA2CzE;AAED,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
@@ -89,6 +89,7 @@ export function parseFrontmatter(raw, filePath) {
89
89
  name: fallbackName,
90
90
  description: "",
91
91
  tags: [],
92
+ triggers: [],
92
93
  path: filePath,
93
94
  };
94
95
  const lines = raw.split("\n");
@@ -103,10 +104,19 @@ export function parseFrontmatter(raw, filePath) {
103
104
  const parsed = YAML.parse(yamlBlock);
104
105
  if (!parsed || typeof parsed !== "object")
105
106
  return fallback;
107
+ const triggersRaw = parsed.triggers ?? parsed.trigger;
108
+ let triggers = [];
109
+ if (Array.isArray(triggersRaw)) {
110
+ triggers = triggersRaw.map(String).filter(Boolean);
111
+ }
112
+ else if (typeof triggersRaw === "string" && triggersRaw.trim()) {
113
+ triggers = triggersRaw.split(/[,,]/).map((s) => s.trim()).filter(Boolean);
114
+ }
106
115
  return {
107
116
  name: typeof parsed.name === "string" && parsed.name ? parsed.name : fallbackName,
108
117
  description: typeof parsed.description === "string" ? parsed.description : "",
109
118
  tags: Array.isArray(parsed.tags) ? parsed.tags.map(String) : [],
119
+ triggers,
110
120
  path: filePath,
111
121
  };
112
122
  }
@@ -0,0 +1,15 @@
1
+ export type SkillScanSeverity = "critical" | "high" | "medium" | "low";
2
+ export interface SkillScanFinding {
3
+ severity: SkillScanSeverity;
4
+ rule: string;
5
+ detail: string;
6
+ }
7
+ export interface SkillScanResult {
8
+ ok: boolean;
9
+ findings: SkillScanFinding[];
10
+ mode: "on" | "warn" | "off";
11
+ }
12
+ export declare function resolveSkillScanMode(env?: NodeJS.ProcessEnv | Record<string, string | undefined>): "on" | "warn" | "off";
13
+ export declare function scanSkillContent(content: string, env?: NodeJS.ProcessEnv | Record<string, string | undefined>): SkillScanResult;
14
+ export declare function formatSkillScanBlockMessage(name: string, result: SkillScanResult): string;
15
+ //# sourceMappingURL=security-scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-scan.d.ts","sourceRoot":"","sources":["../../src/skills/security-scan.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEvE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;CAC7B;AAkED,wBAAgB,oBAAoB,CAClC,GAAG,GAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACxE,IAAI,GAAG,MAAM,GAAG,KAAK,CAKvB;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACxE,eAAe,CAsBjB;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,MAAM,CASzF"}
@@ -0,0 +1,95 @@
1
+ // ============================================================
2
+ // Phase 3.1 — Skill 静态安全扫描
3
+ // QLING_SKILL_SCAN: on(默认)| warn | off
4
+ // ============================================================
5
+ const RULES = [
6
+ {
7
+ severity: "critical",
8
+ rule: "private-key-pem",
9
+ pattern: /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/i,
10
+ detail: "疑似私钥 PEM 块",
11
+ },
12
+ {
13
+ severity: "critical",
14
+ rule: "aws-access-key",
15
+ pattern: /\bAKIA[0-9A-Z]{16}\b/,
16
+ detail: "疑似 AWS Access Key ID",
17
+ },
18
+ {
19
+ severity: "critical",
20
+ rule: "generic-secret-assignment",
21
+ pattern: /\b(api[_-]?key|secret[_-]?key|access[_-]?token)\s*[:=]\s*['"][A-Za-z0-9_\-]{24,}['"]/i,
22
+ detail: "疑似硬编码密钥赋值",
23
+ },
24
+ {
25
+ severity: "high",
26
+ rule: "curl-pipe-shell",
27
+ pattern: /curl\s+[^\n|]*\|\s*(?:ba)?sh/i,
28
+ detail: "curl 管道 shell 远程执行模式",
29
+ },
30
+ {
31
+ severity: "high",
32
+ rule: "irm-iex",
33
+ pattern: /irm\s+[^\n|]*\|\s*iex|Invoke-Expression/i,
34
+ detail: "PowerShell 远程下载执行模式",
35
+ },
36
+ {
37
+ severity: "high",
38
+ rule: "wget-pipe-shell",
39
+ pattern: /wget\s+[^\n|]*\|\s*(?:ba)?sh/i,
40
+ detail: "wget 管道 shell 远程执行模式",
41
+ },
42
+ {
43
+ severity: "high",
44
+ rule: "base64-decode-exec",
45
+ pattern: /base64\s+-d[^;\n]*\|\s*(?:ba)?sh|Buffer\.from\([^)]+,\s*['"]base64['"]\)[^;]{0,80}(exec|spawn|eval)/i,
46
+ detail: "base64 解码后执行模式",
47
+ },
48
+ {
49
+ severity: "medium",
50
+ rule: "eval-call",
51
+ pattern: /\beval\s*\(/,
52
+ detail: "动态 eval 调用",
53
+ },
54
+ {
55
+ severity: "medium",
56
+ rule: "child-process",
57
+ pattern: /child_process\.(exec|spawn|execSync|spawnSync)/,
58
+ detail: "Node child_process 直接调用(需人工确认)",
59
+ },
60
+ ];
61
+ export function resolveSkillScanMode(env = process.env) {
62
+ const raw = String(env.QLING_SKILL_SCAN ?? "on").trim().toLowerCase();
63
+ if (raw === "off" || raw === "0" || raw === "false")
64
+ return "off";
65
+ if (raw === "warn" || raw === "warning")
66
+ return "warn";
67
+ return "on";
68
+ }
69
+ export function scanSkillContent(content, env = process.env) {
70
+ const mode = resolveSkillScanMode(env);
71
+ if (mode === "off") {
72
+ return { ok: true, findings: [], mode };
73
+ }
74
+ const findings = [];
75
+ for (const rule of RULES) {
76
+ if (rule.pattern.test(content)) {
77
+ findings.push({
78
+ severity: rule.severity,
79
+ rule: rule.rule,
80
+ detail: rule.detail,
81
+ });
82
+ }
83
+ }
84
+ const blocking = findings.some((f) => f.severity === "critical" || f.severity === "high");
85
+ if (mode === "warn") {
86
+ return { ok: true, findings, mode };
87
+ }
88
+ return { ok: !blocking, findings, mode };
89
+ }
90
+ export function formatSkillScanBlockMessage(name, result) {
91
+ const lines = result.findings.map((f) => ` - [${f.severity}] ${f.rule}: ${f.detail}`);
92
+ return (`skill 安全扫描未通过: ${name}\n` +
93
+ lines.join("\n") +
94
+ `\n(策略 QLING_SKILL_SCAN=${result.mode};调试可设 off/warn)`);
95
+ }