@vedangiitb/qwintly-core 1.0.5 → 1.2.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 (30) hide show
  1. package/dist/core.d.ts +2 -2
  2. package/dist/core.d.ts.map +1 -1
  3. package/dist/core.js +6 -2
  4. package/dist/core.js.map +1 -1
  5. package/dist/logging/redis.service.d.ts.map +1 -1
  6. package/dist/logging/redis.service.js +4 -1
  7. package/dist/logging/redis.service.js.map +1 -1
  8. package/dist/tests/applyPatch.helpers.test.d.ts.map +1 -0
  9. package/dist/{ai/tools/helpers → tests}/applyPatch.helpers.test.js +1 -1
  10. package/dist/tests/applyPatch.helpers.test.js.map +1 -0
  11. package/dist/tests/applyPatch.impl.test.d.ts.map +1 -0
  12. package/dist/{ai/tools/implementations → tests}/applyPatch.impl.test.js +1 -1
  13. package/dist/tests/applyPatch.impl.test.js.map +1 -0
  14. package/dist/tests/fileSystem.helpers.test.d.ts.map +1 -0
  15. package/dist/{ai/tools/helpers → tests}/fileSystem.helpers.test.js +1 -1
  16. package/dist/tests/fileSystem.helpers.test.js.map +1 -0
  17. package/dist/tests/search.impl.test.d.ts +2 -0
  18. package/dist/tests/search.impl.test.d.ts.map +1 -0
  19. package/dist/tests/search.impl.test.js +90 -0
  20. package/dist/tests/search.impl.test.js.map +1 -0
  21. package/package.json +1 -1
  22. package/dist/ai/tools/helpers/applyPatch.helpers.test.d.ts.map +0 -1
  23. package/dist/ai/tools/helpers/applyPatch.helpers.test.js.map +0 -1
  24. package/dist/ai/tools/helpers/fileSystem.helpers.test.d.ts.map +0 -1
  25. package/dist/ai/tools/helpers/fileSystem.helpers.test.js.map +0 -1
  26. package/dist/ai/tools/implementations/applyPatch.impl.test.d.ts.map +0 -1
  27. package/dist/ai/tools/implementations/applyPatch.impl.test.js.map +0 -1
  28. /package/dist/{ai/tools/helpers → tests}/applyPatch.helpers.test.d.ts +0 -0
  29. /package/dist/{ai/tools/implementations → tests}/applyPatch.impl.test.d.ts +0 -0
  30. /package/dist/{ai/tools/helpers → tests}/fileSystem.helpers.test.d.ts +0 -0
package/dist/core.d.ts CHANGED
@@ -17,7 +17,7 @@ export type QwintlyCoreOptions = {
17
17
  url: string;
18
18
  token: string;
19
19
  };
