@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
@@ -0,0 +1,275 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Phase 4.4 — 扫描 src 相对 import,输出分层依赖边(供架构文档/CI 门禁)
4
+ * Usage: node scripts/dep-layers.mjs [--json] [--strict]
5
+ *
6
+ * --strict: 若发现禁止的反向依赖边,exit 1
7
+ */
8
+ import { readdir, readFile, mkdir, writeFile } from "fs/promises";
9
+ import { join, relative, dirname, extname, resolve } from "path";
10
+ import { fileURLToPath } from "url";
11
+ import { existsSync } from "fs";
12
+
13
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
+ const ROOT = resolve(__dirname, "..");
15
+ const SRC = join(ROOT, "src");
16
+
17
+ /** @typedef {'foundation'|'core-services'|'domain'|'agent-runtime'|'adapters'|'presentation'|'cli'|'other'} Layer */
18
+
19
+ /**
20
+ * @param {string} rel posix path under src/
21
+ * @returns {Layer}
22
+ */
23
+ export function layerOf(rel) {
24
+ const p = rel.replace(/\\/g, "/");
25
+ if (
26
+ p === "types.ts" ||
27
+ p === "config.ts" ||
28
+ p === "runtime-paths.ts" ||
29
+ p === "token-usage.ts" ||
30
+ p === "package-version.ts" ||
31
+ p === "output-style.ts" ||
32
+ p.startsWith("utils/") ||
33
+ p.startsWith("i18n/") ||
34
+ p.startsWith("providers/")
35
+ ) {
36
+ return "foundation";
37
+ }
38
+ if (
39
+ p.startsWith("pipeline/") ||
40
+ p.startsWith("guard/") ||
41
+ p === "guard.ts" ||
42
+ p.startsWith("lsp/") ||
43
+ p === "context-compactor.ts" ||
44
+ p === "context-tool-hygiene.ts" ||
45
+ p.startsWith("git/")
46
+ ) {
47
+ return "core-services";
48
+ }
49
+ if (
50
+ p.startsWith("memory/") ||
51
+ p === "memory.ts" ||
52
+ p.startsWith("session/") ||
53
+ p.startsWith("mission/") ||
54
+ p.startsWith("mcp/") ||
55
+ p.startsWith("channels/") ||
56
+ p.startsWith("skills/") ||
57
+ p.startsWith("metrics/") ||
58
+ p.startsWith("agents/") ||
59
+ p.startsWith("onboarding/") ||
60
+ p.startsWith("workflow-") ||
61
+ p === "discovery-registry.ts" ||
62
+ p === "discovery-types.ts" ||
63
+ p === "knowledge-agent.ts"
64
+ ) {
65
+ return "domain";
66
+ }
67
+ if (
68
+ p === "agent-loop.ts" ||
69
+ p.startsWith("agent/") ||
70
+ p.startsWith("tools/") ||
71
+ p === "repl.ts"
72
+ ) {
73
+ return "agent-runtime";
74
+ }
75
+ if (
76
+ p === "sdk.ts" ||
77
+ p === "daemon.ts" ||
78
+ p === "dashboard-server.ts" ||
79
+ p.endsWith("-report.ts") ||
80
+ p === "doctor.ts" ||
81
+ p === "statusline.ts" ||
82
+ p === "shortcuts.ts" ||
83
+ p === "help-topics.ts" ||
84
+ p === "recap.ts" ||
85
+ p.startsWith("session-") ||
86
+ p.startsWith("local-") ||
87
+ p.startsWith("eval/")
88
+ ) {
89
+ return "adapters";
90
+ }
91
+ if (p.startsWith("tui/")) return "presentation";
92
+ if (p === "index.ts" || p.startsWith("cli/") || p.startsWith("commands/")) {
93
+ return "cli";
94
+ }
95
+ return "other";
96
+ }
97
+
98
+ /** 允许的依赖方向:上层 → 下层(数字越小越底层) */
99
+ export const LAYER_RANK = {
100
+ foundation: 0,
101
+ "core-services": 1,
102
+ domain: 2,
103
+ "agent-runtime": 3,
104
+ adapters: 4,
105
+ presentation: 5,
106
+ cli: 6,
107
+ other: 3,
108
+ };
109
+
110
+ /**
111
+ * 禁止的边:下层依赖上层
112
+ * @param {Layer} from
113
+ * @param {Layer} to
114
+ */
115
+ export function isForbiddenEdge(from, to) {
116
+ if (from === to) return false;
117
+ const a = LAYER_RANK[from] ?? 99;
118
+ const b = LAYER_RANK[to] ?? 99;
119
+ // 允许同层外:from 只能依赖 rank <= from 的层(含向下)
120
+ // 禁止:from.rank < to.rank(下层依赖上层)—— 不对:
121
+ // foundation rank 0 依赖 cli rank 6 是禁止的 (0 < 6 且 from is lower)
122
+ // cli 依赖 foundation: 6 > 0 OK
123
+ // foundation 依赖 cli: 0 < 6 FORBIDDEN
124
+ return a < b;
125
+ }
126
+
127
+ async function walk(dir, acc = []) {
128
+ for (const e of await readdir(dir, { withFileTypes: true })) {
129
+ const p = join(dir, e.name);
130
+ if (e.isDirectory()) await walk(p, acc);
131
+ else if (e.isFile() && extname(e.name) === ".ts") acc.push(p);
132
+ }
133
+ return acc;
134
+ }
135
+
136
+ function resolveImport(fromFile, spec) {
137
+ let target = resolve(dirname(fromFile), spec);
138
+ target = target.replace(/\\/g, "/");
139
+ if (target.endsWith(".js")) target = target.slice(0, -3) + ".ts";
140
+ else if (!target.endsWith(".ts")) {
141
+ // bare directory index not common; try .ts
142
+ if (existsSync(target + ".ts")) target = target + ".ts";
143
+ else if (existsSync(join(target, "index.ts"))) target = join(target, "index.ts");
144
+ else target = target + ".ts";
145
+ }
146
+ return target;
147
+ }
148
+
149
+ export async function scanLayers() {
150
+ const files = await walk(SRC);
151
+ /** @type {Map<string, number>} */
152
+ const edgeCounts = new Map();
153
+ /** @type {Array<{from:string,to:string,fromLayer:string,toLayer:string}>} */
154
+ const forbidden = [];
155
+ /** @type {Record<string, number>} */
156
+ const layerCounts = {};
157
+
158
+ for (const f of files) {
159
+ const rel = relative(SRC, f).replace(/\\/g, "/");
160
+ const fromL = layerOf(rel);
161
+ layerCounts[fromL] = (layerCounts[fromL] || 0) + 1;
162
+ const text = await readFile(f, "utf8");
163
+ const re = /from\s+['"](\.[^'"]+)['"]/g;
164
+ let m;
165
+ while ((m = re.exec(text))) {
166
+ const targetAbs = resolveImport(f, m[1]);
167
+ const tRel = relative(SRC, targetAbs).replace(/\\/g, "/");
168
+ if (tRel.startsWith("..")) continue;
169
+ if (!tRel.endsWith(".ts") && !existsSync(join(SRC, tRel))) continue;
170
+ const toL = layerOf(tRel);
171
+ if (fromL === toL) continue;
172
+ const key = `${fromL}->${toL}`;
173
+ edgeCounts.set(key, (edgeCounts.get(key) || 0) + 1);
174
+ if (isForbiddenEdge(fromL, toL)) {
175
+ forbidden.push({
176
+ from: rel,
177
+ to: tRel,
178
+ fromLayer: fromL,
179
+ toLayer: toL,
180
+ });
181
+ }
182
+ }
183
+ }
184
+
185
+ return {
186
+ fileCount: files.length,
187
+ layerCounts,
188
+ edges: [...edgeCounts.entries()]
189
+ .map(([edge, count]) => ({ edge, count }))
190
+ .sort((a, b) => b.count - a.count),
191
+ forbidden: forbidden.slice(0, 200),
192
+ forbiddenCount: forbidden.length,
193
+ };
194
+ }
195
+
196
+ function formatMermaid(layerCounts, edges) {
197
+ const lines = ["```mermaid", "flowchart TB"];
198
+ const order = [
199
+ "foundation",
200
+ "core-services",
201
+ "domain",
202
+ "agent-runtime",
203
+ "adapters",
204
+ "presentation",
205
+ "cli",
206
+ "other",
207
+ ];
208
+ for (const l of order) {
209
+ if (layerCounts[l]) {
210
+ lines.push(` ${l.replace(/-/g, "_")}["${l} (${layerCounts[l]})"]`);
211
+ }
212
+ }
213
+ // unique edges for diagram (not forbidden only — all)
214
+ const seen = new Set();
215
+ for (const { edge } of edges) {
216
+ const [a, b] = edge.split("->");
217
+ const id = `${a}->${b}`;
218
+ if (seen.has(id)) continue;
219
+ seen.add(id);
220
+ const fa = a.replace(/-/g, "_");
221
+ const fb = b.replace(/-/g, "_");
222
+ const bad = isForbiddenEdge(/** @type {any} */ (a), /** @type {any} */ (b));
223
+ lines.push(` ${fa} ${bad ? "-.->|forbidden|" : "-->"} ${fb}`);
224
+ }
225
+ lines.push("```");
226
+ return lines.join("\n");
227
+ }
228
+
229
+ const asJson = process.argv.includes("--json");
230
+ const strict = process.argv.includes("--strict");
231
+ const writeDoc = process.argv.includes("--write-doc");
232
+
233
+ const result = await scanLayers();
234
+
235
+ if (asJson) {
236
+ process.stdout.write(JSON.stringify(result, null, 2) + "\n");
237
+ } else {
238
+ console.log(`src files: ${result.fileCount}`);
239
+ console.log("layer counts:", result.layerCounts);
240
+ console.log("cross-layer edges:");
241
+ for (const e of result.edges) console.log(` ${e.count}\t${e.edge}`);
242
+ console.log(`forbidden reverse edges: ${result.forbiddenCount}`);
243
+ if (result.forbiddenCount > 0) {
244
+ console.log("sample forbidden (up to 15):");
245
+ for (const f of result.forbidden.slice(0, 15)) {
246
+ console.log(` ${f.fromLayer} -> ${f.toLayer}: ${f.from} imports ${f.to}`);
247
+ }
248
+ }
249
+ console.log("\n" + formatMermaid(result.layerCounts, result.edges));
250
+ }
251
+
252
+ if (writeDoc) {
253
+ const outDir = join(ROOT, "docs");
254
+ await mkdir(outDir, { recursive: true });
255
+ // doc written by separate architecture file; optional snapshot
256
+ const snap = join(outDir, "dependency-layers.snapshot.json");
257
+ await writeFile(
258
+ snap,
259
+ JSON.stringify(
260
+ {
261
+ generatedAt: new Date().toISOString(),
262
+ ...result,
263
+ forbidden: result.forbidden.slice(0, 50),
264
+ },
265
+ null,
266
+ 2
267
+ ),
268
+ "utf8"
269
+ );
270
+ console.error(`[dep-layers] wrote ${snap}`);
271
+ }
272
+
273
+ if (strict && result.forbiddenCount > 0) {
274
+ process.exit(1);
275
+ }
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 可选 LLM 评测:默认 skip,不进入 ci:check
4
+ * Usage:
5
+ * QLING_EVAL_LLM=1 DEEPSEEK_API_KEY=... node scripts/eval-llm.mjs
6
+ * npm run eval:llm
7
+ */
8
+ import {
9
+ runEvalSuite,
10
+ formatEvalReport,
11
+ evalReportToJson,
12
+ } from "../dist/eval/runner.js";
13
+ import { buildEvalLlmTasks } from "../dist/eval/llm-tasks.js";
14
+
15
+ const asJson = process.argv.includes("--json");
16
+ const report = await runEvalSuite({ tasks: buildEvalLlmTasks() });
17
+
18
+ if (asJson) {
19
+ process.stdout.write(evalReportToJson(report) + "\n");
20
+ } else {
21
+ process.stdout.write(
22
+ formatEvalReport(report, { title: "🧪 Qling eval:llm (optional)" }).join("\n") + "\n"
23
+ );
24
+ }
25
+
26
+ // skip 全部视为成功;仅 fail 导致非 0
27
+ process.exit(report.fail === 0 ? 0 : 1);
@@ -0,0 +1,101 @@
1
+ import assert from "node:assert/strict";
2
+ import { classifyFailure } from "../dist/execution/failure-classifier.js";
3
+ import { RecoveryController } from "../dist/execution/recovery-controller.js";
4
+ import { RecoveryStrategyPlanner } from "../dist/execution/recovery-strategy-planner.js";
5
+ import { calculateRecoveryMetrics } from "../dist/execution/recovery-metrics.js";
6
+
7
+ const fixtures = [
8
+ [Object.assign(new Error("rate limited"), { status: 429 }), "provider_transient"],
9
+ [new Error("approval_required"), "permission_required"],
10
+ [new Error("sandbox denied outside workspace"), "sandbox_denied"],
11
+ [new Error("command not found"), "tool_not_found"],
12
+ [new Error("maximum context length exhausted"), "context_exhausted"],
13
+ [new Error("permission denied"), "permission_denied"],
14
+ [new Error("duplicate tool call repeated action"), "repeated_action"],
15
+ [new Error("invalid tool arguments: missing required field"), "invalid_tool_arguments"],
16
+ [new Error("verification command exited with code 1"), "verification_failed"],
17
+ ];
18
+
19
+ for (const [error, expected] of fixtures) {
20
+ assert.equal(classifyFailure(error).category, expected);
21
+ }
22
+
23
+ // Same fingerprint without progress -> pause
24
+ const controller = new RecoveryController();
25
+ controller.startRun({ runId: "eval_run", sessionId: "eval_session", originalTask: "deterministic fixture" });
26
+ const failure = { category: "verification_failed", message: "tests failed", fingerprint: "same" };
27
+ assert.equal(controller.recordFailure(failure, { diffHash: "a", failingTests: ["one"] }).action, "recover");
28
+ assert.equal(controller.recordFailure(failure, { diffHash: "a", failingTests: ["one"] }).action, "pause");
29
+
30
+ // Progress between same fingerprint failures still allows recover with next strategy
31
+ const improved = new RecoveryController();
32
+ improved.startRun({ runId: "eval_improved", sessionId: "eval_session", originalTask: "deterministic fixture" });
33
+ assert.equal(improved.recordFailure(
34
+ { category: "verification_failed", message: "tests failed", fingerprint: "improved" },
35
+ { diffHash: "a", failingTests: ["one", "two"] }
36
+ ).recommendedStrategy, "targeted_verification_repair");
37
+ assert.equal(improved.recordFailure(
38
+ { category: "verification_failed", message: "tests failed", fingerprint: "improved" },
39
+ { diffHash: "b", failingTests: ["two"] }
40
+ ).recommendedStrategy, "narrow_verification_scope");
41
+
42
+ // Hard-stop categories pause immediately
43
+ const stopped = new RecoveryController();
44
+ stopped.startRun({ runId: "eval_stopped", sessionId: "eval_session", originalTask: "deterministic fixture" });
45
+ assert.equal(stopped.recordFailure(
46
+ { category: "sandbox_denied", message: "outside workspace", fingerprint: "sandbox" },
47
+ {}
48
+ ).action, "pause");
49
+ assert.equal(stopped.recordFailure(
50
+ { category: "permission_required", message: "approval_required", fingerprint: "approval" },
51
+ {}
52
+ ).action, "pause");
53
+
54
+ // Context compaction strategy is single-use
55
+ const ctx = new RecoveryController();
56
+ ctx.startRun({ runId: "eval_ctx", sessionId: "eval_session", originalTask: "deterministic fixture" });
57
+ assert.equal(ctx.recordFailure(
58
+ { category: "context_exhausted", message: "context exhausted", fingerprint: "ctx" },
59
+ {}
60
+ ).recommendedStrategy, "compact_context_once");
61
+ assert.equal(ctx.recordFailure(
62
+ { category: "context_exhausted", message: "context exhausted", fingerprint: "ctx2" },
63
+ { changed: true }
64
+ ).reason, "no_recovery_strategy");
65
+
66
+ // User next strategy after pause
67
+ const planner = new RecoveryStrategyPlanner();
68
+ assert.deepEqual(planner.list("invalid_tool_arguments"), [
69
+ "repair_tool_arguments",
70
+ "return_tool_schema",
71
+ ]);
72
+ const args = new RecoveryController({ planner });
73
+ args.startRun({ runId: "eval_args", sessionId: "eval_session", originalTask: "deterministic fixture" });
74
+ args.recordFailure(
75
+ { category: "invalid_tool_arguments", message: "invalid arguments", fingerprint: "args" },
76
+ {}
77
+ );
78
+ args.recordFailure(
79
+ { category: "invalid_tool_arguments", message: "invalid arguments", fingerprint: "args" },
80
+ {}
81
+ );
82
+ assert.equal(args.getRecoveryState().status, "paused");
83
+ assert.equal(args.applyAction("next").currentStrategy, "return_tool_schema");
84
+ assert.equal(args.applyAction("cancel").status, "canceled");
85
+
86
+ // Trajectory replay metrics from redacted JSONL-like events (no prompt/tool body)
87
+ const metrics = calculateRecoveryMetrics([
88
+ { eventId: "e1", runId: "eval_improved", type: "attempt_completed", status: "failed", timestamp: 1 },
89
+ { eventId: "e2", runId: "eval_improved", type: "recovery_started", status: "recovering", timestamp: 2, recoveryAction: "targeted_verification_repair" },
90
+ { eventId: "e3", runId: "eval_improved", type: "attempt_completed", status: "succeeded", timestamp: 3 },
91
+ { eventId: "e4", runId: "eval_improved", type: "run_completed", status: "succeeded", timestamp: 4 },
92
+ ]);
93
+ assert.equal(metrics.finalSuccessRate, 1);
94
+ assert.ok(metrics.automaticRecoverySuccessRate >= 0);
95
+
96
+ console.log(JSON.stringify({
97
+ ok: true,
98
+ fixtures: fixtures.length + 6,
99
+ metrics,
100
+ mode: "deterministic-no-model",
101
+ }));
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 本地 repo fixture 评测(不依赖外部 LLM / API key)
4
+ * Usage: node scripts/eval-tasks.mjs [--json]
5
+ */
6
+ import { runEvalSuite, formatEvalReport, evalReportToJson } from "../dist/eval/runner.js";
7
+ import { buildEvalRepoTasks } from "../dist/eval/repo-tasks.js";
8
+
9
+ const asJson = process.argv.includes("--json");
10
+
11
+ const report = await runEvalSuite({ tasks: buildEvalRepoTasks() });
12
+ if (asJson) {
13
+ process.stdout.write(evalReportToJson(report) + "\n");
14
+ } else {
15
+ process.stdout.write(
16
+ formatEvalReport(report, { title: "🧪 Qling eval:tasks (repo fixtures)" }).join("\n") + "\n"
17
+ );
18
+ }
19
+
20
+ process.exit(report.fail === 0 ? 0 : 1);
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Validate Scoop / winget draft manifests align with package.json version.
4
+ * Usage: node scripts/validate-packaging.mjs
5
+ */
6
+ import { readFile } from "node:fs/promises";
7
+ import { join, dirname } from "node:path";
8
+ import { fileURLToPath } from "node:url";
9
+
10
+ const root = join(dirname(fileURLToPath(import.meta.url)), "..");
11
+ const errors = [];
12
+
13
+ const pkg = JSON.parse(await readFile(join(root, "package.json"), "utf8"));
14
+ const version = pkg.version;
15
+
16
+ const scoopRaw = await readFile(join(root, "packaging", "scoop", "qling.json"), "utf8");
17
+ const scoop = JSON.parse(scoopRaw);
18
+ if (scoop.version !== version) {
19
+ errors.push(`scoop version ${scoop.version} != package ${version}`);
20
+ }
21
+ if (!String(scoop.url || "").includes(version)) {
22
+ errors.push(`scoop url does not pin ${version}: ${scoop.url}`);
23
+ }
24
+ if (!Array.isArray(scoop.notes) || !scoop.notes.some((n) => /DRAFT|draft/i.test(n))) {
25
+ errors.push("scoop notes should mark DRAFT status");
26
+ }
27
+
28
+ const winget = await readFile(
29
+ join(root, "packaging", "winget", "Zzy-min.qling.yaml"),
30
+ "utf8"
31
+ );
32
+ if (!winget.includes(`PackageVersion: ${version}`)) {
33
+ errors.push(`winget PackageVersion missing ${version}`);
34
+ }
35
+ if (!winget.includes("PackageIdentifier: Zzy-min.qling")) {
36
+ errors.push("winget PackageIdentifier missing");
37
+ }
38
+ if (!/DRAFT|not submitted/i.test(winget)) {
39
+ errors.push("winget should remain marked as DRAFT");
40
+ }
41
+
42
+ if (errors.length) {
43
+ console.error("validate-packaging FAILED:");
44
+ for (const e of errors) console.error(" -", e);
45
+ process.exit(1);
46
+ }
47
+
48
+ console.log(`validate-packaging OK (version ${version})`);
49
+ console.log(" scoop:", scoop.url);
50
+ console.log(" winget: Zzy-min.qling @", version);
51
+ console.log(" note: still drafts — not published to official catalogs");
@@ -0,0 +1,23 @@
1
+ # Example skills pack
2
+
3
+ Bundled under `skills/examples/` and discovered by Qling's progressive skill loader.
4
+
5
+ | Skill | Purpose |
6
+ |-------|---------|
7
+ | `repo-triage` | Map an unfamiliar repository quickly |
8
+ | `fix-failing-test` | Reproduce, patch, and re-verify a red test |
9
+ | `add-function` | Add an exported function with minimal diff |
10
+ | `pr-summary` | Draft PR / release notes from git history |
11
+
12
+ ## Usage
13
+
14
+ ```text
15
+ /skill list
16
+ /skill fix-failing-test
17
+ /skill add-function
18
+ /skill pr-summary
19
+ ```
20
+
21
+ Copy the template at `skills/templates/SKILL.md` to create your own under `~/.qling/skills/` or the project `skills/` directory.
22
+
23
+ See [docs/skills.md](../../docs/skills.md).
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: add-function
3
+ description: 在现有模块中增量添加导出函数:对齐风格、补调用点、补测试
4
+ tags: [example, coding, refactor]
5
+ triggers: [加函数, add function, export, 新增 API]
6
+ ---
7
+
8
+ # Add Function
9
+
10
+ ## 何时使用
11
+
12
+ 用户要求「加一个函数」「导出 xxx」「补一个工具方法」时加载。
13
+
14
+ ## 步骤
15
+
16
+ 1. **读现有模块** — 风格、命名、错误处理、导入习惯
17
+ 2. **设计签名** — 参数/返回值/边界;与相邻 API 一致
18
+ 3. **实现** — `patch` 或 `write` 最小增量
19
+ 4. **调用点** — 若用户给了使用场景,同步更新调用处
20
+ 5. **测试** — 能测则加/改测试;不能测则给手动验证步骤
21
+
22
+ ## 约束
23
+
24
+ - 不引入新依赖,除非用户同意
25
+ - 不顺手大重构
26
+ - 公开 API 变更要在回复里写清楚
27
+
28
+ ## 验收
29
+
30
+ - [ ] 新符号可 import / 可调用
31
+ - [ ] 有验证命令或测试
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: fix-failing-test
3
+ description: 定位并修复失败的单元测试:读错误、最小改动、再跑验证
4
+ tags: [example, testing, coding]
5
+ triggers: [修测试, failing test, unit test, 红灯, assert]
6
+ ---
7
+
8
+ # Fix Failing Test
9
+
10
+ ## 何时使用
11
+
12
+ 用户说「测试挂了」「帮我修这个 unit test」「红了」时加载。
13
+
14
+ ## 步骤
15
+
16
+ 1. **复现** — 用 `bash` 跑失败命令(`npm test` / `node --test path`),保存完整错误
17
+ 2. **定位** — `read` 失败文件与被测实现;`search` 相关符号
18
+ 3. **假设** — 区分「断言错了」vs「实现错了」vs「环境/路径」
19
+ 4. **最小修复** — `patch` 只改必要行;避免无关重构
20
+ 5. **验证** — 再跑同一命令;必要时补一条窄测试
21
+
22
+ ## 约束
23
+
24
+ - 不要为了让测试变绿而删除断言(除非用户明确要求)
25
+ - 不要改 `.env` / 密钥文件
26
+ - Plan Mode 下只输出计划
27
+
28
+ ## 验收
29
+
30
+ - [ ] 失败命令现已通过
31
+ - [ ] diff 可读、范围小
32
+ - [ ] 说明根因一句话
@@ -0,0 +1,34 @@
1
+ ---
2
+ name: pr-summary
3
+ description: 根据 git diff / 最近提交写中英 PR 摘要与测试计划
4
+ tags: [example, git, docs, shipping]
5
+ triggers: [PR 摘要, pull request, changelog, 发布说明]
6
+ ---
7
+
8
+ # PR Summary
9
+
10
+ ## 何时使用
11
+
12
+ 用户要「写 PR 描述」「总结这次改动」「release notes」时加载。
13
+
14
+ ## 步骤
15
+
16
+ 1. `bash`:`git status` / `git log --oneline -15` / `git diff`(或 `git diff main...HEAD`)
17
+ 2. 按 **Why / What / How to test** 组织
18
+ 3. 标出 breaking change / 迁移注意(若有)
19
+ 4. 中文主描述 + 可选英文一节
20
+
21
+ ## 输出模板
22
+
23
+ ```markdown
24
+ ## Summary
25
+ - …
26
+
27
+ ## Test plan
28
+ - [ ] …
29
+ ```
30
+
31
+ ## 约束
32
+
33
+ - 不编造未出现的文件或测试结果
34
+ - 密钥/token 不得写入摘要
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: lifecycle-build
3
+ description: 按计划增量实现:小步修改、每步可验证。触发:开始写代码、实现功能。
4
+ tags: [lifecycle, build, implement]
5
+ triggers: [实现, 编码, 写代码, /build]
6
+ ---
7
+
8
+ # 生命周期 · 实现(Build)
9
+
10
+ ## 步骤
11
+
12
+ 1. 只实现 **当前计划中的下一步**,不偷跑范围外需求。
13
+ 2. 优先 `read` / `search` 理解现有模式,再 `patch`/`write`。
14
+ 3. 每完成一步:跑最小相关测试或命令;失败先修再前进。
15
+ 4. 保持 diff 小而可读;大文件用 patch。
16
+ 5. 进度用 todo 标记;中断可 checkpoint。
17
+
18
+ ## 不要
19
+
20
+ - 不要无读就大范围改。
21
+ - 不要静默吞掉测试失败。
22
+ - 不要在 Plan Mode 下写文件(先 `/plan off`)。
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: lifecycle-plan
3
+ description: 把已确认规格拆成小而可验证的实现任务。触发:已有 Spec、要排期、/plan。
4
+ tags: [lifecycle, plan]
5
+ triggers: [实施计划, 任务拆分, 排期, /plan]
6
+ ---
7
+
8
+ # 生命周期 · 计划(Plan)
9
+
10
+ ## 步骤
11
+
12
+ 1. 重述 Spec 中的验收标准(不得改写成功定义)。
13
+ 2. 拆成 **原子任务**(每步可独立验证,通常 15–45 分钟量级)。
14
+ 3. 标注依赖顺序与可并行只读探索。
15
+ 4. 标明将触碰的文件路径(估计即可)。
16
+ 5. 写出 **测试计划**:先写什么测、如何证明完成。
17
+ 6. 风险与回滚点。
18
+
19
+ ## 输出格式
20
+
21
+ ```markdown
22
+ ## Plan
23
+ 1. [ ] 任务… — 文件… — 验证…
24
+ 2. [ ] …
25
+ ## 风险
26
+ - …
27
+ ```
28
+
29
+ ## 不要
30
+
31
+ - 不要跳过测试步骤。
32
+ - 不要一次计划「重写整个仓库」。
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: lifecycle-review
3
+ description: 合并前代码健康检查:正确性、安全、可维护性。触发:准备提交、CR、/review。
4
+ tags: [lifecycle, review, quality]
5
+ triggers: [代码审查, review, 合并前, /review]
6
+ ---
7
+
8
+ # 生命周期 · 审查(Review)
9
+
10
+ ## 五轴快速检查
11
+
12
+ 1. **正确性**:是否满足 Spec 验收?边界?
13
+ 2. **安全**:密钥、注入、路径穿越、危险 bash?
14
+ 3. **可维护性**:命名、重复、文件是否过大?
15
+ 4. **可观测/错误**:失败是否诚实、是否吞异常?
16
+ 5. **测试**:关键路径是否有证据?
17
+
18
+ ## 输出
19
+
20
+ - CRITICAL / HIGH / MEDIUM / LOW 列表 + 建议修复顺序。
21
+ - 无问题也写「已核对验收条款」。
22
+
23
+ ## 不要
24
+
25
+ - 不要只夸「看起来不错」而无检查清单。