@kenkaiiii/ggcoder 5.37.0 → 5.38.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/dist/app-sidecar.js +31 -18
- package/dist/app-sidecar.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +12 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +15 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +34 -75
- package/dist/config.js.map +1 -1
- package/dist/config.test.js +19 -11
- package/dist/config.test.js.map +1 -1
- package/dist/core/agent-session.d.ts +24 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +31 -6
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/agents.d.ts +29 -1
- package/dist/core/agents.d.ts.map +1 -1
- package/dist/core/agents.js +47 -97
- package/dist/core/agents.js.map +1 -1
- package/dist/core/agents.test.js +85 -5
- package/dist/core/agents.test.js.map +1 -1
- package/dist/core/bundled-agents.d.ts +3 -0
- package/dist/core/bundled-agents.d.ts.map +1 -0
- package/dist/core/bundled-agents.js +252 -0
- package/dist/core/bundled-agents.js.map +1 -0
- package/dist/core/shutdown.d.ts +71 -0
- package/dist/core/shutdown.d.ts.map +1 -0
- package/dist/core/shutdown.js +144 -0
- package/dist/core/shutdown.js.map +1 -0
- package/dist/core/shutdown.test.d.ts +2 -0
- package/dist/core/shutdown.test.d.ts.map +1 -0
- package/dist/core/shutdown.test.js +160 -0
- package/dist/core/shutdown.test.js.map +1 -0
- package/dist/core/subagent-manager.d.ts +9 -0
- package/dist/core/subagent-manager.d.ts.map +1 -1
- package/dist/core/subagent-manager.js +45 -12
- package/dist/core/subagent-manager.js.map +1 -1
- package/dist/core/subagent-manager.test.js +13 -7
- package/dist/core/subagent-manager.test.js.map +1 -1
- package/dist/modes/agent-home-mode.d.ts.map +1 -1
- package/dist/modes/agent-home-mode.js +15 -11
- package/dist/modes/agent-home-mode.js.map +1 -1
- package/dist/modes/json-mode.d.ts +8 -0
- package/dist/modes/json-mode.d.ts.map +1 -1
- package/dist/modes/json-mode.js +2 -0
- package/dist/modes/json-mode.js.map +1 -1
- package/dist/modes/serve-mode.d.ts +2 -1
- package/dist/modes/serve-mode.d.ts.map +1 -1
- package/dist/modes/serve-mode.js +15 -9
- package/dist/modes/serve-mode.js.map +1 -1
- package/dist/modes/subagent-worker-mode.d.ts +5 -0
- package/dist/modes/subagent-worker-mode.d.ts.map +1 -1
- package/dist/modes/subagent-worker-mode.js.map +1 -1
- package/dist/system-prompt.d.ts +31 -0
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +81 -0
- package/dist/system-prompt.js.map +1 -1
- package/dist/system-prompt.test.js +48 -1
- package/dist/system-prompt.test.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/prompt-hints.d.ts +9 -0
- package/dist/tools/prompt-hints.d.ts.map +1 -1
- package/dist/tools/prompt-hints.js +38 -0
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/tools/subagent-control.d.ts.map +1 -1
- package/dist/tools/subagent-control.js +20 -5
- package/dist/tools/subagent-control.js.map +1 -1
- package/dist/tools/subagent-control.test.js +34 -1
- package/dist/tools/subagent-control.test.js.map +1 -1
- package/dist/tools/subagent-shared.d.ts +19 -0
- package/dist/tools/subagent-shared.d.ts.map +1 -1
- package/dist/tools/subagent-shared.js +32 -5
- package/dist/tools/subagent-shared.js.map +1 -1
- package/dist/tools/subagent-shared.test.js +42 -8
- package/dist/tools/subagent-shared.test.js.map +1 -1
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +11 -8
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/subagent.test.js +3 -0
- package/dist/tools/subagent.test.js.map +1 -1
- package/package.json +4 -4
package/dist/core/agents.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { stripBom } from "../utils/text.js";
|
|
4
|
+
import { log } from "./logger.js";
|
|
5
|
+
import { BUILTIN_TOOL_NAMES } from "../tools/prompt-hints.js";
|
|
6
|
+
import { BUNDLED_AGENTS } from "./bundled-agents.js";
|
|
4
7
|
/**
|
|
5
8
|
* MCP server names an agent's `tools:` list asks for, derived from any
|
|
6
9
|
* `mcp__<server>__<tool>` entries.
|
|
@@ -22,6 +25,30 @@ export function mcpServersForAgent(tools) {
|
|
|
22
25
|
}
|
|
23
26
|
return [...servers];
|
|
24
27
|
}
|
|
28
|
+
const BUILTIN_TOOL_NAME_SET = new Set(BUILTIN_TOOL_NAMES);
|
|
29
|
+
// mcp__<server>__<tool> — the only non-built-in shape a session can register.
|
|
30
|
+
const MCP_TOOL_PATTERN = /^mcp__(.+?)__(.+)$/;
|
|
31
|
+
/**
|
|
32
|
+
* Report `tools:` entries the session could never register.
|
|
33
|
+
*
|
|
34
|
+
* `AgentSession` filters its tool set by name, so an unknown entry is dropped
|
|
35
|
+
* without a word: the agent just quietly loses a capability (or, if every name
|
|
36
|
+
* is wrong, runs with nothing). Warn instead — and stay non-fatal, because a
|
|
37
|
+
* bad agent file must never take down a session.
|
|
38
|
+
*
|
|
39
|
+
* @returns the unrecognized names, for tests and callers that want to report.
|
|
40
|
+
*/
|
|
41
|
+
export function validateAgentTools(agent, origin) {
|
|
42
|
+
const unknown = agent.tools.filter((tool) => !BUILTIN_TOOL_NAME_SET.has(tool) && !MCP_TOOL_PATTERN.test(tool));
|
|
43
|
+
if (unknown.length > 0) {
|
|
44
|
+
log("WARN", "agents", "Agent lists unknown tools; they will be ignored", {
|
|
45
|
+
agent: agent.name,
|
|
46
|
+
origin,
|
|
47
|
+
unknown,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return unknown;
|
|
51
|
+
}
|
|
25
52
|
/**
|
|
26
53
|
* Discover agent definitions from global and project-local directories.
|
|
27
54
|
* Agent files are markdown with frontmatter (similar to skills).
|
|
@@ -48,6 +75,7 @@ export async function discoverAgents(options) {
|
|
|
48
75
|
const userNames = new Set(agents.map((a) => a.name.toLowerCase()));
|
|
49
76
|
for (const bundled of BUNDLED_AGENTS) {
|
|
50
77
|
if (!userNames.has(bundled.name.toLowerCase())) {
|
|
78
|
+
validateAgentTools(bundled, "bundled");
|
|
51
79
|
agents.push(bundled);
|
|
52
80
|
}
|
|
53
81
|
}
|
|
@@ -72,6 +100,7 @@ async function loadAgentsFromDir(dir, source) {
|
|
|
72
100
|
if (!agent.name) {
|
|
73
101
|
agent.name = path.basename(file, ".md");
|
|
74
102
|
}
|
|
103
|
+
validateAgentTools(agent, filePath);
|
|
75
104
|
agents.push(agent);
|
|
76
105
|
}
|
|
77
106
|
catch {
|
|
@@ -99,6 +128,8 @@ export function parseAgentFile(rawInput, source) {
|
|
|
99
128
|
let name = "";
|
|
100
129
|
let description = "";
|
|
101
130
|
let tools = [];
|
|
131
|
+
let model;
|
|
132
|
+
let context;
|
|
102
133
|
let systemPrompt = raw;
|
|
103
134
|
if (raw.startsWith("---")) {
|
|
104
135
|
const endIndex = raw.indexOf("---", 3);
|
|
@@ -121,106 +152,25 @@ export function parseAgentFile(rawInput, source) {
|
|
|
121
152
|
.map((t) => t.trim())
|
|
122
153
|
.filter(Boolean);
|
|
123
154
|
}
|
|
155
|
+
else if (key === "model") {
|
|
156
|
+
if (value)
|
|
157
|
+
model = value;
|
|
158
|
+
}
|
|
159
|
+
else if (key === "context") {
|
|
160
|
+
const normalized = value.toLowerCase();
|
|
161
|
+
if (normalized === "project" || normalized === "none")
|
|
162
|
+
context = normalized;
|
|
163
|
+
}
|
|
164
|
+
// Unknown keys are ignored on purpose: agent files stay
|
|
165
|
+
// forward-compatible with fields a newer ggcoder understands.
|
|
124
166
|
}
|
|
125
167
|
}
|
|
126
168
|
}
|
|
127
|
-
return { name, description, tools, systemPrompt, source };
|
|
169
|
+
return { name, description, tools, model, context, systemPrompt, source };
|
|
128
170
|
}
|
|
129
171
|
// ── Bundled agents ─────────────────────────────────────────
|
|
130
|
-
// Shipped with ggcoder. Used by /bullet-proof and
|
|
131
|
-
// subagent call. User-defined agents with the same name
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
You review code rigorously: you look for bypasses that would matter in practice, not pattern violations. You trace data flow from untrusted sources to dangerous sinks. Assume a sophisticated adversary with SDK-level access, an intercepting proxy, the public source, and time — and identify what would expose the project to them.
|
|
135
|
-
|
|
136
|
-
## Core discipline
|
|
137
|
-
|
|
138
|
-
1. **Trace, don't pattern-match.** Every finding must have a concrete Source → Sink path traced through the actual code.
|
|
139
|
-
2. **Untrusted vs trusted inputs.** Before flagging, decide whether the input is *actually* reachable by an untrusted source, or a settings constant / build-time string / hardcoded value. If the latter, drop it.
|
|
140
|
-
3. **Vulnerability scenarios are mandatory.** Describe how the weakness is triggered: input, system response, resulting exposure. If you cannot describe the steps, you cannot flag the finding.
|
|
141
|
-
4. **Confidence ≥0.8 only.** Better to miss theoretical issues than flood the report with noise.
|
|
142
|
-
5. **Framework awareness.** ORM parameterization, auto-escape, memory-safe languages, JSX/template escaping all eliminate entire vuln classes. Don't flag what the framework already handles.
|
|
143
|
-
|
|
144
|
-
## Output for each finding
|
|
145
|
-
|
|
146
|
-
- **Location**: file:line
|
|
147
|
-
- **Category**: <slug> (sql_injection, ssrf, prototype_pollution, supply_chain, ...)
|
|
148
|
-
- **CWE**: CWE-XXX
|
|
149
|
-
- **Confidence**: 0.0–1.0
|
|
150
|
-
- **Source → Sink**: the actual data path
|
|
151
|
-
- **Vulnerability scenario**: numbered steps showing trigger → response → exposure
|
|
152
|
-
- **Impact**: what is exposed, blast radius
|
|
153
|
-
- **Fix**: concrete code-level remediation
|
|
154
|
-
|
|
155
|
-
## Hard exclusions — do NOT report:
|
|
156
|
-
|
|
157
|
-
- DOS / rate-limiting / memory exhaustion without an amplification primitive
|
|
158
|
-
- Theoretical race conditions without a demonstrable window
|
|
159
|
-
- Regex-DOS without untrusted-supplied regex
|
|
160
|
-
- Log spoofing / log injection (cosmetic)
|
|
161
|
-
- SSRF where the URL is a settings constant or build-time string
|
|
162
|
-
- Env-var trust (env is server-controlled by definition)
|
|
163
|
-
- Client-side authentication theatre on a server-validated endpoint
|
|
164
|
-
- React/Vue/Angular XSS without unsafe sinks (\`dangerouslySetInnerHTML\`, \`v-html\`, \`bypassSecurityTrust*\` are the only real ones)
|
|
165
|
-
- Shell-script command injection without an untrusted input path
|
|
166
|
-
- Findings in documentation, example code, or test fixtures
|
|
167
|
-
- Insecure-by-design dev tooling that doesn't ship to users
|
|
168
|
-
- "Could be improved" preferences with no demonstrable path
|
|
169
|
-
|
|
170
|
-
Return findings ranked Critical → High → Medium. If nothing meets the bar, return "No high-confidence findings."`;
|
|
171
|
-
const SKEPTIC_PROMPT = `You are Skeptic, a rigorous reviewer whose job is to DISPROVE security findings handed to you. You start from "this is a false positive" and only conclude otherwise if the evidence is overwhelming.
|
|
172
|
-
|
|
173
|
-
## Your mission
|
|
174
|
-
|
|
175
|
-
Given a security finding, attempt to break it. Try every angle:
|
|
176
|
-
|
|
177
|
-
1. **Reachability**: Is the claimed source actually untrusted-controlled, or a settings constant, build-time value, or env var (server-controlled by definition)?
|
|
178
|
-
2. **Control flow**: Even if the source is real, does control flow actually reach the sink? Is there a guard, validator, or sanitizer in between that the original audit missed?
|
|
179
|
-
3. **Framework handling**: Would the framework (ORM, template engine, auto-escape, memory-safe language) eliminate this entire vuln class?
|
|
180
|
-
4. **Trigger feasibility**: Can you actually construct the input that triggers the path? What would the response look like? If you can't construct it, the finding stands on theory.
|
|
181
|
-
5. **Severity inflation**: Is the impact overstated? "RCE" claims often turn out to be "writes to a sandboxed file path."
|
|
182
|
-
|
|
183
|
-
Read the code yourself. Do not trust the audit's claim — verify each step.
|
|
184
|
-
|
|
185
|
-
## Verdict format
|
|
186
|
-
|
|
187
|
-
For each finding, return:
|
|
188
|
-
- **Verdict**: CONFIRMED / DROP / DOWNGRADE
|
|
189
|
-
- **Reason**: 1-3 sentence explanation
|
|
190
|
-
- **If CONFIRMED**: re-state the vulnerability scenario in your own words to prove you verified it end-to-end
|
|
191
|
-
- **If DROP**: cite which exclusion rule applies, or which step in the chain fails
|
|
192
|
-
- **If DOWNGRADE**: new severity + reason
|
|
193
|
-
|
|
194
|
-
## Hard exclusions — automatic DROP regardless of source:
|
|
195
|
-
|
|
196
|
-
- DOS / rate-limiting / memory exhaustion without an amplification primitive
|
|
197
|
-
- Theoretical race conditions without a demonstrable window
|
|
198
|
-
- Regex-DOS without untrusted-supplied regex
|
|
199
|
-
- Log spoofing / log injection (cosmetic only)
|
|
200
|
-
- SSRF where the URL is a settings constant or build-time string
|
|
201
|
-
- Env-var trust ("untrusted source controls \\$HOME" — env is server-controlled)
|
|
202
|
-
- Client-side authn checks on endpoints that re-validate server-side
|
|
203
|
-
- React/Vue/Angular XSS unless \`dangerouslySetInnerHTML\` / \`v-html\` / \`bypassSecurityTrust*\` is the sink
|
|
204
|
-
- Shell-script command injection without an untrusted input path
|
|
205
|
-
- Findings in documentation, example code, or test fixtures
|
|
206
|
-
- Insecure-by-design dev tooling that doesn't ship to users
|
|
207
|
-
- "Could be improved" preferences with no demonstrable path
|
|
208
|
-
|
|
209
|
-
Be rigorous. The cost of a false positive is the user's trust in the entire report.`;
|
|
210
|
-
export const BUNDLED_AGENTS = [
|
|
211
|
-
{
|
|
212
|
-
name: "auditor",
|
|
213
|
-
description: "Defensive security analyst — finds exploitable weaknesses with concrete vulnerability scenarios",
|
|
214
|
-
tools: ["read", "grep", "find", "ls", "bash", "web_fetch", "web_search"],
|
|
215
|
-
systemPrompt: AUDITOR_PROMPT,
|
|
216
|
-
source: "bundled",
|
|
217
|
-
},
|
|
218
|
-
{
|
|
219
|
-
name: "skeptic",
|
|
220
|
-
description: "Rigorous false-positive reviewer — disproves security findings and applies exclusion rules strictly",
|
|
221
|
-
tools: ["read", "grep", "find", "ls", "bash", "web_fetch", "web_search"],
|
|
222
|
-
systemPrompt: SKEPTIC_PROMPT,
|
|
223
|
-
source: "bundled",
|
|
224
|
-
},
|
|
225
|
-
];
|
|
172
|
+
// Shipped with ggcoder (see ./bundled-agents.ts). Used by /bullet-proof and
|
|
173
|
+
// available to any subagent call. User-defined agents with the same name
|
|
174
|
+
// override these because they come first in `discoverAgents`.
|
|
175
|
+
export { BUNDLED_AGENTS };
|
|
226
176
|
//# sourceMappingURL=agents.js.map
|
package/dist/core/agents.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/core/agents.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/core/agents.ts"],"names":[],"mappings":"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"}
|
package/dist/core/agents.test.js
CHANGED
|
@@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest";
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { BUNDLED_AGENTS, discoverAgents, mcpServersForAgent, parseAgentFile } from "./agents.js";
|
|
5
|
+
import { BUNDLED_AGENTS, discoverAgents, mcpServersForAgent, parseAgentFile, validateAgentTools, } from "./agents.js";
|
|
6
6
|
describe("mcpServersForAgent", () => {
|
|
7
7
|
it("derives server names from mcp__<server>__<tool> entries", () => {
|
|
8
8
|
expect(mcpServersForAgent([
|
|
@@ -33,11 +33,91 @@ describe("mcpServersForAgent", () => {
|
|
|
33
33
|
expect(mcpServersForAgent(agent.tools)).toEqual(["kencode-search"]);
|
|
34
34
|
});
|
|
35
35
|
});
|
|
36
|
+
describe("parseAgentFile", () => {
|
|
37
|
+
it("reads the model and context policies from frontmatter", () => {
|
|
38
|
+
const agent = parseAgentFile([
|
|
39
|
+
"---",
|
|
40
|
+
"name: scout",
|
|
41
|
+
"description: Recon",
|
|
42
|
+
"tools: read, grep",
|
|
43
|
+
"model: fast",
|
|
44
|
+
"context: none",
|
|
45
|
+
"---",
|
|
46
|
+
"Scout it.",
|
|
47
|
+
].join("\n"), "project");
|
|
48
|
+
expect(agent.model).toBe("fast");
|
|
49
|
+
expect(agent.context).toBe("none");
|
|
50
|
+
expect(agent.systemPrompt).toBe("Scout it.");
|
|
51
|
+
});
|
|
52
|
+
it("leaves both unset when absent, and ignores unknown keys", () => {
|
|
53
|
+
const agent = parseAgentFile(["---", "name: scout", "description: Recon", "temperature: 0.3", "---", "Scout."].join("\n"), "project");
|
|
54
|
+
expect(agent.model).toBeUndefined();
|
|
55
|
+
expect(agent.context).toBeUndefined();
|
|
56
|
+
expect(agent.name).toBe("scout");
|
|
57
|
+
});
|
|
58
|
+
it("accepts an explicit model id and rejects a nonsense context", () => {
|
|
59
|
+
const agent = parseAgentFile([
|
|
60
|
+
"---",
|
|
61
|
+
"name: scout",
|
|
62
|
+
"description: Recon",
|
|
63
|
+
"model: claude-haiku-4-5",
|
|
64
|
+
"context: sometimes",
|
|
65
|
+
"---",
|
|
66
|
+
"Scout.",
|
|
67
|
+
].join("\n"), "project");
|
|
68
|
+
expect(agent.model).toBe("claude-haiku-4-5");
|
|
69
|
+
expect(agent.context).toBeUndefined();
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
describe("validateAgentTools", () => {
|
|
73
|
+
const base = {
|
|
74
|
+
name: "scout",
|
|
75
|
+
description: "Recon",
|
|
76
|
+
systemPrompt: "x",
|
|
77
|
+
source: "project",
|
|
78
|
+
};
|
|
79
|
+
it("accepts built-in and mcp__<server>__<tool> names", () => {
|
|
80
|
+
expect(validateAgentTools({ ...base, tools: ["read", "code_search", "mcp__kencode-search__searchCode"] }, "test")).toEqual([]);
|
|
81
|
+
});
|
|
82
|
+
it("reports names no session could ever register", () => {
|
|
83
|
+
expect(validateAgentTools({ ...base, tools: ["read", "webfetch", "Bash", "mcp__broken"] }, "test")).toEqual(["webfetch", "Bash", "mcp__broken"]);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
36
86
|
describe("bundled agents", () => {
|
|
37
|
-
it("ships
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
87
|
+
it("ships all six agents on a fresh install", () => {
|
|
88
|
+
expect(BUNDLED_AGENTS.map((a) => a.name).sort()).toEqual([
|
|
89
|
+
"auditor",
|
|
90
|
+
"bee",
|
|
91
|
+
"owl",
|
|
92
|
+
"researcher",
|
|
93
|
+
"skeptic",
|
|
94
|
+
"worker",
|
|
95
|
+
]);
|
|
96
|
+
});
|
|
97
|
+
it("lists only tools a session can actually register", () => {
|
|
98
|
+
for (const agent of BUNDLED_AGENTS) {
|
|
99
|
+
expect(validateAgentTools(agent, "bundled"), agent.name).toEqual([]);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
it("declares its model policy instead of leaving it to inference", () => {
|
|
103
|
+
for (const agent of BUNDLED_AGENTS) {
|
|
104
|
+
expect(agent.model, agent.name).toBeDefined();
|
|
105
|
+
}
|
|
106
|
+
// Only cheap structural recon opts out of the parent's model.
|
|
107
|
+
const fast = BUNDLED_AGENTS.filter((a) => a.model === "fast").map((a) => a.name);
|
|
108
|
+
expect(fast).toEqual(["owl"]);
|
|
109
|
+
});
|
|
110
|
+
it("writes descriptions that route — distinct, and never 'does anything'", () => {
|
|
111
|
+
const descriptions = BUNDLED_AGENTS.map((a) => a.description);
|
|
112
|
+
expect(new Set(descriptions).size).toBe(BUNDLED_AGENTS.length);
|
|
113
|
+
for (const description of descriptions) {
|
|
114
|
+
expect(description.toLowerCase()).not.toContain("does anything");
|
|
115
|
+
expect(description.length).toBeGreaterThan(40);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
it("gives the researcher live code search so it cannot fall back to training data", () => {
|
|
119
|
+
const researcher = BUNDLED_AGENTS.find((a) => a.name === "researcher");
|
|
120
|
+
expect(mcpServersForAgent(researcher.tools)).toEqual(["kencode-search"]);
|
|
41
121
|
});
|
|
42
122
|
it("does not shadow bundled agents unless the user defines that name", async () => {
|
|
43
123
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "gg-agents-"));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.test.js","sourceRoot":"","sources":["../../src/core/agents.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,
|
|
1
|
+
{"version":3,"file":"agents.test.js","sourceRoot":"","sources":["../../src/core/agents.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundled-agents.d.ts","sourceRoot":"","sources":["../../src/core/bundled-agents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAkMnD,eAAO,MAAM,cAAc,EAAE,eAAe,EAuE3C,CAAC"}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent definitions that ship with every ggcoder install.
|
|
3
|
+
*
|
|
4
|
+
* These are TypeScript constants rather than `assets/*.md` on purpose: the
|
|
5
|
+
* desktop sidecar bundler (`bundle-sidecar.mjs`) externalizes asset trees, so a
|
|
6
|
+
* new one is a packaging risk, while constants compile straight into `dist`.
|
|
7
|
+
*
|
|
8
|
+
* They are also NOT seeded into `~/.gg/agents`. A seeded file shadows every
|
|
9
|
+
* future improvement forever (user-dir agents win by design), which is exactly
|
|
10
|
+
* the bug `removeShadowingSeededAgents` exists to undo. Users who want to
|
|
11
|
+
* customize one still can — writing `~/.gg/agents/<name>.md` overrides the
|
|
12
|
+
* bundled definition of the same name.
|
|
13
|
+
*
|
|
14
|
+
* `description` is the routing signal the dispatcher reads, so each one names
|
|
15
|
+
* concrete task shapes ("Use when…") instead of describing the agent's vibe.
|
|
16
|
+
*/
|
|
17
|
+
const OWL_PROMPT = `You are Owl, a sharp-eyed codebase explorer.
|
|
18
|
+
You map how THIS repository fits together — structure, symbols, call chains, patterns. You work only from local code and never research the web (that's \`researcher\`).
|
|
19
|
+
|
|
20
|
+
When given a task:
|
|
21
|
+
1. Fix the scope — the exact symbol, pattern, or question to resolve
|
|
22
|
+
2. \`find\`/\`ls\` to map the relevant directories
|
|
23
|
+
3. \`code_search\` for "where is X implemented" in TS/JS; \`grep\` for exact strings and other languages
|
|
24
|
+
4. \`read\` the key files to confirm details — never report a call chain you haven't read
|
|
25
|
+
5. Trace connections — exports, imports, callers, data flow
|
|
26
|
+
|
|
27
|
+
Structure the answer as:
|
|
28
|
+
- **Answer**: the direct answer, first
|
|
29
|
+
- **Files**: each relevant path + one line on what it holds
|
|
30
|
+
- **Connections**: who calls/imports what
|
|
31
|
+
- **Flags**: anything surprising, risky, or ambiguous
|
|
32
|
+
|
|
33
|
+
Explore widely, report tightly. Miss nothing, waste no words.`;
|
|
34
|
+
const BEE_PROMPT = `You are Bee, an industrious task worker.
|
|
35
|
+
You complete an assigned task end-to-end — writing code, running commands, fixing bugs, refactoring — and deliver a working result, not a description of one.
|
|
36
|
+
|
|
37
|
+
When given a task:
|
|
38
|
+
1. Understand what's asked and explore the relevant code for context
|
|
39
|
+
2. Implement directly, in minimal focused changes that match the surrounding code
|
|
40
|
+
3. Verify: run the narrowest check that proves the change (typecheck or the nearest test), and fix what breaks
|
|
41
|
+
4. Report concisely
|
|
42
|
+
|
|
43
|
+
## Stop when
|
|
44
|
+
- The task is done and your verification passes — OR
|
|
45
|
+
- You're blocked (ambiguous requirement, missing dependency, a failure you can't resolve without guessing). Stop and report the blocker; don't thrash or expand scope to force it.
|
|
46
|
+
|
|
47
|
+
Do the work, don't just describe it. Don't over-engineer, and don't refactor what you weren't asked to touch.`;
|
|
48
|
+
const RESEARCHER_PROMPT = `You are Researcher, a deep-dive analyst.
|
|
49
|
+
You answer questions the code alone can't settle — dependency behavior, API contracts, framework internals, version differences, best practices — by cross-referencing THIS codebase against authoritative external sources. For pure in-repo tracing with no web, defer to \`owl\`.
|
|
50
|
+
|
|
51
|
+
When given a research task:
|
|
52
|
+
1. Pin down the question — what must be resolved, and what counts as proof
|
|
53
|
+
2. Ground it in the code — read the call sites and conventions that matter here
|
|
54
|
+
3. Verify against authoritative sources — \`source_path\` for the installed dependency's real source, \`web_fetch\` for official docs and changelogs, the kencode-search tools for real public usage. Never assert an API, flag, or default from memory
|
|
55
|
+
4. Reconcile — where does this repo agree with or diverge from the source?
|
|
56
|
+
|
|
57
|
+
Structure the answer as:
|
|
58
|
+
- **Summary**: the direct answer (2-3 sentences)
|
|
59
|
+
- **Evidence**: the specific files, doc URLs, package versions, or source paths that back it
|
|
60
|
+
- **Risks**: mismatches, stale assumptions, or gotchas
|
|
61
|
+
|
|
62
|
+
Be exhaustive in research, compressed in reporting. Cite sources; don't guess.`;
|
|
63
|
+
const WORKER_PROMPT = `You are Worker, a branch-isolated implementer.
|
|
64
|
+
|
|
65
|
+
Your job is to implement a scoped change on its own git branch, verify it works, and open a PR. You always work on a fresh branch — never commit to the current branch directly.
|
|
66
|
+
|
|
67
|
+
## Workflow
|
|
68
|
+
|
|
69
|
+
1. **Branch**: Create and switch to a new branch from the current HEAD.
|
|
70
|
+
- Branch name format: \`batch/<short-kebab-description>\`
|
|
71
|
+
- Run: \`git checkout -b batch/<name>\`
|
|
72
|
+
|
|
73
|
+
2. **Implement**: Make the assigned change. Follow any conventions and patterns described in your task.
|
|
74
|
+
|
|
75
|
+
3. **Self-review**: Before committing, review your own diff (\`git diff\`) for:
|
|
76
|
+
- Code that duplicates existing utilities (search the codebase first)
|
|
77
|
+
- Redundant state, copy-paste, leaky abstractions
|
|
78
|
+
- Unnecessary work, missed concurrency, hot-path bloat
|
|
79
|
+
- Fix any issues found.
|
|
80
|
+
|
|
81
|
+
4. **Test**: Run the project's test suite. Fix failures **your change caused**. If a failure is pre-existing or outside your assigned unit, do NOT expand scope to chase it — leave it and note it in the report. Scope wins over green.
|
|
82
|
+
|
|
83
|
+
5. **Commit & Push**:
|
|
84
|
+
- Stage specific files (not \`git add -A\`)
|
|
85
|
+
- Write a clear, descriptive commit message
|
|
86
|
+
- \`git push -u origin <branch-name>\`
|
|
87
|
+
|
|
88
|
+
6. **Open PR**: \`gh pr create --title "<title>" --body "<description>"\`. If \`gh\` is unavailable or the push fails, note it.
|
|
89
|
+
|
|
90
|
+
7. **Switch back**: \`git checkout -\` to the original branch.
|
|
91
|
+
|
|
92
|
+
## Stop when
|
|
93
|
+
- The change is implemented, self-reviewed, and pushed with a PR open — OR
|
|
94
|
+
- You cannot proceed without exceeding scope, touching unrelated code, or fixing a pre-existing failure. Stop and report rather than sprawl.
|
|
95
|
+
|
|
96
|
+
## What to report — lead with exactly these lines
|
|
97
|
+
- **PR**: \`<url>\` — or \`PR: none — <reason>\`
|
|
98
|
+
- **Changed**: files touched + one line each
|
|
99
|
+
- **Tests**: pass / fail, and which failures were left as out-of-scope
|
|
100
|
+
- **Notes**: assumptions made, anything left for follow-up
|
|
101
|
+
|
|
102
|
+
## Rules
|
|
103
|
+
|
|
104
|
+
- Never commit to main/master or the branch you started on
|
|
105
|
+
- Always switch back to the original branch when done
|
|
106
|
+
- Keep changes minimal and scoped to your assigned unit
|
|
107
|
+
- If something is unclear, make your best judgment and note the assumption`;
|
|
108
|
+
const AUDITOR_PROMPT = `You are Auditor, a defensive security analyst tasked with finding exploitable weaknesses in this codebase so the team can patch them before the project ships.
|
|
109
|
+
|
|
110
|
+
You review code rigorously: you look for bypasses that would matter in practice, not pattern violations. You trace data flow from untrusted sources to dangerous sinks. Assume a sophisticated adversary with SDK-level access, an intercepting proxy, the public source, and time — and identify what would expose the project to them.
|
|
111
|
+
|
|
112
|
+
## Core discipline
|
|
113
|
+
|
|
114
|
+
1. **Trace, don't pattern-match.** Every finding must have a concrete Source → Sink path traced through the actual code.
|
|
115
|
+
2. **Untrusted vs trusted inputs.** Before flagging, decide whether the input is *actually* reachable by an untrusted source, or a settings constant / build-time string / hardcoded value. If the latter, drop it.
|
|
116
|
+
3. **Vulnerability scenarios are mandatory.** Describe how the weakness is triggered: input, system response, resulting exposure. If you cannot describe the steps, you cannot flag the finding.
|
|
117
|
+
4. **Confidence ≥0.8 only.** Better to miss theoretical issues than flood the report with noise.
|
|
118
|
+
5. **Framework awareness.** ORM parameterization, auto-escape, memory-safe languages, JSX/template escaping all eliminate entire vuln classes. Don't flag what the framework already handles.
|
|
119
|
+
|
|
120
|
+
## Output for each finding
|
|
121
|
+
|
|
122
|
+
- **Location**: file:line
|
|
123
|
+
- **Category**: <slug> (sql_injection, ssrf, prototype_pollution, supply_chain, ...)
|
|
124
|
+
- **CWE**: CWE-XXX
|
|
125
|
+
- **Confidence**: 0.0–1.0
|
|
126
|
+
- **Source → Sink**: the actual data path
|
|
127
|
+
- **Vulnerability scenario**: numbered steps showing trigger → response → exposure
|
|
128
|
+
- **Impact**: what is exposed, blast radius
|
|
129
|
+
- **Fix**: concrete code-level remediation
|
|
130
|
+
|
|
131
|
+
## Hard exclusions — do NOT report:
|
|
132
|
+
|
|
133
|
+
- DOS / rate-limiting / memory exhaustion without an amplification primitive
|
|
134
|
+
- Theoretical race conditions without a demonstrable window
|
|
135
|
+
- Regex-DOS without untrusted-supplied regex
|
|
136
|
+
- Log spoofing / log injection (cosmetic)
|
|
137
|
+
- SSRF where the URL is a settings constant or build-time string
|
|
138
|
+
- Env-var trust (env is server-controlled by definition)
|
|
139
|
+
- Client-side authentication theatre on a server-validated endpoint
|
|
140
|
+
- React/Vue/Angular XSS without unsafe sinks (\`dangerouslySetInnerHTML\`, \`v-html\`, \`bypassSecurityTrust*\` are the only real ones)
|
|
141
|
+
- Shell-script command injection without an untrusted input path
|
|
142
|
+
- Findings in documentation, example code, or test fixtures
|
|
143
|
+
- Insecure-by-design dev tooling that doesn't ship to users
|
|
144
|
+
- "Could be improved" preferences with no demonstrable path
|
|
145
|
+
|
|
146
|
+
Return findings ranked Critical → High → Medium. If nothing meets the bar, return "No high-confidence findings."`;
|
|
147
|
+
const SKEPTIC_PROMPT = `You are Skeptic, a rigorous reviewer whose job is to DISPROVE security findings handed to you. You start from "this is a false positive" and only conclude otherwise if the evidence is overwhelming.
|
|
148
|
+
|
|
149
|
+
## Your mission
|
|
150
|
+
|
|
151
|
+
Given a security finding, attempt to break it. Try every angle:
|
|
152
|
+
|
|
153
|
+
1. **Reachability**: Is the claimed source actually untrusted-controlled, or a settings constant, build-time value, or env var (server-controlled by definition)?
|
|
154
|
+
2. **Control flow**: Even if the source is real, does control flow actually reach the sink? Is there a guard, validator, or sanitizer in between that the original audit missed?
|
|
155
|
+
3. **Framework handling**: Would the framework (ORM, template engine, auto-escape, memory-safe language) eliminate this entire vuln class?
|
|
156
|
+
4. **Trigger feasibility**: Can you actually construct the input that triggers the path? What would the response look like? If you can't construct it, the finding stands on theory.
|
|
157
|
+
5. **Severity inflation**: Is the impact overstated? "RCE" claims often turn out to be "writes to a sandboxed file path."
|
|
158
|
+
|
|
159
|
+
Read the code yourself. Do not trust the audit's claim — verify each step.
|
|
160
|
+
|
|
161
|
+
## Verdict format
|
|
162
|
+
|
|
163
|
+
For each finding, return:
|
|
164
|
+
- **Verdict**: CONFIRMED / DROP / DOWNGRADE
|
|
165
|
+
- **Reason**: 1-3 sentence explanation
|
|
166
|
+
- **If CONFIRMED**: re-state the vulnerability scenario in your own words to prove you verified it end-to-end
|
|
167
|
+
- **If DROP**: cite which exclusion rule applies, or which step in the chain fails
|
|
168
|
+
- **If DOWNGRADE**: new severity + reason
|
|
169
|
+
|
|
170
|
+
## Hard exclusions — automatic DROP regardless of source:
|
|
171
|
+
|
|
172
|
+
- DOS / rate-limiting / memory exhaustion without an amplification primitive
|
|
173
|
+
- Theoretical race conditions without a demonstrable window
|
|
174
|
+
- Regex-DOS without untrusted-supplied regex
|
|
175
|
+
- Log spoofing / log injection (cosmetic only)
|
|
176
|
+
- SSRF where the URL is a settings constant or build-time string
|
|
177
|
+
- Env-var trust ("untrusted source controls \\$HOME" — env is server-controlled)
|
|
178
|
+
- Client-side authn checks on endpoints that re-validate server-side
|
|
179
|
+
- React/Vue/Angular XSS unless \`dangerouslySetInnerHTML\` / \`v-html\` / \`bypassSecurityTrust*\` is the sink
|
|
180
|
+
- Shell-script command injection without an untrusted input path
|
|
181
|
+
- Findings in documentation, example code, or test fixtures
|
|
182
|
+
- Insecure-by-design dev tooling that doesn't ship to users
|
|
183
|
+
- "Could be improved" preferences with no demonstrable path
|
|
184
|
+
|
|
185
|
+
Be rigorous. The cost of a false positive is the user's trust in the entire report.`;
|
|
186
|
+
export const BUNDLED_AGENTS = [
|
|
187
|
+
{
|
|
188
|
+
name: "bee",
|
|
189
|
+
description: "Use for a self-contained implementation task on the current branch: write a module, fix a bug, run a migration, make a failing test pass. Edits files and runs commands. Use `worker` instead when the change needs its own git branch and a PR; use `owl` when nothing should be modified.",
|
|
190
|
+
tools: ["read", "write", "edit", "bash", "find", "grep", "code_search", "ls", "source_path"],
|
|
191
|
+
model: "inherit",
|
|
192
|
+
systemPrompt: BEE_PROMPT,
|
|
193
|
+
source: "bundled",
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
name: "owl",
|
|
197
|
+
description: 'Use for read-only questions about THIS repository: "where is X implemented", "what calls Y", "how does module Z fit together", tracing a data flow or mapping a directory. Never edits and never uses the web.',
|
|
198
|
+
tools: ["read", "grep", "find", "ls", "code_search", "source_path"],
|
|
199
|
+
// Structural recon is mechanical pattern work; the cheap tier handles it
|
|
200
|
+
// well and keeps wide fan-out affordable.
|
|
201
|
+
model: "fast",
|
|
202
|
+
// Conventions and style rules don't change where a symbol is defined, and
|
|
203
|
+
// skipping them keeps recon fast (matching Claude Code's Explore agent).
|
|
204
|
+
context: "none",
|
|
205
|
+
systemPrompt: OWL_PROMPT,
|
|
206
|
+
source: "bundled",
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: "researcher",
|
|
210
|
+
description: "Use when an answer needs sources outside this repo: a dependency's real behavior, an API contract, framework internals, version/changelog differences, or current best practice. Reads installed package source, official docs, and public code. Use `owl` when the repo alone can settle it.",
|
|
211
|
+
tools: [
|
|
212
|
+
"read",
|
|
213
|
+
"grep",
|
|
214
|
+
"find",
|
|
215
|
+
"ls",
|
|
216
|
+
"code_search",
|
|
217
|
+
"source_path",
|
|
218
|
+
"web_fetch",
|
|
219
|
+
"web_search",
|
|
220
|
+
"mcp__kencode-search__searchCode",
|
|
221
|
+
"mcp__kencode-search__referenceSources",
|
|
222
|
+
],
|
|
223
|
+
model: "inherit",
|
|
224
|
+
systemPrompt: RESEARCHER_PROMPT,
|
|
225
|
+
source: "bundled",
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
name: "worker",
|
|
229
|
+
description: "Use to land one scoped change in isolation: it creates a `batch/*` git branch, implements, self-reviews, tests, commits, pushes, and opens a PR, then returns to the original branch. Use for parallel fan-out of independent units of work. Use `bee` for in-place edits with no branch or PR.",
|
|
230
|
+
tools: ["read", "write", "edit", "bash", "find", "grep", "code_search", "ls"],
|
|
231
|
+
model: "inherit",
|
|
232
|
+
systemPrompt: WORKER_PROMPT,
|
|
233
|
+
source: "bundled",
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
name: "auditor",
|
|
237
|
+
description: "Use for a defensive security review of code or a diff: traces untrusted input to dangerous sinks and reports exploitable findings with concrete vulnerability scenarios, CWE, and fixes. Read-only.",
|
|
238
|
+
tools: ["read", "grep", "find", "ls", "code_search", "bash", "web_fetch", "web_search"],
|
|
239
|
+
model: "inherit",
|
|
240
|
+
systemPrompt: AUDITOR_PROMPT,
|
|
241
|
+
source: "bundled",
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: "skeptic",
|
|
245
|
+
description: "Use to triage security findings before reporting them: re-verifies each claimed source→sink path in the code and returns CONFIRMED / DROP / DOWNGRADE with the reason. Pair it with `auditor` output. Read-only.",
|
|
246
|
+
tools: ["read", "grep", "find", "ls", "code_search", "bash", "web_fetch", "web_search"],
|
|
247
|
+
model: "inherit",
|
|
248
|
+
systemPrompt: SKEPTIC_PROMPT,
|
|
249
|
+
source: "bundled",
|
|
250
|
+
},
|
|
251
|
+
];
|
|
252
|
+
//# sourceMappingURL=bundled-agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundled-agents.js","sourceRoot":"","sources":["../../src/core/bundled-agents.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;8DAgB2C,CAAC;AAE/D,MAAM,UAAU,GAAG;;;;;;;;;;;;;8GAa2F,CAAC;AAE/G,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;+EAcqD,CAAC;AAEhF,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2EA4CqD,CAAC;AAE5E,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iHAsC0F,CAAC;AAElH,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oFAsC6D,CAAC;AAErF,MAAM,CAAC,MAAM,cAAc,GAAsB;IAC/C;QACE,IAAI,EAAE,KAAK;QACX,WAAW,EACT,6RAA6R;QAC/R,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,CAAC;QAC5F,KAAK,EAAE,SAAS;QAChB,YAAY,EAAE,UAAU;QACxB,MAAM,EAAE,SAAS;KAClB;IACD;QACE,IAAI,EAAE,KAAK;QACX,WAAW,EACT,gNAAgN;QAClN,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,aAAa,CAAC;QACnE,yEAAyE;QACzE,0CAA0C;QAC1C,KAAK,EAAE,MAAM;QACb,0EAA0E;QAC1E,yEAAyE;QACzE,OAAO,EAAE,MAAM;QACf,YAAY,EAAE,UAAU;QACxB,MAAM,EAAE,SAAS;KAClB;IACD;QACE,IAAI,EAAE,YAAY;QAClB,WAAW,EACT,+RAA+R;QACjS,KAAK,EAAE;YACL,MAAM;YACN,MAAM;YACN,MAAM;YACN,IAAI;YACJ,aAAa;YACb,aAAa;YACb,WAAW;YACX,YAAY;YACZ,iCAAiC;YACjC,uCAAuC;SACxC;QACD,KAAK,EAAE,SAAS;QAChB,YAAY,EAAE,iBAAiB;QAC/B,MAAM,EAAE,SAAS;KAClB;IACD;QACE,IAAI,EAAE,QAAQ;QACd,WAAW,EACT,iSAAiS;QACnS,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,CAAC;QAC7E,KAAK,EAAE,SAAS;QAChB,YAAY,EAAE,aAAa;QAC3B,MAAM,EAAE,SAAS;KAClB;IACD;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EACT,qMAAqM;QACvM,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,CAAC;QACvF,KAAK,EAAE,SAAS;QAChB,YAAY,EAAE,cAAc;QAC5B,MAAM,EAAE,SAAS;KAClB;IACD;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EACT,kNAAkN;QACpN,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,CAAC;QACvF,KAAK,EAAE,SAAS;QAChB,YAAY,EAAE,cAAc;QAC5B,MAAM,EAAE,SAAS;KAClB;CACF,CAAC"}
|