20
- gemini: {
20
+ gemini?: {
21
21
  apiKey: string;
22
22
  model?: string;
23
23
  };
@@ -28,7 +28,7 @@ export declare class QwintlyCore {
28
28
  readonly workspacePath: string;
29
29
  readonly source: string;
30
30
  readonly step: GenStep;
31
- private readonly aiClient;
31
+ private readonly aiClient?;
32
32
  private readonly statusRepo;
33
33
  private readonly ctxRepo;
34
34
  private readonly redisStatusPublisher;
@@ -1 +1 @@
1
- {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,IAAI,EAAE,MAAM,eAAe,CAAC;AAEhE,OAAO,EAGL,WAAW,EACX,cAAc,EACf,MAAM,iCAAiC,CAAC;AASzC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,cAAc,EACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAGhE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C,CAAC;AAiBF,qBAAa,WAAW;IACtB,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC,SAAgB,aAAa,EAAE,MAAM,CAAC;IACtC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,IAAI,EAAE,OAAO,CAAC;IAE9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAoB;gBAE7C,OAAO,EAAE,kBAAkB;IA0C1B,SAAS,CACpB,eAAe,EAAE,GAAG,EAAE,EACtB,KAAK,EAAE,IAAI,EAAE,EACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,MAAM,EAAE,GAC1B,OAAO,CAAC,cAAc,CAAC;IAmBb,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B/D,mBAAmB,IAAI,OAAO,CAAC,WAAW,CAAC;YAQ1C,UAAU;IAMX,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC;IAIxC,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC;IAIxC,iBAAiB,IAAI,OAAO,CAAC,cAAc,CAAC;CAG1D"}
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,IAAI,EAAE,MAAM,eAAe,CAAC;AAEhE,OAAO,EAGL,WAAW,EACX,cAAc,EACf,MAAM,iCAAiC,CAAC;AASzC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,cAAc,EACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAGhE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,MAAM,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C,CAAC;AAiBF,qBAAa,WAAW;IACtB,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,SAAS,EAAE,MAAM,CAAC;IAClC,SAAgB,aAAa,EAAE,MAAM,CAAC;IACtC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,IAAI,EAAE,OAAO,CAAC;IAE9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAoB;gBAE7C,OAAO,EAAE,kBAAkB;IA2C1B,SAAS,CACpB,eAAe,EAAE,GAAG,EAAE,EACtB,KAAK,EAAE,IAAI,EAAE,EACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EACrC,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,MAAM,EAAE,GAC1B,OAAO,CAAC,cAAc,CAAC;IAwBb,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B/D,mBAAmB,IAAI,OAAO,CAAC,WAAW,CAAC;YAQ1C,UAAU;IAMX,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC;IAIxC,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC;IAIxC,iBAAiB,IAAI,OAAO,CAAC,cAAc,CAAC;CAG1D"}
package/dist/core.js CHANGED
@@ -20,19 +20,23 @@ export class QwintlyCore {
20
20
  assertNonEmptyString(options.supabase?.secret, "supabase.secret");
21
21
  assertNonEmptyString(options.upstash?.url, "upstash.url");
22
22
  assertNonEmptyString(options.upstash?.token, "upstash.token");
23
- assertNonEmptyString(options.gemini?.apiKey, "gemini.apiKey");
24
23
  this.chatId = options.chatId;
25
24
  this.sessionId = options.sessionId;
26
25
  this.workspacePath = options.workspacePath;
27
26
  this.source = options.source;
28
27
  this.step = options.step;
29
- this.aiClient = getClient("gemini", options.gemini.apiKey, options.gemini.model);
28
+ if (options.gemini?.apiKey) {
29
+ this.aiClient = getClient("gemini", options.gemini.apiKey, options.gemini.model);
30
+ }
30
31
  this.statusRepo = new GenStatusRepository(options.supabase.endpoint, options.supabase.secret);
31
32
  this.ctxRepo = new ContextRepository(options.supabase.endpoint, options.supabase.secret);
32
33
  this.redisStatusPublisher = new SendStatusToRedis(options.upstash.url, options.upstash.token);
33
34
  console.log(`QwintlyCore initialized (chatId=${this.chatId}, sessionId=${this.sessionId})`);
34
35
  }
35
36
  async runAiFlow(initialContents, tools, handlers, maxSteps, terminalToolNames) {
37
+ if (!this.aiClient) {
38
+ throw new Error("AI client not initialized. Please provide 'gemini' config to use runAiFlow.");
39
+ }
36
40
  const toolLoopOptions = {
37
41
  initialContents: initialContents,
38
42
  tools: tools,
package/dist/core.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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","sourcesContent":["import { FunctionCallingConfigMode, Tool } from \"@google/genai\";\nimport { getClient } from \"./ai/generate/generateClient.js\";\nimport {\n runToolLoop,\n RunToolLoopOptions,\n ToolHandler,\n ToolLoopResult,\n} from \"./ai/toolLoop/toolLoopRunner.js\";\nimport { buildCodegenIndex } from \"./indexer/codegenIndex.js\";\nimport { buildPlannerIndex } from \"./indexer/plannerIndex.js\";\nimport { computeProjectInfo } from \"./indexer/projectInfoIndex.js\";\nimport { buildValidatorIndex } from \"./indexer/validatorIndex.js\";\nimport { statusService } from \"./logging/genStatus.service.js\";\nimport { SendStatusToRedis } from \"./logging/redis.service.js\";\nimport { ContextRepository } from \"./repository/context.repository.js\";\nimport { GenStatusRepository } from \"./repository/genStatus.repository.js\";\nimport { EventType, GenStep } from \"./types/events.js\";\nimport {\n CodegenIndex,\n PlannerIndex,\n ValidatorIndex,\n} from \"./types/index/index.types.js\";\nimport type { ProjectInfo } from \"./types/projectInfo.types.js\";\nimport { assertNonEmptyString } from \"./utils/utils.js\";\n\nexport type QwintlyCoreOptions = {\n chatId: string;\n sessionId: string;\n workspacePath: string;\n source: string;\n step: GenStep;\n supabase: { endpoint: string; secret: string };\n upstash: { url: string; token: string };\n gemini: { apiKey: string; model?: string };\n};\n\ntype AiResponseOptions = {\n tools?: Tool[];\n toolCallingMode?: FunctionCallingConfigMode;\n};\n\ntype AiClient = {\n aiResponse: (\n request: unknown,\n options?: AiResponseOptions,\n ) => Promise<{\n functionCalls?: any[];\n text?: string;\n }>;\n};\n\nexport class QwintlyCore {\n public readonly chatId: string;\n public readonly sessionId: string;\n public readonly workspacePath: string;\n public readonly source: string;\n public readonly step: GenStep;\n\n private readonly aiClient: AiClient;\n private readonly statusRepo: GenStatusRepository;\n private readonly ctxRepo: ContextRepository;\n private readonly redisStatusPublisher: SendStatusToRedis;\n\n constructor(options: QwintlyCoreOptions) {\n assertNonEmptyString(options.chatId, \"chatId\");\n assertNonEmptyString(options.sessionId, \"sessionId\");\n assertNonEmptyString(options.workspacePath, \"workspacePath\");\n assertNonEmptyString(options.source, \"source\");\n assertNonEmptyString(options.step, \"step\");\n assertNonEmptyString(options.supabase?.endpoint, \"supabase.endpoint\");\n assertNonEmptyString(options.supabase?.secret, \"supabase.secret\");\n assertNonEmptyString(options.upstash?.url, \"upstash.url\");\n assertNonEmptyString(options.upstash?.token, \"upstash.token\");\n assertNonEmptyString(options.gemini?.apiKey, \"gemini.apiKey\");\n\n this.chatId = options.chatId;\n this.sessionId = options.sessionId;\n this.workspacePath = options.workspacePath;\n this.source = options.source;\n this.step = options.step;\n\n this.aiClient = getClient(\n \"gemini\",\n options.gemini.apiKey,\n options.gemini.model,\n ) as AiClient;\n\n this.statusRepo = new GenStatusRepository(\n options.supabase.endpoint,\n options.supabase.secret,\n );\n this.ctxRepo = new ContextRepository(\n options.supabase.endpoint,\n options.supabase.secret,\n );\n this.redisStatusPublisher = new SendStatusToRedis(\n options.upstash.url,\n options.upstash.token,\n );\n\n console.log(\n `QwintlyCore initialized (chatId=${this.chatId}, sessionId=${this.sessionId})`,\n );\n }\n\n public async runAiFlow(\n initialContents: any[],\n tools: Tool[],\n handlers: Record<string, ToolHandler>,\n maxSteps: number,\n terminalToolNames: string[],\n ): Promise<ToolLoopResult> {\n const toolLoopOptions: RunToolLoopOptions = {\n initialContents: initialContents,\n tools: tools,\n handlers: handlers,\n maxSteps: maxSteps,\n terminalToolNames: terminalToolNames,\n aiCall: (request, options) =>\n this.aiClient.aiResponse(request, {\n tools: options.tools,\n toolCallingMode: options.toolCallingMode,\n }),\n logger: this.streamLog.bind(this),\n };\n\n const result = await runToolLoop(toolLoopOptions);\n return result;\n }\n\n public async streamLog(message: string, eventType: EventType): Promise<void> {\n try {\n assertNonEmptyString(message, \"message\");\n await statusService(\n this.chatId,\n this.sessionId,\n eventType,\n this.step,\n message,\n this.source,\n {\n repository: {\n persist: this.statusRepo.persistStatusMessage.bind(this.statusRepo),\n },\n publisher: {\n publish: this.redisStatusPublisher.sendStatusToRedis.bind(\n this.redisStatusPublisher,\n ),\n },\n },\n );\n } catch (error) {\n console.error(error);\n }\n }\n\n public async buildProjectInfoIdx(): Promise<ProjectInfo> {\n const projectInfo = await computeProjectInfo(this.workspacePath);\n\n await this.ctxRepo.updateProjectInfo(this.chatId, projectInfo);\n\n return projectInfo;\n }\n\n private async buildIndex<T>(\n builder: (path: string) => Promise<T>,\n ): Promise<T> {\n return builder(this.workspacePath);\n }\n\n public async buildPlannerIdx(): Promise<PlannerIndex> {\n return this.buildIndex(buildPlannerIndex);\n }\n\n public async buildCodegenIdx(): Promise<CodegenIndex> {\n return this.buildIndex(buildCodegenIndex);\n }\n\n public async buildValidatorIdx(): Promise<ValidatorIndex> {\n return this.buildIndex(buildValidatorIndex);\n }\n}\n"]}
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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","sourcesContent":["import { FunctionCallingConfigMode, Tool } from \"@google/genai\";\nimport { getClient } from \"./ai/generate/generateClient.js\";\nimport {\n runToolLoop,\n RunToolLoopOptions,\n ToolHandler,\n ToolLoopResult,\n} from \"./ai/toolLoop/toolLoopRunner.js\";\nimport { buildCodegenIndex } from \"./indexer/codegenIndex.js\";\nimport { buildPlannerIndex } from \"./indexer/plannerIndex.js\";\nimport { computeProjectInfo } from \"./indexer/projectInfoIndex.js\";\nimport { buildValidatorIndex } from \"./indexer/validatorIndex.js\";\nimport { statusService } from \"./logging/genStatus.service.js\";\nimport { SendStatusToRedis } from \"./logging/redis.service.js\";\nimport { ContextRepository } from \"./repository/context.repository.js\";\nimport { GenStatusRepository } from \"./repository/genStatus.repository.js\";\nimport { EventType, GenStep } from \"./types/events.js\";\nimport {\n CodegenIndex,\n PlannerIndex,\n ValidatorIndex,\n} from \"./types/index/index.types.js\";\nimport type { ProjectInfo } from \"./types/projectInfo.types.js\";\nimport { assertNonEmptyString } from \"./utils/utils.js\";\n\nexport type QwintlyCoreOptions = {\n chatId: string;\n sessionId: string;\n workspacePath: string;\n source: string;\n step: GenStep;\n supabase: { endpoint: string; secret: string };\n upstash: { url: string; token: string };\n gemini?: { apiKey: string; model?: string };\n};\n\ntype AiResponseOptions = {\n tools?: Tool[];\n toolCallingMode?: FunctionCallingConfigMode;\n};\n\ntype AiClient = {\n aiResponse: (\n request: unknown,\n options?: AiResponseOptions,\n ) => Promise<{\n functionCalls?: any[];\n text?: string;\n }>;\n};\n\nexport class QwintlyCore {\n public readonly chatId: string;\n public readonly sessionId: string;\n public readonly workspacePath: string;\n public readonly source: string;\n public readonly step: GenStep;\n\n private readonly aiClient?: AiClient;\n private readonly statusRepo: GenStatusRepository;\n private readonly ctxRepo: ContextRepository;\n private readonly redisStatusPublisher: SendStatusToRedis;\n\n constructor(options: QwintlyCoreOptions) {\n assertNonEmptyString(options.chatId, \"chatId\");\n assertNonEmptyString(options.sessionId, \"sessionId\");\n assertNonEmptyString(options.workspacePath, \"workspacePath\");\n assertNonEmptyString(options.source, \"source\");\n assertNonEmptyString(options.step, \"step\");\n assertNonEmptyString(options.supabase?.endpoint, \"supabase.endpoint\");\n assertNonEmptyString(options.supabase?.secret, \"supabase.secret\");\n assertNonEmptyString(options.upstash?.url, \"upstash.url\");\n assertNonEmptyString(options.upstash?.token, \"upstash.token\");\n\n this.chatId = options.chatId;\n this.sessionId = options.sessionId;\n this.workspacePath = options.workspacePath;\n this.source = options.source;\n this.step = options.step;\n\n if (options.gemini?.apiKey) {\n this.aiClient = getClient(\n \"gemini\",\n options.gemini.apiKey,\n options.gemini.model,\n ) as AiClient;\n }\n\n this.statusRepo = new GenStatusRepository(\n options.supabase.endpoint,\n options.supabase.secret,\n );\n this.ctxRepo = new ContextRepository(\n options.supabase.endpoint,\n options.supabase.secret,\n );\n this.redisStatusPublisher = new SendStatusToRedis(\n options.upstash.url,\n options.upstash.token,\n );\n\n console.log(\n `QwintlyCore initialized (chatId=${this.chatId}, sessionId=${this.sessionId})`,\n );\n }\n\n public async runAiFlow(\n initialContents: any[],\n tools: Tool[],\n handlers: Record<string, ToolHandler>,\n maxSteps: number,\n terminalToolNames: string[],\n ): Promise<ToolLoopResult> {\n if (!this.aiClient) {\n throw new Error(\n \"AI client not initialized. Please provide 'gemini' config to use runAiFlow.\",\n );\n }\n const toolLoopOptions: RunToolLoopOptions = {\n initialContents: initialContents,\n tools: tools,\n handlers: handlers,\n maxSteps: maxSteps,\n terminalToolNames: terminalToolNames,\n aiCall: (request, options) =>\n this.aiClient!.aiResponse(request, {\n tools: options.tools,\n toolCallingMode: options.toolCallingMode,\n }),\n logger: this.streamLog.bind(this),\n };\n\n const result = await runToolLoop(toolLoopOptions);\n return result;\n }\n\n public async streamLog(message: string, eventType: EventType): Promise<void> {\n try {\n assertNonEmptyString(message, \"message\");\n await statusService(\n this.chatId,\n this.sessionId,\n eventType,\n this.step,\n message,\n this.source,\n {\n repository: {\n persist: this.statusRepo.persistStatusMessage.bind(this.statusRepo),\n },\n publisher: {\n publish: this.redisStatusPublisher.sendStatusToRedis.bind(\n this.redisStatusPublisher,\n ),\n },\n },\n );\n } catch (error) {\n console.error(error);\n }\n }\n\n public async buildProjectInfoIdx(): Promise<ProjectInfo> {\n const projectInfo = await computeProjectInfo(this.workspacePath);\n\n await this.ctxRepo.updateProjectInfo(this.chatId, projectInfo);\n\n return projectInfo;\n }\n\n private async buildIndex<T>(\n builder: (path: string) => Promise<T>,\n ): Promise<T> {\n return builder(this.workspacePath);\n }\n\n public async buildPlannerIdx(): Promise<PlannerIndex> {\n return this.buildIndex(buildPlannerIndex);\n }\n\n public async buildCodegenIdx(): Promise<CodegenIndex> {\n return this.buildIndex(buildCodegenIndex);\n }\n\n public async buildValidatorIdx(): Promise<ValidatorIndex> {\n return this.buildIndex(buildValidatorIndex);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"redis.service.d.ts","sourceRoot":"","sources":["../../src/logging/redis.service.ts"],"names":[],"mappings":"AAEA,qBAAa,iBAAiB;IACrB,aAAa,EAAE,GAAG,CAAC;gBACd,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;IAIpD,iBAAiB,GACf,QAAQ,MAAM,EACd,OAAO,MAAM,EACb,OAAO;QACL,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,mBA0BD;CACH"}
1
+ {"version":3,"file":"redis.service.d.ts","sourceRoot":"","sources":["../../src/logging/redis.service.ts"],"names":[],"mappings":"AAEA,qBAAa,iBAAiB;IACrB,aAAa,EAAE,GAAG,CAAC;gBACd,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;IAIpD,iBAAiB,GACf,QAAQ,MAAM,EACd,OAAO,MAAM,EACb,OAAO;QACL,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,mBA6BD;CACH"}
@@ -16,7 +16,10 @@ export class SendStatusToRedis {
16
16
  },
17
17
  });
18
18
  await this.upstashClient.hset(`chat:${chatId}:state:${genId}`, {
19
- current_status: event.message,
19
+ event_type: event.event_type,
20
+ step: event.step ?? "",
21
+ message: event.message ?? "",
22
+ seq_num: event.seq_num.toString(),
20
23
  last_seq: event.seq_num.toString(),
21
24
  });
22
25
  };
