@contractspec/module.ai-chat 1.44.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.
Files changed (105) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +169 -0
  3. package/dist/ai-chat.feature.d.ts +12 -0
  4. package/dist/ai-chat.feature.d.ts.map +1 -0
  5. package/dist/ai-chat.feature.js +95 -0
  6. package/dist/ai-chat.feature.js.map +1 -0
  7. package/dist/ai-chat.operations.d.ts +243 -0
  8. package/dist/ai-chat.operations.d.ts.map +1 -0
  9. package/dist/ai-chat.operations.js +174 -0
  10. package/dist/ai-chat.operations.js.map +1 -0
  11. package/dist/context/context-builder.d.ts +57 -0
  12. package/dist/context/context-builder.d.ts.map +1 -0
  13. package/dist/context/context-builder.js +148 -0
  14. package/dist/context/context-builder.js.map +1 -0
  15. package/dist/context/file-operations.d.ts +100 -0
  16. package/dist/context/file-operations.d.ts.map +1 -0
  17. package/dist/context/file-operations.js +175 -0
  18. package/dist/context/file-operations.js.map +1 -0
  19. package/dist/context/index.d.ts +4 -0
  20. package/dist/context/index.js +5 -0
  21. package/dist/context/workspace-context.d.ts +117 -0
  22. package/dist/context/workspace-context.d.ts.map +1 -0
  23. package/dist/context/workspace-context.js +124 -0
  24. package/dist/context/workspace-context.js.map +1 -0
  25. package/dist/core/chat-service.d.ts +73 -0
  26. package/dist/core/chat-service.d.ts.map +1 -0
  27. package/dist/core/chat-service.js +227 -0
  28. package/dist/core/chat-service.js.map +1 -0
  29. package/dist/core/conversation-store.d.ts +74 -0
  30. package/dist/core/conversation-store.d.ts.map +1 -0
  31. package/dist/core/conversation-store.js +109 -0
  32. package/dist/core/conversation-store.js.map +1 -0
  33. package/dist/core/index.d.ts +4 -0
  34. package/dist/core/index.js +4 -0
  35. package/dist/core/message-types.d.ts +150 -0
  36. package/dist/core/message-types.d.ts.map +1 -0
  37. package/dist/events.d.ts +115 -0
  38. package/dist/events.d.ts.map +1 -0
  39. package/dist/events.js +100 -0
  40. package/dist/events.js.map +1 -0
  41. package/dist/index.d.ts +21 -0
  42. package/dist/index.js +23 -0
  43. package/dist/libs/schema/dist/EnumType.js +2 -0
  44. package/dist/libs/schema/dist/FieldType.js +50 -0
  45. package/dist/libs/schema/dist/FieldType.js.map +1 -0
  46. package/dist/libs/schema/dist/GraphQLSchemaType.js +1 -0
  47. package/dist/libs/schema/dist/JsonSchemaType.js +1 -0
  48. package/dist/libs/schema/dist/ScalarTypeEnum.js +237 -0
  49. package/dist/libs/schema/dist/ScalarTypeEnum.js.map +1 -0
  50. package/dist/libs/schema/dist/SchemaModel.js +40 -0
  51. package/dist/libs/schema/dist/SchemaModel.js.map +1 -0
  52. package/dist/libs/schema/dist/ZodSchemaType.js +1 -0
  53. package/dist/libs/schema/dist/entity/defineEntity.js +1 -0
  54. package/dist/libs/schema/dist/entity/index.js +2 -0
  55. package/dist/libs/schema/dist/entity/types.js +1 -0
  56. package/dist/libs/schema/dist/index.js +9 -0
  57. package/dist/presentation/components/ChatContainer.d.ts +21 -0
  58. package/dist/presentation/components/ChatContainer.d.ts.map +1 -0
  59. package/dist/presentation/components/ChatContainer.js +63 -0
  60. package/dist/presentation/components/ChatContainer.js.map +1 -0
  61. package/dist/presentation/components/ChatInput.d.ts +35 -0
  62. package/dist/presentation/components/ChatInput.d.ts.map +1 -0
  63. package/dist/presentation/components/ChatInput.js +149 -0
  64. package/dist/presentation/components/ChatInput.js.map +1 -0
  65. package/dist/presentation/components/ChatMessage.d.ts +24 -0
  66. package/dist/presentation/components/ChatMessage.d.ts.map +1 -0
  67. package/dist/presentation/components/ChatMessage.js +136 -0
  68. package/dist/presentation/components/ChatMessage.js.map +1 -0
  69. package/dist/presentation/components/CodePreview.d.ts +40 -0
  70. package/dist/presentation/components/CodePreview.d.ts.map +1 -0
  71. package/dist/presentation/components/CodePreview.js +127 -0
  72. package/dist/presentation/components/CodePreview.js.map +1 -0
  73. package/dist/presentation/components/ContextIndicator.d.ts +26 -0
  74. package/dist/presentation/components/ContextIndicator.d.ts.map +1 -0
  75. package/dist/presentation/components/ContextIndicator.js +97 -0
  76. package/dist/presentation/components/ContextIndicator.js.map +1 -0
  77. package/dist/presentation/components/ModelPicker.d.ts +39 -0
  78. package/dist/presentation/components/ModelPicker.d.ts.map +1 -0
  79. package/dist/presentation/components/ModelPicker.js +202 -0
  80. package/dist/presentation/components/ModelPicker.js.map +1 -0
  81. package/dist/presentation/components/index.d.ts +7 -0
  82. package/dist/presentation/components/index.js +8 -0
  83. package/dist/presentation/hooks/index.d.ts +3 -0
  84. package/dist/presentation/hooks/index.js +4 -0
  85. package/dist/presentation/hooks/useChat.d.ts +67 -0
  86. package/dist/presentation/hooks/useChat.d.ts.map +1 -0
  87. package/dist/presentation/hooks/useChat.js +172 -0
  88. package/dist/presentation/hooks/useChat.js.map +1 -0
  89. package/dist/presentation/hooks/useProviders.d.ts +38 -0
  90. package/dist/presentation/hooks/useProviders.d.ts.map +1 -0
  91. package/dist/presentation/hooks/useProviders.js +41 -0
  92. package/dist/presentation/hooks/useProviders.js.map +1 -0
  93. package/dist/presentation/index.d.ts +11 -0
  94. package/dist/presentation/index.js +12 -0
  95. package/dist/providers/chat-utilities.d.ts +15 -0
  96. package/dist/providers/chat-utilities.d.ts.map +1 -0
  97. package/dist/providers/chat-utilities.js +17 -0
  98. package/dist/providers/chat-utilities.js.map +1 -0
  99. package/dist/providers/index.d.ts +3 -0
  100. package/dist/providers/index.js +4 -0
  101. package/dist/schema.d.ts +222 -0
  102. package/dist/schema.d.ts.map +1 -0
  103. package/dist/schema.js +102 -0
  104. package/dist/schema.js.map +1 -0
  105. package/package.json +80 -0
