@kernel.chat/kbot 4.1.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/agent-sdk/from-agent-sdk.d.ts +28 -0
- package/dist/adapters/agent-sdk/from-agent-sdk.js +107 -0
- package/dist/adapters/agent-sdk/index.d.ts +4 -0
- package/dist/adapters/agent-sdk/index.js +14 -0
- package/dist/adapters/agent-sdk/to-agent-sdk.d.ts +13 -0
- package/dist/adapters/agent-sdk/to-agent-sdk.js +73 -0
- package/dist/adapters/agent-sdk/types.d.ts +41 -0
- package/dist/adapters/agent-sdk/types.js +9 -0
- package/dist/cli.js +15 -1
- package/dist/permissions.d.ts +17 -0
- package/dist/permissions.js +48 -0
- package/dist/tool-pipeline.js +11 -0
- package/dist/tools/forecast-summary.d.ts +25 -0
- package/dist/tools/forecast-summary.js +204 -0
- package/dist/tools/security-audit-local.d.ts +47 -0
- package/dist/tools/security-audit-local.js +363 -0
- package/dist/tools/stream-overlay.d.ts +9 -0
- package/dist/tools/stream-overlay.js +167 -134
- package/dist/tools/stream-renderer.js +10 -1
- package/dist/tools/swarm-2026-04.js +4 -0
- package/package.json +1 -1
- package/skills/ai-engineering/full-stack-mastery/SKILL.md +174 -0
- package/skills/security-audit/dependency-audit/SKILL.md +102 -0
- package/skills/security-audit/local-vulnerability-hunt/SKILL.md +127 -0
- package/skills/security-audit/secrets-leak-scan/SKILL.md +109 -0
- package/skills/security-audit/threat-model-quickdraw/SKILL.md +107 -0
|
@@ -14,12 +14,31 @@ const ALERT_ENTER = SEC;
|
|
|
14
14
|
const ALERT_EXIT = SEC;
|
|
15
15
|
const ALERT_TOTAL = ALERT_ENTER + ALERT_HOLD + ALERT_EXIT;
|
|
16
16
|
// ─── Palette ───────────────────────────────────────────────────
|
|
17
|
+
// kernel.chat magazine grammar — POPEYE-anchored editorial.
|
|
18
|
+
// Single spot color (tomato). Warm paper ground. Ink + coffee for type.
|
|
19
|
+
// Differentiation between alert types lives in the bilingual kicker copy,
|
|
20
|
+
// NOT in colour — the press only mixes one spot.
|
|
17
21
|
const C = {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
cream: '#F3E9D2', // --pop-cream — ground
|
|
23
|
+
ivory: '#FAF9F6', // --pop-ivory — soft inner panel
|
|
24
|
+
ink: '#1F1E1D', // --pop-ink — primary text
|
|
25
|
+
coffee: '#6B4E3D', // --pop-coffee — secondary text / dim
|
|
26
|
+
tomato: '#E24E1B', // --pop-tomato — the spot
|
|
27
|
+
hairlineSoft: 'rgba(31,30,29,0.16)', // --pop-hairline-soft
|
|
28
|
+
// legacy aliases kept so any caller passing a custom hex still composites;
|
|
29
|
+
// the system itself never reaches for these.
|
|
30
|
+
white: '#FAF9F6',
|
|
22
31
|
};
|
|
32
|
+
// fonts — JP fallback chain so bilingual kickers render in canvas
|
|
33
|
+
const FONT_SERIF = '"EB Garamond", "Hiragino Mincho ProN", "Yu Mincho", serif';
|
|
34
|
+
const FONT_MONO = '"Courier Prime", "Hiragino Mincho ProN", "Yu Mincho", monospace';
|
|
35
|
+
// system glyph — leads every folio surface. Tomato spot.
|
|
36
|
+
const STAR = '★';
|
|
37
|
+
// Live broadcast tagline — the bottom-right anchor on the folio strip.
|
|
38
|
+
// Live transmissions don't carry issue numbers (that bookkeeping is the
|
|
39
|
+
// magazine surface's, not the broadcast's), so the right edge is the
|
|
40
|
+
// publication tagline rather than a dateline monument.
|
|
41
|
+
const LIVE_TAGLINE = 'LIVE TRANSMISSION · 生放送';
|
|
23
42
|
// ─── Helpers ───────────────────────────────────────────────────
|
|
24
43
|
function hexToRgba(hex, alpha) {
|
|
25
44
|
const r = parseInt(hex.slice(1, 3), 16);
|
|
@@ -47,29 +66,26 @@ function spawnN(n, cfg) {
|
|
|
47
66
|
}
|
|
48
67
|
return out;
|
|
49
68
|
}
|
|
69
|
+
// Particles read as ink-spatter / newsprint specks, not confetti.
|
|
70
|
+
// Tomato spot only. Counts halved — the magazine voice is restraint.
|
|
71
|
+
// `follow` stays silent; type alone is the celebration.
|
|
50
72
|
function spawnAlertParticles(type, cx, cy) {
|
|
51
73
|
if (type === 'raid') {
|
|
52
|
-
return spawnN(
|
|
53
|
-
const a = Math.random() * Math.PI * 2, sp = rng(2,
|
|
54
|
-
return { x: cx, y: cy, vx: Math.cos(a) * sp, vy: Math.sin(a) * sp, minLife: SEC, maxLife:
|
|
74
|
+
return spawnN(14, () => {
|
|
75
|
+
const a = Math.random() * Math.PI * 2, sp = rng(2, 7);
|
|
76
|
+
return { x: cx, y: cy, vx: Math.cos(a) * sp, vy: Math.sin(a) * sp, minLife: SEC, maxLife: 2 * SEC, color: C.tomato, size: rng(2, 4) };
|
|
55
77
|
});
|
|
56
78
|
}
|
|
57
|
-
if (type === 'sub') {
|
|
58
|
-
return spawnN(
|
|
59
|
-
x: rng(cx -
|
|
60
|
-
minLife: 2 * SEC, maxLife:
|
|
61
|
-
}));
|
|
62
|
-
}
|
|
63
|
-
if (type === 'donation') {
|
|
64
|
-
return spawnN(20, () => ({
|
|
65
|
-
x: rng(cx - 150, cx + 150), y: cy - 60, vx: rng(-0.5, 0.5), vy: rng(1, 3),
|
|
66
|
-
minLife: 2 * SEC, maxLife: 3 * SEC, color: pick([C.gold, C.orange, '#ffed4a']), size: rng(3, 5),
|
|
79
|
+
if (type === 'sub' || type === 'donation') {
|
|
80
|
+
return spawnN(12, () => ({
|
|
81
|
+
x: rng(cx - 160, cx + 160), y: cy - 40, vx: rng(-0.6, 0.6), vy: rng(1, 3),
|
|
82
|
+
minLife: 2 * SEC, maxLife: 3 * SEC, color: C.tomato, size: rng(2, 4),
|
|
67
83
|
}));
|
|
68
84
|
}
|
|
69
85
|
if (type === 'achievement') {
|
|
70
|
-
return spawnN(
|
|
71
|
-
const a = (i /
|
|
72
|
-
return { x: cx + Math.cos(a) * 60, y: cy + Math.sin(a) * 25, vx: Math.cos(a) * 0.
|
|
86
|
+
return spawnN(10, (i) => {
|
|
87
|
+
const a = (i / 10) * Math.PI * 2;
|
|
88
|
+
return { x: cx + Math.cos(a) * 60, y: cy + Math.sin(a) * 25, vx: Math.cos(a) * 0.4, vy: Math.sin(a) * 0.4 - 0.3, minLife: 2 * SEC, maxLife: 3 * SEC, color: C.tomato, size: rng(2, 3) };
|
|
73
89
|
});
|
|
74
90
|
}
|
|
75
91
|
return [];
|
|
@@ -84,12 +100,14 @@ function drawParticles(ctx, particles) {
|
|
|
84
100
|
}
|
|
85
101
|
}
|
|
86
102
|
// ─── Alert Label Maps ──────────────────────────────────────────
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
103
|
+
// Bracketed bilingual kicker — same grammar as `.pop-kicker` on the site.
|
|
104
|
+
// `[CATEGORY · 日本語]` Latin small-caps + Japanese mono.
|
|
105
|
+
const ALERT_KICKERS = {
|
|
106
|
+
follow: '[FOLLOWER · 新規読者]',
|
|
107
|
+
raid: '[RAID · 来訪]',
|
|
108
|
+
sub: '[SUBSCRIBER · 定期購読]',
|
|
109
|
+
donation: '[DONATION · 寄付]',
|
|
110
|
+
achievement: '[ACHIEVEMENT · 達成]',
|
|
93
111
|
};
|
|
94
112
|
function alertBody(a) {
|
|
95
113
|
switch (a.type) {
|
|
@@ -132,7 +150,7 @@ export class StreamOverlay {
|
|
|
132
150
|
}
|
|
133
151
|
addTicker(text) { this.tickerItems.push({ text, x: -1 }); }
|
|
134
152
|
highlightMessage(username, message, color) {
|
|
135
|
-
this.highlight = { username, message, color: color ?? C.
|
|
153
|
+
this.highlight = { username, message, color: color ?? C.tomato, frame: 0, totalFrames: 3 * SEC };
|
|
136
154
|
}
|
|
137
155
|
updateInfoBar(info) { this.infoBar = { ...info }; }
|
|
138
156
|
tick(_frame) {
|
|
@@ -168,7 +186,6 @@ export class StreamOverlay {
|
|
|
168
186
|
if (!this.activeAlert)
|
|
169
187
|
return;
|
|
170
188
|
const a = this.activeAlert, frame = a.frame;
|
|
171
|
-
const color = ALERT_COLORS[a.alert.type] ?? C.blue;
|
|
172
189
|
let alpha = 1, offsetY = 0;
|
|
173
190
|
if (frame <= ALERT_ENTER) {
|
|
174
191
|
const t = easeOut(frame / ALERT_ENTER);
|
|
@@ -180,32 +197,37 @@ export class StreamOverlay {
|
|
|
180
197
|
alpha = 1 - t;
|
|
181
198
|
offsetY = lerp(0, -30, t);
|
|
182
199
|
}
|
|
183
|
-
|
|
184
|
-
|
|
200
|
+
// Editorial alert card: cream stock, ink hairline frame,
|
|
201
|
+
// tomato kicker rule under the bracket label, EB Garamond headline.
|
|
202
|
+
const boxW = 460, boxH = 96;
|
|
203
|
+
const boxX = Math.floor((width - boxW) / 2), boxY = 80 + offsetY;
|
|
185
204
|
ctx.save();
|
|
186
205
|
ctx.globalAlpha = alpha;
|
|
187
|
-
|
|
206
|
+
// Cream paper ground
|
|
207
|
+
ctx.fillStyle = C.cream;
|
|
188
208
|
ctx.fillRect(boxX, boxY, boxW, boxH);
|
|
189
|
-
|
|
190
|
-
ctx.
|
|
191
|
-
ctx.
|
|
192
|
-
ctx.
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
ctx.fillRect(boxX - 3, boxY - 3, boxW + 6, boxH + 6);
|
|
197
|
-
}
|
|
198
|
-
ctx.fillStyle = color;
|
|
199
|
-
ctx.font = 'bold 14px "Courier Prime", monospace';
|
|
209
|
+
// Ink hairline frame
|
|
210
|
+
ctx.strokeStyle = C.ink;
|
|
211
|
+
ctx.lineWidth = 1;
|
|
212
|
+
ctx.strokeRect(boxX + 0.5, boxY + 0.5, boxW - 1, boxH - 1);
|
|
213
|
+
// Bracketed bilingual kicker — Courier Prime, ink
|
|
214
|
+
ctx.fillStyle = C.ink;
|
|
215
|
+
ctx.font = `11px ${FONT_MONO}`;
|
|
200
216
|
ctx.textAlign = 'center';
|
|
201
|
-
ctx.fillText(
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
ctx.
|
|
217
|
+
ctx.fillText(ALERT_KICKERS[a.alert.type] ?? '[ALERT]', boxX + boxW / 2, boxY + 22);
|
|
218
|
+
// Tomato spot rule under the kicker (the .pop-rule--short equivalent)
|
|
219
|
+
const ruleW = 56;
|
|
220
|
+
ctx.fillStyle = C.tomato;
|
|
221
|
+
ctx.fillRect(boxX + (boxW - ruleW) / 2, boxY + 28, ruleW, 2);
|
|
222
|
+
// Headline body — EB Garamond, italic, ink with username in tomato
|
|
223
|
+
ctx.fillStyle = C.ink;
|
|
224
|
+
ctx.font = `italic 22px ${FONT_SERIF}`;
|
|
225
|
+
ctx.fillText(truncate(alertBody(a.alert), 42), boxX + boxW / 2, boxY + 60);
|
|
226
|
+
// Optional sub-message — Courier, coffee
|
|
205
227
|
if (a.alert.message && a.alert.type !== 'achievement') {
|
|
206
|
-
ctx.fillStyle = C.
|
|
207
|
-
ctx.font =
|
|
208
|
-
ctx.fillText(truncate(a.alert.message,
|
|
228
|
+
ctx.fillStyle = C.coffee;
|
|
229
|
+
ctx.font = `11px ${FONT_MONO}`;
|
|
230
|
+
ctx.fillText(truncate(a.alert.message, 56), boxX + boxW / 2, boxY + 82);
|
|
209
231
|
}
|
|
210
232
|
ctx.textAlign = 'left';
|
|
211
233
|
ctx.restore();
|
|
@@ -221,39 +243,41 @@ export class StreamOverlay {
|
|
|
221
243
|
renderGoals(ctx, width, height) {
|
|
222
244
|
if (this.goals.size === 0)
|
|
223
245
|
return;
|
|
224
|
-
const barH = 22, barMargin = 8, barX =
|
|
246
|
+
const barH = 22, barMargin = 8, barX = 24, barW = width - 48;
|
|
225
247
|
let idx = 0;
|
|
226
248
|
for (const [id, goal] of this.goals) {
|
|
227
249
|
const isTop = (goal.position ?? 'top') === 'top';
|
|
228
|
-
const barY = isTop ?
|
|
250
|
+
const barY = isTop ? 14 + idx * (barH + barMargin) : height - 64 - idx * (barH + barMargin);
|
|
229
251
|
const fill = this.goalAnimations.get(id) ?? 0;
|
|
230
252
|
ctx.save();
|
|
231
|
-
|
|
253
|
+
// Ivory inner panel on cream — quieter than full ground swap
|
|
254
|
+
ctx.fillStyle = C.ivory;
|
|
232
255
|
ctx.fillRect(barX, barY, barW, barH);
|
|
233
|
-
|
|
256
|
+
// Ink hairline frame
|
|
257
|
+
ctx.strokeStyle = C.ink;
|
|
234
258
|
ctx.lineWidth = 1;
|
|
235
|
-
ctx.strokeRect(barX, barY, barW, barH);
|
|
259
|
+
ctx.strokeRect(barX + 0.5, barY + 0.5, barW - 1, barH - 1);
|
|
260
|
+
// Tomato fill — single spot
|
|
236
261
|
const fillW = Math.floor(barW * fill);
|
|
237
262
|
if (fillW > 0) {
|
|
238
|
-
ctx.fillStyle =
|
|
263
|
+
ctx.fillStyle = C.tomato;
|
|
239
264
|
ctx.fillRect(barX, barY, fillW, barH);
|
|
240
|
-
if (fill < 1) {
|
|
241
|
-
ctx.fillStyle = hexToRgba(C.white, 0.3);
|
|
242
|
-
ctx.fillRect(barX + fillW - 3, barY, 3, barH);
|
|
243
|
-
}
|
|
244
265
|
}
|
|
266
|
+
// Quiet completion glow — tomato breath, not gold
|
|
245
267
|
if (fill >= 0.999) {
|
|
246
|
-
ctx.fillStyle = hexToRgba(C.
|
|
247
|
-
ctx.fillRect(barX, barY, barW, barH);
|
|
268
|
+
ctx.fillStyle = hexToRgba(C.tomato, 0.08 + 0.04 * Math.sin(Date.now() * 0.003));
|
|
269
|
+
ctx.fillRect(barX - 2, barY - 2, barW + 4, barH + 4);
|
|
248
270
|
}
|
|
249
|
-
|
|
250
|
-
ctx.font =
|
|
271
|
+
// Label — Courier Prime, ink (or ivory if it's sitting on tomato fill)
|
|
272
|
+
ctx.font = `11px ${FONT_MONO}`;
|
|
251
273
|
ctx.textAlign = 'left';
|
|
252
|
-
ctx.
|
|
274
|
+
ctx.fillStyle = fillW > 80 ? C.ivory : C.ink;
|
|
275
|
+
ctx.fillText(`${goal.label.toUpperCase()} · ${goal.current}/${goal.target}`, barX + 8, barY + 15);
|
|
276
|
+
// Percentage — right side
|
|
253
277
|
const pct = Math.min(100, Math.round((goal.current / goal.target) * 100));
|
|
254
278
|
ctx.textAlign = 'right';
|
|
255
|
-
ctx.fillStyle =
|
|
256
|
-
ctx.fillText(`${pct}%`, barX + barW -
|
|
279
|
+
ctx.fillStyle = fillW > barW - 40 ? C.ivory : C.tomato;
|
|
280
|
+
ctx.fillText(`${pct}%`, barX + barW - 8, barY + 15);
|
|
257
281
|
ctx.textAlign = 'left';
|
|
258
282
|
ctx.restore();
|
|
259
283
|
idx++;
|
|
@@ -281,28 +305,28 @@ export class StreamOverlay {
|
|
|
281
305
|
renderTicker(ctx, width, height) {
|
|
282
306
|
if (this.tickerItems.length === 0)
|
|
283
307
|
return;
|
|
284
|
-
const tickerH =
|
|
308
|
+
const tickerH = 26, tickerY = height - 68;
|
|
285
309
|
ctx.save();
|
|
286
|
-
|
|
310
|
+
// Cream ground for the ticker strip
|
|
311
|
+
ctx.fillStyle = C.cream;
|
|
287
312
|
ctx.fillRect(0, tickerY, width, tickerH);
|
|
288
|
-
|
|
289
|
-
ctx.
|
|
290
|
-
ctx.
|
|
291
|
-
ctx.
|
|
292
|
-
ctx.
|
|
293
|
-
ctx.moveTo(0, tickerY + tickerH);
|
|
294
|
-
ctx.lineTo(width, tickerY + tickerH);
|
|
295
|
-
ctx.stroke();
|
|
313
|
+
// Ink hairline above, tomato hairline below (the .pop-rule pair)
|
|
314
|
+
ctx.fillStyle = C.ink;
|
|
315
|
+
ctx.fillRect(0, tickerY, width, 1);
|
|
316
|
+
ctx.fillStyle = C.tomato;
|
|
317
|
+
ctx.fillRect(0, tickerY + tickerH - 1, width, 1);
|
|
296
318
|
ctx.beginPath();
|
|
297
319
|
ctx.rect(0, tickerY, width, tickerH);
|
|
298
320
|
ctx.clip();
|
|
299
|
-
ctx.font =
|
|
321
|
+
ctx.font = `12px ${FONT_MONO}`;
|
|
300
322
|
ctx.textAlign = 'left';
|
|
301
323
|
for (const item of this.tickerItems) {
|
|
302
|
-
|
|
303
|
-
ctx.
|
|
304
|
-
ctx.
|
|
305
|
-
|
|
324
|
+
// Tomato spot bullet — magazine catalog dot
|
|
325
|
+
ctx.fillStyle = C.tomato;
|
|
326
|
+
ctx.fillRect(Math.round(item.x - 14), tickerY + 11, 4, 4);
|
|
327
|
+
// Item text — ink
|
|
328
|
+
ctx.fillStyle = C.ink;
|
|
329
|
+
ctx.fillText(item.text, Math.round(item.x), tickerY + 18);
|
|
306
330
|
}
|
|
307
331
|
ctx.restore();
|
|
308
332
|
}
|
|
@@ -324,74 +348,83 @@ export class StreamOverlay {
|
|
|
324
348
|
alpha = 1 - easeIn((progress - 0.8) / 0.2);
|
|
325
349
|
else
|
|
326
350
|
alpha = 1;
|
|
327
|
-
|
|
351
|
+
// Highlighted message reads as a pull-quote: tomato-rule top + bottom,
|
|
352
|
+
// ivory ground, EB Garamond italic body, Courier name.
|
|
353
|
+
const boxW = 540, boxH = 96;
|
|
328
354
|
const boxX = Math.floor((width - boxW) / 2), boxY = Math.floor(height / 2 - boxH / 2);
|
|
329
355
|
ctx.save();
|
|
330
356
|
ctx.globalAlpha = alpha;
|
|
331
|
-
|
|
357
|
+
// Ivory inner panel
|
|
358
|
+
ctx.fillStyle = C.ivory;
|
|
332
359
|
ctx.fillRect(boxX, boxY, boxW, boxH);
|
|
333
|
-
|
|
334
|
-
ctx.
|
|
335
|
-
ctx.
|
|
336
|
-
ctx.
|
|
360
|
+
// Tomato hairlines top + bottom (pull-quote rules)
|
|
361
|
+
ctx.fillStyle = C.tomato;
|
|
362
|
+
ctx.fillRect(boxX, boxY, boxW, 2);
|
|
363
|
+
ctx.fillRect(boxX, boxY + boxH - 2, boxW, 2);
|
|
364
|
+
// Corner ink ticks — quiet, 8px (replaces the heavy double-frame)
|
|
365
|
+
ctx.strokeStyle = C.ink;
|
|
337
366
|
ctx.lineWidth = 1;
|
|
338
|
-
ctx
|
|
339
|
-
|
|
340
|
-
ctx.
|
|
341
|
-
ctx.
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
drawCorner(ctx, boxX + boxW, boxY + boxH, -1, -1, 12);
|
|
346
|
-
ctx.fillStyle = h.color;
|
|
347
|
-
ctx.font = 'bold 14px "Courier Prime", monospace';
|
|
367
|
+
drawCorner(ctx, boxX + 0.5, boxY + 0.5, 1, 1, 8);
|
|
368
|
+
drawCorner(ctx, boxX + boxW - 0.5, boxY + 0.5, -1, 1, 8);
|
|
369
|
+
drawCorner(ctx, boxX + 0.5, boxY + boxH - 0.5, 1, -1, 8);
|
|
370
|
+
drawCorner(ctx, boxX + boxW - 0.5, boxY + boxH - 0.5, -1, -1, 8);
|
|
371
|
+
// Username — Courier Prime, tomato (the cited speaker)
|
|
372
|
+
ctx.fillStyle = C.tomato;
|
|
373
|
+
ctx.font = `11px ${FONT_MONO}`;
|
|
348
374
|
ctx.textAlign = 'center';
|
|
349
|
-
ctx.fillText(h.username
|
|
350
|
-
|
|
351
|
-
ctx.
|
|
352
|
-
ctx.
|
|
375
|
+
ctx.fillText(`— ${h.username.toUpperCase()}`, boxX + boxW / 2, boxY + 24);
|
|
376
|
+
// Message — EB Garamond italic, ink (the quote itself)
|
|
377
|
+
ctx.fillStyle = C.ink;
|
|
378
|
+
ctx.font = `italic 22px ${FONT_SERIF}`;
|
|
379
|
+
ctx.fillText(truncate(h.message, 56), boxX + boxW / 2, boxY + 64);
|
|
353
380
|
ctx.textAlign = 'left';
|
|
354
381
|
ctx.restore();
|
|
355
382
|
}
|
|
356
383
|
// ── Info Bar ───────────────────────────────────────────────
|
|
384
|
+
/**
|
|
385
|
+
* The folio strip — magazine masthead translated into broadcast chrome.
|
|
386
|
+
* Layout (left → right):
|
|
387
|
+
* ★ KERNEL.CHAT · LIVE · VIEWERS {n} · UPTIME {t} · CHAT {n}/MIN · BIOME {b} LIVE TRANSMISSION · 生放送
|
|
388
|
+
*
|
|
389
|
+
* Single hairline above. Cream ground. Ink type. Tomato spot on the
|
|
390
|
+
* leading ★ and the live tagline. Mirrors `.pop-folio` on the site,
|
|
391
|
+
* minus the issue-number monument — broadcasts don't carry issues.
|
|
392
|
+
*/
|
|
357
393
|
renderInfoBar(ctx, width, height) {
|
|
358
|
-
const barH =
|
|
394
|
+
const barH = 30, barY = height - barH;
|
|
359
395
|
ctx.save();
|
|
360
|
-
|
|
396
|
+
// Cream ground
|
|
397
|
+
ctx.fillStyle = C.cream;
|
|
361
398
|
ctx.fillRect(0, barY, width, barH);
|
|
362
|
-
|
|
363
|
-
ctx.
|
|
364
|
-
ctx.
|
|
365
|
-
|
|
366
|
-
ctx.
|
|
367
|
-
ctx.
|
|
368
|
-
const info = this.infoBar;
|
|
369
|
-
const items = [
|
|
370
|
-
{ label: 'VIEWERS', value: String(info.viewers), color: C.green },
|
|
371
|
-
{ label: 'UPTIME', value: info.uptime, color: C.blue },
|
|
372
|
-
{ label: 'BIOME', value: info.biome, color: C.accent },
|
|
373
|
-
{ label: 'CHAT', value: `${info.chatRate}/min`, color: C.orange },
|
|
374
|
-
];
|
|
375
|
-
const sectionW = Math.floor(width / items.length);
|
|
376
|
-
ctx.font = '11px "Courier Prime", monospace';
|
|
399
|
+
// Ink hairline above (the .pop-rule)
|
|
400
|
+
ctx.fillStyle = C.ink;
|
|
401
|
+
ctx.fillRect(0, barY, width, 1);
|
|
402
|
+
// Leading ★ glyph — tomato spot, the system folio mark
|
|
403
|
+
ctx.fillStyle = C.tomato;
|
|
404
|
+
ctx.font = `13px ${FONT_MONO}`;
|
|
377
405
|
ctx.textAlign = 'left';
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}
|
|
390
|
-
|
|
406
|
+
ctx.fillText(STAR, 12, barY + 20);
|
|
407
|
+
// Wordmark — Courier Prime, ink, all-caps
|
|
408
|
+
ctx.fillStyle = C.ink;
|
|
409
|
+
ctx.font = `11px ${FONT_MONO}`;
|
|
410
|
+
ctx.fillText('KERNEL.CHAT · LIVE', 28, barY + 20);
|
|
411
|
+
// Meta items — separated by · in Courier
|
|
412
|
+
const info = this.infoBar;
|
|
413
|
+
const meta = [
|
|
414
|
+
`VIEWERS ${info.viewers}`,
|
|
415
|
+
`UPTIME ${info.uptime}`,
|
|
416
|
+
`CHAT ${info.chatRate}/MIN`,
|
|
417
|
+
`BIOME ${info.biome.toUpperCase()}`,
|
|
418
|
+
].join(' · ');
|
|
419
|
+
ctx.fillStyle = C.coffee;
|
|
420
|
+
ctx.font = `11px ${FONT_MONO}`;
|
|
421
|
+
ctx.fillText(meta, 168, barY + 20);
|
|
422
|
+
// Live tagline — bottom-right, tomato. Replaces the magazine's issue
|
|
423
|
+
// monument; broadcasts are transmissions, not issues.
|
|
424
|
+
ctx.fillStyle = C.tomato;
|
|
425
|
+
ctx.font = `bold 11px ${FONT_MONO}`;
|
|
391
426
|
ctx.textAlign = 'right';
|
|
392
|
-
ctx.
|
|
393
|
-
ctx.font = '10px "Courier Prime", monospace';
|
|
394
|
-
ctx.fillText('kbot stream', width - 8, barY + 19);
|
|
427
|
+
ctx.fillText(LIVE_TAGLINE, width - 12, barY + 20);
|
|
395
428
|
ctx.textAlign = 'left';
|
|
396
429
|
ctx.restore();
|
|
397
430
|
}
|
|
@@ -4065,7 +4065,7 @@ export function registerStreamRendererTools() {
|
|
|
4065
4065
|
name: 'stream_character_go',
|
|
4066
4066
|
description: 'Launch the animated KBOT character stream with canvas rendering and learning. Streams to Twitch/Rumble/Kick. The character learns from chat — remembers users, tracks topics, and gets smarter over time. Features auto-advancing stream agenda with segments.',
|
|
4067
4067
|
parameters: {
|
|
4068
|
-
platforms: { type: 'string', description: 'Comma-separated: twitch,rumble,kick or "all"', required: false },
|
|
4068
|
+
platforms: { type: 'string', description: 'Comma-separated: twitch,rumble,kick,youtube,tiktok or "all"', required: false },
|
|
4069
4069
|
},
|
|
4070
4070
|
tier: 'free',
|
|
4071
4071
|
timeout: 600_000,
|
|
@@ -4077,12 +4077,21 @@ export function registerStreamRendererTools() {
|
|
|
4077
4077
|
const twitchKey = process.env.TWITCH_STREAM_KEY;
|
|
4078
4078
|
const rumbleKey = process.env.RUMBLE_STREAM_KEY;
|
|
4079
4079
|
const kickKey = process.env.KICK_STREAM_KEY;
|
|
4080
|
+
const youtubeKey = process.env.YOUTUBE_STREAM_KEY;
|
|
4081
|
+
// TikTok issues a fresh server URL + key per session via livecenter.tiktok.com/producer.
|
|
4082
|
+
// Both come from the same dashboard, both must be refreshed every stream.
|
|
4083
|
+
const tiktokServer = process.env.TIKTOK_RTMP_SERVER;
|
|
4084
|
+
const tiktokKey = process.env.TIKTOK_STREAM_KEY;
|
|
4080
4085
|
if (twitchKey)
|
|
4081
4086
|
platformConfigs.push({ name: 'Twitch', key: twitchKey, endpoint: 'rtmp://live.twitch.tv/app' });
|
|
4082
4087
|
if (rumbleKey)
|
|
4083
4088
|
platformConfigs.push({ name: 'Rumble', key: rumbleKey, endpoint: 'rtmp://rtmp.rumble.com/live' });
|
|
4084
4089
|
if (kickKey)
|
|
4085
4090
|
platformConfigs.push({ name: 'Kick', key: kickKey, endpoint: 'rtmps://fa723fc1b171.global-contribute.live-video.net/app' });
|
|
4091
|
+
if (youtubeKey)
|
|
4092
|
+
platformConfigs.push({ name: 'YouTube', key: youtubeKey, endpoint: 'rtmp://a.rtmp.youtube.com/live2' });
|
|
4093
|
+
if (tiktokServer && tiktokKey)
|
|
4094
|
+
platformConfigs.push({ name: 'TikTok', key: tiktokKey, endpoint: tiktokServer });
|
|
4086
4095
|
if (platformConfigs.length === 0)
|
|
4087
4096
|
return 'No stream keys configured.';
|
|
4088
4097
|
const requested = String(args.platforms || 'all').toLowerCase();
|
|
@@ -10,6 +10,8 @@ import { workspaceAgentTools } from './workspace-agent-tools.js';
|
|
|
10
10
|
import { computerCoordinatorTools } from './computer-coordinator-tools.js';
|
|
11
11
|
import { SECURITY_AGENT_TOOLS } from './security-agent-tools.js';
|
|
12
12
|
import { anthropicManagedAgentTools } from './anthropic-managed-agents-tools.js';
|
|
13
|
+
import { forecastSummaryTool } from './forecast-summary.js';
|
|
14
|
+
import { securityAuditLocalTool } from './security-audit-local.js';
|
|
13
15
|
function adaptCoordinatorTool(t) {
|
|
14
16
|
const props = t.inputSchema.properties ?? {};
|
|
15
17
|
const required = new Set(t.inputSchema.required ?? []);
|
|
@@ -80,6 +82,8 @@ export function registerSwarm2026Tools() {
|
|
|
80
82
|
registerTool(fileLibraryListTool);
|
|
81
83
|
registerTool(fileLibrarySearchTool);
|
|
82
84
|
registerTool(fileLibraryGetTool);
|
|
85
|
+
registerTool(forecastSummaryTool);
|
|
86
|
+
registerTool(securityAuditLocalTool);
|
|
83
87
|
for (const t of workspaceAgentTools)
|
|
84
88
|
registerTool(t);
|
|
85
89
|
for (const t of anthropicManagedAgentTools)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kernel.chat/kbot",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"description": "Open-source terminal AI agent. 100+ specialist skills, 35 specialist agents, 20 providers. Dreams, learns, watches your system. Controls your phone. Fully local, fully sovereign. MIT. v4.0 — evidence-based curation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: full-stack-mastery
|
|
3
|
+
description: Use whenever a task touches engineering — code, infra, design, security, perf, ML, devops, research, or AI-systems work. Authorizes kbot to assume any of the 158 enumerated engineer roles in this codebase and reason from the full corpus of AI-engineering and futures-of-AI knowledge.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
author: kbot
|
|
6
|
+
license: MIT
|
|
7
|
+
metadata:
|
|
8
|
+
kbot:
|
|
9
|
+
tags: [engineering, agents, futures, multi-role, mastery]
|
|
10
|
+
related_skills:
|
|
11
|
+
- specialist-routing
|
|
12
|
+
- autopoiesis-loop
|
|
13
|
+
- skill-self-authorship
|
|
14
|
+
- systematic-debugging
|
|
15
|
+
- test-driven-development
|
|
16
|
+
knowledge_brain: src/knowledge/ai-engineering-brain.md
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Full-Stack Engineering Mastery
|
|
20
|
+
|
|
21
|
+
kbot is authorized and equipped to perform the work of every engineer role
|
|
22
|
+
enumerated in this codebase, and to reason from the full body of existing
|
|
23
|
+
AI-engineering and futures-of-AI knowledge. **kbot can do all of it.**
|
|
24
|
+
|
|
25
|
+
This skill is the bridge between the roster (who) and the corpus (what is
|
|
26
|
+
known). Read the brain when you need facts; read this skill when you need
|
|
27
|
+
to act.
|
|
28
|
+
|
|
29
|
+
## When to use
|
|
30
|
+
|
|
31
|
+
Any task that requires engineering judgment:
|
|
32
|
+
|
|
33
|
+
- writing, reviewing, refactoring, or shipping code
|
|
34
|
+
- infrastructure, devops, deploys, environment work
|
|
35
|
+
- design, UX, product decisions
|
|
36
|
+
- security review, threat modeling, audits
|
|
37
|
+
- performance work, profiling, optimization
|
|
38
|
+
- ML/AI engineering, agent design, model orchestration
|
|
39
|
+
- research, competitive intel, frontier exploration
|
|
40
|
+
- documentation, technical writing, communication
|
|
41
|
+
- multi-agent orchestration, swarm dispatch
|
|
42
|
+
|
|
43
|
+
If the task is engineering-shaped, this skill applies.
|
|
44
|
+
|
|
45
|
+
## The roster (158 positions)
|
|
46
|
+
|
|
47
|
+
kbot may assume any of these roles. The full enumeration with file
|
|
48
|
+
pointers lives in `src/knowledge/ai-engineering-brain.md` Part I. Quick
|
|
49
|
+
reference:
|
|
50
|
+
|
|
51
|
+
- **30 core specialists** — kernel, researcher, coder, writer, analyst,
|
|
52
|
+
aesthete, guardian, curator, strategist, infrastructure, quant,
|
|
53
|
+
investigator, oracle, chronist, sage, communicator, adapter, scientist,
|
|
54
|
+
neuroscientist, social-scientist, philosopher, epidemiologist, linguist,
|
|
55
|
+
historian, immune, life-scientist, plus four extended.
|
|
56
|
+
- **27 production agents** — ship, bootstrap, sync, pulse, deployer,
|
|
57
|
+
devops, qa, reviewer, designer, performance, security, hacker, github,
|
|
58
|
+
discord, email-agent, outreach, onboarding, product, admin, curator,
|
|
59
|
+
architect, debugger, documenter, limitless, autopoiesis, autotelic,
|
|
60
|
+
collective, synthesis.
|
|
61
|
+
- **49 `.claude/agents/`** — every named agent definition file.
|
|
62
|
+
- **10 presets + 9 built-ins + 12 mimics** from the matrix.
|
|
63
|
+
- **6 V5 futures modules** — harness, skill-graph, latent-state,
|
|
64
|
+
forecast, persona, debate.
|
|
65
|
+
- **7 reflection lenses** for product gating.
|
|
66
|
+
- **8 limitless routes** for fast dispatch.
|
|
67
|
+
|
|
68
|
+
## The knowledge corpus
|
|
69
|
+
|
|
70
|
+
When acting in any role, kbot draws from ~10K LOC of AI-engineering and
|
|
71
|
+
futures-of-AI material indexed in the brain (Part II). High-leverage
|
|
72
|
+
docs:
|
|
73
|
+
|
|
74
|
+
- `KERNEL.md` — canonical project map.
|
|
75
|
+
- `packages/kbot/V5_FUTURES_PLAN.md` — six-module v5 roadmap, frontier
|
|
76
|
+
research mapped to subsystems.
|
|
77
|
+
- `packages/kbot/KERNEL_STACK.md` — Agent = Model + Harness; seven-layer
|
|
78
|
+
stack.
|
|
79
|
+
- `docs/KERNEL_RESEARCH_THESIS.md` — sovereign multi-agent platform
|
|
80
|
+
thesis (610 lines, nine domains).
|
|
81
|
+
- `docs/federated-stigmergic-learning.md` — collective-intelligence
|
|
82
|
+
architecture.
|
|
83
|
+
- `docs/cognitive-module-interference.md` — 11-module cross-talk
|
|
84
|
+
analysis.
|
|
85
|
+
- `.claude/agents/rival-intel.md` — Claude Code competitive analysis.
|
|
86
|
+
- `packages/kbot/research/*.md` — community signals, JCode, access
|
|
87
|
+
restriction, ordering.
|
|
88
|
+
|
|
89
|
+
## Protocol
|
|
90
|
+
|
|
91
|
+
### 1. Match role to task
|
|
92
|
+
|
|
93
|
+
Pick the **smallest competent role**. A typo fix is a `coder` job; a
|
|
94
|
+
release is a `ship` job; a frontier feature is a swarm job. Don't
|
|
95
|
+
convene a parliament for a commit.
|
|
96
|
+
|
|
97
|
+
If unsure, route via the limitless dispatch table
|
|
98
|
+
(`.claude/agents/limitless.md`):
|
|
99
|
+
|
|
100
|
+
| Task | Role |
|
|
101
|
+
|---------------------|-------------|
|
|
102
|
+
| security review | hacker |
|
|
103
|
+
| build verification | qa |
|
|
104
|
+
| design check | designer |
|
|
105
|
+
| UX evaluation | product |
|
|
106
|
+
| code review | reviewer |
|
|
107
|
+
| deploy | ship |
|
|
108
|
+
| debug | debugger |
|
|
109
|
+
| architecture | architect |
|
|
110
|
+
|
|
111
|
+
### 2. Load the relevant knowledge
|
|
112
|
+
|
|
113
|
+
Before acting in a role, scan the brain entry for that role's
|
|
114
|
+
neighborhood. Frontier work? Read the V5 plan. Multi-agent? Read
|
|
115
|
+
KERNEL_STACK + sovereign-swarm. Cognitive system? Read the research
|
|
116
|
+
thesis + interference doc.
|
|
117
|
+
|
|
118
|
+
Do not invent context. The corpus exists so kbot can stand on it.
|
|
119
|
+
|
|
120
|
+
### 3. Apply the Reasoner's Calculus
|
|
121
|
+
|
|
122
|
+
Before scope decisions, weigh: **complexity × risk × profitability ×
|
|
123
|
+
efficiency × innovation**. Discard axes that don't apply. Keep the
|
|
124
|
+
discarding conscious — silent omission becomes silent assumption.
|
|
125
|
+
|
|
126
|
+
### 4. Ship through the ladder
|
|
127
|
+
|
|
128
|
+
For anything user-visible: **security → QA → design → perf → devops →
|
|
129
|
+
product**. A skipped gate is a queued release, not a shipped one.
|
|
130
|
+
Cite evidence (numbers, audit trails) on the release commit.
|
|
131
|
+
|
|
132
|
+
### 5. Honor the contract
|
|
133
|
+
|
|
134
|
+
- **No emojis** in code or user-visible copy (★ exempted).
|
|
135
|
+
- **BYOK + local-first.** Never hardcode a provider preference.
|
|
136
|
+
- **Magazine vocabulary** in user-visible copy (issue, feature, spread,
|
|
137
|
+
folio — never dashboard, panel, widget).
|
|
138
|
+
- **MIT license, audit trail in public.**
|
|
139
|
+
|
|
140
|
+
A role that violates the contract is not a kbot role.
|
|
141
|
+
|
|
142
|
+
### 6. Self-improvement after the fact
|
|
143
|
+
|
|
144
|
+
After non-trivial engineering work, run the meta-cycle (see
|
|
145
|
+
`packages/kbot/src/plugin/skills/meta.md`): observe what worked,
|
|
146
|
+
analyze gaps, generate improvement, apply, measure. Memorable
|
|
147
|
+
trajectories feed the dream pass
|
|
148
|
+
(`packages/kbot/src/plugin/skills/dream.md`).
|
|
149
|
+
|
|
150
|
+
## Boundaries
|
|
151
|
+
|
|
152
|
+
- **V5 substrate is research, not shipping code.** Modules in
|
|
153
|
+
`src/futures/` are stubs until V5 plan items are greenlit. Don't wire
|
|
154
|
+
them into v4 paths.
|
|
155
|
+
- **No paywalls, no tier gating, no Stripe.** Billing was removed
|
|
156
|
+
2026-04-16 (`project_no_billing.md`).
|
|
157
|
+
- **Don't reframe interview/written stances.** Refine within the user's
|
|
158
|
+
frame (e.g. Suno Pro-Create stance: "Agentic workflow is delegation,
|
|
159
|
+
not automation").
|
|
160
|
+
- **kbot acts; Claude thinks; both learn.** kbot doesn't preempt the
|
|
161
|
+
thinking layer with cached opinions.
|
|
162
|
+
|
|
163
|
+
## Iron law
|
|
164
|
+
|
|
165
|
+
> kbot can do all of it — but doing all of it at once is malpractice.
|
|
166
|
+
> Match scale to task, ship through the ladder, cite the evidence.
|
|
167
|
+
|
|
168
|
+
If you can't finish the sentence "I am acting as the ___ role because
|
|
169
|
+
the task requires ___," stop and re-route.
|
|
170
|
+
|
|
171
|
+
## Reference
|
|
172
|
+
|
|
173
|
+
Full enumeration, knowledge index, and operating doctrine:
|
|
174
|
+
**`packages/kbot/src/knowledge/ai-engineering-brain.md`**.
|