@qlingzzy/qling 1.0.0 → 1.1.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 (254) hide show
  1. package/CHANGELOG.md +158 -0
  2. package/README.en.md +83 -18
  3. package/README.md +19 -9
  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 +46 -12
  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 +57 -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,9 +1,18 @@
1
- import { DiscoverySource, DiscoveredItem } from "./discovery-types.js";
2
- import { ToolDefinition } from "./types.js";
1
+ import type { DiscoverySource, DiscoveredItem } from "./discovery-types.js";
2
+ import type { ToolDefinition } from "./types.js";
3
+ import { type GuardConfig } from "./config.js";
4
+ export interface DiscoveryRegistryOptions {
5
+ allowUnsigned?: boolean;
6
+ guardConfig?: GuardConfig;
7
+ env?: NodeJS.ProcessEnv | Record<string, string | undefined>;
8
+ }
3
9
  export declare class DiscoveryRegistry {
4
10
  private items;
5
11
  private sources;
6
- constructor(sources?: DiscoverySource[]);
12
+ private allowUnsigned;
13
+ private guardConfig;
14
+ private env;
15
+ constructor(sources?: DiscoverySource[], options?: DiscoveryRegistryOptions);
7
16
  /**
8
17
  * 同步所有源
9
18
  */
@@ -19,6 +28,11 @@ export declare class DiscoveryRegistry {
19
28
  * 获取所有发现的工具定义
20
29
  */
21
30
  getDiscoveredTools(): ToolDefinition[];
31
+ /**
32
+ * Manifest tool entries are metadata only until an executable handler or
33
+ * MCP transport has been bound. Never advertise metadata-only tools to the model.
34
+ */
35
+ getExecutableTools(): ToolDefinition[];
22
36
  /**
23
37
  * 获取所有发现的 MCP 服务器配置
24
38
  */
@@ -1 +1 @@
1
- {"version":3,"file":"discovery-registry.d.ts","sourceRoot":"","sources":["../src/discovery-registry.ts"],"names":[],"mappings":"AASA,OAAO,EAAqB,eAAe,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,KAAK,CAA0C;IACvD,OAAO,CAAC,OAAO,CAAyB;gBAE5B,OAAO,GAAE,eAAe,EAAO;IAI3C;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;YAY1C,SAAS;YAoBT,UAAU;IAWxB,OAAO,CAAC,YAAY;IAWpB;;OAEG;IACH,kBAAkB,IAAI,cAAc,EAAE;IAUtC;;OAEG;IACH,uBAAuB,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAU9C,WAAW,IAAI,cAAc,EAAE;CAGhC"}
1
+ {"version":3,"file":"discovery-registry.d.ts","sourceRoot":"","sources":["../src/discovery-registry.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAqB,eAAe,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC/F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAGnE,MAAM,WAAW,wBAAwB;IACvC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC9D;AAiCD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,KAAK,CAA0C;IACvD,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,aAAa,CAAU;IAC/B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,GAAG,CAAyD;gBAExD,OAAO,GAAE,eAAe,EAAO,EAAE,OAAO,GAAE,wBAA6B;IASnF;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;YAe1C,SAAS;YAoBT,UAAU;IAsCxB,OAAO,CAAC,YAAY;IAYpB;;OAEG;IACH,kBAAkB,IAAI,cAAc,EAAE;IAUtC;;;OAGG;IACH,kBAAkB,IAAI,cAAc,EAAE;IAItC;;OAEG;IACH,uBAAuB,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAU9C,WAAW,IAAI,cAAc,EAAE;CAGhC"}
@@ -6,11 +6,49 @@ import * as fs from "fs/promises";
6
6
  import * as path from "path";
7
7
  import { existsSync } from "fs";
8
8
  import axios from "axios";
9
+ import { guardConfigFromEnv } from "./config.js";
10
+ import { appendGuardAudit, checkUrlFetchPolicy } from "./guard.js";
11
+ const ENABLED_VALUES = new Set(["1", "true", "on", "yes"]);
12
+ function isExplicitlyEnabled(raw) {
13
+ return ENABLED_VALUES.has(String(raw ?? "").trim().toLowerCase());
14
+ }
15
+ function assertValidManifest(value) {
16
+ if (!value || typeof value !== "object") {
17
+ throw new Error("manifest must be an object");
18
+ }
19
+ const manifest = value;
20
+ for (const key of ["id", "name", "version"]) {
21
+ if (typeof manifest[key] !== "string" || !manifest[key].trim()) {
22
+ throw new Error(`manifest.${key} must be a non-empty string`);
23
+ }
24
+ }
25
+ if (!new Set(["skill", "mcp", "bundle"]).has(String(manifest.type))) {
26
+ throw new Error("manifest.type must be skill, mcp, or bundle");
27
+ }
28
+ if (manifest.tools !== undefined) {
29
+ if (!Array.isArray(manifest.tools)) {
30
+ throw new Error("manifest.tools must be an array");
31
+ }
32
+ for (const tool of manifest.tools) {
33
+ if (!tool || typeof tool !== "object" || typeof tool.name !== "string" || !tool.name.trim()) {
34
+ throw new Error("manifest tool name must be a non-empty string");
35
+ }
36
+ }
37
+ }
38
+ }
9
39
  export class DiscoveryRegistry {
10
40
  items = new Map();
11
41
  sources = [];
12
- constructor(sources = []) {
42
+ allowUnsigned;
43
+ guardConfig;
44
+ env;
45
+ constructor(sources = [], options = {}) {
13
46
  this.sources = sources;
47
+ this.env = options.env ?? process.env;
48
+ this.allowUnsigned =
49
+ options.allowUnsigned ?? isExplicitlyEnabled(this.env.QLING_DISCOVERY_ALLOW_UNSIGNED);
50
+ this.guardConfig =
51
+ options.guardConfig ?? guardConfigFromEnv(this.env);
14
52
  }
15
53
  /**
16
54
  * 同步所有源
@@ -24,6 +62,9 @@ export class DiscoveryRegistry {
24
62
  */
25
63
  async syncSource(source) {
26
64
  try {
65
+ if (source.requireApproval) {
66
+ throw new Error("source requires approval, but no discovery approval callback is configured");
67
+ }
27
68
  if (source.type === "local") {
28
69
  await this.syncLocal(source);
29
70
  }
@@ -57,9 +98,35 @@ export class DiscoveryRegistry {
57
98
  }
58
99
  async syncRemote(source) {
59
100
  try {
60
- const resp = await axios.get(source.uri, { timeout: 10000 });
101
+ if (!this.allowUnsigned) {
102
+ throw new Error("unsigned remote discovery is disabled; set QLING_DISCOVERY_ALLOW_UNSIGNED=true only for a trusted source");
103
+ }
104
+ let target;
105
+ try {
106
+ target = new URL(source.uri);
107
+ }
108
+ catch {
109
+ throw new Error(`invalid remote manifest URL: ${source.uri}`);
110
+ }
111
+ const decision = await checkUrlFetchPolicy(target, this.guardConfig, this.env);
112
+ if (!decision.allowed) {
113
+ await appendGuardAudit(this.guardConfig, {
114
+ tool: "dynamic_discovery",
115
+ action: "deny",
116
+ category: decision.category,
117
+ target: target.toString(),
118
+ reason: decision.reason,
119
+ });
120
+ throw new Error(decision.reason ?? "network guard denied remote manifest");
121
+ }
122
+ const resp = await axios.get(source.uri, {
123
+ timeout: 10_000,
124
+ maxRedirects: 0,
125
+ maxContentLength: 1024 * 1024,
126
+ maxBodyLength: 1024 * 1024,
127
+ });
61
128
  const manifest = resp.data;
62
- // TODO: 签名校验
129
+ assertValidManifest(manifest);
63
130
  this.registerItem(source.id, manifest);
64
131
  }
65
132
  catch (err) {
@@ -67,6 +134,7 @@ export class DiscoveryRegistry {
67
134
  }
68
135
  }
69
136
  registerItem(sourceId, manifest) {
137
+ assertValidManifest(manifest);
70
138
  const id = manifest.id;
71
139
  this.items.set(id, {
72
140
  id,
@@ -88,6 +156,13 @@ export class DiscoveryRegistry {
88
156
  }
89
157
  return tools;
90
158
  }
159
+ /**
160
+ * Manifest tool entries are metadata only until an executable handler or
161
+ * MCP transport has been bound. Never advertise metadata-only tools to the model.
162
+ */
163
+ getExecutableTools() {
164
+ return [];
165
+ }
91
166
  /**
92
167
  * 获取所有发现的 MCP 服务器配置
93
168
  */
package/dist/doctor.d.ts CHANGED
@@ -26,6 +26,14 @@ export interface DoctorOptions {
26
26
  detail: string;
27
27
  }>;
28
28
  }
29
+ /** Phase 3 可选能力开关(informational) */
30
+ export declare function buildPhase3FeatureChecks(env?: DoctorOptions["env"]): DoctorCheck[];
31
+ /** Phase 5 韧性 / 验证管线(informational) */
32
+ export declare function buildPhase5FeatureChecks(env?: DoctorOptions["env"], options?: {
33
+ exists?: (path: string) => boolean;
34
+ stateDir?: string;
35
+ verificationStagesSummary?: string;
36
+ }): DoctorCheck[];
29
37
  export declare function buildDoctorReport(context: SlashCommandContext, options?: DoctorOptions): Promise<DoctorReport>;
30
38
  export declare function formatDoctorReport(report: DoctorReport): string[];
31
39
  //# sourceMappingURL=doctor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAUjE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEpD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7D,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,SAAS,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7D,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9D;AA0PD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,mBAAmB,EAC5B,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CAmFvB;AAQD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,EAAE,CAqBjE"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../src/doctor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAUjE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEpD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACtC,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC7D,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,SAAS,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7D,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9D;AAgDD,oCAAoC;AACpC,wBAAgB,wBAAwB,CAAC,GAAG,GAAE,aAAa,CAAC,KAAK,CAAe,GAAG,WAAW,EAAE,CA0C/F;AAED,uCAAuC;AACvC,wBAAgB,wBAAwB,CACtC,GAAG,GAAE,aAAa,CAAC,KAAK,CAAe,EACvC,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yBAAyB,CAAC,EAAE,MAAM,CAAC;CAC/B,GACL,WAAW,EAAE,CAyCf;AAqOD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,mBAAmB,EAC5B,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CA4FvB;AAQD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,EAAE,CAqBjE"}
package/dist/doctor.js CHANGED
@@ -40,6 +40,111 @@ function envNumber(env, name) {
40
40
  function boolText(value) {
41
41
  return value ? "on" : "off";
42
42
  }
43
+ function envFlagOn(env, name) {
44
+ const raw = envText(env, name).toLowerCase();
45
+ return raw === "1" || raw === "true" || raw === "on" || raw === "yes";
46
+ }
47
+ /** Phase 3 可选能力开关(informational) */
48
+ export function buildPhase3FeatureChecks(env = process.env) {
49
+ const browserAct = envFlagOn(env, "QLING_BROWSER_ACT");
50
+ const parallel = envFlagOn(env, "QLING_SUBTASK_PARALLEL");
51
+ const missionNotify = envText(env, "QLING_MISSION_NOTIFY").toLowerCase();
52
+ const notifyOn = !(missionNotify === "off" || missionNotify === "0" || missionNotify === "false");
53
+ const logMode = envText(env, "QLING_MISSION_NOTIFY_LOGS") || "milestone";
54
+ const style = envText(env, "QLING_MISSION_NOTIFY_STYLE") || "rich";
55
+ const hasTg = Boolean(envText(env, "QLING_CHANNEL_TELEGRAM_TOKEN"));
56
+ const hasSlack = Boolean(envText(env, "QLING_CHANNEL_SLACK_BOT_TOKEN"));
57
+ return [
58
+ {
59
+ id: "phase3_browser_act",
60
+ label: "phase3:browser_act",
61
+ status: browserAct ? "pass" : "warn",
62
+ detail: browserAct
63
+ ? "QLING_BROWSER_ACT=on(交互浏览已启用)"
64
+ : "默认关闭;启用设 QLING_BROWSER_ACT=1,见 docs/web-routing.md",
65
+ },
66
+ {
67
+ id: "phase3_subtask_parallel",
68
+ label: "phase3:subtask_parallel",
69
+ status: parallel ? "pass" : "warn",
70
+ detail: parallel
71
+ ? "QLING_SUBTASK_PARALLEL=on(explore 并行已启用)"
72
+ : "默认关闭;启用设 QLING_SUBTASK_PARALLEL=1",
73
+ },
74
+ {
75
+ id: "phase3_mission_notify",
76
+ label: "phase3:mission_notify",
77
+ status: notifyOn && (hasTg || hasSlack) ? "pass" : notifyOn ? "warn" : "pass",
78
+ detail: `notify=${notifyOn ? "on" : "off"} style=${style} logs=${logMode} telegram=${hasTg ? "token" : "none"} slack=${hasSlack ? "token" : "none"}`,
79
+ },
80
+ {
81
+ id: "phase4_lsp",
82
+ label: "phase4:lsp",
83
+ status: envFlagOn(env, "QLING_LSP") ? "pass" : "warn",
84
+ detail: envFlagOn(env, "QLING_LSP")
85
+ ? "QLING_LSP=on(TS LanguageService 语义查询已启用)"
86
+ : "默认关闭;启用设 QLING_LSP=1(需 typescript 包)",
87
+ },
88
+ ];
89
+ }
90
+ /** Phase 5 韧性 / 验证管线(informational) */
91
+ export function buildPhase5FeatureChecks(env = process.env, options = {}) {
92
+ const exists = options.exists ?? existsSync;
93
+ const stateDir = options.stateDir || envText(env, "QLING_FILE_STATE_DIR") || DEFAULT_STATE_DIR;
94
+ const runsDir = join(stateDir, "runs");
95
+ const sameFp = envNumber(env, "QLING_RECOVERY_SAME_FINGERPRINT_LIMIT") || 2;
96
+ const strategyBudget = envNumber(env, "QLING_RECOVERY_STRATEGY_LIMIT") || 4;
97
+ const stagesSummary = options.verificationStagesSummary ||
98
+ summarizeEnvVerificationStages(env);
99
+ const verifyLlm = envFlagOn(env, "QLING_VERIFY_LLM");
100
+ return [
101
+ {
102
+ id: "phase5_recovery_budget",
103
+ label: "phase5:recovery_budget",
104
+ status: "pass",
105
+ detail: `same_fingerprint_limit=${sameFp} strategy_attempt_limit=${strategyBudget}(硬停: 审批/沙箱/重复动作)`,
106
+ },
107
+ {
108
+ id: "phase5_run_traces",
109
+ label: "phase5:run_traces",
110
+ status: exists(runsDir) ? "pass" : "warn",
111
+ detail: exists(runsDir)
112
+ ? `trace_dir=${resolve(runsDir)}(脱敏 JSONL,30 天 / 50 MiB)`
113
+ : `trace_dir=${resolve(runsDir)} 尚未创建;首次失败恢复后生成`,
114
+ },
115
+ {
116
+ id: "phase5_verifier_stages",
117
+ label: "phase5:verifier_stages",
118
+ status: stagesSummary.startsWith("none") ? "warn" : "pass",
119
+ detail: stagesSummary,
120
+ },
121
+ {
122
+ id: "phase5_verify_llm_advisory",
123
+ label: "phase5:verify_llm_advisory",
124
+ status: verifyLlm ? "warn" : "pass",
125
+ detail: verifyLlm
126
+ ? "QLING_VERIFY_LLM=on(deprecated VerificationAgent LLM 旁路;不驱动恢复)"
127
+ : "默认规则旁路;恢复闭环仅 StagedVerifier",
128
+ },
129
+ ];
130
+ }
131
+ function summarizeEnvVerificationStages(env) {
132
+ // Lazy import avoidance: inline minimal summary for doctor without agent loop
133
+ const parts = [];
134
+ const stages = envText(env, "QLING_VERIFY_STAGES");
135
+ if (stages)
136
+ parts.push(`QLING_VERIFY_STAGES set`);
137
+ if (envText(env, "QLING_VERIFY_TYPECHECK_CMD"))
138
+ parts.push("typecheck");
139
+ if (envText(env, "QLING_VERIFY_TEST_CMD"))
140
+ parts.push("test");
141
+ if (envText(env, "QLING_VERIFY_FULL_CMD"))
142
+ parts.push("full_gate");
143
+ if (parts.length === 0) {
144
+ return "none(可设 /verify set 或 QLING_VERIFY_TYPECHECK_CMD / QLING_VERIFY_TEST_CMD / QLING_VERIFY_STAGES)";
145
+ }
146
+ return parts.join(" + ");
147
+ }
43
148
  function buildConfigCheck(env) {
44
149
  const provider = envText(env, "QLING_LLM_PROVIDER") || "unset";
45
150
  const model = envText(env, "QLING_LLM_MODEL") || "unset";
@@ -82,6 +187,9 @@ async function buildSecretsCheck() {
82
187
  function buildRecommendations(checks) {
83
188
  const recommendations = [];
84
189
  const byId = new Map(checks.map((check) => [check.id, check]));
190
+ if (byId.get("phase5_verifier_stages")?.status === "warn") {
191
+ recommendations.push("- 写操作恢复验证:`/verify set \"npm test\"` 或设置 `QLING_VERIFY_TYPECHECK_CMD` / `QLING_VERIFY_TEST_CMD`。");
192
+ }
85
193
  if (byId.get("config")?.status === "warn") {
86
194
  const text = getLocalizedText();
87
195
  recommendations.push("- 新用户优先运行 `qling bootstrap` 完成本机初始化检查。");
@@ -305,6 +413,14 @@ export async function buildDoctorReport(context, options = {}) {
305
413
  status: ollama.ok ? "pass" : "warn",
306
414
  detail: ollama.detail,
307
415
  },
416
+ ...buildPhase3FeatureChecks(env),
417
+ ...buildPhase5FeatureChecks(env, {
418
+ exists,
419
+ stateDir,
420
+ verificationStagesSummary: typeof context.agentLoop?.getVerificationStagesSummary === "function"
421
+ ? context.agentLoop.getVerificationStagesSummary()
422
+ : undefined,
423
+ }),
308
424
  ];
309
425
  return {
310
426
  checks,
@@ -0,0 +1,5 @@
1
+ import type { EvalTask } from "./types.js";
2
+ export declare function resolveChatCompletionsUrl(endpoint: string): string;
3
+ export declare function isExactQok(content: string): boolean;
4
+ export declare function buildEvalLlmTasks(): EvalTask[];
5
+ //# sourceMappingURL=llm-tasks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-tasks.d.ts","sourceRoot":"","sources":["../../src/eval/llm-tasks.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAmB,MAAM,YAAY,CAAC;AA6B5D,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKlE;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED,wBAAgB,iBAAiB,IAAI,QAAQ,EAAE,CAgF9C"}
@@ -0,0 +1,125 @@
1
+ // ============================================================
2
+ // Phase 4.1 — 可选 LLM 评测任务(默认 skip,不进 ci:check)
3
+ // 启用:QLING_EVAL_LLM=1 且具备 API key
4
+ // ============================================================
5
+ import axios from "axios";
6
+ function resolveApiKey(env) {
7
+ return (env.QLING_LLM_API_KEY ||
8
+ env.DEEPSEEK_API_KEY ||
9
+ env.OPENAI_API_KEY ||
10
+ "").trim();
11
+ }
12
+ function llmEvalEnabled(env) {
13
+ const raw = String(env.QLING_EVAL_LLM ?? "").trim().toLowerCase();
14
+ return raw === "1" || raw === "true" || raw === "on" || raw === "yes";
15
+ }
16
+ function resolveEndpoint(env) {
17
+ return (env.QLING_LLM_ENDPOINT ||
18
+ env.OPENAI_BASE_URL ||
19
+ env.DEEPSEEK_BASE_URL ||
20
+ "https://api.deepseek.com").replace(/\/$/, "");
21
+ }
22
+ function resolveModel(env) {
23
+ return env.QLING_LLM_MODEL || "deepseek-chat";
24
+ }
25
+ export function resolveChatCompletionsUrl(endpoint) {
26
+ const normalized = endpoint.replace(/\/+$/, "");
27
+ if (/\/chat\/completions$/i.test(normalized))
28
+ return normalized;
29
+ if (/\/v1$/i.test(normalized))
30
+ return `${normalized}/chat/completions`;
31
+ return `${normalized}/v1/chat/completions`;
32
+ }
33
+ export function isExactQok(content) {
34
+ return content.trim().toLowerCase() === "qok";
35
+ }
36
+ export function buildEvalLlmTasks() {
37
+ return [
38
+ {
39
+ id: "llm-gate-enabled",
40
+ title: "LLM eval 开关与密钥门禁",
41
+ run: async ({ env }) => {
42
+ if (!llmEvalEnabled(env)) {
43
+ return {
44
+ ok: true,
45
+ skip: true,
46
+ detail: "QLING_EVAL_LLM 未开启;跳过真实 LLM 评测",
47
+ };
48
+ }
49
+ if (!resolveApiKey(env)) {
50
+ return {
51
+ ok: true,
52
+ skip: true,
53
+ detail: "无 API key(QLING_LLM_API_KEY / DEEPSEEK_API_KEY / OPENAI_API_KEY)",
54
+ };
55
+ }
56
+ return {
57
+ ok: true,
58
+ detail: `enabled model=${resolveModel(env)} endpoint=${resolveEndpoint(env)}`,
59
+ };
60
+ },
61
+ },
62
+ {
63
+ id: "llm-chat-connectivity",
64
+ title: "LLM chat 连通性(固定短语)",
65
+ run: async (ctx) => {
66
+ const gate = await gateOrSkip(ctx);
67
+ if (gate)
68
+ return gate;
69
+ const env = ctx.env;
70
+ const apiKey = resolveApiKey(env);
71
+ const endpoint = resolveEndpoint(env);
72
+ const model = resolveModel(env);
73
+ const url = resolveChatCompletionsUrl(endpoint);
74
+ try {
75
+ const resp = await axios.post(url, {
76
+ model,
77
+ messages: [
78
+ {
79
+ role: "user",
80
+ content: 'Reply with exactly the three letters QOK and nothing else. No punctuation.',
81
+ },
82
+ ],
83
+ max_tokens: 16,
84
+ temperature: 0,
85
+ }, {
86
+ headers: {
87
+ Authorization: `Bearer ${apiKey}`,
88
+ "Content-Type": "application/json",
89
+ },
90
+ timeout: 45_000,
91
+ });
92
+ const content = String(resp.data?.choices?.[0]?.message?.content ?? "").trim();
93
+ const ok = isExactQok(content);
94
+ return {
95
+ ok,
96
+ detail: `model=${model} reply=${JSON.stringify(content).slice(0, 120)}`,
97
+ };
98
+ }
99
+ catch (err) {
100
+ return {
101
+ ok: false,
102
+ detail: err instanceof Error ? err.message : String(err),
103
+ };
104
+ }
105
+ },
106
+ },
107
+ ];
108
+ }
109
+ async function gateOrSkip(ctx) {
110
+ if (!llmEvalEnabled(ctx.env)) {
111
+ return {
112
+ ok: true,
113
+ skip: true,
114
+ detail: "QLING_EVAL_LLM 未开启",
115
+ };
116
+ }
117
+ if (!resolveApiKey(ctx.env)) {
118
+ return {
119
+ ok: true,
120
+ skip: true,
121
+ detail: "missing API key",
122
+ };
123
+ }
124
+ return null;
125
+ }
@@ -0,0 +1,12 @@
1
+ import type { EvalTask } from "./types.js";
2
+ /**
3
+ * 10 个本地 fixture:每个任务自带 broken 状态 + 确定性修复步骤。
4
+ * 不调用外部 LLM;用于回归「编码工作台」基础能力与验收脚本。
5
+ */
6
+ export declare function buildEvalRepoTasks(): EvalTask[];
7
+ /** 仅 materialize fixture,不自动修复(供可选 LLM / 人工评测) */
8
+ export declare function materializeBrokenFixture(workspaceDir: string, fixtureId: string): Promise<{
9
+ root: string;
10
+ prompt: string;
11
+ } | null>;
12
+ //# sourceMappingURL=repo-tasks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo-tasks.d.ts","sourceRoot":"","sources":["../../src/eval/repo-tasks.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAoC,MAAM,YAAY,CAAC;AAiC7E;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,QAAQ,EAAE,CAwO/C;AAED,kDAAkD;AAClD,wBAAsB,wBAAwB,CAC5C,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAwBlD"}