@contractspec/module.ai-chat 1.46.1 → 1.48.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.
@@ -1,4 +1,4 @@
1
- import { FeatureModuleSpec } from "@contractspec/lib.contracts";
1
+ import * as _contractspec_lib_contracts4 from "@contractspec/lib.contracts";
2
2
 
3
3
  //#region src/ai-chat.feature.d.ts
4
4
 
@@ -6,7 +6,7 @@ import { FeatureModuleSpec } from "@contractspec/lib.contracts";
6
6
  * AI Chat feature module that bundles conversational AI assistance
7
7
  * for ContractSpec development across CLI, VSCode, and Studio.
8
8
  */
9
- declare const AiChatFeature: FeatureModuleSpec;
9
+ declare const AiChatFeature: _contractspec_lib_contracts4.FeatureModuleSpec;
10
10
  //#endregion
11
11
  export { AiChatFeature };
12
12
  //# sourceMappingURL=ai-chat.feature.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai-chat.feature.d.ts","names":[],"sources":["../src/ai-chat.feature.ts"],"sourcesContent":[],"mappings":";;;;;;;;cAWa,eAAe"}
1
+ {"version":3,"file":"ai-chat.feature.d.ts","names":[],"sources":["../src/ai-chat.feature.ts"],"sourcesContent":[],"mappings":";;;;;;;AAWA;cAAa,eA8CX,4BAAA,CA9CwB"}
@@ -1,9 +1,16 @@
1
+ import { defineFeature } from "@contractspec/lib.contracts";
2
+
1
3
  //#region src/ai-chat.feature.ts
2
4
  /**
5
+ * AI Chat Feature Module Specification
6
+ *
7
+ * Defines the feature module for AI-powered vibe coding chat.
8
+ */
9
+ /**
3
10
  * AI Chat feature module that bundles conversational AI assistance
4
11
  * for ContractSpec development across CLI, VSCode, and Studio.
5
12
  */
6
- const AiChatFeature = {
13
+ const AiChatFeature = defineFeature({
7
14
  meta: {
8
15
  key: "ai-chat",
9
16
  version: "1.0.0",
@@ -88,7 +95,7 @@ const AiChatFeature = {
88
95
  version: "1.0.0"
89
96
  }]
90
97
  }
91
- };
98
+ });
92
99
 
93
100
  //#endregion
94
101
  export { AiChatFeature };
@@ -1 +1 @@
1
- {"version":3,"file":"ai-chat.feature.js","names":["AiChatFeature: FeatureModuleSpec"],"sources":["../src/ai-chat.feature.ts"],"sourcesContent":["/**\n * AI Chat Feature Module Specification\n *\n * Defines the feature module for AI-powered vibe coding chat.\n */\nimport type { FeatureModuleSpec } from '@contractspec/lib.contracts';\n\n/**\n * AI Chat feature module that bundles conversational AI assistance\n * for ContractSpec development across CLI, VSCode, and Studio.\n */\nexport const AiChatFeature: FeatureModuleSpec = {\n meta: {\n key: 'ai-chat',\n version: '1.0.0',\n title: 'AI Vibe Coding Chat',\n description:\n 'AI-powered conversational coding assistant with full workspace context',\n domain: 'platform',\n owners: ['@platform.ai'],\n tags: ['ai', 'chat', 'llm', 'vibe-coding', 'assistant'],\n stability: 'experimental',\n },\n\n // Contract operations for chat functionality\n operations: [\n { key: 'ai-chat.send', version: '1.0.0' },\n { key: 'ai-chat.stream', version: '1.0.0' },\n { key: 'ai-chat.conversations.list', version: '1.0.0' },\n { key: 'ai-chat.conversations.get', version: '1.0.0' },\n { key: 'ai-chat.conversations.delete', version: '1.0.0' },\n { key: 'ai-chat.providers.list', version: '1.0.0' },\n { key: 'ai-chat.context.scan', version: '1.0.0' },\n ],\n\n // Events emitted by the chat system\n events: [\n { key: 'ai-chat.message.sent', version: '1.0.0' },\n { key: 'ai-chat.message.received', version: '1.0.0' },\n { key: 'ai-chat.conversation.created', version: '1.0.0' },\n { key: 'ai-chat.conversation.deleted', version: '1.0.0' },\n { key: 'ai-chat.error', version: '1.0.0' },\n ],\n\n // No presentations for core module\n presentations: [],\n opToPresentation: [],\n presentationsTargets: [],\n\n // Capability definitions\n capabilities: {\n provides: [{ key: 'ai-chat', version: '1.0.0' }],\n requires: [\n { key: 'identity', version: '1.0.0' },\n { key: 'metering', version: '1.0.0' },\n ],\n },\n};\n"],"mappings":";;;;;AAWA,MAAaA,gBAAmC;CAC9C,MAAM;EACJ,KAAK;EACL,SAAS;EACT,OAAO;EACP,aACE;EACF,QAAQ;EACR,QAAQ,CAAC,eAAe;EACxB,MAAM;GAAC;GAAM;GAAQ;GAAO;GAAe;GAAY;EACvD,WAAW;EACZ;CAGD,YAAY;EACV;GAAE,KAAK;GAAgB,SAAS;GAAS;EACzC;GAAE,KAAK;GAAkB,SAAS;GAAS;EAC3C;GAAE,KAAK;GAA8B,SAAS;GAAS;EACvD;GAAE,KAAK;GAA6B,SAAS;GAAS;EACtD;GAAE,KAAK;GAAgC,SAAS;GAAS;EACzD;GAAE,KAAK;GAA0B,SAAS;GAAS;EACnD;GAAE,KAAK;GAAwB,SAAS;GAAS;EAClD;CAGD,QAAQ;EACN;GAAE,KAAK;GAAwB,SAAS;GAAS;EACjD;GAAE,KAAK;GAA4B,SAAS;GAAS;EACrD;GAAE,KAAK;GAAgC,SAAS;GAAS;EACzD;GAAE,KAAK;GAAgC,SAAS;GAAS;EACzD;GAAE,KAAK;GAAiB,SAAS;GAAS;EAC3C;CAGD,eAAe,EAAE;CACjB,kBAAkB,EAAE;CACpB,sBAAsB,EAAE;CAGxB,cAAc;EACZ,UAAU,CAAC;GAAE,KAAK;GAAW,SAAS;GAAS,CAAC;EAChD,UAAU,CACR;GAAE,KAAK;GAAY,SAAS;GAAS,EACrC;GAAE,KAAK;GAAY,SAAS;GAAS,CACtC;EACF;CACF"}
1
+ {"version":3,"file":"ai-chat.feature.js","names":[],"sources":["../src/ai-chat.feature.ts"],"sourcesContent":["/**\n * AI Chat Feature Module Specification\n *\n * Defines the feature module for AI-powered vibe coding chat.\n */\nimport { defineFeature } from '@contractspec/lib.contracts';\n\n/**\n * AI Chat feature module that bundles conversational AI assistance\n * for ContractSpec development across CLI, VSCode, and Studio.\n */\nexport const AiChatFeature = defineFeature({\n meta: {\n key: 'ai-chat',\n version: '1.0.0',\n title: 'AI Vibe Coding Chat',\n description:\n 'AI-powered conversational coding assistant with full workspace context',\n domain: 'platform',\n owners: ['@platform.ai'],\n tags: ['ai', 'chat', 'llm', 'vibe-coding', 'assistant'],\n stability: 'experimental',\n },\n\n // Contract operations for chat functionality\n operations: [\n { key: 'ai-chat.send', version: '1.0.0' },\n { key: 'ai-chat.stream', version: '1.0.0' },\n { key: 'ai-chat.conversations.list', version: '1.0.0' },\n { key: 'ai-chat.conversations.get', version: '1.0.0' },\n { key: 'ai-chat.conversations.delete', version: '1.0.0' },\n { key: 'ai-chat.providers.list', version: '1.0.0' },\n { key: 'ai-chat.context.scan', version: '1.0.0' },\n ],\n\n // Events emitted by the chat system\n events: [\n { key: 'ai-chat.message.sent', version: '1.0.0' },\n { key: 'ai-chat.message.received', version: '1.0.0' },\n { key: 'ai-chat.conversation.created', version: '1.0.0' },\n { key: 'ai-chat.conversation.deleted', version: '1.0.0' },\n { key: 'ai-chat.error', version: '1.0.0' },\n ],\n\n // No presentations for core module\n presentations: [],\n opToPresentation: [],\n presentationsTargets: [],\n\n // Capability definitions\n capabilities: {\n provides: [{ key: 'ai-chat', version: '1.0.0' }],\n requires: [\n { key: 'identity', version: '1.0.0' },\n { key: 'metering', version: '1.0.0' },\n ],\n },\n});\n"],"mappings":";;;;;;;;;;;;AAWA,MAAa,gBAAgB,cAAc;CACzC,MAAM;EACJ,KAAK;EACL,SAAS;EACT,OAAO;EACP,aACE;EACF,QAAQ;EACR,QAAQ,CAAC,eAAe;EACxB,MAAM;GAAC;GAAM;GAAQ;GAAO;GAAe;GAAY;EACvD,WAAW;EACZ;CAGD,YAAY;EACV;GAAE,KAAK;GAAgB,SAAS;GAAS;EACzC;GAAE,KAAK;GAAkB,SAAS;GAAS;EAC3C;GAAE,KAAK;GAA8B,SAAS;GAAS;EACvD;GAAE,KAAK;GAA6B,SAAS;GAAS;EACtD;GAAE,KAAK;GAAgC,SAAS;GAAS;EACzD;GAAE,KAAK;GAA0B,SAAS;GAAS;EACnD;GAAE,KAAK;GAAwB,SAAS;GAAS;EAClD;CAGD,QAAQ;EACN;GAAE,KAAK;GAAwB,SAAS;GAAS;EACjD;GAAE,KAAK;GAA4B,SAAS;GAAS;EACrD;GAAE,KAAK;GAAgC,SAAS;GAAS;EACzD;GAAE,KAAK;GAAgC,SAAS;GAAS;EACzD;GAAE,KAAK;GAAiB,SAAS;GAAS;EAC3C;CAGD,eAAe,EAAE;CACjB,kBAAkB,EAAE;CACpB,sBAAsB,EAAE;CAGxB,cAAc;EACZ,UAAU,CAAC;GAAE,KAAK;GAAW,SAAS;GAAS,CAAC;EAChD,UAAU,CACR;GAAE,KAAK;GAAY,SAAS;GAAS,EACrC;GAAE,KAAK;GAAY,SAAS;GAAS,CACtC;EACF;CACF,CAAC"}
@@ -1,80 +1,80 @@
1
- import * as _contractspec_lib_schema53 from "@contractspec/lib.schema";
2
- import * as _contractspec_lib_contracts0 from "@contractspec/lib.contracts";
1
+ import * as _contractspec_lib_contracts5 from "@contractspec/lib.contracts";
2
+ import * as _contractspec_lib_schema82 from "@contractspec/lib.schema";
3
3
 
4
4
  //#region src/ai-chat.operations.d.ts
