@contractspec/module.ai-chat 4.3.16 → 4.3.18

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,415 +1,3 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined")
5
- return require.apply(this, arguments);
6
- throw Error('Dynamic require of "' + x + '" is not supported');
7
- });
8
-
9
- // src/context/context-builder.ts
10
- function estimateTokens(text) {
11
- return Math.ceil(text.length / 4);
12
- }
13
- function scoreSpec(spec, query) {
14
- if (!query)
15
- return 0.5;
16
- const lowerQuery = query.toLowerCase();
17
- let score = 0;
18
- if (spec.name.toLowerCase().includes(lowerQuery)) {
19
- score += 0.4;
20
- }
21
- if (spec.description?.toLowerCase().includes(lowerQuery)) {
22
- score += 0.3;
23
- }
24
- if (spec.tags?.some((t) => t.toLowerCase().includes(lowerQuery))) {
25
- score += 0.2;
26
- }
27
- return Math.min(score, 1);
28
- }
29
- function scoreFile(file, query) {
30
- if (!query)
31
- return 0.5;
32
- const lowerQuery = query.toLowerCase();
33
- let score = 0;
34
- if (file.path.toLowerCase().includes(lowerQuery)) {
35
- score += 0.5;
36
- }
37
- if (file.name.toLowerCase().includes(lowerQuery)) {
38
- score += 0.3;
39
- }
40
- if (file.isSpec) {
41
- score += 0.2;
42
- }
43
- return Math.min(score, 1);
44
- }
45
-
46
- class ContextBuilder {
47
- context;
48
- constructor(context) {
49
- this.context = context;
50
- }
51
- build(options = {}) {
52
- const maxTokens = options.maxTokens ?? 4000;
53
- const entries = [];
54
- let totalTokens = 0;
55
- if (options.includeSpecs?.length) {
56
- for (const specName of options.includeSpecs) {
57
- const spec = this.context.getSpecs().find((s) => s.name === specName);
58
- if (spec) {
59
- const entry = {
60
- type: "spec",
61
- path: spec.path,
62
- summary: `${spec.type}: ${spec.name}${spec.description ? ` - ${spec.description}` : ""}`,
63
- relevance: 1
64
- };
65
- entries.push(entry);
66
- totalTokens += estimateTokens(entry.summary ?? "");
67
- }
68
- }
69
- }
70
- if (options.includeFiles?.length) {
71
- for (const filePath of options.includeFiles) {
72
- const file = this.context.getFiles().find((f) => f.path === filePath);
73
- if (file) {
74
- const entry = {
75
- type: "file",
76
- path: file.path,
77
- summary: `File: ${file.relativePath}`,
78
- relevance: 1
79
- };
80
- entries.push(entry);
81
- totalTokens += estimateTokens(entry.summary ?? "");
82
- }
83
- }
84
- }
85
- if (options.query) {
86
- const scoredSpecs = this.context.getSpecs().map((spec) => ({ spec, score: scoreSpec(spec, options.query) })).filter(({ score }) => score > 0.2).sort((a, b) => b.score - a.score);
87
- for (const { spec, score } of scoredSpecs) {
88
- if (totalTokens >= maxTokens)
89
- break;
90
- if (entries.some((e) => e.path === spec.path))
91
- continue;
92
- const entry = {
93
- type: "spec",
94
- path: spec.path,
95
- summary: `${spec.type}: ${spec.name}${spec.description ? ` - ${spec.description}` : ""}`,
96
- relevance: score
97
- };
98
- entries.push(entry);
99
- totalTokens += estimateTokens(entry.summary ?? "");
100
- }
101
- }
102
- if (options.query) {
103
- const scoredFiles = this.context.getFiles().map((file) => ({ file, score: scoreFile(file, options.query) })).filter(({ score }) => score > 0.2).sort((a, b) => b.score - a.score);
104
- for (const { file, score } of scoredFiles) {
105
- if (totalTokens >= maxTokens)
106
- break;
107
- if (entries.some((e) => e.path === file.path))
108
- continue;
109
- const entry = {
110
- type: "file",
111
- path: file.path,
112
- summary: `File: ${file.relativePath}`,
113
- relevance: score
114
- };
115
- entries.push(entry);
116
- totalTokens += estimateTokens(entry.summary ?? "");
117
- }
118
- }
119
- const summary = this.buildSummary(entries);
120
- return {
121
- entries,
122
- summary,
123
- totalTokensEstimate: totalTokens + estimateTokens(summary)
124
- };
125
- }
126
- buildSummary(entries) {
127
- if (entries.length === 0) {
128
- return this.context.getContextSummary();
129
- }
130
- const parts = [];
131
- const workspaceSummary = this.context.getSummary();
132
- parts.push(`Workspace: ${workspaceSummary.name}`);
133
- parts.push("");
134
- const specs = entries.filter((e) => e.type === "spec");
135
- if (specs.length > 0) {
136
- parts.push("### Relevant Specs");
137
- for (const entry of specs) {
138
- parts.push(`- ${entry.summary}`);
139
- }
140
- parts.push("");
141
- }
142
- const files = entries.filter((e) => e.type === "file");
143
- if (files.length > 0) {
144
- parts.push("### Relevant Files");
145
- for (const entry of files) {
146
- parts.push(`- ${entry.summary}`);
147
- }
148
- }
149
- return parts.join(`
150
- `);
151
- }
152
- }
153
- function createContextBuilder(context) {
154
- return new ContextBuilder(context);
155
- }
156
- // src/context/file-operations.ts
157
- class FileOperations {
158
- fs;
159
- workspacePath;
160
- allowWrites;
161
- constructor(fs, workspacePath, allowWrites = false) {
162
- this.fs = fs;
163
- this.workspacePath = workspacePath;
164
- this.allowWrites = allowWrites;
165
- }
166
- async read(relativePath) {
167
- const fullPath = this.resolvePath(relativePath);
168
- try {
169
- const content = await this.fs.readFile(fullPath);
170
- return { success: true, path: relativePath, content };
171
- } catch (error) {
172
- return {
173
- success: false,
174
- path: relativePath,
175
- error: error instanceof Error ? error.message : String(error)
176
- };
177
- }
178
- }
179
- async write(relativePath, content) {
180
- if (!this.allowWrites) {
181
- return {
182
- success: false,
183
- path: relativePath,
184
- error: "File writes are not enabled"
185
- };
186
- }
187
- const fullPath = this.resolvePath(relativePath);
188
- try {
189
- await this.fs.writeFile(fullPath, content);
190
- return { success: true, path: relativePath };
191
- } catch (error) {
192
- return {
193
- success: false,
194
- path: relativePath,
195
- error: error instanceof Error ? error.message : String(error)
196
- };
197
- }
198
- }
199
- async execute(operations) {
200
- const results = [];
201
- for (const operation of operations) {
202
- let result;
203
- switch (operation.type) {
204
- case "read": {
205
- const readResult = await this.read(operation.path);
206
- result = {
207
- operation,
208
- success: readResult.success,
209
- content: readResult.content,
210
- error: readResult.error
211
- };
212
- break;
213
- }
214
- case "write":
215
- case "create": {
216
- if (!operation.content) {
217
- result = {
218
- operation,
219
- success: false,
220
- error: "Content is required for write operations"
221
- };
222
- } else {
223
- const writeResult = await this.write(operation.path, operation.content);
224
- result = {
225
- operation,
226
- success: writeResult.success,
227
- error: writeResult.error
228
- };
229
- }
230
- break;
231
- }
232
- case "delete": {
233
- if (!this.allowWrites) {
234
- result = {
235
- operation,
236
- success: false,
237
- error: "File writes are not enabled"
238
- };
239
- } else {
240
- try {
241
- await this.fs.deleteFile(this.resolvePath(operation.path));
242
- result = { operation, success: true };
243
- } catch (error) {
244
- result = {
245
- operation,
246
- success: false,
247
- error: error instanceof Error ? error.message : String(error)
248
- };
249
- }
250
- }
251
- break;
252
- }
253
- default:
254
- result = {
255
- operation,
256
- success: false,
257
- error: `Unknown operation type: ${operation.type}`
258
- };
259
- }
260
- results.push(result);
261
- }
262
- return results;
263
- }
264
- resolvePath(relativePath) {
265
- const normalized = relativePath.replace(/\.\./g, "").replace(/^\//, "");
266
- return `${this.workspacePath}/${normalized}`;
267
- }
268
- }
269
- function createNodeFileOperations(workspacePath, allowWrites = false) {
270
- const fs = {
271
- async readFile(path) {
272
- const { readFile } = await import("node:fs/promises");
273
- return readFile(path, "utf-8");
274
- },
275
- async writeFile(path, content) {
276
- const { writeFile, mkdir } = await import("node:fs/promises");
277
- const { dirname } = await import("node:path");
278
- await mkdir(dirname(path), { recursive: true });
279
- await writeFile(path, content, "utf-8");
280
- },
281
- async exists(path) {
282
- const { access } = await import("node:fs/promises");
283
- try {
284
- await access(path);
285
- return true;
286
- } catch {
287
- return false;
288
- }
289
- },
290
- async deleteFile(path) {
291
- const { unlink } = await import("node:fs/promises");
292
- await unlink(path);
293
- },
294
- async listFiles(directory, options) {
295
- const { readdir } = await import("node:fs/promises");
296
- const { join } = await import("node:path");
297
- const files = [];
298
- const entries = await readdir(directory, { withFileTypes: true });
299
- for (const entry of entries) {
300
- const fullPath = join(directory, entry.name);
301
- if (entry.isDirectory() && options?.recursive) {
302
- const subFiles = await this.listFiles(fullPath, options);
303
- files.push(...subFiles);
304
- } else if (entry.isFile()) {
305
- if (!options?.pattern || entry.name.match(new RegExp(options.pattern))) {
306
- files.push(fullPath);
307
- }
308
- }
309
- }
310
- return files;
311
- }
312
- };
313
- return new FileOperations(fs, workspacePath, allowWrites);
314
- }
315
- // src/context/workspace-context.ts
316
- class WorkspaceContext {
317
- workspacePath;
318
- allowWrites;
319
- specs = [];
320
- files = [];
321
- initialized = false;
322
- constructor(config) {
323
- this.workspacePath = config.workspacePath;
324
- this.allowWrites = config.allowWrites ?? false;
325
- }
326
- async initialize() {
327
- if (this.initialized)
328
- return;
329
- this.initialized = true;
330
- }
331
- getSpecs() {
332
- return this.specs;
333
- }
334
- getFiles() {
335
- return this.files;
336
- }
337
- addSpecs(specs) {
338
- this.specs.push(...specs);
339
- }
340
- addFiles(files) {
341
- this.files.push(...files);
342
- }
343
- getSummary() {
344
- const commands = this.specs.filter((s) => s.type === "command").length;
345
- const queries = this.specs.filter((s) => s.type === "query").length;
346
- const events = this.specs.filter((s) => s.type === "event").length;
347
- const presentations = this.specs.filter((s) => s.type === "presentation").length;
348
- const tsFiles = this.files.filter((f) => f.extension === ".ts").length;
349
- const specFiles = this.files.filter((f) => f.isSpec).length;
350
- return {
351
- name: this.workspacePath.split("/").pop() ?? "workspace",
352
- path: this.workspacePath,
353
- specs: {
354
- total: this.specs.length,
355
- commands,
356
- queries,
357
- events,
358
- presentations
359
- },
360
- files: {
361
- total: this.files.length,
362
- typescript: tsFiles,
363
- specFiles
364
- }
365
- };
366
- }
367
- getContextSummary() {
368
- const summary = this.getSummary();
369
- const parts = [
370
- `Workspace: ${summary.name}`,
371
- `Path: ${summary.path}`,
372
- "",
373
- "### Specs",
374
- `- Commands: ${summary.specs.commands}`,
375
- `- Queries: ${summary.specs.queries}`,
376
- `- Events: ${summary.specs.events}`,
377
- `- Presentations: ${summary.specs.presentations}`
378
- ];
379
- if (this.specs.length > 0) {
380
- parts.push("", "### Available Specs");
381
- for (const spec of this.specs.slice(0, 20)) {
382
- parts.push(`- ${spec.name} (${spec.type})`);
383
- }
384
- if (this.specs.length > 20) {
385
- parts.push(`- ... and ${this.specs.length - 20} more`);
386
- }
387
- }
388
- return parts.join(`
389
- `);
390
- }
391
- findSpecs(query) {
392
- const lowerQuery = query.toLowerCase();
393
- return this.specs.filter((s) => s.name.toLowerCase().includes(lowerQuery) || s.description?.toLowerCase().includes(lowerQuery) || s.tags?.some((t) => t.toLowerCase().includes(lowerQuery)));
394
- }
395
- findFiles(query) {
396
- const lowerQuery = query.toLowerCase();
397
- return this.files.filter((f) => f.path.toLowerCase().includes(lowerQuery) || f.name.toLowerCase().includes(lowerQuery));
398
- }
399
- }
400
- async function createWorkspaceContext(path, options) {
401
- const context = new WorkspaceContext({
402
- workspacePath: path,
403
- ...options
404
- });
405
- await context.initialize();
406
- return context;
407
- }
408
- export {
409
- createWorkspaceContext,
410
- createNodeFileOperations,
411
- createContextBuilder,
412
- WorkspaceContext,
413
- FileOperations,
414
- ContextBuilder
415
- };
1
+ var V=((A)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(A,{get:(I,E)=>(typeof require<"u"?require:I)[E]}):A)(function(A){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+A+'" is not supported')});function X(A){return Math.ceil(A.length/4)}function z(A,I){if(!I)return 0.5;let E=I.toLowerCase(),H=0;if(A.name.toLowerCase().includes(E))H+=0.4;if(A.description?.toLowerCase().includes(E))H+=0.3;if(A.tags?.some((J)=>J.toLowerCase().includes(E)))H+=0.2;return Math.min(H,1)}function D(A,I){if(!I)return 0.5;let E=I.toLowerCase(),H=0;if(A.path.toLowerCase().includes(E))H+=0.5;if(A.name.toLowerCase().includes(E))H+=0.3;if(A.isSpec)H+=0.2;return Math.min(H,1)}class Z{context;constructor(A){this.context=A}build(A={}){let I=A.maxTokens??4000,E=[],H=0;if(A.includeSpecs?.length)for(let L of A.includeSpecs){let G=this.context.getSpecs().find((K)=>K.name===L);if(G){let K={type:"spec",path:G.path,summary:`${G.type}: ${G.name}${G.description?` - ${G.description}`:""}`,relevance:1};E.push(K),H+=X(K.summary??"")}}if(A.includeFiles?.length)for(let L of A.includeFiles){let G=this.context.getFiles().find((K)=>K.path===L);if(G){let K={type:"file",path:G.path,summary:`File: ${G.relativePath}`,relevance:1};E.push(K),H+=X(K.summary??"")}}if(A.query){let L=this.context.getSpecs().map((G)=>({spec:G,score:z(G,A.query)})).filter(({score:G})=>G>0.2).sort((G,K)=>K.score-G.score);for(let{spec:G,score:K}of L){if(H>=I)break;if(E.some((M)=>M.path===G.path))continue;let U={type:"spec",path:G.path,summary:`${G.type}: ${G.name}${G.description?` - ${G.description}`:""}`,relevance:K};E.push(U),H+=X(U.summary??"")}}if(A.query){let L=this.context.getFiles().map((G)=>({file:G,score:D(G,A.query)})).filter(({score:G})=>G>0.2).sort((G,K)=>K.score-G.score);for(let{file:G,score:K}of L){if(H>=I)break;if(E.some((M)=>M.path===G.path))continue;let U={type:"file",path:G.path,summary:`File: ${G.relativePath}`,relevance:K};E.push(U),H+=X(U.summary??"")}}let J=this.buildSummary(E);return{entries:E,summary:J,totalTokensEstimate:H+X(J)}}buildSummary(A){if(A.length===0)return this.context.getContextSummary();let I=[],E=this.context.getSummary();I.push(`Workspace: ${E.name}`),I.push("");let H=A.filter((L)=>L.type==="spec");if(H.length>0){I.push("### Relevant Specs");for(let L of H)I.push(`- ${L.summary}`);I.push("")}let J=A.filter((L)=>L.type==="file");if(J.length>0){I.push("### Relevant Files");for(let L of J)I.push(`- ${L.summary}`)}return I.join(`
2
+ `)}}function B(A){return new Z(A)}class _{fs;workspacePath;allowWrites;constructor(A,I,E=!1){this.fs=A;this.workspacePath=I;this.allowWrites=E}async read(A){let I=this.resolvePath(A);try{let E=await this.fs.readFile(I);return{success:!0,path:A,content:E}}catch(E){return{success:!1,path:A,error:E instanceof Error?E.message:String(E)}}}async write(A,I){if(!this.allowWrites)return{success:!1,path:A,error:"File writes are not enabled"};let E=this.resolvePath(A);try{return await this.fs.writeFile(E,I),{success:!0,path:A}}catch(H){return{success:!1,path:A,error:H instanceof Error?H.message:String(H)}}}async execute(A){let I=[];for(let E of A){let H;switch(E.type){case"read":{let J=await this.read(E.path);H={operation:E,success:J.success,content:J.content,error:J.error};break}case"write":case"create":{if(!E.content)H={operation:E,success:!1,error:"Content is required for write operations"};else{let J=await this.write(E.path,E.content);H={operation:E,success:J.success,error:J.error}}break}case"delete":{if(!this.allowWrites)H={operation:E,success:!1,error:"File writes are not enabled"};else try{await this.fs.deleteFile(this.resolvePath(E.path)),H={operation:E,success:!0}}catch(J){H={operation:E,success:!1,error:J instanceof Error?J.message:String(J)}}break}default:H={operation:E,success:!1,error:`Unknown operation type: ${E.type}`}}I.push(H)}return I}resolvePath(A){let I=A.replace(/\.\./g,"").replace(/^\//,"");return`${this.workspacePath}/${I}`}}function S(A,I=!1){return new _({async readFile(H){let{readFile:J}=await import("node:fs/promises");return J(H,"utf-8")},async writeFile(H,J){let{writeFile:L,mkdir:G}=await import("node:fs/promises"),{dirname:K}=await import("node:path");await G(K(H),{recursive:!0}),await L(H,J,"utf-8")},async exists(H){let{access:J}=await import("node:fs/promises");try{return await J(H),!0}catch{return!1}},async deleteFile(H){let{unlink:J}=await import("node:fs/promises");await J(H)},async listFiles(H,J){let{readdir:L}=await import("node:fs/promises"),{join:G}=await import("node:path"),K=[],U=await L(H,{withFileTypes:!0});for(let M of U){let Y=G(H,M.name);if(M.isDirectory()&&J?.recursive){let j=await this.listFiles(Y,J);K.push(...j)}else if(M.isFile()){if(!J?.pattern||M.name.match(new RegExp(J.pattern)))K.push(Y)}}return K}},A,I)}class ${workspacePath;allowWrites;specs=[];files=[];initialized=!1;constructor(A){this.workspacePath=A.workspacePath,this.allowWrites=A.allowWrites??!1}async initialize(){if(this.initialized)return;this.initialized=!0}getSpecs(){return this.specs}getFiles(){return this.files}addSpecs(A){this.specs.push(...A)}addFiles(A){this.files.push(...A)}getSummary(){let A=this.specs.filter((G)=>G.type==="command").length,I=this.specs.filter((G)=>G.type==="query").length,E=this.specs.filter((G)=>G.type==="event").length,H=this.specs.filter((G)=>G.type==="presentation").length,J=this.files.filter((G)=>G.extension===".ts").length,L=this.files.filter((G)=>G.isSpec).length;return{name:this.workspacePath.split("/").pop()??"workspace",path:this.workspacePath,specs:{total:this.specs.length,commands:A,queries:I,events:E,presentations:H},files:{total:this.files.length,typescript:J,specFiles:L}}}getContextSummary(){let A=this.getSummary(),I=[`Workspace: ${A.name}`,`Path: ${A.path}`,"","### Specs",`- Commands: ${A.specs.commands}`,`- Queries: ${A.specs.queries}`,`- Events: ${A.specs.events}`,`- Presentations: ${A.specs.presentations}`];if(this.specs.length>0){I.push("","### Available Specs");for(let E of this.specs.slice(0,20))I.push(`- ${E.name} (${E.type})`);if(this.specs.length>20)I.push(`- ... and ${this.specs.length-20} more`)}return I.join(`
3
+ `)}findSpecs(A){let I=A.toLowerCase();return this.specs.filter((E)=>E.name.toLowerCase().includes(I)||E.description?.toLowerCase().includes(I)||E.tags?.some((H)=>H.toLowerCase().includes(I)))}findFiles(A){let I=A.toLowerCase();return this.files.filter((E)=>E.path.toLowerCase().includes(I)||E.name.toLowerCase().includes(I))}}async function g(A,I){let E=new $({workspacePath:A,...I});return await E.initialize(),E}export{g as createWorkspaceContext,S as createNodeFileOperations,B as createContextBuilder,$ as WorkspaceContext,_ as FileOperations,Z as ContextBuilder};