typeclaw 0.37.5 → 0.37.7
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/package.json +2 -2
- package/src/agent/attention-escalation.ts +590 -0
- package/src/agent/plugin-tools.ts +23 -1
- package/src/agent/session-origin.ts +10 -7
- package/src/agent/subagents.ts +2 -0
- package/src/agent/system-prompt.ts +2 -2
- package/src/bundled-plugins/doc-render/index.ts +10 -0
- package/src/bundled-plugins/doc-render/skills/typeclaw-render-pdf/SKILL.md +171 -165
- package/src/bundled-plugins/doc-render/templates/lib.typ +339 -0
- package/src/bundled-plugins/github-cli-auth/gh-command.ts +95 -11
- package/src/bundled-plugins/github-cli-auth/git-command.ts +11 -0
- package/src/bundled-plugins/github-cli-auth/index.ts +68 -7
- package/src/channels/manager.ts +77 -1
- package/src/channels/router.ts +72 -3
- package/src/cli/channel.ts +1 -1
- package/src/cli/compose.ts +11 -2
- package/src/cli/init.ts +8 -1
- package/src/cli/mount.ts +5 -5
- package/src/cli/restart.ts +3 -1
- package/src/cli/start.ts +3 -1
- package/src/cli/ui.ts +13 -0
- package/src/compose/restart.ts +1 -1
- package/src/compose/start.ts +4 -2
- package/src/config/config.ts +202 -9
- package/src/container/start.ts +17 -4
- package/src/cron/consumer.ts +10 -3
- package/src/doctor/checks.ts +13 -1
- package/src/init/dockerfile.ts +62 -11
- package/src/server/command-runner.ts +2 -0
- package/src/server/index.ts +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typeclaw",
|
|
3
|
-
"version": "0.37.
|
|
3
|
+
"version": "0.37.7",
|
|
4
4
|
"homepage": "https://github.com/typeclaw/typeclaw#readme",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/typeclaw/typeclaw/issues"
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@mariozechner/pi-tui": "^0.67.3",
|
|
51
51
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
52
52
|
"@mozilla/readability": "^0.6.0",
|
|
53
|
-
"agent-messenger": "2.20.
|
|
53
|
+
"agent-messenger": "2.20.5",
|
|
54
54
|
"cheerio": "^1.2.0",
|
|
55
55
|
"citty": "^0.2.2",
|
|
56
56
|
"cron-parser": "^5.5.0",
|
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
import type { ThinkingLevel } from '@mariozechner/pi-agent-core'
|
|
2
|
+
|
|
3
|
+
function normalize(text: string): string {
|
|
4
|
+
return text
|
|
5
|
+
.toLowerCase()
|
|
6
|
+
.replace(/[`*_~]/g, ' ')
|
|
7
|
+
.replace(/\s+/g, ' ')
|
|
8
|
+
.trim()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Human attention-escalation is a budget hint, not a command. Keep phrases narrow:
|
|
12
|
+
// explicit demands for care, or clear dissatisfaction directed at this response.
|
|
13
|
+
const EN_PHRASES: readonly string[] = [
|
|
14
|
+
'do it properly',
|
|
15
|
+
'do it right',
|
|
16
|
+
'do it correctly',
|
|
17
|
+
'be careful',
|
|
18
|
+
'be thorough',
|
|
19
|
+
'think hard',
|
|
20
|
+
'think harder',
|
|
21
|
+
'think carefully',
|
|
22
|
+
'more carefully',
|
|
23
|
+
'ultrathink',
|
|
24
|
+
'ultrawork',
|
|
25
|
+
'ultracode',
|
|
26
|
+
'wtf',
|
|
27
|
+
'wtf is this',
|
|
28
|
+
'fuck',
|
|
29
|
+
'fucking',
|
|
30
|
+
'fucked',
|
|
31
|
+
'fuck this',
|
|
32
|
+
'fuck off',
|
|
33
|
+
'what the fuck',
|
|
34
|
+
'what the hell',
|
|
35
|
+
'da fuck',
|
|
36
|
+
'the fuck',
|
|
37
|
+
'what are you doing',
|
|
38
|
+
'what are u doing',
|
|
39
|
+
'this is wrong',
|
|
40
|
+
"that's wrong",
|
|
41
|
+
'ffs',
|
|
42
|
+
'for fucks sake',
|
|
43
|
+
'shit',
|
|
44
|
+
'this is shit',
|
|
45
|
+
'bullshit',
|
|
46
|
+
'damn it',
|
|
47
|
+
'damn this',
|
|
48
|
+
'dammit',
|
|
49
|
+
'goddamn',
|
|
50
|
+
'god damn',
|
|
51
|
+
'this is crap',
|
|
52
|
+
'piece of shit',
|
|
53
|
+
'screw this',
|
|
54
|
+
'screwed up',
|
|
55
|
+
'you suck',
|
|
56
|
+
'this sucks',
|
|
57
|
+
'garbage',
|
|
58
|
+
'trash',
|
|
59
|
+
'useless',
|
|
60
|
+
'are you serious',
|
|
61
|
+
'seriously?',
|
|
62
|
+
'are you kidding',
|
|
63
|
+
'you kidding me',
|
|
64
|
+
'come on',
|
|
65
|
+
'cmon',
|
|
66
|
+
'jesus christ',
|
|
67
|
+
'oh my god',
|
|
68
|
+
'omfg',
|
|
69
|
+
'stupid',
|
|
70
|
+
'idiot',
|
|
71
|
+
'moron',
|
|
72
|
+
'pathetic',
|
|
73
|
+
'terrible',
|
|
74
|
+
'awful',
|
|
75
|
+
'broken again',
|
|
76
|
+
'still broken',
|
|
77
|
+
'not again',
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
const KO_PHRASES: readonly string[] = [
|
|
81
|
+
'제대로 해',
|
|
82
|
+
'제대로 좀',
|
|
83
|
+
'똑바로 해',
|
|
84
|
+
'똑바로 좀',
|
|
85
|
+
'잘 좀',
|
|
86
|
+
'잘 해',
|
|
87
|
+
'신중하게',
|
|
88
|
+
'꼼꼼하게',
|
|
89
|
+
'씨발',
|
|
90
|
+
'시발',
|
|
91
|
+
'씨바',
|
|
92
|
+
'ㅅㅂ',
|
|
93
|
+
'시바',
|
|
94
|
+
'존나',
|
|
95
|
+
'졸라',
|
|
96
|
+
'ㅈㄴ',
|
|
97
|
+
'개같',
|
|
98
|
+
'개판',
|
|
99
|
+
'병신',
|
|
100
|
+
'ㅂㅅ',
|
|
101
|
+
'미친',
|
|
102
|
+
'미쳤',
|
|
103
|
+
'ㅁㅊ',
|
|
104
|
+
'엿같',
|
|
105
|
+
'짜증',
|
|
106
|
+
'짜증나',
|
|
107
|
+
'빡치',
|
|
108
|
+
'빡쳐',
|
|
109
|
+
'개소리',
|
|
110
|
+
'말도 안',
|
|
111
|
+
'실화냐',
|
|
112
|
+
'에휴',
|
|
113
|
+
'아오',
|
|
114
|
+
'하…',
|
|
115
|
+
'쓰레기',
|
|
116
|
+
'구려',
|
|
117
|
+
'구리',
|
|
118
|
+
'왜 안',
|
|
119
|
+
'또 안',
|
|
120
|
+
'또 틀',
|
|
121
|
+
'왜 이래',
|
|
122
|
+
'뭐하는 거야',
|
|
123
|
+
'뭐하는거야',
|
|
124
|
+
'뭐 하는 거야',
|
|
125
|
+
'아 진짜',
|
|
126
|
+
'장난해',
|
|
127
|
+
'장난하냐',
|
|
128
|
+
'이게 뭐야',
|
|
129
|
+
'똑바로 안 해',
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
const ES_PHRASES: readonly string[] = [
|
|
133
|
+
'hazlo bien',
|
|
134
|
+
'hazlo correctamente',
|
|
135
|
+
'con cuidado',
|
|
136
|
+
'piensa bien',
|
|
137
|
+
'qué haces',
|
|
138
|
+
'que haces',
|
|
139
|
+
'mierda',
|
|
140
|
+
'joder',
|
|
141
|
+
'jode',
|
|
142
|
+
'puto',
|
|
143
|
+
'puta madre',
|
|
144
|
+
'cabrón',
|
|
145
|
+
'cabron',
|
|
146
|
+
'coño',
|
|
147
|
+
'no jodas',
|
|
148
|
+
'qué carajo',
|
|
149
|
+
'que carajo',
|
|
150
|
+
'carajo',
|
|
151
|
+
'basura',
|
|
152
|
+
'esto es una mierda',
|
|
153
|
+
'es una basura',
|
|
154
|
+
'inútil',
|
|
155
|
+
'inutil',
|
|
156
|
+
'me cago',
|
|
157
|
+
'qué asco',
|
|
158
|
+
'que asco',
|
|
159
|
+
'maldita sea',
|
|
160
|
+
'estás de broma',
|
|
161
|
+
'estas de broma',
|
|
162
|
+
'qué mierda',
|
|
163
|
+
'que mierda',
|
|
164
|
+
'en serio',
|
|
165
|
+
'esto está mal',
|
|
166
|
+
'esto esta mal',
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
const FR_PHRASES: readonly string[] = [
|
|
170
|
+
'fais-le correctement',
|
|
171
|
+
'fais-le bien',
|
|
172
|
+
'sois attentif',
|
|
173
|
+
'réfléchis bien',
|
|
174
|
+
'reflechis bien',
|
|
175
|
+
"qu'est-ce que tu fais",
|
|
176
|
+
'putain',
|
|
177
|
+
'merde',
|
|
178
|
+
'fait chier',
|
|
179
|
+
'fait chié',
|
|
180
|
+
'connerie',
|
|
181
|
+
'conneries',
|
|
182
|
+
'bordel',
|
|
183
|
+
'foutu',
|
|
184
|
+
'fous-toi',
|
|
185
|
+
"c'est de la merde",
|
|
186
|
+
'c’est de la merde',
|
|
187
|
+
"c'est pourri",
|
|
188
|
+
'c’est pourri',
|
|
189
|
+
'tu te fous',
|
|
190
|
+
"n'importe quoi",
|
|
191
|
+
'n’importe quoi',
|
|
192
|
+
'inutile',
|
|
193
|
+
'poubelle',
|
|
194
|
+
'tu déconnes',
|
|
195
|
+
'tu deconnes',
|
|
196
|
+
'c’est nul',
|
|
197
|
+
"c'est nul",
|
|
198
|
+
'sérieusement',
|
|
199
|
+
'serieusement',
|
|
200
|
+
'c’est faux',
|
|
201
|
+
"c'est faux",
|
|
202
|
+
]
|
|
203
|
+
|
|
204
|
+
const IT_PHRASES: readonly string[] = [
|
|
205
|
+
'fallo bene',
|
|
206
|
+
'con attenzione',
|
|
207
|
+
'pensa bene',
|
|
208
|
+
'ma che fai',
|
|
209
|
+
'cazzo',
|
|
210
|
+
'merda',
|
|
211
|
+
'che cazzo',
|
|
212
|
+
'porca',
|
|
213
|
+
'porca miseria',
|
|
214
|
+
'stronzata',
|
|
215
|
+
'stronzate',
|
|
216
|
+
'vaffanculo',
|
|
217
|
+
'è una merda',
|
|
218
|
+
'e una merda',
|
|
219
|
+
'che schifo',
|
|
220
|
+
'schifo',
|
|
221
|
+
'spazzatura',
|
|
222
|
+
'inutile',
|
|
223
|
+
'ma che cavolo',
|
|
224
|
+
'fai schifo',
|
|
225
|
+
'scherzi',
|
|
226
|
+
'che cavolo',
|
|
227
|
+
'sul serio',
|
|
228
|
+
'è sbagliato',
|
|
229
|
+
'e sbagliato',
|
|
230
|
+
]
|
|
231
|
+
|
|
232
|
+
const PT_PHRASES: readonly string[] = [
|
|
233
|
+
'faça direito',
|
|
234
|
+
'faca direito',
|
|
235
|
+
'faça corretamente',
|
|
236
|
+
'faca corretamente',
|
|
237
|
+
'com cuidado',
|
|
238
|
+
'pense bem',
|
|
239
|
+
'que isso',
|
|
240
|
+
'merda',
|
|
241
|
+
'porra',
|
|
242
|
+
'caralho',
|
|
243
|
+
'que merda',
|
|
244
|
+
'que porra',
|
|
245
|
+
'puta que pariu',
|
|
246
|
+
'porcaria',
|
|
247
|
+
'é uma merda',
|
|
248
|
+
'e uma merda',
|
|
249
|
+
'que saco',
|
|
250
|
+
'lixo',
|
|
251
|
+
'inútil',
|
|
252
|
+
'inutil',
|
|
253
|
+
'que droga',
|
|
254
|
+
'tá de brincadeira',
|
|
255
|
+
'ta de brincadeira',
|
|
256
|
+
'foda-se',
|
|
257
|
+
'foda se',
|
|
258
|
+
'está errado',
|
|
259
|
+
'esta errado',
|
|
260
|
+
]
|
|
261
|
+
|
|
262
|
+
const DE_PHRASES: readonly string[] = [
|
|
263
|
+
'mach es richtig',
|
|
264
|
+
'sei gründlich',
|
|
265
|
+
'sei gruendlich',
|
|
266
|
+
'denk nach',
|
|
267
|
+
'sorgfältig',
|
|
268
|
+
'sorgfaeltig',
|
|
269
|
+
'was machst du',
|
|
270
|
+
'was soll das',
|
|
271
|
+
'scheiße',
|
|
272
|
+
'scheisse',
|
|
273
|
+
'scheiss',
|
|
274
|
+
'verdammt',
|
|
275
|
+
'verflucht',
|
|
276
|
+
'so ein mist',
|
|
277
|
+
'blödsinn',
|
|
278
|
+
'bloedsinn',
|
|
279
|
+
'quatsch',
|
|
280
|
+
'das ist mist',
|
|
281
|
+
'das ist müll',
|
|
282
|
+
'das ist mull',
|
|
283
|
+
'müll',
|
|
284
|
+
'schwachsinn',
|
|
285
|
+
'nutzlos',
|
|
286
|
+
'unbrauchbar',
|
|
287
|
+
'verarschst',
|
|
288
|
+
'soll das',
|
|
289
|
+
'im ernst',
|
|
290
|
+
'ernsthaft',
|
|
291
|
+
'das ist falsch',
|
|
292
|
+
]
|
|
293
|
+
|
|
294
|
+
const RU_PHRASES: readonly string[] = [
|
|
295
|
+
'сделай правильно',
|
|
296
|
+
'сделай как надо',
|
|
297
|
+
'внимательно',
|
|
298
|
+
'тщательно',
|
|
299
|
+
'что ты делаешь',
|
|
300
|
+
'что за',
|
|
301
|
+
'блять',
|
|
302
|
+
'бля',
|
|
303
|
+
'блядь',
|
|
304
|
+
'сука',
|
|
305
|
+
'нахуй',
|
|
306
|
+
'нахер',
|
|
307
|
+
'пиздец',
|
|
308
|
+
'хуйня',
|
|
309
|
+
'говно',
|
|
310
|
+
'дерьмо',
|
|
311
|
+
'бред',
|
|
312
|
+
'это бред',
|
|
313
|
+
'фигня',
|
|
314
|
+
'хрень',
|
|
315
|
+
'мусор',
|
|
316
|
+
'бесполезно',
|
|
317
|
+
'издеваешься',
|
|
318
|
+
'охренеть',
|
|
319
|
+
'какого черта',
|
|
320
|
+
'какого чёрта',
|
|
321
|
+
'да блин',
|
|
322
|
+
'серьёзно',
|
|
323
|
+
'серьезно',
|
|
324
|
+
'это неправильно',
|
|
325
|
+
]
|
|
326
|
+
|
|
327
|
+
const ZH_PHRASES: readonly string[] = [
|
|
328
|
+
'认真做',
|
|
329
|
+
'好好做',
|
|
330
|
+
'仔细点',
|
|
331
|
+
'用心做',
|
|
332
|
+
'卧槽',
|
|
333
|
+
'我操',
|
|
334
|
+
'操你',
|
|
335
|
+
'操你妈',
|
|
336
|
+
'我擦',
|
|
337
|
+
'草泥马',
|
|
338
|
+
'我草',
|
|
339
|
+
'草你',
|
|
340
|
+
'我靠',
|
|
341
|
+
'靠北',
|
|
342
|
+
'靠杯',
|
|
343
|
+
'妈的',
|
|
344
|
+
'他妈的',
|
|
345
|
+
'tmd',
|
|
346
|
+
'垃圾',
|
|
347
|
+
'狗屎',
|
|
348
|
+
'搞屁',
|
|
349
|
+
'搞毛',
|
|
350
|
+
'什么垃圾',
|
|
351
|
+
'太烂了',
|
|
352
|
+
'烂代码',
|
|
353
|
+
'废话',
|
|
354
|
+
'神经病',
|
|
355
|
+
'有病',
|
|
356
|
+
'认真点',
|
|
357
|
+
'搞什么',
|
|
358
|
+
'搞什么鬼',
|
|
359
|
+
'你在干什么',
|
|
360
|
+
'什么鬼',
|
|
361
|
+
'认真的吗',
|
|
362
|
+
]
|
|
363
|
+
|
|
364
|
+
const JA_PHRASES: readonly string[] = [
|
|
365
|
+
'ちゃんとやって',
|
|
366
|
+
'しっかりやって',
|
|
367
|
+
'真面目にやって',
|
|
368
|
+
'丁寧に',
|
|
369
|
+
'くそ',
|
|
370
|
+
'クソ',
|
|
371
|
+
'くそが',
|
|
372
|
+
'ふざけんな',
|
|
373
|
+
'ふざけるな',
|
|
374
|
+
'ばか',
|
|
375
|
+
'バカ',
|
|
376
|
+
'あほ',
|
|
377
|
+
'アホ',
|
|
378
|
+
'ゴミ',
|
|
379
|
+
'クズ',
|
|
380
|
+
'ちくしょう',
|
|
381
|
+
'畜生',
|
|
382
|
+
'使えない',
|
|
383
|
+
'最悪',
|
|
384
|
+
'ありえない',
|
|
385
|
+
'うざい',
|
|
386
|
+
'むかつく',
|
|
387
|
+
'なんなの',
|
|
388
|
+
'ksk',
|
|
389
|
+
'何やってんの',
|
|
390
|
+
'何してるの',
|
|
391
|
+
'ふざけてるの',
|
|
392
|
+
'マジで',
|
|
393
|
+
'ちゃんとして',
|
|
394
|
+
]
|
|
395
|
+
|
|
396
|
+
const AR_PHRASES: readonly string[] = [
|
|
397
|
+
'اعملها صح',
|
|
398
|
+
'بعناية',
|
|
399
|
+
'فكر جيدا',
|
|
400
|
+
'تبا',
|
|
401
|
+
'تباً',
|
|
402
|
+
'اللعنة',
|
|
403
|
+
'لعنة',
|
|
404
|
+
'قرف',
|
|
405
|
+
'هراء',
|
|
406
|
+
'حقير',
|
|
407
|
+
'غبي',
|
|
408
|
+
'سخيف',
|
|
409
|
+
'فاشل',
|
|
410
|
+
'هذا هراء',
|
|
411
|
+
'ما هذا الهراء',
|
|
412
|
+
'تافه',
|
|
413
|
+
'زبالة',
|
|
414
|
+
'عديم الفائدة',
|
|
415
|
+
'هل تمزح',
|
|
416
|
+
'ماذا تفعل',
|
|
417
|
+
'ما هذا',
|
|
418
|
+
'بجدية',
|
|
419
|
+
'هذا خطأ',
|
|
420
|
+
]
|
|
421
|
+
|
|
422
|
+
const HI_PHRASES: readonly string[] = [
|
|
423
|
+
'ठीक से करो',
|
|
424
|
+
'ध्यान से',
|
|
425
|
+
'अच्छे से करो',
|
|
426
|
+
'बकवास',
|
|
427
|
+
'यह बकवास है',
|
|
428
|
+
'बेकार',
|
|
429
|
+
'बेवकूफ',
|
|
430
|
+
'घटिया',
|
|
431
|
+
'कचरा',
|
|
432
|
+
'गंदा',
|
|
433
|
+
'मज़ाक',
|
|
434
|
+
'मजाक',
|
|
435
|
+
'धत',
|
|
436
|
+
'क्या बकवास',
|
|
437
|
+
'पागल हो',
|
|
438
|
+
'बहुत बुरा',
|
|
439
|
+
'क्या कर रहे हो',
|
|
440
|
+
'यह गलत है',
|
|
441
|
+
'सच में',
|
|
442
|
+
]
|
|
443
|
+
|
|
444
|
+
const TR_PHRASES: readonly string[] = [
|
|
445
|
+
'düzgün yap',
|
|
446
|
+
'duzgun yap',
|
|
447
|
+
'doğru yap',
|
|
448
|
+
'dogru yap',
|
|
449
|
+
'dikkatli ol',
|
|
450
|
+
'iyice düşün',
|
|
451
|
+
'iyice dusun',
|
|
452
|
+
'siktir',
|
|
453
|
+
'lanet',
|
|
454
|
+
'kahretsin',
|
|
455
|
+
'saçmalık',
|
|
456
|
+
'saçma',
|
|
457
|
+
'bok',
|
|
458
|
+
'boktan',
|
|
459
|
+
'rezalet',
|
|
460
|
+
'berbat',
|
|
461
|
+
'çöp',
|
|
462
|
+
'işe yaramaz',
|
|
463
|
+
'ise yaramaz',
|
|
464
|
+
'aptal',
|
|
465
|
+
'salak',
|
|
466
|
+
'dalga mı',
|
|
467
|
+
'dalga mi',
|
|
468
|
+
'bu ne rezalet',
|
|
469
|
+
'ne yapıyorsun',
|
|
470
|
+
'ne yapiyorsun',
|
|
471
|
+
'ne saçmalık',
|
|
472
|
+
'ne sacmalik',
|
|
473
|
+
'cidden mi',
|
|
474
|
+
'bu yanlış',
|
|
475
|
+
'bu yanlis',
|
|
476
|
+
]
|
|
477
|
+
|
|
478
|
+
const VI_PHRASES: readonly string[] = [
|
|
479
|
+
'làm cho đúng',
|
|
480
|
+
'lam cho dung',
|
|
481
|
+
'làm cẩn thận',
|
|
482
|
+
'lam can than',
|
|
483
|
+
'suy nghĩ kỹ',
|
|
484
|
+
'suy nghi ky',
|
|
485
|
+
'đệch',
|
|
486
|
+
'đếch',
|
|
487
|
+
'vãi',
|
|
488
|
+
'cứt',
|
|
489
|
+
'rác',
|
|
490
|
+
'vô dụng',
|
|
491
|
+
'vo dung',
|
|
492
|
+
'ngớ ngẩn',
|
|
493
|
+
'tệ',
|
|
494
|
+
'tệ hại',
|
|
495
|
+
'quá tệ',
|
|
496
|
+
'đùa à',
|
|
497
|
+
'dua a',
|
|
498
|
+
'vớ vẩn',
|
|
499
|
+
'vo van',
|
|
500
|
+
'chán',
|
|
501
|
+
'đang làm gì vậy',
|
|
502
|
+
'dang lam gi vay',
|
|
503
|
+
'cái gì vậy',
|
|
504
|
+
'cai gi vay',
|
|
505
|
+
'nghiêm túc',
|
|
506
|
+
'nghiem tuc',
|
|
507
|
+
'sai rồi',
|
|
508
|
+
'sai roi',
|
|
509
|
+
]
|
|
510
|
+
|
|
511
|
+
const ID_PHRASES: readonly string[] = [
|
|
512
|
+
'lakukan dengan benar',
|
|
513
|
+
'hati-hati',
|
|
514
|
+
'pikirkan baik-baik',
|
|
515
|
+
'anjing',
|
|
516
|
+
'bangsat',
|
|
517
|
+
'sialan',
|
|
518
|
+
'kampret',
|
|
519
|
+
'goblok',
|
|
520
|
+
'tolol',
|
|
521
|
+
'bodoh',
|
|
522
|
+
'sampah',
|
|
523
|
+
'jelek',
|
|
524
|
+
'payah',
|
|
525
|
+
'tidak berguna',
|
|
526
|
+
'gak guna',
|
|
527
|
+
'omong kosong',
|
|
528
|
+
'yang benar saja',
|
|
529
|
+
'bercanda',
|
|
530
|
+
'lagi ngapain',
|
|
531
|
+
'apa-apaan',
|
|
532
|
+
'ini salah',
|
|
533
|
+
]
|
|
534
|
+
|
|
535
|
+
const ALL_PHRASES: readonly string[] = [
|
|
536
|
+
...EN_PHRASES,
|
|
537
|
+
...KO_PHRASES,
|
|
538
|
+
...ES_PHRASES,
|
|
539
|
+
...FR_PHRASES,
|
|
540
|
+
...IT_PHRASES,
|
|
541
|
+
...PT_PHRASES,
|
|
542
|
+
...DE_PHRASES,
|
|
543
|
+
...RU_PHRASES,
|
|
544
|
+
...ZH_PHRASES,
|
|
545
|
+
...JA_PHRASES,
|
|
546
|
+
...AR_PHRASES,
|
|
547
|
+
...HI_PHRASES,
|
|
548
|
+
...TR_PHRASES,
|
|
549
|
+
...VI_PHRASES,
|
|
550
|
+
...ID_PHRASES,
|
|
551
|
+
]
|
|
552
|
+
|
|
553
|
+
const MORPHEME_PATTERNS: readonly RegExp[] = []
|
|
554
|
+
|
|
555
|
+
const MIN_LENGTH = 2
|
|
556
|
+
|
|
557
|
+
export function detectAttentionEscalation(text: string): boolean {
|
|
558
|
+
if (text.length < MIN_LENGTH) return false
|
|
559
|
+
const normalized = normalize(text)
|
|
560
|
+
if (normalized.length < MIN_LENGTH) return false
|
|
561
|
+
if (ALL_PHRASES.some((phrase) => normalized.includes(phrase))) return true
|
|
562
|
+
return MORPHEME_PATTERNS.some((pattern) => pattern.test(normalized))
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Not `xhigh`: that level is OpenAI-family-only. `high` is universal and
|
|
566
|
+
// `setThinkingLevel` clamps it down per-model, so it's safe to pass unconditionally.
|
|
567
|
+
const ESCALATED_LEVEL: ThinkingLevel = 'high'
|
|
568
|
+
|
|
569
|
+
export function resolveTurnThinkingLevel(
|
|
570
|
+
text: string,
|
|
571
|
+
sessionDefault: ThinkingLevel | undefined,
|
|
572
|
+
): ThinkingLevel | undefined {
|
|
573
|
+
return detectAttentionEscalation(text) ? ESCALATED_LEVEL : sessionDefault
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
type ThinkingLevelSettable = {
|
|
577
|
+
setThinkingLevel(level: ThinkingLevel): void
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// `setThinkingLevel` only mutates reasoning_effort (a per-request param), so a
|
|
581
|
+
// per-turn bump preserves the prompt-prefix cache — no session recreation, no
|
|
582
|
+
// model swap. Skipping the call when nothing resolves leaves the SDK default intact.
|
|
583
|
+
export function applyTurnThinkingLevel(
|
|
584
|
+
session: ThinkingLevelSettable,
|
|
585
|
+
text: string,
|
|
586
|
+
sessionDefault: ThinkingLevel | undefined,
|
|
587
|
+
): void {
|
|
588
|
+
const resolved = resolveTurnThinkingLevel(text, sessionDefault)
|
|
589
|
+
if (resolved !== undefined) session.setThinkingLevel(resolved)
|
|
590
|
+
}
|
|
@@ -576,6 +576,8 @@ async function applyBashSandbox(
|
|
|
576
576
|
const { dirs, files } = resolveHiddenPaths(permissions, origin, agentDir)
|
|
577
577
|
if (dirs.length === 0 && files.length === 0) return
|
|
578
578
|
|
|
579
|
+
const sandboxEnvOverlay = buildRoleScopedConfigEnv(agentDir, dirs, envOverlay)
|
|
580
|
+
|
|
579
581
|
await ensureBwrapAvailable()
|
|
580
582
|
// Per-session /tmp: bind this session's scratch dir over the default
|
|
581
583
|
// --tmpfs /tmp so writes survive across the role's sandboxed bash calls AND
|
|
@@ -671,11 +673,31 @@ async function applyBashSandbox(
|
|
|
671
673
|
cwd: agentDir,
|
|
672
674
|
proc,
|
|
673
675
|
procSelfExe: resolveProcSelfExe(),
|
|
674
|
-
...(
|
|
676
|
+
...(sandboxEnvOverlay !== undefined ? { env: { set: sandboxEnvOverlay } } : {}),
|
|
675
677
|
})
|
|
676
678
|
mutableArgs.command = commandString
|
|
677
679
|
}
|
|
678
680
|
|
|
681
|
+
function buildRoleScopedConfigEnv(
|
|
682
|
+
agentDir: string,
|
|
683
|
+
hiddenDirs: string[],
|
|
684
|
+
envOverlay: BashEnvOverlay | undefined,
|
|
685
|
+
): BashEnvOverlay | undefined {
|
|
686
|
+
// Low-trust roles have workspace/ masked. Do not let container-global config
|
|
687
|
+
// env vars point CLIs back at that private surface: apps that honor XDG should
|
|
688
|
+
// still run, but their config must land in the sandbox's per-session /tmp.
|
|
689
|
+
// Trusted/owner never get here (no hidden dirs), so their Dockerfile-level
|
|
690
|
+
// persistent GWS_CONFIG_HOME remains /agent/workspace/.config/gws.
|
|
691
|
+
const workspaceHidden = hiddenDirs.includes(join(agentDir, 'workspace'))
|
|
692
|
+
if (!workspaceHidden) return envOverlay
|
|
693
|
+
|
|
694
|
+
return {
|
|
695
|
+
...envOverlay,
|
|
696
|
+
XDG_CONFIG_HOME: '/tmp/.config',
|
|
697
|
+
GWS_CONFIG_HOME: '/tmp/.config/gws',
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
679
701
|
function subtractMaskedProtected(
|
|
680
702
|
zones: { root: string; protected: { dirs: string[]; files: string[] } },
|
|
681
703
|
masked: { dirs: string[]; files: string[] },
|
|
@@ -538,16 +538,19 @@ function renderMembershipSummary(
|
|
|
538
538
|
function renderResearchReportDeliveryGuidance(platformInfo: PlatformInfo): string[] {
|
|
539
539
|
if (!platformInfo.supportsAttachments) return []
|
|
540
540
|
return [
|
|
541
|
-
`**Ship
|
|
542
|
-
'attachments. When the user asks for a
|
|
543
|
-
'`researcher` subagent returns `research-<slug>.md` in
|
|
544
|
-
'markdown with `typeclaw-render-pdf` and deliver via',
|
|
541
|
+
`**Ship explicit deliverables as PDFs.** ${platformInfo.displayName} accepts file`,
|
|
542
|
+
'attachments. When the user clearly asks for a PDF/file/export/attachment, a standalone',
|
|
543
|
+
'document/brief, or when a `researcher` subagent returns `research-<slug>.md` in',
|
|
544
|
+
'`<report>`, render the markdown with `typeclaw-render-pdf` and deliver via',
|
|
545
545
|
'`channel_send({ ..., attachments: [{ path, filename }] })` plus a 1–2 line',
|
|
546
|
-
'summary.
|
|
547
|
-
'
|
|
546
|
+
'summary. Do not treat the bare word "report" as enough: routine daily stats,',
|
|
547
|
+
'user trends, status reports, and other operational updates should stay inline',
|
|
548
|
+
'unless the user asks for a downloadable/exported artifact. A `researcher`',
|
|
549
|
+
'`<summary>` is a teaser, NOT the deliverable. Never use an ad-hoc library',
|
|
550
|
+
'(jsPDF, pdfkit, raw-text dump); it breaks markdown/CJK.',
|
|
548
551
|
"For Korean/Japanese/Chinese, follow the skill's CJK guidance and never ship",
|
|
549
552
|
'tofu boxes. Do not paste the full markdown into chat; do not attach the raw `.md`',
|
|
550
|
-
'unless explicitly asked; inline text is
|
|
553
|
+
'unless explicitly asked; inline text is right for routine updates.',
|
|
551
554
|
'',
|
|
552
555
|
]
|
|
553
556
|
}
|
package/src/agent/subagents.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { PermissionService } from '@/permissions'
|
|
|
5
5
|
import type { HookBus } from '@/plugin'
|
|
6
6
|
import type { Stream, Unsubscribe } from '@/stream'
|
|
7
7
|
|
|
8
|
+
import { applyTurnThinkingLevel } from './attention-escalation'
|
|
8
9
|
import { type AgentSession, createSession, type PluginSessionWiring } from './index'
|
|
9
10
|
import { subscribeProviderErrors } from './provider-error'
|
|
10
11
|
import type { SubagentBashPolicy } from './reviewer-bash-policy'
|
|
@@ -304,6 +305,7 @@ export async function invokeSubagent(name: string, options: InvokeSubagentOption
|
|
|
304
305
|
retrievalContext.results.length > 0
|
|
305
306
|
? `${renderTurnTimeAnchor()}\n\n${userPromptForTurn}\n\n${retrievalContext.results}`
|
|
306
307
|
: `${renderTurnTimeAnchor()}\n\n${userPromptForTurn}`
|
|
308
|
+
applyTurnThinkingLevel(session, userPromptForTurn, session.thinkingLevel)
|
|
307
309
|
await session.prompt(turnText)
|
|
308
310
|
} finally {
|
|
309
311
|
if (hooks && turnEvent !== undefined) {
|
|
@@ -62,9 +62,9 @@ Do not narrate routine low-risk tools. Narrate only for multi-step context, risk
|
|
|
62
62
|
|
|
63
63
|
## Delivering reports and documents
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
Produce a polished file only when the user clearly asks for something a human would download, print, forward, attach, export, or keep as a standalone deliverable. Do **not** treat the bare word "report" as enough by itself: routine operational updates, daily stats, user trends, status reports, and other chat-native summaries should stay inline unless the user asks for a file/PDF/export. A summary is a pointer to the deliverable, never the deliverable itself, but only after a deliverable was actually requested.
|
|
66
66
|
|
|
67
|
-
For Markdown-to-PDF, use the bundled \`typeclaw-render-pdf\` skill; it is the supported path and renders headings, lists, and tables. Never hand-roll PDFs with jsPDF, pdfkit, canvas text dumps, raw headless-browser prints, or ReportLab: they often emit raw markup and mojibake for non-Latin text. For Korean/Japanese/Chinese, follow the skill's CJK font guidance and do not ship tofu boxes. Short answers
|
|
67
|
+
For Markdown-to-PDF, use the bundled \`typeclaw-render-pdf\` skill; it is the supported path and renders headings, lists, and tables. Never hand-roll PDFs with jsPDF, pdfkit, canvas text dumps, raw headless-browser prints, or ReportLab: they often emit raw markup and mojibake for non-Latin text. For Korean/Japanese/Chinese, follow the skill's CJK font guidance and do not ship tofu boxes. Short answers, snippets, explanations, and routine reports can stay inline.
|
|
68
68
|
|
|
69
69
|
## Long-running and interactive shell work
|
|
70
70
|
|