crewly 1.20.214 → 1.20.215
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/skills/agent/core/project-tickets/SKILL.md +42 -10
- package/config/skills/agent/core/project-tickets/execute.sh +45 -12
- package/config/skills/agent/core/project-tickets/execute.test.sh +19 -0
- package/dist/backend/backend/src/constants.d.ts +57 -9
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +75 -8
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts +9 -1
- 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 +13 -1
- 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/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/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 +67 -1
- 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 +75 -1
- 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 +99 -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 +422 -11
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js.map +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/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +57 -9
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +75 -8
- package/dist/cli/backend/src/constants.js.map +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-839f4374.js} +272 -272
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Switch a project's autopilot speed from the owner's DM with the orc
|
|
3
|
+
* (specs/2026-10-04-autopilot-speed-modes.md §5). Handled by the backend as
|
|
4
|
+
* an owner command — never by the orc's LLM — and only for the owner's own
|
|
5
|
+
* messages in their DM with the orc (the team pause command's pattern):
|
|
6
|
+
*
|
|
7
|
+
* - `set <project> to rush` / `set <project> autopilot to chill`
|
|
8
|
+
* - `switch <project> to normal` / `put <project> in rush mode`
|
|
9
|
+
* - `<project> rush` / `<project> chill mode`
|
|
10
|
+
* - Chinese: `<project> 切到 rush`, `把 <project> 切换到 chill`,
|
|
11
|
+
* `<project> 改成 正常`, `<project> 调成 冲刺模式`
|
|
12
|
+
* - mode words: rush / normal / chill, and 冲刺·急速·快 / 正常·普通 / 慢·慢速·悠闲·佛系
|
|
13
|
+
*
|
|
14
|
+
* A message is consumed only when its target names a known project (or it
|
|
15
|
+
* says `set project <x> to …` explicitly); anything else goes on to the orc.
|
|
16
|
+
* Replies are English (harness text rule); switching to Rush carries a
|
|
17
|
+
* one-line cost warning.
|
|
18
|
+
*
|
|
19
|
+
* @module services/project-tickets/autopilot-speed-command
|
|
20
|
+
*/
|
|
21
|
+
import type { SlackIncomingMessage } from '../../types/slack.types.js';
|
|
22
|
+
import type { AutopilotSpeedMode } from '../../types/ticket-autopilot.types.js';
|
|
23
|
+
import type { TicketAutopilotStatus } from './ticket-autopilot.service.js';
|
|
24
|
+
/** A parsed command. `target` is the project as typed. */
|
|
25
|
+
export interface AutopilotSpeedCommand {
|
|
26
|
+
target: string;
|
|
27
|
+
mode: AutopilotSpeedMode;
|
|
28
|
+
/** Said "project" explicitly: answered even when no project matches */
|
|
29
|
+
explicitProject: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parse a speed-mode command.
|
|
33
|
+
*
|
|
34
|
+
* @param text - Message text
|
|
35
|
+
* @returns The command, or null when the message is not one
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* parseAutopilotSpeedCommand('set CE to rush') // { target: 'CE', mode: 'rush', explicitProject: false }
|
|
39
|
+
* parseAutopilotSpeedCommand('CE 切到 chill') // { target: 'CE', mode: 'chill', explicitProject: false }
|
|
40
|
+
*/
|
|
41
|
+
export declare function parseAutopilotSpeedCommand(text: string | undefined): AutopilotSpeedCommand | null;
|
|
42
|
+
/** The one-line cost warning shown when Rush is switched on. */
|
|
43
|
+
export declare const RUSH_COST_WARNING = "Cost warning: Rush keeps the team busy all day and can use the whole daily budget every day; the budget brake still stops it.";
|
|
44
|
+
/**
|
|
45
|
+
* Mode name for the owner.
|
|
46
|
+
*
|
|
47
|
+
* @param mode - Mode
|
|
48
|
+
* @returns "Rush" / "Normal" / "Chill"
|
|
49
|
+
*/
|
|
50
|
+
export declare function modeLabel(mode: AutopilotSpeedMode): string;
|
|
51
|
+
/**
|
|
52
|
+
* The owner's reply after a switch.
|
|
53
|
+
*
|
|
54
|
+
* @param status - The project's status after the change
|
|
55
|
+
* @param previous - The mode before
|
|
56
|
+
* @returns Reply text
|
|
57
|
+
*/
|
|
58
|
+
export declare function speedModeReply(status: TicketAutopilotStatus, previous: AutopilotSpeedMode): string;
|
|
59
|
+
/** What the interceptor needs. */
|
|
60
|
+
export interface AutopilotSpeedCommandDeps {
|
|
61
|
+
/** `orc` when the message is the owner writing in their DM with the orc (see SlackReloginDmService.ownerDmScope) */
|
|
62
|
+
ownerDmScope: (message: SlackIncomingMessage) => 'orc' | 'agent' | null;
|
|
63
|
+
/** Reply target for the message */
|
|
64
|
+
replyTargetOf: (message: SlackIncomingMessage) => unknown;
|
|
65
|
+
/** Send a reply to the owner */
|
|
66
|
+
reply: (text: string, target: unknown) => Promise<unknown>;
|
|
67
|
+
/** Known projects, synchronously (a cache the wiring refreshes) */
|
|
68
|
+
knownProjects: () => Array<{
|
|
69
|
+
id: string;
|
|
70
|
+
name: string;
|
|
71
|
+
}>;
|
|
72
|
+
/** The project's current mode */
|
|
73
|
+
currentMode: (projectId: string) => Promise<AutopilotSpeedMode>;
|
|
74
|
+
/** Set the mode as the owner; resolves to the new status */
|
|
75
|
+
setMode: (projectId: string, mode: AutopilotSpeedMode) => Promise<TicketAutopilotStatus>;
|
|
76
|
+
onError?: (err: unknown) => void;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Find a project by id or name (case-insensitive).
|
|
80
|
+
*
|
|
81
|
+
* @param projects - Known projects
|
|
82
|
+
* @param ref - As typed
|
|
83
|
+
* @returns The project, or null
|
|
84
|
+
*/
|
|
85
|
+
export declare function findProjectByRef(projects: Array<{
|
|
86
|
+
id: string;
|
|
87
|
+
name: string;
|
|
88
|
+
}>, ref: string): {
|
|
89
|
+
id: string;
|
|
90
|
+
name: string;
|
|
91
|
+
} | null;
|
|
92
|
+
/**
|
|
93
|
+
* Run a parsed command and build the owner's reply.
|
|
94
|
+
*
|
|
95
|
+
* @param cmd - Command
|
|
96
|
+
* @param projectId - Resolved project
|
|
97
|
+
* @param deps - Collaborators
|
|
98
|
+
* @returns Reply text
|
|
99
|
+
*/
|
|
100
|
+
export declare function runAutopilotSpeedCommand(cmd: AutopilotSpeedCommand, projectId: string, deps: AutopilotSpeedCommandDeps): Promise<string>;
|
|
101
|
+
/**
|
|
102
|
+
* The Slack bridge interceptor for the owner's orc DM.
|
|
103
|
+
*
|
|
104
|
+
* @param deps - Collaborators
|
|
105
|
+
* @returns Interceptor: true when the message was a speed command (consumed)
|
|
106
|
+
*/
|
|
107
|
+
export declare function createAutopilotSpeedInterceptor(deps: AutopilotSpeedCommandDeps): (message: SlackIncomingMessage) => boolean;
|
|
108
|
+
//# sourceMappingURL=autopilot-speed-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autopilot-speed-command.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/project-tickets/autopilot-speed-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAE3E,0DAA0D;AAC1D,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,kBAAkB,CAAC;IACzB,uEAAuE;IACvE,eAAe,EAAE,OAAO,CAAC;CACzB;AA+DD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,qBAAqB,GAAG,IAAI,CAuBjG;AASD,gEAAgE;AAChE,eAAO,MAAM,iBAAiB,kIACkG,CAAC;AAEjI;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAE1D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,qBAAqB,EAAE,QAAQ,EAAE,kBAAkB,GAAG,MAAM,CAclG;AAED,kCAAkC;AAClC,MAAM,WAAW,yBAAyB;IACzC,oHAAoH;IACpH,YAAY,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,KAAK,GAAG,OAAO,GAAG,IAAI,CAAC;IACxE,mCAAmC;IACnC,aAAa,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC;IAC1D,gCAAgC;IAChC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3D,mEAAmE;IACnE,aAAa,EAAE,MAAM,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzD,iCAAiC;IACjC,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAChE,4DAA4D;IAC5D,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACzF,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CACjC;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAIhI;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,yBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,CAI9I;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,yBAAyB,GAAG,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CA0B3H"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Switch a project's autopilot speed from the owner's DM with the orc
|
|
3
|
+
* (specs/2026-10-04-autopilot-speed-modes.md §5). Handled by the backend as
|
|
4
|
+
* an owner command — never by the orc's LLM — and only for the owner's own
|
|
5
|
+
* messages in their DM with the orc (the team pause command's pattern):
|
|
6
|
+
*
|
|
7
|
+
* - `set <project> to rush` / `set <project> autopilot to chill`
|
|
8
|
+
* - `switch <project> to normal` / `put <project> in rush mode`
|
|
9
|
+
* - `<project> rush` / `<project> chill mode`
|
|
10
|
+
* - Chinese: `<project> 切到 rush`, `把 <project> 切换到 chill`,
|
|
11
|
+
* `<project> 改成 正常`, `<project> 调成 冲刺模式`
|
|
12
|
+
* - mode words: rush / normal / chill, and 冲刺·急速·快 / 正常·普通 / 慢·慢速·悠闲·佛系
|
|
13
|
+
*
|
|
14
|
+
* A message is consumed only when its target names a known project (or it
|
|
15
|
+
* says `set project <x> to …` explicitly); anything else goes on to the orc.
|
|
16
|
+
* Replies are English (harness text rule); switching to Rush carries a
|
|
17
|
+
* one-line cost warning.
|
|
18
|
+
*
|
|
19
|
+
* @module services/project-tickets/autopilot-speed-command
|
|
20
|
+
*/
|
|
21
|
+
import { compactTokens } from '../usage/token-format.js';
|
|
22
|
+
/** Mode words (lower-case) → mode. */
|
|
23
|
+
const MODE_WORDS = {
|
|
24
|
+
rush: 'rush',
|
|
25
|
+
normal: 'normal',
|
|
26
|
+
chill: 'chill',
|
|
27
|
+
冲刺: 'rush',
|
|
28
|
+
急速: 'rush',
|
|
29
|
+
快: 'rush',
|
|
30
|
+
快速: 'rush',
|
|
31
|
+
正常: 'normal',
|
|
32
|
+
普通: 'normal',
|
|
33
|
+
慢: 'chill',
|
|
34
|
+
慢速: 'chill',
|
|
35
|
+
悠闲: 'chill',
|
|
36
|
+
佛系: 'chill',
|
|
37
|
+
};
|
|
38
|
+
/** Alternation of the mode words, longest first (regex source). */
|
|
39
|
+
const MODE_RE = Object.keys(MODE_WORDS)
|
|
40
|
+
.sort((a, b) => b.length - a.length)
|
|
41
|
+
.join('|');
|
|
42
|
+
/**
|
|
43
|
+
* Normalise a message for matching.
|
|
44
|
+
*
|
|
45
|
+
* @param text - Raw text
|
|
46
|
+
* @returns Mentions, emphasis and trailing punctuation removed; whitespace collapsed
|
|
47
|
+
*/
|
|
48
|
+
function norm(text) {
|
|
49
|
+
return text
|
|
50
|
+
.replace(/<@[A-Z0-9]+>/g, '')
|
|
51
|
+
.replace(/[`*_]/g, '')
|
|
52
|
+
.replace(/[\s.。!!~~]+$/u, '')
|
|
53
|
+
.replace(/^\s*(?:please|pls|请)\s*/iu, '')
|
|
54
|
+
.replace(/\s+/g, ' ')
|
|
55
|
+
.trim();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Clean the typed project: drop "project", "the", "'s autopilot", "speed", "mode".
|
|
59
|
+
*
|
|
60
|
+
* @param raw - Target as typed
|
|
61
|
+
* @returns Project reference and whether "project" was said
|
|
62
|
+
*/
|
|
63
|
+
function cleanTarget(raw) {
|
|
64
|
+
let t = raw.trim();
|
|
65
|
+
let explicitProject = false;
|
|
66
|
+
const lead = /^(?:the\s+)?(?:project\s+|项目\s*)/iu.exec(t);
|
|
67
|
+
if (lead) {
|
|
68
|
+
explicitProject = /project|项目/iu.test(lead[0]);
|
|
69
|
+
t = t.slice(lead[0].length);
|
|
70
|
+
}
|
|
71
|
+
t = t
|
|
72
|
+
.replace(/^the\s+/i, '')
|
|
73
|
+
.replace(/(?:'s)?\s+(?:autopilot|speed|pace|mode)(?:\s+(?:speed|mode|pace))?$/i, '')
|
|
74
|
+
.replace(/\s*(?:的)?(?:自动驾驶|速度|模式)$/u, '')
|
|
75
|
+
.replace(/\s+project$/i, '')
|
|
76
|
+
.trim();
|
|
77
|
+
return { target: t, explicitProject };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Parse a speed-mode command.
|
|
81
|
+
*
|
|
82
|
+
* @param text - Message text
|
|
83
|
+
* @returns The command, or null when the message is not one
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* parseAutopilotSpeedCommand('set CE to rush') // { target: 'CE', mode: 'rush', explicitProject: false }
|
|
87
|
+
* parseAutopilotSpeedCommand('CE 切到 chill') // { target: 'CE', mode: 'chill', explicitProject: false }
|
|
88
|
+
*/
|
|
89
|
+
export function parseAutopilotSpeedCommand(text) {
|
|
90
|
+
if (!text)
|
|
91
|
+
return null;
|
|
92
|
+
const t = norm(text);
|
|
93
|
+
if (!t || t.includes('\n'))
|
|
94
|
+
return null;
|
|
95
|
+
const modeTail = `(${MODE_RE})(?:\\s*(?:mode|模式))?`;
|
|
96
|
+
const patterns = [
|
|
97
|
+
// set / switch / put / change / turn … to|in|into <mode>
|
|
98
|
+
new RegExp(`^(?:set|switch|put|change|turn|move)\\s+(.+?)\\s+(?:to|in|into|on)\\s+${modeTail}$`, 'iu'),
|
|
99
|
+
// 把 <project> 切到 / 切换到 / 改成 / 调成 / 调到 / 设为 <mode>
|
|
100
|
+
new RegExp(`^(?:把\\s*)?(.+?)\\s*(?:切到|切换到|切换成|切成|改成|改为|调成|调到|调为|设为|设成|设置为)\\s*${modeTail}$`, 'iu'),
|
|
101
|
+
// <project> <mode> [mode]
|
|
102
|
+
new RegExp(`^(.+?)\\s+${modeTail}$`, 'iu'),
|
|
103
|
+
];
|
|
104
|
+
for (const re of patterns) {
|
|
105
|
+
const m = re.exec(t);
|
|
106
|
+
if (!m)
|
|
107
|
+
continue;
|
|
108
|
+
const mode = MODE_WORDS[m[2].toLowerCase()];
|
|
109
|
+
if (!mode)
|
|
110
|
+
continue;
|
|
111
|
+
const { target, explicitProject } = cleanTarget(m[1]);
|
|
112
|
+
if (!target)
|
|
113
|
+
return null;
|
|
114
|
+
return { target, mode, explicitProject };
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
/** What each mode does, in one line (owner reply). */
|
|
119
|
+
const MODE_LINES = {
|
|
120
|
+
rush: 'replans whenever the queue runs dry (at least 1 h apart, at most 12 a day), self-review every hour, and an empty replan is retried after 1 h',
|
|
121
|
+
normal: 'replans when the queue runs dry (at least 3 h apart, at most 4 a day), self-review daily, and an empty replan is retried the next day',
|
|
122
|
+
chill: 'at most 1 replan a day, self-review weekly, and an empty replan is retried the next week',
|
|
123
|
+
};
|
|
124
|
+
/** The one-line cost warning shown when Rush is switched on. */
|
|
125
|
+
export const RUSH_COST_WARNING = 'Cost warning: Rush keeps the team busy all day and can use the whole daily budget every day; the budget brake still stops it.';
|
|
126
|
+
/**
|
|
127
|
+
* Mode name for the owner.
|
|
128
|
+
*
|
|
129
|
+
* @param mode - Mode
|
|
130
|
+
* @returns "Rush" / "Normal" / "Chill"
|
|
131
|
+
*/
|
|
132
|
+
export function modeLabel(mode) {
|
|
133
|
+
return mode.charAt(0).toUpperCase() + mode.slice(1);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The owner's reply after a switch.
|
|
137
|
+
*
|
|
138
|
+
* @param status - The project's status after the change
|
|
139
|
+
* @param previous - The mode before
|
|
140
|
+
* @returns Reply text
|
|
141
|
+
*/
|
|
142
|
+
export function speedModeReply(status, previous) {
|
|
143
|
+
const s = status.settings;
|
|
144
|
+
const name = status.project.name;
|
|
145
|
+
const mode = s.speedMode;
|
|
146
|
+
const parts = [
|
|
147
|
+
previous === mode ? `${name} is already on ${modeLabel(mode)}: ${MODE_LINES[mode]}.` : `${name} is on ${modeLabel(mode)} now (was ${modeLabel(previous)}): ${MODE_LINES[mode]}.`,
|
|
148
|
+
s.budgetSource === 'explicit'
|
|
149
|
+
? `Daily budget: ${compactTokens(s.dailyBudgetTokens)} tokens (your setting, unchanged).`
|
|
150
|
+
: `Daily budget: ${compactTokens(s.dailyBudgetTokens)} tokens (the ${modeLabel(mode)} default).`,
|
|
151
|
+
];
|
|
152
|
+
if (s.replansPerDaySource === 'explicit')
|
|
153
|
+
parts.push(`Your replans-per-day setting (${s.replansPerDay}) still caps replans.`);
|
|
154
|
+
if (!s.enabled)
|
|
155
|
+
parts.push(`The autopilot is off on ${name}, so nothing runs until it is switched on.`);
|
|
156
|
+
if (mode === 'rush' && previous !== 'rush')
|
|
157
|
+
parts.push(RUSH_COST_WARNING);
|
|
158
|
+
return parts.join(' ');
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Find a project by id or name (case-insensitive).
|
|
162
|
+
*
|
|
163
|
+
* @param projects - Known projects
|
|
164
|
+
* @param ref - As typed
|
|
165
|
+
* @returns The project, or null
|
|
166
|
+
*/
|
|
167
|
+
export function findProjectByRef(projects, ref) {
|
|
168
|
+
const wanted = ref.trim().toLowerCase();
|
|
169
|
+
if (!wanted)
|
|
170
|
+
return null;
|
|
171
|
+
return projects.find((p) => p.id === ref.trim()) ?? projects.find((p) => p.name.trim().toLowerCase() === wanted) ?? null;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Run a parsed command and build the owner's reply.
|
|
175
|
+
*
|
|
176
|
+
* @param cmd - Command
|
|
177
|
+
* @param projectId - Resolved project
|
|
178
|
+
* @param deps - Collaborators
|
|
179
|
+
* @returns Reply text
|
|
180
|
+
*/
|
|
181
|
+
export async function runAutopilotSpeedCommand(cmd, projectId, deps) {
|
|
182
|
+
const previous = await deps.currentMode(projectId);
|
|
183
|
+
const status = await deps.setMode(projectId, cmd.mode);
|
|
184
|
+
return speedModeReply(status, previous);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* The Slack bridge interceptor for the owner's orc DM.
|
|
188
|
+
*
|
|
189
|
+
* @param deps - Collaborators
|
|
190
|
+
* @returns Interceptor: true when the message was a speed command (consumed)
|
|
191
|
+
*/
|
|
192
|
+
export function createAutopilotSpeedInterceptor(deps) {
|
|
193
|
+
return (message) => {
|
|
194
|
+
if (message.hasFiles)
|
|
195
|
+
return false;
|
|
196
|
+
if (deps.ownerDmScope(message) !== 'orc')
|
|
197
|
+
return false;
|
|
198
|
+
const cmd = parseAutopilotSpeedCommand(message.text);
|
|
199
|
+
if (!cmd)
|
|
200
|
+
return false;
|
|
201
|
+
const projects = deps.knownProjects();
|
|
202
|
+
const project = findProjectByRef(projects, cmd.target);
|
|
203
|
+
const target = deps.replyTargetOf(message);
|
|
204
|
+
if (!project) {
|
|
205
|
+
// "set project X to rush" is unmistakably a command: answer it.
|
|
206
|
+
// Anything else ("let's rush") is the orc's.
|
|
207
|
+
if (!cmd.explicitProject)
|
|
208
|
+
return false;
|
|
209
|
+
void deps
|
|
210
|
+
.reply(`No project named "${cmd.target}". Projects: ${projects.map((p) => p.name).join(', ') || 'none'}.`, target)
|
|
211
|
+
.catch((err) => deps.onError?.(err));
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
void runAutopilotSpeedCommand(cmd, project.id, deps)
|
|
215
|
+
.then((text) => deps.reply(text, target))
|
|
216
|
+
.catch((err) => {
|
|
217
|
+
deps.onError?.(err);
|
|
218
|
+
return deps.reply(`Couldn't switch ${project.name} to ${modeLabel(cmd.mode)}: ${err instanceof Error ? err.message : String(err)}`, target).catch(() => undefined);
|
|
219
|
+
});
|
|
220
|
+
return true;
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=autopilot-speed-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autopilot-speed-command.js","sourceRoot":"","sources":["../../../../../../backend/src/services/project-tickets/autopilot-speed-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Autopilot speed modes — boot wiring (specs/2026-10-04-autopilot-speed-modes.md §5):
|
|
3
|
+
* registers the owner's "set <project> to rush|normal|chill" DM commands
|
|
4
|
+
* with the Slack bridge (handled here, never by the orc's LLM). The
|
|
5
|
+
* interceptor is synchronous, so the project names it matches against are a
|
|
6
|
+
* cache refreshed from storage on a timer.
|
|
7
|
+
*
|
|
8
|
+
* Heavy modules are imported lazily so index.ts gains no import cycles.
|
|
9
|
+
*
|
|
10
|
+
* @module services/project-tickets/autopilot-speed.wiring
|
|
11
|
+
*/
|
|
12
|
+
import type { Project } from '../../types/index.js';
|
|
13
|
+
import type { TicketAutopilotService } from './ticket-autopilot.service.js';
|
|
14
|
+
/** What index.ts provides. */
|
|
15
|
+
export interface AutopilotSpeedWiringInput {
|
|
16
|
+
/** All projects (storage) */
|
|
17
|
+
getProjects: () => Promise<Project[]>;
|
|
18
|
+
/** The running autopilot */
|
|
19
|
+
autopilot: () => TicketAutopilotService;
|
|
20
|
+
logger: {
|
|
21
|
+
info(msg: string, meta?: Record<string, unknown>): void;
|
|
22
|
+
warn(msg: string, meta?: Record<string, unknown>): void;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** A cache of project ids / names for the synchronous interceptor. */
|
|
26
|
+
export declare class KnownProjectsCache {
|
|
27
|
+
private readonly load;
|
|
28
|
+
private projects;
|
|
29
|
+
private timer;
|
|
30
|
+
/**
|
|
31
|
+
* @param load - Reads the projects
|
|
32
|
+
*/
|
|
33
|
+
constructor(load: () => Promise<Project[]>);
|
|
34
|
+
/** The cached projects. */
|
|
35
|
+
list(): Array<{
|
|
36
|
+
id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
}>;
|
|
39
|
+
/** Re-read the projects (a failed read keeps the old list). */
|
|
40
|
+
refresh(): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Refresh on a timer.
|
|
43
|
+
*
|
|
44
|
+
* @param intervalMs - How often
|
|
45
|
+
*/
|
|
46
|
+
start(intervalMs: number): void;
|
|
47
|
+
/** Stop the timer. */
|
|
48
|
+
stop(): void;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Wire the speed-mode DM commands.
|
|
52
|
+
*
|
|
53
|
+
* @param input - Projects, the autopilot, a logger
|
|
54
|
+
* @returns The project cache (running)
|
|
55
|
+
*/
|
|
56
|
+
export declare function startAutopilotSpeedCommands(input: AutopilotSpeedWiringInput): Promise<KnownProjectsCache>;
|
|
57
|
+
//# sourceMappingURL=autopilot-speed.wiring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autopilot-speed.wiring.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/project-tickets/autopilot-speed.wiring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAE5E,8BAA8B;AAC9B,MAAM,WAAW,yBAAyB;IACzC,6BAA6B;IAC7B,WAAW,EAAE,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACtC,4BAA4B;IAC5B,SAAS,EAAE,MAAM,sBAAsB,CAAC;IACxC,MAAM,EAAE;QAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;KAAE,CAAC;CAC7H;AAED,sEAAsE;AACtE,qBAAa,kBAAkB;IAOlB,OAAO,CAAC,QAAQ,CAAC,IAAI;IANjC,OAAO,CAAC,QAAQ,CAA2C;IAC3D,OAAO,CAAC,KAAK,CAA+C;IAE5D;;OAEG;gBAC0B,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IAE3D,2BAA2B;IAC3B,IAAI,IAAI,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAI3C,+DAA+D;IACzD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B;;;;OAIG;IACH,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAM/B,sBAAsB;IACtB,IAAI,IAAI,IAAI;CAIZ;AAED;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAkC/G"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Autopilot speed modes — boot wiring (specs/2026-10-04-autopilot-speed-modes.md §5):
|
|
3
|
+
* registers the owner's "set <project> to rush|normal|chill" DM commands
|
|
4
|
+
* with the Slack bridge (handled here, never by the orc's LLM). The
|
|
5
|
+
* interceptor is synchronous, so the project names it matches against are a
|
|
6
|
+
* cache refreshed from storage on a timer.
|
|
7
|
+
*
|
|
8
|
+
* Heavy modules are imported lazily so index.ts gains no import cycles.
|
|
9
|
+
*
|
|
10
|
+
* @module services/project-tickets/autopilot-speed.wiring
|
|
11
|
+
*/
|
|
12
|
+
import { TICKET_AUTOPILOT_CONSTANTS } from '../../constants.js';
|
|
13
|
+
import { resolveTicketAutopilotSettings } from '../../types/ticket-autopilot.types.js';
|
|
14
|
+
import { createAutopilotSpeedInterceptor } from './autopilot-speed-command.js';
|
|
15
|
+
/** A cache of project ids / names for the synchronous interceptor. */
|
|
16
|
+
export class KnownProjectsCache {
|
|
17
|
+
load;
|
|
18
|
+
projects = [];
|
|
19
|
+
timer = null;
|
|
20
|
+
/**
|
|
21
|
+
* @param load - Reads the projects
|
|
22
|
+
*/
|
|
23
|
+
constructor(load) {
|
|
24
|
+
this.load = load;
|
|
25
|
+
}
|
|
26
|
+
/** The cached projects. */
|
|
27
|
+
list() {
|
|
28
|
+
return this.projects;
|
|
29
|
+
}
|
|
30
|
+
/** Re-read the projects (a failed read keeps the old list). */
|
|
31
|
+
async refresh() {
|
|
32
|
+
try {
|
|
33
|
+
this.projects = (await this.load()).map((p) => ({ id: p.id, name: p.name }));
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Keep what we had: a stale list only delays a brand-new project's name.
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Refresh on a timer.
|
|
41
|
+
*
|
|
42
|
+
* @param intervalMs - How often
|
|
43
|
+
*/
|
|
44
|
+
start(intervalMs) {
|
|
45
|
+
if (this.timer)
|
|
46
|
+
return;
|
|
47
|
+
this.timer = setInterval(() => void this.refresh(), intervalMs);
|
|
48
|
+
this.timer.unref?.();
|
|
49
|
+
}
|
|
50
|
+
/** Stop the timer. */
|
|
51
|
+
stop() {
|
|
52
|
+
if (this.timer)
|
|
53
|
+
clearInterval(this.timer);
|
|
54
|
+
this.timer = null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Wire the speed-mode DM commands.
|
|
59
|
+
*
|
|
60
|
+
* @param input - Projects, the autopilot, a logger
|
|
61
|
+
* @returns The project cache (running)
|
|
62
|
+
*/
|
|
63
|
+
export async function startAutopilotSpeedCommands(input) {
|
|
64
|
+
const cache = new KnownProjectsCache(input.getProjects);
|
|
65
|
+
await cache.refresh();
|
|
66
|
+
cache.start(TICKET_AUTOPILOT_CONSTANTS.SPEED_PROJECT_CACHE_REFRESH_MS);
|
|
67
|
+
const { SlackReloginDmService } = await import('../slack/slack-relogin-dm.service.js');
|
|
68
|
+
const { getSlackService } = await import('../slack/slack.service.js');
|
|
69
|
+
const { getSlackAgentIdentityService } = await import('../slack/slack-agent-identity.service.js');
|
|
70
|
+
const dm = new SlackReloginDmService(() => getSlackService(), undefined, (agentSession) => getSlackAgentIdentityService()?.getInstalled(agentSession)?.botToken ?? null);
|
|
71
|
+
try {
|
|
72
|
+
const { getSlackOrchestratorBridge } = await import('../slack/slack-orchestrator-bridge.js');
|
|
73
|
+
getSlackOrchestratorBridge().addInboundInterceptor('the autopilot speed commands', createAutopilotSpeedInterceptor({
|
|
74
|
+
ownerDmScope: (m) => dm.ownerDmScope(m),
|
|
75
|
+
replyTargetOf: (m) => dm.replyTargetOf(m),
|
|
76
|
+
reply: (text, target) => dm.sendToOwner(text, target),
|
|
77
|
+
knownProjects: () => cache.list(),
|
|
78
|
+
currentMode: async (projectId) => resolveTicketAutopilotSettings((await input.getProjects()).find((p) => p.id === projectId)?.ticketAutopilot).speedMode,
|
|
79
|
+
// The owner's own command: the owner caller (no session).
|
|
80
|
+
setMode: (projectId, mode) => input.autopilot().updateSettings(projectId, { speedMode: mode }, {}),
|
|
81
|
+
onError: (err) => input.logger.warn('Autopilot speed command failed', { error: err instanceof Error ? err.message : String(err) }),
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
input.logger.warn('Autopilot speed Slack commands not wired (non-critical)', { error: err instanceof Error ? err.message : String(err) });
|
|
86
|
+
}
|
|
87
|
+
input.logger.info('Autopilot speed commands wired');
|
|
88
|
+
return cache;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=autopilot-speed.wiring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autopilot-speed.wiring.js","sourceRoot":"","sources":["../../../../../../backend/src/services/project-tickets/autopilot-speed.wiring.ts"],"names":[],"mappings":"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"}
|
package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts
CHANGED
|
@@ -57,6 +57,15 @@ export interface ProjectTicketAutopilotPolicy {
|
|
|
57
57
|
isAutoClaimPaused(project: Project): Promise<boolean>;
|
|
58
58
|
/** In-progress tickets one member may hold when the project's autopilot is on, or null when it is off */
|
|
59
59
|
maxInFlightPerMember(project: Project): Promise<number | null>;
|
|
60
|
+
/**
|
|
61
|
+
* Checks a new ticket before it is written (the metric rule of goal-replan
|
|
62
|
+
* tickets, specs/2026-10-04-autopilot-speed-modes.md §3).
|
|
63
|
+
*
|
|
64
|
+
* @returns Why it is refused (answered as a 400 the agent can act on), or null
|
|
65
|
+
*/
|
|
66
|
+
checkCreate?(project: Project, caller: ProjectTicketCaller, input: CreateProjectTicketInput & {
|
|
67
|
+
metric?: string;
|
|
68
|
+
}): Promise<string | null>;
|
|
60
69
|
}
|
|
61
70
|
/** Dependencies. */
|
|
62
71
|
export interface ProjectTicketWorkflowDeps {
|
|
@@ -239,15 +248,20 @@ export declare class ProjectTicketWorkflowService {
|
|
|
239
248
|
status?: string;
|
|
240
249
|
}): Promise<ProjectTicketsOfProject[]>;
|
|
241
250
|
/**
|
|
242
|
-
* Create a ticket. Workers' tickets always start in `backlog`.
|
|
251
|
+
* Create a ticket. Workers' tickets always start in `backlog`. `metric`
|
|
252
|
+
* (the goal metric it moves and the expected effect) is written as the
|
|
253
|
+
* description's first line, `Metric: …`; a ticket the driver opens during
|
|
254
|
+
* a goal replan is refused without one (the autopilot policy).
|
|
243
255
|
*
|
|
244
256
|
* @param ref - Project reference
|
|
245
|
-
* @param input - Content
|
|
257
|
+
* @param input - Content (+ optional `metric`)
|
|
246
258
|
* @param caller - Caller
|
|
247
259
|
* @returns New ticket
|
|
248
|
-
* @throws ProjectTicketError(403) for outsiders, (400) for a team not on the project
|
|
260
|
+
* @throws ProjectTicketError(403) for outsiders, (400) for a team not on the project or a replan ticket without a metric
|
|
249
261
|
*/
|
|
250
|
-
create(ref: string,
|
|
262
|
+
create(ref: string, rawInput: CreateProjectTicketInput & {
|
|
263
|
+
metric?: string;
|
|
264
|
+
}, caller: ProjectTicketCaller): Promise<ProjectTicket>;
|
|
251
265
|
/**
|
|
252
266
|
* Change fields / sections, optionally followed by a status transition.
|
|
253
267
|
*
|
package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-ticket-workflow.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/project-tickets/project-ticket-workflow.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AASH,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,cAAc,EACpB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAIL,KAAK,aAAa,EAElB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACzB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAEL,oBAAoB,EACpB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC9B,MAAM,6BAA6B,CAAC;AAGrC,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAIvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAiBpF,mDAAmD;AACnD,eAAO,MAAM,0BAA0B,EAAE,SAAS,SAAS,EAAqF,CAAC;AAQjJ,sEAAsE;AACtE,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,0CAA0C;AAC1C,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE5F,qDAAqD;AACrD,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpF,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC/F,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAC3D,WAAW,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACnC,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAC3J,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;CACjG;AAED,+CAA+C;AAC/C,MAAM,WAAW,sBAAsB;IACrC,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5B,WAAW,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;CACnC;AAED;;;;GAIG;AACH,MAAM,WAAW,4BAA4B;IAC3C,sHAAsH;IACtH,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtD,yGAAyG;IACzG,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"project-ticket-workflow.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/project-tickets/project-ticket-workflow.service.ts"],"names":[],"mappings":"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"}
|
package/dist/backend/backend/src/services/project-tickets/project-ticket-workflow.service.js
CHANGED
|
@@ -285,18 +285,32 @@ export class ProjectTicketWorkflowService {
|
|
|
285
285
|
// Writes
|
|
286
286
|
// ---------------------------------------------------------------------------
|
|
287
287
|
/**
|
|
288
|
-
* Create a ticket. Workers' tickets always start in `backlog`.
|
|
288
|
+
* Create a ticket. Workers' tickets always start in `backlog`. `metric`
|
|
289
|
+
* (the goal metric it moves and the expected effect) is written as the
|
|
290
|
+
* description's first line, `Metric: …`; a ticket the driver opens during
|
|
291
|
+
* a goal replan is refused without one (the autopilot policy).
|
|
289
292
|
*
|
|
290
293
|
* @param ref - Project reference
|
|
291
|
-
* @param input - Content
|
|
294
|
+
* @param input - Content (+ optional `metric`)
|
|
292
295
|
* @param caller - Caller
|
|
293
296
|
* @returns New ticket
|
|
294
|
-
* @throws ProjectTicketError(403) for outsiders, (400) for a team not on the project
|
|
297
|
+
* @throws ProjectTicketError(403) for outsiders, (400) for a team not on the project or a replan ticket without a metric
|
|
295
298
|
*/
|
|
296
|
-
async create(ref,
|
|
299
|
+
async create(ref, rawInput, caller) {
|
|
297
300
|
const project = await this.resolveProject(ref);
|
|
298
301
|
const { access } = await this.accessOf(caller, project);
|
|
299
302
|
this.requireAccess(access, ['owner', 'orchestrator', 'lead', 'member'], 'create tickets');
|
|
303
|
+
const { metric: rawMetric, ...rest } = rawInput;
|
|
304
|
+
const metric = typeof rawMetric === 'string' ? rawMetric.replace(/\s+/g, ' ').trim() : '';
|
|
305
|
+
if (metric.length > TICKET_AUTOPILOT_CONSTANTS.METRIC_MAX_CHARS) {
|
|
306
|
+
throw new ProjectTicketError(400, `metric is longer than ${TICKET_AUTOPILOT_CONSTANTS.METRIC_MAX_CHARS} characters`);
|
|
307
|
+
}
|
|
308
|
+
const input = metric
|
|
309
|
+
? { ...rest, description: [`${TICKET_AUTOPILOT_CONSTANTS.METRIC_LINE_PREFIX}${metric}`, rest.description?.trim() ?? ''].filter((l) => l).join('\n\n') }
|
|
310
|
+
: rest;
|
|
311
|
+
const refusal = await this.autopilotPolicy?.checkCreate?.(project, caller, { ...input, ...(metric ? { metric } : {}) });
|
|
312
|
+
if (refusal)
|
|
313
|
+
throw new ProjectTicketError(400, refusal);
|
|
300
314
|
await this.assertTeamOnProject(project, input.team);
|
|
301
315
|
const status = access === 'member' ? 'backlog' : input.status ?? 'backlog';
|
|
302
316
|
if (status === 'in_progress' || status === 'review' || status === 'done') {
|