5
- declare const SendMessageContract: _contractspec_lib_contracts0.OperationSpec<_contractspec_lib_schema53.SchemaModel<{
5
+ declare const SendMessageContract: _contractspec_lib_contracts5.OperationSpec<_contractspec_lib_schema82.SchemaModel<{
6
6
  conversationId: {
7
- type: _contractspec_lib_schema53.FieldType<string, string>;
7
+ type: _contractspec_lib_schema82.FieldType<string, string>;
8
8
  isOptional: true;
9
9
  };
10
10
  content: {
11
- type: _contractspec_lib_schema53.FieldType<string, string>;
11
+ type: _contractspec_lib_schema82.FieldType<string, string>;
12
12
  isOptional: false;
13
13
  };
14
14
  stream: {
15
- type: _contractspec_lib_schema53.FieldType<boolean, boolean>;
15
+ type: _contractspec_lib_schema82.FieldType<boolean, boolean>;
16
16
  isOptional: true;
17
17
  };
18
- }>, _contractspec_lib_schema53.SchemaModel<{
18
+ }>, _contractspec_lib_schema82.SchemaModel<{
19
19
  message: {
20
- type: _contractspec_lib_schema53.SchemaModel<{
20
+ type: _contractspec_lib_schema82.SchemaModel<{
21
21
  id: {
22
- type: _contractspec_lib_schema53.FieldType<string, string>;
22
+ type: _contractspec_lib_schema82.FieldType<string, string>;
23
23
  isOptional: false;
24
24
  };
25
25
  role: {
26
- type: _contractspec_lib_schema53.FieldType<string, string>;
26
+ type: _contractspec_lib_schema82.FieldType<string, string>;
27
27
  isOptional: false;
28
28
  };
29
29
  content: {
30
- type: _contractspec_lib_schema53.FieldType<string, string>;
30
+ type: _contractspec_lib_schema82.FieldType<string, string>;
31
31
  isOptional: false;
32
32
  };
33
33
  status: {
34
- type: _contractspec_lib_schema53.FieldType<string, string>;
34
+ type: _contractspec_lib_schema82.FieldType<string, string>;
35
35
  isOptional: false;
36
36
  };
37
37
  createdAt: {
38
- type: _contractspec_lib_schema53.FieldType<Date, string>;
38
+ type: _contractspec_lib_schema82.FieldType<Date, string>;
39
39
  isOptional: false;
40
40
  };
41
41
  }>;
42
42
  isOptional: false;
43
43
  };
44
44
  conversation: {
45
- type: _contractspec_lib_schema53.SchemaModel<{
45
+ type: _contractspec_lib_schema82.SchemaModel<{
46
46
  id: {
47
- type: _contractspec_lib_schema53.FieldType<string, string>;
47
+ type: _contractspec_lib_schema82.FieldType<string, string>;
48
48
  isOptional: false;
49
49
  };
50
50
  title: {
51
- type: _contractspec_lib_schema53.FieldType<string, string>;
51
+ type: _contractspec_lib_schema82.FieldType<string, string>;
52
52
  isOptional: true;
53
53
  };
54
54
  status: {
55
- type: _contractspec_lib_schema53.FieldType<string, string>;
55
+ type: _contractspec_lib_schema82.FieldType<string, string>;
56
56
  isOptional: false;
57
57
  };
58
58
  messages: {
59
- type: _contractspec_lib_schema53.SchemaModel<{
59
+ type: _contractspec_lib_schema82.SchemaModel<{
60
60
  id: {
61
- type: _contractspec_lib_schema53.FieldType<string, string>;
61
+ type: _contractspec_lib_schema82.FieldType<string, string>;
62
62
  isOptional: false;
63
63
  };
64
64
  role: {
65
- type: _contractspec_lib_schema53.FieldType<string, string>;
65
+ type: _contractspec_lib_schema82.FieldType<string, string>;
66
66
  isOptional: false;
67
67
  };
68
68
  content: {
69
- type: _contractspec_lib_schema53.FieldType<string, string>;
69
+ type: _contractspec_lib_schema82.FieldType<string, string>;
70
70
  isOptional: false;
71
71
  };
72
72
  status: {
73
- type: _contractspec_lib_schema53.FieldType<string, string>;
73
+ type: _contractspec_lib_schema82.FieldType<string, string>;
74
74
  isOptional: false;
75
75
  };
76
76
  createdAt: {
77
- type: _contractspec_lib_schema53.FieldType<Date, string>;
77
+ type: _contractspec_lib_schema82.FieldType<Date, string>;
78
78
  isOptional: false;
79
79
  };
80
80
  }>;
@@ -82,71 +82,71 @@ declare const SendMessageContract: _contractspec_lib_contracts0.OperationSpec<_c
82
82
  isOptional: false;
83
83
  };
84
84
  provider: {
85
- type: _contractspec_lib_schema53.FieldType<string, string>;
85
+ type: _contractspec_lib_schema82.FieldType<string, string>;
86
86
  isOptional: false;
87
87
  };
88
88
  model: {
89
- type: _contractspec_lib_schema53.FieldType<string, string>;
89
+ type: _contractspec_lib_schema82.FieldType<string, string>;
90
90
  isOptional: false;
91
91
  };
92
92
  }>;
93
93
  isOptional: false;
94
94
  };
95
95
  }>, undefined>;
96
- declare const StreamMessageContract: _contractspec_lib_contracts0.OperationSpec<_contractspec_lib_schema53.SchemaModel<{
96
+ declare const StreamMessageContract: _contractspec_lib_contracts5.OperationSpec<_contractspec_lib_schema82.SchemaModel<{
97
97
  conversationId: {
98
- type: _contractspec_lib_schema53.FieldType<string, string>;
98
+ type: _contractspec_lib_schema82.FieldType<string, string>;
99
99
  isOptional: true;
100
100
  };
101
101
  content: {
102
- type: _contractspec_lib_schema53.FieldType<string, string>;
102
+ type: _contractspec_lib_schema82.FieldType<string, string>;
103
103
  isOptional: false;
104
104
  };
105
105
  stream: {
106
- type: _contractspec_lib_schema53.FieldType<boolean, boolean>;
106
+ type: _contractspec_lib_schema82.FieldType<boolean, boolean>;
107
107
  isOptional: true;
108
108
  };
109
- }>, _contractspec_lib_schema53.SchemaModel<{
109
+ }>, _contractspec_lib_schema82.SchemaModel<{
110
110
  stream: {
111
- type: _contractspec_lib_schema53.FieldType<string, string>;
111
+ type: _contractspec_lib_schema82.FieldType<string, string>;
112
112
  isOptional: false;
113
113
  };
114
114
  }>, undefined>;
115
- declare const ListConversationsContract: _contractspec_lib_contracts0.OperationSpec<_contractspec_lib_schema53.SchemaModel<{}>, _contractspec_lib_schema53.SchemaModel<{
115
+ declare const ListConversationsContract: _contractspec_lib_contracts5.OperationSpec<_contractspec_lib_schema82.SchemaModel<{}>, _contractspec_lib_schema82.SchemaModel<{
116
116
  conversations: {
117
- type: _contractspec_lib_schema53.SchemaModel<{
117
+ type: _contractspec_lib_schema82.SchemaModel<{
118
118
  id: {
119
- type: _contractspec_lib_schema53.FieldType<string, string>;
119
+ type: _contractspec_lib_schema82.FieldType<string, string>;
120
120
  isOptional: false;
121
121
  };
122
122
  title: {
123
- type: _contractspec_lib_schema53.FieldType<string, string>;
123
+ type: _contractspec_lib_schema82.FieldType<string, string>;
124
124
  isOptional: true;
125
125
  };
126
126
  status: {
127
- type: _contractspec_lib_schema53.FieldType<string, string>;
127
+ type: _contractspec_lib_schema82.FieldType<string, string>;
128
128
  isOptional: false;
129
129
  };
130
130
  messages: {
131
- type: _contractspec_lib_schema53.SchemaModel<{
131
+ type: _contractspec_lib_schema82.SchemaModel<{
132
132
  id: {
133
- type: _contractspec_lib_schema53.FieldType<string, string>;
133
+ type: _contractspec_lib_schema82.FieldType<string, string>;
134
134
  isOptional: false;
135
135
  };
136
136
  role: {
137
- type: _contractspec_lib_schema53.FieldType<string, string>;
137
+ type: _contractspec_lib_schema82.FieldType<string, string>;
138
138
  isOptional: false;
139
139
  };
140
140
  content: {
141
- type: _contractspec_lib_schema53.FieldType<string, string>;
141
+ type: _contractspec_lib_schema82.FieldType<string, string>;
142
142
  isOptional: false;
143
143
  };
144
144
  status: {
145
- type: _contractspec_lib_schema53.FieldType<string, string>;
145
+ type: _contractspec_lib_schema82.FieldType<string, string>;
146
146
  isOptional: false;
147
147
  };
148
148
  createdAt: {
149
- type: _contractspec_lib_schema53.FieldType<Date, string>;
149
+ type: _contractspec_lib_schema82.FieldType<Date, string>;
150
150
  isOptional: false;
151
151
  };
152
152
  }>;
@@ -154,11 +154,11 @@ declare const ListConversationsContract: _contractspec_lib_contracts0.OperationS
154
154
  isOptional: false;
155
155
  };
156
156
  provider: {
157
- type: _contractspec_lib_schema53.FieldType<string, string>;
157
+ type: _contractspec_lib_schema82.FieldType<string, string>;
158
158
  isOptional: false;
159
159
  };
160
160
  model: {
161
- type: _contractspec_lib_schema53.FieldType<string, string>;
161
+ type: _contractspec_lib_schema82.FieldType<string, string>;
162
162
  isOptional: false;
163
163
  };
164
164
  }>;
@@ -166,44 +166,44 @@ declare const ListConversationsContract: _contractspec_lib_contracts0.OperationS
166
166
  isOptional: false;
167
167
  };
168
168
  }>, undefined>;
169
- declare const GetConversationContract: _contractspec_lib_contracts0.OperationSpec<_contractspec_lib_schema53.SchemaModel<{
169
+ declare const GetConversationContract: _contractspec_lib_contracts5.OperationSpec<_contractspec_lib_schema82.SchemaModel<{
170
170
  id: {
171
- type: _contractspec_lib_schema53.FieldType<string, string>;
171
+ type: _contractspec_lib_schema82.FieldType<string, string>;
172
172
  isOptional: false;
173
173
  };
174
- }>, _contractspec_lib_schema53.SchemaModel<{
174
+ }>, _contractspec_lib_schema82.SchemaModel<{
175
175
  id: {
176
- type: _contractspec_lib_schema53.FieldType<string, string>;
176
+ type: _contractspec_lib_schema82.FieldType<string, string>;
177
177
  isOptional: false;
178
178
  };
179
179
  title: {
180
- type: _contractspec_lib_schema53.FieldType<string, string>;
180
+ type: _contractspec_lib_schema82.FieldType<string, string>;
181
181
  isOptional: true;
182
182
  };
183
183
  status: {
184
- type: _contractspec_lib_schema53.FieldType<string, string>;
184
+ type: _contractspec_lib_schema82.FieldType<string, string>;
185
185
  isOptional: false;
186
186
  };
187
187
  messages: {
188
- type: _contractspec_lib_schema53.SchemaModel<{
188
+ type: _contractspec_lib_schema82.SchemaModel<{
189
189
  id: {
190
- type: _contractspec_lib_schema53.FieldType<string, string>;
190
+ type: _contractspec_lib_schema82.FieldType<string, string>;
191
191
  isOptional: false;
192
192
  };
193
193
  role: {
194
- type: _contractspec_lib_schema53.FieldType<string, string>;
194
+ type: _contractspec_lib_schema82.FieldType<string, string>;
195
195
  isOptional: false;
196
196
  };
197
197
  content: {
198
- type: _contractspec_lib_schema53.FieldType<string, string>;
198
+ type: _contractspec_lib_schema82.FieldType<string, string>;
199
199
  isOptional: false;
200
200
  };
201
201
  status: {
202
- type: _contractspec_lib_schema53.FieldType<string, string>;
202
+ type: _contractspec_lib_schema82.FieldType<string, string>;
203
203
  isOptional: false;
204
204
  };
205
205
  createdAt: {
206
- type: _contractspec_lib_schema53.FieldType<Date, string>;
206
+ type: _contractspec_lib_schema82.FieldType<Date, string>;
207
207
  isOptional: false;
208
208
  };
209
209
  }>;
@@ -211,33 +211,33 @@ declare const GetConversationContract: _contractspec_lib_contracts0.OperationSpe
211
211
  isOptional: false;
212
212
  };
213
213
  provider: {
214
- type: _contractspec_lib_schema53.FieldType<string, string>;
214
+ type: _contractspec_lib_schema82.FieldType<string, string>;
215
215
  isOptional: false;
216
216
  };
217
217
  model: {
218
- type: _contractspec_lib_schema53.FieldType<string, string>;
218
+ type: _contractspec_lib_schema82.FieldType<string, string>;
219
219
  isOptional: false;
220
220
  };
221
221
  }>, undefined>;
222
- declare const DeleteConversationContract: _contractspec_lib_contracts0.OperationSpec<_contractspec_lib_schema53.SchemaModel<{
222
+ declare const DeleteConversationContract: _contractspec_lib_contracts5.OperationSpec<_contractspec_lib_schema82.SchemaModel<{
223
223
  id: {
224
- type: _contractspec_lib_schema53.FieldType<string, string>;
224
+ type: _contractspec_lib_schema82.FieldType<string, string>;
225
225
  isOptional: false;
226
226
  };
227
- }>, _contractspec_lib_schema53.SchemaModel<{}>, undefined>;
228
- declare const ListProvidersContract: _contractspec_lib_contracts0.OperationSpec<_contractspec_lib_schema53.SchemaModel<{}>, _contractspec_lib_schema53.SchemaModel<{
227
+ }>, _contractspec_lib_schema82.SchemaModel<{}>, undefined>;
228
+ declare const ListProvidersContract: _contractspec_lib_contracts5.OperationSpec<_contractspec_lib_schema82.SchemaModel<{}>, _contractspec_lib_schema82.SchemaModel<{
229
229
  providers: {
230
- type: _contractspec_lib_schema53.FieldType<string, string>;
230
+ type: _contractspec_lib_schema82.FieldType<string, string>;
231
231
  isArray: true;
232
232
  isOptional: false;
233
233
  };
234
234
  }>, undefined>;
235
- declare const ScanContextContract: _contractspec_lib_contracts0.OperationSpec<_contractspec_lib_schema53.SchemaModel<{
235
+ declare const ScanContextContract: _contractspec_lib_contracts5.OperationSpec<_contractspec_lib_schema82.SchemaModel<{
236
236
  path: {
237
- type: _contractspec_lib_schema53.FieldType<string, string>;
237
+ type: _contractspec_lib_schema82.FieldType<string, string>;
238
238
  isOptional: false;
239
239
  };
240
- }>, _contractspec_lib_schema53.SchemaModel<{}>, undefined>;
240
+ }>, _contractspec_lib_schema82.SchemaModel<{}>, undefined>;
241
241
  //#endregion
242
242
  export { DeleteConversationContract, GetConversationContract, ListConversationsContract, ListProvidersContract, ScanContextContract, SendMessageContract, StreamMessageContract };
243
243
  //# sourceMappingURL=ai-chat.operations.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import { ChatConversationModel, ListConversationsOutputModel, SendMessageInputModel, SendMessageOutputModel } from "./schema.js";
2
- import { ScalarTypeEnum, defineSchemaModel } from "@contractspec/lib.schema";
3
2
  import { defineCommand, defineQuery } from "@contractspec/lib.contracts";
3
+ import { ScalarTypeEnum, defineSchemaModel } from "@contractspec/lib.schema";
4
4
 
5
5
  //#region src/ai-chat.operations.ts
6
6
  const SendMessageContract = defineCommand({
@@ -1 +1 @@
1
- {"version":3,"file":"context-builder.js","names":["entries: ContextEntry[]","entry: ContextEntry","parts: string[]"],"sources":["../../src/context/context-builder.ts"],"sourcesContent":["/**\n * Context builder for LLM prompts\n *\n * Builds rich context from workspace information for AI assistance.\n */\nimport type { WorkspaceContext, SpecInfo, FileInfo } from './workspace-context';\n\n/**\n * Context entry for a file or spec\n */\nexport interface ContextEntry {\n type: 'spec' | 'file' | 'reference';\n path: string;\n content?: string;\n summary?: string;\n relevance: number; // 0-1 score\n}\n\n/**\n * Built context for LLM\n */\nexport interface BuiltContext {\n entries: ContextEntry[];\n summary: string;\n totalTokensEstimate: number;\n}\n\n/**\n * Options for building context\n */\nexport interface ContextBuilderOptions {\n /** Maximum estimated tokens for context */\n maxTokens?: number;\n /** Query to use for relevance scoring */\n query?: string;\n /** Specific files to include */\n includeFiles?: string[];\n /** Specific specs to include */\n includeSpecs?: string[];\n}\n\n/**\n * Estimates token count from string (rough approximation)\n */\nfunction estimateTokens(text: string): number {\n // Rough estimate: ~4 characters per token\n return Math.ceil(text.length / 4);\n}\n\n/**\n * Calculate relevance score for a spec\n */\nfunction scoreSpec(spec: SpecInfo, query?: string): number {\n if (!query) return 0.5;\n\n const lowerQuery = query.toLowerCase();\n let score = 0;\n\n // Name match\n if (spec.name.toLowerCase().includes(lowerQuery)) {\n score += 0.4;\n }\n\n // Description match\n if (spec.description?.toLowerCase().includes(lowerQuery)) {\n score += 0.3;\n }\n\n // Tag match\n if (spec.tags?.some((t) => t.toLowerCase().includes(lowerQuery))) {\n score += 0.2;\n }\n\n return Math.min(score, 1);\n}\n\n/**\n * Calculate relevance score for a file\n */\nfunction scoreFile(file: FileInfo, query?: string): number {\n if (!query) return 0.5;\n\n const lowerQuery = query.toLowerCase();\n let score = 0;\n\n // Path match\n if (file.path.toLowerCase().includes(lowerQuery)) {\n score += 0.5;\n }\n\n // Name match\n if (file.name.toLowerCase().includes(lowerQuery)) {\n score += 0.3;\n }\n\n // Spec file bonus\n if (file.isSpec) {\n score += 0.2;\n }\n\n return Math.min(score, 1);\n}\n\n/**\n * Context builder for creating rich LLM context\n */\nexport class ContextBuilder {\n private readonly context: WorkspaceContext;\n\n constructor(context: WorkspaceContext) {\n this.context = context;\n }\n\n /**\n * Build context for a chat message\n */\n build(options: ContextBuilderOptions = {}): BuiltContext {\n const maxTokens = options.maxTokens ?? 4000;\n const entries: ContextEntry[] = [];\n let totalTokens = 0;\n\n // Add explicitly included specs\n if (options.includeSpecs?.length) {\n for (const specName of options.includeSpecs) {\n const spec = this.context.getSpecs().find((s) => s.name === specName);\n if (spec) {\n const entry: ContextEntry = {\n type: 'spec',\n path: spec.path,\n summary: `${spec.type}: ${spec.name}${spec.description ? ` - ${spec.description}` : ''}`,\n relevance: 1,\n };\n entries.push(entry);\n totalTokens += estimateTokens(entry.summary ?? '');\n }\n }\n }\n\n // Add explicitly included files\n if (options.includeFiles?.length) {\n for (const filePath of options.includeFiles) {\n const file = this.context.getFiles().find((f) => f.path === filePath);\n if (file) {\n const entry: ContextEntry = {\n type: 'file',\n path: file.path,\n summary: `File: ${file.relativePath}`,\n relevance: 1,\n };\n entries.push(entry);\n totalTokens += estimateTokens(entry.summary ?? '');\n }\n }\n }\n\n // Add relevant specs based on query\n if (options.query) {\n const scoredSpecs = this.context\n .getSpecs()\n .map((spec) => ({ spec, score: scoreSpec(spec, options.query) }))\n .filter(({ score }) => score > 0.2)\n .sort((a, b) => b.score - a.score);\n\n for (const { spec, score } of scoredSpecs) {\n if (totalTokens >= maxTokens) break;\n if (entries.some((e) => e.path === spec.path)) continue;\n\n const entry: ContextEntry = {\n type: 'spec',\n path: spec.path,\n summary: `${spec.type}: ${spec.name}${spec.description ? ` - ${spec.description}` : ''}`,\n relevance: score,\n };\n entries.push(entry);\n totalTokens += estimateTokens(entry.summary ?? '');\n }\n }\n\n // Add relevant files based on query\n if (options.query) {\n const scoredFiles = this.context\n .getFiles()\n .map((file) => ({ file, score: scoreFile(file, options.query) }))\n .filter(({ score }) => score > 0.2)\n .sort((a, b) => b.score - a.score);\n\n for (const { file, score } of scoredFiles) {\n if (totalTokens >= maxTokens) break;\n if (entries.some((e) => e.path === file.path)) continue;\n\n const entry: ContextEntry = {\n type: 'file',\n path: file.path,\n summary: `File: ${file.relativePath}`,\n relevance: score,\n };\n entries.push(entry);\n totalTokens += estimateTokens(entry.summary ?? '');\n }\n }\n\n // Build summary\n const summary = this.buildSummary(entries);\n\n return {\n entries,\n summary,\n totalTokensEstimate: totalTokens + estimateTokens(summary),\n };\n }\n\n /**\n * Build a text summary of the context entries\n */\n private buildSummary(entries: ContextEntry[]): string {\n if (entries.length === 0) {\n return this.context.getContextSummary();\n }\n\n const parts: string[] = [];\n\n // Workspace info\n const workspaceSummary = this.context.getSummary();\n parts.push(`Workspace: ${workspaceSummary.name}`);\n parts.push('');\n\n // Relevant specs\n const specs = entries.filter((e) => e.type === 'spec');\n if (specs.length > 0) {\n parts.push('### Relevant Specs');\n for (const entry of specs) {\n parts.push(`- ${entry.summary}`);\n }\n parts.push('');\n }\n\n // Relevant files\n const files = entries.filter((e) => e.type === 'file');\n if (files.length > 0) {\n parts.push('### Relevant Files');\n for (const entry of files) {\n parts.push(`- ${entry.summary}`);\n }\n }\n\n return parts.join('\\n');\n }\n}\n\n/**\n * Create a context builder\n */\nexport function createContextBuilder(\n context: WorkspaceContext\n): ContextBuilder {\n return new ContextBuilder(context);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"context-builder.js","names":[],"sources":["../../src/context/context-builder.ts"],"sourcesContent":["/**\n * Context builder for LLM prompts\n *\n * Builds rich context from workspace information for AI assistance.\n */\nimport type { WorkspaceContext, SpecInfo, FileInfo } from './workspace-context';\n\n/**\n * Context entry for a file or spec\n */\nexport interface ContextEntry {\n type: 'spec' | 'file' | 'reference';\n path: string;\n content?: string;\n summary?: string;\n relevance: number; // 0-1 score\n}\n\n/**\n * Built context for LLM\n */\nexport interface BuiltContext {\n entries: ContextEntry[];\n summary: string;\n totalTokensEstimate: number;\n}\n\n/**\n * Options for building context\n */\nexport interface ContextBuilderOptions {\n /** Maximum estimated tokens for context */\n maxTokens?: number;\n /** Query to use for relevance scoring */\n query?: string;\n /** Specific files to include */\n includeFiles?: string[];\n /** Specific specs to include */\n includeSpecs?: string[];\n}\n\n/**\n * Estimates token count from string (rough approximation)\n */\nfunction estimateTokens(text: string): number {\n // Rough estimate: ~4 characters per token\n return Math.ceil(text.length / 4);\n}\n\n/**\n * Calculate relevance score for a spec\n */\nfunction scoreSpec(spec: SpecInfo, query?: string): number {\n if (!query) return 0.5;\n\n const lowerQuery = query.toLowerCase();\n let score = 0;\n\n // Name match\n if (spec.name.toLowerCase().includes(lowerQuery)) {\n score += 0.4;\n }\n\n // Description match\n if (spec.description?.toLowerCase().includes(lowerQuery)) {\n score += 0.3;\n }\n\n // Tag match\n if (spec.tags?.some((t) => t.toLowerCase().includes(lowerQuery))) {\n score += 0.2;\n }\n\n return Math.min(score, 1);\n}\n\n/**\n * Calculate relevance score for a file\n */\nfunction scoreFile(file: FileInfo, query?: string): number {\n if (!query) return 0.5;\n\n const lowerQuery = query.toLowerCase();\n let score = 0;\n\n // Path match\n if (file.path.toLowerCase().includes(lowerQuery)) {\n score += 0.5;\n }\n\n // Name match\n if (file.name.toLowerCase().includes(lowerQuery)) {\n score += 0.3;\n }\n\n // Spec file bonus\n if (file.isSpec) {\n score += 0.2;\n }\n\n return Math.min(score, 1);\n}\n\n/**\n * Context builder for creating rich LLM context\n */\nexport class ContextBuilder {\n private readonly context: WorkspaceContext;\n\n constructor(context: WorkspaceContext) {\n this.context = context;\n }\n\n /**\n * Build context for a chat message\n */\n build(options: ContextBuilderOptions = {}): BuiltContext {\n const maxTokens = options.maxTokens ?? 4000;\n const entries: ContextEntry[] = [];\n let totalTokens = 0;\n\n // Add explicitly included specs\n if (options.includeSpecs?.length) {\n for (const specName of options.includeSpecs) {\n const spec = this.context.getSpecs().find((s) => s.name === specName);\n if (spec) {\n const entry: ContextEntry = {\n type: 'spec',\n path: spec.path,\n summary: `${spec.type}: ${spec.name}${spec.description ? ` - ${spec.description}` : ''}`,\n relevance: 1,\n };\n entries.push(entry);\n totalTokens += estimateTokens(entry.summary ?? '');\n }\n }\n }\n\n // Add explicitly included files\n if (options.includeFiles?.length) {\n for (const filePath of options.includeFiles) {\n const file = this.context.getFiles().find((f) => f.path === filePath);\n if (file) {\n const entry: ContextEntry = {\n type: 'file',\n path: file.path,\n summary: `File: ${file.relativePath}`,\n relevance: 1,\n };\n entries.push(entry);\n totalTokens += estimateTokens(entry.summary ?? '');\n }\n }\n }\n\n // Add relevant specs based on query\n if (options.query) {\n const scoredSpecs = this.context\n .getSpecs()\n .map((spec) => ({ spec, score: scoreSpec(spec, options.query) }))\n .filter(({ score }) => score > 0.2)\n .sort((a, b) => b.score - a.score);\n\n for (const { spec, score } of scoredSpecs) {\n if (totalTokens >= maxTokens) break;\n if (entries.some((e) => e.path === spec.path)) continue;\n\n const entry: ContextEntry = {\n type: 'spec',\n path: spec.path,\n summary: `${spec.type}: ${spec.name}${spec.description ? ` - ${spec.description}` : ''}`,\n relevance: score,\n };\n entries.push(entry);\n totalTokens += estimateTokens(entry.summary ?? '');\n }\n }\n\n // Add relevant files based on query\n if (options.query) {\n const scoredFiles = this.context\n .getFiles()\n .map((file) => ({ file, score: scoreFile(file, options.query) }))\n .filter(({ score }) => score > 0.2)\n .sort((a, b) => b.score - a.score);\n\n for (const { file, score } of scoredFiles) {\n if (totalTokens >= maxTokens) break;\n if (entries.some((e) => e.path === file.path)) continue;\n\n const entry: ContextEntry = {\n type: 'file',\n path: file.path,\n summary: `File: ${file.relativePath}`,\n relevance: score,\n };\n entries.push(entry);\n totalTokens += estimateTokens(entry.summary ?? '');\n }\n }\n\n // Build summary\n const summary = this.buildSummary(entries);\n\n return {\n entries,\n summary,\n totalTokensEstimate: totalTokens + estimateTokens(summary),\n };\n }\n\n /**\n * Build a text summary of the context entries\n */\n private buildSummary(entries: ContextEntry[]): string {\n if (entries.length === 0) {\n return this.context.getContextSummary();\n }\n\n const parts: string[] = [];\n\n // Workspace info\n const workspaceSummary = this.context.getSummary();\n parts.push(`Workspace: ${workspaceSummary.name}`);\n parts.push('');\n\n // Relevant specs\n const specs = entries.filter((e) => e.type === 'spec');\n if (specs.length > 0) {\n parts.push('### Relevant Specs');\n for (const entry of specs) {\n parts.push(`- ${entry.summary}`);\n }\n parts.push('');\n }\n\n // Relevant files\n const files = entries.filter((e) => e.type === 'file');\n if (files.length > 0) {\n parts.push('### Relevant Files');\n for (const entry of files) {\n parts.push(`- ${entry.summary}`);\n }\n }\n\n return parts.join('\\n');\n }\n}\n\n/**\n * Create a context builder\n */\nexport function createContextBuilder(\n context: WorkspaceContext\n): ContextBuilder {\n return new ContextBuilder(context);\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"file-operations.js","names":["fs: FileSystem","workspacePath: string","results: FileOperationResult[]","result: FileOperationResult","files: string[]"],"sources":["../../src/context/file-operations.ts"],"sourcesContent":["/**\n * File operations for workspace context\n *\n * Provides read/write operations for files in the workspace.\n */\n\n/**\n * Result of a file read operation\n */\nexport interface FileReadResult {\n success: boolean;\n path: string;\n content?: string;\n error?: string;\n}\n\n/**\n * Result of a file write operation\n */\nexport interface FileWriteResult {\n success: boolean;\n path: string;\n error?: string;\n}\n\n/**\n * File operation to perform\n */\nexport interface FileOperation {\n type: 'read' | 'write' | 'create' | 'delete';\n path: string;\n content?: string;\n}\n\n/**\n * Result of a file operation\n */\nexport interface FileOperationResult {\n operation: FileOperation;\n success: boolean;\n content?: string;\n error?: string;\n}\n\n/**\n * Interface for file system operations\n */\nexport interface FileSystem {\n /**\n * Read a file's contents\n */\n readFile(path: string): Promise<string>;\n\n /**\n * Write content to a file\n */\n writeFile(path: string, content: string): Promise<void>;\n\n /**\n * Check if a file exists\n */\n exists(path: string): Promise<boolean>;\n\n /**\n * Delete a file\n */\n deleteFile(path: string): Promise<void>;\n\n /**\n * List files in a directory\n */\n listFiles(\n directory: string,\n options?: { recursive?: boolean; pattern?: string }\n ): Promise<string[]>;\n}\n\n/**\n * File operations executor\n */\nexport class FileOperations {\n constructor(\n private readonly fs: FileSystem,\n private readonly workspacePath: string,\n private readonly allowWrites = false\n ) {}\n\n /**\n * Read a file\n */\n async read(relativePath: string): Promise<FileReadResult> {\n const fullPath = this.resolvePath(relativePath);\n\n try {\n const content = await this.fs.readFile(fullPath);\n return { success: true, path: relativePath, content };\n } catch (error) {\n return {\n success: false,\n path: relativePath,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n /**\n * Write to a file\n */\n async write(relativePath: string, content: string): Promise<FileWriteResult> {\n if (!this.allowWrites) {\n return {\n success: false,\n path: relativePath,\n error: 'File writes are not enabled',\n };\n }\n\n const fullPath = this.resolvePath(relativePath);\n\n try {\n await this.fs.writeFile(fullPath, content);\n return { success: true, path: relativePath };\n } catch (error) {\n return {\n success: false,\n path: relativePath,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n /**\n * Execute multiple file operations\n */\n async execute(operations: FileOperation[]): Promise<FileOperationResult[]> {\n const results: FileOperationResult[] = [];\n\n for (const operation of operations) {\n let result: FileOperationResult;\n\n switch (operation.type) {\n case 'read': {\n const readResult = await this.read(operation.path);\n result = {\n operation,\n success: readResult.success,\n content: readResult.content,\n error: readResult.error,\n };\n break;\n }\n\n case 'write':\n case 'create': {\n if (!operation.content) {\n result = {\n operation,\n success: false,\n error: 'Content is required for write operations',\n };\n } else {\n const writeResult = await this.write(\n operation.path,\n operation.content\n );\n result = {\n operation,\n success: writeResult.success,\n error: writeResult.error,\n };\n }\n break;\n }\n\n case 'delete': {\n if (!this.allowWrites) {\n result = {\n operation,\n success: false,\n error: 'File writes are not enabled',\n };\n } else {\n try {\n await this.fs.deleteFile(this.resolvePath(operation.path));\n result = { operation, success: true };\n } catch (error) {\n result = {\n operation,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n break;\n }\n\n default:\n result = {\n operation,\n success: false,\n error: `Unknown operation type: ${(operation as FileOperation).type}`,\n };\n }\n\n results.push(result);\n }\n\n return results;\n }\n\n /**\n * Resolve a relative path to an absolute path\n */\n private resolvePath(relativePath: string): string {\n // Prevent path traversal\n const normalized = relativePath.replace(/\\.\\./g, '').replace(/^\\//, '');\n return `${this.workspacePath}/${normalized}`;\n }\n}\n\n/**\n * Create a file operations instance with Node.js fs\n */\nexport function createNodeFileOperations(\n workspacePath: string,\n allowWrites = false\n): FileOperations {\n // Dynamic import to avoid issues in browser environments\n const fs: FileSystem = {\n async readFile(path: string): Promise<string> {\n const { readFile } = await import('node:fs/promises');\n return readFile(path, 'utf-8');\n },\n async writeFile(path: string, content: string): Promise<void> {\n const { writeFile, mkdir } = await import('node:fs/promises');\n const { dirname } = await import('node:path');\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, content, 'utf-8');\n },\n async exists(path: string): Promise<boolean> {\n const { access } = await import('node:fs/promises');\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n },\n async deleteFile(path: string): Promise<void> {\n const { unlink } = await import('node:fs/promises');\n await unlink(path);\n },\n async listFiles(\n directory: string,\n options?: { recursive?: boolean; pattern?: string }\n ): Promise<string[]> {\n const { readdir } = await import('node:fs/promises');\n const { join } = await import('node:path');\n\n const files: string[] = [];\n const entries = await readdir(directory, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = join(directory, entry.name);\n if (entry.isDirectory() && options?.recursive) {\n const subFiles = await this.listFiles(fullPath, options);\n files.push(...subFiles);\n } else if (entry.isFile()) {\n if (\n !options?.pattern ||\n entry.name.match(new RegExp(options.pattern))\n ) {\n files.push(fullPath);\n }\n }\n }\n\n return files;\n },\n };\n\n return new FileOperations(fs, workspacePath, allowWrites);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"file-operations.js","names":[],"sources":["../../src/context/file-operations.ts"],"sourcesContent":["/**\n * File operations for workspace context\n *\n * Provides read/write operations for files in the workspace.\n */\n\n/**\n * Result of a file read operation\n */\nexport interface FileReadResult {\n success: boolean;\n path: string;\n content?: string;\n error?: string;\n}\n\n/**\n * Result of a file write operation\n */\nexport interface FileWriteResult {\n success: boolean;\n path: string;\n error?: string;\n}\n\n/**\n * File operation to perform\n */\nexport interface FileOperation {\n type: 'read' | 'write' | 'create' | 'delete';\n path: string;\n content?: string;\n}\n\n/**\n * Result of a file operation\n */\nexport interface FileOperationResult {\n operation: FileOperation;\n success: boolean;\n content?: string;\n error?: string;\n}\n\n/**\n * Interface for file system operations\n */\nexport interface FileSystem {\n /**\n * Read a file's contents\n */\n readFile(path: string): Promise<string>;\n\n /**\n * Write content to a file\n */\n writeFile(path: string, content: string): Promise<void>;\n\n /**\n * Check if a file exists\n */\n exists(path: string): Promise<boolean>;\n\n /**\n * Delete a file\n */\n deleteFile(path: string): Promise<void>;\n\n /**\n * List files in a directory\n */\n listFiles(\n directory: string,\n options?: { recursive?: boolean; pattern?: string }\n ): Promise<string[]>;\n}\n\n/**\n * File operations executor\n */\nexport class FileOperations {\n constructor(\n private readonly fs: FileSystem,\n private readonly workspacePath: string,\n private readonly allowWrites = false\n ) {}\n\n /**\n * Read a file\n */\n async read(relativePath: string): Promise<FileReadResult> {\n const fullPath = this.resolvePath(relativePath);\n\n try {\n const content = await this.fs.readFile(fullPath);\n return { success: true, path: relativePath, content };\n } catch (error) {\n return {\n success: false,\n path: relativePath,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n /**\n * Write to a file\n */\n async write(relativePath: string, content: string): Promise<FileWriteResult> {\n if (!this.allowWrites) {\n return {\n success: false,\n path: relativePath,\n error: 'File writes are not enabled',\n };\n }\n\n const fullPath = this.resolvePath(relativePath);\n\n try {\n await this.fs.writeFile(fullPath, content);\n return { success: true, path: relativePath };\n } catch (error) {\n return {\n success: false,\n path: relativePath,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n\n /**\n * Execute multiple file operations\n */\n async execute(operations: FileOperation[]): Promise<FileOperationResult[]> {\n const results: FileOperationResult[] = [];\n\n for (const operation of operations) {\n let result: FileOperationResult;\n\n switch (operation.type) {\n case 'read': {\n const readResult = await this.read(operation.path);\n result = {\n operation,\n success: readResult.success,\n content: readResult.content,\n error: readResult.error,\n };\n break;\n }\n\n case 'write':\n case 'create': {\n if (!operation.content) {\n result = {\n operation,\n success: false,\n error: 'Content is required for write operations',\n };\n } else {\n const writeResult = await this.write(\n operation.path,\n operation.content\n );\n result = {\n operation,\n success: writeResult.success,\n error: writeResult.error,\n };\n }\n break;\n }\n\n case 'delete': {\n if (!this.allowWrites) {\n result = {\n operation,\n success: false,\n error: 'File writes are not enabled',\n };\n } else {\n try {\n await this.fs.deleteFile(this.resolvePath(operation.path));\n result = { operation, success: true };\n } catch (error) {\n result = {\n operation,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n }\n break;\n }\n\n default:\n result = {\n operation,\n success: false,\n error: `Unknown operation type: ${(operation as FileOperation).type}`,\n };\n }\n\n results.push(result);\n }\n\n return results;\n }\n\n /**\n * Resolve a relative path to an absolute path\n */\n private resolvePath(relativePath: string): string {\n // Prevent path traversal\n const normalized = relativePath.replace(/\\.\\./g, '').replace(/^\\//, '');\n return `${this.workspacePath}/${normalized}`;\n }\n}\n\n/**\n * Create a file operations instance with Node.js fs\n */\nexport function createNodeFileOperations(\n workspacePath: string,\n allowWrites = false\n): FileOperations {\n // Dynamic import to avoid issues in browser environments\n const fs: FileSystem = {\n async readFile(path: string): Promise<string> {\n const { readFile } = await import('node:fs/promises');\n return readFile(path, 'utf-8');\n },\n async writeFile(path: string, content: string): Promise<void> {\n const { writeFile, mkdir } = await import('node:fs/promises');\n const { dirname } = await import('node:path');\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, content, 'utf-8');\n },\n async exists(path: string): Promise<boolean> {\n const { access } = await import('node:fs/promises');\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n },\n async deleteFile(path: string): Promise<void> {\n const { unlink } = await import('node:fs/promises');\n await unlink(path);\n },\n async listFiles(\n directory: string,\n options?: { recursive?: boolean; pattern?: string }\n ): Promise<string[]> {\n const { readdir } = await import('node:fs/promises');\n const { join } = await import('node:path');\n\n const files: string[] = [];\n const entries = await readdir(directory, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = join(directory, entry.name);\n if (entry.isDirectory() && options?.recursive) {\n const subFiles = await this.listFiles(fullPath, options);\n files.push(...subFiles);\n } else if (entry.isFile()) {\n if (\n !options?.pattern ||\n entry.name.match(new RegExp(options.pattern))\n ) {\n files.push(fullPath);\n }\n }\n }\n\n return files;\n },\n };\n\n return new FileOperations(fs, workspacePath, allowWrites);\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-context.js","names":["parts: string[]"],"sources":["../../src/context/workspace-context.ts"],"sourcesContent":["/**\n * Workspace context management\n *\n * Provides access to specs, files, and codebase information\n * for context-aware AI chat assistance.\n */\n\n/**\n * Spec information for context\n */\nexport interface SpecInfo {\n name: string;\n version: string;\n type: 'command' | 'query' | 'event' | 'presentation';\n path: string;\n description?: string;\n tags?: string[];\n}\n\n/**\n * File information for context\n */\nexport interface FileInfo {\n path: string;\n relativePath: string;\n name: string;\n extension: string;\n size: number;\n isSpec: boolean;\n}\n\n/**\n * Workspace summary for context\n */\nexport interface WorkspaceSummary {\n name: string;\n path: string;\n specs: {\n total: number;\n commands: number;\n queries: number;\n events: number;\n presentations: number;\n };\n files: {\n total: number;\n typescript: number;\n specFiles: number;\n };\n}\n\n/**\n * Configuration for workspace context\n */\nexport interface WorkspaceContextConfig {\n /** Root path of the workspace */\n workspacePath: string;\n /** File patterns to include */\n includePatterns?: string[];\n /** File patterns to exclude */\n excludePatterns?: string[];\n /** Maximum file size to read (bytes) */\n maxFileSize?: number;\n /** Whether to enable file writes */\n allowWrites?: boolean;\n}\n\n/**\n * Workspace context for AI chat\n */\nexport class WorkspaceContext {\n readonly workspacePath: string;\n readonly allowWrites: boolean;\n\n private specs: SpecInfo[] = [];\n private files: FileInfo[] = [];\n private initialized = false;\n\n constructor(config: WorkspaceContextConfig) {\n this.workspacePath = config.workspacePath;\n this.allowWrites = config.allowWrites ?? false;\n }\n\n /**\n * Initialize the workspace context by scanning files\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n // This would scan the workspace for specs and files\n // For now, we just mark as initialized\n this.initialized = true;\n }\n\n /**\n * Get all discovered specs\n */\n getSpecs(): SpecInfo[] {\n return this.specs;\n }\n\n /**\n * Get all discovered files\n */\n getFiles(): FileInfo[] {\n return this.files;\n }\n\n /**\n * Add specs to the context\n */\n addSpecs(specs: SpecInfo[]): void {\n this.specs.push(...specs);\n }\n\n /**\n * Add files to the context\n */\n addFiles(files: FileInfo[]): void {\n this.files.push(...files);\n }\n\n /**\n * Get a summary of the workspace for context\n */\n getSummary(): WorkspaceSummary {\n const commands = this.specs.filter((s) => s.type === 'command').length;\n const queries = this.specs.filter((s) => s.type === 'query').length;\n const events = this.specs.filter((s) => s.type === 'event').length;\n const presentations = this.specs.filter(\n (s) => s.type === 'presentation'\n ).length;\n\n const tsFiles = this.files.filter((f) => f.extension === '.ts').length;\n const specFiles = this.files.filter((f) => f.isSpec).length;\n\n return {\n name: this.workspacePath.split('/').pop() ?? 'workspace',\n path: this.workspacePath,\n specs: {\n total: this.specs.length,\n commands,\n queries,\n events,\n presentations,\n },\n files: {\n total: this.files.length,\n typescript: tsFiles,\n specFiles,\n },\n };\n }\n\n /**\n * Get a context summary for LLM prompts\n */\n getContextSummary(): string {\n const summary = this.getSummary();\n\n const parts: string[] = [\n `Workspace: ${summary.name}`,\n `Path: ${summary.path}`,\n '',\n '### Specs',\n `- Commands: ${summary.specs.commands}`,\n `- Queries: ${summary.specs.queries}`,\n `- Events: ${summary.specs.events}`,\n `- Presentations: ${summary.specs.presentations}`,\n ];\n\n if (this.specs.length > 0) {\n parts.push('', '### Available Specs');\n for (const spec of this.specs.slice(0, 20)) {\n parts.push(`- ${spec.name} (${spec.type})`);\n }\n if (this.specs.length > 20) {\n parts.push(`- ... and ${this.specs.length - 20} more`);\n }\n }\n\n return parts.join('\\n');\n }\n\n /**\n * Find specs matching a query\n */\n findSpecs(query: string): SpecInfo[] {\n const lowerQuery = query.toLowerCase();\n return this.specs.filter(\n (s) =>\n s.name.toLowerCase().includes(lowerQuery) ||\n s.description?.toLowerCase().includes(lowerQuery) ||\n s.tags?.some((t) => t.toLowerCase().includes(lowerQuery))\n );\n }\n\n /**\n * Find files matching a query\n */\n findFiles(query: string): FileInfo[] {\n const lowerQuery = query.toLowerCase();\n return this.files.filter(\n (f) =>\n f.path.toLowerCase().includes(lowerQuery) ||\n f.name.toLowerCase().includes(lowerQuery)\n );\n }\n}\n\n/**\n * Create a workspace context from a path\n */\nexport async function createWorkspaceContext(\n path: string,\n options?: Partial<WorkspaceContextConfig>\n): Promise<WorkspaceContext> {\n const context = new WorkspaceContext({\n workspacePath: path,\n ...options,\n });\n await context.initialize();\n return context;\n}\n"],"mappings":";;;;AAsEA,IAAa,mBAAb,MAA8B;CAC5B,AAAS;CACT,AAAS;CAET,AAAQ,QAAoB,EAAE;CAC9B,AAAQ,QAAoB,EAAE;CAC9B,AAAQ,cAAc;CAEtB,YAAY,QAAgC;AAC1C,OAAK,gBAAgB,OAAO;AAC5B,OAAK,cAAc,OAAO,eAAe;;;;;CAM3C,MAAM,aAA4B;AAChC,MAAI,KAAK,YAAa;AAItB,OAAK,cAAc;;;;;CAMrB,WAAuB;AACrB,SAAO,KAAK;;;;;CAMd,WAAuB;AACrB,SAAO,KAAK;;;;;CAMd,SAAS,OAAyB;AAChC,OAAK,MAAM,KAAK,GAAG,MAAM;;;;;CAM3B,SAAS,OAAyB;AAChC,OAAK,MAAM,KAAK,GAAG,MAAM;;;;;CAM3B,aAA+B;EAC7B,MAAM,WAAW,KAAK,MAAM,QAAQ,MAAM,EAAE,SAAS,UAAU,CAAC;EAChE,MAAM,UAAU,KAAK,MAAM,QAAQ,MAAM,EAAE,SAAS,QAAQ,CAAC;EAC7D,MAAM,SAAS,KAAK,MAAM,QAAQ,MAAM,EAAE,SAAS,QAAQ,CAAC;EAC5D,MAAM,gBAAgB,KAAK,MAAM,QAC9B,MAAM,EAAE,SAAS,eACnB,CAAC;EAEF,MAAM,UAAU,KAAK,MAAM,QAAQ,MAAM,EAAE,cAAc,MAAM,CAAC;EAChE,MAAM,YAAY,KAAK,MAAM,QAAQ,MAAM,EAAE,OAAO,CAAC;AAErD,SAAO;GACL,MAAM,KAAK,cAAc,MAAM,IAAI,CAAC,KAAK,IAAI;GAC7C,MAAM,KAAK;GACX,OAAO;IACL,OAAO,KAAK,MAAM;IAClB;IACA;IACA;IACA;IACD;GACD,OAAO;IACL,OAAO,KAAK,MAAM;IAClB,YAAY;IACZ;IACD;GACF;;;;;CAMH,oBAA4B;EAC1B,MAAM,UAAU,KAAK,YAAY;EAEjC,MAAMA,QAAkB;GACtB,cAAc,QAAQ;GACtB,SAAS,QAAQ;GACjB;GACA;GACA,eAAe,QAAQ,MAAM;GAC7B,cAAc,QAAQ,MAAM;GAC5B,aAAa,QAAQ,MAAM;GAC3B,oBAAoB,QAAQ,MAAM;GACnC;AAED,MAAI,KAAK,MAAM,SAAS,GAAG;AACzB,SAAM,KAAK,IAAI,sBAAsB;AACrC,QAAK,MAAM,QAAQ,KAAK,MAAM,MAAM,GAAG,GAAG,CACxC,OAAM,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,GAAG;AAE7C,OAAI,KAAK,MAAM,SAAS,GACtB,OAAM,KAAK,aAAa,KAAK,MAAM,SAAS,GAAG,OAAO;;AAI1D,SAAO,MAAM,KAAK,KAAK;;;;;CAMzB,UAAU,OAA2B;EACnC,MAAM,aAAa,MAAM,aAAa;AACtC,SAAO,KAAK,MAAM,QACf,MACC,EAAE,KAAK,aAAa,CAAC,SAAS,WAAW,IACzC,EAAE,aAAa,aAAa,CAAC,SAAS,WAAW,IACjD,EAAE,MAAM,MAAM,MAAM,EAAE,aAAa,CAAC,SAAS,WAAW,CAAC,CAC5D;;;;;CAMH,UAAU,OAA2B;EACnC,MAAM,aAAa,MAAM,aAAa;AACtC,SAAO,KAAK,MAAM,QACf,MACC,EAAE,KAAK,aAAa,CAAC,SAAS,WAAW,IACzC,EAAE,KAAK,aAAa,CAAC,SAAS,WAAW,CAC5C;;;;;;AAOL,eAAsB,uBACpB,MACA,SAC2B;CAC3B,MAAM,UAAU,IAAI,iBAAiB;EACnC,eAAe;EACf,GAAG;EACJ,CAAC;AACF,OAAM,QAAQ,YAAY;AAC1B,QAAO"}
1
+ {"version":3,"file":"workspace-context.js","names":[],"sources":["../../src/context/workspace-context.ts"],"sourcesContent":["/**\n * Workspace context management\n *\n * Provides access to specs, files, and codebase information\n * for context-aware AI chat assistance.\n */\n\n/**\n * Spec information for context\n */\nexport interface SpecInfo {\n name: string;\n version: string;\n type: 'command' | 'query' | 'event' | 'presentation';\n path: string;\n description?: string;\n tags?: string[];\n}\n\n/**\n * File information for context\n */\nexport interface FileInfo {\n path: string;\n relativePath: string;\n name: string;\n extension: string;\n size: number;\n isSpec: boolean;\n}\n\n/**\n * Workspace summary for context\n */\nexport interface WorkspaceSummary {\n name: string;\n path: string;\n specs: {\n total: number;\n commands: number;\n queries: number;\n events: number;\n presentations: number;\n };\n files: {\n total: number;\n typescript: number;\n specFiles: number;\n };\n}\n\n/**\n * Configuration for workspace context\n */\nexport interface WorkspaceContextConfig {\n /** Root path of the workspace */\n workspacePath: string;\n /** File patterns to include */\n includePatterns?: string[];\n /** File patterns to exclude */\n excludePatterns?: string[];\n /** Maximum file size to read (bytes) */\n maxFileSize?: number;\n /** Whether to enable file writes */\n allowWrites?: boolean;\n}\n\n/**\n * Workspace context for AI chat\n */\nexport class WorkspaceContext {\n readonly workspacePath: string;\n readonly allowWrites: boolean;\n\n private specs: SpecInfo[] = [];\n private files: FileInfo[] = [];\n private initialized = false;\n\n constructor(config: WorkspaceContextConfig) {\n this.workspacePath = config.workspacePath;\n this.allowWrites = config.allowWrites ?? false;\n }\n\n /**\n * Initialize the workspace context by scanning files\n */\n async initialize(): Promise<void> {\n if (this.initialized) return;\n\n // This would scan the workspace for specs and files\n // For now, we just mark as initialized\n this.initialized = true;\n }\n\n /**\n * Get all discovered specs\n */\n getSpecs(): SpecInfo[] {\n return this.specs;\n }\n\n /**\n * Get all discovered files\n */\n getFiles(): FileInfo[] {\n return this.files;\n }\n\n /**\n * Add specs to the context\n */\n addSpecs(specs: SpecInfo[]): void {\n this.specs.push(...specs);\n }\n\n /**\n * Add files to the context\n */\n addFiles(files: FileInfo[]): void {\n this.files.push(...files);\n }\n\n /**\n * Get a summary of the workspace for context\n */\n getSummary(): WorkspaceSummary {\n const commands = this.specs.filter((s) => s.type === 'command').length;\n const queries = this.specs.filter((s) => s.type === 'query').length;\n const events = this.specs.filter((s) => s.type === 'event').length;\n const presentations = this.specs.filter(\n (s) => s.type === 'presentation'\n ).length;\n\n const tsFiles = this.files.filter((f) => f.extension === '.ts').length;\n const specFiles = this.files.filter((f) => f.isSpec).length;\n\n return {\n name: this.workspacePath.split('/').pop() ?? 'workspace',\n path: this.workspacePath,\n specs: {\n total: this.specs.length,\n commands,\n queries,\n events,\n presentations,\n },\n files: {\n total: this.files.length,\n typescript: tsFiles,\n specFiles,\n },\n };\n }\n\n /**\n * Get a context summary for LLM prompts\n */\n getContextSummary(): string {\n const summary = this.getSummary();\n\n const parts: string[] = [\n `Workspace: ${summary.name}`,\n `Path: ${summary.path}`,\n '',\n '### Specs',\n `- Commands: ${summary.specs.commands}`,\n `- Queries: ${summary.specs.queries}`,\n `- Events: ${summary.specs.events}`,\n `- Presentations: ${summary.specs.presentations}`,\n ];\n\n if (this.specs.length > 0) {\n parts.push('', '### Available Specs');\n for (const spec of this.specs.slice(0, 20)) {\n parts.push(`- ${spec.name} (${spec.type})`);\n }\n if (this.specs.length > 20) {\n parts.push(`- ... and ${this.specs.length - 20} more`);\n }\n }\n\n return parts.join('\\n');\n }\n\n /**\n * Find specs matching a query\n */\n findSpecs(query: string): SpecInfo[] {\n const lowerQuery = query.toLowerCase();\n return this.specs.filter(\n (s) =>\n s.name.toLowerCase().includes(lowerQuery) ||\n s.description?.toLowerCase().includes(lowerQuery) ||\n s.tags?.some((t) => t.toLowerCase().includes(lowerQuery))\n );\n }\n\n /**\n * Find files matching a query\n */\n findFiles(query: string): FileInfo[] {\n const lowerQuery = query.toLowerCase();\n return this.files.filter(\n (f) =>\n f.path.toLowerCase().includes(lowerQuery) ||\n f.name.toLowerCase().includes(lowerQuery)\n );\n }\n}\n\n/**\n * Create a workspace context from a path\n */\nexport async function createWorkspaceContext(\n path: string,\n options?: Partial<WorkspaceContextConfig>\n): Promise<WorkspaceContext> {\n const context = new WorkspaceContext({\n workspacePath: path,\n ...options,\n });\n await context.initialize();\n return context;\n}\n"],"mappings":";;;;AAsEA,IAAa,mBAAb,MAA8B;CAC5B,AAAS;CACT,AAAS;CAET,AAAQ,QAAoB,EAAE;CAC9B,AAAQ,QAAoB,EAAE;CAC9B,AAAQ,cAAc;CAEtB,YAAY,QAAgC;AAC1C,OAAK,gBAAgB,OAAO;AAC5B,OAAK,cAAc,OAAO,eAAe;;;;;CAM3C,MAAM,aAA4B;AAChC,MAAI,KAAK,YAAa;AAItB,OAAK,cAAc;;;;;CAMrB,WAAuB;AACrB,SAAO,KAAK;;;;;CAMd,WAAuB;AACrB,SAAO,KAAK;;;;;CAMd,SAAS,OAAyB;AAChC,OAAK,MAAM,KAAK,GAAG,MAAM;;;;;CAM3B,SAAS,OAAyB;AAChC,OAAK,MAAM,KAAK,GAAG,MAAM;;;;;CAM3B,aAA+B;EAC7B,MAAM,WAAW,KAAK,MAAM,QAAQ,MAAM,EAAE,SAAS,UAAU,CAAC;EAChE,MAAM,UAAU,KAAK,MAAM,QAAQ,MAAM,EAAE,SAAS,QAAQ,CAAC;EAC7D,MAAM,SAAS,KAAK,MAAM,QAAQ,MAAM,EAAE,SAAS,QAAQ,CAAC;EAC5D,MAAM,gBAAgB,KAAK,MAAM,QAC9B,MAAM,EAAE,SAAS,eACnB,CAAC;EAEF,MAAM,UAAU,KAAK,MAAM,QAAQ,MAAM,EAAE,cAAc,MAAM,CAAC;EAChE,MAAM,YAAY,KAAK,MAAM,QAAQ,MAAM,EAAE,OAAO,CAAC;AAErD,SAAO;GACL,MAAM,KAAK,cAAc,MAAM,IAAI,CAAC,KAAK,IAAI;GAC7C,MAAM,KAAK;GACX,OAAO;IACL,OAAO,KAAK,MAAM;IAClB;IACA;IACA;IACA;IACD;GACD,OAAO;IACL,OAAO,KAAK,MAAM;IAClB,YAAY;IACZ;IACD;GACF;;;;;CAMH,oBAA4B;EAC1B,MAAM,UAAU,KAAK,YAAY;EAEjC,MAAM,QAAkB;GACtB,cAAc,QAAQ;GACtB,SAAS,QAAQ;GACjB;GACA;GACA,eAAe,QAAQ,MAAM;GAC7B,cAAc,QAAQ,MAAM;GAC5B,aAAa,QAAQ,MAAM;GAC3B,oBAAoB,QAAQ,MAAM;GACnC;AAED,MAAI,KAAK,MAAM,SAAS,GAAG;AACzB,SAAM,KAAK,IAAI,sBAAsB;AACrC,QAAK,MAAM,QAAQ,KAAK,MAAM,MAAM,GAAG,GAAG,CACxC,OAAM,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,GAAG;AAE7C,OAAI,KAAK,MAAM,SAAS,GACtB,OAAM,KAAK,aAAa,KAAK,MAAM,SAAS,GAAG,OAAO;;AAI1D,SAAO,MAAM,KAAK,KAAK;;;;;CAMzB,UAAU,OAA2B;EACnC,MAAM,aAAa,MAAM,aAAa;AACtC,SAAO,KAAK,MAAM,QACf,MACC,EAAE,KAAK,aAAa,CAAC,SAAS,WAAW,IACzC,EAAE,aAAa,aAAa,CAAC,SAAS,WAAW,IACjD,EAAE,MAAM,MAAM,MAAM,EAAE,aAAa,CAAC,SAAS,WAAW,CAAC,CAC5D;;;;;CAMH,UAAU,OAA2B;EACnC,MAAM,aAAa,MAAM,aAAa;AACtC,SAAO,KAAK,MAAM,QACf,MACC,EAAE,KAAK,aAAa,CAAC,SAAS,WAAW,IACzC,EAAE,KAAK,aAAa,CAAC,SAAS,WAAW,CAC5C;;;;;;AAOL,eAAsB,uBACpB,MACA,SAC2B;CAC3B,MAAM,UAAU,IAAI,iBAAiB;EACnC,eAAe;EACf,GAAG;EACJ,CAAC;AACF,OAAM,QAAQ,YAAY;AAC1B,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"chat-service.js","names":["conversation: ChatConversation"],"sources":["../../src/core/chat-service.ts"],"sourcesContent":["/**\n * Main chat orchestration service\n */\nimport { generateText, streamText } from 'ai';\nimport type { Provider as ChatProvider } from '@contractspec/lib.ai-providers';\nimport type { WorkspaceContext } from '../context/workspace-context';\nimport type { ConversationStore } from './conversation-store';\nimport { InMemoryConversationStore } from './conversation-store';\nimport type {\n ChatConversation,\n ChatStreamChunk,\n SendMessageOptions,\n SendMessageResult,\n StreamMessageResult,\n} from './message-types';\n\n/**\n * Configuration for ChatService\n */\nexport interface ChatServiceConfig {\n /** LLM provider to use */\n provider: ChatProvider;\n /** Optional workspace context for code-aware chat */\n context?: WorkspaceContext;\n /** Optional conversation store (defaults to in-memory) */\n store?: ConversationStore;\n /** Default system prompt */\n systemPrompt?: string;\n /** Maximum conversation history to include */\n maxHistoryMessages?: number;\n /** Callback for usage tracking */\n onUsage?: (usage: { inputTokens: number; outputTokens: number }) => void;\n}\n\n/**\n * Default system prompt for ContractSpec vibe coding\n */\nconst DEFAULT_SYSTEM_PROMPT = `You are ContractSpec AI, an expert coding assistant specialized in ContractSpec development.\n\nYour capabilities:\n- Help users create, modify, and understand ContractSpec specifications\n- Generate code that follows ContractSpec patterns and best practices\n- Explain concepts from the ContractSpec documentation\n- Suggest improvements and identify issues in specs and implementations\n\nGuidelines:\n- Be concise but thorough\n- Provide code examples when helpful\n- Reference relevant ContractSpec concepts and patterns\n- Ask clarifying questions when the user's intent is unclear\n- When suggesting code changes, explain the rationale`;\n\n/**\n * Main chat service for AI-powered conversations\n */\nexport class ChatService {\n private readonly provider: ChatProvider;\n private readonly context?: WorkspaceContext;\n private readonly store: ConversationStore;\n private readonly systemPrompt: string;\n private readonly maxHistoryMessages: number;\n private readonly onUsage?: (usage: {\n inputTokens: number;\n outputTokens: number;\n }) => void;\n\n constructor(config: ChatServiceConfig) {\n this.provider = config.provider;\n this.context = config.context;\n this.store = config.store ?? new InMemoryConversationStore();\n this.systemPrompt = config.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;\n this.maxHistoryMessages = config.maxHistoryMessages ?? 20;\n this.onUsage = config.onUsage;\n }\n\n /**\n * Send a message and get a complete response\n */\n async send(options: SendMessageOptions): Promise<SendMessageResult> {\n // Get or create conversation\n let conversation: ChatConversation;\n if (options.conversationId) {\n const existing = await this.store.get(options.conversationId);\n if (!existing) {\n throw new Error(`Conversation ${options.conversationId} not found`);\n }\n conversation = existing;\n } else {\n conversation = await this.store.create({\n status: 'active',\n provider: this.provider.name,\n model: this.provider.model,\n messages: [],\n workspacePath: this.context?.workspacePath,\n });\n }\n\n // Add user message\n await this.store.appendMessage(conversation.id, {\n role: 'user',\n content: options.content,\n status: 'completed',\n attachments: options.attachments,\n });\n\n // Build prompt from messages\n const prompt = this.buildPrompt(conversation, options);\n\n // Get the language model\n const model = this.provider.getModel();\n\n try {\n // Generate response\n const result = await generateText({\n model,\n prompt,\n system: this.systemPrompt,\n });\n\n // Save assistant message\n const assistantMessage = await this.store.appendMessage(conversation.id, {\n role: 'assistant',\n content: result.text,\n status: 'completed',\n });\n\n // Refresh conversation\n const updatedConversation = await this.store.get(conversation.id);\n if (!updatedConversation) {\n throw new Error('Conversation lost after update');\n }\n\n return {\n message: assistantMessage,\n conversation: updatedConversation,\n };\n } catch (error) {\n // Save error message\n await this.store.appendMessage(conversation.id, {\n role: 'assistant',\n content: '',\n status: 'error',\n error: {\n code: 'generation_failed',\n message: error instanceof Error ? error.message : String(error),\n },\n });\n\n throw error;\n }\n }\n\n /**\n * Send a message and get a streaming response\n */\n async stream(options: SendMessageOptions): Promise<StreamMessageResult> {\n // Get or create conversation\n let conversation: ChatConversation;\n if (options.conversationId) {\n const existing = await this.store.get(options.conversationId);\n if (!existing) {\n throw new Error(`Conversation ${options.conversationId} not found`);\n }\n conversation = existing;\n } else {\n conversation = await this.store.create({\n status: 'active',\n provider: this.provider.name,\n model: this.provider.model,\n messages: [],\n workspacePath: this.context?.workspacePath,\n });\n }\n\n // Add user message\n await this.store.appendMessage(conversation.id, {\n role: 'user',\n content: options.content,\n status: 'completed',\n attachments: options.attachments,\n });\n\n // Create placeholder for assistant message\n const assistantMessage = await this.store.appendMessage(conversation.id, {\n role: 'assistant',\n content: '',\n status: 'streaming',\n });\n\n // Build prompt\n const prompt = this.buildPrompt(conversation, options);\n\n // Get the language model\n const model = this.provider.getModel();\n\n // Create async generator for streaming\n const self = {\n systemPrompt: this.systemPrompt,\n store: this.store,\n };\n async function* streamGenerator(): AsyncIterable<ChatStreamChunk> {\n let fullContent = '';\n\n try {\n const result = streamText({\n model,\n prompt,\n system: self.systemPrompt,\n });\n\n for await (const chunk of result.textStream) {\n fullContent += chunk;\n yield { type: 'text', content: chunk };\n }\n\n // Update message with final content\n await self.store.updateMessage(conversation.id, assistantMessage.id, {\n content: fullContent,\n status: 'completed',\n });\n\n yield {\n type: 'done',\n };\n } catch (error) {\n await self.store.updateMessage(conversation.id, assistantMessage.id, {\n content: fullContent,\n status: 'error',\n error: {\n code: 'stream_failed',\n message: error instanceof Error ? error.message : String(error),\n },\n });\n\n yield {\n type: 'error',\n error: {\n code: 'stream_failed',\n message: error instanceof Error ? error.message : String(error),\n },\n };\n }\n }\n\n return {\n conversationId: conversation.id,\n messageId: assistantMessage.id,\n stream: streamGenerator(),\n };\n }\n\n /**\n * Get a conversation by ID\n */\n async getConversation(\n conversationId: string\n ): Promise<ChatConversation | null> {\n return this.store.get(conversationId);\n }\n\n /**\n * List conversations\n */\n async listConversations(options?: {\n limit?: number;\n offset?: number;\n }): Promise<ChatConversation[]> {\n return this.store.list({\n status: 'active',\n ...options,\n });\n }\n\n /**\n * Delete a conversation\n */\n async deleteConversation(conversationId: string): Promise<boolean> {\n return this.store.delete(conversationId);\n }\n\n /**\n * Build prompt string for LLM\n */\n private buildPrompt(\n conversation: ChatConversation,\n options: SendMessageOptions\n ): string {\n let prompt = '';\n\n // Add conversation history (limited)\n const historyStart = Math.max(\n 0,\n conversation.messages.length - this.maxHistoryMessages\n );\n for (let i = historyStart; i < conversation.messages.length; i++) {\n const msg = conversation.messages[i];\n if (!msg) continue;\n if (msg.role === 'user' || msg.role === 'assistant') {\n prompt += `${msg.role === 'user' ? 'User' : 'Assistant'}: ${msg.content}\\n\\n`;\n }\n }\n\n // Add current message with attachments\n let content = options.content;\n if (options.attachments?.length) {\n const attachmentInfo = options.attachments\n .map((a) => {\n if (a.type === 'file' || a.type === 'code') {\n return `\\n\\n### ${a.name}\\n\\`\\`\\`\\n${a.content}\\n\\`\\`\\``;\n }\n return `\\n\\n[Attachment: ${a.name}]`;\n })\n .join('');\n content += attachmentInfo;\n }\n\n prompt += `User: ${content}\\n\\nAssistant:`;\n\n return prompt;\n }\n}\n\n/**\n * Create a chat service with the given configuration\n */\nexport function createChatService(config: ChatServiceConfig): ChatService {\n return new ChatService(config);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"chat-service.js","names":[],"sources":["../../src/core/chat-service.ts"],"sourcesContent":["/**\n * Main chat orchestration service\n */\nimport { generateText, streamText } from 'ai';\nimport type { Provider as ChatProvider } from '@contractspec/lib.ai-providers';\nimport type { WorkspaceContext } from '../context/workspace-context';\nimport type { ConversationStore } from './conversation-store';\nimport { InMemoryConversationStore } from './conversation-store';\nimport type {\n ChatConversation,\n ChatStreamChunk,\n SendMessageOptions,\n SendMessageResult,\n StreamMessageResult,\n} from './message-types';\n\n/**\n * Configuration for ChatService\n */\nexport interface ChatServiceConfig {\n /** LLM provider to use */\n provider: ChatProvider;\n /** Optional workspace context for code-aware chat */\n context?: WorkspaceContext;\n /** Optional conversation store (defaults to in-memory) */\n store?: ConversationStore;\n /** Default system prompt */\n systemPrompt?: string;\n /** Maximum conversation history to include */\n maxHistoryMessages?: number;\n /** Callback for usage tracking */\n onUsage?: (usage: { inputTokens: number; outputTokens: number }) => void;\n}\n\n/**\n * Default system prompt for ContractSpec vibe coding\n */\nconst DEFAULT_SYSTEM_PROMPT = `You are ContractSpec AI, an expert coding assistant specialized in ContractSpec development.\n\nYour capabilities:\n- Help users create, modify, and understand ContractSpec specifications\n- Generate code that follows ContractSpec patterns and best practices\n- Explain concepts from the ContractSpec documentation\n- Suggest improvements and identify issues in specs and implementations\n\nGuidelines:\n- Be concise but thorough\n- Provide code examples when helpful\n- Reference relevant ContractSpec concepts and patterns\n- Ask clarifying questions when the user's intent is unclear\n- When suggesting code changes, explain the rationale`;\n\n/**\n * Main chat service for AI-powered conversations\n */\nexport class ChatService {\n private readonly provider: ChatProvider;\n private readonly context?: WorkspaceContext;\n private readonly store: ConversationStore;\n private readonly systemPrompt: string;\n private readonly maxHistoryMessages: number;\n private readonly onUsage?: (usage: {\n inputTokens: number;\n outputTokens: number;\n }) => void;\n\n constructor(config: ChatServiceConfig) {\n this.provider = config.provider;\n this.context = config.context;\n this.store = config.store ?? new InMemoryConversationStore();\n this.systemPrompt = config.systemPrompt ?? DEFAULT_SYSTEM_PROMPT;\n this.maxHistoryMessages = config.maxHistoryMessages ?? 20;\n this.onUsage = config.onUsage;\n }\n\n /**\n * Send a message and get a complete response\n */\n async send(options: SendMessageOptions): Promise<SendMessageResult> {\n // Get or create conversation\n let conversation: ChatConversation;\n if (options.conversationId) {\n const existing = await this.store.get(options.conversationId);\n if (!existing) {\n throw new Error(`Conversation ${options.conversationId} not found`);\n }\n conversation = existing;\n } else {\n conversation = await this.store.create({\n status: 'active',\n provider: this.provider.name,\n model: this.provider.model,\n messages: [],\n workspacePath: this.context?.workspacePath,\n });\n }\n\n // Add user message\n await this.store.appendMessage(conversation.id, {\n role: 'user',\n content: options.content,\n status: 'completed',\n attachments: options.attachments,\n });\n\n // Build prompt from messages\n const prompt = this.buildPrompt(conversation, options);\n\n // Get the language model\n const model = this.provider.getModel();\n\n try {\n // Generate response\n const result = await generateText({\n model,\n prompt,\n system: this.systemPrompt,\n });\n\n // Save assistant message\n const assistantMessage = await this.store.appendMessage(conversation.id, {\n role: 'assistant',\n content: result.text,\n status: 'completed',\n });\n\n // Refresh conversation\n const updatedConversation = await this.store.get(conversation.id);\n if (!updatedConversation) {\n throw new Error('Conversation lost after update');\n }\n\n return {\n message: assistantMessage,\n conversation: updatedConversation,\n };\n } catch (error) {\n // Save error message\n await this.store.appendMessage(conversation.id, {\n role: 'assistant',\n content: '',\n status: 'error',\n error: {\n code: 'generation_failed',\n message: error instanceof Error ? error.message : String(error),\n },\n });\n\n throw error;\n }\n }\n\n /**\n * Send a message and get a streaming response\n */\n async stream(options: SendMessageOptions): Promise<StreamMessageResult> {\n // Get or create conversation\n let conversation: ChatConversation;\n if (options.conversationId) {\n const existing = await this.store.get(options.conversationId);\n if (!existing) {\n throw new Error(`Conversation ${options.conversationId} not found`);\n }\n conversation = existing;\n } else {\n conversation = await this.store.create({\n status: 'active',\n provider: this.provider.name,\n model: this.provider.model,\n messages: [],\n workspacePath: this.context?.workspacePath,\n });\n }\n\n // Add user message\n await this.store.appendMessage(conversation.id, {\n role: 'user',\n content: options.content,\n status: 'completed',\n attachments: options.attachments,\n });\n\n // Create placeholder for assistant message\n const assistantMessage = await this.store.appendMessage(conversation.id, {\n role: 'assistant',\n content: '',\n status: 'streaming',\n });\n\n // Build prompt\n const prompt = this.buildPrompt(conversation, options);\n\n // Get the language model\n const model = this.provider.getModel();\n\n // Create async generator for streaming\n const self = {\n systemPrompt: this.systemPrompt,\n store: this.store,\n };\n async function* streamGenerator(): AsyncIterable<ChatStreamChunk> {\n let fullContent = '';\n\n try {\n const result = streamText({\n model,\n prompt,\n system: self.systemPrompt,\n });\n\n for await (const chunk of result.textStream) {\n fullContent += chunk;\n yield { type: 'text', content: chunk };\n }\n\n // Update message with final content\n await self.store.updateMessage(conversation.id, assistantMessage.id, {\n content: fullContent,\n status: 'completed',\n });\n\n yield {\n type: 'done',\n };\n } catch (error) {\n await self.store.updateMessage(conversation.id, assistantMessage.id, {\n content: fullContent,\n status: 'error',\n error: {\n code: 'stream_failed',\n message: error instanceof Error ? error.message : String(error),\n },\n });\n\n yield {\n type: 'error',\n error: {\n code: 'stream_failed',\n message: error instanceof Error ? error.message : String(error),\n },\n };\n }\n }\n\n return {\n conversationId: conversation.id,\n messageId: assistantMessage.id,\n stream: streamGenerator(),\n };\n }\n\n /**\n * Get a conversation by ID\n */\n async getConversation(\n conversationId: string\n ): Promise<ChatConversation | null> {\n return this.store.get(conversationId);\n }\n\n /**\n * List conversations\n */\n async listConversations(options?: {\n limit?: number;\n offset?: number;\n }): Promise<ChatConversation[]> {\n return this.store.list({\n status: 'active',\n ...options,\n });\n }\n\n /**\n * Delete a conversation\n */\n async deleteConversation(conversationId: string): Promise<boolean> {\n return this.store.delete(conversationId);\n }\n\n /**\n * Build prompt string for LLM\n */\n private buildPrompt(\n conversation: ChatConversation,\n options: SendMessageOptions\n ): string {\n let prompt = '';\n\n // Add conversation history (limited)\n const historyStart = Math.max(\n 0,\n conversation.messages.length - this.maxHistoryMessages\n );\n for (let i = historyStart; i < conversation.messages.length; i++) {\n const msg = conversation.messages[i];\n if (!msg) continue;\n if (msg.role === 'user' || msg.role === 'assistant') {\n prompt += `${msg.role === 'user' ? 'User' : 'Assistant'}: ${msg.content}\\n\\n`;\n }\n }\n\n // Add current message with attachments\n let content = options.content;\n if (options.attachments?.length) {\n const attachmentInfo = options.attachments\n .map((a) => {\n if (a.type === 'file' || a.type === 'code') {\n return `\\n\\n### ${a.name}\\n\\`\\`\\`\\n${a.content}\\n\\`\\`\\``;\n }\n return `\\n\\n[Attachment: ${a.name}]`;\n })\n .join('');\n content += attachmentInfo;\n }\n\n prompt += `User: ${content}\\n\\nAssistant:`;\n\n return prompt;\n }\n}\n\n/**\n * Create a chat service with the given configuration\n */\nexport function createChatService(config: ChatServiceConfig): ChatService {\n return new ChatService(config);\n}\n"],"mappings":"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"}