@company-semantics/contracts 62.11.0 → 63.0.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.
@@ -0,0 +1,79 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * THE AGENT PRINCIPAL (control INVARIANTS.md, INV-AGENT-IDENTITY).
5
+ *
6
+ * One identity constant. The glyph is DERIVED from the handle so this package
7
+ * carries exactly one literal; the ASCII/email renderers and the app's avatar
8
+ * read it from here, never retype it.
9
+ *
10
+ * SINGLETON, BY DECISION: `{ kind: 'agent' }` carries no id because there is
11
+ * exactly one agent principal, forever. A second agent is a new decision and a
12
+ * MAJOR that adds `agentId`; nothing is pre-added now (ADR-CONTRACTS-160).
13
+ *
14
+ * NOT the ACL `Principal` in src/permissions/share-api.ts. That one names a
15
+ * GRANTEE on a share (user | unit | org, discriminated by `type`); this one
16
+ * names WHO authored an utterance or was mentioned in one (user | agent,
17
+ * discriminated by `kind`). Different axis — do not conflate or extend either
18
+ * into the other.
19
+ *
20
+ * `userId` is a bare `z.string()`, not `.uuid()`, deliberately diverging from
21
+ * the rest of this domain (Person, IdentityLink and PositionRef are all
22
+ * uuid-tight). It mirrors the comments boundary, where the shapes in this
23
+ * package mirror the backend's looseness rather than tightening past it:
24
+ * a ref that rejects an id the server considers valid is a client-side outage
25
+ * for no security gain. Do not "fix" this to `.uuid()`.
26
+ *
27
+ * Zero-dependency (zod only): every domain that speaks principals imports this
28
+ * module, so it must never import one of them back.
29
+ */
30
+ export const CS_AGENT_HANDLE = "c_S" as const;
31
+
32
+ /**
33
+ * The agent's identity, in the three forms a surface needs: the handle a
34
+ * mention is typed as, the name a chip renders, and the glyph a monospace or
35
+ * plain-text surface draws. `glyph` is a template over the handle — the single
36
+ * point of truth the renderers derive from.
37
+ */
38
+ export const CS_AGENT = {
39
+ handle: CS_AGENT_HANDLE,
40
+ displayName: CS_AGENT_HANDLE,
41
+ glyph: `[${CS_AGENT_HANDLE}]`,
42
+ } as const;
43
+
44
+ /**
45
+ * A principal: a person by id, or the one agent.
46
+ *
47
+ * STRICT on both arms, following the comment-anchor precedent: the failure
48
+ * modes worth having are real refusals, not silent coercions. A non-strict
49
+ * object would STRIP a stray `userId` off an agent ref and hand the caller a
50
+ * ref that parsed cleanly while meaning something it did not say.
51
+ */
52
+ export const PrincipalRefSchema = z.discriminatedUnion("kind", [
53
+ z.strictObject({ kind: z.literal("user"), userId: z.string() }),
54
+ z.strictObject({ kind: z.literal("agent") }),
55
+ ]);
56
+ export type PrincipalRef = z.infer<typeof PrincipalRefSchema>;
57
+
58
+ /** The one agent principal. There is no second value of this shape. */
59
+ export const AGENT_PRINCIPAL: PrincipalRef = { kind: "agent" };
60
+
61
+ /** A person as a principal. */
62
+ export function userPrincipal(userId: string): PrincipalRef {
63
+ return { kind: "user", userId };
64
+ }
65
+
66
+ /** Narrows a ref to the agent arm. */
67
+ export function isAgentPrincipal(ref: PrincipalRef): ref is { kind: "agent" } {
68
+ return ref.kind === "agent";
69
+ }
70
+
71
+ /**
72
+ * Stable key for Set/Map use: 'agent' | 'user:<id>'.
73
+ *
74
+ * The agent needs no id to be keyable precisely because it is a singleton;
75
+ * `'agent'` cannot collide with `'user:<id>'` because a user key is prefixed.
76
+ */
77
+ export function principalKey(ref: PrincipalRef): string {
78
+ return ref.kind === "agent" ? "agent" : `user:${ref.userId}`;
79
+ }
@@ -94,3 +94,17 @@ export type { Person } from "./person";
94
94
  // Identity Link — external system id → Person (provider is an open string)
