tandem-mode 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +191 -0
  3. package/README.sr.md +194 -0
  4. package/dist/agent/clipboard.js +26 -0
  5. package/dist/agent/clipboard.js.map +1 -0
  6. package/dist/agent/loop.js +157 -0
  7. package/dist/agent/loop.js.map +1 -0
  8. package/dist/agent/pricing.js +21 -0
  9. package/dist/agent/pricing.js.map +1 -0
  10. package/dist/agent/session.js +78 -0
  11. package/dist/agent/session.js.map +1 -0
  12. package/dist/agent/tools/edit.js +78 -0
  13. package/dist/agent/tools/edit.js.map +1 -0
  14. package/dist/agent/tools/gitDiff.js +42 -0
  15. package/dist/agent/tools/gitDiff.js.map +1 -0
  16. package/dist/agent/tools/index.js +24 -0
  17. package/dist/agent/tools/index.js.map +1 -0
  18. package/dist/agent/tools/listDir.js +29 -0
  19. package/dist/agent/tools/listDir.js.map +1 -0
  20. package/dist/agent/tools/readFile.js +40 -0
  21. package/dist/agent/tools/readFile.js.map +1 -0
  22. package/dist/agent/tools/search.js +51 -0
  23. package/dist/agent/tools/search.js.map +1 -0
  24. package/dist/agent/tools/shell.js +95 -0
  25. package/dist/agent/tools/shell.js.map +1 -0
  26. package/dist/agent/tools/types.js +11 -0
  27. package/dist/agent/tools/types.js.map +1 -0
  28. package/dist/agent/tools/viewImage.js +34 -0
  29. package/dist/agent/tools/viewImage.js.map +1 -0
  30. package/dist/agent/tools/webSearch.js +27 -0
  31. package/dist/agent/tools/webSearch.js.map +1 -0
  32. package/dist/agent/usage.js +36 -0
  33. package/dist/agent/usage.js.map +1 -0
  34. package/dist/benchmark/runner.js +176 -0
  35. package/dist/benchmark/runner.js.map +1 -0
  36. package/dist/benchmark/tasks/bitwiseBulkPriceWizard.js +50 -0
  37. package/dist/benchmark/tasks/bitwiseBulkPriceWizard.js.map +1 -0
  38. package/dist/benchmark/types.js +2 -0
  39. package/dist/benchmark/types.js.map +1 -0
  40. package/dist/cli.js +442 -0
  41. package/dist/cli.js.map +1 -0
  42. package/dist/config/credentials.js +80 -0
  43. package/dist/config/credentials.js.map +1 -0
  44. package/dist/config/env.js +12 -0
  45. package/dist/config/env.js.map +1 -0
  46. package/dist/config/schema.js +6 -0
  47. package/dist/config/schema.js.map +1 -0
  48. package/dist/config/store.js +35 -0
  49. package/dist/config/store.js.map +1 -0
  50. package/dist/deepseek/client.js +145 -0
  51. package/dist/deepseek/client.js.map +1 -0
  52. package/dist/deepseek/types.js +2 -0
  53. package/dist/deepseek/types.js.map +1 -0
  54. package/dist/deepseek/vision.js +59 -0
  55. package/dist/deepseek/vision.js.map +1 -0
  56. package/dist/deepseek/webSearch.js +43 -0
  57. package/dist/deepseek/webSearch.js.map +1 -0
  58. package/dist/orchestrator/orchestrate.js +63 -0
  59. package/dist/orchestrator/orchestrate.js.map +1 -0
  60. package/dist/orchestrator/planner.js +48 -0
  61. package/dist/orchestrator/planner.js.map +1 -0
  62. package/dist/orchestrator/repoMap.js +52 -0
  63. package/dist/orchestrator/repoMap.js.map +1 -0
  64. package/dist/orchestrator/reviewer.js +53 -0
  65. package/dist/orchestrator/reviewer.js.map +1 -0
  66. package/dist/orchestrator/types.js +18 -0
  67. package/dist/orchestrator/types.js.map +1 -0
  68. package/dist/repl/commands.js +139 -0
  69. package/dist/repl/commands.js.map +1 -0
  70. package/dist/repl/state.js +2 -0
  71. package/dist/repl/state.js.map +1 -0
  72. package/dist/repl/system-prompt.js +5 -0
  73. package/dist/repl/system-prompt.js.map +1 -0
  74. package/dist/repl/wizard.js +34 -0
  75. package/dist/repl/wizard.js.map +1 -0
  76. package/package.json +49 -0
