@company-semantics/contracts 0.93.0 → 0.95.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@company-semantics/contracts",
3
- "version": "0.93.0",
3
+ "version": "0.95.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,55 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { CHAT_RUNTIME_PROFILES, DEFAULT_CHAT_RUNTIME_PROFILE } from '../runtime-profile.js'
3
+
4
+ describe('CHAT_RUNTIME_PROFILES golden snapshot', () => {
5
+ it('exact values are frozen', () => {
6
+ expect(CHAT_RUNTIME_PROFILES).toStrictEqual([
7
+ { id: 'fast', label: 'Fast', description: 'Single-step, no tools', model: 'gpt-3.5-turbo' },
8
+ { id: 'balanced', label: 'Balanced', description: 'Multi-step with tools', model: 'gpt-4o' },
9
+ { id: 'agentic', label: 'Agentic', description: 'Agent loop, full reasoning', model: 'claude-sonnet-4-20250514' },
10
+ ])
11
+ })
12
+ })
13
+
14
+ describe('CHAT_RUNTIME_PROFILES invariants', () => {
15
+ it('covers all ChatRuntimeProfile values', () => {
16
+ const ids = CHAT_RUNTIME_PROFILES.map(p => p.id)
17
+ expect(ids).toContain('fast')
18
+ expect(ids).toContain('balanced')
19
+ expect(ids).toContain('agentic')
20
+ })
21
+
22
+ it('has no duplicate profile IDs', () => {
23
+ const ids = CHAT_RUNTIME_PROFILES.map(p => p.id)
24
+ expect(new Set(ids).size).toBe(ids.length)
25
+ })
26
+
27
+ it('all entries have non-empty label and description', () => {
28
+ for (const profile of CHAT_RUNTIME_PROFILES) {
29
+ expect(profile.label.length).toBeGreaterThan(0)
30
+ expect(profile.description.length).toBeGreaterThan(0)
31
+ }
32
+ })
33
+
34
+ it('all entries have non-empty model strings', () => {
35
+ for (const profile of CHAT_RUNTIME_PROFILES) {
36
+ expect(profile.model.length).toBeGreaterThan(0)
37
+ }
38
+ })
39
+ })
40
+
41
+ describe('DEFAULT_CHAT_RUNTIME_PROFILE', () => {
42
+ it('is agentic', () => {
43
+ expect(DEFAULT_CHAT_RUNTIME_PROFILE).toBe('agentic')
44
+ })
45
+
46
+ it('exists in CHAT_RUNTIME_PROFILES', () => {
47
+ const ids = CHAT_RUNTIME_PROFILES.map(p => p.id)
48
+ expect(ids).toContain(DEFAULT_CHAT_RUNTIME_PROFILE)
49
+ })
50
+
51
+ it('is a valid ChatRuntimeProfile value', () => {
52
+ const validIds = CHAT_RUNTIME_PROFILES.map(p => p.id) as readonly string[]
53
+ expect(validIds).toContain(DEFAULT_CHAT_RUNTIME_PROFILE)
54
+ })
55
+ })
@@ -172,7 +172,7 @@ describe('applyIntent', () => {
172
172
  expect(applyIntent('undone', 'confirm')).toBe('conflict')
173
173
  })
174
174
 
