takomi 2.1.2 → 2.1.4

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.
Files changed (52) hide show
  1. package/.pi/README.md +124 -124
  2. package/.pi/agents/architect.md +15 -15
  3. package/.pi/agents/coder.md +14 -14
  4. package/.pi/agents/designer.md +17 -17
  5. package/.pi/agents/orchestrator.md +22 -22
  6. package/.pi/agents/reviewer.md +16 -16
  7. package/.pi/extensions/oauth-router/README.md +125 -125
  8. package/.pi/extensions/oauth-router/commands.ts +380 -380
  9. package/.pi/extensions/oauth-router/config.ts +200 -200
  10. package/.pi/extensions/oauth-router/index.ts +41 -41
  11. package/.pi/extensions/oauth-router/oauth-flow.ts +154 -154
  12. package/.pi/extensions/oauth-router/oauth-store.ts +121 -121
  13. package/.pi/extensions/oauth-router/package.json +14 -14
  14. package/.pi/extensions/oauth-router/policies.ts +27 -27
  15. package/.pi/extensions/oauth-router/provider.ts +492 -492
  16. package/.pi/extensions/oauth-router/scripts/vibe-verify.py +98 -98
  17. package/.pi/extensions/oauth-router/state.ts +174 -174
  18. package/.pi/extensions/oauth-router/types.ts +153 -153
  19. package/.pi/extensions/takomi-runtime/command-text.ts +130 -130
  20. package/.pi/extensions/takomi-runtime/commands.ts +179 -179
  21. package/.pi/extensions/takomi-runtime/context-panel.ts +282 -282
  22. package/.pi/extensions/takomi-runtime/index.ts +1288 -1288
  23. package/.pi/extensions/takomi-runtime/profile.ts +114 -114
  24. package/.pi/extensions/takomi-runtime/routing-policy.ts +105 -105
  25. package/.pi/extensions/takomi-runtime/shared.ts +511 -492
  26. package/.pi/extensions/takomi-runtime/subagent-controller.ts +364 -364
  27. package/.pi/extensions/takomi-runtime/subagent-render.ts +501 -501
  28. package/.pi/extensions/takomi-runtime/subagent-types.ts +90 -83
  29. package/.pi/extensions/takomi-runtime/ui.ts +133 -133
  30. package/.pi/extensions/takomi-subagents/agent-aliases.ts +18 -18
  31. package/.pi/extensions/takomi-subagents/agents.ts +113 -113
  32. package/.pi/extensions/takomi-subagents/delegation-plan.ts +95 -95
  33. package/.pi/extensions/takomi-subagents/dispatch-helpers.ts +26 -26
  34. package/.pi/extensions/takomi-subagents/dispatch.ts +306 -215
  35. package/.pi/extensions/takomi-subagents/index.ts +76 -75
  36. package/.pi/extensions/takomi-subagents/live-updates.ts +136 -83
  37. package/.pi/extensions/takomi-subagents/native-render.ts +5 -142
  38. package/.pi/extensions/takomi-subagents/pi-subagents-engine.ts +228 -0
  39. package/.pi/extensions/takomi-subagents/tool-runner.ts +209 -209
  40. package/.pi/themes/takomi-noir.json +81 -81
  41. package/package.json +59 -59
  42. package/src/cli.js +14 -0
  43. package/src/doctor.js +87 -84
  44. package/src/pi-harness.js +355 -351
  45. package/src/pi-installer.js +193 -171
  46. package/src/pi-takomi-core/index.ts +4 -4
  47. package/src/pi-takomi-core/orchestration.ts +402 -402
  48. package/src/pi-takomi-core/routing.ts +93 -93
  49. package/src/pi-takomi-core/types.ts +173 -173
  50. package/src/pi-takomi-core/workflows.ts +299 -299
  51. package/src/skills-installer.js +101 -101
  52. package/src/update-check.js +140 -0
