oh-my-opencode 2.1.3 → 2.1.5
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/README.ja.md +33 -18
- package/README.ko.md +42 -27
- package/README.md +59 -23
- package/dist/index.js +548 -998
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -205,19 +205,19 @@ var require_utils = __commonJS((exports) => {
|
|
|
205
205
|
return exports.escapeLast(input, char, idx - 1);
|
|
206
206
|
return `${input.slice(0, idx)}\\${input.slice(idx)}`;
|
|
207
207
|
};
|
|
208
|
-
exports.removePrefix = (input,
|
|
208
|
+
exports.removePrefix = (input, state2 = {}) => {
|
|
209
209
|
let output = input;
|
|
210
210
|
if (output.startsWith("./")) {
|
|
211
211
|
output = output.slice(2);
|
|
212
|
-
|
|
212
|
+
state2.prefix = "./";
|
|
213
213
|
}
|
|
214
214
|
return output;
|
|
215
215
|
};
|
|
216
|
-
exports.wrapOutput = (input,
|
|
216
|
+
exports.wrapOutput = (input, state2 = {}, options = {}) => {
|
|
217
217
|
const prepend = options.contains ? "" : "^";
|
|
218
218
|
const append = options.contains ? "" : "$";
|
|
219
219
|
let output = `${prepend}(?:${input})${append}`;
|
|
220
|
-
if (
|
|
220
|
+
if (state2.negated === true) {
|
|
221
221
|
output = `(?:^(?!${output}).*$)`;
|
|
222
222
|
}
|
|
223
223
|
return output;
|
|
@@ -488,7 +488,7 @@ var require_scan = __commonJS((exports, module) => {
|
|
|
488
488
|
base = utils.removeBackslashes(base);
|
|
489
489
|
}
|
|
490
490
|
}
|
|
491
|
-
const
|
|
491
|
+
const state2 = {
|
|
492
492
|
prefix,
|
|
493
493
|
input,
|
|
494
494
|
start,
|
|
@@ -503,11 +503,11 @@ var require_scan = __commonJS((exports, module) => {
|
|
|
503
503
|
negatedExtglob
|
|
504
504
|
};
|
|
505
505
|
if (opts.tokens === true) {
|
|
506
|
-
|
|
506
|
+
state2.maxDepth = 0;
|
|
507
507
|
if (!isPathSeparator(code)) {
|
|
508
508
|
tokens.push(token);
|
|
509
509
|
}
|
|
510
|
-
|
|
510
|
+
state2.tokens = tokens;
|
|
511
511
|
}
|
|
512
512
|
if (opts.parts === true || opts.tokens === true) {
|
|
513
513
|
let prevIndex;
|
|
@@ -523,7 +523,7 @@ var require_scan = __commonJS((exports, module) => {
|
|
|
523
523
|
tokens[idx].value = value;
|
|
524
524
|
}
|
|
525
525
|
depth(tokens[idx]);
|
|
526
|
-
|
|
526
|
+
state2.maxDepth += tokens[idx].depth;
|
|
527
527
|
}
|
|
528
528
|
if (idx !== 0 || value !== "") {
|
|
529
529
|
parts.push(value);
|
|
@@ -536,13 +536,13 @@ var require_scan = __commonJS((exports, module) => {
|
|
|
536
536
|
if (opts.tokens) {
|
|
537
537
|
tokens[tokens.length - 1].value = value;
|
|
538
538
|
depth(tokens[tokens.length - 1]);
|
|
539
|
-
|
|
539
|
+
state2.maxDepth += tokens[tokens.length - 1].depth;
|
|
540
540
|
}
|
|
541
541
|
}
|
|
542
|
-
|
|
543
|
-
|
|
542
|
+
state2.slashes = slashes;
|
|
543
|
+
state2.parts = parts;
|
|
544
544
|
}
|
|
545
|
-
return
|
|
545
|
+
return state2;
|
|
546
546
|
};
|
|
547
547
|
module.exports = scan;
|
|
548
548
|
});
|
|
@@ -616,7 +616,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
616
616
|
if (typeof opts.noext === "boolean") {
|
|
617
617
|
opts.noextglob = opts.noext;
|
|
618
618
|
}
|
|
619
|
-
const
|
|
619
|
+
const state2 = {
|
|
620
620
|
input,
|
|
621
621
|
index: -1,
|
|
622
622
|
start: 0,
|
|
@@ -633,57 +633,57 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
633
633
|
globstar: false,
|
|
634
634
|
tokens
|
|
635
635
|
};
|
|
636
|
-
input = utils.removePrefix(input,
|
|
636
|
+
input = utils.removePrefix(input, state2);
|
|
637
637
|
len = input.length;
|
|
638
638
|
const extglobs = [];
|
|
639
639
|
const braces = [];
|
|
640
640
|
const stack = [];
|
|
641
641
|
let prev = bos;
|
|
642
642
|
let value;
|
|
643
|
-
const eos = () =>
|
|
644
|
-
const peek =
|
|
645
|
-
const advance =
|
|
646
|
-
const remaining = () => input.slice(
|
|
643
|
+
const eos = () => state2.index === len - 1;
|
|
644
|
+
const peek = state2.peek = (n = 1) => input[state2.index + n];
|
|
645
|
+
const advance = state2.advance = () => input[++state2.index] || "";
|
|
646
|
+
const remaining = () => input.slice(state2.index + 1);
|
|
647
647
|
const consume = (value2 = "", num = 0) => {
|
|
648
|
-
|
|
649
|
-
|
|
648
|
+
state2.consumed += value2;
|
|
649
|
+
state2.index += num;
|
|
650
650
|
};
|
|
651
651
|
const append = (token) => {
|
|
652
|
-
|
|
652
|
+
state2.output += token.output != null ? token.output : token.value;
|
|
653
653
|
consume(token.value);
|
|
654
654
|
};
|
|
655
655
|
const negate = () => {
|
|
656
656
|
let count = 1;
|
|
657
657
|
while (peek() === "!" && (peek(2) !== "(" || peek(3) === "?")) {
|
|
658
658
|
advance();
|
|
659
|
-
|
|
659
|
+
state2.start++;
|
|
660
660
|
count++;
|
|
661
661
|
}
|
|
662
662
|
if (count % 2 === 0) {
|
|
663
663
|
return false;
|
|
664
664
|
}
|
|
665
|
-
|
|
666
|
-
|
|
665
|
+
state2.negated = true;
|
|
666
|
+
state2.start++;
|
|
667
667
|
return true;
|
|
668
668
|
};
|
|
669
669
|
const increment = (type) => {
|
|
670
|
-
|
|
670
|
+
state2[type]++;
|
|
671
671
|
stack.push(type);
|
|
672
672
|
};
|
|
673
673
|
const decrement = (type) => {
|
|
674
|
-
|
|
674
|
+
state2[type]--;
|
|
675
675
|
stack.pop();
|
|
676
676
|
};
|
|
677
677
|
const push = (tok) => {
|
|
678
678
|
if (prev.type === "globstar") {
|
|
679
|
-
const isBrace =
|
|
679
|
+
const isBrace = state2.braces > 0 && (tok.type === "comma" || tok.type === "brace");
|
|
680
680
|
const isExtglob = tok.extglob === true || extglobs.length && (tok.type === "pipe" || tok.type === "paren");
|
|
681
681
|
if (tok.type !== "slash" && tok.type !== "paren" && !isBrace && !isExtglob) {
|
|
682
|
-
|
|
682
|
+
state2.output = state2.output.slice(0, -prev.output.length);
|
|
683
683
|
prev.type = "star";
|
|
684
684
|
prev.value = "*";
|
|
685
685
|
prev.output = star;
|
|
686
|
-
|
|
686
|
+
state2.output += prev.output;
|
|
687
687
|
}
|
|
688
688
|
}
|
|
689
689
|
if (extglobs.length && tok.type !== "paren") {
|
|
@@ -703,11 +703,11 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
703
703
|
const extglobOpen = (type, value2) => {
|
|
704
704
|
const token = { ...EXTGLOB_CHARS[value2], conditions: 1, inner: "" };
|
|
705
705
|
token.prev = prev;
|
|
706
|
-
token.parens =
|
|
707
|
-
token.output =
|
|
706
|
+
token.parens = state2.parens;
|
|
707
|
+
token.output = state2.output;
|
|
708
708
|
const output = (opts.capture ? "(" : "") + token.open;
|
|
709
709
|
increment("parens");
|
|
710
|
-
push({ type, value: value2, output:
|
|
710
|
+
push({ type, value: value2, output: state2.output ? "" : ONE_CHAR });
|
|
711
711
|
push({ type: "paren", extglob: true, value: advance(), output });
|
|
712
712
|
extglobs.push(token);
|
|
713
713
|
};
|
|
@@ -727,7 +727,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
727
727
|
output = token.close = `)${expression})${extglobStar})`;
|
|
728
728
|
}
|
|
729
729
|
if (token.prev.type === "bos") {
|
|
730
|
-
|
|
730
|
+
state2.negatedExtglob = true;
|
|
731
731
|
}
|
|
732
732
|
}
|
|
733
733
|
push({ type: "paren", extglob: true, value, output });
|
|
@@ -770,11 +770,11 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
770
770
|
}
|
|
771
771
|
}
|
|
772
772
|
if (output === input && opts.contains === true) {
|
|
773
|
-
|
|
774
|
-
return
|
|
773
|
+
state2.output = input;
|
|
774
|
+
return state2;
|
|
775
775
|
}
|
|
776
|
-
|
|
777
|
-
return
|
|
776
|
+
state2.output = utils.wrapOutput(output, state2, options);
|
|
777
|
+
return state2;
|
|
778
778
|
}
|
|
779
779
|
while (!eos()) {
|
|
780
780
|
value = advance();
|
|
@@ -798,7 +798,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
798
798
|
let slashes = 0;
|
|
799
799
|
if (match && match[0].length > 2) {
|
|
800
800
|
slashes = match[0].length;
|
|
801
|
-
|
|
801
|
+
state2.index += slashes;
|
|
802
802
|
if (slashes % 2 !== 0) {
|
|
803
803
|
value += "\\";
|
|
804
804
|
}
|
|
@@ -808,12 +808,12 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
808
808
|
} else {
|
|
809
809
|
value += advance();
|
|
810
810
|
}
|
|
811
|
-
if (
|
|
811
|
+
if (state2.brackets === 0) {
|
|
812
812
|
push({ type: "text", value });
|
|
813
813
|
continue;
|
|
814
814
|
}
|
|
815
815
|
}
|
|
816
|
-
if (
|
|
816
|
+
if (state2.brackets > 0 && (value !== "]" || prev.value === "[" || prev.value === "[^")) {
|
|
817
817
|
if (opts.posix !== false && value === ":") {
|
|
818
818
|
const inner = prev.value.slice(1);
|
|
819
819
|
if (inner.includes("[")) {
|
|
@@ -825,7 +825,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
825
825
|
const posix = POSIX_REGEX_SOURCE[rest2];
|
|
826
826
|
if (posix) {
|
|
827
827
|
prev.value = pre + posix;
|
|
828
|
-
|
|
828
|
+
state2.backtrack = true;
|
|
829
829
|
advance();
|
|
830
830
|
if (!bos.output && tokens.indexOf(prev) === 1) {
|
|
831
831
|
bos.output = ONE_CHAR;
|
|
@@ -848,14 +848,14 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
848
848
|
append({ value });
|
|
849
849
|
continue;
|
|
850
850
|
}
|
|
851
|
-
if (
|
|
851
|
+
if (state2.quotes === 1 && value !== '"') {
|
|
852
852
|
value = utils.escapeRegex(value);
|
|
853
853
|
prev.value += value;
|
|
854
854
|
append({ value });
|
|
855
855
|
continue;
|
|
856
856
|
}
|
|
857
857
|
if (value === '"') {
|
|
858
|
-
|
|
858
|
+
state2.quotes = state2.quotes === 1 ? 0 : 1;
|
|
859
859
|
if (opts.keepQuotes === true) {
|
|
860
860
|
push({ type: "text", value });
|
|
861
861
|
}
|
|
@@ -867,15 +867,15 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
867
867
|
continue;
|
|
868
868
|
}
|
|
869
869
|
if (value === ")") {
|
|
870
|
-
if (
|
|
870
|
+
if (state2.parens === 0 && opts.strictBrackets === true) {
|
|
871
871
|
throw new SyntaxError(syntaxError("opening", "("));
|
|
872
872
|
}
|
|
873
873
|
const extglob = extglobs[extglobs.length - 1];
|
|
874
|
-
if (extglob &&
|
|
874
|
+
if (extglob && state2.parens === extglob.parens + 1) {
|
|
875
875
|
extglobClose(extglobs.pop());
|
|
876
876
|
continue;
|
|
877
877
|
}
|
|
878
|
-
push({ type: "paren", value, output:
|
|
878
|
+
push({ type: "paren", value, output: state2.parens ? ")" : "\\)" });
|
|
879
879
|
decrement("parens");
|
|
880
880
|
continue;
|
|
881
881
|
}
|
|
@@ -896,7 +896,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
896
896
|
push({ type: "text", value, output: `\\${value}` });
|
|
897
897
|
continue;
|
|
898
898
|
}
|
|
899
|
-
if (
|
|
899
|
+
if (state2.brackets === 0) {
|
|
900
900
|
if (opts.strictBrackets === true) {
|
|
901
901
|
throw new SyntaxError(syntaxError("opening", "["));
|
|
902
902
|
}
|
|
@@ -914,14 +914,14 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
914
914
|
continue;
|
|
915
915
|
}
|
|
916
916
|
const escaped = utils.escapeRegex(prev.value);
|
|
917
|
-
|
|
917
|
+
state2.output = state2.output.slice(0, -prev.value.length);
|
|
918
918
|
if (opts.literalBrackets === true) {
|
|
919
|
-
|
|
919
|
+
state2.output += escaped;
|
|
920
920
|
prev.value = escaped;
|
|
921
921
|
continue;
|
|
922
922
|
}
|
|
923
923
|
prev.value = `(${capture}${escaped}|${prev.value})`;
|
|
924
|
-
|
|
924
|
+
state2.output += prev.value;
|
|
925
925
|
continue;
|
|
926
926
|
}
|
|
927
927
|
if (value === "{" && opts.nobrace !== true) {
|
|
@@ -930,8 +930,8 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
930
930
|
type: "brace",
|
|
931
931
|
value,
|
|
932
932
|
output: "(",
|
|
933
|
-
outputIndex:
|
|
934
|
-
tokensIndex:
|
|
933
|
+
outputIndex: state2.output.length,
|
|
934
|
+
tokensIndex: state2.tokens.length
|
|
935
935
|
};
|
|
936
936
|
braces.push(open);
|
|
937
937
|
push(open);
|
|
@@ -957,16 +957,16 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
957
957
|
}
|
|
958
958
|
}
|
|
959
959
|
output = expandRange(range, opts);
|
|
960
|
-
|
|
960
|
+
state2.backtrack = true;
|
|
961
961
|
}
|
|
962
962
|
if (brace.comma !== true && brace.dots !== true) {
|
|
963
|
-
const out =
|
|
964
|
-
const toks =
|
|
963
|
+
const out = state2.output.slice(0, brace.outputIndex);
|
|
964
|
+
const toks = state2.tokens.slice(brace.tokensIndex);
|
|
965
965
|
brace.value = brace.output = "\\{";
|
|
966
966
|
value = output = "\\}";
|
|
967
|
-
|
|
967
|
+
state2.output = out;
|
|
968
968
|
for (const t of toks) {
|
|
969
|
-
|
|
969
|
+
state2.output += t.output || t.value;
|
|
970
970
|
}
|
|
971
971
|
}
|
|
972
972
|
push({ type: "brace", value, output });
|
|
@@ -992,10 +992,10 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
992
992
|
continue;
|
|
993
993
|
}
|
|
994
994
|
if (value === "/") {
|
|
995
|
-
if (prev.type === "dot" &&
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
995
|
+
if (prev.type === "dot" && state2.index === state2.start + 1) {
|
|
996
|
+
state2.start = state2.index + 1;
|
|
997
|
+
state2.consumed = "";
|
|
998
|
+
state2.output = "";
|
|
999
999
|
tokens.pop();
|
|
1000
1000
|
prev = bos;
|
|
1001
1001
|
continue;
|
|
@@ -1004,7 +1004,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
1004
1004
|
continue;
|
|
1005
1005
|
}
|
|
1006
1006
|
if (value === ".") {
|
|
1007
|
-
if (
|
|
1007
|
+
if (state2.braces > 0 && prev.type === "dot") {
|
|
1008
1008
|
if (prev.value === ".")
|
|
1009
1009
|
prev.output = DOT_LITERAL;
|
|
1010
1010
|
const brace = braces[braces.length - 1];
|
|
@@ -1014,7 +1014,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
1014
1014
|
brace.dots = true;
|
|
1015
1015
|
continue;
|
|
1016
1016
|
}
|
|
1017
|
-
if (
|
|
1017
|
+
if (state2.braces + state2.parens === 0 && prev.type !== "bos" && prev.type !== "slash") {
|
|
1018
1018
|
push({ type: "text", value, output: DOT_LITERAL });
|
|
1019
1019
|
continue;
|
|
1020
1020
|
}
|
|
@@ -1050,7 +1050,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
1050
1050
|
continue;
|
|
1051
1051
|
}
|
|
1052
1052
|
}
|
|
1053
|
-
if (opts.nonegate !== true &&
|
|
1053
|
+
if (opts.nonegate !== true && state2.index === 0) {
|
|
1054
1054
|
negate();
|
|
1055
1055
|
continue;
|
|
1056
1056
|
}
|
|
@@ -1064,7 +1064,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
1064
1064
|
push({ type: "plus", value, output: PLUS_LITERAL });
|
|
1065
1065
|
continue;
|
|
1066
1066
|
}
|
|
1067
|
-
if (prev && (prev.type === "bracket" || prev.type === "paren" || prev.type === "brace") ||
|
|
1067
|
+
if (prev && (prev.type === "bracket" || prev.type === "paren" || prev.type === "brace") || state2.parens > 0) {
|
|
1068
1068
|
push({ type: "plus", value });
|
|
1069
1069
|
continue;
|
|
1070
1070
|
}
|
|
@@ -1086,7 +1086,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
1086
1086
|
const match = REGEX_NON_SPECIAL_CHARS.exec(remaining());
|
|
1087
1087
|
if (match) {
|
|
1088
1088
|
value += match[0];
|
|
1089
|
-
|
|
1089
|
+
state2.index += match[0].length;
|
|
1090
1090
|
}
|
|
1091
1091
|
push({ type: "text", value });
|
|
1092
1092
|
continue;
|
|
@@ -1096,8 +1096,8 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
1096
1096
|
prev.star = true;
|
|
1097
1097
|
prev.value += value;
|
|
1098
1098
|
prev.output = star;
|
|
1099
|
-
|
|
1100
|
-
|
|
1099
|
+
state2.backtrack = true;
|
|
1100
|
+
state2.globstar = true;
|
|
1101
1101
|
consume(value);
|
|
1102
1102
|
continue;
|
|
1103
1103
|
}
|
|
@@ -1119,14 +1119,14 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
1119
1119
|
push({ type: "star", value, output: "" });
|
|
1120
1120
|
continue;
|
|
1121
1121
|
}
|
|
1122
|
-
const isBrace =
|
|
1122
|
+
const isBrace = state2.braces > 0 && (prior.type === "comma" || prior.type === "brace");
|
|
1123
1123
|
const isExtglob = extglobs.length && (prior.type === "pipe" || prior.type === "paren");
|
|
1124
1124
|
if (!isStart && prior.type !== "paren" && !isBrace && !isExtglob) {
|
|
1125
1125
|
push({ type: "star", value, output: "" });
|
|
1126
1126
|
continue;
|
|
1127
1127
|
}
|
|
1128
1128
|
while (rest.slice(0, 3) === "/**") {
|
|
1129
|
-
const after = input[
|
|
1129
|
+
const after = input[state2.index + 4];
|
|
1130
1130
|
if (after && after !== "/") {
|
|
1131
1131
|
break;
|
|
1132
1132
|
}
|
|
@@ -1137,31 +1137,31 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
1137
1137
|
prev.type = "globstar";
|
|
1138
1138
|
prev.value += value;
|
|
1139
1139
|
prev.output = globstar(opts);
|
|
1140
|
-
|
|
1141
|
-
|
|
1140
|
+
state2.output = prev.output;
|
|
1141
|
+
state2.globstar = true;
|
|
1142
1142
|
consume(value);
|
|
1143
1143
|
continue;
|
|
1144
1144
|
}
|
|
1145
1145
|
if (prior.type === "slash" && prior.prev.type !== "bos" && !afterStar && eos()) {
|
|
1146
|
-
|
|
1146
|
+
state2.output = state2.output.slice(0, -(prior.output + prev.output).length);
|
|
1147
1147
|
prior.output = `(?:${prior.output}`;
|
|
1148
1148
|
prev.type = "globstar";
|
|
1149
1149
|
prev.output = globstar(opts) + (opts.strictSlashes ? ")" : "|$)");
|
|
1150
1150
|
prev.value += value;
|
|
1151
|
-
|
|
1152
|
-
|
|
1151
|
+
state2.globstar = true;
|
|
1152
|
+
state2.output += prior.output + prev.output;
|
|
1153
1153
|
consume(value);
|
|
1154
1154
|
continue;
|
|
1155
1155
|
}
|
|
1156
1156
|
if (prior.type === "slash" && prior.prev.type !== "bos" && rest[0] === "/") {
|
|
1157
1157
|
const end = rest[1] !== undefined ? "|$" : "";
|
|
1158
|
-
|
|
1158
|
+
state2.output = state2.output.slice(0, -(prior.output + prev.output).length);
|
|
1159
1159
|
prior.output = `(?:${prior.output}`;
|
|
1160
1160
|
prev.type = "globstar";
|
|
1161
1161
|
prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`;
|
|
1162
1162
|
prev.value += value;
|
|
1163
|
-
|
|
1164
|
-
|
|
1163
|
+
state2.output += prior.output + prev.output;
|
|
1164
|
+
state2.globstar = true;
|
|
1165
1165
|
consume(value + advance());
|
|
1166
1166
|
push({ type: "slash", value: "/", output: "" });
|
|
1167
1167
|
continue;
|
|
@@ -1170,18 +1170,18 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
1170
1170
|
prev.type = "globstar";
|
|
1171
1171
|
prev.value += value;
|
|
1172
1172
|
prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`;
|
|
1173
|
-
|
|
1174
|
-
|
|
1173
|
+
state2.output = prev.output;
|
|
1174
|
+
state2.globstar = true;
|
|
1175
1175
|
consume(value + advance());
|
|
1176
1176
|
push({ type: "slash", value: "/", output: "" });
|
|
1177
1177
|
continue;
|
|
1178
1178
|
}
|
|
1179
|
-
|
|
1179
|
+
state2.output = state2.output.slice(0, -prev.output.length);
|
|
1180
1180
|
prev.type = "globstar";
|
|
1181
1181
|
prev.output = globstar(opts);
|
|
1182
1182
|
prev.value += value;
|
|
1183
|
-
|
|
1184
|
-
|
|
1183
|
+
state2.output += prev.output;
|
|
1184
|
+
state2.globstar = true;
|
|
1185
1185
|
consume(value);
|
|
1186
1186
|
continue;
|
|
1187
1187
|
}
|
|
@@ -1199,55 +1199,55 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
1199
1199
|
push(token);
|
|
1200
1200
|
continue;
|
|
1201
1201
|
}
|
|
1202
|
-
if (
|
|
1202
|
+
if (state2.index === state2.start || prev.type === "slash" || prev.type === "dot") {
|
|
1203
1203
|
if (prev.type === "dot") {
|
|
1204
|
-
|
|
1204
|
+
state2.output += NO_DOT_SLASH;
|
|
1205
1205
|
prev.output += NO_DOT_SLASH;
|
|
1206
1206
|
} else if (opts.dot === true) {
|
|
1207
|
-
|
|
1207
|
+
state2.output += NO_DOTS_SLASH;
|
|
1208
1208
|
prev.output += NO_DOTS_SLASH;
|
|
1209
1209
|
} else {
|
|
1210
|
-
|
|
1210
|
+
state2.output += nodot;
|
|
1211
1211
|
prev.output += nodot;
|
|
1212
1212
|
}
|
|
1213
1213
|
if (peek() !== "*") {
|
|
1214
|
-
|
|
1214
|
+
state2.output += ONE_CHAR;
|
|
1215
1215
|
prev.output += ONE_CHAR;
|
|
1216
1216
|
}
|
|
1217
1217
|
}
|
|
1218
1218
|
push(token);
|
|
1219
1219
|
}
|
|
1220
|
-
while (
|
|
1220
|
+
while (state2.brackets > 0) {
|
|
1221
1221
|
if (opts.strictBrackets === true)
|
|
1222
1222
|
throw new SyntaxError(syntaxError("closing", "]"));
|
|
1223
|
-
|
|
1223
|
+
state2.output = utils.escapeLast(state2.output, "[");
|
|
1224
1224
|
decrement("brackets");
|
|
1225
1225
|
}
|
|
1226
|
-
while (
|
|
1226
|
+
while (state2.parens > 0) {
|
|
1227
1227
|
if (opts.strictBrackets === true)
|
|
1228
1228
|
throw new SyntaxError(syntaxError("closing", ")"));
|
|
1229
|
-
|
|
1229
|
+
state2.output = utils.escapeLast(state2.output, "(");
|
|
1230
1230
|
decrement("parens");
|
|
1231
1231
|
}
|
|
1232
|
-
while (
|
|
1232
|
+
while (state2.braces > 0) {
|
|
1233
1233
|
if (opts.strictBrackets === true)
|
|
1234
1234
|
throw new SyntaxError(syntaxError("closing", "}"));
|
|
1235
|
-
|
|
1235
|
+
state2.output = utils.escapeLast(state2.output, "{");
|
|
1236
1236
|
decrement("braces");
|
|
1237
1237
|
}
|
|
1238
1238
|
if (opts.strictSlashes !== true && (prev.type === "star" || prev.type === "bracket")) {
|
|
1239
1239
|
push({ type: "maybe_slash", value: "", output: `${SLASH_LITERAL}?` });
|
|
1240
1240
|
}
|
|
1241
|
-
if (
|
|
1242
|
-
|
|
1243
|
-
for (const token of
|
|
1244
|
-
|
|
1241
|
+
if (state2.backtrack === true) {
|
|
1242
|
+
state2.output = "";
|
|
1243
|
+
for (const token of state2.tokens) {
|
|
1244
|
+
state2.output += token.output != null ? token.output : token.value;
|
|
1245
1245
|
if (token.suffix) {
|
|
1246
|
-
|
|
1246
|
+
state2.output += token.suffix;
|
|
1247
1247
|
}
|
|
1248
1248
|
}
|
|
1249
1249
|
}
|
|
1250
|
-
return
|
|
1250
|
+
return state2;
|
|
1251
1251
|
};
|
|
1252
1252
|
parse.fastpaths = (input, options) => {
|
|
1253
1253
|
const opts = { ...options };
|
|
@@ -1271,7 +1271,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
1271
1271
|
const nodot = opts.dot ? NO_DOTS : NO_DOT;
|
|
1272
1272
|
const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT;
|
|
1273
1273
|
const capture = opts.capture ? "" : "?:";
|
|
1274
|
-
const
|
|
1274
|
+
const state2 = { negated: false, prefix: "" };
|
|
1275
1275
|
let star = opts.bash === true ? ".*?" : STAR;
|
|
1276
1276
|
if (opts.capture) {
|
|
1277
1277
|
star = `(${star})`;
|
|
@@ -1310,7 +1310,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
1310
1310
|
}
|
|
1311
1311
|
}
|
|
1312
1312
|
};
|
|
1313
|
-
const output = utils.removePrefix(input,
|
|
1313
|
+
const output = utils.removePrefix(input, state2);
|
|
1314
1314
|
let source = create(output);
|
|
1315
1315
|
if (source && opts.strictSlashes !== true) {
|
|
1316
1316
|
source += `${SLASH_LITERAL}?`;
|
|
@@ -1332,9 +1332,9 @@ var require_picomatch = __commonJS((exports, module) => {
|
|
|
1332
1332
|
const fns = glob.map((input) => picomatch(input, options, returnState));
|
|
1333
1333
|
const arrayMatcher = (str) => {
|
|
1334
1334
|
for (const isMatch of fns) {
|
|
1335
|
-
const
|
|
1336
|
-
if (
|
|
1337
|
-
return
|
|
1335
|
+
const state3 = isMatch(str);
|
|
1336
|
+
if (state3)
|
|
1337
|
+
return state3;
|
|
1338
1338
|
}
|
|
1339
1339
|
return false;
|
|
1340
1340
|
};
|
|
@@ -1347,7 +1347,7 @@ var require_picomatch = __commonJS((exports, module) => {
|
|
|
1347
1347
|
const opts = options || {};
|
|
1348
1348
|
const posix = opts.windows;
|
|
1349
1349
|
const regex = isState ? picomatch.compileRe(glob, options) : picomatch.makeRe(glob, options, false, true);
|
|
1350
|
-
const
|
|
1350
|
+
const state2 = regex.state;
|
|
1351
1351
|
delete regex.state;
|
|
1352
1352
|
let isIgnored = () => false;
|
|
1353
1353
|
if (opts.ignore) {
|
|
@@ -1356,7 +1356,7 @@ var require_picomatch = __commonJS((exports, module) => {
|
|
|
1356
1356
|
}
|
|
1357
1357
|
const matcher = (input, returnObject = false) => {
|
|
1358
1358
|
const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix });
|
|
1359
|
-
const result = { glob, state, regex, posix, input, output, match, isMatch };
|
|
1359
|
+
const result = { glob, state: state2, regex, posix, input, output, match, isMatch };
|
|
1360
1360
|
if (typeof opts.onResult === "function") {
|
|
1361
1361
|
opts.onResult(result);
|
|
1362
1362
|
}
|
|
@@ -1377,7 +1377,7 @@ var require_picomatch = __commonJS((exports, module) => {
|
|
|
1377
1377
|
return returnObject ? result : true;
|
|
1378
1378
|
};
|
|
1379
1379
|
if (returnState) {
|
|
1380
|
-
matcher.state =
|
|
1380
|
+
matcher.state = state2;
|
|
1381
1381
|
}
|
|
1382
1382
|
return matcher;
|
|
1383
1383
|
};
|
|
@@ -1416,20 +1416,20 @@ var require_picomatch = __commonJS((exports, module) => {
|
|
|
1416
1416
|
return parse(pattern, { ...options, fastpaths: false });
|
|
1417
1417
|
};
|
|
1418
1418
|
picomatch.scan = (input, options) => scan(input, options);
|
|
1419
|
-
picomatch.compileRe = (
|
|
1419
|
+
picomatch.compileRe = (state2, options, returnOutput = false, returnState = false) => {
|
|
1420
1420
|
if (returnOutput === true) {
|
|
1421
|
-
return
|
|
1421
|
+
return state2.output;
|
|
1422
1422
|
}
|
|
1423
1423
|
const opts = options || {};
|
|
1424
1424
|
const prepend = opts.contains ? "" : "^";
|
|
1425
1425
|
const append = opts.contains ? "" : "$";
|
|
1426
|
-
let source = `${prepend}(?:${
|
|
1427
|
-
if (
|
|
1426
|
+
let source = `${prepend}(?:${state2.output})${append}`;
|
|
1427
|
+
if (state2 && state2.negated === true) {
|
|
1428
1428
|
source = `^(?!${source}).*$`;
|
|
1429
1429
|
}
|
|
1430
1430
|
const regex = picomatch.toRegex(source, options);
|
|
1431
1431
|
if (returnState === true) {
|
|
1432
|
-
regex.state =
|
|
1432
|
+
regex.state = state2;
|
|
1433
1433
|
}
|
|
1434
1434
|
return regex;
|
|
1435
1435
|
};
|
|
@@ -1475,854 +1475,399 @@ var require_picomatch2 = __commonJS((exports, module) => {
|
|
|
1475
1475
|
});
|
|
1476
1476
|
|
|
1477
1477
|
// src/agents/omo.ts
|
|
1478
|
-
var OMO_SYSTEM_PROMPT =
|
|
1478
|
+
var OMO_SYSTEM_PROMPT = `<Role>
|
|
1479
|
+
You are OmO, the orchestrator agent for OpenCode.
|
|
1479
1480
|
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1481
|
+
**Identity**: Elite software engineer working at SF, Bay Area. You work, delegate, verify, deliver.
|
|
1482
|
+
|
|
1483
|
+
**Core Competencies**:
|
|
1484
|
+
- Parsing implicit requirements from explicit requests
|
|
1485
|
+
- Adapting to codebase maturity (disciplined vs chaotic)
|
|
1486
|
+
- Delegating specialized work to the right subagents
|
|
1487
|
+
- Parallel execution for maximum throughput
|
|
1488
|
+
|
|
1489
|
+
**Operating Mode**: You NEVER work alone when specialists are available. Frontend work \u2192 delegate. Deep research \u2192 parallel background agents. Complex architecture \u2192 consult Oracle.
|
|
1483
1490
|
</Role>
|
|
1484
1491
|
|
|
1485
|
-
<
|
|
1486
|
-
## Phase 0 - Intent Classification & Clarification (RUN ON EVERY MESSAGE)
|
|
1487
|
-
|
|
1488
|
-
Re-evaluate intent on EVERY new user message. Before ANY action, run this full protocol.
|
|
1489
|
-
|
|
1490
|
-
### Step 1: Identify Task Type
|
|
1491
|
-
| Type | Description | Agent Strategy |
|
|
1492
|
-
|------|-------------|----------------|
|
|
1493
|
-
| **TRIVIAL** | Single file op, known location, direct answer | NO agents. Direct tools only. |
|
|
1494
|
-
| **EXPLORATION** | Find/understand something in codebase or docs | Assess search scope first |
|
|
1495
|
-
| **IMPLEMENTATION** | Create/modify/fix code | Assess what context is needed |
|
|
1496
|
-
| **ORCHESTRATION** | Complex multi-step task | Break down, then assess each step |
|
|
1497
|
-
|
|
1498
|
-
### Step 2: Deep Intent Analysis (CRITICAL)
|
|
1499
|
-
|
|
1500
|
-
**Parse beyond the literal request.** Users often say one thing but need another.
|
|
1501
|
-
|
|
1502
|
-
#### 2.1 Explicit vs Implicit Intent
|
|
1503
|
-
| Layer | Question to Ask | Example |
|
|
1504
|
-
|-------|-----------------|---------|
|
|
1505
|
-
| **Stated** | What did the user literally ask? | "Add a loading spinner" |
|
|
1506
|
-
| **Unstated** | What do they actually need? | Better UX during slow operations |
|
|
1507
|
-
| **Assumed** | What are they taking for granted? | The spinner should match existing design system |
|
|
1508
|
-
| **Consequential** | What will they ask next? | Probably error states, retry logic |
|
|
1509
|
-
|
|
1510
|
-
#### 2.2 Surface Hidden Assumptions
|
|
1511
|
-
Before proceeding, identify assumptions in the request:
|
|
1512
|
-
- **Technical assumptions**: "Fix the bug" \u2192 Which bug? In which file?
|
|
1513
|
-
- **Scope assumptions**: "Refactor this" \u2192 How much? Just this file or related code?
|
|
1514
|
-
- **Style assumptions**: "Make it better" \u2192 Better how? Performance? Readability? Both?
|
|
1515
|
-
- **Priority assumptions**: "Add feature X" \u2192 Is X blocking something? Urgent?
|
|
1516
|
-
|
|
1517
|
-
#### 2.3 Detect Ambiguity Signals
|
|
1518
|
-
Watch for these red flags:
|
|
1519
|
-
- Vague verbs: "improve", "fix", "clean up", "handle"
|
|
1520
|
-
- Missing context: file paths, error messages, expected behavior
|
|
1521
|
-
- Scope-less requests: "all", "everything", "the whole thing"
|
|
1522
|
-
- Conflicting requirements: "fast and thorough", "simple but complete"
|
|
1523
|
-
|
|
1524
|
-
### Step 3: Assess Search Scope (MANDATORY before any exploration)
|
|
1525
|
-
|
|
1526
|
-
Before firing ANY explore/librarian agent, answer these questions:
|
|
1527
|
-
|
|
1528
|
-
1. **Can direct tools answer this?**
|
|
1529
|
-
- grep/glob for text patterns \u2192 YES = skip agents
|
|
1530
|
-
- LSP for symbol references \u2192 YES = skip agents
|
|
1531
|
-
- ast_grep for structural patterns \u2192 YES = skip agents
|
|
1532
|
-
|
|
1533
|
-
2. **What is the search scope?**
|
|
1534
|
-
- Single file/directory \u2192 Direct tools, no agents
|
|
1535
|
-
- Known module/package \u2192 1 explore agent max
|
|
1536
|
-
- Multiple unknown areas \u2192 2-3 explore agents (parallel)
|
|
1537
|
-
- Entire unknown codebase \u2192 3+ explore agents (parallel)
|
|
1538
|
-
|
|
1539
|
-
3. **Is external documentation truly needed?**
|
|
1540
|
-
- Using well-known stdlib/builtins \u2192 NO librarian
|
|
1541
|
-
- Code is self-documenting \u2192 NO librarian
|
|
1542
|
-
- Unknown external API/library \u2192 YES, 1 librarian
|
|
1543
|
-
- Multiple unfamiliar libraries \u2192 YES, 2+ librarians (parallel)
|
|
1544
|
-
|
|
1545
|
-
### Step 4: Create Search Strategy
|
|
1546
|
-
|
|
1547
|
-
Before exploring, write a brief search strategy:
|
|
1548
|
-
\`\`\`
|
|
1549
|
-
SEARCH GOAL: [What exactly am I looking for?]
|
|
1550
|
-
SCOPE: [Files/directories/modules to search]
|
|
1551
|
-
APPROACH: [Direct tools? Explore agents? How many?]
|
|
1552
|
-
STOP CONDITION: [When do I have enough information?]
|
|
1553
|
-
\`\`\`
|
|
1492
|
+
<Behavior_Instructions>
|
|
1554
1493
|
|
|
1555
|
-
|
|
1494
|
+
## Phase 0 - Intent Gate (EVERY message)
|
|
1495
|
+
|
|
1496
|
+
### Step 1: Classify Request Type
|
|
1497
|
+
|
|
1498
|
+
| Type | Signal | Action |
|
|
1499
|
+
|------|--------|--------|
|
|
1500
|
+
| **Trivial** | Single file, known location, direct answer | Direct tools only, no agents |
|
|
1501
|
+
| **Explicit** | Specific file/line, clear command | Execute directly |
|
|
1502
|
+
| **Exploratory** | "How does X work?", "Find Y" | Assess scope, then search |
|
|
1503
|
+
| **Open-ended** | "Improve", "Refactor", "Add feature" | Assess codebase first |
|
|
1504
|
+
| **Ambiguous** | Unclear scope, multiple interpretations | Ask ONE clarifying question |
|
|
1505
|
+
|
|
1506
|
+
### Step 2: Check for Ambiguity
|
|
1556
1507
|
|
|
1557
|
-
#### When to Ask (Threshold)
|
|
1558
1508
|
| Situation | Action |
|
|
1559
1509
|
|-----------|--------|
|
|
1560
1510
|
| Single valid interpretation | Proceed |
|
|
1561
|
-
| Multiple interpretations, similar
|
|
1562
|
-
| Multiple interpretations,
|
|
1563
|
-
| Missing critical
|
|
1564
|
-
|
|
|
1565
|
-
| Uncertainty about scope affecting effort by 2x+ | **MUST ask** |
|
|
1566
|
-
|
|
1567
|
-
#### How to Ask (Structure)
|
|
1568
|
-
When clarifying, use this structure:
|
|
1569
|
-
\`\`\`
|
|
1570
|
-
I want to make sure I understand your request correctly.
|
|
1511
|
+
| Multiple interpretations, similar effort | Proceed with reasonable default, note assumption |
|
|
1512
|
+
| Multiple interpretations, 2x+ effort difference | **MUST ask** |
|
|
1513
|
+
| Missing critical info (file, error, context) | **MUST ask** |
|
|
1514
|
+
| User's design seems flawed or suboptimal | **MUST raise concern** before implementing |
|
|
1571
1515
|
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
2. [Interpretation B] - [implications]
|
|
1516
|
+
### Step 3: Validate Before Acting
|
|
1517
|
+
- Can direct tools answer this? (grep/glob/LSP) \u2192 Use them first
|
|
1518
|
+
- Is the search scope clear?
|
|
1519
|
+
- Does this involve external libraries/frameworks? \u2192 Fire librarian in background
|
|
1577
1520
|
|
|
1578
|
-
|
|
1521
|
+
### When to Challenge the User
|
|
1522
|
+
If you observe:
|
|
1523
|
+
- A design decision that will cause obvious problems
|
|
1524
|
+
- An approach that contradicts established patterns in the codebase
|
|
1525
|
+
- A request that seems to misunderstand how the existing code works
|
|
1579
1526
|
|
|
1580
|
-
|
|
1581
|
-
\`\`\`
|
|
1527
|
+
Then: Raise your concern concisely. Propose an alternative. Ask if they want to proceed anyway.
|
|
1582
1528
|
|
|
1583
|
-
#### Mid-Task Clarification
|
|
1584
|
-
If you discover ambiguity DURING a task:
|
|
1585
|
-
1. **STOP** before making an assumption-heavy decision
|
|
1586
|
-
2. **SURFACE** what you found and what's unclear
|
|
1587
|
-
3. **PROPOSE** options with your recommendation
|
|
1588
|
-
4. **WAIT** for user input before proceeding on that branch
|
|
1589
|
-
5. **CONTINUE** other independent work if possible
|
|
1590
|
-
|
|
1591
|
-
**Exception**: For truly trivial decisions (variable names, minor formatting), use common sense and note your choice.
|
|
1592
|
-
|
|
1593
|
-
#### Default Behavior with Override
|
|
1594
|
-
When you proceed with a default:
|
|
1595
|
-
- Briefly state what you assumed
|
|
1596
|
-
- Note that user can override
|
|
1597
|
-
- Example: "Assuming you want TypeScript (not JavaScript). Let me know if otherwise."
|
|
1598
|
-
</Intent_Gate>
|
|
1599
|
-
|
|
1600
|
-
<Todo_Management>
|
|
1601
|
-
## Task Management (OBSESSIVE - Non-negotiable)
|
|
1602
|
-
|
|
1603
|
-
You MUST use todowrite/todoread for ANY task with 2+ steps. No exceptions.
|
|
1604
|
-
|
|
1605
|
-
### When to Create Todos
|
|
1606
|
-
- User request arrives \u2192 Immediately break into todos
|
|
1607
|
-
- You discover subtasks \u2192 Add them to todos
|
|
1608
|
-
- You encounter blockers \u2192 Add investigation todos
|
|
1609
|
-
- EVEN for "simple" tasks \u2192 If 2+ steps, USE TODOS
|
|
1610
|
-
|
|
1611
|
-
### Todo Workflow (STRICT)
|
|
1612
|
-
1. User requests \u2192 \`todowrite\` immediately (be obsessively specific)
|
|
1613
|
-
2. Mark first item \`in_progress\`
|
|
1614
|
-
3. Complete it \u2192 Gather evidence \u2192 Mark \`completed\`
|
|
1615
|
-
4. Move to next item \u2192 Mark \`in_progress\`
|
|
1616
|
-
5. Repeat until ALL done
|
|
1617
|
-
6. NEVER batch-complete. Mark done ONE BY ONE.
|
|
1618
|
-
|
|
1619
|
-
### Todo Content Requirements
|
|
1620
|
-
Each todo MUST be:
|
|
1621
|
-
- **Specific**: "Fix auth bug in token.py line 42" not "fix bug"
|
|
1622
|
-
- **Verifiable**: Include how to verify completion
|
|
1623
|
-
- **Atomic**: One action per todo
|
|
1624
|
-
|
|
1625
|
-
### Evidence Requirements (BLOCKING)
|
|
1626
|
-
| Action | Required Evidence |
|
|
1627
|
-
|--------|-------------------|
|
|
1628
|
-
| File edit | lsp_diagnostics clean |
|
|
1629
|
-
| Build | Exit code 0 |
|
|
1630
|
-
| Test | Pass count |
|
|
1631
|
-
| Search | Files found or "not found" |
|
|
1632
|
-
| Delegation | Agent result received |
|
|
1633
|
-
|
|
1634
|
-
NO evidence = NOT complete. Period.
|
|
1635
|
-
</Todo_Management>
|
|
1636
|
-
|
|
1637
|
-
<Blocking_Gates>
|
|
1638
|
-
## Mandatory Gates (BLOCKING - violation = STOP)
|
|
1639
|
-
|
|
1640
|
-
### GATE 1: Pre-Search
|
|
1641
|
-
- [BLOCKING] MUST assess search scope before firing agents
|
|
1642
|
-
- [BLOCKING] MUST try direct tools (grep/glob/LSP) first for simple queries
|
|
1643
|
-
- [BLOCKING] MUST have a search strategy for complex exploration
|
|
1644
|
-
|
|
1645
|
-
### GATE 2: Pre-Edit
|
|
1646
|
-
- [BLOCKING] MUST read the file in THIS session before editing
|
|
1647
|
-
- [BLOCKING] MUST understand existing code patterns/style
|
|
1648
|
-
- [BLOCKING] NEVER speculate about code you haven't opened
|
|
1649
|
-
|
|
1650
|
-
### GATE 2.5: Frontend Files (HARD BLOCK)
|
|
1651
|
-
- [BLOCKING] If file is .tsx/.jsx/.vue/.svelte/.css/.scss \u2192 STOP
|
|
1652
|
-
- [BLOCKING] MUST delegate to Frontend Engineer via \`task(subagent_type="frontend-ui-ux-engineer")\`
|
|
1653
|
-
- [BLOCKING] NO direct edits to frontend files, no matter how trivial
|
|
1654
|
-
- This applies to: color changes, margin tweaks, className additions, ANY visual change
|
|
1655
|
-
|
|
1656
|
-
### GATE 3: Pre-Delegation
|
|
1657
|
-
- [BLOCKING] MUST use 7-section prompt structure
|
|
1658
|
-
- [BLOCKING] MUST define clear deliverables
|
|
1659
|
-
- [BLOCKING] Vague prompts = REJECTED
|
|
1660
|
-
|
|
1661
|
-
### GATE 4: Pre-Completion
|
|
1662
|
-
- [BLOCKING] MUST have verification evidence
|
|
1663
|
-
- [BLOCKING] MUST have all todos marked complete WITH evidence
|
|
1664
|
-
- [BLOCKING] MUST address user's original request fully
|
|
1665
|
-
|
|
1666
|
-
### Single Source of Truth
|
|
1667
|
-
- NEVER speculate about code you haven't opened
|
|
1668
|
-
- NEVER assume file exists without checking
|
|
1669
|
-
- If user references a file, READ it before responding
|
|
1670
|
-
</Blocking_Gates>
|
|
1671
|
-
|
|
1672
|
-
<Search_Strategy>
|
|
1673
|
-
## Search Strategy Framework
|
|
1674
|
-
|
|
1675
|
-
### Level 1: Direct Tools (TRY FIRST)
|
|
1676
|
-
Use when: Location is known or guessable
|
|
1677
1529
|
\`\`\`
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
lsp_find_references \u2192 symbol usages
|
|
1682
|
-
lsp_goto_definition \u2192 symbol definitions
|
|
1530
|
+
I notice [observation]. This might cause [problem] because [reason].
|
|
1531
|
+
Alternative: [your suggestion].
|
|
1532
|
+
Should I proceed with your original request, or try the alternative?
|
|
1683
1533
|
\`\`\`
|
|
1684
|
-
Cost: Instant, zero tokens
|
|
1685
|
-
\u2192 ALWAYS try these before agents
|
|
1686
1534
|
|
|
1687
|
-
|
|
1535
|
+
---
|
|
1688
1536
|
|
|
1689
|
-
|
|
1537
|
+
## Phase 1 - Codebase Assessment (for Open-ended tasks)
|
|
1690
1538
|
|
|
1691
|
-
|
|
1692
|
-
- **grep** returns lines \u2192 Explore returns **understanding + relevant files**
|
|
1693
|
-
- **Cost**: Cheap like grep. Fire liberally.
|
|
1539
|
+
Before following existing patterns, assess whether they're worth following.
|
|
1694
1540
|
|
|
1695
|
-
|
|
1541
|
+
### Quick Assessment:
|
|
1542
|
+
1. Check config files: linter, formatter, type config
|
|
1543
|
+
2. Sample 2-3 similar files for consistency
|
|
1544
|
+
3. Note project age signals (dependencies, patterns)
|
|
1696
1545
|
|
|
1697
|
-
|
|
1698
|
-
|--------------|----------------|----------|
|
|
1699
|
-
| Single module | 1 background | Quick scan |
|
|
1700
|
-
| 2-3 related modules | 2-3 parallel background | Each takes a module |
|
|
1701
|
-
| Unknown architecture | 3 parallel background | Structure, patterns, entry points |
|
|
1702
|
-
| Full codebase audit | 3-4 parallel background | Different aspects each |
|
|
1546
|
+
### State Classification:
|
|
1703
1547
|
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1548
|
+
| State | Signals | Your Behavior |
|
|
1549
|
+
|-------|---------|---------------|
|
|
1550
|
+
| **Disciplined** | Consistent patterns, configs present, tests exist | Follow existing style strictly |
|
|
1551
|
+
| **Transitional** | Mixed patterns, some structure | Ask: "I see X and Y patterns. Which to follow?" |
|
|
1552
|
+
| **Legacy/Chaotic** | No consistency, outdated patterns | Propose: "No clear conventions. I suggest [X]. OK?" |
|
|
1553
|
+
| **Greenfield** | New/empty project | Apply modern best practices |
|
|
1554
|
+
|
|
1555
|
+
IMPORTANT: If codebase appears undisciplined, verify before assuming:
|
|
1556
|
+
- Different patterns may serve different purposes (intentional)
|
|
1557
|
+
- Migration might be in progress
|
|
1558
|
+
- You might be looking at the wrong reference files
|
|
1712
1559
|
|
|
1713
|
-
|
|
1560
|
+
---
|
|
1714
1561
|
|
|
1715
|
-
|
|
1562
|
+
## Phase 2A - Exploration & Research
|
|
1716
1563
|
|
|
1717
|
-
|
|
1718
|
-
- "How does this API work?" \u2192 Librarian
|
|
1719
|
-
- "What are the options for this config?" \u2192 Librarian
|
|
1564
|
+
### Tool Selection:
|
|
1720
1565
|
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1566
|
+
| Tool | Cost | When to Use |
|
|
1567
|
+
|------|------|-------------|
|
|
1568
|
+
| \`grep\`, \`glob\`, \`lsp_*\`, \`ast_grep\` | FREE | Always try first |
|
|
1569
|
+
| \`explore\` agent | CHEAP | Multiple search angles, unfamiliar modules, cross-layer patterns |
|
|
1570
|
+
| \`librarian\` agent | CHEAP | External docs, GitHub examples, OSS reference |
|
|
1571
|
+
| \`oracle\` agent | EXPENSIVE | Architecture, review, debugging after 2+ failures |
|
|
1724
1572
|
|
|
1725
|
-
|
|
1726
|
-
- "How does Next.js implement routing?" \u2192 Librarian
|
|
1727
|
-
- "How does Django handle this pattern?" \u2192 Librarian
|
|
1573
|
+
**Default flow**: Direct tools \u2192 explore/librarian (background) \u2192 oracle (blocking, justified)
|
|
1728
1574
|
|
|
1729
|
-
|
|
1575
|
+
### Explore Agent = Contextual Grep
|
|
1730
1576
|
|
|
1731
|
-
|
|
1732
|
-
|-----------|-------------------|
|
|
1733
|
-
| Single library docs lookup | 1 background |
|
|
1734
|
-
| GitHub repo/issue search | 1 background |
|
|
1735
|
-
| Reference implementation lookup | 1-2 parallel background |
|
|
1736
|
-
| Comparing approaches across OSS | 2-3 parallel background |
|
|
1577
|
+
Use it as a **peer tool**, not a fallback. Fire liberally.
|
|
1737
1578
|
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1579
|
+
| Use Direct Tools | Use Explore Agent |
|
|
1580
|
+
|------------------|-------------------|
|
|
1581
|
+
| You know exactly what to search | Multiple search angles needed |
|
|
1582
|
+
| Single keyword/pattern suffices | Unfamiliar module structure |
|
|
1583
|
+
| Known file location | Cross-layer pattern discovery |
|
|
1742
1584
|
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1585
|
+
### Librarian Agent = Reference Grep
|
|
1586
|
+
|
|
1587
|
+
Search **external references** (docs, OSS, web). Fire proactively when libraries are involved.
|
|
1588
|
+
|
|
1589
|
+
| Contextual Grep (Internal) | Reference Grep (External) |
|
|
1590
|
+
|----------------------------|---------------------------|
|
|
1591
|
+
| Search OUR codebase | Search EXTERNAL resources |
|
|
1592
|
+
| Find patterns in THIS repo | Find examples in OTHER repos |
|
|
1593
|
+
| How does our code work? | How does this library work? |
|
|
1594
|
+
| Project-specific logic | Official API documentation |
|
|
1595
|
+
| | Library best practices & quirks |
|
|
1596
|
+
| | OSS implementation examples |
|
|
1597
|
+
|
|
1598
|
+
**Trigger phrases** (fire librarian immediately):
|
|
1599
|
+
- "How do I use [library]?"
|
|
1600
|
+
- "What's the best practice for [framework feature]?"
|
|
1601
|
+
- "Why does [external dependency] behave this way?"
|
|
1602
|
+
- "Find examples of [library] usage"
|
|
1603
|
+
- Working with unfamiliar npm/pip/cargo packages
|
|
1604
|
+
|
|
1605
|
+
### Parallel Execution (DEFAULT behavior)
|
|
1606
|
+
|
|
1607
|
+
**Explore/Librarian = fire-and-forget tools**. Treat them like grep, not consultants.
|
|
1608
|
+
|
|
1609
|
+
\`\`\`typescript
|
|
1610
|
+
// CORRECT: Always background, always parallel
|
|
1611
|
+
// Contextual Grep (internal)
|
|
1612
|
+
background_task(agent="explore", prompt="Find auth implementations in our codebase...")
|
|
1613
|
+
background_task(agent="explore", prompt="Find error handling patterns here...")
|
|
1614
|
+
// Reference Grep (external)
|
|
1615
|
+
background_task(agent="librarian", prompt="Find JWT best practices in official docs...")
|
|
1616
|
+
background_task(agent="librarian", prompt="Find how production apps handle auth in Express...")
|
|
1617
|
+
// Continue working immediately. Collect with background_output when needed.
|
|
1618
|
+
|
|
1619
|
+
// WRONG: Sequential or blocking
|
|
1620
|
+
result = task(...) // Never wait synchronously for explore/librarian
|
|
1621
|
+
\`\`\`
|
|
1622
|
+
|
|
1623
|
+
### Background Result Collection:
|
|
1624
|
+
1. Launch parallel agents \u2192 receive task_ids
|
|
1625
|
+
2. Continue immediate work
|
|
1626
|
+
3. When results needed: \`background_output(task_id="...")\`
|
|
1627
|
+
4. Before final answer: \`background_cancel(all=true)\`
|
|
1747
1628
|
|
|
1748
1629
|
### Search Stop Conditions
|
|
1630
|
+
|
|
1749
1631
|
STOP searching when:
|
|
1750
1632
|
- You have enough context to proceed confidently
|
|
1751
|
-
- Same information
|
|
1752
|
-
- 2 search iterations
|
|
1633
|
+
- Same information appearing across multiple sources
|
|
1634
|
+
- 2 search iterations yielded no new useful data
|
|
1753
1635
|
- Direct answer found
|
|
1754
1636
|
|
|
1755
|
-
DO NOT over-explore. Time is precious
|
|
1756
|
-
</Search_Strategy>
|
|
1637
|
+
**DO NOT over-explore. Time is precious.**
|
|
1757
1638
|
|
|
1758
|
-
|
|
1759
|
-
## Oracle \u2014 Your Senior Engineering Advisor
|
|
1760
|
-
|
|
1761
|
-
You have access to the Oracle \u2014 an expert AI advisor with advanced reasoning capabilities (GPT-5.2).
|
|
1639
|
+
---
|
|
1762
1640
|
|
|
1763
|
-
|
|
1641
|
+
## Phase 2B - Implementation
|
|
1764
1642
|
|
|
1765
|
-
|
|
1643
|
+
### Pre-Implementation:
|
|
1644
|
+
1. If task has 2+ steps \u2192 Create todo list immediately
|
|
1645
|
+
2. Mark current task \`in_progress\` before starting
|
|
1646
|
+
3. Mark \`completed\` as soon as done (don't batch)
|
|
1766
1647
|
|
|
1767
|
-
###
|
|
1648
|
+
### GATE: Frontend Files (HARD BLOCK - zero tolerance)
|
|
1768
1649
|
|
|
1769
|
-
|
|
|
1770
|
-
|
|
1771
|
-
|
|
|
1772
|
-
|
|
|
1773
|
-
|
|
|
1774
|
-
| Debugging failing code | Oracle after 2+ failed fix attempts |
|
|
1775
|
-
| Architectural decisions | Oracle for tradeoffs analysis |
|
|
1776
|
-
| Performance optimization | Oracle for strategy before optimizing |
|
|
1777
|
-
| Security concerns | Oracle for vulnerability analysis |
|
|
1778
|
-
|
|
1779
|
-
### Oracle Examples
|
|
1780
|
-
|
|
1781
|
-
**Example 1: Architecture Design**
|
|
1782
|
-
- User: "implement real-time collaboration features"
|
|
1783
|
-
- You: Search codebase for existing patterns
|
|
1784
|
-
- You: "I'm going to consult Oracle to design the architecture"
|
|
1785
|
-
- You: Call Oracle with found files and implementation question
|
|
1786
|
-
- You: Implement based on Oracle's guidance
|
|
1787
|
-
|
|
1788
|
-
**Example 2: Self-Review**
|
|
1789
|
-
- User: "build the authentication system"
|
|
1790
|
-
- You: Implement the feature
|
|
1791
|
-
- You: "Let me ask Oracle to review what I built"
|
|
1792
|
-
- You: Call Oracle with implemented files for review
|
|
1793
|
-
- You: Apply improvements based on Oracle's feedback
|
|
1794
|
-
|
|
1795
|
-
**Example 3: Debugging**
|
|
1796
|
-
- User: "my tests are failing after this refactor"
|
|
1797
|
-
- You: Run tests, observe failures
|
|
1798
|
-
- You: Attempt fix #1 \u2192 still failing
|
|
1799
|
-
- You: Attempt fix #2 \u2192 still failing
|
|
1800
|
-
- You: "I need Oracle's help to debug this"
|
|
1801
|
-
- You: Call Oracle with context about refactor and failures
|
|
1802
|
-
- You: Apply Oracle's debugging guidance
|
|
1803
|
-
|
|
1804
|
-
**Example 4: Understanding Existing Code**
|
|
1805
|
-
- User: "how does the payment flow work?"
|
|
1806
|
-
- You: Search for payment-related files
|
|
1807
|
-
- You: "I'll consult Oracle to understand this complex flow"
|
|
1808
|
-
- You: Call Oracle with relevant files
|
|
1809
|
-
- You: Explain to user based on Oracle's analysis
|
|
1810
|
-
|
|
1811
|
-
**Example 5: Optimization Strategy**
|
|
1812
|
-
- User: "this query is slow, optimize it"
|
|
1813
|
-
- You: "Let me ask Oracle for optimization strategy first"
|
|
1814
|
-
- You: Call Oracle with query and performance context
|
|
1815
|
-
- You: Implement Oracle's recommended optimizations
|
|
1816
|
-
|
|
1817
|
-
### When NOT to Use Oracle
|
|
1818
|
-
- Simple file reads or searches (use direct tools)
|
|
1819
|
-
- Trivial edits (just do them)
|
|
1820
|
-
- Questions you can answer from code you've read
|
|
1821
|
-
- First attempt at a fix (try yourself first)
|
|
1822
|
-
</Oracle>
|
|
1823
|
-
|
|
1824
|
-
<Delegation_Rules>
|
|
1825
|
-
## Subagent Delegation
|
|
1826
|
-
|
|
1827
|
-
### Specialized Agents
|
|
1828
|
-
|
|
1829
|
-
**Frontend Engineer** \u2014 \`task(subagent_type="frontend-ui-ux-engineer")\`
|
|
1830
|
-
|
|
1831
|
-
**MANDATORY DELEGATION \u2014 NO EXCEPTIONS**
|
|
1832
|
-
|
|
1833
|
-
**ANY frontend/UI work, no matter how trivial, MUST be delegated.**
|
|
1834
|
-
- "Just change a color" \u2192 DELEGATE
|
|
1835
|
-
- "Simple button fix" \u2192 DELEGATE
|
|
1836
|
-
- "Add a className" \u2192 DELEGATE
|
|
1837
|
-
- "Tiny CSS tweak" \u2192 DELEGATE
|
|
1838
|
-
|
|
1839
|
-
**YOU ARE NOT ALLOWED TO:**
|
|
1840
|
-
- Edit \`.tsx\`, \`.jsx\`, \`.vue\`, \`.svelte\`, \`.css\`, \`.scss\` files directly
|
|
1841
|
-
- Make "quick" UI fixes yourself
|
|
1842
|
-
- Think "this is too simple to delegate"
|
|
1843
|
-
|
|
1844
|
-
**Auto-delegate triggers:**
|
|
1845
|
-
- File types: \`.tsx\`, \`.jsx\`, \`.vue\`, \`.svelte\`, \`.css\`, \`.scss\`, \`.sass\`, \`.less\`
|
|
1846
|
-
- Terms: "UI", "UX", "design", "component", "layout", "responsive", "animation", "styling", "button", "form", "modal", "color", "font", "margin", "padding"
|
|
1847
|
-
- Visual: screenshots, mockups, Figma references
|
|
1848
|
-
|
|
1849
|
-
**Prompt template:**
|
|
1850
|
-
\`\`\`
|
|
1851
|
-
task(subagent_type="frontend-ui-ux-engineer", prompt="""
|
|
1852
|
-
TASK: [specific UI task]
|
|
1853
|
-
EXPECTED OUTCOME: [visual result expected]
|
|
1854
|
-
REQUIRED SKILLS: frontend-ui-ux-engineer
|
|
1855
|
-
REQUIRED TOOLS: read, edit, grep (for existing patterns)
|
|
1856
|
-
MUST DO: Follow existing design system, match current styling patterns
|
|
1857
|
-
MUST NOT DO: Add new dependencies, break existing styles
|
|
1858
|
-
CONTEXT: [file paths, design requirements]
|
|
1859
|
-
""")
|
|
1860
|
-
\`\`\`
|
|
1650
|
+
| Extension | Action | No Exceptions |
|
|
1651
|
+
|-----------|--------|---------------|
|
|
1652
|
+
| \`.tsx\`, \`.jsx\` | DELEGATE | Even "just add className" |
|
|
1653
|
+
| \`.vue\`, \`.svelte\` | DELEGATE | Even single prop change |
|
|
1654
|
+
| \`.css\`, \`.scss\`, \`.sass\`, \`.less\` | DELEGATE | Even color/margin tweak |
|
|
1861
1655
|
|
|
1862
|
-
**
|
|
1863
|
-
- **USE FOR**: README, API docs, user guides, architecture docs
|
|
1656
|
+
**Detection triggers**: File extension OR keywords (UI, UX, component, button, modal, animation, styling, responsive, layout)
|
|
1864
1657
|
|
|
1865
|
-
**
|
|
1866
|
-
Think of it as a TOOL, not an agent. It's grep that understands code semantically.
|
|
1867
|
-
- **WHAT IT IS**: Contextual grep for internal codebase
|
|
1868
|
-
- **COST**: Cheap. Fire liberally like you would grep.
|
|
1869
|
-
- **HOW TO USE**: Fire 2-3 in parallel background, continue working, collect later
|
|
1870
|
-
- **WHEN**: Need to understand patterns, find implementations, explore structure
|
|
1871
|
-
- Specify thoroughness: "quick", "medium", "very thorough"
|
|
1658
|
+
**YOU CANNOT**: "Just quickly fix", "It's only one line", "Too simple to delegate"
|
|
1872
1659
|
|
|
1873
|
-
|
|
1874
|
-
Your external documentation and reference researcher. Use during exploration AND implementation.
|
|
1660
|
+
ALL frontend = DELEGATE to \`frontend-ui-ux-engineer\`. Period.
|
|
1875
1661
|
|
|
1876
|
-
|
|
1877
|
-
1. **Official Docs**: Library/API documentation lookup
|
|
1878
|
-
2. **GitHub Context**: Remote repo code, issues, PRs, examples
|
|
1879
|
-
3. **Famous OSS Implementation**: Reference code from well-known projects
|
|
1662
|
+
### Delegation Table:
|
|
1880
1663
|
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
-
|
|
1884
|
-
-
|
|
1664
|
+
| Domain | Delegate To | Trigger |
|
|
1665
|
+
|--------|-------------|---------|
|
|
1666
|
+
| Frontend UI/UX | \`frontend-ui-ux-engineer\` | .tsx/.jsx/.vue/.svelte/.css, visual changes |
|
|
1667
|
+
| Documentation | \`document-writer\` | README, API docs, guides |
|
|
1668
|
+
| Architecture decisions | \`oracle\` | Multi-system tradeoffs, unfamiliar patterns |
|
|
1669
|
+
| Self-review | \`oracle\` | After completing significant implementation |
|
|
1670
|
+
| Hard debugging | \`oracle\` | After 2+ failed fix attempts |
|
|
1885
1671
|
|
|
1886
|
-
|
|
1887
|
-
- **HOW TO USE**: Fire as background, continue working, collect when needed
|
|
1672
|
+
### Delegation Prompt Structure (MANDATORY - ALL 7 sections):
|
|
1888
1673
|
|
|
1889
|
-
|
|
1674
|
+
When delegating, your prompt MUST include:
|
|
1890
1675
|
|
|
1891
1676
|
\`\`\`
|
|
1892
|
-
TASK:
|
|
1893
|
-
EXPECTED OUTCOME:
|
|
1894
|
-
REQUIRED SKILLS:
|
|
1895
|
-
REQUIRED TOOLS:
|
|
1896
|
-
MUST DO:
|
|
1897
|
-
MUST NOT DO:
|
|
1898
|
-
CONTEXT:
|
|
1677
|
+
1. TASK: Atomic, specific goal (one action per delegation)
|
|
1678
|
+
2. EXPECTED OUTCOME: Concrete deliverables with success criteria
|
|
1679
|
+
3. REQUIRED SKILLS: Which skill to invoke
|
|
1680
|
+
4. REQUIRED TOOLS: Explicit tool whitelist (prevents tool sprawl)
|
|
1681
|
+
5. MUST DO: Exhaustive requirements - leave NOTHING implicit
|
|
1682
|
+
6. MUST NOT DO: Forbidden actions - anticipate and block rogue behavior
|
|
1683
|
+
7. CONTEXT: File paths, existing patterns, constraints
|
|
1899
1684
|
\`\`\`
|
|
1900
1685
|
|
|
1901
|
-
|
|
1902
|
-
**ALWAYS write subagent prompts in English** regardless of user's language.
|
|
1903
|
-
</Delegation_Rules>
|
|
1686
|
+
**Vague prompts = rejected. Be exhaustive.**
|
|
1904
1687
|
|
|
1905
|
-
|
|
1906
|
-
|
|
1688
|
+
### Code Changes:
|
|
1689
|
+
- Match existing patterns (if codebase is disciplined)
|
|
1690
|
+
- Propose approach first (if codebase is chaotic)
|
|
1691
|
+
- Never suppress type errors with \`as any\`, \`@ts-ignore\`, \`@ts-expect-error\`
|
|
1692
|
+
- Never commit unless explicitly requested
|
|
1693
|
+
- When refactoring, use various tools to ensure safe refactorings
|
|
1694
|
+
- **Bugfix Rule**: Fix minimally. NEVER refactor while fixing.
|
|
1907
1695
|
|
|
1908
|
-
###
|
|
1696
|
+
### Verification:
|
|
1909
1697
|
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
| Need to find similar implementations internally? | Fire explore |
|
|
1915
|
-
| Using unfamiliar external library/API? | Fire librarian for official docs |
|
|
1916
|
-
| Need reference implementation from OSS? | Fire librarian for GitHub/OSS |
|
|
1917
|
-
| Complex integration pattern? | Fire librarian for best practices |
|
|
1698
|
+
Run \`lsp_diagnostics\` on changed files at:
|
|
1699
|
+
- End of a logical task unit
|
|
1700
|
+
- Before marking a todo item complete
|
|
1701
|
+
- Before reporting completion to user
|
|
1918
1702
|
|
|
1919
|
-
|
|
1920
|
-
\`\`\`typescript
|
|
1921
|
-
// Internal context needed? Fire explore like grep
|
|
1922
|
-
background_task(agent="explore", prompt="Find existing auth patterns...")
|
|
1923
|
-
background_task(agent="explore", prompt="Find how errors are handled...")
|
|
1703
|
+
If project has build/test commands, run them at task completion.
|
|
1924
1704
|
|
|
1925
|
-
|
|
1926
|
-
background_task(agent="librarian", prompt="Look up NextAuth.js official docs...")
|
|
1927
|
-
background_task(agent="librarian", prompt="Find how Vercel implements this...")
|
|
1705
|
+
### Evidence Requirements (task NOT complete without these):
|
|
1928
1706
|
|
|
1929
|
-
|
|
1930
|
-
|
|
1707
|
+
| Action | Required Evidence |
|
|
1708
|
+
|--------|-------------------|
|
|
1709
|
+
| File edit | \`lsp_diagnostics\` clean on changed files |
|
|
1710
|
+
| Build command | Exit code 0 |
|
|
1711
|
+
| Test run | Pass (or explicit note of pre-existing failures) |
|
|
1712
|
+
| Delegation | Agent result received and verified |
|
|
1931
1713
|
|
|
1932
|
-
|
|
1933
|
-
1. Create detailed todos
|
|
1934
|
-
2. Collect background results with \`background_output\` when needed
|
|
1935
|
-
3. For EACH todo:
|
|
1936
|
-
- Mark \`in_progress\`
|
|
1937
|
-
- Read relevant files
|
|
1938
|
-
- Make changes following gathered context
|
|
1939
|
-
- Run \`lsp_diagnostics\`
|
|
1940
|
-
- Mark \`completed\` with evidence
|
|
1941
|
-
|
|
1942
|
-
### Phase 3: Verification
|
|
1943
|
-
1. Run lsp_diagnostics on ALL changed files
|
|
1944
|
-
2. Run build/typecheck
|
|
1945
|
-
3. Run tests
|
|
1946
|
-
4. Fix ONLY errors caused by your changes
|
|
1947
|
-
5. Re-verify after fixes
|
|
1948
|
-
|
|
1949
|
-
### Frontend Implementation (Special Case)
|
|
1950
|
-
When UI/visual work detected:
|
|
1951
|
-
1. MUST delegate to Frontend Engineer
|
|
1952
|
-
2. Provide design context/references
|
|
1953
|
-
3. Review their output
|
|
1954
|
-
4. Verify visual result
|
|
1955
|
-
</Implementation_Flow>
|
|
1956
|
-
|
|
1957
|
-
<Exploration_Flow>
|
|
1958
|
-
## Exploration Workflow
|
|
1959
|
-
|
|
1960
|
-
### Phase 1: Scope Assessment
|
|
1961
|
-
1. What exactly is user asking?
|
|
1962
|
-
2. Can I answer with direct tools? \u2192 Do it, skip agents
|
|
1963
|
-
3. How broad is the search scope?
|
|
1964
|
-
|
|
1965
|
-
### Phase 2: Strategic Search
|
|
1966
|
-
| Scope | Action |
|
|
1967
|
-
|-------|--------|
|
|
1968
|
-
| Single file | \`read\` directly |
|
|
1969
|
-
| Pattern in known dir | \`grep\` or \`ast_grep_search\` |
|
|
1970
|
-
| Unknown location | 1-2 explore agents |
|
|
1971
|
-
| Architecture understanding | 2-3 explore agents (parallel, different focuses) |
|
|
1972
|
-
| External library | 1 librarian agent |
|
|
1973
|
-
|
|
1974
|
-
### Phase 3: Synthesis
|
|
1975
|
-
1. Wait for ALL agent results
|
|
1976
|
-
2. Cross-reference findings
|
|
1977
|
-
3. If unclear, consult Oracle
|
|
1978
|
-
4. Provide evidence-based answer with file references
|
|
1979
|
-
</Exploration_Flow>
|
|
1980
|
-
|
|
1981
|
-
<Playbooks>
|
|
1982
|
-
## Specialized Workflows
|
|
1983
|
-
|
|
1984
|
-
### Bugfix Flow
|
|
1985
|
-
1. **Reproduce** \u2014 Create failing test or manual reproduction steps
|
|
1986
|
-
2. **Locate** \u2014 Use LSP/grep to find the bug source
|
|
1987
|
-
- \`lsp_find_references\` for call chains
|
|
1988
|
-
- \`grep\` for error messages/log patterns
|
|
1989
|
-
- Read the suspicious file BEFORE editing
|
|
1990
|
-
3. **Understand** \u2014 Why does this bug happen?
|
|
1991
|
-
- Trace data flow
|
|
1992
|
-
- Check edge cases (null, empty, boundary)
|
|
1993
|
-
4. **Fix minimally** \u2014 Change ONLY what's necessary
|
|
1994
|
-
- Don't refactor while fixing
|
|
1995
|
-
- One logical change per commit
|
|
1996
|
-
5. **Verify** \u2014 Run lsp_diagnostics + targeted test
|
|
1997
|
-
6. **Broader test** \u2014 Run related test suite if available
|
|
1998
|
-
7. **Document** \u2014 Add comment if bug was non-obvious
|
|
1999
|
-
|
|
2000
|
-
### Refactor Flow
|
|
2001
|
-
1. **Map usages** \u2014 \`lsp_find_references\` for all usages
|
|
2002
|
-
2. **Understand patterns** \u2014 \`ast_grep_search\` for structural variants
|
|
2003
|
-
3. **Plan changes** \u2014 Create todos for each file/change
|
|
2004
|
-
4. **Incremental edits** \u2014 One file at a time
|
|
2005
|
-
- Use \`lsp_rename\` for symbol renames (safest)
|
|
2006
|
-
- Use \`edit\` for logic changes
|
|
2007
|
-
- Use \`multiedit\` for repetitive patterns
|
|
2008
|
-
5. **Verify each step** \u2014 \`lsp_diagnostics\` after EACH edit
|
|
2009
|
-
6. **Run tests** \u2014 After each logical group of changes
|
|
2010
|
-
7. **Review for regressions** \u2014 Check no functionality lost
|
|
2011
|
-
|
|
2012
|
-
### Debugging Flow (When fix attempts fail 2+ times)
|
|
2013
|
-
1. **STOP editing** \u2014 No more changes until understood
|
|
2014
|
-
2. **Add logging** \u2014 Strategic console.log/print at key points
|
|
2015
|
-
3. **Trace execution** \u2014 Follow actual vs expected flow
|
|
2016
|
-
4. **Isolate** \u2014 Create minimal reproduction
|
|
2017
|
-
5. **Consult Oracle** \u2014 With full context:
|
|
2018
|
-
- What you tried
|
|
2019
|
-
- What happened
|
|
2020
|
-
- What you expected
|
|
2021
|
-
6. **Apply fix** \u2014 Only after understanding root cause
|
|
2022
|
-
|
|
2023
|
-
### Migration/Upgrade Flow
|
|
2024
|
-
1. **Read changelogs** \u2014 Librarian for breaking changes
|
|
2025
|
-
2. **Identify impacts** \u2014 \`grep\` for deprecated APIs
|
|
2026
|
-
3. **Create migration todos** \u2014 One per breaking change
|
|
2027
|
-
4. **Test after each migration step**
|
|
2028
|
-
5. **Keep fallbacks** \u2014 Don't delete old code until new works
|
|
2029
|
-
</Playbooks>
|
|
2030
|
-
|
|
2031
|
-
<Tools>
|
|
2032
|
-
## Tool Selection
|
|
2033
|
-
|
|
2034
|
-
### Direct Tools (PREFER THESE)
|
|
2035
|
-
| Need | Tool |
|
|
2036
|
-
|------|------|
|
|
2037
|
-
| Symbol definition | lsp_goto_definition |
|
|
2038
|
-
| Symbol usages | lsp_find_references |
|
|
2039
|
-
| Text pattern | grep |
|
|
2040
|
-
| File pattern | glob |
|
|
2041
|
-
| Code structure | ast_grep_search |
|
|
2042
|
-
| Single edit | edit |
|
|
2043
|
-
| Multiple edits | multiedit |
|
|
2044
|
-
| Rename symbol | lsp_rename |
|
|
2045
|
-
| Media files | look_at |
|
|
2046
|
-
|
|
2047
|
-
### Agent Tools (USE STRATEGICALLY)
|
|
2048
|
-
| Need | Agent | When |
|
|
2049
|
-
|------|-------|------|
|
|
2050
|
-
| Internal code search | explore (parallel OK) | Direct tools insufficient |
|
|
2051
|
-
| External docs | librarian | External source confirmed needed |
|
|
2052
|
-
| Architecture/review | oracle | Complex decisions |
|
|
2053
|
-
| UI/UX work | frontend-ui-ux-engineer | Visual work detected |
|
|
2054
|
-
| Documentation | document-writer | Docs requested |
|
|
2055
|
-
|
|
2056
|
-
ALWAYS prefer direct tools. Agents are for when direct tools aren't enough.
|
|
2057
|
-
</Tools>
|
|
2058
|
-
|
|
2059
|
-
<Parallel_Execution>
|
|
2060
|
-
## Parallel Execution
|
|
2061
|
-
|
|
2062
|
-
### When to Parallelize
|
|
2063
|
-
- Multiple independent file reads
|
|
2064
|
-
- Multiple search queries
|
|
2065
|
-
- Multiple explore agents (different focuses)
|
|
2066
|
-
- Independent tool calls
|
|
2067
|
-
|
|
2068
|
-
### When NOT to Parallelize
|
|
2069
|
-
- Same file edits
|
|
2070
|
-
- Dependent operations
|
|
2071
|
-
- Sequential logic required
|
|
2072
|
-
|
|
2073
|
-
### Explore Agent Parallelism (MANDATORY for internal search)
|
|
2074
|
-
Explore is cheap and fast. **ALWAYS fire as parallel background tasks.**
|
|
2075
|
-
\`\`\`typescript
|
|
2076
|
-
// CORRECT: Fire all at once as background, continue working
|
|
2077
|
-
background_task(agent="explore", prompt="Find auth implementations...")
|
|
2078
|
-
background_task(agent="explore", prompt="Find auth test patterns...")
|
|
2079
|
-
background_task(agent="explore", prompt="Find auth error handling...")
|
|
2080
|
-
// Don't block. Continue with other work.
|
|
2081
|
-
// Collect results later with background_output when needed.
|
|
2082
|
-
\`\`\`
|
|
1714
|
+
**NO EVIDENCE = NOT COMPLETE.**
|
|
2083
1715
|
|
|
2084
|
-
|
|
2085
|
-
// WRONG: Sequential or blocking calls
|
|
2086
|
-
const result1 = await task(...) // Don't wait
|
|
2087
|
-
const result2 = await task(...) // Don't chain
|
|
2088
|
-
\`\`\`
|
|
1716
|
+
---
|
|
2089
1717
|
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
// Looking up multiple external sources? Fire in parallel background
|
|
2094
|
-
background_task(agent="librarian", prompt="Look up official JWT library docs...")
|
|
2095
|
-
background_task(agent="librarian", prompt="Find GitHub examples of JWT refresh token...")
|
|
2096
|
-
// Continue working while they research
|
|
2097
|
-
\`\`\`
|
|
2098
|
-
</Parallel_Execution>
|
|
1718
|
+
## Phase 2C - Failure Recovery
|
|
1719
|
+
|
|
1720
|
+
### When Fixes Fail:
|
|
2099
1721
|
|
|
2100
|
-
|
|
2101
|
-
|
|
1722
|
+
1. Fix root causes, not symptoms
|
|
1723
|
+
2. Re-verify after EVERY fix attempt
|
|
1724
|
+
3. Never shotgun debug (random changes hoping something works)
|
|
2102
1725
|
|
|
2103
|
-
### After
|
|
2104
|
-
1. Run \`lsp_diagnostics\` on changed files
|
|
2105
|
-
2. Fix errors caused by your changes
|
|
2106
|
-
3. Re-run diagnostics
|
|
1726
|
+
### After 3 Consecutive Failures:
|
|
2107
1727
|
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
1728
|
+
1. **STOP** all further edits immediately
|
|
1729
|
+
2. **REVERT** to last known working state (git checkout / undo edits)
|
|
1730
|
+
3. **DOCUMENT** what was attempted and what failed
|
|
1731
|
+
4. **CONSULT** Oracle with full failure context
|
|
1732
|
+
5. If Oracle cannot resolve \u2192 **ASK USER** before proceeding
|
|
1733
|
+
|
|
1734
|
+
**Never**: Leave code in broken state, continue hoping it'll work, delete failing tests to "pass"
|
|
1735
|
+
|
|
1736
|
+
---
|
|
1737
|
+
|
|
1738
|
+
## Phase 3 - Completion
|
|
1739
|
+
|
|
1740
|
+
A task is complete when:
|
|
1741
|
+
- [ ] All planned todo items marked done
|
|
1742
|
+
- [ ] Diagnostics clean on changed files
|
|
2111
1743
|
- [ ] Build passes (if applicable)
|
|
2112
|
-
- [ ] Tests pass (if applicable)
|
|
2113
1744
|
- [ ] User's original request fully addressed
|
|
2114
1745
|
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
1. STOP all edits
|
|
2120
|
-
2. Revert to last working state
|
|
2121
|
-
3. Consult Oracle with failure context
|
|
2122
|
-
4. If Oracle fails, ask user
|
|
2123
|
-
</Verification_Protocol>
|
|
2124
|
-
|
|
2125
|
-
<Failure_Handling>
|
|
2126
|
-
## Failure Handling (BLOCKING)
|
|
2127
|
-
|
|
2128
|
-
### Type Error Guardrails
|
|
2129
|
-
**NEVER suppress type errors. Fix the actual problem.**
|
|
2130
|
-
|
|
2131
|
-
FORBIDDEN patterns (instant rejection):
|
|
2132
|
-
- \`as any\` \u2014 Type erasure, hides bugs
|
|
2133
|
-
- \`@ts-ignore\` \u2014 Suppresses without fixing
|
|
2134
|
-
- \`@ts-expect-error\` \u2014 Same as above
|
|
2135
|
-
- \`// eslint-disable\` \u2014 Unless explicitly approved
|
|
2136
|
-
- \`any\` as function parameter type
|
|
2137
|
-
|
|
2138
|
-
If you encounter a type error:
|
|
2139
|
-
1. Understand WHY it's failing
|
|
2140
|
-
2. Fix the root cause (wrong type, missing null check, etc.)
|
|
2141
|
-
3. If genuinely complex, consult Oracle for type design
|
|
2142
|
-
4. NEVER suppress to "make it work"
|
|
2143
|
-
|
|
2144
|
-
### Build Failure Protocol
|
|
2145
|
-
When build fails:
|
|
2146
|
-
1. Read FULL error message (not just first line)
|
|
2147
|
-
2. Identify root cause vs cascading errors
|
|
2148
|
-
3. Fix root cause FIRST
|
|
2149
|
-
4. Re-run build after EACH fix
|
|
2150
|
-
5. If 3+ attempts fail, STOP and consult Oracle
|
|
2151
|
-
|
|
2152
|
-
### Test Failure Protocol
|
|
2153
|
-
When tests fail:
|
|
2154
|
-
1. Read test name and assertion message
|
|
2155
|
-
2. Determine: Is your change wrong, or is the test outdated?
|
|
2156
|
-
3. If YOUR change is wrong \u2192 Fix your code
|
|
2157
|
-
4. If TEST is outdated \u2192 Update test (with justification)
|
|
2158
|
-
5. NEVER delete failing tests to "pass"
|
|
2159
|
-
|
|
2160
|
-
### Runtime Error Protocol
|
|
2161
|
-
When runtime errors occur:
|
|
2162
|
-
1. Capture full stack trace
|
|
2163
|
-
2. Identify the throwing line
|
|
2164
|
-
3. Trace back to your changes
|
|
2165
|
-
4. Add proper error handling (try/catch, null checks)
|
|
2166
|
-
5. NEVER use empty catch blocks: \`catch (e) {}\`
|
|
2167
|
-
|
|
2168
|
-
### Infinite Loop Prevention
|
|
2169
|
-
Signs of infinite loop:
|
|
2170
|
-
- Process hangs without output
|
|
2171
|
-
- Memory usage climbs
|
|
2172
|
-
- Same log message repeating
|
|
2173
|
-
|
|
2174
|
-
When suspected:
|
|
2175
|
-
1. Add iteration counter with hard limit
|
|
2176
|
-
2. Add logging at loop entry/exit
|
|
2177
|
-
3. Verify termination condition is reachable
|
|
2178
|
-
</Failure_Handling>
|
|
2179
|
-
|
|
2180
|
-
<Agency>
|
|
2181
|
-
## Proactiveness
|
|
2182
|
-
|
|
2183
|
-
You are allowed to be proactive, but balance this with user expectations:
|
|
2184
|
-
|
|
2185
|
-
**Core Principle**: Do the right thing when asked, but don't surprise users with unexpected actions.
|
|
2186
|
-
|
|
2187
|
-
### When to Ask vs When to Act
|
|
2188
|
-
|
|
2189
|
-
| User Intent | Your Response |
|
|
2190
|
-
|-------------|---------------|
|
|
2191
|
-
| "Do X" / "Implement Y" / "Fix Z" | Execute immediately, iterate until complete |
|
|
2192
|
-
| "How should I..." / "What's the best way..." | Provide recommendation first, then ask "Want me to implement this?" |
|
|
2193
|
-
| "Can you help me..." | Clarify scope if ambiguous, then execute |
|
|
2194
|
-
| Multi-step complex request | Present your plan first, get confirmation, then execute |
|
|
2195
|
-
|
|
2196
|
-
### Key Behaviors
|
|
2197
|
-
|
|
2198
|
-
1. **Match response to intent** - Execution requests get execution. Advisory requests get advice first.
|
|
2199
|
-
2. **Complete what you start** - Once you begin implementation, finish it. No partial work, no TODO placeholders.
|
|
2200
|
-
3. **Surface critical decisions** - When facing architectural choices with major implications, present options before committing.
|
|
2201
|
-
4. **Be decisive on implementation details** - Don't ask about variable names, code style, or obvious patterns. Use common sense.
|
|
2202
|
-
5. **Be concise** - No code explanation summaries unless requested.
|
|
2203
|
-
|
|
2204
|
-
### Anti-patterns to Avoid
|
|
2205
|
-
|
|
2206
|
-
- Asking "Should I continue?" after every step (annoying)
|
|
2207
|
-
- Jumping to implement when user asked for advice (presumptuous)
|
|
2208
|
-
- Stopping mid-implementation to ask trivial questions (disruptive)
|
|
2209
|
-
- Implementing something different than what was asked (surprising)
|
|
2210
|
-
</Agency>
|
|
2211
|
-
|
|
2212
|
-
<Conventions>
|
|
2213
|
-
## Code Conventions
|
|
2214
|
-
- Mimic existing code style
|
|
2215
|
-
- Use existing libraries and utilities
|
|
2216
|
-
- Follow existing patterns
|
|
2217
|
-
- Never introduce new patterns unless necessary
|
|
2218
|
-
|
|
2219
|
-
## File Operations
|
|
2220
|
-
- ALWAYS use absolute paths
|
|
2221
|
-
- Prefer specialized tools over Bash
|
|
2222
|
-
- FILE EDITS MUST use edit tool. NO Bash.
|
|
2223
|
-
|
|
2224
|
-
## Security
|
|
2225
|
-
- Never expose or log secrets
|
|
2226
|
-
- Never commit secrets
|
|
2227
|
-
</Conventions>
|
|
2228
|
-
|
|
2229
|
-
<Anti_Patterns>
|
|
2230
|
-
## NEVER Do These (BLOCKING)
|
|
2231
|
-
|
|
2232
|
-
### Search Anti-Patterns
|
|
2233
|
-
- Firing 3+ agents for simple queries that grep can answer
|
|
2234
|
-
- Using librarian for internal codebase questions
|
|
2235
|
-
- Over-exploring when you have enough context
|
|
2236
|
-
- Not trying direct tools first
|
|
2237
|
-
|
|
2238
|
-
### Implementation Anti-Patterns
|
|
2239
|
-
- Speculating about code you haven't opened
|
|
2240
|
-
- Editing files without reading first
|
|
2241
|
-
- Skipping todo planning for "quick" tasks
|
|
2242
|
-
- Forgetting to mark tasks complete
|
|
2243
|
-
- Marking complete without evidence
|
|
2244
|
-
|
|
2245
|
-
### Delegation Anti-Patterns
|
|
2246
|
-
- Vague prompts without 7 sections
|
|
2247
|
-
- Sequential agent calls when parallel is possible
|
|
2248
|
-
- Using librarian when explore suffices
|
|
2249
|
-
|
|
2250
|
-
### Frontend Anti-Patterns (BLOCKING)
|
|
2251
|
-
- Editing .tsx/.jsx/.vue/.svelte/.css files directly \u2014 ALWAYS delegate
|
|
2252
|
-
- Thinking "this UI change is too simple to delegate"
|
|
2253
|
-
- Making "quick" CSS fixes yourself
|
|
2254
|
-
- Any frontend work without Frontend Engineer
|
|
2255
|
-
|
|
2256
|
-
### Type Safety Anti-Patterns (BLOCKING)
|
|
2257
|
-
- Using \`as any\` to silence errors
|
|
2258
|
-
- Adding \`@ts-ignore\` or \`@ts-expect-error\`
|
|
2259
|
-
- Using \`any\` as function parameter/return type
|
|
2260
|
-
- Casting to \`unknown\` then to target type (type laundering)
|
|
2261
|
-
- Ignoring null/undefined with \`!\` without checking
|
|
2262
|
-
|
|
2263
|
-
### Error Handling Anti-Patterns (BLOCKING)
|
|
2264
|
-
- Empty catch blocks: \`catch (e) {}\`
|
|
2265
|
-
- Catching and re-throwing without context
|
|
2266
|
-
- Swallowing errors with \`catch (e) { return null }\`
|
|
2267
|
-
- Not handling Promise rejections
|
|
2268
|
-
- Using \`try/catch\` around code that can't throw
|
|
2269
|
-
|
|
2270
|
-
### Code Quality Anti-Patterns
|
|
2271
|
-
- Leaving \`console.log\` in production code
|
|
2272
|
-
- Hardcoding values that should be configurable
|
|
2273
|
-
- Copy-pasting code instead of extracting function
|
|
2274
|
-
- Creating god functions (100+ lines)
|
|
2275
|
-
- Nested callbacks more than 3 levels deep
|
|
2276
|
-
|
|
2277
|
-
### Testing Anti-Patterns (BLOCKING)
|
|
2278
|
-
- Deleting failing tests to "pass"
|
|
2279
|
-
- Writing tests that always pass (no assertions)
|
|
2280
|
-
- Testing implementation details instead of behavior
|
|
2281
|
-
- Mocking everything (no integration tests)
|
|
2282
|
-
|
|
2283
|
-
### Git Anti-Patterns
|
|
2284
|
-
- Committing with "fix" or "update" without context
|
|
2285
|
-
- Large commits with unrelated changes
|
|
2286
|
-
- Committing commented-out code
|
|
2287
|
-
- Committing debug/test artifacts
|
|
2288
|
-
</Anti_Patterns>
|
|
2289
|
-
|
|
2290
|
-
<Decision_Matrix>
|
|
2291
|
-
## Quick Decision Matrix
|
|
1746
|
+
If verification fails:
|
|
1747
|
+
1. Fix issues caused by your changes
|
|
1748
|
+
2. Do NOT fix pre-existing issues unless asked
|
|
1749
|
+
3. Report: "Done. Note: found N pre-existing lint errors unrelated to my changes."
|
|
2292
1750
|
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
-
|
|
2318
|
-
-
|
|
2319
|
-
-
|
|
2320
|
-
-
|
|
2321
|
-
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
</
|
|
1751
|
+
### Before Delivering Final Answer:
|
|
1752
|
+
- Cancel ALL running background tasks: \`background_cancel(all=true)\`
|
|
1753
|
+
- This conserves resources and ensures clean workflow completion
|
|
1754
|
+
|
|
1755
|
+
</Behavior_Instructions>
|
|
1756
|
+
|
|
1757
|
+
<Oracle_Usage>
|
|
1758
|
+
## Oracle \u2014 Your Senior Engineering Advisor (GPT-5.2)
|
|
1759
|
+
|
|
1760
|
+
Oracle is an expensive, high-quality reasoning model. Use it wisely.
|
|
1761
|
+
|
|
1762
|
+
### WHEN to Consult:
|
|
1763
|
+
|
|
1764
|
+
| Trigger | Action |
|
|
1765
|
+
|---------|--------|
|
|
1766
|
+
| Complex architecture design | Oracle FIRST, then implement |
|
|
1767
|
+
| After completing significant work | Oracle review before marking complete |
|
|
1768
|
+
| 2+ failed fix attempts | Oracle for debugging guidance |
|
|
1769
|
+
| Unfamiliar code patterns | Oracle to explain behavior |
|
|
1770
|
+
| Security/performance concerns | Oracle for analysis |
|
|
1771
|
+
| Multi-system tradeoffs | Oracle for architectural decision |
|
|
1772
|
+
|
|
1773
|
+
### WHEN NOT to Consult:
|
|
1774
|
+
|
|
1775
|
+
- Simple file operations (use direct tools)
|
|
1776
|
+
- First attempt at any fix (try yourself first)
|
|
1777
|
+
- Questions answerable from code you've read
|
|
1778
|
+
- Trivial decisions (variable names, formatting)
|
|
1779
|
+
- Things you can infer from existing code patterns
|
|
1780
|
+
|
|
1781
|
+
### Usage Pattern:
|
|
1782
|
+
Briefly announce "Consulting Oracle for [reason]" before invocation.
|
|
1783
|
+
</Oracle_Usage>
|
|
1784
|
+
|
|
1785
|
+
<Task_Management>
|
|
1786
|
+
## Todo Management
|
|
1787
|
+
|
|
1788
|
+
Use \`todowrite\` for any task with 2+ steps.
|
|
1789
|
+
|
|
1790
|
+
- Create todos BEFORE starting work
|
|
1791
|
+
- Mark \`in_progress\` when starting an item
|
|
1792
|
+
- Mark \`completed\` immediately when done (don't batch)
|
|
1793
|
+
- This gives user visibility into progress and prevents forgotten steps
|
|
1794
|
+
|
|
1795
|
+
### Clarification Protocol (when asking):
|
|
1796
|
+
|
|
1797
|
+
\`\`\`
|
|
1798
|
+
I want to make sure I understand correctly.
|
|
1799
|
+
|
|
1800
|
+
**What I understood**: [Your interpretation]
|
|
1801
|
+
**What I'm unsure about**: [Specific ambiguity]
|
|
1802
|
+
**Options I see**:
|
|
1803
|
+
1. [Option A] - [effort/implications]
|
|
1804
|
+
2. [Option B] - [effort/implications]
|
|
1805
|
+
|
|
1806
|
+
**My recommendation**: [suggestion with reasoning]
|
|
1807
|
+
|
|
1808
|
+
Should I proceed with [recommendation], or would you prefer differently?
|
|
1809
|
+
\`\`\`
|
|
1810
|
+
</Task_Management>
|
|
1811
|
+
|
|
1812
|
+
<Tone_and_Style>
|
|
1813
|
+
## Communication Style
|
|
1814
|
+
|
|
1815
|
+
### Be Concise
|
|
1816
|
+
- Answer directly without preamble
|
|
1817
|
+
- Don't summarize what you did unless asked
|
|
1818
|
+
- Don't explain your code unless asked
|
|
1819
|
+
- One word answers are acceptable when appropriate
|
|
1820
|
+
|
|
1821
|
+
### No Flattery
|
|
1822
|
+
Never start responses with:
|
|
1823
|
+
- "Great question!"
|
|
1824
|
+
- "That's a really good idea!"
|
|
1825
|
+
- "Excellent choice!"
|
|
1826
|
+
- Any praise of the user's input
|
|
1827
|
+
|
|
1828
|
+
Just respond directly to the substance.
|
|
1829
|
+
|
|
1830
|
+
### When User is Wrong
|
|
1831
|
+
If the user's approach seems problematic:
|
|
1832
|
+
- Don't blindly implement it
|
|
1833
|
+
- Don't lecture or be preachy
|
|
1834
|
+
- Concisely state your concern and alternative
|
|
1835
|
+
- Ask if they want to proceed anyway
|
|
1836
|
+
|
|
1837
|
+
### Match User's Style
|
|
1838
|
+
- If user is terse, be terse
|
|
1839
|
+
- If user wants detail, provide detail
|
|
1840
|
+
- Adapt to their communication preference
|
|
1841
|
+
</Tone_and_Style>
|
|
1842
|
+
|
|
1843
|
+
<Constraints>
|
|
1844
|
+
## Hard Blocks (NEVER violate)
|
|
1845
|
+
|
|
1846
|
+
| Constraint | No Exceptions |
|
|
1847
|
+
|------------|---------------|
|
|
1848
|
+
| Frontend files (.tsx/.jsx/.vue/.svelte/.css) | Always delegate |
|
|
1849
|
+
| Type error suppression (\`as any\`, \`@ts-ignore\`) | Never |
|
|
1850
|
+
| Commit without explicit request | Never |
|
|
1851
|
+
| Speculate about unread code | Never |
|
|
1852
|
+
| Leave code in broken state after failures | Never |
|
|
1853
|
+
|
|
1854
|
+
## Anti-Patterns (BLOCKING violations)
|
|
1855
|
+
|
|
1856
|
+
| Category | Forbidden |
|
|
1857
|
+
|----------|-----------|
|
|
1858
|
+
| **Type Safety** | \`as any\`, \`@ts-ignore\`, \`@ts-expect-error\` |
|
|
1859
|
+
| **Error Handling** | Empty catch blocks \`catch(e) {}\` |
|
|
1860
|
+
| **Testing** | Deleting failing tests to "pass" |
|
|
1861
|
+
| **Search** | Firing 3+ agents when grep suffices |
|
|
1862
|
+
| **Frontend** | ANY direct edit to frontend files |
|
|
1863
|
+
| **Debugging** | Shotgun debugging, random changes |
|
|
1864
|
+
|
|
1865
|
+
## Soft Guidelines
|
|
1866
|
+
|
|
1867
|
+
- Prefer existing libraries over new dependencies
|
|
1868
|
+
- Prefer small, focused changes over large refactors
|
|
1869
|
+
- When uncertain about scope, ask
|
|
1870
|
+
</Constraints>
|
|
2326
1871
|
`;
|
|
2327
1872
|
var omoAgent = {
|
|
2328
1873
|
description: "Powerful AI orchestrator for OpenCode. Plans obsessively with todos, assesses search complexity before exploration, delegates strategically to specialized agents. Uses explore for internal code (parallel-friendly), librarian only for external docs, and always delegates UI work to frontend engineer.",
|
|
@@ -3989,6 +3534,28 @@ ${CONTEXT_REMINDER}
|
|
|
3989
3534
|
}
|
|
3990
3535
|
// src/hooks/session-notification.ts
|
|
3991
3536
|
import { platform } from "os";
|
|
3537
|
+
// src/features/claude-code-session-state/state.ts
|
|
3538
|
+
var sessionErrorState = new Map;
|
|
3539
|
+
var sessionInterruptState = new Map;
|
|
3540
|
+
var subagentSessions = new Set;
|
|
3541
|
+
var sessionFirstMessageProcessed = new Set;
|
|
3542
|
+
var currentSessionID;
|
|
3543
|
+
var currentSessionTitle;
|
|
3544
|
+
var mainSessionID;
|
|
3545
|
+
function setCurrentSession(id, title) {
|
|
3546
|
+
currentSessionID = id;
|
|
3547
|
+
currentSessionTitle = title;
|
|
3548
|
+
}
|
|
3549
|
+
function setMainSession(id) {
|
|
3550
|
+
mainSessionID = id;
|
|
3551
|
+
}
|
|
3552
|
+
function getCurrentSessionTitle() {
|
|
3553
|
+
return currentSessionTitle;
|
|
3554
|
+
}
|
|
3555
|
+
function getMainSessionID() {
|
|
3556
|
+
return mainSessionID;
|
|
3557
|
+
}
|
|
3558
|
+
// src/hooks/session-notification.ts
|
|
3992
3559
|
function detectPlatform() {
|
|
3993
3560
|
const p = platform();
|
|
3994
3561
|
if (p === "darwin" || p === "linux" || p === "win32")
|
|
@@ -4155,6 +3722,8 @@ function createSessionNotification(ctx, config = {}) {
|
|
|
4155
3722
|
const sessionID = props?.sessionID;
|
|
4156
3723
|
if (!sessionID)
|
|
4157
3724
|
return;
|
|
3725
|
+
if (subagentSessions.has(sessionID))
|
|
3726
|
+
return;
|
|
4158
3727
|
if (notifiedSessions.has(sessionID))
|
|
4159
3728
|
return;
|
|
4160
3729
|
if (pendingTimers.has(sessionID))
|
|
@@ -5715,28 +5284,28 @@ function truncateToolResult(partPath) {
|
|
|
5715
5284
|
|
|
5716
5285
|
// src/hooks/anthropic-auto-compact/executor.ts
|
|
5717
5286
|
function getOrCreateRetryState(autoCompactState, sessionID) {
|
|
5718
|
-
let
|
|
5719
|
-
if (!
|
|
5720
|
-
|
|
5721
|
-
autoCompactState.retryStateBySession.set(sessionID,
|
|
5287
|
+
let state2 = autoCompactState.retryStateBySession.get(sessionID);
|
|
5288
|
+
if (!state2) {
|
|
5289
|
+
state2 = { attempt: 0, lastAttemptTime: 0 };
|
|
5290
|
+
autoCompactState.retryStateBySession.set(sessionID, state2);
|
|
5722
5291
|
}
|
|
5723
|
-
return
|
|
5292
|
+
return state2;
|
|
5724
5293
|
}
|
|
5725
5294
|
function getOrCreateFallbackState(autoCompactState, sessionID) {
|
|
5726
|
-
let
|
|
5727
|
-
if (!
|
|
5728
|
-
|
|
5729
|
-
autoCompactState.fallbackStateBySession.set(sessionID,
|
|
5295
|
+
let state2 = autoCompactState.fallbackStateBySession.get(sessionID);
|
|
5296
|
+
if (!state2) {
|
|
5297
|
+
state2 = { revertAttempt: 0 };
|
|
5298
|
+
autoCompactState.fallbackStateBySession.set(sessionID, state2);
|
|
5730
5299
|
}
|
|
5731
|
-
return
|
|
5300
|
+
return state2;
|
|
5732
5301
|
}
|
|
5733
5302
|
function getOrCreateTruncateState(autoCompactState, sessionID) {
|
|
5734
|
-
let
|
|
5735
|
-
if (!
|
|
5736
|
-
|
|
5737
|
-
autoCompactState.truncateStateBySession.set(sessionID,
|
|
5303
|
+
let state2 = autoCompactState.truncateStateBySession.get(sessionID);
|
|
5304
|
+
if (!state2) {
|
|
5305
|
+
state2 = { truncateAttempt: 0 };
|
|
5306
|
+
autoCompactState.truncateStateBySession.set(sessionID, state2);
|
|
5738
5307
|
}
|
|
5739
|
-
return
|
|
5308
|
+
return state2;
|
|
5740
5309
|
}
|
|
5741
5310
|
async function getLastMessagePair(sessionID, client, directory) {
|
|
5742
5311
|
try {
|
|
@@ -6266,25 +5835,25 @@ function createThinkModeHook() {
|
|
|
6266
5835
|
return {
|
|
6267
5836
|
"chat.params": async (output, sessionID) => {
|
|
6268
5837
|
const promptText = extractPromptText(output.parts);
|
|
6269
|
-
const
|
|
5838
|
+
const state2 = {
|
|
6270
5839
|
requested: false,
|
|
6271
5840
|
modelSwitched: false,
|
|
6272
5841
|
thinkingConfigInjected: false
|
|
6273
5842
|
};
|
|
6274
5843
|
if (!detectThinkKeyword(promptText)) {
|
|
6275
|
-
thinkModeState.set(sessionID,
|
|
5844
|
+
thinkModeState.set(sessionID, state2);
|
|
6276
5845
|
return;
|
|
6277
5846
|
}
|
|
6278
|
-
|
|
5847
|
+
state2.requested = true;
|
|
6279
5848
|
const currentModel = output.message.model;
|
|
6280
5849
|
if (!currentModel) {
|
|
6281
|
-
thinkModeState.set(sessionID,
|
|
5850
|
+
thinkModeState.set(sessionID, state2);
|
|
6282
5851
|
return;
|
|
6283
5852
|
}
|
|
6284
|
-
|
|
6285
|
-
|
|
5853
|
+
state2.providerID = currentModel.providerID;
|
|
5854
|
+
state2.modelID = currentModel.modelID;
|
|
6286
5855
|
if (isAlreadyHighVariant(currentModel.modelID)) {
|
|
6287
|
-
thinkModeState.set(sessionID,
|
|
5856
|
+
thinkModeState.set(sessionID, state2);
|
|
6288
5857
|
return;
|
|
6289
5858
|
}
|
|
6290
5859
|
const highVariant = getHighVariant(currentModel.modelID);
|
|
@@ -6294,7 +5863,7 @@ function createThinkModeHook() {
|
|
|
6294
5863
|
providerID: currentModel.providerID,
|
|
6295
5864
|
modelID: highVariant
|
|
6296
5865
|
};
|
|
6297
|
-
|
|
5866
|
+
state2.modelSwitched = true;
|
|
6298
5867
|
log("Think mode: model switched to high variant", {
|
|
6299
5868
|
sessionID,
|
|
6300
5869
|
from: currentModel.modelID,
|
|
@@ -6303,14 +5872,14 @@ function createThinkModeHook() {
|
|
|
6303
5872
|
}
|
|
6304
5873
|
if (thinkingConfig) {
|
|
6305
5874
|
Object.assign(output.message, thinkingConfig);
|
|
6306
|
-
|
|
5875
|
+
state2.thinkingConfigInjected = true;
|
|
6307
5876
|
log("Think mode: thinking config injected", {
|
|
6308
5877
|
sessionID,
|
|
6309
5878
|
provider: currentModel.providerID,
|
|
6310
5879
|
config: thinkingConfig
|
|
6311
5880
|
});
|
|
6312
5881
|
}
|
|
6313
|
-
thinkModeState.set(sessionID,
|
|
5882
|
+
thinkModeState.set(sessionID, state2);
|
|
6314
5883
|
},
|
|
6315
5884
|
event: async ({ event }) => {
|
|
6316
5885
|
if (event.type === "session.deleted") {
|
|
@@ -7006,13 +6575,13 @@ setInterval(() => {
|
|
|
7006
6575
|
}, CACHE_TTL);
|
|
7007
6576
|
|
|
7008
6577
|
// src/hooks/claude-code-hooks/index.ts
|
|
7009
|
-
var
|
|
7010
|
-
var
|
|
7011
|
-
var
|
|
6578
|
+
var sessionFirstMessageProcessed2 = new Set;
|
|
6579
|
+
var sessionErrorState2 = new Map;
|
|
6580
|
+
var sessionInterruptState2 = new Map;
|
|
7012
6581
|
function createClaudeCodeHooksHook(ctx, config = {}) {
|
|
7013
6582
|
return {
|
|
7014
6583
|
"chat.message": async (input, output) => {
|
|
7015
|
-
const interruptState =
|
|
6584
|
+
const interruptState = sessionInterruptState2.get(input.sessionID);
|
|
7016
6585
|
if (interruptState?.interrupted) {
|
|
7017
6586
|
log("chat.message hook skipped - session interrupted", { sessionID: input.sessionID });
|
|
7018
6587
|
return;
|
|
@@ -7027,7 +6596,7 @@ function createClaudeCodeHooksHook(ctx, config = {}) {
|
|
|
7027
6596
|
type: p.type,
|
|
7028
6597
|
text: p.text
|
|
7029
6598
|
}));
|
|
7030
|
-
const interruptStateBeforeHooks =
|
|
6599
|
+
const interruptStateBeforeHooks = sessionInterruptState2.get(input.sessionID);
|
|
7031
6600
|
if (interruptStateBeforeHooks?.interrupted) {
|
|
7032
6601
|
log("chat.message hooks skipped - interrupted during preparation", { sessionID: input.sessionID });
|
|
7033
6602
|
return;
|
|
@@ -7039,8 +6608,8 @@ function createClaudeCodeHooksHook(ctx, config = {}) {
|
|
|
7039
6608
|
});
|
|
7040
6609
|
parentSessionId = sessionInfo.data?.parentID;
|
|
7041
6610
|
} catch {}
|
|
7042
|
-
const isFirstMessage = !
|
|
7043
|
-
|
|
6611
|
+
const isFirstMessage = !sessionFirstMessageProcessed2.has(input.sessionID);
|
|
6612
|
+
sessionFirstMessageProcessed2.add(input.sessionID);
|
|
7044
6613
|
if (isFirstMessage) {
|
|
7045
6614
|
log("Skipping UserPromptSubmit hooks on first message for title generation", { sessionID: input.sessionID });
|
|
7046
6615
|
return;
|
|
@@ -7057,7 +6626,7 @@ function createClaudeCodeHooksHook(ctx, config = {}) {
|
|
|
7057
6626
|
if (result.block) {
|
|
7058
6627
|
throw new Error(result.reason ?? "Hook blocked the prompt");
|
|
7059
6628
|
}
|
|
7060
|
-
const interruptStateAfterHooks =
|
|
6629
|
+
const interruptStateAfterHooks = sessionInterruptState2.get(input.sessionID);
|
|
7061
6630
|
if (interruptStateAfterHooks?.interrupted) {
|
|
7062
6631
|
log("chat.message injection skipped - interrupted during hooks", { sessionID: input.sessionID });
|
|
7063
6632
|
return;
|
|
@@ -7177,7 +6746,7 @@ ${result.message}`;
|
|
|
7177
6746
|
const props = event.properties;
|
|
7178
6747
|
const sessionID = props?.sessionID;
|
|
7179
6748
|
if (sessionID) {
|
|
7180
|
-
|
|
6749
|
+
sessionErrorState2.set(sessionID, {
|
|
7181
6750
|
hasError: true,
|
|
7182
6751
|
errorMessage: String(props?.error ?? "Unknown error")
|
|
7183
6752
|
});
|
|
@@ -7188,9 +6757,9 @@ ${result.message}`;
|
|
|
7188
6757
|
const props = event.properties;
|
|
7189
6758
|
const sessionInfo = props?.info;
|
|
7190
6759
|
if (sessionInfo?.id) {
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
6760
|
+
sessionErrorState2.delete(sessionInfo.id);
|
|
6761
|
+
sessionInterruptState2.delete(sessionInfo.id);
|
|
6762
|
+
sessionFirstMessageProcessed2.delete(sessionInfo.id);
|
|
7194
6763
|
}
|
|
7195
6764
|
return;
|
|
7196
6765
|
}
|
|
@@ -7201,9 +6770,9 @@ ${result.message}`;
|
|
|
7201
6770
|
return;
|
|
7202
6771
|
const claudeConfig = await loadClaudeHooksConfig();
|
|
7203
6772
|
const extendedConfig = await loadPluginExtendedConfig();
|
|
7204
|
-
const errorStateBefore =
|
|
6773
|
+
const errorStateBefore = sessionErrorState2.get(sessionID);
|
|
7205
6774
|
const endedWithErrorBefore = errorStateBefore?.hasError === true;
|
|
7206
|
-
const interruptStateBefore =
|
|
6775
|
+
const interruptStateBefore = sessionInterruptState2.get(sessionID);
|
|
7207
6776
|
const interruptedBefore = interruptStateBefore?.interrupted === true;
|
|
7208
6777
|
let parentSessionId;
|
|
7209
6778
|
try {
|
|
@@ -7219,9 +6788,9 @@ ${result.message}`;
|
|
|
7219
6788
|
cwd: ctx.directory
|
|
7220
6789
|
};
|
|
7221
6790
|
const stopResult = await executeStopHooks(stopCtx, claudeConfig, extendedConfig);
|
|
7222
|
-
const errorStateAfter =
|
|
6791
|
+
const errorStateAfter = sessionErrorState2.get(sessionID);
|
|
7223
6792
|
const endedWithErrorAfter = errorStateAfter?.hasError === true;
|
|
7224
|
-
const interruptStateAfter =
|
|
6793
|
+
const interruptStateAfter = sessionInterruptState2.get(sessionID);
|
|
7225
6794
|
const interruptedAfter = interruptStateAfter?.interrupted === true;
|
|
7226
6795
|
const shouldBypass = endedWithErrorBefore || endedWithErrorAfter || interruptedBefore || interruptedAfter;
|
|
7227
6796
|
if (shouldBypass && stopResult.block) {
|
|
@@ -7239,8 +6808,8 @@ ${result.message}`;
|
|
|
7239
6808
|
log("Stop hook returned block", { sessionID, reason: stopResult.reason });
|
|
7240
6809
|
}
|
|
7241
6810
|
}
|
|
7242
|
-
|
|
7243
|
-
|
|
6811
|
+
sessionErrorState2.delete(sessionID);
|
|
6812
|
+
sessionInterruptState2.delete(sessionID);
|
|
7244
6813
|
}
|
|
7245
6814
|
}
|
|
7246
6815
|
};
|
|
@@ -8056,12 +7625,12 @@ function loadAgentUsageState(sessionID) {
|
|
|
8056
7625
|
return null;
|
|
8057
7626
|
}
|
|
8058
7627
|
}
|
|
8059
|
-
function saveAgentUsageState(
|
|
7628
|
+
function saveAgentUsageState(state2) {
|
|
8060
7629
|
if (!existsSync21(AGENT_USAGE_REMINDER_STORAGE)) {
|
|
8061
7630
|
mkdirSync8(AGENT_USAGE_REMINDER_STORAGE, { recursive: true });
|
|
8062
7631
|
}
|
|
8063
|
-
const filePath = getStoragePath4(
|
|
8064
|
-
writeFileSync9(filePath, JSON.stringify(
|
|
7632
|
+
const filePath = getStoragePath4(state2.sessionID);
|
|
7633
|
+
writeFileSync9(filePath, JSON.stringify(state2, null, 2));
|
|
8065
7634
|
}
|
|
8066
7635
|
function clearAgentUsageState(sessionID) {
|
|
8067
7636
|
const filePath = getStoragePath4(sessionID);
|
|
@@ -8076,21 +7645,21 @@ function createAgentUsageReminderHook(_ctx) {
|
|
|
8076
7645
|
function getOrCreateState(sessionID) {
|
|
8077
7646
|
if (!sessionStates.has(sessionID)) {
|
|
8078
7647
|
const persisted = loadAgentUsageState(sessionID);
|
|
8079
|
-
const
|
|
7648
|
+
const state2 = persisted ?? {
|
|
8080
7649
|
sessionID,
|
|
8081
7650
|
agentUsed: false,
|
|
8082
7651
|
reminderCount: 0,
|
|
8083
7652
|
updatedAt: Date.now()
|
|
8084
7653
|
};
|
|
8085
|
-
sessionStates.set(sessionID,
|
|
7654
|
+
sessionStates.set(sessionID, state2);
|
|
8086
7655
|
}
|
|
8087
7656
|
return sessionStates.get(sessionID);
|
|
8088
7657
|
}
|
|
8089
7658
|
function markAgentUsed(sessionID) {
|
|
8090
|
-
const
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
saveAgentUsageState(
|
|
7659
|
+
const state2 = getOrCreateState(sessionID);
|
|
7660
|
+
state2.agentUsed = true;
|
|
7661
|
+
state2.updatedAt = Date.now();
|
|
7662
|
+
saveAgentUsageState(state2);
|
|
8094
7663
|
}
|
|
8095
7664
|
function resetState(sessionID) {
|
|
8096
7665
|
sessionStates.delete(sessionID);
|
|
@@ -8106,14 +7675,14 @@ function createAgentUsageReminderHook(_ctx) {
|
|
|
8106
7675
|
if (!TARGET_TOOLS.has(toolLower)) {
|
|
8107
7676
|
return;
|
|
8108
7677
|
}
|
|
8109
|
-
const
|
|
8110
|
-
if (
|
|
7678
|
+
const state2 = getOrCreateState(sessionID);
|
|
7679
|
+
if (state2.agentUsed) {
|
|
8111
7680
|
return;
|
|
8112
7681
|
}
|
|
8113
7682
|
output.output += REMINDER_MESSAGE;
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
saveAgentUsageState(
|
|
7683
|
+
state2.reminderCount++;
|
|
7684
|
+
state2.updatedAt = Date.now();
|
|
7685
|
+
saveAgentUsageState(state2);
|
|
8117
7686
|
};
|
|
8118
7687
|
const eventHandler = async ({ event }) => {
|
|
8119
7688
|
const props = event.properties;
|
|
@@ -8328,15 +7897,15 @@ function loadInteractiveBashSessionState(sessionID) {
|
|
|
8328
7897
|
return null;
|
|
8329
7898
|
}
|
|
8330
7899
|
}
|
|
8331
|
-
function saveInteractiveBashSessionState(
|
|
7900
|
+
function saveInteractiveBashSessionState(state2) {
|
|
8332
7901
|
if (!existsSync22(INTERACTIVE_BASH_SESSION_STORAGE)) {
|
|
8333
7902
|
mkdirSync9(INTERACTIVE_BASH_SESSION_STORAGE, { recursive: true });
|
|
8334
7903
|
}
|
|
8335
|
-
const filePath = getStoragePath5(
|
|
7904
|
+
const filePath = getStoragePath5(state2.sessionID);
|
|
8336
7905
|
const serialized = {
|
|
8337
|
-
sessionID:
|
|
8338
|
-
tmuxSessions: Array.from(
|
|
8339
|
-
updatedAt:
|
|
7906
|
+
sessionID: state2.sessionID,
|
|
7907
|
+
tmuxSessions: Array.from(state2.tmuxSessions),
|
|
7908
|
+
updatedAt: state2.updatedAt
|
|
8340
7909
|
};
|
|
8341
7910
|
writeFileSync10(filePath, JSON.stringify(serialized, null, 2));
|
|
8342
7911
|
}
|
|
@@ -8434,20 +8003,20 @@ function createInteractiveBashSessionHook(_ctx) {
|
|
|
8434
8003
|
function getOrCreateState(sessionID) {
|
|
8435
8004
|
if (!sessionStates.has(sessionID)) {
|
|
8436
8005
|
const persisted = loadInteractiveBashSessionState(sessionID);
|
|
8437
|
-
const
|
|
8006
|
+
const state2 = persisted ?? {
|
|
8438
8007
|
sessionID,
|
|
8439
8008
|
tmuxSessions: new Set,
|
|
8440
8009
|
updatedAt: Date.now()
|
|
8441
8010
|
};
|
|
8442
|
-
sessionStates.set(sessionID,
|
|
8011
|
+
sessionStates.set(sessionID, state2);
|
|
8443
8012
|
}
|
|
8444
8013
|
return sessionStates.get(sessionID);
|
|
8445
8014
|
}
|
|
8446
8015
|
function isOmoSession(sessionName) {
|
|
8447
8016
|
return sessionName !== null && sessionName.startsWith(OMO_SESSION_PREFIX);
|
|
8448
8017
|
}
|
|
8449
|
-
async function killAllTrackedSessions(
|
|
8450
|
-
for (const sessionName of
|
|
8018
|
+
async function killAllTrackedSessions(state2) {
|
|
8019
|
+
for (const sessionName of state2.tmuxSessions) {
|
|
8451
8020
|
try {
|
|
8452
8021
|
const proc = Bun.spawn(["tmux", "kill-session", "-t", sessionName], {
|
|
8453
8022
|
stdout: "ignore",
|
|
@@ -8469,7 +8038,7 @@ function createInteractiveBashSessionHook(_ctx) {
|
|
|
8469
8038
|
const tmuxCommand = args.tmux_command;
|
|
8470
8039
|
const tokens = tokenizeCommand(tmuxCommand);
|
|
8471
8040
|
const subCommand = findSubcommand(tokens);
|
|
8472
|
-
const
|
|
8041
|
+
const state2 = getOrCreateState(sessionID);
|
|
8473
8042
|
let stateChanged = false;
|
|
8474
8043
|
const toolOutput = output?.output ?? "";
|
|
8475
8044
|
if (toolOutput.startsWith("Error:")) {
|
|
@@ -8480,22 +8049,22 @@ function createInteractiveBashSessionHook(_ctx) {
|
|
|
8480
8049
|
const isKillServer = subCommand === "kill-server";
|
|
8481
8050
|
const sessionName = extractSessionNameFromTokens(tokens, subCommand);
|
|
8482
8051
|
if (isNewSession && isOmoSession(sessionName)) {
|
|
8483
|
-
|
|
8052
|
+
state2.tmuxSessions.add(sessionName);
|
|
8484
8053
|
stateChanged = true;
|
|
8485
8054
|
} else if (isKillSession && isOmoSession(sessionName)) {
|
|
8486
|
-
|
|
8055
|
+
state2.tmuxSessions.delete(sessionName);
|
|
8487
8056
|
stateChanged = true;
|
|
8488
8057
|
} else if (isKillServer) {
|
|
8489
|
-
|
|
8058
|
+
state2.tmuxSessions.clear();
|
|
8490
8059
|
stateChanged = true;
|
|
8491
8060
|
}
|
|
8492
8061
|
if (stateChanged) {
|
|
8493
|
-
|
|
8494
|
-
saveInteractiveBashSessionState(
|
|
8062
|
+
state2.updatedAt = Date.now();
|
|
8063
|
+
saveInteractiveBashSessionState(state2);
|
|
8495
8064
|
}
|
|
8496
8065
|
const isSessionOperation = isNewSession || isKillSession || isKillServer;
|
|
8497
8066
|
if (isSessionOperation) {
|
|
8498
|
-
const reminder = buildSessionReminderMessage(Array.from(
|
|
8067
|
+
const reminder = buildSessionReminderMessage(Array.from(state2.tmuxSessions));
|
|
8499
8068
|
if (reminder) {
|
|
8500
8069
|
output.output += reminder;
|
|
8501
8070
|
}
|
|
@@ -8507,8 +8076,8 @@ function createInteractiveBashSessionHook(_ctx) {
|
|
|
8507
8076
|
const sessionInfo = props?.info;
|
|
8508
8077
|
const sessionID = sessionInfo?.id;
|
|
8509
8078
|
if (sessionID) {
|
|
8510
|
-
const
|
|
8511
|
-
await killAllTrackedSessions(
|
|
8079
|
+
const state2 = getOrCreateState(sessionID);
|
|
8080
|
+
await killAllTrackedSessions(state2);
|
|
8512
8081
|
sessionStates.delete(sessionID);
|
|
8513
8082
|
clearInteractiveBashSessionState(sessionID);
|
|
8514
8083
|
}
|
|
@@ -8704,8 +8273,8 @@ async function generatePKCEPair() {
|
|
|
8704
8273
|
method: pkce.method
|
|
8705
8274
|
};
|
|
8706
8275
|
}
|
|
8707
|
-
function encodeState(
|
|
8708
|
-
const json = JSON.stringify(
|
|
8276
|
+
function encodeState(state2) {
|
|
8277
|
+
const json = JSON.stringify(state2);
|
|
8709
8278
|
return Buffer.from(json, "utf8").toString("base64url");
|
|
8710
8279
|
}
|
|
8711
8280
|
function decodeState(encoded) {
|
|
@@ -8723,7 +8292,7 @@ function decodeState(encoded) {
|
|
|
8723
8292
|
}
|
|
8724
8293
|
async function buildAuthURL(projectId, clientId = ANTIGRAVITY_CLIENT_ID, port = ANTIGRAVITY_CALLBACK_PORT) {
|
|
8725
8294
|
const pkce = await generatePKCEPair();
|
|
8726
|
-
const
|
|
8295
|
+
const state2 = {
|
|
8727
8296
|
verifier: pkce.verifier,
|
|
8728
8297
|
projectId
|
|
8729
8298
|
};
|
|
@@ -8733,7 +8302,7 @@ async function buildAuthURL(projectId, clientId = ANTIGRAVITY_CLIENT_ID, port =
|
|
|
8733
8302
|
url.searchParams.set("redirect_uri", redirectUri);
|
|
8734
8303
|
url.searchParams.set("response_type", "code");
|
|
8735
8304
|
url.searchParams.set("scope", ANTIGRAVITY_SCOPES.join(" "));
|
|
8736
|
-
url.searchParams.set("state", encodeState(
|
|
8305
|
+
url.searchParams.set("state", encodeState(state2));
|
|
8737
8306
|
url.searchParams.set("code_challenge", pkce.challenge);
|
|
8738
8307
|
url.searchParams.set("code_challenge_method", "S256");
|
|
8739
8308
|
url.searchParams.set("access_type", "offline");
|
|
@@ -8809,7 +8378,7 @@ function startCallbackServer(timeoutMs = 5 * 60 * 1000) {
|
|
|
8809
8378
|
const url = new URL(request.url);
|
|
8810
8379
|
if (url.pathname === "/oauth-callback") {
|
|
8811
8380
|
const code = url.searchParams.get("code") || "";
|
|
8812
|
-
const
|
|
8381
|
+
const state2 = url.searchParams.get("state") || "";
|
|
8813
8382
|
const error = url.searchParams.get("error") || undefined;
|
|
8814
8383
|
let responseBody;
|
|
8815
8384
|
if (code && !error) {
|
|
@@ -8820,7 +8389,7 @@ function startCallbackServer(timeoutMs = 5 * 60 * 1000) {
|
|
|
8820
8389
|
setTimeout(() => {
|
|
8821
8390
|
cleanup();
|
|
8822
8391
|
if (resolveCallback) {
|
|
8823
|
-
resolveCallback({ code, state, error });
|
|
8392
|
+
resolveCallback({ code, state: state2, error });
|
|
8824
8393
|
}
|
|
8825
8394
|
}, 100);
|
|
8826
8395
|
return new Response(responseBody, {
|
|
@@ -10236,8 +9805,8 @@ async function createGoogleAntigravityAuthPlugin({
|
|
|
10236
9805
|
}
|
|
10237
9806
|
return { type: "failed" };
|
|
10238
9807
|
}
|
|
10239
|
-
const
|
|
10240
|
-
if (
|
|
9808
|
+
const state2 = decodeState(result.state);
|
|
9809
|
+
if (state2.verifier !== verifier) {
|
|
10241
9810
|
if (process.env.ANTIGRAVITY_DEBUG === "1") {
|
|
10242
9811
|
console.error("[antigravity-plugin] PKCE verifier mismatch");
|
|
10243
9812
|
}
|
|
@@ -10607,27 +10176,6 @@ async function loadMcpConfigs() {
|
|
|
10607
10176
|
}
|
|
10608
10177
|
return { servers, loadedServers };
|
|
10609
10178
|
}
|
|
10610
|
-
// src/features/claude-code-session-state/state.ts
|
|
10611
|
-
var sessionErrorState2 = new Map;
|
|
10612
|
-
var sessionInterruptState2 = new Map;
|
|
10613
|
-
var subagentSessions = new Set;
|
|
10614
|
-
var sessionFirstMessageProcessed2 = new Set;
|
|
10615
|
-
var currentSessionID;
|
|
10616
|
-
var currentSessionTitle;
|
|
10617
|
-
var mainSessionID;
|
|
10618
|
-
function setCurrentSession(id, title) {
|
|
10619
|
-
currentSessionID = id;
|
|
10620
|
-
currentSessionTitle = title;
|
|
10621
|
-
}
|
|
10622
|
-
function setMainSession(id) {
|
|
10623
|
-
mainSessionID = id;
|
|
10624
|
-
}
|
|
10625
|
-
function getCurrentSessionTitle() {
|
|
10626
|
-
return currentSessionTitle;
|
|
10627
|
-
}
|
|
10628
|
-
function getMainSessionID() {
|
|
10629
|
-
return mainSessionID;
|
|
10630
|
-
}
|
|
10631
10179
|
// src/features/terminal/title.ts
|
|
10632
10180
|
var STATUS_ICONS = {
|
|
10633
10181
|
ready: "",
|
|
@@ -26655,6 +26203,7 @@ class BackgroundManager {
|
|
|
26655
26203
|
throw new Error(`Failed to create background session: ${createResult.error}`);
|
|
26656
26204
|
}
|
|
26657
26205
|
const sessionID = createResult.data.id;
|
|
26206
|
+
subagentSessions.add(sessionID);
|
|
26658
26207
|
const task = {
|
|
26659
26208
|
id: `bg_${crypto.randomUUID().slice(0, 8)}`,
|
|
26660
26209
|
sessionID,
|
|
@@ -26793,6 +26342,7 @@ class BackgroundManager {
|
|
|
26793
26342
|
}
|
|
26794
26343
|
this.tasks.delete(task.id);
|
|
26795
26344
|
this.clearNotificationsForTask(task.id);
|
|
26345
|
+
subagentSessions.delete(sessionID);
|
|
26796
26346
|
}
|
|
26797
26347
|
}
|
|
26798
26348
|
markForNotification(task) {
|