tau-coding-agent 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -32
- package/extensions/answer.ts +111 -118
- package/package.json +5 -1
- package/skills/oracle/scripts/oracle-bundle +82 -34
- package/themes/tau-dark.json +85 -0
package/README.md
CHANGED
|
@@ -2,41 +2,61 @@
|
|
|
2
2
|
|
|
3
3
|
Coding-focused Tau package for [Pi](https://pi.dev).
|
|
4
4
|
|
|
5
|
+
Tau turns Pi's minimal core into an opinionated, polished coding-agent setup with web search, code review workflows, sandboxing, local memory, usage reporting, and a curated skill set for day-to-day software work.
|
|
6
|
+
|
|
5
7
|
## Install
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
10
|
pi install npm:tau-coding-agent
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
- `
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
- `
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
13
|
+
Project-local install lets a repository pin Tau for everyone working on it:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pi install -l npm:tau-coding-agent
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Extensions
|
|
20
|
+
|
|
21
|
+
| Extension | Command | Description |
|
|
22
|
+
| ------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
23
|
+
| `answer` | `/answer` | Extract and interactively answer agent questions. |
|
|
24
|
+
| `branch-term` | `/branch` | Open a new terminal on the current session's git branch. |
|
|
25
|
+
| `btw` | `/btw` | Run a one-off side request with read-only tools and no context persistence. |
|
|
26
|
+
| `ghostty` | — | Ghostty tab title enhancements while the agent is working, waiting, or idle. |
|
|
27
|
+
| `git-diff-stats` | — | Status bar diff stats for local changes in the current repo. |
|
|
28
|
+
| `git-pr-status` | — | Status bar PR number and link for the current branch. |
|
|
29
|
+
| `insights` | `/insights` | Analyze Pi sessions and suggest reusable instructions, templates, skills, and extensions. |
|
|
30
|
+
| `interlude` | `alt+x` | Stash the current message draft, send one interlude message, then restore the draft. |
|
|
31
|
+
| `loop` | `/loop` | Repeat a prompt until the agent signals success. |
|
|
32
|
+
| `memory` | `/memory` | Opt-in project-local memory for learning and continuity across sessions. |
|
|
33
|
+
| `notify` | — | Terminal notification when the agent is waiting for input. |
|
|
34
|
+
| `openai-fast` | `/fast` | Toggle priority service tier for supported OpenAI models. |
|
|
35
|
+
| `openai-verbosity` | `/verbosity` | Set verbosity for supported OpenAI models. |
|
|
36
|
+
| `review` | `/review`, `/triage` | Multi-focus review and PR feedback triage for PRs, branches, commits, and local changes, with integrated follow-up fixes. |
|
|
37
|
+
| `sandbox` | `/sandbox` | OS-level sandboxing for bash commands with runtime overrides. |
|
|
38
|
+
| `usage` | `/usage` | Historical provider usage breakdown with all-provider history and live quota snapshots. |
|
|
39
|
+
| `websearch` | — | Web search via Gemini, OpenAI, or Claude, leveraging Pi or browser session credentials. |
|
|
40
|
+
| `worktree` | `/worktree` | Create, list, and archive git worktrees, optionally opening them in a new terminal or tmux pane. |
|
|
41
|
+
|
|
42
|
+
## Skills
|
|
43
|
+
|
|
44
|
+
| Skill | Description |
|
|
45
|
+
| ------------------- | ---------------------------------------------------------------------------------- |
|
|
46
|
+
| `browser-tools` | Interactive browser automation via Chrome DevTools Protocol. |
|
|
47
|
+
| `git-clean-history` | Reimplement a branch on a fresh branch off `main` with a clean commit history. |
|
|
48
|
+
| `git-commit` | Tidy, focused commits with clear rationale in messages. |
|
|
49
|
+
| `oracle` | Second opinion from another LLM for debugging, refactors, design, or code reviews. |
|
|
50
|
+
| `sentry` | Fetch and analyze Sentry issues, events, transactions, and logs. |
|
|
51
|
+
| `update-changelog` | Update CHANGELOG.md following Keep a Changelog. |
|
|
52
|
+
| `web-design` | Distinctive, production-ready web interfaces. |
|
|
53
|
+
|
|
54
|
+
## Themes
|
|
55
|
+
|
|
56
|
+
| Theme | Description |
|
|
57
|
+
| ---------- | ------------------------------------------------------------- |
|
|
58
|
+
| `tau-dark` | Pi's official dark theme with a calmer, more cohesive polish. |
|
|
59
|
+
|
|
60
|
+
## Agent configuration
|
|
61
|
+
|
|
62
|
+
Tau does not include agent configuration; those files are highly personal. Configure Pi with your own `AGENTS.md`, `settings.json`, sandbox config, and model preferences.
|
package/extensions/answer.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { complete, type Model, type Api, type UserMessage } from "@mariozechner/pi-ai";
|
|
14
|
-
import type { ExtensionAPI
|
|
14
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
15
15
|
import { BorderedLoader } from "@mariozechner/pi-coding-agent";
|
|
16
16
|
import {
|
|
17
17
|
type Component,
|
|
@@ -464,138 +464,131 @@ class QnAComponent implements Component {
|
|
|
464
464
|
}
|
|
465
465
|
|
|
466
466
|
export default function (pi: ExtensionAPI) {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
467
|
+
pi.registerCommand("answer", {
|
|
468
|
+
description: "Extract questions from last assistant message into interactive Q&A",
|
|
469
|
+
handler: async (_args, ctx) => {
|
|
470
|
+
if (!ctx.hasUI) {
|
|
471
|
+
ctx.ui.notify("answer requires interactive mode", "error");
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
472
474
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
475
|
+
if (!ctx.model) {
|
|
476
|
+
ctx.ui.notify("No model selected", "error");
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
477
479
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
480
|
+
// Find the last assistant message on the current branch
|
|
481
|
+
const branch = ctx.sessionManager.getBranch();
|
|
482
|
+
let lastAssistantText: string | undefined;
|
|
483
|
+
|
|
484
|
+
for (let i = branch.length - 1; i >= 0; i--) {
|
|
485
|
+
const entry = branch[i];
|
|
486
|
+
if (entry.type === "message") {
|
|
487
|
+
const msg = entry.message;
|
|
488
|
+
if ("role" in msg && msg.role === "assistant") {
|
|
489
|
+
if (msg.stopReason !== "stop") {
|
|
490
|
+
ctx.ui.notify(`Last assistant message incomplete (${msg.stopReason})`, "error");
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
const textParts = msg.content
|
|
494
|
+
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
|
495
|
+
.map((c) => c.text);
|
|
496
|
+
if (textParts.length > 0) {
|
|
497
|
+
lastAssistantText = textParts.join("\n");
|
|
498
|
+
break;
|
|
499
|
+
}
|
|
497
500
|
}
|
|
498
501
|
}
|
|
499
502
|
}
|
|
500
|
-
}
|
|
501
503
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
// Select the best model for extraction (prefer a fast model in the current family).
|
|
508
|
-
const extractionSelection = await selectExtractionModel(ctx.model, ctx.modelRegistry);
|
|
509
|
-
if (!extractionSelection) {
|
|
510
|
-
ctx.ui.notify("No configured Pi model is available for question extraction", "error");
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
504
|
+
if (!lastAssistantText) {
|
|
505
|
+
ctx.ui.notify("No assistant messages found", "error");
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
513
508
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
(
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
`Extracting questions using ${extractionSelection.model.id}...`,
|
|
521
|
-
);
|
|
522
|
-
loader.onAbort = () => done(null);
|
|
523
|
-
|
|
524
|
-
const doExtract = async () => {
|
|
525
|
-
const userMessage: UserMessage = {
|
|
526
|
-
role: "user",
|
|
527
|
-
content: [{ type: "text", text: lastAssistantText! }],
|
|
528
|
-
timestamp: Date.now(),
|
|
529
|
-
};
|
|
509
|
+
// Select the best model for extraction (prefer a fast model in the current family).
|
|
510
|
+
const extractionSelection = await selectExtractionModel(ctx.model, ctx.modelRegistry);
|
|
511
|
+
if (!extractionSelection) {
|
|
512
|
+
ctx.ui.notify("No configured Pi model is available for question extraction", "error");
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
530
515
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
},
|
|
516
|
+
// Run extraction with loader UI
|
|
517
|
+
const extractionResult = await ctx.ui.custom<ExtractionResult | null>(
|
|
518
|
+
(tui, theme, _kb, done) => {
|
|
519
|
+
const loader = new BorderedLoader(
|
|
520
|
+
tui,
|
|
521
|
+
theme,
|
|
522
|
+
`Extracting questions using ${extractionSelection.model.id}...`,
|
|
539
523
|
);
|
|
524
|
+
loader.onAbort = () => done(null);
|
|
525
|
+
|
|
526
|
+
const doExtract = async () => {
|
|
527
|
+
const userMessage: UserMessage = {
|
|
528
|
+
role: "user",
|
|
529
|
+
content: [{ type: "text", text: lastAssistantText! }],
|
|
530
|
+
timestamp: Date.now(),
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
const response = await complete(
|
|
534
|
+
extractionSelection.model,
|
|
535
|
+
{ systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
|
|
536
|
+
{
|
|
537
|
+
apiKey: extractionSelection.apiKey,
|
|
538
|
+
headers: extractionSelection.headers,
|
|
539
|
+
signal: loader.signal,
|
|
540
|
+
},
|
|
541
|
+
);
|
|
542
|
+
|
|
543
|
+
if (response.stopReason === "aborted") {
|
|
544
|
+
return null;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const responseText = response.content
|
|
548
|
+
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
|
549
|
+
.map((c) => c.text)
|
|
550
|
+
.join("\n");
|
|
551
|
+
|
|
552
|
+
return parseExtractionResult(responseText);
|
|
553
|
+
};
|
|
540
554
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
const responseText = response.content
|
|
546
|
-
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
|
547
|
-
.map((c) => c.text)
|
|
548
|
-
.join("\n");
|
|
549
|
-
|
|
550
|
-
return parseExtractionResult(responseText);
|
|
551
|
-
};
|
|
552
|
-
|
|
553
|
-
doExtract()
|
|
554
|
-
.then(done)
|
|
555
|
-
.catch(() => done(null));
|
|
556
|
-
|
|
557
|
-
return loader;
|
|
558
|
-
},
|
|
559
|
-
);
|
|
560
|
-
|
|
561
|
-
if (extractionResult === null) {
|
|
562
|
-
ctx.ui.notify("Cancelled", "info");
|
|
563
|
-
return;
|
|
564
|
-
}
|
|
555
|
+
doExtract()
|
|
556
|
+
.then(done)
|
|
557
|
+
.catch(() => done(null));
|
|
565
558
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
}
|
|
559
|
+
return loader;
|
|
560
|
+
},
|
|
561
|
+
);
|
|
570
562
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
563
|
+
if (extractionResult === null) {
|
|
564
|
+
ctx.ui.notify("Cancelled", "info");
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
575
567
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
568
|
+
if (extractionResult.questions.length === 0) {
|
|
569
|
+
ctx.ui.notify("No questions found in the last message", "info");
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
580
572
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
content: "Here are my answers to your questions:\n\n" + answersResult,
|
|
586
|
-
display: true,
|
|
587
|
-
},
|
|
588
|
-
{ triggerTurn: true },
|
|
589
|
-
);
|
|
590
|
-
};
|
|
573
|
+
// Show the Q&A component
|
|
574
|
+
const answersResult = await ctx.ui.custom<string | null>((tui, _theme, _kb, done) => {
|
|
575
|
+
return new QnAComponent(extractionResult.questions, tui, done);
|
|
576
|
+
});
|
|
591
577
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
578
|
+
if (answersResult === null) {
|
|
579
|
+
ctx.ui.notify("Cancelled", "info");
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
596
582
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
583
|
+
// Send the answers directly as a message and trigger a turn
|
|
584
|
+
pi.sendMessage(
|
|
585
|
+
{
|
|
586
|
+
customType: "answers",
|
|
587
|
+
content: "Here are my answers to your questions:\n\n" + answersResult,
|
|
588
|
+
display: true,
|
|
589
|
+
},
|
|
590
|
+
{ triggerTurn: true },
|
|
591
|
+
);
|
|
592
|
+
},
|
|
600
593
|
});
|
|
601
594
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tau-coding-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Coding-focused Tau distribution for Pi",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-extension",
|
|
@@ -61,11 +61,15 @@
|
|
|
61
61
|
"skills/sentry",
|
|
62
62
|
"skills/update-changelog",
|
|
63
63
|
"skills/web-design"
|
|
64
|
+
],
|
|
65
|
+
"themes": [
|
|
66
|
+
"themes/tau-dark.json"
|
|
64
67
|
]
|
|
65
68
|
},
|
|
66
69
|
"files": [
|
|
67
70
|
"extensions",
|
|
68
71
|
"skills",
|
|
72
|
+
"themes",
|
|
69
73
|
"README.md",
|
|
70
74
|
"LICENSE"
|
|
71
75
|
]
|
|
@@ -130,10 +130,31 @@ done
|
|
|
130
130
|
|
|
131
131
|
include_patterns=()
|
|
132
132
|
exclude_patterns=()
|
|
133
|
+
explicit_files=()
|
|
134
|
+
|
|
135
|
+
add_pattern() {
|
|
136
|
+
local is_exclude="$1"
|
|
137
|
+
local pattern="$2"
|
|
138
|
+
if [[ "$is_exclude" -eq 1 ]]; then
|
|
139
|
+
exclude_patterns+=("$pattern")
|
|
140
|
+
else
|
|
141
|
+
include_patterns+=("$pattern")
|
|
142
|
+
fi
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
add_exact_file() {
|
|
146
|
+
local is_exclude="$1"
|
|
147
|
+
local file="$2"
|
|
148
|
+
if [[ "$is_exclude" -eq 1 ]]; then
|
|
149
|
+
exclude_patterns+=("$file")
|
|
150
|
+
else
|
|
151
|
+
explicit_files+=("$file")
|
|
152
|
+
fi
|
|
153
|
+
}
|
|
133
154
|
|
|
134
155
|
for sel in "${selectors[@]}"; do
|
|
135
156
|
is_exclude=0
|
|
136
|
-
if [[ "$sel" ==
|
|
157
|
+
if [[ "${sel:0:1}" == "!" ]]; then
|
|
137
158
|
is_exclude=1
|
|
138
159
|
sel="${sel:1}"
|
|
139
160
|
fi
|
|
@@ -148,69 +169,96 @@ for sel in "${selectors[@]}"; do
|
|
|
148
169
|
if [[ "$sel" == "${ROOT_DIR}/"* ]]; then
|
|
149
170
|
sel="${sel#"${ROOT_DIR}/"}"
|
|
150
171
|
else
|
|
151
|
-
|
|
152
|
-
|
|
172
|
+
if [[ "$is_exclude" -eq 1 ]]; then
|
|
173
|
+
add_pattern "$is_exclude" "$sel"
|
|
174
|
+
continue
|
|
175
|
+
fi
|
|
176
|
+
if [[ ! -f "$sel" ]]; then
|
|
177
|
+
echo "error: absolute paths outside repo must name an existing file: ${sel}" >&2
|
|
178
|
+
exit 2
|
|
179
|
+
fi
|
|
180
|
+
add_exact_file "$is_exclude" "$sel"
|
|
181
|
+
continue
|
|
153
182
|
fi
|
|
154
183
|
fi
|
|
155
184
|
|
|
156
|
-
|
|
157
|
-
|
|
185
|
+
sel="${sel#./}"
|
|
186
|
+
|
|
187
|
+
if [[ -f "$sel" ]]; then
|
|
188
|
+
add_exact_file "$is_exclude" "$sel"
|
|
189
|
+
continue
|
|
158
190
|
fi
|
|
159
191
|
|
|
160
|
-
if [[
|
|
161
|
-
|
|
162
|
-
else
|
|
163
|
-
include_patterns+=("$sel")
|
|
192
|
+
if [[ -d "$sel" ]] && ! has_glob_chars "$sel"; then
|
|
193
|
+
sel="${sel}/**"
|
|
164
194
|
fi
|
|
195
|
+
|
|
196
|
+
add_pattern "$is_exclude" "$sel"
|
|
165
197
|
done
|
|
166
198
|
|
|
167
|
-
if [[ "${#include_patterns[@]}" -eq 0 ]]; then
|
|
199
|
+
if [[ "${#include_patterns[@]}" -eq 0 && "${#explicit_files[@]}" -eq 0 ]]; then
|
|
168
200
|
echo "error: no include patterns provided (need at least one non-! --file)" >&2
|
|
169
201
|
exit 2
|
|
170
202
|
fi
|
|
171
203
|
|
|
172
204
|
all_files=()
|
|
173
|
-
if
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
205
|
+
if [[ "${#include_patterns[@]}" -gt 0 ]]; then
|
|
206
|
+
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
207
|
+
while IFS= read -r f; do
|
|
208
|
+
[[ -n "$f" ]] && all_files+=("$f")
|
|
209
|
+
done < <(git ls-files -co --exclude-standard)
|
|
210
|
+
else
|
|
211
|
+
while IFS= read -r f; do
|
|
212
|
+
f="${f#./}"
|
|
213
|
+
[[ -n "$f" ]] && all_files+=("$f")
|
|
214
|
+
done < <(find . -type f -print)
|
|
215
|
+
fi
|
|
182
216
|
fi
|
|
183
217
|
|
|
184
218
|
selected=()
|
|
185
219
|
skipped=()
|
|
186
220
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
221
|
+
select_file() {
|
|
222
|
+
local file="$1"
|
|
223
|
+
local size=""
|
|
190
224
|
|
|
191
|
-
|
|
192
|
-
continue
|
|
193
|
-
fi
|
|
225
|
+
[[ -z "$file" ]] && return 0
|
|
194
226
|
|
|
195
|
-
if [[ "${#exclude_patterns[@]}" -gt 0 ]] && matches_any_pattern "$
|
|
196
|
-
|
|
227
|
+
if [[ "${#exclude_patterns[@]}" -gt 0 ]] && matches_any_pattern "$file" "${exclude_patterns[@]}"; then
|
|
228
|
+
return 0
|
|
197
229
|
fi
|
|
198
230
|
|
|
199
|
-
if [[ ! -f "$
|
|
200
|
-
|
|
231
|
+
if [[ ! -f "$file" ]]; then
|
|
232
|
+
return 0
|
|
201
233
|
fi
|
|
202
234
|
|
|
203
|
-
size="$(file_size_bytes "$
|
|
235
|
+
size="$(file_size_bytes "$file")"
|
|
204
236
|
if [[ "$size" -gt "$MAX_BYTES" ]]; then
|
|
205
|
-
skipped+=("${
|
|
237
|
+
skipped+=("${file} (too large: ${size} bytes)")
|
|
238
|
+
return 0
|
|
239
|
+
fi
|
|
240
|
+
|
|
241
|
+
selected+=("$file")
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
for file in "${explicit_files[@]}"; do
|
|
245
|
+
select_file "$file"
|
|
246
|
+
done
|
|
247
|
+
|
|
248
|
+
for rel in "${all_files[@]}"; do
|
|
249
|
+
[[ -z "$rel" ]] && continue
|
|
250
|
+
|
|
251
|
+
path_has_ignored_dir "$rel" && continue
|
|
252
|
+
|
|
253
|
+
if ! matches_any_pattern "$rel" "${include_patterns[@]}"; then
|
|
206
254
|
continue
|
|
207
255
|
fi
|
|
208
256
|
|
|
209
|
-
|
|
257
|
+
select_file "$rel"
|
|
210
258
|
done
|
|
211
259
|
|
|
212
260
|
if [[ "$DRY_RUN" -eq 1 ]]; then
|
|
213
|
-
printf '%s\n' "${selected[@]}" | LC_ALL=C sort
|
|
261
|
+
printf '%s\n' "${selected[@]}" | LC_ALL=C sort -u
|
|
214
262
|
if [[ "${#skipped[@]}" -gt 0 ]]; then
|
|
215
263
|
printf '\nSkipped:\n' >&2
|
|
216
264
|
printf '%s\n' "${skipped[@]}" >&2
|
|
@@ -219,7 +267,7 @@ if [[ "$DRY_RUN" -eq 1 ]]; then
|
|
|
219
267
|
fi
|
|
220
268
|
|
|
221
269
|
printf '# Task\n\n%s\n\n# Files\n' "$(trim "$PROMPT")"
|
|
222
|
-
printf '%s\n' "${selected[@]}" | LC_ALL=C sort | while IFS= read -r rel; do
|
|
270
|
+
printf '%s\n' "${selected[@]}" | LC_ALL=C sort -u | while IFS= read -r rel; do
|
|
223
271
|
[[ -z "$rel" ]] && continue
|
|
224
272
|
printf '\n## %s\n\n```\n' "$rel"
|
|
225
273
|
cat "$rel"
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
|
|
3
|
+
"name": "tau-dark",
|
|
4
|
+
"vars": {
|
|
5
|
+
"accent": "#8abeb7",
|
|
6
|
+
"blue": "#5f87af",
|
|
7
|
+
"green": "#b5bd68",
|
|
8
|
+
"red": "#cc6666",
|
|
9
|
+
"yellow": "#f0c674",
|
|
10
|
+
"gray": "#808080",
|
|
11
|
+
"dimGray": "#666666",
|
|
12
|
+
"darkGray": "#505050",
|
|
13
|
+
"heading": "#DCDCAA",
|
|
14
|
+
"selectedBg": "#3a3a4a",
|
|
15
|
+
"userMsgBg": "#343541",
|
|
16
|
+
"toolPendingBg": "#282832",
|
|
17
|
+
"toolSuccessBg": "#283228",
|
|
18
|
+
"toolErrorBg": "#3c2828",
|
|
19
|
+
"customMsgBg": "#2d2838"
|
|
20
|
+
},
|
|
21
|
+
"colors": {
|
|
22
|
+
"accent": "accent",
|
|
23
|
+
"border": "blue",
|
|
24
|
+
"borderAccent": "accent",
|
|
25
|
+
"borderMuted": "darkGray",
|
|
26
|
+
"success": "green",
|
|
27
|
+
"error": "red",
|
|
28
|
+
"warning": "yellow",
|
|
29
|
+
"muted": "gray",
|
|
30
|
+
"dim": "dimGray",
|
|
31
|
+
"text": "",
|
|
32
|
+
"thinkingText": "gray",
|
|
33
|
+
|
|
34
|
+
"selectedBg": "selectedBg",
|
|
35
|
+
"userMessageBg": "userMsgBg",
|
|
36
|
+
"userMessageText": "",
|
|
37
|
+
"customMessageBg": "customMsgBg",
|
|
38
|
+
"customMessageText": "",
|
|
39
|
+
"customMessageLabel": "#9575cd",
|
|
40
|
+
"toolPendingBg": "toolPendingBg",
|
|
41
|
+
"toolSuccessBg": "toolSuccessBg",
|
|
42
|
+
"toolErrorBg": "toolErrorBg",
|
|
43
|
+
"toolTitle": "",
|
|
44
|
+
"toolOutput": "gray",
|
|
45
|
+
|
|
46
|
+
"mdHeading": "heading",
|
|
47
|
+
"mdLink": "#81a2be",
|
|
48
|
+
"mdLinkUrl": "dimGray",
|
|
49
|
+
"mdCode": "accent",
|
|
50
|
+
"mdCodeBlock": "green",
|
|
51
|
+
"mdCodeBlockBorder": "gray",
|
|
52
|
+
"mdQuote": "gray",
|
|
53
|
+
"mdQuoteBorder": "gray",
|
|
54
|
+
"mdHr": "gray",
|
|
55
|
+
"mdListBullet": "accent",
|
|
56
|
+
|
|
57
|
+
"toolDiffAdded": "green",
|
|
58
|
+
"toolDiffRemoved": "red",
|
|
59
|
+
"toolDiffContext": "gray",
|
|
60
|
+
|
|
61
|
+
"syntaxComment": "#6A9955",
|
|
62
|
+
"syntaxKeyword": "#569CD6",
|
|
63
|
+
"syntaxFunction": "#DCDCAA",
|
|
64
|
+
"syntaxVariable": "#9CDCFE",
|
|
65
|
+
"syntaxString": "#CE9178",
|
|
66
|
+
"syntaxNumber": "#B5CEA8",
|
|
67
|
+
"syntaxType": "#4EC9B0",
|
|
68
|
+
"syntaxOperator": "#D4D4D4",
|
|
69
|
+
"syntaxPunctuation": "#D4D4D4",
|
|
70
|
+
|
|
71
|
+
"thinkingOff": "darkGray",
|
|
72
|
+
"thinkingMinimal": "dimGray",
|
|
73
|
+
"thinkingLow": "#657B83",
|
|
74
|
+
"thinkingMedium": "#6f9bb3",
|
|
75
|
+
"thinkingHigh": "#78a8a1",
|
|
76
|
+
"thinkingXhigh": "accent",
|
|
77
|
+
|
|
78
|
+
"bashMode": "green"
|
|
79
|
+
},
|
|
80
|
+
"export": {
|
|
81
|
+
"pageBg": "#18181e",
|
|
82
|
+
"cardBg": "#1e1e24",
|
|
83
|
+
"infoBg": "#3c3728"
|
|
84
|
+
}
|
|
85
|
+
}
|