@@ -0,0 +1,176 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import path from "node:path";
4
+ import { runAgentLoop } from "../agent/loop.js";
5
+ import { runOrchestration } from "../orchestrator/orchestrate.js";
6
+ import { createSession, appendSessionMessage } from "../agent/session.js";
7
+ import { UsageAccumulator } from "../agent/usage.js";
8
+ const execFileAsync = promisify(execFile);
9
+ const SYSTEM_PROMPT = `You are a coding agent fixing a reported bug in a WordPress/WooCommerce
10
+ plugin. Use the available tools (read_file, list_dir, search, edit, git_diff,
11
+ shell) to find and fix exactly the bug described. When you are done, reply
12
+ concisely without further tool calls.`;
13
+ async function resetRepo(repoPath, baselineRef) {
14
+ await execFileAsync("git", ["reset", "--hard", baselineRef], { cwd: repoPath });
15
+ await execFileAsync("git", ["clean", "-fd"], { cwd: repoPath });
16
+ }
17
+ async function runHeadlessTurn(messages, model, thinking, env, cwd, session, usage, stats) {
18
+ for await (const ev of runAgentLoop(messages, {
19
+ env,
20
+ model,
21
+ cwd,
22
+ session,
23
+ usage,
24
+ ...(thinking ? { thinking } : {}),
25
+ approve: async () => true,
26
+ maxIterations: 30,
27
+ })) {
28
+ if (ev.type === "tool_call_result") {
29
+ stats.toolHistory.push({ name: ev.name, isError: ev.result.isError });
30
+ if (ev.result.isError)
31
+ stats.failedAttempts++;
32
+ }
33
+ if (ev.type === "final") {
34
+ stats.completed = true;
35
+ }
36
+ }
37
+ }
38
+ function detectSelfCorrection(history) {
39
+ for (let i = 0; i < history.length; i++) {
40
+ if (!history[i]?.isError)
41
+ continue;
42
+ for (let j = i + 1; j < history.length; j++) {
43
+ if (history[j]?.name === history[i]?.name && !history[j]?.isError)
44
+ return true;
45
+ }
46
+ }
47
+ return false;
48
+ }
49
+ export async function runOneAttempt(env, config, task, repoPath, baselineRef) {
50
+ await resetRepo(repoPath, baselineRef);
51
+ await task.injectBug(repoPath);
52
+ await execFileAsync("git", ["add", "-A"], { cwd: repoPath });
53
+ await execFileAsync("git", ["commit", "-m", `bench: inject ${task.id}`], { cwd: repoPath });
54
+ const { stdout: bugCommitRaw } = await execFileAsync("git", ["rev-parse", "HEAD"], { cwd: repoPath });
55
+ const bugCommit = bugCommitRaw.trim();
56
+ const session = await createSession(repoPath);
57
+ const usage = new UsageAccumulator();
58
+ const stats = { failedAttempts: 0, completed: false, toolHistory: [] };
59
+ const startedAt = Date.now();
60
+ if (config === "orchestration") {
61
+ await runOrchestration(task.description, {
62
+ cwd: repoPath,
63
+ env,
64
+ maxReviewLoops: 3,
65
+ usage,
66
+ runWorkerTurn: (turn) => runHeadlessTurn(turn.messages, turn.model, turn.thinking, env, repoPath, session, usage, stats),
67
+ });
68
+ // Orkestracija nema jedan "final" signal kao obična petlja — "completed"
69
+ // ovde znači da je pipeline stigao do kraja bez izuzetka, ne da je
70
+ // reviewer odobrio (to pokriva dimenzija "correct" preko verify skripte).
71
+ stats.completed = true;
72
+ }
73
+ else {
74
+ const model = config === "pro-only" ? "deepseek-v4-pro" : "deepseek-v4-flash";
75
+ const systemMsg = { role: "system", content: SYSTEM_PROMPT };
76
+ const userMsg = { role: "user", content: task.description };
77
+ await appendSessionMessage(session, systemMsg);
78
+ await appendSessionMessage(session, userMsg);
79
+ await runHeadlessTurn([systemMsg, userMsg], model, { reasoningEffort: "high" }, env, repoPath, session, usage, stats);
80
+ }
81
+ const durationMs = Date.now() - startedAt;
82
+ const { stdout: diffOut } = await execFileAsync("git", ["diff", "--name-only", bugCommit], { cwd: repoPath });
83
+ const touchedFiles = diffOut
84
+ .split("\n")
85
+ .map((s) => s.trim())
86
+ .filter(Boolean);
87
+ let buildPassed = null;
88
+ const phpFiles = touchedFiles.filter((f) => f.endsWith(".php"));
89
+ if (phpFiles.length > 0) {
90
+ buildPassed = true;
91
+ for (const f of phpFiles) {
92
+ try {
93
+ await execFileAsync("php", ["-l", path.join(repoPath, f)]);
94
+ }
95
+ catch {
96
+ buildPassed = false;
97
+ }
98
+ }
99
+ }
100
+ let correct = false;
101
+ try {
102
+ await execFileAsync("php", [task.verifyScript, repoPath]);
103
+ correct = true;
104
+ }
105
+ catch {
106
+ correct = false;
107
+ }
108
+ const unnecessaryFileChanges = touchedFiles.filter((f) => !task.expectedFiles.includes(f)).length;
109
+ return {
110
+ taskId: task.id,
111
+ config,
112
+ completed: stats.completed,
113
+ correct,
114
+ buildPassed,
115
+ testPassed: null,
116
+ unnecessaryFileChanges,
117
+ failedAttempts: stats.failedAttempts,
118
+ selfCorrected: detectSelfCorrection(stats.toolHistory),
119
+ usage: usage.totals(),
120
+ requestCount: usage.callCount,
121
+ costUsd: usage.estimatedCostUsd(),
122
+ offPeakCostUsd: usage.offPeakEquivalentCostUsd(),
123
+ durationMs,
124
+ };
125
+ }
126
+ export async function runBenchmark(env, tasks, configs, repoPath, baselineRef, onProgress) {
127
+ const log = onProgress ?? ((line) => console.log(line));
128
+ const results = [];
129
+ for (const task of tasks) {
130
+ for (const config of configs) {
131
+ log(`\n=== ${task.id} / ${config} ===`);
132
+ try {
133
+ const result = await runOneAttempt(env, config, task, repoPath, baselineRef);
134
+ log(` completed=${result.completed} correct=${result.correct} build=${result.buildPassed} ` +
135
+ `failedAttempts=${result.failedAttempts} selfCorrected=${result.selfCorrected} ` +
136
+ `unnecessaryFiles=${result.unnecessaryFileChanges} requests=${result.requestCount} ` +
137
+ `cost=$${result.costUsd.toFixed(4)} time=${(result.durationMs / 1000).toFixed(1)}s`);
138
+ results.push(result);
139
+ }
140
+ catch (err) {
141
+ const message = err instanceof Error ? err.message : String(err);
142
+ log(` ERROR — pokušaj pukao, beleži se kao neuspešan i nastavlja se dalje: ${message}`);
143
+ results.push({
144
+ taskId: task.id,
145
+ config,
146
+ completed: false,
147
+ correct: false,
148
+ buildPassed: null,
149
+ testPassed: null,
150
+ unnecessaryFileChanges: 0,
151
+ failedAttempts: 0,
152
+ selfCorrected: false,
153
+ usage: {
154
+ promptTokens: 0,
155
+ completionTokens: 0,
156
+ totalTokens: 0,
157
+ promptCacheHitTokens: 0,
158
+ promptCacheMissTokens: 0,
159
+ reasoningTokens: 0,
160
+ },
161
+ requestCount: 0,
162
+ costUsd: 0,
163
+ offPeakCostUsd: 0,
164
+ durationMs: 0,
165
+ error: message,
166
+ });
167
+ // Vrati repo u čisto stanje čak i posle pucanja usred pokušaja,
168
+ // da sledeći task/config ne nasledi polu-izmenjeno radno stablo.
169
+ await resetRepo(repoPath, baselineRef).catch(() => { });
170
+ }
171
+ }
172
+ }
173
+ await resetRepo(repoPath, baselineRef);
174
+ return results;
175
+ }
176
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/benchmark/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const FIXTURES_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "fixtures", "bitwise-bulk-price-wizard");
5
+ async function replaceInFile(filePath, from, to) {
6
+ const content = await readFile(filePath, "utf8");
7
+ if (!content.includes(from)) {
8
+ throw new Error(`Bug injection anchor not found in ${filePath}: ${JSON.stringify(from)}`);
9
+ }
10
+ await writeFile(filePath, content.replace(from, to), "utf8");
11
+ }
12
+ export const bwTasks = [
13
+ {
14
+ id: "money-rounding",
15
+ description: "Users report the 'Round to nearest 0.05' rounding preset is broken — it's rounding to the nearest 50 cents instead of 5 cents. Find and fix the bug in includes/Data/MoneyUtil.php.",
16
+ expectedFiles: ["includes/Data/MoneyUtil.php"],
17
+ async injectBug(repoPath) {
18
+ await replaceInFile(path.join(repoPath, "includes/Data/MoneyUtil.php"), "'nearest_005' => round($price / 0.05) * 0.05,", "'nearest_005' => round($price / 0.5) * 0.5,");
19
+ },
20
+ verifyScript: path.join(FIXTURES_DIR, "verify-task1.php"),
21
+ },
22
+ {
23
+ id: "percent-decrease",
24
+ description: "Bulk 'decrease by percentage' operations are producing wildly wrong results (way too low, sometimes negative) instead of a normal percentage decrease. Find and fix the pricing bug in includes/Engine/PriceEngine.php.",
25
+ expectedFiles: ["includes/Engine/PriceEngine.php"],
26
+ async injectBug(repoPath) {
27
+ await replaceInFile(path.join(repoPath, "includes/Engine/PriceEngine.php"), "'percent_decrease' => $current * (1.0 - $amount / 100.0),", "'percent_decrease' => $current * (1.0 - $amount),");
28
+ },
29
+ verifyScript: path.join(FIXTURES_DIR, "verify-task2.php"),
30
+ },
31
+ {
32
+ id: "min-price-guard",
33
+ description: "The minimum-price safety guard isn't preventing computed prices from going below the configured minimum — store managers are seeing prices below their configured floor after a bulk update. Find and fix the guard bug in includes/Engine/PriceEngine.php.",
34
+ expectedFiles: ["includes/Engine/PriceEngine.php"],
35
+ async injectBug(repoPath) {
36
+ await replaceInFile(path.join(repoPath, "includes/Engine/PriceEngine.php"), "if ($min !== null && $price < (float) $min) {", "if ($min !== null && $price > (float) $min) {");
37
+ },
38
+ verifyScript: path.join(FIXTURES_DIR, "verify-task3.php"),
39
+ },
40
+ {
41
+ id: "validator-percent-cap",
42
+ description: "Submitting a 100% price decrease operation is incorrectly accepted as valid by the operation validator, even though that would zero out or invalidate the price (it should be rejected — only decreases strictly less than 100% are valid). Find and fix the validation bug in includes/Data/OperationValidator.php.",
43
+ expectedFiles: ["includes/Data/OperationValidator.php"],
44
+ async injectBug(repoPath) {
45
+ await replaceInFile(path.join(repoPath, "includes/Data/OperationValidator.php"), "if (($op['type'] ?? '') === 'percent_decrease' && (float) $amount >= 100) {", "if (($op['type'] ?? '') === 'percent_decrease' && (float) $amount > 100) {");
46
+ },
47
+ verifyScript: path.join(FIXTURES_DIR, "verify-task4.php"),
48
+ },
49
+ ];
50
+ //# sourceMappingURL=bitwiseBulkPriceWizard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bitwiseBulkPriceWizard.js","sourceRoot":"","sources":["../../../src/benchmark/tasks/bitwiseBulkPriceWizard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAC5B,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAC5C,IAAI,EACJ,UAAU,EACV,2BAA2B,CAC5B,CAAC;AAYF,KAAK,UAAU,aAAa,CAAC,QAAgB,EAAE,IAAY,EAAE,EAAU;IACrE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjD,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,qCAAqC,QAAQ,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5F,CAAC;IACD,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAa;IAC/B;QACE,EAAE,EAAE,gBAAgB;QACpB,WAAW,EACT,qLAAqL;QACvL,aAAa,EAAE,CAAC,6BAA6B,CAAC;QAC9C,KAAK,CAAC,SAAS,CAAC,QAAQ;YACtB,MAAM,aAAa,CACjB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,6BAA6B,CAAC,EAClD,+CAA+C,EAC/C,6CAA6C,CAC9C,CAAC;QACJ,CAAC;QACD,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,kBAAkB,CAAC;KAC1D;IACD;QACE,EAAE,EAAE,kBAAkB;QACtB,WAAW,EACT,yNAAyN;QAC3N,aAAa,EAAE,CAAC,iCAAiC,CAAC;QAClD,KAAK,CAAC,SAAS,CAAC,QAAQ;YACtB,MAAM,aAAa,CACjB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,iCAAiC,CAAC,EACtD,2DAA2D,EAC3D,mDAAmD,CACpD,CAAC;QACJ,CAAC;QACD,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,kBAAkB,CAAC;KAC1D;IACD;QACE,EAAE,EAAE,iBAAiB;QACrB,WAAW,EACT,6PAA6P;QAC/P,aAAa,EAAE,CAAC,iCAAiC,CAAC;QAClD,KAAK,CAAC,SAAS,CAAC,QAAQ;YACtB,MAAM,aAAa,CACjB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,iCAAiC,CAAC,EACtD,+CAA+C,EAC/C,+CAA+C,CAChD,CAAC;QACJ,CAAC;QACD,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,kBAAkB,CAAC;KAC1D;IACD;QACE,EAAE,EAAE,uBAAuB;QAC3B,WAAW,EACT,sTAAsT;QACxT,aAAa,EAAE,CAAC,sCAAsC,CAAC;QACvD,KAAK,CAAC,SAAS,CAAC,QAAQ;YACtB,MAAM,aAAa,CACjB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,sCAAsC,CAAC,EAC3D,6EAA6E,EAC7E,4EAA4E,CAC7E,CAAC;QACJ,CAAC;QACD,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,kBAAkB,CAAC;KAC1D;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/benchmark/types.ts"],"names":[],"mappings":""}