@opencxh/domain 1.191.0 → 1.193.0
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/dist/entities/activity/descriptor.d.ts +1 -1
- package/dist/entities/analytics/dashboard.d.ts +0 -15
- package/dist/entities/analytics/source.d.ts +2 -1
- package/dist/entities/interaction/attention.d.ts +4 -2
- package/dist/entities/interaction/types.d.ts +2 -1
- package/dist/entities/memory/kind.d.ts +1 -1
- package/dist/entities/onboarding/source.d.ts +1 -1
- package/dist/entities/onboarding/types.d.ts +1 -1
- package/dist/entities/playbook/assignment.d.ts +1 -1
- package/dist/index.cjs +8 -8
- package/dist/index.js +739 -711
- package/dist/platform/ai-tools.d.ts +9 -0
- package/dist/platform/assist-source.d.ts +62 -57
- package/dist/platform/attention.d.ts +19 -8
- package/dist/platform/localization.d.ts +20 -0
- package/dist/platform/notification.d.ts +3 -15
- package/package.json +1 -1
|
@@ -38,6 +38,15 @@ export interface ToolCatalogEntry {
|
|
|
38
38
|
/** internal | outward as the tool declares it; absent = outward. */
|
|
39
39
|
effect?: "internal" | "outward";
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Can this tool reach outside the building? A read never does; an `effect: "internal"` write says
|
|
43
|
+
* so itself. Everything else — including a tool that declares neither — counts as outward, so a
|
|
44
|
+
* forgotten declaration costs a tool for the turn rather than quietly sending a mail.
|
|
45
|
+
*/
|
|
46
|
+
export declare function isOutwardTool(tool: {
|
|
47
|
+
access?: "read" | "write";
|
|
48
|
+
effect?: "internal" | "outward";
|
|
49
|
+
}): boolean;
|
|
41
50
|
/** A model's request to call a tool. */
|
|
42
51
|
export interface AiToolCall {
|
|
43
52
|
id: string;
|
|
@@ -1,99 +1,104 @@
|
|
|
1
|
-
import { LocaleBundle } from '
|
|
2
|
-
import { NotificationText } from './notification';
|
|
1
|
+
import { LocaleBundle, LocalizedText } from './localization';
|
|
3
2
|
/**
|
|
4
|
-
* Role group of an app that reports what currently needs someone's attention.
|
|
5
|
-
*
|
|
6
|
-
* A constant and not a literal at both ends: `Bridge.providers.list` answers an unknown group
|
|
7
|
-
* with an empty list, so a typo would read as "nothing needs attention".
|
|
3
|
+
* Role group of an app that reports what currently needs someone's attention. A constant, not a
|
|
4
|
+
* literal: `Bridge.providers.list` answers an unknown group with an empty list.
|
|
8
5
|
*/
|
|
9
6
|
export declare const ASSIST_SOURCE_PROVIDER_GROUP = "assist-source";
|
|
10
7
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* first reply is worse than an unread newsletter, and only `apps/work` knows that `closedAt`
|
|
15
|
-
* and not a status name decides whether an item is done. A hub that scored this itself would
|
|
16
|
-
* need every app's types.
|
|
8
|
+
* How urgent a nudge is, across sources. `blocking` = nothing moves until you answer (an approval),
|
|
9
|
+
* `due` = a deadline is here or past (SLA, overdue), `open` = everything else. The hub orders by
|
|
10
|
+
* band first, then `priority` within the band, so no source has to calibrate against another.
|
|
17
11
|
*/
|
|
18
|
-
export
|
|
12
|
+
export declare const ASSIST_BANDS: readonly ["blocking", "due", "open"];
|
|
13
|
+
export type AssistBand = (typeof ASSIST_BANDS)[number];
|
|
14
|
+
/** What a source gets to say about one thing: the same texts, whether nudge or starter. */
|
|
15
|
+
interface AssistRanked {
|
|
19
16
|
/** `<app>.<thing>` — the prefix is the owner, as with memory kinds and dossier keys. */
|
|
20
17
|
id: string;
|
|
21
|
-
/**
|
|
22
|
-
|
|
18
|
+
/** Absent counts as `"open"`. */
|
|
19
|
+
band?: AssistBand;
|
|
20
|
+
/** Rank within the band; higher sorts earlier. */
|
|
21
|
+
priority?: number;
|
|
23
22
|
/** Lucide icon name. */
|
|
24
23
|
icon?: string;
|
|
25
|
-
/** One line, in the owner's words. */
|
|
26
|
-
text: NotificationText;
|
|
27
24
|
/** The assignment that handles this — fills the launcher, or the agent's procedure. */
|
|
28
|
-
ask:
|
|
29
|
-
|
|
25
|
+
ask: LocalizedText;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* One thing that needs attention now, declared by the app that owns it. Only comms knows that an
|
|
29
|
+
* unanswered first reply outranks an unread newsletter; a hub scoring this itself would need every
|
|
30
|
+
* app's types. All texts are bare i18n keys; the hub stamps the source's namespace.
|
|
31
|
+
*/
|
|
32
|
+
export interface AssistNudge extends AssistRanked {
|
|
33
|
+
/** Short label: "SLA", "Over tijd". */
|
|
34
|
+
tag: LocalizedText;
|
|
35
|
+
/** One line, in the owner's words. */
|
|
36
|
+
text: LocalizedText;
|
|
37
|
+
/** What it is about, as `<kind>:<ref>`. Also the scope the queue's composer writes to. */
|
|
30
38
|
subjectKey?: string;
|
|
31
|
-
/**
|
|
32
|
-
priority?: number;
|
|
33
|
-
/**
|
|
34
|
-
* Where "open it" goes. `/…` follows the kernel router, `https://…` opens a tab — the same
|
|
35
|
-
* convention `AiToolResult.sources` uses.
|
|
36
|
-
*/
|
|
39
|
+
/** Where "open it" goes: `/…` follows the kernel router, `https://…` opens a tab. */
|
|
37
40
|
url?: string;
|
|
38
41
|
/**
|
|
39
|
-
* Where "later" posts `{ remindAt }`, as an invoke action
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* The owner names the route rather than the board deriving one, because parking checks the
|
|
43
|
-
* resource's own ACL and only the owning app has it. A source without such a route omits this
|
|
44
|
-
* and simply gets no "later" button — better than a button that always fails.
|
|
42
|
+
* Where "later" posts `{ remindAt }`, as an invoke action. The owner names the route because
|
|
43
|
+
* parking checks the resource's own ACL. Absent = no "later" button, which beats one that fails.
|
|
45
44
|
*/
|
|
46
45
|
snoozeAction?: string;
|
|
46
|
+
/** Where "done" posts, as an invoke action. Same rule as `snoozeAction`. */
|
|
47
|
+
resolveAction?: string;
|
|
47
48
|
/**
|
|
48
49
|
* Federated resource that draws this nudge's body in the queue, as `"<app>:<Component>"`.
|
|
49
|
-
*
|
|
50
|
-
* Absent = the queue falls back to `text` plus a button to `url`, so a source that never
|
|
51
|
-
* adopts this keeps working. The component is handed `{ nudge, onHandled }`.
|
|
50
|
+
* Handed {@link AssistCardProps}. Absent = the queue falls back to `text` plus a button to `url`.
|
|
52
51
|
*/
|
|
53
52
|
resource?: string;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
}
|
|
54
|
+
/** What a nudge's federated body receives. */
|
|
55
|
+
export interface AssistCardProps {
|
|
56
|
+
nudge: AssistNudge;
|
|
57
|
+
/** The body handled the card itself (a reply went out); the queue moves on. */
|
|
58
|
+
onHandled: () => void;
|
|
60
59
|
}
|
|
61
60
|
/** A fixed starting point, offered even when nothing needs attention. */
|
|
62
|
-
export interface AssistStarter {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
sub?: NotificationText;
|
|
66
|
-
icon?: string;
|
|
67
|
-
ask: NotificationText;
|
|
61
|
+
export interface AssistStarter extends AssistRanked {
|
|
62
|
+
label: LocalizedText;
|
|
63
|
+
sub?: LocalizedText;
|
|
68
64
|
/**
|
|
69
|
-
* Whether this sets an agent to work or just asks something. The source knows
|
|
70
|
-
*
|
|
71
|
-
* from the wording is the classify step the launcher deliberately does not have. Absent
|
|
72
|
-
* counts as `"task"`: a nudge is always something to be done.
|
|
65
|
+
* Whether this sets an agent to work or just asks something. The source knows; guessing it from
|
|
66
|
+
* the wording is the classify step the launcher deliberately does not have. Absent = `"task"`.
|
|
73
67
|
*/
|
|
74
68
|
mode?: "chat" | "task";
|
|
75
69
|
}
|
|
76
70
|
/**
|
|
77
|
-
* Bare payload of `GET /provider/assist/describe` — not wrapped in `ResponseFactory`,
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* User-scoped: the hub calls it with an acting identity, because a nudge is per person.
|
|
71
|
+
* Bare payload of `GET /provider/assist/describe` — not wrapped in `ResponseFactory`, like every
|
|
72
|
+
* fan-out describe in this repo. User-scoped: the hub calls it with an acting identity.
|
|
81
73
|
*/
|
|
82
74
|
export interface AssistSourceDescribe {
|
|
83
|
-
/** The declaring app
|
|
75
|
+
/** The declaring app. A label: the hub namespaces on which provider actually answered. */
|
|
84
76
|
source: string;
|
|
85
77
|
nudges: AssistNudge[];
|
|
86
78
|
starters: AssistStarter[];
|
|
87
79
|
/** Texts for every key above, in every language this app ships. `flattenLocales()` helps. */
|
|
88
80
|
locales?: LocaleBundle;
|
|
81
|
+
/**
|
|
82
|
+
* This app's own SSE event names that can change the rows above, so the board refreshes on a
|
|
83
|
+
* push. Bare names, matched against `SSEMessage.payload.event` exactly as pushed.
|
|
84
|
+
*/
|
|
85
|
+
refreshOn?: string[];
|
|
89
86
|
}
|
|
90
87
|
/** Every source's answer, merged. */
|
|
91
88
|
export interface AssistBoard {
|
|
92
89
|
nudges: AssistNudge[];
|
|
93
90
|
starters: AssistStarter[];
|
|
94
|
-
/** Which apps answered. */
|
|
95
|
-
sources: string[];
|
|
96
91
|
locales: LocaleBundle;
|
|
97
92
|
/** Apps that answered nothing. Silence is not an answer, so it is named. */
|
|
98
93
|
degradedApps: string[];
|
|
94
|
+
/**
|
|
95
|
+
* Which app's realtime events invalidate this board, as app name -> event names. Assembled by
|
|
96
|
+
* the hub because the client cannot know its sources at build time.
|
|
97
|
+
*/
|
|
98
|
+
refreshOn: Record<string, string[]>;
|
|
99
99
|
}
|
|
100
|
+
/** The `<ref>` of a nudge's `subjectKey` when it is of `kind`, else `undefined`. */
|
|
101
|
+
export declare function subjectRef(nudge: Pick<AssistNudge, "subjectKey">, kind: string): string | undefined;
|
|
102
|
+
/** Band, then priority, then id — so two equal rows never reshuffle between reads. */
|
|
103
|
+
export declare function compareAssistRank(a: AssistRanked, b: AssistRanked): number;
|
|
104
|
+
export {};
|
|
@@ -1,23 +1,32 @@
|
|
|
1
|
+
import { ResourceReminder } from '../entities/resource-reminder/types';
|
|
1
2
|
/**
|
|
2
3
|
* The primitives both attention scorers share.
|
|
3
4
|
*
|
|
4
5
|
* Here rather than in one of them, so `apps/work` can score its items without importing
|
|
5
6
|
* interaction types and vice versa: each app owns one half and neither owns the other.
|
|
6
7
|
*/
|
|
7
|
-
|
|
8
|
+
export declare const HOUR_MS = 3600000;
|
|
9
|
+
export declare const DAY_MS = 86400000;
|
|
10
|
+
/** Score of something that must not surface at all. Filter with {@link isEligible}. */
|
|
8
11
|
export declare const INELIGIBLE: number;
|
|
12
|
+
export declare const isEligible: (scored: {
|
|
13
|
+
score: number;
|
|
14
|
+
}) => boolean;
|
|
15
|
+
export type Priority = "urgent" | "high" | "normal" | "low";
|
|
9
16
|
/** Priority weight, shared by interactions and work items. */
|
|
10
|
-
export declare const W_PRIORITY: Record<
|
|
17
|
+
export declare const W_PRIORITY: Record<Priority, number>;
|
|
18
|
+
/**
|
|
19
|
+
* Every contributor a scorer may name. A closed union, because the assist sources map these to
|
|
20
|
+
* nudge tags: a reason renamed here fails to compile there instead of silently falling through.
|
|
21
|
+
*/
|
|
22
|
+
export type AttentionReason = `priority:${Priority}` | "unseen" | "assigned-to-you" | `waiting:${number}h` | "awaiting-approval" | "no-reply" | "awaiting-reply" | "bulk" | "overdue" | "due-today" | `auto:${string}`;
|
|
11
23
|
export interface Scored {
|
|
12
24
|
score: number;
|
|
13
|
-
/**
|
|
14
|
-
reasons:
|
|
25
|
+
/** Contributors in insertion order. Drives the tag on an assist nudge. */
|
|
26
|
+
reasons: AttentionReason[];
|
|
15
27
|
}
|
|
16
28
|
/** One user's own "later" mark on a resource, as both scorers read it. */
|
|
17
|
-
export
|
|
18
|
-
remindAt: number;
|
|
19
|
-
parkedAt: number;
|
|
20
|
-
}
|
|
29
|
+
export type ParkMark = Pick<ResourceReminder, "remindAt" | "parkedAt">;
|
|
21
30
|
export interface AttentionCtx {
|
|
22
31
|
/** Whose attention. Drives the unseen + assigned-to-me boosts. */
|
|
23
32
|
userId: string;
|
|
@@ -26,3 +35,5 @@ export interface AttentionCtx {
|
|
|
26
35
|
/** Personally parked: resourceId -> own mark. */
|
|
27
36
|
remindersById?: Record<string, ParkMark>;
|
|
28
37
|
}
|
|
38
|
+
/** Index one user's reminders the way `AttentionCtx.remindersById` wants them. */
|
|
39
|
+
export declare function parkMarksById(reminders: readonly ResourceReminder[]): Record<string, ParkMark>;
|
|
@@ -4,4 +4,24 @@ type Prev = [never, 0, 1, 2, 3, 4, 5, ...0[]];
|
|
|
4
4
|
export type Paths<T, D extends number = 5> = [D] extends [never] ? never : T extends object ? {
|
|
5
5
|
[K in keyof T]-?: K extends string | number ? T[K] extends object ? `${K}` | `${K}.${Paths<T[K], Prev[D]>}` : `${K}` : never;
|
|
6
6
|
}[keyof T] : "";
|
|
7
|
+
/**
|
|
8
|
+
* An i18n reference as federated describes ship it: a bare key plus its variables. The hub that
|
|
9
|
+
* receives it stamps the source's namespace (`qualifyText` in platform-api).
|
|
10
|
+
*/
|
|
11
|
+
export interface LocalizedText {
|
|
12
|
+
key: string;
|
|
13
|
+
vars?: Record<string, string | number>;
|
|
14
|
+
}
|
|
15
|
+
export interface LocaleString {
|
|
16
|
+
lang: string;
|
|
17
|
+
key: string;
|
|
18
|
+
value: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Flat list, not a nested map: every consumer already iterates it. Kept flat since the http key
|
|
22
|
+
* transform that once forced it was removed (2026-08-17).
|
|
23
|
+
*/
|
|
24
|
+
export type LocaleBundle = LocaleString[];
|
|
25
|
+
/** Authoring convenience: turn a nested { lang: { key: value } } map into a LocaleBundle. */
|
|
26
|
+
export declare function flattenLocales(nested: Record<string, Record<string, string>>): LocaleBundle;
|
|
7
27
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LocaleBundle } from '
|
|
1
|
+
import { LocaleBundle, LocalizedText } from './localization';
|
|
2
2
|
/**
|
|
3
3
|
* Role group of an app that declares its own notification kinds.
|
|
4
4
|
*
|
|
@@ -7,20 +7,8 @@ import { LocaleBundle } from '../entities/analytics/dashboard';
|
|
|
7
7
|
* `ONBOARDING_SOURCE_PROVIDER_GROUP` is a constant.
|
|
8
8
|
*/
|
|
9
9
|
export declare const NOTIFICATION_SOURCE_PROVIDER_GROUP = "notification-source";
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
-
* app's own bundle, plus values for `{name}` placeholders.
|
|
13
|
-
*
|
|
14
|
-
* Not a rendered string, because one notification is read on a laptop in Dutch and pushed to a
|
|
15
|
-
* phone in English. Not a bare key either: half of these lines carry data ("Vincent mentioned you")
|
|
16
|
-
* and a key per person does not exist.
|
|
17
|
-
*
|
|
18
|
-
* Sources write **bare** keys; the hub stamps the namespace (see `qualifyText` in platform-api).
|
|
19
|
-
*/
|
|
20
|
-
export interface NotificationText {
|
|
21
|
-
key: string;
|
|
22
|
-
vars?: Record<string, string | number>;
|
|
23
|
-
}
|
|
10
|
+
/** Alias of {@link LocalizedText}: sources write bare keys, the hub stamps the namespace. */
|
|
11
|
+
export type NotificationText = LocalizedText;
|
|
24
12
|
/**
|
|
25
13
|
* One switchable kind of notification, declared by the app that sends it.
|
|
26
14
|
*
|