@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.
- package/CHANGELOG.md +154 -0
- package/README.en.md +82 -17
- package/README.md +15 -7
- 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 +29 -8
- 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 +51 -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,386 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Phase 3.5 — Mission 进度通知(Telegram / Slack 结构化卡片)
|
|
3
|
+
// QLING_MISSION_NOTIFY=on|off(默认 on:有 token 才发)
|
|
4
|
+
// QLING_MISSION_NOTIFY_STYLE=plain|rich(默认 rich)
|
|
5
|
+
// ============================================================
|
|
6
|
+
import axios from "axios";
|
|
7
|
+
export function isMissionNotifyEnabled(env = process.env) {
|
|
8
|
+
const raw = String(env.QLING_MISSION_NOTIFY ?? "on").trim().toLowerCase();
|
|
9
|
+
if (raw === "off" || raw === "0" || raw === "false")
|
|
10
|
+
return false;
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
export function resolveNotifyStyle(env = process.env) {
|
|
14
|
+
const raw = String(env.QLING_MISSION_NOTIFY_STYLE ?? "rich").trim().toLowerCase();
|
|
15
|
+
return raw === "plain" || raw === "text" ? "plain" : "rich";
|
|
16
|
+
}
|
|
17
|
+
export function resolveMissionLogNotifyMode(env = process.env) {
|
|
18
|
+
const raw = String(env.QLING_MISSION_NOTIFY_LOGS ?? "milestone").trim().toLowerCase();
|
|
19
|
+
if (raw === "off" || raw === "0" || raw === "false" || raw === "none")
|
|
20
|
+
return "off";
|
|
21
|
+
if (raw === "all" || raw === "on" || raw === "1" || raw === "true")
|
|
22
|
+
return "all";
|
|
23
|
+
return "milestone";
|
|
24
|
+
}
|
|
25
|
+
const MILESTONE_LOG_RE = /使命(开始|执行成功|执行失败|未启动)|开始执行|执行成功|执行失败|恢复状态机|checkpoint|失败|succeeded|failed|canceled|paused|blocked/i;
|
|
26
|
+
/**
|
|
27
|
+
* 是否应对本条使命日志发通道通知。
|
|
28
|
+
*/
|
|
29
|
+
export function shouldNotifyMissionLog(message, env = process.env) {
|
|
30
|
+
if (!isMissionNotifyEnabled(env))
|
|
31
|
+
return false;
|
|
32
|
+
const mode = resolveMissionLogNotifyMode(env);
|
|
33
|
+
if (mode === "off")
|
|
34
|
+
return false;
|
|
35
|
+
if (mode === "all")
|
|
36
|
+
return true;
|
|
37
|
+
return MILESTONE_LOG_RE.test(String(message ?? ""));
|
|
38
|
+
}
|
|
39
|
+
export function formatMissionLogMessage(mission, message) {
|
|
40
|
+
const msg = String(message ?? "").replace(/\s+/g, " ").slice(0, 240);
|
|
41
|
+
return [
|
|
42
|
+
`📝 【轻灵使命日志】`,
|
|
43
|
+
`id: ${mission.id}`,
|
|
44
|
+
`name: ${mission.name}`,
|
|
45
|
+
`status: ${mission.status}`,
|
|
46
|
+
`log: ${msg}`,
|
|
47
|
+
].join("\n");
|
|
48
|
+
}
|
|
49
|
+
const STATUS_EMOJI = {
|
|
50
|
+
queued: "⏳",
|
|
51
|
+
running: "🚀",
|
|
52
|
+
blocked: "🛑",
|
|
53
|
+
paused: "⏸️",
|
|
54
|
+
succeeded: "✅",
|
|
55
|
+
failed: "❌",
|
|
56
|
+
canceled: "🚫",
|
|
57
|
+
};
|
|
58
|
+
export function statusEmoji(status) {
|
|
59
|
+
return STATUS_EMOJI[status] ?? "📡";
|
|
60
|
+
}
|
|
61
|
+
export function formatMissionProgressMessage(mission, from, to) {
|
|
62
|
+
const arrow = from ? `${from} → ${to}` : `→ ${to}`;
|
|
63
|
+
const desc = (mission.description || "").replace(/\s+/g, " ").slice(0, 120);
|
|
64
|
+
const err = to === "failed" && mission.error?.message
|
|
65
|
+
? `\n错误: ${mission.error.message.slice(0, 200)}`
|
|
66
|
+
: "";
|
|
67
|
+
return [
|
|
68
|
+
`${statusEmoji(to)} 【轻灵使命进度】`,
|
|
69
|
+
`id: ${mission.id}`,
|
|
70
|
+
`name: ${mission.name}`,
|
|
71
|
+
`status: ${arrow}`,
|
|
72
|
+
desc ? `task: ${desc}` : null,
|
|
73
|
+
err || null,
|
|
74
|
+
]
|
|
75
|
+
.filter(Boolean)
|
|
76
|
+
.join("\n");
|
|
77
|
+
}
|
|
78
|
+
/** Telegram HTML(需 escape) */
|
|
79
|
+
export function formatMissionProgressTelegramHtml(mission, from, to) {
|
|
80
|
+
const esc = (s) => s
|
|
81
|
+
.replace(/&/g, "&")
|
|
82
|
+
.replace(/</g, "<")
|
|
83
|
+
.replace(/>/g, ">");
|
|
84
|
+
const arrow = from ? `${esc(from)} → <b>${esc(to)}</b>` : `→ <b>${esc(to)}</b>`;
|
|
85
|
+
const desc = (mission.description || "").replace(/\s+/g, " ").slice(0, 120);
|
|
86
|
+
const lines = [
|
|
87
|
+
`${statusEmoji(to)} <b>轻灵使命进度</b>`,
|
|
88
|
+
`<code>${esc(mission.id)}</code>`,
|
|
89
|
+
`名称: ${esc(mission.name || "-")}`,
|
|
90
|
+
`状态: ${arrow}`,
|
|
91
|
+
];
|
|
92
|
+
if (desc)
|
|
93
|
+
lines.push(`任务: ${esc(desc)}`);
|
|
94
|
+
if (to === "failed" && mission.error?.message) {
|
|
95
|
+
lines.push(`错误: <i>${esc(mission.error.message.slice(0, 200))}</i>`);
|
|
96
|
+
}
|
|
97
|
+
return lines.join("\n");
|
|
98
|
+
}
|
|
99
|
+
/** Slack Block Kit 最小卡片 */
|
|
100
|
+
export function formatMissionProgressSlackBlocks(mission, from, to) {
|
|
101
|
+
const plain = formatMissionProgressMessage(mission, from, to);
|
|
102
|
+
const arrow = from ? `${from} → *${to}*` : `→ *${to}*`;
|
|
103
|
+
const desc = (mission.description || "").replace(/\s+/g, " ").slice(0, 120);
|
|
104
|
+
const fields = [
|
|
105
|
+
{ type: "mrkdwn", text: `*ID*\n\`${mission.id}\`` },
|
|
106
|
+
{ type: "mrkdwn", text: `*状态*\n${arrow}` },
|
|
107
|
+
{ type: "mrkdwn", text: `*名称*\n${mission.name || "-"}` },
|
|
108
|
+
];
|
|
109
|
+
if (desc) {
|
|
110
|
+
fields.push({ type: "mrkdwn", text: `*任务*\n${desc}` });
|
|
111
|
+
}
|
|
112
|
+
const blocks = [
|
|
113
|
+
{
|
|
114
|
+
type: "header",
|
|
115
|
+
text: {
|
|
116
|
+
type: "plain_text",
|
|
117
|
+
text: `${statusEmoji(to)} 轻灵使命进度`,
|
|
118
|
+
emoji: true,
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
{ type: "section", fields },
|
|
122
|
+
];
|
|
123
|
+
if (to === "failed" && mission.error?.message) {
|
|
124
|
+
blocks.push({
|
|
125
|
+
type: "section",
|
|
126
|
+
text: {
|
|
127
|
+
type: "mrkdwn",
|
|
128
|
+
text: `*错误*\n${mission.error.message.slice(0, 200)}`,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
blocks.push({ type: "divider" });
|
|
133
|
+
return { text: plain, blocks };
|
|
134
|
+
}
|
|
135
|
+
function parseJsonStringArray(raw) {
|
|
136
|
+
if (!raw || !raw.trim())
|
|
137
|
+
return [];
|
|
138
|
+
try {
|
|
139
|
+
const parsed = JSON.parse(raw);
|
|
140
|
+
if (Array.isArray(parsed))
|
|
141
|
+
return parsed.map(String).filter(Boolean);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return raw.split(/[,,]/).map((s) => s.trim()).filter(Boolean);
|
|
145
|
+
}
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
export function assertSlackResponseOk(data) {
|
|
149
|
+
if (!data || typeof data !== "object")
|
|
150
|
+
return;
|
|
151
|
+
const body = data;
|
|
152
|
+
if (body.ok === false) {
|
|
153
|
+
const code = String(body.error ?? "unknown_error")
|
|
154
|
+
.replace(/[^a-zA-Z0-9_.-]/g, "_")
|
|
155
|
+
.slice(0, 120);
|
|
156
|
+
throw new Error(`Slack API error: ${code}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* 向已配置的 Telegram / Slack 发送使命进度(失败不抛出)。
|
|
161
|
+
*/
|
|
162
|
+
export async function notifyMissionProgress(mission, from, to, env = process.env) {
|
|
163
|
+
const style = resolveNotifyStyle(env);
|
|
164
|
+
if (!isMissionNotifyEnabled(env)) {
|
|
165
|
+
return {
|
|
166
|
+
attempted: false,
|
|
167
|
+
telegram: "skipped",
|
|
168
|
+
slack: "skipped",
|
|
169
|
+
detail: "QLING_MISSION_NOTIFY off",
|
|
170
|
+
style,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
const notable = new Set([
|
|
174
|
+
"running",
|
|
175
|
+
"blocked",
|
|
176
|
+
"paused",
|
|
177
|
+
"succeeded",
|
|
178
|
+
"failed",
|
|
179
|
+
"canceled",
|
|
180
|
+
]);
|
|
181
|
+
if (!notable.has(to)) {
|
|
182
|
+
return {
|
|
183
|
+
attempted: false,
|
|
184
|
+
telegram: "skipped",
|
|
185
|
+
slack: "skipped",
|
|
186
|
+
detail: `status ${to} not notable`,
|
|
187
|
+
style,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
const plain = formatMissionProgressMessage(mission, from, to);
|
|
191
|
+
let telegram = "skipped";
|
|
192
|
+
let slack = "skipped";
|
|
193
|
+
const details = [];
|
|
194
|
+
const tgToken = String(env.QLING_CHANNEL_TELEGRAM_TOKEN ?? "").trim();
|
|
195
|
+
const tgChats = parseJsonStringArray(env.QLING_CHANNEL_TELEGRAM_ALLOWED_CHAT_IDS);
|
|
196
|
+
const tgProgress = String(env.QLING_MISSION_TELEGRAM_CHAT_ID ?? "").trim();
|
|
197
|
+
const chatIds = tgProgress ? [tgProgress, ...tgChats] : tgChats;
|
|
198
|
+
if (tgToken && chatIds.length > 0) {
|
|
199
|
+
try {
|
|
200
|
+
for (const chatId of [...new Set(chatIds)]) {
|
|
201
|
+
if (style === "rich") {
|
|
202
|
+
const html = formatMissionProgressTelegramHtml(mission, from, to);
|
|
203
|
+
await axios.post(`https://api.telegram.org/bot${tgToken}/sendMessage`, {
|
|
204
|
+
chat_id: chatId,
|
|
205
|
+
text: html.length > 3900 ? html.slice(0, 3900) + "…" : html,
|
|
206
|
+
parse_mode: "HTML",
|
|
207
|
+
disable_web_page_preview: true,
|
|
208
|
+
}, { timeout: 10_000 });
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
const body = plain.length > 3900 ? plain.slice(0, 3900) + "\n…" : plain;
|
|
212
|
+
await axios.post(`https://api.telegram.org/bot${tgToken}/sendMessage`, { chat_id: chatId, text: body }, { timeout: 10_000 });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
telegram = "sent";
|
|
216
|
+
details.push(`telegram chats=${chatIds.length} style=${style}`);
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
telegram = "error";
|
|
220
|
+
details.push(`telegram: ${err.message}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const slackToken = String(env.QLING_CHANNEL_SLACK_BOT_TOKEN ?? "").trim();
|
|
224
|
+
let slackChannels = parseJsonStringArray(env.QLING_CHANNEL_SLACK_CHANNEL_IDS);
|
|
225
|
+
const slackProgress = String(env.QLING_MISSION_SLACK_CHANNEL_ID ?? "").trim();
|
|
226
|
+
if (slackProgress)
|
|
227
|
+
slackChannels = [slackProgress, ...slackChannels];
|
|
228
|
+
if (slackToken && slackChannels.length > 0) {
|
|
229
|
+
try {
|
|
230
|
+
const card = style === "rich"
|
|
231
|
+
? formatMissionProgressSlackBlocks(mission, from, to)
|
|
232
|
+
: { text: plain, blocks: undefined };
|
|
233
|
+
for (const channel of [...new Set(slackChannels)]) {
|
|
234
|
+
const payload = {
|
|
235
|
+
channel,
|
|
236
|
+
text: card.text.length > 2900 ? card.text.slice(0, 2900) + "\n…" : card.text,
|
|
237
|
+
};
|
|
238
|
+
if (style === "rich" && card.blocks) {
|
|
239
|
+
payload.blocks = card.blocks;
|
|
240
|
+
}
|
|
241
|
+
const response = await axios.post("https://slack.com/api/chat.postMessage", payload, {
|
|
242
|
+
timeout: 10_000,
|
|
243
|
+
headers: {
|
|
244
|
+
Authorization: `Bearer ${slackToken}`,
|
|
245
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
assertSlackResponseOk(response.data);
|
|
249
|
+
}
|
|
250
|
+
slack = "sent";
|
|
251
|
+
details.push(`slack channels=${slackChannels.length} style=${style}`);
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
slack = "error";
|
|
255
|
+
details.push(`slack: ${err.message}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
const attempted = telegram === "sent" || slack === "sent" || telegram === "error" || slack === "error";
|
|
259
|
+
return {
|
|
260
|
+
attempted,
|
|
261
|
+
telegram,
|
|
262
|
+
slack,
|
|
263
|
+
detail: details.join("; ") || "no channel targets configured",
|
|
264
|
+
style,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* 使命日志推送(默认仅里程碑;失败不抛出)。
|
|
269
|
+
* QLING_MISSION_NOTIFY_LOGS=off|milestone|all
|
|
270
|
+
*/
|
|
271
|
+
export async function notifyMissionLog(mission, message, env = process.env) {
|
|
272
|
+
const style = resolveNotifyStyle(env);
|
|
273
|
+
if (!shouldNotifyMissionLog(message, env)) {
|
|
274
|
+
return {
|
|
275
|
+
attempted: false,
|
|
276
|
+
telegram: "skipped",
|
|
277
|
+
slack: "skipped",
|
|
278
|
+
detail: "log not notifiable",
|
|
279
|
+
style,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
const plain = formatMissionLogMessage(mission, message);
|
|
283
|
+
const esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
284
|
+
const html = [
|
|
285
|
+
`📝 <b>轻灵使命日志</b>`,
|
|
286
|
+
`<code>${esc(mission.id)}</code>`,
|
|
287
|
+
`名称: ${esc(mission.name || "-")}`,
|
|
288
|
+
`状态: ${esc(mission.status)}`,
|
|
289
|
+
`日志: ${esc(String(message).slice(0, 240))}`,
|
|
290
|
+
].join("\n");
|
|
291
|
+
let telegram = "skipped";
|
|
292
|
+
let slack = "skipped";
|
|
293
|
+
const details = [];
|
|
294
|
+
const tgToken = String(env.QLING_CHANNEL_TELEGRAM_TOKEN ?? "").trim();
|
|
295
|
+
const tgChats = parseJsonStringArray(env.QLING_CHANNEL_TELEGRAM_ALLOWED_CHAT_IDS);
|
|
296
|
+
const tgProgress = String(env.QLING_MISSION_TELEGRAM_CHAT_ID ?? "").trim();
|
|
297
|
+
const chatIds = tgProgress ? [tgProgress, ...tgChats] : tgChats;
|
|
298
|
+
if (tgToken && chatIds.length > 0) {
|
|
299
|
+
try {
|
|
300
|
+
for (const chatId of [...new Set(chatIds)]) {
|
|
301
|
+
const payload = {
|
|
302
|
+
chat_id: chatId,
|
|
303
|
+
text: style === "rich"
|
|
304
|
+
? html.length > 3900
|
|
305
|
+
? html.slice(0, 3900) + "…"
|
|
306
|
+
: html
|
|
307
|
+
: plain.length > 3900
|
|
308
|
+
? plain.slice(0, 3900) + "\n…"
|
|
309
|
+
: plain,
|
|
310
|
+
};
|
|
311
|
+
if (style === "rich") {
|
|
312
|
+
payload.parse_mode = "HTML";
|
|
313
|
+
payload.disable_web_page_preview = true;
|
|
314
|
+
}
|
|
315
|
+
await axios.post(`https://api.telegram.org/bot${tgToken}/sendMessage`, payload, {
|
|
316
|
+
timeout: 10_000,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
telegram = "sent";
|
|
320
|
+
details.push("telegram log");
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
telegram = "error";
|
|
324
|
+
details.push(`telegram: ${err.message}`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
const slackToken = String(env.QLING_CHANNEL_SLACK_BOT_TOKEN ?? "").trim();
|
|
328
|
+
let slackChannels = parseJsonStringArray(env.QLING_CHANNEL_SLACK_CHANNEL_IDS);
|
|
329
|
+
const slackProgress = String(env.QLING_MISSION_SLACK_CHANNEL_ID ?? "").trim();
|
|
330
|
+
if (slackProgress)
|
|
331
|
+
slackChannels = [slackProgress, ...slackChannels];
|
|
332
|
+
if (slackToken && slackChannels.length > 0) {
|
|
333
|
+
try {
|
|
334
|
+
for (const channel of [...new Set(slackChannels)]) {
|
|
335
|
+
const payload = {
|
|
336
|
+
channel,
|
|
337
|
+
text: plain.length > 2900 ? plain.slice(0, 2900) + "\n…" : plain,
|
|
338
|
+
};
|
|
339
|
+
if (style === "rich") {
|
|
340
|
+
payload.blocks = [
|
|
341
|
+
{
|
|
342
|
+
type: "header",
|
|
343
|
+
text: { type: "plain_text", text: "📝 轻灵使命日志", emoji: true },
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
type: "section",
|
|
347
|
+
fields: [
|
|
348
|
+
{ type: "mrkdwn", text: `*ID*\n\`${mission.id}\`` },
|
|
349
|
+
{ type: "mrkdwn", text: `*状态*\n${mission.status}` },
|
|
350
|
+
],
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
type: "section",
|
|
354
|
+
text: {
|
|
355
|
+
type: "mrkdwn",
|
|
356
|
+
text: `*日志*\n${String(message).replace(/\s+/g, " ").slice(0, 240)}`,
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
];
|
|
360
|
+
}
|
|
361
|
+
const response = await axios.post("https://slack.com/api/chat.postMessage", payload, {
|
|
362
|
+
timeout: 10_000,
|
|
363
|
+
headers: {
|
|
364
|
+
Authorization: `Bearer ${slackToken}`,
|
|
365
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
366
|
+
},
|
|
367
|
+
});
|
|
368
|
+
assertSlackResponseOk(response.data);
|
|
369
|
+
}
|
|
370
|
+
slack = "sent";
|
|
371
|
+
details.push("slack log");
|
|
372
|
+
}
|
|
373
|
+
catch (err) {
|
|
374
|
+
slack = "error";
|
|
375
|
+
details.push(`slack: ${err.message}`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
const attempted = telegram === "sent" || slack === "sent" || telegram === "error" || slack === "error";
|
|
379
|
+
return {
|
|
380
|
+
attempted,
|
|
381
|
+
telegram,
|
|
382
|
+
slack,
|
|
383
|
+
detail: details.join("; ") || "no channel targets configured",
|
|
384
|
+
style,
|
|
385
|
+
};
|
|
386
|
+
}
|
package/dist/pipeline/hooks.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export declare class SpeculativeClassifier {
|
|
|
26
26
|
classify(toolCall: ToolCall): ClassifierResult;
|
|
27
27
|
}
|
|
28
28
|
/** Plan 模式下禁止的写/执行类工具(OpenCode plan agent 语义) */
|
|
29
|
-
export declare const PLAN_MODE_DENY_TOOLS: readonly ["write", "patch", "bash", "subtask", "browser_fetch"];
|
|
29
|
+
export declare const PLAN_MODE_DENY_TOOLS: readonly ["write", "patch", "bash", "subtask", "browser_fetch", "browser_act"];
|
|
30
30
|
export declare class HookManager {
|
|
31
31
|
private preHooks;
|
|
32
32
|
private postHooks;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/pipeline/hooks.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,QAAQ,EACR,UAAU,EACV,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EAEd,gBAAgB,EAChB,cAAc,EACf,MAAM,aAAa,CAAC;AAIrB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAMhD,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,QAAQ;gBADR,QAAQ,EAAE,cAAc,EAAE,EAC1B,QAAQ,GAAE,MAA0B;IAG9C;;;;;;OAMG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,EAAE;IA0BrD;;;OAGG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE;IAmBtD,MAAM,IAAI,cAAc,EAAE;IAI1B,QAAQ,IAAI,MAAM;CAGnB;AAuDD,qBAAa,qBAAqB;IACpB,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,cAAc,EAAE;IAE9C,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,gBAAgB;CA8C/C;AAID,iDAAiD;AACjD,eAAO,MAAM,oBAAoB,
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/pipeline/hooks.ts"],"names":[],"mappings":"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"}
|
package/dist/pipeline/hooks.js
CHANGED
|
@@ -7,7 +7,6 @@ export declare const SECTION_IDS: {
|
|
|
7
7
|
readonly RESTRICTIONS: "restrictions";
|
|
8
8
|
readonly TONE: "tone";
|
|
9
9
|
readonly REPOMAP: "repomap";
|
|
10
|
-
readonly TOKEN_BUDGET: "token_budget";
|
|
11
10
|
readonly SESSION: "session";
|
|
12
11
|
readonly MCP: "mcp";
|
|
13
12
|
readonly MEMORY: "memory";
|
|
@@ -23,17 +22,22 @@ export declare function buildRestrictionsSection(): PromptSection;
|
|
|
23
22
|
export declare function buildToneSection(): PromptSection;
|
|
24
23
|
export declare function buildSessionSection(): PromptSection;
|
|
25
24
|
export declare function buildMemorySection(): PromptSection;
|
|
26
|
-
export declare function buildTokenBudgetSection(usedTokens: number, maxTokens: number): PromptSection;
|
|
27
25
|
export declare function buildSkillsSection(skills: SkillMeta[]): PromptSection;
|
|
28
26
|
export declare function buildMCPSection(serverInfo?: string): PromptSection;
|
|
27
|
+
/** Default budgets keep repo map from dominating context window. */
|
|
28
|
+
export declare const REPOMAP_DEFAULT_MAX_SYMBOLS = 200;
|
|
29
|
+
export declare const REPOMAP_DEFAULT_MAX_CHARS = 6000;
|
|
29
30
|
export declare function buildRepoMapSection(symbols: {
|
|
30
31
|
file: string;
|
|
31
32
|
name: string;
|
|
32
33
|
type: string;
|
|
33
34
|
line: number;
|
|
34
35
|
signature: string;
|
|
35
|
-
}[]
|
|
36
|
-
|
|
36
|
+
}[], options?: {
|
|
37
|
+
maxSymbols?: number;
|
|
38
|
+
maxChars?: number;
|
|
39
|
+
}): PromptSection;
|
|
40
|
+
export declare function buildDefaultRegistry(tools: AgentConfig["tools"]): PromptSectionRegistry;
|
|
37
41
|
export declare function buildSystemPrompt(registry: PromptSectionRegistry, dynamicSections?: {
|
|
38
42
|
memory?: string;
|
|
39
43
|
session?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sections.d.ts","sourceRoot":"","sources":["../../src/pipeline/sections.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAKpD,eAAO,MAAM,WAAW
|
|
1
|
+
{"version":3,"file":"sections.d.ts","sourceRoot":"","sources":["../../src/pipeline/sections.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAKpD,eAAO,MAAM,WAAW;;;;;;;;;;;;;CAad,CAAC;AAEX,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,MAAM,CAgBzE;AAID,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,CAS9E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,aAAa,CAwB5E;AAED,wBAAgB,oBAAoB,IAAI,aAAa,CAiBpD;AAED,wBAAgB,wBAAwB,IAAI,aAAa,CAsCxD;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CAahD;AAED,wBAAgB,mBAAmB,IAAI,aAAa,CAYnD;AAED,wBAAgB,kBAAkB,IAAI,aAAa,CAUlD;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,aAAa,CA+BrE;AAED,wBAAgB,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,CAWlE;AAED,oEAAoE;AACpE,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAC/C,eAAO,MAAM,yBAAyB,OAAQ,CAAC;AAE/C,wBAAgB,mBAAmB,CACjC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAAE,EACxF,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GACvD,aAAa,CAuDf;AAID,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,qBAAqB,CAavF;AAID,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,qBAAqB,EAC/B,eAAe,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACtD,MAAM,CAgBR"}
|
|
@@ -12,7 +12,6 @@ export const SECTION_IDS = {
|
|
|
12
12
|
RESTRICTIONS: "restrictions",
|
|
13
13
|
TONE: "tone",
|
|
14
14
|
REPOMAP: "repomap",
|
|
15
|
-
TOKEN_BUDGET: "token_budget",
|
|
16
15
|
SESSION: "session",
|
|
17
16
|
MCP: "mcp",
|
|
18
17
|
MEMORY: "memory",
|
|
@@ -73,7 +72,12 @@ export function buildWorkflowSection() {
|
|
|
73
72
|
1. 先思考:这个任务需要几步?是否需要规划?
|
|
74
73
|
2. 如果任务复杂(超过2步),先用 todo add 依次列出执行步骤
|
|
75
74
|
3. 然后逐个执行:每完成一步用 todo done 标记
|
|
76
|
-
4.
|
|
75
|
+
4. 所有步骤完成后返回清晰总结
|
|
76
|
+
|
|
77
|
+
【任务执行三条基本规则】
|
|
78
|
+
1. **外部工具先关联分析再调用**:调用 bash/opencli/url_fetch/browser_fetch/MCP 等外部能力前,先说明「任务要什么 → 该工具是否匹配 → 选哪个子命令/参数 → 预期输出」;不匹配则换工具或先 skill 加载,禁止盲目试错。
|
|
79
|
+
2. **成功后总结正确流程**:任一关键路径成功后,用中文给出可复现步骤(顺序、关键命令、成功判据、结果要点),便于用户下次照做。
|
|
80
|
+
3. **失败须实事求是**:单流程失败、部分成功或结果与目标不符时,明确写「未完成/失败/偏差」及证据(错误信息、反爬页、命令退出码等),禁止把挑战页/空结果/猜测说成已成功。`,
|
|
77
81
|
cacheable: true,
|
|
78
82
|
cached: false,
|
|
79
83
|
};
|
|
@@ -83,15 +87,35 @@ export function buildRestrictionsSection() {
|
|
|
83
87
|
id: SECTION_IDS.RESTRICTIONS,
|
|
84
88
|
title: "限制",
|
|
85
89
|
content: `【工具使用原则】
|
|
86
|
-
- bash
|
|
90
|
+
- bash:执行命令、安装、构建、运行;调用本机 opencli 也用 bash
|
|
87
91
|
- read:查看文件内容后再决定怎么写
|
|
88
92
|
- write:创建或覆盖文件
|
|
93
|
+
- search:内容/文件名搜索
|
|
94
|
+
- code_symbols:按符号名检索函数/类/类型(轻量静态提取)
|
|
95
|
+
- lsp:可选 TS 语义查询(definition/hover/references;须 QLING_LSP=1)
|
|
89
96
|
- todo:规划步骤、跟踪进度
|
|
90
97
|
- skill:遇到不熟悉的工具/API/框架时,用 skill 加载对应知识文件
|
|
98
|
+
- **调用外部工具前必须做关联分析**(任务目标 ↔ 工具能力 ↔ 参数/站点);分析通过后再调用
|
|
99
|
+
|
|
100
|
+
【诚实与收尾】
|
|
101
|
+
- 成功:总结「正确流程」(步骤 + 关键命令 + 结果)
|
|
102
|
+
- 失败或未准确执行:明确承认,引用真实输出/错误码,不编造完成结论
|
|
103
|
+
- 禁止用「可能已经…」「应该成功了」替代验证证据
|
|
104
|
+
|
|
105
|
+
【网页 / 社交平台数据(opencli)】
|
|
106
|
+
- 抖音、小红书、微博、B站、TikTok、推特/X 等:先 skill name="opencli",再用 bash 执行 opencli <站点> … -f json
|
|
107
|
+
- 禁止用 url_fetch / 裸 curl 抓取上述强反爬站点(会返回 _$jsvmprt、acrawler 挑战页,不是业务数据)
|
|
108
|
+
- 抖音 ≠ TikTok:douyin.com 必须 opencli douyin;禁止用 opencli tiktok 操作抖音
|
|
109
|
+
- 小红书:用 opencli xiaohongshu;note/comments/download 必须传 search/feed 返回的「含 xsec_token 的完整 URL」,禁止只传裸 note-id
|
|
110
|
+
- 不确定子命令时:opencli list -f json 或 opencli <site> --help;需登录时先 opencli <site> whoami / login
|
|
111
|
+
- browser_fetch 适合文档站,不保证能过抖音/小红书风控;平台结构化数据优先 opencli 站点适配器
|
|
112
|
+
- browser_act(点击/填表)默认关闭;仅当 QLING_BROWSER_ACT=1 且非强反爬场景;优先 opencli browser <session>
|
|
113
|
+
- 外联路由详见包内 docs/web-routing.md;先选对通道再调用
|
|
91
114
|
|
|
92
115
|
【安全限制】
|
|
93
116
|
- 危险命令(rm -rf /、格式化磁盘等)会被自动拒绝
|
|
94
117
|
- 删除/覆盖操作前必须先读取确认
|
|
118
|
+
- opencli 的 delete/publish 等写操作须先征得用户确认
|
|
95
119
|
- 不确定的操作先问用户`,
|
|
96
120
|
cacheable: true,
|
|
97
121
|
cached: false,
|
|
@@ -105,7 +129,8 @@ export function buildToneSection() {
|
|
|
105
129
|
回答应当平衡“简洁”与“丰富”:
|
|
106
130
|
- 对于纯技术、文件或系统操作:保持极致简洁,给出完成报告。
|
|
107
131
|
- 对于图片分析、创意设计或意境咨询:**禁止使用表格 (Table)**。你应当使用分段的叙述性文字、文学化的词汇和排比句,完整转述视觉意象和氛围。**绝对不要将感性描述提取为结构化数据列。**
|
|
108
|
-
工具执行结果用 ✅(成功)或
|
|
132
|
+
工具执行结果用 ✅(成功)或 ❌(失败)标记。
|
|
133
|
+
成功路径结束时附「正确流程」小结;失败时用 ❌ 并写清原因与已验证事实,不粉饰。`,
|
|
109
134
|
cacheable: true,
|
|
110
135
|
cached: false,
|
|
111
136
|
};
|
|
@@ -134,21 +159,6 @@ export function buildMemorySection() {
|
|
|
134
159
|
cached: false,
|
|
135
160
|
};
|
|
136
161
|
}
|
|
137
|
-
export function buildTokenBudgetSection(usedTokens, maxTokens) {
|
|
138
|
-
const remaining = maxTokens - usedTokens;
|
|
139
|
-
const pct = Math.round((remaining / maxTokens) * 100);
|
|
140
|
-
return {
|
|
141
|
-
id: SECTION_IDS.TOKEN_BUDGET,
|
|
142
|
-
title: "Token 预算",
|
|
143
|
-
content: `【Token 预算】
|
|
144
|
-
已使用: ~${usedTokens.toLocaleString()} tokens
|
|
145
|
-
剩余: ~${remaining.toLocaleString()} tokens (${pct}%)
|
|
146
|
-
当剩余低于 20% 时,主动精简回复,减少工具调用频率。`,
|
|
147
|
-
cacheable: false,
|
|
148
|
-
dynamic: true,
|
|
149
|
-
cached: false,
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
162
|
export function buildSkillsSection(skills) {
|
|
153
163
|
if (skills.length === 0) {
|
|
154
164
|
return {
|
|
@@ -160,11 +170,22 @@ export function buildSkillsSection(skills) {
|
|
|
160
170
|
cached: false,
|
|
161
171
|
};
|
|
162
172
|
}
|
|
163
|
-
|
|
173
|
+
// Progressive skills:system 仅索引(name/desc/tags/triggers),禁止注入正文
|
|
174
|
+
const DESC_MAX = 160;
|
|
175
|
+
const lines = skills.map((s) => {
|
|
176
|
+
let desc = (s.description || "(无描述)").replace(/\s+/g, " ").trim();
|
|
177
|
+
if (desc.length > DESC_MAX)
|
|
178
|
+
desc = desc.slice(0, DESC_MAX - 1) + "…";
|
|
179
|
+
const tags = s.tags?.length ? ` tags=[${s.tags.join(",")}]` : "";
|
|
180
|
+
const triggers = s.triggers?.length ? ` triggers=[${s.triggers.join(",")}]` : "";
|
|
181
|
+
return `- ${s.name}: ${desc}${tags}${triggers}`;
|
|
182
|
+
});
|
|
164
183
|
return {
|
|
165
184
|
id: SECTION_IDS.SKILLS,
|
|
166
185
|
title: "可用技能",
|
|
167
|
-
content:
|
|
186
|
+
content: `【可用技能 · 渐进索引】仅名称与描述;**不要假设已掌握正文**。` +
|
|
187
|
+
`需要步骤时必须 skill name="<名>" 或 /skill <名> 加载全文。\n` +
|
|
188
|
+
lines.join("\n"),
|
|
168
189
|
cacheable: false,
|
|
169
190
|
dynamic: true,
|
|
170
191
|
cached: false,
|
|
@@ -182,9 +203,19 @@ export function buildMCPSection(serverInfo) {
|
|
|
182
203
|
cached: false,
|
|
183
204
|
};
|
|
184
205
|
}
|
|
185
|
-
|
|
206
|
+
/** Default budgets keep repo map from dominating context window. */
|
|
207
|
+
export const REPOMAP_DEFAULT_MAX_SYMBOLS = 200;
|
|
208
|
+
export const REPOMAP_DEFAULT_MAX_CHARS = 6_000;
|
|
209
|
+
export function buildRepoMapSection(symbols, options = {}) {
|
|
210
|
+
const maxSymbols = Math.max(1, options.maxSymbols ?? REPOMAP_DEFAULT_MAX_SYMBOLS);
|
|
211
|
+
const maxChars = Math.max(500, options.maxChars ?? REPOMAP_DEFAULT_MAX_CHARS);
|
|
212
|
+
const limited = symbols.length > maxSymbols
|
|
213
|
+
? [...symbols]
|
|
214
|
+
.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line)
|
|
215
|
+
.slice(0, maxSymbols)
|
|
216
|
+
: symbols;
|
|
186
217
|
const fileGroups = new Map();
|
|
187
|
-
for (const sym of
|
|
218
|
+
for (const sym of limited) {
|
|
188
219
|
if (!fileGroups.has(sym.file)) {
|
|
189
220
|
fileGroups.set(sym.file, []);
|
|
190
221
|
}
|
|
@@ -192,16 +223,29 @@ export function buildRepoMapSection(symbols) {
|
|
|
192
223
|
}
|
|
193
224
|
const lines = [];
|
|
194
225
|
const sortedFiles = Array.from(fileGroups.keys()).sort();
|
|
226
|
+
let truncatedByChars = false;
|
|
195
227
|
for (const file of sortedFiles) {
|
|
196
228
|
lines.push(`📄 ${file}`);
|
|
197
229
|
const fileSymbols = fileGroups.get(file);
|
|
198
230
|
fileSymbols.sort((a, b) => a.line - b.line);
|
|
199
231
|
for (const sym of fileSymbols) {
|
|
200
|
-
|
|
232
|
+
const next = ` - [${sym.type}] L${sym.line}: ${sym.name} (${sym.signature})`;
|
|
233
|
+
const draft = [...lines, next].join("\n");
|
|
234
|
+
if (draft.length > maxChars) {
|
|
235
|
+
truncatedByChars = true;
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
lines.push(next);
|
|
201
239
|
}
|
|
240
|
+
if (truncatedByChars)
|
|
241
|
+
break;
|
|
202
242
|
}
|
|
243
|
+
const truncatedByCount = symbols.length > maxSymbols;
|
|
244
|
+
const note = truncatedByCount || truncatedByChars
|
|
245
|
+
? `\n\n…已截断:共 ${symbols.length} 符号,展示 ${limited.length}${truncatedByChars ? "(字符预算)" : ""}。可用 search/code_symbols 精确定位。`
|
|
246
|
+
: "";
|
|
203
247
|
const content = lines.length > 0
|
|
204
|
-
? `已编制项目符号索引,供全局参考:\n\n${lines.join("\n")}`
|
|
248
|
+
? `已编制项目符号索引,供全局参考:\n\n${lines.join("\n")}${note}`
|
|
205
249
|
: "当前没有索引到项目符号。运行 /repomap 命令来索引符号。";
|
|
206
250
|
return {
|
|
207
251
|
id: SECTION_IDS.REPOMAP,
|
|
@@ -212,7 +256,7 @@ export function buildRepoMapSection(symbols) {
|
|
|
212
256
|
};
|
|
213
257
|
}
|
|
214
258
|
// --- 默认 Registry Builder ---
|
|
215
|
-
export function buildDefaultRegistry(tools
|
|
259
|
+
export function buildDefaultRegistry(tools) {
|
|
216
260
|
const registry = new PromptSectionRegistry();
|
|
217
261
|
registry.register(buildIntroSection("轻灵", getPackageVersion()));
|
|
218
262
|
registry.register(buildToolsSection(tools));
|
|
@@ -222,7 +266,6 @@ export function buildDefaultRegistry(tools, usedTokens = 0, maxTokens = 120_000)
|
|
|
222
266
|
registry.register(buildRepoMapSection([]));
|
|
223
267
|
registry.register(buildSessionSection());
|
|
224
268
|
registry.register(buildMemorySection());
|
|
225
|
-
registry.register(buildTokenBudgetSection(usedTokens, maxTokens));
|
|
226
269
|
return registry;
|
|
227
270
|
}
|
|
228
271
|
// --- Prompt Builder Utility ---
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verification.d.ts","sourceRoot":"","sources":["../../src/pipeline/verification.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"verification.d.ts","sourceRoot":"","sources":["../../src/pipeline/verification.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,kBAAkB,EAGnB,MAAM,aAAa,CAAC;AAmBrB,2EAA2E;AAC3E,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,KAAK;gBADL,MAAM,EAAE,MAAM,EACd,KAAK,GAAE,MAAwB;IAGnC,MAAM,CACV,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,EACvB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,CAAC;YAoBhB,aAAa;YAkBb,OAAO;IAoBrB,OAAO,CAAC,aAAa;IA0BrB,OAAO,CAAC,eAAe;CAyCxB"}
|