@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 +1 -1
- package/src/chat/__tests__/runtime-profile.test.ts +55 -0
- package/src/execution/__tests__/lifecycle.test.ts +1 -1
- package/src/index.ts +7 -7
- package/src/message-parts/__tests__/wire.test.ts +127 -0
- package/src/org/__tests__/view-scopes.test.ts +47 -0
- package/src/org/{strategy.ts → goals.ts} +17 -17
- package/src/org/index.ts +11 -11
- package/src/org/view-scopes.ts +1 -1
- package/src/ralph/__tests__/prd.test.ts +41 -0
- package/src/usage/types.ts +1 -1
package/package.json
CHANGED
|
@@ -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
|
|
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
|
-
//
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
*
|
|
2
|
+
* Goals Domain Types
|
|
3
3
|
*
|
|
4
|
-
* Vocabulary types for the Company.md
|
|
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
|
|
9
|
+
export type GoalVisibility = 'public' | 'private';
|
|
10
10
|
|
|
11
|
-
export type
|
|
11
|
+
export type GoalDocLevel = 'root' | 'department';
|
|
12
12
|
|
|
13
|
-
export interface
|
|
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
|
|
19
|
+
export interface GoalDependency {
|
|
20
20
|
readonly targetSlug: string;
|
|
21
21
|
readonly description: string;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export interface
|
|
24
|
+
export interface GoalTreeNode {
|
|
25
25
|
readonly id: string;
|
|
26
26
|
readonly slug: string;
|
|
27
27
|
readonly title: string;
|
|
28
|
-
readonly level:
|
|
28
|
+
readonly level: GoalDocLevel;
|
|
29
29
|
readonly department: string | null;
|
|
30
|
-
readonly visibility:
|
|
30
|
+
readonly visibility: GoalVisibility;
|
|
31
31
|
readonly canEdit: boolean;
|
|
32
32
|
readonly memberCount: number;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export interface
|
|
35
|
+
export interface GoalDocCore {
|
|
36
36
|
readonly id: string;
|
|
37
37
|
readonly slug: string;
|
|
38
38
|
readonly title: string;
|
|
39
|
-
readonly level:
|
|
39
|
+
readonly level: GoalDocLevel;
|
|
40
40
|
readonly department: string | null;
|
|
41
41
|
readonly content: string;
|
|
42
|
-
readonly visibility:
|
|
42
|
+
readonly visibility: GoalVisibility;
|
|
43
43
|
readonly parentId: string | null;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
export interface
|
|
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
|
|
53
|
+
export interface GoalDocRelations {
|
|
54
54
|
readonly inheritsFrom: string | null;
|
|
55
|
-
readonly sources: readonly
|
|
56
|
-
readonly dependencies: readonly
|
|
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
|
|
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
|
-
//
|
|
83
|
+
// Goals domain types (PRD-00173)
|
|
84
84
|
export type {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
} from './
|
|
85
|
+
GoalVisibility,
|
|
86
|
+
GoalDocLevel,
|
|
87
|
+
GoalSource,
|
|
88
|
+
GoalDependency,
|
|
89
|
+
GoalTreeNode,
|
|
90
|
+
GoalDocCore,
|
|
91
|
+
GoalDocCollaborators,
|
|
92
|
+
GoalDocRelations,
|
|
93
|
+
GoalDoc,
|
|
94
|
+
} from './goals';
|
package/src/org/view-scopes.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
+
})
|
package/src/usage/types.ts
CHANGED
|
@@ -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' | '
|
|
7
|
+
export type AiFeature = 'chat' | 'chat_title' | 'ingest_summarize' | 'ingest_embedding' | 'goal_extraction';
|
|
8
8
|
|
|
9
9
|
export interface UsageSummary {
|
|
10
10
|
totalTokens: number;
|