@opencode_weave/weave 0.7.4-preview.1 → 0.7.4

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.
package/dist/index.js CHANGED
@@ -1,11 +1,814 @@
1
1
  // src/index.ts
2
- import { join as join13 } from "path";
2
+ import { join as join12 } from "path";
3
3
 
4
4
  // src/config/loader.ts
5
- import { existsSync as existsSync2, readFileSync } from "node:fs";
6
- import { join as join2 } from "node:path";
7
- import { homedir as homedir2 } from "node:os";
8
- import { parse } from "jsonc-parser";
5
+ import { existsSync, readFileSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { homedir } from "node:os";
8
+
9
+ // node_modules/jsonc-parser/lib/esm/impl/scanner.js
10
+ function createScanner(text, ignoreTrivia = false) {
11
+ const len = text.length;
12
+ let pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
13
+ function scanHexDigits(count, exact) {
14
+ let digits = 0;
15
+ let value2 = 0;
16
+ while (digits < count || !exact) {
17
+ let ch = text.charCodeAt(pos);
18
+ if (ch >= 48 && ch <= 57) {
19
+ value2 = value2 * 16 + ch - 48;
20
+ } else if (ch >= 65 && ch <= 70) {
21
+ value2 = value2 * 16 + ch - 65 + 10;
22
+ } else if (ch >= 97 && ch <= 102) {
23
+ value2 = value2 * 16 + ch - 97 + 10;
24
+ } else {
25
+ break;
26
+ }
27
+ pos++;
28
+ digits++;
29
+ }
30
+ if (digits < count) {
31
+ value2 = -1;
32
+ }
33
+ return value2;
34
+ }
35
+ function setPosition(newPosition) {
36
+ pos = newPosition;
37
+ value = "";
38
+ tokenOffset = 0;
39
+ token = 16;
40
+ scanError = 0;
41
+ }
42
+ function scanNumber() {
43
+ let start = pos;
44
+ if (text.charCodeAt(pos) === 48) {
45
+ pos++;
46
+ } else {
47
+ pos++;
48
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
49
+ pos++;
50
+ }
51
+ }
52
+ if (pos < text.length && text.charCodeAt(pos) === 46) {
53
+ pos++;
54
+ if (pos < text.length && isDigit(text.charCodeAt(pos))) {
55
+ pos++;
56
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
57
+ pos++;
58
+ }
59
+ } else {
60
+ scanError = 3;
61
+ return text.substring(start, pos);
62
+ }
63
+ }
64
+ let end = pos;
65
+ if (pos < text.length && (text.charCodeAt(pos) === 69 || text.charCodeAt(pos) === 101)) {
66
+ pos++;
67
+ if (pos < text.length && text.charCodeAt(pos) === 43 || text.charCodeAt(pos) === 45) {
68
+ pos++;
69
+ }
70
+ if (pos < text.length && isDigit(text.charCodeAt(pos))) {
71
+ pos++;
72
+ while (pos < text.length && isDigit(text.charCodeAt(pos))) {
73
+ pos++;
74
+ }
75
+ end = pos;
76
+ } else {
77
+ scanError = 3;
78
+ }
79
+ }
80
+ return text.substring(start, end);
81
+ }
82
+ function scanString() {
83
+ let result = "", start = pos;
84
+ while (true) {
85
+ if (pos >= len) {
86
+ result += text.substring(start, pos);
87
+ scanError = 2;
88
+ break;
89
+ }
90
+ const ch = text.charCodeAt(pos);
91
+ if (ch === 34) {
92
+ result += text.substring(start, pos);
93
+ pos++;
94
+ break;
95
+ }
96
+ if (ch === 92) {
97
+ result += text.substring(start, pos);
98
+ pos++;
99
+ if (pos >= len) {
100
+ scanError = 2;
101
+ break;
102
+ }
103
+ const ch2 = text.charCodeAt(pos++);
104
+ switch (ch2) {
105
+ case 34:
106
+ result += '"';
107
+ break;
108
+ case 92:
109
+ result += "\\";
110
+ break;
111
+ case 47:
112
+ result += "/";
113
+ break;
114
+ case 98:
115
+ result += "\b";
116
+ break;
117
+ case 102:
118
+ result += "\f";
119
+ break;
120
+ case 110:
121
+ result += `
122
+ `;
123
+ break;
124
+ case 114:
125
+ result += "\r";
126
+ break;
127
+ case 116:
128
+ result += "\t";
129
+ break;
130
+ case 117:
131
+ const ch3 = scanHexDigits(4, true);
132
+ if (ch3 >= 0) {
133
+ result += String.fromCharCode(ch3);
134
+ } else {
135
+ scanError = 4;
136
+ }
137
+ break;
138
+ default:
139
+ scanError = 5;
140
+ }
141
+ start = pos;
142
+ continue;
143
+ }
144
+ if (ch >= 0 && ch <= 31) {
145
+ if (isLineBreak(ch)) {
146
+ result += text.substring(start, pos);
147
+ scanError = 2;
148
+ break;
149
+ } else {
150
+ scanError = 6;
151
+ }
152
+ }
153
+ pos++;
154
+ }
155
+ return result;
156
+ }
157
+ function scanNext() {
158
+ value = "";
159
+ scanError = 0;
160
+ tokenOffset = pos;
161
+ lineStartOffset = lineNumber;
162
+ prevTokenLineStartOffset = tokenLineStartOffset;
163
+ if (pos >= len) {
164
+ tokenOffset = len;
165
+ return token = 17;
166
+ }
167
+ let code = text.charCodeAt(pos);
168
+ if (isWhiteSpace(code)) {
169
+ do {
170
+ pos++;
171
+ value += String.fromCharCode(code);
172
+ code = text.charCodeAt(pos);
173
+ } while (isWhiteSpace(code));
174
+ return token = 15;
175
+ }
176
+ if (isLineBreak(code)) {
177
+ pos++;
178
+ value += String.fromCharCode(code);
179
+ if (code === 13 && text.charCodeAt(pos) === 10) {
180
+ pos++;
181
+ value += `
182
+ `;
183
+ }
184
+ lineNumber++;
185
+ tokenLineStartOffset = pos;
186
+ return token = 14;
187
+ }
188
+ switch (code) {
189
+ case 123:
190
+ pos++;
191
+ return token = 1;
192
+ case 125:
193
+ pos++;
194
+ return token = 2;
195
+ case 91:
196
+ pos++;
197
+ return token = 3;
198
+ case 93:
199
+ pos++;
200
+ return token = 4;
201
+ case 58:
202
+ pos++;
203
+ return token = 6;
204
+ case 44:
205
+ pos++;
206
+ return token = 5;
207
+ case 34:
208
+ pos++;
209
+ value = scanString();
210
+ return token = 10;
211
+ case 47:
212
+ const start = pos - 1;
213
+ if (text.charCodeAt(pos + 1) === 47) {
214
+ pos += 2;
215
+ while (pos < len) {
216
+ if (isLineBreak(text.charCodeAt(pos))) {
217
+ break;
218
+ }
219
+ pos++;
220
+ }
221
+ value = text.substring(start, pos);
222
+ return token = 12;
223
+ }
224
+ if (text.charCodeAt(pos + 1) === 42) {
225
+ pos += 2;
226
+ const safeLength = len - 1;
227
+ let commentClosed = false;
228
+ while (pos < safeLength) {
229
+ const ch = text.charCodeAt(pos);
230
+ if (ch === 42 && text.charCodeAt(pos + 1) === 47) {
231
+ pos += 2;
232
+ commentClosed = true;
233
+ break;
234
+ }
235
+ pos++;
236
+ if (isLineBreak(ch)) {
237
+ if (ch === 13 && text.charCodeAt(pos) === 10) {
238
+ pos++;
239
+ }
240
+ lineNumber++;
241
+ tokenLineStartOffset = pos;
242
+ }
243
+ }
244
+ if (!commentClosed) {
245
+ pos++;
246
+ scanError = 1;
247
+ }
248
+ value = text.substring(start, pos);
249
+ return token = 13;
250
+ }
251
+ value += String.fromCharCode(code);
252
+ pos++;
253
+ return token = 16;
254
+ case 45:
255
+ value += String.fromCharCode(code);
256
+ pos++;
257
+ if (pos === len || !isDigit(text.charCodeAt(pos))) {
258
+ return token = 16;
259
+ }
260
+ case 48:
261
+ case 49:
262
+ case 50:
263
+ case 51:
264
+ case 52:
265
+ case 53:
266
+ case 54:
267
+ case 55:
268
+ case 56:
269
+ case 57:
270
+ value += scanNumber();
271
+ return token = 11;
272
+ default:
273
+ while (pos < len && isUnknownContentCharacter(code)) {
274
+ pos++;
275
+ code = text.charCodeAt(pos);
276
+ }
277
+ if (tokenOffset !== pos) {
278
+ value = text.substring(tokenOffset, pos);
279
+ switch (value) {
280
+ case "true":
281
+ return token = 8;
282
+ case "false":
283
+ return token = 9;
284
+ case "null":
285
+ return token = 7;
286
+ }
287
+ return token = 16;
288
+ }
289
+ value += String.fromCharCode(code);
290
+ pos++;
291
+ return token = 16;
292
+ }
293
+ }
294
+ function isUnknownContentCharacter(code) {
295
+ if (isWhiteSpace(code) || isLineBreak(code)) {
296
+ return false;
297
+ }
298
+ switch (code) {
299
+ case 125:
300
+ case 93:
301
+ case 123:
302
+ case 91:
303
+ case 34:
304
+ case 58:
305
+ case 44:
306
+ case 47:
307
+ return false;
308
+ }
309
+ return true;
310
+ }
311
+ function scanNextNonTrivia() {
312
+ let result;
313
+ do {
314
+ result = scanNext();
315
+ } while (result >= 12 && result <= 15);
316
+ return result;
317
+ }
318
+ return {
319
+ setPosition,
320
+ getPosition: () => pos,
321
+ scan: ignoreTrivia ? scanNextNonTrivia : scanNext,
322
+ getToken: () => token,
323
+ getTokenValue: () => value,
324
+ getTokenOffset: () => tokenOffset,
325
+ getTokenLength: () => pos - tokenOffset,
326
+ getTokenStartLine: () => lineStartOffset,
327
+ getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset,
328
+ getTokenError: () => scanError
329
+ };
330
+ }
331
+ function isWhiteSpace(ch) {
332
+ return ch === 32 || ch === 9;
333
+ }
334
+ function isLineBreak(ch) {
335
+ return ch === 10 || ch === 13;
336
+ }
337
+ function isDigit(ch) {
338
+ return ch >= 48 && ch <= 57;
339
+ }
340
+ var CharacterCodes;
341
+ (function(CharacterCodes2) {
342
+ CharacterCodes2[CharacterCodes2["lineFeed"] = 10] = "lineFeed";
343
+ CharacterCodes2[CharacterCodes2["carriageReturn"] = 13] = "carriageReturn";
344
+ CharacterCodes2[CharacterCodes2["space"] = 32] = "space";
345
+ CharacterCodes2[CharacterCodes2["_0"] = 48] = "_0";
346
+ CharacterCodes2[CharacterCodes2["_1"] = 49] = "_1";
347
+ CharacterCodes2[CharacterCodes2["_2"] = 50] = "_2";
348
+ CharacterCodes2[CharacterCodes2["_3"] = 51] = "_3";
349
+ CharacterCodes2[CharacterCodes2["_4"] = 52] = "_4";
350
+ CharacterCodes2[CharacterCodes2["_5"] = 53] = "_5";
351
+ CharacterCodes2[CharacterCodes2["_6"] = 54] = "_6";
352
+ CharacterCodes2[CharacterCodes2["_7"] = 55] = "_7";
353
+ CharacterCodes2[CharacterCodes2["_8"] = 56] = "_8";
354
+ CharacterCodes2[CharacterCodes2["_9"] = 57] = "_9";
355
+ CharacterCodes2[CharacterCodes2["a"] = 97] = "a";
356
+ CharacterCodes2[CharacterCodes2["b"] = 98] = "b";
357
+ CharacterCodes2[CharacterCodes2["c"] = 99] = "c";
358
+ CharacterCodes2[CharacterCodes2["d"] = 100] = "d";
359
+ CharacterCodes2[CharacterCodes2["e"] = 101] = "e";
360
+ CharacterCodes2[CharacterCodes2["f"] = 102] = "f";
361
+ CharacterCodes2[CharacterCodes2["g"] = 103] = "g";
362
+ CharacterCodes2[CharacterCodes2["h"] = 104] = "h";
363
+ CharacterCodes2[CharacterCodes2["i"] = 105] = "i";
364
+ CharacterCodes2[CharacterCodes2["j"] = 106] = "j";
365
+ CharacterCodes2[CharacterCodes2["k"] = 107] = "k";
366
+ CharacterCodes2[CharacterCodes2["l"] = 108] = "l";
367
+ CharacterCodes2[CharacterCodes2["m"] = 109] = "m";
368
+ CharacterCodes2[CharacterCodes2["n"] = 110] = "n";
369
+ CharacterCodes2[CharacterCodes2["o"] = 111] = "o";
370
+ CharacterCodes2[CharacterCodes2["p"] = 112] = "p";
371
+ CharacterCodes2[CharacterCodes2["q"] = 113] = "q";
372
+ CharacterCodes2[CharacterCodes2["r"] = 114] = "r";
373
+ CharacterCodes2[CharacterCodes2["s"] = 115] = "s";
374
+ CharacterCodes2[CharacterCodes2["t"] = 116] = "t";
375
+ CharacterCodes2[CharacterCodes2["u"] = 117] = "u";
376
+ CharacterCodes2[CharacterCodes2["v"] = 118] = "v";
377
+ CharacterCodes2[CharacterCodes2["w"] = 119] = "w";
378
+ CharacterCodes2[CharacterCodes2["x"] = 120] = "x";
379
+ CharacterCodes2[CharacterCodes2["y"] = 121] = "y";
380
+ CharacterCodes2[CharacterCodes2["z"] = 122] = "z";
381
+ CharacterCodes2[CharacterCodes2["A"] = 65] = "A";
382
+ CharacterCodes2[CharacterCodes2["B"] = 66] = "B";
383
+ CharacterCodes2[CharacterCodes2["C"] = 67] = "C";
384
+ CharacterCodes2[CharacterCodes2["D"] = 68] = "D";
385
+ CharacterCodes2[CharacterCodes2["E"] = 69] = "E";
386
+ CharacterCodes2[CharacterCodes2["F"] = 70] = "F";
387
+ CharacterCodes2[CharacterCodes2["G"] = 71] = "G";
388
+ CharacterCodes2[CharacterCodes2["H"] = 72] = "H";
389
+ CharacterCodes2[CharacterCodes2["I"] = 73] = "I";
390
+ CharacterCodes2[CharacterCodes2["J"] = 74] = "J";
391
+ CharacterCodes2[CharacterCodes2["K"] = 75] = "K";
392
+ CharacterCodes2[CharacterCodes2["L"] = 76] = "L";
393
+ CharacterCodes2[CharacterCodes2["M"] = 77] = "M";
394
+ CharacterCodes2[CharacterCodes2["N"] = 78] = "N";
395
+ CharacterCodes2[CharacterCodes2["O"] = 79] = "O";
396
+ CharacterCodes2[CharacterCodes2["P"] = 80] = "P";
397
+ CharacterCodes2[CharacterCodes2["Q"] = 81] = "Q";
398
+ CharacterCodes2[CharacterCodes2["R"] = 82] = "R";
399
+ CharacterCodes2[CharacterCodes2["S"] = 83] = "S";
400
+ CharacterCodes2[CharacterCodes2["T"] = 84] = "T";
401
+ CharacterCodes2[CharacterCodes2["U"] = 85] = "U";
402
+ CharacterCodes2[CharacterCodes2["V"] = 86] = "V";
403
+ CharacterCodes2[CharacterCodes2["W"] = 87] = "W";
404
+ CharacterCodes2[CharacterCodes2["X"] = 88] = "X";
405
+ CharacterCodes2[CharacterCodes2["Y"] = 89] = "Y";
406
+ CharacterCodes2[CharacterCodes2["Z"] = 90] = "Z";
407
+ CharacterCodes2[CharacterCodes2["asterisk"] = 42] = "asterisk";
408
+ CharacterCodes2[CharacterCodes2["backslash"] = 92] = "backslash";
409
+ CharacterCodes2[CharacterCodes2["closeBrace"] = 125] = "closeBrace";
410
+ CharacterCodes2[CharacterCodes2["closeBracket"] = 93] = "closeBracket";
411
+ CharacterCodes2[CharacterCodes2["colon"] = 58] = "colon";
412
+ CharacterCodes2[CharacterCodes2["comma"] = 44] = "comma";
413
+ CharacterCodes2[CharacterCodes2["dot"] = 46] = "dot";
414
+ CharacterCodes2[CharacterCodes2["doubleQuote"] = 34] = "doubleQuote";
415
+ CharacterCodes2[CharacterCodes2["minus"] = 45] = "minus";
416
+ CharacterCodes2[CharacterCodes2["openBrace"] = 123] = "openBrace";
417
+ CharacterCodes2[CharacterCodes2["openBracket"] = 91] = "openBracket";
418
+ CharacterCodes2[CharacterCodes2["plus"] = 43] = "plus";
419
+ CharacterCodes2[CharacterCodes2["slash"] = 47] = "slash";
420
+ CharacterCodes2[CharacterCodes2["formFeed"] = 12] = "formFeed";
421
+ CharacterCodes2[CharacterCodes2["tab"] = 9] = "tab";
422
+ })(CharacterCodes || (CharacterCodes = {}));
423
+
424
+ // node_modules/jsonc-parser/lib/esm/impl/string-intern.js
425
+ var cachedSpaces = new Array(20).fill(0).map((_, index) => {
426
+ return " ".repeat(index);
427
+ });
428
+ var maxCachedValues = 200;
429
+ var cachedBreakLinesWithSpaces = {
430
+ " ": {
431
+ "\n": new Array(maxCachedValues).fill(0).map((_, index) => {
432
+ return `
433
+ ` + " ".repeat(index);
434
+ }),
435
+ "\r": new Array(maxCachedValues).fill(0).map((_, index) => {
436
+ return "\r" + " ".repeat(index);
437
+ }),
438
+ "\r\n": new Array(maxCachedValues).fill(0).map((_, index) => {
439
+ return `\r
440
+ ` + " ".repeat(index);
441
+ })
442
+ },
443
+ "\t": {
444
+ "\n": new Array(maxCachedValues).fill(0).map((_, index) => {
445
+ return `
446
+ ` + "\t".repeat(index);
447
+ }),
448
+ "\r": new Array(maxCachedValues).fill(0).map((_, index) => {
449
+ return "\r" + "\t".repeat(index);
450
+ }),
451
+ "\r\n": new Array(maxCachedValues).fill(0).map((_, index) => {
452
+ return `\r
453
+ ` + "\t".repeat(index);
454
+ })
455
+ }
456
+ };
457
+
458
+ // node_modules/jsonc-parser/lib/esm/impl/parser.js
459
+ var ParseOptions;
460
+ (function(ParseOptions2) {
461
+ ParseOptions2.DEFAULT = {
462
+ allowTrailingComma: false
463
+ };
464
+ })(ParseOptions || (ParseOptions = {}));
465
+ function parse(text, errors = [], options = ParseOptions.DEFAULT) {
466
+ let currentProperty = null;
467
+ let currentParent = [];
468
+ const previousParents = [];
469
+ function onValue(value) {
470
+ if (Array.isArray(currentParent)) {
471
+ currentParent.push(value);
472
+ } else if (currentProperty !== null) {
473
+ currentParent[currentProperty] = value;
474
+ }
475
+ }
476
+ const visitor = {
477
+ onObjectBegin: () => {
478
+ const object = {};
479
+ onValue(object);
480
+ previousParents.push(currentParent);
481
+ currentParent = object;
482
+ currentProperty = null;
483
+ },
484
+ onObjectProperty: (name) => {
485
+ currentProperty = name;
486
+ },
487
+ onObjectEnd: () => {
488
+ currentParent = previousParents.pop();
489
+ },
490
+ onArrayBegin: () => {
491
+ const array = [];
492
+ onValue(array);
493
+ previousParents.push(currentParent);
494
+ currentParent = array;
495
+ currentProperty = null;
496
+ },
497
+ onArrayEnd: () => {
498
+ currentParent = previousParents.pop();
499
+ },
500
+ onLiteralValue: onValue,
501
+ onError: (error, offset, length) => {
502
+ errors.push({ error, offset, length });
503
+ }
504
+ };
505
+ visit(text, visitor, options);
506
+ return currentParent[0];
507
+ }
508
+ function visit(text, visitor, options = ParseOptions.DEFAULT) {
509
+ const _scanner = createScanner(text, false);
510
+ const _jsonPath = [];
511
+ let suppressedCallbacks = 0;
512
+ function toNoArgVisit(visitFunction) {
513
+ return visitFunction ? () => suppressedCallbacks === 0 && visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
514
+ }
515
+ function toOneArgVisit(visitFunction) {
516
+ return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;
517
+ }
518
+ function toOneArgVisitWithPath(visitFunction) {
519
+ return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice()) : () => true;
520
+ }
521
+ function toBeginVisit(visitFunction) {
522
+ return visitFunction ? () => {
523
+ if (suppressedCallbacks > 0) {
524
+ suppressedCallbacks++;
525
+ } else {
526
+ let cbReturn = visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice());
527
+ if (cbReturn === false) {
528
+ suppressedCallbacks = 1;
529
+ }
530
+ }
531
+ } : () => true;
532
+ }
533
+ function toEndVisit(visitFunction) {
534
+ return visitFunction ? () => {
535
+ if (suppressedCallbacks > 0) {
536
+ suppressedCallbacks--;
537
+ }
538
+ if (suppressedCallbacks === 0) {
539
+ visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter());
540
+ }
541
+ } : () => true;
542
+ }
543
+ const onObjectBegin = toBeginVisit(visitor.onObjectBegin), onObjectProperty = toOneArgVisitWithPath(visitor.onObjectProperty), onObjectEnd = toEndVisit(visitor.onObjectEnd), onArrayBegin = toBeginVisit(visitor.onArrayBegin), onArrayEnd = toEndVisit(visitor.onArrayEnd), onLiteralValue = toOneArgVisitWithPath(visitor.onLiteralValue), onSeparator = toOneArgVisit(visitor.onSeparator), onComment = toNoArgVisit(visitor.onComment), onError = toOneArgVisit(visitor.onError);
544
+ const disallowComments = options && options.disallowComments;
545
+ const allowTrailingComma = options && options.allowTrailingComma;
546
+ function scanNext() {
547
+ while (true) {
548
+ const token = _scanner.scan();
549
+ switch (_scanner.getTokenError()) {
550
+ case 4:
551
+ handleError(14);
552
+ break;
553
+ case 5:
554
+ handleError(15);
555
+ break;
556
+ case 3:
557
+ handleError(13);
558
+ break;
559
+ case 1:
560
+ if (!disallowComments) {
561
+ handleError(11);
562
+ }
563
+ break;
564
+ case 2:
565
+ handleError(12);
566
+ break;
567
+ case 6:
568
+ handleError(16);
569
+ break;
570
+ }
571
+ switch (token) {
572
+ case 12:
573
+ case 13:
574
+ if (disallowComments) {
575
+ handleError(10);
576
+ } else {
577
+ onComment();
578
+ }
579
+ break;
580
+ case 16:
581
+ handleError(1);
582
+ break;
583
+ case 15:
584
+ case 14:
585
+ break;
586
+ default:
587
+ return token;
588
+ }
589
+ }
590
+ }
591
+ function handleError(error, skipUntilAfter = [], skipUntil = []) {
592
+ onError(error);
593
+ if (skipUntilAfter.length + skipUntil.length > 0) {
594
+ let token = _scanner.getToken();
595
+ while (token !== 17) {
596
+ if (skipUntilAfter.indexOf(token) !== -1) {
597
+ scanNext();
598
+ break;
599
+ } else if (skipUntil.indexOf(token) !== -1) {
600
+ break;
601
+ }
602
+ token = scanNext();
603
+ }
604
+ }
605
+ }
606
+ function parseString(isValue) {
607
+ const value = _scanner.getTokenValue();
608
+ if (isValue) {
609
+ onLiteralValue(value);
610
+ } else {
611
+ onObjectProperty(value);
612
+ _jsonPath.push(value);
613
+ }
614
+ scanNext();
615
+ return true;
616
+ }
617
+ function parseLiteral() {
618
+ switch (_scanner.getToken()) {
619
+ case 11:
620
+ const tokenValue = _scanner.getTokenValue();
621
+ let value = Number(tokenValue);
622
+ if (isNaN(value)) {
623
+ handleError(2);
624
+ value = 0;
625
+ }
626
+ onLiteralValue(value);
627
+ break;
628
+ case 7:
629
+ onLiteralValue(null);
630
+ break;
631
+ case 8:
632
+ onLiteralValue(true);
633
+ break;
634
+ case 9:
635
+ onLiteralValue(false);
636
+ break;
637
+ default:
638
+ return false;
639
+ }
640
+ scanNext();
641
+ return true;
642
+ }
643
+ function parseProperty() {
644
+ if (_scanner.getToken() !== 10) {
645
+ handleError(3, [], [2, 5]);
646
+ return false;
647
+ }
648
+ parseString(false);
649
+ if (_scanner.getToken() === 6) {
650
+ onSeparator(":");
651
+ scanNext();
652
+ if (!parseValue()) {
653
+ handleError(4, [], [2, 5]);
654
+ }
655
+ } else {
656
+ handleError(5, [], [2, 5]);
657
+ }
658
+ _jsonPath.pop();
659
+ return true;
660
+ }
661
+ function parseObject() {
662
+ onObjectBegin();
663
+ scanNext();
664
+ let needsComma = false;
665
+ while (_scanner.getToken() !== 2 && _scanner.getToken() !== 17) {
666
+ if (_scanner.getToken() === 5) {
667
+ if (!needsComma) {
668
+ handleError(4, [], []);
669
+ }
670
+ onSeparator(",");
671
+ scanNext();
672
+ if (_scanner.getToken() === 2 && allowTrailingComma) {
673
+ break;
674
+ }
675
+ } else if (needsComma) {
676
+ handleError(6, [], []);
677
+ }
678
+ if (!parseProperty()) {
679
+ handleError(4, [], [2, 5]);
680
+ }
681
+ needsComma = true;
682
+ }
683
+ onObjectEnd();
684
+ if (_scanner.getToken() !== 2) {
685
+ handleError(7, [2], []);
686
+ } else {
687
+ scanNext();
688
+ }
689
+ return true;
690
+ }
691
+ function parseArray() {
692
+ onArrayBegin();
693
+ scanNext();
694
+ let isFirstElement = true;
695
+ let needsComma = false;
696
+ while (_scanner.getToken() !== 4 && _scanner.getToken() !== 17) {
697
+ if (_scanner.getToken() === 5) {
698
+ if (!needsComma) {
699
+ handleError(4, [], []);
700
+ }
701
+ onSeparator(",");
702
+ scanNext();
703
+ if (_scanner.getToken() === 4 && allowTrailingComma) {
704
+ break;
705
+ }
706
+ } else if (needsComma) {
707
+ handleError(6, [], []);
708
+ }
709
+ if (isFirstElement) {
710
+ _jsonPath.push(0);
711
+ isFirstElement = false;
712
+ } else {
713
+ _jsonPath[_jsonPath.length - 1]++;
714
+ }
715
+ if (!parseValue()) {
716
+ handleError(4, [], [4, 5]);
717
+ }
718
+ needsComma = true;
719
+ }
720
+ onArrayEnd();
721
+ if (!isFirstElement) {
722
+ _jsonPath.pop();
723
+ }
724
+ if (_scanner.getToken() !== 4) {
725
+ handleError(8, [4], []);
726
+ } else {
727
+ scanNext();
728
+ }
729
+ return true;
730
+ }
731
+ function parseValue() {
732
+ switch (_scanner.getToken()) {
733
+ case 3:
734
+ return parseArray();
735
+ case 1:
736
+ return parseObject();
737
+ case 10:
738
+ return parseString(true);
739
+ default:
740
+ return parseLiteral();
741
+ }
742
+ }
743
+ scanNext();
744
+ if (_scanner.getToken() === 17) {
745
+ if (options.allowEmptyContent) {
746
+ return true;
747
+ }
748
+ handleError(4, [], []);
749
+ return false;
750
+ }
751
+ if (!parseValue()) {
752
+ handleError(4, [], []);
753
+ return false;
754
+ }
755
+ if (_scanner.getToken() !== 17) {
756
+ handleError(9, [], []);
757
+ }
758
+ return true;
759
+ }
760
+
761
+ // node_modules/jsonc-parser/lib/esm/main.js
762
+ var ScanError;
763
+ (function(ScanError2) {
764
+ ScanError2[ScanError2["None"] = 0] = "None";
765
+ ScanError2[ScanError2["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
766
+ ScanError2[ScanError2["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
767
+ ScanError2[ScanError2["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
768
+ ScanError2[ScanError2["InvalidUnicode"] = 4] = "InvalidUnicode";
769
+ ScanError2[ScanError2["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
770
+ ScanError2[ScanError2["InvalidCharacter"] = 6] = "InvalidCharacter";
771
+ })(ScanError || (ScanError = {}));
772
+ var SyntaxKind;
773
+ (function(SyntaxKind2) {
774
+ SyntaxKind2[SyntaxKind2["OpenBraceToken"] = 1] = "OpenBraceToken";
775
+ SyntaxKind2[SyntaxKind2["CloseBraceToken"] = 2] = "CloseBraceToken";
776
+ SyntaxKind2[SyntaxKind2["OpenBracketToken"] = 3] = "OpenBracketToken";
777
+ SyntaxKind2[SyntaxKind2["CloseBracketToken"] = 4] = "CloseBracketToken";
778
+ SyntaxKind2[SyntaxKind2["CommaToken"] = 5] = "CommaToken";
779
+ SyntaxKind2[SyntaxKind2["ColonToken"] = 6] = "ColonToken";
780
+ SyntaxKind2[SyntaxKind2["NullKeyword"] = 7] = "NullKeyword";
781
+ SyntaxKind2[SyntaxKind2["TrueKeyword"] = 8] = "TrueKeyword";
782
+ SyntaxKind2[SyntaxKind2["FalseKeyword"] = 9] = "FalseKeyword";
783
+ SyntaxKind2[SyntaxKind2["StringLiteral"] = 10] = "StringLiteral";
784
+ SyntaxKind2[SyntaxKind2["NumericLiteral"] = 11] = "NumericLiteral";
785
+ SyntaxKind2[SyntaxKind2["LineCommentTrivia"] = 12] = "LineCommentTrivia";
786
+ SyntaxKind2[SyntaxKind2["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
787
+ SyntaxKind2[SyntaxKind2["LineBreakTrivia"] = 14] = "LineBreakTrivia";
788
+ SyntaxKind2[SyntaxKind2["Trivia"] = 15] = "Trivia";
789
+ SyntaxKind2[SyntaxKind2["Unknown"] = 16] = "Unknown";
790
+ SyntaxKind2[SyntaxKind2["EOF"] = 17] = "EOF";
791
+ })(SyntaxKind || (SyntaxKind = {}));
792
+ var parse2 = parse;
793
+ var ParseErrorCode;
794
+ (function(ParseErrorCode2) {
795
+ ParseErrorCode2[ParseErrorCode2["InvalidSymbol"] = 1] = "InvalidSymbol";
796
+ ParseErrorCode2[ParseErrorCode2["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
797
+ ParseErrorCode2[ParseErrorCode2["PropertyNameExpected"] = 3] = "PropertyNameExpected";
798
+ ParseErrorCode2[ParseErrorCode2["ValueExpected"] = 4] = "ValueExpected";
799
+ ParseErrorCode2[ParseErrorCode2["ColonExpected"] = 5] = "ColonExpected";
800
+ ParseErrorCode2[ParseErrorCode2["CommaExpected"] = 6] = "CommaExpected";
801
+ ParseErrorCode2[ParseErrorCode2["CloseBraceExpected"] = 7] = "CloseBraceExpected";
802
+ ParseErrorCode2[ParseErrorCode2["CloseBracketExpected"] = 8] = "CloseBracketExpected";
803
+ ParseErrorCode2[ParseErrorCode2["EndOfFileExpected"] = 9] = "EndOfFileExpected";
804
+ ParseErrorCode2[ParseErrorCode2["InvalidCommentToken"] = 10] = "InvalidCommentToken";
805
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfComment"] = 11] = "UnexpectedEndOfComment";
806
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfString"] = 12] = "UnexpectedEndOfString";
807
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfNumber"] = 13] = "UnexpectedEndOfNumber";
808
+ ParseErrorCode2[ParseErrorCode2["InvalidUnicode"] = 14] = "InvalidUnicode";
809
+ ParseErrorCode2[ParseErrorCode2["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
810
+ ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
811
+ })(ParseErrorCode || (ParseErrorCode = {}));
9
812
 
10
813
  // src/config/schema.ts
11
814
  import { z } from "zod";
@@ -101,7 +904,8 @@ var WeaveConfigSchema = z.object({
101
904
  analytics: AnalyticsConfigSchema.optional(),
102
905
  tmux: TmuxConfigSchema.optional(),
103
906
  experimental: ExperimentalConfigSchema.optional(),
104
- workflows: WorkflowConfigSchema.optional()
907
+ workflows: WorkflowConfigSchema.optional(),
908
+ log_level: z.enum(["DEBUG", "INFO", "WARN", "ERROR"]).optional()
105
909
  });
106
910
 
107
911
  // src/config/merge.ts
@@ -141,30 +945,56 @@ function mergeConfigs(user, project) {
141
945
  }
142
946
 
143
947
  // src/shared/log.ts
144
- import * as fs from "fs";
145
- import * as path from "path";
146
- import * as os from "os";
147
- function getLogDir() {
148
- const home = os.homedir();
149
- return path.join(home, ".opencode", "logs");
948
+ var LEVEL_PRIORITY = {
949
+ DEBUG: 0,
950
+ INFO: 1,
951
+ WARN: 2,
952
+ ERROR: 3
953
+ };
954
+ function parseLogLevel(value) {
955
+ if (value === "DEBUG" || value === "INFO" || value === "WARN" || value === "ERROR") {
956
+ return value;
957
+ }
958
+ return "INFO";
150
959
  }
151
- function resolveLogFile() {
152
- const dir = getLogDir();
153
- try {
154
- if (!fs.existsSync(dir)) {
155
- fs.mkdirSync(dir, { recursive: true });
960
+ var activeLevel = parseLogLevel(process.env.WEAVE_LOG_LEVEL);
961
+ var client = null;
962
+ function setClient(c) {
963
+ client = c;
964
+ }
965
+ function setLogLevel(level) {
966
+ activeLevel = level;
967
+ }
968
+ function shouldLog(level) {
969
+ return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[activeLevel];
970
+ }
971
+ function emit(level, message, data) {
972
+ if (!shouldLog(level))
973
+ return;
974
+ const appRef = client?.app;
975
+ if (appRef && typeof appRef.log === "function") {
976
+ const extra = data !== undefined ? typeof data === "object" && data !== null ? data : { value: data } : undefined;
977
+ appRef.log({ body: { service: "weave", level: level.toLowerCase(), message, extra } }).catch(() => {});
978
+ } else {
979
+ if (level === "ERROR" || level === "WARN") {
980
+ console.error(`[weave:${level}] ${message}`, data ?? "");
156
981
  }
157
- } catch {}
158
- return path.join(dir, "weave-opencode.log");
982
+ }
983
+ }
984
+ function debug(message, data) {
985
+ emit("DEBUG", message, data);
986
+ }
987
+ function info(message, data) {
988
+ emit("INFO", message, data);
989
+ }
990
+ function warn(message, data) {
991
+ emit("WARN", message, data);
992
+ }
993
+ function error(message, data) {
994
+ emit("ERROR", message, data);
159
995
  }
160
- var LOG_FILE = resolveLogFile();
161
996
  function log(message, data) {
162
- try {
163
- const timestamp = new Date().toISOString();
164
- const entry = `[${timestamp}] ${message}${data !== undefined ? " " + JSON.stringify(data) : ""}
165
- `;
166
- fs.appendFileSync(LOG_FILE, entry);
167
- } catch {}
997
+ info(message, data);
168
998
  }
169
999
  function logDelegation(event) {
170
1000
  const prefix = `[delegation:${event.phase}]`;
@@ -181,38 +1011,49 @@ function readJsoncFile(filePath) {
181
1011
  try {
182
1012
  const text = readFileSync(filePath, "utf-8");
183
1013
  const errors = [];
184
- const parsed = parse(text, errors);
1014
+ const parsed = parse2(text, errors);
185
1015
  if (errors.length > 0) {
186
- log(`JSONC parse warnings in ${filePath}: ${errors.length} issue(s)`);
1016
+ warn(`JSONC parse warnings in ${filePath}: ${errors.length} issue(s)`);
187
1017
  }
188
1018
  return parsed ?? {};
189
1019
  } catch (e) {
190
- log(`Failed to read config file ${filePath}`, e);
1020
+ error(`Failed to read config file ${filePath}`, e);
191
1021
  return {};
192
1022
  }
193
1023
  }
194
1024
  function detectConfigFile(basePath) {
195
1025
  const jsoncPath = basePath + ".jsonc";
196
- if (existsSync2(jsoncPath))
1026
+ if (existsSync(jsoncPath))
197
1027
  return jsoncPath;
198
1028
  const jsonPath = basePath + ".json";
199
- if (existsSync2(jsonPath))
1029
+ if (existsSync(jsonPath))
200
1030
  return jsonPath;
201
1031
  return null;
202
1032
  }
203
1033
  function loadWeaveConfig(directory, _ctx, _homeDir) {
204
- const userBasePath = join2(_homeDir ?? homedir2(), ".config", "opencode", "weave-opencode");
205
- const projectBasePath = join2(directory, ".opencode", "weave-opencode");
1034
+ const userBasePath = join(_homeDir ?? homedir(), ".config", "opencode", "weave-opencode");
1035
+ const projectBasePath = join(directory, ".opencode", "weave-opencode");
206
1036
  const userConfigPath = detectConfigFile(userBasePath);
207
1037
  const projectConfigPath = detectConfigFile(projectBasePath);
1038
+ debug("Loading Weave config", {
1039
+ userConfig: userConfigPath ?? "(none)",
1040
+ projectConfig: projectConfigPath ?? "(none)"
1041
+ });
208
1042
  const userRaw = userConfigPath ? readJsoncFile(userConfigPath) : {};
209
1043
  const projectRaw = projectConfigPath ? readJsoncFile(projectConfigPath) : {};
210
1044
  const merged = mergeConfigs(userRaw, projectRaw);
211
1045
  const result = WeaveConfigSchema.safeParse(merged);
212
1046
  if (!result.success) {
213
- log("WeaveConfig validation errors — using defaults", result.error.issues);
1047
+ error("WeaveConfig validation errors — using defaults", result.error.issues);
214
1048
  return WeaveConfigSchema.parse({});
215
1049
  }
1050
+ debug("Weave config loaded successfully", {
1051
+ hasAgentOverrides: !!result.data.agents && Object.keys(result.data.agents).length > 0,
1052
+ disabledAgents: result.data.disabled_agents ?? [],
1053
+ customAgents: result.data.custom_agents ? Object.keys(result.data.custom_agents) : [],
1054
+ logLevel: result.data.log_level ?? "(default)",
1055
+ analyticsEnabled: result.data.analytics?.enabled ?? false
1056
+ });
216
1057
  return result.data;
217
1058
  }
218
1059
 
@@ -510,9 +1351,9 @@ class BackgroundManager {
510
1351
  }
511
1352
 
512
1353
  // src/managers/skill-mcp-manager.ts
513
- function createStdioClient(config, info) {
1354
+ function createStdioClient(config, info2) {
514
1355
  const { command, args = [] } = config;
515
- const { serverName, skillName } = info;
1356
+ const { serverName, skillName } = info2;
516
1357
  if (!command) {
517
1358
  throw new Error(`missing 'command' field for stdio MCP server '${serverName}' in skill '${skillName}'`);
518
1359
  }
@@ -541,28 +1382,28 @@ function createStdioClient(config, info) {
541
1382
  }
542
1383
  };
543
1384
  }
544
- function getClientKey(info) {
545
- return `${info.sessionID}:${info.skillName}:${info.serverName}`;
1385
+ function getClientKey(info2) {
1386
+ return `${info2.sessionID}:${info2.skillName}:${info2.serverName}`;
546
1387
  }
547
1388
 
548
1389
  class SkillMcpManager {
549
1390
  clients = new Map;
550
- async getOrCreateClient(info, config) {
551
- const key = getClientKey(info);
1391
+ async getOrCreateClient(info2, config) {
1392
+ const key = getClientKey(info2);
552
1393
  const existing = this.clients.get(key);
553
1394
  if (existing) {
554
1395
  return existing;
555
1396
  }
556
- const { serverName, skillName } = info;
1397
+ const { serverName, skillName } = info2;
557
1398
  if (config.type === "http") {
558
1399
  throw new Error("HTTP MCP not supported in v1");
559
1400
  }
560
1401
  if (!config.command) {
561
1402
  throw new Error(`missing 'command' field for stdio MCP server '${serverName}' in skill '${skillName}'`);
562
1403
  }
563
- const client = createStdioClient(config, info);
564
- this.clients.set(key, client);
565
- return client;
1404
+ const client2 = createStdioClient(config, info2);
1405
+ this.clients.set(key, client2);
1406
+ return client2;
566
1407
  }
567
1408
  async disconnectSession(sessionID) {
568
1409
  const prefix = `${sessionID}:`;
@@ -573,16 +1414,16 @@ class SkillMcpManager {
573
1414
  }
574
1415
  }
575
1416
  await Promise.all(keysToRemove.map(async (key) => {
576
- const client = this.clients.get(key);
577
- if (client) {
578
- await client.close();
1417
+ const client2 = this.clients.get(key);
1418
+ if (client2) {
1419
+ await client2.close();
579
1420
  this.clients.delete(key);
580
1421
  }
581
1422
  }));
582
1423
  }
583
1424
  async disconnectAll() {
584
- await Promise.all(Array.from(this.clients.entries()).map(async ([key, client]) => {
585
- await client.close();
1425
+ await Promise.all(Array.from(this.clients.entries()).map(async ([key, client2]) => {
1426
+ await client2.close();
586
1427
  this.clients.delete(key);
587
1428
  }));
588
1429
  this.clients.clear();
@@ -590,19 +1431,19 @@ class SkillMcpManager {
590
1431
  getConnectedServers() {
591
1432
  return Array.from(this.clients.keys());
592
1433
  }
593
- isConnected(info) {
594
- return this.clients.has(getClientKey(info));
1434
+ isConnected(info2) {
1435
+ return this.clients.has(getClientKey(info2));
595
1436
  }
596
- async callTool(info, config, name, args) {
1437
+ async callTool(info2, config, name, args) {
597
1438
  const maxAttempts = 3;
598
1439
  let lastError = null;
599
1440
  for (let attempt = 1;attempt <= maxAttempts; attempt++) {
600
1441
  try {
601
- const client = await this.getOrCreateClient(info, config);
602
- const result = await client.callTool({ name, arguments: args });
1442
+ const client2 = await this.getOrCreateClient(info2, config);
1443
+ const result = await client2.callTool({ name, arguments: args });
603
1444
  return result.content;
604
- } catch (error) {
605
- lastError = error instanceof Error ? error : new Error(String(error));
1445
+ } catch (error2) {
1446
+ lastError = error2 instanceof Error ? error2 : new Error(String(error2));
606
1447
  if (!lastError.message.toLowerCase().includes("not connected")) {
607
1448
  throw lastError;
608
1449
  }
@@ -729,8 +1570,6 @@ function buildDelegationSection(disabled) {
729
1570
  lines.push("- MUST use Warp for security audits when changes touch auth, crypto, certificates, tokens, signatures, input validation, secrets, passwords, sessions, CORS, CSP, .env files, or OAuth/OIDC/SAML flows — not optional.");
730
1571
  }
731
1572
  lines.push("- Delegate aggressively to keep your context lean");
732
- lines.push("");
733
- lines.push('RATIONALIZATION CHECK: If you catch yourself thinking "this is just a quick fix" but it touches 3+ files — delegate. Quick fixes that grow are the most common failure mode. When in doubt, delegate.');
734
1573
  return `<Delegation>
735
1574
  ${lines.join(`
736
1575
  `)}
@@ -995,33 +1834,6 @@ After completing work for each task — BEFORE marking \`- [ ]\` → \`- [x]\`:
995
1834
  **Gate**: Only mark complete when ALL checks pass. If ANY check fails, fix first.
996
1835
  </Verification>`;
997
1836
  }
998
- function buildTapestryVerificationGateSection() {
999
- return `<VerificationGate>
1000
- BEFORE claiming ANY status — "done", "passes", "works", "fixed", "complete":
1001
-
1002
- 1. IDENTIFY: What command proves this claim? (test runner, build, linter, curl, etc.)
1003
- 2. RUN: Execute the command NOW — fresh, complete, in this message
1004
- 3. READ: Check exit code, count failures, read full output
1005
- 4. VERIFY: Does the output confirm the claim?
1006
- - YES → State the claim WITH the evidence
1007
- - NO → State actual status with evidence. Fix. Re-run.
1008
-
1009
- | Claim | Requires | NOT Sufficient |
1010
- |-------|----------|----------------|
1011
- | "Tests pass" | Test command output showing 0 failures | Previous run, "should pass", partial suite |
1012
- | "Build succeeds" | Build command with exit 0 | Linter passing, "looks correct" |
1013
- | "Bug is fixed" | Failing test now passes | "Code changed, should be fixed" |
1014
- | "No regressions" | Full test suite output | Spot-checking a few files |
1015
-
1016
- RED FLAGS — if you catch yourself writing these, STOP:
1017
- - "should", "probably", "seems to", "looks correct"
1018
- - "Great!", "Done!", "Perfect!" before running verification
1019
- - Claiming completion based on a previous run
1020
- - Trusting your own Edit/Write calls without reading the result
1021
-
1022
- **Verification you didn't run in this message does not exist.**
1023
- </VerificationGate>`;
1024
- }
1025
1837
  function buildTapestryPostExecutionReviewSection(disabled) {
1026
1838
  const hasWeft = isAgentEnabled("weft", disabled);
1027
1839
  const hasWarp = isAgentEnabled("warp", disabled);
@@ -1067,30 +1879,6 @@ function buildTapestryExecutionSection() {
1067
1879
  - Report completion with evidence (test output, file paths, commands run)
1068
1880
  </Execution>`;
1069
1881
  }
1070
- function buildTapestryDebuggingSection() {
1071
- return `<WhenStuck>
1072
- When a task fails or produces unexpected results:
1073
-
1074
- 1. **Read error messages completely** — stack traces, line numbers, exit codes. They often contain the answer.
1075
- 2. **Form a single hypothesis** — "I think X is the root cause because Y." Be specific.
1076
- 3. **Make the smallest possible change** to test that hypothesis. One variable at a time.
1077
- 4. **Verify** — did it work? If yes, continue. If no, form a NEW hypothesis.
1078
-
1079
- ESCALATION RULE:
1080
- - Fix attempt #1 failed → re-read errors, try different hypothesis
1081
- - Fix attempt #2 failed → step back, trace the data flow from source to error
1082
- - Fix attempt #3 failed → **STOP. Do NOT attempt fix #4.**
1083
- - Document: what you tried, what happened, what you think the root cause is
1084
- - Report to the user: "Blocked after 3 attempts on task N. Here's what I've tried: [...]"
1085
- - This is likely an architectural issue, not a code bug. The user needs to decide.
1086
-
1087
- RED FLAGS — you are debugging wrong if you:
1088
- - Propose fixes without reading the error message carefully
1089
- - Change multiple things at once ("shotgun debugging")
1090
- - Re-try the same approach hoping for a different result
1091
- - Think "just one more fix" after 2 failures
1092
- </WhenStuck>`;
1093
- }
1094
1882
  function buildTapestryStyleSection() {
1095
1883
  return `<Style>
1096
1884
  - Terse status updates only
@@ -1106,10 +1894,8 @@ function composeTapestryPrompt(options = {}) {
1106
1894
  buildTapestrySidebarTodosSection(),
1107
1895
  buildTapestryPlanExecutionSection(disabled),
1108
1896
  buildTapestryVerificationSection(),
1109
- buildTapestryVerificationGateSection(),
1110
1897
  buildTapestryPostExecutionReviewSection(disabled),
1111
1898
  buildTapestryExecutionSection(),
1112
- buildTapestryDebuggingSection(),
1113
1899
  buildTapestryStyleSection()
1114
1900
  ];
1115
1901
  return sections.join(`
@@ -1270,30 +2056,6 @@ FILES FIELD: For verification-only tasks that have no associated files (e.g., "r
1270
2056
  - After completing a plan, tell the user: "Plan saved to \`.weave/plans/{name}.md\`. Run /start-work to begin execution."
1271
2057
  </Constraints>
1272
2058
 
1273
- <NoPlaceholders>
1274
- Every task must contain the actual detail an engineer needs to start working. These are PLAN FAILURES — never write them:
1275
-
1276
- - "TBD", "TODO", "implement later", "fill in details"
1277
- - "Add appropriate error handling" / "add validation" / "handle edge cases"
1278
- - "Write tests for the above" (without describing what to test)
1279
- - "Similar to Task N" (repeat the detail — the executor may read tasks independently)
1280
- - Steps that describe WHAT to do without specifying HOW (file paths, approach, acceptance criteria required)
1281
- - References to types, functions, or files that aren't defined or explained in any task
1282
-
1283
- If you can't specify something concretely, you haven't researched enough. Go read more code.
1284
- </NoPlaceholders>
1285
-
1286
- <SelfReview>
1287
- After writing the complete plan, review it with fresh eyes:
1288
-
1289
- 1. **Requirement coverage**: Re-read the original request. Can you point to a task for each requirement? List any gaps.
1290
- 2. **Placeholder scan**: Search your plan for any patterns from the \`<NoPlaceholders>\` list above. Fix them.
1291
- 3. **Name consistency**: Do file paths, function names, and type names used in later tasks match what you defined in earlier tasks? A function called \`createUser()\` in Task 2 but \`addUser()\` in Task 5 is a bug.
1292
- 4. **Dependency order**: Can each task be started after completing only the tasks before it? If Task 4 depends on Task 6, reorder.
1293
-
1294
- Fix any issues inline. Then report the plan as complete.
1295
- </SelfReview>
1296
-
1297
2059
  <Research>
1298
2060
  - Read relevant files before planning
1299
2061
  - Check existing patterns in the codebase
@@ -1422,10 +2184,9 @@ You operate in two modes depending on what you're asked to review:
1422
2184
 
1423
2185
  **Work Review** (reviewing completed implementation):
1424
2186
  - Read every changed file (use git diff --stat, then Read each file)
1425
- - Do NOT trust commit messages, PR descriptions, or task completion claims — the implementer may have been optimistic or incomplete. Verify everything by reading the actual code.
1426
- - Check spec compliance FIRST: does the code do what the task required? If it doesn't match requirements, reject before evaluating code quality.
1427
- - Then check code quality: look for stubs, TODOs, placeholders, hardcoded values
1428
- - Verify tests exist and test real behavior (not mocks of mocks)
2187
+ - Check the code actually does what the task required
2188
+ - Look for stubs, TODOs, placeholders, hardcoded values
2189
+ - Verify tests exist and test real behavior
1429
2190
  - Check for scope creep (changes outside the task spec)
1430
2191
  </ReviewModes>
1431
2192
 
@@ -1733,34 +2494,47 @@ var AGENT_MODEL_REQUIREMENTS = {
1733
2494
  function resolveAgentModel(agentName, options) {
1734
2495
  const { availableModels, agentMode, uiSelectedModel, categoryModel, overrideModel, systemDefaultModel, customFallbackChain } = options;
1735
2496
  const requirement = AGENT_MODEL_REQUIREMENTS[agentName];
1736
- if (overrideModel)
2497
+ if (overrideModel) {
2498
+ debug(`Model resolved for "${agentName}"`, { via: "override", model: overrideModel });
1737
2499
  return overrideModel;
2500
+ }
1738
2501
  if (uiSelectedModel && (agentMode === "primary" || agentMode === "all")) {
2502
+ debug(`Model resolved for "${agentName}"`, { via: "ui-selection", model: uiSelectedModel, agentMode });
1739
2503
  return uiSelectedModel;
1740
2504
  }
1741
- if (categoryModel && availableModels.has(categoryModel))
2505
+ if (categoryModel && availableModels.has(categoryModel)) {
2506
+ debug(`Model resolved for "${agentName}"`, { via: "category", model: categoryModel });
1742
2507
  return categoryModel;
2508
+ }
1743
2509
  const fallbackChain = requirement?.fallbackChain ?? customFallbackChain;
1744
2510
  if (fallbackChain) {
1745
2511
  for (const entry of fallbackChain) {
1746
2512
  for (const provider of entry.providers) {
1747
2513
  const qualified = `${provider}/${entry.model}`;
1748
- if (availableModels.has(qualified))
2514
+ if (availableModels.has(qualified)) {
2515
+ debug(`Model resolved for "${agentName}"`, { via: "fallback-chain", model: qualified });
1749
2516
  return qualified;
1750
- if (availableModels.has(entry.model))
2517
+ }
2518
+ if (availableModels.has(entry.model)) {
2519
+ debug(`Model resolved for "${agentName}"`, { via: "fallback-chain", model: entry.model });
1751
2520
  return entry.model;
2521
+ }
1752
2522
  }
1753
2523
  }
1754
2524
  }
1755
- if (systemDefaultModel)
2525
+ if (systemDefaultModel) {
2526
+ debug(`Model resolved for "${agentName}"`, { via: "system-default", model: systemDefaultModel });
1756
2527
  return systemDefaultModel;
2528
+ }
1757
2529
  if (fallbackChain && fallbackChain.length > 0) {
1758
2530
  const first = fallbackChain[0];
1759
2531
  if (first.providers.length > 0) {
1760
- return `${first.providers[0]}/${first.model}`;
2532
+ const guessed = `${first.providers[0]}/${first.model}`;
2533
+ debug(`Model resolved for "${agentName}" (offline best-guess — no available models matched)`, { via: "offline-guess", model: guessed });
2534
+ return guessed;
1761
2535
  }
1762
2536
  }
1763
- console.warn(`[weave] No model resolved for agent "${agentName}" — falling back to default github-copilot/claude-opus-4.6`);
2537
+ warn(`No model resolved for agent "${agentName}" — falling back to default github-copilot/claude-opus-4.6`, { agentName });
1764
2538
  return "github-copilot/claude-opus-4.6";
1765
2539
  }
1766
2540
 
@@ -1873,8 +2647,10 @@ function createBuiltinAgents(options = {}) {
1873
2647
  const disabledSet = new Set(disabledAgents);
1874
2648
  const result = {};
1875
2649
  for (const [name, factory] of Object.entries(AGENT_FACTORIES)) {
1876
- if (disabledSet.has(name))
2650
+ if (disabledSet.has(name)) {
2651
+ debug(`Builtin agent "${name}" is disabled — skipping`);
1877
2652
  continue;
2653
+ }
1878
2654
  const override = agentOverrides[name];
1879
2655
  const overrideModel = override?.model;
1880
2656
  const resolvedModel = resolveAgentModel(name, {
@@ -1884,6 +2660,9 @@ function createBuiltinAgents(options = {}) {
1884
2660
  systemDefaultModel,
1885
2661
  overrideModel
1886
2662
  });
2663
+ if (overrideModel) {
2664
+ debug(`Builtin agent "${name}" model overridden via config`, { model: resolvedModel });
2665
+ }
1887
2666
  let built;
1888
2667
  if (name === "loom") {
1889
2668
  built = createLoomAgentWithOptions(resolvedModel, disabledSet, fingerprint, customAgentMetadata);
@@ -1921,7 +2700,7 @@ function createBuiltinAgents(options = {}) {
1921
2700
  }
1922
2701
 
1923
2702
  // src/agents/prompt-loader.ts
1924
- import { readFileSync as readFileSync2, existsSync as existsSync3 } from "fs";
2703
+ import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
1925
2704
  import { resolve, isAbsolute as isAbsolute2, normalize, sep } from "path";
1926
2705
  function loadPromptFile(promptFilePath, basePath) {
1927
2706
  if (isAbsolute2(promptFilePath)) {
@@ -1932,7 +2711,7 @@ function loadPromptFile(promptFilePath, basePath) {
1932
2711
  if (!resolvedPath.startsWith(base + sep) && resolvedPath !== base) {
1933
2712
  return null;
1934
2713
  }
1935
- if (!existsSync3(resolvedPath)) {
2714
+ if (!existsSync2(resolvedPath)) {
1936
2715
  return null;
1937
2716
  }
1938
2717
  return readFileSync2(resolvedPath, "utf-8").trim();
@@ -1968,11 +2747,17 @@ function buildCustomAgent(name, config, options = {}) {
1968
2747
  }
1969
2748
  const { resolveSkills, disabledSkills, availableModels = new Set, systemDefaultModel, uiSelectedModel, configDir } = options;
1970
2749
  let prompt = config.prompt ?? "";
2750
+ let promptSource = "inline";
1971
2751
  if (config.prompt_file) {
1972
2752
  const fileContent = loadPromptFile(config.prompt_file, configDir);
1973
2753
  if (fileContent) {
1974
2754
  prompt = fileContent;
2755
+ promptSource = `file:${config.prompt_file}`;
2756
+ } else {
2757
+ promptSource = `file:${config.prompt_file} (not found — falling back to inline)`;
1975
2758
  }
2759
+ } else if (config.skills?.length) {
2760
+ promptSource = `skills:[${config.skills.join(",")}]`;
1976
2761
  }
1977
2762
  if (config.skills?.length && resolveSkills) {
1978
2763
  const skillContent = resolveSkills(config.skills, disabledSkills);
@@ -1995,6 +2780,13 @@ function buildCustomAgent(name, config, options = {}) {
1995
2780
  const displayName = config.display_name ?? name;
1996
2781
  registerAgentDisplayName(name, displayName);
1997
2782
  registerAgentNameVariants(name, displayName !== name ? [name, displayName] : undefined);
2783
+ debug(`Custom agent "${name}" built`, {
2784
+ model,
2785
+ displayName,
2786
+ mode,
2787
+ promptSource,
2788
+ hasPrompt: !!prompt
2789
+ });
1998
2790
  const agentConfig = {
1999
2791
  model,
2000
2792
  prompt: prompt || undefined,
@@ -2062,7 +2854,7 @@ function createManagers(options) {
2062
2854
  }
2063
2855
  } catch (err) {
2064
2856
  if (err instanceof Error && err.message.includes("not a built-in agent")) {
2065
- log(`Skipping display_name override for non-builtin agent "${name}"`);
2857
+ debug(`Skipping display_name override for non-builtin agent "${name}"`);
2066
2858
  } else {
2067
2859
  throw err;
2068
2860
  }
@@ -2095,8 +2887,8 @@ function createManagers(options) {
2095
2887
  }
2096
2888
 
2097
2889
  // src/features/skill-loader/loader.ts
2098
- import * as path3 from "path";
2099
- import * as os2 from "os";
2890
+ import * as path2 from "path";
2891
+ import * as os from "os";
2100
2892
 
2101
2893
  // src/features/skill-loader/opencode-client.ts
2102
2894
  function deriveScope(location) {
@@ -2111,11 +2903,11 @@ async function fetchSkillsFromOpenCode(serverUrl, directory) {
2111
2903
  try {
2112
2904
  response = await fetch(url, { signal: AbortSignal.timeout(3000) });
2113
2905
  } catch (err) {
2114
- log("Failed to fetch skills from OpenCode — skills will not be loaded", { url, error: String(err) });
2906
+ error("Failed to fetch skills from OpenCode — skills will not be loaded", { url, error: String(err) });
2115
2907
  return [];
2116
2908
  }
2117
2909
  if (!response.ok) {
2118
- log("OpenCode /skill endpoint returned non-OK status — skills will not be loaded", {
2910
+ warn("OpenCode /skill endpoint returned non-OK status — skills will not be loaded", {
2119
2911
  url,
2120
2912
  status: response.status
2121
2913
  });
@@ -2125,11 +2917,11 @@ async function fetchSkillsFromOpenCode(serverUrl, directory) {
2125
2917
  try {
2126
2918
  data = await response.json();
2127
2919
  } catch (err) {
2128
- log("Failed to parse skills response from OpenCode", { url, error: String(err) });
2920
+ error("Failed to parse skills response from OpenCode", { url, error: String(err) });
2129
2921
  return [];
2130
2922
  }
2131
2923
  if (!Array.isArray(data)) {
2132
- log("Unexpected skills response shape from OpenCode — expected array", { url });
2924
+ warn("Unexpected skills response shape from OpenCode — expected array", { url });
2133
2925
  return [];
2134
2926
  }
2135
2927
  const skills = [];
@@ -2148,8 +2940,8 @@ async function fetchSkillsFromOpenCode(serverUrl, directory) {
2148
2940
  }
2149
2941
 
2150
2942
  // src/features/skill-loader/discovery.ts
2151
- import * as fs2 from "fs";
2152
- import * as path2 from "path";
2943
+ import * as fs from "fs";
2944
+ import * as path from "path";
2153
2945
  function parseFrontmatter(text) {
2154
2946
  const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/;
2155
2947
  const match = frontmatterRegex.exec(text);
@@ -2196,7 +2988,7 @@ function parseFrontmatter(text) {
2196
2988
  i++;
2197
2989
  }
2198
2990
  } catch (err) {
2199
- log("Failed to parse YAML frontmatter", { error: String(err) });
2991
+ warn("Failed to parse YAML frontmatter", { error: String(err) });
2200
2992
  return { metadata: {}, content: text };
2201
2993
  }
2202
2994
  return { metadata, content: body };
@@ -2224,22 +3016,22 @@ function setMetadataField(metadata, key, value) {
2224
3016
  }
2225
3017
  function scanDirectory(options) {
2226
3018
  const { directory, scope } = options;
2227
- if (!fs2.existsSync(directory)) {
3019
+ if (!fs.existsSync(directory)) {
2228
3020
  return [];
2229
3021
  }
2230
3022
  let entries;
2231
3023
  try {
2232
- entries = fs2.readdirSync(directory, { withFileTypes: true });
3024
+ entries = fs.readdirSync(directory, { withFileTypes: true });
2233
3025
  } catch (err) {
2234
- log("Failed to read skills directory", { directory, error: String(err) });
3026
+ warn("Failed to read skills directory", { directory, error: String(err) });
2235
3027
  return [];
2236
3028
  }
2237
3029
  const skills = [];
2238
3030
  for (const entry of entries) {
2239
- const fullPath = path2.join(directory, entry.name);
3031
+ const fullPath = path.join(directory, entry.name);
2240
3032
  if (entry.isDirectory()) {
2241
- const skillFile = path2.join(fullPath, "SKILL.md");
2242
- if (fs2.existsSync(skillFile)) {
3033
+ const skillFile = path.join(fullPath, "SKILL.md");
3034
+ if (fs.existsSync(skillFile)) {
2243
3035
  const skill = loadSkillFile(skillFile, scope);
2244
3036
  if (skill)
2245
3037
  skills.push(skill);
@@ -2257,14 +3049,14 @@ function scanDirectory(options) {
2257
3049
  function loadSkillFile(filePath, scope) {
2258
3050
  let text;
2259
3051
  try {
2260
- text = fs2.readFileSync(filePath, "utf8");
3052
+ text = fs.readFileSync(filePath, "utf8");
2261
3053
  } catch (err) {
2262
- log("Failed to read skill file", { filePath, error: String(err) });
3054
+ warn("Failed to read skill file", { filePath, error: String(err) });
2263
3055
  return null;
2264
3056
  }
2265
3057
  const { metadata, content } = parseFrontmatter(text);
2266
3058
  if (!metadata.name) {
2267
- log("Skill file missing name in frontmatter — skipping", { filePath });
3059
+ debug("Skill file missing name in frontmatter — skipping", { filePath });
2268
3060
  return null;
2269
3061
  }
2270
3062
  return { name: metadata.name, description: metadata.description ?? "", content, scope, path: filePath, model: metadata.model };
@@ -2292,8 +3084,8 @@ function resolveSafePath(dir, projectRoot) {
2292
3084
 
2293
3085
  // src/features/skill-loader/loader.ts
2294
3086
  function scanFilesystemSkills(directory, customDirs) {
2295
- const userDir = path3.join(os2.homedir(), ".config", "opencode", "skills");
2296
- const projectDir = path3.join(directory, ".opencode", "skills");
3087
+ const userDir = path2.join(os.homedir(), ".config", "opencode", "skills");
3088
+ const projectDir = path2.join(directory, ".opencode", "skills");
2297
3089
  const userSkills = scanDirectory({ directory: userDir, scope: "user" });
2298
3090
  const projectSkills = scanDirectory({ directory: projectDir, scope: "project" });
2299
3091
  const customSkills = [];
@@ -2324,7 +3116,7 @@ async function loadSkills(options) {
2324
3116
  const fsSkills = scanFilesystemSkills(directory, customDirs);
2325
3117
  const skills = mergeSkillSources(apiSkills, fsSkills);
2326
3118
  if (apiSkills.length === 0 && fsSkills.length > 0) {
2327
- log("OpenCode API returned no skills — using filesystem fallback", {
3119
+ debug("OpenCode API returned no skills — using filesystem fallback", {
2328
3120
  fsSkillCount: fsSkills.length,
2329
3121
  fsSkillNames: fsSkills.map((s) => s.name)
2330
3122
  });
@@ -2382,11 +3174,11 @@ function checkContextWindow(state, thresholds = { warningPct: 0.8, criticalPct:
2382
3174
  const usagePct = state.maxTokens > 0 ? state.usedTokens / state.maxTokens : 0;
2383
3175
  if (usagePct >= thresholds.criticalPct) {
2384
3176
  const message = buildRecoveryMessage(state, usagePct);
2385
- log(`[context-window] CRITICAL ${(usagePct * 100).toFixed(1)}% used in session ${state.sessionId}`);
3177
+ warn(`[context-window] CRITICAL ${(usagePct * 100).toFixed(1)}% used in session ${state.sessionId}`);
2386
3178
  return { action: "recover", usagePct, message };
2387
3179
  }
2388
3180
  if (usagePct >= thresholds.warningPct) {
2389
- log(`[context-window] WARNING ${(usagePct * 100).toFixed(1)}% used in session ${state.sessionId}`);
3181
+ warn(`[context-window] WARNING ${(usagePct * 100).toFixed(1)}% used in session ${state.sessionId}`);
2390
3182
  return { action: "warn", usagePct, message: buildWarningMessage(usagePct) };
2391
3183
  }
2392
3184
  return { action: "none", usagePct };
@@ -2411,7 +3203,7 @@ Update the sidebar: use todowrite to create a todo (in_progress, high priority):
2411
3203
  }
2412
3204
 
2413
3205
  // src/hooks/write-existing-file-guard.ts
2414
- import * as fs3 from "fs";
3206
+ import * as fs2 from "fs";
2415
3207
  function createWriteGuardState() {
2416
3208
  return { readFiles: new Set };
2417
3209
  }
@@ -2419,14 +3211,14 @@ function trackFileRead(state, filePath) {
2419
3211
  state.readFiles.add(filePath);
2420
3212
  }
2421
3213
  function checkWriteAllowed(state, filePath) {
2422
- if (!fs3.existsSync(filePath)) {
3214
+ if (!fs2.existsSync(filePath)) {
2423
3215
  return { allowed: true };
2424
3216
  }
2425
3217
  if (state.readFiles.has(filePath)) {
2426
3218
  return { allowed: true };
2427
3219
  }
2428
3220
  const warning = `⚠️ Write guard: Attempting to write to '${filePath}' without reading it first. Read the file before overwriting to avoid data loss.`;
2429
- log(`[write-guard] BLOCKED write to unread file: ${filePath}`);
3221
+ warn(`[write-guard] BLOCKED write to unread file: ${filePath}`);
2430
3222
  return { allowed: false, warning };
2431
3223
  }
2432
3224
  function createWriteGuard(state) {
@@ -2437,13 +3229,13 @@ function createWriteGuard(state) {
2437
3229
  }
2438
3230
 
2439
3231
  // src/hooks/rules-injector.ts
2440
- import * as fs4 from "fs";
2441
- import * as path4 from "path";
3232
+ import * as fs3 from "fs";
3233
+ import * as path3 from "path";
2442
3234
  var RULES_FILENAMES = ["AGENTS.md", ".rules", "CLAUDE.md"];
2443
3235
  function findRulesFile(directory) {
2444
3236
  for (const filename of RULES_FILENAMES) {
2445
- const candidate = path4.join(directory, filename);
2446
- if (fs4.existsSync(candidate)) {
3237
+ const candidate = path3.join(directory, filename);
3238
+ if (fs3.existsSync(candidate)) {
2447
3239
  return candidate;
2448
3240
  }
2449
3241
  }
@@ -2454,11 +3246,11 @@ function loadRulesForDirectory(directory) {
2454
3246
  if (!rulesFile)
2455
3247
  return;
2456
3248
  try {
2457
- const content = fs4.readFileSync(rulesFile, "utf8");
2458
- log(`[rules-injector] Loaded rules from ${rulesFile}`);
3249
+ const content = fs3.readFileSync(rulesFile, "utf8");
3250
+ debug(`[rules-injector] Loaded rules from ${rulesFile}`);
2459
3251
  return content;
2460
3252
  } catch {
2461
- log(`[rules-injector] Failed to read rules file: ${rulesFile}`);
3253
+ warn(`[rules-injector] Failed to read rules file: ${rulesFile}`);
2462
3254
  return;
2463
3255
  }
2464
3256
  }
@@ -2466,7 +3258,7 @@ function shouldInjectRules(toolName) {
2466
3258
  return toolName === "read" || toolName === "write" || toolName === "edit";
2467
3259
  }
2468
3260
  function getDirectoryFromFilePath(filePath) {
2469
- return path4.dirname(path4.resolve(filePath));
3261
+ return path3.dirname(path3.resolve(filePath));
2470
3262
  }
2471
3263
  function buildRulesInjection(rulesContent, directory) {
2472
3264
  return `<rules source="${directory}">
@@ -2525,7 +3317,7 @@ function buildKeywordInjection(detected) {
2525
3317
  function processMessageForKeywords(message, sessionId, actions) {
2526
3318
  const detected = detectKeywords(message, actions);
2527
3319
  if (detected.length > 0) {
2528
- log(`[keyword-detector] Detected keywords in session ${sessionId}: ${detected.map((a) => a.keyword).join(", ")}`);
3320
+ debug(`[keyword-detector] Detected keywords in session ${sessionId}: ${detected.map((a) => a.keyword).join(", ")}`);
2529
3321
  }
2530
3322
  return buildKeywordInjection(detected);
2531
3323
  }
@@ -2562,15 +3354,15 @@ var WORK_STATE_FILE = "state.json";
2562
3354
  var WORK_STATE_PATH = `${WEAVE_DIR}/${WORK_STATE_FILE}`;
2563
3355
  var PLANS_DIR = `${WEAVE_DIR}/plans`;
2564
3356
  // src/features/work-state/storage.ts
2565
- import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync, unlinkSync, mkdirSync as mkdirSync2, readdirSync as readdirSync2, statSync } from "fs";
2566
- import { join as join6, basename } from "path";
3357
+ import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync, unlinkSync, mkdirSync, readdirSync as readdirSync2, statSync } from "fs";
3358
+ import { join as join5, basename } from "path";
2567
3359
  import { execSync } from "child_process";
2568
3360
  var UNCHECKED_RE = /^[-*]\s*\[\s*\]/gm;
2569
3361
  var CHECKED_RE = /^[-*]\s*\[[xX]\]/gm;
2570
3362
  function readWorkState(directory) {
2571
- const filePath = join6(directory, WEAVE_DIR, WORK_STATE_FILE);
3363
+ const filePath = join5(directory, WEAVE_DIR, WORK_STATE_FILE);
2572
3364
  try {
2573
- if (!existsSync7(filePath))
3365
+ if (!existsSync6(filePath))
2574
3366
  return null;
2575
3367
  const raw = readFileSync5(filePath, "utf-8");
2576
3368
  const parsed = JSON.parse(raw);
@@ -2588,20 +3380,20 @@ function readWorkState(directory) {
2588
3380
  }
2589
3381
  function writeWorkState(directory, state) {
2590
3382
  try {
2591
- const dir = join6(directory, WEAVE_DIR);
2592
- if (!existsSync7(dir)) {
2593
- mkdirSync2(dir, { recursive: true });
3383
+ const dir = join5(directory, WEAVE_DIR);
3384
+ if (!existsSync6(dir)) {
3385
+ mkdirSync(dir, { recursive: true });
2594
3386
  }
2595
- writeFileSync(join6(dir, WORK_STATE_FILE), JSON.stringify(state, null, 2), "utf-8");
3387
+ writeFileSync(join5(dir, WORK_STATE_FILE), JSON.stringify(state, null, 2), "utf-8");
2596
3388
  return true;
2597
3389
  } catch {
2598
3390
  return false;
2599
3391
  }
2600
3392
  }
2601
3393
  function clearWorkState(directory) {
2602
- const filePath = join6(directory, WEAVE_DIR, WORK_STATE_FILE);
3394
+ const filePath = join5(directory, WEAVE_DIR, WORK_STATE_FILE);
2603
3395
  try {
2604
- if (existsSync7(filePath)) {
3396
+ if (existsSync6(filePath)) {
2605
3397
  unlinkSync(filePath);
2606
3398
  }
2607
3399
  return true;
@@ -2643,12 +3435,12 @@ function getHeadSha(directory) {
2643
3435
  }
2644
3436
  }
2645
3437
  function findPlans(directory) {
2646
- const plansDir = join6(directory, PLANS_DIR);
3438
+ const plansDir = join5(directory, PLANS_DIR);
2647
3439
  try {
2648
- if (!existsSync7(plansDir))
3440
+ if (!existsSync6(plansDir))
2649
3441
  return [];
2650
3442
  const files = readdirSync2(plansDir).filter((f) => f.endsWith(".md")).map((f) => {
2651
- const fullPath = join6(plansDir, f);
3443
+ const fullPath = join5(plansDir, f);
2652
3444
  const stat = statSync(fullPath);
2653
3445
  return { path: fullPath, mtime: stat.mtimeMs };
2654
3446
  }).sort((a, b) => b.mtime - a.mtime).map((f) => f.path);
@@ -2658,7 +3450,7 @@ function findPlans(directory) {
2658
3450
  }
2659
3451
  }
2660
3452
  function getPlanProgress(planPath) {
2661
- if (!existsSync7(planPath)) {
3453
+ if (!existsSync6(planPath)) {
2662
3454
  return { total: 0, completed: 0, isComplete: true };
2663
3455
  }
2664
3456
  try {
@@ -2694,7 +3486,7 @@ function resumeWork(directory) {
2694
3486
  return writeWorkState(directory, state);
2695
3487
  }
2696
3488
  // src/features/work-state/validation.ts
2697
- import { readFileSync as readFileSync6, existsSync as existsSync8 } from "fs";
3489
+ import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
2698
3490
  import { resolve as resolve4, sep as sep3 } from "path";
2699
3491
  function validatePlan(planPath, projectDir) {
2700
3492
  const errors = [];
@@ -2709,7 +3501,7 @@ function validatePlan(planPath, projectDir) {
2709
3501
  });
2710
3502
  return { valid: false, errors, warnings };
2711
3503
  }
2712
- if (!existsSync8(resolvedPlanPath)) {
3504
+ if (!existsSync7(resolvedPlanPath)) {
2713
3505
  errors.push({
2714
3506
  severity: "error",
2715
3507
  category: "structure",
@@ -2899,7 +3691,7 @@ function validateFileReferences(content, projectDir, warnings) {
2899
3691
  });
2900
3692
  continue;
2901
3693
  }
2902
- if (!existsSync8(absolutePath)) {
3694
+ if (!existsSync7(absolutePath)) {
2903
3695
  warnings.push({
2904
3696
  severity: "warning",
2905
3697
  category: "file-references",
@@ -2990,8 +3782,8 @@ var ACTIVE_INSTANCE_FILE = "active-instance.json";
2990
3782
  var WORKFLOWS_DIR_PROJECT = ".opencode/workflows";
2991
3783
  var WORKFLOWS_DIR_USER = "workflows";
2992
3784
  // src/features/workflow/storage.ts
2993
- import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync3, readdirSync as readdirSync3 } from "fs";
2994
- import { join as join7 } from "path";
3785
+ import { existsSync as existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync2, readdirSync as readdirSync3 } from "fs";
3786
+ import { join as join6 } from "path";
2995
3787
  import { randomBytes } from "node:crypto";
2996
3788
  function generateInstanceId() {
2997
3789
  return `wf_${randomBytes(4).toString("hex")}`;
@@ -3027,9 +3819,9 @@ function createWorkflowInstance(definition, definitionPath, goal, sessionId) {
3027
3819
  };
3028
3820
  }
3029
3821
  function readWorkflowInstance(directory, instanceId) {
3030
- const filePath = join7(directory, WORKFLOWS_STATE_DIR, instanceId, INSTANCE_STATE_FILE);
3822
+ const filePath = join6(directory, WORKFLOWS_STATE_DIR, instanceId, INSTANCE_STATE_FILE);
3031
3823
  try {
3032
- if (!existsSync9(filePath))
3824
+ if (!existsSync8(filePath))
3033
3825
  return null;
3034
3826
  const raw = readFileSync7(filePath, "utf-8");
3035
3827
  const parsed = JSON.parse(raw);
@@ -3044,20 +3836,20 @@ function readWorkflowInstance(directory, instanceId) {
3044
3836
  }
3045
3837
  function writeWorkflowInstance(directory, instance) {
3046
3838
  try {
3047
- const dir = join7(directory, WORKFLOWS_STATE_DIR, instance.instance_id);
3048
- if (!existsSync9(dir)) {
3049
- mkdirSync3(dir, { recursive: true });
3839
+ const dir = join6(directory, WORKFLOWS_STATE_DIR, instance.instance_id);
3840
+ if (!existsSync8(dir)) {
3841
+ mkdirSync2(dir, { recursive: true });
3050
3842
  }
3051
- writeFileSync2(join7(dir, INSTANCE_STATE_FILE), JSON.stringify(instance, null, 2), "utf-8");
3843
+ writeFileSync2(join6(dir, INSTANCE_STATE_FILE), JSON.stringify(instance, null, 2), "utf-8");
3052
3844
  return true;
3053
3845
  } catch {
3054
3846
  return false;
3055
3847
  }
3056
3848
  }
3057
3849
  function readActiveInstance(directory) {
3058
- const filePath = join7(directory, WORKFLOWS_STATE_DIR, ACTIVE_INSTANCE_FILE);
3850
+ const filePath = join6(directory, WORKFLOWS_STATE_DIR, ACTIVE_INSTANCE_FILE);
3059
3851
  try {
3060
- if (!existsSync9(filePath))
3852
+ if (!existsSync8(filePath))
3061
3853
  return null;
3062
3854
  const raw = readFileSync7(filePath, "utf-8");
3063
3855
  const parsed = JSON.parse(raw);
@@ -3070,21 +3862,21 @@ function readActiveInstance(directory) {
3070
3862
  }
3071
3863
  function setActiveInstance(directory, instanceId) {
3072
3864
  try {
3073
- const dir = join7(directory, WORKFLOWS_STATE_DIR);
3074
- if (!existsSync9(dir)) {
3075
- mkdirSync3(dir, { recursive: true });
3865
+ const dir = join6(directory, WORKFLOWS_STATE_DIR);
3866
+ if (!existsSync8(dir)) {
3867
+ mkdirSync2(dir, { recursive: true });
3076
3868
  }
3077
3869
  const pointer = { instance_id: instanceId };
3078
- writeFileSync2(join7(dir, ACTIVE_INSTANCE_FILE), JSON.stringify(pointer, null, 2), "utf-8");
3870
+ writeFileSync2(join6(dir, ACTIVE_INSTANCE_FILE), JSON.stringify(pointer, null, 2), "utf-8");
3079
3871
  return true;
3080
3872
  } catch {
3081
3873
  return false;
3082
3874
  }
3083
3875
  }
3084
3876
  function clearActiveInstance(directory) {
3085
- const filePath = join7(directory, WORKFLOWS_STATE_DIR, ACTIVE_INSTANCE_FILE);
3877
+ const filePath = join6(directory, WORKFLOWS_STATE_DIR, ACTIVE_INSTANCE_FILE);
3086
3878
  try {
3087
- if (existsSync9(filePath)) {
3879
+ if (existsSync8(filePath)) {
3088
3880
  unlinkSync2(filePath);
3089
3881
  }
3090
3882
  return true;
@@ -3099,10 +3891,9 @@ function getActiveWorkflowInstance(directory) {
3099
3891
  return readWorkflowInstance(directory, pointer.instance_id);
3100
3892
  }
3101
3893
  // src/features/workflow/discovery.ts
3102
- import * as fs5 from "fs";
3103
- import * as path5 from "path";
3104
- import * as os3 from "os";
3105
- import { parse as parseJsonc } from "jsonc-parser";
3894
+ import * as fs4 from "fs";
3895
+ import * as path4 from "path";
3896
+ import * as os2 from "os";
3106
3897
 
3107
3898
  // src/features/workflow/schema.ts
3108
3899
  import { z as z2 } from "zod";
@@ -3140,21 +3931,21 @@ var WorkflowDefinitionSchema = z2.object({
3140
3931
  function loadWorkflowDefinition(filePath) {
3141
3932
  let raw;
3142
3933
  try {
3143
- raw = fs5.readFileSync(filePath, "utf-8");
3934
+ raw = fs4.readFileSync(filePath, "utf-8");
3144
3935
  } catch (err) {
3145
- log("Failed to read workflow definition file", { filePath, error: String(err) });
3936
+ error("Failed to read workflow definition file", { filePath, error: String(err) });
3146
3937
  return null;
3147
3938
  }
3148
3939
  let parsed;
3149
3940
  try {
3150
- parsed = parseJsonc(raw);
3941
+ parsed = parse2(raw);
3151
3942
  } catch (err) {
3152
- log("Failed to parse workflow definition JSONC", { filePath, error: String(err) });
3943
+ error("Failed to parse workflow definition JSONC", { filePath, error: String(err) });
3153
3944
  return null;
3154
3945
  }
3155
3946
  const result = WorkflowDefinitionSchema.safeParse(parsed);
3156
3947
  if (!result.success) {
3157
- log("Workflow definition failed validation", {
3948
+ warn("Workflow definition failed validation", {
3158
3949
  filePath,
3159
3950
  errors: result.error.issues.map((i) => i.message)
3160
3951
  });
@@ -3163,13 +3954,13 @@ function loadWorkflowDefinition(filePath) {
3163
3954
  return result.data;
3164
3955
  }
3165
3956
  function scanWorkflowDirectory(directory, scope) {
3166
- if (!fs5.existsSync(directory))
3957
+ if (!fs4.existsSync(directory))
3167
3958
  return [];
3168
3959
  let entries;
3169
3960
  try {
3170
- entries = fs5.readdirSync(directory, { withFileTypes: true });
3961
+ entries = fs4.readdirSync(directory, { withFileTypes: true });
3171
3962
  } catch (err) {
3172
- log("Failed to read workflows directory", { directory, error: String(err) });
3963
+ warn("Failed to read workflows directory", { directory, error: String(err) });
3173
3964
  return [];
3174
3965
  }
3175
3966
  const workflows = [];
@@ -3178,7 +3969,7 @@ function scanWorkflowDirectory(directory, scope) {
3178
3969
  continue;
3179
3970
  if (!entry.name.endsWith(".jsonc") && !entry.name.endsWith(".json"))
3180
3971
  continue;
3181
- const filePath = path5.join(directory, entry.name);
3972
+ const filePath = path4.join(directory, entry.name);
3182
3973
  const definition = loadWorkflowDefinition(filePath);
3183
3974
  if (definition) {
3184
3975
  workflows.push({ definition, path: filePath, scope });
@@ -3187,8 +3978,8 @@ function scanWorkflowDirectory(directory, scope) {
3187
3978
  return workflows;
3188
3979
  }
3189
3980
  function discoverWorkflows(directory, customDirs) {
3190
- const projectDir = path5.join(directory, WORKFLOWS_DIR_PROJECT);
3191
- const userDir = path5.join(os3.homedir(), ".config", "opencode", WORKFLOWS_DIR_USER);
3981
+ const projectDir = path4.join(directory, WORKFLOWS_DIR_PROJECT);
3982
+ const userDir = path4.join(os2.homedir(), ".config", "opencode", WORKFLOWS_DIR_USER);
3192
3983
  const userWorkflows = scanWorkflowDirectory(userDir, "user");
3193
3984
  const projectWorkflows = scanWorkflowDirectory(projectDir, "project");
3194
3985
  const customWorkflows = [];
@@ -3310,8 +4101,8 @@ function truncateSummary(text) {
3310
4101
  return text.slice(0, maxLength - 3) + "...";
3311
4102
  }
3312
4103
  // src/features/workflow/completion.ts
3313
- import { existsSync as existsSync11 } from "fs";
3314
- import { join as join9 } from "path";
4104
+ import { existsSync as existsSync10 } from "fs";
4105
+ import { join as join8 } from "path";
3315
4106
  var DEFAULT_CONFIRM_KEYWORDS = ["confirmed", "approved", "continue", "done", "let's proceed", "looks good", "lgtm"];
3316
4107
  var VERDICT_APPROVE_RE = /\[\s*APPROVE\s*\]/i;
3317
4108
  var VERDICT_REJECT_RE = /\[\s*REJECT\s*\]/i;
@@ -3363,8 +4154,8 @@ function checkPlanCreated(context) {
3363
4154
  summary: `Plan created at ${matchingPlan}`
3364
4155
  };
3365
4156
  }
3366
- const directPath = join9(directory, ".weave", "plans", `${planName}.md`);
3367
- if (existsSync11(directPath)) {
4157
+ const directPath = join8(directory, ".weave", "plans", `${planName}.md`);
4158
+ if (existsSync10(directPath)) {
3368
4159
  return {
3369
4160
  complete: true,
3370
4161
  artifacts: { plan_path: directPath },
@@ -3379,8 +4170,8 @@ function checkPlanComplete(context) {
3379
4170
  if (!planName) {
3380
4171
  return { complete: false, reason: "plan_complete requires plan_name in completion config" };
3381
4172
  }
3382
- const planPath = join9(directory, ".weave", "plans", `${planName}.md`);
3383
- if (!existsSync11(planPath)) {
4173
+ const planPath = join8(directory, ".weave", "plans", `${planName}.md`);
4174
+ if (!existsSync10(planPath)) {
3384
4175
  return { complete: false, reason: `Plan file not found: ${planPath}` };
3385
4176
  }
3386
4177
  const progress = getPlanProgress(planPath);
@@ -3811,7 +4602,7 @@ ${available ? `Available workflows: ${available}` : "No workflow definitions ava
3811
4602
  sessionId,
3812
4603
  directory
3813
4604
  });
3814
- log("Workflow started", {
4605
+ info("Workflow started", {
3815
4606
  workflowName: match.definition.name,
3816
4607
  goal,
3817
4608
  agent: action.agent
@@ -4176,8 +4967,8 @@ function formatValidationResults(result) {
4176
4967
  if (result.errors.length > 0)
4177
4968
  lines.push("");
4178
4969
  lines.push("**Warnings:**");
4179
- for (const warn of result.warnings) {
4180
- lines.push(`- [${warn.category}] ${warn.message}`);
4970
+ for (const warn2 of result.warnings) {
4971
+ lines.push(`- [${warn2.category}] ${warn2.message}`);
4181
4972
  }
4182
4973
  }
4183
4974
  return lines.join(`
@@ -4376,21 +5167,21 @@ async function resolveTodoWriter() {
4376
5167
  }
4377
5168
 
4378
5169
  // src/hooks/compaction-todo-preserver.ts
4379
- function createCompactionTodoPreserver(client) {
5170
+ function createCompactionTodoPreserver(client2) {
4380
5171
  const snapshots = new Map;
4381
5172
  async function capture(sessionID) {
4382
5173
  try {
4383
- const response = await client.session.todo({ path: { id: sessionID } });
5174
+ const response = await client2.session.todo({ path: { id: sessionID } });
4384
5175
  const todos = response.data ?? [];
4385
5176
  if (todos.length > 0) {
4386
5177
  snapshots.set(sessionID, todos);
4387
- log("[compaction-todo-preserver] Captured snapshot", {
5178
+ debug("[compaction-todo-preserver] Captured snapshot", {
4388
5179
  sessionID,
4389
5180
  count: todos.length
4390
5181
  });
4391
5182
  }
4392
5183
  } catch (err) {
4393
- log("[compaction-todo-preserver] Failed to capture snapshot (non-fatal)", {
5184
+ warn("[compaction-todo-preserver] Failed to capture snapshot (non-fatal)", {
4394
5185
  sessionID,
4395
5186
  error: String(err)
4396
5187
  });
@@ -4402,10 +5193,10 @@ function createCompactionTodoPreserver(client) {
4402
5193
  return;
4403
5194
  }
4404
5195
  try {
4405
- const response = await client.session.todo({ path: { id: sessionID } });
5196
+ const response = await client2.session.todo({ path: { id: sessionID } });
4406
5197
  const currentTodos = response.data ?? [];
4407
5198
  if (currentTodos.length > 0) {
4408
- log("[compaction-todo-preserver] Todos survived compaction, skipping restore", {
5199
+ debug("[compaction-todo-preserver] Todos survived compaction, skipping restore", {
4409
5200
  sessionID,
4410
5201
  currentCount: currentTodos.length
4411
5202
  });
@@ -4415,18 +5206,18 @@ function createCompactionTodoPreserver(client) {
4415
5206
  const todoWriter = await resolveTodoWriter();
4416
5207
  if (todoWriter) {
4417
5208
  todoWriter({ sessionID, todos: snapshot });
4418
- log("[compaction-todo-preserver] Restored todos via direct write", {
5209
+ debug("[compaction-todo-preserver] Restored todos via direct write", {
4419
5210
  sessionID,
4420
5211
  count: snapshot.length
4421
5212
  });
4422
5213
  } else {
4423
- log("[compaction-todo-preserver] Direct write unavailable — todos cannot be restored", {
5214
+ warn("[compaction-todo-preserver] Direct write unavailable — todos cannot be restored", {
4424
5215
  sessionID,
4425
5216
  count: snapshot.length
4426
5217
  });
4427
5218
  }
4428
5219
  } catch (err) {
4429
- log("[compaction-todo-preserver] Failed to restore todos (non-fatal)", {
5220
+ warn("[compaction-todo-preserver] Failed to restore todos (non-fatal)", {
4430
5221
  sessionID,
4431
5222
  error: String(err)
4432
5223
  });
@@ -4447,7 +5238,7 @@ function createCompactionTodoPreserver(client) {
4447
5238
  const sessionID = props?.sessionID ?? props?.info?.id ?? "";
4448
5239
  if (sessionID) {
4449
5240
  snapshots.delete(sessionID);
4450
- log("[compaction-todo-preserver] Cleaned up snapshot on session delete", { sessionID });
5241
+ debug("[compaction-todo-preserver] Cleaned up snapshot on session delete", { sessionID });
4451
5242
  }
4452
5243
  return;
4453
5244
  }
@@ -4459,7 +5250,7 @@ function createCompactionTodoPreserver(client) {
4459
5250
  }
4460
5251
  // src/hooks/todo-continuation-enforcer.ts
4461
5252
  var FINALIZE_TODOS_MARKER = "<!-- weave:finalize-todos -->";
4462
- function createTodoContinuationEnforcer(client, options) {
5253
+ function createTodoContinuationEnforcer(client2, options) {
4463
5254
  const todoFinalizedSessions = new Set;
4464
5255
  let todoWriterPromise;
4465
5256
  if (options !== undefined && "todoWriterOverride" in options) {
@@ -4469,9 +5260,9 @@ function createTodoContinuationEnforcer(client, options) {
4469
5260
  }
4470
5261
  todoWriterPromise.then((writer) => {
4471
5262
  if (writer) {
4472
- log("[todo-continuation-enforcer] Direct write: available");
5263
+ debug("[todo-continuation-enforcer] Direct write: available");
4473
5264
  } else {
4474
- log("[todo-continuation-enforcer] Direct write: unavailable, will fall back to LLM prompt");
5265
+ debug("[todo-continuation-enforcer] Direct write: unavailable, will fall back to LLM prompt");
4475
5266
  }
4476
5267
  }).catch(() => {});
4477
5268
  async function checkAndFinalize(sessionID) {
@@ -4479,7 +5270,7 @@ function createTodoContinuationEnforcer(client, options) {
4479
5270
  return;
4480
5271
  }
4481
5272
  try {
4482
- const todosResponse = await client.session.todo({ path: { id: sessionID } });
5273
+ const todosResponse = await client2.session.todo({ path: { id: sessionID } });
4483
5274
  const todos = todosResponse.data ?? [];
4484
5275
  const inProgressTodos = todos.filter((t) => t.status === "in_progress");
4485
5276
  if (inProgressTodos.length === 0) {
@@ -4490,14 +5281,14 @@ function createTodoContinuationEnforcer(client, options) {
4490
5281
  if (todoWriter) {
4491
5282
  const updatedTodos = todos.map((t) => t.status === "in_progress" ? { ...t, status: "completed" } : t);
4492
5283
  todoWriter({ sessionID, todos: updatedTodos });
4493
- log("[todo-continuation-enforcer] Finalized via direct write (0 tokens)", {
5284
+ debug("[todo-continuation-enforcer] Finalized via direct write (0 tokens)", {
4494
5285
  sessionID,
4495
5286
  count: inProgressTodos.length
4496
5287
  });
4497
5288
  } else {
4498
5289
  const inProgressItems = inProgressTodos.map((t) => ` - "${t.content}"`).join(`
4499
5290
  `);
4500
- await client.session.promptAsync({
5291
+ await client2.session.promptAsync({
4501
5292
  path: { id: sessionID },
4502
5293
  body: {
4503
5294
  parts: [
@@ -4512,14 +5303,14 @@ Use todowrite NOW to mark all of them as "completed" (or "cancelled" if abandone
4512
5303
  ]
4513
5304
  }
4514
5305
  });
4515
- log("[todo-continuation-enforcer] Finalized via LLM prompt (fallback)", {
5306
+ debug("[todo-continuation-enforcer] Finalized via LLM prompt (fallback)", {
4516
5307
  sessionID,
4517
5308
  count: inProgressTodos.length
4518
5309
  });
4519
5310
  }
4520
5311
  } catch (err) {
4521
5312
  todoFinalizedSessions.delete(sessionID);
4522
- log("[todo-continuation-enforcer] Failed to check/finalize todos (non-fatal, will retry)", {
5313
+ warn("[todo-continuation-enforcer] Failed to check/finalize todos (non-fatal, will retry)", {
4523
5314
  sessionID,
4524
5315
  error: String(err)
4525
5316
  });
@@ -4546,8 +5337,8 @@ Use todowrite NOW to mark all of them as "completed" (or "cancelled" if abandone
4546
5337
  };
4547
5338
  }
4548
5339
  // src/features/analytics/storage.ts
4549
- import { existsSync as existsSync12, mkdirSync as mkdirSync4, appendFileSync as appendFileSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync3, statSync as statSync2 } from "fs";
4550
- import { join as join10 } from "path";
5340
+ import { existsSync as existsSync11, mkdirSync as mkdirSync3, appendFileSync, readFileSync as readFileSync9, writeFileSync as writeFileSync3, statSync as statSync2 } from "fs";
5341
+ import { join as join9 } from "path";
4551
5342
 
4552
5343
  // src/features/analytics/types.ts
4553
5344
  var ANALYTICS_DIR = ".weave/analytics";
@@ -4562,17 +5353,17 @@ function zeroTokenUsage() {
4562
5353
  // src/features/analytics/storage.ts
4563
5354
  var MAX_SESSION_ENTRIES = 1000;
4564
5355
  function ensureAnalyticsDir(directory) {
4565
- const dir = join10(directory, ANALYTICS_DIR);
4566
- mkdirSync4(dir, { recursive: true, mode: 448 });
5356
+ const dir = join9(directory, ANALYTICS_DIR);
5357
+ mkdirSync3(dir, { recursive: true, mode: 448 });
4567
5358
  return dir;
4568
5359
  }
4569
5360
  function appendSessionSummary(directory, summary) {
4570
5361
  try {
4571
5362
  const dir = ensureAnalyticsDir(directory);
4572
- const filePath = join10(dir, SESSION_SUMMARIES_FILE);
5363
+ const filePath = join9(dir, SESSION_SUMMARIES_FILE);
4573
5364
  const line = JSON.stringify(summary) + `
4574
5365
  `;
4575
- appendFileSync2(filePath, line, { encoding: "utf-8", mode: 384 });
5366
+ appendFileSync(filePath, line, { encoding: "utf-8", mode: 384 });
4576
5367
  try {
4577
5368
  const TYPICAL_ENTRY_BYTES = 200;
4578
5369
  const rotationSizeThreshold = MAX_SESSION_ENTRIES * TYPICAL_ENTRY_BYTES * 0.9;
@@ -4595,9 +5386,9 @@ function appendSessionSummary(directory, summary) {
4595
5386
  }
4596
5387
  }
4597
5388
  function readSessionSummaries(directory) {
4598
- const filePath = join10(directory, ANALYTICS_DIR, SESSION_SUMMARIES_FILE);
5389
+ const filePath = join9(directory, ANALYTICS_DIR, SESSION_SUMMARIES_FILE);
4599
5390
  try {
4600
- if (!existsSync12(filePath))
5391
+ if (!existsSync11(filePath))
4601
5392
  return [];
4602
5393
  const content = readFileSync9(filePath, "utf-8");
4603
5394
  const lines = content.split(`
@@ -4616,7 +5407,7 @@ function readSessionSummaries(directory) {
4616
5407
  function writeFingerprint(directory, fingerprint) {
4617
5408
  try {
4618
5409
  const dir = ensureAnalyticsDir(directory);
4619
- const filePath = join10(dir, FINGERPRINT_FILE);
5410
+ const filePath = join9(dir, FINGERPRINT_FILE);
4620
5411
  writeFileSync3(filePath, JSON.stringify(fingerprint, null, 2), { encoding: "utf-8", mode: 384 });
4621
5412
  return true;
4622
5413
  } catch {
@@ -4624,9 +5415,9 @@ function writeFingerprint(directory, fingerprint) {
4624
5415
  }
4625
5416
  }
4626
5417
  function readFingerprint(directory) {
4627
- const filePath = join10(directory, ANALYTICS_DIR, FINGERPRINT_FILE);
5418
+ const filePath = join9(directory, ANALYTICS_DIR, FINGERPRINT_FILE);
4628
5419
  try {
4629
- if (!existsSync12(filePath))
5420
+ if (!existsSync11(filePath))
4630
5421
  return null;
4631
5422
  const content = readFileSync9(filePath, "utf-8");
4632
5423
  const parsed = JSON.parse(content);
@@ -4640,10 +5431,10 @@ function readFingerprint(directory) {
4640
5431
  function writeMetricsReport(directory, report) {
4641
5432
  try {
4642
5433
  const dir = ensureAnalyticsDir(directory);
4643
- const filePath = join10(dir, METRICS_REPORTS_FILE);
5434
+ const filePath = join9(dir, METRICS_REPORTS_FILE);
4644
5435
  const line = JSON.stringify(report) + `
4645
5436
  `;
4646
- appendFileSync2(filePath, line, { encoding: "utf-8", mode: 384 });
5437
+ appendFileSync(filePath, line, { encoding: "utf-8", mode: 384 });
4647
5438
  try {
4648
5439
  const TYPICAL_ENTRY_BYTES = 200;
4649
5440
  const rotationSizeThreshold = MAX_METRICS_ENTRIES * TYPICAL_ENTRY_BYTES * 0.9;
@@ -4666,9 +5457,9 @@ function writeMetricsReport(directory, report) {
4666
5457
  }
4667
5458
  }
4668
5459
  function readMetricsReports(directory) {
4669
- const filePath = join10(directory, ANALYTICS_DIR, METRICS_REPORTS_FILE);
5460
+ const filePath = join9(directory, ANALYTICS_DIR, METRICS_REPORTS_FILE);
4670
5461
  try {
4671
- if (!existsSync12(filePath))
5462
+ if (!existsSync11(filePath))
4672
5463
  return [];
4673
5464
  const content = readFileSync9(filePath, "utf-8");
4674
5465
  const lines = content.split(`
@@ -5198,7 +5989,7 @@ function generateMetricsReport(directory, state) {
5198
5989
  totalTokens
5199
5990
  });
5200
5991
  } catch (qualityErr) {
5201
- log("[analytics] Failed to calculate quality score (non-fatal)", {
5992
+ warn("[analytics] Failed to calculate quality score (non-fatal)", {
5202
5993
  error: String(qualityErr)
5203
5994
  });
5204
5995
  }
@@ -5219,10 +6010,10 @@ function generateMetricsReport(directory, state) {
5219
6010
  };
5220
6011
  const written = writeMetricsReport(directory, report);
5221
6012
  if (!written) {
5222
- log("[analytics] Failed to write metrics report (non-fatal)");
6013
+ warn("[analytics] Failed to write metrics report (non-fatal)");
5223
6014
  return null;
5224
6015
  }
5225
- log("[analytics] Metrics report generated", {
6016
+ debug("[analytics] Metrics report generated", {
5226
6017
  plan: report.planName,
5227
6018
  coverage: adherence.coverage,
5228
6019
  precision: adherence.precision,
@@ -5230,7 +6021,7 @@ function generateMetricsReport(directory, state) {
5230
6021
  });
5231
6022
  return report;
5232
6023
  } catch (err) {
5233
- log("[analytics] Failed to generate metrics report (non-fatal)", {
6024
+ warn("[analytics] Failed to generate metrics report (non-fatal)", {
5234
6025
  error: String(err)
5235
6026
  });
5236
6027
  return null;
@@ -5239,11 +6030,11 @@ function generateMetricsReport(directory, state) {
5239
6030
 
5240
6031
  // src/plugin/plugin-interface.ts
5241
6032
  function createPluginInterface(args) {
5242
- const { pluginConfig, hooks, tools, configHandler, agents, client, directory = "", tracker } = args;
6033
+ const { pluginConfig, hooks, tools, configHandler, agents, client: client2, directory = "", tracker } = args;
5243
6034
  const lastAssistantMessageText = new Map;
5244
6035
  const lastUserMessageText = new Map;
5245
- const compactionPreserver = hooks.compactionTodoPreserverEnabled && client ? createCompactionTodoPreserver(client) : null;
5246
- const todoContinuationEnforcer = hooks.todoContinuationEnforcerEnabled && client ? createTodoContinuationEnforcer(client) : null;
6036
+ const compactionPreserver = hooks.compactionTodoPreserverEnabled && client2 ? createCompactionTodoPreserver(client2) : null;
6037
+ const todoContinuationEnforcer = hooks.todoContinuationEnforcerEnabled && client2 ? createTodoContinuationEnforcer(client2) : null;
5247
6038
  return {
5248
6039
  tool: tools,
5249
6040
  config: async (config) => {
@@ -5254,14 +6045,14 @@ function createPluginInterface(args) {
5254
6045
  });
5255
6046
  const existingAgents = config.agent ?? {};
5256
6047
  if (Object.keys(existingAgents).length > 0) {
5257
- log("[config] Merging Weave agents over existing agents", {
6048
+ debug("[config] Merging Weave agents over existing agents", {
5258
6049
  existingCount: Object.keys(existingAgents).length,
5259
6050
  weaveCount: Object.keys(result.agents).length,
5260
6051
  existingKeys: Object.keys(existingAgents)
5261
6052
  });
5262
6053
  const collisions = Object.keys(result.agents).filter((key) => (key in existingAgents));
5263
6054
  if (collisions.length > 0) {
5264
- log("[config] Weave agents overriding user-defined agents with same name", {
6055
+ info("[config] Weave agents overriding user-defined agents with same name", {
5265
6056
  overriddenKeys: collisions
5266
6057
  });
5267
6058
  }
@@ -5300,6 +6091,12 @@ function createPluginInterface(args) {
5300
6091
  const result = isWorkflowCommand ? { contextInjection: null, switchAgent: null } : hooks.startWork(promptText, sessionID);
5301
6092
  if (result.switchAgent && message) {
5302
6093
  message.agent = getAgentDisplayName(result.switchAgent);
6094
+ debug("[start-work] Switching agent for plan execution", {
6095
+ sessionId: sessionID,
6096
+ agent: result.switchAgent,
6097
+ displayName: message.agent,
6098
+ hasContextInjection: !!result.contextInjection
6099
+ });
5303
6100
  }
5304
6101
  if (result.contextInjection && parts) {
5305
6102
  const idx = parts.findIndex((p) => p.type === "text" && p.text);
@@ -5322,6 +6119,11 @@ ${result.contextInjection}`;
5322
6119
  const result = hooks.workflowStart(promptText, sessionID);
5323
6120
  if (result.switchAgent && message) {
5324
6121
  message.agent = getAgentDisplayName(result.switchAgent);
6122
+ debug("[workflow] Switching agent for workflow execution", {
6123
+ sessionId: sessionID,
6124
+ agent: result.switchAgent,
6125
+ displayName: message.agent
6126
+ });
5325
6127
  }
5326
6128
  if (result.contextInjection && parts) {
5327
6129
  const idx = parts.findIndex((p) => p.type === "text" && p.text);
@@ -5371,6 +6173,10 @@ ${cmdResult.contextInjection}`;
5371
6173
  }
5372
6174
  if (cmdResult.switchAgent && message) {
5373
6175
  message.agent = getAgentDisplayName(cmdResult.switchAgent);
6176
+ debug("[workflow] Switching agent via workflow command", {
6177
+ agent: cmdResult.switchAgent,
6178
+ displayName: message.agent
6179
+ });
5374
6180
  }
5375
6181
  }
5376
6182
  }
@@ -5391,7 +6197,7 @@ ${cmdResult.contextInjection}`;
5391
6197
  const state = readWorkState(directory);
5392
6198
  if (state && !state.paused) {
5393
6199
  pauseWork(directory);
5394
- log("[work-continuation] Auto-paused: user message received during active plan", { sessionId: sessionID });
6200
+ info("[work-continuation] Auto-paused: user message received during active plan", { sessionId: sessionID });
5395
6201
  }
5396
6202
  }
5397
6203
  }
@@ -5402,7 +6208,7 @@ ${cmdResult.contextInjection}`;
5402
6208
  const maxTokens = input.model?.limit?.context ?? 0;
5403
6209
  if (sessionId && maxTokens > 0) {
5404
6210
  setContextLimit(sessionId, maxTokens);
5405
- log("[context-window] Captured context limit", { sessionId, maxTokens });
6211
+ debug("[context-window] Captured context limit", { sessionId, maxTokens });
5406
6212
  }
5407
6213
  if (tracker && hooks.analyticsEnabled && sessionId && input.agent) {
5408
6214
  tracker.setAgentName(sessionId, input.agent);
@@ -5437,7 +6243,7 @@ ${cmdResult.contextInjection}`;
5437
6243
  try {
5438
6244
  tracker.endSession(evt.properties.info.id);
5439
6245
  } catch (err) {
5440
- log("[analytics] Failed to end session (non-fatal)", { error: String(err) });
6246
+ warn("[analytics] Failed to end session (non-fatal)", { error: String(err) });
5441
6247
  }
5442
6248
  if (directory) {
5443
6249
  try {
@@ -5449,29 +6255,29 @@ ${cmdResult.contextInjection}`;
5449
6255
  }
5450
6256
  }
5451
6257
  } catch (err) {
5452
- log("[analytics] Failed to generate metrics report on session end (non-fatal)", { error: String(err) });
6258
+ warn("[analytics] Failed to generate metrics report on session end (non-fatal)", { error: String(err) });
5453
6259
  }
5454
6260
  }
5455
6261
  }
5456
6262
  }
5457
6263
  if (event.type === "message.updated") {
5458
6264
  const evt = event;
5459
- const info = evt.properties?.info;
5460
- if (info?.role === "assistant" && info.sessionID) {
6265
+ const info2 = evt.properties?.info;
6266
+ if (info2?.role === "assistant" && info2.sessionID) {
5461
6267
  if (hooks.checkContextWindow) {
5462
- const inputTokens = info.tokens?.input ?? 0;
6268
+ const inputTokens = info2.tokens?.input ?? 0;
5463
6269
  if (inputTokens > 0) {
5464
- updateUsage(info.sessionID, inputTokens);
5465
- const tokenState = getState(info.sessionID);
6270
+ updateUsage(info2.sessionID, inputTokens);
6271
+ const tokenState = getState(info2.sessionID);
5466
6272
  if (tokenState && tokenState.maxTokens > 0) {
5467
6273
  const result = hooks.checkContextWindow({
5468
6274
  usedTokens: tokenState.usedTokens,
5469
6275
  maxTokens: tokenState.maxTokens,
5470
- sessionId: info.sessionID
6276
+ sessionId: info2.sessionID
5471
6277
  });
5472
6278
  if (result.action !== "none") {
5473
- log("[context-window] Threshold crossed", {
5474
- sessionId: info.sessionID,
6279
+ warn("[context-window] Threshold crossed", {
6280
+ sessionId: info2.sessionID,
5475
6281
  action: result.action,
5476
6282
  usagePct: result.usagePct
5477
6283
  });
@@ -5483,18 +6289,18 @@ ${cmdResult.contextInjection}`;
5483
6289
  }
5484
6290
  if (event.type === "message.updated" && tracker && hooks.analyticsEnabled) {
5485
6291
  const evt = event;
5486
- const info = evt.properties?.info;
5487
- if (info?.role === "assistant" && info.sessionID) {
5488
- if (typeof info.cost === "number" && info.cost > 0) {
5489
- tracker.trackCost(info.sessionID, info.cost);
6292
+ const info2 = evt.properties?.info;
6293
+ if (info2?.role === "assistant" && info2.sessionID) {
6294
+ if (typeof info2.cost === "number" && info2.cost > 0) {
6295
+ tracker.trackCost(info2.sessionID, info2.cost);
5490
6296
  }
5491
- if (info.tokens) {
5492
- tracker.trackTokenUsage(info.sessionID, {
5493
- input: info.tokens.input ?? 0,
5494
- output: info.tokens.output ?? 0,
5495
- reasoning: info.tokens.reasoning ?? 0,
5496
- cacheRead: info.tokens.cache?.read ?? 0,
5497
- cacheWrite: info.tokens.cache?.write ?? 0
6297
+ if (info2.tokens) {
6298
+ tracker.trackTokenUsage(info2.sessionID, {
6299
+ input: info2.tokens.input ?? 0,
6300
+ output: info2.tokens.output ?? 0,
6301
+ reasoning: info2.tokens.reasoning ?? 0,
6302
+ cacheRead: info2.tokens.cache?.read ?? 0,
6303
+ cacheWrite: info2.tokens.cache?.write ?? 0
5498
6304
  });
5499
6305
  }
5500
6306
  }
@@ -5503,12 +6309,12 @@ ${cmdResult.contextInjection}`;
5503
6309
  const evt = event;
5504
6310
  if (evt.properties?.command === "session.interrupt") {
5505
6311
  pauseWork(directory);
5506
- log("[work-continuation] User interrupt detected — work paused");
6312
+ info("[work-continuation] User interrupt detected — work paused");
5507
6313
  if (directory) {
5508
6314
  const activeWorkflow = getActiveWorkflowInstance(directory);
5509
6315
  if (activeWorkflow && activeWorkflow.status === "running") {
5510
6316
  pauseWorkflow(directory, "User interrupt");
5511
- log("[workflow] User interrupt detected — workflow paused");
6317
+ info("[workflow] User interrupt detected — workflow paused");
5512
6318
  }
5513
6319
  }
5514
6320
  }
@@ -5530,21 +6336,21 @@ ${cmdResult.contextInjection}`;
5530
6336
  const lastMsg = lastAssistantMessageText.get(sessionId) ?? undefined;
5531
6337
  const lastUserMsg = lastUserMessageText.get(sessionId) ?? undefined;
5532
6338
  const result = hooks.workflowContinuation(sessionId, lastMsg, lastUserMsg);
5533
- if (result.continuationPrompt && client) {
6339
+ if (result.continuationPrompt && client2) {
5534
6340
  try {
5535
- await client.session.promptAsync({
6341
+ await client2.session.promptAsync({
5536
6342
  path: { id: sessionId },
5537
6343
  body: {
5538
6344
  parts: [{ type: "text", text: result.continuationPrompt }],
5539
6345
  ...result.switchAgent ? { agent: getAgentDisplayName(result.switchAgent) } : {}
5540
6346
  }
5541
6347
  });
5542
- log("[workflow] Injected workflow continuation prompt", {
6348
+ debug("[workflow] Injected workflow continuation prompt", {
5543
6349
  sessionId,
5544
6350
  agent: result.switchAgent
5545
6351
  });
5546
6352
  } catch (err) {
5547
- log("[workflow] Failed to inject workflow continuation", { sessionId, error: String(err) });
6353
+ error("[workflow] Failed to inject workflow continuation", { sessionId, error: String(err) });
5548
6354
  }
5549
6355
  return;
5550
6356
  }
@@ -5556,21 +6362,21 @@ ${cmdResult.contextInjection}`;
5556
6362
  const sessionId = evt.properties?.sessionID ?? "";
5557
6363
  if (sessionId) {
5558
6364
  const result = hooks.workContinuation(sessionId);
5559
- if (result.continuationPrompt && client) {
6365
+ if (result.continuationPrompt && client2) {
5560
6366
  try {
5561
- await client.session.promptAsync({
6367
+ await client2.session.promptAsync({
5562
6368
  path: { id: sessionId },
5563
6369
  body: {
5564
6370
  parts: [{ type: "text", text: result.continuationPrompt }]
5565
6371
  }
5566
6372
  });
5567
- log("[work-continuation] Injected continuation prompt", { sessionId });
6373
+ debug("[work-continuation] Injected continuation prompt", { sessionId });
5568
6374
  continuationFired = true;
5569
6375
  } catch (err) {
5570
- log("[work-continuation] Failed to inject continuation", { sessionId, error: String(err) });
6376
+ error("[work-continuation] Failed to inject continuation", { sessionId, error: String(err) });
5571
6377
  }
5572
6378
  } else if (result.continuationPrompt) {
5573
- log("[work-continuation] continuationPrompt available but no client", { sessionId });
6379
+ debug("[work-continuation] continuationPrompt available but no client", { sessionId });
5574
6380
  }
5575
6381
  }
5576
6382
  }
@@ -5674,14 +6480,14 @@ ${cmdResult.contextInjection}`;
5674
6480
  };
5675
6481
  }
5676
6482
  // src/features/analytics/fingerprint.ts
5677
- import { existsSync as existsSync13, readFileSync as readFileSync12, readdirSync as readdirSync5 } from "fs";
5678
- import { join as join12 } from "path";
6483
+ import { existsSync as existsSync12, readFileSync as readFileSync12, readdirSync as readdirSync5 } from "fs";
6484
+ import { join as join11 } from "path";
5679
6485
  import { arch } from "os";
5680
6486
 
5681
6487
  // src/shared/version.ts
5682
6488
  import { readFileSync as readFileSync11 } from "fs";
5683
6489
  import { fileURLToPath } from "url";
5684
- import { dirname as dirname2, join as join11 } from "path";
6490
+ import { dirname as dirname2, join as join10 } from "path";
5685
6491
  var cachedVersion;
5686
6492
  function getWeaveVersion() {
5687
6493
  if (cachedVersion !== undefined)
@@ -5690,7 +6496,7 @@ function getWeaveVersion() {
5690
6496
  const thisDir = dirname2(fileURLToPath(import.meta.url));
5691
6497
  for (const rel of ["../../package.json", "../package.json"]) {
5692
6498
  try {
5693
- const pkg = JSON.parse(readFileSync11(join11(thisDir, rel), "utf-8"));
6499
+ const pkg = JSON.parse(readFileSync11(join10(thisDir, rel), "utf-8"));
5694
6500
  if (pkg.name === "@opencode_weave/weave" && typeof pkg.version === "string") {
5695
6501
  const version = pkg.version;
5696
6502
  cachedVersion = version;
@@ -5795,7 +6601,7 @@ function detectStack(directory) {
5795
6601
  const detected = [];
5796
6602
  for (const marker of STACK_MARKERS) {
5797
6603
  for (const file of marker.files) {
5798
- if (existsSync13(join12(directory, file))) {
6604
+ if (existsSync12(join11(directory, file))) {
5799
6605
  detected.push({
5800
6606
  name: marker.name,
5801
6607
  confidence: marker.confidence,
@@ -5806,8 +6612,8 @@ function detectStack(directory) {
5806
6612
  }
5807
6613
  }
5808
6614
  try {
5809
- const pkgPath = join12(directory, "package.json");
5810
- if (existsSync13(pkgPath)) {
6615
+ const pkgPath = join11(directory, "package.json");
6616
+ if (existsSync12(pkgPath)) {
5811
6617
  const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
5812
6618
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
5813
6619
  if (deps.react) {
@@ -5841,26 +6647,26 @@ function detectStack(directory) {
5841
6647
  });
5842
6648
  }
5843
6649
  function detectPackageManager(directory) {
5844
- if (existsSync13(join12(directory, "bun.lockb")))
6650
+ if (existsSync12(join11(directory, "bun.lockb")))
5845
6651
  return "bun";
5846
- if (existsSync13(join12(directory, "pnpm-lock.yaml")))
6652
+ if (existsSync12(join11(directory, "pnpm-lock.yaml")))
5847
6653
  return "pnpm";
5848
- if (existsSync13(join12(directory, "yarn.lock")))
6654
+ if (existsSync12(join11(directory, "yarn.lock")))
5849
6655
  return "yarn";
5850
- if (existsSync13(join12(directory, "package-lock.json")))
6656
+ if (existsSync12(join11(directory, "package-lock.json")))
5851
6657
  return "npm";
5852
- if (existsSync13(join12(directory, "package.json")))
6658
+ if (existsSync12(join11(directory, "package.json")))
5853
6659
  return "npm";
5854
6660
  return;
5855
6661
  }
5856
6662
  function detectMonorepo(directory) {
5857
6663
  for (const marker of MONOREPO_MARKERS) {
5858
- if (existsSync13(join12(directory, marker)))
6664
+ if (existsSync12(join11(directory, marker)))
5859
6665
  return true;
5860
6666
  }
5861
6667
  try {
5862
- const pkgPath = join12(directory, "package.json");
5863
- if (existsSync13(pkgPath)) {
6668
+ const pkgPath = join11(directory, "package.json");
6669
+ if (existsSync12(pkgPath)) {
5864
6670
  const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
5865
6671
  if (pkg.workspaces)
5866
6672
  return true;
@@ -5895,14 +6701,14 @@ function fingerprintProject(directory) {
5895
6701
  try {
5896
6702
  const fingerprint = generateFingerprint(directory);
5897
6703
  writeFingerprint(directory, fingerprint);
5898
- log("[analytics] Project fingerprinted", {
6704
+ debug("[analytics] Project fingerprinted", {
5899
6705
  stack: fingerprint.stack.map((s) => s.name),
5900
6706
  primaryLanguage: fingerprint.primaryLanguage,
5901
6707
  packageManager: fingerprint.packageManager
5902
6708
  });
5903
6709
  return fingerprint;
5904
6710
  } catch (err) {
5905
- log("[analytics] Fingerprinting failed (non-fatal)", { error: String(err) });
6711
+ warn("[analytics] Fingerprinting failed (non-fatal)", { error: String(err) });
5906
6712
  return null;
5907
6713
  }
5908
6714
  }
@@ -5914,14 +6720,14 @@ function getOrCreateFingerprint(directory) {
5914
6720
  if (existing.weaveVersion === currentVersion) {
5915
6721
  return existing;
5916
6722
  }
5917
- log("[analytics] Fingerprint version mismatch — regenerating", {
6723
+ debug("[analytics] Fingerprint version mismatch — regenerating", {
5918
6724
  cached: existing.weaveVersion ?? "none",
5919
6725
  current: currentVersion
5920
6726
  });
5921
6727
  }
5922
6728
  return fingerprintProject(directory);
5923
6729
  } catch (err) {
5924
- log("[analytics] getOrCreateFingerprint failed (non-fatal)", { error: String(err) });
6730
+ warn("[analytics] getOrCreateFingerprint failed (non-fatal)", { error: String(err) });
5925
6731
  return null;
5926
6732
  }
5927
6733
  }
@@ -6045,7 +6851,7 @@ class SessionTracker {
6045
6851
  };
6046
6852
  try {
6047
6853
  appendSessionSummary(this.directory, summary);
6048
- log("[analytics] Session summary persisted", {
6854
+ debug("[analytics] Session summary persisted", {
6049
6855
  sessionId,
6050
6856
  totalToolCalls,
6051
6857
  totalDelegations: session.delegations.length,
@@ -6055,7 +6861,7 @@ class SessionTracker {
6055
6861
  } : {}
6056
6862
  });
6057
6863
  } catch (err) {
6058
- log("[analytics] Failed to persist session summary (non-fatal)", {
6864
+ warn("[analytics] Failed to persist session summary (non-fatal)", {
6059
6865
  sessionId,
6060
6866
  error: String(err)
6061
6867
  });
@@ -6085,12 +6891,16 @@ function createAnalytics(directory, fingerprint) {
6085
6891
  // src/index.ts
6086
6892
  var WeavePlugin = async (ctx) => {
6087
6893
  const pluginConfig = loadWeaveConfig(ctx.directory, ctx);
6894
+ setClient(ctx.client);
6895
+ if (pluginConfig.log_level) {
6896
+ setLogLevel(pluginConfig.log_level);
6897
+ }
6088
6898
  const disabledHooks = new Set(pluginConfig.disabled_hooks ?? []);
6089
6899
  const isHookEnabled = (name) => !disabledHooks.has(name);
6090
6900
  const analyticsEnabled = pluginConfig.analytics?.enabled === true;
6091
6901
  const fingerprintEnabled = analyticsEnabled && pluginConfig.analytics?.use_fingerprint === true;
6092
6902
  const fingerprint = fingerprintEnabled ? getOrCreateFingerprint(ctx.directory) : null;
6093
- const configDir = join13(ctx.directory, ".opencode");
6903
+ const configDir = join12(ctx.directory, ".opencode");
6094
6904
  const toolsResult = await createTools({ ctx, pluginConfig });
6095
6905
  const managers = createManagers({ ctx, pluginConfig, resolveSkills: toolsResult.resolveSkillsFn, fingerprint, configDir });
6096
6906
  const hooks = createHooks({ pluginConfig, isHookEnabled, directory: ctx.directory, analyticsEnabled });