tau-coding-agent 0.1.5 → 0.2.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/README.md +15 -12
- package/extensions/answer.ts +129 -73
- package/extensions/branch-term/README.md +7 -0
- package/extensions/{branch-term.ts → branch-term/index.ts} +113 -104
- package/extensions/btw.ts +90 -4
- package/extensions/caffeinate/README.md +5 -0
- package/extensions/caffeinate/index.ts +144 -0
- package/extensions/fast.ts +292 -0
- package/extensions/ghostty.ts +214 -211
- package/extensions/git-diff-stats.ts +124 -84
- package/extensions/git-pr-status.ts +274 -208
- package/extensions/insights.ts +138 -183
- package/extensions/loop.ts +150 -135
- package/extensions/memory.ts +172 -97
- package/extensions/notify.ts +14 -26
- package/extensions/openai-verbosity.ts +108 -42
- package/extensions/review/fix.ts +15 -6
- package/extensions/review/git.ts +93 -103
- package/extensions/review/index.ts +60 -62
- package/extensions/review/interrupt.ts +117 -0
- package/extensions/review/message-queue.ts +45 -12
- package/extensions/review/models.ts +79 -3
- package/extensions/review/prompts.ts +43 -40
- package/extensions/review/review.ts +161 -166
- package/extensions/review/runner.ts +139 -147
- package/extensions/review/runtime.ts +173 -120
- package/extensions/review/submit-review-tool.ts +1 -5
- package/extensions/review/submit-triage-tool.ts +1 -0
- package/extensions/review/triage.ts +41 -44
- package/extensions/sandbox/bash.ts +775 -0
- package/extensions/sandbox/command.ts +605 -0
- package/extensions/sandbox/config.ts +764 -0
- package/extensions/sandbox/index.ts +138 -2850
- package/extensions/sandbox/macos-sandbox-shell.mjs +202 -0
- package/extensions/sandbox/permissions/dialog.ts +118 -0
- package/extensions/sandbox/permissions/filesystem.ts +559 -0
- package/extensions/sandbox/permissions/mach-lookup.ts +186 -0
- package/extensions/sandbox/permissions/network.ts +164 -0
- package/extensions/sandbox/permissions/unsandboxed.ts +270 -0
- package/extensions/sandbox/runtime.ts +616 -0
- package/extensions/stash.ts +28 -15
- package/extensions/subagent/README.md +73 -0
- package/extensions/subagent/index.ts +822 -0
- package/extensions/subagent/interrupt.ts +117 -0
- package/extensions/subagent/permissions.ts +101 -0
- package/extensions/subagent/rpc.ts +177 -0
- package/extensions/tool-display-mode.ts +267 -64
- package/extensions/usage/anthropic.ts +5 -6
- package/extensions/usage/github-copilot.ts +30 -9
- package/extensions/usage/index.ts +250 -357
- package/extensions/usage/openai-codex.ts +2 -2
- package/extensions/usage/openrouter.ts +10 -2
- package/extensions/websearch/README.md +12 -47
- package/extensions/websearch/config.ts +5 -2
- package/extensions/websearch/index.ts +94 -109
- package/extensions/websearch/output.ts +51 -0
- package/extensions/websearch/providers/anthropic.pi.ts +27 -44
- package/extensions/websearch/providers/gemini.browser.ts +68 -77
- package/extensions/websearch/providers/gemini.pi.ts +17 -17
- package/extensions/websearch/providers/openai-codex.pi.ts +145 -7
- package/extensions/websearch/providers/pi-model.shared.ts +44 -32
- package/extensions/websearch/providers/shared.ts +87 -2
- package/extensions/websearch/types.ts +0 -3
- package/extensions/worktree.ts +132 -172
- package/package.json +10 -5
- package/skills/browser-tools/SKILL.md +29 -234
- package/skills/browser-tools/references/cookies.md +36 -0
- package/skills/browser-tools/references/interaction.md +90 -0
- package/skills/browser-tools/references/logging.md +34 -0
- package/skills/git-clean-history/SKILL.md +6 -6
- package/skills/git-commit/SKILL.md +5 -3
- package/skills/github-pull-request/SKILL.md +60 -0
- package/skills/github-pull-request/references/create.md +40 -0
- package/skills/github-pull-request/references/stewardship.md +60 -0
- package/skills/oracle/SKILL.md +4 -4
- package/skills/oracle/scripts/oracle +64 -51
- package/skills/sentry/SKILL.md +15 -185
- package/skills/sentry/references/events.md +79 -0
- package/skills/sentry/references/issues.md +62 -0
- package/skills/sentry/references/logs.md +46 -0
- package/skills/update-changelog/SKILL.md +27 -121
- package/skills/web-design/SKILL.md +16 -105
- package/themes/tau-dark.json +4 -0
- package/extensions/openai-fast.ts +0 -229
- package/extensions/websearch/providers/openai-codex.browser.ts +0 -77
- package/extensions/websearch/providers/openai-codex.shared.ts +0 -123
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ pi install -l npm:tau-coding-agent
|
|
|
23
23
|
| `answer` | `/answer` | Extract and interactively answer agent questions. |
|
|
24
24
|
| `branch-term` | `/branch` | Open a new terminal on the current session's git branch. |
|
|
25
25
|
| `btw` | `/btw` | Run a one-off side request with read-only tools and no context persistence. |
|
|
26
|
+
| `caffeinate` | — | Prevent system sleep while the agent runs. |
|
|
26
27
|
| `ghostty` | — | Ghostty tab title enhancements while the agent is working, waiting, or idle. |
|
|
27
28
|
| `git-diff-stats` | — | Status bar diff stats for local changes in the current repo. |
|
|
28
29
|
| `git-pr-status` | — | Status bar PR number and link for the current branch. |
|
|
@@ -31,26 +32,28 @@ pi install -l npm:tau-coding-agent
|
|
|
31
32
|
| `loop` | `/loop` | Repeat a prompt until the agent signals success. |
|
|
32
33
|
| `memory` | `/memory` | Opt-in project-local memory for learning and continuity across sessions. |
|
|
33
34
|
| `notify` | — | Terminal notification when the agent is waiting for input. |
|
|
34
|
-
| `
|
|
35
|
-
| `openai-verbosity` | `/verbosity` | Set verbosity for supported
|
|
35
|
+
| `fast` | `/fast` | Toggle fast processing for compatible models. |
|
|
36
|
+
| `openai-verbosity` | `/verbosity` | Set verbosity for supported GPT models. |
|
|
36
37
|
| `review` | `/review`, `/triage` | Multi-focus review and PR feedback triage for PRs, branches, commits, and local changes, with integrated follow-up fixes. |
|
|
37
38
|
| `sandbox` | `/sandbox` | OS-level sandboxing for bash commands with runtime overrides. |
|
|
38
|
-
| `
|
|
39
|
+
| `subagent` | — | Delegate work to background Pi agents and follow up with them. |
|
|
40
|
+
| `tool-display-mode` | `ctrl+o` | Cycle tool output modes and combine background activity in the composer. |
|
|
39
41
|
| `usage` | `/usage` | Historical provider usage breakdown with all-provider history and live quota snapshots. |
|
|
40
42
|
| `websearch` | — | Web search via Gemini, OpenAI, or Claude, leveraging Pi or browser session credentials. |
|
|
41
43
|
| `worktree` | `/worktree` | Create, list, and archive git worktrees, optionally opening them in a new terminal or tmux pane. |
|
|
42
44
|
|
|
43
45
|
## Skills
|
|
44
46
|
|
|
45
|
-
| Skill
|
|
46
|
-
|
|
|
47
|
-
| `browser-tools`
|
|
48
|
-
| `git-clean-history`
|
|
49
|
-
| `git-commit`
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
| `
|
|
47
|
+
| Skill | Description |
|
|
48
|
+
| --------------------- | ---------------------------------------------------------------------------------- |
|
|
49
|
+
| `browser-tools` | Interactive browser automation via Chrome DevTools Protocol. |
|
|
50
|
+
| `git-clean-history` | Reimplement a branch on a fresh branch off `main` with a clean commit history. |
|
|
51
|
+
| `git-commit` | Tidy, focused commits with clear rationale in messages. |
|
|
52
|
+
| `github-pull-request` | Create and steward pull requests through CI, review, and merge. |
|
|
53
|
+
| `oracle` | Second opinion from another LLM for debugging, refactors, design, or code reviews. |
|
|
54
|
+
| `sentry` | Fetch and analyze Sentry issues, events, transactions, and logs. |
|
|
55
|
+
| `update-changelog` | Update CHANGELOG.md following Keep a Changelog. |
|
|
56
|
+
| `web-design` | Distinctive, production-ready web interfaces. |
|
|
54
57
|
|
|
55
58
|
## Themes
|
|
56
59
|
|
package/extensions/answer.ts
CHANGED
|
@@ -10,9 +10,13 @@
|
|
|
10
10
|
* 4. Submits the compiled answers when done
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { complete } from "@earendil-works/pi-ai/compat";
|
|
14
13
|
import type { Model, Api, UserMessage } from "@earendil-works/pi-ai";
|
|
15
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
BorderedLoader,
|
|
16
|
+
type ExtensionAPI,
|
|
17
|
+
type ModelRegistry,
|
|
18
|
+
type Theme,
|
|
19
|
+
} from "@earendil-works/pi-coding-agent";
|
|
16
20
|
import {
|
|
17
21
|
type Component,
|
|
18
22
|
Editor,
|
|
@@ -26,6 +30,8 @@ import {
|
|
|
26
30
|
wrapTextWithAnsi,
|
|
27
31
|
} from "@earendil-works/pi-tui";
|
|
28
32
|
|
|
33
|
+
const MIN_QUESTIONNAIRE_WIDTH = 40;
|
|
34
|
+
|
|
29
35
|
const SYSTEM_PROMPT = `You extract items that need user input from assistant text:
|
|
30
36
|
|
|
31
37
|
- Direct questions
|
|
@@ -78,7 +84,7 @@ Example output:
|
|
|
78
84
|
"questions": []
|
|
79
85
|
}`;
|
|
80
86
|
|
|
81
|
-
const OPENAI_FAST_MODEL_ID = "gpt-5.
|
|
87
|
+
const OPENAI_FAST_MODEL_ID = "gpt-5.6-luna";
|
|
82
88
|
const ANTHROPIC_FAST_MODEL_ID = "claude-haiku-4-5";
|
|
83
89
|
|
|
84
90
|
// Structured output format for question extraction
|
|
@@ -91,20 +97,16 @@ interface ExtractionResult {
|
|
|
91
97
|
questions: ExtractedQuestion[];
|
|
92
98
|
}
|
|
93
99
|
|
|
94
|
-
|
|
100
|
+
type ExtractionOutcome =
|
|
101
|
+
| { status: "success"; result: ExtractionResult }
|
|
102
|
+
| { status: "cancelled" }
|
|
103
|
+
| { status: "error"; message: string };
|
|
104
|
+
|
|
105
|
+
interface ModelSelection {
|
|
95
106
|
model: Model<Api>;
|
|
96
|
-
apiKey?: string;
|
|
97
|
-
headers?: Record<string, string>;
|
|
98
107
|
}
|
|
99
108
|
|
|
100
|
-
type
|
|
101
|
-
find: (provider: string, modelId: string) => Model<Api> | undefined;
|
|
102
|
-
getApiKeyAndHeaders: (
|
|
103
|
-
model: Model<Api>,
|
|
104
|
-
) => Promise<
|
|
105
|
-
{ ok: true; apiKey?: string; headers?: Record<string, string> } | { ok: false; error: string }
|
|
106
|
-
>;
|
|
107
|
-
};
|
|
109
|
+
type ModelLookup = Pick<ModelRegistry, "find" | "getApiKeyAndHeaders">;
|
|
108
110
|
|
|
109
111
|
type ModelFamily = "openai" | "anthropic";
|
|
110
112
|
|
|
@@ -120,10 +122,10 @@ function detectModelFamily(provider: string): ModelFamily | null {
|
|
|
120
122
|
*/
|
|
121
123
|
async function selectExtractionModel(
|
|
122
124
|
currentModel: Model<Api>,
|
|
123
|
-
modelRegistry:
|
|
124
|
-
): Promise<
|
|
125
|
+
modelRegistry: ModelLookup,
|
|
126
|
+
): Promise<ModelSelection | null> {
|
|
125
127
|
const family = detectModelFamily(currentModel.provider);
|
|
126
|
-
if (!family) return
|
|
128
|
+
if (!family) return resolveModelSelection(modelRegistry, currentModel);
|
|
127
129
|
|
|
128
130
|
const modelId = family === "openai" ? OPENAI_FAST_MODEL_ID : ANTHROPIC_FAST_MODEL_ID;
|
|
129
131
|
const providerCandidates =
|
|
@@ -135,21 +137,21 @@ async function selectExtractionModel(
|
|
|
135
137
|
const model = modelRegistry.find(provider, modelId);
|
|
136
138
|
if (!model) continue;
|
|
137
139
|
|
|
138
|
-
const
|
|
139
|
-
if (
|
|
140
|
-
return
|
|
140
|
+
const selection = await resolveModelSelection(modelRegistry, model);
|
|
141
|
+
if (selection) {
|
|
142
|
+
return selection;
|
|
141
143
|
}
|
|
142
144
|
}
|
|
143
145
|
|
|
144
|
-
return
|
|
146
|
+
return resolveModelSelection(modelRegistry, currentModel);
|
|
145
147
|
}
|
|
146
148
|
|
|
147
|
-
async function
|
|
148
|
-
modelRegistry:
|
|
149
|
+
async function resolveModelSelection(
|
|
150
|
+
modelRegistry: ModelLookup,
|
|
149
151
|
model: Model<Api>,
|
|
150
|
-
): Promise<
|
|
152
|
+
): Promise<ModelSelection | null> {
|
|
151
153
|
const auth = await modelRegistry.getApiKeyAndHeaders(model);
|
|
152
|
-
return auth.ok ? { model
|
|
154
|
+
return auth.ok ? { model } : null;
|
|
153
155
|
}
|
|
154
156
|
|
|
155
157
|
/**
|
|
@@ -166,11 +168,25 @@ function parseExtractionResult(text: string): ExtractionResult | null {
|
|
|
166
168
|
jsonStr = jsonMatch[1].trim();
|
|
167
169
|
}
|
|
168
170
|
|
|
169
|
-
const parsed = JSON.parse(jsonStr);
|
|
170
|
-
if (
|
|
171
|
-
|
|
171
|
+
const parsed: unknown = JSON.parse(jsonStr);
|
|
172
|
+
if (
|
|
173
|
+
!parsed ||
|
|
174
|
+
typeof parsed !== "object" ||
|
|
175
|
+
!("questions" in parsed) ||
|
|
176
|
+
!Array.isArray(parsed.questions) ||
|
|
177
|
+
!parsed.questions.every(
|
|
178
|
+
(question: unknown): question is ExtractedQuestion =>
|
|
179
|
+
question !== null &&
|
|
180
|
+
typeof question === "object" &&
|
|
181
|
+
"question" in question &&
|
|
182
|
+
typeof question.question === "string" &&
|
|
183
|
+
question.question.trim().length > 0 &&
|
|
184
|
+
(!("context" in question) || typeof question.context === "string"),
|
|
185
|
+
)
|
|
186
|
+
) {
|
|
187
|
+
return null;
|
|
172
188
|
}
|
|
173
|
-
return
|
|
189
|
+
return { questions: parsed.questions };
|
|
174
190
|
} catch {
|
|
175
191
|
return null;
|
|
176
192
|
}
|
|
@@ -190,6 +206,7 @@ class QnAComponent implements Component, Focusable {
|
|
|
190
206
|
private showingConfirmation: boolean = false;
|
|
191
207
|
|
|
192
208
|
// Cache
|
|
209
|
+
private renderWidth?: number;
|
|
193
210
|
private cachedWidth?: number;
|
|
194
211
|
private cachedLines?: string[];
|
|
195
212
|
|
|
@@ -239,7 +256,7 @@ class QnAComponent implements Component, Focusable {
|
|
|
239
256
|
}
|
|
240
257
|
|
|
241
258
|
private saveCurrentAnswer(): void {
|
|
242
|
-
this.answers[this.currentIndex] = this.editor.
|
|
259
|
+
this.answers[this.currentIndex] = this.editor.getExpandedText();
|
|
243
260
|
}
|
|
244
261
|
|
|
245
262
|
private navigateTo(index: number): void {
|
|
@@ -282,6 +299,11 @@ class QnAComponent implements Component, Focusable {
|
|
|
282
299
|
}
|
|
283
300
|
|
|
284
301
|
handleInput(data: string): void {
|
|
302
|
+
if ((this.renderWidth ?? this.tui.terminal.columns) < MIN_QUESTIONNAIRE_WIDTH) {
|
|
303
|
+
if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c"))) this.cancel();
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
285
307
|
// Handle confirmation dialog
|
|
286
308
|
if (this.showingConfirmation) {
|
|
287
309
|
if (matchesKey(data, Key.enter) || data.toLowerCase() === "y") {
|
|
@@ -363,6 +385,19 @@ class QnAComponent implements Component, Focusable {
|
|
|
363
385
|
}
|
|
364
386
|
|
|
365
387
|
render(width: number): string[] {
|
|
388
|
+
this.renderWidth = width;
|
|
389
|
+
if (width < MIN_QUESTIONNAIRE_WIDTH) {
|
|
390
|
+
return [
|
|
391
|
+
truncateToWidth(
|
|
392
|
+
this.theme.fg(
|
|
393
|
+
"muted",
|
|
394
|
+
`Resize to ${MIN_QUESTIONNAIRE_WIDTH}+ columns to answer. Esc cancels.`,
|
|
395
|
+
),
|
|
396
|
+
width,
|
|
397
|
+
),
|
|
398
|
+
];
|
|
399
|
+
}
|
|
400
|
+
|
|
366
401
|
if (this.cachedLines && this.cachedWidth === width) {
|
|
367
402
|
return this.cachedLines;
|
|
368
403
|
}
|
|
@@ -411,7 +446,9 @@ class QnAComponent implements Component, Focusable {
|
|
|
411
446
|
progressParts.push(theme.fg("dim", "○"));
|
|
412
447
|
}
|
|
413
448
|
}
|
|
414
|
-
|
|
449
|
+
for (const line of wrapTextWithAnsi(progressParts.join(" "), contentWidth)) {
|
|
450
|
+
lines.push(padToWidth(boxLine(line)));
|
|
451
|
+
}
|
|
415
452
|
lines.push(padToWidth(emptyBoxLine()));
|
|
416
453
|
|
|
417
454
|
// Current question
|
|
@@ -520,65 +557,84 @@ export default function (pi: ExtensionAPI) {
|
|
|
520
557
|
}
|
|
521
558
|
|
|
522
559
|
// Run extraction with loader UI
|
|
523
|
-
const
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
560
|
+
const extraction = await ctx.ui.custom<ExtractionOutcome>((tui, theme, _kb, done) => {
|
|
561
|
+
const loader = new BorderedLoader(
|
|
562
|
+
tui,
|
|
563
|
+
theme,
|
|
564
|
+
`Extracting questions using ${extractionSelection.model.id}...`,
|
|
565
|
+
);
|
|
566
|
+
loader.onAbort = () => done({ status: "cancelled" });
|
|
567
|
+
|
|
568
|
+
const doExtract = async (): Promise<ExtractionOutcome> => {
|
|
569
|
+
const userMessage: UserMessage = {
|
|
570
|
+
role: "user",
|
|
571
|
+
content: [{ type: "text", text: lastAssistantText! }],
|
|
572
|
+
timestamp: Date.now(),
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
const response = await ctx.modelRegistry.complete(
|
|
576
|
+
extractionSelection.model,
|
|
577
|
+
{ systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
|
|
578
|
+
{ signal: loader.signal },
|
|
529
579
|
);
|
|
530
|
-
loader.onAbort = () => done(null);
|
|
531
580
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
581
|
+
if (loader.signal.aborted || response.stopReason === "aborted") {
|
|
582
|
+
return { status: "cancelled" };
|
|
583
|
+
}
|
|
584
|
+
if (response.stopReason !== "stop") {
|
|
585
|
+
return {
|
|
586
|
+
status: "error",
|
|
587
|
+
message: response.errorMessage
|
|
588
|
+
? `Question extraction failed: ${response.errorMessage}`
|
|
589
|
+
: `Question extraction did not complete (${response.stopReason})`,
|
|
537
590
|
};
|
|
591
|
+
}
|
|
538
592
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
593
|
+
const responseText = response.content
|
|
594
|
+
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
|
595
|
+
.map((c) => c.text)
|
|
596
|
+
.join("\n");
|
|
597
|
+
|
|
598
|
+
const result = parseExtractionResult(responseText);
|
|
599
|
+
return result
|
|
600
|
+
? { status: "success", result }
|
|
601
|
+
: { status: "error", message: "Question extraction returned an invalid response" };
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
doExtract()
|
|
605
|
+
.then(done)
|
|
606
|
+
.catch((error: unknown) => {
|
|
607
|
+
done(
|
|
608
|
+
loader.signal.aborted
|
|
609
|
+
? { status: "cancelled" }
|
|
610
|
+
: {
|
|
611
|
+
status: "error",
|
|
612
|
+
message: `Question extraction failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
613
|
+
},
|
|
547
614
|
);
|
|
615
|
+
});
|
|
548
616
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
const responseText = response.content
|
|
554
|
-
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
|
555
|
-
.map((c) => c.text)
|
|
556
|
-
.join("\n");
|
|
557
|
-
|
|
558
|
-
return parseExtractionResult(responseText);
|
|
559
|
-
};
|
|
560
|
-
|
|
561
|
-
doExtract()
|
|
562
|
-
.then(done)
|
|
563
|
-
.catch(() => done(null));
|
|
564
|
-
|
|
565
|
-
return loader;
|
|
566
|
-
},
|
|
567
|
-
);
|
|
617
|
+
return loader;
|
|
618
|
+
});
|
|
568
619
|
|
|
569
|
-
if (
|
|
620
|
+
if (extraction.status === "cancelled") {
|
|
570
621
|
ctx.ui.notify("Cancelled", "info");
|
|
571
622
|
return;
|
|
572
623
|
}
|
|
624
|
+
if (extraction.status === "error") {
|
|
625
|
+
ctx.ui.notify(extraction.message, "error");
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
573
628
|
|
|
574
|
-
|
|
629
|
+
const { questions } = extraction.result;
|
|
630
|
+
if (questions.length === 0) {
|
|
575
631
|
ctx.ui.notify("No questions found in the last message", "info");
|
|
576
632
|
return;
|
|
577
633
|
}
|
|
578
634
|
|
|
579
635
|
// Show the Q&A component
|
|
580
636
|
const answersResult = await ctx.ui.custom<string | null>((tui, theme, _kb, done) => {
|
|
581
|
-
return new QnAComponent(
|
|
637
|
+
return new QnAComponent(questions, tui, theme, done);
|
|
582
638
|
});
|
|
583
639
|
|
|
584
640
|
if (answersResult === null) {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Branch terminals
|
|
2
|
+
|
|
3
|
+
`/branch` forks the selected conversation without switching the current session. Inside tmux, `--branch-tmux-layout` chooses `window`, `split-right`, or `split-down`; a `/branch` argument overrides that setting.
|
|
4
|
+
|
|
5
|
+
`--branch-term` takes precedence over tmux and accepts a Bash launcher template. Use unquoted `{cwd}` and `{session}` placeholders for path arguments. `{command}` supplies a single command-string argument, suitable for a launcher's command option or `bash -c`. Do not add shell quotes around placeholders; they are already quoted. If neither `{session}` nor `{command}` appears, the fork path is appended. The launcher runs in the session's working directory with the current environment.
|
|
6
|
+
|
|
7
|
+
A failed launcher produces a recovery command. Reloading or closing the original Pi session stops observing launcher failures but does not close user-owned terminals.
|