@makerbi/remodex 2.3.2 → 2.5.6

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.
@@ -0,0 +1,523 @@
1
+ // FILE: codex-tool-wrapper.js
2
+ // Purpose: Safely projects Codex's JavaScript exec wrapper into the nested tool calls it contains.
3
+ // Layer: CLI helper
4
+ // Exports: expandExecWrapperToolCall, isOrchestrationWaitCall
5
+
6
+ const EXEC_WRAPPER_NAME = "exec";
7
+ const APPLY_PATCH_NAME = "apply_patch";
8
+
9
+ function expandExecWrapperToolCall(payload) {
10
+ if (!isExecWrapperPayload(payload)) {
11
+ return [payload];
12
+ }
13
+
14
+ const calls = extractNestedToolCalls(payload.input);
15
+ if (calls.length === 0) {
16
+ return [payload];
17
+ }
18
+
19
+ const outerCallId = firstNonEmptyString([
20
+ payload.call_id,
21
+ payload.callId,
22
+ payload.id,
23
+ ]);
24
+
25
+ return calls.map((call, index) => {
26
+ const callId = index === 0 || !outerCallId
27
+ ? outerCallId
28
+ : `${outerCallId}:nested:${index + 1}`;
29
+ const isApplyPatch = normalizeString(call.name).toLowerCase() === APPLY_PATCH_NAME;
30
+ const projected = {
31
+ ...payload,
32
+ type: isApplyPatch ? "custom_tool_call" : "function_call",
33
+ name: call.name,
34
+ tool_name: call.name,
35
+ remodexWrappedExecCallId: outerCallId || undefined,
36
+ remodexWrappedExecCallIndex: index,
37
+ remodexWrappedExecCallCount: calls.length,
38
+ };
39
+
40
+ if (callId) {
41
+ projected.id = callId;
42
+ projected.call_id = callId;
43
+ projected.callId = callId;
44
+ }
45
+
46
+ if (isApplyPatch) {
47
+ projected.input = typeof call.argument === "string" ? call.argument : "";
48
+ delete projected.arguments;
49
+ } else {
50
+ projected.arguments = JSON.stringify(
51
+ call.argument && typeof call.argument === "object" ? call.argument : {}
52
+ );
53
+ delete projected.input;
54
+ }
55
+
56
+ return projected;
57
+ });
58
+ }
59
+
60
+ function isOrchestrationWaitCall(payload) {
61
+ if (normalizeString(payload?.name).toLowerCase() !== "wait") {
62
+ return false;
63
+ }
64
+
65
+ const argumentsObject = parseJSON(payload?.arguments);
66
+ return Boolean(
67
+ argumentsObject
68
+ && typeof argumentsObject === "object"
69
+ && !Array.isArray(argumentsObject)
70
+ && (argumentsObject.cell_id !== undefined || argumentsObject.cellId !== undefined)
71
+ );
72
+ }
73
+
74
+ function isExecWrapperPayload(payload) {
75
+ return normalizeString(payload?.name).toLowerCase() === EXEC_WRAPPER_NAME
76
+ && typeof payload?.input === "string"
77
+ && payload.input.includes("tools.");
78
+ }
79
+
80
+ function extractNestedToolCalls(source) {
81
+ const bindings = collectLiteralBindings(source);
82
+ const code = maskNonCode(source);
83
+ const pattern = /\btools\.([A-Za-z_$][\w$]*)\s*\(/g;
84
+ const calls = [];
85
+ let match;
86
+
87
+ while ((match = pattern.exec(code)) !== null) {
88
+ const openParenthesis = code.indexOf("(", match.index);
89
+ const parsed = parseLiteralAt(source, openParenthesis + 1, bindings);
90
+ calls.push({
91
+ name: match[1],
92
+ argument: parsed.ok ? parsed.value : null,
93
+ });
94
+ }
95
+
96
+ return calls;
97
+ }
98
+
99
+ function collectLiteralBindings(source) {
100
+ const bindings = new Map();
101
+ const code = maskNonCode(source);
102
+ const pattern = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=/g;
103
+ let match;
104
+
105
+ while ((match = pattern.exec(code)) !== null) {
106
+ const equalsIndex = code.indexOf("=", match.index);
107
+ const parsed = parseLiteralAt(source, equalsIndex + 1, bindings);
108
+ if (parsed.ok) {
109
+ bindings.set(match[1], parsed.value);
110
+ }
111
+ }
112
+
113
+ return bindings;
114
+ }
115
+
116
+ function parseLiteralAt(source, startIndex, bindings = new Map()) {
117
+ const parser = new SafeLiteralParser(source, bindings);
118
+ return parser.parse(startIndex);
119
+ }
120
+
121
+ class SafeLiteralParser {
122
+ constructor(source, bindings) {
123
+ this.source = source;
124
+ this.bindings = bindings;
125
+ }
126
+
127
+ parse(startIndex) {
128
+ const index = this.skipTrivia(startIndex);
129
+ const parsed = this.parseValue(index);
130
+ return parsed || { ok: false, value: null, end: index };
131
+ }
132
+
133
+ parseValue(startIndex) {
134
+ const index = this.skipTrivia(startIndex);
135
+ const character = this.source[index];
136
+
137
+ if (character === "\"" || character === "'") {
138
+ return this.parseQuotedString(index, character);
139
+ }
140
+ if (character === "`") {
141
+ return this.parseTemplateString(index);
142
+ }
143
+ if (character === "{") {
144
+ return this.parseObject(index);
145
+ }
146
+ if (character === "[") {
147
+ return this.parseArray(index);
148
+ }
149
+ if (character === "-" || isDigit(character)) {
150
+ return this.parseNumber(index);
151
+ }
152
+ if (isIdentifierStart(character)) {
153
+ return this.parseIdentifierValue(index);
154
+ }
155
+ return null;
156
+ }
157
+
158
+ parseObject(startIndex) {
159
+ const value = {};
160
+ let index = this.skipTrivia(startIndex + 1);
161
+
162
+ while (index < this.source.length && this.source[index] !== "}") {
163
+ if (this.source.startsWith("...", index)) {
164
+ index = this.skipUnknownExpression(index + 3, new Set([",", "}"]));
165
+ index = this.consumeObjectDelimiter(index);
166
+ continue;
167
+ }
168
+
169
+ const key = this.parsePropertyKey(index);
170
+ if (!key) {
171
+ return null;
172
+ }
173
+ index = this.skipTrivia(key.end);
174
+
175
+ if (this.source[index] === ":") {
176
+ const parsedValue = this.parseValue(index + 1);
177
+ if (parsedValue) {
178
+ value[key.value] = parsedValue.value;
179
+ index = parsedValue.end;
180
+ } else {
181
+ index = this.skipUnknownExpression(index + 1, new Set([",", "}"]));
182
+ }
183
+ } else if (this.bindings.has(key.value)) {
184
+ value[key.value] = this.bindings.get(key.value);
185
+ }
186
+
187
+ index = this.consumeObjectDelimiter(index);
188
+ }
189
+
190
+ if (this.source[index] !== "}") {
191
+ return null;
192
+ }
193
+ return { ok: true, value, end: index + 1 };
194
+ }
195
+
196
+ consumeObjectDelimiter(startIndex) {
197
+ let index = this.skipTrivia(startIndex);
198
+ if (this.source[index] === ",") {
199
+ index = this.skipTrivia(index + 1);
200
+ }
201
+ return index;
202
+ }
203
+
204
+ parsePropertyKey(startIndex) {
205
+ const index = this.skipTrivia(startIndex);
206
+ const character = this.source[index];
207
+ if (character === "\"" || character === "'") {
208
+ return this.parseQuotedString(index, character);
209
+ }
210
+ return this.parseIdentifier(index);
211
+ }
212
+
213
+ parseArray(startIndex) {
214
+ const value = [];
215
+ let index = this.skipTrivia(startIndex + 1);
216
+
217
+ while (index < this.source.length && this.source[index] !== "]") {
218
+ const parsedValue = this.parseValue(index);
219
+ if (parsedValue) {
220
+ value.push(parsedValue.value);
221
+ index = parsedValue.end;
222
+ } else {
223
+ index = this.skipUnknownExpression(index, new Set([",", "]"]));
224
+ }
225
+
226
+ index = this.skipTrivia(index);
227
+ if (this.source[index] === ",") {
228
+ index = this.skipTrivia(index + 1);
229
+ }
230
+ }
231
+
232
+ if (this.source[index] !== "]") {
233
+ return null;
234
+ }
235
+ return { ok: true, value, end: index + 1 };
236
+ }
237
+
238
+ parseQuotedString(startIndex, quote) {
239
+ let value = "";
240
+ let index = startIndex + 1;
241
+
242
+ while (index < this.source.length) {
243
+ const character = this.source[index];
244
+ if (character === quote) {
245
+ return { ok: true, value, end: index + 1 };
246
+ }
247
+ if (character !== "\\") {
248
+ value += character;
249
+ index += 1;
250
+ continue;
251
+ }
252
+
253
+ const escape = decodeEscape(this.source, index + 1);
254
+ if (!escape) {
255
+ return null;
256
+ }
257
+ value += escape.value;
258
+ index = escape.end;
259
+ }
260
+
261
+ return null;
262
+ }
263
+
264
+ parseTemplateString(startIndex) {
265
+ let value = "";
266
+ let index = startIndex + 1;
267
+
268
+ while (index < this.source.length) {
269
+ const character = this.source[index];
270
+ if (character === "`") {
271
+ return { ok: true, value, end: index + 1 };
272
+ }
273
+ if (character === "$" && this.source[index + 1] === "{") {
274
+ return null;
275
+ }
276
+ if (character !== "\\") {
277
+ value += character;
278
+ index += 1;
279
+ continue;
280
+ }
281
+
282
+ const escape = decodeEscape(this.source, index + 1);
283
+ if (!escape) {
284
+ return null;
285
+ }
286
+ value += escape.value;
287
+ index = escape.end;
288
+ }
289
+
290
+ return null;
291
+ }
292
+
293
+ parseNumber(startIndex) {
294
+ const match = /^-?(?:0[xX][0-9a-fA-F]+|0[bB][01]+|0[oO][0-7]+|(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?)/
295
+ .exec(this.source.slice(startIndex));
296
+ if (!match) {
297
+ return null;
298
+ }
299
+ const value = Number(match[0]);
300
+ return Number.isFinite(value)
301
+ ? { ok: true, value, end: startIndex + match[0].length }
302
+ : null;
303
+ }
304
+
305
+ parseIdentifierValue(startIndex) {
306
+ const identifier = this.parseIdentifier(startIndex);
307
+ if (!identifier) {
308
+ return null;
309
+ }
310
+
311
+ switch (identifier.value) {
312
+ case "true":
313
+ return { ok: true, value: true, end: identifier.end };
314
+ case "false":
315
+ return { ok: true, value: false, end: identifier.end };
316
+ case "null":
317
+ return { ok: true, value: null, end: identifier.end };
318
+ case "undefined":
319
+ return { ok: true, value: undefined, end: identifier.end };
320
+ default:
321
+ return this.bindings.has(identifier.value)
322
+ ? { ok: true, value: this.bindings.get(identifier.value), end: identifier.end }
323
+ : null;
324
+ }
325
+ }
326
+
327
+ parseIdentifier(startIndex) {
328
+ const match = /^[A-Za-z_$][\w$]*/.exec(this.source.slice(startIndex));
329
+ return match
330
+ ? { ok: true, value: match[0], end: startIndex + match[0].length }
331
+ : null;
332
+ }
333
+
334
+ skipUnknownExpression(startIndex, delimiters) {
335
+ const code = maskNonCode(this.source);
336
+ const stack = [];
337
+ let index = this.skipTrivia(startIndex);
338
+
339
+ while (index < code.length) {
340
+ const character = code[index];
341
+ if (character === "(" || character === "[" || character === "{") {
342
+ stack.push(character);
343
+ } else if (character === ")" || character === "]" || character === "}") {
344
+ if (stack.length === 0 && delimiters.has(character)) {
345
+ return index;
346
+ }
347
+ stack.pop();
348
+ } else if (stack.length === 0 && delimiters.has(character)) {
349
+ return index;
350
+ }
351
+ index += 1;
352
+ }
353
+
354
+ return index;
355
+ }
356
+
357
+ skipTrivia(startIndex) {
358
+ let index = startIndex;
359
+ while (index < this.source.length) {
360
+ if (/\s/.test(this.source[index])) {
361
+ index += 1;
362
+ continue;
363
+ }
364
+ if (this.source.startsWith("//", index)) {
365
+ const newline = this.source.indexOf("\n", index + 2);
366
+ index = newline === -1 ? this.source.length : newline + 1;
367
+ continue;
368
+ }
369
+ if (this.source.startsWith("/*", index)) {
370
+ const end = this.source.indexOf("*/", index + 2);
371
+ index = end === -1 ? this.source.length : end + 2;
372
+ continue;
373
+ }
374
+ break;
375
+ }
376
+ return index;
377
+ }
378
+ }
379
+
380
+ function maskNonCode(source) {
381
+ // Keep UTF-16 indexes aligned with String#indexOf/RegExp even when wrapper
382
+ // strings contain emoji or other surrogate pairs.
383
+ const characters = source.split("");
384
+ let index = 0;
385
+
386
+ while (index < source.length) {
387
+ const character = source[index];
388
+ if (character === "\"" || character === "'" || character === "`") {
389
+ index = maskQuotedRange(source, characters, index, character);
390
+ continue;
391
+ }
392
+ if (source.startsWith("//", index)) {
393
+ const end = source.indexOf("\n", index + 2);
394
+ index = maskRange(characters, index, end === -1 ? source.length : end);
395
+ continue;
396
+ }
397
+ if (source.startsWith("/*", index)) {
398
+ const end = source.indexOf("*/", index + 2);
399
+ index = maskRange(characters, index, end === -1 ? source.length : end + 2);
400
+ continue;
401
+ }
402
+ index += 1;
403
+ }
404
+
405
+ return characters.join("");
406
+ }
407
+
408
+ function maskQuotedRange(source, characters, startIndex, quote) {
409
+ let index = startIndex;
410
+ while (index < source.length) {
411
+ const character = source[index];
412
+ characters[index] = " ";
413
+ index += 1;
414
+ if (character === "\\" && index < source.length) {
415
+ characters[index] = " ";
416
+ index += 1;
417
+ continue;
418
+ }
419
+ if (index > startIndex + 1 && character === quote) {
420
+ break;
421
+ }
422
+ }
423
+ return index;
424
+ }
425
+
426
+ function maskRange(characters, startIndex, endIndex) {
427
+ for (let index = startIndex; index < endIndex; index += 1) {
428
+ characters[index] = " ";
429
+ }
430
+ return endIndex;
431
+ }
432
+
433
+ function decodeEscape(source, escapeIndex) {
434
+ const character = source[escapeIndex];
435
+ const simple = {
436
+ "0": "\0",
437
+ b: "\b",
438
+ f: "\f",
439
+ n: "\n",
440
+ r: "\r",
441
+ t: "\t",
442
+ v: "\v",
443
+ "\\": "\\",
444
+ "\"": "\"",
445
+ "'": "'",
446
+ "`": "`",
447
+ };
448
+ if (Object.prototype.hasOwnProperty.call(simple, character)) {
449
+ return { value: simple[character], end: escapeIndex + 1 };
450
+ }
451
+ if (character === "\n") {
452
+ return { value: "", end: escapeIndex + 1 };
453
+ }
454
+ if (character === "x") {
455
+ return decodeHexEscape(source, escapeIndex + 1, 2);
456
+ }
457
+ if (character === "u") {
458
+ if (source[escapeIndex + 1] === "{") {
459
+ const endBrace = source.indexOf("}", escapeIndex + 2);
460
+ if (endBrace === -1) {
461
+ return null;
462
+ }
463
+ const codePoint = Number.parseInt(source.slice(escapeIndex + 2, endBrace), 16);
464
+ return Number.isFinite(codePoint)
465
+ ? { value: String.fromCodePoint(codePoint), end: endBrace + 1 }
466
+ : null;
467
+ }
468
+ return decodeHexEscape(source, escapeIndex + 1, 4);
469
+ }
470
+ return { value: character || "", end: escapeIndex + 1 };
471
+ }
472
+
473
+ function decodeHexEscape(source, startIndex, length) {
474
+ const text = source.slice(startIndex, startIndex + length);
475
+ if (!new RegExp(`^[0-9a-fA-F]{${length}}$`).test(text)) {
476
+ return null;
477
+ }
478
+ return {
479
+ value: String.fromCodePoint(Number.parseInt(text, 16)),
480
+ end: startIndex + length,
481
+ };
482
+ }
483
+
484
+ function parseJSON(value) {
485
+ if (value && typeof value === "object") {
486
+ return value;
487
+ }
488
+ if (typeof value !== "string" || !value.trim()) {
489
+ return null;
490
+ }
491
+ try {
492
+ return JSON.parse(value);
493
+ } catch {
494
+ return null;
495
+ }
496
+ }
497
+
498
+ function firstNonEmptyString(values) {
499
+ for (const value of values) {
500
+ const normalized = normalizeString(value);
501
+ if (normalized) {
502
+ return normalized;
503
+ }
504
+ }
505
+ return "";
506
+ }
507
+
508
+ function normalizeString(value) {
509
+ return typeof value === "string" && value.trim() ? value.trim() : "";
510
+ }
511
+
512
+ function isDigit(character) {
513
+ return typeof character === "string" && /\d/.test(character);
514
+ }
515
+
516
+ function isIdentifierStart(character) {
517
+ return typeof character === "string" && /[A-Za-z_$]/.test(character);
518
+ }
519
+
520
+ module.exports = {
521
+ expandExecWrapperToolCall,
522
+ isOrchestrationWaitCall,
523
+ };