workermill 0.4.0 → 0.4.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.
|
@@ -3162,6 +3162,42 @@ var CostTracker = class {
|
|
|
3162
3162
|
}
|
|
3163
3163
|
};
|
|
3164
3164
|
|
|
3165
|
+
// src/logger.ts
|
|
3166
|
+
init_esm_shims();
|
|
3167
|
+
import fs9 from "fs";
|
|
3168
|
+
import path11 from "path";
|
|
3169
|
+
var LOG_DIR = path11.join(process.cwd(), ".workermill");
|
|
3170
|
+
var LOG_FILE = path11.join(LOG_DIR, "cli.log");
|
|
3171
|
+
var logStream = null;
|
|
3172
|
+
function ensureLogDir() {
|
|
3173
|
+
if (!fs9.existsSync(LOG_DIR)) {
|
|
3174
|
+
fs9.mkdirSync(LOG_DIR, { recursive: true });
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
function getStream() {
|
|
3178
|
+
if (!logStream) {
|
|
3179
|
+
ensureLogDir();
|
|
3180
|
+
logStream = fs9.createWriteStream(LOG_FILE, { flags: "a" });
|
|
3181
|
+
}
|
|
3182
|
+
return logStream;
|
|
3183
|
+
}
|
|
3184
|
+
function timestamp() {
|
|
3185
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
3186
|
+
}
|
|
3187
|
+
function log(level, message, data) {
|
|
3188
|
+
const entry = data ? `[${timestamp()}] ${level}: ${message} ${JSON.stringify(data)}` : `[${timestamp()}] ${level}: ${message}`;
|
|
3189
|
+
getStream().write(entry + "\n");
|
|
3190
|
+
}
|
|
3191
|
+
function info(message, data) {
|
|
3192
|
+
log("INFO", message, data);
|
|
3193
|
+
}
|
|
3194
|
+
function error(message, data) {
|
|
3195
|
+
log("ERROR", message, data);
|
|
3196
|
+
}
|
|
3197
|
+
function debug(message, data) {
|
|
3198
|
+
log("DEBUG", message, data);
|
|
3199
|
+
}
|
|
3200
|
+
|
|
3165
3201
|
export {
|
|
3166
3202
|
__dirname,
|
|
3167
3203
|
init_esm_shims,
|
|
@@ -3172,5 +3208,8 @@ export {
|
|
|
3172
3208
|
createModel,
|
|
3173
3209
|
killActiveProcess,
|
|
3174
3210
|
createToolDefinitions,
|
|
3175
|
-
CostTracker
|
|
3211
|
+
CostTracker,
|
|
3212
|
+
info,
|
|
3213
|
+
error,
|
|
3214
|
+
debug
|
|
3176
3215
|
};
|
package/dist/index.js
CHANGED
|
@@ -4,12 +4,15 @@ import {
|
|
|
4
4
|
buildOllamaOptions,
|
|
5
5
|
createModel,
|
|
6
6
|
createToolDefinitions,
|
|
7
|
+
debug,
|
|
8
|
+
error,
|
|
7
9
|
getProviderForPersona,
|
|
10
|
+
info,
|
|
8
11
|
init_esm_shims,
|
|
9
12
|
killActiveProcess,
|
|
10
13
|
loadConfig,
|
|
11
14
|
saveConfig
|
|
12
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-77CAVW3Y.js";
|
|
13
16
|
|
|
14
17
|
// src/index.ts
|
|
15
18
|
init_esm_shims();
|
|
@@ -49,8 +52,8 @@ var PROVIDERS = [
|
|
|
49
52
|
needsKey: true,
|
|
50
53
|
envVar: "OPENAI_API_KEY",
|
|
51
54
|
models: [
|
|
52
|
-
{ id: "gpt-5.
|
|
53
|
-
{ id: "gpt-5", label: "GPT-5 (
|
|
55
|
+
{ id: "gpt-5.4", label: "GPT-5.4 (latest flagship)" },
|
|
56
|
+
{ id: "gpt-5.3-codex", label: "GPT-5.3 Codex (built for code)" }
|
|
54
57
|
]
|
|
55
58
|
},
|
|
56
59
|
{
|
|
@@ -338,8 +341,8 @@ init_esm_shims();
|
|
|
338
341
|
import { useState as useState5, useCallback as useCallback3, useRef as useRef3, useEffect as useEffect2 } from "react";
|
|
339
342
|
import { useApp as useApp2 } from "ink";
|
|
340
343
|
import { execSync as execSync2 } from "child_process";
|
|
341
|
-
import
|
|
342
|
-
import
|
|
344
|
+
import fs2 from "fs";
|
|
345
|
+
import path2 from "path";
|
|
343
346
|
import os from "os";
|
|
344
347
|
|
|
345
348
|
// src/ui/useAgent.ts
|
|
@@ -474,42 +477,6 @@ ${result.text}` },
|
|
|
474
477
|
}
|
|
475
478
|
}
|
|
476
479
|
|
|
477
|
-
// src/logger.ts
|
|
478
|
-
init_esm_shims();
|
|
479
|
-
import fs2 from "fs";
|
|
480
|
-
import path2 from "path";
|
|
481
|
-
var LOG_DIR = path2.join(process.cwd(), ".workermill");
|
|
482
|
-
var LOG_FILE = path2.join(LOG_DIR, "cli.log");
|
|
483
|
-
var logStream = null;
|
|
484
|
-
function ensureLogDir() {
|
|
485
|
-
if (!fs2.existsSync(LOG_DIR)) {
|
|
486
|
-
fs2.mkdirSync(LOG_DIR, { recursive: true });
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
function getStream() {
|
|
490
|
-
if (!logStream) {
|
|
491
|
-
ensureLogDir();
|
|
492
|
-
logStream = fs2.createWriteStream(LOG_FILE, { flags: "a" });
|
|
493
|
-
}
|
|
494
|
-
return logStream;
|
|
495
|
-
}
|
|
496
|
-
function timestamp() {
|
|
497
|
-
return (/* @__PURE__ */ new Date()).toISOString();
|
|
498
|
-
}
|
|
499
|
-
function log(level, message, data) {
|
|
500
|
-
const entry = data ? `[${timestamp()}] ${level}: ${message} ${JSON.stringify(data)}` : `[${timestamp()}] ${level}: ${message}`;
|
|
501
|
-
getStream().write(entry + "\n");
|
|
502
|
-
}
|
|
503
|
-
function info(message, data) {
|
|
504
|
-
log("INFO", message, data);
|
|
505
|
-
}
|
|
506
|
-
function error(message, data) {
|
|
507
|
-
log("ERROR", message, data);
|
|
508
|
-
}
|
|
509
|
-
function debug(message, data) {
|
|
510
|
-
log("DEBUG", message, data);
|
|
511
|
-
}
|
|
512
|
-
|
|
513
480
|
// src/ui/useAgent.ts
|
|
514
481
|
var DANGEROUS_PATTERNS = [
|
|
515
482
|
{
|
|
@@ -1028,7 +995,7 @@ function useOrchestrator(addMessage2, setCost) {
|
|
|
1028
995
|
setRunning(false);
|
|
1029
996
|
return;
|
|
1030
997
|
}
|
|
1031
|
-
const { classifyComplexity, runOrchestration } = await import("./orchestrator-
|
|
998
|
+
const { classifyComplexity, runOrchestration } = await import("./orchestrator-L5LDQYO7.js");
|
|
1032
999
|
const output = {
|
|
1033
1000
|
log(persona, message) {
|
|
1034
1001
|
const emoji = getEmoji(persona);
|
|
@@ -1785,13 +1752,13 @@ function App(props) {
|
|
|
1785
1752
|
|
|
1786
1753
|
// src/ui/Root.tsx
|
|
1787
1754
|
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1788
|
-
var HISTORY_DIR =
|
|
1789
|
-
var HISTORY_FILE =
|
|
1755
|
+
var HISTORY_DIR = path2.join(os.homedir(), ".workermill");
|
|
1756
|
+
var HISTORY_FILE = path2.join(HISTORY_DIR, "history");
|
|
1790
1757
|
var MAX_HISTORY = 1e3;
|
|
1791
1758
|
function loadHistory() {
|
|
1792
1759
|
try {
|
|
1793
|
-
if (
|
|
1794
|
-
const raw =
|
|
1760
|
+
if (fs2.existsSync(HISTORY_FILE)) {
|
|
1761
|
+
const raw = fs2.readFileSync(HISTORY_FILE, "utf-8").trim();
|
|
1795
1762
|
if (!raw) return [];
|
|
1796
1763
|
return raw.split("\n").slice(-MAX_HISTORY);
|
|
1797
1764
|
}
|
|
@@ -1801,10 +1768,10 @@ function loadHistory() {
|
|
|
1801
1768
|
}
|
|
1802
1769
|
function appendHistory(line) {
|
|
1803
1770
|
try {
|
|
1804
|
-
if (!
|
|
1805
|
-
|
|
1771
|
+
if (!fs2.existsSync(HISTORY_DIR)) {
|
|
1772
|
+
fs2.mkdirSync(HISTORY_DIR, { recursive: true });
|
|
1806
1773
|
}
|
|
1807
|
-
|
|
1774
|
+
fs2.appendFileSync(HISTORY_FILE, line + "\n", "utf-8");
|
|
1808
1775
|
} catch {
|
|
1809
1776
|
}
|
|
1810
1777
|
}
|
|
@@ -2046,15 +2013,15 @@ To change: edit \`~/.workermill/cli.json\` or restart with \`--provider\` / \`--
|
|
|
2046
2013
|
// ---- /editor ----
|
|
2047
2014
|
case "editor": {
|
|
2048
2015
|
const editor = process.env.EDITOR || process.env.VISUAL || "vi";
|
|
2049
|
-
const tmpFile =
|
|
2016
|
+
const tmpFile = path2.join(os.tmpdir(), `workermill-${Date.now()}.md`);
|
|
2050
2017
|
try {
|
|
2051
|
-
|
|
2018
|
+
fs2.writeFileSync(tmpFile, "", "utf-8");
|
|
2052
2019
|
execSync2(`${editor} ${tmpFile}`, {
|
|
2053
2020
|
cwd: props.workingDir,
|
|
2054
2021
|
stdio: "inherit",
|
|
2055
2022
|
timeout: 5 * 60 * 1e3
|
|
2056
2023
|
});
|
|
2057
|
-
const contents =
|
|
2024
|
+
const contents = fs2.readFileSync(tmpFile, "utf-8").trim();
|
|
2058
2025
|
if (contents) {
|
|
2059
2026
|
agent.addUserMessage(contents);
|
|
2060
2027
|
agent.submit(contents);
|
|
@@ -2066,7 +2033,7 @@ To change: edit \`~/.workermill/cli.json\` or restart with \`--provider\` / \`--
|
|
|
2066
2033
|
agent.addSystemMessage(`Failed to open editor (\`${editor}\`): ${errMsg}`);
|
|
2067
2034
|
} finally {
|
|
2068
2035
|
try {
|
|
2069
|
-
|
|
2036
|
+
fs2.unlinkSync(tmpFile);
|
|
2070
2037
|
} catch {
|
|
2071
2038
|
}
|
|
2072
2039
|
}
|
|
@@ -2208,7 +2175,7 @@ function printWelcome(provider, model, workingDir) {
|
|
|
2208
2175
|
console.log(dim(" Type ") + white("/help") + dim(" for all commands."));
|
|
2209
2176
|
console.log();
|
|
2210
2177
|
}
|
|
2211
|
-
var VERSION = "0.4.
|
|
2178
|
+
var VERSION = "0.4.1";
|
|
2212
2179
|
function addSharedOptions(cmd) {
|
|
2213
2180
|
return cmd.option("--provider <provider>", "Override default provider").option("--model <model>", "Override model").option("--trust", "Skip all tool permission prompts").option("--full-disk", "Allow tools to access files outside working directory");
|
|
2214
2181
|
}
|
|
@@ -4,9 +4,11 @@ import {
|
|
|
4
4
|
buildOllamaOptions,
|
|
5
5
|
createModel,
|
|
6
6
|
createToolDefinitions,
|
|
7
|
+
error,
|
|
7
8
|
getProviderForPersona,
|
|
9
|
+
info,
|
|
8
10
|
init_esm_shims
|
|
9
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-77CAVW3Y.js";
|
|
10
12
|
|
|
11
13
|
// src/orchestrator.ts
|
|
12
14
|
init_esm_shims();
|
|
@@ -153,9 +155,9 @@ function buildReasoningOptions(provider, modelName) {
|
|
|
153
155
|
return {};
|
|
154
156
|
}
|
|
155
157
|
}
|
|
156
|
-
function isTransientError(
|
|
157
|
-
if (!
|
|
158
|
-
const msg =
|
|
158
|
+
function isTransientError(error2) {
|
|
159
|
+
if (!error2 || typeof error2 !== "object") return false;
|
|
160
|
+
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
159
161
|
if (/status code (502|503|504)|socket hang up|ECONNRESET|ETIMEDOUT|network error|ECONNREFUSED/i.test(msg)) {
|
|
160
162
|
return true;
|
|
161
163
|
}
|
|
@@ -219,6 +221,7 @@ function formatToolCallDisplay(toolName, toolInput) {
|
|
|
219
221
|
return msg;
|
|
220
222
|
}
|
|
221
223
|
async function classifyComplexity(config, userInput, output) {
|
|
224
|
+
info("Classifying complexity", { input: userInput.slice(0, 200) });
|
|
222
225
|
const resolvedInput = resolveTaskInput(userInput, process.cwd());
|
|
223
226
|
const { provider, model: modelName, apiKey, host, contextLength } = getProviderForPersona(config);
|
|
224
227
|
if (apiKey) {
|
|
@@ -635,6 +638,7 @@ ${plannerStories.map((s) => `- ${s.id}: ${s.title} (${s.persona}) \u2014 ${s.des
|
|
|
635
638
|
output.coordinatorLog(`Task claimed by orchestrator`);
|
|
636
639
|
output.log(story.persona, `Starting ${story.title}`);
|
|
637
640
|
output.log(story.persona, `Executing story with AIClient (model: ${modelName})...`);
|
|
641
|
+
info(`Story ${i + 1}/${sorted.length} started`, { persona: story.persona, title: story.title, provider, model: modelName });
|
|
638
642
|
output.status("");
|
|
639
643
|
const model = createModel(provider, modelName, host, contextLength);
|
|
640
644
|
const allTools = createToolDefinitions(workingDir, model, sandboxed);
|
|
@@ -765,13 +769,16 @@ ${revisionFeedback}` : ""}`;
|
|
|
765
769
|
costTracker.addUsage(persona.name, provider, modelName, inTokens, outTokens);
|
|
766
770
|
output.updateCost?.(costTracker.getTotalCost());
|
|
767
771
|
output.log(story.persona, `${story.title} \u2014 completed! (${i + 1}/${sorted.length})`);
|
|
772
|
+
info(`Story ${i + 1} completed`, { persona: story.persona, inputTokens: inTokens, outputTokens: outTokens });
|
|
768
773
|
output.log("system", "");
|
|
769
774
|
break;
|
|
770
775
|
} catch (err) {
|
|
771
776
|
output.statusDone();
|
|
772
777
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
778
|
+
error(`Story ${i + 1} error`, { persona: story.persona, error: errMsg, revision });
|
|
773
779
|
if (isTransientError(err) && revision < 2) {
|
|
774
780
|
output.log(story.persona, `Transient error: ${errMsg} \u2014 retrying...`);
|
|
781
|
+
info(`Story ${i + 1} retrying (transient)`, { revision });
|
|
775
782
|
continue;
|
|
776
783
|
}
|
|
777
784
|
output.error(`Story ${i + 1} failed: ${errMsg}`);
|
|
@@ -812,8 +819,10 @@ ${revisionFeedback}` : ""}`;
|
|
|
812
819
|
}
|
|
813
820
|
}
|
|
814
821
|
let previousReviewFeedback = "";
|
|
822
|
+
info("Starting review loop", { maxRevisions, approvalThreshold, provider: revProvider, model: revModel });
|
|
815
823
|
for (let reviewRound = 0; reviewRound <= maxRevisions; reviewRound++) {
|
|
816
824
|
const isRevision = reviewRound > 0;
|
|
825
|
+
info(`Review round ${reviewRound}`, { isRevision, maxRevisions });
|
|
817
826
|
output.coordinatorLog(isRevision ? `Starting Tech Lead review (revision ${reviewRound}/${maxRevisions})...` : "Starting Tech Lead review...");
|
|
818
827
|
output.log("tech_lead", `Starting agent execution (model: ${revModel})`);
|
|
819
828
|
output.status(isRevision ? "Reviewer -- Re-checking after revisions" : "Reviewer -- Checking code quality");
|
|
@@ -907,6 +916,7 @@ AFFECTED_REASONS: {"2": "Missing error handling in auth controller", "3": "Front
|
|
|
907
916
|
output.statusDone();
|
|
908
917
|
const score = extractScore(reviewText);
|
|
909
918
|
const approved = score >= approvalThreshold;
|
|
919
|
+
info(`Review round ${reviewRound} result`, { score, approved, threshold: approvalThreshold, reviewTextLength: reviewText.length });
|
|
910
920
|
output.log("tech_lead", `::code_quality_score::${score}`);
|
|
911
921
|
output.log("tech_lead", `::review_decision::${approved ? "approved" : "needs_revision"}`);
|
|
912
922
|
output.coordinatorLog(approved ? `Review approved (score: ${score}/100)` : `Review needs revision (score: ${score}/100)`);
|