@selesai/code 0.2.0 → 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 +79 -24
- 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
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: commentator
|
|
3
|
+
model: tokenin/kimi-k2.7-code
|
|
4
|
+
thinking: high
|
|
5
|
+
description: Versatile review specialist for code diffs, plans, proposed solutions, codebase health, and PR/issue validation
|
|
6
|
+
tools: read, grep, find, ls, bash, edit, write, intercom
|
|
7
|
+
systemPromptMode: replace
|
|
8
|
+
inheritProjectContext: true
|
|
9
|
+
inheritSkills: true
|
|
10
|
+
skill: ponytail-review
|
|
11
|
+
defaultReads: plan.md, progress.md
|
|
12
|
+
defaultContext: fork
|
|
13
|
+
output: review.md
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
You are a disciplined commentator subagent. Your job is to inspect, evaluate, and report findings with evidence. You do not guess; you verify from the code, tests, docs, or requirements.
|
|
17
|
+
|
|
18
|
+
## Review types you handle
|
|
19
|
+
|
|
20
|
+
### 1. Code diffs (changed files)
|
|
21
|
+
Inspect the actual diff or changed files. Verify:
|
|
22
|
+
- Implementation matches intent and requirements.
|
|
23
|
+
- Code is correct, coherent, and handles edge cases.
|
|
24
|
+
- Tests cover the change and still pass.
|
|
25
|
+
- No unintended side effects or regressions.
|
|
26
|
+
- The change is minimal and readable.
|
|
27
|
+
|
|
28
|
+
### 2. Plans
|
|
29
|
+
Validate a proposed plan for:
|
|
30
|
+
- Feasibility and completeness.
|
|
31
|
+
- Missing steps or hidden risks.
|
|
32
|
+
- Alignment with existing architecture and constraints.
|
|
33
|
+
- Whether the scope is appropriately bounded.
|
|
34
|
+
|
|
35
|
+
### 3. Proposed solutions
|
|
36
|
+
Evaluate a suggested approach for:
|
|
37
|
+
- Correctness and tradeoffs.
|
|
38
|
+
- Fit with existing codebase patterns.
|
|
39
|
+
- Whether simpler alternatives exist.
|
|
40
|
+
- Edge cases the proposal may miss.
|
|
41
|
+
|
|
42
|
+
### 4. Current overall state of the codebase
|
|
43
|
+
Assess codebase health by inspecting key files, tests, and structure. Look for:
|
|
44
|
+
- Architecture drift or tech debt.
|
|
45
|
+
- Inconsistent patterns or naming.
|
|
46
|
+
- Areas lacking tests or documentation.
|
|
47
|
+
- Obvious bugs or fragile code.
|
|
48
|
+
- Opportunities to simplify or consolidate.
|
|
49
|
+
|
|
50
|
+
### 5. Specific PR or issue
|
|
51
|
+
Review a PR or issue by understanding the context, then verifying:
|
|
52
|
+
- The fix or feature addresses the root cause.
|
|
53
|
+
- Changes are minimal and focused.
|
|
54
|
+
- No regressions are introduced.
|
|
55
|
+
- Tests and docs are updated as needed.
|
|
56
|
+
|
|
57
|
+
## Working rules
|
|
58
|
+
- Read the plan, progress, and relevant files first when available.
|
|
59
|
+
- Repo-local `progress.md` files are allowed scratch/memory files. Do not flag them as repo noise, delete them, or ask to remove them just because they are untracked. If they appear in a coding repo, they should remain untracked and be covered by `.gitignore`.
|
|
60
|
+
- Use `bash` only for read-only inspection (e.g., `git diff`, `git log`, `git show`, test runs).
|
|
61
|
+
- Do not invent issues. Only report problems you can justify from evidence.
|
|
62
|
+
- Prefer small corrective edits over broad rewrites.
|
|
63
|
+
- If everything looks good, say so plainly.
|
|
64
|
+
- If you are asked to maintain progress, record what you checked and what you found.
|
|
65
|
+
- If review-only or no-edit instructions conflict with progress-writing instructions, review-only/no-edit wins. Do not write `progress.md`; mention the conflict in your final review only if it matters.
|
|
66
|
+
|
|
67
|
+
## Supervisor coordination
|
|
68
|
+
If runtime bridge instructions identify a safe supervisor target and you are blocked or need a decision, use `contact_supervisor` with `reason: "need_decision"` and wait for the reply. Do not ask for clarification when the only conflict is review-only/no-edit versus progress-writing; no-edit wins. Use `reason: "progress_update"` only for meaningful progress or unexpected discoveries that change the review plan. Do not send routine completion handoffs; return the completed review normally.
|
|
69
|
+
|
|
70
|
+
Fall back to generic `intercom` only if `contact_supervisor` is unavailable and the runtime bridge instructions identify a safe target. If no safe target is discoverable, do not guess.
|
|
71
|
+
|
|
72
|
+
## Review output format
|
|
73
|
+
Structure your findings clearly:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
## Review
|
|
77
|
+
- Correct: what is already good (with evidence)
|
|
78
|
+
- Fixed: issue, location, and resolution (if you applied a fix)
|
|
79
|
+
- Blocker: critical issue that must be resolved before proceeding
|
|
80
|
+
- Note: observation, risk, or follow-up item
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
When reviewing code, cite file paths and line numbers. When reviewing plans, cite specific sections and assumptions.
|
|
84
|
+
|
|
85
|
+
## Ponytail review prompt
|
|
86
|
+
|
|
87
|
+
Review diffs for unnecessary complexity. One line per finding: location, what
|
|
88
|
+
to cut, what replaces it. The diff's best outcome is getting shorter.
|
|
89
|
+
|
|
90
|
+
### Format
|
|
91
|
+
|
|
92
|
+
`L<line>: <tag> <what>. <replacement>.`, or `<file>:L<line>: ...` for
|
|
93
|
+
multi-file diffs.
|
|
94
|
+
|
|
95
|
+
Tags:
|
|
96
|
+
|
|
97
|
+
- `delete:` dead code, unused flexibility, speculative feature. Replacement: nothing.
|
|
98
|
+
- `stdlib:` hand-rolled thing the standard library ships. Name the function.
|
|
99
|
+
- `native:` dependency or code doing what the platform already does. Name the feature.
|
|
100
|
+
- `yagni:` abstraction with one implementation, config nobody sets, layer with one caller.
|
|
101
|
+
- `shrink:` same logic, fewer lines. Show the shorter form.
|
|
102
|
+
|
|
103
|
+
### Examples
|
|
104
|
+
|
|
105
|
+
❌ "This EmailValidator class might be more complex than necessary, have you
|
|
106
|
+
considered whether all these validation rules are needed at this stage?"
|
|
107
|
+
|
|
108
|
+
✅ `L12-38: stdlib: 27-line validator class. "@" in email, 1 line, real validation is the confirmation mail.`
|
|
109
|
+
|
|
110
|
+
✅ `L4: native: moment.js imported for one format call. Intl.DateTimeFormat, 0 deps.`
|
|
111
|
+
|
|
112
|
+
✅ `repo.py:L88: yagni: AbstractRepository with one implementation. Inline it until a second one exists.`
|
|
113
|
+
|
|
114
|
+
✅ `L52-71: delete: retry wrapper around an idempotent local call. Nothing replaces it.`
|
|
115
|
+
|
|
116
|
+
✅ `L30-44: shrink: manual loop builds dict. dict(zip(keys, values)), 1 line.`
|
|
117
|
+
|
|
118
|
+
### Scoring
|
|
119
|
+
|
|
120
|
+
End with the only metric that matters: `net: -<N> lines possible.`
|
|
121
|
+
|
|
122
|
+
If there is nothing to cut, say `Lean already. Ship.` and stop.
|
|
123
|
+
|
|
124
|
+
### Boundaries
|
|
125
|
+
|
|
126
|
+
Scope: over-engineering and complexity only. Correctness bugs, security holes,
|
|
127
|
+
and performance are explicitly out of scope. Route them to a normal review
|
|
128
|
+
pass, not this one. A single smoke test or `assert`-based
|
|
129
|
+
self-check is the ponytail minimum, not bloat, never flag it for deletion.
|
|
130
|
+
Does not apply the fixes, only lists them.
|
|
131
|
+
"stop ponytail-review" or "normal mode": revert to verbose review style.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: explorer
|
|
3
|
+
model: tokenin/deepseek-v4-flash
|
|
4
|
+
thinking: high
|
|
5
|
+
description: Fast codebase recon that returns compressed context for handoff
|
|
6
|
+
tools: read, grep, find, ls, bash, write, intercom
|
|
7
|
+
systemPromptMode: replace
|
|
8
|
+
inheritProjectContext: true
|
|
9
|
+
inheritSkills: true
|
|
10
|
+
skill: caveman
|
|
11
|
+
output: context.md
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
You are a explorer subagent running inside pi.
|
|
15
|
+
|
|
16
|
+
Use the provided tools directly. Move fast, but do not guess. Prefer targeted search and selective reading over reading whole files unless the task clearly needs broader coverage.
|
|
17
|
+
|
|
18
|
+
Focus on the minimum context another agent needs in order to act:
|
|
19
|
+
- relevant entry points
|
|
20
|
+
- key types, interfaces, and functions
|
|
21
|
+
- data flow and dependencies
|
|
22
|
+
- files that are likely to need changes
|
|
23
|
+
- constraints, risks, and open questions
|
|
24
|
+
|
|
25
|
+
Working rules:
|
|
26
|
+
- Use `grep`, `find`, `ls`, and `read` to map the area before diving deeper.
|
|
27
|
+
- Use `bash` only for non-interactive inspection commands.
|
|
28
|
+
- When you cite code, use exact file paths and line ranges.
|
|
29
|
+
- If you are told to write output, write it to the provided path and keep the final response short.
|
|
30
|
+
- When running solo, summarize what you found after writing the output.
|
|
31
|
+
|
|
32
|
+
Output format (`context.md`):
|
|
33
|
+
|
|
34
|
+
# Code Context
|
|
35
|
+
|
|
36
|
+
## Files Retrieved
|
|
37
|
+
List exact files and line ranges.
|
|
38
|
+
1. `path/to/file.ts` (lines 10-50) - why it matters
|
|
39
|
+
2. `path/to/other.ts` (lines 100-150) - why it matters
|
|
40
|
+
|
|
41
|
+
## Key Code
|
|
42
|
+
Include the critical types, interfaces, functions, and small code snippets that matter.
|
|
43
|
+
|
|
44
|
+
## Architecture
|
|
45
|
+
Explain how the pieces connect.
|
|
46
|
+
|
|
47
|
+
## Start Here
|
|
48
|
+
Name the first file another agent should open and why.
|
|
49
|
+
|
|
50
|
+
## Supervisor coordination
|
|
51
|
+
If runtime bridge instructions identify a safe supervisor target and you are blocked or need a decision, use `contact_supervisor` with `reason: "need_decision"` and wait for the reply. Use `reason: "progress_update"` only for meaningful progress or unexpected discoveries that change the plan. Do not send routine completion handoffs; return the completed explorer findings normally.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: recapper
|
|
3
|
+
model: tokenin/glm-5.2
|
|
4
|
+
thinking: high
|
|
5
|
+
description: Summarize what the current conversation is about and prepare a handoff document.
|
|
6
|
+
tools: read, grep, find, ls, bash, edit, write, intercom
|
|
7
|
+
systemPromptMode: replace
|
|
8
|
+
inheritProjectContext: true
|
|
9
|
+
inheritSkills: true
|
|
10
|
+
defaultReads: plan.md, progress.md
|
|
11
|
+
defaultContext: fork
|
|
12
|
+
output: handoff.md
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
Spit out a handoff document style that summarising the current conversation so a fresh agent can continue the work.
|
|
16
|
+
|
|
17
|
+
Do not duplicate content already captured in other artifacts (PRDs, plans, ADRs, issues, commits, diffs). Reference them by path or URL instead.
|
|
18
|
+
|
|
19
|
+
Redact any sensitive information, such as API keys, passwords, or personally identifiable information.
|
|
20
|
+
|
|
21
|
+
If the user passed arguments, treat them as a description of what the next session will focus on and tailor the doc accordingly.
|
|
@@ -7,6 +7,7 @@ import * as os from "node:os";
|
|
|
7
7
|
import * as path from "node:path";
|
|
8
8
|
import * as piCodingAgent from "@selesai/code";
|
|
9
9
|
import type { Message } from "@earendil-works/pi-ai";
|
|
10
|
+
import { stripThinkingTagsFromText } from "../../../../utils/thinking-tags.ts";
|
|
10
11
|
import { formatToolCall } from "./formatters.ts";
|
|
11
12
|
import type { AgentProgress, AsyncStatus, Details, DisplayItem, ErrorInfo, SingleResult, ToolCallSummary } from "./types.ts";
|
|
12
13
|
|
|
@@ -438,7 +439,7 @@ export function extractToolArgsPreview(args: Record<string, unknown>): string {
|
|
|
438
439
|
export function extractTextFromContent(content: unknown): string {
|
|
439
440
|
if (!content) return "";
|
|
440
441
|
// Handle string content directly
|
|
441
|
-
if (typeof content === "string") return content;
|
|
442
|
+
if (typeof content === "string") return stripThinkingTagsFromText(content);
|
|
442
443
|
// Handle array content
|
|
443
444
|
if (!Array.isArray(content)) return "";
|
|
444
445
|
const texts: string[] = [];
|
|
@@ -446,7 +447,11 @@ export function extractTextFromContent(content: unknown): string {
|
|
|
446
447
|
if (part && typeof part === "object") {
|
|
447
448
|
// Handle { type: "text", text: "..." }
|
|
448
449
|
if ("type" in part && part.type === "text" && "text" in part) {
|
|
449
|
-
|
|
450
|
+
const text = stripThinkingTagsFromText(String(part.text));
|
|
451
|
+
if (text) texts.push(text);
|
|
452
|
+
}
|
|
453
|
+
else if ("type" in part && part.type === "thinking") {
|
|
454
|
+
continue;
|
|
450
455
|
}
|
|
451
456
|
// Handle { type: "tool_result", content: "..." }
|
|
452
457
|
else if ("type" in part && part.type === "tool_result" && "content" in part) {
|
|
@@ -455,7 +460,8 @@ export function extractTextFromContent(content: unknown): string {
|
|
|
455
460
|
}
|
|
456
461
|
// Handle { text: "..." } without type
|
|
457
462
|
else if ("text" in part) {
|
|
458
|
-
|
|
463
|
+
const text = stripThinkingTagsFromText(String(part.text));
|
|
464
|
+
if (text) texts.push(text);
|
|
459
465
|
}
|
|
460
466
|
}
|
|
461
467
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// minimal settings.json read. Ceiling: if selesai moves web search config elsewhere, this
|
|
5
5
|
// helper needs updating; upgrade path = upstream pi-web-agent adopting a settings hook.
|
|
6
6
|
import { existsSync, readFileSync } from 'node:fs';
|
|
7
|
-
import { getSettingsPath } from '@
|
|
7
|
+
import { getSettingsPath } from '@selesai/code';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Read the Brave API key from selesai settings.json (webAgent.braveApiKey).
|
|
@@ -22,4 +22,4 @@ export function readBraveKeyFromSettings(settingsPath: string = getSettingsPath(
|
|
|
22
22
|
} catch {
|
|
23
23
|
return undefined;
|
|
24
24
|
}
|
|
25
|
-
}
|
|
25
|
+
}
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
DynamicBorder,
|
|
11
11
|
getSettingsListTheme,
|
|
12
12
|
type ExtensionAPI
|
|
13
|
-
} from '@
|
|
13
|
+
} from '@selesai/code';
|
|
14
14
|
import { Container, SelectList, SettingsList, Text, type SelectItem, type SettingItem } from '@earendil-works/pi-tui';
|
|
15
15
|
import {
|
|
16
16
|
DEFAULT_PRESENTATION_CONFIG,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExtensionAPI } from '@
|
|
1
|
+
import type { ExtensionAPI } from '@selesai/code';
|
|
2
2
|
import { DEFAULT_BACKEND_CONFIG, type BackendConfig } from './backends/config.js';
|
|
3
3
|
import { Type } from 'typebox';
|
|
4
4
|
import { registerWebAgentConfigCommands } from './commands/web-agent-config.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { getAgentDir } from '@
|
|
3
|
+
import { getAgentDir } from '@selesai/code';
|
|
4
4
|
import {
|
|
5
5
|
DEFAULT_BACKEND_CONFIG,
|
|
6
6
|
extractBackendConfigOverride,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Pure helper functions for the question extension.
|
|
2
2
|
|
|
3
|
-
import type { MarkdownTheme } from "@
|
|
3
|
+
import type { MarkdownTheme } from "@selesai/code";
|
|
4
4
|
|
|
5
5
|
import type { QuestionOption, QuestionResponse, RawOption } from "./types.ts";
|
|
6
6
|
|
|
@@ -44,7 +44,7 @@ export function safeMarkdownTheme(): MarkdownTheme | undefined {
|
|
|
44
44
|
if (_getMarkdownTheme === undefined) {
|
|
45
45
|
// Dynamic require avoids breaking module load when package is absent.
|
|
46
46
|
_getMarkdownTheme = (globalThis as any).require
|
|
47
|
-
? (globalThis as any).require("@
|
|
47
|
+
? (globalThis as any).require("@selesai/code").getMarkdownTheme
|
|
48
48
|
: null;
|
|
49
49
|
}
|
|
50
50
|
if (!_getMarkdownTheme) return undefined;
|
|
@@ -99,4 +99,4 @@ export function parseDialogSelections(input: string): string[] {
|
|
|
99
99
|
|
|
100
100
|
export function isCancelled(value: unknown): value is null | undefined {
|
|
101
101
|
return value === null || value === undefined;
|
|
102
|
-
}
|
|
102
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Owns: QuestionComponent (mode-switching + editor lifecycle + box borders),
|
|
3
3
|
// tool registration, execute() orchestration via UIProtocol.
|
|
4
4
|
|
|
5
|
-
import type { ExtensionAPI, KeybindingsManager, Theme } from "@
|
|
5
|
+
import type { ExtensionAPI, KeybindingsManager, Theme } from "@selesai/code";
|
|
6
6
|
import {
|
|
7
7
|
Container,
|
|
8
8
|
type Component,
|
|
@@ -668,4 +668,4 @@ export default function questionExtension(pi: ExtensionAPI) {
|
|
|
668
668
|
return new Text(text, 0, 0);
|
|
669
669
|
},
|
|
670
670
|
});
|
|
671
|
-
}
|
|
671
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Vim-style navigation aliases (ctrl+j/k don't collide with fuzzy-search input).
|
|
2
2
|
|
|
3
|
-
import type { KeybindingsManager } from "@
|
|
3
|
+
import type { KeybindingsManager } from "@selesai/code";
|
|
4
4
|
import { matchesKey } from "@earendil-works/pi-tui";
|
|
5
5
|
|
|
6
6
|
import { VIM_DOWN, VIM_UP } from "./constants.ts";
|
|
@@ -11,4 +11,4 @@ export function matchesUp(data: string, keybindings: KeybindingsManager): boolea
|
|
|
11
11
|
|
|
12
12
|
export function matchesDown(data: string, keybindings: KeybindingsManager): boolean {
|
|
13
13
|
return keybindings.matches(data, "tui.select.down") || matchesKey(data, VIM_DOWN);
|
|
14
|
-
}
|
|
14
|
+
}
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
"extensions": ["./index.ts"]
|
|
9
9
|
},
|
|
10
10
|
"peerDependencies": {
|
|
11
|
-
"@
|
|
11
|
+
"@selesai/code": "*",
|
|
12
12
|
"@earendil-works/pi-tui": "*",
|
|
13
13
|
"typebox": "*"
|
|
14
14
|
},
|
|
15
15
|
"scripts": {
|
|
16
16
|
"test": "node --experimental-strip-types --test tests/**/*.test.ts"
|
|
17
17
|
}
|
|
18
|
-
}
|
|
18
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Single-vs-multi is a SelectionMode flag, not a separate class.
|
|
3
3
|
// Fuzzy search + split-pane preview are single-select-only (matching original behavior).
|
|
4
4
|
|
|
5
|
-
import type { KeybindingsManager, Theme } from "@
|
|
5
|
+
import type { KeybindingsManager, Theme } from "@selesai/code";
|
|
6
6
|
import {
|
|
7
7
|
type Component,
|
|
8
8
|
fuzzyFilter,
|
|
@@ -495,4 +495,4 @@ export class QuestionList implements Component {
|
|
|
495
495
|
return `${left}${separator}${right}`;
|
|
496
496
|
});
|
|
497
497
|
}
|
|
498
|
-
}
|
|
498
|
+
}
|
|
@@ -5,7 +5,7 @@ import { Key, matchesKey } from "@earendil-works/pi-tui";
|
|
|
5
5
|
|
|
6
6
|
import { QuestionList } from "../question-list.ts";
|
|
7
7
|
import { MultiSelect, SingleSelect } from "../selection-mode.ts";
|
|
8
|
-
import type { KeybindingsManager, Theme } from "@
|
|
8
|
+
import type { KeybindingsManager, Theme } from "@selesai/code";
|
|
9
9
|
import type { ResolvedShortcut } from "../types.ts";
|
|
10
10
|
|
|
11
11
|
// ---------------------------------------------------------------------------
|
|
@@ -227,4 +227,4 @@ test("onSubmit passes commentEnabled=true when comment is enabled", () => {
|
|
|
227
227
|
list.handleInput(CTRL_G); // enable comment
|
|
228
228
|
list.handleInput(ENTER); // confirm
|
|
229
229
|
assert.deepEqual(submitted, [["a"], true]);
|
|
230
|
-
});
|
|
230
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// TUI protocol adapter — wraps ctx.ui into UIProtocol.
|
|
2
2
|
|
|
3
|
-
import type { ExtensionContext } from "@
|
|
3
|
+
import type { ExtensionContext } from "@selesai/code";
|
|
4
4
|
import type { OverlayHandle } from "@earendil-works/pi-tui";
|
|
5
5
|
|
|
6
6
|
import { OVERLAY_MIN_WIDTH, OVERLAY_OVERLAY_MAX_HEIGHT, OVERLAY_WIDTH } from "./constants.ts";
|
|
@@ -30,4 +30,4 @@ export function createTUIProtocol(ctx: ExtensionContext): UIProtocol {
|
|
|
30
30
|
setStatus: (key, text) => ctx.ui.setStatus(key, text),
|
|
31
31
|
notify: (msg, level) => ctx.ui.notify(msg, level),
|
|
32
32
|
};
|
|
33
|
-
}
|
|
33
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Shared type definitions for the question extension.
|
|
2
2
|
|
|
3
|
-
import type { KeybindingsManager } from "@
|
|
3
|
+
import type { KeybindingsManager } from "@selesai/code";
|
|
4
4
|
|
|
5
5
|
export type RawOption = string | { label: string; description?: string };
|
|
6
6
|
|
|
@@ -99,4 +99,4 @@ export interface ResolvedQuestionParams {
|
|
|
99
99
|
displayMode: DisplayMode;
|
|
100
100
|
shortcuts: ResolvedShortcuts;
|
|
101
101
|
timeout: number | undefined;
|
|
102
|
-
}
|
|
102
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// UIProtocol port — abstracts TUI vs dialog/RPC transport.
|
|
2
2
|
|
|
3
|
-
import type { KeybindingsManager } from "@
|
|
3
|
+
import type { KeybindingsManager } from "@selesai/code";
|
|
4
4
|
import type { OverlayHandle, Theme, TUI } from "@earendil-works/pi-tui";
|
|
5
5
|
|
|
6
6
|
import type { QuestionResponse, ResolvedQuestionParams } from "./types.ts";
|
|
@@ -43,4 +43,4 @@ export interface UIProtocol {
|
|
|
43
43
|
|
|
44
44
|
export interface FallbackProtocol {
|
|
45
45
|
ask(params: ResolvedQuestionParams, protocol: UIProtocol): Promise<QuestionResponse | null>;
|
|
46
|
-
}
|
|
46
|
+
}
|
package/dist/extensions/rtk.ts
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
// 1 No RTK equivalent → pass through unchanged
|
|
11
11
|
// 3 + stdout Rewrite (advisory) → mutate command
|
|
12
12
|
|
|
13
|
-
import type { ExtensionAPI } from "@
|
|
14
|
-
import { isToolCallEventType } from "@
|
|
13
|
+
import type { ExtensionAPI } from "@selesai/code"
|
|
14
|
+
import { isToolCallEventType } from "@selesai/code"
|
|
15
15
|
|
|
16
16
|
const REWRITE_TIMEOUT_MS = 2_000
|
|
17
17
|
const MIN_SUPPORTED_RTK_MINOR = 23
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
13
13
|
import { dirname, join } from "node:path";
|
|
14
|
-
import { getAgentDir, getModelsPath } from "@
|
|
15
|
-
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext, SessionStartEvent } from "@
|
|
14
|
+
import { getAgentDir, getModelsPath } from "@selesai/code";
|
|
15
|
+
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext, SessionStartEvent } from "@selesai/code";
|
|
16
16
|
|
|
17
17
|
export const TOKEN_IN_PROVIDER = "tokenin";
|
|
18
18
|
export const TOKEN_IN_DASHBOARD_URL = "https://token-in.selesai.in/dashboard/tokens";
|
package/dist/extensions/undo.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExtensionAPI } from "@
|
|
1
|
+
import type { ExtensionAPI } from "@selesai/code";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
13
13
|
import { dirname, join } from "node:path";
|
|
14
|
-
import { getAgentDir, getSettingsPath } from "@
|
|
15
|
-
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext, SessionStartEvent } from "@
|
|
14
|
+
import { getAgentDir, getSettingsPath } from "@selesai/code";
|
|
15
|
+
import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext, SessionStartEvent } from "@selesai/code";
|
|
16
16
|
|
|
17
17
|
export type OnboardingResult =
|
|
18
18
|
| { kind: "saved" }
|
|
@@ -219,4 +219,4 @@ export default function webAgentOnboardingExtension(pi: ExtensionAPI): void {
|
|
|
219
219
|
}
|
|
220
220
|
},
|
|
221
221
|
});
|
|
222
|
-
}
|
|
222
|
+
}
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
ExtensionCommandContext,
|
|
9
9
|
ExtensionContext,
|
|
10
10
|
ToolDefinition,
|
|
11
|
-
} from "@
|
|
11
|
+
} from "@selesai/code";
|
|
12
12
|
import { Text } from "@earendil-works/pi-tui";
|
|
13
13
|
import { Type } from "typebox";
|
|
14
14
|
import { access, mkdir, writeFile } from "node:fs/promises";
|
|
@@ -504,12 +504,20 @@ export function createWorkflowExtension(
|
|
|
504
504
|
if (event.toolName === "subagent" && sm.snapshot.active && SUBAGENT_FALLBACK_PHASES.has(sm.snapshot.phase)) {
|
|
505
505
|
const file = config.phaseArtifacts[sm.snapshot.phase];
|
|
506
506
|
if (file) {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
507
|
+
// ponytail: management actions (list/get/models/doctor/status/...)
|
|
508
|
+
// return text but are NOT the architect/recapper/... execution
|
|
509
|
+
// result. Writing their text to plan.md would advance the workflow
|
|
510
|
+
// on agent-listing output (the `subagent list` result is plain
|
|
511
|
+
// text). Execution calls set `agent`/`chain`/`tasks`; management
|
|
512
|
+
// calls set `action`. Only fall back for execution calls.
|
|
513
|
+
if (typeof event.input?.action !== "string") {
|
|
514
|
+
const expectedPath = resolve(sm.snapshot.artifactDir, file);
|
|
515
|
+
if (!(await realFileExists(expectedPath))) {
|
|
516
|
+
const text = textFromToolResultContent(event.content);
|
|
517
|
+
if (text) {
|
|
518
|
+
await mkdir(sm.snapshot.artifactDir, { recursive: true });
|
|
519
|
+
await writeFile(expectedPath, text, "utf8");
|
|
520
|
+
}
|
|
513
521
|
}
|
|
514
522
|
}
|
|
515
523
|
}
|
|
@@ -585,4 +593,4 @@ export function createWorkflowExtension(
|
|
|
585
593
|
},
|
|
586
594
|
});
|
|
587
595
|
};
|
|
588
|
-
}
|
|
596
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// load conflict (multiple extension modules would each try to register the
|
|
4
4
|
// shared writer).
|
|
5
5
|
|
|
6
|
-
import type { ExtensionAPI } from "@
|
|
6
|
+
import type { ExtensionAPI } from "@selesai/code";
|
|
7
7
|
import { __resetWorkflowRegistryForTests, createWorkflowExtension } from "./adapter.ts";
|
|
8
8
|
import { prototypeMode } from "./modes/prototype.ts";
|
|
9
9
|
import { quickMode } from "./modes/quick.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,wBAAwB,CAAC;AAQ/F;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,iBAAiB,CAAU;IACnC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,YAAY,CAAS;IAE7B,YACC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,iBAAiB,UAAQ,EACzB,aAAa,GAAE,aAAkC,EACjD,mBAAmB,SAAgB,EAenC;IAEQ,UAAU,IAAI,IAAI,CAK1B;IAED,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAKxC;IAED,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAK1C;IAEQ,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CASvC;IAED,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CA0E7C;CACD","sourcesContent":["import type { AssistantMessage } from \"@earendil-works/pi-ai\";\nimport { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@earendil-works/pi-tui\";\nimport { normalizeAssistantThinkingTags } from \"../../../utils/thinking-tags.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\tprivate markdownTheme: MarkdownTheme;\n\tprivate hiddenThinkingLabel: string;\n\tprivate lastMessage?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = \"Thinking...\",\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst lines = super.render(width);\n\t\tif (this.hasToolCalls || lines.length === 0) {\n\t\t\treturn lines;\n\t\t}\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\t\treturn lines;\n\t}\n\n\tupdateContent(message: AssistantMessage): void {\n\t\tmessage = normalizeAssistantThinkingTags(message);\n\t\tthis.lastMessage = message;\n\n\t\t// Clear content container\n\t\tthis.contentContainer.clear();\n\n\t\tconst hasVisibleContent = message.content.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\n\t\tif (hasVisibleContent) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\t// Render content in order\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\tthis.contentContainer.addChild(new Markdown(content.text.trim(), 1, 0, this.markdownTheme));\n\t\t\t} else if (content.type === \"thinking\" && content.thinking.trim()) {\n\t\t\t\t// Add spacing only when another visible assistant content block follows.\n\t\t\t\t// This avoids a superfluous blank line before separately-rendered tool execution blocks.\n\t\t\t\tconst hasVisibleContentAfter = message.content\n\t\t\t\t\t.slice(i + 1)\n\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()));\n\n\t\t\t\tif (this.hideThinkingBlock) {\n\t\t\t\t\t// Show static thinking label when hidden\n\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\tnew Text(theme.italic(theme.fg(\"thinkingText\", this.hiddenThinkingLabel)), 1, 0),\n\t\t\t\t\t);\n\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Thinking traces in thinkingText color, italic\n\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\tnew Markdown(content.thinking.trim(), 1, 0, this.markdownTheme, {\n\t\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\t\titalic: true,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check if aborted - show after partial content\n\t\t// But only if there are no tool calls (tool execution components will show the error)\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t\tif (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: \"Operation aborted\";\n\t\t\t\tif (hasVisibleContent) {\n\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t} else {\n\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t}\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), 1, 0));\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || \"Unknown error\";\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", `Error: ${errorMsg}`), 1, 0));\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Container, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
|
|
2
|
+
import { normalizeAssistantThinkingTags } from "../../../utils/thinking-tags.js";
|
|
2
3
|
import { getMarkdownTheme, theme } from "../theme/theme.js";
|
|
3
4
|
const OSC133_ZONE_START = "\x1b]133;A\x07";
|
|
4
5
|
const OSC133_ZONE_END = "\x1b]133;B\x07";
|
|
@@ -53,6 +54,7 @@ export class AssistantMessageComponent extends Container {
|
|
|
53
54
|
return lines;
|
|
54
55
|
}
|
|
55
56
|
updateContent(message) {
|
|
57
|
+
message = normalizeAssistantThinkingTags(message);
|
|
56
58
|
this.lastMessage = message;
|
|
57
59
|
// Clear content container
|
|
58
60
|
this.contentContainer.clear();
|