@vedangiitb/qwintly-core 1.3.11 → 1.3.13

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 +1 @@
1
- {"version":3,"file":"toolLoopRunner.d.ts","sourceRoot":"","sources":["../../../src/ai/toolLoop/toolLoopRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAe,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAML,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAS9B,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE9E,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,GAAG,EAAE,CAAC;IAChB,aAAa,EAAE,GAAG,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC9B,QAAQ,EAAE,OAAO,CAAC;KACnB,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9E,MAAM,MAAM,cAAc,GAAG;IAC3B,aAAa,CAAC,EAAE,GAAG,EAAE,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,CACrB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE;IACP,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,yBAAyB,CAAC;CAC7C,KACE,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,eAAe,EAAE,GAAG,EAAE,CAAC;IACvB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,yBAAyB,CAAC;IAC5C,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,qBAAqB,CAAC;IACtC,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF,wBAAsB,WAAW,CAC/B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,cAAc,CAAC,CA4SzB"}
1
+ {"version":3,"file":"toolLoopRunner.d.ts","sourceRoot":"","sources":["../../../src/ai/toolLoop/toolLoopRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAEhE,OAAO,EAAe,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAML,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAQ9B,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE9E,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,GAAG,EAAE,CAAC;IAChB,aAAa,EAAE,GAAG,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC9B,QAAQ,EAAE,OAAO,CAAC;KACnB,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE9E,MAAM,MAAM,cAAc,GAAG;IAC3B,aAAa,CAAC,EAAE,GAAG,EAAE,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,CACrB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE;IACP,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,yBAAyB,CAAC;CAC7C,KACE,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,eAAe,EAAE,GAAG,EAAE,CAAC;IACvB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,yBAAyB,CAAC;IAC5C,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,qBAAqB,CAAC;IACtC,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF,wBAAsB,WAAW,CAC/B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,cAAc,CAAC,CAuUzB"}
@@ -1,8 +1,8 @@
1
1
  import { FunctionCallingConfigMode } from "@google/genai";
2
+ import { persistToolCall } from "../../services/toolcallPersist.service.js";
2
3
  import { EVENT_TYPES } from "../../types/events.js";
3
4
  import { compactForModel, DEFAULT_CONTEXT_POLICY, normalizeReadFileArgs, redactFunctionCallArgs, } from "./toolLoopContext.js";
4
5
  import { aiCallWithRetry, buildToolStatusMessage, recordToolEvent, serializeError, } from "./toolLoopRunnerUtils.js";
5
- import { persistToolCall } from "../../services/toolcallPersist.service.js";
6
6
  export async function runToolLoop(options) {
7
7
  const { initialContents, tools, handlers, maxSteps = 30, toolCallingMode = FunctionCallingConfigMode.ANY, terminalToolNames = [], keepFullTrace = true, contextPolicy, aiCall, logger, applyPatchAutoRetryMax = 2, aiCallAutoRetryMax = 3, // must have it to try 3 times as gemini errors a lot due to high demand sometimes
8
8
  aiCallAutoRetryBaseMs = 400, aiCallAutoRetryMaxMs = 10000, } = options;
@@ -26,6 +26,22 @@ export async function runToolLoop(options) {
26
26
  modelContents.push(modelItem);
27
27
  };
28
28
  for (let step = 0; step < maxSteps; step++) {
29
+ const remaining = maxSteps - step;
30
+ const budgetInstruction = {
31
+ role: "user",
32
+ parts: [
33
+ {
34
+ text: `Execution limit: ${remaining} turn(s) remaining including this one. ` +
35
+ `One turn = one assistant response in the tool loop. ` +
36
+ `Complete the task in as few turns as possible and avoid unnecessary actions. Prioritize correctness` +
37
+ `${remaining <= 5 ? `Approaching execution limit. Only ${remaining} turns left` : ""}`,
38
+ },
39
+ ],
40
+ };
41
+ if (keepFullTrace) {
42
+ fullTraceContents.push(budgetInstruction);
43
+ }
44
+ modelContents.push(budgetInstruction);
29
45
  modelContents = compactForModel({
30
46
  initialCount: initialContents.length,
31
47
  modelContents,
@@ -142,7 +158,9 @@ export async function runToolLoop(options) {
142
158
  let toolResult = toolResultRaw;
143
159
  if (name === "read_file" && readFileMeta) {
144
160
  const path = String(effectiveArgs.path ?? "");
145
- const jsonPayload = toolResultRaw?.kind === "json" ? toolResultRaw?.json : undefined;
161
+ const jsonPayload = toolResultRaw?.kind === "json"
162
+ ? toolResultRaw?.json
163
+ : undefined;
146
164
  if (jsonPayload !== undefined) {
147
165
  // Token-efficient: return JSON as structured data (no double-stringifying).
148
166
  toolResult = { path, json: jsonPayload };
@@ -239,6 +257,11 @@ export async function runToolLoop(options) {
239
257
  }
240
258
  }
241
259
  }
242
- throw new Error(`Tool loop: max steps reached (${maxSteps}).`);
260
+ return {
261
+ contents: keepFullTrace ? fullTraceContents : modelContents,
262
+ modelContents,
263
+ finalText: `Stopped: max steps reached (${maxSteps}).`,
264
+ steps: maxSteps,
265
+ };
243
266
  }
244
267
  //# sourceMappingURL=toolLoopRunner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"toolLoopRunner.js","sourceRoot":"","sources":["../../../src/ai/toolLoop/toolLoopRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAQ,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,WAAW,EAAa,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,GAGvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,eAAe,EACf,cAAc,GACf,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AAiD5E,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,OAA2B;IAE3B,MAAM,EACJ,eAAe,EACf,KAAK,EACL,QAAQ,EACR,QAAQ,GAAG,EAAE,EACb,eAAe,GAAG,yBAAyB,CAAC,GAAG,EAC/C,iBAAiB,GAAG,EAAE,EACtB,aAAa,GAAG,IAAI,EACpB,aAAa,EACb,MAAM,EACN,MAAM,EACN,sBAAsB,GAAG,CAAC,EAC1B,kBAAkB,GAAG,CAAC,EAAE,kFAAkF;IAC1G,qBAAqB,GAAG,GAAG,EAC3B,oBAAoB,GAAG,KAAM,GAC9B,GAAG,OAAO,CAAC;IAEZ,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,MAAM,GAAoC;QAC9C,GAAG,sBAAsB;QACzB,GAAG,CAAC,aAAa,IAAI,EAAE,CAAC;KACzB,CAAC;IAEF,MAAM,UAAU,GAAgB,EAAE,CAAC;IACnC,IAAI,oBAAoB,GAAG,CAAC,CAAC;IAE7B,MAAM,iBAAiB,GAAU,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3E,IAAI,aAAa,GAAU,CAAC,GAAG,eAAe,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,CAAC,QAAa,EAAE,SAAc,EAAE,EAAE;QACjD,IAAI,aAAa;YAAE,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpD,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAChC,CAAC,CAAC;IACF,MAAM,aAAa,GAAG,CAAC,SAAc,EAAE,EAAE;QACvC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAChC,CAAC,CAAC;IAEF,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;QAC3C,aAAa,GAAG,eAAe,CAAC;YAC9B,YAAY,EAAE,eAAe,CAAC,MAAM;YACpC,aAAa;YACb,UAAU;YACV,MAAM;SACP,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,mBAAmB,EAAE,CAAC;YAC/B,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,+BAA+B,EAAE;gBAC3C,WAAW;gBACX,IAAI,EAAE,IAAI,GAAG,CAAC;aACf,CAAC,CAAC;QACL,CAAC;QAED,IAAI,QAAuC,CAAC;QAC5C,QAAQ,GAAG,MAAM,eAAe,CAAC;YAC/B,MAAM;YACN,OAAO,EAAE,aAAa;YACtB,OAAO,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE;YACnC,QAAQ,EAAE,kBAAkB;YAC5B,WAAW,EAAE,qBAAqB;YAClC,UAAU,EAAE,oBAAoB;YAChC,IAAI,EAAE,IAAI,GAAG,CAAC;YACd,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,aAAa,GAAG,QAAQ,CAAC,aAAa,IAAI,EAAE,CAAC;QACnD,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO;gBACL,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,aAAa;gBAC3D,aAAa;gBACb,SAAS,EAAE,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;gBACvC,KAAK,EAAE,IAAI,GAAG,CAAC;aAChB,CAAC;QACJ,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;YACzC,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAA4B,CAAC;YAE1D,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;YAC5D,CAAC;YAED,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC/B,MAAM,oBAAoB,GAAG,CAAC,OAAO;gBACnC,CAAC,CAAC;oBACE,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,8BAA8B,IAAI,IAAI;oBAC7C,YAAY,EAAE;wBACZ,IAAI,EAAE,yBAAyB;wBAC/B,OAAO,EAAE,8BAA8B,IAAI,IAAI;qBAChD;iBACF;gBACH,CAAC,CAAC,IAAI,CAAC;YAET,IAAI,aAAa,GAA4B,IAAI,CAAC;YAClD,IAAI,YAAY,GAIL,IAAI,CAAC;YAChB,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;gBACzB,MAAM,UAAU,GAAG,qBAAqB,CACtC,aAAa,EACb,MAAM,CAAC,uBAAuB,CAC/B,CAAC;gBACF,aAAa,GAAG,UAAU,CAAC,aAAa,CAAC;gBACzC,YAAY,GAAG;oBACb,KAAK,EAAE,UAAU,CAAC,KAAK;oBACvB,GAAG,EAAE,UAAU,CAAC,GAAG;oBACnB,SAAS,EAAE,UAAU,CAAC,SAAS;iBAChC,CAAC;YACJ,CAAC;YAED,MAAM,CACJ,sBAAsB,CAAC,IAAI,EAAE,aAAa,EAAE,YAAY,CAAC,EACzD,WAAW,CAAC,YAAY,CACzB,CAAC;YAEF,MAAM,SAAS,GAAG,sBAAsB,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;YAE9D,MAAM,aAAa,GAAG;gBACpB,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE;oBACL;wBACE,YAAY,EAAE;4BACZ,IAAI;4BACJ,IAAI,EAAE,aAAa;yBACpB;qBACF;iBACF;aACF,CAAC;YAEF,MAAM,cAAc,GAAG;gBACrB,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE;oBACL;wBACE,YAAY,EAAE;4BACZ,IAAI;4BACJ,IAAI,EAAE,SAAS;yBAChB;qBACF;iBACF;aACF,CAAC;YAEF,IAAI,aAAa,EAAE,CAAC;gBAClB,QAAQ,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;YAC1C,CAAC;iBAAM,CAAC;gBACN,aAAa,CAAC,cAAc,CAAC,CAAC;YAChC,CAAC;YAED,IAAI,aAAsB,CAAC;YAC3B,IAAI,oBAAoB,EAAE,CAAC;gBACzB,aAAa,GAAG,oBAAoB,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC;oBACH,aAAa,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;gBAC/C,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,CAAC,YAAY,IAAI,SAAS,EAAE,WAAW,CAAC,UAAU,CAAC,CAAC;oBAC1D,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,GAAG,EAAE;wBAC7C,IAAI,EAAE,IAAI;wBACV,IAAI,EAAE,IAAI,GAAG,CAAC;qBACf,CAAC,CAAC;oBACH,aAAa,GAAG;wBACd,OAAO,EAAE,KAAK;wBACd,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;wBACvD,YAAY,EAAE,cAAc,CAAC,GAAG,CAAC;wBACjC,IAAI,EAAE,iGAAiG;qBACxG,CAAC;gBACJ,CAAC;YACH,CAAC;YACD,IAAI,UAAU,GAAY,aAAa,CAAC;YAExC,IAAI,IAAI,KAAK,WAAW,IAAI,YAAY,EAAE,CAAC;gBACzC,MAAM,IAAI,GAAG,MAAM,CAAC,aAAa,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;gBAE9C,MAAM,WAAW,GACd,aAAqB,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAE,aAAqB,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;gBACrF,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;oBAC9B,4EAA4E;oBAC5E,UAAU,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;gBAC3C,CAAC;qBAAM,CAAC;oBACN,MAAM,UAAU,GACd,OAAQ,aAAqB,EAAE,OAAO,KAAK,QAAQ;wBACjD,CAAC,CAAC,MAAM,CAAE,aAAqB,CAAC,OAAO,CAAC;wBACxC,CAAC,CAAC,OAAO,aAAa,KAAK,QAAQ;4BACjC,CAAC,CAAC,aAAa;4BACf,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,IAAI,IAAI,CAAC,CAAC;oBAE9C,UAAU,GAAG;wBACX,IAAI;wBACJ,UAAU,EAAE,YAAY,CAAC,KAAK;wBAC9B,QAAQ,EAAE,YAAY,CAAC,GAAG;wBAC1B,SAAS,EAAE,YAAY,CAAC,SAAS;wBACjC,OAAO,EAAE,UAAU;wBACnB,IAAI,EAAE,YAAY,CAAC,SAAS;4BAC1B,CAAC,CAAC,aAAa,MAAM,CAAC,uBAAuB,gDAAgD;4BAC7F,CAAC,CAAC,SAAS;qBACd,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;YACrD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,GAAG,EAAE;oBAC3D,IAAI,EAAE,IAAI;oBACV,IAAI,EAAE,IAAI,GAAG,CAAC;iBACf,CAAC,CAAC;YACL,CAAC;YAED,MAAM,YAAY,GAAG;gBACnB,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE;oBACL;wBACE,gBAAgB,EAAE;4BAChB,IAAI;4BACJ,QAAQ,EAAE,UAAU;yBACrB;qBACF;iBACF;aACF,CAAC;YAEF,IAAI,aAAa,EAAE,CAAC;gBAClB,iBAAiB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACvC,CAAC;YACD,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAEjC,IACE,IAAI,KAAK,aAAa;gBACrB,UAAkB,EAAE,OAAO,KAAK,KAAK;gBACtC,sBAAsB,GAAG,CAAC;gBAC1B,oBAAoB,GAAG,sBAAsB,EAC7C,CAAC;gBACD,oBAAoB,IAAI,CAAC,CAAC;gBAE1B,MAAM,KAAK,GAAG,MAAM,CAAE,UAAkB,EAAE,KAAK,IAAI,eAAe,CAAC,CAAC;gBACpE,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAE,UAAkB,EAAE,KAAK,EAAE,KAAK,CAAC;oBACjE,CAAC,CAAG,UAAkB,CAAC,KAAK,CAAC,KAGxB;oBACL,CAAC,CAAC,EAAE,CAAC;gBAEP,MAAM,SAAS,GACb,UAAU,CAAC,MAAM,GAAG,CAAC;oBACnB,CAAC,CAAC,qDAAqD,UAAU;yBAC5D,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;yBACX,GAAG,CACF,CAAC,CAAC,EAAE,EAAE,CACJ,OAAO,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,SAAS,MAAM,CACxC,CAAC,CAAC,IAAI,IAAI,EAAE,CACb,eAAe,CACnB;yBACA,IAAI,CAAC,MAAM,CAAC,EAAE;oBACnB,CAAC,CAAC,EAAE,CAAC;gBAET,MAAM,gBAAgB,GAAG;oBACvB,IAAI,EAAE,MAAM;oBACZ,KAAK,EAAE;wBACL;4BACE,IAAI,EACF,+BAA+B,oBAAoB,IAAI,sBAAsB,MAAM,KAAK,IAAI;gCAC5F,6DAA6D;gCAC7D,uFAAuF;gCACvF,SAAS;yBACZ;qBACF;iBACF,CAAC;gBAEF,IAAI,aAAa;oBAAE,iBAAiB,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;gBAC5D,aAAa,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACvC,CAAC;YAED,eAAe,CAAC;gBACd,UAAU;gBACV,IAAI;gBACJ,aAAa;gBACb,SAAS;gBACT,YAAY;gBACZ,UAAU;gBACV,aAAa;aACd,CAAC,CAAC;YAEH,IAAI,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrC,OAAO;oBACL,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,aAAa;oBAC3D,aAAa;oBACb,SAAS,EAAE,EAAE;oBACb,KAAK,EAAE,IAAI,GAAG,CAAC;oBACf,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE;iBACrE,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,iCAAiC,QAAQ,IAAI,CAAC,CAAC;AACjE,CAAC","sourcesContent":["import { FunctionCallingConfigMode, Tool } from \"@google/genai\";\nimport { EVENT_TYPES, EventType } from \"../../types/events.js\";\nimport {\n compactForModel,\n DEFAULT_CONTEXT_POLICY,\n normalizeReadFileArgs,\n redactFunctionCallArgs,\n ToolEvent,\n ToolLoopContextPolicy,\n} from \"./toolLoopContext.js\";\nimport {\n aiCallWithRetry,\n buildToolStatusMessage,\n recordToolEvent,\n serializeError,\n} from \"./toolLoopRunnerUtils.js\";\nimport { persistToolCall } from \"../../services/toolcallPersist.service.js\";\n\nexport type ToolHandler = (args: Record<string, unknown>) => Promise<unknown>;\n\nexport type ToolLoopResult = {\n contents: any[];\n modelContents: any[];\n finalText: string;\n steps: number;\n terminalCall?: {\n name: string;\n args: Record<string, unknown>;\n response: unknown;\n };\n};\n\nexport type Logger = (message: string, eventType: EventType) => Promise<void>;\n\nexport type AiCallResponse = {\n functionCalls?: any[];\n text?: string;\n};\n\nexport type AiCallFn = (\n request: unknown,\n options: {\n tools?: Tool[];\n model?: string;\n toolCallingMode?: FunctionCallingConfigMode;\n },\n) => Promise<AiCallResponse>;\n\nexport type RunToolLoopOptions = {\n initialContents: any[];\n tools: Tool[];\n handlers: Record<string, ToolHandler>;\n maxSteps?: number;\n toolCallingMode?: FunctionCallingConfigMode;\n terminalToolNames?: string[];\n keepFullTrace?: boolean;\n contextPolicy?: ToolLoopContextPolicy;\n aiCall: AiCallFn;\n logger: Logger;\n applyPatchAutoRetryMax?: number;\n aiCallAutoRetryMax?: number;\n aiCallAutoRetryBaseMs?: number;\n aiCallAutoRetryMaxMs?: number;\n};\n\nexport async function runToolLoop(\n options: RunToolLoopOptions,\n): Promise<ToolLoopResult> {\n const {\n initialContents,\n tools,\n handlers,\n maxSteps = 30,\n toolCallingMode = FunctionCallingConfigMode.ANY,\n terminalToolNames = [],\n keepFullTrace = true,\n contextPolicy,\n aiCall,\n logger,\n applyPatchAutoRetryMax = 2,\n aiCallAutoRetryMax = 3, // must have it to try 3 times as gemini errors a lot due to high demand sometimes\n aiCallAutoRetryBaseMs = 400,\n aiCallAutoRetryMaxMs = 10_000,\n } = options;\n\n if (typeof aiCall !== \"function\") {\n throw new Error(\"Tool loop: aiCall is required.\");\n }\n\n const policy: Required<ToolLoopContextPolicy> = {\n ...DEFAULT_CONTEXT_POLICY,\n ...(contextPolicy ?? {}),\n };\n\n const toolEvents: ToolEvent[] = [];\n let applyPatchRetryCount = 0;\n\n const fullTraceContents: any[] = keepFullTrace ? [...initialContents] : [];\n let modelContents: any[] = [...initialContents];\n const pushBoth = (fullItem: any, modelItem: any) => {\n if (keepFullTrace) fullTraceContents.push(fullItem);\n modelContents.push(modelItem);\n };\n const pushModelOnly = (modelItem: any) => {\n modelContents.push(modelItem);\n };\n\n for (let step = 0; step < maxSteps; step++) {\n modelContents = compactForModel({\n initialCount: initialContents.length,\n modelContents,\n toolEvents,\n policy,\n });\n\n if (policy.logApproxModelChars) {\n const approxChars = JSON.stringify(modelContents).length;\n console.log(\"Tool loop: approx model chars\", {\n approxChars,\n step: step + 1,\n });\n }\n\n let response: Awaited<ReturnType<AiCallFn>>;\n response = await aiCallWithRetry({\n aiCall,\n request: modelContents,\n options: { tools, toolCallingMode },\n retryMax: aiCallAutoRetryMax,\n retryBaseMs: aiCallAutoRetryBaseMs,\n retryMaxMs: aiCallAutoRetryMaxMs,\n step: step + 1,\n logger,\n });\n\n const functionCalls = response.functionCalls ?? [];\n if (functionCalls.length === 0) {\n return {\n contents: keepFullTrace ? fullTraceContents : modelContents,\n modelContents,\n finalText: (response.text ?? \"\").trim(),\n steps: step + 1,\n };\n }\n\n for (const call of functionCalls) {\n const name = call.name?.toString() ?? \"\";\n const args = (call.args ?? {}) as Record<string, unknown>;\n\n if (!name) {\n throw new Error(\"Tool loop: function call missing name.\");\n }\n\n const handler = handlers[name];\n const handlerMissingResult = !handler\n ? {\n success: false,\n error: `No handler registered for \"${name}\".`,\n error_detail: {\n name: \"MissingToolHandlerError\",\n message: `No handler registered for \"${name}\".`,\n },\n }\n : null;\n\n let effectiveArgs: Record<string, unknown> = args;\n let readFileMeta: {\n start: number;\n end: number;\n wasCapped: boolean;\n } | null = null;\n if (name === \"read_file\") {\n const normalized = normalizeReadFileArgs(\n effectiveArgs,\n policy.readFileDefaultMaxLines,\n );\n effectiveArgs = normalized.effectiveArgs;\n readFileMeta = {\n start: normalized.start,\n end: normalized.end,\n wasCapped: normalized.wasCapped,\n };\n }\n\n logger(\n buildToolStatusMessage(name, effectiveArgs, readFileMeta),\n EVENT_TYPES.STEP_STARTED,\n );\n\n const modelArgs = redactFunctionCallArgs(name, effectiveArgs);\n\n const assistantFull = {\n role: \"model\",\n parts: [\n {\n functionCall: {\n name,\n args: effectiveArgs,\n },\n },\n ],\n };\n\n const assistantModel = {\n role: \"model\",\n parts: [\n {\n functionCall: {\n name,\n args: modelArgs,\n },\n },\n ],\n };\n\n if (keepFullTrace) {\n pushBoth(assistantFull, assistantModel);\n } else {\n pushModelOnly(assistantModel);\n }\n\n let toolResultRaw: unknown;\n if (handlerMissingResult) {\n toolResultRaw = handlerMissingResult;\n } else {\n try {\n toolResultRaw = await handler(effectiveArgs);\n } catch (err) {\n logger(`AI tool: ${name} failed`, EVENT_TYPES.STEP_ERROR);\n console.error(\"Tool loop: handler threw\", err, {\n tool: name,\n step: step + 1,\n });\n toolResultRaw = {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n error_detail: serializeError(err),\n note: \"Tool handler threw. Inspect error_detail and retry with corrected args or a different approach.\",\n };\n }\n }\n let toolResult: unknown = toolResultRaw;\n\n if (name === \"read_file\" && readFileMeta) {\n const path = String(effectiveArgs.path ?? \"\");\n\n const jsonPayload =\n (toolResultRaw as any)?.kind === \"json\" ? (toolResultRaw as any)?.json : undefined;\n if (jsonPayload !== undefined) {\n // Token-efficient: return JSON as structured data (no double-stringifying).\n toolResult = { path, json: jsonPayload };\n } else {\n const rawContent =\n typeof (toolResultRaw as any)?.content === \"string\"\n ? String((toolResultRaw as any).content)\n : typeof toolResultRaw === \"string\"\n ? toolResultRaw\n : JSON.stringify(toolResultRaw ?? null);\n\n toolResult = {\n path,\n start_line: readFileMeta.start,\n end_line: readFileMeta.end,\n truncated: readFileMeta.wasCapped,\n content: rawContent,\n note: readFileMeta.wasCapped\n ? `Capped to ${policy.readFileDefaultMaxLines} lines. Request more with start_line/end_line.`\n : undefined,\n };\n }\n }\n\n try {\n await persistToolCall(name, modelArgs, toolResult);\n } catch (err) {\n console.error(\"Tool loop: failed to persist tool call\", err, {\n tool: name,\n step: step + 1,\n });\n }\n\n const responseFull = {\n role: \"user\",\n parts: [\n {\n functionResponse: {\n name,\n response: toolResult,\n },\n },\n ],\n };\n\n if (keepFullTrace) {\n fullTraceContents.push(responseFull);\n }\n modelContents.push(responseFull);\n\n if (\n name === \"apply_patch\" &&\n (toolResult as any)?.success === false &&\n applyPatchAutoRetryMax > 0 &&\n applyPatchRetryCount < applyPatchAutoRetryMax\n ) {\n applyPatchRetryCount += 1;\n\n const error = String((toolResult as any)?.error ?? \"unknown error\");\n const debugFiles = Array.isArray((toolResult as any)?.debug?.files)\n ? ((toolResult as any).debug.files as Array<{\n path?: string;\n head?: string;\n }>)\n : [];\n\n const debugText =\n debugFiles.length > 0\n ? `\\n\\nFILE SNAPSHOTS (for regenerating the patch):\\n${debugFiles\n .slice(0, 3)\n .map(\n (f) =>\n `--- ${String(f.path ?? \"\")} ---\\n${String(\n f.head ?? \"\",\n )}\\n--- end ---`,\n )\n .join(\"\\n\\n\")}`\n : \"\";\n\n const retryInstruction = {\n role: \"user\",\n parts: [\n {\n text:\n `apply_patch failed (attempt ${applyPatchRetryCount}/${applyPatchAutoRetryMax}): ${error}\\n` +\n `Regenerate a patch that matches the current file contents. ` +\n `For large rewrites, prefer write_file(path, content) or Delete+Add instead of Update.` +\n debugText,\n },\n ],\n };\n\n if (keepFullTrace) fullTraceContents.push(retryInstruction);\n modelContents.push(retryInstruction);\n }\n\n recordToolEvent({\n toolEvents,\n name,\n effectiveArgs,\n modelArgs,\n readFileMeta,\n toolResult,\n toolResultRaw,\n });\n\n if (terminalToolNames.includes(name)) {\n return {\n contents: keepFullTrace ? fullTraceContents : modelContents,\n modelContents,\n finalText: \"\",\n steps: step + 1,\n terminalCall: { name, args: effectiveArgs, response: toolResultRaw },\n };\n }\n }\n }\n\n throw new Error(`Tool loop: max steps reached (${maxSteps}).`);\n}\n"]}
1
+ {"version":3,"file":"toolLoopRunner.js","sourceRoot":"","sources":["../../../src/ai/toolLoop/toolLoopRunner.ts"],"names":[],"mappings":"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","sourcesContent":["import { FunctionCallingConfigMode, Tool } from \"@google/genai\";\nimport { persistToolCall } from \"../../services/toolcallPersist.service.js\";\nimport { EVENT_TYPES, EventType } from \"../../types/events.js\";\nimport {\n compactForModel,\n DEFAULT_CONTEXT_POLICY,\n normalizeReadFileArgs,\n redactFunctionCallArgs,\n ToolEvent,\n ToolLoopContextPolicy,\n} from \"./toolLoopContext.js\";\nimport {\n aiCallWithRetry,\n buildToolStatusMessage,\n recordToolEvent,\n serializeError,\n} from \"./toolLoopRunnerUtils.js\";\n\nexport type ToolHandler = (args: Record<string, unknown>) => Promise<unknown>;\n\nexport type ToolLoopResult = {\n contents: any[];\n modelContents: any[];\n finalText: string;\n steps: number;\n terminalCall?: {\n name: string;\n args: Record<string, unknown>;\n response: unknown;\n };\n};\n\nexport type Logger = (message: string, eventType: EventType) => Promise<void>;\n\nexport type AiCallResponse = {\n functionCalls?: any[];\n text?: string;\n};\n\nexport type AiCallFn = (\n request: unknown,\n options: {\n tools?: Tool[];\n model?: string;\n toolCallingMode?: FunctionCallingConfigMode;\n },\n) => Promise<AiCallResponse>;\n\nexport type RunToolLoopOptions = {\n initialContents: any[];\n tools: Tool[];\n handlers: Record<string, ToolHandler>;\n maxSteps?: number;\n toolCallingMode?: FunctionCallingConfigMode;\n terminalToolNames?: string[];\n keepFullTrace?: boolean;\n contextPolicy?: ToolLoopContextPolicy;\n aiCall: AiCallFn;\n logger: Logger;\n applyPatchAutoRetryMax?: number;\n aiCallAutoRetryMax?: number;\n aiCallAutoRetryBaseMs?: number;\n aiCallAutoRetryMaxMs?: number;\n};\n\nexport async function runToolLoop(\n options: RunToolLoopOptions,\n): Promise<ToolLoopResult> {\n const {\n initialContents,\n tools,\n handlers,\n maxSteps = 30,\n toolCallingMode = FunctionCallingConfigMode.ANY,\n terminalToolNames = [],\n keepFullTrace = true,\n contextPolicy,\n aiCall,\n logger,\n applyPatchAutoRetryMax = 2,\n aiCallAutoRetryMax = 3, // must have it to try 3 times as gemini errors a lot due to high demand sometimes\n aiCallAutoRetryBaseMs = 400,\n aiCallAutoRetryMaxMs = 10_000,\n } = options;\n\n if (typeof aiCall !== \"function\") {\n throw new Error(\"Tool loop: aiCall is required.\");\n }\n\n const policy: Required<ToolLoopContextPolicy> = {\n ...DEFAULT_CONTEXT_POLICY,\n ...(contextPolicy ?? {}),\n };\n\n const toolEvents: ToolEvent[] = [];\n let applyPatchRetryCount = 0;\n\n const fullTraceContents: any[] = keepFullTrace ? [...initialContents] : [];\n let modelContents: any[] = [...initialContents];\n const pushBoth = (fullItem: any, modelItem: any) => {\n if (keepFullTrace) fullTraceContents.push(fullItem);\n modelContents.push(modelItem);\n };\n const pushModelOnly = (modelItem: any) => {\n modelContents.push(modelItem);\n };\n\n for (let step = 0; step < maxSteps; step++) {\n const remaining = maxSteps - step;\n\n const budgetInstruction = {\n role: \"user\",\n parts: [\n {\n text:\n `Execution limit: ${remaining} turn(s) remaining including this one. ` +\n `One turn = one assistant response in the tool loop. ` +\n `Complete the task in as few turns as possible and avoid unnecessary actions. Prioritize correctness` +\n `${remaining <= 5 ? `Approaching execution limit. Only ${remaining} turns left` : \"\"}`,\n },\n ],\n };\n\n if (keepFullTrace) {\n fullTraceContents.push(budgetInstruction);\n }\n modelContents.push(budgetInstruction);\n\n modelContents = compactForModel({\n initialCount: initialContents.length,\n modelContents,\n toolEvents,\n policy,\n });\n\n if (policy.logApproxModelChars) {\n const approxChars = JSON.stringify(modelContents).length;\n console.log(\"Tool loop: approx model chars\", {\n approxChars,\n step: step + 1,\n });\n }\n\n let response: Awaited<ReturnType<AiCallFn>>;\n response = await aiCallWithRetry({\n aiCall,\n request: modelContents,\n options: { tools, toolCallingMode },\n retryMax: aiCallAutoRetryMax,\n retryBaseMs: aiCallAutoRetryBaseMs,\n retryMaxMs: aiCallAutoRetryMaxMs,\n step: step + 1,\n logger,\n });\n\n const functionCalls = response.functionCalls ?? [];\n if (functionCalls.length === 0) {\n return {\n contents: keepFullTrace ? fullTraceContents : modelContents,\n modelContents,\n finalText: (response.text ?? \"\").trim(),\n steps: step + 1,\n };\n }\n\n for (const call of functionCalls) {\n const name = call.name?.toString() ?? \"\";\n const args = (call.args ?? {}) as Record<string, unknown>;\n\n if (!name) {\n throw new Error(\"Tool loop: function call missing name.\");\n }\n\n const handler = handlers[name];\n const handlerMissingResult = !handler\n ? {\n success: false,\n error: `No handler registered for \"${name}\".`,\n error_detail: {\n name: \"MissingToolHandlerError\",\n message: `No handler registered for \"${name}\".`,\n },\n }\n : null;\n\n let effectiveArgs: Record<string, unknown> = args;\n let readFileMeta: {\n start: number;\n end: number;\n wasCapped: boolean;\n } | null = null;\n if (name === \"read_file\") {\n const normalized = normalizeReadFileArgs(\n effectiveArgs,\n policy.readFileDefaultMaxLines,\n );\n effectiveArgs = normalized.effectiveArgs;\n readFileMeta = {\n start: normalized.start,\n end: normalized.end,\n wasCapped: normalized.wasCapped,\n };\n }\n\n logger(\n buildToolStatusMessage(name, effectiveArgs, readFileMeta),\n EVENT_TYPES.STEP_STARTED,\n );\n\n const modelArgs = redactFunctionCallArgs(name, effectiveArgs);\n\n const assistantFull = {\n role: \"model\",\n parts: [\n {\n functionCall: {\n name,\n args: effectiveArgs,\n },\n },\n ],\n };\n\n const assistantModel = {\n role: \"model\",\n parts: [\n {\n functionCall: {\n name,\n args: modelArgs,\n },\n },\n ],\n };\n\n if (keepFullTrace) {\n pushBoth(assistantFull, assistantModel);\n } else {\n pushModelOnly(assistantModel);\n }\n\n let toolResultRaw: unknown;\n if (handlerMissingResult) {\n toolResultRaw = handlerMissingResult;\n } else {\n try {\n toolResultRaw = await handler(effectiveArgs);\n } catch (err) {\n logger(`AI tool: ${name} failed`, EVENT_TYPES.STEP_ERROR);\n console.error(\"Tool loop: handler threw\", err, {\n tool: name,\n step: step + 1,\n });\n toolResultRaw = {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n error_detail: serializeError(err),\n note: \"Tool handler threw. Inspect error_detail and retry with corrected args or a different approach.\",\n };\n }\n }\n let toolResult: unknown = toolResultRaw;\n\n if (name === \"read_file\" && readFileMeta) {\n const path = String(effectiveArgs.path ?? \"\");\n\n const jsonPayload =\n (toolResultRaw as any)?.kind === \"json\"\n ? (toolResultRaw as any)?.json\n : undefined;\n if (jsonPayload !== undefined) {\n // Token-efficient: return JSON as structured data (no double-stringifying).\n toolResult = { path, json: jsonPayload };\n } else {\n const rawContent =\n typeof (toolResultRaw as any)?.content === \"string\"\n ? String((toolResultRaw as any).content)\n : typeof toolResultRaw === \"string\"\n ? toolResultRaw\n : JSON.stringify(toolResultRaw ?? null);\n\n toolResult = {\n path,\n start_line: readFileMeta.start,\n end_line: readFileMeta.end,\n truncated: readFileMeta.wasCapped,\n content: rawContent,\n note: readFileMeta.wasCapped\n ? `Capped to ${policy.readFileDefaultMaxLines} lines. Request more with start_line/end_line.`\n : undefined,\n };\n }\n }\n\n try {\n await persistToolCall(name, modelArgs, toolResult);\n } catch (err) {\n console.error(\"Tool loop: failed to persist tool call\", err, {\n tool: name,\n step: step + 1,\n });\n }\n\n const responseFull = {\n role: \"user\",\n parts: [\n {\n functionResponse: {\n name,\n response: toolResult,\n },\n },\n ],\n };\n\n if (keepFullTrace) {\n fullTraceContents.push(responseFull);\n }\n modelContents.push(responseFull);\n\n if (\n name === \"apply_patch\" &&\n (toolResult as any)?.success === false &&\n applyPatchAutoRetryMax > 0 &&\n applyPatchRetryCount < applyPatchAutoRetryMax\n ) {\n applyPatchRetryCount += 1;\n\n const error = String((toolResult as any)?.error ?? \"unknown error\");\n const debugFiles = Array.isArray((toolResult as any)?.debug?.files)\n ? ((toolResult as any).debug.files as Array<{\n path?: string;\n head?: string;\n }>)\n : [];\n\n const debugText =\n debugFiles.length > 0\n ? `\\n\\nFILE SNAPSHOTS (for regenerating the patch):\\n${debugFiles\n .slice(0, 3)\n .map(\n (f) =>\n `--- ${String(f.path ?? \"\")} ---\\n${String(\n f.head ?? \"\",\n )}\\n--- end ---`,\n )\n .join(\"\\n\\n\")}`\n : \"\";\n\n const retryInstruction = {\n role: \"user\",\n parts: [\n {\n text:\n `apply_patch failed (attempt ${applyPatchRetryCount}/${applyPatchAutoRetryMax}): ${error}\\n` +\n `Regenerate a patch that matches the current file contents. ` +\n `For large rewrites, prefer write_file(path, content) or Delete+Add instead of Update.` +\n debugText,\n },\n ],\n };\n\n if (keepFullTrace) fullTraceContents.push(retryInstruction);\n modelContents.push(retryInstruction);\n }\n\n recordToolEvent({\n toolEvents,\n name,\n effectiveArgs,\n modelArgs,\n readFileMeta,\n toolResult,\n toolResultRaw,\n });\n\n if (terminalToolNames.includes(name)) {\n return {\n contents: keepFullTrace ? fullTraceContents : modelContents,\n modelContents,\n finalText: \"\",\n steps: step + 1,\n terminalCall: { name, args: effectiveArgs, response: toolResultRaw },\n };\n }\n }\n }\n\n return {\n contents: keepFullTrace ? fullTraceContents : modelContents,\n modelContents,\n finalText: `Stopped: max steps reached (${maxSteps}).`,\n steps: maxSteps,\n };\n}\n"]}
package/dist/core.d.ts CHANGED
@@ -36,6 +36,7 @@ export declare class QwintlyCore {
36
36
  private readonly statusRepo;
37
37
  private readonly ctxRepo;
38
38
  private readonly redisStatusPublisher;
39
+ private readonly projectOpsRepo;
39
40
  constructor(options: QwintlyCoreOptions);
40
41
  runAiFlow(initialContents: any[], tools: Tool[], handlers: Record<string, ToolHandler>, maxSteps: number, terminalToolNames: string[]): Promise<ToolLoopResult>;
41
42
  streamLog(message: string, eventType: EventType, displayedSummary?: boolean): Promise<void>;
@@ -44,5 +45,6 @@ export declare class QwintlyCore {
44
45
  buildPlannerIdx(): Promise<PlannerIndex>;
45
46
  buildCodegenIdx(): Promise<CodegenIndex>;
46
47
  buildValidatorIdx(): Promise<ValidatorIndex>;
48
+ syncEditOps(genId: string, workspace: string): Promise<void>;
47
49
  }
48
50
  //# sourceMappingURL=core.d.ts.map
@@ -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;AAUzC,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;AAIhE,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,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,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;IAuD1B,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,CACpB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,EACpB,gBAAgB,GAAE,OAAe,GAChC,OAAO,CAAC,IAAI,CAAC;IA2BH,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;AAazC,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,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,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;IACzD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAuB;gBAE1C,OAAO,EAAE,kBAAkB;IA2D1B,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,CACpB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,EACpB,gBAAgB,GAAE,OAAe,GAChC,OAAO,CAAC,IAAI,CAAC;IA2BH,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;IAI5C,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CAU1D"}
package/dist/core.js CHANGED
@@ -9,8 +9,10 @@ import { statusService } from "./logging/genStatus.service.js";
9
9
  import { SendStatusToRedis } from "./logging/redis.service.js";
10
10
  import { ContextRepository } from "./repository/context.repository.js";
11
11
  import { GenStatusRepository } from "./repository/genStatus.repository.js";
12
- import { assertNonEmptyString } from "./utils/utils.js";
12
+ import { ProjectOpsRepository } from "./repository/projectOperations.repository.js";
13
+ import { applyOperations } from "./services/syncEditOps.service.js";
13
14
  import { initializeToolCallsRepository } from "./services/toolcallPersist.service.js";
15
+ import { assertNonEmptyString } from "./utils/utils.js";
14
16
  export class QwintlyCore {
15
17
  constructor(options) {
16
18
  assertNonEmptyString(options.chatId, "chatId");
@@ -38,6 +40,7 @@ export class QwintlyCore {
38
40
  }
39
41
  this.statusRepo = new GenStatusRepository(options.supabase.endpoint, options.supabase.secret);
40
42
  this.ctxRepo = new ContextRepository(options.supabase.endpoint, options.supabase.secret);
43
+ this.projectOpsRepo = new ProjectOpsRepository(options.supabase.endpoint, options.supabase.secret);
41
44
  this.redisStatusPublisher = new SendStatusToRedis(options.upstash.url, options.upstash.token);
42
45
  initializeToolCallsRepository(options.supabase.endpoint, options.supabase.secret, options.sessionId);
43
46
  console.log(`QwintlyCore initialized (chatId=${this.chatId}, sessionId=${this.sessionId})`);
@@ -94,5 +97,17 @@ export class QwintlyCore {
94
97
  async buildValidatorIdx() {
95
98
  return this.buildIndex(buildValidatorIndex);
96
99
  }
100
+ async syncEditOps(genId, workspace) {
101
+ if (!genId)
102
+ return;
103
+ const projectOpsRepo = this.projectOpsRepo;
104
+ const ops = await projectOpsRepo.fetchProjectOperations(genId);
105
+ if (!ops || ops.length === 0)
106
+ return;
107
+ const appliedIds = await applyOperations(ops, workspace);
108
+ if (appliedIds.length > 0) {
109
+ await projectOpsRepo.markOperationsApplied(appliedIds);
110
+ }
111
+ }
97
112
  }
98
113
  //# sourceMappingURL=core.js.map
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 { initUnsplash } from \"./image/unsplash.service.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\";\nimport { initializeToolCallsRepository } from \"./services/toolcallPersist.service.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 unsplash: { url: string; accessKey: 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.unsplash?.url && options.unsplash?.accessKey) {\n initUnsplash({\n url: options.unsplash.url,\n accessKey: options.unsplash.accessKey,\n });\n }\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 initializeToolCallsRepository(\n options.supabase.endpoint,\n options.supabase.secret,\n options.sessionId,\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(\n message: string,\n eventType: EventType,\n displayedSummary: boolean = false,\n ): 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 displayedSummary,\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 { initUnsplash } from \"./image/unsplash.service.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 { ProjectOpsRepository } from \"./repository/projectOperations.repository.js\";\nimport { applyOperations } from \"./services/syncEditOps.service.js\";\nimport { initializeToolCallsRepository } from \"./services/toolcallPersist.service.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 unsplash: { url: string; accessKey: 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 private readonly projectOpsRepo: ProjectOpsRepository;\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.unsplash?.url && options.unsplash?.accessKey) {\n initUnsplash({\n url: options.unsplash.url,\n accessKey: options.unsplash.accessKey,\n });\n }\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.projectOpsRepo = new ProjectOpsRepository(\n options.supabase.endpoint,\n options.supabase.secret,\n );\n this.redisStatusPublisher = new SendStatusToRedis(\n options.upstash.url,\n options.upstash.token,\n );\n initializeToolCallsRepository(\n options.supabase.endpoint,\n options.supabase.secret,\n options.sessionId,\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(\n message: string,\n eventType: EventType,\n displayedSummary: boolean = false,\n ): 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 displayedSummary,\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 public async syncEditOps(genId: string, workspace: string) {\n if (!genId) return;\n const projectOpsRepo = this.projectOpsRepo;\n const ops = await projectOpsRepo.fetchProjectOperations(genId);\n if (!ops || ops.length === 0) return;\n const appliedIds = await applyOperations(ops, workspace);\n if (appliedIds.length > 0) {\n await projectOpsRepo.markOperationsApplied(appliedIds);\n }\n }\n}\n"]}
@@ -46,7 +46,7 @@ export declare const projectConfigs: {
46
46
  };
47
47
  readonly guidance: {
48
48
  readonly do: readonly ["route = URL path", "edit only pageConfig.json for UI changes", "keep '/' populated", "RenderElement and BuilderElement already exist", "new routes require page.tsx + pageConfig.json", "prefer nested composition"];
49
- readonly dont: readonly ["don't treat routes as file paths", "don't modify page.tsx", "don't generate React layout components"];
49
+ readonly dont: readonly ["don't treat routes as file paths", "don't generate React layout components", "You are not allowed to modify anything other than pageConfig.json. Edits to page.tsx, layout.tsx, global.css, tailwind.config.ts are strictly prohibited. You can however create new routes with new pageConfig.json files but they will have fixed page.tsx."];
50
50
  };
51
51
  };
52
52
  };
@@ -73,8 +73,8 @@ export const projectConfigs = {
73
73
  ],
74
74
  dont: [
75
75
  "don't treat routes as file paths",
76
- "don't modify page.tsx",
77
76
  "don't generate React layout components",
77
+ "You are not allowed to modify anything other than pageConfig.json. Edits to page.tsx, layout.tsx, global.css, tailwind.config.ts are strictly prohibited. You can however create new routes with new pageConfig.json files but they will have fixed page.tsx.",
78
78
  ],
79
79
  },
80
80
  },
@@ -1 +1 @@
1
- {"version":3,"file":"configs.constants.js","sourceRoot":"","sources":["../../../src/indexer/data/configs.constants.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,eAAe,EAAE;QACf,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,YAAY;QACpB,QAAQ,EAAE,YAAY;QACtB,KAAK,EAAE,oBAAoB;QAC3B,OAAO,EAAE,cAAc;KACxB;IACD,aAAa,EAAE;QACb,MAAM,EAAE,eAAe;QACvB,aAAa,EAAE,UAAU;QACzB,SAAS,EAAE,UAAU;QACrB,YAAY,EAAE,+BAA+B;KAC9C;IACD,aAAa,EAAE;QACb,cAAc,EAAE,KAAK;QACrB,OAAO,EAAE,QAAQ;QACjB,UAAU,EAAE,UAAU;QACtB,SAAS,EAAE,cAAc;QACzB,OAAO,EAAE,MAAM;KAChB;IACD,eAAe,EAAE;QACf,QAAQ,EAAE,eAAe;QAEzB,MAAM,EAAE;YACN,OAAO,EAAE,6BAA6B;YACtC,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,CAAC;YAErC,SAAS,EAAE;gBACT,GAAG,EAAE,oCAAoC;gBACzC,QAAQ,EAAE,gDAAgD;aAC3D;YAED,KAAK,EAAE,CAAC,UAAU,EAAE,iBAAiB,CAAC;YAEtC,aAAa,EAAE,iBAAiB;YAEhC,MAAM,EAAE;gBACN,IAAI,EAAE,4BAA4B;aACnC;SACF;QAED,QAAQ,EAAE;YACR,IAAI,EAAE,UAAU;YAEhB,QAAQ,EAAE;gBACR,2BAA2B;gBAC3B,yCAAyC;gBACzC,4CAA4C;aAC7C;YAED,KAAK,EAAE,IAAI;SACZ;QAED,QAAQ,EAAE;YACR,IAAI,EAAE,gBAAgB;YAEtB,SAAS,EAAE;gBACT,UAAU;gBACV,KAAK;gBACL,MAAM;gBACN,OAAO;gBACP,QAAQ;gBACR,OAAO;gBACP,UAAU;gBACV,MAAM;gBACN,MAAM;aACP;YAED,KAAK,EAAE;gBACL,6BAA6B;gBAC7B,qCAAqC;gBACrC,+BAA+B;aAChC;SACF;QAED,QAAQ,EAAE;YACR,EAAE,EAAE;gBACF,kBAAkB;gBAClB,0CAA0C;gBAC1C,oBAAoB;gBACpB,gDAAgD;gBAChD,+CAA+C;gBAC/C,2BAA2B;aAC5B;YAED,IAAI,EAAE;gBACJ,kCAAkC;gBAClC,uBAAuB;gBACvB,wCAAwC;aACzC;SACF;KACF;CACsC,CAAC;AAE1C,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,iBAAiB,EAAE;QACjB,KAAK;QACL,MAAM;QACN,KAAK;QACL,MAAM;QACN,OAAO;QACP,KAAK;QACL,MAAM;QACN,MAAM;QACN,OAAO;QACP,OAAO;KACR;IACD,kBAAkB,EAAE;QAClB,cAAc;QACd,OAAO;QACP,MAAM;QACN,OAAO;QACP,KAAK;QACL,UAAU;QACV,MAAM;KACP;IACD,YAAY,EAAE,MAAO;IACrB,SAAS,EAAE,GAAG;IACd,YAAY,EAAE,GAAG;CACgB,CAAC","sourcesContent":["import { ProjectConfigsConfig } from \"../../types/index/configs.types.js\";\nimport { IndexingConfig } from \"../../types/index/indexing.types.js\";\n\nexport const projectConfigs = {\n frameworkConfig: {\n name: \"Next.js\",\n router: \"App Router\",\n language: \"TypeScript\",\n icons: \"lucide-react icons\",\n styling: \"Tailwind CSS\",\n },\n runtimeConfig: {\n target: \"frontend-only\",\n serverActions: \"disabled\",\n apiRoutes: \"disabled\",\n dataFetching: \"client-side (fetch or mocked)\",\n },\n toolingConfig: {\n packageManager: \"npm\",\n linting: \"eslint\",\n formatting: \"prettier\",\n typecheck: \"tsc --noEmit\",\n testing: \"none\",\n },\n renderingConfig: {\n approach: \"config-driven\",\n\n routes: {\n meaning: \"URL pathname, not file path\",\n examples: [\"/\", \"/about\", \"/pricing\"],\n\n structure: {\n \"/\": \"app/page.tsx + app/pageConfig.json\",\n \"/about\": \"app/about/page.tsx + app/about/pageConfig.json\",\n },\n\n files: [\"page.tsx\", \"pageConfig.json\"],\n\n sourceOfTruth: \"pageConfig.json\",\n\n config: {\n root: \"elements: BuilderElement[]\",\n },\n },\n\n renderer: {\n file: \"page.tsx\",\n\n behavior: [\n \"imports ./pageConfig.json\",\n \"casts to { elements: BuilderElement[] }\",\n \"renders config.elements with RenderElement\",\n ],\n\n fixed: true,\n },\n\n elements: {\n type: \"BuilderElement\",\n\n supported: [\n \"fragment\",\n \"div\",\n \"text\",\n \"image\",\n \"button\",\n \"input\",\n \"textarea\",\n \"link\",\n \"icon\",\n ],\n\n rules: [\n \"Tailwind via className only\",\n \"supports children: BuilderElement[]\",\n \"unknown types render error UI\",\n ],\n },\n\n guidance: {\n do: [\n \"route = URL path\",\n \"edit only pageConfig.json for UI changes\",\n \"keep '/' populated\",\n \"RenderElement and BuilderElement already exist\",\n \"new routes require page.tsx + pageConfig.json\",\n \"prefer nested composition\",\n ],\n\n dont: [\n \"don't treat routes as file paths\",\n \"don't modify page.tsx\",\n \"don't generate React layout components\",\n ],\n },\n },\n} as const satisfies ProjectConfigsConfig;\n\nexport const indexing = {\n includeExtensions: [\n \".ts\",\n \".tsx\",\n \".js\",\n \".jsx\",\n \".json\",\n \".md\",\n \".mdx\",\n \".css\",\n \".scss\",\n \".sass\",\n ],\n excludeDirectories: [\n \"node_modules\",\n \".next\",\n \"dist\",\n \"build\",\n \"out\",\n \"coverage\",\n \".git\",\n ],\n maxFileBytes: 200_000,\n chunkSize: 900,\n chunkOverlap: 150,\n} as const satisfies IndexingConfig;\n"]}
1
+ {"version":3,"file":"configs.constants.js","sourceRoot":"","sources":["../../../src/indexer/data/configs.constants.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,eAAe,EAAE;QACf,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,YAAY;QACpB,QAAQ,EAAE,YAAY;QACtB,KAAK,EAAE,oBAAoB;QAC3B,OAAO,EAAE,cAAc;KACxB;IACD,aAAa,EAAE;QACb,MAAM,EAAE,eAAe;QACvB,aAAa,EAAE,UAAU;QACzB,SAAS,EAAE,UAAU;QACrB,YAAY,EAAE,+BAA+B;KAC9C;IACD,aAAa,EAAE;QACb,cAAc,EAAE,KAAK;QACrB,OAAO,EAAE,QAAQ;QACjB,UAAU,EAAE,UAAU;QACtB,SAAS,EAAE,cAAc;QACzB,OAAO,EAAE,MAAM;KAChB;IACD,eAAe,EAAE;QACf,QAAQ,EAAE,eAAe;QAEzB,MAAM,EAAE;YACN,OAAO,EAAE,6BAA6B;YACtC,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,CAAC;YAErC,SAAS,EAAE;gBACT,GAAG,EAAE,oCAAoC;gBACzC,QAAQ,EAAE,gDAAgD;aAC3D;YAED,KAAK,EAAE,CAAC,UAAU,EAAE,iBAAiB,CAAC;YAEtC,aAAa,EAAE,iBAAiB;YAEhC,MAAM,EAAE;gBACN,IAAI,EAAE,4BAA4B;aACnC;SACF;QAED,QAAQ,EAAE;YACR,IAAI,EAAE,UAAU;YAEhB,QAAQ,EAAE;gBACR,2BAA2B;gBAC3B,yCAAyC;gBACzC,4CAA4C;aAC7C;YAED,KAAK,EAAE,IAAI;SACZ;QAED,QAAQ,EAAE;YACR,IAAI,EAAE,gBAAgB;YAEtB,SAAS,EAAE;gBACT,UAAU;gBACV,KAAK;gBACL,MAAM;gBACN,OAAO;gBACP,QAAQ;gBACR,OAAO;gBACP,UAAU;gBACV,MAAM;gBACN,MAAM;aACP;YAED,KAAK,EAAE;gBACL,6BAA6B;gBAC7B,qCAAqC;gBACrC,+BAA+B;aAChC;SACF;QAED,QAAQ,EAAE;YACR,EAAE,EAAE;gBACF,kBAAkB;gBAClB,0CAA0C;gBAC1C,oBAAoB;gBACpB,gDAAgD;gBAChD,+CAA+C;gBAC/C,2BAA2B;aAC5B;YAED,IAAI,EAAE;gBACJ,kCAAkC;gBAClC,wCAAwC;gBACxC,+PAA+P;aAChQ;SACF;KACF;CACsC,CAAC;AAE1C,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,iBAAiB,EAAE;QACjB,KAAK;QACL,MAAM;QACN,KAAK;QACL,MAAM;QACN,OAAO;QACP,KAAK;QACL,MAAM;QACN,MAAM;QACN,OAAO;QACP,OAAO;KACR;IACD,kBAAkB,EAAE;QAClB,cAAc;QACd,OAAO;QACP,MAAM;QACN,OAAO;QACP,KAAK;QACL,UAAU;QACV,MAAM;KACP;IACD,YAAY,EAAE,MAAO;IACrB,SAAS,EAAE,GAAG;IACd,YAAY,EAAE,GAAG;CACgB,CAAC","sourcesContent":["import { ProjectConfigsConfig } from \"../../types/index/configs.types.js\";\nimport { IndexingConfig } from \"../../types/index/indexing.types.js\";\n\nexport const projectConfigs = {\n frameworkConfig: {\n name: \"Next.js\",\n router: \"App Router\",\n language: \"TypeScript\",\n icons: \"lucide-react icons\",\n styling: \"Tailwind CSS\",\n },\n runtimeConfig: {\n target: \"frontend-only\",\n serverActions: \"disabled\",\n apiRoutes: \"disabled\",\n dataFetching: \"client-side (fetch or mocked)\",\n },\n toolingConfig: {\n packageManager: \"npm\",\n linting: \"eslint\",\n formatting: \"prettier\",\n typecheck: \"tsc --noEmit\",\n testing: \"none\",\n },\n renderingConfig: {\n approach: \"config-driven\",\n\n routes: {\n meaning: \"URL pathname, not file path\",\n examples: [\"/\", \"/about\", \"/pricing\"],\n\n structure: {\n \"/\": \"app/page.tsx + app/pageConfig.json\",\n \"/about\": \"app/about/page.tsx + app/about/pageConfig.json\",\n },\n\n files: [\"page.tsx\", \"pageConfig.json\"],\n\n sourceOfTruth: \"pageConfig.json\",\n\n config: {\n root: \"elements: BuilderElement[]\",\n },\n },\n\n renderer: {\n file: \"page.tsx\",\n\n behavior: [\n \"imports ./pageConfig.json\",\n \"casts to { elements: BuilderElement[] }\",\n \"renders config.elements with RenderElement\",\n ],\n\n fixed: true,\n },\n\n elements: {\n type: \"BuilderElement\",\n\n supported: [\n \"fragment\",\n \"div\",\n \"text\",\n \"image\",\n \"button\",\n \"input\",\n \"textarea\",\n \"link\",\n \"icon\",\n ],\n\n rules: [\n \"Tailwind via className only\",\n \"supports children: BuilderElement[]\",\n \"unknown types render error UI\",\n ],\n },\n\n guidance: {\n do: [\n \"route = URL path\",\n \"edit only pageConfig.json for UI changes\",\n \"keep '/' populated\",\n \"RenderElement and BuilderElement already exist\",\n \"new routes require page.tsx + pageConfig.json\",\n \"prefer nested composition\",\n ],\n\n dont: [\n \"don't treat routes as file paths\",\n \"don't generate React layout components\",\n \"You are not allowed to modify anything other than pageConfig.json. Edits to page.tsx, layout.tsx, global.css, tailwind.config.ts are strictly prohibited. You can however create new routes with new pageConfig.json files but they will have fixed page.tsx.\",\n ],\n },\n },\n} as const satisfies ProjectConfigsConfig;\n\nexport const indexing = {\n includeExtensions: [\n \".ts\",\n \".tsx\",\n \".js\",\n \".jsx\",\n \".json\",\n \".md\",\n \".mdx\",\n \".css\",\n \".scss\",\n \".sass\",\n ],\n excludeDirectories: [\n \"node_modules\",\n \".next\",\n \"dist\",\n \"build\",\n \"out\",\n \"coverage\",\n \".git\",\n ],\n maxFileBytes: 200_000,\n chunkSize: 900,\n chunkOverlap: 150,\n} as const satisfies IndexingConfig;\n"]}
@@ -0,0 +1,6 @@
1
+ import { DBRepository } from "./repository.js";
2
+ export declare class ProjectOpsRepository extends DBRepository {
3
+ fetchProjectOperations(genId: string): Promise<any>;
4
+ markOperationsApplied(ids: string[]): Promise<void>;
5
+ }
6
+ //# sourceMappingURL=projectOperations.repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectOperations.repository.d.ts","sourceRoot":"","sources":["../../src/repository/projectOperations.repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,qBAAa,oBAAqB,SAAQ,YAAY;IAM9C,sBAAsB,CAAC,KAAK,EAAE,MAAM;IAiBpC,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE;CAY1C"}
@@ -0,0 +1,35 @@
1
+ import { DBRepository } from "./repository.js";
2
+ export class ProjectOpsRepository extends DBRepository {
3
+ /*
4
+ * Table: project_operations
5
+ * Use: Fetch queued project operations
6
+ */
7
+ async fetchProjectOperations(genId) {
8
+ const supabase = this.client;
9
+ const { data, error } = await supabase
10
+ .from("project_operations")
11
+ .select("id, operation, route")
12
+ .eq("gen_id", genId)
13
+ .eq("status", "queued")
14
+ .order("created_at", { ascending: true });
15
+ if (error)
16
+ throw error;
17
+ return data;
18
+ }
19
+ /*
20
+ * Table: project_operations
21
+ * Use: Update project operation status
22
+ */
23
+ async markOperationsApplied(ids) {
24
+ if (!Array.isArray(ids) || ids.length === 0)
25
+ return;
26
+ const supabase = this.client;
27
+ const { error } = await supabase
28
+ .from("project_operations")
29
+ .update({ status: "applied" })
30
+ .in("id", ids);
31
+ if (error)
32
+ throw error;
33
+ }
34
+ }
35
+ //# sourceMappingURL=projectOperations.repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectOperations.repository.js","sourceRoot":"","sources":["../../src/repository/projectOperations.repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,OAAO,oBAAqB,SAAQ,YAAY;IACpD;;;OAGG;IAEH,KAAK,CAAC,sBAAsB,CAAC,KAAa;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;QAE7B,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ;aACnC,IAAI,CAAC,oBAAoB,CAAC;aAC1B,MAAM,CAAC,sBAAsB,CAAC;aAC9B,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC;aACnB,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC;aACtB,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,IAAI,KAAK;YAAE,MAAM,KAAK,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,qBAAqB,CAAC,GAAa;QACvC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEpD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC;QAC7B,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,QAAQ;aAC7B,IAAI,CAAC,oBAAoB,CAAC;aAC1B,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;aAC7B,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAEjB,IAAI,KAAK;YAAE,MAAM,KAAK,CAAC;IACzB,CAAC;CAEF","sourcesContent":["import { DBRepository } from \"./repository.js\";\r\n\r\nexport class ProjectOpsRepository extends DBRepository {\n /*\r\n * Table: project_operations\r\n * Use: Fetch queued project operations\r\n */\r\n\r\n async fetchProjectOperations(genId: string) {\n const supabase = this.client;\r\n\r\n const { data, error } = await supabase\r\n .from(\"project_operations\")\r\n .select(\"id, operation, route\")\r\n .eq(\"gen_id\", genId)\r\n .eq(\"status\", \"queued\")\r\n .order(\"created_at\", { ascending: true });\r\n if (error) throw error;\n return data;\n }\n\n /*\n * Table: project_operations\n * Use: Update project operation status\n */\n async markOperationsApplied(ids: string[]) {\n if (!Array.isArray(ids) || ids.length === 0) return;\n\n const supabase = this.client;\n const { error } = await supabase\n .from(\"project_operations\")\n .update({ status: \"applied\" })\n .in(\"id\", ids);\n\n if (error) throw error;\n }\n\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare const applyOperations: (ops: any, workspace: string) => Promise<string[]>;
2
+ //# sourceMappingURL=syncEditOps.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syncEditOps.service.d.ts","sourceRoot":"","sources":["../../src/services/syncEditOps.service.ts"],"names":[],"mappings":"AA0HA,eAAO,MAAM,eAAe,GAC1B,KAAK,GAAG,EACR,WAAW,MAAM,KAChB,OAAO,CAAC,MAAM,EAAE,CAuHlB,CAAC"}
@@ -0,0 +1,221 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ async function pathExists(p) {
4
+ try {
5
+ await fs.stat(p);
6
+ return true;
7
+ }
8
+ catch {
9
+ return false;
10
+ }
11
+ }
12
+ function isRouteGroupSegment(segment) {
13
+ return segment.startsWith("(") && segment.endsWith(")");
14
+ }
15
+ function routeFromAppDir(appRoot, dirAbsPath) {
16
+ const rel = path.relative(appRoot, dirAbsPath);
17
+ if (!rel || rel === ".")
18
+ return "/";
19
+ const parts = rel
20
+ .split(path.sep)
21
+ .filter(Boolean)
22
+ .filter((seg) => {
23
+ if (isRouteGroupSegment(seg))
24
+ return false;
25
+ if (seg.startsWith("@"))
26
+ return false; // parallel routes
27
+ return true;
28
+ });
29
+ return `/${parts.join("/")}`;
30
+ }
31
+ async function walkDirs(rootAbs) {
32
+ const dirs = [];
33
+ const queue = [rootAbs];
34
+ while (queue.length) {
35
+ const current = queue.shift();
36
+ dirs.push(current);
37
+ const entries = await fs.readdir(current, { withFileTypes: true });
38
+ for (const entry of entries) {
39
+ if (!entry.isDirectory())
40
+ continue;
41
+ queue.push(path.join(current, entry.name));
42
+ }
43
+ }
44
+ return dirs;
45
+ }
46
+ async function readJsonFile(filePath) {
47
+ const raw = await fs.readFile(filePath, "utf-8");
48
+ return JSON.parse(raw);
49
+ }
50
+ async function writeJsonFile(filePath, value) {
51
+ const out = `${JSON.stringify(value, null, 2)}\n`;
52
+ await fs.writeFile(filePath, out, "utf-8");
53
+ }
54
+ function findElementById(elements, id) {
55
+ for (const element of elements) {
56
+ if (!element || typeof element !== "object")
57
+ continue;
58
+ if (element.id === id)
59
+ return { element, parent: null };
60
+ const children = element.children;
61
+ if (Array.isArray(children) && children.length) {
62
+ const found = findElementById(children, id);
63
+ if (found)
64
+ return { element: found.element, parent: element };
65
+ }
66
+ }
67
+ return null;
68
+ }
69
+ function removeElementById(elements, id) {
70
+ for (let i = 0; i < elements.length; i++) {
71
+ const el = elements[i];
72
+ if (!el || typeof el !== "object")
73
+ continue;
74
+ if (el.id === id) {
75
+ elements.splice(i, 1);
76
+ return true;
77
+ }
78
+ if (Array.isArray(el.children) && el.children.length) {
79
+ const removed = removeElementById(el.children, id);
80
+ if (removed)
81
+ return true;
82
+ }
83
+ }
84
+ return false;
85
+ }
86
+ function normalizeOps(value) {
87
+ if (!value)
88
+ return [];
89
+ if (Array.isArray(value))
90
+ return value;
91
+ if (typeof value === "string") {
92
+ try {
93
+ const parsed = JSON.parse(value);
94
+ return Array.isArray(parsed) ? parsed : [];
95
+ }
96
+ catch {
97
+ return [];
98
+ }
99
+ }
100
+ return [];
101
+ }
102
+ function normalizeRoute(value) {
103
+ if (typeof value !== "string")
104
+ return "";
105
+ const trimmed = value.trim();
106
+ if (!trimmed)
107
+ return "";
108
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
109
+ }
110
+ export const applyOperations = async (ops, workspace) => {
111
+ const appRoot = path.join(workspace, "app");
112
+ if (!(await pathExists(appRoot)))
113
+ return [];
114
+ const rows = Array.isArray(ops) ? ops : [];
115
+ if (rows.length === 0)
116
+ return [];
117
+ // Map route -> pageConfig.json path
118
+ const routeToConfigPath = new Map();
119
+ const allDirs = await walkDirs(appRoot);
120
+ for (const dirAbs of allDirs) {
121
+ const pageTsx = path.join(dirAbs, "page.tsx");
122
+ const pageConfigJson = path.join(dirAbs, "pageConfig.json");
123
+ const hasPage = await pathExists(pageTsx);
124
+ const hasConfig = await pathExists(pageConfigJson);
125
+ if (!hasPage || !hasConfig)
126
+ continue;
127
+ const routeKey = routeFromAppDir(appRoot, dirAbs);
128
+ routeToConfigPath.set(routeKey, pageConfigJson);
129
+ }
130
+ // Group ops per route so we only read/write each config once.
131
+ const opsByRoute = new Map();
132
+ for (const row of rows) {
133
+ if (!row || typeof row !== "object")
134
+ continue;
135
+ const rowId = typeof row.id === "string" ? row.id : "";
136
+ if (!rowId)
137
+ continue;
138
+ const route = normalizeRoute(row.route);
139
+ if (!route)
140
+ continue;
141
+ const list = normalizeOps(row.operation);
142
+ if (list.length === 0)
143
+ continue;
144
+ const existing = opsByRoute.get(route) ?? [];
145
+ existing.push({ rowId, ops: list });
146
+ opsByRoute.set(route, existing);
147
+ }
148
+ const appliedIds = new Set();
149
+ for (const [route, entries] of opsByRoute) {
150
+ const configPath = routeToConfigPath.get(route);
151
+ if (!configPath)
152
+ continue;
153
+ let config;
154
+ try {
155
+ config = await readJsonFile(configPath);
156
+ }
157
+ catch {
158
+ continue;
159
+ }
160
+ if (!config || typeof config !== "object")
161
+ continue;
162
+ if (!Array.isArray(config.elements))
163
+ continue;
164
+ let changed = false;
165
+ for (const entry of entries) {
166
+ let rowChanged = false;
167
+ for (const op of entry.ops) {
168
+ if (!op || typeof op !== "object")
169
+ continue;
170
+ const kind = op.kind;
171
+ if (kind === "text") {
172
+ const id = op.id;
173
+ const newText = op.newText;
174
+ if (typeof id !== "string" || typeof newText !== "string")
175
+ continue;
176
+ const found = findElementById(config.elements, id);
177
+ if (!found)
178
+ continue;
179
+ found.element.props = {
180
+ ...(found.element.props ?? {}),
181
+ text: newText,
182
+ };
183
+ changed = true;
184
+ rowChanged = true;
185
+ continue;
186
+ }
187
+ if (kind === "delete") {
188
+ const id = op.id;
189
+ const parentId = op.parentId;
190
+ if (typeof id !== "string")
191
+ continue;
192
+ if (typeof parentId === "string" && parentId) {
193
+ const parent = findElementById(config.elements, parentId)?.element;
194
+ if (parent?.children && Array.isArray(parent.children)) {
195
+ const before = parent.children.length;
196
+ parent.children = parent.children.filter((child) => child?.id !== id);
197
+ if (parent.children.length !== before) {
198
+ changed = true;
199
+ rowChanged = true;
200
+ }
201
+ continue;
202
+ }
203
+ }
204
+ // Fallback: locate and remove by id anywhere in the tree (including top-level).
205
+ if (removeElementById(config.elements, id)) {
206
+ changed = true;
207
+ rowChanged = true;
208
+ }
209
+ }
210
+ }
211
+ if (rowChanged) {
212
+ appliedIds.add(entry.rowId);
213
+ }
214
+ }
215
+ if (changed) {
216
+ await writeJsonFile(configPath, config);
217
+ }
218
+ }
219
+ return [...appliedIds];
220
+ };
221
+ //# sourceMappingURL=syncEditOps.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syncEditOps.service.js","sourceRoot":"","sources":["../../src/services/syncEditOps.service.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { BuilderElement } from \"../types/elements.js\";\nimport { ProjectOp, ProjectOperationRow } from \"../types/projectOps.types.js\";\nimport { PageConfig } from \"../types/snapshot.js\";\n\nasync function pathExists(p: string) {\n try {\n await fs.stat(p);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isRouteGroupSegment(segment: string) {\n return segment.startsWith(\"(\") && segment.endsWith(\")\");\n}\n\nfunction routeFromAppDir(appRoot: string, dirAbsPath: string) {\n const rel = path.relative(appRoot, dirAbsPath);\n if (!rel || rel === \".\") return \"/\";\n\n const parts = rel\n .split(path.sep)\n .filter(Boolean)\n .filter((seg) => {\n if (isRouteGroupSegment(seg)) return false;\n if (seg.startsWith(\"@\")) return false; // parallel routes\n return true;\n });\n\n return `/${parts.join(\"/\")}`;\n}\n\nasync function walkDirs(rootAbs: string): Promise<string[]> {\n const dirs: string[] = [];\n const queue: string[] = [rootAbs];\n\n while (queue.length) {\n const current = queue.shift()!;\n dirs.push(current);\n\n const entries = await fs.readdir(current, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n queue.push(path.join(current, entry.name));\n }\n }\n\n return dirs;\n}\n\nasync function readJsonFile<T>(filePath: string): Promise<T> {\n const raw = await fs.readFile(filePath, \"utf-8\");\n return JSON.parse(raw) as T;\n}\n\nasync function writeJsonFile(filePath: string, value: unknown) {\n const out = `${JSON.stringify(value, null, 2)}\\n`;\n await fs.writeFile(filePath, out, \"utf-8\");\n}\n\nfunction findElementById(\n elements: BuilderElement[],\n id: string,\n): { element: BuilderElement; parent: BuilderElement | null } | null {\n for (const element of elements) {\n if (!element || typeof element !== \"object\") continue;\n if (element.id === id) return { element, parent: null };\n\n const children = element.children;\n if (Array.isArray(children) && children.length) {\n const found = findElementById(children, id);\n if (found) return { element: found.element, parent: element };\n }\n }\n return null;\n}\n\nfunction removeElementById(elements: BuilderElement[], id: string): boolean {\n for (let i = 0; i < elements.length; i++) {\n const el = elements[i];\n if (!el || typeof el !== \"object\") continue;\n\n if (el.id === id) {\n elements.splice(i, 1);\n return true;\n }\n\n if (Array.isArray(el.children) && el.children.length) {\n const removed = removeElementById(el.children, id);\n if (removed) return true;\n }\n }\n\n return false;\n}\n\nfunction normalizeOps(value: unknown): ProjectOp[] {\n if (!value) return [];\n if (Array.isArray(value)) return value as ProjectOp[];\n\n if (typeof value === \"string\") {\n try {\n const parsed = JSON.parse(value) as unknown;\n return Array.isArray(parsed) ? (parsed as ProjectOp[]) : [];\n } catch {\n return [];\n }\n }\n\n return [];\n}\n\nfunction normalizeRoute(value: unknown): string {\n if (typeof value !== \"string\") return \"\";\n const trimmed = value.trim();\n if (!trimmed) return \"\";\n return trimmed.startsWith(\"/\") ? trimmed : `/${trimmed}`;\n}\n\nexport const applyOperations = async (\n ops: any,\n workspace: string,\n): Promise<string[]> => {\n const appRoot = path.join(workspace, \"app\");\n if (!(await pathExists(appRoot))) return [];\n\n const rows: ProjectOperationRow[] = Array.isArray(ops) ? ops : [];\n if (rows.length === 0) return [];\n\n // Map route -> pageConfig.json path\n const routeToConfigPath = new Map<string, string>();\n const allDirs = await walkDirs(appRoot);\n for (const dirAbs of allDirs) {\n const pageTsx = path.join(dirAbs, \"page.tsx\");\n const pageConfigJson = path.join(dirAbs, \"pageConfig.json\");\n const hasPage = await pathExists(pageTsx);\n const hasConfig = await pathExists(pageConfigJson);\n if (!hasPage || !hasConfig) continue;\n\n const routeKey = routeFromAppDir(appRoot, dirAbs);\n routeToConfigPath.set(routeKey, pageConfigJson);\n }\n\n // Group ops per route so we only read/write each config once.\n const opsByRoute = new Map<string, { rowId: string; ops: ProjectOp[] }[]>();\n for (const row of rows) {\n if (!row || typeof row !== \"object\") continue;\n const rowId = typeof row.id === \"string\" ? row.id : \"\";\n if (!rowId) continue;\n const route = normalizeRoute((row as ProjectOperationRow).route);\n if (!route) continue;\n\n const list = normalizeOps((row as ProjectOperationRow).operation);\n if (list.length === 0) continue;\n\n const existing = opsByRoute.get(route) ?? [];\n existing.push({ rowId, ops: list });\n opsByRoute.set(route, existing);\n }\n\n const appliedIds = new Set<string>();\n\n for (const [route, entries] of opsByRoute) {\n const configPath = routeToConfigPath.get(route);\n if (!configPath) continue;\n\n let config: PageConfig;\n try {\n config = await readJsonFile<PageConfig>(configPath);\n } catch {\n continue;\n }\n\n if (!config || typeof config !== \"object\") continue;\n if (!Array.isArray(config.elements)) continue;\n\n let changed = false;\n\n for (const entry of entries) {\n let rowChanged = false;\n\n for (const op of entry.ops) {\n if (!op || typeof op !== \"object\") continue;\n const kind = (op as any).kind;\n\n if (kind === \"text\") {\n const id = (op as any).id;\n const newText = (op as any).newText;\n if (typeof id !== \"string\" || typeof newText !== \"string\") continue;\n\n const found = findElementById(config.elements, id);\n if (!found) continue;\n\n found.element.props = {\n ...(found.element.props ?? {}),\n text: newText,\n };\n changed = true;\n rowChanged = true;\n continue;\n }\n\n if (kind === \"delete\") {\n const id = (op as any).id;\n const parentId = (op as any).parentId;\n if (typeof id !== \"string\") continue;\n\n if (typeof parentId === \"string\" && parentId) {\n const parent = findElementById(config.elements, parentId)?.element;\n if (parent?.children && Array.isArray(parent.children)) {\n const before = parent.children.length;\n parent.children = parent.children.filter(\n (child) => child?.id !== id,\n );\n if (parent.children.length !== before) {\n changed = true;\n rowChanged = true;\n }\n continue;\n }\n }\n\n // Fallback: locate and remove by id anywhere in the tree (including top-level).\n if (removeElementById(config.elements, id)) {\n changed = true;\n rowChanged = true;\n }\n }\n }\n\n if (rowChanged) {\n appliedIds.add(entry.rowId);\n }\n }\n\n if (changed) {\n await writeJsonFile(configPath, config);\n }\n }\n\n return [...appliedIds];\n};\n"]}
@@ -0,0 +1,18 @@
1
+ export type ProjectOperationRow = {
2
+ id?: unknown;
3
+ route?: unknown;
4
+ operation?: unknown;
5
+ };
6
+ export type TextOp = {
7
+ kind: "text";
8
+ id: string;
9
+ newText: string;
10
+ oldText?: string;
11
+ };
12
+ export type DeleteOp = {
13
+ kind: "delete";
14
+ id: string;
15
+ parentId?: string;
16
+ };
17
+ export type ProjectOp = TextOp | DeleteOp | Record<string, unknown>;
18
+ //# sourceMappingURL=projectOps.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectOps.types.d.ts","sourceRoot":"","sources":["../../src/types/projectOps.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=projectOps.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectOps.types.js","sourceRoot":"","sources":["../../src/types/projectOps.types.ts"],"names":[],"mappings":"","sourcesContent":["export type ProjectOperationRow = {\r\n id?: unknown;\r\n route?: unknown;\r\n operation?: unknown;\r\n};\r\n\r\nexport type TextOp = {\r\n kind: \"text\";\r\n id: string;\r\n newText: string;\r\n oldText?: string;\r\n};\r\n\r\nexport type DeleteOp = {\r\n kind: \"delete\";\r\n id: string;\r\n parentId?: string;\r\n};\r\n\r\nexport type ProjectOp = TextOp | DeleteOp | Record<string, unknown>;\r\n"]}
@@ -0,0 +1,8 @@
1
+ import { BuilderElement } from "./elements.js";
2
+ export type PageConfig = {
3
+ elements: BuilderElement[];
4
+ };
5
+ export type Snapshot = {
6
+ routes: Record<string, PageConfig>;
7
+ };
8
+ //# sourceMappingURL=snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/types/snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACpC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/types/snapshot.ts"],"names":[],"mappings":"","sourcesContent":["import { BuilderElement } from \"./elements.js\";\r\n\r\nexport type PageConfig = {\r\n elements: BuilderElement[];\r\n};\r\n\r\nexport type Snapshot = {\r\n routes: Record<string, PageConfig>;\r\n};\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vedangiitb/qwintly-core",
3
- "version": "1.3.11",
3
+ "version": "1.3.13",
4
4
  "description": "Qwintly Core",
5
5
  "homepage": "https://github.com/vedangiitb/qwintly-core#readme",
6
6
  "bugs": {