@onepointfour-packs/flaredeck-agent 0.2.194 → 0.2.195
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/dist/envtools.d.ts +2 -0
- package/dist/envtools.js +1 -0
- package/dist/envtools.js.map +1 -1
- package/dist/serve.d.ts +13 -0
- package/dist/serve.js +100 -2
- package/dist/serve.js.map +1 -1
- package/dist/worktree.d.ts +11 -0
- package/dist/worktree.js +18 -0
- package/dist/worktree.js.map +1 -1
- package/package.json +1 -1
package/dist/envtools.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export type EnvDeps = {
|
|
|
22
22
|
script: () => string | undefined;
|
|
23
23
|
/** Hand the started environment back, so the browser's addresses are live at once. */
|
|
24
24
|
onStarted: (started: Started) => void;
|
|
25
|
+
/** Before a start: stop this agent's environments for its other cards, which hold the ports. */
|
|
26
|
+
beforeStart?: () => Promise<void>;
|
|
25
27
|
/** What is already up, so asking twice is cheap and honest. */
|
|
26
28
|
running: () => Started | null;
|
|
27
29
|
/**
|
package/dist/envtools.js
CHANGED
|
@@ -51,6 +51,7 @@ export function environmentTools(deps) {
|
|
|
51
51
|
}
|
|
52
52
|
// The branch can move mid-card — a merge or fast-forward from dev — and bring packages the
|
|
53
53
|
// checkout never installed. HAL's API died on start twice for it (HR-0340, HR-0184).
|
|
54
|
+
await deps.beforeStart?.().catch(() => { });
|
|
54
55
|
if (depsStale(deps.cwd()))
|
|
55
56
|
await installDeps(deps.cwd(), deps.onNote);
|
|
56
57
|
const started = await startEnvironment(deps.cwd(), deps.onNote, deps.script());
|
package/dist/envtools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"envtools.js","sourceRoot":"","sources":["../src/envtools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,gBAAgB,EAAgB,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,gCAAgC,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,6BAA6B,EAAE,2BAA2B,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"envtools.js","sourceRoot":"","sources":["../src/envtools.ts"],"names":[],"mappings":"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"}
|
package/dist/serve.d.ts
CHANGED
|
@@ -9,6 +9,19 @@ import { type StreamEvent } from './stream.js';
|
|
|
9
9
|
* read, means the sweep turn runs as before.
|
|
10
10
|
*/
|
|
11
11
|
export declare function nothingOutstanding(text: string): boolean;
|
|
12
|
+
export type HandoverLog = {
|
|
13
|
+
notesAt?: number;
|
|
14
|
+
changedAt?: number;
|
|
15
|
+
};
|
|
16
|
+
/** Tools that only look: reading files, searching, asking FlareDeck or a service what is there. */
|
|
17
|
+
export declare function onlyLooks(tool: string): boolean;
|
|
18
|
+
/** Record a tool call against the session it ran in. */
|
|
19
|
+
export declare function noteHandoverTool(logs: Map<string, HandoverLog>, key: string, tool: string, at: number): void;
|
|
20
|
+
/**
|
|
21
|
+
* Whether a session ending needs a handover note: it changed something, after its last notes.
|
|
22
|
+
* Unknown (no record) is treated as needed, as before.
|
|
23
|
+
*/
|
|
24
|
+
export declare function handoverNeeded(l: HandoverLog | undefined): boolean;
|
|
12
25
|
/** How long after a card's turn the harness leaves it alone, unless an event brings it back. */
|
|
13
26
|
export declare const RESUME_COOLDOWN_MS: number;
|
|
14
27
|
/** Whether any of these ids had a turn within the cooldown. */
|
package/dist/serve.js
CHANGED
|
@@ -29,7 +29,7 @@ class RetryOnAnotherPlan extends CouldNotWork {
|
|
|
29
29
|
}
|
|
30
30
|
import { isJustReading, jevGuard, judgeCommand } from './jevguard.js';
|
|
31
31
|
import { loadProviders } from './providers.js';
|
|
32
|
-
import { cardWorkOnBase, currentBranch, ensureWorktree, finishRefusalStands, freeDiskBytes, sweepWorktrees, releaseSharedPushGuard, existingWorktree, produced, releaseWorktree, tooEarlyToFinish, uncommittedCount, worktreeBrief } from './worktree.js';
|
|
32
|
+
import { cardWorkOnBase, currentBranch, ensureWorktree, finishRefusalStands, freeDiskBytes, headOf, leadGaveItBack, sweepWorktrees, releaseSharedPushGuard, existingWorktree, produced, releaseWorktree, tooEarlyToFinish, uncommittedCount, worktreeBrief } from './worktree.js';
|
|
33
33
|
import { askingForComponent, checkouts, repoIdentity, resolveCheckout, voteByCode, workspaceBrief, describeCheckout } from './workspace.js';
|
|
34
34
|
import { chooseRepoWithJev } from './jev.js';
|
|
35
35
|
import { ROUTE, intake, intakeText, unclearBrief } from './intake.js';
|
|
@@ -92,6 +92,33 @@ export function nothingOutstanding(text) {
|
|
|
92
92
|
return false;
|
|
93
93
|
return text.includes('*Nothing to do here. 🎉*') && text.includes('*No unactioned comments or mentions. 🎉*') && !/^### \d+\./m.test(text);
|
|
94
94
|
}
|
|
95
|
+
/** Tools that only look: reading files, searching, asking FlareDeck or a service what is there. */
|
|
96
|
+
export function onlyLooks(tool) {
|
|
97
|
+
if (['Read', 'Grep', 'Glob', 'LS', 'ToolSearch', 'TodoWrite', 'TaskOutput', 'LSP', 'WebFetch', 'WebSearch', 'Monitor', 'Skill'].includes(tool))
|
|
98
|
+
return true;
|
|
99
|
+
const op = tool.startsWith('mcp__') ? tool.split('__').slice(2).join('__') : '';
|
|
100
|
+
return /^(get|find|list|read|search|health|hello|whats|check|describe|site_map|see_screen|browser_look|browser_screenshot|browser_events|pull_request_status|preview)/i.test(op);
|
|
101
|
+
}
|
|
102
|
+
/** Record a tool call against the session it ran in. */
|
|
103
|
+
export function noteHandoverTool(logs, key, tool, at) {
|
|
104
|
+
const l = logs.get(key) ?? {};
|
|
105
|
+
if (/__set-card-notes$/.test(tool))
|
|
106
|
+
l.notesAt = at;
|
|
107
|
+
else if (!onlyLooks(tool))
|
|
108
|
+
l.changedAt = at;
|
|
109
|
+
logs.set(key, l);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Whether a session ending needs a handover note: it changed something, after its last notes.
|
|
113
|
+
* Unknown (no record) is treated as needed, as before.
|
|
114
|
+
*/
|
|
115
|
+
export function handoverNeeded(l) {
|
|
116
|
+
if (!l)
|
|
117
|
+
return true;
|
|
118
|
+
if (!l.changedAt)
|
|
119
|
+
return false;
|
|
120
|
+
return !l.notesAt || l.changedAt > l.notesAt;
|
|
121
|
+
}
|
|
95
122
|
/** How long after a card's turn the harness leaves it alone, unless an event brings it back. */
|
|
96
123
|
export const RESUME_COOLDOWN_MS = 15 * 60_000;
|
|
97
124
|
/** Whether any of these ids had a turn within the cooldown. */
|
|
@@ -1008,6 +1035,8 @@ export async function serve(opts) {
|
|
|
1008
1035
|
const keepTool = (name) => offeredTo(isManager || isAssistant ? 'manager' : isLead ? 'lead' : 'worker', name);
|
|
1009
1036
|
/** Cards already handed to the lead, so a retried tool call does not assign or message twice. */
|
|
1010
1037
|
const handedBack = new Set();
|
|
1038
|
+
/** The branch head when each card was handed to the lead: unchanged, a card given back is the lead's "move it". */
|
|
1039
|
+
const handedBackHead = new Map();
|
|
1011
1040
|
try {
|
|
1012
1041
|
const team = await fetchTeam(opts.baseUrl, await opts.auth());
|
|
1013
1042
|
// Who is an agent, so a parked card can tell a person answering from agents talking shop.
|
|
@@ -1544,6 +1573,30 @@ export async function serve(opts) {
|
|
|
1544
1573
|
*/
|
|
1545
1574
|
const signInPending = new Map();
|
|
1546
1575
|
const SIGN_IN_HOLD_MS = 2 * 60 * 60_000;
|
|
1576
|
+
/**
|
|
1577
|
+
* Stop this agent's environments for its other cards before starting one for this card. An agent
|
|
1578
|
+
* works one card at a time, and the other card's servers hold the ports: CASE could not rerun its
|
|
1579
|
+
* HR-1091 browser check because HR-1074's environment still served on them (20 Oct), and JARVIS
|
|
1580
|
+
* hit the same twice on 19 Oct. A checkout with a sign-in waiting on a person is left up.
|
|
1581
|
+
*/
|
|
1582
|
+
const stopOtherEnvironments = async (cwd) => {
|
|
1583
|
+
for (const other of [...envUp.keys()]) {
|
|
1584
|
+
if (other === cwd)
|
|
1585
|
+
continue;
|
|
1586
|
+
const waiting = signInPending.get(other);
|
|
1587
|
+
if (waiting && Date.now() - waiting < SIGN_IN_HOLD_MS)
|
|
1588
|
+
continue;
|
|
1589
|
+
const timer = idleStops.get(other);
|
|
1590
|
+
if (timer) {
|
|
1591
|
+
clearTimeout(timer);
|
|
1592
|
+
idleStops.delete(other);
|
|
1593
|
+
}
|
|
1594
|
+
envUp.delete(other);
|
|
1595
|
+
const ok = await stopEnvironment(other).catch(() => false);
|
|
1596
|
+
if (ok)
|
|
1597
|
+
log('tool', `environment stopped in ${other.split('/').pop()} — another card's, and this card needs its ports`);
|
|
1598
|
+
}
|
|
1599
|
+
};
|
|
1547
1600
|
const scheduleEnvironmentStop = (cwd) => {
|
|
1548
1601
|
const before = idleStops.get(cwd);
|
|
1549
1602
|
if (before)
|
|
@@ -1782,6 +1835,8 @@ export async function serve(opts) {
|
|
|
1782
1835
|
timer.unref();
|
|
1783
1836
|
live.set(key, { cwd, tokens, timer });
|
|
1784
1837
|
};
|
|
1838
|
+
/** Per session: when it last wrote the card's notes, and last did something that changed anything. */
|
|
1839
|
+
const handoverLog = new Map();
|
|
1785
1840
|
const closeSession = async (key, done = false) => {
|
|
1786
1841
|
const s = live.get(key);
|
|
1787
1842
|
if (!s)
|
|
@@ -3188,8 +3243,29 @@ export async function serve(opts) {
|
|
|
3188
3243
|
const code = tag || event.cardCode || event.cardKey || '';
|
|
3189
3244
|
if (!code)
|
|
3190
3245
|
return null;
|
|
3246
|
+
// Handed over before, and the lead has given it back with nothing new on the branch: the
|
|
3247
|
+
// lead reviewed it and wants it moved on. Let the move through instead of refusing again.
|
|
3248
|
+
if (handedBack.has(code) && tree && opts.deck) {
|
|
3249
|
+
const [here, head] = await Promise.all([opts.deck.card(code).catch(() => null), headOf(tree)]);
|
|
3250
|
+
if (leadGaveItBack(handedBackHead.get(code), head, here?.assigned_to?.uid, selfId)) {
|
|
3251
|
+
log('tool', `moving ${code} on — ${leadName} reviewed it and gave it back, nothing new since`);
|
|
3252
|
+
return null;
|
|
3253
|
+
}
|
|
3254
|
+
// Back with this worker and changed since (or we cannot tell): it is new work, handed to the
|
|
3255
|
+
// lead again like the first time. Remembering the old hand-back forever refused HAL's second
|
|
3256
|
+
// "done" on HR-1074 with "JARVIS's to verify" while the card stayed assigned to HAL (20 Oct).
|
|
3257
|
+
if (here?.assigned_to?.uid && here.assigned_to.uid === selfId) {
|
|
3258
|
+
handedBack.delete(code);
|
|
3259
|
+
handedBackHead.delete(code);
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
3191
3262
|
if (!handedBack.has(code)) {
|
|
3192
3263
|
handedBack.add(code);
|
|
3264
|
+
if (tree) {
|
|
3265
|
+
const head = await headOf(tree);
|
|
3266
|
+
if (head)
|
|
3267
|
+
handedBackHead.set(code, head);
|
|
3268
|
+
}
|
|
3193
3269
|
const made = tree ? await produced(tree) : null;
|
|
3194
3270
|
const where = tree
|
|
3195
3271
|
? `Branch \`${tree.branch}\`${made ? ` — ${made.commits} commit(s), ${made.pushed ? 'pushed' : 'NOT pushed'}` : ''}.`
|
|
@@ -3208,6 +3284,7 @@ export async function serve(opts) {
|
|
|
3208
3284
|
catch (e) {
|
|
3209
3285
|
// A handback that did not happen must not read as one that did.
|
|
3210
3286
|
handedBack.delete(code);
|
|
3287
|
+
handedBackHead.delete(code);
|
|
3211
3288
|
const text = e instanceof Error ? e.message : String(e);
|
|
3212
3289
|
log('warn', `could not hand ${code} to ${leadName}: ${text}`);
|
|
3213
3290
|
return `Could not hand this card to ${leadName} for review (${text}). Do not move it; say so on the card instead.`;
|
|
@@ -3402,7 +3479,7 @@ export async function serve(opts) {
|
|
|
3402
3479
|
: forACard && needsRunning
|
|
3403
3480
|
// The script this board declared for the repository this card is in, if it declared one.
|
|
3404
3481
|
// Matched on the remote, the same way the base branch is.
|
|
3405
|
-
? await startEnvironment(cwd, (t) => log('tool', t), where.kind === 'repo' ? where.script : undefined)
|
|
3482
|
+
? await stopOtherEnvironments(cwd).then(() => startEnvironment(cwd, (t) => log('tool', t), where.kind === 'repo' ? where.script : undefined))
|
|
3406
3483
|
: { ran: false, ok: true, endpoints: {}, detail: '' };
|
|
3407
3484
|
if (env.ran && env.ok)
|
|
3408
3485
|
envUp.set(cwd, env);
|
|
@@ -3445,6 +3522,7 @@ export async function serve(opts) {
|
|
|
3445
3522
|
envUp.set(cwd, started);
|
|
3446
3523
|
},
|
|
3447
3524
|
onNote: (t) => log('tool', t),
|
|
3525
|
+
beforeStart: () => stopOtherEnvironments(cwd),
|
|
3448
3526
|
/**
|
|
3449
3527
|
* Turning "ask somebody" into something that actually asks.
|
|
3450
3528
|
*
|
|
@@ -3938,6 +4016,8 @@ export async function serve(opts) {
|
|
|
3938
4016
|
log('warn', `${r.status.over.message} — Claude answers from the next turn`);
|
|
3939
4017
|
});
|
|
3940
4018
|
}
|
|
4019
|
+
if (out.kind === 'tool' && !out.sub)
|
|
4020
|
+
noteHandoverTool(handoverLog, key, out.name, Date.now());
|
|
3941
4021
|
if (out.kind === 'tool') {
|
|
3942
4022
|
const stepBack = struggling.saw(out.name);
|
|
3943
4023
|
if (stepBack) {
|
|
@@ -4168,6 +4248,17 @@ export async function serve(opts) {
|
|
|
4168
4248
|
return flaredeckProxy(config.mcpServerName, config.mcpUrl, opts.auth, check.discovered);
|
|
4169
4249
|
}
|
|
4170
4250
|
async function wrapUp(key, cwd, done = false) {
|
|
4251
|
+
// Nothing to hand over: the session changed nothing since it last wrote the card's notes, or
|
|
4252
|
+
// never changed anything. A handover reopens the whole session (often 70k-126k tokens, the
|
|
4253
|
+
// cache long cold) to say so: JARVIS spent about half its turns on 20 Oct rewriting notes it
|
|
4254
|
+
// had just written (HR-0759 five times in three minutes). A finished card is always handed over.
|
|
4255
|
+
if (!done && !handoverNeeded(handoverLog.get(key))) {
|
|
4256
|
+
log('tool', `${key}: nothing changed since the last handover — closing without another`);
|
|
4257
|
+
handoverLog.delete(key);
|
|
4258
|
+
sessions.delete(key);
|
|
4259
|
+
return;
|
|
4260
|
+
}
|
|
4261
|
+
handoverLog.delete(key);
|
|
4171
4262
|
// Resume the session the work actually happened in — NOT the options the turn started with.
|
|
4172
4263
|
// On a new card those carry no resume id, so reusing them would open a third session and ask
|
|
4173
4264
|
// an agent with no memory of the work to summarise it. It would answer, too.
|
|
@@ -4228,6 +4319,13 @@ export async function serve(opts) {
|
|
|
4228
4319
|
'',
|
|
4229
4320
|
'Keep it short. If there is genuinely nothing worth passing on, say so and write nothing —',
|
|
4230
4321
|
'an empty note is better than a paragraph restating the card.',
|
|
4322
|
+
'',
|
|
4323
|
+
// HAL stopped a browser check six minutes into its run on this handover, "so nothing is
|
|
4324
|
+
// left running", and the next session started it over (HR-1074, 20 Oct). The card is
|
|
4325
|
+
// not finished: the environment and a run being waited on are what the next session needs.
|
|
4326
|
+
'Do NOT stop anything that is still running: the environment, a test run or a background',
|
|
4327
|
+
'job you are waiting on. The card is not finished, and the next session on it picks those',
|
|
4328
|
+
'up. Say in the note what is still running and where its result will be.',
|
|
4231
4329
|
]).join('\n'), {
|
|
4232
4330
|
config: { ...config, repo: cwd },
|
|
4233
4331
|
decider: sessionDecider,
|