@@ -1,83 +1,90 @@
1
- import type { TakomiThinkingLevel } from "../../../src/pi-takomi-core";
2
- import type { ChecklistInput } from "./shared";
3
-
4
- export type SubagentViewMode = "compact" | "expanded" | "fullscreen";
5
- export type SubagentFocusDirection = "next" | "prev";
6
- export type TakomiSubagentStatus = "running" | "completed" | "blocked";
7
- export type TakomiBoardTaskStatus = "pending" | "in-progress" | "completed" | "blocked";
8
- export type TakomiSubagentSource = "runtime-board" | "takomi-tool";
9
- export const TAKOMI_SUBAGENT_EVENT_CHANNEL = "takomi:subagent-runtime";
10
-
11
- export type TakomiSubagentRun = {
12
- runKey: string;
13
- conversationId?: string;
14
- parentTaskId?: string;
15
- parentRunKey?: string;
16
- agent: string;
17
- taskLabel: string;
18
- status: TakomiSubagentStatus;
19
- stage?: string;
20
- workflow?: string;
21
- model?: string;
22
- fallbackModels?: string[];
23
- thinking?: TakomiThinkingLevel;
24
- checklist?: ChecklistInput;
25
- boardTaskStatus?: TakomiBoardTaskStatus;
26
- summary?: string;
27
- outputText?: string;
28
- logs: string[];
29
- startedAt: number;
30
- updatedAt: number;
31
- source: TakomiSubagentSource;
32
- };
33
-
34
- export type TakomiSubagentRunInit = Omit<TakomiSubagentRun, "runKey" | "logs" | "startedAt" | "updatedAt" | "status"> & {
35
- logs?: string[];
36
- status?: TakomiSubagentStatus;
37
- };
38
-
39
- export type TakomiSubagentRunPatch = Partial<Omit<TakomiSubagentRun, "runKey" | "startedAt" | "source">> & {
40
- source?: TakomiSubagentSource;
41
- };
42
-
43
- export type TakomiSubagentRenderEntry = {
44
- run: TakomiSubagentRun;
45
- depth: number;
46
- relation: "focused" | "ancestor" | "peer";
47
- };
48
-
49
- export type TakomiSubagentRenderState = {
50
- mode: SubagentViewMode;
51
- activeCount: number;
52
- focusPosition: number;
53
- focusedRun?: TakomiSubagentRun;
54
- activePath: TakomiSubagentRenderEntry[];
55
- peerRuns: TakomiSubagentRenderEntry[];
56
- compactRuns: TakomiSubagentRenderEntry[];
57
- };
58
-
59
- export interface TakomiSubagentController {
60
- hasRuns(): boolean;
61
- getStatusSummary(): string;
62
- getViewMode(): SubagentViewMode;
63
- start(ctx: import("@mariozechner/pi-coding-agent").ExtensionContext, state: TakomiSubagentRunInit, runKey?: string): Promise<void>;
64
- update(ctx: import("@mariozechner/pi-coding-agent").ExtensionContext, patch: TakomiSubagentRunPatch, runKey?: string): Promise<void>;
65
- appendLog(ctx: import("@mariozechner/pi-coding-agent").ExtensionContext, chunk: string, runKey?: string): Promise<void>;
66
- complete(ctx: import("@mariozechner/pi-coding-agent").ExtensionContext, patch?: TakomiSubagentRunPatch, runKey?: string): Promise<void>;
67
- block(ctx: import("@mariozechner/pi-coding-agent").ExtensionContext, patch?: TakomiSubagentRunPatch, runKey?: string): Promise<void>;
68
- reset(ctx?: import("@mariozechner/pi-coding-agent").ExtensionContext): void;
69
- refresh(): void;
70
- refreshWithContext(ctx: import("@mariozechner/pi-coding-agent").ExtensionContext): void;
71
- cycleFocus(direction: SubagentFocusDirection, ctx?: import("@mariozechner/pi-coding-agent").ExtensionContext): boolean;
72
- setViewMode(mode: SubagentViewMode, ctx?: import("@mariozechner/pi-coding-agent").ExtensionContext): SubagentViewMode | undefined;
73
- cycleViewMode(ctx?: import("@mariozechner/pi-coding-agent").ExtensionContext): SubagentViewMode | undefined;
74
- closeFullscreen(ctx?: import("@mariozechner/pi-coding-agent").ExtensionContext): SubagentViewMode;
75
- getKnownParentRunKey(parentTaskId: string): string | undefined;
76
- }
77
-
78
- export type TakomiSubagentRuntimeEvent =
79
- | { type: "start"; runKey?: string; state: TakomiSubagentRunInit }
80
- | { type: "update"; runKey?: string; patch: TakomiSubagentRunPatch }
81
- | { type: "appendLog"; runKey?: string; chunk: string }
82
- | { type: "complete"; runKey?: string; patch?: TakomiSubagentRunPatch }
83
- | { type: "block"; runKey?: string; patch?: TakomiSubagentRunPatch };
1
+ import type { TakomiThinkingLevel } from "../../../src/pi-takomi-core";
2
+ import type { ChecklistInput } from "./shared";
3
+
4
+ export type SubagentViewMode = "compact" | "expanded" | "fullscreen";
5
+ export type SubagentFocusDirection = "next" | "prev";
6
+ export type TakomiSubagentStatus = "running" | "completed" | "blocked";
7
+ export type TakomiBoardTaskStatus = "pending" | "in-progress" | "completed" | "blocked";
8
+ export type TakomiSubagentSource = "runtime-board" | "takomi-tool";
9
+ export const TAKOMI_SUBAGENT_EVENT_CHANNEL = "takomi:subagent-runtime";
10
+
11
+ export type TakomiSubagentRun = {
12
+ runKey: string;
13
+ conversationId?: string;
14
+ parentTaskId?: string;
15
+ parentRunKey?: string;
16
+ agent: string;
17
+ taskLabel: string;
18
+ status: TakomiSubagentStatus;
19
+ stage?: string;
20
+ workflow?: string;
21
+ model?: string;
22
+ fallbackModels?: string[];
23
+ thinking?: TakomiThinkingLevel;
24
+ checklist?: ChecklistInput;
25
+ boardTaskStatus?: TakomiBoardTaskStatus;
26
+ summary?: string;
27
+ outputText?: string;
28
+ currentTool?: string;
29
+ currentToolArgs?: string;
30
+ currentToolStartedAt?: number;
31
+ recentTools?: Array<{ tool: string; args: string; endMs: number }>;
32
+ recentOutput?: string[];
33
+ toolCount?: number;
34
+ sessionFile?: string;
35
+ logs: string[];
36
+ startedAt: number;
37
+ updatedAt: number;
38
+ source: TakomiSubagentSource;
39
+ };
40
+
41
+ export type TakomiSubagentRunInit = Omit<TakomiSubagentRun, "runKey" | "logs" | "startedAt" | "updatedAt" | "status"> & {
42
+ logs?: string[];
43
+ status?: TakomiSubagentStatus;
44
+ };
45
+
46
+ export type TakomiSubagentRunPatch = Partial<Omit<TakomiSubagentRun, "runKey" | "startedAt" | "source">> & {
47
+ source?: TakomiSubagentSource;
48
+ };
49
+
50
+ export type TakomiSubagentRenderEntry = {
51
+ run: TakomiSubagentRun;
52
+ depth: number;
53
+ relation: "focused" | "ancestor" | "peer";
54
+ };
55
+
56
+ export type TakomiSubagentRenderState = {
57
+ mode: SubagentViewMode;
58
+ activeCount: number;
59
+ focusPosition: number;
60
+ focusedRun?: TakomiSubagentRun;
61
+ activePath: TakomiSubagentRenderEntry[];
62
+ peerRuns: TakomiSubagentRenderEntry[];
63
+ compactRuns: TakomiSubagentRenderEntry[];
64
+ };
65
+
66
+ export interface TakomiSubagentController {
67
+ hasRuns(): boolean;
68
+ getStatusSummary(): string;
69
+ getViewMode(): SubagentViewMode;
70
+ start(ctx: import("@mariozechner/pi-coding-agent").ExtensionContext, state: TakomiSubagentRunInit, runKey?: string): Promise<void>;
71
+ update(ctx: import("@mariozechner/pi-coding-agent").ExtensionContext, patch: TakomiSubagentRunPatch, runKey?: string): Promise<void>;
72
+ appendLog(ctx: import("@mariozechner/pi-coding-agent").ExtensionContext, chunk: string, runKey?: string): Promise<void>;
73
+ complete(ctx: import("@mariozechner/pi-coding-agent").ExtensionContext, patch?: TakomiSubagentRunPatch, runKey?: string): Promise<void>;
74
+ block(ctx: import("@mariozechner/pi-coding-agent").ExtensionContext, patch?: TakomiSubagentRunPatch, runKey?: string): Promise<void>;
75
+ reset(ctx?: import("@mariozechner/pi-coding-agent").ExtensionContext): void;
76
+ refresh(): void;
77
+ refreshWithContext(ctx: import("@mariozechner/pi-coding-agent").ExtensionContext): void;
78
+ cycleFocus(direction: SubagentFocusDirection, ctx?: import("@mariozechner/pi-coding-agent").ExtensionContext): boolean;
79
+ setViewMode(mode: SubagentViewMode, ctx?: import("@mariozechner/pi-coding-agent").ExtensionContext): SubagentViewMode | undefined;
80
+ cycleViewMode(ctx?: import("@mariozechner/pi-coding-agent").ExtensionContext): SubagentViewMode | undefined;
81
+ closeFullscreen(ctx?: import("@mariozechner/pi-coding-agent").ExtensionContext): SubagentViewMode;
82
+ getKnownParentRunKey(parentTaskId: string): string | undefined;
83
+ }
84
+
85
+ export type TakomiSubagentRuntimeEvent =
86
+ | { type: "start"; runKey?: string; state: TakomiSubagentRunInit }
87
+ | { type: "update"; runKey?: string; patch: TakomiSubagentRunPatch }
88
+ | { type: "appendLog"; runKey?: string; chunk: string }
89
+ | { type: "complete"; runKey?: string; patch?: TakomiSubagentRunPatch }
90
+ | { type: "block"; runKey?: string; patch?: TakomiSubagentRunPatch };
@@ -1,133 +1,133 @@
1
- import type { AssistantMessage } from "@mariozechner/pi-ai";
2
- import type { ExtensionContext, ReadonlyFooterDataProvider, Theme } from "@mariozechner/pi-coding-agent";
3
- import {
4
- ellipsizeMiddle,
5
- formatFooterNumber,
6
- truncateToWidth,
7
- visibleWidth,
8
- } from "./shared";
9
-
10
- interface Component {
11
- render(width: number): string[];
12
- invalidate(): void;
13
- dispose?(): void;
14
- }
15
-
16
- interface RenderTui {
17
- requestRender(force?: boolean): void;
18
- }
19
-
20
- export type RuntimeHudState = {
21
- enabled: boolean;
22
- autoOrch: boolean;
23
- planMode: boolean;
24
- role: string;
25
- stage?: string;
26
- workflow?: string;
27
- activeSessionId?: string;
28
- launchMode?: string;
29
- subagentsEnabled?: boolean;
30
- };
31
-
32
- type Tone = "accent" | "warning" | "success" | "error" | "muted" | "dim" | "thinkingMinimal";
33
-
34
- function stageTone(stage?: string): Tone {
35
- switch (stage) {
36
- case "genesis":
37
- return "thinkingMinimal";
38
- case "design":
39
- return "accent";
40
- case "build":
41
- return "warning";
42
- default:
43
- return "muted";
44
- }
45
- }
46
-
47
- function badge(theme: Theme, label: string, tone: Tone): string {
48
- return theme.fg(tone, `<${label.toUpperCase()}>`);
49
- }
50
-
51
- export function renderRuntimeStatus(theme: Theme, state: RuntimeHudState): string {
52
- const primary = state.stage ?? state.role;
53
- const stageBadge = badge(theme, primary, stageTone(state.stage));
54
- const auto = state.autoOrch ? theme.fg("accent", "auto") : theme.fg("dim", "manual");
55
- const gate = state.launchMode === "manual" ? theme.fg("warning", "review-gate") : theme.fg("accent", "auto-gate");
56
- const plan = state.planMode ? theme.fg("warning", "plan") : theme.fg("dim", "direct");
57
- const subagents = state.subagentsEnabled === false ? theme.fg("error", "subagents:off") : theme.fg("dim", "subagents:on");
58
- return [theme.fg("accent", "Takomi"), stageBadge, theme.fg("dim", `role:${state.role}`), auto, gate, plan, subagents].join(" ");
59
- }
60
-
61
- export function renderRuntimeWidget(theme: Theme, state: RuntimeHudState): string[] {
62
- if (!state.enabled) return [];
63
- const primary = state.stage ?? state.role;
64
- const parts = [
65
- theme.fg("accent", "Takomi"),
66
- badge(theme, primary, stageTone(state.stage)),
67
- theme.fg("dim", `role:${state.role}`),
68
- state.autoOrch ? theme.fg("accent", "auto") : theme.fg("dim", "manual"),
69
- state.launchMode === "manual" ? theme.fg("warning", "review-gate") : theme.fg("accent", "auto-gate"),
70
- state.planMode ? theme.fg("warning", "plan") : theme.fg("dim", "direct"),
71
- state.subagentsEnabled === false ? theme.fg("error", "subagents:off") : theme.fg("dim", "subagents:on"),
72
- state.workflow ? theme.fg("dim", `wf:${state.workflow}`) : "",
73
- state.activeSessionId ? theme.fg("dim", `session:${ellipsizeMiddle(state.activeSessionId, 12)}`) : "",
74
- ].filter(Boolean);
75
- return [parts.join(" ")];
76
- }
77
-
78
- export class TakomiFooterComponent implements Component {
79
- private readonly unsubscribeBranchChange: () => void;
80
-
81
- constructor(
82
- private readonly tui: RenderTui,
83
- private readonly theme: Theme,
84
- private readonly footerData: ReadonlyFooterDataProvider,
85
- private readonly ctx: ExtensionContext,
86
- private readonly getState: () => RuntimeHudState,
87
- ) {
88
- this.unsubscribeBranchChange = footerData.onBranchChange(() => {
89
- this.tui.requestRender();
90
- });
91
- }
92
-
93
- dispose(): void {
94
- this.unsubscribeBranchChange();
95
- }
96
-
97
- invalidate(): void {}
98
-
99
- render(width: number): string[] {
100
- const state = this.getState();
101
- let input = 0;
102
- let output = 0;
103
- let cost = 0;
104
-
105
- for (const entry of this.ctx.sessionManager.getBranch()) {
106
- if (entry.type === "message" && entry.message.role === "assistant") {
107
- const message = entry.message as AssistantMessage;
108
- input += message.usage.input;
109
- output += message.usage.output;
110
- cost += message.usage.cost.total;
111
- }
112
- }
113
-
114
- const cwd = this.theme.fg("dim", this.ctx.cwd);
115
- const stats = this.theme.fg("dim", `up:${formatFooterNumber(input)} down:${formatFooterNumber(output)} $${cost.toFixed(3)}`);
116
- const leftPad = " ".repeat(Math.max(1, width - visibleWidth(cwd) - visibleWidth(stats)));
117
- const topLine = truncateToWidth(`${cwd}${leftPad}${stats}`, width);
118
-
119
- const extensionStatuses = [...this.footerData.getExtensionStatuses().entries()]
120
- .filter(([key]) => key !== "takomi-runtime")
121
- .map(([, value]) => value)
122
- .filter(Boolean);
123
- const runtimeStatus = renderRuntimeStatus(this.theme, state);
124
- const left = [runtimeStatus, ...extensionStatuses].join(this.theme.fg("dim", " | "));
125
- const branch = this.footerData.getGitBranch();
126
- const rightText = [this.ctx.model?.id || "no-model", branch ? `git:${branch}` : ""].filter(Boolean).join(" | ");
127
- const right = this.theme.fg("dim", rightText);
128
- const rightPad = " ".repeat(Math.max(1, width - visibleWidth(left) - visibleWidth(right)));
129
- const bottomLine = truncateToWidth(`${left}${rightPad}${right}`, width);
130
-
131
- return [topLine, bottomLine];
132
- }
133
- }
1
+ import type { AssistantMessage } from "@mariozechner/pi-ai";
2
+ import type { ExtensionContext, ReadonlyFooterDataProvider, Theme } from "@mariozechner/pi-coding-agent";
3
+ import {
4
+ ellipsizeMiddle,
5
+ formatFooterNumber,
6
+ truncateToWidth,
7
+ visibleWidth,
8
+ } from "./shared";
9
+
10
+ interface Component {
11
+ render(width: number): string[];
12
+ invalidate(): void;
13
+ dispose?(): void;
14
+ }
15
+
16
+ interface RenderTui {
17
+ requestRender(force?: boolean): void;
18
+ }
19
+
20
+ export type RuntimeHudState = {
21
+ enabled: boolean;
22
+ autoOrch: boolean;
23
+ planMode: boolean;
24
+ role: string;
25
+ stage?: string;
26
+ workflow?: string;
27
+ activeSessionId?: string;
28
+ launchMode?: string;
29
+ subagentsEnabled?: boolean;
30
+ };
31
+
32
+ type Tone = "accent" | "warning" | "success" | "error" | "muted" | "dim" | "thinkingMinimal";
33
+
34
+ function stageTone(stage?: string): Tone {
35
+ switch (stage) {
36
+ case "genesis":
37
+ return "thinkingMinimal";
38
+ case "design":
39
+ return "accent";
40
+ case "build":
41
+ return "warning";
42
+ default:
43
+ return "muted";
44
+ }
45
+ }
46
+
47
+ function badge(theme: Theme, label: string, tone: Tone): string {
48
+ return theme.fg(tone, `<${label.toUpperCase()}>`);
49
+ }
50
+
51
+ export function renderRuntimeStatus(theme: Theme, state: RuntimeHudState): string {
52
+ const primary = state.stage ?? state.role;
53
+ const stageBadge = badge(theme, primary, stageTone(state.stage));
54
+ const auto = state.autoOrch ? theme.fg("accent", "auto") : theme.fg("dim", "manual");
55
+ const gate = state.launchMode === "manual" ? theme.fg("warning", "review-gate") : theme.fg("accent", "auto-gate");
56
+ const plan = state.planMode ? theme.fg("warning", "plan") : theme.fg("dim", "direct");
57
+ const subagents = state.subagentsEnabled === false ? theme.fg("error", "subagents:off") : theme.fg("dim", "subagents:on");
58
+ return [theme.fg("accent", "Takomi"), stageBadge, theme.fg("dim", `role:${state.role}`), auto, gate, plan, subagents].join(" ");
59
+ }
60
+
61
+ export function renderRuntimeWidget(theme: Theme, state: RuntimeHudState): string[] {
62
+ if (!state.enabled) return [];
63
+ const primary = state.stage ?? state.role;
64
+ const parts = [
65
+ theme.fg("accent", "Takomi"),
66
+ badge(theme, primary, stageTone(state.stage)),
67
+ theme.fg("dim", `role:${state.role}`),
68
+ state.autoOrch ? theme.fg("accent", "auto") : theme.fg("dim", "manual"),
69
+ state.launchMode === "manual" ? theme.fg("warning", "review-gate") : theme.fg("accent", "auto-gate"),
70
+ state.planMode ? theme.fg("warning", "plan") : theme.fg("dim", "direct"),
71
+ state.subagentsEnabled === false ? theme.fg("error", "subagents:off") : theme.fg("dim", "subagents:on"),
72
+ state.workflow ? theme.fg("dim", `wf:${state.workflow}`) : "",
73
+ state.activeSessionId ? theme.fg("dim", `session:${ellipsizeMiddle(state.activeSessionId, 12)}`) : "",
74
+ ].filter(Boolean);
75
+ return [parts.join(" ")];
76
+ }
77
+
78
+ export class TakomiFooterComponent implements Component {
79
+ private readonly unsubscribeBranchChange: () => void;
80
+
81
+ constructor(
82
+ private readonly tui: RenderTui,
83
+ private readonly theme: Theme,
84
+ private readonly footerData: ReadonlyFooterDataProvider,
85
+ private readonly ctx: ExtensionContext,
86
+ private readonly getState: () => RuntimeHudState,
87
+ ) {
88
+ this.unsubscribeBranchChange = footerData.onBranchChange(() => {
89
+ this.tui.requestRender();
90
+ });
91
+ }
92
+
93
+ dispose(): void {
94
+ this.unsubscribeBranchChange();
95
+ }
96
+
97
+ invalidate(): void {}
98
+
99
+ render(width: number): string[] {
100
+ const state = this.getState();
101
+ let input = 0;
102
+ let output = 0;
103
+ let cost = 0;
104
+
105
+ for (const entry of this.ctx.sessionManager.getBranch()) {
106
+ if (entry.type === "message" && entry.message.role === "assistant") {
107
+ const message = entry.message as AssistantMessage;
108
+ input += message.usage.input;
109
+ output += message.usage.output;
110
+ cost += message.usage.cost.total;
111
+ }
112
+ }
113
+
114
+ const cwd = this.theme.fg("dim", this.ctx.cwd);
115
+ const stats = this.theme.fg("dim", `up:${formatFooterNumber(input)} down:${formatFooterNumber(output)} $${cost.toFixed(3)}`);
116
+ const leftPad = " ".repeat(Math.max(1, width - visibleWidth(cwd) - visibleWidth(stats)));
117
+ const topLine = truncateToWidth(`${cwd}${leftPad}${stats}`, width);
118
+
119
+ const extensionStatuses = [...this.footerData.getExtensionStatuses().entries()]
120
+ .filter(([key]) => key !== "takomi-runtime")
121
+ .map(([, value]) => value)
122
+ .filter(Boolean);
123
+ const runtimeStatus = renderRuntimeStatus(this.theme, state);
124
+ const left = [runtimeStatus, ...extensionStatuses].join(this.theme.fg("dim", " | "));
125
+ const branch = this.footerData.getGitBranch();
126
+ const rightText = [this.ctx.model?.id || "no-model", branch ? `git:${branch}` : ""].filter(Boolean).join(" | ");
127
+ const right = this.theme.fg("dim", rightText);
128
+ const rightPad = " ".repeat(Math.max(1, width - visibleWidth(left) - visibleWidth(right)));
129
+ const bottomLine = truncateToWidth(`${left}${rightPad}${right}`, width);
130
+
131
+ return [topLine, bottomLine];
132
+ }
133
+ }
@@ -1,18 +1,18 @@
1
- import type { TakomiAgentConfig } from "./agents";
2
-
3
- const AGENT_ALIASES: Record<string, string[]> = {
4
- general: ["orchestrator", "coder", "architect"],
5
- code: ["coder"],
6
- build: ["coder", "orchestrator"],
7
- design: ["designer"],
8
- review: ["reviewer"],
9
- architecture: ["architect"],
10
- };
11
-
12
- export function resolveAgentName(name: string, agents: Map<string, TakomiAgentConfig>): string {
13
- if (agents.has(name)) return name;
14
- const lower = name.toLowerCase();
15
- const exactCase = [...agents.keys()].find((agentName) => agentName.toLowerCase() === lower);
16
- if (exactCase) return exactCase;
17
- return AGENT_ALIASES[lower]?.find((candidate) => agents.has(candidate)) ?? name;
18
- }
1
+ import type { TakomiAgentConfig } from "./agents";
2
+
3
+ const AGENT_ALIASES: Record<string, string[]> = {
4
+ general: ["orchestrator", "coder", "architect"],
5
+ code: ["coder"],
6
+ build: ["coder", "orchestrator"],
7
+ design: ["designer"],
8
+ review: ["reviewer"],
9
+ architecture: ["architect"],
10
+ };
11
+
12
+ export function resolveAgentName(name: string, agents: Map<string, TakomiAgentConfig>): string {
13
+ if (agents.has(name)) return name;
14
+ const lower = name.toLowerCase();
15
+ const exactCase = [...agents.keys()].find((agentName) => agentName.toLowerCase() === lower);
16
+ if (exactCase) return exactCase;
17
+ return AGENT_ALIASES[lower]?.find((candidate) => agents.has(candidate)) ?? name;
18
+ }