crewly 1.20.181 → 1.20.183
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/roles/orchestrator/prompt.md +4 -0
- package/config/skills/agent/core/report-status/execute.sh +4 -2
- package/dist/backend/backend/src/constants.d.ts +101 -1
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +110 -1
- package/dist/backend/backend/src/constants.js.map +1 -1
- 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 +22 -1
- package/dist/backend/backend/src/controllers/chat/agent-reply.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.js +25 -24
- package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.js +15 -0
- package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/system/runtime-fallback.controller.d.ts +11 -1
- package/dist/backend/backend/src/controllers/system/runtime-fallback.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/system/runtime-fallback.controller.js +44 -9
- package/dist/backend/backend/src/controllers/system/runtime-fallback.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/system/runtime-terms.controller.d.ts +31 -0
- package/dist/backend/backend/src/controllers/system/runtime-terms.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/system/runtime-terms.controller.js +99 -0
- package/dist/backend/backend/src/controllers/system/runtime-terms.controller.js.map +1 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +4 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/modules/system.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/modules/system.routes.js +3 -0
- package/dist/backend/backend/src/routes/modules/system.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/antigravity-runtime.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/antigravity-runtime.service.js +5 -0
- package/dist/backend/backend/src/services/agent/antigravity-runtime.service.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-card.d.ts +14 -4
- package/dist/backend/backend/src/services/decisions/decision-card.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision-card.js +31 -10
- package/dist/backend/backend/src/services/decisions/decision-card.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts +40 -2
- package/dist/backend/backend/src/services/decisions/decision.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.service.js +100 -8
- package/dist/backend/backend/src/services/decisions/decision.service.js.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/decisions/decision.wiring.js +7 -0
- package/dist/backend/backend/src/services/decisions/decision.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/message-queue.service.d.ts +2 -1
- package/dist/backend/backend/src/services/messaging/message-queue.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/message-queue.service.js +6 -3
- package/dist/backend/backend/src/services/messaging/message-queue.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js +6 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js.map +1 -1
- package/dist/backend/backend/src/services/orc/orc-delivery-enforcer.service.d.ts +3 -1
- package/dist/backend/backend/src/services/orc/orc-delivery-enforcer.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orc/orc-delivery-enforcer.service.js +7 -4
- package/dist/backend/backend/src/services/orc/orc-delivery-enforcer.service.js.map +1 -1
- package/dist/backend/backend/src/services/orc/orc-status-router.service.d.ts +110 -0
- package/dist/backend/backend/src/services/orc/orc-status-router.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orc/orc-status-router.service.js +229 -0
- package/dist/backend/backend/src/services/orc/orc-status-router.service.js.map +1 -0
- package/dist/backend/backend/src/services/orc/orc-status-routing.d.ts +108 -0
- package/dist/backend/backend/src/services/orc/orc-status-routing.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orc/orc-status-routing.js +145 -0
- package/dist/backend/backend/src/services/orc/orc-status-routing.js.map +1 -0
- package/dist/backend/backend/src/services/orc/orc-wake-counter.d.ts +86 -0
- package/dist/backend/backend/src/services/orc/orc-wake-counter.d.ts.map +1 -0
- package/dist/backend/backend/src/services/orc/orc-wake-counter.js +130 -0
- package/dist/backend/backend/src/services/orc/orc-wake-counter.js.map +1 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.d.ts +33 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orc/work-item-destination.js +49 -0
- package/dist/backend/backend/src/services/orc/work-item-destination.js.map +1 -1
- package/dist/backend/backend/src/services/orc/work-item-destination.wiring.d.ts +2 -1
- package/dist/backend/backend/src/services/orc/work-item-destination.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orc/work-item-destination.wiring.js +10 -4
- package/dist/backend/backend/src/services/orc/work-item-destination.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/runtime-fallback/runtime-availability.d.ts +8 -0
- package/dist/backend/backend/src/services/runtime-fallback/runtime-availability.d.ts.map +1 -1
- package/dist/backend/backend/src/services/runtime-fallback/runtime-availability.js +5 -0
- package/dist/backend/backend/src/services/runtime-fallback/runtime-availability.js.map +1 -1
- package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.service.d.ts +2 -0
- package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.service.js +4 -0
- package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.service.js.map +1 -1
- package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.types.d.ts +2 -0
- package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.types.js.map +1 -1
- package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.wiring.js +3 -0
- package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/runtime-fallback/runtime-smoke-test.service.d.ts +15 -1
- package/dist/backend/backend/src/services/runtime-fallback/runtime-smoke-test.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/runtime-fallback/runtime-smoke-test.service.js +13 -2
- package/dist/backend/backend/src/services/runtime-fallback/runtime-smoke-test.service.js.map +1 -1
- package/dist/backend/backend/src/services/runtime-terms/antigravity-terms-driver.d.ts +92 -0
- package/dist/backend/backend/src/services/runtime-terms/antigravity-terms-driver.d.ts.map +1 -0
- package/dist/backend/backend/src/services/runtime-terms/antigravity-terms-driver.js +199 -0
- package/dist/backend/backend/src/services/runtime-terms/antigravity-terms-driver.js.map +1 -0
- package/dist/backend/backend/src/services/runtime-terms/antigravity-terms-screens.d.ts +79 -0
- package/dist/backend/backend/src/services/runtime-terms/antigravity-terms-screens.d.ts.map +1 -0
- package/dist/backend/backend/src/services/runtime-terms/antigravity-terms-screens.js +145 -0
- package/dist/backend/backend/src/services/runtime-terms/antigravity-terms-screens.js.map +1 -0
- package/dist/backend/backend/src/services/runtime-terms/fake-agy-tui.fixture.d.ts +75 -0
- package/dist/backend/backend/src/services/runtime-terms/fake-agy-tui.fixture.d.ts.map +1 -0
- package/dist/backend/backend/src/services/runtime-terms/fake-agy-tui.fixture.js +218 -0
- package/dist/backend/backend/src/services/runtime-terms/fake-agy-tui.fixture.js.map +1 -0
- package/dist/backend/backend/src/services/runtime-terms/runtime-terms-consent.service.d.ts +245 -0
- package/dist/backend/backend/src/services/runtime-terms/runtime-terms-consent.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/runtime-terms/runtime-terms-consent.service.js +428 -0
- package/dist/backend/backend/src/services/runtime-terms/runtime-terms-consent.service.js.map +1 -0
- package/dist/backend/backend/src/services/runtime-terms/runtime-terms.store.d.ts +67 -0
- package/dist/backend/backend/src/services/runtime-terms/runtime-terms.store.d.ts.map +1 -0
- package/dist/backend/backend/src/services/runtime-terms/runtime-terms.store.js +78 -0
- package/dist/backend/backend/src/services/runtime-terms/runtime-terms.store.js.map +1 -0
- package/dist/backend/backend/src/services/runtime-terms/runtime-terms.wiring.d.ts +39 -0
- package/dist/backend/backend/src/services/runtime-terms/runtime-terms.wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/runtime-terms/runtime-terms.wiring.js +161 -0
- package/dist/backend/backend/src/services/runtime-terms/runtime-terms.wiring.js.map +1 -0
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts +16 -0
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +31 -8
- package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/give-up/give-up-recovery.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/give-up/give-up-recovery.service.js +2 -0
- package/dist/backend/backend/src/services/task-pool/give-up/give-up-recovery.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +23 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js +61 -0
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/backend/backend/src/types/decision.types.d.ts +29 -5
- package/dist/backend/backend/src/types/decision.types.d.ts.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +101 -1
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +110 -1
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/agent/antigravity-runtime.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/antigravity-runtime.service.js +5 -0
- package/dist/cli/backend/src/services/agent/antigravity-runtime.service.js.map +1 -1
- package/dist/cli/backend/src/services/decisions/decision-card.d.ts +165 -0
- package/dist/cli/backend/src/services/decisions/decision-card.d.ts.map +1 -0
- package/dist/cli/backend/src/services/decisions/decision-card.js +358 -0
- package/dist/cli/backend/src/services/decisions/decision-card.js.map +1 -0
- package/dist/cli/backend/src/services/decisions/decision-contract.d.ts +83 -0
- package/dist/cli/backend/src/services/decisions/decision-contract.d.ts.map +1 -0
- package/dist/cli/backend/src/services/decisions/decision-contract.js +226 -0
- package/dist/cli/backend/src/services/decisions/decision-contract.js.map +1 -0
- package/dist/cli/backend/src/services/decisions/decision-store.d.ts +80 -0
- package/dist/cli/backend/src/services/decisions/decision-store.d.ts.map +1 -0
- package/dist/cli/backend/src/services/decisions/decision-store.js +151 -0
- package/dist/cli/backend/src/services/decisions/decision-store.js.map +1 -0
- package/dist/cli/backend/src/services/decisions/decision.service.d.ts +376 -0
- package/dist/cli/backend/src/services/decisions/decision.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/decisions/decision.service.js +821 -0
- package/dist/cli/backend/src/services/decisions/decision.service.js.map +1 -0
- package/dist/cli/backend/src/services/decisions/ticket-thread-store.d.ts +97 -0
- package/dist/cli/backend/src/services/decisions/ticket-thread-store.d.ts.map +1 -0
- package/dist/cli/backend/src/services/decisions/ticket-thread-store.js +137 -0
- package/dist/cli/backend/src/services/decisions/ticket-thread-store.js.map +1 -0
- package/dist/cli/backend/src/services/messaging/message-queue.service.d.ts +2 -1
- package/dist/cli/backend/src/services/messaging/message-queue.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/messaging/message-queue.service.js +6 -3
- package/dist/cli/backend/src/services/messaging/message-queue.service.js.map +1 -1
- package/dist/cli/backend/src/services/messaging/queue-processor.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/messaging/queue-processor.service.js +6 -1
- package/dist/cli/backend/src/services/messaging/queue-processor.service.js.map +1 -1
- package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.d.ts +3 -1
- package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.js +7 -4
- package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.js.map +1 -1
- package/dist/cli/backend/src/services/orc/orc-status-routing.d.ts +108 -0
- package/dist/cli/backend/src/services/orc/orc-status-routing.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orc/orc-status-routing.js +145 -0
- package/dist/cli/backend/src/services/orc/orc-status-routing.js.map +1 -0
- package/dist/cli/backend/src/services/orc/orc-wake-counter.d.ts +86 -0
- package/dist/cli/backend/src/services/orc/orc-wake-counter.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orc/orc-wake-counter.js +130 -0
- package/dist/cli/backend/src/services/orc/orc-wake-counter.js.map +1 -0
- package/dist/cli/backend/src/services/orc/work-item-destination.d.ts +198 -0
- package/dist/cli/backend/src/services/orc/work-item-destination.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orc/work-item-destination.js +288 -0
- package/dist/cli/backend/src/services/orc/work-item-destination.js.map +1 -0
- package/dist/cli/backend/src/services/runtime-fallback/runtime-fallback.types.d.ts +136 -0
- package/dist/cli/backend/src/services/runtime-fallback/runtime-fallback.types.d.ts.map +1 -0
- package/dist/cli/backend/src/services/runtime-fallback/runtime-fallback.types.js +152 -0
- package/dist/cli/backend/src/services/runtime-fallback/runtime-fallback.types.js.map +1 -0
- package/dist/cli/backend/src/services/runtime-fallback/runtime-smoke-test.service.d.ts +217 -0
- package/dist/cli/backend/src/services/runtime-fallback/runtime-smoke-test.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/runtime-fallback/runtime-smoke-test.service.js +430 -0
- package/dist/cli/backend/src/services/runtime-fallback/runtime-smoke-test.service.js.map +1 -0
- package/dist/cli/backend/src/services/runtime-terms/antigravity-terms-driver.d.ts +92 -0
- package/dist/cli/backend/src/services/runtime-terms/antigravity-terms-driver.d.ts.map +1 -0
- package/dist/cli/backend/src/services/runtime-terms/antigravity-terms-driver.js +199 -0
- package/dist/cli/backend/src/services/runtime-terms/antigravity-terms-driver.js.map +1 -0
- package/dist/cli/backend/src/services/runtime-terms/antigravity-terms-screens.d.ts +79 -0
- package/dist/cli/backend/src/services/runtime-terms/antigravity-terms-screens.d.ts.map +1 -0
- package/dist/cli/backend/src/services/runtime-terms/antigravity-terms-screens.js +145 -0
- package/dist/cli/backend/src/services/runtime-terms/antigravity-terms-screens.js.map +1 -0
- package/dist/cli/backend/src/services/runtime-terms/runtime-terms-consent.service.d.ts +245 -0
- package/dist/cli/backend/src/services/runtime-terms/runtime-terms-consent.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/runtime-terms/runtime-terms-consent.service.js +428 -0
- package/dist/cli/backend/src/services/runtime-terms/runtime-terms-consent.service.js.map +1 -0
- package/dist/cli/backend/src/services/runtime-terms/runtime-terms.store.d.ts +67 -0
- package/dist/cli/backend/src/services/runtime-terms/runtime-terms.store.d.ts.map +1 -0
- package/dist/cli/backend/src/services/runtime-terms/runtime-terms.store.js +78 -0
- package/dist/cli/backend/src/services/runtime-terms/runtime-terms.store.js.map +1 -0
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts +16 -0
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +31 -8
- package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +23 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js +61 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/cli/backend/src/types/decision.types.d.ts +192 -0
- package/dist/cli/backend/src/types/decision.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/decision.types.js +13 -0
- package/dist/cli/backend/src/types/decision.types.js.map +1 -0
- package/dist/cli/cli/src/commands/harness-setup.js +2 -2
- package/frontend/dist/assets/{index-4271e95e.js → index-9c91de50.js} +138 -138
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
|
@@ -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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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable store of owner decisions (specs/2026-10-01-decision-cards.md §1).
|
|
3
|
+
*
|
|
4
|
+
* One JSON file under CREWLY_HOME with a monotonically increasing id
|
|
5
|
+
* counter, so `D-7` is never reused. All writes are serialised and atomic.
|
|
6
|
+
* Settled decisions are pruned after {@link DECISION_CONSTANTS.RESOLVED_KEEP_MS}.
|
|
7
|
+
*
|
|
8
|
+
* @module services/decisions/decision-store
|
|
9
|
+
*/
|
|
10
|
+
import type { OwnerDecision } from '../../types/decision.types.js';
|
|
11
|
+
/** Statuses still in front of the owner. */
|
|
12
|
+
export declare const PENDING_DECISION_STATUSES: ReadonlySet<OwnerDecision['status']>;
|
|
13
|
+
/**
|
|
14
|
+
* Persistent decision store.
|
|
15
|
+
*/
|
|
16
|
+
export declare class DecisionStore {
|
|
17
|
+
private readonly filePath;
|
|
18
|
+
private readonly now;
|
|
19
|
+
private data;
|
|
20
|
+
private chain;
|
|
21
|
+
/**
|
|
22
|
+
* @param filePath - JSON file
|
|
23
|
+
* @param now - Clock (tests)
|
|
24
|
+
*/
|
|
25
|
+
constructor(filePath: string, now?: () => Date);
|
|
26
|
+
/**
|
|
27
|
+
* Store under a CREWLY_HOME.
|
|
28
|
+
*
|
|
29
|
+
* @param crewlyHome - CREWLY_HOME
|
|
30
|
+
* @returns The store
|
|
31
|
+
*/
|
|
32
|
+
static inHome(crewlyHome: string): DecisionStore;
|
|
33
|
+
/**
|
|
34
|
+
* Add a decision, assigning its id.
|
|
35
|
+
*
|
|
36
|
+
* @param draft - Decision without id/timestamps
|
|
37
|
+
* @returns The stored decision
|
|
38
|
+
*/
|
|
39
|
+
create(draft: Omit<OwnerDecision, 'id' | 'createdAt' | 'updatedAt'>): Promise<OwnerDecision>;
|
|
40
|
+
/**
|
|
41
|
+
* Change a decision under the write lock.
|
|
42
|
+
*
|
|
43
|
+
* @param id - Decision id
|
|
44
|
+
* @param fn - Returns the patch, or null to leave it alone
|
|
45
|
+
* @returns The updated decision, or null when missing / unchanged
|
|
46
|
+
*/
|
|
47
|
+
update(id: string, fn: (d: OwnerDecision) => Partial<OwnerDecision> | null): Promise<OwnerDecision | null>;
|
|
48
|
+
/**
|
|
49
|
+
* One decision.
|
|
50
|
+
*
|
|
51
|
+
* @param id - Decision id
|
|
52
|
+
* @returns Copy, or null
|
|
53
|
+
*/
|
|
54
|
+
get(id: string): Promise<OwnerDecision | null>;
|
|
55
|
+
/**
|
|
56
|
+
* All decisions, newest first, optionally filtered.
|
|
57
|
+
*
|
|
58
|
+
* @param filter - Predicate
|
|
59
|
+
* @returns Copies
|
|
60
|
+
*/
|
|
61
|
+
list(filter?: (d: OwnerDecision) => boolean): Promise<OwnerDecision[]>;
|
|
62
|
+
/**
|
|
63
|
+
* The open decision whose card is this message (or whose thread this is).
|
|
64
|
+
*
|
|
65
|
+
* @param slackChannelId - Channel
|
|
66
|
+
* @param ts - Card ts or thread ts
|
|
67
|
+
* @returns Decision, or null
|
|
68
|
+
*/
|
|
69
|
+
findByCard(slackChannelId: string, ts: string): Promise<OwnerDecision | null>;
|
|
70
|
+
/**
|
|
71
|
+
* Drop settled decisions older than the keep window.
|
|
72
|
+
*
|
|
73
|
+
* @returns How many were dropped
|
|
74
|
+
*/
|
|
75
|
+
prune(): Promise<number>;
|
|
76
|
+
private load;
|
|
77
|
+
private save;
|
|
78
|
+
private serial;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=decision-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision-store.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/decisions/decision-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAQnE,4CAA4C;AAC5C,eAAO,MAAM,yBAAyB,EAAE,WAAW,CAAC,aAAa,CAAC,QAAQ,CAAC,CAA+B,CAAC;AAE3G;;GAEG;AACH,qBAAa,aAAa;IAStB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG;IATtB,OAAO,CAAC,IAAI,CAA6B;IACzC,OAAO,CAAC,KAAK,CAAuC;IAEpD;;;OAGG;gBAEgB,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,MAAM,IAAuB;IAGrD;;;;;OAKG;IACH,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa;IAIhD;;;;;OAKG;IACG,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC;IAYlG;;;;;;OAMG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAchH;;;;;OAKG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAMpD;;;;;OAKG;IACG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,OAAO,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAQ5E;;;;;;OAMG;IACG,UAAU,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAMnF;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;YAYhB,IAAI;YASJ,IAAI;IAIlB,OAAO,CAAC,MAAM;CAKf"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable store of owner decisions (specs/2026-10-01-decision-cards.md §1).
|
|
3
|
+
*
|
|
4
|
+
* One JSON file under CREWLY_HOME with a monotonically increasing id
|
|
5
|
+
* counter, so `D-7` is never reused. All writes are serialised and atomic.
|
|
6
|
+
* Settled decisions are pruned after {@link DECISION_CONSTANTS.RESOLVED_KEEP_MS}.
|
|
7
|
+
*
|
|
8
|
+
* @module services/decisions/decision-store
|
|
9
|
+
*/
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
import { DECISION_CONSTANTS } from '../../constants.js';
|
|
12
|
+
import { atomicWriteJson, safeReadJson } from '../../utils/file-io.utils.js';
|
|
13
|
+
/** Statuses still in front of the owner. */
|
|
14
|
+
export const PENDING_DECISION_STATUSES = new Set(['open', 'parked']);
|
|
15
|
+
/**
|
|
16
|
+
* Persistent decision store.
|
|
17
|
+
*/
|
|
18
|
+
export class DecisionStore {
|
|
19
|
+
filePath;
|
|
20
|
+
now;
|
|
21
|
+
data = null;
|
|
22
|
+
chain = Promise.resolve();
|
|
23
|
+
/**
|
|
24
|
+
* @param filePath - JSON file
|
|
25
|
+
* @param now - Clock (tests)
|
|
26
|
+
*/
|
|
27
|
+
constructor(filePath, now = () => new Date()) {
|
|
28
|
+
this.filePath = filePath;
|
|
29
|
+
this.now = now;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Store under a CREWLY_HOME.
|
|
33
|
+
*
|
|
34
|
+
* @param crewlyHome - CREWLY_HOME
|
|
35
|
+
* @returns The store
|
|
36
|
+
*/
|
|
37
|
+
static inHome(crewlyHome) {
|
|
38
|
+
return new DecisionStore(path.join(crewlyHome, DECISION_CONSTANTS.STORE_FILENAME));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Add a decision, assigning its id.
|
|
42
|
+
*
|
|
43
|
+
* @param draft - Decision without id/timestamps
|
|
44
|
+
* @returns The stored decision
|
|
45
|
+
*/
|
|
46
|
+
async create(draft) {
|
|
47
|
+
return this.serial(async () => {
|
|
48
|
+
const data = await this.load();
|
|
49
|
+
const at = this.now().toISOString();
|
|
50
|
+
const decision = { ...draft, id: `${DECISION_CONSTANTS.ID_PREFIX}${data.nextId}`, createdAt: at, updatedAt: at };
|
|
51
|
+
data.nextId += 1;
|
|
52
|
+
data.decisions.push(decision);
|
|
53
|
+
await this.save();
|
|
54
|
+
return { ...decision };
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Change a decision under the write lock.
|
|
59
|
+
*
|
|
60
|
+
* @param id - Decision id
|
|
61
|
+
* @param fn - Returns the patch, or null to leave it alone
|
|
62
|
+
* @returns The updated decision, or null when missing / unchanged
|
|
63
|
+
*/
|
|
64
|
+
async update(id, fn) {
|
|
65
|
+
return this.serial(async () => {
|
|
66
|
+
const data = await this.load();
|
|
67
|
+
const idx = data.decisions.findIndex((d) => d.id === id);
|
|
68
|
+
if (idx < 0)
|
|
69
|
+
return null;
|
|
70
|
+
const patch = fn({ ...data.decisions[idx] });
|
|
71
|
+
if (!patch)
|
|
72
|
+
return null;
|
|
73
|
+
const next = { ...data.decisions[idx], ...patch, updatedAt: this.now().toISOString() };
|
|
74
|
+
data.decisions[idx] = next;
|
|
75
|
+
await this.save();
|
|
76
|
+
return { ...next };
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* One decision.
|
|
81
|
+
*
|
|
82
|
+
* @param id - Decision id
|
|
83
|
+
* @returns Copy, or null
|
|
84
|
+
*/
|
|
85
|
+
async get(id) {
|
|
86
|
+
const data = await this.load();
|
|
87
|
+
const d = data.decisions.find((x) => x.id === id);
|
|
88
|
+
return d ? { ...d } : null;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* All decisions, newest first, optionally filtered.
|
|
92
|
+
*
|
|
93
|
+
* @param filter - Predicate
|
|
94
|
+
* @returns Copies
|
|
95
|
+
*/
|
|
96
|
+
async list(filter) {
|
|
97
|
+
const data = await this.load();
|
|
98
|
+
return data.decisions
|
|
99
|
+
.filter((d) => !filter || filter(d))
|
|
100
|
+
.map((d) => ({ ...d }))
|
|
101
|
+
.sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt) || b.id.localeCompare(a.id, undefined, { numeric: true }));
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The open decision whose card is this message (or whose thread this is).
|
|
105
|
+
*
|
|
106
|
+
* @param slackChannelId - Channel
|
|
107
|
+
* @param ts - Card ts or thread ts
|
|
108
|
+
* @returns Decision, or null
|
|
109
|
+
*/
|
|
110
|
+
async findByCard(slackChannelId, ts) {
|
|
111
|
+
const data = await this.load();
|
|
112
|
+
const d = data.decisions.find((x) => x.card?.slackChannelId === slackChannelId && x.card.messageTs === ts);
|
|
113
|
+
return d ? { ...d } : null;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Drop settled decisions older than the keep window.
|
|
117
|
+
*
|
|
118
|
+
* @returns How many were dropped
|
|
119
|
+
*/
|
|
120
|
+
async prune() {
|
|
121
|
+
return this.serial(async () => {
|
|
122
|
+
const data = await this.load();
|
|
123
|
+
const cutoff = this.now().getTime() - DECISION_CONSTANTS.RESOLVED_KEEP_MS;
|
|
124
|
+
const before = data.decisions.length;
|
|
125
|
+
data.decisions = data.decisions.filter((d) => PENDING_DECISION_STATUSES.has(d.status) || Date.parse(d.updatedAt) >= cutoff);
|
|
126
|
+
const dropped = before - data.decisions.length;
|
|
127
|
+
if (dropped > 0)
|
|
128
|
+
await this.save();
|
|
129
|
+
return dropped;
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
async load() {
|
|
133
|
+
if (this.data)
|
|
134
|
+
return this.data;
|
|
135
|
+
const raw = await safeReadJson(this.filePath, {});
|
|
136
|
+
const decisions = Array.isArray(raw.decisions) ? raw.decisions : [];
|
|
137
|
+
const maxId = decisions.reduce((m, d) => Math.max(m, Number(String(d.id).replace(DECISION_CONSTANTS.ID_PREFIX, '')) || 0), 0);
|
|
138
|
+
this.data = { nextId: Math.max(Number(raw.nextId) || 1, maxId + 1), decisions };
|
|
139
|
+
return this.data;
|
|
140
|
+
}
|
|
141
|
+
async save() {
|
|
142
|
+
if (this.data)
|
|
143
|
+
await atomicWriteJson(this.filePath, this.data);
|
|
144
|
+
}
|
|
145
|
+
serial(fn) {
|
|
146
|
+
const next = this.chain.then(fn, fn);
|
|
147
|
+
this.chain = next.catch(() => undefined);
|
|
148
|
+
return next;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=decision-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decision-store.js","sourceRoot":"","sources":["../../../../../../backend/src/services/decisions/decision-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAS7E,4CAA4C;AAC5C,MAAM,CAAC,MAAM,yBAAyB,GAAyC,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;AAE3G;;GAEG;AACH,MAAM,OAAO,aAAa;IASL;IACA;IATX,IAAI,GAAwB,IAAI,CAAC;IACjC,KAAK,GAAqB,OAAO,CAAC,OAAO,EAAE,CAAC;IAEpD;;;OAGG;IACH,YACmB,QAAgB,EAChB,MAAkB,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE;QADlC,aAAQ,GAAR,QAAQ,CAAQ;QAChB,QAAG,GAAH,GAAG,CAA+B;IAClD,CAAC;IAEJ;;;;;OAKG;IACH,MAAM,CAAC,MAAM,CAAC,UAAkB;QAC9B,OAAO,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,cAAc,CAAC,CAAC,CAAC;IACrF,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,MAAM,CAAC,KAA4D;QACvE,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;YAC5B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YAC/B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAkB,EAAE,GAAG,KAAK,EAAE,EAAE,EAAE,GAAG,kBAAkB,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;YAChI,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YACjB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC9B,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,CAAC,EAAU,EAAE,EAAuD;QAC9E,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;YAC5B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YACzD,IAAI,GAAG,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;YACzB,MAAM,KAAK,GAAG,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC7C,IAAI,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAC;YACxB,MAAM,IAAI,GAAkB,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;YACtG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YAC3B,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC;QACrB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,GAAG,CAAC,EAAU;QAClB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAClD,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7B,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,IAAI,CAAC,MAAsC;QAC/C,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,SAAS;aAClB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;aACnC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;aACtB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACjI,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,UAAU,CAAC,cAAsB,EAAE,EAAU;QACjD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,cAAc,KAAK,cAAc,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;QAC3G,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;YAC5B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,GAAG,kBAAkB,CAAC,gBAAgB,CAAC;YAC1E,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;YACrC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,yBAAyB,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,CAAC;YAC5H,MAAM,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;YAC/C,IAAI,OAAO,GAAG,CAAC;gBAAE,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YACnC,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC,IAAI,CAAC;QAChC,MAAM,GAAG,GAAG,MAAM,YAAY,CAAwB,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACzE,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9H,IAAI,CAAC,IAAI,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;QAChF,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,IAAI,CAAC,IAAI;YAAE,MAAM,eAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACjE,CAAC;IAEO,MAAM,CAAI,EAAoB;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|