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