crewly 1.20.178 → 1.20.180
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/team-leader/prompt.md +2 -2
- package/config/roles/team-leader/tl-addon.md +2 -2
- package/config/skills/agent/core/ask-owner/SKILL.md +79 -0
- package/config/skills/agent/core/ask-owner/execute.sh +66 -0
- package/config/skills/agent/core/ask-owner/execute.test.sh +62 -0
- package/config/skills/agent/core/project-tickets/SKILL.md +21 -9
- package/config/skills/agent/core/project-tickets/execute.sh +28 -9
- package/config/skills/agent/core/project-tickets/execute.test.sh +12 -4
- package/config/skills/agent/core/reply/SKILL.md +22 -5
- package/config/skills/agent/core/reply/execute.sh +12 -5
- package/config/skills/agent/core/reply/execute.test.sh +8 -0
- package/config/skills/agent/core/schedule-followup/SKILL.md +8 -0
- package/config/skills/agent/core/schedule-followup/execute.sh +7 -0
- package/config/slack-app-manifest.json +5 -1
- package/config/slack-master-app-manifest.json +7 -2
- package/dist/backend/backend/src/constants.d.ts +76 -5
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +83 -5
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.d.ts +3 -0
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js +54 -1
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/decisions/decisions.controller.d.ts +67 -0
- package/dist/backend/backend/src/controllers/decisions/decisions.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/decisions/decisions.controller.js +215 -0
- package/dist/backend/backend/src/controllers/decisions/decisions.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts +8 -5
- 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 +51 -12
- package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts +4 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +88 -2
- package/dist/backend/backend/src/index.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 +6 -0
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/boot/boot-announce.service.d.ts +1 -1
- package/dist/backend/backend/src/services/boot/boot-announce.service.js +13 -13
- package/dist/backend/backend/src/services/boot/boot-announce.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-disconnect-notice.service.js +6 -6
- package/dist/backend/backend/src/services/cloud/cloud-disconnect-notice.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-disconnect-notice.utils.d.ts +3 -3
- package/dist/backend/backend/src/services/cloud/cloud-disconnect-notice.utils.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-disconnect-notice.utils.js +14 -13
- package/dist/backend/backend/src/services/cloud/cloud-disconnect-notice.utils.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-card.d.ts +147 -0
- package/dist/backend/backend/src/services/decisions/decision-card.d.ts.map +1 -0
- package/dist/backend/backend/src/services/decisions/decision-card.js +311 -0
- package/dist/backend/backend/src/services/decisions/decision-card.js.map +1 -0
- package/dist/backend/backend/src/services/decisions/decision-contract.d.ts +83 -0
- package/dist/backend/backend/src/services/decisions/decision-contract.d.ts.map +1 -0
- package/dist/backend/backend/src/services/decisions/decision-contract.js +226 -0
- package/dist/backend/backend/src/services/decisions/decision-contract.js.map +1 -0
- package/dist/backend/backend/src/services/decisions/decision-routing.d.ts +34 -0
- package/dist/backend/backend/src/services/decisions/decision-routing.d.ts.map +1 -0
- package/dist/backend/backend/src/services/decisions/decision-routing.js +64 -0
- package/dist/backend/backend/src/services/decisions/decision-routing.js.map +1 -0
- package/dist/backend/backend/src/services/decisions/decision-store.d.ts +80 -0
- package/dist/backend/backend/src/services/decisions/decision-store.d.ts.map +1 -0
- package/dist/backend/backend/src/services/decisions/decision-store.js +151 -0
- package/dist/backend/backend/src/services/decisions/decision-store.js.map +1 -0
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts +281 -0
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/decisions/decision.service.js +639 -0
- package/dist/backend/backend/src/services/decisions/decision.service.js.map +1 -0
- package/dist/backend/backend/src/services/decisions/decision.wiring.d.ts +70 -0
- package/dist/backend/backend/src/services/decisions/decision.wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/decisions/decision.wiring.js +172 -0
- package/dist/backend/backend/src/services/decisions/decision.wiring.js.map +1 -0
- package/dist/backend/backend/src/services/decisions/ticket-thread-store.d.ts +97 -0
- package/dist/backend/backend/src/services/decisions/ticket-thread-store.d.ts.map +1 -0
- package/dist/backend/backend/src/services/decisions/ticket-thread-store.js +137 -0
- package/dist/backend/backend/src/services/decisions/ticket-thread-store.js.map +1 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.d.ts +165 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.js +239 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.js.map +1 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.wiring.d.ts +134 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.wiring.js +217 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.wiring.js.map +1 -0
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts +1 -30
- 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 +1 -22
- 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 +2 -15
- 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 +8 -22
- 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.service.d.ts +11 -12
- 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 +27 -52
- package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-agent-post.service.d.ts +6 -0
- package/dist/backend/backend/src/services/slack/slack-agent-post.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-agent-post.service.js +3 -1
- package/dist/backend/backend/src/services/slack/slack-agent-post.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +12 -12
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.d.ts +16 -1
- package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack.service.js +56 -2
- package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
- package/dist/backend/backend/src/services/system/auto-update.service.js +2 -2
- package/dist/backend/backend/src/services/system/auto-update.service.js.map +1 -1
- package/dist/backend/backend/src/services/system/auto-update.utils.js +2 -2
- package/dist/backend/backend/src/services/system/auto-update.utils.js.map +1 -1
- package/dist/backend/backend/src/types/decision.types.d.ts +139 -0
- package/dist/backend/backend/src/types/decision.types.d.ts.map +1 -0
- package/dist/backend/backend/src/types/decision.types.js +13 -0
- package/dist/backend/backend/src/types/decision.types.js.map +1 -0
- package/dist/backend/backend/src/types/slack.types.d.ts +30 -0
- package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/slack.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/trigger.types.d.ts +17 -0
- package/dist/backend/backend/src/types/v2/trigger.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/trigger.types.js +17 -0
- package/dist/backend/backend/src/types/v2/trigger.types.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +76 -5
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +83 -5
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +12 -12
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack.service.d.ts +16 -1
- package/dist/cli/backend/src/services/slack/slack.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack.service.js +56 -2
- package/dist/cli/backend/src/services/slack/slack.service.js.map +1 -1
- package/dist/cli/backend/src/services/system/auto-update.utils.js +2 -2
- package/dist/cli/backend/src/services/system/auto-update.utils.js.map +1 -1
- package/dist/cli/backend/src/types/slack.types.d.ts +30 -0
- package/dist/cli/backend/src/types/slack.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/slack.types.js.map +1 -1
- package/dist/cli/backend/src/types/v2/trigger.types.d.ts +17 -0
- package/dist/cli/backend/src/types/v2/trigger.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/trigger.types.js +17 -0
- package/dist/cli/backend/src/types/v2/trigger.types.js.map +1 -1
- package/frontend/dist/assets/index-04d192f8.css +42 -0
- package/frontend/dist/assets/{index-69af46c3.js → index-4271e95e.js} +259 -259
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
- package/frontend/dist/assets/index-cdc52122.css +0 -42
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where an agent's answer goes, decided by the WORK it is answering
|
|
3
|
+
* (specs/2026-10-01-decision-cards.md §6).
|
|
4
|
+
*
|
|
5
|
+
* Incident: Atlas posted the output of a scheduled task ("steveswiki 第一次季度
|
|
6
|
+
* 回看…") into an unrelated #pro-think-tank thread. The 1.20.170 `reply` sent
|
|
7
|
+
* every answer to "the thread the agent was last asked in", and a cron run
|
|
8
|
+
* has no asker — so the last owner thread, however old, won.
|
|
9
|
+
*
|
|
10
|
+
* Now each work item carries its own origin and the answer follows it:
|
|
11
|
+
*
|
|
12
|
+
* | Work | Destination |
|
|
13
|
+
* |---|---|
|
|
14
|
+
* | owner asked (newest, < 2 h) | that conversation / thread (turn origin) |
|
|
15
|
+
* | ticket work | the ticket's Slack thread (created on first post) |
|
|
16
|
+
* | trigger / cron / auto work | the trigger's `destination`, else a NEW top-level post in the team channel |
|
|
17
|
+
* | no current work | a NEW top-level post in the team channel |
|
|
18
|
+
*
|
|
19
|
+
* Pure functions only; the effects live in `work-item-destination.wiring.ts`.
|
|
20
|
+
*
|
|
21
|
+
* @module services/orc/work-item-destination
|
|
22
|
+
*/
|
|
23
|
+
import type { WorkItem } from '../../types/v2/work-item.types.js';
|
|
24
|
+
import type { TurnOrigin } from './orc-reply-route.service.js';
|
|
25
|
+
/** The origin a work item carries in `metadata.origin`. */
|
|
26
|
+
export type WorkItemOrigin =
|
|
27
|
+
/** Asked by the owner in a conversation / Slack thread */
|
|
28
|
+
{
|
|
29
|
+
kind: 'owner';
|
|
30
|
+
conversationId?: string;
|
|
31
|
+
slackChannelId?: string;
|
|
32
|
+
threadTs?: string;
|
|
33
|
+
}
|
|
34
|
+
/** Work on a project ticket */
|
|
35
|
+
| {
|
|
36
|
+
kind: 'ticket';
|
|
37
|
+
projectPath: string;
|
|
38
|
+
ticketId: string;
|
|
39
|
+
title?: string;
|
|
40
|
+
teamId?: string;
|
|
41
|
+
}
|
|
42
|
+
/** Fired by a trigger or a cron task */
|
|
43
|
+
| {
|
|
44
|
+
kind: 'trigger';
|
|
45
|
+
triggerId?: string;
|
|
46
|
+
cronTaskId?: string;
|
|
47
|
+
destination?: string;
|
|
48
|
+
teamId?: string;
|
|
49
|
+
topic: string;
|
|
50
|
+
};
|
|
51
|
+
/** Where the answer goes. */
|
|
52
|
+
export type WorkDestination =
|
|
53
|
+
/** The owner's turn origin — the existing `reply` path */
|
|
54
|
+
{
|
|
55
|
+
kind: 'owner-origin';
|
|
56
|
+
origin: TurnOrigin;
|
|
57
|
+
reason: string;
|
|
58
|
+
}
|
|
59
|
+
/** The ticket's Slack thread (created with a `*ID · title*` root when missing) */
|
|
60
|
+
| {
|
|
61
|
+
kind: 'ticket-thread';
|
|
62
|
+
projectPath: string;
|
|
63
|
+
ticketId: string;
|
|
64
|
+
title?: string;
|
|
65
|
+
teamId?: string;
|
|
66
|
+
reason: string;
|
|
67
|
+
}
|
|
68
|
+
/** An explicit Slack place (a trigger's destination): channel name/id, optional thread */
|
|
69
|
+
| {
|
|
70
|
+
kind: 'slack';
|
|
71
|
+
target: string;
|
|
72
|
+
threadTs?: string;
|
|
73
|
+
topic?: string;
|
|
74
|
+
reason: string;
|
|
75
|
+
}
|
|
76
|
+
/** A new top-level post in the agent's (or the work's) team channel */
|
|
77
|
+
| {
|
|
78
|
+
kind: 'new-top-level';
|
|
79
|
+
teamId?: string;
|
|
80
|
+
topic?: string;
|
|
81
|
+
reason: string;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Build the origin stamped on a trigger- or cron-created work item.
|
|
85
|
+
*
|
|
86
|
+
* @param input - Trigger/cron ids, its destination, team and a topic
|
|
87
|
+
* @returns The origin (topic shortened to one line)
|
|
88
|
+
*/
|
|
89
|
+
export declare function buildTriggerOrigin(input: {
|
|
90
|
+
triggerId?: string;
|
|
91
|
+
cronTaskId?: string;
|
|
92
|
+
destination?: string;
|
|
93
|
+
teamId?: string;
|
|
94
|
+
topic: string;
|
|
95
|
+
}): WorkItemOrigin;
|
|
96
|
+
/**
|
|
97
|
+
* One-line topic, capped at {@link WORK_ITEM_DESTINATION_CONSTANTS.TOPIC_MAX_CHARS}.
|
|
98
|
+
*
|
|
99
|
+
* @param text - Any text
|
|
100
|
+
* @returns Single line, possibly shortened with an ellipsis
|
|
101
|
+
*/
|
|
102
|
+
export declare function shortTopic(text: string | undefined): string;
|
|
103
|
+
/**
|
|
104
|
+
* The agent's current work item: the newest (by start) item targeted at it
|
|
105
|
+
* that is running or accepted.
|
|
106
|
+
*
|
|
107
|
+
* @param items - Pool items
|
|
108
|
+
* @param session - Agent session
|
|
109
|
+
* @returns The item, or null
|
|
110
|
+
*/
|
|
111
|
+
export declare function currentWorkItemOf(items: readonly WorkItem[], session: string): WorkItem | null;
|
|
112
|
+
/**
|
|
113
|
+
* The origin of a work item: its stamped `metadata.origin`, else what its
|
|
114
|
+
* other fields say (a linked project ticket, a trigger, a cron task).
|
|
115
|
+
*
|
|
116
|
+
* @param wi - Work item
|
|
117
|
+
* @returns The origin, or null when nothing tells where it came from
|
|
118
|
+
*/
|
|
119
|
+
export declare function originOfWorkItem(wi: WorkItem): WorkItemOrigin | null;
|
|
120
|
+
/**
|
|
121
|
+
* Shape check for a stamped origin.
|
|
122
|
+
*
|
|
123
|
+
* @param value - Anything
|
|
124
|
+
* @returns True for a {@link WorkItemOrigin}
|
|
125
|
+
*/
|
|
126
|
+
export declare function isWorkItemOrigin(value: unknown): value is WorkItemOrigin;
|
|
127
|
+
/**
|
|
128
|
+
* Split a trigger destination into a post target and an optional thread.
|
|
129
|
+
*
|
|
130
|
+
* @param destination - `#name`, `C…` or `C…:<ts>`
|
|
131
|
+
* @returns Target + thread, or null when unreadable
|
|
132
|
+
*/
|
|
133
|
+
export declare function parseDestination(destination: string): {
|
|
134
|
+
target: string;
|
|
135
|
+
threadTs?: string;
|
|
136
|
+
} | null;
|
|
137
|
+
/** Inputs of {@link planWorkDestination}. */
|
|
138
|
+
export interface WorkDestinationInput {
|
|
139
|
+
/** The agent's current work item (see {@link currentWorkItemOf}) */
|
|
140
|
+
workItem: WorkItem | null;
|
|
141
|
+
/** The agent's last owner turn origin (OrcReplyRouteService) */
|
|
142
|
+
ownerOrigin?: TurnOrigin;
|
|
143
|
+
/** Clock (epoch ms) */
|
|
144
|
+
now: number;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Decide where the answer to the agent's current work goes.
|
|
148
|
+
*
|
|
149
|
+
* The current work is the newer of the running work item and the last owner
|
|
150
|
+
* message — the owner message only counts while it is fresh
|
|
151
|
+
* ({@link WORK_ITEM_DESTINATION_CONSTANTS.OWNER_ORIGIN_FRESH_MS}).
|
|
152
|
+
*
|
|
153
|
+
* @param input - Current work item, owner origin, clock
|
|
154
|
+
* @returns The destination
|
|
155
|
+
*/
|
|
156
|
+
export declare function planWorkDestination(input: WorkDestinationInput): WorkDestination;
|
|
157
|
+
/**
|
|
158
|
+
* The text of a new top-level post: the topic line in bold, then the body.
|
|
159
|
+
*
|
|
160
|
+
* @param topic - Topic (may be empty)
|
|
161
|
+
* @param text - Body
|
|
162
|
+
* @returns Post text
|
|
163
|
+
*/
|
|
164
|
+
export declare function withTopicLine(topic: string | undefined, text: string): string;
|
|
165
|
+
//# sourceMappingURL=work-item-destination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-item-destination.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/work-item-destination.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where an agent's answer goes, decided by the WORK it is answering
|
|
3
|
+
* (specs/2026-10-01-decision-cards.md §6).
|
|
4
|
+
*
|
|
5
|
+
* Incident: Atlas posted the output of a scheduled task ("steveswiki 第一次季度
|
|
6
|
+
* 回看…") into an unrelated #pro-think-tank thread. The 1.20.170 `reply` sent
|
|
7
|
+
* every answer to "the thread the agent was last asked in", and a cron run
|
|
8
|
+
* has no asker — so the last owner thread, however old, won.
|
|
9
|
+
*
|
|
10
|
+
* Now each work item carries its own origin and the answer follows it:
|
|
11
|
+
*
|
|
12
|
+
* | Work | Destination |
|
|
13
|
+
* |---|---|
|
|
14
|
+
* | owner asked (newest, < 2 h) | that conversation / thread (turn origin) |
|
|
15
|
+
* | ticket work | the ticket's Slack thread (created on first post) |
|
|
16
|
+
* | trigger / cron / auto work | the trigger's `destination`, else a NEW top-level post in the team channel |
|
|
17
|
+
* | no current work | a NEW top-level post in the team channel |
|
|
18
|
+
*
|
|
19
|
+
* Pure functions only; the effects live in `work-item-destination.wiring.ts`.
|
|
20
|
+
*
|
|
21
|
+
* @module services/orc/work-item-destination
|
|
22
|
+
*/
|
|
23
|
+
import { WORK_ITEM_DESTINATION_CONSTANTS } from '../../constants.js';
|
|
24
|
+
/** Statuses in which a work item is the agent's current work. */
|
|
25
|
+
const CURRENT_STATUSES = new Set(['running', 'accepted']);
|
|
26
|
+
/**
|
|
27
|
+
* Build the origin stamped on a trigger- or cron-created work item.
|
|
28
|
+
*
|
|
29
|
+
* @param input - Trigger/cron ids, its destination, team and a topic
|
|
30
|
+
* @returns The origin (topic shortened to one line)
|
|
31
|
+
*/
|
|
32
|
+
export function buildTriggerOrigin(input) {
|
|
33
|
+
return {
|
|
34
|
+
kind: 'trigger',
|
|
35
|
+
...(input.triggerId ? { triggerId: input.triggerId } : {}),
|
|
36
|
+
...(input.cronTaskId ? { cronTaskId: input.cronTaskId } : {}),
|
|
37
|
+
...(input.destination?.trim() ? { destination: input.destination.trim() } : {}),
|
|
38
|
+
...(input.teamId ? { teamId: input.teamId } : {}),
|
|
39
|
+
topic: shortTopic(input.topic),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* One-line topic, capped at {@link WORK_ITEM_DESTINATION_CONSTANTS.TOPIC_MAX_CHARS}.
|
|
44
|
+
*
|
|
45
|
+
* @param text - Any text
|
|
46
|
+
* @returns Single line, possibly shortened with an ellipsis
|
|
47
|
+
*/
|
|
48
|
+
export function shortTopic(text) {
|
|
49
|
+
const flat = String(text ?? '').replace(/\s+/g, ' ').trim();
|
|
50
|
+
const max = WORK_ITEM_DESTINATION_CONSTANTS.TOPIC_MAX_CHARS;
|
|
51
|
+
return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The agent's current work item: the newest (by start) item targeted at it
|
|
55
|
+
* that is running or accepted.
|
|
56
|
+
*
|
|
57
|
+
* @param items - Pool items
|
|
58
|
+
* @param session - Agent session
|
|
59
|
+
* @returns The item, or null
|
|
60
|
+
*/
|
|
61
|
+
export function currentWorkItemOf(items, session) {
|
|
62
|
+
let best = null;
|
|
63
|
+
let bestAt = -Infinity;
|
|
64
|
+
for (const wi of items) {
|
|
65
|
+
if (wi.target !== session || !CURRENT_STATUSES.has(wi.status))
|
|
66
|
+
continue;
|
|
67
|
+
const at = startOf(wi);
|
|
68
|
+
if (at > bestAt) {
|
|
69
|
+
best = wi;
|
|
70
|
+
bestAt = at;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return best;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* When a work item started (else when it was created).
|
|
77
|
+
*
|
|
78
|
+
* @param wi - Work item
|
|
79
|
+
* @returns Epoch ms (0 when unreadable)
|
|
80
|
+
*/
|
|
81
|
+
function startOf(wi) {
|
|
82
|
+
return Date.parse(wi.startedAt ?? '') || Date.parse(wi.createdAt) || 0;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The origin of a work item: its stamped `metadata.origin`, else what its
|
|
86
|
+
* other fields say (a linked project ticket, a trigger, a cron task).
|
|
87
|
+
*
|
|
88
|
+
* @param wi - Work item
|
|
89
|
+
* @returns The origin, or null when nothing tells where it came from
|
|
90
|
+
*/
|
|
91
|
+
export function originOfWorkItem(wi) {
|
|
92
|
+
const meta = (wi.metadata ?? {});
|
|
93
|
+
const stamped = meta[WORK_ITEM_DESTINATION_CONSTANTS.METADATA_KEY];
|
|
94
|
+
if (isWorkItemOrigin(stamped))
|
|
95
|
+
return stamped;
|
|
96
|
+
const link = meta.projectTicket;
|
|
97
|
+
if (link && typeof link.projectPath === 'string' && typeof link.id === 'string') {
|
|
98
|
+
return {
|
|
99
|
+
kind: 'ticket',
|
|
100
|
+
projectPath: link.projectPath,
|
|
101
|
+
ticketId: link.id,
|
|
102
|
+
...(typeof meta.teamId === 'string' ? { teamId: meta.teamId } : {}),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
if (wi.triggerId)
|
|
106
|
+
return buildTriggerOrigin({ triggerId: wi.triggerId, topic: wi.title });
|
|
107
|
+
if (meta.source === 'cron') {
|
|
108
|
+
return buildTriggerOrigin({
|
|
109
|
+
...(typeof meta.cronTaskId === 'string' ? { cronTaskId: meta.cronTaskId } : {}),
|
|
110
|
+
...(typeof meta.targetTeamId === 'string' ? { teamId: meta.targetTeamId } : {}),
|
|
111
|
+
topic: wi.description ?? wi.title,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Shape check for a stamped origin.
|
|
118
|
+
*
|
|
119
|
+
* @param value - Anything
|
|
120
|
+
* @returns True for a {@link WorkItemOrigin}
|
|
121
|
+
*/
|
|
122
|
+
export function isWorkItemOrigin(value) {
|
|
123
|
+
if (!value || typeof value !== 'object')
|
|
124
|
+
return false;
|
|
125
|
+
const v = value;
|
|
126
|
+
if (v.kind === 'owner')
|
|
127
|
+
return true;
|
|
128
|
+
if (v.kind === 'ticket')
|
|
129
|
+
return typeof v.projectPath === 'string' && typeof v.ticketId === 'string';
|
|
130
|
+
if (v.kind === 'trigger')
|
|
131
|
+
return typeof v.topic === 'string';
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Split a trigger destination into a post target and an optional thread.
|
|
136
|
+
*
|
|
137
|
+
* @param destination - `#name`, `C…` or `C…:<ts>`
|
|
138
|
+
* @returns Target + thread, or null when unreadable
|
|
139
|
+
*/
|
|
140
|
+
export function parseDestination(destination) {
|
|
141
|
+
const d = destination.trim();
|
|
142
|
+
const thread = /^([CG][A-Z0-9]{6,}):(\d{6,}\.\d+)$/.exec(d);
|
|
143
|
+
if (thread)
|
|
144
|
+
return { target: thread[1], threadTs: thread[2] };
|
|
145
|
+
if (/^[CG][A-Z0-9]{6,}$/.test(d))
|
|
146
|
+
return { target: d };
|
|
147
|
+
if (/^#[a-z0-9][a-z0-9._-]*$/.test(d))
|
|
148
|
+
return { target: d };
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Decide where the answer to the agent's current work goes.
|
|
153
|
+
*
|
|
154
|
+
* The current work is the newer of the running work item and the last owner
|
|
155
|
+
* message — the owner message only counts while it is fresh
|
|
156
|
+
* ({@link WORK_ITEM_DESTINATION_CONSTANTS.OWNER_ORIGIN_FRESH_MS}).
|
|
157
|
+
*
|
|
158
|
+
* @param input - Current work item, owner origin, clock
|
|
159
|
+
* @returns The destination
|
|
160
|
+
*/
|
|
161
|
+
export function planWorkDestination(input) {
|
|
162
|
+
const { workItem, ownerOrigin, now } = input;
|
|
163
|
+
const ownerFresh = !!ownerOrigin && now - ownerOrigin.receivedAt < WORK_ITEM_DESTINATION_CONSTANTS.OWNER_ORIGIN_FRESH_MS;
|
|
164
|
+
if (ownerOrigin && ownerFresh && (!workItem || ownerOrigin.receivedAt >= startOf(workItem))) {
|
|
165
|
+
return { kind: 'owner-origin', origin: ownerOrigin, reason: workItem ? 'the owner asked after the work item started' : 'the owner asked (no work item running)' };
|
|
166
|
+
}
|
|
167
|
+
if (!workItem) {
|
|
168
|
+
return { kind: 'new-top-level', reason: ownerOrigin ? 'no current work; the last owner message is stale' : 'no current work' };
|
|
169
|
+
}
|
|
170
|
+
const origin = originOfWorkItem(workItem);
|
|
171
|
+
if (!origin) {
|
|
172
|
+
return { kind: 'new-top-level', topic: shortTopic(workItem.title), reason: `work item ${workItem.id} has no recorded origin` };
|
|
173
|
+
}
|
|
174
|
+
switch (origin.kind) {
|
|
175
|
+
case 'owner': {
|
|
176
|
+
if (origin.conversationId) {
|
|
177
|
+
const threadKey = origin.slackChannelId && origin.threadTs ? `${origin.slackChannelId}:${origin.threadTs}` : undefined;
|
|
178
|
+
return {
|
|
179
|
+
kind: 'owner-origin',
|
|
180
|
+
origin: {
|
|
181
|
+
conversationId: origin.conversationId,
|
|
182
|
+
...(origin.slackChannelId ? { slackChannelId: origin.slackChannelId } : {}),
|
|
183
|
+
...(origin.threadTs ? { slackThreadTs: origin.threadTs } : {}),
|
|
184
|
+
...(threadKey ? { slackThreadKey: threadKey } : {}),
|
|
185
|
+
receivedAt: startOf(workItem),
|
|
186
|
+
},
|
|
187
|
+
reason: `work item ${workItem.id} was asked by the owner`,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
if (origin.slackChannelId) {
|
|
191
|
+
return { kind: 'slack', target: origin.slackChannelId, ...(origin.threadTs ? { threadTs: origin.threadTs } : {}), reason: `work item ${workItem.id} was asked by the owner in Slack` };
|
|
192
|
+
}
|
|
193
|
+
return { kind: 'new-top-level', topic: shortTopic(workItem.title), reason: `work item ${workItem.id} owner origin has no place` };
|
|
194
|
+
}
|
|
195
|
+
case 'ticket':
|
|
196
|
+
return {
|
|
197
|
+
kind: 'ticket-thread',
|
|
198
|
+
projectPath: origin.projectPath,
|
|
199
|
+
ticketId: origin.ticketId,
|
|
200
|
+
...(origin.title ? { title: origin.title } : {}),
|
|
201
|
+
...(origin.teamId ? { teamId: origin.teamId } : {}),
|
|
202
|
+
reason: `work item ${workItem.id} is ticket ${origin.ticketId}`,
|
|
203
|
+
};
|
|
204
|
+
case 'trigger': {
|
|
205
|
+
const parsed = origin.destination ? parseDestination(origin.destination) : null;
|
|
206
|
+
if (parsed) {
|
|
207
|
+
return {
|
|
208
|
+
kind: 'slack',
|
|
209
|
+
target: parsed.target,
|
|
210
|
+
...(parsed.threadTs ? { threadTs: parsed.threadTs } : { topic: origin.topic }),
|
|
211
|
+
reason: `scheduled work item ${workItem.id}: its trigger's destination`,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
kind: 'new-top-level',
|
|
216
|
+
...(origin.teamId ? { teamId: origin.teamId } : {}),
|
|
217
|
+
topic: origin.topic,
|
|
218
|
+
reason: `scheduled work item ${workItem.id}: new top-level post`,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* The text of a new top-level post: the topic line in bold, then the body.
|
|
225
|
+
*
|
|
226
|
+
* @param topic - Topic (may be empty)
|
|
227
|
+
* @param text - Body
|
|
228
|
+
* @returns Post text
|
|
229
|
+
*/
|
|
230
|
+
export function withTopicLine(topic, text) {
|
|
231
|
+
const t = shortTopic(topic);
|
|
232
|
+
if (!t)
|
|
233
|
+
return text;
|
|
234
|
+
// An agent that already opened with the topic needs no second copy.
|
|
235
|
+
if (text.trimStart().startsWith(`*${t}*`))
|
|
236
|
+
return text;
|
|
237
|
+
return `*${t}*\n${text}`;
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=work-item-destination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-item-destination.js","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/work-item-destination.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effects of the work-item destination plan (specs/2026-10-01-decision-cards.md §6):
|
|
3
|
+
* find the agent's current work, post its answer where that work came from
|
|
4
|
+
* (ticket thread, trigger destination, new top-level post in the team
|
|
5
|
+
* channel), and tell other services (decision cards) the Slack place of the
|
|
6
|
+
* agent's current work.
|
|
7
|
+
*
|
|
8
|
+
* Every collaborator is injectable; {@link defaultWorkDestinationDeps} wires
|
|
9
|
+
* the real services lazily.
|
|
10
|
+
*
|
|
11
|
+
* @module services/orc/work-item-destination.wiring
|
|
12
|
+
*/
|
|
13
|
+
import type { WorkItem } from '../../types/v2/work-item.types.js';
|
|
14
|
+
import type { TurnOrigin } from './orc-reply-route.service.js';
|
|
15
|
+
import { type WorkDestination } from './work-item-destination.js';
|
|
16
|
+
/** One Slack post as an agent (SlackAgentPostService.post). */
|
|
17
|
+
export interface WorkDestinationPostRequest {
|
|
18
|
+
agentSession: string;
|
|
19
|
+
target: string;
|
|
20
|
+
text: string;
|
|
21
|
+
threadTs?: string;
|
|
22
|
+
newTopLevel?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** Collaborators. */
|
|
25
|
+
export interface WorkDestinationDeps {
|
|
26
|
+
/** Pool items (for the agent's current work item) */
|
|
27
|
+
poolItems(): Promise<WorkItem[]>;
|
|
28
|
+
/** The agent's last owner turn origin */
|
|
29
|
+
ownerOrigin(session: string): TurnOrigin | undefined;
|
|
30
|
+
/** Clock */
|
|
31
|
+
now(): number;
|
|
32
|
+
/** The Slack team channel of a team (hint) or of the agent's own team */
|
|
33
|
+
teamChannelOf(session: string, teamIdHint?: string | null): Promise<{
|
|
34
|
+
slackChannelId: string;
|
|
35
|
+
teamId: string;
|
|
36
|
+
} | null>;
|
|
37
|
+
/** Ticket → Slack thread store, when wired */
|
|
38
|
+
ticketThreads(): {
|
|
39
|
+
get(projectPath: string, ticketId: string): Promise<{
|
|
40
|
+
slackChannelId: string;
|
|
41
|
+
threadTs: string;
|
|
42
|
+
teamId?: string;
|
|
43
|
+
} | null>;
|
|
44
|
+
set(projectPath: string, ticketId: string, thread: {
|
|
45
|
+
slackChannelId: string;
|
|
46
|
+
threadTs: string;
|
|
47
|
+
teamId?: string;
|
|
48
|
+
}): Promise<{
|
|
49
|
+
slackChannelId: string;
|
|
50
|
+
threadTs: string;
|
|
51
|
+
teamId?: string;
|
|
52
|
+
}>;
|
|
53
|
+
} | null;
|
|
54
|
+
/** A ticket's title and team */
|
|
55
|
+
ticketInfo(projectPath: string, ticketId: string): Promise<{
|
|
56
|
+
title: string;
|
|
57
|
+
team: string | null;
|
|
58
|
+
} | null>;
|
|
59
|
+
/** Post as the agent (its own bot when installed) */
|
|
60
|
+
post(req: WorkDestinationPostRequest): Promise<{
|
|
61
|
+
channelId: string;
|
|
62
|
+
messageTs: string;
|
|
63
|
+
}>;
|
|
64
|
+
/** Channel id for `#name` (optional) */
|
|
65
|
+
findChannelId?(name: string): Promise<string | null>;
|
|
66
|
+
/** The Slack DM a chat-v2 conversation is bridged to (optional) */
|
|
67
|
+
dmOfConversation?(conversationId: string): {
|
|
68
|
+
slackChannelId: string;
|
|
69
|
+
threadTs?: string;
|
|
70
|
+
} | null;
|
|
71
|
+
}
|
|
72
|
+
/** Where an answer landed. */
|
|
73
|
+
export interface WorkDestinationDelivery {
|
|
74
|
+
kind: WorkDestination['kind'];
|
|
75
|
+
slackChannelId: string;
|
|
76
|
+
messageTs: string;
|
|
77
|
+
/** Thread the answer is in (undefined = top level) */
|
|
78
|
+
threadTs?: string;
|
|
79
|
+
reason: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The agent's current work and where its answer goes.
|
|
83
|
+
*
|
|
84
|
+
* @param session - Agent session
|
|
85
|
+
* @param deps - Collaborators
|
|
86
|
+
* @returns The plan and the work item behind it
|
|
87
|
+
*/
|
|
88
|
+
export declare function planForSession(session: string, deps: WorkDestinationDeps): Promise<{
|
|
89
|
+
destination: WorkDestination;
|
|
90
|
+
workItem: WorkItem | null;
|
|
91
|
+
}>;
|
|
92
|
+
/**
|
|
93
|
+
* Post an answer at a non-owner destination. Owner origins are not handled
|
|
94
|
+
* here (the existing chat-v2 reply path owns them) and return null.
|
|
95
|
+
*
|
|
96
|
+
* @param session - Answering agent
|
|
97
|
+
* @param destination - From {@link planWorkDestination}
|
|
98
|
+
* @param text - Answer
|
|
99
|
+
* @param deps - Collaborators
|
|
100
|
+
* @returns Where it landed, or null when there is nowhere to post (no team channel)
|
|
101
|
+
*/
|
|
102
|
+
export declare function deliverToWorkDestination(session: string, destination: WorkDestination, text: string, deps: WorkDestinationDeps): Promise<WorkDestinationDelivery | null>;
|
|
103
|
+
/**
|
|
104
|
+
* `reply --new-thread "<title>"`: a new top-level post in the agent's team
|
|
105
|
+
* channel, opened with the title in bold.
|
|
106
|
+
*
|
|
107
|
+
* @param session - Agent
|
|
108
|
+
* @param title - Thread title
|
|
109
|
+
* @param text - Body
|
|
110
|
+
* @param deps - Collaborators
|
|
111
|
+
* @returns Where it landed, or null when the agent has no team channel
|
|
112
|
+
*/
|
|
113
|
+
export declare function postNewThread(session: string, title: string, text: string, deps: WorkDestinationDeps): Promise<WorkDestinationDelivery | null>;
|
|
114
|
+
/**
|
|
115
|
+
* The Slack place of an agent's current work, for posts that must go there
|
|
116
|
+
* (decision cards). No posting happens: a ticket without a thread yields its
|
|
117
|
+
* team channel (the caller starts the thread).
|
|
118
|
+
*
|
|
119
|
+
* @param session - Agent session
|
|
120
|
+
* @param deps - Collaborators (default: the real services)
|
|
121
|
+
* @returns Channel (+ thread, + team), or null when the work is not in a Slack place
|
|
122
|
+
*/
|
|
123
|
+
export declare function resolveAgentSlackDestination(session: string, deps?: WorkDestinationDeps): Promise<{
|
|
124
|
+
slackChannelId: string;
|
|
125
|
+
threadTs?: string;
|
|
126
|
+
teamId?: string;
|
|
127
|
+
} | null>;
|
|
128
|
+
/**
|
|
129
|
+
* The real collaborators (lazy imports keep this module light for tests).
|
|
130
|
+
*
|
|
131
|
+
* @returns Deps
|
|
132
|
+
*/
|
|
133
|
+
export declare function defaultWorkDestinationDeps(): Promise<WorkDestinationDeps>;
|
|
134
|
+
//# sourceMappingURL=work-item-destination.wiring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-item-destination.wiring.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/orc/work-item-destination.wiring.ts"],"names":[],"mappings":"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"}
|