@@ -1 +1 @@
1
- {"version":3,"file":"redis.service.js","sourceRoot":"","sources":["../../src/logging/redis.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAExC,MAAM,OAAO,iBAAiB;IAE5B,YAAY,UAAkB,EAAE,YAAoB;QAIpD,sBAAiB,GAAG,KAAK,EACvB,MAAc,EACd,KAAa,EACb,KAKC,EACD,EAAE;YACF,MAAM,SAAS,GAAG,QAAQ,MAAM,QAAQ,KAAK,SAAS,CAAC;YAEvD,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAC3B,SAAS,EACT,GAAG,EACH;gBACE,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;gBACtB,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;gBAC5B,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE;aAClC,EACD;gBACE,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,SAAS,EAAE,IAAI;oBACf,UAAU,EAAE,GAAG;iBAChB;aACF,CACF,CAAC;YAEF,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,MAAM,UAAU,KAAK,EAAE,EAAE;gBAC7D,cAAc,EAAE,KAAK,CAAC,OAAO;gBAC7B,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE;aACnC,CAAC,CAAC;QACL,CAAC,CAAC;QArCA,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IACvD,CAAC;CAqCF","sourcesContent":["import { redis } from \"../lib/redis.js\";\r\n\r\nexport class SendStatusToRedis {\r\n public upstashClient: any;\r\n constructor(upstashUrl: string, upstashToken: string) {\r\n this.upstashClient = redis(upstashUrl, upstashToken);\r\n }\r\n\r\n sendStatusToRedis = async (\r\n chatId: string,\r\n genId: string,\r\n event: {\r\n event_type: string;\r\n step?: string;\r\n message?: string;\r\n seq_num: number;\r\n },\r\n ) => {\r\n const streamKey = `chat:${chatId}:gen:${genId}:events`;\r\n\r\n await this.upstashClient.xadd(\r\n streamKey,\r\n \"*\",\r\n {\r\n event_type: event.event_type,\r\n step: event.step ?? \"\",\r\n message: event.message ?? \"\",\r\n seq_num: event.seq_num.toString(),\r\n },\r\n {\r\n trim: {\r\n type: \"MAXLEN\",\r\n threshold: 1000,\r\n comparison: \"=\",\r\n },\r\n },\r\n );\r\n\r\n await this.upstashClient.hset(`chat:${chatId}:state:${genId}`, {\r\n current_status: event.message,\r\n last_seq: event.seq_num.toString(),\r\n });\r\n };\r\n}\r\n"]}
1
+ {"version":3,"file":"redis.service.js","sourceRoot":"","sources":["../../src/logging/redis.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAExC,MAAM,OAAO,iBAAiB;IAE5B,YAAY,UAAkB,EAAE,YAAoB;QAIpD,sBAAiB,GAAG,KAAK,EACvB,MAAc,EACd,KAAa,EACb,KAKC,EACD,EAAE;YACF,MAAM,SAAS,GAAG,QAAQ,MAAM,QAAQ,KAAK,SAAS,CAAC;YAEvD,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAC3B,SAAS,EACT,GAAG,EACH;gBACE,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;gBACtB,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;gBAC5B,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE;aAClC,EACD;gBACE,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,SAAS,EAAE,IAAI;oBACf,UAAU,EAAE,GAAG;iBAChB;aACF,CACF,CAAC;YAEF,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,MAAM,UAAU,KAAK,EAAE,EAAE;gBAC7D,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;gBACtB,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;gBAC5B,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE;gBACjC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE;aACnC,CAAC,CAAC;QACL,CAAC,CAAC;QAxCA,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IACvD,CAAC;CAwCF","sourcesContent":["import { redis } from \"../lib/redis.js\";\r\n\r\nexport class SendStatusToRedis {\r\n public upstashClient: any;\r\n constructor(upstashUrl: string, upstashToken: string) {\r\n this.upstashClient = redis(upstashUrl, upstashToken);\r\n }\r\n\r\n sendStatusToRedis = async (\r\n chatId: string,\r\n genId: string,\r\n event: {\r\n event_type: string;\r\n step?: string;\r\n message?: string;\r\n seq_num: number;\r\n },\r\n ) => {\r\n const streamKey = `chat:${chatId}:gen:${genId}:events`;\r\n\r\n await this.upstashClient.xadd(\r\n streamKey,\r\n \"*\",\r\n {\r\n event_type: event.event_type,\r\n step: event.step ?? \"\",\r\n message: event.message ?? \"\",\r\n seq_num: event.seq_num.toString(),\r\n },\r\n {\r\n trim: {\r\n type: \"MAXLEN\",\r\n threshold: 1000,\r\n comparison: \"=\",\r\n },\r\n },\r\n );\r\n\r\n await this.upstashClient.hset(`chat:${chatId}:state:${genId}`, {\r\n event_type: event.event_type,\r\n step: event.step ?? \"\",\r\n message: event.message ?? \"\",\r\n seq_num: event.seq_num.toString(),\r\n last_seq: event.seq_num.toString(),\r\n });\r\n };\r\n}\r\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyPatch.helpers.test.d.ts","sourceRoot":"","sources":["../../src/tests/applyPatch.helpers.test.ts"],"names":[],"mappings":""}
@@ -1,6 +1,6 @@
1
1
  import assert from "node:assert/strict";
2
2
  import test from "node:test";
3
- import { parseApplyPatch } from "./applyPatch.helpers.js";
3
+ import { parseApplyPatch } from "../ai/tools/helpers/applyPatch.helpers.js";
4
4
  test("parseApplyPatch: tolerates leading indentation (dedent)", () => {
5
5
  const patch = `
6
6
  *** Begin Patch
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyPatch.helpers.test.js","sourceRoot":"","sources":["../../src/tests/applyPatch.helpers.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAE5E,IAAI,CAAC,yDAAyD,EAAE,GAAG,EAAE;IACnE,MAAM,KAAK,GAAG;;;;;;;GAOb,CAAC;IAEF,MAAM,GAAG,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC5B,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACrC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,0DAA0D,EAAE,GAAG,EAAE;IACpE,MAAM,KAAK,GAAG;;;;;;;;;CASf,CAAC;IAEA,MAAM,GAAG,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC5B,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACrC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4DAA4D,EAAE,GAAG,EAAE;IACtE,MAAM,KAAK,GAAG;;;;;;;;CAQf,CAAC;IAEA,MAAM,GAAG,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC5B,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACrC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACxC,MAAM,CAAC,KAAK,CAAE,GAAG,CAAC,CAAC,CAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC","sourcesContent":["import assert from \"node:assert/strict\";\nimport test from \"node:test\";\nimport { parseApplyPatch } from \"../ai/tools/helpers/applyPatch.helpers.js\";\n\ntest(\"parseApplyPatch: tolerates leading indentation (dedent)\", () => {\n const patch = `\n *** Begin Patch\n *** Update File: a.txt\n @@\n -hello\n +hi\n *** End Patch\n `;\n\n const ops = parseApplyPatch(patch);\n assert.equal(ops.length, 1);\n assert.equal(ops[0]?.kind, \"update\");\n assert.equal(ops[0]?.filePath, \"a.txt\");\n});\n\ntest(\"parseApplyPatch: strips surrounding markdown code fences\", () => {\n const patch = `\n\\`\\`\\`diff\n*** Begin Patch\n*** Update File: a.txt\n@@\n-hello\n+hi\n*** End Patch\n\\`\\`\\`\n`;\n\n const ops = parseApplyPatch(patch);\n assert.equal(ops.length, 1);\n assert.equal(ops[0]?.kind, \"update\");\n assert.equal(ops[0]?.filePath, \"a.txt\");\n});\n\ntest('parseApplyPatch: supports \"*** Move to:\" after Update File', () => {\n const patch = `\n*** Begin Patch\n*** Update File: a.txt\n*** Move to: b.txt\n@@\n-hello\n+hi\n*** End Patch\n`;\n\n const ops = parseApplyPatch(patch);\n assert.equal(ops.length, 1);\n assert.equal(ops[0]?.kind, \"update\");\n assert.equal(ops[0]?.filePath, \"a.txt\");\n assert.equal((ops[0] as any).moveTo, \"b.txt\");\n});\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyPatch.impl.test.d.ts","sourceRoot":"","sources":["../../src/tests/applyPatch.impl.test.ts"],"names":[],"mappings":""}
@@ -1,7 +1,7 @@
1
1
  import assert from "node:assert/strict";
2
2
  import path from "node:path";
3
3
  import test from "node:test";
4
- import { createApplyPatchImpl } from "./applyPatch.impl.js";
4
+ import { createApplyPatchImpl } from "../ai/tools/implementations/applyPatch.impl.js";
5
5
  const enoent = (message) => {
6
6
  const err = new Error(message);
7
7
  err.code = "ENOENT";
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyPatch.impl.test.js","sourceRoot":"","sources":["../../src/tests/applyPatch.impl.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,gDAAgD,CAAC;AAMtF,MAAM,MAAM,GAAG,CAAC,OAAe,EAAE,EAAE;IACjC,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,OAAO,CAA0B,CAAC;IACxD,GAAG,CAAC,IAAI,GAAG,QAAQ,CAAC;IACpB,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,GAA6D,EAAE;IAC/E,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IAExC,OAAO;QACL,KAAK;QACL,QAAQ,EAAE,KAAK,EAAE,YAAoB,EAAE,EAAE;YACvC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YACvC,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACzB,IAAI,CAAC,KAAK,SAAS;gBAAE,MAAM,MAAM,CAAC,+BAA+B,YAAY,GAAG,CAAC,CAAC;YAClF,OAAO,CAAC,CAAC;QACX,CAAC;QACD,SAAS,EAAE,KAAK,EAAE,YAAoB,EAAE,OAAe,EAAE,EAAE;YACzD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC;QAC/D,CAAC;QACD,MAAM,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;QACtB,MAAM,EAAE,KAAK,EAAE,YAAoB,EAAE,EAAE;YACrC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YACvC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,MAAM,MAAM,CAAC,iCAAiC,YAAY,GAAG,CAAC,CAAC;YACpF,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;QACD,IAAI,EAAE,KAAK,EAAE,YAAoB,EAAE,EAAE;YACnC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YACvC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,MAAM,MAAM,CAAC,+BAA+B,YAAY,GAAG,CAAC,CAAC;YAClF,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;QACtC,CAAC;QACD,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC,EAAE;KAC5B,CAAC;AACJ,CAAC,CAAC;AAEF,IAAI,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;IACjF,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC5D,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IACvB,MAAM,UAAU,GAAG,oBAAoB,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CAAC;IAE/D,EAAE,CAAC,KAAK,CAAC,GAAG,CACV,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,sBAAsB,CAAC,EACnD,2CAA2C,CAC5C,CAAC;IAEF,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC;;;;;;CAM9B,CAAC,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAChC,MAAM,CAAC,KAAK,CAAE,GAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACzC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACvF,MAAM,CAAC,KAAK,CACV,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAAC,EACjE,2CAA2C,CAC5C,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;IACpE,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC5D,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IACvB,MAAM,UAAU,GAAG,oBAAoB,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CAAC;IAE/D,EAAE,CAAC,KAAK,CAAC,GAAG,CACV,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,sBAAsB,CAAC,EACnD,2CAA2C,CAC5C,CAAC;IAEF,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC;;;;;CAK9B,CAAC,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAChC,MAAM,CAAC,KAAK,CAAE,GAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC1C,MAAM,CAAC,KAAK,CACV,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAAC,EACjE,2CAA2C,CAC5C,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["import assert from \"node:assert/strict\";\nimport path from \"node:path\";\nimport test from \"node:test\";\nimport { createApplyPatchImpl } from \"../ai/tools/implementations/applyPatch.impl.js\";\n\ntype MemFs = {\n files: Map<string, string>;\n};\n\nconst enoent = (message: string) => {\n const err = new Error(message) as NodeJS.ErrnoException;\n err.code = \"ENOENT\";\n return err;\n};\n\nconst makeMemFs = (): MemFs & Parameters<typeof createApplyPatchImpl>[0][\"fs\"] => {\n const files = new Map<string, string>();\n\n return {\n files,\n readFile: async (absolutePath: string) => {\n const key = path.resolve(absolutePath);\n const v = files.get(key);\n if (v === undefined) throw enoent(`ENOENT: no such file, open '${absolutePath}'`);\n return v;\n },\n writeFile: async (absolutePath: string, content: string) => {\n files.set(path.resolve(absolutePath), String(content ?? \"\"));\n },\n mkdirp: async () => {},\n rmFile: async (absolutePath: string) => {\n const key = path.resolve(absolutePath);\n if (!files.has(key)) throw enoent(`ENOENT: no such file, unlink '${absolutePath}'`);\n files.delete(key);\n },\n stat: async (absolutePath: string) => {\n const key = path.resolve(absolutePath);\n if (!files.has(key)) throw enoent(`ENOENT: no such file, stat '${absolutePath}'`);\n return { isDirectory: () => false };\n },\n safeReadDir: async () => [],\n };\n};\n\ntest('apply_patch: Update + Move writes new path and deletes old path', async () => {\n const workspaceRoot = path.resolve(\"C:\\\\virtual-workspace\");\n const fs = makeMemFs();\n const applyPatch = createApplyPatchImpl({ workspaceRoot, fs });\n\n fs.files.set(\n path.resolve(workspaceRoot, \"app/a/page.config.ts\"),\n \"export const config = { elements: [] };\\n\",\n );\n\n const res = await applyPatch(`*** Begin Patch\n*** Update File: app/a/page.config.ts\n*** Move to: app/b/page.config.ts\n@@\n export const config = { elements: [] };\n*** End Patch\n`);\n\n assert.equal(res.success, true);\n assert.equal((res as any).changed, true);\n assert.equal(fs.files.has(path.resolve(workspaceRoot, \"app/a/page.config.ts\")), false);\n assert.equal(\n fs.files.get(path.resolve(workspaceRoot, \"app/b/page.config.ts\")),\n \"export const config = { elements: [] };\\n\",\n );\n});\n\ntest(\"apply_patch: context-only Update succeeds as no-op\", async () => {\n const workspaceRoot = path.resolve(\"C:\\\\virtual-workspace\");\n const fs = makeMemFs();\n const applyPatch = createApplyPatchImpl({ workspaceRoot, fs });\n\n fs.files.set(\n path.resolve(workspaceRoot, \"app/a/page.config.ts\"),\n \"export const config = { elements: [] };\\n\",\n );\n\n const res = await applyPatch(`*** Begin Patch\n*** Update File: app/a/page.config.ts\n@@\n export const config = { elements: [] };\n*** End Patch\n`);\n\n assert.equal(res.success, true);\n assert.equal((res as any).changed, false);\n assert.equal(\n fs.files.get(path.resolve(workspaceRoot, \"app/a/page.config.ts\")),\n \"export const config = { elements: [] };\\n\",\n );\n});\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileSystem.helpers.test.d.ts","sourceRoot":"","sources":["../../src/tests/fileSystem.helpers.test.ts"],"names":[],"mappings":""}
@@ -1,7 +1,7 @@
1
1
  import assert from "node:assert/strict";
2
2
  import path from "node:path";
3
3
  import test from "node:test";
4
- import { toWorkspacePath } from "./fileSystem.helpers.js";
4
+ import { toWorkspacePath } from "../ai/tools/helpers/fileSystem.helpers.js";
5
5
  test("toWorkspacePath: tolerates case mismatch for absolute paths on Windows", () => {
6
6
  if (process.platform !== "win32") {
7
7
  assert.ok(true);
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileSystem.helpers.test.js","sourceRoot":"","sources":["../../src/tests/fileSystem.helpers.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAE5E,IAAI,CAAC,wEAAwE,EAAE,GAAG,EAAE;IAClF,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAChB,OAAO;IACT,CAAC;IAED,MAAM,aAAa,GAAG,qBAAqB,CAAC;IAC5C,MAAM,KAAK,GAAG,oCAAoC,CAAC;IACnD,MAAM,QAAQ,GAAG,eAAe,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IACvD,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;AACzE,CAAC,CAAC,CAAC","sourcesContent":["import assert from \"node:assert/strict\";\nimport path from \"node:path\";\nimport test from \"node:test\";\nimport { toWorkspacePath } from \"../ai/tools/helpers/fileSystem.helpers.js\";\n\ntest(\"toWorkspacePath: tolerates case mismatch for absolute paths on Windows\", () => {\n if (process.platform !== \"win32\") {\n assert.ok(true);\n return;\n }\n\n const workspaceRoot = \"C:\\\\Repo\\\\Workspace\";\n const input = \"c:\\\\repo\\\\workspace\\\\src\\\\index.ts\";\n const resolved = toWorkspacePath(workspaceRoot, input);\n assert.equal(resolved, path.resolve(workspaceRoot, \"src\", \"index.ts\"));\n});\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=search.impl.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.impl.test.d.ts","sourceRoot":"","sources":["../../src/tests/search.impl.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,90 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { createSearchImpl } from "../ai/tools/implementations/search.impl.js";
4
+ const makeDeps = (overrides) => {
5
+ return {
6
+ workspaceRoot: overrides?.workspaceRoot ?? "C:\\virtual-workspace",
7
+ fs: {},
8
+ execRg: overrides?.execRg,
9
+ };
10
+ };
11
+ test("search: blank query returns empty and does not call rg", async () => {
12
+ let called = 0;
13
+ const search = createSearchImpl(makeDeps({
14
+ execRg: async () => {
15
+ called++;
16
+ return { code: 0, stdout: "", stderr: "" };
17
+ },
18
+ }));
19
+ const res = await search(" ");
20
+ assert.deepEqual(res, []);
21
+ assert.equal(called, 0);
22
+ });
23
+ test("search: trims query and calls rg with cwd and maxCount=20", async () => {
24
+ let got = null;
25
+ const search = createSearchImpl(makeDeps({
26
+ workspaceRoot: "C:\\my-workspace",
27
+ execRg: async (input) => {
28
+ got = input;
29
+ return { code: 0, stdout: "", stderr: "" };
30
+ },
31
+ }));
32
+ const res = await search(" hello ");
33
+ assert.deepEqual(res, []);
34
+ assert.deepEqual(got, { query: "hello", cwd: "C:\\my-workspace", maxCount: 20 });
35
+ });
36
+ test("search: parses rg output into {path, content}", async () => {
37
+ const search = createSearchImpl(makeDeps({
38
+ execRg: async () => ({
39
+ code: 0,
40
+ stdout: "a.ts:10:hello\nb.ts:2:world\r\nc.ts:3: spaced \n",
41
+ stderr: "",
42
+ }),
43
+ }));
44
+ const res = await search("q");
45
+ assert.deepEqual(res, [
46
+ { path: "a.ts:10", content: "hello" },
47
+ { path: "b.ts:2", content: "world" },
48
+ { path: "c.ts:3", content: " spaced " },
49
+ ]);
50
+ });
51
+ test("search: malformed lines fall back to path-only result", async () => {
52
+ const search = createSearchImpl(makeDeps({
53
+ execRg: async () => ({
54
+ code: 0,
55
+ stdout: "no-colons-here\nfile.ts:12:ok\nfile.ts:onlyonecolon\n",
56
+ stderr: "",
57
+ }),
58
+ }));
59
+ const res = await search("q");
60
+ assert.deepEqual(res, [
61
+ { path: "no-colons-here", content: "" },
62
+ { path: "file.ts:12", content: "ok" },
63
+ { path: "file.ts:onlyonecolon", content: "" },
64
+ ]);
65
+ });
66
+ test("search: rg exit code 1 returns empty (no matches)", async () => {
67
+ const search = createSearchImpl(makeDeps({
68
+ execRg: async () => ({ code: 1, stdout: "ignored", stderr: "" }),
69
+ }));
70
+ const res = await search("q");
71
+ assert.deepEqual(res, []);
72
+ });
73
+ test("search: non-zero rg exit code returns empty (error is caught)", async () => {
74
+ const search = createSearchImpl(makeDeps({
75
+ execRg: async () => ({ code: 2, stdout: "", stderr: "rg blew up" }),
76
+ }));
77
+ const res = await search("q");
78
+ assert.deepEqual(res, []);
79
+ });
80
+ test("search: limits results to 20 lines", async () => {
81
+ const stdout = Array.from({ length: 25 }, (_, i) => `f.ts:${i + 1}:x`).join("\n") + "\n";
82
+ const search = createSearchImpl(makeDeps({
83
+ execRg: async () => ({ code: 0, stdout, stderr: "" }),
84
+ }));
85
+ const res = await search("q");
86
+ assert.equal(res.length, 20);
87
+ assert.deepEqual(res[0], { path: "f.ts:1", content: "x" });
88
+ assert.deepEqual(res[19], { path: "f.ts:20", content: "x" });
89
+ });
90
+ //# sourceMappingURL=search.impl.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.impl.test.js","sourceRoot":"","sources":["../../src/tests/search.impl.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\";\nimport test from \"node:test\";\nimport { createSearchImpl } from \"../ai/tools/implementations/search.impl.js\";\n\nconst makeDeps = (overrides?: {\n workspaceRoot?: string;\n execRg?: Parameters<typeof createSearchImpl>[0][\"execRg\"];\n}) => {\n return {\n workspaceRoot: overrides?.workspaceRoot ?? \"C:\\\\virtual-workspace\",\n fs: {} as any,\n execRg: overrides?.execRg,\n } as Parameters<typeof createSearchImpl>[0];\n};\n\ntest(\"search: blank query returns empty and does not call rg\", async () => {\n let called = 0;\n const search = createSearchImpl(\n makeDeps({\n execRg: async () => {\n called++;\n return { code: 0, stdout: \"\", stderr: \"\" };\n },\n }),\n );\n\n const res = await search(\" \");\n assert.deepEqual(res, []);\n assert.equal(called, 0);\n});\n\ntest(\"search: trims query and calls rg with cwd and maxCount=20\", async () => {\n let got: any = null;\n const search = createSearchImpl(\n makeDeps({\n workspaceRoot: \"C:\\\\my-workspace\",\n execRg: async (input) => {\n got = input;\n return { code: 0, stdout: \"\", stderr: \"\" };\n },\n }),\n );\n\n const res = await search(\" hello \");\n assert.deepEqual(res, []);\n assert.deepEqual(got, { query: \"hello\", cwd: \"C:\\\\my-workspace\", maxCount: 20 });\n});\n\ntest(\"search: parses rg output into {path, content}\", async () => {\n const search = createSearchImpl(\n makeDeps({\n execRg: async () => ({\n code: 0,\n stdout: \"a.ts:10:hello\\nb.ts:2:world\\r\\nc.ts:3: spaced \\n\",\n stderr: \"\",\n }),\n }),\n );\n\n const res = await search(\"q\");\n assert.deepEqual(res, [\n { path: \"a.ts:10\", content: \"hello\" },\n { path: \"b.ts:2\", content: \"world\" },\n { path: \"c.ts:3\", content: \" spaced \" },\n ]);\n});\n\ntest(\"search: malformed lines fall back to path-only result\", async () => {\n const search = createSearchImpl(\n makeDeps({\n execRg: async () => ({\n code: 0,\n stdout: \"no-colons-here\\nfile.ts:12:ok\\nfile.ts:onlyonecolon\\n\",\n stderr: \"\",\n }),\n }),\n );\n\n const res = await search(\"q\");\n assert.deepEqual(res, [\n { path: \"no-colons-here\", content: \"\" },\n { path: \"file.ts:12\", content: \"ok\" },\n { path: \"file.ts:onlyonecolon\", content: \"\" },\n ]);\n});\n\ntest(\"search: rg exit code 1 returns empty (no matches)\", async () => {\n const search = createSearchImpl(\n makeDeps({\n execRg: async () => ({ code: 1, stdout: \"ignored\", stderr: \"\" }),\n }),\n );\n\n const res = await search(\"q\");\n assert.deepEqual(res, []);\n});\n\ntest(\"search: non-zero rg exit code returns empty (error is caught)\", async () => {\n const search = createSearchImpl(\n makeDeps({\n execRg: async () => ({ code: 2, stdout: \"\", stderr: \"rg blew up\" }),\n }),\n );\n\n const res = await search(\"q\");\n assert.deepEqual(res, []);\n});\n\ntest(\"search: limits results to 20 lines\", async () => {\n const stdout = Array.from({ length: 25 }, (_, i) => `f.ts:${i + 1}:x`).join(\"\\n\") + \"\\n\";\n const search = createSearchImpl(\n makeDeps({\n execRg: async () => ({ code: 0, stdout, stderr: \"\" }),\n }),\n );\n\n const res = await search(\"q\");\n assert.equal(res.length, 20);\n assert.deepEqual(res[0], { path: \"f.ts:1\", content: \"x\" });\n assert.deepEqual(res[19], { path: \"f.ts:20\", content: \"x\" });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vedangiitb/qwintly-core",
3
- "version": "1.0.5",
3
+ "version": "1.2.0",
4
4
  "description": "Qwintly Core",
5
5
  "homepage": "https://github.com/vedangiitb/qwintly-core#readme",
6
6
  "bugs": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"applyPatch.helpers.test.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/helpers/applyPatch.helpers.test.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"applyPatch.helpers.test.js","sourceRoot":"","sources":["../../../../src/ai/tools/helpers/applyPatch.helpers.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,IAAI,CAAC,yDAAyD,EAAE,GAAG,EAAE;IACnE,MAAM,KAAK,GAAG;;;;;;;GAOb,CAAC;IAEF,MAAM,GAAG,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC5B,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACrC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,0DAA0D,EAAE,GAAG,EAAE;IACpE,MAAM,KAAK,GAAG;;;;;;;;;CASf,CAAC;IAEA,MAAM,GAAG,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC5B,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACrC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4DAA4D,EAAE,GAAG,EAAE;IACtE,MAAM,KAAK,GAAG;;;;;;;;CAQf,CAAC;IAEA,MAAM,GAAG,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC5B,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACrC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACxC,MAAM,CAAC,KAAK,CAAE,GAAG,CAAC,CAAC,CAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC","sourcesContent":["import assert from \"node:assert/strict\";\nimport test from \"node:test\";\nimport { parseApplyPatch } from \"./applyPatch.helpers.js\";\n\ntest(\"parseApplyPatch: tolerates leading indentation (dedent)\", () => {\n const patch = `\n *** Begin Patch\n *** Update File: a.txt\n @@\n -hello\n +hi\n *** End Patch\n `;\n\n const ops = parseApplyPatch(patch);\n assert.equal(ops.length, 1);\n assert.equal(ops[0]?.kind, \"update\");\n assert.equal(ops[0]?.filePath, \"a.txt\");\n});\n\ntest(\"parseApplyPatch: strips surrounding markdown code fences\", () => {\n const patch = `\n\\`\\`\\`diff\n*** Begin Patch\n*** Update File: a.txt\n@@\n-hello\n+hi\n*** End Patch\n\\`\\`\\`\n`;\n\n const ops = parseApplyPatch(patch);\n assert.equal(ops.length, 1);\n assert.equal(ops[0]?.kind, \"update\");\n assert.equal(ops[0]?.filePath, \"a.txt\");\n});\n\ntest('parseApplyPatch: supports \"*** Move to:\" after Update File', () => {\n const patch = `\n*** Begin Patch\n*** Update File: a.txt\n*** Move to: b.txt\n@@\n-hello\n+hi\n*** End Patch\n`;\n\n const ops = parseApplyPatch(patch);\n assert.equal(ops.length, 1);\n assert.equal(ops[0]?.kind, \"update\");\n assert.equal(ops[0]?.filePath, \"a.txt\");\n assert.equal((ops[0] as any).moveTo, \"b.txt\");\n});\n\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"fileSystem.helpers.test.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/helpers/fileSystem.helpers.test.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"fileSystem.helpers.test.js","sourceRoot":"","sources":["../../../../src/ai/tools/helpers/fileSystem.helpers.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,IAAI,CAAC,wEAAwE,EAAE,GAAG,EAAE;IAClF,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAChB,OAAO;IACT,CAAC;IAED,MAAM,aAAa,GAAG,qBAAqB,CAAC;IAC5C,MAAM,KAAK,GAAG,oCAAoC,CAAC;IACnD,MAAM,QAAQ,GAAG,eAAe,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IACvD,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;AACzE,CAAC,CAAC,CAAC","sourcesContent":["import assert from \"node:assert/strict\";\nimport path from \"node:path\";\nimport test from \"node:test\";\nimport { toWorkspacePath } from \"./fileSystem.helpers.js\";\n\ntest(\"toWorkspacePath: tolerates case mismatch for absolute paths on Windows\", () => {\n if (process.platform !== \"win32\") {\n assert.ok(true);\n return;\n }\n\n const workspaceRoot = \"C:\\\\Repo\\\\Workspace\";\n const input = \"c:\\\\repo\\\\workspace\\\\src\\\\index.ts\";\n const resolved = toWorkspacePath(workspaceRoot, input);\n assert.equal(resolved, path.resolve(workspaceRoot, \"src\", \"index.ts\"));\n});\n\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"applyPatch.impl.test.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/applyPatch.impl.test.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"applyPatch.impl.test.js","sourceRoot":"","sources":["../../../../src/ai/tools/implementations/applyPatch.impl.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\";\nimport path from \"node:path\";\nimport test from \"node:test\";\nimport { createApplyPatchImpl } from \"./applyPatch.impl.js\";\n\ntype MemFs = {\n files: Map<string, string>;\n};\n\nconst enoent = (message: string) => {\n const err = new Error(message) as NodeJS.ErrnoException;\n err.code = \"ENOENT\";\n return err;\n};\n\nconst makeMemFs = (): MemFs & Parameters<typeof createApplyPatchImpl>[0][\"fs\"] => {\n const files = new Map<string, string>();\n\n return {\n files,\n readFile: async (absolutePath: string) => {\n const key = path.resolve(absolutePath);\n const v = files.get(key);\n if (v === undefined) throw enoent(`ENOENT: no such file, open '${absolutePath}'`);\n return v;\n },\n writeFile: async (absolutePath: string, content: string) => {\n files.set(path.resolve(absolutePath), String(content ?? \"\"));\n },\n mkdirp: async () => {},\n rmFile: async (absolutePath: string) => {\n const key = path.resolve(absolutePath);\n if (!files.has(key)) throw enoent(`ENOENT: no such file, unlink '${absolutePath}'`);\n files.delete(key);\n },\n stat: async (absolutePath: string) => {\n const key = path.resolve(absolutePath);\n if (!files.has(key)) throw enoent(`ENOENT: no such file, stat '${absolutePath}'`);\n return { isDirectory: () => false };\n },\n safeReadDir: async () => [],\n };\n};\n\ntest('apply_patch: Update + Move writes new path and deletes old path', async () => {\n const workspaceRoot = path.resolve(\"C:\\\\virtual-workspace\");\n const fs = makeMemFs();\n const applyPatch = createApplyPatchImpl({ workspaceRoot, fs });\n\n fs.files.set(\n path.resolve(workspaceRoot, \"app/a/page.config.ts\"),\n \"export const config = { elements: [] };\\n\",\n );\n\n const res = await applyPatch(`*** Begin Patch\n*** Update File: app/a/page.config.ts\n*** Move to: app/b/page.config.ts\n@@\n export const config = { elements: [] };\n*** End Patch\n`);\n\n assert.equal(res.success, true);\n assert.equal((res as any).changed, true);\n assert.equal(fs.files.has(path.resolve(workspaceRoot, \"app/a/page.config.ts\")), false);\n assert.equal(\n fs.files.get(path.resolve(workspaceRoot, \"app/b/page.config.ts\")),\n \"export const config = { elements: [] };\\n\",\n );\n});\n\ntest(\"apply_patch: context-only Update succeeds as no-op\", async () => {\n const workspaceRoot = path.resolve(\"C:\\\\virtual-workspace\");\n const fs = makeMemFs();\n const applyPatch = createApplyPatchImpl({ workspaceRoot, fs });\n\n fs.files.set(\n path.resolve(workspaceRoot, \"app/a/page.config.ts\"),\n \"export const config = { elements: [] };\\n\",\n );\n\n const res = await applyPatch(`*** Begin Patch\n*** Update File: app/a/page.config.ts\n@@\n export const config = { elements: [] };\n*** End Patch\n`);\n\n assert.equal(res.success, true);\n assert.equal((res as any).changed, false);\n assert.equal(\n fs.files.get(path.resolve(workspaceRoot, \"app/a/page.config.ts\")),\n \"export const config = { elements: [] };\\n\",\n );\n});\n"]}