@loompad/cli 1.2.0 → 1.2.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.
- package/CHANGELOG.md +36 -0
- package/README.md +13 -7
- package/dist/adapters/antigravity-cli.js +7 -3
- package/dist/adapters/antigravity-cli.js.map +1 -1
- package/dist/adapters/opencode.d.ts +4 -0
- package/dist/adapters/opencode.js +18 -0
- package/dist/adapters/opencode.js.map +1 -1
- package/dist/cli/doctor.d.ts +8 -0
- package/dist/cli/doctor.js +41 -3
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/index.js +65 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/ui.js +1 -1
- package/dist/cli/ui.js.map +1 -1
- package/dist/core/council.d.ts +3 -3
- package/dist/core/council.js +6 -4
- package/dist/core/council.js.map +1 -1
- package/dist/core/crew-protocol.js +4 -1
- package/dist/core/crew-protocol.js.map +1 -1
- package/dist/core/crew.d.ts +13 -1
- package/dist/core/crew.js +40 -6
- package/dist/core/crew.js.map +1 -1
- package/dist/core/digest.d.ts +2 -0
- package/dist/core/digest.js +9 -0
- package/dist/core/digest.js.map +1 -1
- package/dist/core/loops.js +22 -2
- package/dist/core/loops.js.map +1 -1
- package/dist/core/orchestra.d.ts +16 -0
- package/dist/core/orchestra.js +45 -2
- package/dist/core/orchestra.js.map +1 -1
- package/dist/core/prices.d.ts +11 -0
- package/dist/core/prices.js +10 -0
- package/dist/core/prices.js.map +1 -1
- package/dist/core/proof.d.ts +11 -1
- package/dist/core/proof.js +56 -7
- package/dist/core/proof.js.map +1 -1
- package/dist/core/replay.js +1 -1
- package/dist/core/replay.js.map +1 -1
- package/dist/core/routes.js +14 -0
- package/dist/core/routes.js.map +1 -1
- package/dist/core/setup.d.ts +14 -0
- package/dist/core/setup.js +22 -6
- package/dist/core/setup.js.map +1 -1
- package/dist/core/shield.js +7 -3
- package/dist/core/shield.js.map +1 -1
- package/dist/core/shift.d.ts +2 -0
- package/dist/core/shift.js +14 -2
- package/dist/core/shift.js.map +1 -1
- package/dist/daemon/client.d.ts +14 -1
- package/dist/daemon/client.js +6 -1
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/council.js +10 -4
- package/dist/daemon/council.js.map +1 -1
- package/dist/daemon/proof.js +11 -7
- package/dist/daemon/proof.js.map +1 -1
- package/dist/daemon/review.d.ts +6 -0
- package/dist/daemon/review.js +19 -1
- package/dist/daemon/review.js.map +1 -1
- package/dist/daemon/routes/crews.js +2 -0
- package/dist/daemon/routes/crews.js.map +1 -1
- package/dist/daemon/routes/messages.js +8 -2
- package/dist/daemon/routes/messages.js.map +1 -1
- package/dist/daemon/routes/setup.js +9 -1
- package/dist/daemon/routes/setup.js.map +1 -1
- package/dist/daemon/runtime/queue.d.ts +7 -0
- package/dist/daemon/runtime/queue.js +13 -1
- package/dist/daemon/runtime/queue.js.map +1 -1
- package/dist/daemon/runtime/relay.d.ts +2 -0
- package/dist/daemon/runtime/relay.js +7 -0
- package/dist/daemon/runtime/relay.js.map +1 -1
- package/dist/daemon/runtime/turns.d.ts +2 -0
- package/dist/daemon/runtime/turns.js +1 -0
- package/dist/daemon/runtime/turns.js.map +1 -1
- package/dist/daemon/runtime-support.js +1 -1
- package/dist/daemon/runtime-support.js.map +1 -1
- package/dist/daemon/runtime.d.ts +25 -2
- package/dist/daemon/runtime.js +67 -3
- package/dist/daemon/runtime.js.map +1 -1
- package/dist/daemon/shift.js +1 -1
- package/dist/daemon/shift.js.map +1 -1
- package/dist/providers/agent.js +3 -0
- package/dist/providers/agent.js.map +1 -1
- package/dist/types.d.ts +12 -0
- package/dist/types.js.map +1 -1
- package/dist/web/app.css +7 -0
- package/dist/web/app.js +30 -7
- package/dist/web/app.js.map +2 -2
- package/docs/release-notes/v1.2.1.md +40 -0
- package/package.json +1 -1
package/dist/daemon/runtime.js
CHANGED
|
@@ -58,6 +58,7 @@ import { ProviderAgent } from "../providers/agent.js";
|
|
|
58
58
|
import { READ_ONLY_RULE } from "../core/review.js";
|
|
59
59
|
import { ReviewRunner } from "./review.js";
|
|
60
60
|
import { CouncilRunner } from "./council.js";
|
|
61
|
+
import { coldResume, priceBook } from "../core/prices.js";
|
|
61
62
|
import { LiveDeltaThrottle } from "../providers/live.js";
|
|
62
63
|
import { AdapterBase } from "../adapters/base.js";
|
|
63
64
|
export { BudgetExceededError, CLOCK_TICK_MS, LOOM_ASK_TIMEOUT_MESSAGE, LOOM_ASK_TIMEOUT_MS, LoomAskTimeoutError, QuarantinedError, activityLine, planModeBriefing, relativeToProject, withLoomAskTimeout } from './runtime-support.js';
|
|
@@ -304,6 +305,7 @@ export class ProjectRuntime {
|
|
|
304
305
|
projectId: info.id,
|
|
305
306
|
projectName: info.name,
|
|
306
307
|
projectDir: info.dir,
|
|
308
|
+
worktreeDir: () => this.config.orchestra?.worktreeDir,
|
|
307
309
|
roster: () => this.config.agents.filter((a) => a.enabled !== false && tierForKind(a.kind) === "adapter" && !isWithdrawnKind(a.kind)),
|
|
308
310
|
installedKinds: () => this.installedKinds,
|
|
309
311
|
makeAgent: (cfg, dir) => {
|
|
@@ -355,6 +357,7 @@ export class ProjectRuntime {
|
|
|
355
357
|
config: () => this.config,
|
|
356
358
|
busy: (id) => { const a = this.agents.get(id); return Boolean(a && isAdapter(a) && a.busy()) || this.turns.busySince.has(id); },
|
|
357
359
|
turnChat: (id) => this.turns.turnChat.get(id),
|
|
360
|
+
inSubtask: (id) => [...this.subtasks.values()].some((t) => t.agentId === id),
|
|
358
361
|
available: async (id) => { const a = this.agents.get(id); return Boolean(a && isAdapter(a) && (await a.available())); },
|
|
359
362
|
interrupt: (chat) => this.interrupt({ chat, source: "route" }),
|
|
360
363
|
handoff: (to) => this.handoff(to, { source: "route" }),
|
|
@@ -416,6 +419,12 @@ export class ProjectRuntime {
|
|
|
416
419
|
this.brain.add({ kind: "decision", text, provenance: { agentId: "user", eventId: event.id, ts: event.ts } });
|
|
417
420
|
},
|
|
418
421
|
maxReviewers: ProjectRuntime.MAX_CONCURRENT_SUBTASKS,
|
|
422
|
+
reviewerTimeoutMs: () => Math.max(1, Number(this.config.review?.timeoutMin) || 15) * 60_000,
|
|
423
|
+
stopReviewer: async (agentId) => {
|
|
424
|
+
const a = this.agents.get(agentId);
|
|
425
|
+
if (a && isAdapter(a) && a.busy())
|
|
426
|
+
await a.interrupt();
|
|
427
|
+
},
|
|
419
428
|
});
|
|
420
429
|
this.councils = new CouncilRunner({
|
|
421
430
|
hasAgent: (id) => this.config.agents.some((a) => a.id === id),
|
|
@@ -552,6 +561,10 @@ export class ProjectRuntime {
|
|
|
552
561
|
}
|
|
553
562
|
rt.configMtime = configMtimeOf(info.dir);
|
|
554
563
|
rt.rehydrateCosts();
|
|
564
|
+
rt.rehydrateSignIns();
|
|
565
|
+
// finished orchestra runs older than a week give their disk back (#295)
|
|
566
|
+
setTimeout(() => void (rt.closed ? Promise.resolve([]) : rt.orchestra.sweep()).then((ids) => { if (ids.length)
|
|
567
|
+
logbook.info("orchestra", `removed the worktrees of ${ids.length} finished run(s)`, ids.join(", "), rt.info.id); }).catch(() => { }), 30_000).unref?.();
|
|
555
568
|
// Pull each connected ADE's native memory into the shared brain on open.
|
|
556
569
|
try {
|
|
557
570
|
rt.importMemories();
|
|
@@ -2378,8 +2391,8 @@ export class ProjectRuntime {
|
|
|
2378
2391
|
}
|
|
2379
2392
|
/**
|
|
2380
2393
|
* A plan turn on a provider agent runs in the agent's own plan mode, which
|
|
2381
|
-
* changes nothing; Loom keeps the plan it proposes under plans
|
|
2382
|
-
*
|
|
2394
|
+
* changes nothing; Loom keeps the plan it proposes under .loom/plans/ — its
|
|
2395
|
+
* own folder, not a new untracked one in your repo (#279).
|
|
2383
2396
|
*/
|
|
2384
2397
|
saveProposedPlan(agentId, chat, markdown) {
|
|
2385
2398
|
if (!markdown.trim())
|
|
@@ -2388,7 +2401,7 @@ export class ProjectRuntime {
|
|
|
2388
2401
|
const heading = /^#+\s*(.+)$/m.exec(markdown)?.[1] ?? markdown.split("\n")[0] ?? "plan";
|
|
2389
2402
|
const slug = heading.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40) || "plan";
|
|
2390
2403
|
const day = new Date().toISOString().slice(0, 10);
|
|
2391
|
-
const dir = path.join(this.agentDir(agentId), "plans");
|
|
2404
|
+
const dir = path.join(projectLoomDir(this.agentDir(agentId)), "plans");
|
|
2392
2405
|
fs.mkdirSync(dir, { recursive: true });
|
|
2393
2406
|
let file = path.join(dir, `${day}-${slug}.md`);
|
|
2394
2407
|
for (let n = 2; fs.existsSync(file); n++)
|
|
@@ -2502,6 +2515,29 @@ export class ProjectRuntime {
|
|
|
2502
2515
|
if (message && SIGNED_OUT.test(message))
|
|
2503
2516
|
this.signedOutAgents.set(event.agentId, message.split("\n")[0].slice(0, 200));
|
|
2504
2517
|
}
|
|
2518
|
+
/**
|
|
2519
|
+
* The size of an agent's native session in a chat — the context its last
|
|
2520
|
+
* turn sent — and how long ago that was; a resumed session past the cache's
|
|
2521
|
+
* life is re-read in full (#280).
|
|
2522
|
+
*/
|
|
2523
|
+
sessionWeight(agentId, chat = MAIN_CHAT) {
|
|
2524
|
+
const last = this.log.list({ chat, agentId, kinds: ["run_complete"], limit: 50 }).at(-1);
|
|
2525
|
+
if (!last)
|
|
2526
|
+
return null;
|
|
2527
|
+
const tokens = Number(last.payload.inputTokens ?? 0) || 0;
|
|
2528
|
+
const model = typeof last.payload.model === "string" ? last.payload.model : undefined;
|
|
2529
|
+
const ageMs = Date.now() - last.ts;
|
|
2530
|
+
return { tokens, ageMs, ...(model ? { model } : {}), ...coldResume({ tokens, ageMs, ...(model ? { model } : {}) }, priceBook()) };
|
|
2531
|
+
}
|
|
2532
|
+
/** The agents a real turn found signed out, with what the CLI said (for `loom doctor`). */
|
|
2533
|
+
learnedSignOuts() {
|
|
2534
|
+
return [...this.signedOutAgents.entries()].map(([agentId, message]) => ({ agentId, kind: this.config.agents.find((a) => a.id === agentId)?.kind ?? "", message }));
|
|
2535
|
+
}
|
|
2536
|
+
/** What a restart would forget: each agent's latest sign-in failure that no successful turn has cleared since. */
|
|
2537
|
+
rehydrateSignIns() {
|
|
2538
|
+
for (const e of this.log.list({ kinds: ["error", "run_complete"], limit: 3000 }))
|
|
2539
|
+
this.noteSignIn(e);
|
|
2540
|
+
}
|
|
2505
2541
|
/** What status says about an agent's sign-in: a real failure beats the CLI's own (cached) check. */
|
|
2506
2542
|
signInState(agentId, kind) {
|
|
2507
2543
|
const learned = this.signedOutAgents.get(agentId);
|
|
@@ -2547,6 +2583,18 @@ export class ProjectRuntime {
|
|
|
2547
2583
|
}
|
|
2548
2584
|
/** The loop card's buttons: stop the turn, nudge the agent, or hand the task to another agent. */
|
|
2549
2585
|
async actOnLoop(chat, agentId, action, to, loop) {
|
|
2586
|
+
if (action !== "stop") {
|
|
2587
|
+
const release = this.queueCoordinator.hold();
|
|
2588
|
+
try {
|
|
2589
|
+
return await this.actOnLoopNow(chat, agentId, action, to, loop);
|
|
2590
|
+
}
|
|
2591
|
+
finally {
|
|
2592
|
+
release();
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
return this.actOnLoopNow(chat, agentId, action, to, loop);
|
|
2596
|
+
}
|
|
2597
|
+
async actOnLoopNow(chat, agentId, action, to, loop) {
|
|
2550
2598
|
const card = loop ?? this.lastLoop(chat, agentId);
|
|
2551
2599
|
await this.interrupt({ chat, source: "route" });
|
|
2552
2600
|
if (action === "stop")
|
|
@@ -3183,8 +3231,24 @@ export class ProjectRuntime {
|
|
|
3183
3231
|
// "the self-heal did nothing".
|
|
3184
3232
|
quarantine: this.quarantined(),
|
|
3185
3233
|
orchestra: this.orchestraSummary(),
|
|
3234
|
+
activity: this.inFlight(),
|
|
3186
3235
|
};
|
|
3187
3236
|
}
|
|
3237
|
+
/** What's in flight besides an agent's own turn — an orchestra planning, a crew, a council — so "idle" isn't said of a busy project (#294). */
|
|
3238
|
+
inFlight() {
|
|
3239
|
+
const out = [];
|
|
3240
|
+
if (this.orchestra.active())
|
|
3241
|
+
out.push("orchestra");
|
|
3242
|
+
for (const c of this.crews.workingCrews)
|
|
3243
|
+
out.push(`crew ${c}`);
|
|
3244
|
+
if (this.councils.active)
|
|
3245
|
+
out.push("council");
|
|
3246
|
+
if (this.shifts.active)
|
|
3247
|
+
out.push("night shift");
|
|
3248
|
+
if (this.reviews.running)
|
|
3249
|
+
out.push("review");
|
|
3250
|
+
return out;
|
|
3251
|
+
}
|
|
3188
3252
|
/**
|
|
3189
3253
|
* What every agent in this project is doing right now — for the fleet view.
|
|
3190
3254
|
*
|