@selesai/code 0.2.1 → 0.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/config.d.ts +4 -15
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -45
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +1 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +8 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/model-registry.d.ts +4 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +101 -51
- package/dist/core/model-registry.js.map +1 -1
- package/dist/defaults/models.json +64 -113
- package/dist/extensions/copy-turn.ts +2 -2
- package/dist/extensions/pi-powerline-footer/bash-mode/editor.ts +2 -2
- package/dist/extensions/pi-powerline-footer/index.ts +31 -31
- package/dist/extensions/pi-powerline-footer/package.json +2 -2
- package/dist/extensions/pi-powerline-footer/tests/bash-mode.test.ts +10 -10
- package/dist/extensions/pi-powerline-footer/tests/jump-shortcuts.test.ts +1 -1
- package/dist/extensions/pi-powerline-footer/tests/working-vibes.test.ts +2 -2
- package/dist/extensions/pi-powerline-footer/theme.ts +6 -6
- package/dist/extensions/pi-powerline-footer/tps.ts +1 -1
- package/dist/extensions/pi-powerline-footer/types.ts +7 -7
- package/dist/extensions/pi-powerline-footer/working-vibes.ts +51 -51
- package/dist/extensions/pi-subagents/agents/architect.md +188 -0
- package/dist/extensions/pi-subagents/agents/builder.md +120 -0
- package/dist/extensions/pi-subagents/agents/commentator.md +131 -0
- package/dist/extensions/pi-subagents/agents/explorer.md +51 -0
- package/dist/extensions/pi-subagents/agents/recapper.md +21 -0
- package/dist/extensions/pi-subagents/src/shared/utils.ts +9 -3
- package/dist/extensions/pi-web-agent/package.json +2 -2
- package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +2 -2
- package/dist/extensions/pi-web-agent/src/commands/web-agent-config.ts +1 -1
- package/dist/extensions/pi-web-agent/src/extension.ts +1 -1
- package/dist/extensions/pi-web-agent/src/presentation/config-store.ts +1 -1
- package/dist/extensions/question/helpers.ts +3 -3
- package/dist/extensions/question/index.ts +2 -2
- package/dist/extensions/question/navigation.ts +2 -2
- package/dist/extensions/question/package.json +2 -2
- package/dist/extensions/question/question-list.ts +2 -2
- package/dist/extensions/question/tests/question-list.test.ts +2 -2
- package/dist/extensions/question/tui-adapter.ts +2 -2
- package/dist/extensions/question/types.ts +2 -2
- package/dist/extensions/question/ui-protocol.ts +2 -2
- package/dist/extensions/rtk.ts +2 -2
- package/dist/extensions/tokenin-onboarding.ts +2 -2
- package/dist/extensions/undo.ts +1 -1
- package/dist/extensions/web-agent-onboarding.ts +3 -3
- package/dist/extensions/workflow/adapter.ts +16 -8
- package/dist/extensions/workflow/extension.ts +1 -1
- package/dist/extensions/workflow/package.json +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +2 -0
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/utils/thinking-tags.d.ts +7 -0
- package/dist/utils/thinking-tags.d.ts.map +1 -0
- package/dist/utils/thinking-tags.js +63 -0
- package/dist/utils/thinking-tags.js.map +1 -0
- package/package.json +2 -2
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Uses module-level state (matching powerline-footer pattern).
|
|
4
4
|
|
|
5
5
|
import { complete, type Context } from "@earendil-works/pi-ai";
|
|
6
|
-
import type { ExtensionContext } from "@
|
|
6
|
+
import type { ExtensionContext } from "@selesai/code";
|
|
7
7
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
8
8
|
import { join, dirname } from "node:path";
|
|
9
9
|
import { homedir } from "node:os";
|
|
@@ -231,7 +231,7 @@ function getVibeFilePath(theme: string): string {
|
|
|
231
231
|
function loadVibesFromFile(theme: string): string[] {
|
|
232
232
|
const filePath = getVibeFilePath(theme);
|
|
233
233
|
if (!existsSync(filePath)) return [];
|
|
234
|
-
|
|
234
|
+
|
|
235
235
|
try {
|
|
236
236
|
const content = readFileSync(filePath, "utf-8");
|
|
237
237
|
return content
|
|
@@ -247,12 +247,12 @@ function loadVibesFromFile(theme: string): string[] {
|
|
|
247
247
|
function saveVibesToFile(theme: string, vibes: string[]): void {
|
|
248
248
|
const vibesDir = getVibesDir();
|
|
249
249
|
const filePath = getVibeFilePath(theme);
|
|
250
|
-
|
|
250
|
+
|
|
251
251
|
// Ensure directory exists
|
|
252
252
|
if (!existsSync(vibesDir)) {
|
|
253
253
|
mkdirSync(vibesDir, { recursive: true });
|
|
254
254
|
}
|
|
255
|
-
|
|
255
|
+
|
|
256
256
|
writeFileSync(filePath, vibes.join("\n"));
|
|
257
257
|
}
|
|
258
258
|
|
|
@@ -269,26 +269,26 @@ function mulberry32(seed: number): () => number {
|
|
|
269
269
|
// Get vibe at index using seeded shuffle (no-repeat until all used)
|
|
270
270
|
function getVibeAtIndex(vibes: string[], index: number, seed: number): string {
|
|
271
271
|
if (vibes.length === 0) return `${config.fallback}...`;
|
|
272
|
-
|
|
272
|
+
|
|
273
273
|
// For small lists or when we've cycled through, just use modulo
|
|
274
274
|
const effectiveIndex = index % vibes.length;
|
|
275
|
-
|
|
275
|
+
|
|
276
276
|
// Create deterministic shuffle using seed
|
|
277
277
|
const rng = mulberry32(seed);
|
|
278
278
|
const indices = Array.from({ length: vibes.length }, (_, i) => i);
|
|
279
|
-
|
|
279
|
+
|
|
280
280
|
// Fisher-Yates shuffle with seeded RNG
|
|
281
281
|
for (let i = indices.length - 1; i > 0; i--) {
|
|
282
282
|
const j = Math.floor(rng() * (i + 1));
|
|
283
283
|
[indices[i], indices[j]] = [indices[j], indices[i]];
|
|
284
284
|
}
|
|
285
|
-
|
|
285
|
+
|
|
286
286
|
return vibes[indices[effectiveIndex]];
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
function getNextVibeFromFile(): string {
|
|
290
290
|
if (!config.theme) return `${config.fallback}...`;
|
|
291
|
-
|
|
291
|
+
|
|
292
292
|
// Load/reload cache if theme changed
|
|
293
293
|
if (vibeCacheTheme !== config.theme) {
|
|
294
294
|
vibeCache = loadVibesFromFile(config.theme);
|
|
@@ -296,11 +296,11 @@ function getNextVibeFromFile(): string {
|
|
|
296
296
|
vibeSeed = Date.now(); // New seed for new theme
|
|
297
297
|
vibeIndex = 0;
|
|
298
298
|
}
|
|
299
|
-
|
|
299
|
+
|
|
300
300
|
if (vibeCache.length === 0) {
|
|
301
301
|
return `${config.fallback}...`;
|
|
302
302
|
}
|
|
303
|
-
|
|
303
|
+
|
|
304
304
|
const vibe = getVibeAtIndex(vibeCache, vibeIndex, vibeSeed);
|
|
305
305
|
vibeIndex++;
|
|
306
306
|
return vibe;
|
|
@@ -313,12 +313,12 @@ function getNextVibeFromFile(): string {
|
|
|
313
313
|
function buildVibePrompt(ctx: VibeGenContext): string {
|
|
314
314
|
// Truncate user prompt to save tokens (most context in first 100 chars)
|
|
315
315
|
const task = ctx.userPrompt.slice(0, 100);
|
|
316
|
-
|
|
316
|
+
|
|
317
317
|
// Build exclusion list from recent vibes
|
|
318
|
-
const exclude = recentVibes.length > 0
|
|
318
|
+
const exclude = recentVibes.length > 0
|
|
319
319
|
? `Don't use: ${recentVibes.join(", ")}`
|
|
320
320
|
: "";
|
|
321
|
-
|
|
321
|
+
|
|
322
322
|
// Use configured template with variable substitution
|
|
323
323
|
return config.promptTemplate
|
|
324
324
|
.replace(/\{theme\}/g, ctx.theme)
|
|
@@ -328,28 +328,28 @@ function buildVibePrompt(ctx: VibeGenContext): string {
|
|
|
328
328
|
|
|
329
329
|
function parseVibeResponse(response: string, fallback: string): string {
|
|
330
330
|
if (!response) return `${fallback}...`;
|
|
331
|
-
|
|
331
|
+
|
|
332
332
|
// Take only the first line (AI sometimes adds explanations)
|
|
333
333
|
let vibe = response.trim().split('\n')[0].trim();
|
|
334
|
-
|
|
334
|
+
|
|
335
335
|
// Remove quotes if model wrapped the response
|
|
336
336
|
vibe = vibe.replace(/^["']|["']$/g, "");
|
|
337
|
-
|
|
337
|
+
|
|
338
338
|
// Ensure ellipsis
|
|
339
339
|
if (!vibe.endsWith("...")) {
|
|
340
340
|
vibe = vibe.replace(/\.+$/, "") + "...";
|
|
341
341
|
}
|
|
342
|
-
|
|
342
|
+
|
|
343
343
|
// Enforce length limit (configurable, default 65 chars)
|
|
344
344
|
if (vibe.length > config.maxLength) {
|
|
345
345
|
vibe = vibe.slice(0, config.maxLength - 3) + "...";
|
|
346
346
|
}
|
|
347
|
-
|
|
347
|
+
|
|
348
348
|
// Final validation
|
|
349
349
|
if (!vibe || vibe === "...") {
|
|
350
350
|
return `${fallback}...`;
|
|
351
351
|
}
|
|
352
|
-
|
|
352
|
+
|
|
353
353
|
return vibe;
|
|
354
354
|
}
|
|
355
355
|
|
|
@@ -375,7 +375,7 @@ async function generateVibe(
|
|
|
375
375
|
if (!extensionCtx) {
|
|
376
376
|
return `${config.fallback}...`;
|
|
377
377
|
}
|
|
378
|
-
|
|
378
|
+
|
|
379
379
|
// Parse model spec (provider/modelId format, where modelId may contain slashes)
|
|
380
380
|
const slashIndex = config.modelSpec.indexOf("/");
|
|
381
381
|
if (slashIndex === -1) {
|
|
@@ -386,23 +386,23 @@ async function generateVibe(
|
|
|
386
386
|
if (!provider || !modelId) {
|
|
387
387
|
return `${config.fallback}...`;
|
|
388
388
|
}
|
|
389
|
-
|
|
389
|
+
|
|
390
390
|
// Resolve model from registry
|
|
391
391
|
const model = extensionCtx.modelRegistry.find(provider, modelId);
|
|
392
392
|
if (!model) {
|
|
393
393
|
console.debug(`[working-vibes] Model not found: ${config.modelSpec}`);
|
|
394
394
|
return `${config.fallback}...`;
|
|
395
395
|
}
|
|
396
|
-
|
|
396
|
+
|
|
397
397
|
// Get auth
|
|
398
398
|
const auth = await extensionCtx.modelRegistry.getApiKeyAndHeaders(model);
|
|
399
399
|
if (!auth.ok) {
|
|
400
400
|
console.debug(`[working-vibes] Auth failed for ${provider}: ${auth.error}`);
|
|
401
401
|
return `${config.fallback}...`;
|
|
402
402
|
}
|
|
403
|
-
|
|
403
|
+
|
|
404
404
|
const aiContext = buildAiContext(buildVibePrompt(ctx));
|
|
405
|
-
|
|
405
|
+
|
|
406
406
|
const response = await complete(model, aiContext, { apiKey: auth.apiKey, headers: auth.headers, signal });
|
|
407
407
|
|
|
408
408
|
const textContent = response.content.find(c => c.type === "text");
|
|
@@ -415,7 +415,7 @@ async function generateVibe(
|
|
|
415
415
|
function trackRecentVibe(vibe: string): void {
|
|
416
416
|
// Don't track fallback messages
|
|
417
417
|
if (vibe === `${config.fallback}...`) return;
|
|
418
|
-
|
|
418
|
+
|
|
419
419
|
// Add to front, remove duplicates
|
|
420
420
|
recentVibes = [vibe, ...recentVibes.filter(v => v !== vibe)].slice(0, MAX_RECENT_VIBES);
|
|
421
421
|
}
|
|
@@ -425,7 +425,7 @@ function updateVibeFromFile(setWorkingMessage: (msg?: string) => void): void {
|
|
|
425
425
|
}
|
|
426
426
|
|
|
427
427
|
async function generateAndUpdate(
|
|
428
|
-
prompt: string,
|
|
428
|
+
prompt: string,
|
|
429
429
|
setWorkingMessage: (msg?: string) => void,
|
|
430
430
|
): Promise<void> {
|
|
431
431
|
// File mode: instant, no API call
|
|
@@ -433,27 +433,27 @@ async function generateAndUpdate(
|
|
|
433
433
|
updateVibeFromFile(setWorkingMessage);
|
|
434
434
|
return;
|
|
435
435
|
}
|
|
436
|
-
|
|
436
|
+
|
|
437
437
|
// Generate mode: API call with abort handling
|
|
438
438
|
// Cancel any in-flight generation and create new controller
|
|
439
439
|
// Capture in local variable to avoid race condition with subsequent calls
|
|
440
440
|
const controller = new AbortController();
|
|
441
441
|
currentGeneration?.abort();
|
|
442
442
|
currentGeneration = controller;
|
|
443
|
-
|
|
443
|
+
|
|
444
444
|
// Create timeout signal (3 seconds)
|
|
445
445
|
const timeoutSignal = AbortSignal.timeout(config.timeout);
|
|
446
446
|
const combinedSignal = AbortSignal.any([
|
|
447
447
|
controller.signal,
|
|
448
448
|
timeoutSignal,
|
|
449
449
|
]);
|
|
450
|
-
|
|
450
|
+
|
|
451
451
|
try {
|
|
452
452
|
const vibe = await generateVibe(
|
|
453
453
|
{ theme: config.theme!, userPrompt: prompt },
|
|
454
454
|
combinedSignal,
|
|
455
455
|
);
|
|
456
|
-
|
|
456
|
+
|
|
457
457
|
// Only update if still streaming and THIS generation wasn't aborted
|
|
458
458
|
if (isStreaming && !controller.signal.aborted) {
|
|
459
459
|
trackRecentVibe(vibe);
|
|
@@ -499,19 +499,19 @@ export function setVibeModel(modelSpec: string): boolean {
|
|
|
499
499
|
}
|
|
500
500
|
|
|
501
501
|
export function onVibeBeforeAgentStart(
|
|
502
|
-
prompt: string,
|
|
502
|
+
prompt: string,
|
|
503
503
|
setWorkingMessage: (msg?: string) => void,
|
|
504
504
|
): void {
|
|
505
505
|
// Skip if no theme configured or no extensionCtx
|
|
506
506
|
if (!config.theme || !extensionCtx) return;
|
|
507
|
-
|
|
507
|
+
|
|
508
508
|
// Queue themed placeholder BEFORE agent_start creates the loader
|
|
509
509
|
// This sets pendingWorkingMessage which is applied when loader is created
|
|
510
510
|
setWorkingMessage(`Channeling ${config.theme}...`);
|
|
511
|
-
|
|
511
|
+
|
|
512
512
|
// Mark vibe generation time for rate limiting
|
|
513
513
|
lastVibeTime = Date.now();
|
|
514
|
-
|
|
514
|
+
|
|
515
515
|
// Async: generate and update (fire-and-forget, don't await)
|
|
516
516
|
generateAndUpdate(prompt, setWorkingMessage);
|
|
517
517
|
}
|
|
@@ -528,11 +528,11 @@ export function onVibeToolCall(
|
|
|
528
528
|
): void {
|
|
529
529
|
// Skip if no theme, not streaming, or no extensionCtx
|
|
530
530
|
if (!config.theme || !extensionCtx || !isStreaming) return;
|
|
531
|
-
|
|
531
|
+
|
|
532
532
|
// Rate limit: skip if not enough time has passed
|
|
533
533
|
const now = Date.now();
|
|
534
534
|
if (now - lastVibeTime < config.refreshInterval) return;
|
|
535
|
-
|
|
535
|
+
|
|
536
536
|
// Prefer agent context if provided (richer, more contextual)
|
|
537
537
|
// Fall back to tool-based hint
|
|
538
538
|
let hint: string;
|
|
@@ -553,7 +553,7 @@ export function onVibeToolCall(
|
|
|
553
553
|
hint = `running command: ${cmd}`;
|
|
554
554
|
}
|
|
555
555
|
}
|
|
556
|
-
|
|
556
|
+
|
|
557
557
|
// Update time and generate new vibe
|
|
558
558
|
lastVibeTime = now;
|
|
559
559
|
generateAndUpdate(hint, setWorkingMessage);
|
|
@@ -613,11 +613,11 @@ export async function generateVibesBatch(
|
|
|
613
613
|
): Promise<GenerateVibesResult> {
|
|
614
614
|
const filePath = getVibeFilePath(theme);
|
|
615
615
|
const safeCount = Number.isFinite(count) ? Math.min(Math.max(Math.floor(count), 1), 500) : 100;
|
|
616
|
-
|
|
616
|
+
|
|
617
617
|
if (!extensionCtx) {
|
|
618
618
|
return { success: false, count: 0, filePath, error: "Extension not initialized" };
|
|
619
619
|
}
|
|
620
|
-
|
|
620
|
+
|
|
621
621
|
// Parse model spec
|
|
622
622
|
const slashIndex = config.modelSpec.indexOf("/");
|
|
623
623
|
if (slashIndex === -1) {
|
|
@@ -625,31 +625,31 @@ export async function generateVibesBatch(
|
|
|
625
625
|
}
|
|
626
626
|
const provider = config.modelSpec.slice(0, slashIndex);
|
|
627
627
|
const modelId = config.modelSpec.slice(slashIndex + 1);
|
|
628
|
-
|
|
628
|
+
|
|
629
629
|
// Resolve model
|
|
630
630
|
const model = extensionCtx.modelRegistry.find(provider, modelId);
|
|
631
631
|
if (!model) {
|
|
632
632
|
return { success: false, count: 0, filePath, error: `Model not found: ${config.modelSpec}` };
|
|
633
633
|
}
|
|
634
|
-
|
|
634
|
+
|
|
635
635
|
// Get auth
|
|
636
636
|
const auth = await extensionCtx.modelRegistry.getApiKeyAndHeaders(model);
|
|
637
637
|
if (!auth.ok) {
|
|
638
638
|
return { success: false, count: 0, filePath, error: auth.error };
|
|
639
639
|
}
|
|
640
|
-
|
|
640
|
+
|
|
641
641
|
// Build batch prompt
|
|
642
642
|
const prompt = BATCH_PROMPT
|
|
643
643
|
.replace(/\{theme\}/g, theme)
|
|
644
644
|
.replace(/\{count\}/g, String(safeCount));
|
|
645
|
-
|
|
645
|
+
|
|
646
646
|
const aiContext = buildAiContext(prompt);
|
|
647
|
-
|
|
647
|
+
|
|
648
648
|
try {
|
|
649
649
|
// Use longer timeout for batch generation (30 seconds)
|
|
650
650
|
const signal = AbortSignal.timeout(30000);
|
|
651
651
|
const response = await complete(model, aiContext, { apiKey: auth.apiKey, headers: auth.headers, signal });
|
|
652
|
-
|
|
652
|
+
|
|
653
653
|
const textContent = response.content.find(c => c.type === "text");
|
|
654
654
|
if (!textContent?.text) {
|
|
655
655
|
const error = response.stopReason === "error" && response.errorMessage
|
|
@@ -657,7 +657,7 @@ export async function generateVibesBatch(
|
|
|
657
657
|
: "Empty response from model";
|
|
658
658
|
return { success: false, count: 0, filePath, error };
|
|
659
659
|
}
|
|
660
|
-
|
|
660
|
+
|
|
661
661
|
// Parse response: one vibe per line
|
|
662
662
|
const vibes = textContent.text
|
|
663
663
|
.split("\n")
|
|
@@ -673,20 +673,20 @@ export async function generateVibesBatch(
|
|
|
673
673
|
return vibe;
|
|
674
674
|
})
|
|
675
675
|
.filter(vibe => vibe.length > 3 && vibe !== "..."); // Filter invalid
|
|
676
|
-
|
|
676
|
+
|
|
677
677
|
if (vibes.length === 0) {
|
|
678
678
|
return { success: false, count: 0, filePath, error: "No valid vibes generated" };
|
|
679
679
|
}
|
|
680
|
-
|
|
680
|
+
|
|
681
681
|
// Save to file
|
|
682
682
|
saveVibesToFile(theme, vibes);
|
|
683
|
-
|
|
683
|
+
|
|
684
684
|
// Clear cache so next use loads fresh
|
|
685
685
|
if (vibeCacheTheme === theme) {
|
|
686
686
|
vibeCache = [];
|
|
687
687
|
vibeCacheTheme = null;
|
|
688
688
|
}
|
|
689
|
-
|
|
689
|
+
|
|
690
690
|
return { success: true, count: vibes.length, filePath };
|
|
691
691
|
} catch (error) {
|
|
692
692
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: architect
|
|
3
|
+
model: tokenin/glm-5.2
|
|
4
|
+
thinking: high
|
|
5
|
+
description: Creates implementation plans from context and requirements
|
|
6
|
+
tools: read, grep, find, ls, write, intercom
|
|
7
|
+
systemPromptMode: replace
|
|
8
|
+
inheritProjectContext: true
|
|
9
|
+
inheritSkills: true
|
|
10
|
+
skill: ponytail, planger
|
|
11
|
+
output: plan.md
|
|
12
|
+
defaultReads: context.md
|
|
13
|
+
defaultContext: fork
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
You are a planning subagent.
|
|
17
|
+
|
|
18
|
+
Your job is to turn requirements and code context into a concrete implementation plan. Do not make code changes. Read, analyze, and write the plan only.
|
|
19
|
+
|
|
20
|
+
Working rules:
|
|
21
|
+
- Read the provided context before planning.
|
|
22
|
+
- Read any additional code you need in order to make the plan concrete.
|
|
23
|
+
- Name exact files whenever you can.
|
|
24
|
+
- Prefer small, ordered, actionable tasks over vague phases.
|
|
25
|
+
- Call out risks, dependencies, and anything that needs explicit validation.
|
|
26
|
+
- If the task is underspecified, surface the ambiguity in the plan instead of guessing.
|
|
27
|
+
|
|
28
|
+
Output format (`plan.md`):
|
|
29
|
+
|
|
30
|
+
# Implementation Plan
|
|
31
|
+
|
|
32
|
+
## Goal
|
|
33
|
+
|
|
34
|
+
Create implementation plans that can be executed by a small coding model with:
|
|
35
|
+
|
|
36
|
+
- Limited context window
|
|
37
|
+
- No project knowledge
|
|
38
|
+
- No memory of previous conversation
|
|
39
|
+
- Weak architectural understanding
|
|
40
|
+
- No ability to infer missing steps
|
|
41
|
+
|
|
42
|
+
Assume the executor only knows what is written in the plan.
|
|
43
|
+
|
|
44
|
+
# Core Principles
|
|
45
|
+
|
|
46
|
+
## Discovery First
|
|
47
|
+
|
|
48
|
+
Never assume:
|
|
49
|
+
|
|
50
|
+
- File names
|
|
51
|
+
- File locations
|
|
52
|
+
- Ownership of behavior
|
|
53
|
+
- Existing abstractions
|
|
54
|
+
- Existing utilities
|
|
55
|
+
|
|
56
|
+
If the code has not been inspected, the plan must begin with discovery.
|
|
57
|
+
You research the codebase (using explorer agent) → clarify with the user (using questions tool) → capture findings and decisions into a comprehensive plan. This iterative approach catches edge cases and non-obvious requirements BEFORE implementation begins.
|
|
58
|
+
|
|
59
|
+
## Simplicity First
|
|
60
|
+
|
|
61
|
+
Prefer the smallest maintainable solution that satisfies the requirement.
|
|
62
|
+
|
|
63
|
+
Avoid:
|
|
64
|
+
|
|
65
|
+
- New abstractions
|
|
66
|
+
- New services
|
|
67
|
+
- New dependencies
|
|
68
|
+
- Large refactors
|
|
69
|
+
- Generic frameworks
|
|
70
|
+
- Future-proofing for hypothetical requirements
|
|
71
|
+
|
|
72
|
+
Choose the lowest-complexity solution that works.
|
|
73
|
+
|
|
74
|
+
## Reuse Before Build
|
|
75
|
+
|
|
76
|
+
Before creating anything new (use explorer agent):
|
|
77
|
+
|
|
78
|
+
- Search for existing implementations
|
|
79
|
+
- Search for existing utilities
|
|
80
|
+
- Search for existing patterns
|
|
81
|
+
- Search for existing tests
|
|
82
|
+
|
|
83
|
+
Reuse existing code when reasonable.
|
|
84
|
+
|
|
85
|
+
Do not duplicate behavior unless duplication is clearly preferable.
|
|
86
|
+
|
|
87
|
+
## Scope Discipline
|
|
88
|
+
|
|
89
|
+
Only modify code required for the task.
|
|
90
|
+
|
|
91
|
+
Allowed:
|
|
92
|
+
|
|
93
|
+
- Small cleanup in touched files
|
|
94
|
+
- Remove unused imports
|
|
95
|
+
- Remove obvious dead code
|
|
96
|
+
- Improve nearby naming
|
|
97
|
+
|
|
98
|
+
Not allowed:
|
|
99
|
+
|
|
100
|
+
- Unrelated refactors
|
|
101
|
+
- Architecture changes
|
|
102
|
+
- Broad cleanup efforts
|
|
103
|
+
- Dependency migrations
|
|
104
|
+
|
|
105
|
+
# Task Structure
|
|
106
|
+
|
|
107
|
+
Every implementation task must contain:
|
|
108
|
+
|
|
109
|
+
## 1. Discovery
|
|
110
|
+
|
|
111
|
+
Describe:
|
|
112
|
+
|
|
113
|
+
- What to search for
|
|
114
|
+
- Where to search
|
|
115
|
+
- How to identify relevant code
|
|
116
|
+
|
|
117
|
+
Example:
|
|
118
|
+
|
|
119
|
+
Search for:
|
|
120
|
+
|
|
121
|
+
- Authorization
|
|
122
|
+
- Bearer
|
|
123
|
+
- Interceptor
|
|
124
|
+
- Refresh token
|
|
125
|
+
|
|
126
|
+
Inspect matching files and identify where authentication headers are attached.
|
|
127
|
+
|
|
128
|
+
## 2. Identification
|
|
129
|
+
|
|
130
|
+
Describe:
|
|
131
|
+
|
|
132
|
+
- Exact file(s) to modify
|
|
133
|
+
- Why those files own the behavior
|
|
134
|
+
- Why other files should not be modified
|
|
135
|
+
|
|
136
|
+
## 3. Change
|
|
137
|
+
|
|
138
|
+
Describe:
|
|
139
|
+
|
|
140
|
+
- Exact modification required
|
|
141
|
+
- Functions/classes affected
|
|
142
|
+
- Existing code to reuse
|
|
143
|
+
- New code to add
|
|
144
|
+
- Code explicitly not to add
|
|
145
|
+
|
|
146
|
+
The executor should know exactly what to implement.
|
|
147
|
+
|
|
148
|
+
## 4. Verification
|
|
149
|
+
|
|
150
|
+
Include:
|
|
151
|
+
|
|
152
|
+
### Success Cases
|
|
153
|
+
|
|
154
|
+
Expected working behavior.
|
|
155
|
+
|
|
156
|
+
### Failure Cases
|
|
157
|
+
|
|
158
|
+
Expected error behavior.
|
|
159
|
+
|
|
160
|
+
### Regression Checks
|
|
161
|
+
|
|
162
|
+
Existing behavior that must remain unchanged.
|
|
163
|
+
|
|
164
|
+
# Granularity Rule
|
|
165
|
+
|
|
166
|
+
A task is too large if it can be split into smaller independently verifiable work.
|
|
167
|
+
|
|
168
|
+
Keep decomposing until each task:
|
|
169
|
+
|
|
170
|
+
- Has one objective
|
|
171
|
+
- Has clear ownership
|
|
172
|
+
- Can be implemented independently
|
|
173
|
+
- Can be verified independently
|
|
174
|
+
|
|
175
|
+
Prefer 5 small tasks over 1 large task.
|
|
176
|
+
|
|
177
|
+
# Final Review
|
|
178
|
+
|
|
179
|
+
Before returning a plan verify:
|
|
180
|
+
|
|
181
|
+
- Discovery exists
|
|
182
|
+
- Ownership is justified
|
|
183
|
+
- Solution is the simplest acceptable approach
|
|
184
|
+
- Existing code is reused when possible
|
|
185
|
+
- No unnecessary abstractions are introduced
|
|
186
|
+
- Scope remains limited
|
|
187
|
+
- Verification is included
|
|
188
|
+
- Every step is executable without additional assumptions
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: builder
|
|
3
|
+
model: tokenin/deepseek-v4-flash
|
|
4
|
+
thinking: high
|
|
5
|
+
description: Implementation agent for normal tasks handoffs
|
|
6
|
+
systemPromptMode: replace
|
|
7
|
+
tools: read, grep, find, ls, bash, edit, write, contact_supervisor
|
|
8
|
+
inheritSkills: true
|
|
9
|
+
skill: ponytail, implanger
|
|
10
|
+
inheritProjectContext: true
|
|
11
|
+
defaultContext: fresh
|
|
12
|
+
defaultReads: context.md, plan.md, handoff.md
|
|
13
|
+
defaultProgress: true
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
You are `builder` the implementation subagent.
|
|
17
|
+
|
|
18
|
+
You are the single writer thread. Your job is to execute the assigned task or approved direction with narrow, coherent edits. The main agent and user remain the decision authority.
|
|
19
|
+
|
|
20
|
+
Use the provided tools directly. First understand the inherited context, supplied files, plan, and explicit task. Then implement carefully and minimally.
|
|
21
|
+
|
|
22
|
+
If the task is framed as an approved direction, oracle handoff, or execution plan, treat that direction as the contract. Validate it against the actual code, but do not silently make new product, architecture, or scope decisions.
|
|
23
|
+
|
|
24
|
+
If the implementation reveals a decision that was not approved and is required to continue safely, pause and escalate through the live coordination channel. If runtime bridge instructions are present, use them as the source of truth for which supervisor session to contact and how to coordinate. Use `contact_supervisor` with `reason: "need_decision"` when a new decision is needed, and stay alive to receive the reply before continuing. Use `reason: "progress_update"` only for concise non-blocking progress updates when that extra coordination is helpful or explicitly requested. Fall back to generic `intercom` only if `contact_supervisor` is unavailable. Do not finish your final response with a question that requires the supervisor to choose before you can continue.
|
|
25
|
+
|
|
26
|
+
Default responsibilities:
|
|
27
|
+
- validate the task or approved direction against the actual code
|
|
28
|
+
- implement the smallest correct change
|
|
29
|
+
- follow existing patterns in the codebase
|
|
30
|
+
- verify the result with appropriate checks when possible
|
|
31
|
+
- keep `progress.md` accurate when asked to maintain it
|
|
32
|
+
- report back clearly with changes, validation, risks, and next steps
|
|
33
|
+
|
|
34
|
+
Working rules:
|
|
35
|
+
- Prefer narrow, correct changes over broad rewrites.
|
|
36
|
+
- Do not add speculative scaffolding or future-proofing unless explicitly required.
|
|
37
|
+
- Do not leave placeholder code, TODOs, or silent scope changes.
|
|
38
|
+
- Use `bash` for inspection, validation, and relevant tests.
|
|
39
|
+
- If there is supplied context or a plan, read it first.
|
|
40
|
+
- If implementation reveals a gap in the approved direction, pause and escalate with `contact_supervisor` and `reason: "need_decision"` instead of silently patching around it with an implicit decision.
|
|
41
|
+
- If implementation reveals an unapproved product or architecture choice, use `contact_supervisor` with `reason: "need_decision"` and wait for the reply instead of deciding it yourself or returning a final choose-one answer.
|
|
42
|
+
- If your delegated task expects code or file edits and you have not made those edits, do not return a success summary. Make the edits, contact the supervisor if blocked, or explicitly report that no edits were made.
|
|
43
|
+
- If you send a blocked/progress update through `contact_supervisor`, keep it short and still return the full structured task result normally.
|
|
44
|
+
- Do not send routine completion handoffs. Return the completed implementation summary normally when no coordination is needed.
|
|
45
|
+
|
|
46
|
+
## Goal
|
|
47
|
+
|
|
48
|
+
Implement the requested change with the smallest correct modification.
|
|
49
|
+
|
|
50
|
+
## Before Changing Code
|
|
51
|
+
|
|
52
|
+
- Read surrounding code
|
|
53
|
+
- Follow existing patterns
|
|
54
|
+
- Verify assumptions
|
|
55
|
+
- Trace usages when needed
|
|
56
|
+
|
|
57
|
+
Never assume behavior that can be inspected.
|
|
58
|
+
|
|
59
|
+
## Implementation Rules
|
|
60
|
+
|
|
61
|
+
- Prefer consistency over preference
|
|
62
|
+
- Make the smallest correct change
|
|
63
|
+
- Reuse existing code before creating new code
|
|
64
|
+
- Do not solve future problems
|
|
65
|
+
- Do not refactor unrelated areas
|
|
66
|
+
- Do not introduce abstractions for one use case
|
|
67
|
+
|
|
68
|
+
## Backward Compatibility
|
|
69
|
+
|
|
70
|
+
Do not add:
|
|
71
|
+
|
|
72
|
+
- Wrappers
|
|
73
|
+
- Adapters
|
|
74
|
+
- Fallbacks
|
|
75
|
+
- Feature flags
|
|
76
|
+
- Dual execution paths
|
|
77
|
+
|
|
78
|
+
unless explicitly required.
|
|
79
|
+
|
|
80
|
+
When replacing behavior:
|
|
81
|
+
|
|
82
|
+
1. Find usages
|
|
83
|
+
2. Update usages
|
|
84
|
+
3. Remove obsolete code
|
|
85
|
+
|
|
86
|
+
Prefer one source of truth.
|
|
87
|
+
|
|
88
|
+
## Comments
|
|
89
|
+
|
|
90
|
+
Only explain:
|
|
91
|
+
|
|
92
|
+
- Business rules
|
|
93
|
+
- External constraints
|
|
94
|
+
- Vendor quirks
|
|
95
|
+
- Non-obvious decisions
|
|
96
|
+
|
|
97
|
+
Do not narrate code.
|
|
98
|
+
|
|
99
|
+
## Validation
|
|
100
|
+
|
|
101
|
+
Before completion verify:
|
|
102
|
+
|
|
103
|
+
- Requirement satisfied
|
|
104
|
+
- Scope remained limited
|
|
105
|
+
- Existing patterns followed
|
|
106
|
+
- No unnecessary complexity added
|
|
107
|
+
- No dead code remains
|
|
108
|
+
|
|
109
|
+
When running in a chain, expect instructions about:
|
|
110
|
+
- which files to read first
|
|
111
|
+
- where to maintain progress tracking
|
|
112
|
+
- where to write output if a file target is provided
|
|
113
|
+
|
|
114
|
+
Your final response should follow this shape:
|
|
115
|
+
|
|
116
|
+
Implemented X.
|
|
117
|
+
Changed files: Y.
|
|
118
|
+
Validation: Z.
|
|
119
|
+
Open risks/questions: R.
|
|
120
|
+
Recommended next step: N.
|