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,311 @@
1
+ /**
2
+ * Decision cards — Block Kit rendering and answer parsing
3
+ * (specs/2026-10-01-decision-cards.md §3). Pure.
4
+ *
5
+ * @module services/decisions/decision-card
6
+ */
7
+ import { DECISION_CONSTANTS } from '../../constants.js';
8
+ import { matchOption } from './decision-contract.js';
9
+ const DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
10
+ const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
11
+ /**
12
+ * Short local time for the card: "14:05" today, "tomorrow 12:00", else "Thu Oct 2 12:00".
13
+ *
14
+ * @param at - Moment
15
+ * @param now - Clock
16
+ * @returns Text
17
+ */
18
+ export function formatWhen(at, now = new Date()) {
19
+ const hm = `${String(at.getHours()).padStart(2, '0')}:${String(at.getMinutes()).padStart(2, '0')}`;
20
+ const day = (d) => `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
21
+ if (day(at) === day(now))
22
+ return hm;
23
+ const tomorrow = new Date(now.getTime());
24
+ tomorrow.setDate(tomorrow.getDate() + 1);
25
+ if (day(at) === day(tomorrow))
26
+ return `tomorrow ${hm}`;
27
+ return `${DAYS[at.getDay()]} ${MONTHS[at.getMonth()]} ${at.getDate()} ${hm}`;
28
+ }
29
+ /**
30
+ * The label of the default, as the card says it ("wait" for none).
31
+ *
32
+ * @param d - Decision
33
+ * @returns Option label, or "wait"
34
+ */
35
+ export function defaultLabel(d) {
36
+ return d.options.find((o) => o.key === d.defaultKey)?.label ?? DECISION_CONSTANTS.WAIT_DEFAULT;
37
+ }
38
+ /**
39
+ * The label of an option key.
40
+ *
41
+ * @param d - Decision
42
+ * @param key - Option key
43
+ * @returns Label (the key itself when unknown)
44
+ */
45
+ export function optionLabel(d, key) {
46
+ return d.options.find((o) => o.key === key)?.label ?? String(key ?? '');
47
+ }
48
+ /**
49
+ * The card header: ticket id + title, else the asker's topic.
50
+ *
51
+ * @param d - Decision
52
+ * @returns Header text (≤ 150 characters, Slack's header limit)
53
+ */
54
+ export function cardHeader(d) {
55
+ const text = d.ticket ? `${d.ticket.id} · ${d.ticket.title}` : `Decision ${d.id}`;
56
+ return text.length > 150 ? `${text.slice(0, 149)}…` : text;
57
+ }
58
+ /**
59
+ * The thread root for a ticket that has no thread yet.
60
+ *
61
+ * @param ticket - Ticket id + title
62
+ * @returns mrkdwn line
63
+ */
64
+ export function ticketThreadRootText(ticket) {
65
+ return `*${ticket.id} · ${ticket.title}*`;
66
+ }
67
+ /**
68
+ * Button value JSON.
69
+ *
70
+ * @param decisionId - Decision id
71
+ * @param option - Option key or `remind`
72
+ * @param instanceId - This instance (Cloud routes the click by it)
73
+ * @returns JSON string
74
+ */
75
+ export function buttonValue(decisionId, option, instanceId) {
76
+ const v = { d: decisionId, o: option, i: instanceId };
77
+ return JSON.stringify(v);
78
+ }
79
+ /**
80
+ * Parse a button value.
81
+ *
82
+ * @param raw - `value` of the clicked button
83
+ * @returns The value, or null when it is not a decision button
84
+ */
85
+ export function parseButtonValue(raw) {
86
+ if (typeof raw !== 'string' || !raw.startsWith('{'))
87
+ return null;
88
+ try {
89
+ const v = JSON.parse(raw);
90
+ if (typeof v.d !== 'string' || typeof v.o !== 'string')
91
+ return null;
92
+ return { d: v.d, o: v.o, i: typeof v.i === 'string' ? v.i : '' };
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ }
98
+ /**
99
+ * The context line of a pending card.
100
+ *
101
+ * @param d - Decision
102
+ * @param now - Clock
103
+ * @returns mrkdwn text
104
+ */
105
+ export function pendingContextLine(d, now = new Date()) {
106
+ const when = formatWhen(new Date(d.deadline), now);
107
+ const parts = [];
108
+ if (d.remindAt && Date.parse(d.remindAt) > now.getTime()) {
109
+ parts.push(`⏰ Reminding you ${formatWhen(new Date(d.remindAt), now)}.`);
110
+ }
111
+ if (d.sensitive) {
112
+ parts.push(`This needs your OK (${d.sensitive}); I won't go ahead without an answer.`);
113
+ }
114
+ else if (d.defaultKey === DECISION_CONSTANTS.WAIT_DEFAULT) {
115
+ parts.push(`If no answer by ${when}, I'll keep waiting.`);
116
+ }
117
+ else {
118
+ parts.push(`If no answer by ${when}, I'll go with ${defaultLabel(d)}.`);
119
+ }
120
+ parts.push(d.id);
121
+ return parts.join(' · ');
122
+ }
123
+ /**
124
+ * The option lines under the question (only when some option has a detail).
125
+ *
126
+ * @param options - Options
127
+ * @returns mrkdwn, or null
128
+ */
129
+ function optionDetails(options) {
130
+ if (!options.some((o) => o.detail))
131
+ return null;
132
+ return options.map((o) => `• *${o.label}*${o.detail ? ` — ${o.detail}` : ''}`).join('\n');
133
+ }
134
+ /**
135
+ * Blocks of an open card.
136
+ *
137
+ * @param d - Decision
138
+ * @param instanceId - This instance id (button values)
139
+ * @param now - Clock
140
+ * @returns Blocks
141
+ */
142
+ export function renderOpenCard(d, instanceId, now = new Date()) {
143
+ const blocks = [
144
+ { type: 'header', text: { type: 'plain_text', text: cardHeader(d), emoji: true } },
145
+ { type: 'section', text: { type: 'mrkdwn', text: d.question } },
146
+ ];
147
+ const details = optionDetails(d.options);
148
+ if (details)
149
+ blocks.push({ type: 'section', text: { type: 'mrkdwn', text: details } });
150
+ blocks.push({
151
+ type: 'actions',
152
+ block_id: `decision:${d.id}`,
153
+ elements: [
154
+ ...d.options.map((o) => ({
155
+ type: 'button',
156
+ action_id: `${DECISION_CONSTANTS.ACTION_PREFIX}${o.key}`,
157
+ text: { type: 'plain_text', text: o.label, emoji: true },
158
+ value: buttonValue(d.id, o.key, instanceId),
159
+ ...(o.key === d.defaultKey && !d.sensitive ? { style: 'primary' } : {}),
160
+ })),
161
+ {
162
+ type: 'button',
163
+ action_id: DECISION_CONSTANTS.REMIND_ACTION_ID,
164
+ text: { type: 'plain_text', text: 'Remind me tomorrow', emoji: true },
165
+ value: buttonValue(d.id, 'remind', instanceId),
166
+ },
167
+ ],
168
+ });
169
+ blocks.push({ type: 'context', elements: [{ type: 'mrkdwn', text: pendingContextLine(d, now) }] });
170
+ return blocks;
171
+ }
172
+ /**
173
+ * Blocks of a settled card (no buttons).
174
+ *
175
+ * @param d - Decision (resolved / defaulted / parked / cancelled)
176
+ * @param ownerName - How to name the owner ("Steve"), when known
177
+ * @param now - Clock
178
+ * @returns Blocks
179
+ */
180
+ export function renderSettledCard(d, ownerName, now = new Date()) {
181
+ return [
182
+ { type: 'header', text: { type: 'plain_text', text: cardHeader(d), emoji: true } },
183
+ { type: 'section', text: { type: 'mrkdwn', text: d.question } },
184
+ { type: 'context', elements: [{ type: 'mrkdwn', text: settledLine(d, ownerName, now) }] },
185
+ ];
186
+ }
187
+ /**
188
+ * The one line a settled card shows.
189
+ *
190
+ * @param d - Decision
191
+ * @param ownerName - Owner display name
192
+ * @param now - Clock
193
+ * @returns Text
194
+ */
195
+ export function settledLine(d, ownerName, now = new Date()) {
196
+ const at = formatWhen(new Date(d.resolvedAt ?? d.updatedAt), now);
197
+ const who = ownerName || (d.answeredBy ? `<@${d.answeredBy}>` : 'The owner');
198
+ switch (d.status) {
199
+ case 'resolved':
200
+ return d.chosenKey
201
+ ? `✔ ${who} chose *${optionLabel(d, d.chosenKey)}* · ${at}`
202
+ : `✔ ${who} answered: “${(d.answerText ?? '').slice(0, 200)}” · ${at}`;
203
+ case 'defaulted':
204
+ return deadlineDefaultLine(d, now);
205
+ case 'parked':
206
+ return `⏸ Parked — no answer, so I'm not going ahead. Answer from "Waiting on you" to reopen it. · ${d.id}`;
207
+ case 'cancelled':
208
+ return `Withdrawn · ${at}`;
209
+ default:
210
+ return pendingContextLine(d, now);
211
+ }
212
+ }
213
+ /**
214
+ * "No answer by <deadline> — going with <default>." (or "— still waiting." for `wait`).
215
+ *
216
+ * @param d - Decision
217
+ * @param now - Clock
218
+ * @returns Text
219
+ */
220
+ export function deadlineDefaultLine(d, now = new Date()) {
221
+ const when = formatWhen(new Date(d.deadline), now);
222
+ return d.defaultKey === DECISION_CONSTANTS.WAIT_DEFAULT
223
+ ? `No answer by ${when} — I'll keep waiting.`
224
+ : `No answer by ${when} — going with ${defaultLabel(d)}.`;
225
+ }
226
+ /**
227
+ * The plain-text fallback of a card (notifications, screen readers).
228
+ *
229
+ * @param d - Decision
230
+ * @returns Text
231
+ */
232
+ export function cardFallbackText(d) {
233
+ return `${cardHeader(d)}: ${d.question} (${d.options.map((o) => o.label).join(' / ')})`;
234
+ }
235
+ /**
236
+ * The option that reads as "no", when one does.
237
+ *
238
+ * @param options - Options
239
+ * @returns Option, or null
240
+ */
241
+ export function noOption(options) {
242
+ const words = DECISION_CONSTANTS.NO_WORDS;
243
+ return (options.find((o) => {
244
+ const l = o.label.toLowerCase().trim();
245
+ return words.includes(l) || words.includes(l.split(/[\s,—–-]+/)[0]) || words.some((w) => /[^\x00-\x7F]/.test(w) && l.startsWith(w));
246
+ }) ?? null);
247
+ }
248
+ /**
249
+ * The option ✅ / "yes" means: the default, else the first option.
250
+ *
251
+ * @param d - Decision
252
+ * @returns Option key
253
+ */
254
+ export function acceptKey(d) {
255
+ return d.options.some((o) => o.key === d.defaultKey) ? d.defaultKey : d.options[0].key;
256
+ }
257
+ /**
258
+ * Map a reaction on a card to a choice.
259
+ *
260
+ * @param d - Decision
261
+ * @param reaction - Emoji name (no colons; skin tone suffix allowed)
262
+ * @returns Choice, or null when the reaction means nothing
263
+ */
264
+ export function choiceFromReaction(d, reaction) {
265
+ const name = reaction.replace(/::skin-tone-\d$/, '');
266
+ if (DECISION_CONSTANTS.REACTION_ACCEPT.includes(name))
267
+ return { kind: 'option', key: acceptKey(d) };
268
+ if (DECISION_CONSTANTS.REACTION_REMIND.includes(name))
269
+ return { kind: 'remind' };
270
+ if (DECISION_CONSTANTS.REACTION_REJECT.includes(name)) {
271
+ const no = noOption(d.options);
272
+ return no ? { kind: 'option', key: no.key } : null;
273
+ }
274
+ return null;
275
+ }
276
+ /**
277
+ * Map a free-text thread reply to a choice: an option (label, key, number),
278
+ * a yes word (the default / first option), a no word (the "no" option), a
279
+ * remind word — else the text itself, for the asker to read.
280
+ *
281
+ * @param d - Decision
282
+ * @param text - The owner's reply
283
+ * @returns Choice, or null for an empty reply
284
+ */
285
+ export function choiceFromText(d, text) {
286
+ const clean = text.replace(/<@[A-Z0-9]+>/g, '').replace(/\s+/g, ' ').trim();
287
+ if (!clean)
288
+ return null;
289
+ const opt = matchOption(clean, d.options);
290
+ if (opt)
291
+ return { kind: 'option', key: opt.key };
292
+ const norm = clean.toLowerCase().replace(/[\s.。!!,,]+$/u, '');
293
+ if (DECISION_CONSTANTS.REMIND_WORDS.includes(norm))
294
+ return { kind: 'remind' };
295
+ if (DECISION_CONSTANTS.YES_WORDS.includes(norm))
296
+ return { kind: 'option', key: acceptKey(d) };
297
+ if (DECISION_CONSTANTS.NO_WORDS.includes(norm)) {
298
+ const no = noOption(d.options);
299
+ if (no)
300
+ return { kind: 'option', key: no.key };
301
+ }
302
+ // "go with Hold", "option 2", "let's do B"
303
+ const tail = /^(?:go with|option|choose|pick|let'?s do|do|选)\s*(.+)$/i.exec(norm);
304
+ if (tail) {
305
+ const o = matchOption(tail[1], d.options);
306
+ if (o)
307
+ return { kind: 'option', key: o.key };
308
+ }
309
+ return { kind: 'text', text: clean };
310
+ }
311
+ //# sourceMappingURL=decision-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision-card.js","sourceRoot":"","sources":["../../../../../../backend/src/services/decisions/decision-card.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * The ask-owner contract (specs/2026-10-01-decision-cards.md §1): validate a
3
+ * structured owner question and turn it into a {@link ValidatedAsk}. Pure.
4
+ *
5
+ * Every rejection says what to fix and shows a correct ask, because the
6
+ * reader is an agent that will retry with whatever the error tells it.
7
+ *
8
+ * @module services/decisions/decision-contract
9
+ */
10
+ import type { AskOwnerInput, DecisionOption, DecisionSensitiveKind, ValidatedAsk } from '../../types/decision.types.js';
11
+ /** A rejected ask. */
12
+ export declare class DecisionContractError extends Error {
13
+ constructor(message: string);
14
+ }
15
+ /** The example appended to every contract error. */
16
+ export declare const ASK_OWNER_EXAMPLE = "Example: ask-owner --question \"Send the partner email on Monday?\" --option \"Send Monday \u2014 after the review call\" --option \"Hold \u2014 wait for legal\" --default \"Hold\" [--deadline 2026-10-02T12:00] [--ticket APP-12 --project P] [--sensitive email]";
17
+ /**
18
+ * The next day at {@link DECISION_CONSTANTS.DEFAULT_DEADLINE_HOUR_LOCAL}:00 local.
19
+ *
20
+ * @param now - Clock
21
+ * @returns Default deadline
22
+ */
23
+ export declare function defaultDeadline(now: Date): Date;
24
+ /**
25
+ * Whether a question is too vague to put in front of the owner.
26
+ *
27
+ * @param question - One-line question
28
+ * @returns True for "thoughts?", "OK?", "可以吗" and the like
29
+ */
30
+ export declare function isVagueQuestion(question: string): boolean;
31
+ /**
32
+ * Parse the options: an array of `{label, detail?}` objects or of strings
33
+ * (`"Label"` / `"Label — detail"`).
34
+ *
35
+ * @param raw - Input
36
+ * @returns Options with keys a/b/c
37
+ * @throws DecisionContractError
38
+ */
39
+ export declare function parseOptions(raw: unknown): DecisionOption[];
40
+ /**
41
+ * Resolve the default to an option key or `wait`.
42
+ *
43
+ * @param raw - Label, key (a/b/c), number (1–3) or `wait`
44
+ * @param options - Parsed options
45
+ * @returns Option key or `wait`
46
+ * @throws DecisionContractError
47
+ */
48
+ export declare function resolveDefault(raw: unknown, options: DecisionOption[]): string;
49
+ /**
50
+ * Find the option a label, key (a/b/c) or number (1–3) names.
51
+ *
52
+ * @param text - What was given
53
+ * @param options - Options
54
+ * @returns The option, or null
55
+ */
56
+ export declare function matchOption(text: string, options: DecisionOption[]): DecisionOption | null;
57
+ /**
58
+ * Parse the deadline.
59
+ *
60
+ * @param raw - ISO / date-time string, or empty for the default
61
+ * @param now - Clock
62
+ * @returns The deadline
63
+ * @throws DecisionContractError when unreadable or not in the future
64
+ */
65
+ export declare function parseDeadline(raw: unknown, now: Date): Date;
66
+ /**
67
+ * Parse the sensitive kind.
68
+ *
69
+ * @param raw - `email` | `publish` | `deploy` | `spend`, or empty
70
+ * @returns The kind, or undefined
71
+ * @throws DecisionContractError on anything else
72
+ */
73
+ export declare function parseSensitive(raw: unknown): DecisionSensitiveKind | undefined;
74
+ /**
75
+ * Validate a whole ask.
76
+ *
77
+ * @param input - Raw input (skill / API body)
78
+ * @param now - Clock
79
+ * @returns The validated ask
80
+ * @throws DecisionContractError with a fix-it message
81
+ */
82
+ export declare function validateAskOwner(input: AskOwnerInput, now?: Date): ValidatedAsk;
83
+ //# sourceMappingURL=decision-contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision-contract.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/decisions/decision-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAExH,sBAAsB;AACtB,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,oDAAoD;AACpD,eAAO,MAAM,iBAAiB,yQACwN,CAAC;AAiBvP;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,CAK/C;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGzD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,EAAE,CA8C3D;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,MAAM,CAa9E;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,cAAc,GAAG,IAAI,CAa1F;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,GAAG,IAAI,CAQ3D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,qBAAqB,GAAG,SAAS,CAO9E;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,GAAE,IAAiB,GAAG,YAAY,CA+B3F"}
@@ -0,0 +1,226 @@
1
+ /**
2
+ * The ask-owner contract (specs/2026-10-01-decision-cards.md §1): validate a
3
+ * structured owner question and turn it into a {@link ValidatedAsk}. Pure.
4
+ *
5
+ * Every rejection says what to fix and shows a correct ask, because the
6
+ * reader is an agent that will retry with whatever the error tells it.
7
+ *
8
+ * @module services/decisions/decision-contract
9
+ */
10
+ import { DECISION_CONSTANTS } from '../../constants.js';
11
+ /** A rejected ask. */
12
+ export class DecisionContractError extends Error {
13
+ constructor(message) {
14
+ super(message);
15
+ this.name = 'DecisionContractError';
16
+ }
17
+ }
18
+ /** The example appended to every contract error. */
19
+ export const ASK_OWNER_EXAMPLE = 'Example: ask-owner --question "Send the partner email on Monday?" --option "Send Monday — after the review call" --option "Hold — wait for legal" --default "Hold" [--deadline 2026-10-02T12:00] [--ticket APP-12 --project P] [--sensitive email]';
20
+ const OPTION_KEYS = ['a', 'b', 'c'];
21
+ /** Separators accepted between an option's label and its detail in a string form. */
22
+ const DETAIL_SEPARATOR = /\s+(?:—|–|--|-|:)\s+/;
23
+ /**
24
+ * Collapse whitespace.
25
+ *
26
+ * @param s - Text
27
+ * @returns One trimmed line
28
+ */
29
+ function oneLine(s) {
30
+ return s.replace(/\s+/g, ' ').trim();
31
+ }
32
+ /**
33
+ * The next day at {@link DECISION_CONSTANTS.DEFAULT_DEADLINE_HOUR_LOCAL}:00 local.
34
+ *
35
+ * @param now - Clock
36
+ * @returns Default deadline
37
+ */
38
+ export function defaultDeadline(now) {
39
+ const d = new Date(now.getTime());
40
+ d.setDate(d.getDate() + 1);
41
+ d.setHours(DECISION_CONSTANTS.DEFAULT_DEADLINE_HOUR_LOCAL, 0, 0, 0);
42
+ return d;
43
+ }
44
+ /**
45
+ * Whether a question is too vague to put in front of the owner.
46
+ *
47
+ * @param question - One-line question
48
+ * @returns True for "thoughts?", "OK?", "可以吗" and the like
49
+ */
50
+ export function isVagueQuestion(question) {
51
+ const core = question.toLowerCase().replace(/[\s??!!.。…]+$/u, '').trim();
52
+ return DECISION_CONSTANTS.VAGUE_QUESTIONS.includes(core);
53
+ }
54
+ /**
55
+ * Parse the options: an array of `{label, detail?}` objects or of strings
56
+ * (`"Label"` / `"Label — detail"`).
57
+ *
58
+ * @param raw - Input
59
+ * @returns Options with keys a/b/c
60
+ * @throws DecisionContractError
61
+ */
62
+ export function parseOptions(raw) {
63
+ if (!Array.isArray(raw) || raw.length === 0) {
64
+ throw new DecisionContractError(`options are required: give the owner ${DECISION_CONSTANTS.MIN_OPTIONS}–${DECISION_CONSTANTS.MAX_OPTIONS} concrete choices they can tap. ${ASK_OWNER_EXAMPLE}`);
65
+ }
66
+ if (raw.length < DECISION_CONSTANTS.MIN_OPTIONS || raw.length > DECISION_CONSTANTS.MAX_OPTIONS) {
67
+ throw new DecisionContractError(`give ${DECISION_CONSTANTS.MIN_OPTIONS}–${DECISION_CONSTANTS.MAX_OPTIONS} options (got ${raw.length}). Pick the real alternatives; leave out "other". ${ASK_OWNER_EXAMPLE}`);
68
+ }
69
+ const options = raw.map((item, i) => {
70
+ let label = '';
71
+ let detail;
72
+ if (typeof item === 'string') {
73
+ const text = oneLine(item);
74
+ const m = DETAIL_SEPARATOR.exec(text);
75
+ if (m && m.index > 0) {
76
+ label = text.slice(0, m.index).trim();
77
+ detail = text.slice(m.index + m[0].length).trim() || undefined;
78
+ }
79
+ else {
80
+ label = text;
81
+ }
82
+ }
83
+ else if (item && typeof item === 'object') {
84
+ const o = item;
85
+ label = typeof o.label === 'string' ? oneLine(o.label) : '';
86
+ detail = typeof o.detail === 'string' && oneLine(o.detail) ? oneLine(o.detail) : undefined;
87
+ }
88
+ if (!label)
89
+ throw new DecisionContractError(`option ${i + 1} has no label. ${ASK_OWNER_EXAMPLE}`);
90
+ if (label.length > DECISION_CONSTANTS.OPTION_LABEL_MAX_CHARS) {
91
+ throw new DecisionContractError(`option "${label.slice(0, 30)}…" is too long for a button (max ${DECISION_CONSTANTS.OPTION_LABEL_MAX_CHARS} characters): put the short choice first and the explanation after " — ".`);
92
+ }
93
+ if (detail && detail.length > DECISION_CONSTANTS.OPTION_DETAIL_MAX_CHARS) {
94
+ throw new DecisionContractError(`the detail of option "${label}" is too long (max ${DECISION_CONSTANTS.OPTION_DETAIL_MAX_CHARS} characters).`);
95
+ }
96
+ return { key: OPTION_KEYS[i], label, ...(detail ? { detail } : {}) };
97
+ });
98
+ const seen = new Set();
99
+ for (const o of options) {
100
+ const k = o.label.toLowerCase();
101
+ if (seen.has(k))
102
+ throw new DecisionContractError(`two options are both "${o.label}": each option must be a different choice.`);
103
+ seen.add(k);
104
+ }
105
+ return options;
106
+ }
107
+ /**
108
+ * Resolve the default to an option key or `wait`.
109
+ *
110
+ * @param raw - Label, key (a/b/c), number (1–3) or `wait`
111
+ * @param options - Parsed options
112
+ * @returns Option key or `wait`
113
+ * @throws DecisionContractError
114
+ */
115
+ export function resolveDefault(raw, options) {
116
+ const text = typeof raw === 'string' ? oneLine(raw) : typeof raw === 'number' ? String(raw) : '';
117
+ if (!text) {
118
+ throw new DecisionContractError(`default is required: the option you will take if the owner does not answer by the deadline, or "wait" to do nothing until they answer. ${ASK_OWNER_EXAMPLE}`);
119
+ }
120
+ const found = matchOption(text, options);
121
+ if (found)
122
+ return found.key;
123
+ if (text.toLowerCase() === DECISION_CONSTANTS.WAIT_DEFAULT)
124
+ return DECISION_CONSTANTS.WAIT_DEFAULT;
125
+ throw new DecisionContractError(`default "${text}" is not one of the options (${options.map((o) => `"${o.label}"`).join(', ')}) and not "wait".`);
126
+ }
127
+ /**
128
+ * Find the option a label, key (a/b/c) or number (1–3) names.
129
+ *
130
+ * @param text - What was given
131
+ * @param options - Options
132
+ * @returns The option, or null
133
+ */
134
+ export function matchOption(text, options) {
135
+ const t = oneLine(text).toLowerCase().replace(/[.。!!]+$/u, '');
136
+ if (!t)
137
+ return null;
138
+ const byLabel = options.find((o) => o.label.toLowerCase() === t);
139
+ if (byLabel)
140
+ return byLabel;
141
+ const byKey = options.find((o) => o.key === t);
142
+ if (byKey)
143
+ return byKey;
144
+ const n = /^#?(\d)$/.exec(t);
145
+ if (n) {
146
+ const idx = Number(n[1]) - 1;
147
+ if (idx >= 0 && idx < options.length)
148
+ return options[idx];
149
+ }
150
+ return null;
151
+ }
152
+ /**
153
+ * Parse the deadline.
154
+ *
155
+ * @param raw - ISO / date-time string, or empty for the default
156
+ * @param now - Clock
157
+ * @returns The deadline
158
+ * @throws DecisionContractError when unreadable or not in the future
159
+ */
160
+ export function parseDeadline(raw, now) {
161
+ if (raw === undefined || raw === null || (typeof raw === 'string' && raw.trim() === ''))
162
+ return defaultDeadline(now);
163
+ const ms = typeof raw === 'number' ? raw : Date.parse(String(raw).trim());
164
+ if (!Number.isFinite(ms)) {
165
+ throw new DecisionContractError(`deadline "${String(raw)}" is not a date-time. Use ISO, e.g. 2026-10-02T12:00, or leave it out (default: tomorrow 12:00).`);
166
+ }
167
+ if (ms <= now.getTime())
168
+ throw new DecisionContractError(`deadline ${new Date(ms).toISOString()} is in the past.`);
169
+ return new Date(ms);
170
+ }
171
+ /**
172
+ * Parse the sensitive kind.
173
+ *
174
+ * @param raw - `email` | `publish` | `deploy` | `spend`, or empty
175
+ * @returns The kind, or undefined
176
+ * @throws DecisionContractError on anything else
177
+ */
178
+ export function parseSensitive(raw) {
179
+ if (raw === undefined || raw === null || raw === '' || raw === false)
180
+ return undefined;
181
+ const v = String(raw).trim().toLowerCase();
182
+ if (DECISION_CONSTANTS.SENSITIVE_KINDS.includes(v))
183
+ return v;
184
+ throw new DecisionContractError(`sensitive must be one of ${DECISION_CONSTANTS.SENSITIVE_KINDS.join(' | ')} (outside email/messages, public publishing, prod deploys, spending money).`);
185
+ }
186
+ /**
187
+ * Validate a whole ask.
188
+ *
189
+ * @param input - Raw input (skill / API body)
190
+ * @param now - Clock
191
+ * @returns The validated ask
192
+ * @throws DecisionContractError with a fix-it message
193
+ */
194
+ export function validateAskOwner(input, now = new Date()) {
195
+ const rawQ = typeof input.question === 'string' ? input.question : '';
196
+ if (/\n\s*\S/.test(rawQ.trim())) {
197
+ throw new DecisionContractError('question must be ONE line. Put the context in the ticket, the choices in --option. ' + ASK_OWNER_EXAMPLE);
198
+ }
199
+ const question = oneLine(rawQ);
200
+ if (!question)
201
+ throw new DecisionContractError(`question is required. ${ASK_OWNER_EXAMPLE}`);
202
+ if (question.length > DECISION_CONSTANTS.QUESTION_MAX_CHARS) {
203
+ throw new DecisionContractError(`question is too long (max ${DECISION_CONSTANTS.QUESTION_MAX_CHARS} characters) — one line the owner can answer with a tap.`);
204
+ }
205
+ if (question.length < DECISION_CONSTANTS.QUESTION_MIN_CHARS || isVagueQuestion(question)) {
206
+ throw new DecisionContractError(`"${question}" is too vague to answer from a phone. Name the concrete decision (what, and when), e.g. "Send the partner email on Monday?". ${ASK_OWNER_EXAMPLE}`);
207
+ }
208
+ const options = parseOptions(input.options);
209
+ const defaultKey = resolveDefault(input.default, options);
210
+ const deadline = parseDeadline(input.deadline, now);
211
+ const sensitive = parseSensitive(input.sensitive);
212
+ const ticketId = typeof input.ticket === 'string' && input.ticket.trim() ? input.ticket.trim() : undefined;
213
+ const project = typeof input.project === 'string' && input.project.trim() ? input.project.trim() : undefined;
214
+ if (ticketId && !project)
215
+ throw new DecisionContractError('ticket needs --project too (the project the ticket belongs to).');
216
+ return {
217
+ question,
218
+ options,
219
+ defaultKey,
220
+ deadline,
221
+ ...(sensitive ? { sensitive } : {}),
222
+ ...(ticketId ? { ticketId } : {}),
223
+ ...(project ? { project } : {}),
224
+ };
225
+ }
226
+ //# sourceMappingURL=decision-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision-contract.js","sourceRoot":"","sources":["../../../../../../backend/src/services/decisions/decision-contract.ts"],"names":[],"mappings":"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"}