crewly 1.20.161 → 1.20.163
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/roles/orchestrator/prompt.md +2 -0
- package/config/roles/team-leader/prompt.md +12 -0
- package/config/roles/team-leader/tl-addon.md +12 -0
- package/config/skills/agent/core/project-tickets/SKILL.md +32 -1
- package/config/skills/agent/core/project-tickets/execute.sh +56 -2
- package/config/skills/agent/core/project-tickets/execute.test.sh +22 -0
- package/dist/backend/backend/src/constants.d.ts +84 -1
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +105 -16
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts +43 -0
- 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 +85 -0
- 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 +12 -0
- 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 +19 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +30 -1
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/models/Project.d.ts +3 -0
- package/dist/backend/backend/src/models/Project.d.ts.map +1 -1
- package/dist/backend/backend/src/models/Project.js +7 -0
- package/dist/backend/backend/src/models/Project.js.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +3 -1
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.d.ts +66 -13
- package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.js +161 -32
- package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts +48 -0
- 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 +79 -2
- 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 +223 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js +240 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts +94 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js +195 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts +286 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js +626 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js.map +1 -0
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts +37 -3
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.js +57 -6
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts +21 -1
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js +62 -4
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts +6 -0
- package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler.service.js +9 -5
- package/dist/backend/backend/src/services/reconciler/reconciler.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/claim.service.d.ts +23 -3
- package/dist/backend/backend/src/services/task-pool/claim.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/claim.service.js +52 -11
- package/dist/backend/backend/src/services/task-pool/claim.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +42 -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 +82 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/ticket-claim-policy.d.ts +19 -0
- package/dist/backend/backend/src/services/task-pool/ticket-claim-policy.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/ticket-claim-policy.js +33 -0
- package/dist/backend/backend/src/services/task-pool/ticket-claim-policy.js.map +1 -1
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.d.ts +28 -0
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.js +74 -29
- package/dist/backend/backend/src/services/v3/agent-auto-claim.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js +3 -2
- package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js.map +1 -1
- package/dist/backend/backend/src/types/index.d.ts +6 -0
- package/dist/backend/backend/src/types/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/index.js.map +1 -1
- package/dist/backend/backend/src/types/ticket-autopilot.types.d.ts +73 -0
- package/dist/backend/backend/src/types/ticket-autopilot.types.d.ts.map +1 -0
- package/dist/backend/backend/src/types/ticket-autopilot.types.js +88 -0
- package/dist/backend/backend/src/types/ticket-autopilot.types.js.map +1 -0
- package/dist/backend/backend/src/types/v2/claim.types.d.ts +27 -0
- package/dist/backend/backend/src/types/v2/claim.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/claim.types.js +37 -0
- package/dist/backend/backend/src/types/v2/claim.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/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +84 -1
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +105 -16
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/models/Project.d.ts +3 -0
- package/dist/cli/backend/src/models/Project.d.ts.map +1 -1
- package/dist/cli/backend/src/models/Project.js +7 -0
- package/dist/cli/backend/src/models/Project.js.map +1 -1
- package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.d.ts +66 -13
- package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.js +161 -32
- package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/claim.service.d.ts +23 -3
- package/dist/cli/backend/src/services/task-pool/claim.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/claim.service.js +52 -11
- package/dist/cli/backend/src/services/task-pool/claim.service.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +42 -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 +82 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/ticket-claim-policy.d.ts +19 -0
- package/dist/cli/backend/src/services/task-pool/ticket-claim-policy.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/ticket-claim-policy.js +33 -0
- package/dist/cli/backend/src/services/task-pool/ticket-claim-policy.js.map +1 -1
- package/dist/cli/backend/src/types/index.d.ts +6 -0
- package/dist/cli/backend/src/types/index.d.ts.map +1 -1
- package/dist/cli/backend/src/types/index.js.map +1 -1
- package/dist/cli/backend/src/types/ticket-autopilot.types.d.ts +73 -0
- package/dist/cli/backend/src/types/ticket-autopilot.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/ticket-autopilot.types.js +88 -0
- package/dist/cli/backend/src/types/ticket-autopilot.types.js.map +1 -0
- package/dist/cli/backend/src/types/v2/claim.types.d.ts +27 -0
- package/dist/cli/backend/src/types/v2/claim.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/claim.types.js +37 -0
- package/dist/cli/backend/src/types/v2/claim.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-8f30aa74.js → index-64c8a616.js} +2 -2
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ticket autopilot — the texts (specs/2026-09-30-ticket-autopilot.md §3, §5):
|
|
3
|
+
* the driver's triage brief, the owner's batched questions and the evening
|
|
4
|
+
* digest. Pure functions; the owner-facing texts are phone-sized and carry no
|
|
5
|
+
* harness mechanics (no WorkItem ids, claims or pool states).
|
|
6
|
+
*
|
|
7
|
+
* @module services/project-tickets/ticket-autopilot-messages
|
|
8
|
+
*/
|
|
9
|
+
import { TICKET_AUTOPILOT_CONSTANTS } from '../../constants.js';
|
|
10
|
+
/**
|
|
11
|
+
* Actions that need the owner's explicit OK even with the autopilot on.
|
|
12
|
+
* Spelled out in the triage brief and in the team-leader prompt.
|
|
13
|
+
*/
|
|
14
|
+
export const TICKET_AUTOPILOT_BOUNDARIES = [
|
|
15
|
+
'sending email or messages to outside people',
|
|
16
|
+
'publishing content publicly',
|
|
17
|
+
'deploying to production',
|
|
18
|
+
'spending money',
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Human age of a timestamp ("3h", "2d").
|
|
22
|
+
*
|
|
23
|
+
* @param iso - ISO time
|
|
24
|
+
* @param now - Clock (epoch ms)
|
|
25
|
+
* @returns Short age, or "?" when unreadable
|
|
26
|
+
*/
|
|
27
|
+
export function formatAge(iso, now) {
|
|
28
|
+
const t = Date.parse(iso);
|
|
29
|
+
if (!Number.isFinite(t))
|
|
30
|
+
return '?';
|
|
31
|
+
const minutes = Math.max(0, Math.floor((now - t) / 60_000));
|
|
32
|
+
if (minutes < 60)
|
|
33
|
+
return `${minutes}m`;
|
|
34
|
+
const hours = Math.floor(minutes / 60);
|
|
35
|
+
if (hours < 48)
|
|
36
|
+
return `${hours}h`;
|
|
37
|
+
return `${Math.floor(hours / 24)}d`;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Who created a ticket, for the brief.
|
|
41
|
+
*
|
|
42
|
+
* @param source - Ticket `source`
|
|
43
|
+
* @returns `owner`, the agent session, the request, or `unknown`
|
|
44
|
+
*/
|
|
45
|
+
function creatorOf(source) {
|
|
46
|
+
if (!source)
|
|
47
|
+
return 'unknown';
|
|
48
|
+
if (source.startsWith('agent:'))
|
|
49
|
+
return source.slice('agent:'.length);
|
|
50
|
+
return source;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Shorten free text to one excerpt line.
|
|
54
|
+
*
|
|
55
|
+
* @param text - Text
|
|
56
|
+
* @param max - Max characters
|
|
57
|
+
* @returns Single-line excerpt
|
|
58
|
+
*/
|
|
59
|
+
function excerpt(text, max) {
|
|
60
|
+
const flat = text.replace(/\s+/g, ' ').trim();
|
|
61
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The triage brief the driver receives (WorkItem `briefMarkdown`).
|
|
65
|
+
*
|
|
66
|
+
* @param input - Project, tickets, team, limits, clock
|
|
67
|
+
* @returns Markdown brief
|
|
68
|
+
*/
|
|
69
|
+
export function buildTriageBrief(input) {
|
|
70
|
+
const p = input.project.id;
|
|
71
|
+
const tk = '$AGENT_SKILLS_PATH/core/project-tickets/execute.sh';
|
|
72
|
+
const lines = [
|
|
73
|
+
`# Ticket triage — ${input.project.name} (${input.candidates.length} ticket${input.candidates.length === 1 ? '' : 's'})`,
|
|
74
|
+
'',
|
|
75
|
+
'Ticket autopilot is on for this project: you keep its backlog moving while the owner is away (on a phone).',
|
|
76
|
+
'Decide every ticket below, then complete this WorkItem (complete-task with its id) with one line per ticket saying what you did.',
|
|
77
|
+
'',
|
|
78
|
+
'## For each ticket, do one of these',
|
|
79
|
+
'',
|
|
80
|
+
`1. **Ready + assign** — \`bash ${tk} assign --project ${p} --id <ID> --to <member>\`, or \`… update --project ${p} --id <ID> --status ready\` to let the next idle member take it. At most ${input.maxInFlightPerMember} ticket${input.maxInFlightPerMember === 1 ? '' : 's'} in progress per member.`,
|
|
81
|
+
`2. **Split** — create smaller tickets (\`… create --project ${p} --title "…" --acceptance "…" --status ready\`), then cancel the original with a note naming the new ids.`,
|
|
82
|
+
`3. **Needs the owner** — \`bash ${tk} ask-owner --project ${p} --id <ID> --question "<one line the owner can answer with a tap or a word>"\`. Crewly batches these to the owner's phone; do not message the owner about them yourself.`,
|
|
83
|
+
`4. **Cancel** — \`… update --project ${p} --id <ID> --status cancelled --note "<reason>"\`.`,
|
|
84
|
+
'',
|
|
85
|
+
'## Boundaries — the autopilot does NOT lift these',
|
|
86
|
+
'',
|
|
87
|
+
'Even with the autopilot on, these need the owner\'s explicit OK:',
|
|
88
|
+
...TICKET_AUTOPILOT_BOUNDARIES.map((b) => `- ${b};`),
|
|
89
|
+
'',
|
|
90
|
+
'A ticket whose completion needs one of these may be worked up to a draft or a PR; then use ask-owner for the final step.',
|
|
91
|
+
'"The autopilot is on" is never that OK, and neither is your own judgement.',
|
|
92
|
+
'',
|
|
93
|
+
'Tickets marked **worker-created — review first** were filed by a team member, not by the owner, a lead or the orchestrator.',
|
|
94
|
+
'Check that they are wanted and in scope before making them ready; if unsure, ask the owner.',
|
|
95
|
+
'',
|
|
96
|
+
'## Team',
|
|
97
|
+
'',
|
|
98
|
+
...(input.members.length > 0
|
|
99
|
+
? input.members.map((m) => `- ${m.session}${m.name && m.name !== m.session ? ` (${m.name}${m.role ? `, ${m.role}` : ''})` : m.role ? ` (${m.role})` : ''} — ${m.idle ? 'idle' : 'busy'}, ${m.inFlight} in progress`)
|
|
100
|
+
: ['- (no members found)']),
|
|
101
|
+
'',
|
|
102
|
+
'## Tickets',
|
|
103
|
+
'',
|
|
104
|
+
];
|
|
105
|
+
for (const c of input.candidates) {
|
|
106
|
+
const t = c.ticket;
|
|
107
|
+
const why = c.reason === 'backlog' ? 'backlog' : c.reason === 'ready_no_taker' ? 'ready, but nobody on the team can take it' : 'ready, but nobody has taken it for a day';
|
|
108
|
+
lines.push(`### ${t.id} · ${t.priority} · ${why} · ${formatAge(t.createdAt, input.now)} old`);
|
|
109
|
+
lines.push(t.title);
|
|
110
|
+
const meta = [`created by ${creatorOf(t.source)}`];
|
|
111
|
+
if (t.labels.length > 0)
|
|
112
|
+
meta.push(`labels: ${t.labels.join(', ')}`);
|
|
113
|
+
if (t.team)
|
|
114
|
+
meta.push(`team: ${t.team}`);
|
|
115
|
+
lines.push(`${meta.join(' · ')}${c.workerCreated ? ' · **worker-created — review first**' : ''}`);
|
|
116
|
+
if (t.description)
|
|
117
|
+
lines.push(`> ${excerpt(t.description, TICKET_AUTOPILOT_CONSTANTS.TRIAGE_DESCRIPTION_EXCERPT_CHARS)}`);
|
|
118
|
+
lines.push('');
|
|
119
|
+
}
|
|
120
|
+
if (input.more > 0)
|
|
121
|
+
lines.push(`${input.more} more ticket${input.more === 1 ? '' : 's'} will come in the next triage.`, '');
|
|
122
|
+
lines.push(`Full ticket: \`bash ${tk} show --project ${p} --id <ID>\`.`);
|
|
123
|
+
return lines.join('\n');
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The one batched message with every open owner question — numbered, short,
|
|
127
|
+
* answerable with a tap or a word.
|
|
128
|
+
*
|
|
129
|
+
* @param items - Questions (already ordered)
|
|
130
|
+
* @returns Message text
|
|
131
|
+
*/
|
|
132
|
+
export function buildOwnerQuestionsMessage(items) {
|
|
133
|
+
const multiProject = new Set(items.map((i) => i.projectName)).size > 1;
|
|
134
|
+
const lines = [
|
|
135
|
+
items.length === 1 ? 'One ticket is waiting on you:' : `${items.length} tickets are waiting on you:`,
|
|
136
|
+
'',
|
|
137
|
+
...items.map((q, i) => `${i + 1}. ${q.ticketId}${multiProject ? ` (${q.projectName})` : ''} ${excerpt(q.title, 60)} — ${q.question}`),
|
|
138
|
+
'',
|
|
139
|
+
'Reply with the number and your answer (e.g. "1 yes").',
|
|
140
|
+
];
|
|
141
|
+
return lines.join('\n');
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* One digest section line: count plus the first few tickets.
|
|
145
|
+
*
|
|
146
|
+
* @param label - Section label
|
|
147
|
+
* @param tickets - Tickets
|
|
148
|
+
* @param withAssignee - Append the assignee
|
|
149
|
+
* @returns Line, or null when empty
|
|
150
|
+
*/
|
|
151
|
+
function digestSection(label, tickets, withAssignee) {
|
|
152
|
+
if (tickets.length === 0)
|
|
153
|
+
return null;
|
|
154
|
+
const max = TICKET_AUTOPILOT_CONSTANTS.DIGEST_MAX_ITEMS_PER_SECTION;
|
|
155
|
+
const named = tickets
|
|
156
|
+
.slice(0, max)
|
|
157
|
+
.map((t) => `${t.id} ${excerpt(t.title, 50)}${withAssignee && t.assignee ? ` (${t.assignee})` : ''}`);
|
|
158
|
+
const rest = tickets.length > max ? `; +${tickets.length - max} more` : '';
|
|
159
|
+
return `${label} (${tickets.length}): ${named.join('; ')}${rest}`;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* The evening digest: per project, done today / in progress / waiting on the
|
|
163
|
+
* owner. Projects with nothing to report are left out.
|
|
164
|
+
*
|
|
165
|
+
* @param projects - Per-project sections
|
|
166
|
+
* @returns Message text, or null when there is nothing to say
|
|
167
|
+
*/
|
|
168
|
+
export function buildDigestMessage(projects) {
|
|
169
|
+
const blocks = [];
|
|
170
|
+
for (const p of projects) {
|
|
171
|
+
const rows = [
|
|
172
|
+
digestSection('Done today', p.doneToday, false),
|
|
173
|
+
digestSection('In progress', p.inProgress, true),
|
|
174
|
+
digestSection('Waiting on you', p.waitingOnOwner, false),
|
|
175
|
+
].filter((r) => r !== null);
|
|
176
|
+
if (rows.length === 0)
|
|
177
|
+
continue;
|
|
178
|
+
blocks.push([`*${p.name}*`, ...rows.map((r) => `- ${r}`)].join('\n'));
|
|
179
|
+
}
|
|
180
|
+
if (blocks.length === 0)
|
|
181
|
+
return null;
|
|
182
|
+
return ['Tickets today', '', blocks.join('\n\n')].join('\n');
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* The once-a-day notice that the autopilot paused on its budget.
|
|
186
|
+
*
|
|
187
|
+
* @param projectName - Project
|
|
188
|
+
* @param spentUsd - Spent today
|
|
189
|
+
* @param budgetUsd - Daily budget
|
|
190
|
+
* @returns Message text
|
|
191
|
+
*/
|
|
192
|
+
export function buildBudgetPausedMessage(projectName, spentUsd, budgetUsd) {
|
|
193
|
+
return `Ticket autopilot paused for today on ${projectName}: the team has used $${spentUsd.toFixed(2)} of its $${budgetUsd.toFixed(2)} daily budget. It picks up again tomorrow. Reply "raise the budget to $N" to change it.`;
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=ticket-autopilot-messages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ticket-autopilot-messages.js","sourceRoot":"","sources":["../../../../../../backend/src/services/project-tickets/ticket-autopilot-messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ticket autopilot (specs/2026-09-30-ticket-autopilot.md).
|
|
3
|
+
*
|
|
4
|
+
* A per-project switch (default off). While it is on:
|
|
5
|
+
* - the project's driver (its team lead) is woken with ONE `ticket_triage`
|
|
6
|
+
* WorkItem listing the backlog tickets to decide (ready + assign, split,
|
|
7
|
+
* ask the owner, cancel) — only when someone on the team is idle, at most
|
|
8
|
+
* one live triage per project, at most every 30 min (sooner when a member
|
|
9
|
+
* goes idle with nothing ready);
|
|
10
|
+
* - brakes hold: a daily USD budget over the team's agents (pauses the
|
|
11
|
+
* autopilot and ticket auto-claim for the day, owner told once) and an
|
|
12
|
+
* in-progress cap per member ({@link ProjectTicketAutopilotPolicy});
|
|
13
|
+
* - the owner gets the open `needs-owner` questions batched into one phone
|
|
14
|
+
* message (at most every 2 h unless a new P0 one appears) and one evening
|
|
15
|
+
* digest (skipped when nothing changed).
|
|
16
|
+
*
|
|
17
|
+
* The approval boundary is unchanged: the autopilot only wakes the lead and
|
|
18
|
+
* talks to the owner; it never makes a ticket ready or starts work itself.
|
|
19
|
+
*
|
|
20
|
+
* @module services/project-tickets/ticket-autopilot.service
|
|
21
|
+
*/
|
|
22
|
+
import { type ComponentLogger } from '../core/logger.service.js';
|
|
23
|
+
import type { Project, Team } from '../../types/index.js';
|
|
24
|
+
import { type WorkItem } from '../../types/v2/work-item.types.js';
|
|
25
|
+
import type { ProjectTicketList } from '../../types/project-ticket.types.js';
|
|
26
|
+
import { type ResolvedTicketAutopilotSettings, type TicketAutopilotSettingsInput } from '../../types/ticket-autopilot.types.js';
|
|
27
|
+
import { type ProjectTicketAccess, type ProjectTicketAutopilotPolicy, type ProjectTicketCaller } from './project-ticket-workflow.service.js';
|
|
28
|
+
import { type TriageDecision } from './ticket-autopilot-decision.js';
|
|
29
|
+
/** The subset of the task pool the autopilot uses. */
|
|
30
|
+
export interface TicketAutopilotPool {
|
|
31
|
+
addToPool(workItem: WorkItem): Promise<void>;
|
|
32
|
+
getAllItems(): Promise<WorkItem[]>;
|
|
33
|
+
cancelQueued(workItemId: string, reason: string): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
/** The subset of storage the autopilot uses. */
|
|
36
|
+
export interface TicketAutopilotDirectory {
|
|
37
|
+
getTeams(): Promise<Team[]>;
|
|
38
|
+
getProjects(): Promise<Project[]>;
|
|
39
|
+
saveProject(project: Project): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
/** The ticket store (read only). */
|
|
42
|
+
export interface TicketAutopilotTicketStore {
|
|
43
|
+
list(projectPath: string): Promise<ProjectTicketList>;
|
|
44
|
+
}
|
|
45
|
+
/** Project resolution + caller access (the ticket workflow). */
|
|
46
|
+
export interface TicketAutopilotWorkflow {
|
|
47
|
+
resolveProject(ref: string): Promise<Project>;
|
|
48
|
+
accessOf(caller: ProjectTicketCaller, project: Project): Promise<{
|
|
49
|
+
access: ProjectTicketAccess;
|
|
50
|
+
}>;
|
|
51
|
+
setAutopilotPolicy?(policy: ProjectTicketAutopilotPolicy | null): void;
|
|
52
|
+
}
|
|
53
|
+
/** Token / cost ledger (see TokenUsageService.getSessionUsageSince). */
|
|
54
|
+
export interface TicketAutopilotLedger {
|
|
55
|
+
getSessionUsageSince(sessionName: string, since: Date, until?: Date): {
|
|
56
|
+
cost: number;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** A message to the owner through the usual owner-notification path. */
|
|
60
|
+
export interface OwnerNotice {
|
|
61
|
+
title: string;
|
|
62
|
+
message: string;
|
|
63
|
+
urgent: boolean;
|
|
64
|
+
}
|
|
65
|
+
/** Dependencies. */
|
|
66
|
+
export interface TicketAutopilotDeps {
|
|
67
|
+
tickets: TicketAutopilotTicketStore;
|
|
68
|
+
pool: TicketAutopilotPool;
|
|
69
|
+
directory: TicketAutopilotDirectory;
|
|
70
|
+
workflow: TicketAutopilotWorkflow;
|
|
71
|
+
ledger: TicketAutopilotLedger;
|
|
72
|
+
/** Sends to the owner; resolves false when it could not be sent (retried on the next tick) */
|
|
73
|
+
notifyOwner: (notice: OwnerNotice) => Promise<boolean>;
|
|
74
|
+
/** JSON file holding the autopilot's bookkeeping */
|
|
75
|
+
stateFile: string;
|
|
76
|
+
now?: () => Date;
|
|
77
|
+
logger?: ComponentLogger;
|
|
78
|
+
}
|
|
79
|
+
/** The driver of a project. */
|
|
80
|
+
export interface ResolvedDriver {
|
|
81
|
+
session: string;
|
|
82
|
+
teamId: string;
|
|
83
|
+
source: 'setting' | 'team_lead';
|
|
84
|
+
}
|
|
85
|
+
/** What {@link TicketAutopilotService.getStatus} returns. */
|
|
86
|
+
export interface TicketAutopilotStatus {
|
|
87
|
+
project: {
|
|
88
|
+
id: string;
|
|
89
|
+
name: string;
|
|
90
|
+
path: string;
|
|
91
|
+
};
|
|
92
|
+
settings: ResolvedTicketAutopilotSettings;
|
|
93
|
+
driver: ResolvedDriver | null;
|
|
94
|
+
spentTodayUsd: number;
|
|
95
|
+
pausedForToday: boolean;
|
|
96
|
+
triageInFlight: boolean;
|
|
97
|
+
lastTriageAt: string | null;
|
|
98
|
+
}
|
|
99
|
+
/** Outcome of one project evaluation. */
|
|
100
|
+
export interface ProjectEvaluation {
|
|
101
|
+
projectId: string;
|
|
102
|
+
decision: TriageDecision;
|
|
103
|
+
/** The triage WorkItem created, when the decision was `triage` */
|
|
104
|
+
workItem?: WorkItem;
|
|
105
|
+
}
|
|
106
|
+
export declare class TicketAutopilotService {
|
|
107
|
+
private static instance;
|
|
108
|
+
private readonly deps;
|
|
109
|
+
private readonly logger;
|
|
110
|
+
private readonly now;
|
|
111
|
+
private state;
|
|
112
|
+
private timer;
|
|
113
|
+
/** Serialises evaluations so an idle event and the tick never create two triages */
|
|
114
|
+
private chain;
|
|
115
|
+
/**
|
|
116
|
+
* @param deps - Stores, pool, ledger, owner notifier, state file, clock
|
|
117
|
+
*/
|
|
118
|
+
constructor(deps: TicketAutopilotDeps);
|
|
119
|
+
/**
|
|
120
|
+
* The wired process-wide instance, or null before boot wired it.
|
|
121
|
+
*
|
|
122
|
+
* @returns Instance or null
|
|
123
|
+
*/
|
|
124
|
+
static getInstance(): TicketAutopilotService | null;
|
|
125
|
+
/**
|
|
126
|
+
* Install the process-wide instance (boot path).
|
|
127
|
+
*
|
|
128
|
+
* @param service - Instance, or null to clear (tests)
|
|
129
|
+
*/
|
|
130
|
+
static setInstance(service: TicketAutopilotService | null): void;
|
|
131
|
+
/**
|
|
132
|
+
* Install the brakes on the ticket workflow and start the periodic tick.
|
|
133
|
+
*
|
|
134
|
+
* @param intervalMs - Tick interval (0 = no timer; tests call {@link tick})
|
|
135
|
+
*/
|
|
136
|
+
start(intervalMs?: number): void;
|
|
137
|
+
/** Stop the tick and remove the brakes. */
|
|
138
|
+
stop(): void;
|
|
139
|
+
/**
|
|
140
|
+
* The brakes the ticket workflow asks about.
|
|
141
|
+
*
|
|
142
|
+
* @returns Policy bound to this service
|
|
143
|
+
*/
|
|
144
|
+
policy(): ProjectTicketAutopilotPolicy;
|
|
145
|
+
/**
|
|
146
|
+
* The project's autopilot settings and live status.
|
|
147
|
+
*
|
|
148
|
+
* @param ref - Project id, name or path
|
|
149
|
+
* @param caller - Owner or orchestrator
|
|
150
|
+
* @returns Settings, driver, today's spend, pause / triage state
|
|
151
|
+
* @throws ProjectTicketError(403/404)
|
|
152
|
+
*/
|
|
153
|
+
getStatus(ref: string, caller: ProjectTicketCaller): Promise<TicketAutopilotStatus>;
|
|
154
|
+
/**
|
|
155
|
+
* Change the project's autopilot settings.
|
|
156
|
+
*
|
|
157
|
+
* @param ref - Project id, name or path
|
|
158
|
+
* @param input - `enabled`, `driver`, `dailyBudgetUsd`, `maxInFlightPerMember` (null resets one)
|
|
159
|
+
* @param caller - Owner or orchestrator
|
|
160
|
+
* @returns The new status
|
|
161
|
+
* @throws ProjectTicketError(400) on invalid input or a driver who is not a lead of a project team; (403/404)
|
|
162
|
+
*/
|
|
163
|
+
updateSettings(ref: string, input: TicketAutopilotSettingsInput, caller: ProjectTicketCaller): Promise<TicketAutopilotStatus>;
|
|
164
|
+
/**
|
|
165
|
+
* Periodic pass: evaluate every enabled project, then the owner questions
|
|
166
|
+
* and the daily digest.
|
|
167
|
+
*
|
|
168
|
+
* @returns Per-project evaluations
|
|
169
|
+
*/
|
|
170
|
+
tick(): Promise<ProjectEvaluation[]>;
|
|
171
|
+
/**
|
|
172
|
+
* A member went idle and AutoClaim found nothing ready for it: evaluate
|
|
173
|
+
* the enabled projects it works on right away (bounded by
|
|
174
|
+
* {@link TICKET_AUTOPILOT_CONSTANTS.IDLE_TRIGGER_MIN_INTERVAL_MS}).
|
|
175
|
+
*
|
|
176
|
+
* @param session - The idle agent
|
|
177
|
+
* @returns Per-project evaluations
|
|
178
|
+
*/
|
|
179
|
+
onMemberIdle(session: string): Promise<ProjectEvaluation[]>;
|
|
180
|
+
/**
|
|
181
|
+
* Evaluate one project and, when {@link decideTriage} says so, wake its
|
|
182
|
+
* driver with a triage WorkItem.
|
|
183
|
+
*
|
|
184
|
+
* @param project - Project (with its stored settings)
|
|
185
|
+
* @param trigger - Periodic tick or a member going idle
|
|
186
|
+
* @param idleSession - The member that just went idle
|
|
187
|
+
* @returns The decision (and the WorkItem when one was created)
|
|
188
|
+
*/
|
|
189
|
+
private evaluateProject;
|
|
190
|
+
/**
|
|
191
|
+
* The project's live triage item, if any. A triage item still queued
|
|
192
|
+
* (never picked up) after {@link TICKET_AUTOPILOT_CONSTANTS.TRIAGE_STALE_QUEUED_MS}
|
|
193
|
+
* is cancelled so a fresh one can replace it.
|
|
194
|
+
*
|
|
195
|
+
* @param project - Project
|
|
196
|
+
* @param nowMs - Clock
|
|
197
|
+
* @returns The live item, or null
|
|
198
|
+
*/
|
|
199
|
+
private liveTriageItem;
|
|
200
|
+
/**
|
|
201
|
+
* Send the batched owner questions of every enabled project when due.
|
|
202
|
+
*
|
|
203
|
+
* @param projects - Enabled projects
|
|
204
|
+
* @returns True when a batch went out
|
|
205
|
+
*/
|
|
206
|
+
private processOwnerQuestions;
|
|
207
|
+
/**
|
|
208
|
+
* Send the evening digest of the enabled projects when due.
|
|
209
|
+
*
|
|
210
|
+
* @param projects - Enabled projects
|
|
211
|
+
* @returns True when a digest went out
|
|
212
|
+
*/
|
|
213
|
+
private processDigest;
|
|
214
|
+
/**
|
|
215
|
+
* Tell the owner once per day that a project's autopilot paused on its budget.
|
|
216
|
+
*
|
|
217
|
+
* @param project - Project
|
|
218
|
+
* @param ps - Its bookkeeping
|
|
219
|
+
* @param spent - Spent today
|
|
220
|
+
* @param budget - Daily budget
|
|
221
|
+
* @param now - Clock
|
|
222
|
+
*/
|
|
223
|
+
private noticeBudgetPaused;
|
|
224
|
+
/**
|
|
225
|
+
* The settings view plus live status of a project.
|
|
226
|
+
*
|
|
227
|
+
* @param project - Project
|
|
228
|
+
* @returns Status
|
|
229
|
+
*/
|
|
230
|
+
private statusOf;
|
|
231
|
+
/**
|
|
232
|
+
* Refuse anyone but the owner and the orchestrator.
|
|
233
|
+
*
|
|
234
|
+
* @param caller - Caller
|
|
235
|
+
* @param project - Project
|
|
236
|
+
* @throws ProjectTicketError(403)
|
|
237
|
+
*/
|
|
238
|
+
private requireOwnerOrOrc;
|
|
239
|
+
/**
|
|
240
|
+
* Non-archived teams working on a project.
|
|
241
|
+
*
|
|
242
|
+
* @param project - Project
|
|
243
|
+
* @returns Teams
|
|
244
|
+
*/
|
|
245
|
+
private projectTeams;
|
|
246
|
+
/**
|
|
247
|
+
* A lead of one of the teams running as `session`.
|
|
248
|
+
*
|
|
249
|
+
* @param teams - Project teams
|
|
250
|
+
* @param session - Session
|
|
251
|
+
* @returns The team id, or null
|
|
252
|
+
*/
|
|
253
|
+
private findLead;
|
|
254
|
+
/**
|
|
255
|
+
* Who triages: the configured driver (must be a lead of a project team),
|
|
256
|
+
* else the first lead found on the project's teams.
|
|
257
|
+
*
|
|
258
|
+
* @param settings - Resolved settings
|
|
259
|
+
* @param teams - Project teams
|
|
260
|
+
* @returns Driver, or null when there is none
|
|
261
|
+
*/
|
|
262
|
+
private resolveDriver;
|
|
263
|
+
/**
|
|
264
|
+
* USD spent since local midnight by the agents of the given teams.
|
|
265
|
+
*
|
|
266
|
+
* @param teams - Teams
|
|
267
|
+
* @returns Spend
|
|
268
|
+
*/
|
|
269
|
+
private spentToday;
|
|
270
|
+
/**
|
|
271
|
+
* Run `fn` after every evaluation queued before it.
|
|
272
|
+
*
|
|
273
|
+
* @param fn - Work
|
|
274
|
+
* @returns Its result
|
|
275
|
+
*/
|
|
276
|
+
private serial;
|
|
277
|
+
/**
|
|
278
|
+
* Load the bookkeeping (once per process).
|
|
279
|
+
*
|
|
280
|
+
* @returns State
|
|
281
|
+
*/
|
|
282
|
+
private loadState;
|
|
283
|
+
/** Persist the bookkeeping (best-effort). */
|
|
284
|
+
private saveState;
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=ticket-autopilot.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ticket-autopilot.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/project-tickets/ticket-autopilot.service.ts"],"names":[],"mappings":"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"}
|