crewly 1.20.214 → 1.20.216
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/config/hooks/agent-status/report.sh +45 -6
- package/config/roles/team-leader/fragments/role-boundary.md +2 -1
- package/config/roles/team-leader/prompt.md +9 -5
- package/config/roles/team-leader/role-boundaries.md +3 -2
- package/config/roles/team-leader/tl-addon.md +9 -5
- package/config/skills/agent/core/ask-owner/SKILL.md +9 -2
- package/config/skills/agent/core/ask-owner/execute.sh +1 -1
- package/config/skills/agent/core/project-tickets/SKILL.md +44 -12
- package/config/skills/agent/core/project-tickets/execute.sh +46 -13
- package/config/skills/agent/core/project-tickets/execute.test.sh +19 -0
- package/config/skills/team-leader/delegate-task/SKILL.md +40 -0
- package/config/skills/team-leader/delegate-task/execute.sh +39 -1
- package/dist/backend/backend/src/constants.d.ts +101 -10
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +119 -9
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.d.ts +2 -1
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.js +26 -3
- package/dist/backend/backend/src/controllers/agent-hooks/agent-hooks.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts +10 -2
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js +17 -2
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts +2 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js +4 -2
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +32 -0
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team-lead-share.controller.d.ts +27 -0
- package/dist/backend/backend/src/controllers/team/team-lead-share.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/team/team-lead-share.controller.js +92 -0
- package/dist/backend/backend/src/controllers/team/team-lead-share.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/team/team.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.routes.js +4 -0
- package/dist/backend/backend/src/controllers/team/team.routes.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +16 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +6 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-contract.d.ts +25 -1
- package/dist/backend/backend/src/services/decisions/decision-contract.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-contract.js +39 -2
- package/dist/backend/backend/src/services/decisions/decision-contract.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.js +17 -1
- package/dist/backend/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-item-card.d.ts +26 -0
- package/dist/backend/backend/src/services/open-items/open-item-card.d.ts.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-item-card.js +71 -1
- package/dist/backend/backend/src/services/open-items/open-item-card.js.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/open-items/open-items.service.js +6 -3
- package/dist/backend/backend/src/services/open-items/open-items.service.js.map +1 -1
- package/dist/backend/backend/src/services/orc/reply-destination.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orc/reply-destination.wiring.js +46 -1
- package/dist/backend/backend/src/services/orc/reply-destination.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/orc/work-item-destination.d.ts +35 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orc/work-item-destination.js +75 -2
- package/dist/backend/backend/src/services/orc/work-item-destination.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed-command.d.ts +108 -0
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed-command.d.ts.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed-command.js +223 -0
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed-command.js.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed.wiring.d.ts +57 -0
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed.wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed.wiring.js +90 -0
- package/dist/backend/backend/src/services/project-tickets/autopilot-speed.wiring.js.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts +18 -4
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.js +18 -4
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts +135 -14
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js +111 -18
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts +73 -4
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js +86 -7
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-trace.d.ts +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-trace.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-trace.js +7 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-trace.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts +104 -4
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js +424 -12
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-agent-dm.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-agent-dm.service.js +2 -1
- package/dist/backend/backend/src/services/slack/slack-agent-dm.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-initializer.js +10 -0
- package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts +7 -0
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +25 -2
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +23 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js +74 -2
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/backend/backend/src/services/tl-delegation/lead-share.d.ts +108 -0
- package/dist/backend/backend/src/services/tl-delegation/lead-share.d.ts.map +1 -0
- package/dist/backend/backend/src/services/tl-delegation/lead-share.js +170 -0
- package/dist/backend/backend/src/services/tl-delegation/lead-share.js.map +1 -0
- package/dist/backend/backend/src/services/tl-delegation/lead-share.wiring.d.ts +32 -0
- package/dist/backend/backend/src/services/tl-delegation/lead-share.wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/tl-delegation/lead-share.wiring.js +47 -0
- package/dist/backend/backend/src/services/tl-delegation/lead-share.wiring.js.map +1 -0
- package/dist/backend/backend/src/services/tl-delegation/tl-delegation.service.d.ts +207 -0
- package/dist/backend/backend/src/services/tl-delegation/tl-delegation.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/tl-delegation/tl-delegation.service.js +377 -0
- package/dist/backend/backend/src/services/tl-delegation/tl-delegation.service.js.map +1 -0
- package/dist/backend/backend/src/types/decision.types.d.ts +6 -1
- package/dist/backend/backend/src/types/decision.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/decision.types.js +1 -1
- package/dist/backend/backend/src/types/ticket-autopilot.types.d.ts +46 -4
- package/dist/backend/backend/src/types/ticket-autopilot.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/ticket-autopilot.types.js +43 -2
- package/dist/backend/backend/src/types/ticket-autopilot.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.js +1 -0
- package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
- package/dist/backend/backend/src/utils/defaultPrompts.js +3 -3
- package/dist/backend/backend/src/utils/defaultPrompts.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +101 -10
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +119 -9
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +6 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision-contract.d.ts +25 -1
- package/dist/cli/backend/src/services/decisions/decision-contract.d.ts.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision-contract.js +39 -2
- package/dist/cli/backend/src/services/decisions/decision-contract.js.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision.service.js +17 -1
- package/dist/cli/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-item-card.d.ts +26 -0
- package/dist/cli/backend/src/services/open-items/open-item-card.d.ts.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-item-card.js +71 -1
- package/dist/cli/backend/src/services/open-items/open-item-card.js.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-items.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/open-items/open-items.service.js +6 -3
- package/dist/cli/backend/src/services/open-items/open-items.service.js.map +1 -1
- package/dist/cli/backend/src/services/orc/work-item-destination.d.ts +35 -0
- package/dist/cli/backend/src/services/orc/work-item-destination.d.ts.map +1 -1
- package/dist/cli/backend/src/services/orc/work-item-destination.js +75 -2
- package/dist/cli/backend/src/services/orc/work-item-destination.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-agent-dm.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-agent-dm.service.js +2 -1
- package/dist/cli/backend/src/services/slack/slack-agent-dm.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts +7 -0
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +25 -2
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +23 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js +74 -2
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/cli/backend/src/types/decision.types.d.ts +6 -1
- package/dist/cli/backend/src/types/decision.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/decision.types.js +1 -1
- package/dist/cli/backend/src/types/ticket-autopilot.types.d.ts +46 -4
- package/dist/cli/backend/src/types/ticket-autopilot.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/ticket-autopilot.types.js +43 -2
- package/dist/cli/backend/src/types/ticket-autopilot.types.js.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.js +1 -0
- package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
- package/frontend/dist/assets/{index-917db1b8.js → index-bc4e2a93.js} +274 -274
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team-lead delegation: the execution nudge, its counts, and "no member
|
|
3
|
+
* fits" records (crewly#1083, specs/2026-10-04-tl-delegation.md §2, §4).
|
|
4
|
+
*
|
|
5
|
+
* The nudge rides on the Claude Code agent-status hook: each `PostToolUse`
|
|
6
|
+
* reports the tool name, and a lead that edited files
|
|
7
|
+
* {@link TL_DELEGATION_CONSTANTS.EDIT_THRESHOLD} times within
|
|
8
|
+
* {@link TL_DELEGATION_CONSTANTS.WINDOW_MS} gets one note back as hook
|
|
9
|
+
* `additionalContext` — at most once per
|
|
10
|
+
* {@link TL_DELEGATION_CONSTANTS.NUDGE_COOLDOWN_MS}. It never blocks: the
|
|
11
|
+
* tool already ran, and any failure means no note.
|
|
12
|
+
*
|
|
13
|
+
* @module services/tl-delegation/tl-delegation.service
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from 'fs';
|
|
16
|
+
import * as path from 'path';
|
|
17
|
+
import { TL_DELEGATION_CONSTANTS } from '../../constants.js';
|
|
18
|
+
import { getTeamLeads } from '../../utils/team.utils.js';
|
|
19
|
+
import { getCrewlyHomePath } from '../core/crewly-home.utils.js';
|
|
20
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
21
|
+
import { memberLedgerKeys } from './lead-share.js';
|
|
22
|
+
const AVAILABILITY_ORDER = { idle: 0, stopped: 1, working: 2 };
|
|
23
|
+
const AVAILABILITY_WORDS = {
|
|
24
|
+
idle: 'idle',
|
|
25
|
+
stopped: 'stopped — starts when assigned',
|
|
26
|
+
working: 'working',
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Members best placed to take hands-on work: idle first, then stopped, then
|
|
30
|
+
* working; at most {@link TL_DELEGATION_CONSTANTS.NUDGE_MAX_MEMBERS}.
|
|
31
|
+
*
|
|
32
|
+
* @param members - The lead's members
|
|
33
|
+
* @returns Ranked, capped list
|
|
34
|
+
*/
|
|
35
|
+
export function rankMembersForNudge(members) {
|
|
36
|
+
return [...members]
|
|
37
|
+
.sort((a, b) => AVAILABILITY_ORDER[a.availability] - AVAILABILITY_ORDER[b.availability])
|
|
38
|
+
.slice(0, TL_DELEGATION_CONSTANTS.NUDGE_MAX_MEMBERS);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The nudge text (English harness text).
|
|
42
|
+
*
|
|
43
|
+
* @param edits - Edits counted in the window
|
|
44
|
+
* @param members - The lead's members
|
|
45
|
+
* @returns Note
|
|
46
|
+
*/
|
|
47
|
+
export function buildNudgeText(edits, members) {
|
|
48
|
+
const minutes = Math.round(TL_DELEGATION_CONSTANTS.WINDOW_MS / 60000);
|
|
49
|
+
const named = rankMembersForNudge(members)
|
|
50
|
+
.map((m) => `${m.name} (${m.role}, ${AVAILABILITY_WORDS[m.availability]})`)
|
|
51
|
+
.join(', ');
|
|
52
|
+
return (`${TL_DELEGATION_CONSTANTS.NUDGE_TAG} You have edited files ${edits} times in the last ${minutes} minutes. ` +
|
|
53
|
+
`As team lead, hand hands-on work to a member: ${named}. ` +
|
|
54
|
+
'Any member can do any work that needs no special account, tool or permission — role is a preference, not a limit. ' +
|
|
55
|
+
'Delegate with delegate-task (pass --thread <key> for an owner request, so the member answers the owner in that thread). ' +
|
|
56
|
+
'Keep it only if the change is tiny, every member is busy, or it needs your own judgment — then record why: ' +
|
|
57
|
+
'delegate-task --no-member-fits "<what is missing>" --task "<the work>".');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Local date key (YYYY-MM-DD).
|
|
61
|
+
*
|
|
62
|
+
* @param ms - Epoch ms
|
|
63
|
+
* @returns Day key
|
|
64
|
+
*/
|
|
65
|
+
export function localDayKey(ms) {
|
|
66
|
+
const d = new Date(ms);
|
|
67
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
68
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Trim a free-text field to one line within the cap.
|
|
72
|
+
*
|
|
73
|
+
* @param text - Any text
|
|
74
|
+
* @returns One line, capped
|
|
75
|
+
*/
|
|
76
|
+
function oneLine(text) {
|
|
77
|
+
const flat = text.replace(/\s+/g, ' ').trim();
|
|
78
|
+
const max = TL_DELEGATION_CONSTANTS.MAX_TEXT_CHARS;
|
|
79
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Nudge bookkeeping and kept-work records.
|
|
83
|
+
*/
|
|
84
|
+
export class TlDelegationService {
|
|
85
|
+
static instance = null;
|
|
86
|
+
deps;
|
|
87
|
+
statePath;
|
|
88
|
+
now;
|
|
89
|
+
logger;
|
|
90
|
+
/** session → recent edit times (epoch ms), in-memory only */
|
|
91
|
+
edits = new Map();
|
|
92
|
+
state = null;
|
|
93
|
+
writing = Promise.resolve();
|
|
94
|
+
/**
|
|
95
|
+
* @param deps - Collaborators
|
|
96
|
+
*/
|
|
97
|
+
constructor(deps) {
|
|
98
|
+
this.deps = deps;
|
|
99
|
+
this.statePath = deps.statePath ?? path.join(getCrewlyHomePath(), TL_DELEGATION_CONSTANTS.STATE_FILENAME);
|
|
100
|
+
this.now = deps.now ?? (() => Date.now());
|
|
101
|
+
this.logger = deps.logger ?? LoggerService.getInstance().createComponentLogger('TlDelegation');
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The process instance (built from the team store on first use).
|
|
105
|
+
*
|
|
106
|
+
* @returns Service
|
|
107
|
+
*/
|
|
108
|
+
static getInstance() {
|
|
109
|
+
if (!TlDelegationService.instance) {
|
|
110
|
+
TlDelegationService.instance = new TlDelegationService({ leadContext: cachedLeadContext() });
|
|
111
|
+
}
|
|
112
|
+
return TlDelegationService.instance;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Replace (tests) or clear the process instance.
|
|
116
|
+
*
|
|
117
|
+
* @param service - New instance, or null
|
|
118
|
+
*/
|
|
119
|
+
static setInstance(service) {
|
|
120
|
+
TlDelegationService.instance = service;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* A tool call finished in `session`. Returns the nudge to show the agent,
|
|
124
|
+
* or null. Never throws.
|
|
125
|
+
*
|
|
126
|
+
* @param session - Agent session
|
|
127
|
+
* @param toolName - Claude Code tool name
|
|
128
|
+
* @returns Nudge text, or null
|
|
129
|
+
*/
|
|
130
|
+
async observeToolUse(session, toolName) {
|
|
131
|
+
try {
|
|
132
|
+
if (!TL_DELEGATION_CONSTANTS.EDIT_TOOLS.includes(toolName))
|
|
133
|
+
return null;
|
|
134
|
+
const now = this.now();
|
|
135
|
+
const recent = (this.edits.get(session) ?? []).filter((t) => now - t < TL_DELEGATION_CONSTANTS.WINDOW_MS);
|
|
136
|
+
recent.push(now);
|
|
137
|
+
this.edits.set(session, recent);
|
|
138
|
+
if (recent.length < TL_DELEGATION_CONSTANTS.EDIT_THRESHOLD)
|
|
139
|
+
return null;
|
|
140
|
+
const state = this.load();
|
|
141
|
+
const counts = state.nudges[session];
|
|
142
|
+
if (counts?.lastAt !== undefined && now - counts.lastAt < TL_DELEGATION_CONSTANTS.NUDGE_COOLDOWN_MS)
|
|
143
|
+
return null;
|
|
144
|
+
const lead = await this.deps.leadContext(session);
|
|
145
|
+
if (!lead || lead.members.length === 0) {
|
|
146
|
+
// Not a lead: stop counting for it until the window passes.
|
|
147
|
+
this.edits.set(session, []);
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
const text = buildNudgeText(recent.length, lead.members);
|
|
151
|
+
this.edits.set(session, []);
|
|
152
|
+
const next = { ...(counts ?? { count: 0, followed: 0 }) };
|
|
153
|
+
next.count += 1;
|
|
154
|
+
next.lastAt = now;
|
|
155
|
+
next.pendingSince = now;
|
|
156
|
+
const day = localDayKey(now);
|
|
157
|
+
const days = { ...(next.days ?? {}) };
|
|
158
|
+
days[day] = { count: (days[day]?.count ?? 0) + 1, followed: days[day]?.followed ?? 0 };
|
|
159
|
+
next.days = pruneDays(days, now);
|
|
160
|
+
state.nudges[session] = next;
|
|
161
|
+
this.save();
|
|
162
|
+
this.logger.info('Team lead nudged to delegate', { session, teamId: lead.teamId, edits: recent.length });
|
|
163
|
+
return text;
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
this.logger.debug('Nudge check failed — no nudge', { session, error: err instanceof Error ? err.message : String(err) });
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* A work item was delegated. Counts as following a nudge when the
|
|
172
|
+
* delegator was nudged within {@link TL_DELEGATION_CONSTANTS.FOLLOW_WINDOW_MS}.
|
|
173
|
+
*
|
|
174
|
+
* @param delegator - Delegating session
|
|
175
|
+
* @param target - Target session
|
|
176
|
+
* @returns True when it followed a nudge
|
|
177
|
+
*/
|
|
178
|
+
recordDelegation(delegator, target) {
|
|
179
|
+
try {
|
|
180
|
+
if (!delegator || !target || delegator === target)
|
|
181
|
+
return false;
|
|
182
|
+
const state = this.load();
|
|
183
|
+
const counts = state.nudges[delegator];
|
|
184
|
+
if (!counts?.pendingSince)
|
|
185
|
+
return false;
|
|
186
|
+
const now = this.now();
|
|
187
|
+
if (now - counts.pendingSince > TL_DELEGATION_CONSTANTS.FOLLOW_WINDOW_MS) {
|
|
188
|
+
delete counts.pendingSince;
|
|
189
|
+
this.save();
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
counts.followed += 1;
|
|
193
|
+
const day = localDayKey(counts.pendingSince);
|
|
194
|
+
if (counts.days?.[day])
|
|
195
|
+
counts.days[day].followed += 1;
|
|
196
|
+
delete counts.pendingSince;
|
|
197
|
+
this.save();
|
|
198
|
+
this.logger.info('Team lead delegated after a nudge', { delegator, target });
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Record work a lead keeps because no member fits.
|
|
207
|
+
*
|
|
208
|
+
* @param input - Lead session, team, reason, work, optional work item / ticket
|
|
209
|
+
* @returns The stored record
|
|
210
|
+
*/
|
|
211
|
+
recordKeptWork(input) {
|
|
212
|
+
const record = {
|
|
213
|
+
at: new Date(this.now()).toISOString(),
|
|
214
|
+
session: input.session,
|
|
215
|
+
...(input.teamId ? { teamId: input.teamId } : {}),
|
|
216
|
+
reason: oneLine(input.reason),
|
|
217
|
+
work: oneLine(input.work),
|
|
218
|
+
...(input.workItemId ? { workItemId: input.workItemId } : {}),
|
|
219
|
+
...(input.ticket ? { ticket: input.ticket } : {}),
|
|
220
|
+
};
|
|
221
|
+
const state = this.load();
|
|
222
|
+
state.records.push(record);
|
|
223
|
+
if (state.records.length > TL_DELEGATION_CONSTANTS.MAX_RECORDS) {
|
|
224
|
+
state.records.splice(0, state.records.length - TL_DELEGATION_CONSTANTS.MAX_RECORDS);
|
|
225
|
+
}
|
|
226
|
+
this.save();
|
|
227
|
+
this.logger.info('Team lead kept work: no member fits', { session: input.session, teamId: input.teamId });
|
|
228
|
+
return record;
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Kept-work records since a time, optionally for one team or set of sessions.
|
|
232
|
+
*
|
|
233
|
+
* @param sinceMs - Lower bound (epoch ms)
|
|
234
|
+
* @param filter - Team id and/or lead sessions (either matches)
|
|
235
|
+
* @returns Records, oldest first
|
|
236
|
+
*/
|
|
237
|
+
keptWorkSince(sinceMs, filter) {
|
|
238
|
+
const sessions = new Set(filter?.sessions ?? []);
|
|
239
|
+
return this.load().records.filter((r) => {
|
|
240
|
+
if ((Date.parse(r.at) || 0) < sinceMs)
|
|
241
|
+
return false;
|
|
242
|
+
if (!filter)
|
|
243
|
+
return true;
|
|
244
|
+
return (filter.teamId !== undefined && r.teamId === filter.teamId) || sessions.has(r.session);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Nudge counts of some sessions: all-time, and for one local day.
|
|
249
|
+
*
|
|
250
|
+
* @param sessions - Lead sessions
|
|
251
|
+
* @param dayMs - A time on the day to report (default: now)
|
|
252
|
+
* @returns Totals and that day's numbers
|
|
253
|
+
*/
|
|
254
|
+
nudgeCounts(sessions, dayMs) {
|
|
255
|
+
const state = this.load();
|
|
256
|
+
const day = localDayKey(dayMs ?? this.now());
|
|
257
|
+
const out = { total: { count: 0, followed: 0 }, day: { count: 0, followed: 0 } };
|
|
258
|
+
for (const s of new Set(sessions)) {
|
|
259
|
+
const c = state.nudges[s];
|
|
260
|
+
if (!c)
|
|
261
|
+
continue;
|
|
262
|
+
out.total.count += c.count;
|
|
263
|
+
out.total.followed += c.followed;
|
|
264
|
+
out.day.count += c.days?.[day]?.count ?? 0;
|
|
265
|
+
out.day.followed += c.days?.[day]?.followed ?? 0;
|
|
266
|
+
}
|
|
267
|
+
return out;
|
|
268
|
+
}
|
|
269
|
+
/** Wait for pending writes (tests, shutdown). */
|
|
270
|
+
async flush() {
|
|
271
|
+
await this.writing;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Load the state once (a missing or broken file starts empty).
|
|
275
|
+
*
|
|
276
|
+
* @returns State
|
|
277
|
+
*/
|
|
278
|
+
load() {
|
|
279
|
+
if (this.state)
|
|
280
|
+
return this.state;
|
|
281
|
+
let parsed = null;
|
|
282
|
+
try {
|
|
283
|
+
parsed = JSON.parse(fs.readFileSync(this.statePath, 'utf8'));
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
parsed = null;
|
|
287
|
+
}
|
|
288
|
+
this.state = {
|
|
289
|
+
version: 1,
|
|
290
|
+
nudges: parsed && typeof parsed.nudges === 'object' && parsed.nudges ? parsed.nudges : {},
|
|
291
|
+
records: Array.isArray(parsed?.records) ? parsed.records : [],
|
|
292
|
+
};
|
|
293
|
+
return this.state;
|
|
294
|
+
}
|
|
295
|
+
/** Write the state (serialized, best-effort). */
|
|
296
|
+
save() {
|
|
297
|
+
const snapshot = JSON.stringify(this.state, null, 2);
|
|
298
|
+
this.writing = this.writing
|
|
299
|
+
.then(async () => {
|
|
300
|
+
await fs.promises.mkdir(path.dirname(this.statePath), { recursive: true });
|
|
301
|
+
const tmp = `${this.statePath}.tmp`;
|
|
302
|
+
await fs.promises.writeFile(tmp, snapshot, 'utf8');
|
|
303
|
+
await fs.promises.rename(tmp, this.statePath);
|
|
304
|
+
})
|
|
305
|
+
.catch((err) => {
|
|
306
|
+
this.logger.warn('Could not save team-lead delegation state', { error: err instanceof Error ? err.message : String(err) });
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Keep only the last 14 days of per-day counts.
|
|
312
|
+
*
|
|
313
|
+
* @param days - Day key → counts
|
|
314
|
+
* @param now - Clock
|
|
315
|
+
* @returns Pruned map
|
|
316
|
+
*/
|
|
317
|
+
function pruneDays(days, now) {
|
|
318
|
+
const oldest = localDayKey(now - 14 * 24 * 60 * 60 * 1000);
|
|
319
|
+
return Object.fromEntries(Object.entries(days).filter(([k]) => k >= oldest));
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* The availability of a member, as the nudge words it.
|
|
323
|
+
*
|
|
324
|
+
* @param m - Member
|
|
325
|
+
* @returns Availability
|
|
326
|
+
*/
|
|
327
|
+
export function memberAvailability(m) {
|
|
328
|
+
if (m.agentStatus === 'inactive' || m.agentStatus === 'suspended')
|
|
329
|
+
return 'stopped';
|
|
330
|
+
return m.workingStatus === 'in_progress' ? 'working' : 'idle';
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* The lead context of a session among teams: the team it leads, with its
|
|
334
|
+
* other members. Null when it leads no team with other members.
|
|
335
|
+
*
|
|
336
|
+
* @param teams - Teams
|
|
337
|
+
* @param session - Agent session
|
|
338
|
+
* @returns Context, or null
|
|
339
|
+
*/
|
|
340
|
+
export function leadContextFromTeams(teams, session) {
|
|
341
|
+
for (const team of teams) {
|
|
342
|
+
if (team.archived)
|
|
343
|
+
continue;
|
|
344
|
+
const leads = getTeamLeads(team);
|
|
345
|
+
if (!leads.some((l) => memberLedgerKeys(l).includes(session)))
|
|
346
|
+
continue;
|
|
347
|
+
const leadIds = new Set(leads.map((l) => l.id));
|
|
348
|
+
const members = (team.members ?? [])
|
|
349
|
+
.filter((m) => !leadIds.has(m.id) && m.role !== 'orchestrator')
|
|
350
|
+
.map((m) => ({ name: m.name, role: String(m.role), availability: memberAvailability(m) }));
|
|
351
|
+
if (members.length === 0)
|
|
352
|
+
continue;
|
|
353
|
+
return { teamId: team.id, teamName: team.name, members };
|
|
354
|
+
}
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Lead context from the team store, cached per session for a minute (the
|
|
359
|
+
* hook calls this on every file edit).
|
|
360
|
+
*
|
|
361
|
+
* @returns Lookup
|
|
362
|
+
*/
|
|
363
|
+
function cachedLeadContext() {
|
|
364
|
+
const cache = new Map();
|
|
365
|
+
const TTL = 60 * 1000;
|
|
366
|
+
return async (session) => {
|
|
367
|
+
const hit = cache.get(session);
|
|
368
|
+
if (hit && Date.now() - hit.at < TTL)
|
|
369
|
+
return hit.value;
|
|
370
|
+
const { StorageService } = await import('../core/storage.service.js');
|
|
371
|
+
const teams = await StorageService.getInstance().getTeams().catch(() => []);
|
|
372
|
+
const value = leadContextFromTeams(teams, session);
|
|
373
|
+
cache.set(session, { at: Date.now(), value });
|
|
374
|
+
return value;
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
//# sourceMappingURL=tl-delegation.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tl-delegation.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/tl-delegation/tl-delegation.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Decision cards — structured owner questions (specs/2026-10-01-decision-cards.md).
|
|
3
3
|
*
|
|
4
|
-
* An agent that needs the owner asks ONE question with 2–
|
|
4
|
+
* An agent that needs the owner asks ONE question with 2–5 options, a default
|
|
5
5
|
* and a deadline. The responsible agent's own Slack bot posts it as a card in
|
|
6
6
|
* the team channel (ticket thread, or a new thread), and the owner answers
|
|
7
7
|
* with a button, a reaction or a thread reply. The decision is stored here
|
|
@@ -71,6 +71,11 @@ export interface DecisionOption {
|
|
|
71
71
|
label: string;
|
|
72
72
|
/** Optional one-line detail shown under the question */
|
|
73
73
|
detail?: string;
|
|
74
|
+
/**
|
|
75
|
+
* The agent's full question this option stands for (either/or cards derived
|
|
76
|
+
* from consecutive reply questions): quoted back to the agent when chosen.
|
|
77
|
+
*/
|
|
78
|
+
question?: string;
|
|
74
79
|
}
|
|
75
80
|
/** Lifecycle of a decision. */
|
|
76
81
|
export type DecisionStatus =
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decision.types.d.ts","sourceRoot":"","sources":["../../../../../backend/src/types/decision.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,6DAA6D;AAC7D,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,gBAAgB,GAAG,eAAe,CAAC;AAElH;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,YAAY,GAAG,gBAAgB,GAAG,eAAe,GAAG,gBAAgB,GAAG,WAAW,GAAG,sBAAsB,GAAG,oBAAoB,CAAC;AAE/I,mFAAmF;AACnF,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,UAAU,CAAC;AAEjD,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,0DAA0D;IAC1D,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,oEAAoE;AACpE,MAAM,WAAW,oBAAoB;IACnC,iCAAiC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,4BAA4B;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qCAAqC;AACrC,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"decision.types.d.ts","sourceRoot":"","sources":["../../../../../backend/src/types/decision.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,6DAA6D;AAC7D,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,gBAAgB,GAAG,eAAe,CAAC;AAElH;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,YAAY,GAAG,gBAAgB,GAAG,eAAe,GAAG,gBAAgB,GAAG,WAAW,GAAG,sBAAsB,GAAG,oBAAoB,CAAC;AAE/I,mFAAmF;AACnF,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,UAAU,CAAC;AAEjD,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,0DAA0D;IAC1D,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,oEAAoE;AACpE,MAAM,WAAW,oBAAoB;IACnC,iCAAiC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,4BAA4B;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qCAAqC;AACrC,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,+BAA+B;AAC/B,MAAM,MAAM,cAAc;AACxB,2DAA2D;AACzD,MAAM;AACR,qEAAqE;GACnE,UAAU;AACZ,sDAAsD;GACpD,WAAW;AACb,gGAAgG;GAC9F,QAAQ;AACV,2DAA2D;GACzD,WAAW;AACb,4FAA4F;GAC1F,SAAS;AACX,0GAA0G;GACxG,SAAS,CAAC;AAEd,6BAA6B;AAC7B;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,GAAG,UAAU,GAAG,MAAM,CAAC;AAE/G,yDAAyD;AACzD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sBAAsB;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qCAAqC;AACrC,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,gCAAgC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,MAAM,EAAE,OAAO,CAAC;IAChB,4GAA4G;IAC5G,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC5B,cAAc;IACd,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,sEAAsE;IACtE,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,sDAAsD;IACtD,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,2GAA2G;IAC3G,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,MAAM,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACrG,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,KAAK,CAAC,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,8DAA8D;IAC9D,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC;;;OAGG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,cAAc,CAAC;IACvB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,0FAA0F;IAC1F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wGAAwG;IACxG,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4FAA4F;IAC5F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACnC,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wCAAwC;AACxC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iCAAiC;IACjC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,uBAAuB;AACvB,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,IAAI,CAAC;IACf,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,0DAA0D;AAC1D,MAAM,WAAW,mBAAmB;IAClC,kBAAkB;IAClB,CAAC,EAAE,MAAM,CAAC;IACV,qCAAqC;IACrC,CAAC,EAAE,MAAM,CAAC;IACV,qEAAqE;IACrE,CAAC,EAAE,MAAM,CAAC;CACX;AAED,kFAAkF;AAClF,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE;AACpB,wCAAwC;GACtC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AAChC,mGAAmG;GACjG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Decision cards — structured owner questions (specs/2026-10-01-decision-cards.md).
|
|
3
3
|
*
|
|
4
|
-
* An agent that needs the owner asks ONE question with 2–
|
|
4
|
+
* An agent that needs the owner asks ONE question with 2–5 options, a default
|
|
5
5
|
* and a deadline. The responsible agent's own Slack bot posts it as a card in
|
|
6
6
|
* the team channel (ticket thread, or a new thread), and the owner answers
|
|
7
7
|
* with a button, a reaction or a thread reply. The decision is stored here
|
|
@@ -6,6 +6,25 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module types/ticket-autopilot.types
|
|
8
8
|
*/
|
|
9
|
+
import { TICKET_AUTOPILOT_CONSTANTS } from '../constants.js';
|
|
10
|
+
/** Autopilot speed (specs/2026-10-04-autopilot-speed-modes.md). */
|
|
11
|
+
export type AutopilotSpeedMode = 'rush' | 'normal' | 'chill';
|
|
12
|
+
/** What a speed mode supplies (see TICKET_AUTOPILOT_CONSTANTS.SPEED_MODES). */
|
|
13
|
+
export type AutopilotSpeedProfile = (typeof TICKET_AUTOPILOT_CONSTANTS.SPEED_MODES)[AutopilotSpeedMode];
|
|
14
|
+
/**
|
|
15
|
+
* Whether a value is a speed mode name.
|
|
16
|
+
*
|
|
17
|
+
* @param value - Anything
|
|
18
|
+
* @returns True for rush / normal / chill
|
|
19
|
+
*/
|
|
20
|
+
export declare function isAutopilotSpeedMode(value: unknown): value is AutopilotSpeedMode;
|
|
21
|
+
/**
|
|
22
|
+
* The profile of a speed mode.
|
|
23
|
+
*
|
|
24
|
+
* @param mode - Mode
|
|
25
|
+
* @returns Its replan gap / cap, self-review cadence, empty-replan retry and default budget
|
|
26
|
+
*/
|
|
27
|
+
export declare function speedProfile(mode: AutopilotSpeedMode): AutopilotSpeedProfile;
|
|
9
28
|
/** The per-project switch as stored. Every field but `enabled` is optional. */
|
|
10
29
|
export interface TicketAutopilotSettings {
|
|
11
30
|
/** Master switch (default off) */
|
|
@@ -35,11 +54,17 @@ export interface TicketAutopilotSettings {
|
|
|
35
54
|
retro?: boolean;
|
|
36
55
|
/**
|
|
37
56
|
* Goal replans per local day (specs/2026-10-04-autopilot-goal-replan.md):
|
|
38
|
-
* how often the driver may be woken to plan the next tickets
|
|
39
|
-
* project's goal when nothing is left to triage. 0 = off.
|
|
40
|
-
*
|
|
57
|
+
* a hard cap on how often the driver may be woken to plan the next tickets
|
|
58
|
+
* toward the project's goal when nothing is left to triage. 0 = off.
|
|
59
|
+
* Absent = the speed mode's daily cap.
|
|
41
60
|
*/
|
|
42
61
|
replansPerDay?: number;
|
|
62
|
+
/**
|
|
63
|
+
* Speed mode (specs/2026-10-04-autopilot-speed-modes.md): replan gap and
|
|
64
|
+
* daily cap, self-review cadence, retry after an empty replan, and the
|
|
65
|
+
* budget when none is set. Absent = normal.
|
|
66
|
+
*/
|
|
67
|
+
speedMode?: AutopilotSpeedMode;
|
|
43
68
|
/**
|
|
44
69
|
* Hours a goal replan may stay live before it is expired (cancelled where
|
|
45
70
|
* possible, never counted as live again). Absent = the default
|
|
@@ -56,10 +81,25 @@ export interface ResolvedTicketAutopilotSettings {
|
|
|
56
81
|
maxInFlightPerMember: number;
|
|
57
82
|
/** The retro switch as set (null = the default: on while an autopilot experiment runs) */
|
|
58
83
|
retro: boolean | null;
|
|
59
|
-
/** Goal replans allowed per local day (0 = off) */
|
|
84
|
+
/** Goal replans allowed per local day (0 = off): the explicit setting, else the mode's cap */
|
|
60
85
|
replansPerDay: number;
|
|
61
86
|
/** Hours a goal replan may stay live */
|
|
62
87
|
replanTtlHours: number;
|
|
88
|
+
/** Speed mode (normal when never set) */
|
|
89
|
+
speedMode: AutopilotSpeedMode;
|
|
90
|
+
/** Where the budget comes from: the project's own setting, or the mode's default */
|
|
91
|
+
budgetSource: 'explicit' | 'mode';
|
|
92
|
+
/** Where the daily replan cap comes from: the project's own setting, or the mode */
|
|
93
|
+
replansPerDaySource: 'explicit' | 'mode';
|
|
94
|
+
/** A replan never starts sooner than this after the last one (ms) */
|
|
95
|
+
replanMinGapMs: number;
|
|
96
|
+
/** Cadence of the driver's self-review (ms) */
|
|
97
|
+
selfReviewEveryMs: number;
|
|
98
|
+
/** After a replan that opened no tickets: retry after this many hours, or this many days later */
|
|
99
|
+
emptyReplanRetry: {
|
|
100
|
+
unit: 'hours' | 'days';
|
|
101
|
+
amount: number;
|
|
102
|
+
};
|
|
63
103
|
}
|
|
64
104
|
/** A change request for the settings (API / skill body). */
|
|
65
105
|
export interface TicketAutopilotSettingsInput {
|
|
@@ -78,6 +118,8 @@ export interface TicketAutopilotSettingsInput {
|
|
|
78
118
|
replansPerDay?: unknown;
|
|
79
119
|
/** An integer 1..limit (hours); `null` resets to the default */
|
|
80
120
|
replanTtlHours?: unknown;
|
|
121
|
+
/** rush / normal / chill; `null` or "default" resets to normal */
|
|
122
|
+
speedMode?: unknown;
|
|
81
123
|
}
|
|
82
124
|
/** Outcome of {@link applyTicketAutopilotInput}. */
|
|
83
125
|
export type TicketAutopilotInputResult = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ticket-autopilot.types.d.ts","sourceRoot":"","sources":["../../../../../backend/src/types/ticket-autopilot.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"ticket-autopilot.types.d.ts","sourceRoot":"","sources":["../../../../../backend/src/types/ticket-autopilot.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,0BAA0B,EAAmB,MAAM,iBAAiB,CAAC;AAG9E,mEAAmE;AACnE,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE7D,+EAA+E;AAC/E,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,0BAA0B,CAAC,WAAW,CAAC,CAAC,kBAAkB,CAAC,CAAC;AAExG;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAEhF;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,kBAAkB,GAAG,qBAAqB,CAE5E;AAED,+EAA+E;AAC/E,MAAM,WAAW,uBAAuB;IACtC,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,6CAA6C;AAC7C,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,iEAAiE;IACjE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,0FAA0F;IAC1F,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACtB,8FAA8F;IAC9F,aAAa,EAAE,MAAM,CAAC;IACtB,wCAAwC;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,SAAS,EAAE,kBAAkB,CAAC;IAC9B,oFAAoF;IACpF,YAAY,EAAE,UAAU,GAAG,MAAM,CAAC;IAClC,oFAAoF;IACpF,mBAAmB,EAAE,UAAU,GAAG,MAAM,CAAC;IACzC,qEAAqE;IACrE,cAAc,EAAE,MAAM,CAAC;IACvB,+CAA+C;IAC/C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kGAAkG;IAClG,gBAAgB,EAAE;QAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9D;AAED,4DAA4D;AAC5D,MAAM,WAAW,4BAA4B;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iFAAiF;IACjF,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,0CAA0C;IAC1C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wDAAwD;IACxD,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,sFAAsF;IACtF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gEAAgE;IAChE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kEAAkE;IAClE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,oDAAoD;AACpD,MAAM,MAAM,0BAA0B,GAClC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,uBAAuB,CAAA;CAAE,GAC/C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjC;;;;;GAKG;AACH;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,CAAC,uBAAuB,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAG7G;AAsBD,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,OAAO,CAAC,uBAAuB,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,+BAA+B,CA2B3I;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,OAAO,CAAC,uBAAuB,CAAC,GAAG,SAAS,GAAG,IAAI,EAC5D,KAAK,EAAE,4BAA4B,GAClC,0BAA0B,CA8E5B"}
|
|
@@ -8,6 +8,24 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { TICKET_AUTOPILOT_CONSTANTS, USAGE_CONSTANTS } from '../constants.js';
|
|
10
10
|
import { parseTokenAmount } from '../services/usage/token-format.js';
|
|
11
|
+
/**
|
|
12
|
+
* Whether a value is a speed mode name.
|
|
13
|
+
*
|
|
14
|
+
* @param value - Anything
|
|
15
|
+
* @returns True for rush / normal / chill
|
|
16
|
+
*/
|
|
17
|
+
export function isAutopilotSpeedMode(value) {
|
|
18
|
+
return typeof value === 'string' && TICKET_AUTOPILOT_CONSTANTS.SPEED_MODE_NAMES.includes(value);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The profile of a speed mode.
|
|
22
|
+
*
|
|
23
|
+
* @param mode - Mode
|
|
24
|
+
* @returns Its replan gap / cap, self-review cadence, empty-replan retry and default budget
|
|
25
|
+
*/
|
|
26
|
+
export function speedProfile(mode) {
|
|
27
|
+
return TICKET_AUTOPILOT_CONSTANTS.SPEED_MODES[mode];
|
|
28
|
+
}
|
|
11
29
|
/**
|
|
12
30
|
* Fill in the defaults of stored (possibly absent) settings.
|
|
13
31
|
*
|
|
@@ -45,16 +63,28 @@ function isReplanTtlHours(n) {
|
|
|
45
63
|
export function resolveTicketAutopilotSettings(stored) {
|
|
46
64
|
const budget = stored?.dailyBudgetTokens ?? legacyBudgetTokens(stored) ?? undefined;
|
|
47
65
|
const cap = stored?.maxInFlightPerMember;
|
|
66
|
+
const speedMode = isAutopilotSpeedMode(stored?.speedMode)
|
|
67
|
+
? stored.speedMode
|
|
68
|
+
: TICKET_AUTOPILOT_CONSTANTS.DEFAULT_SPEED_MODE;
|
|
69
|
+
const profile = speedProfile(speedMode);
|
|
70
|
+
const explicitBudget = typeof budget === 'number' && Number.isFinite(budget) && budget > 0;
|
|
71
|
+
const explicitReplans = isReplansPerDay(stored?.replansPerDay);
|
|
48
72
|
return {
|
|
49
73
|
enabled: stored?.enabled === true,
|
|
50
74
|
driver: typeof stored?.driver === 'string' && stored.driver.trim() ? stored.driver.trim() : null,
|
|
51
|
-
dailyBudgetTokens:
|
|
75
|
+
dailyBudgetTokens: explicitBudget ? budget : profile.dailyBudgetTokens,
|
|
52
76
|
maxInFlightPerMember: typeof cap === 'number' && Number.isInteger(cap) && cap >= 1 && cap <= TICKET_AUTOPILOT_CONSTANTS.MAX_IN_FLIGHT_PER_MEMBER_LIMIT
|
|
53
77
|
? cap
|
|
54
78
|
: TICKET_AUTOPILOT_CONSTANTS.DEFAULT_MAX_IN_FLIGHT_PER_MEMBER,
|
|
55
79
|
retro: typeof stored?.retro === 'boolean' ? stored.retro : null,
|
|
56
|
-
replansPerDay:
|
|
80
|
+
replansPerDay: explicitReplans ? stored?.replansPerDay : profile.replansPerDayCap,
|
|
57
81
|
replanTtlHours: isReplanTtlHours(stored?.replanTtlHours) ? stored.replanTtlHours : TICKET_AUTOPILOT_CONSTANTS.DEFAULT_REPLAN_TTL_HOURS,
|
|
82
|
+
speedMode,
|
|
83
|
+
budgetSource: explicitBudget ? 'explicit' : 'mode',
|
|
84
|
+
replansPerDaySource: explicitReplans ? 'explicit' : 'mode',
|
|
85
|
+
replanMinGapMs: profile.replanMinGapMs,
|
|
86
|
+
selfReviewEveryMs: profile.selfReviewEveryMs,
|
|
87
|
+
emptyReplanRetry: { ...profile.emptyReplanRetry },
|
|
58
88
|
};
|
|
59
89
|
}
|
|
60
90
|
/**
|
|
@@ -88,6 +118,8 @@ export function applyTicketAutopilotInput(current, input) {
|
|
|
88
118
|
next.replansPerDay = current.replansPerDay;
|
|
89
119
|
if (isReplanTtlHours(current?.replanTtlHours))
|
|
90
120
|
next.replanTtlHours = current.replanTtlHours;
|
|
121
|
+
if (isAutopilotSpeedMode(current?.speedMode))
|
|
122
|
+
next.speedMode = current.speedMode;
|
|
91
123
|
if (input.enabled !== undefined) {
|
|
92
124
|
if (typeof input.enabled !== 'boolean')
|
|
93
125
|
return { ok: false, error: 'enabled must be true or false' };
|
|
@@ -161,6 +193,15 @@ export function applyTicketAutopilotInput(current, input) {
|
|
|
161
193
|
next.replanTtlHours = n;
|
|
162
194
|
}
|
|
163
195
|
}
|
|
196
|
+
if (input.speedMode !== undefined) {
|
|
197
|
+
const raw = typeof input.speedMode === 'string' ? input.speedMode.trim().toLowerCase() : input.speedMode;
|
|
198
|
+
if (raw === null || raw === 'default' || raw === '')
|
|
199
|
+
delete next.speedMode;
|
|
200
|
+
else if (isAutopilotSpeedMode(raw))
|
|
201
|
+
next.speedMode = raw;
|
|
202
|
+
else
|
|
203
|
+
return { ok: false, error: 'speedMode must be rush, normal or chill' };
|
|
204
|
+
}
|
|
164
205
|
return { ok: true, settings: next };
|
|
165
206
|
}
|
|
166
207
|
//# sourceMappingURL=ticket-autopilot.types.js.map
|