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.
Files changed (145) hide show
  1. package/config/roles/team-leader/prompt.md +2 -2
  2. package/config/roles/team-leader/tl-addon.md +2 -2
  3. package/config/skills/agent/core/ask-owner/SKILL.md +79 -0
  4. package/config/skills/agent/core/ask-owner/execute.sh +66 -0
  5. package/config/skills/agent/core/ask-owner/execute.test.sh +62 -0
  6. package/config/skills/agent/core/project-tickets/SKILL.md +21 -9
  7. package/config/skills/agent/core/project-tickets/execute.sh +28 -9
  8. package/config/skills/agent/core/project-tickets/execute.test.sh +12 -4
  9. package/config/skills/agent/core/reply/SKILL.md +22 -5
  10. package/config/skills/agent/core/reply/execute.sh +12 -5
  11. package/config/skills/agent/core/reply/execute.test.sh +8 -0
  12. package/config/skills/agent/core/schedule-followup/SKILL.md +8 -0
  13. package/config/skills/agent/core/schedule-followup/execute.sh +7 -0
  14. package/config/slack-app-manifest.json +5 -1
  15. package/config/slack-master-app-manifest.json +7 -2
  16. package/dist/backend/backend/src/constants.d.ts +76 -5
  17. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  18. package/dist/backend/backend/src/constants.js +83 -5
  19. package/dist/backend/backend/src/constants.js.map +1 -1
  20. package/dist/backend/backend/src/controllers/chat/agent-reply.controller.d.ts +3 -0
  21. package/dist/backend/backend/src/controllers/chat/agent-reply.controller.d.ts.map +1 -1
  22. package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js +54 -1
  23. package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js.map +1 -1
  24. package/dist/backend/backend/src/controllers/decisions/decisions.controller.d.ts +67 -0
  25. package/dist/backend/backend/src/controllers/decisions/decisions.controller.d.ts.map +1 -0
  26. package/dist/backend/backend/src/controllers/decisions/decisions.controller.js +215 -0
  27. package/dist/backend/backend/src/controllers/decisions/decisions.controller.js.map +1 -0
  28. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts +8 -5
  29. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts.map +1 -1
  30. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js +51 -12
  31. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js.map +1 -1
  32. package/dist/backend/backend/src/index.d.ts +4 -0
  33. package/dist/backend/backend/src/index.d.ts.map +1 -1
  34. package/dist/backend/backend/src/index.js +88 -2
  35. package/dist/backend/backend/src/index.js.map +1 -1
  36. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  37. package/dist/backend/backend/src/routes/api.routes.js +6 -0
  38. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  39. package/dist/backend/backend/src/services/boot/boot-announce.service.d.ts +1 -1
  40. package/dist/backend/backend/src/services/boot/boot-announce.service.js +13 -13
  41. package/dist/backend/backend/src/services/boot/boot-announce.service.js.map +1 -1
  42. package/dist/backend/backend/src/services/cloud/cloud-disconnect-notice.service.js +6 -6
  43. package/dist/backend/backend/src/services/cloud/cloud-disconnect-notice.service.js.map +1 -1
  44. package/dist/backend/backend/src/services/cloud/cloud-disconnect-notice.utils.d.ts +3 -3
  45. package/dist/backend/backend/src/services/cloud/cloud-disconnect-notice.utils.d.ts.map +1 -1
  46. package/dist/backend/backend/src/services/cloud/cloud-disconnect-notice.utils.js +14 -13
  47. package/dist/backend/backend/src/services/cloud/cloud-disconnect-notice.utils.js.map +1 -1
  48. package/dist/backend/backend/src/services/decisions/decision-card.d.ts +147 -0
  49. package/dist/backend/backend/src/services/decisions/decision-card.d.ts.map +1 -0
  50. package/dist/backend/backend/src/services/decisions/decision-card.js +311 -0
  51. package/dist/backend/backend/src/services/decisions/decision-card.js.map +1 -0
  52. package/dist/backend/backend/src/services/decisions/decision-contract.d.ts +83 -0
  53. package/dist/backend/backend/src/services/decisions/decision-contract.d.ts.map +1 -0
  54. package/dist/backend/backend/src/services/decisions/decision-contract.js +226 -0
  55. package/dist/backend/backend/src/services/decisions/decision-contract.js.map +1 -0
  56. package/dist/backend/backend/src/services/decisions/decision-routing.d.ts +34 -0
  57. package/dist/backend/backend/src/services/decisions/decision-routing.d.ts.map +1 -0
  58. package/dist/backend/backend/src/services/decisions/decision-routing.js +64 -0
  59. package/dist/backend/backend/src/services/decisions/decision-routing.js.map +1 -0
  60. package/dist/backend/backend/src/services/decisions/decision-store.d.ts +80 -0
  61. package/dist/backend/backend/src/services/decisions/decision-store.d.ts.map +1 -0
  62. package/dist/backend/backend/src/services/decisions/decision-store.js +151 -0
  63. package/dist/backend/backend/src/services/decisions/decision-store.js.map +1 -0
  64. package/dist/backend/backend/src/services/decisions/decision.service.d.ts +281 -0
  65. package/dist/backend/backend/src/services/decisions/decision.service.d.ts.map +1 -0
  66. package/dist/backend/backend/src/services/decisions/decision.service.js +639 -0
  67. package/dist/backend/backend/src/services/decisions/decision.service.js.map +1 -0
  68. package/dist/backend/backend/src/services/decisions/decision.wiring.d.ts +70 -0
  69. package/dist/backend/backend/src/services/decisions/decision.wiring.d.ts.map +1 -0
  70. package/dist/backend/backend/src/services/decisions/decision.wiring.js +172 -0
  71. package/dist/backend/backend/src/services/decisions/decision.wiring.js.map +1 -0
  72. package/dist/backend/backend/src/services/decisions/ticket-thread-store.d.ts +97 -0
  73. package/dist/backend/backend/src/services/decisions/ticket-thread-store.d.ts.map +1 -0
  74. package/dist/backend/backend/src/services/decisions/ticket-thread-store.js +137 -0
  75. package/dist/backend/backend/src/services/decisions/ticket-thread-store.js.map +1 -0
  76. package/dist/backend/backend/src/services/orc/work-item-destination.d.ts +165 -0
  77. package/dist/backend/backend/src/services/orc/work-item-destination.d.ts.map +1 -0
  78. package/dist/backend/backend/src/services/orc/work-item-destination.js +239 -0
  79. package/dist/backend/backend/src/services/orc/work-item-destination.js.map +1 -0
  80. package/dist/backend/backend/src/services/orc/work-item-destination.wiring.d.ts +134 -0
  81. package/dist/backend/backend/src/services/orc/work-item-destination.wiring.d.ts.map +1 -0
  82. package/dist/backend/backend/src/services/orc/work-item-destination.wiring.js +217 -0
  83. package/dist/backend/backend/src/services/orc/work-item-destination.wiring.js.map +1 -0
  84. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts +1 -30
  85. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts.map +1 -1
  86. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js +1 -22
  87. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js.map +1 -1
  88. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts +2 -15
  89. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts.map +1 -1
  90. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js +8 -22
  91. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js.map +1 -1
  92. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts +11 -12
  93. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts.map +1 -1
  94. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js +27 -52
  95. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js.map +1 -1
  96. package/dist/backend/backend/src/services/slack/slack-agent-post.service.d.ts +6 -0
  97. package/dist/backend/backend/src/services/slack/slack-agent-post.service.d.ts.map +1 -1
  98. package/dist/backend/backend/src/services/slack/slack-agent-post.service.js +3 -1
  99. package/dist/backend/backend/src/services/slack/slack-agent-post.service.js.map +1 -1
  100. package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +12 -12
  101. package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
  102. package/dist/backend/backend/src/services/slack/slack.service.d.ts +16 -1
  103. package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
  104. package/dist/backend/backend/src/services/slack/slack.service.js +56 -2
  105. package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
  106. package/dist/backend/backend/src/services/system/auto-update.service.js +2 -2
  107. package/dist/backend/backend/src/services/system/auto-update.service.js.map +1 -1
  108. package/dist/backend/backend/src/services/system/auto-update.utils.js +2 -2
  109. package/dist/backend/backend/src/services/system/auto-update.utils.js.map +1 -1
  110. package/dist/backend/backend/src/types/decision.types.d.ts +139 -0
  111. package/dist/backend/backend/src/types/decision.types.d.ts.map +1 -0
  112. package/dist/backend/backend/src/types/decision.types.js +13 -0
  113. package/dist/backend/backend/src/types/decision.types.js.map +1 -0
  114. package/dist/backend/backend/src/types/slack.types.d.ts +30 -0
  115. package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
  116. package/dist/backend/backend/src/types/slack.types.js.map +1 -1
  117. package/dist/backend/backend/src/types/v2/trigger.types.d.ts +17 -0
  118. package/dist/backend/backend/src/types/v2/trigger.types.d.ts.map +1 -1
  119. package/dist/backend/backend/src/types/v2/trigger.types.js +17 -0
  120. package/dist/backend/backend/src/types/v2/trigger.types.js.map +1 -1
  121. package/dist/backend/build-info.json +2 -2
  122. package/dist/cli/backend/src/constants.d.ts +76 -5
  123. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  124. package/dist/cli/backend/src/constants.js +83 -5
  125. package/dist/cli/backend/src/constants.js.map +1 -1
  126. package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +12 -12
  127. package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
  128. package/dist/cli/backend/src/services/slack/slack.service.d.ts +16 -1
  129. package/dist/cli/backend/src/services/slack/slack.service.d.ts.map +1 -1
  130. package/dist/cli/backend/src/services/slack/slack.service.js +56 -2
  131. package/dist/cli/backend/src/services/slack/slack.service.js.map +1 -1
  132. package/dist/cli/backend/src/services/system/auto-update.utils.js +2 -2
  133. package/dist/cli/backend/src/services/system/auto-update.utils.js.map +1 -1
  134. package/dist/cli/backend/src/types/slack.types.d.ts +30 -0
  135. package/dist/cli/backend/src/types/slack.types.d.ts.map +1 -1
  136. package/dist/cli/backend/src/types/slack.types.js.map +1 -1
  137. package/dist/cli/backend/src/types/v2/trigger.types.d.ts +17 -0
  138. package/dist/cli/backend/src/types/v2/trigger.types.d.ts.map +1 -1
  139. package/dist/cli/backend/src/types/v2/trigger.types.js +17 -0
  140. package/dist/cli/backend/src/types/v2/trigger.types.js.map +1 -1
  141. package/frontend/dist/assets/index-04d192f8.css +42 -0
  142. package/frontend/dist/assets/{index-69af46c3.js → index-4271e95e.js} +259 -259
  143. package/frontend/dist/index.html +2 -2
  144. package/package.json +1 -1
  145. 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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"}