95
95
  export { IdentityLinkSchema } from "./identity-link";
96
96
  export type { IdentityLink } from "./identity-link";
97
+
98
+ // Agent Principal — CS_AGENT (the one identity constant, glyph derived from the
99
+ // handle) and PrincipalRef, the only vocabulary for an author, a mention target
100
+ // or a picker candidate (ADR-CONTRACTS-160, INV-AGENT-IDENTITY).
101
+ export {
102
+ CS_AGENT,
103
+ CS_AGENT_HANDLE,
104
+ PrincipalRefSchema,
105
+ AGENT_PRINCIPAL,
106
+ userPrincipal,
107
+ isAgentPrincipal,
108
+ principalKey,
109
+ } from "./agent";
110
+ export type { PrincipalRef } from "./agent";
package/src/index.ts CHANGED
@@ -204,6 +204,20 @@ export type { Person } from "./identity/index";
204
204
  export { IdentityLinkSchema } from "./identity/index";
205
205
  export type { IdentityLink } from "./identity/index";
206
206
 
207
+ // Agent Principal — CS_AGENT and PrincipalRef (ADR-CONTRACTS-160).
208
+ // Not the ACL `Principal` in src/permissions: that names a share grantee, this
209
+ // names who authored an utterance or was mentioned in one.
210
+ export {
211
+ CS_AGENT,
212
+ CS_AGENT_HANDLE,
213
+ PrincipalRefSchema,
214
+ AGENT_PRINCIPAL,
215
+ userPrincipal,
216
+ isAgentPrincipal,
217
+ principalKey,
218
+ } from "./identity/index";
219
+ export type { PrincipalRef } from "./identity/index";
220
+
207
221
  // Auth domain types
208
222
  export type { AuthStartMode, AuthStartResponse } from "./auth/index";
209
223
  export { OTPErrorCode } from "./auth/index";