@@ -0,0 +1,174 @@
1
+ import { ScalarTypeEnum } from "./libs/schema/dist/ScalarTypeEnum.js";
2
+ import { defineSchemaModel } from "./libs/schema/dist/SchemaModel.js";
3
+ import "./libs/schema/dist/index.js";
4
+ import { ChatConversationModel, ListConversationsOutputModel, SendMessageInputModel, SendMessageOutputModel } from "./schema.js";
5
+ import { defineCommand, defineQuery } from "@contractspec/lib.contracts";
6
+
7
+ //#region src/ai-chat.operations.ts
8
+ const SendMessageContract = defineCommand({
9
+ meta: {
10
+ key: "ai-chat.send",
11
+ version: 1,
12
+ owners: ["@ai-team"],
13
+ stability: "experimental",
14
+ description: "Send a message to the AI chat.",
15
+ tags: ["chat", "send"],
16
+ goal: "Send message",
17
+ context: "Chat UI"
18
+ },
19
+ io: {
20
+ input: SendMessageInputModel,
21
+ output: SendMessageOutputModel
22
+ },
23
+ policy: { auth: "user" }
24
+ });
25
+ const StreamMessageOutputModel = defineSchemaModel({
26
+ name: "StreamMessageOutput",
27
+ fields: { stream: {
28
+ type: ScalarTypeEnum.String_unsecure(),
29
+ isOptional: false
30
+ } }
31
+ });
32
+ const StreamMessageContract = defineCommand({
33
+ meta: {
34
+ key: "ai-chat.stream",
35
+ version: 1,
36
+ owners: ["@ai-team"],
37
+ stability: "experimental",
38
+ description: "Stream a message response from the AI chat.",
39
+ tags: ["chat", "stream"],
40
+ goal: "Stream response",
41
+ context: "Chat UI"
42
+ },
43
+ io: {
44
+ input: SendMessageInputModel,
45
+ output: StreamMessageOutputModel
46
+ },
47
+ policy: { auth: "user" }
48
+ });
49
+ const ListConversationsContract = defineQuery({
50
+ meta: {
51
+ key: "ai-chat.conversations.list",
52
+ version: 1,
53
+ owners: ["@ai-team"],
54
+ stability: "experimental",
55
+ description: "List user conversations.",
56
+ tags: ["chat", "list"],
57
+ goal: "List conversations",
58
+ context: "Chat History"
59
+ },
60
+ io: {
61
+ input: defineSchemaModel({
62
+ name: "VoidInput",
63
+ fields: {}
64
+ }),
65
+ output: ListConversationsOutputModel
66
+ },
67
+ policy: { auth: "user" }
68
+ });
69
+ const GetConversationContract = defineQuery({
70
+ meta: {
71
+ key: "ai-chat.conversations.get",
72
+ version: 1,
73
+ owners: ["@ai-team"],
74
+ stability: "experimental",
75
+ description: "Get a specific conversation.",
76
+ tags: ["chat", "get"],
77
+ goal: "Get conversation",
78
+ context: "Chat UI"
79
+ },
80
+ io: {
81
+ input: defineSchemaModel({
82
+ name: "GetConversationInput",
83
+ fields: { id: {
84
+ type: ScalarTypeEnum.String_unsecure(),
85
+ isOptional: false
86
+ } }
87
+ }),
88
+ output: ChatConversationModel
89
+ },
90
+ policy: { auth: "user" }
91
+ });
92
+ const DeleteConversationContract = defineCommand({
93
+ meta: {
94
+ key: "ai-chat.conversations.delete",
95
+ version: 1,
96
+ owners: ["@ai-team"],
97
+ stability: "experimental",
98
+ description: "Delete a conversation.",
99
+ tags: ["chat", "delete"],
100
+ goal: "Delete conversation",
101
+ context: "Chat History"
102
+ },
103
+ io: {
104
+ input: defineSchemaModel({
105
+ name: "DeleteConversationInput",
106
+ fields: { id: {
107
+ type: ScalarTypeEnum.String_unsecure(),
108
+ isOptional: false
109
+ } }
110
+ }),
111
+ output: defineSchemaModel({
112
+ name: "VoidOutput",
113
+ fields: {}
114
+ })
115
+ },
116
+ policy: { auth: "user" }
117
+ });
118
+ const ListProvidersContract = defineQuery({
119
+ meta: {
120
+ key: "ai-chat.providers.list",
121
+ version: 1,
122
+ owners: ["@ai-team"],
123
+ stability: "experimental",
124
+ description: "List available AI providers.",
125
+ tags: ["chat", "providers"],
126
+ goal: "List providers",
127
+ context: "Settings"
128
+ },
129
+ io: {
130
+ input: defineSchemaModel({
131
+ name: "VoidInput2",
132
+ fields: {}
133
+ }),
134
+ output: defineSchemaModel({
135
+ name: "ProviderList",
136
+ fields: { providers: {
137
+ type: ScalarTypeEnum.String_unsecure(),
138
+ isArray: true,
139
+ isOptional: false
140
+ } }
141
+ })
142
+ },
143
+ policy: { auth: "user" }
144
+ });
145
+ const ScanContextContract = defineCommand({
146
+ meta: {
147
+ key: "ai-chat.context.scan",
148
+ version: 1,
149
+ owners: ["@ai-team"],
150
+ stability: "experimental",
151
+ description: "Scan workspace context.",
152
+ tags: ["chat", "context"],
153
+ goal: "Scan context",
154
+ context: "Background"
155
+ },
156
+ io: {
157
+ input: defineSchemaModel({
158
+ name: "ScanContextInput",
159
+ fields: { path: {
160
+ type: ScalarTypeEnum.String_unsecure(),
161
+ isOptional: false
162
+ } }
163
+ }),
164
+ output: defineSchemaModel({
165
+ name: "VoidOutput2",
166
+ fields: {}
167
+ })
168
+ },
169
+ policy: { auth: "user" }
170
+ });
171
+
172
+ //#endregion
173
+ export { DeleteConversationContract, GetConversationContract, ListConversationsContract, ListProvidersContract, ScanContextContract, SendMessageContract, StreamMessageContract };
174
+ //# sourceMappingURL=ai-chat.operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-chat.operations.js","names":[],"sources":["../src/ai-chat.operations.ts"],"sourcesContent":["import { defineCommand, defineQuery } from '@contractspec/lib.contracts';\nimport { ScalarTypeEnum, defineSchemaModel } from '@contractspec/lib.schema';\nimport {\n ChatConversationModel,\n ListConversationsOutputModel,\n SendMessageInputModel,\n SendMessageOutputModel,\n} from './schema';\n\nexport const SendMessageContract = defineCommand({\n meta: {\n key: 'ai-chat.send',\n version: 1,\n owners: ['@ai-team'],\n stability: 'experimental',\n description: 'Send a message to the AI chat.',\n tags: ['chat', 'send'],\n goal: 'Send message',\n context: 'Chat UI',\n },\n io: { input: SendMessageInputModel, output: SendMessageOutputModel },\n policy: { auth: 'user' },\n});\n\nconst StreamMessageOutputModel = defineSchemaModel({\n name: 'StreamMessageOutput',\n fields: {\n stream: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }, // Placeholder for stream content\n },\n});\n\nexport const StreamMessageContract = defineCommand({\n meta: {\n key: 'ai-chat.stream',\n version: 1,\n owners: ['@ai-team'],\n stability: 'experimental',\n description: 'Stream a message response from the AI chat.',\n tags: ['chat', 'stream'],\n goal: 'Stream response',\n context: 'Chat UI',\n },\n io: { input: SendMessageInputModel, output: StreamMessageOutputModel },\n policy: { auth: 'user' },\n});\n\nexport const ListConversationsContract = defineQuery({\n meta: {\n key: 'ai-chat.conversations.list',\n version: 1,\n owners: ['@ai-team'],\n stability: 'experimental',\n description: 'List user conversations.',\n tags: ['chat', 'list'],\n goal: 'List conversations',\n context: 'Chat History',\n },\n io: {\n input: defineSchemaModel({ name: 'VoidInput', fields: {} }),\n output: ListConversationsOutputModel,\n },\n policy: { auth: 'user' },\n});\n\nexport const GetConversationContract = defineQuery({\n meta: {\n key: 'ai-chat.conversations.get',\n version: 1,\n owners: ['@ai-team'],\n stability: 'experimental',\n description: 'Get a specific conversation.',\n tags: ['chat', 'get'],\n goal: 'Get conversation',\n context: 'Chat UI',\n },\n io: {\n input: defineSchemaModel({\n name: 'GetConversationInput',\n fields: {\n id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n },\n }),\n output: ChatConversationModel,\n },\n policy: { auth: 'user' },\n});\n\nexport const DeleteConversationContract = defineCommand({\n meta: {\n key: 'ai-chat.conversations.delete',\n version: 1,\n owners: ['@ai-team'],\n stability: 'experimental',\n description: 'Delete a conversation.',\n tags: ['chat', 'delete'],\n goal: 'Delete conversation',\n context: 'Chat History',\n },\n io: {\n input: defineSchemaModel({\n name: 'DeleteConversationInput',\n fields: {\n id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n },\n }),\n output: defineSchemaModel({ name: 'VoidOutput', fields: {} }),\n },\n policy: { auth: 'user' },\n});\n\nexport const ListProvidersContract = defineQuery({\n meta: {\n key: 'ai-chat.providers.list',\n version: 1,\n owners: ['@ai-team'],\n stability: 'experimental',\n description: 'List available AI providers.',\n tags: ['chat', 'providers'],\n goal: 'List providers',\n context: 'Settings',\n },\n io: {\n input: defineSchemaModel({ name: 'VoidInput2', fields: {} }),\n output: defineSchemaModel({\n name: 'ProviderList',\n fields: {\n providers: {\n type: ScalarTypeEnum.String_unsecure(),\n isArray: true,\n isOptional: false,\n },\n },\n }),\n },\n policy: { auth: 'user' },\n});\n\nexport const ScanContextContract = defineCommand({\n meta: {\n key: 'ai-chat.context.scan',\n version: 1,\n owners: ['@ai-team'],\n stability: 'experimental',\n description: 'Scan workspace context.',\n tags: ['chat', 'context'],\n goal: 'Scan context',\n context: 'Background',\n },\n io: {\n input: defineSchemaModel({\n name: 'ScanContextInput',\n fields: {\n path: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },\n },\n }),\n output: defineSchemaModel({ name: 'VoidOutput2', fields: {} }),\n },\n policy: { auth: 'user' },\n});\n"],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import { WorkspaceContext } from "./workspace-context.js";
2
+
3
+ //#region src/context/context-builder.d.ts
4
+
5
+ /**
6
+ * Context entry for a file or spec
7
+ */
8
+ interface ContextEntry {
9
+ type: 'spec' | 'file' | 'reference';
10
+ path: string;
11
+ content?: string;
12
+ summary?: string;
13
+ relevance: number;
14
+ }
15
+ /**
16
+ * Built context for LLM
17
+ */
18
+ interface BuiltContext {
19
+ entries: ContextEntry[];
20
+ summary: string;
21
+ totalTokensEstimate: number;
22
+ }
23
+ /**
24
+ * Options for building context
25
+ */
26
+ interface ContextBuilderOptions {
27
+ /** Maximum estimated tokens for context */
28
+ maxTokens?: number;
29
+ /** Query to use for relevance scoring */
30
+ query?: string;
31
+ /** Specific files to include */
32
+ includeFiles?: string[];
33
+ /** Specific specs to include */
34
+ includeSpecs?: string[];
35
+ }
36
+ /**
37
+ * Context builder for creating rich LLM context
38
+ */
39
+ declare class ContextBuilder {
40
+ private readonly context;
41
+ constructor(context: WorkspaceContext);
42
+ /**
43
+ * Build context for a chat message
44
+ */
45
+ build(options?: ContextBuilderOptions): BuiltContext;
46
+ /**
47
+ * Build a text summary of the context entries
48
+ */
49
+ private buildSummary;
50
+ }
51
+ /**
52
+ * Create a context builder
53
+ */
54
+ declare function createContextBuilder(context: WorkspaceContext): ContextBuilder;
55
+ //#endregion
56
+ export { BuiltContext, ContextBuilder, ContextBuilderOptions, ContextEntry, createContextBuilder };
57
+ //# sourceMappingURL=context-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-builder.d.ts","names":[],"sources":["../../src/context/context-builder.ts"],"sourcesContent":[],"mappings":";;;;AA0GA;;;AAU8C,UA1G7B,YAAA,CA0G6B;EAAY,IAAA,EAAA,MAAA,GAAA,MAAA,GAAA,WAAA;EAwI1C,IAAA,EAAA,MAAA;;;;;;;;UAvOC,YAAA;WACN;;;;;;;UAQM,qBAAA;;;;;;;;;;;;;cA4EJ,cAAA;;uBAGU;;;;kBAON,wBAA6B;;;;;;;;;iBAwI9B,oBAAA,UACL,mBACR"}
@@ -0,0 +1,148 @@
1
+ //#region src/context/context-builder.ts
2
+ /**
3
+ * Estimates token count from string (rough approximation)
4
+ */
5
+ function estimateTokens(text) {
6
+ return Math.ceil(text.length / 4);
7
+ }
8
+ /**
9
+ * Calculate relevance score for a spec
10
+ */
11
+ function scoreSpec(spec, query) {
12
+ if (!query) return .5;
13
+ const lowerQuery = query.toLowerCase();
14
+ let score = 0;
15
+ if (spec.name.toLowerCase().includes(lowerQuery)) score += .4;
16
+ if (spec.description?.toLowerCase().includes(lowerQuery)) score += .3;
17
+ if (spec.tags?.some((t) => t.toLowerCase().includes(lowerQuery))) score += .2;
18
+ return Math.min(score, 1);
19
+ }
20
+ /**
21
+ * Calculate relevance score for a file
22
+ */
23
+ function scoreFile(file, query) {
24
+ if (!query) return .5;
25
+ const lowerQuery = query.toLowerCase();
26
+ let score = 0;
27
+ if (file.path.toLowerCase().includes(lowerQuery)) score += .5;
28
+ if (file.name.toLowerCase().includes(lowerQuery)) score += .3;
29
+ if (file.isSpec) score += .2;
30
+ return Math.min(score, 1);
31
+ }
32
+ /**
33
+ * Context builder for creating rich LLM context
34
+ */
35
+ var ContextBuilder = class {
36
+ context;
37
+ constructor(context) {
38
+ this.context = context;
39
+ }
40
+ /**
41
+ * Build context for a chat message
42
+ */
43
+ build(options = {}) {
44
+ const maxTokens = options.maxTokens ?? 4e3;
45
+ const entries = [];
46
+ let totalTokens = 0;
47
+ if (options.includeSpecs?.length) for (const specName of options.includeSpecs) {
48
+ const spec = this.context.getSpecs().find((s) => s.name === specName);
49
+ if (spec) {
50
+ const entry = {
51
+ type: "spec",
52
+ path: spec.path,
53
+ summary: `${spec.type}: ${spec.name}${spec.description ? ` - ${spec.description}` : ""}`,
54
+ relevance: 1
55
+ };
56
+ entries.push(entry);
57
+ totalTokens += estimateTokens(entry.summary ?? "");
58
+ }
59
+ }
60
+ if (options.includeFiles?.length) for (const filePath of options.includeFiles) {
61
+ const file = this.context.getFiles().find((f) => f.path === filePath);
62
+ if (file) {
63
+ const entry = {
64
+ type: "file",
65
+ path: file.path,
66
+ summary: `File: ${file.relativePath}`,
67
+ relevance: 1
68
+ };
69
+ entries.push(entry);
70
+ totalTokens += estimateTokens(entry.summary ?? "");
71
+ }
72
+ }
73
+ if (options.query) {
74
+ const scoredSpecs = this.context.getSpecs().map((spec) => ({
75
+ spec,
76
+ score: scoreSpec(spec, options.query)
77
+ })).filter(({ score }) => score > .2).sort((a, b) => b.score - a.score);
78
+ for (const { spec, score } of scoredSpecs) {
79
+ if (totalTokens >= maxTokens) break;
80
+ if (entries.some((e) => e.path === spec.path)) continue;
81
+ const entry = {
82
+ type: "spec",
83
+ path: spec.path,
84
+ summary: `${spec.type}: ${spec.name}${spec.description ? ` - ${spec.description}` : ""}`,
85
+ relevance: score
86
+ };
87
+ entries.push(entry);
88
+ totalTokens += estimateTokens(entry.summary ?? "");
89
+ }
90
+ }
91
+ if (options.query) {
92
+ const scoredFiles = this.context.getFiles().map((file) => ({
93
+ file,
94
+ score: scoreFile(file, options.query)
95
+ })).filter(({ score }) => score > .2).sort((a, b) => b.score - a.score);
96
+ for (const { file, score } of scoredFiles) {
97
+ if (totalTokens >= maxTokens) break;
98
+ if (entries.some((e) => e.path === file.path)) continue;
99
+ const entry = {
100
+ type: "file",
101
+ path: file.path,
102
+ summary: `File: ${file.relativePath}`,
103
+ relevance: score
104
+ };
105
+ entries.push(entry);
106
+ totalTokens += estimateTokens(entry.summary ?? "");
107
+ }
108
+ }
109
+ const summary = this.buildSummary(entries);
110
+ return {
111
+ entries,
112
+ summary,
113
+ totalTokensEstimate: totalTokens + estimateTokens(summary)
114
+ };
115
+ }
116
+ /**
117
+ * Build a text summary of the context entries
118
+ */
119
+ buildSummary(entries) {
120
+ if (entries.length === 0) return this.context.getContextSummary();
121
+ const parts = [];
122
+ const workspaceSummary = this.context.getSummary();
123
+ parts.push(`Workspace: ${workspaceSummary.name}`);
124
+ parts.push("");
125
+ const specs = entries.filter((e) => e.type === "spec");
126
+ if (specs.length > 0) {
127
+ parts.push("### Relevant Specs");
128
+ for (const entry of specs) parts.push(`- ${entry.summary}`);
129
+ parts.push("");
130
+ }
131
+ const files = entries.filter((e) => e.type === "file");
132
+ if (files.length > 0) {
133
+ parts.push("### Relevant Files");
134
+ for (const entry of files) parts.push(`- ${entry.summary}`);
135
+ }
136
+ return parts.join("\n");
137
+ }
138
+ };
139
+ /**
140
+ * Create a context builder
141
+ */
142
+ function createContextBuilder(context) {
143
+ return new ContextBuilder(context);
144
+ }
145
+
146
+ //#endregion
147
+ export { ContextBuilder, createContextBuilder };
148
+ //# sourceMappingURL=context-builder.js.map
@@ -0,0 +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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"}
@@ -0,0 +1,100 @@
1
+ //#region src/context/file-operations.d.ts
2
+ /**
3
+ * File operations for workspace context
4
+ *
5
+ * Provides read/write operations for files in the workspace.
6
+ */
7
+ /**
8
+ * Result of a file read operation
9
+ */
10
+ interface FileReadResult {
11
+ success: boolean;
12
+ path: string;
13
+ content?: string;
14
+ error?: string;
15
+ }
16
+ /**
17
+ * Result of a file write operation
18
+ */
19
+ interface FileWriteResult {
20
+ success: boolean;
21
+ path: string;
22
+ error?: string;
23
+ }
24
+ /**
25
+ * File operation to perform
26
+ */
27
+ interface FileOperation {
28
+ type: 'read' | 'write' | 'create' | 'delete';
29
+ path: string;
30
+ content?: string;
31
+ }
32
+ /**
33
+ * Result of a file operation
34
+ */
35
+ interface FileOperationResult {
36
+ operation: FileOperation;
37
+ success: boolean;
38
+ content?: string;
39
+ error?: string;
40
+ }
41
+ /**
42
+ * Interface for file system operations
43
+ */
44
+ interface FileSystem {
45
+ /**
46
+ * Read a file's contents
47
+ */
48
+ readFile(path: string): Promise<string>;
49
+ /**
50
+ * Write content to a file
51
+ */
52
+ writeFile(path: string, content: string): Promise<void>;
53
+ /**
54
+ * Check if a file exists
55
+ */
56
+ exists(path: string): Promise<boolean>;
57
+ /**
58
+ * Delete a file
59
+ */
60
+ deleteFile(path: string): Promise<void>;
61
+ /**
62
+ * List files in a directory
63
+ */
64
+ listFiles(directory: string, options?: {
65
+ recursive?: boolean;
66
+ pattern?: string;
67
+ }): Promise<string[]>;
68
+ }
69
+ /**
70
+ * File operations executor
71
+ */
72
+ declare class FileOperations {
73
+ private readonly fs;
74
+ private readonly workspacePath;
75
+ private readonly allowWrites;
76
+ constructor(fs: FileSystem, workspacePath: string, allowWrites?: boolean);
77
+ /**
78
+ * Read a file
79
+ */
80
+ read(relativePath: string): Promise<FileReadResult>;
81
+ /**
82
+ * Write to a file
83
+ */
84
+ write(relativePath: string, content: string): Promise<FileWriteResult>;
85
+ /**
86
+ * Execute multiple file operations
87
+ */
88
+ execute(operations: FileOperation[]): Promise<FileOperationResult[]>;
89
+ /**
90
+ * Resolve a relative path to an absolute path
91
+ */
92
+ private resolvePath;
93
+ }
94
+ /**
95
+ * Create a file operations instance with Node.js fs
96
+ */
97
+ declare function createNodeFileOperations(workspacePath: string, allowWrites?: boolean): FileOperations;
98
+ //#endregion
99
+ export { FileOperation, FileOperationResult, FileOperations, FileReadResult, FileSystem, FileWriteResult, createNodeFileOperations };
100
+ //# sourceMappingURL=file-operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-operations.d.ts","names":[],"sources":["../../src/context/file-operations.ts"],"sourcesContent":[],"mappings":";;AASA;AAUA;AASA;AASA;AAUA;;;AAcwB,UApDP,cAAA,CAoDO;EAKI,OAAA,EAAA,OAAA;EAQvB,IAAA,EAAA,MAAA;EAAO,OAAA,CAAA,EAAA,MAAA;EAMC,KAAA,CAAA,EAAA,MAAA;;;;;AA4ByC,UAzFrC,eAAA,CAyFqC;EA0B1B,OAAA,EAAA,OAAA;EAA0B,IAAA,EAAA,MAAA;EAAR,KAAA,CAAA,EAAA,MAAA;;AAyF9C;;;UAnMiB,aAAA;;;;;;;;UASA,mBAAA;aACJ;;;;;;;;UASI,UAAA;;;;0BAIS;;;;4CAKkB;;;;wBAKpB;;;;4BAKI;;;;;;;MAQvB;;;;;cAMQ,cAAA;;;;kBAEY;;;;8BAQW,QAAQ;;;;gDAkBU,QAAQ;;;;sBA0BlC,kBAAkB,QAAQ;;;;;;;;;iBAyFtC,wBAAA,gDAGb"}