@company-semantics/contracts 58.1.0 → 58.3.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.
Files changed (40) hide show
  1. package/package.json +1 -1
  2. package/src/__tests__/resource-keys.test.ts +30 -0
  3. package/src/api/generated-spec-hash.ts +2 -2
  4. package/src/api/generated.ts +77 -1
  5. package/src/chat/README.md +15 -4
  6. package/src/chat/__tests__/proactive-kind.test.ts +51 -0
  7. package/src/chat/index.ts +9 -0
  8. package/src/chat/proactive-kind.ts +51 -0
  9. package/src/chat/schemas.ts +92 -1
  10. package/src/chat/types.ts +19 -1
  11. package/src/generated/openapi-routes.ts +1 -0
  12. package/src/index.ts +58 -0
  13. package/src/message-parts/README.md +5 -0
  14. package/src/message-parts/__tests__/suggested-replies.test.ts +52 -0
  15. package/src/message-parts/__tests__/wire.test.ts +48 -0
  16. package/src/message-parts/index.ts +8 -0
  17. package/src/message-parts/suggested-replies.ts +48 -0
  18. package/src/message-parts/types.ts +7 -1
  19. package/src/message-parts/wire.ts +26 -0
  20. package/src/proactive/README.md +125 -0
  21. package/src/proactive/__tests__/README.md +56 -0
  22. package/src/proactive/__tests__/chat-templates.test.ts +167 -0
  23. package/src/proactive/__tests__/compile-fixtures.ts +110 -0
  24. package/src/proactive/__tests__/vocabulary.test.ts +279 -0
  25. package/src/proactive/classes.ts +125 -0
  26. package/src/proactive/composer.ts +104 -0
  27. package/src/proactive/facts.ts +87 -0
  28. package/src/proactive/index.ts +52 -0
  29. package/src/proactive/kinds.ts +127 -0
  30. package/src/proactive/plan.ts +79 -0
  31. package/src/proactive/registry.ts +71 -0
  32. package/src/proactive/surfaces.ts +59 -0
  33. package/src/proactive/templates/README.md +58 -0
  34. package/src/proactive/templates/index.ts +32 -0
  35. package/src/proactive/templates/morning-brief.ts +77 -0
  36. package/src/proactive/templates/org-became-shared.ts +54 -0
  37. package/src/resource-key-types.ts +9 -0
  38. package/src/resource-keys.ts +2 -0
  39. package/src/user-notifications/README.md +10 -0
  40. package/src/user-notifications/kinds.ts +28 -0
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The org-became-shared pushed chat — the first invited person accepted, so
3
+ * the owner's personal workspace is now a shared one (ADR-CONTRACTS-142).
4
+ *
5
+ * The prose NAMES THE RELOCATION, and that is its job. The app ADR with slug
6
+ * `nav-posture-opens-on-invite-send` established that conversion is a
7
+ * relocation, not an addition: five sections leave My settings (Integrations,
8
+ * Invite team members, AI Usage, Budget, Billing) and reappear under Org
9
+ * settings. Unannounced, that reads as things going missing — and a banner
10
+ * can say "something moved" but not walk the owner through what and why.
11
+ * This chat is where that explanation lives, and the chips let the owner ask
12
+ * the question the banner cannot answer.
13
+ *
14
+ * FROZEN AT WRITE TIME (INV-PROACTIVE-CONTENT). Both interpolated facts are
15
+ * things the owner was entitled to at compose time: they named the org, and
16
+ * they invited the person who accepted. Nothing here can be revoked later in
17
+ * a way the transcript would have to take back.
18
+ */
19
+
20
+ import type { ProactiveChatComposer } from "../composer";
21
+
22
+ export const orgBecameSharedComposer: ProactiveChatComposer<"orgBecameShared"> =
23
+ {
24
+ template: "orgBecameShared",
25
+ compose: (facts) => ({
26
+ title: "Your workspace is now shared",
27
+ text:
28
+ `${facts.joinerDisplayName} accepted your invite, so ${facts.orgName} ` +
29
+ `moved from a personal workspace to a shared one.\n\n` +
30
+ `This is a relocation, not an addition: Integrations, Invite team ` +
31
+ `members, AI Usage, Budget and Billing have moved out of My settings ` +
32
+ `and into Org settings. Nothing was removed — the five sections now ` +
33
+ `belong to the workspace rather than to you.`,
34
+ replies: [
35
+ {
36
+ id: "plain-english",
37
+ label: "Explain in plain English",
38
+ prompt:
39
+ "Explain in plain English what changed when my workspace became shared.",
40
+ },
41
+ {
42
+ id: "what-first",
43
+ label: "What should I set up first?",
44
+ prompt:
45
+ "Now that my workspace is shared, what should I set up first?",
46
+ },
47
+ {
48
+ id: "who-can-see",
49
+ label: "Who can see what now?",
50
+ prompt: "Who can see what in my workspace now that it is shared?",
51
+ },
52
+ ],
53
+ }),
54
+ };
@@ -150,6 +150,15 @@ export type ResourceKey =
150
150
  // every badge in the shell, and the two have different invalidation triggers
