@onepointfour-packs/flaredeck-agent 0.2.215 → 0.2.217
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/agent.js +3 -0
- package/dist/agent.js.map +1 -1
- package/dist/engine-antigravity.js +5 -0
- package/dist/engine-antigravity.js.map +1 -1
- package/dist/engine.d.ts +2 -0
- package/dist/engine.js.map +1 -1
- package/dist/features/hand-back.d.ts +5 -0
- package/dist/features/hand-back.js +7 -0
- package/dist/features/hand-back.js.map +1 -1
- package/dist/flaredeck-proxy.d.ts +6 -2
- package/dist/flaredeck-proxy.js +13 -3
- package/dist/flaredeck-proxy.js.map +1 -1
- package/dist/permissions.d.ts +1 -1
- package/dist/permissions.js +3 -0
- package/dist/permissions.js.map +1 -1
- package/dist/release.d.ts +18 -0
- package/dist/release.js +98 -0
- package/dist/release.js.map +1 -1
- package/dist/runs.d.ts +2 -0
- package/dist/runs.js +3 -0
- package/dist/runs.js.map +1 -1
- package/dist/serve.js +43 -4
- package/dist/serve.js.map +1 -1
- package/dist/team.d.ts +5 -0
- package/dist/team.js.map +1 -1
- package/dist/timesheets.d.ts +45 -0
- package/dist/timesheets.js +78 -0
- package/dist/timesheets.js.map +1 -0
- package/package.json +2 -2
package/dist/serve.js
CHANGED
|
@@ -11,7 +11,7 @@ import { answerFrom, createPresence, heldFor, modeCommand } from './presence.js'
|
|
|
11
11
|
import { defaultUploadRoots, fileTools, flaredeckStores } from './filestore.js';
|
|
12
12
|
import { scratchFor } from './cardmess.js';
|
|
13
13
|
import { installScripts, scriptTools, SCRIPT_TOOL_NAMES } from './trusted-scripts.js';
|
|
14
|
-
import { boardsNaming, fetchLadder, isSoloWorker, namedOnLadders, releaseTools } from './release.js';
|
|
14
|
+
import { boardsNaming, fetchLadder, isSoloWorker, namedOnLadders, releasePermissionAsk, releaseRightsBrief, releaseRightsForJudge, releaseTools } from './release.js';
|
|
15
15
|
import { PROFILES, profileFor, releaseRole, releasesOwnCards } from './profile.js';
|
|
16
16
|
import { ASSISTANT_KEY } from './assistant.js';
|
|
17
17
|
import { codePrefix, loadPrefixes, savePrefixes, SCRATCH_SWEEP_EVERY_MS, sweepScratch } from './scratch.js';
|
|
@@ -22,6 +22,7 @@ import { fetchTeam, myTeam, teamTools, TEAM_TOOL_NAMES } from './team.js';
|
|
|
22
22
|
import { scheduleTools, SCHEDULE_TOOL_NAMES } from './schedules.js';
|
|
23
23
|
import { preflightFlaredeck } from './flaredeck-check.js';
|
|
24
24
|
import { callFlaredeckTool, flaredeckProxy, offeredTo } from './flaredeck-proxy.js';
|
|
25
|
+
import { NO_TIMESHEETS, TimesheetLedger, timesheetRule } from './timesheets.js';
|
|
25
26
|
import { SCRIPT_REQUEST, allTargets, rerouteTo, resumeApprovedRuns, runTools } from './runs.js';
|
|
26
27
|
import { deliverDecision, flaredeckDecider } from './approval.js';
|
|
27
28
|
import { subscriptionsForAgent } from './subscriptions.js';
|
|
@@ -717,13 +718,36 @@ export async function serve(opts) {
|
|
|
717
718
|
`your branch and your notes are as you left them. If it does not, say so and ask again ` +
|
|
718
719
|
`rather than guessing.\n`);
|
|
719
720
|
};
|
|
721
|
+
/** When the turn now running began: anything a person said after that, the agent has not read. */
|
|
722
|
+
let turnSince = 0;
|
|
720
723
|
const park = (cardKey, why) => {
|
|
721
724
|
if (!cardKey)
|
|
722
725
|
return;
|
|
723
|
-
|
|
726
|
+
/* From the start of the turn that parks it, not the moment it parks. HRG-0012 (30 Oct): Cobus
|
|
727
|
+
answered "Yes, release to prod" while FRIDAY's turn was still flagging the card; the answer
|
|
728
|
+
arrived four seconds before the park, counted as "before the question", and the card sat
|
|
729
|
+
until somebody else replied. What arrived before the turn began is still excluded (HR-0932). */
|
|
730
|
+
const since = turnSince && Date.now() - turnSince < 2 * 60 * 60_000 ? turnSince : Date.now();
|
|
731
|
+
parked.set(cardKey, { why, since });
|
|
724
732
|
};
|
|
725
733
|
/** What the agent can reach for the card in hand, for the guard's judge. Set per card. */
|
|
726
734
|
let reachable = null;
|
|
735
|
+
/** The ladder of the board this turn's card is on — the release settings Jev and the agent are told. */
|
|
736
|
+
let boardLadder = null;
|
|
737
|
+
const ladderCache = new Map();
|
|
738
|
+
const ladderFor = async (boardId) => {
|
|
739
|
+
if (!boardId)
|
|
740
|
+
return null;
|
|
741
|
+
const hit = ladderCache.get(boardId);
|
|
742
|
+
if (hit && Date.now() - hit.at < 5 * 60_000)
|
|
743
|
+
return hit.ladder;
|
|
744
|
+
const tid = tenantFromToken(await opts.auth());
|
|
745
|
+
const ladder = tid ? await fetchLadder(config.mcpUrl, tid, boardId, () => opts.auth()).catch(() => null) : null;
|
|
746
|
+
ladderCache.set(boardId, { at: Date.now(), ladder });
|
|
747
|
+
return ladder;
|
|
748
|
+
};
|
|
749
|
+
/** The role the release tool checks against — said the same way to the agent and to Jev. */
|
|
750
|
+
const myReleaseRole = () => releaseRole(profile, soloWorker);
|
|
727
751
|
/**
|
|
728
752
|
* The pane's list of script requests waiting on a person: this agent's own request and, on a
|
|
729
753
|
* lead's pane, its team's. Read from the server — the one place every request and verdict
|
|
@@ -856,6 +880,9 @@ export async function serve(opts) {
|
|
|
856
880
|
: '')
|
|
857
881
|
: 'no running services and no database of its own — nothing is started for this card');
|
|
858
882
|
out.push('it CANNOT push to any git branch: publishing goes through a reviewed path it does not control');
|
|
883
|
+
const rights = releaseRightsForJudge(boardLadder, myReleaseRole(), selfId ?? '');
|
|
884
|
+
if (rights)
|
|
885
|
+
out.push(rights);
|
|
859
886
|
const targets = Object.keys(config.runs ?? {});
|
|
860
887
|
out.push(targets.length
|
|
861
888
|
? `production systems the harness can run an APPROVED script against: ${targets.join(', ')} — only after a person approves that exact script, never by a command the agent runs itself`
|
|
@@ -879,6 +906,7 @@ export async function serve(opts) {
|
|
|
879
906
|
const runsSet = opts.deck
|
|
880
907
|
? runTools(config.runs ?? {}, () => onCard, opts.deck, (t) => log('tool', t), {
|
|
881
908
|
attach: (card, path, comment) => attachFile(card, path, comment),
|
|
909
|
+
releaseAsk: (text) => releasePermissionAsk(text, boardLadder, myReleaseRole(), selfId ?? ''),
|
|
882
910
|
sendFile: (path, to, message) => sendFile(onCard?.cwd ?? config.repo, path, to || chat.person()?.uid || '', message),
|
|
883
911
|
flag: async (reason, kind, ask, flagOpts) => {
|
|
884
912
|
const cur = onCard;
|
|
@@ -1053,7 +1081,10 @@ export async function serve(opts) {
|
|
|
1053
1081
|
const until = presence.deadline();
|
|
1054
1082
|
state.asks = presence.held().map((a) => ({ card: a.code || a.card, question: a.question, options: a.options, person: a.person, ...(until ? { until } : {}) }));
|
|
1055
1083
|
};
|
|
1056
|
-
|
|
1084
|
+
/** The workspace's timesheet rule (Integrations → Agent timesheets), and what has been logged. */
|
|
1085
|
+
let timesheets = NO_TIMESHEETS;
|
|
1086
|
+
const timesheetLedger = new TimesheetLedger();
|
|
1087
|
+
const keepTool = (name) => offeredTo(profile.tools, name, timesheets.required);
|
|
1057
1088
|
/** Cards handed to the lead for review, and the branch head then. See features/hand-back.ts. */
|
|
1058
1089
|
const handedBack = handBackMemory();
|
|
1059
1090
|
try {
|
|
@@ -1087,6 +1118,9 @@ export async function serve(opts) {
|
|
|
1087
1118
|
if (leadId)
|
|
1088
1119
|
log('tool', `your lead is ${leadName} — ${leadName} verifies your work before it goes anywhere`);
|
|
1089
1120
|
profile = profileFor(team.you.role);
|
|
1121
|
+
timesheets = timesheetRule(team.you.timesheets);
|
|
1122
|
+
if (timesheets.required)
|
|
1123
|
+
log('tool', 'this workspace bills agents\' time — every card you finish gets a timesheet entry');
|
|
1090
1124
|
if (profile.chat) {
|
|
1091
1125
|
state.waitingFor = undefined;
|
|
1092
1126
|
await chat.start(tenantFromToken(await opts.auth()));
|
|
@@ -2851,6 +2885,7 @@ export async function serve(opts) {
|
|
|
2851
2885
|
if (beside.length && !event.alongside?.length)
|
|
2852
2886
|
event = { ...event, alongside: beside };
|
|
2853
2887
|
}
|
|
2888
|
+
turnSince = Date.now();
|
|
2854
2889
|
let repoChoiceNote = '';
|
|
2855
2890
|
// An assistant's card on a board it releases for: the board says which repository. A card the
|
|
2856
2891
|
// harness picked up itself carries none, and with one checkout here the turn took that one —
|
|
@@ -3785,6 +3820,7 @@ export async function serve(opts) {
|
|
|
3785
3820
|
lead: leadId ? { id: leadId, name: leadName } : null,
|
|
3786
3821
|
selfId,
|
|
3787
3822
|
handedBack,
|
|
3823
|
+
timesheet: () => timesheetLedger.gate(tag || event.cardCode || event.cardKey || '', timesheets, event.cardKey || ''),
|
|
3788
3824
|
handToLead: async (code, message) => {
|
|
3789
3825
|
const token = await opts.auth();
|
|
3790
3826
|
await callFlaredeckTool(config.mcpUrl, token, 'assign-card', { card_id: code, assignee: leadId });
|
|
@@ -3810,7 +3846,7 @@ export async function serve(opts) {
|
|
|
3810
3846
|
tag = code;
|
|
3811
3847
|
state.working = code;
|
|
3812
3848
|
};
|
|
3813
|
-
const flaredeck = flaredeckProxy(config.mcpServerName, config.mcpUrl, opts.auth, check.discovered, (w) => log('warn', w), gate, noteCard, keepTool, savedSoFar, [...myBoards]);
|
|
3849
|
+
const flaredeck = flaredeckProxy(config.mcpServerName, config.mcpUrl, opts.auth, check.discovered, (w) => log('warn', w), gate, noteCard, keepTool, savedSoFar, [...myBoards], (name, args) => timesheetLedger.record(name, args));
|
|
3814
3850
|
const card = await prepareCard(event, key, repo, queuedBehind);
|
|
3815
3851
|
if (!card)
|
|
3816
3852
|
return;
|
|
@@ -3828,6 +3864,7 @@ export async function serve(opts) {
|
|
|
3828
3864
|
* named. FlareDeck takes a human code wherever it takes a card id, so the code alone is
|
|
3829
3865
|
* enough to flag, comment and clear.
|
|
3830
3866
|
*/
|
|
3867
|
+
boardLadder = await ladderFor(event.boardKey);
|
|
3831
3868
|
onCard = event.cardKey
|
|
3832
3869
|
? {
|
|
3833
3870
|
card: event.cardKey,
|
|
@@ -3925,6 +3962,7 @@ export async function serve(opts) {
|
|
|
3925
3962
|
standing: standingBrief(!!teamSet, config.style ?? process.env['FLAREDECK_AGENT_STYLE'], isAssistantChat, config.mcpServers, config.trustedScripts),
|
|
3926
3963
|
finish: gate,
|
|
3927
3964
|
noteCard,
|
|
3965
|
+
called: (name, args) => timesheetLedger.record(name, args),
|
|
3928
3966
|
keep: keepTool,
|
|
3929
3967
|
saved: savedSoFar,
|
|
3930
3968
|
token: await opts.auth(),
|
|
@@ -3983,6 +4021,7 @@ export async function serve(opts) {
|
|
|
3983
4021
|
const brief = waitedNote(event) + prompt(event, profile.dispatch) + thread + intakeText(prepared) +
|
|
3984
4022
|
workspaceBrief(config.repo, await checkouts(config.repo, scope), chosen) +
|
|
3985
4023
|
worktreeBrief(tree) + (tree ? folderBrief(tree) : '') + notes + repoChoiceNote + (await resumeBrief(event.cardCode || event.cardKey || '', tree)) +
|
|
4024
|
+
releaseRightsBrief(boardLadder, myReleaseRole(), selfId ?? '') +
|
|
3986
4025
|
unclearBrief(prepared?.jev ?? null, leadName) + preflightBrief(checks) + backBrief(event) +
|
|
3987
4026
|
// What this kind of agent is told on top of the card: see roleBriefs in harness/prompt.ts.
|
|
3988
4027
|
roleBriefs(profile, { event, chat: isAssistantChat, person: chat.person(), leadWithoutCode, queuedBehind }) +
|