@flowriki/agent 0.1.0-beta.56 → 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" };
|
|
@@ -9793,7 +9793,8 @@ function assistantHandlers({ deps }) {
|
|
|
9793
9793
|
const status2 = await assistant.status();
|
|
9794
9794
|
if (!status2.installed) return { ok: false, reason: "failed", detail: status2.detail ?? "the assistant is not installed on this machine" };
|
|
9795
9795
|
if (!status2.signedIn) return { ok: false, reason: "failed", detail: "the assistant is not signed in on this machine" };
|
|
9796
|
-
const
|
|
9796
|
+
const given = command.args["askId"];
|
|
9797
|
+
const askId = typeof given === "string" && /^[\w-]{8,100}$/.test(given) ? given : randomUUID();
|
|
9797
9798
|
const linked = foldersFor(project.id).filter((f) => f.exists).map((f) => f.path);
|
|
9798
9799
|
const mode = command.args["mode"] === "ask" ? "ask" : command.args["mode"] === "do" ? "do" : void 0;
|
|
9799
9800
|
const brief = typeof command.args["brief"] === "string" && command.args["brief"].trim() ? command.args["brief"].slice(0, 4e4) : void 0;
|
|
@@ -9805,6 +9806,8 @@ function assistantHandlers({ deps }) {
|
|
|
9805
9806
|
...linked.length ? { folders: linked } : {},
|
|
9806
9807
|
...mode ? { mode } : {},
|
|
9807
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 } : {},
|
|
9808
9811
|
...typeof sessionId === "string" ? { sessionId } : {},
|
|
9809
9812
|
emit
|
|
9810
9813
|
});
|
|
@@ -10174,7 +10177,8 @@ function buildAskArgs(opts) {
|
|
|
10174
10177
|
const brief = opts.brief?.trim();
|
|
10175
10178
|
const guidance = [
|
|
10176
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."),
|
|
10177
|
-
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.",
|
|
10178
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.` : "",
|
|
10179
10183
|
brief ? `
|
|
10180
10184
|
${brief}` : ""
|
|
@@ -10214,8 +10218,10 @@ function eventsFromLine(askId, line) {
|
|
|
10214
10218
|
return [];
|
|
10215
10219
|
}
|
|
10216
10220
|
const out = [];
|
|
10217
|
-
if (parsed.type === "system" && parsed.subtype === "init"
|
|
10218
|
-
|
|
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 } });
|
|
10219
10225
|
}
|
|
10220
10226
|
if (parsed.type === "assistant") {
|
|
10221
10227
|
for (const block of parsed.message?.content ?? []) {
|
|
@@ -10298,6 +10304,35 @@ function createClaudeCli(options) {
|
|
|
10298
10304
|
child.on("close", (code) => finish(code, false));
|
|
10299
10305
|
});
|
|
10300
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
|
+
}
|
|
10301
10336
|
return {
|
|
10302
10337
|
async status() {
|
|
10303
10338
|
const version = await capture(["--version"]);
|
|
@@ -10349,7 +10384,7 @@ function createClaudeCli(options) {
|
|
|
10349
10384
|
JSON.stringify({ mcpServers: { [MCP_SERVER_NAME]: { command: options.mcp.command, args: options.mcp.args } } }),
|
|
10350
10385
|
{ mode: 384 }
|
|
10351
10386
|
);
|
|
10352
|
-
return launch(ask, dir, mcpConfigPath, ask
|
|
10387
|
+
return launch(ask, dir, mcpConfigPath, laneSession(ask, dir));
|
|
10353
10388
|
},
|
|
10354
10389
|
cancel(askId) {
|
|
10355
10390
|
const child = running.get(askId);
|
|
@@ -10365,7 +10400,7 @@ function createClaudeCli(options) {
|
|
|
10365
10400
|
return running.size >= MAX_AT_ONCE;
|
|
10366
10401
|
}
|
|
10367
10402
|
};
|
|
10368
|
-
function launch(ask, dir, mcpConfigPath, sessionId) {
|
|
10403
|
+
function launch(ask, dir, mcpConfigPath, sessionId, attempt = 1) {
|
|
10369
10404
|
let child;
|
|
10370
10405
|
try {
|
|
10371
10406
|
child = spawn2(
|
|
@@ -10389,8 +10424,21 @@ function createClaudeCli(options) {
|
|
|
10389
10424
|
running.set(ask.askId, child);
|
|
10390
10425
|
let buffer = "", stderr = "", sawDone = false, ended = false;
|
|
10391
10426
|
let silentFailure = false;
|
|
10427
|
+
let toolsMissing = false;
|
|
10428
|
+
let session;
|
|
10429
|
+
let spent = 0;
|
|
10392
10430
|
const handleLine = (line) => {
|
|
10431
|
+
if (toolsMissing) return;
|
|
10393
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;
|
|
10394
10442
|
if (event.name === "assistant.done" && event.data["ok"] === false && !String(event.data["result"] ?? "").trim()) {
|
|
10395
10443
|
silentFailure = true;
|
|
10396
10444
|
continue;
|
|
@@ -10398,6 +10446,14 @@ function createClaudeCli(options) {
|
|
|
10398
10446
|
if (event.name === "assistant.done") sawDone = true;
|
|
10399
10447
|
ask.emit(event.name, event.data);
|
|
10400
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
|
+
}
|
|
10401
10457
|
};
|
|
10402
10458
|
const end = (ok, detail) => {
|
|
10403
10459
|
if (ended) return;
|
|
@@ -10405,10 +10461,26 @@ function createClaudeCli(options) {
|
|
|
10405
10461
|
clearTimeout(timer);
|
|
10406
10462
|
if (buffer.trim()) handleLine(buffer);
|
|
10407
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
|
+
}
|
|
10408
10475
|
if (silentFailure && sessionId && /no conversation found/i.test(stderr) && cancelled !== ask.askId) {
|
|
10476
|
+
if (ask.platform) writeLane(dir, ask.platform, null);
|
|
10409
10477
|
const again = launch(ask, dir, mcpConfigPath, void 0);
|
|
10410
10478
|
if (again.started) return;
|
|
10411
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
|
+
}
|
|
10412
10484
|
if (!sawDone) {
|
|
10413
10485
|
const why = detail || stderr.trim().split("\n").filter((l) => l && !/^Warning:/.test(l)).slice(-3).join(" ") || "The assistant stopped without saying why.";
|
|
10414
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