151
151
  // (a notification being READ changes the feed and not the bucket).
152
152
  | { type: "feed"; orgId: string }
153
+ /**
154
+ * Org system events (the banner strip).
155
+ *
156
+ * Lives HERE and not in the app's `AppOnlyKey` union, whose doc bar is "the
157
+ * server can never need to name this key" — here the server is the publisher.
158
+ * Once the banner is an asynchronous projection, an unsubscribed hook means a
159
+ * banner that only appears on next mount or reload.
160
+ */
161
+ | { type: "orgSystemEvents"; orgId: string }
153
162
  // User-scoped
154
163
  | { type: "dismissedBanners"; userId: string }
155
164
  | { type: "userOrgs"; userId: string }
@@ -147,6 +147,7 @@ const ORG_SCOPED_TYPES = [
147
147
  "orgUnitOwners",
148
148
  "actionItems",
149
149
  "feed",
150
+ "orgSystemEvents",
150
151
  ] as const satisfies readonly OrgScopedType[];
151
152
 
152
153
  const USER_SCOPED_TYPES = [
@@ -285,6 +286,7 @@ export function toQueryKey(key: ResourceKey): readonly string[] {
285
286
  case "orgUnitOwners":
286
287
  case "actionItems":
287
288
  case "feed":
289
+ case "orgSystemEvents":
288
290
  return [key.type, key.orgId] as const;
289
291
 
290
292
  // System-scoped (ADR-CONTRACTS-052) — tenant-less super-admin resources
@@ -33,6 +33,16 @@ that renders them alongside action items at the top of `/me/work`.
33
33
  - **The cursor encodes `(createdAt, id)`.** The id breaks ties so two rows
34
34
  written in one transaction cannot straddle a page boundary and be served twice
35
35
  or skipped.
36
+ - **A row can be BORN READ.** Every proactive kind writes a durable row here
37
+ as its paper trail, but only the class whose badge carrier is `inbox` writes
38
+ it unread; `proactive.org_became_shared` is an `announcement`, so the banner
39
+ holds the badge and the row arrives read, and `proactive.brief_morning` is a
40
+ `briefing`, so the pushed chat holds the badge and the row arrives read. That
41
+ rule is stated once, in `bornRead` (`../proactive/classes`), never re-derived
42
+ per call site (ADR-CONTRACTS-142). The kind strings are `proactive.*` — the
43
+ producing domain owns the renderer — and are deliberately not the
44
+ `ProactiveEventKind` strings `org.became_shared` / `brief.morning`, so
45
+ neither union can quietly become derived from the other.
36
46
 
37
47
  ## Public API
38
48
 
@@ -76,6 +76,34 @@ export const USER_NOTIFICATION_KINDS = [
76
76
  "comment.mention",
77
77
  /** A thread you took part in got a new comment. Never emitted for an edit. */
78
78
  "comment.reply",
79
+ /**
80
+ * Your org stopped being personal — its first member joined
81
+ * (ADR-CONTRACTS-142). The durable row of the `org.became_shared` proactive
82
+ * kind.
83
+ *
84
+ * BORN READ: the banner holds the badge for an `announcement`, so this row
85
+ * is the paper trail and never the attention carrier (`bornRead` in
86
+ * `../proactive/classes` is the one place that rule is stated). The
87
+ * producing domain in the string is `proactive` — `src/proactive/` in the
88
+ * backend owns the renderer, matching the `companyMd.*` / `comment.*`
89
+ * convention. The string is deliberately DISTINCT from the proactive kind's
90
+ * `org.became_shared`: identical names across two unions is how one quietly
91
+ * becomes derived from the other, which ADR-CONT-108 forbids.
92
+ */
93
+ "proactive.org_became_shared",
94
+ /**
95
+ * Your morning brief was written (ADR-CONTRACTS-142). The durable row of
96
+ * the `brief.morning` proactive kind.
97
+ *
98
+ * BORN READ: the pushed chat holds the badge for a `briefing`, so this row
99
+ * is the paper trail and never the attention carrier (`bornRead` in
100
+ * `../proactive/classes` is the one place that rule is stated). One row per
101
+ * recipient per org-local day, pointing at that recipient's OWN chat — the
102
+ * occurrence is shared, the row and the chat are not. The string is
103
+ * deliberately DISTINCT from the proactive kind's `brief.morning`, for the
104
+ * reason stated on the member above.
105
+ */
106
+ "proactive.brief_morning",
79
107
  ] as const;
80
108
 
81
109
  export type UserNotificationKind = (typeof USER_NOTIFICATION_KINDS)[number];