pi-loop 0.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/agents/code-reviewer.md +82 -0
- package/agents/coder.md +82 -0
- package/agents/decomposer.md +55 -0
- package/agents/judge.md +90 -0
- package/agents/review-optimizer.md +44 -0
- package/dist/agents/adapter.d.ts +9 -0
- package/dist/agents/adapter.d.ts.map +1 -0
- package/dist/agents/adapter.js +41 -0
- package/dist/agents/adapter.js.map +1 -0
- package/dist/agents/factory.d.ts +7 -0
- package/dist/agents/factory.d.ts.map +1 -0
- package/dist/agents/factory.js +49 -0
- package/dist/agents/factory.js.map +1 -0
- package/dist/agents/registry.d.ts +4 -0
- package/dist/agents/registry.d.ts.map +1 -0
- package/dist/agents/registry.js +98 -0
- package/dist/agents/registry.js.map +1 -0
- package/dist/agents/types.d.ts +21 -0
- package/dist/agents/types.d.ts.map +1 -0
- package/dist/agents/types.js +39 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/cli/args.d.ts +38 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +160 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/commands.d.ts +29 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +362 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/output.d.ts +33 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +99 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/config/defaults.d.ts +3 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +31 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/loader.d.ts +11 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +70 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/types.d.ts +41 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +5 -0
- package/dist/config/types.js.map +1 -0
- package/dist/core/checkpoint.d.ts +18 -0
- package/dist/core/checkpoint.d.ts.map +1 -0
- package/dist/core/checkpoint.js +32 -0
- package/dist/core/checkpoint.js.map +1 -0
- package/dist/core/judge.d.ts +11 -0
- package/dist/core/judge.d.ts.map +1 -0
- package/dist/core/judge.js +91 -0
- package/dist/core/judge.js.map +1 -0
- package/dist/core/learnings.d.ts +4 -0
- package/dist/core/learnings.d.ts.map +1 -0
- package/dist/core/learnings.js +33 -0
- package/dist/core/learnings.js.map +1 -0
- package/dist/core/orchestrator.d.ts +64 -0
- package/dist/core/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestrator.js +499 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/core/plan.d.ts +7 -0
- package/dist/core/plan.d.ts.map +1 -0
- package/dist/core/plan.js +15 -0
- package/dist/core/plan.js.map +1 -0
- package/dist/core/readiness-policy.d.ts +11 -0
- package/dist/core/readiness-policy.d.ts.map +1 -0
- package/dist/core/readiness-policy.js +24 -0
- package/dist/core/readiness-policy.js.map +1 -0
- package/dist/core/scheduling-policy.d.ts +9 -0
- package/dist/core/scheduling-policy.d.ts.map +1 -0
- package/dist/core/scheduling-policy.js +56 -0
- package/dist/core/scheduling-policy.js.map +1 -0
- package/dist/core/task-backend.d.ts +55 -0
- package/dist/core/task-backend.d.ts.map +1 -0
- package/dist/core/task-backend.js +76 -0
- package/dist/core/task-backend.js.map +1 -0
- package/dist/core/task-state.d.ts +26 -0
- package/dist/core/task-state.d.ts.map +1 -0
- package/dist/core/task-state.js +182 -0
- package/dist/core/task-state.js.map +1 -0
- package/dist/core/wiring.d.ts +12 -0
- package/dist/core/wiring.d.ts.map +1 -0
- package/dist/core/wiring.js +131 -0
- package/dist/core/wiring.js.map +1 -0
- package/dist/git/conflict.d.ts +6 -0
- package/dist/git/conflict.d.ts.map +1 -0
- package/dist/git/conflict.js +25 -0
- package/dist/git/conflict.js.map +1 -0
- package/dist/git/repo.d.ts +13 -0
- package/dist/git/repo.d.ts.map +1 -0
- package/dist/git/repo.js +74 -0
- package/dist/git/repo.js.map +1 -0
- package/dist/git/same-branch.d.ts +9 -0
- package/dist/git/same-branch.d.ts.map +1 -0
- package/dist/git/same-branch.js +55 -0
- package/dist/git/same-branch.js.map +1 -0
- package/dist/git/worktree.d.ts +14 -0
- package/dist/git/worktree.d.ts.map +1 -0
- package/dist/git/worktree.js +78 -0
- package/dist/git/worktree.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/linear/backend.d.ts +38 -0
- package/dist/integrations/linear/backend.d.ts.map +1 -0
- package/dist/integrations/linear/backend.js +374 -0
- package/dist/integrations/linear/backend.js.map +1 -0
- package/dist/integrations/linear/client.d.ts +19 -0
- package/dist/integrations/linear/client.d.ts.map +1 -0
- package/dist/integrations/linear/client.js +86 -0
- package/dist/integrations/linear/client.js.map +1 -0
- package/dist/integrations/linear/comment-templates.d.ts +14 -0
- package/dist/integrations/linear/comment-templates.d.ts.map +1 -0
- package/dist/integrations/linear/comment-templates.js +50 -0
- package/dist/integrations/linear/comment-templates.js.map +1 -0
- package/dist/integrations/linear/contract.d.ts +15 -0
- package/dist/integrations/linear/contract.d.ts.map +1 -0
- package/dist/integrations/linear/contract.js +86 -0
- package/dist/integrations/linear/contract.js.map +1 -0
- package/dist/integrations/linear/types.d.ts +39 -0
- package/dist/integrations/linear/types.d.ts.map +1 -0
- package/dist/integrations/linear/types.js +2 -0
- package/dist/integrations/linear/types.js.map +1 -0
- package/dist/swarm/pool.d.ts +33 -0
- package/dist/swarm/pool.d.ts.map +1 -0
- package/dist/swarm/pool.js +182 -0
- package/dist/swarm/pool.js.map +1 -0
- package/dist/swarm/scheduler.d.ts +38 -0
- package/dist/swarm/scheduler.d.ts.map +1 -0
- package/dist/swarm/scheduler.js +191 -0
- package/dist/swarm/scheduler.js.map +1 -0
- package/dist/swarm/worker.d.ts +49 -0
- package/dist/swarm/worker.d.ts.map +1 -0
- package/dist/swarm/worker.js +180 -0
- package/dist/swarm/worker.js.map +1 -0
- package/dist/tools/bash-tool.d.ts +24 -0
- package/dist/tools/bash-tool.d.ts.map +1 -0
- package/dist/tools/bash-tool.js +177 -0
- package/dist/tools/bash-tool.js.map +1 -0
- package/dist/tools/file-tools.d.ts +3 -0
- package/dist/tools/file-tools.d.ts.map +1 -0
- package/dist/tools/file-tools.js +68 -0
- package/dist/tools/file-tools.js.map +1 -0
- package/dist/tools/git-tools.d.ts +3 -0
- package/dist/tools/git-tools.d.ts.map +1 -0
- package/dist/tools/git-tools.js +44 -0
- package/dist/tools/git-tools.js.map +1 -0
- package/dist/tools/learnings-tool.d.ts +3 -0
- package/dist/tools/learnings-tool.d.ts.map +1 -0
- package/dist/tools/learnings-tool.js +48 -0
- package/dist/tools/learnings-tool.js.map +1 -0
- package/dist/tools/plan-tool.d.ts +3 -0
- package/dist/tools/plan-tool.d.ts.map +1 -0
- package/dist/tools/plan-tool.js +24 -0
- package/dist/tools/plan-tool.js.map +1 -0
- package/dist/tools/task-tools.d.ts +3 -0
- package/dist/tools/task-tools.d.ts.map +1 -0
- package/dist/tools/task-tools.js +108 -0
- package/dist/tools/task-tools.js.map +1 -0
- package/dist/tools/test-tool.d.ts +3 -0
- package/dist/tools/test-tool.d.ts.map +1 -0
- package/dist/tools/test-tool.js +43 -0
- package/dist/tools/test-tool.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single worker lifecycle -- coder/reviewer loop for a single task.
|
|
3
|
+
*/
|
|
4
|
+
import type { PiLoopConfig } from "../config/types.js";
|
|
5
|
+
import type { Task } from "../core/task-state.js";
|
|
6
|
+
export interface WorkerResult {
|
|
7
|
+
success: boolean;
|
|
8
|
+
taskId: string;
|
|
9
|
+
commitHash?: string;
|
|
10
|
+
rejection?: string;
|
|
11
|
+
attempts: number;
|
|
12
|
+
changedFiles: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface WorkerDeps {
|
|
15
|
+
createCoderAgent: () => Promise<{
|
|
16
|
+
run: (prompt: string) => Promise<string>;
|
|
17
|
+
}>;
|
|
18
|
+
createReviewerAgent: () => Promise<{
|
|
19
|
+
run: (prompt: string) => Promise<string>;
|
|
20
|
+
}>;
|
|
21
|
+
gitStage: () => Promise<void>;
|
|
22
|
+
gitDiff: () => Promise<string>;
|
|
23
|
+
gitCommit: (message: string) => Promise<string>;
|
|
24
|
+
gitReset: () => Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Executes the worker cycle:
|
|
28
|
+
* 1. Create coder agent, prompt with task description
|
|
29
|
+
* 2. Stage all changes and get git diff
|
|
30
|
+
* 3. Create reviewer agent, prompt with diff + task description
|
|
31
|
+
* 4. Parse reviewer response for PASS/FAIL
|
|
32
|
+
* 5. On PASS: commit changes, return success
|
|
33
|
+
* 6. On FAIL: reset changes, return rejection with reviewer's feedback
|
|
34
|
+
*/
|
|
35
|
+
export declare function runWorker(task: Task, config: PiLoopConfig, deps: WorkerDeps): Promise<WorkerResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Extracts PASS/FAIL verdict from reviewer's response.
|
|
38
|
+
*
|
|
39
|
+
* Strategy (in priority order):
|
|
40
|
+
* 1. Check if response starts with PASS or FAIL (strongest signal)
|
|
41
|
+
* 2. Look for standalone PASS/FAIL on its own line (e.g., "**PASS**", "PASS", "FAIL:")
|
|
42
|
+
* 3. Use the LAST occurrence of PASS/FAIL (conclusion, not analysis)
|
|
43
|
+
* 4. Fall back to first occurrence
|
|
44
|
+
*/
|
|
45
|
+
export declare function parseReviewVerdict(response: string): {
|
|
46
|
+
passed: boolean;
|
|
47
|
+
feedback: string;
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/swarm/worker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAElD,MAAM,WAAW,YAAY;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IAC1B,gBAAgB,EAAE,MAAM,OAAO,CAAC;QAAE,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;KAAE,CAAC,CAAC;IAC9E,mBAAmB,EAAE,MAAM,OAAO,CAAC;QAAE,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;KAAE,CAAC,CAAC;IACjF,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/B,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAOD;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAwGzG;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG;IACrD,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CACjB,CAwDA"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single worker lifecycle -- coder/reviewer loop for a single task.
|
|
3
|
+
*/
|
|
4
|
+
function workerLog(taskId, message) {
|
|
5
|
+
const ts = new Date().toISOString().slice(11, 19);
|
|
6
|
+
console.error(`[worker ${ts}] ${taskId}: ${message}`);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Executes the worker cycle:
|
|
10
|
+
* 1. Create coder agent, prompt with task description
|
|
11
|
+
* 2. Stage all changes and get git diff
|
|
12
|
+
* 3. Create reviewer agent, prompt with diff + task description
|
|
13
|
+
* 4. Parse reviewer response for PASS/FAIL
|
|
14
|
+
* 5. On PASS: commit changes, return success
|
|
15
|
+
* 6. On FAIL: reset changes, return rejection with reviewer's feedback
|
|
16
|
+
*/
|
|
17
|
+
export async function runWorker(task, config, deps) {
|
|
18
|
+
const attempts = 1;
|
|
19
|
+
// Step 1: Create coder agent and prompt with task
|
|
20
|
+
workerLog(task.id, `coder starting: "${task.title}"`);
|
|
21
|
+
const coder = await deps.createCoderAgent();
|
|
22
|
+
const coderPrompt = [
|
|
23
|
+
`## Your Assignment: ${task.title}`,
|
|
24
|
+
"",
|
|
25
|
+
"Implement ONLY this single task. Do not look for other tasks or read Tasks.md.",
|
|
26
|
+
"",
|
|
27
|
+
"Rules:",
|
|
28
|
+
"- You MUST use the write_file tool to create files. Do NOT describe code in text.",
|
|
29
|
+
"- Use read_plan to understand the project architecture if needed.",
|
|
30
|
+
"- Use bash to run commands like npm install, npm test, etc.",
|
|
31
|
+
"- Do NOT use git_commit — the harness commits for you.",
|
|
32
|
+
"- Do NOT use update_task or read_tasks — the harness manages task status.",
|
|
33
|
+
"- Focus only on this one task. Stop when it is complete.",
|
|
34
|
+
].join("\n");
|
|
35
|
+
const coderOutput = await coder.run(coderPrompt);
|
|
36
|
+
workerLog(task.id, `coder done (${coderOutput.length} chars output)`);
|
|
37
|
+
// Step 2: Stage all changes and get git diff (includes new untracked files)
|
|
38
|
+
await deps.gitStage();
|
|
39
|
+
const diffOutput = await deps.gitDiff();
|
|
40
|
+
workerLog(task.id, `diff: ${diffOutput.length} chars (${diffOutput.split("\n").length} lines)`);
|
|
41
|
+
const changedFiles = extractChangedFiles(diffOutput);
|
|
42
|
+
if (!diffOutput.trim()) {
|
|
43
|
+
workerLog(task.id, "FAILED: no changes detected after staging");
|
|
44
|
+
return {
|
|
45
|
+
success: false,
|
|
46
|
+
taskId: task.id,
|
|
47
|
+
rejection: "Coder produced no changes",
|
|
48
|
+
attempts,
|
|
49
|
+
changedFiles: [],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (config.taskBackend === "linear" && changedFiles.length > config.linear.maxFilesPerIssue) {
|
|
53
|
+
const rejection = `FILE_BUDGET_EXCEEDED: changed ${changedFiles.length} files (max ${config.linear.maxFilesPerIssue})`;
|
|
54
|
+
workerLog(task.id, rejection);
|
|
55
|
+
await deps.gitReset();
|
|
56
|
+
return {
|
|
57
|
+
success: false,
|
|
58
|
+
taskId: task.id,
|
|
59
|
+
rejection,
|
|
60
|
+
attempts,
|
|
61
|
+
changedFiles,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// Step 3: Create reviewer agent and prompt with diff + task
|
|
65
|
+
workerLog(task.id, "reviewer starting");
|
|
66
|
+
const reviewer = await deps.createReviewerAgent();
|
|
67
|
+
const reviewPrompt = [
|
|
68
|
+
"Review the following changes for this task:",
|
|
69
|
+
"",
|
|
70
|
+
"## Task",
|
|
71
|
+
task.title,
|
|
72
|
+
"",
|
|
73
|
+
"## Diff",
|
|
74
|
+
"```diff",
|
|
75
|
+
diffOutput,
|
|
76
|
+
"```",
|
|
77
|
+
"",
|
|
78
|
+
"IMPORTANT: Your final text response MUST begin with exactly the word PASS or FAIL.",
|
|
79
|
+
"- Start with PASS if the changes correctly implement the task.",
|
|
80
|
+
"- Start with FAIL followed by specific feedback if they do not.",
|
|
81
|
+
"Do NOT use the update_task tool. Just respond with your verdict as text.",
|
|
82
|
+
].join("\n");
|
|
83
|
+
const reviewResponse = await reviewer.run(reviewPrompt);
|
|
84
|
+
workerLog(task.id, `reviewer done (${reviewResponse.length} chars)`);
|
|
85
|
+
// Step 4: Parse reviewer response
|
|
86
|
+
const verdict = parseReviewVerdict(reviewResponse);
|
|
87
|
+
workerLog(task.id, `verdict: ${verdict.passed ? "PASS" : "FAIL"}${verdict.feedback ? ` — ${verdict.feedback.slice(0, 100)}` : ""}`);
|
|
88
|
+
// Step 5/6: Act on verdict
|
|
89
|
+
if (verdict.passed) {
|
|
90
|
+
const commitHash = await deps.gitCommit(`${config.git.commitPrefix} task(${task.id}): ${task.title.slice(0, 72)}`);
|
|
91
|
+
workerLog(task.id, `committed: ${commitHash.slice(0, 8)}`);
|
|
92
|
+
return {
|
|
93
|
+
success: true,
|
|
94
|
+
taskId: task.id,
|
|
95
|
+
commitHash,
|
|
96
|
+
attempts,
|
|
97
|
+
changedFiles,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
await deps.gitReset();
|
|
101
|
+
workerLog(task.id, "changes reset after FAIL");
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
taskId: task.id,
|
|
105
|
+
rejection: verdict.feedback,
|
|
106
|
+
attempts,
|
|
107
|
+
changedFiles,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Extracts PASS/FAIL verdict from reviewer's response.
|
|
112
|
+
*
|
|
113
|
+
* Strategy (in priority order):
|
|
114
|
+
* 1. Check if response starts with PASS or FAIL (strongest signal)
|
|
115
|
+
* 2. Look for standalone PASS/FAIL on its own line (e.g., "**PASS**", "PASS", "FAIL:")
|
|
116
|
+
* 3. Use the LAST occurrence of PASS/FAIL (conclusion, not analysis)
|
|
117
|
+
* 4. Fall back to first occurrence
|
|
118
|
+
*/
|
|
119
|
+
export function parseReviewVerdict(response) {
|
|
120
|
+
const normalized = response.trim();
|
|
121
|
+
// Strategy 1: Check start of response (our prompt says "begin with PASS or FAIL")
|
|
122
|
+
const startMatch = normalized.match(/^(?:\*\*)?(?:PASS|FAIL)/i);
|
|
123
|
+
if (startMatch) {
|
|
124
|
+
const isPass = startMatch[0].toUpperCase().includes("PASS");
|
|
125
|
+
if (!isPass) {
|
|
126
|
+
const afterKeyword = normalized.slice(startMatch[0].length).trim();
|
|
127
|
+
const feedback = afterKeyword.replace(/^[:\-\u2013\u2014\s*]+/, "").trim();
|
|
128
|
+
return { passed: false, feedback: feedback || "Reviewer rejected without specific feedback" };
|
|
129
|
+
}
|
|
130
|
+
return { passed: true, feedback: "" };
|
|
131
|
+
}
|
|
132
|
+
// Strategy 2: Look for standalone PASS/FAIL on its own line (scan from end)
|
|
133
|
+
const lines = normalized.split("\n");
|
|
134
|
+
const verdictLineRe = /^\s*(?:\*\*)?(?:PASS|FAIL)(?:\*\*)?[\s:.\-]*$/i;
|
|
135
|
+
let verdictLine;
|
|
136
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
137
|
+
if (verdictLineRe.test(lines[i])) {
|
|
138
|
+
verdictLine = lines[i];
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (verdictLine) {
|
|
143
|
+
const isPass = verdictLine.toUpperCase().includes("PASS");
|
|
144
|
+
if (!isPass) {
|
|
145
|
+
return { passed: false, feedback: "Reviewer rejected (verdict on standalone line)" };
|
|
146
|
+
}
|
|
147
|
+
return { passed: true, feedback: "" };
|
|
148
|
+
}
|
|
149
|
+
// Strategy 3: Use the LAST occurrence (conclusion beats analysis)
|
|
150
|
+
const upperResponse = normalized.toUpperCase();
|
|
151
|
+
const lastPassIndex = upperResponse.lastIndexOf("PASS");
|
|
152
|
+
const lastFailIndex = upperResponse.lastIndexOf("FAIL");
|
|
153
|
+
if (lastPassIndex === -1 && lastFailIndex === -1) {
|
|
154
|
+
return {
|
|
155
|
+
passed: false,
|
|
156
|
+
feedback: "Reviewer did not provide a clear PASS/FAIL verdict",
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// The later keyword is the final verdict
|
|
160
|
+
if (lastPassIndex > lastFailIndex) {
|
|
161
|
+
return { passed: true, feedback: "" };
|
|
162
|
+
}
|
|
163
|
+
const afterFail = normalized.slice(lastFailIndex + 4).trim();
|
|
164
|
+
const feedback = afterFail.replace(/^[:\-\u2013\u2014\s*]+/, "").trim();
|
|
165
|
+
return {
|
|
166
|
+
passed: false,
|
|
167
|
+
feedback: feedback || "Reviewer rejected without specific feedback",
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function extractChangedFiles(diff) {
|
|
171
|
+
const files = new Set();
|
|
172
|
+
for (const line of diff.split("\n")) {
|
|
173
|
+
const match = line.match(/^diff --git a\/(.+?) b\/(.+)$/);
|
|
174
|
+
if (!match)
|
|
175
|
+
continue;
|
|
176
|
+
files.add(match[2]);
|
|
177
|
+
}
|
|
178
|
+
return [...files];
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/swarm/worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AgentTool } from "@mariozechner/pi-agent-core";
|
|
2
|
+
/**
|
|
3
|
+
* Check whether a bash command string contains only allowed git operations.
|
|
4
|
+
* Returns { allowed: true } if safe, or { allowed: false, violation } if blocked.
|
|
5
|
+
*
|
|
6
|
+
* Detection handles:
|
|
7
|
+
* - Chained commands (&&, ;, |)
|
|
8
|
+
* - Absolute paths (/usr/bin/git)
|
|
9
|
+
* - Global flags before the subcommand (--no-pager, -C path)
|
|
10
|
+
* - Bare `git` with no subcommand (allowed — just prints usage)
|
|
11
|
+
*/
|
|
12
|
+
export declare function isGitCommandAllowed(command: string): {
|
|
13
|
+
allowed: boolean;
|
|
14
|
+
violation?: string;
|
|
15
|
+
};
|
|
16
|
+
export declare function bashTools(workDir: string): AgentTool[];
|
|
17
|
+
/**
|
|
18
|
+
* Restricted bash tool for worker agents.
|
|
19
|
+
* Intercepts commands before execution and blocks any git subcommand
|
|
20
|
+
* not on the read-only allowlist. Returns an error message (not exception)
|
|
21
|
+
* so the agent can self-correct.
|
|
22
|
+
*/
|
|
23
|
+
export declare function restrictedBashTools(workDir: string): AgentTool[];
|
|
24
|
+
//# sourceMappingURL=bash-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-tool.d.ts","sourceRoot":"","sources":["../../src/tools/bash-tool.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAuC7D;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAmE7F;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,CAgDtD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,CAyBhE"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
const MAX_TIMEOUT_MS = 120_000;
|
|
4
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
5
|
+
/**
|
|
6
|
+
* Read-only git subcommands that workers may legitimately need.
|
|
7
|
+
* Everything not on this list is blocked.
|
|
8
|
+
*/
|
|
9
|
+
const ALLOWED_GIT_SUBCOMMANDS = new Set([
|
|
10
|
+
"status",
|
|
11
|
+
"log",
|
|
12
|
+
"diff",
|
|
13
|
+
"show",
|
|
14
|
+
"blame",
|
|
15
|
+
"ls-files",
|
|
16
|
+
"ls-tree",
|
|
17
|
+
"rev-parse",
|
|
18
|
+
"describe",
|
|
19
|
+
"shortlog",
|
|
20
|
+
"cat-file",
|
|
21
|
+
"version",
|
|
22
|
+
"help",
|
|
23
|
+
]);
|
|
24
|
+
/**
|
|
25
|
+
* Git global flags that appear before the subcommand.
|
|
26
|
+
* These are skipped when extracting the subcommand.
|
|
27
|
+
*/
|
|
28
|
+
const GIT_GLOBAL_FLAGS = new Set([
|
|
29
|
+
"--no-pager",
|
|
30
|
+
"--paginate",
|
|
31
|
+
"--no-replace-objects",
|
|
32
|
+
"--bare",
|
|
33
|
+
"--literal-pathspecs",
|
|
34
|
+
"--glob-pathspecs",
|
|
35
|
+
"--no-optional-locks",
|
|
36
|
+
]);
|
|
37
|
+
/**
|
|
38
|
+
* Check whether a bash command string contains only allowed git operations.
|
|
39
|
+
* Returns { allowed: true } if safe, or { allowed: false, violation } if blocked.
|
|
40
|
+
*
|
|
41
|
+
* Detection handles:
|
|
42
|
+
* - Chained commands (&&, ;, |)
|
|
43
|
+
* - Absolute paths (/usr/bin/git)
|
|
44
|
+
* - Global flags before the subcommand (--no-pager, -C path)
|
|
45
|
+
* - Bare `git` with no subcommand (allowed — just prints usage)
|
|
46
|
+
*/
|
|
47
|
+
export function isGitCommandAllowed(command) {
|
|
48
|
+
// Split on shell operators to handle chained commands.
|
|
49
|
+
// We split on &&, ||, ;, |, and also handle $(...) and `...` subshells
|
|
50
|
+
// by treating them as boundaries.
|
|
51
|
+
const segments = command.split(/&&|\|\||[;|]|\$\(|`/);
|
|
52
|
+
for (const segment of segments) {
|
|
53
|
+
const trimmed = segment.trim();
|
|
54
|
+
if (!trimmed)
|
|
55
|
+
continue;
|
|
56
|
+
// Tokenize the segment and find the command (first non-env-assignment token).
|
|
57
|
+
// This avoids false positives like `grep git file.ts` where "git" is an argument.
|
|
58
|
+
const tokens = trimmed.split(/\s+/);
|
|
59
|
+
let commandIdx = 0;
|
|
60
|
+
// Skip leading env var assignments (e.g. VAR=value git commit)
|
|
61
|
+
while (commandIdx < tokens.length && /^\w+=/.test(tokens[commandIdx])) {
|
|
62
|
+
commandIdx++;
|
|
63
|
+
}
|
|
64
|
+
if (commandIdx >= tokens.length)
|
|
65
|
+
continue;
|
|
66
|
+
// The command is the first token after env assignments.
|
|
67
|
+
// Check if it's `git` or an absolute path to git (e.g. /usr/bin/git).
|
|
68
|
+
const cmd = tokens[commandIdx];
|
|
69
|
+
const isGit = cmd === "git" || /\/git$/.test(cmd);
|
|
70
|
+
if (!isGit)
|
|
71
|
+
continue;
|
|
72
|
+
// Everything after `git` — extract the subcommand, skipping global flags.
|
|
73
|
+
const gitArgs = tokens.slice(commandIdx + 1);
|
|
74
|
+
if (gitArgs.length === 0) {
|
|
75
|
+
// Bare `git` with no subcommand — just prints usage, allowed
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
let subcommand;
|
|
79
|
+
for (let i = 0; i < gitArgs.length; i++) {
|
|
80
|
+
const token = gitArgs[i];
|
|
81
|
+
if (GIT_GLOBAL_FLAGS.has(token))
|
|
82
|
+
continue;
|
|
83
|
+
// -C <path> and -c <key=value> consume the next token
|
|
84
|
+
if (token === "-C" || token === "-c") {
|
|
85
|
+
i++; // skip the argument
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// Skip flags that start with - (other global flags we haven't listed)
|
|
89
|
+
if (token.startsWith("-"))
|
|
90
|
+
continue;
|
|
91
|
+
subcommand = token;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
if (!subcommand) {
|
|
95
|
+
// Only flags after git, no subcommand — allowed (e.g. `git --version`)
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (!ALLOWED_GIT_SUBCOMMANDS.has(subcommand)) {
|
|
99
|
+
return {
|
|
100
|
+
allowed: false,
|
|
101
|
+
violation: `Blocked git subcommand: "git ${subcommand}". Workers may only use read-only git commands: ${[...ALLOWED_GIT_SUBCOMMANDS].join(", ")}.`,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return { allowed: true };
|
|
106
|
+
}
|
|
107
|
+
export function bashTools(workDir) {
|
|
108
|
+
// bash tool intentionally uses shell execution via execFile — that is its purpose
|
|
109
|
+
const bashTool = {
|
|
110
|
+
name: "bash",
|
|
111
|
+
label: "Run Shell Command",
|
|
112
|
+
description: "Execute a shell command via bash and return stdout and stderr. Default timeout is 30 seconds, maximum 120 seconds.",
|
|
113
|
+
parameters: Type.Object({
|
|
114
|
+
command: Type.String({ description: "The shell command to execute" }),
|
|
115
|
+
timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (default 30, max 120)" })),
|
|
116
|
+
}),
|
|
117
|
+
execute: async (_toolCallId, params, signal) => {
|
|
118
|
+
const { command, timeout } = params;
|
|
119
|
+
const timeoutMs = Math.min((timeout ?? DEFAULT_TIMEOUT_MS / 1000) * 1000, MAX_TIMEOUT_MS);
|
|
120
|
+
return new Promise((resolve, reject) => {
|
|
121
|
+
const child = execFile("/bin/bash", ["-c", command], { cwd: workDir, timeout: timeoutMs }, (error, stdout, stderr) => {
|
|
122
|
+
const output = [stdout, stderr].filter(Boolean).join("\n");
|
|
123
|
+
if (error && !stdout && !stderr) {
|
|
124
|
+
reject(new Error(`Command failed: ${error.message}`));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const exitCode = error ? 1 : 0;
|
|
128
|
+
resolve({
|
|
129
|
+
content: [{ type: "text", text: output || "(no output)" }],
|
|
130
|
+
details: { exitCode },
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
if (signal) {
|
|
134
|
+
const onAbort = () => {
|
|
135
|
+
child.kill("SIGTERM");
|
|
136
|
+
reject(new Error("Command aborted"));
|
|
137
|
+
};
|
|
138
|
+
if (signal.aborted) {
|
|
139
|
+
child.kill("SIGTERM");
|
|
140
|
+
reject(new Error("Command aborted"));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
return [bashTool];
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Restricted bash tool for worker agents.
|
|
152
|
+
* Intercepts commands before execution and blocks any git subcommand
|
|
153
|
+
* not on the read-only allowlist. Returns an error message (not exception)
|
|
154
|
+
* so the agent can self-correct.
|
|
155
|
+
*/
|
|
156
|
+
export function restrictedBashTools(workDir) {
|
|
157
|
+
const [unrestricted] = bashTools(workDir);
|
|
158
|
+
const restrictedBash = {
|
|
159
|
+
...unrestricted,
|
|
160
|
+
description: "Execute a shell command via bash. Default timeout is 30s, max 120s. " +
|
|
161
|
+
"RESTRICTION: git commands are limited to read-only operations (status, log, diff, show, blame, ls-files, ls-tree, rev-parse, describe, shortlog, cat-file). " +
|
|
162
|
+
"Mutating git commands (commit, add, reset, push, pull, checkout, branch, merge, rebase, stash, clean, init) are blocked.",
|
|
163
|
+
execute: async (toolCallId, params, signal) => {
|
|
164
|
+
const { command } = params;
|
|
165
|
+
const check = isGitCommandAllowed(command);
|
|
166
|
+
if (!check.allowed) {
|
|
167
|
+
return {
|
|
168
|
+
content: [{ type: "text", text: `ERROR: ${check.violation}` }],
|
|
169
|
+
details: { exitCode: 1 },
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
return unrestricted.execute(toolCallId, params, signal);
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
return [restrictedBash];
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=bash-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-tool.js","sourceRoot":"","sources":["../../src/tools/bash-tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-tools.d.ts","sourceRoot":"","sources":["../../src/tools/file-tools.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,6BAA6B,CAAC;AAc9E,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,CAwDtD"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
2
|
+
import { dirname, isAbsolute, resolve } from "node:path";
|
|
3
|
+
import { Type } from "@sinclair/typebox";
|
|
4
|
+
function textResult(text) {
|
|
5
|
+
return { content: [{ type: "text", text }], details: {} };
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Resolves a path relative to the given working directory.
|
|
9
|
+
* Absolute paths are returned as-is.
|
|
10
|
+
*/
|
|
11
|
+
function resolvePath(workDir, filePath) {
|
|
12
|
+
return isAbsolute(filePath) ? filePath : resolve(workDir, filePath);
|
|
13
|
+
}
|
|
14
|
+
export function fileTools(workDir) {
|
|
15
|
+
const readFileTool = {
|
|
16
|
+
name: "read_file",
|
|
17
|
+
label: "Read File",
|
|
18
|
+
description: "Read the contents of a file at the given path. Returns the full file content as text.",
|
|
19
|
+
parameters: Type.Object({
|
|
20
|
+
path: Type.String({ description: "Absolute or relative path to the file to read" }),
|
|
21
|
+
}),
|
|
22
|
+
execute: async (_toolCallId, params) => {
|
|
23
|
+
const { path } = params;
|
|
24
|
+
const resolved = resolvePath(workDir, path);
|
|
25
|
+
const content = await readFile(resolved, "utf-8");
|
|
26
|
+
return textResult(content);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
const writeFileTool = {
|
|
30
|
+
name: "write_file",
|
|
31
|
+
label: "Write File",
|
|
32
|
+
description: "Write content to a file. Creates parent directories if they don't exist. Overwrites existing files.",
|
|
33
|
+
parameters: Type.Object({
|
|
34
|
+
path: Type.String({ description: "Absolute or relative path to the file to write" }),
|
|
35
|
+
content: Type.String({ description: "The content to write to the file" }),
|
|
36
|
+
}),
|
|
37
|
+
execute: async (_toolCallId, params) => {
|
|
38
|
+
const { path, content } = params;
|
|
39
|
+
const resolved = resolvePath(workDir, path);
|
|
40
|
+
await mkdir(dirname(resolved), { recursive: true });
|
|
41
|
+
await writeFile(resolved, content, "utf-8");
|
|
42
|
+
return textResult(`File written: ${path}`);
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
const editFileTool = {
|
|
46
|
+
name: "edit_file",
|
|
47
|
+
label: "Edit File",
|
|
48
|
+
description: "Replace the first occurrence of old_text with new_text in a file. Throws if old_text is not found.",
|
|
49
|
+
parameters: Type.Object({
|
|
50
|
+
path: Type.String({ description: "Path to the file to edit" }),
|
|
51
|
+
old_text: Type.String({ description: "The exact text to find and replace" }),
|
|
52
|
+
new_text: Type.String({ description: "The replacement text" }),
|
|
53
|
+
}),
|
|
54
|
+
execute: async (_toolCallId, params) => {
|
|
55
|
+
const { path, old_text, new_text } = params;
|
|
56
|
+
const resolved = resolvePath(workDir, path);
|
|
57
|
+
const content = await readFile(resolved, "utf-8");
|
|
58
|
+
if (!content.includes(old_text)) {
|
|
59
|
+
throw new Error(`old_text not found in ${path}`);
|
|
60
|
+
}
|
|
61
|
+
const updated = content.replace(old_text, new_text);
|
|
62
|
+
await writeFile(resolved, updated, "utf-8");
|
|
63
|
+
return textResult(`File edited: ${path}`);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
return [readFileTool, writeFileTool, editFileTool];
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=file-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-tools.js","sourceRoot":"","sources":["../../src/tools/file-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-tools.d.ts","sourceRoot":"","sources":["../../src/tools/git-tools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,6BAA6B,CAAC;AAkB9E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,CA4BjD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { Type } from "@sinclair/typebox";
|
|
3
|
+
function textResult(text) {
|
|
4
|
+
return { content: [{ type: "text", text }], details: {} };
|
|
5
|
+
}
|
|
6
|
+
function execGit(args, cwd) {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
execFile("git", args, { cwd }, (error, stdout, stderr) => {
|
|
9
|
+
if (error) {
|
|
10
|
+
reject(new Error(`git ${args[0]} failed: ${stderr || error.message}`));
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
resolve(stdout);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
export function gitTools(cwd) {
|
|
18
|
+
const gitDiffTool = {
|
|
19
|
+
name: "git_diff",
|
|
20
|
+
label: "Git Diff",
|
|
21
|
+
description: "Show the git diff of all changes against HEAD in the working directory.",
|
|
22
|
+
parameters: Type.Object({}),
|
|
23
|
+
execute: async () => {
|
|
24
|
+
const stdout = await execGit(["diff", "HEAD"], cwd);
|
|
25
|
+
return textResult(stdout || "(no changes)");
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
const gitCommitTool = {
|
|
29
|
+
name: "git_commit",
|
|
30
|
+
label: "Git Commit",
|
|
31
|
+
description: "Stage all changes and create a git commit with the given message. The message will be prefixed with the configured commit prefix.",
|
|
32
|
+
parameters: Type.Object({
|
|
33
|
+
message: Type.String({ description: "Commit message (will be prefixed with configured prefix)" }),
|
|
34
|
+
}),
|
|
35
|
+
execute: async (_toolCallId, params) => {
|
|
36
|
+
const { message } = params;
|
|
37
|
+
await execGit(["add", "-A"], cwd);
|
|
38
|
+
const stdout = await execGit(["commit", "-m", message], cwd);
|
|
39
|
+
return textResult(stdout);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
return [gitDiffTool, gitCommitTool];
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=git-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-tools.js","sourceRoot":"","sources":["../../src/tools/git-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAGzC,SAAS,UAAU,CAAC,IAAY;IAC/B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAC3D,CAAC;AAED,SAAS,OAAO,CAAC,IAAc,EAAE,GAAW;IAC3C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtC,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YACxD,IAAI,KAAK,EAAE,CAAC;gBACX,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,YAAY,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;gBACvE,OAAO;YACR,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,CAAC;QACjB,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAW;IACnC,MAAM,WAAW,GAAc;QAC9B,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,yEAAyE;QACtF,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,KAAK,IAAI,EAAE;YACnB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;YACpD,OAAO,UAAU,CAAC,MAAM,IAAI,cAAc,CAAC,CAAC;QAC7C,CAAC;KACD,CAAC;IAEF,MAAM,aAAa,GAAc;QAChC,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,YAAY;QACnB,WAAW,EAAE,mIAAmI;QAChJ,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC;YACvB,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,0DAA0D,EAAE,CAAC;SACjG,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE;YACtC,MAAM,EAAE,OAAO,EAAE,GAAG,MAA6B,CAAC;YAClD,MAAM,OAAO,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;YAClC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC;YAC7D,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;KACD,CAAC;IAEF,OAAO,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learnings-tool.d.ts","sourceRoot":"","sources":["../../src/tools/learnings-tool.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,6BAA6B,CAAC;AAM9E,wBAAgB,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,EAAE,CA0CjE"}
|