@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.
- package/CHANGELOG.md +158 -0
- package/README.en.md +83 -18
- package/README.md +19 -9
- package/dist/agent/main-loop.d.ts +120 -0
- package/dist/agent/main-loop.d.ts.map +1 -0
- package/dist/agent/main-loop.js +279 -0
- package/dist/agent/subtask-parallel.d.ts +29 -0
- package/dist/agent/subtask-parallel.d.ts.map +1 -0
- package/dist/agent/subtask-parallel.js +107 -0
- package/dist/agent/subtask.d.ts +13 -0
- package/dist/agent/subtask.d.ts.map +1 -1
- package/dist/agent/subtask.js +79 -24
- package/dist/agent/system-prompt.d.ts +39 -0
- package/dist/agent/system-prompt.d.ts.map +1 -0
- package/dist/agent/system-prompt.js +89 -0
- package/dist/agent/tool-orchestrator.d.ts +66 -0
- package/dist/agent/tool-orchestrator.d.ts.map +1 -0
- package/dist/agent/tool-orchestrator.js +355 -0
- package/dist/agent-loop.d.ts +29 -16
- package/dist/agent-loop.d.ts.map +1 -1
- package/dist/agent-loop.js +262 -807
- package/dist/agents/roles.d.ts +57 -0
- package/dist/agents/roles.d.ts.map +1 -0
- package/dist/agents/roles.js +198 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +17 -3
- package/dist/commands/claude-style.d.ts.map +1 -1
- package/dist/commands/claude-style.js +19 -10
- package/dist/commands/help.d.ts.map +1 -1
- package/dist/commands/help.js +3 -2
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +6 -0
- package/dist/commands/mode.d.ts +16 -0
- package/dist/commands/mode.d.ts.map +1 -0
- package/dist/commands/mode.js +67 -0
- package/dist/commands/recover.d.ts +3 -0
- package/dist/commands/recover.d.ts.map +1 -0
- package/dist/commands/recover.js +69 -0
- package/dist/commands/runtime.d.ts +2 -0
- package/dist/commands/runtime.d.ts.map +1 -1
- package/dist/commands/runtime.js +2 -0
- package/dist/commands/trace.d.ts +3 -0
- package/dist/commands/trace.d.ts.map +1 -0
- package/dist/commands/trace.js +45 -0
- package/dist/commands/verify.js +2 -2
- package/dist/config-report.d.ts +0 -1
- package/dist/config-report.d.ts.map +1 -1
- package/dist/config-report.js +1 -2
- package/dist/config.d.ts +0 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -1
- package/dist/context-report.d.ts +13 -7
- package/dist/context-report.d.ts.map +1 -1
- package/dist/context-report.js +64 -61
- package/dist/context-tool-hygiene.d.ts +36 -0
- package/dist/context-tool-hygiene.d.ts.map +1 -0
- package/dist/context-tool-hygiene.js +125 -0
- package/dist/dashboard/client.d.ts +2 -0
- package/dist/dashboard/client.d.ts.map +1 -0
- package/dist/dashboard/client.js +305 -0
- package/dist/dashboard/model.d.ts +13 -0
- package/dist/dashboard/model.d.ts.map +1 -0
- package/dist/dashboard/model.js +112 -0
- package/dist/dashboard/page.d.ts +3 -0
- package/dist/dashboard/page.d.ts.map +1 -0
- package/dist/dashboard/page.js +204 -0
- package/dist/dashboard/types.d.ts +63 -0
- package/dist/dashboard/types.d.ts.map +1 -0
- package/dist/dashboard/types.js +1 -0
- package/dist/dashboard-server.d.ts +24 -4
- package/dist/dashboard-server.d.ts.map +1 -1
- package/dist/dashboard-server.js +397 -302
- package/dist/discovery-registry.d.ts +17 -3
- package/dist/discovery-registry.d.ts.map +1 -1
- package/dist/discovery-registry.js +78 -3
- package/dist/doctor.d.ts +8 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +116 -0
- package/dist/eval/llm-tasks.d.ts +5 -0
- package/dist/eval/llm-tasks.d.ts.map +1 -0
- package/dist/eval/llm-tasks.js +125 -0
- package/dist/eval/repo-tasks.d.ts +12 -0
- package/dist/eval/repo-tasks.d.ts.map +1 -0
- package/dist/eval/repo-tasks.js +220 -0
- package/dist/eval/runner.d.ts +3 -1
- package/dist/eval/runner.d.ts.map +1 -1
- package/dist/eval/runner.js +23 -4
- package/dist/eval/tasks.d.ts.map +1 -1
- package/dist/eval/tasks.js +186 -0
- package/dist/eval/types.d.ts +8 -5
- package/dist/eval/types.d.ts.map +1 -1
- package/dist/execution/event-bus.d.ts +44 -0
- package/dist/execution/event-bus.d.ts.map +1 -0
- package/dist/execution/event-bus.js +76 -0
- package/dist/execution/failure-classifier.d.ts +11 -0
- package/dist/execution/failure-classifier.d.ts.map +1 -0
- package/dist/execution/failure-classifier.js +66 -0
- package/dist/execution/progress-detector.d.ts +3 -0
- package/dist/execution/progress-detector.d.ts.map +1 -0
- package/dist/execution/progress-detector.js +23 -0
- package/dist/execution/recovery-controller.d.ts +24 -0
- package/dist/execution/recovery-controller.d.ts.map +1 -0
- package/dist/execution/recovery-controller.js +114 -0
- package/dist/execution/recovery-messages.d.ts +24 -0
- package/dist/execution/recovery-messages.d.ts.map +1 -0
- package/dist/execution/recovery-messages.js +48 -0
- package/dist/execution/recovery-metrics.d.ts +16 -0
- package/dist/execution/recovery-metrics.d.ts.map +1 -0
- package/dist/execution/recovery-metrics.js +73 -0
- package/dist/execution/recovery-strategy-planner.d.ts +6 -0
- package/dist/execution/recovery-strategy-planner.d.ts.map +1 -0
- package/dist/execution/recovery-strategy-planner.js +24 -0
- package/dist/execution/run-trace-store.d.ts +29 -0
- package/dist/execution/run-trace-store.d.ts.map +1 -0
- package/dist/execution/run-trace-store.js +140 -0
- package/dist/execution/staged-verifier.d.ts +33 -0
- package/dist/execution/staged-verifier.d.ts.map +1 -0
- package/dist/execution/staged-verifier.js +39 -0
- package/dist/execution/types.d.ts +58 -0
- package/dist/execution/types.d.ts.map +1 -0
- package/dist/execution/types.js +1 -0
- package/dist/execution/verification-loop.d.ts +58 -0
- package/dist/execution/verification-loop.d.ts.map +1 -0
- package/dist/execution/verification-loop.js +195 -0
- package/dist/execution/verification-stages.d.ts +17 -0
- package/dist/execution/verification-stages.d.ts.map +1 -0
- package/dist/execution/verification-stages.js +102 -0
- package/dist/help-topics.d.ts.map +1 -1
- package/dist/help-topics.js +11 -0
- package/dist/index.js +0 -8
- package/dist/lsp/ts-service.d.ts +36 -0
- package/dist/lsp/ts-service.d.ts.map +1 -0
- package/dist/lsp/ts-service.js +291 -0
- package/dist/memory/lifecycle.d.ts +19 -0
- package/dist/memory/lifecycle.d.ts.map +1 -0
- package/dist/memory/lifecycle.js +53 -0
- package/dist/memory.d.ts +0 -16
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +0 -36
- package/dist/metrics/collector.d.ts +7 -0
- package/dist/metrics/collector.d.ts.map +1 -1
- package/dist/metrics/collector.js +60 -0
- package/dist/mission/manager.d.ts +1 -0
- package/dist/mission/manager.d.ts.map +1 -1
- package/dist/mission/manager.js +9 -0
- package/dist/mission/progress-notify.d.ts +39 -0
- package/dist/mission/progress-notify.d.ts.map +1 -0
- package/dist/mission/progress-notify.js +386 -0
- package/dist/pipeline/hooks.d.ts +1 -1
- package/dist/pipeline/hooks.d.ts.map +1 -1
- package/dist/pipeline/hooks.js +1 -0
- package/dist/pipeline/sections.d.ts +8 -4
- package/dist/pipeline/sections.d.ts.map +1 -1
- package/dist/pipeline/sections.js +70 -27
- package/dist/pipeline/verification.d.ts +1 -0
- package/dist/pipeline/verification.d.ts.map +1 -1
- package/dist/pipeline/verification.js +10 -7
- package/dist/providers/llm-client.d.ts +38 -0
- package/dist/providers/llm-client.d.ts.map +1 -0
- package/dist/providers/llm-client.js +105 -0
- package/dist/sdk.d.ts +1 -0
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +1 -0
- package/dist/session/durable-session-supervisor.d.ts.map +1 -1
- package/dist/session/durable-session-supervisor.js +13 -6
- package/dist/session/session-persistence.d.ts +29 -0
- package/dist/session/session-persistence.d.ts.map +1 -0
- package/dist/session/session-persistence.js +45 -0
- package/dist/session/session-scheduler.d.ts +8 -1
- package/dist/session/session-scheduler.d.ts.map +1 -1
- package/dist/session/session-scheduler.js +33 -4
- package/dist/session-task-report.d.ts +1 -0
- package/dist/session-task-report.d.ts.map +1 -1
- package/dist/session-task-report.js +2 -1
- package/dist/shortcuts.d.ts.map +1 -1
- package/dist/shortcuts.js +1 -0
- package/dist/skills/registry.d.ts.map +1 -1
- package/dist/skills/registry.js +10 -0
- package/dist/skills/security-scan.d.ts +15 -0
- package/dist/skills/security-scan.d.ts.map +1 -0
- package/dist/skills/security-scan.js +95 -0
- package/dist/skills/types.d.ts +2 -0
- package/dist/skills/types.d.ts.map +1 -1
- package/dist/statusline.d.ts +3 -3
- package/dist/statusline.d.ts.map +1 -1
- package/dist/statusline.js +9 -17
- package/dist/token-usage.d.ts +27 -0
- package/dist/token-usage.d.ts.map +1 -0
- package/dist/token-usage.js +107 -0
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +5 -3
- package/dist/tools/browser-act-session.d.ts +48 -0
- package/dist/tools/browser-act-session.d.ts.map +1 -0
- package/dist/tools/browser-act-session.js +168 -0
- package/dist/tools/browser-act.d.ts +14 -0
- package/dist/tools/browser-act.d.ts.map +1 -0
- package/dist/tools/browser-act.js +297 -0
- package/dist/tools/code-symbols.d.ts +35 -0
- package/dist/tools/code-symbols.d.ts.map +1 -0
- package/dist/tools/code-symbols.js +257 -0
- package/dist/tools/index.d.ts +4 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +22 -2
- package/dist/tools/lsp.d.ts +13 -0
- package/dist/tools/lsp.d.ts.map +1 -0
- package/dist/tools/lsp.js +136 -0
- package/dist/tools/patch.d.ts +5 -0
- package/dist/tools/patch.d.ts.map +1 -1
- package/dist/tools/patch.js +25 -4
- package/dist/tools/search.d.ts +7 -0
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +20 -3
- package/dist/tools/skill.d.ts +2 -0
- package/dist/tools/skill.d.ts.map +1 -1
- package/dist/tools/skill.js +47 -14
- package/dist/tools/subtask.d.ts +3 -1
- package/dist/tools/subtask.d.ts.map +1 -1
- package/dist/tools/subtask.js +151 -56
- package/dist/tui/shell.d.ts +12 -0
- package/dist/tui/shell.d.ts.map +1 -1
- package/dist/tui/shell.js +36 -3
- package/dist/tui/streaming-repl.d.ts +1 -0
- package/dist/tui/streaming-repl.d.ts.map +1 -1
- package/dist/tui/streaming-repl.js +27 -4
- package/dist/tui/streaming-tui.d.ts +10 -0
- package/dist/tui/streaming-tui.d.ts.map +1 -1
- package/dist/tui/streaming-tui.js +70 -12
- package/dist/types.d.ts +0 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow-runtime.d.ts.map +1 -1
- package/dist/workflow-runtime.js +10 -2
- package/dist/workflow-types.d.ts +2 -0
- package/dist/workflow-types.d.ts.map +1 -1
- package/docs/install.md +46 -12
- package/docs/skills.md +56 -7
- package/docs/web-routing.md +83 -0
- package/package.json +18 -4
- package/scripts/dep-layers.mjs +275 -0
- package/scripts/eval-llm.mjs +27 -0
- package/scripts/eval-recovery.mjs +101 -0
- package/scripts/eval-tasks.mjs +20 -0
- package/scripts/validate-packaging.mjs +57 -0
- package/skills/examples/README.md +23 -0
- package/skills/examples/add-function/SKILL.md +31 -0
- package/skills/examples/fix-failing-test/SKILL.md +32 -0
- package/skills/examples/pr-summary/SKILL.md +34 -0
- package/skills/lifecycle-build/SKILL.md +22 -0
- package/skills/lifecycle-plan/SKILL.md +32 -0
- package/skills/lifecycle-review/SKILL.md +25 -0
- package/skills/lifecycle-ship/SKILL.md +22 -0
- package/skills/lifecycle-spec/SKILL.md +24 -0
- package/skills/lifecycle-test/SKILL.md +21 -0
- package/skills/opencli/SKILL.md +222 -0
- package/skills/qling.md +14 -3
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Phase 4.3 — lsp 工具(可选 TS 语义查询)
|
|
3
|
+
// QLING_LSP=1 启用
|
|
4
|
+
// ============================================================
|
|
5
|
+
import { toolError, toolSuccess } from "./error-utils.js";
|
|
6
|
+
import { getRuntimeRootsFromEnv, isWithinAllowedRoots } from "../runtime-paths.js";
|
|
7
|
+
import { getOrCreateServiceForFile, isLspEnabled, loadTypeScript, lspDefinition, lspDocumentSymbols, lspHover, lspReferences, resetTsServiceCache, resolveAbsFile, } from "../lsp/ts-service.js";
|
|
8
|
+
export { isLspEnabled, resetTsServiceCache };
|
|
9
|
+
export const lspTool = {
|
|
10
|
+
name: "lsp",
|
|
11
|
+
description: "Optional TypeScript semantic queries (definition/hover/references/document_symbols). DISABLED by default — set QLING_LSP=1. Uses in-process TypeScript LanguageService (not full multi-language LSP).",
|
|
12
|
+
longDescription: `可选 TypeScript 语义查询(进程内 LanguageService)。
|
|
13
|
+
|
|
14
|
+
**启用**: \`QLING_LSP=1\`(且环境可 resolve \`typescript\` 包)
|
|
15
|
+
|
|
16
|
+
**action**:
|
|
17
|
+
- definition — 跳转到定义(path + line + character,1-based)
|
|
18
|
+
- hover — 类型/文档提示
|
|
19
|
+
- references — 查找引用
|
|
20
|
+
- document_symbols — 当前文件符号大纲
|
|
21
|
+
|
|
22
|
+
**限制**: 当前仅 TS/JS 系;非 LSP 多语言协议客户端。通用符号搜索请用 code_symbols。`,
|
|
23
|
+
parameters: {
|
|
24
|
+
type: "object",
|
|
25
|
+
properties: {
|
|
26
|
+
action: {
|
|
27
|
+
type: "string",
|
|
28
|
+
description: "definition | hover | references | document_symbols",
|
|
29
|
+
},
|
|
30
|
+
path: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description: "File path relative to workspace or absolute",
|
|
33
|
+
},
|
|
34
|
+
line: {
|
|
35
|
+
type: "number",
|
|
36
|
+
description: "1-based line number",
|
|
37
|
+
},
|
|
38
|
+
character: {
|
|
39
|
+
type: "number",
|
|
40
|
+
description: "1-based column (character offset in line)",
|
|
41
|
+
},
|
|
42
|
+
limit: {
|
|
43
|
+
type: "number",
|
|
44
|
+
description: "Max results for references/symbols (default 30/80)",
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
required: ["action", "path"],
|
|
48
|
+
},
|
|
49
|
+
scenes: ["code", "navigation"],
|
|
50
|
+
priority: 7,
|
|
51
|
+
readOnly: true,
|
|
52
|
+
destructive: false,
|
|
53
|
+
concurrencySafe: true,
|
|
54
|
+
effortHint: "low",
|
|
55
|
+
};
|
|
56
|
+
function parseLineChar(args) {
|
|
57
|
+
const line = Number(args.line);
|
|
58
|
+
const character = Number(args.character ?? 1);
|
|
59
|
+
return {
|
|
60
|
+
line: Number.isFinite(line) && line >= 1 ? Math.floor(line) : 1,
|
|
61
|
+
character: Number.isFinite(character) && character >= 1 ? Math.floor(character) : 1,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const MAX_LSP_RESULTS = 200;
|
|
65
|
+
export function clampLspLimit(raw, fallback) {
|
|
66
|
+
const parsed = Number(raw);
|
|
67
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
68
|
+
return fallback;
|
|
69
|
+
return Math.min(MAX_LSP_RESULTS, Math.floor(parsed));
|
|
70
|
+
}
|
|
71
|
+
export async function runLsp(args) {
|
|
72
|
+
if (!isLspEnabled()) {
|
|
73
|
+
return toolError("LSP_DISABLED", "lsp 默认关闭。启用: QLING_LSP=1(需可加载 typescript)。通用符号搜索用 code_symbols。", { category: "permission" });
|
|
74
|
+
}
|
|
75
|
+
const action = String(args.action ?? "").trim().toLowerCase();
|
|
76
|
+
const allowed = ["definition", "hover", "references", "document_symbols", "symbols"];
|
|
77
|
+
if (!allowed.includes(action)) {
|
|
78
|
+
return toolError("LSP_INVALID_ACTION", `action must be one of: definition, hover, references, document_symbols`);
|
|
79
|
+
}
|
|
80
|
+
const filePath = String(args.path ?? "").trim();
|
|
81
|
+
if (!filePath) {
|
|
82
|
+
return toolError("LSP_MISSING_PATH", "path is required");
|
|
83
|
+
}
|
|
84
|
+
const ts = await loadTypeScript();
|
|
85
|
+
if (!ts) {
|
|
86
|
+
return toolError("LSP_TYPESCRIPT_MISSING", "无法加载 typescript 包。请在项目中安装 typescript(devDependency)后重试。");
|
|
87
|
+
}
|
|
88
|
+
const roots = getRuntimeRootsFromEnv();
|
|
89
|
+
const workspaceDir = roots.workspaceDir ?? process.cwd();
|
|
90
|
+
const abs = resolveAbsFile(workspaceDir, filePath);
|
|
91
|
+
const rootsWithWorkspace = { ...roots, workspaceDir };
|
|
92
|
+
if (!isWithinAllowedRoots(abs, rootsWithWorkspace)) {
|
|
93
|
+
return toolError("LSP_PATH_OUTSIDE_ROOTS", `拒绝读取 runtime roots 外文件: ${filePath}`, { category: "permission" });
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const bundle = getOrCreateServiceForFile(ts, workspaceDir, abs);
|
|
97
|
+
const { line, character } = parseLineChar(args);
|
|
98
|
+
if (action === "definition") {
|
|
99
|
+
const locs = lspDefinition(bundle, abs, line, character);
|
|
100
|
+
if (locs.length === 0) {
|
|
101
|
+
return toolSuccess(`lsp definition: (none) at ${filePath}:${line}:${character}`);
|
|
102
|
+
}
|
|
103
|
+
const lines = locs.map((l) => `${l.file}:${l.line}:${l.character}` +
|
|
104
|
+
(l.preview ? ` ${l.preview}` : ""));
|
|
105
|
+
return toolSuccess(`lsp definition (${locs.length}):\n${lines.join("\n")}`);
|
|
106
|
+
}
|
|
107
|
+
if (action === "hover") {
|
|
108
|
+
const h = lspHover(bundle, abs, line, character);
|
|
109
|
+
if (!h) {
|
|
110
|
+
return toolSuccess(`lsp hover: (none) at ${filePath}:${line}:${character}`);
|
|
111
|
+
}
|
|
112
|
+
return toolSuccess(`lsp hover @ ${filePath}:${line}:${character}\n${h.display}` +
|
|
113
|
+
(h.documentation ? `\n\n${h.documentation}` : ""));
|
|
114
|
+
}
|
|
115
|
+
if (action === "references") {
|
|
116
|
+
const limit = clampLspLimit(args.limit, 30);
|
|
117
|
+
const locs = lspReferences(bundle, abs, line, character, limit);
|
|
118
|
+
if (locs.length === 0) {
|
|
119
|
+
return toolSuccess(`lsp references: (none)`);
|
|
120
|
+
}
|
|
121
|
+
const lines = locs.map((l) => `${l.file}:${l.line}:${l.character}`);
|
|
122
|
+
return toolSuccess(`lsp references (${locs.length}):\n${lines.join("\n")}`);
|
|
123
|
+
}
|
|
124
|
+
// document_symbols | symbols
|
|
125
|
+
const limit = clampLspLimit(args.limit, 80);
|
|
126
|
+
const syms = lspDocumentSymbols(bundle, abs, limit);
|
|
127
|
+
if (syms.length === 0) {
|
|
128
|
+
return toolSuccess(`lsp document_symbols: (none) in ${filePath}`);
|
|
129
|
+
}
|
|
130
|
+
const lines = syms.map((s) => `${s.line}:${s.character} [${s.kind}] ${s.name}`);
|
|
131
|
+
return toolSuccess(`lsp document_symbols (${syms.length}) ${filePath}:\n${lines.join("\n")}`);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
return toolError("LSP_FAILED", err instanceof Error ? err.message : String(err), { category: "runtime" });
|
|
135
|
+
}
|
|
136
|
+
}
|
package/dist/tools/patch.d.ts
CHANGED
|
@@ -17,6 +17,11 @@ export declare function runPatch(args: {
|
|
|
17
17
|
chunks: PatchChunk[];
|
|
18
18
|
dry_run?: boolean;
|
|
19
19
|
}): Promise<ToolResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Write via temp file then rename. Falls back to direct write on platforms
|
|
22
|
+
* where rename cannot replace an existing target (common on Windows).
|
|
23
|
+
*/
|
|
24
|
+
export declare function writeFileAtomic(targetPath: string, content: string): Promise<void>;
|
|
20
25
|
export declare function generateUnifiedDiff(filePath: string, originalContent: string, newContent: string): string;
|
|
21
26
|
export {};
|
|
22
27
|
//# sourceMappingURL=patch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patch.d.ts","sourceRoot":"","sources":["../../src/tools/patch.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"patch.d.ts","sourceRoot":"","sources":["../../src/tools/patch.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AASzD,yCAAyC;AACzC,eAAO,MAAM,oBAAoB,QAAkB,CAAC;AAEpD,eAAO,MAAM,SAAS,EAAE,cA+EvB,CAAC;AAEF,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,gBAAgB,CAAC,eAAe,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,CAmC5F;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,OAAO,CAAC,UAAU,CAAC,CA4HtB;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBxF;AAkID,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,GACjB,MAAM,CA6IR"}
|
package/dist/tools/patch.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { randomBytes } from "crypto";
|
|
2
|
+
import { readFile, rename, unlink, writeFile } from "fs/promises";
|
|
3
|
+
import { basename, dirname, join, relative } from "path";
|
|
3
4
|
import { getErrorMessage, toolError, toolSuccess } from "./error-utils.js";
|
|
4
5
|
import { checkSensitiveWriteTarget, getRuntimeRootsFromEnv, isPathAllowedForWrite, resolveToolPath, } from "../runtime-paths.js";
|
|
5
6
|
/** 超过该字节数拒绝做 LCS diff / 写入,防止超大文件 OOM */
|
|
@@ -205,9 +206,9 @@ export async function runPatch(args) {
|
|
|
205
206
|
return toolSuccess(`🔎 dry_run OK — would apply ${chunks.length} patch chunk(s) to ${resolvedPath}\n` +
|
|
206
207
|
`${summary}\n\n${diffText}\n\n(no file written)`);
|
|
207
208
|
}
|
|
208
|
-
//
|
|
209
|
+
// Atomic write after all validations pass (temp + rename; Windows-safe fallback)
|
|
209
210
|
try {
|
|
210
|
-
await
|
|
211
|
+
await writeFileAtomic(resolvedPath, currentContent);
|
|
211
212
|
return toolSuccess(`✅ Successfully applied ${chunks.length} patch chunk(s) to ${resolvedPath}\n` +
|
|
212
213
|
`${summary}\n\n${diffText}`);
|
|
213
214
|
}
|
|
@@ -215,6 +216,26 @@ export async function runPatch(args) {
|
|
|
215
216
|
return toolError("PATCH_WRITE_FAILED", `failed to write file: ${getErrorMessage(err)}`);
|
|
216
217
|
}
|
|
217
218
|
}
|
|
219
|
+
/**
|
|
220
|
+
* Write via temp file then rename. Falls back to direct write on platforms
|
|
221
|
+
* where rename cannot replace an existing target (common on Windows).
|
|
222
|
+
*/
|
|
223
|
+
export async function writeFileAtomic(targetPath, content) {
|
|
224
|
+
const dir = dirname(targetPath);
|
|
225
|
+
const tmp = join(dir, `.qling-patch-${basename(targetPath)}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`);
|
|
226
|
+
await writeFile(tmp, content, "utf-8");
|
|
227
|
+
try {
|
|
228
|
+
await rename(tmp, targetPath);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
try {
|
|
232
|
+
await writeFile(targetPath, content, "utf-8");
|
|
233
|
+
}
|
|
234
|
+
finally {
|
|
235
|
+
await unlink(tmp).catch(() => undefined);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
218
239
|
function countOccurrences(text, searchStr) {
|
|
219
240
|
if (!searchStr)
|
|
220
241
|
return 0;
|
package/dist/tools/search.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { ToolDefinition, ToolResult } from "../types.js";
|
|
2
|
+
/** Sprint 3: 默认更紧的结果预算,减少上下文膨胀 */
|
|
3
|
+
export declare const SEARCH_DEFAULT_LIMIT = 40;
|
|
4
|
+
export declare const SEARCH_MAX_LIMIT = 200;
|
|
5
|
+
/** 单行匹配展示上限(字符,含路径前缀后) */
|
|
6
|
+
export declare const SEARCH_MAX_LINE_CHARS = 240;
|
|
2
7
|
export declare const searchTool: ToolDefinition;
|
|
3
8
|
export declare function runSearch(args: {
|
|
4
9
|
pattern: string;
|
|
@@ -8,4 +13,6 @@ export declare function runSearch(args: {
|
|
|
8
13
|
context?: number;
|
|
9
14
|
limit?: number;
|
|
10
15
|
}): Promise<ToolResult>;
|
|
16
|
+
/** Truncate long match lines so search results stay harness-friendly. */
|
|
17
|
+
export declare function truncateSearchLine(line: string, maxChars?: number): string;
|
|
11
18
|
//# sourceMappingURL=search.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKzD,kCAAkC;AAClC,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,0BAA0B;AAC1B,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAiBzC,eAAO,MAAM,UAAU,EAAE,cAgGxB,CAAC;AAEF,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,UAAU,CAAC,CAmDtB;AA6hBD,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,SAAwB,GAAG,MAAM,CAIzF"}
|
package/dist/tools/search.js
CHANGED
|
@@ -10,6 +10,11 @@ import { execFile } from "child_process";
|
|
|
10
10
|
import { getErrorMessage, toolError, toolSuccess } from "./error-utils.js";
|
|
11
11
|
import { getRuntimeRootsFromEnv, isWithinAllowedRoots, resolveToolPath } from "../runtime-paths.js";
|
|
12
12
|
const MAX_SEARCH_FILE_BYTES = 2 * 1024 * 1024; // 2MB
|
|
13
|
+
/** Sprint 3: 默认更紧的结果预算,减少上下文膨胀 */
|
|
14
|
+
export const SEARCH_DEFAULT_LIMIT = 40;
|
|
15
|
+
export const SEARCH_MAX_LIMIT = 200;
|
|
16
|
+
/** 单行匹配展示上限(字符,含路径前缀后) */
|
|
17
|
+
export const SEARCH_MAX_LINE_CHARS = 240;
|
|
13
18
|
const DEFAULT_IGNORES = new Set([
|
|
14
19
|
"node_modules",
|
|
15
20
|
".git",
|
|
@@ -132,7 +137,8 @@ export async function runSearch(args) {
|
|
|
132
137
|
return toolError("SEARCH_INVALID_TARGET", `unsupported target: ${target}`);
|
|
133
138
|
}
|
|
134
139
|
const context = clamp(args.context ?? 0, 0, 10);
|
|
135
|
-
|
|
140
|
+
// Sprint 3: tighter limit 40;单行过长截断,避免冲垮上下文
|
|
141
|
+
const limit = clamp(args.limit ?? SEARCH_DEFAULT_LIMIT, 1, SEARCH_MAX_LIMIT);
|
|
136
142
|
const absPath = resolveToolPath(searchPath, roots, "workspace");
|
|
137
143
|
if (!isWithinAllowedRoots(absPath, roots)) {
|
|
138
144
|
return toolError("SEARCH_OUTSIDE_ALLOWED_ROOT", `${absPath} is outside allowed roots`);
|
|
@@ -239,7 +245,9 @@ async function searchWithRipgrep(absPath, pattern, target, fileGlob, context, li
|
|
|
239
245
|
const truncated = parsedLines.length > limit;
|
|
240
246
|
const sliced = parsedLines.slice(0, limit);
|
|
241
247
|
const suffix = truncated ? `\n... (truncated at ${limit} results)` : "";
|
|
242
|
-
const formatted = sliced
|
|
248
|
+
const formatted = sliced
|
|
249
|
+
.map((pl) => truncateSearchLine(`${pl.file}:${pl.line}:${pl.content}`))
|
|
250
|
+
.join("\n");
|
|
243
251
|
resolve(toolSuccess(`${truncated ? `${limit}+` : parsedLines.length} match(es):\n${formatted}${suffix}`));
|
|
244
252
|
return;
|
|
245
253
|
}
|
|
@@ -399,7 +407,9 @@ async function searchWithGitGrep(absPath, pattern, target, fileGlob, context, li
|
|
|
399
407
|
const truncated = parsedLines.length > limit;
|
|
400
408
|
const sliced = parsedLines.slice(0, limit);
|
|
401
409
|
const suffix = truncated ? `\n... (truncated at ${limit} results)` : "";
|
|
402
|
-
const formatted = sliced
|
|
410
|
+
const formatted = sliced
|
|
411
|
+
.map((pl) => truncateSearchLine(`${pl.file}:${pl.line}:${pl.content}`))
|
|
412
|
+
.join("\n");
|
|
403
413
|
resolve(toolSuccess(`${truncated ? `${limit}+` : parsedLines.length} match(es):\n${formatted}${suffix}`));
|
|
404
414
|
return;
|
|
405
415
|
}
|
|
@@ -631,6 +641,13 @@ function buildRegex(pattern, flags = "") {
|
|
|
631
641
|
function escapeRegExp(char) {
|
|
632
642
|
return char.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
633
643
|
}
|
|
644
|
+
/** Truncate long match lines so search results stay harness-friendly. */
|
|
645
|
+
export function truncateSearchLine(line, maxChars = SEARCH_MAX_LINE_CHARS) {
|
|
646
|
+
const text = String(line ?? "");
|
|
647
|
+
if (text.length <= maxChars)
|
|
648
|
+
return text;
|
|
649
|
+
return text.slice(0, Math.max(0, maxChars - 1)) + "…";
|
|
650
|
+
}
|
|
634
651
|
function clamp(value, min, max) {
|
|
635
652
|
return Math.max(min, Math.min(max, value));
|
|
636
653
|
}
|
package/dist/tools/skill.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { ToolDefinition, ToolResult } from "../types.js";
|
|
2
|
+
/** 包根目录(dist/tools/skill.js → 仓库或 npm 包根,含 skills/) */
|
|
3
|
+
export declare function getPackageRootForSkills(): string;
|
|
2
4
|
export declare function getSkillDirs(): string[];
|
|
3
5
|
export declare const skillTool: ToolDefinition;
|
|
4
6
|
export declare function runSkill(args: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../../src/tools/skill.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../../src/tools/skill.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQzD,uDAAuD;AACvD,wBAAgB,uBAAuB,IAAI,MAAM,CAIhD;AAMD,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAuBvC;AAiCD,eAAO,MAAM,SAAS,EAAE,cAmEvB,CAAC;AAEF,wBAAsB,QAAQ,CAAC,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CA0E3F"}
|
package/dist/tools/skill.js
CHANGED
|
@@ -5,21 +5,43 @@
|
|
|
5
5
|
// ============================================================
|
|
6
6
|
import { readFile } from "fs/promises";
|
|
7
7
|
import { existsSync } from "fs";
|
|
8
|
-
import {
|
|
8
|
+
import { homedir } from "os";
|
|
9
|
+
import { resolve, join, dirname } from "path";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
9
11
|
import { toolError, toolSuccess } from "./error-utils.js";
|
|
10
12
|
import { listSkills, searchSkills } from "../skills/registry.js";
|
|
13
|
+
import { formatSkillScanBlockMessage, scanSkillContent, } from "../skills/security-scan.js";
|
|
14
|
+
/** 包根目录(dist/tools/skill.js → 仓库或 npm 包根,含 skills/) */
|
|
15
|
+
export function getPackageRootForSkills() {
|
|
16
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
// dist/tools → ../.. = package root
|
|
18
|
+
return resolve(here, "..", "..");
|
|
19
|
+
}
|
|
11
20
|
// Skill 查找路径
|
|
12
21
|
// 支持两种格式:
|
|
13
22
|
// name="foo" → 搜索 skills/foo.md
|
|
14
23
|
// name="@scope/foo" → 搜索 skills/scopes/scope/foo.md
|
|
15
24
|
export function getSkillDirs() {
|
|
16
|
-
const dirs = [
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
25
|
+
const dirs = [];
|
|
26
|
+
const seen = new Set();
|
|
27
|
+
const add = (p) => {
|
|
28
|
+
const abs = resolve(p);
|
|
29
|
+
if (seen.has(abs))
|
|
30
|
+
return;
|
|
31
|
+
seen.add(abs);
|
|
32
|
+
dirs.push(abs);
|
|
33
|
+
};
|
|
34
|
+
// 1) 随包发布的 skills(全局 npm 安装仍可用)
|
|
35
|
+
add(join(getPackageRootForSkills(), "skills"));
|
|
36
|
+
// 2) 用户全局
|
|
37
|
+
add(join(homedir(), ".qling", "skills"));
|
|
38
|
+
// 3) 当前工作区
|
|
39
|
+
add(resolve(process.cwd(), "skills"));
|
|
40
|
+
add(resolve(process.cwd(), ".qling", "skills"));
|
|
41
|
+
// 4) 可选 Hermes 兼容路径
|
|
20
42
|
const hermesHome = process.env.HERMES_HOME;
|
|
21
43
|
if (hermesHome && hermesHome.trim()) {
|
|
22
|
-
|
|
44
|
+
add(join(hermesHome.trim(), "skills"));
|
|
23
45
|
}
|
|
24
46
|
return dirs;
|
|
25
47
|
}
|
|
@@ -58,26 +80,26 @@ function resolveSkillPath(name) {
|
|
|
58
80
|
}
|
|
59
81
|
export const skillTool = {
|
|
60
82
|
name: "skill",
|
|
61
|
-
description: "
|
|
83
|
+
description: "Load a skill knowledge file. Use for unfamiliar tools/APIs and ALWAYS before opencli/social platforms (Douyin, Xiaohongshu, Weibo, Bilibili, TikTok, Twitter). Actions: list | search query= | name=opencli.",
|
|
62
84
|
longDescription: `动态加载技能/知识文件(SKILL.md),内容通过 tool_result 注入上下文。
|
|
63
85
|
|
|
64
86
|
**核心原则**: "用到什么知识,临时加载什么知识,不塞 system prompt"
|
|
65
87
|
|
|
66
88
|
**三种操作**:
|
|
67
89
|
- skill list — 列出所有可用技能
|
|
68
|
-
- skill search query="
|
|
69
|
-
- skill name="
|
|
90
|
+
- skill search query="opencli" — 搜索技能
|
|
91
|
+
- skill name="opencli" — 加载 opencli 调用手册(抖音/小红书等)
|
|
70
92
|
|
|
71
93
|
**查找路径**:
|
|
72
|
-
- skills
|
|
73
|
-
- skills/
|
|
94
|
+
- 包内 skills/(npm 全局安装可用)
|
|
95
|
+
- ~/.qling/skills/
|
|
96
|
+
- 工作区 skills/ 与 .qling/skills/
|
|
74
97
|
- @scope/name → scopes/{scope}/{name}.md
|
|
75
98
|
|
|
76
99
|
**使用场景**:
|
|
100
|
+
- 抖音/小红书/微博/B站/TikTok/推特 → skill(name="opencli") 再用 bash 跑 opencli
|
|
77
101
|
- 调用 docker 但不熟悉命令 → skill(name="docker")
|
|
78
|
-
- 调用 Kubernetes API → skill(name="k8s-debug")
|
|
79
102
|
- 不确定有哪些技能 → skill list
|
|
80
|
-
- 搜索特定领域技能 → skill search query="api"
|
|
81
103
|
|
|
82
104
|
**返回内容**:
|
|
83
105
|
- 文件的 markdown body(不含 frontmatter)
|
|
@@ -167,13 +189,24 @@ export async function runSkill(args) {
|
|
|
167
189
|
}
|
|
168
190
|
try {
|
|
169
191
|
const content = await readFile(filePath, "utf-8");
|
|
192
|
+
const scan = scanSkillContent(content);
|
|
193
|
+
if (!scan.ok) {
|
|
194
|
+
return toolError("SKILL_SECURITY_BLOCKED", formatSkillScanBlockMessage(name, scan));
|
|
195
|
+
}
|
|
170
196
|
const lines = content.split("\n");
|
|
171
197
|
const startIdx = lines.findIndex((l) => l.trim() === "---");
|
|
172
198
|
const endIdx = startIdx >= 0 ? lines.findIndex((l, i) => i > startIdx && l.trim() === "---") : -1;
|
|
173
199
|
const body = startIdx >= 0 && endIdx >= 0
|
|
174
200
|
? lines.slice(endIdx + 1).join("\n").trim()
|
|
175
201
|
: content;
|
|
176
|
-
|
|
202
|
+
let prefix = `📖 Skill: ${name}\n\n`;
|
|
203
|
+
if (scan.findings.length > 0 && scan.mode === "warn") {
|
|
204
|
+
prefix +=
|
|
205
|
+
`⚠️ 安全扫描警告(仍加载):\n` +
|
|
206
|
+
scan.findings.map((f) => ` - [${f.severity}] ${f.rule}: ${f.detail}`).join("\n") +
|
|
207
|
+
"\n\n";
|
|
208
|
+
}
|
|
209
|
+
return toolSuccess(`${prefix}${body}`);
|
|
177
210
|
}
|
|
178
211
|
catch (err) {
|
|
179
212
|
return toolError("SKILL_READ_FAILED", `failed to read skill: ${err.message}`);
|
package/dist/tools/subtask.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { ToolDefinition, ToolResult } from "../types.js";
|
|
2
2
|
export declare const subtaskTool: ToolDefinition;
|
|
3
3
|
export declare function runSubtask(args: {
|
|
4
|
-
task
|
|
4
|
+
task?: string;
|
|
5
|
+
tasks?: unknown;
|
|
5
6
|
context?: string;
|
|
7
|
+
role?: string;
|
|
6
8
|
max_iterations?: number;
|
|
7
9
|
timeout_ms?: number;
|
|
8
10
|
}): Promise<ToolResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subtask.d.ts","sourceRoot":"","sources":["../../src/tools/subtask.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"subtask.d.ts","sourceRoot":"","sources":["../../src/tools/subtask.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA0C9D,eAAO,MAAM,WAAW,EAAE,cAkDzB,CAAC;AAgDF,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,UAAU,CAAC,CAsHtB"}
|