@@ -469,6 +483,8 @@ export {
469
483
  export type { SuggestionReceipt } from "./comments/index";
470
484
 
471
485
  export {
486
+ AGENT_OUTCOME_REASONS,
487
+ AgentOutcomeSchema,
472
488
  CommentAnchorSchema,
473
489
  CommentAnchorTypeSchema,
474
490
  CommentMentionSchema,
@@ -481,9 +497,11 @@ export {
481
497
  MentionableCandidateSchema,
482
498
  MentionableResponseSchema,
483
499
  SuggestionSchema,
500
+ ThreadOriginSchema,
484
501
  } from "./comments/index";
485
502
 
486
503
  export type {
504
+ AgentOutcome,
487
505
  CommentAnchor,
488
506
  CommentAnchorType,
489
507
  CommentMention,
@@ -499,6 +517,7 @@ export type {
499
517
  Suggestion,
500
518
  SuggestionOp,
501
519
  SuggestionStatus,
520
+ ThreadOrigin,
502
521
  } from "./comments/index";
503
522
 
504
523
  // Chat domain types
@@ -544,6 +563,11 @@ export type {
544
563
  // Page context (PRD-00969, ADR-CONTRACTS-153): where the reader is, as
545
564
  // identifiers. Never content, never free text.
546
565
  ChatPageContext,
566
+ // Chat mentions (ADR-CONTRACTS-160): a turn's mention rows are keyed on a
567
+ // PrincipalRef, so the agent is nameable on the chat surface too, and the
568
+ // composer's candidate list reuses the comments candidate shape.
569
+ ChatMessageMention,
570
+ ChatMentionableResponse,
547
571
  } from "./chat/index";
548
572
 
549
573
  export {
@@ -559,6 +583,11 @@ export {
559
583
  // older client reject the whole chat list; this is the ONE place it becomes
560
584
  // a ProactiveEventKind. See src/chat/proactive-kind.ts.
561
585
  recognizeProactiveKind,
586
+ // Chat mentions: the mention row a turn carries, and the composer's
587
+ // candidate envelope (items are `MentionableCandidateSchema`, imported from
588
+ // comments rather than restated).
589
+ ChatMessageMentionSchema,
590
+ ChatMentionableResponseSchema,
562
591
  } from "./chat/index";
563
592
 
564
593
  // Organization domain types
@@ -71,5 +71,11 @@ looking for it again with a regex. That is the hack this shape exists to prevent
71
71
 
72
72
  - `../../content` — `CallToAction`, `ChatTurn`, `ChatUnitItem`. Types only; this
73
73
  layer reads the vocabulary and never extends it.
74
+ - `../../../identity/agent` — `CS_AGENT`, for `AVATAR` alone. The agent has one
75
+ identity and the glyph is DERIVED from it rather than retyped here
76
+ (INV-AGENT-IDENTITY); a second copy is how the drawing and the chip quietly
77
+ drift apart. It is a value rather than a type, and it brings `zod` into this
78
+ layer's transitive imports for the first time — the price of one source of
79
+ truth, and cheap, because `zod` is already a dependency of the package.
74
80
 
75
81
  Nothing else. It knows no channel, no colour, no markup and no `Renderer`.
@@ -23,8 +23,17 @@
23
23
  * promise we are willing to keep.
24
24
  */
25
25
 
26
- /** The assistant's avatar, drawn beside the last line of its bubble. */
27
- export const AVATAR = "[c_S]";
26
+ import { CS_AGENT } from "../../../identity/agent";
27
+
28
+ /**
29
+ * The assistant's avatar, drawn beside the last line of its bubble.
30
+ *
31
+ * DERIVED from `CS_AGENT.glyph`, never retyped (INV-AGENT-IDENTITY): the agent
32
+ * has one identity and this layer reads it rather than restating it. Its LENGTH
33
+ * feeds `indent` below and therefore every box width in this directory — so a
34
+ * change to the handle re-flows the drawing, which is the intended coupling.
35
+ */
36
+ export const AVATAR = CS_AGENT.glyph;
28
37
 
29
38
  /** The recipient's avatar, drawn beside the last line of their bubble. */
30
39
  export const KAOMOJI = "(•̀_ರ╮)";
@@ -21,6 +21,7 @@
21
21
  * through it.
22
22
  */
23
23
 
24
+ import { CS_AGENT } from "../../../identity/agent";
24
25
  import type { CallToAction, ChatTurn, ChatUnitItem } from "../../content";
25
26
  import {
26
27
  ruleAscii,
@@ -95,7 +96,7 @@ function renderBubble(turn: ChatTurn, row: ChatRow): ChatPartRender {
95
96
 
96
97
  const html = `<table cellpadding="0" cellspacing="0" border="0" width="100%" ${styleClass(row)}>
97
98
  <tr>
98
- <td ${styleClass(avatar)}>[c_S]</td>
99
+ <td ${styleClass(avatar)}>${CS_AGENT.glyph}</td>
99
100
  <td ${styleClass(channel)}><table cellpadding="0" cellspacing="0" border="0" ${styleClass("chat-bubble-wrap")}>
100
101
  <tr><td ${styleClass(bubble, "bubble")}>${escapeHtml(clamped)}</td></tr>
101
102
  </table></td>
@@ -130,7 +131,7 @@ function renderChatCta(
130
131
  const stack = `<div ${styleClass("cta-stack")}>${withDots ? dotsOverCtaHtml() : ""}${btnHtml}</div>`;
131
132
  const html = `<table cellpadding="0" cellspacing="0" border="0" width="100%" ${styleClass("chat-row-24")}>
132
133
  <tr>
133
- <td ${styleClass("chat-avatar-left-hidden")}>[c_S]</td>
134
+ <td ${styleClass("chat-avatar-left-hidden")}>${CS_AGENT.glyph}</td>
134
135
  <td ${styleClass(`chat-channel-${align}`)}>${stack}</td>
135
136
  <td ${styleClass("chat-avatar-right-hidden")}>(•̀_ರ╮)</td>
136
137
  </tr>
@@ -150,7 +151,7 @@ function renderChatCta(
150
151
  function renderChatDots(): ChatPartRender {
151
152
  const html = `<table cellpadding="0" cellspacing="0" border="0" width="100%" ${styleClass("chat-row-16")}>
152
153
  <tr>
153
- <td ${styleClass("chat-avatar-left-hidden")}>[c_S]</td>
154
+ <td ${styleClass("chat-avatar-left-hidden")}>${CS_AGENT.glyph}</td>
154
155
  <td ${styleClass("dots-cell", "dots")}>⋮</td>
155
156
  <td ${styleClass("chat-avatar-right-hidden")}>(•̀_ರ╮)</td>
156
157
  </tr>