@flowriki/agent 0.1.0-beta.57 → 0.1.0-beta.58
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.
|
@@ -76,7 +76,7 @@ import os from "os";
|
|
|
76
76
|
import path from "path";
|
|
77
77
|
import { createRequire } from "module";
|
|
78
78
|
import { spawnSync } from "child_process";
|
|
79
|
-
var AGENT_VERSION = "0.1.0-beta.
|
|
79
|
+
var AGENT_VERSION = "0.1.0-beta.58";
|
|
80
80
|
async function prepareBrowsers() {
|
|
81
81
|
if (browsersReady()) {
|
|
82
82
|
return { ok: true, already: true, message: "chromium is already installed" };
|
|
@@ -9806,6 +9806,8 @@ function assistantHandlers({ deps }) {
|
|
|
9806
9806
|
...linked.length ? { folders: linked } : {},
|
|
9807
9807
|
...mode ? { mode } : {},
|
|
9808
9808
|
...brief ? { brief } : {},
|
|
9809
|
+
...command.args["platform"] === "web" || command.args["platform"] === "android" || command.args["platform"] === "ios" ? { platform: command.args["platform"] } : {},
|
|
9810
|
+
...command.args["reuse"] === false ? { reuse: false } : {},
|
|
9809
9811
|
...typeof sessionId === "string" ? { sessionId } : {},
|
|
9810
9812
|
emit
|
|
9811
9813
|
});
|
|
@@ -10175,7 +10177,8 @@ function buildAskArgs(opts) {
|
|
|
10175
10177
|
const brief = opts.brief?.trim();
|
|
10176
10178
|
const guidance = [
|
|
10177
10179
|
`You are the Flowriki assistant for the project "${opts.projectName}" (id ${opts.projectId}). Use the Flowriki tools, and pass projectId "${opts.projectId}" wherever a tool takes one. ` + (brief ? "The project brief below is this project's memory for this job: read it first." : "Start with project_brief: it is this project's memory."),
|
|
10178
|
-
ask ? "ASK MODE: answer the question; change nothing. Cite what you rely on as [[testCase:<its id, tc_\u2026>]], [[knowledge:features/checkout.md]] or [[file:path/in/repo.ts]]." : "DO MODE: do what is asked, on Claude's working branch, for a person to review. Ask in the chat and wait before publishing, deleting, or sending anything to another system.
|
|
10180
|
+
ask ? "ASK MODE: answer the question; change nothing. Cite what you rely on as [[testCase:<its id, tc_\u2026>]], [[knowledge:features/checkout.md]] or [[file:path/in/repo.ts]]." : "DO MODE: do what is asked, on Claude's working branch, for a person to review. Ask in the chat and wait before publishing, deleting, or sending anything to another system. Work quietly: the person sees what you build and your final answer, so keep words between tool calls to a minimum and end with a short result \u2014 what was saved, and anything that needs them. When you saved something, write a short summary with write_knowledge (memory/sessions/<date>-<topic>.md, append) so the next session knows.",
|
|
10181
|
+
"Use only the tools you have: a tool is used by calling it, not by writing the call out as text. If Flowriki's tools are missing, say so in one sentence and stop.",
|
|
10179
10182
|
folders.length ? `The project's code is in ${folders.join(" and ")}. Read it with Read, Grep and Glob when it helps; you cannot change it.` : "",
|
|
10180
10183
|
brief ? `
|
|
10181
10184
|
${brief}` : ""
|
|
@@ -10215,8 +10218,10 @@ function eventsFromLine(askId, line) {
|
|
|
10215
10218
|
return [];
|
|
10216
10219
|
}
|
|
10217
10220
|
const out = [];
|
|
10218
|
-
if (parsed.type === "system" && parsed.subtype === "init"
|
|
10219
|
-
|
|
10221
|
+
if (parsed.type === "system" && parsed.subtype === "init") {
|
|
10222
|
+
const ours = (parsed.mcp_servers ?? []).find((s2) => s2.name === MCP_SERVER_NAME);
|
|
10223
|
+
if (ours) out.push({ name: "assistant.tools", data: { askId, status: ours.status ?? "unknown" } });
|
|
10224
|
+
if (parsed.session_id) out.push({ name: "assistant.session", data: { askId, sessionId: parsed.session_id } });
|
|
10220
10225
|
}
|
|
10221
10226
|
if (parsed.type === "assistant") {
|
|
10222
10227
|
for (const block of parsed.message?.content ?? []) {
|
|
@@ -10299,6 +10304,35 @@ function createClaudeCli(options) {
|
|
|
10299
10304
|
child.on("close", (code) => finish(code, false));
|
|
10300
10305
|
});
|
|
10301
10306
|
}
|
|
10307
|
+
const LANE_FRESH_MS = 60 * 6e4;
|
|
10308
|
+
const LANE_MAX_TOKENS = 15e4;
|
|
10309
|
+
const laneFile = (dir) => path42.join(dir, "lane-sessions.json");
|
|
10310
|
+
const readLanes = (dir) => {
|
|
10311
|
+
try {
|
|
10312
|
+
return JSON.parse(fs43.readFileSync(laneFile(dir), "utf8"));
|
|
10313
|
+
} catch {
|
|
10314
|
+
return {};
|
|
10315
|
+
}
|
|
10316
|
+
};
|
|
10317
|
+
const writeLane = (dir, platform, record) => {
|
|
10318
|
+
const all = readLanes(dir);
|
|
10319
|
+
if (record) all[platform] = record;
|
|
10320
|
+
else delete all[platform];
|
|
10321
|
+
try {
|
|
10322
|
+
fs43.writeFileSync(laneFile(dir), JSON.stringify(all), { mode: 384 });
|
|
10323
|
+
} catch {
|
|
10324
|
+
}
|
|
10325
|
+
};
|
|
10326
|
+
function laneSession(ask, dir) {
|
|
10327
|
+
if (ask.sessionId || !ask.platform) return ask.sessionId;
|
|
10328
|
+
if (ask.reuse === false) {
|
|
10329
|
+
writeLane(dir, ask.platform, null);
|
|
10330
|
+
return void 0;
|
|
10331
|
+
}
|
|
10332
|
+
const kept = readLanes(dir)[ask.platform];
|
|
10333
|
+
if (!kept || Date.now() - kept.updatedAt > LANE_FRESH_MS || kept.tokens > LANE_MAX_TOKENS) return void 0;
|
|
10334
|
+
return kept.sessionId;
|
|
10335
|
+
}
|
|
10302
10336
|
return {
|
|
10303
10337
|
async status() {
|
|
10304
10338
|
const version = await capture(["--version"]);
|
|
@@ -10350,7 +10384,7 @@ function createClaudeCli(options) {
|
|
|
10350
10384
|
JSON.stringify({ mcpServers: { [MCP_SERVER_NAME]: { command: options.mcp.command, args: options.mcp.args } } }),
|
|
10351
10385
|
{ mode: 384 }
|
|
10352
10386
|
);
|
|
10353
|
-
return launch(ask, dir, mcpConfigPath, ask
|
|
10387
|
+
return launch(ask, dir, mcpConfigPath, laneSession(ask, dir));
|
|
10354
10388
|
},
|
|
10355
10389
|
cancel(askId) {
|
|
10356
10390
|
const child = running.get(askId);
|
|
@@ -10366,7 +10400,7 @@ function createClaudeCli(options) {
|
|
|
10366
10400
|
return running.size >= MAX_AT_ONCE;
|
|
10367
10401
|
}
|
|
10368
10402
|
};
|
|
10369
|
-
function launch(ask, dir, mcpConfigPath, sessionId) {
|
|
10403
|
+
function launch(ask, dir, mcpConfigPath, sessionId, attempt = 1) {
|
|
10370
10404
|
let child;
|
|
10371
10405
|
try {
|
|
10372
10406
|
child = spawn2(
|
|
@@ -10390,8 +10424,21 @@ function createClaudeCli(options) {
|
|
|
10390
10424
|
running.set(ask.askId, child);
|
|
10391
10425
|
let buffer = "", stderr = "", sawDone = false, ended = false;
|
|
10392
10426
|
let silentFailure = false;
|
|
10427
|
+
let toolsMissing = false;
|
|
10428
|
+
let session;
|
|
10429
|
+
let spent = 0;
|
|
10393
10430
|
const handleLine = (line) => {
|
|
10431
|
+
if (toolsMissing) return;
|
|
10394
10432
|
for (const event of eventsFromLine(ask.askId, line)) {
|
|
10433
|
+
if (event.name === "assistant.tools") {
|
|
10434
|
+
if (event.data["status"] !== "connected") {
|
|
10435
|
+
toolsMissing = true;
|
|
10436
|
+
child.kill("SIGTERM");
|
|
10437
|
+
return;
|
|
10438
|
+
}
|
|
10439
|
+
continue;
|
|
10440
|
+
}
|
|
10441
|
+
if (event.name === "assistant.session") session = String(event.data["sessionId"] ?? "") || session;
|
|
10395
10442
|
if (event.name === "assistant.done" && event.data["ok"] === false && !String(event.data["result"] ?? "").trim()) {
|
|
10396
10443
|
silentFailure = true;
|
|
10397
10444
|
continue;
|
|
@@ -10399,6 +10446,14 @@ function createClaudeCli(options) {
|
|
|
10399
10446
|
if (event.name === "assistant.done") sawDone = true;
|
|
10400
10447
|
ask.emit(event.name, event.data);
|
|
10401
10448
|
}
|
|
10449
|
+
try {
|
|
10450
|
+
const parsed = JSON.parse(line);
|
|
10451
|
+
if (parsed.type === "result" && parsed.usage) {
|
|
10452
|
+
const u = parsed.usage;
|
|
10453
|
+
spent += (u.input_tokens ?? 0) + (u.output_tokens ?? 0) + (u.cache_read_input_tokens ?? 0) + (u.cache_creation_input_tokens ?? 0);
|
|
10454
|
+
}
|
|
10455
|
+
} catch {
|
|
10456
|
+
}
|
|
10402
10457
|
};
|
|
10403
10458
|
const end = (ok, detail) => {
|
|
10404
10459
|
if (ended) return;
|
|
@@ -10406,10 +10461,26 @@ function createClaudeCli(options) {
|
|
|
10406
10461
|
clearTimeout(timer);
|
|
10407
10462
|
if (buffer.trim()) handleLine(buffer);
|
|
10408
10463
|
running.delete(ask.askId);
|
|
10464
|
+
if (toolsMissing && cancelled !== ask.askId) {
|
|
10465
|
+
if (attempt < 3) {
|
|
10466
|
+
setTimeout(() => {
|
|
10467
|
+
const again = launch(ask, dir, mcpConfigPath, sessionId, attempt + 1);
|
|
10468
|
+
if (!again.started) ask.emit("assistant.done", { askId: ask.askId, ok: false, result: again.detail ?? "The assistant could not be started." });
|
|
10469
|
+
}, 1500 * attempt + Math.floor(Math.random() * 1e3)).unref?.();
|
|
10470
|
+
return;
|
|
10471
|
+
}
|
|
10472
|
+
ask.emit("assistant.done", { askId: ask.askId, ok: false, result: "Flowriki's tools did not connect to the assistant on this computer after three tries, so nothing was done. Send it again in a moment; if it keeps happening, restart the agent." });
|
|
10473
|
+
return;
|
|
10474
|
+
}
|
|
10409
10475
|
if (silentFailure && sessionId && /no conversation found/i.test(stderr) && cancelled !== ask.askId) {
|
|
10476
|
+
if (ask.platform) writeLane(dir, ask.platform, null);
|
|
10410
10477
|
const again = launch(ask, dir, mcpConfigPath, void 0);
|
|
10411
10478
|
if (again.started) return;
|
|
10412
10479
|
}
|
|
10480
|
+
if (ask.platform && session && ok && !silentFailure) {
|
|
10481
|
+
const before = sessionId && readLanes(dir)[ask.platform]?.sessionId === sessionId ? readLanes(dir)[ask.platform].tokens : 0;
|
|
10482
|
+
writeLane(dir, ask.platform, { sessionId: session, updatedAt: Date.now(), tokens: Math.max(before, spent) });
|
|
10483
|
+
}
|
|
10413
10484
|
if (!sawDone) {
|
|
10414
10485
|
const why = detail || stderr.trim().split("\n").filter((l) => l && !/^Warning:/.test(l)).slice(-3).join(" ") || "The assistant stopped without saying why.";
|
|
10415
10486
|
ask.emit("assistant.done", { askId: ask.askId, ok: ok && !silentFailure, result: ok && !silentFailure ? "" : why });
|
package/dist/cli.js
CHANGED
package/dist/engine.js
CHANGED
package/package.json
CHANGED