175
- it('pending_confirmation + reject = approve', () => {
175
+ it('pending_confirmation + reject resolves as approve (rejection uses same cancel path)', () => {
176
176
  expect(applyIntent('pending_confirmation', 'reject')).toBe('approve')
177
177
  })
178
178
 
package/src/index.ts CHANGED
@@ -243,13 +243,13 @@ export type {
243
243
  IdentityTrustLevel,
244
244
  TransferEligibilityResult,
245
245
  TransferMemberEligibility,
246
- // Strategy domain types (PRD-00173)
247
- StrategyVisibility,
248
- StrategyDocLevel,
249
- StrategySource,
250
- StrategyDependency,
251
- StrategyTreeNode,
252
- StrategyDoc,
246
+ // Goals domain types (PRD-00173)
247
+ GoalVisibility,
248
+ GoalDocLevel,
249
+ GoalSource,
250
+ GoalDependency,
251
+ GoalTreeNode,
252
+ GoalDoc,
253
253
  } from './org/index'
254
254
 
255
255
  export { ROLE_DISPLAY_MAP, VIEW_SCOPE_MAP, getViewScope, TRANSFER_RESPONSIBILITIES, IDENTITY_TRUST_LEVEL_LABELS } from './org/index'
@@ -0,0 +1,127 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { WireSurfaceBuilder } from '../wire.js'
3
+ import type { ExecutionResultData } from '../execution.js'
4
+ import type { UndoResultData } from '../execution.js'
5
+
6
+ describe('WireSurfaceBuilder.toolList', () => {
7
+ it('returns data part with type data-tool-list', () => {
8
+ const tools = [{ name: 'search', description: 'Search tool', inputSchema: {} }] as any
9
+ const result = WireSurfaceBuilder.toolList(tools)
10
+ expect(result.type).toBe('data-tool-list')
11
+ })
12
+
13
+ it('data.tools matches input array exactly', () => {
14
+ const tools = [
15
+ { name: 'search', description: 'Search tool', inputSchema: {} },
16
+ { name: 'fetch', description: 'Fetch tool', inputSchema: { type: 'object' } },
17
+ ] as any
18
+ const result = WireSurfaceBuilder.toolList(tools)
19
+ expect(result.data.tools).toEqual(tools)
20
+ })
21
+
22
+ it('works with empty tools array', () => {
23
+ const result = WireSurfaceBuilder.toolList([])
24
+ expect(result.type).toBe('data-tool-list')
25
+ expect(result.data.tools).toEqual([])
26
+ })
27
+ })
28
+
29
+ describe('WireSurfaceBuilder.executionResult', () => {
30
+ const data: ExecutionResultData = {
31
+ actionId: 'act-1',
32
+ executionId: 'exec-001',
33
+ state: 'completed',
34
+ artifacts: [{ kind: 'profile_name', label: 'Name', status: 'success' }],
35
+ summary: { title: 'Profile Updated' },
36
+ }
37
+
38
+ it('returns data part with type data-execution-result', () => {
39
+ const result = WireSurfaceBuilder.executionResult(data)
40
+ expect(result.type).toBe('data-execution-result')
41
+ })
42
+
43
+ it('data matches input ExecutionResultData exactly', () => {
44
+ const result = WireSurfaceBuilder.executionResult(data)
45
+ expect(result.data).toEqual(data)
46
+ })
47
+
48
+ it('preserves actionId from input', () => {
49
+ const result = WireSurfaceBuilder.executionResult(data)
50
+ expect(result.data.actionId).toBe('act-1')
51
+ })
52
+ })
53
+
54
+ describe('WireSurfaceBuilder.undoResult', () => {
55
+ const data: UndoResultData = {
56
+ actionId: 'act-1',
57
+ executionId: 'exec-001',
58
+ undoExecutionId: 'undo-exec-002',
59
+ status: 'success',
60
+ }
61
+
62
+ it('returns data part with type data-undo-result', () => {
63
+ const result = WireSurfaceBuilder.undoResult(data)
64
+ expect(result.type).toBe('data-undo-result')
65
+ })
66
+
67
+ it('data matches input UndoResultData exactly', () => {
68
+ const result = WireSurfaceBuilder.undoResult(data)
69
+ expect(result.data).toEqual(data)
70
+ })
71
+
72
+ it('preserves undoExecutionId from input', () => {
73
+ const result = WireSurfaceBuilder.undoResult(data)
74
+ expect(result.data.undoExecutionId).toBe('undo-exec-002')
75
+ })
76
+ })
77
+
78
+ describe('WireSurfaceBuilder.messageStart', () => {
79
+ it('returns data part with type data-message-start', () => {
80
+ const result = WireSurfaceBuilder.messageStart('msg-123')
81
+ expect(result.type).toBe('data-message-start')
82
+ })
83
+
84
+ it('data.messageId matches input', () => {
85
+ const result = WireSurfaceBuilder.messageStart('msg-456')
86
+ expect(result.data.messageId).toBe('msg-456')
87
+ })
88
+
89
+ it('data.version is 1', () => {
90
+ const result = WireSurfaceBuilder.messageStart('msg-789')
91
+ expect(result.data.version).toBe(1)
92
+ })
93
+
94
+ it('data.timestamp is a valid ISO 8601 string', () => {
95
+ const result = WireSurfaceBuilder.messageStart('msg-ts')
96
+ const parsed = new Date(result.data.timestamp)
97
+ expect(parsed.toISOString()).toBe(result.data.timestamp)
98
+ })
99
+ })
100
+
101
+ describe('WireSurfaceBuilder.messageComplete', () => {
102
+ it('returns data part with type data-message-complete', () => {
103
+ const result = WireSurfaceBuilder.messageComplete('msg-123', 500)
104
+ expect(result.type).toBe('data-message-complete')
105
+ })
106
+
107
+ it('data.messageId matches input', () => {
108
+ const result = WireSurfaceBuilder.messageComplete('msg-456', 200)
109
+ expect(result.data.messageId).toBe('msg-456')
110
+ })
111
+
112
+ it('data.narrativeLength matches input', () => {
113
+ const result = WireSurfaceBuilder.messageComplete('msg-789', 1234)
114
+ expect(result.data.narrativeLength).toBe(1234)
115
+ })
116
+
117
+ it('data.version is 1', () => {
118
+ const result = WireSurfaceBuilder.messageComplete('msg-v', 100)
119
+ expect(result.data.version).toBe(1)
120
+ })
121
+
122
+ it('data.timestamp is a valid ISO 8601 string', () => {
123
+ const result = WireSurfaceBuilder.messageComplete('msg-ts', 300)
124
+ const parsed = new Date(result.data.timestamp)
125
+ expect(parsed.toISOString()).toBe(result.data.timestamp)
126
+ })
127
+ })
@@ -0,0 +1,47 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { VIEW_SCOPE_MAP, getViewScope } from '../view-scopes.js'
3
+
4
+ describe('VIEW_SCOPE_MAP golden snapshot', () => {
5
+ it('exact values are frozen', () => {
6
+ expect(VIEW_SCOPE_MAP).toStrictEqual({
7
+ workspace: 'org.view_workspace',
8
+ timeline: 'org.view_timeline',
9
+ activity: 'org.view_activity',
10
+ goals: 'org.view_goals',
11
+ 'internal-admin': 'internal.view_admin',
12
+ chat: null,
13
+ settings: null,
14
+ chats: null,
15
+ upgrade: null,
16
+ })
17
+ })
18
+ })
19
+
20
+ describe('getViewScope', () => {
21
+ it('returns the required scope for protected views', () => {
22
+ expect(getViewScope('workspace')).toBe('org.view_workspace')
23
+ expect(getViewScope('timeline')).toBe('org.view_timeline')
24
+ expect(getViewScope('activity')).toBe('org.view_activity')
25
+ expect(getViewScope('goals')).toBe('org.view_goals')
26
+ expect(getViewScope('internal-admin')).toBe('internal.view_admin')
27
+ })
28
+
29
+ it('returns null for public views', () => {
30
+ expect(getViewScope('chat')).toBeNull()
31
+ expect(getViewScope('settings')).toBeNull()
32
+ expect(getViewScope('chats')).toBeNull()
33
+ expect(getViewScope('upgrade')).toBeNull()
34
+ })
35
+
36
+ it('returns null for unknown view string', () => {
37
+ expect(getViewScope('nonexistent-view')).toBeNull()
38
+ })
39
+
40
+ it('returns null for empty string', () => {
41
+ expect(getViewScope('')).toBeNull()
42
+ })
43
+
44
+ it('returns null for view name that is a substring of a real view', () => {
45
+ expect(getViewScope('work')).toBeNull()
46
+ })
47
+ })
@@ -1,61 +1,61 @@
1
1
  /**
2
- * Strategy Domain Types
2
+ * Goals Domain Types
3
3
  *
4
- * Vocabulary types for the Company.md strategy feature.
4
+ * Vocabulary types for the Company.md goals feature.
5
5
  * Shared between backend (persistence/service) and app (UI rendering).
6
6
  * @see PRD-00173 for design rationale
7
7
  */
8
8
 
9
- export type StrategyVisibility = 'public' | 'private';
9
+ export type GoalVisibility = 'public' | 'private';
10
10
 
11
- export type StrategyDocLevel = 'root' | 'department';
11
+ export type GoalDocLevel = 'root' | 'department';
12
12
 
13
- export interface StrategySource {
13
+ export interface GoalSource {
14
14
  readonly label: string;
15
15
  readonly sourceType: 'meeting' | 'document' | 'conversation' | 'manual';
16
16
  readonly referencedAt: string;
17
17
  }
18
18
 
19
- export interface StrategyDependency {
19
+ export interface GoalDependency {
20
20
  readonly targetSlug: string;
21
21
  readonly description: string;
22
22
  }
23
23
 
24
- export interface StrategyTreeNode {
24
+ export interface GoalTreeNode {
25
25
  readonly id: string;
26
26
  readonly slug: string;
27
27
  readonly title: string;
28
- readonly level: StrategyDocLevel;
28
+ readonly level: GoalDocLevel;
29
29
  readonly department: string | null;
30
- readonly visibility: StrategyVisibility;
30
+ readonly visibility: GoalVisibility;
31
31
  readonly canEdit: boolean;
32
32
  readonly memberCount: number;
33
33
  }
34
34
 
35
- export interface StrategyDocCore {
35
+ export interface GoalDocCore {
36
36
  readonly id: string;
37
37
  readonly slug: string;
38
38
  readonly title: string;
39
- readonly level: StrategyDocLevel;
39
+ readonly level: GoalDocLevel;
40
40
  readonly department: string | null;
41
41
  readonly content: string;
42
- readonly visibility: StrategyVisibility;
42
+ readonly visibility: GoalVisibility;
43
43
  readonly parentId: string | null;
44
44
  }
45
45
 
46
- export interface StrategyDocCollaborators {
46
+ export interface GoalDocCollaborators {
47
47
  readonly owner: { readonly id: string; readonly name: string } | null;
48
48
  readonly coOwners: ReadonlyArray<{ readonly id: string; readonly name: string }>;
49
49
  readonly canEdit: boolean;
50
50
  readonly members: ReadonlyArray<{ readonly id: string; readonly name: string }>;
51
51
  }
52
52
 
53
- export interface StrategyDocRelations {
53
+ export interface GoalDocRelations {
54
54
  readonly inheritsFrom: string | null;
55
- readonly sources: readonly StrategySource[];
56
- readonly dependencies: readonly StrategyDependency[];
55
+ readonly sources: readonly GoalSource[];
56
+ readonly dependencies: readonly GoalDependency[];
57
57
  readonly createdAt: string;
58
58
  readonly updatedAt: string;
59
59
  }
60
60
 
61
- export type StrategyDoc = StrategyDocCore & StrategyDocCollaborators & StrategyDocRelations;
61
+ export type GoalDoc = GoalDocCore & GoalDocCollaborators & GoalDocRelations;
package/src/org/index.ts CHANGED
@@ -80,15 +80,15 @@ export type {
80
80
  export type { AuthorizableView } from './view-scopes';
81
81
  export { VIEW_SCOPE_MAP, getViewScope } from './view-scopes';
82
82
 
83
- // Strategy domain types (PRD-00173)
83
+ // Goals domain types (PRD-00173)
84
84
  export type {
85
- StrategyVisibility,
86
- StrategyDocLevel,
87
- StrategySource,
88
- StrategyDependency,
89
- StrategyTreeNode,
90
- StrategyDocCore,
91
- StrategyDocCollaborators,
92
- StrategyDocRelations,
93
- StrategyDoc,
94
- } from './strategy';
85
+ GoalVisibility,
86
+ GoalDocLevel,
87
+ GoalSource,
88
+ GoalDependency,
89
+ GoalTreeNode,
90
+ GoalDocCore,
91
+ GoalDocCollaborators,
92
+ GoalDocRelations,
93
+ GoalDoc,
94
+ } from './goals';
@@ -20,7 +20,7 @@ export const VIEW_SCOPE_MAP = {
20
20
  workspace: 'org.view_workspace',
21
21
  timeline: 'org.view_timeline',
22
22
  activity: 'org.view_activity',
23
- strategy: 'org.view_strategy',
23
+ goals: 'org.view_goals',
24
24
  'internal-admin': 'internal.view_admin',
25
25
  // Public views (require only authentication)
26
26
  chat: null,
@@ -0,0 +1,41 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { REPO_PRECEDENCE } from '../prd.js'
3
+
4
+ describe('REPO_PRECEDENCE', () => {
5
+ it('has contracts first (dependency source)', () => {
6
+ expect(REPO_PRECEDENCE[0]).toBe('company-semantics-contracts')
7
+ })
8
+
9
+ it('exact values and order are frozen (golden snapshot)', () => {
10
+ expect(REPO_PRECEDENCE).toStrictEqual([
11
+ 'company-semantics-contracts',
12
+ 'company-semantics-control',
13
+ 'company-semantics-ci',
14
+ 'company-semantics-backend',
15
+ 'company-semantics-edge',
16
+ 'company-semantics-app',
17
+ 'company-semantics-site',
18
+ ])
19
+ })
20
+
21
+ it('has exactly 7 entries (all known repos)', () => {
22
+ expect(REPO_PRECEDENCE).toHaveLength(7)
23
+ })
24
+
25
+ it('has no duplicates', () => {
26
+ expect(new Set(REPO_PRECEDENCE).size).toBe(REPO_PRECEDENCE.length)
27
+ })
28
+
29
+ it('all entries start with company-semantics- prefix', () => {
30
+ for (const repo of REPO_PRECEDENCE) {
31
+ expect(repo).toMatch(/^company-semantics-/)
32
+ }
33
+ })
34
+
35
+ it('all entries are non-empty strings', () => {
36
+ for (const repo of REPO_PRECEDENCE) {
37
+ expect(typeof repo).toBe('string')
38
+ expect(repo.length).toBeGreaterThan(0)
39
+ }
40
+ })
41
+ })
@@ -4,7 +4,7 @@
4
4
  * See PRD-00166 for design rationale and invariants.
5
5
  */
6
6
 
7
- export type AiFeature = 'chat' | 'chat_title' | 'ingest_summarize' | 'ingest_embedding' | 'strategy_extraction';
7
+ export type AiFeature = 'chat' | 'chat_title' | 'ingest_summarize' | 'ingest_embedding' | 'goal_extraction';
8
8
 
9
9
  export interface UsageSummary {
10
10
  totalTokens: number;