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,215 +1,306 @@
1
- import { mkdir } from "node:fs/promises";
2
- import path from "node:path";
3
- import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
4
- import type { TakomiThinkingLevel } from "../../../src/pi-takomi-core";
5
- import {
6
- buildTaskPrompt,
7
- runModelPreflight,
8
- runPiAgentJson,
9
- writeTempPrompt,
10
- type ChecklistInput,
11
- } from "../takomi-runtime/shared";
12
- import type {
13
- TakomiSubagentRuntimeEvent,
14
- TakomiSubagentRunPatch,
15
- } from "../takomi-runtime/subagent-types";
16
- import type { TakomiAgentConfig } from "./agents";
17
- import {
18
- buildFallbackModels,
19
- buildSystemPrompt,
20
- hasThinkingSuffix,
21
- } from "./dispatch-helpers";
22
-
23
- export type TakomiDispatchInput = {
24
- agent: TakomiAgentConfig;
25
- task: string;
26
- rootCwd: string;
27
- cwd?: string;
28
- workflow?: string;
29
- skills?: string[];
30
- model?: string;
31
- fallbackModels?: string[];
32
- thinking?: TakomiThinkingLevel;
33
- conversationId?: string;
34
- checklist?: ChecklistInput;
35
- stage?: string;
36
- taskLabel?: string;
37
- parentTaskId?: string;
38
- parentRunKey?: string;
39
- boardTaskStatus?: "pending" | "in-progress" | "completed" | "blocked";
40
- source: "runtime-board" | "takomi-tool";
41
- rerunInstructions?: string;
42
- };
43
-
44
- export type TakomiDispatchResult = {
45
- agent: string;
46
- task: string;
47
- workflow?: string;
48
- model?: string;
49
- warning?: string;
50
- thinking?: TakomiThinkingLevel;
51
- conversationId: string;
52
- code: number;
53
- output: string;
54
- stderr: string;
55
- preflight: string;
56
- };
57
-
58
- export type TakomiDispatchHooks = {
59
- emit?: (event: TakomiSubagentRuntimeEvent) => void;
60
- onPatch?: (patch: TakomiSubagentRunPatch, runKey: string) => void | Promise<void>;
61
- };
62
-
63
- export async function dispatchTakomiSubagent(
64
- ctx: ExtensionContext,
65
- input: TakomiDispatchInput,
66
- signal?: AbortSignal,
67
- hooks?: TakomiDispatchHooks,
68
- ): Promise<TakomiDispatchResult> {
69
- const subagentCwd = input.cwd ? path.resolve(input.rootCwd, input.cwd) : input.rootCwd;
70
- const conversationId = input.conversationId || `${input.agent.name}-${Date.now()}`;
71
- const runKey = conversationId;
72
- const sessionDir = path.join(input.rootCwd, ".pi", "takomi", "subagents");
73
- const sessionPath = path.join(sessionDir, `${conversationId}.jsonl`);
74
- await mkdir(sessionDir, { recursive: true });
75
-
76
- hooks?.emit?.({
77
- type: "start",
78
- runKey,
79
- state: {
80
- agent: input.agent.name,
81
- taskLabel: input.taskLabel ?? input.task.split(/\r?\n/)[0]?.trim() ?? input.agent.name,
82
- workflow: input.workflow,
83
- stage: input.stage,
84
- conversationId,
85
- parentTaskId: input.parentTaskId,
86
- parentRunKey: input.parentRunKey,
87
- checklist: input.checklist,
88
- boardTaskStatus: input.boardTaskStatus,
89
- fallbackModels: input.fallbackModels,
90
- thinking: input.thinking ?? input.agent.thinking,
91
- summary: "Preparing delegated run.",
92
- source: input.source,
93
- },
94
- });
95
-
96
- const fallbackModels = buildFallbackModels(input);
97
- const preflight = await runModelPreflight(ctx, subagentCwd, input.model, fallbackModels, signal);
98
- const thinking = input.thinking ?? input.agent.thinking;
99
-
100
- if (preflight.model) {
101
- const patch = {
102
- model: preflight.model,
103
- fallbackModels,
104
- thinking,
105
- boardTaskStatus: input.boardTaskStatus,
106
- checklist: input.checklist,
107
- summary: `Model ready: ${preflight.model}${thinking ? ` (${thinking})` : ""}`,
108
- };
109
- hooks?.emit?.({ type: "update", runKey, patch });
110
- await hooks?.onPatch?.(patch, runKey);
111
- }
112
-
113
- if (!preflight.model) {
114
- const result = {
115
- agent: input.agent.name,
116
- task: input.task,
117
- workflow: input.workflow,
118
- model: "",
119
- warning: preflight.warning,
120
- thinking,
121
- conversationId,
122
- code: 1,
123
- output: "",
124
- stderr: preflight.report,
125
- preflight: preflight.report,
126
- };
127
- hooks?.emit?.({
128
- type: "block",
129
- runKey,
130
- patch: {
131
- summary: `Subagent ${input.agent.name} blocked before launch.`,
132
- boardTaskStatus: input.boardTaskStatus,
133
- checklist: input.checklist,
134
- fallbackModels,
135
- thinking,
136
- logs: [preflight.warning || "No model matched the requested run."],
137
- },
138
- });
139
- return result;
140
- }
141
-
142
- const promptPath = await writeTempPrompt(input.agent.name, buildSystemPrompt(input));
143
- const taskPrompt = buildTaskPrompt({
144
- task: input.rerunInstructions?.trim() || input.task,
145
- workflow: input.workflow,
146
- skills: input.skills,
147
- checklist: input.checklist,
148
- stage: input.stage,
149
- });
150
- const args = ["--mode", "json", "--append-system-prompt", promptPath, "--session", sessionPath, taskPrompt];
151
- args.unshift("--model", preflight.model);
152
- if (thinking && !hasThinkingSuffix(preflight.model)) args.unshift("--thinking", thinking);
153
- if (input.agent.tools?.length) args.unshift("--tools", input.agent.tools.join(","));
154
-
155
- const result = await runPiAgentJson(subagentCwd, args, signal, {
156
- onAssistantText: (text) => {
157
- hooks?.emit?.({ type: "update", runKey, patch: { outputText: text, boardTaskStatus: input.boardTaskStatus, checklist: input.checklist } });
158
- },
159
- onEventText: (line) => {
160
- hooks?.emit?.({ type: "appendLog", runKey, chunk: line });
161
- },
162
- onStderr: (chunk) => {
163
- hooks?.emit?.({ type: "appendLog", runKey, chunk });
164
- },
165
- });
166
-
167
- const output = result.stdout.trim();
168
- const dispatchResult: TakomiDispatchResult = {
169
- agent: input.agent.name,
170
- task: input.task,
171
- workflow: input.workflow,
172
- model: preflight.model,
173
- warning: preflight.warning,
174
- thinking,
175
- conversationId,
176
- code: result.code,
177
- output,
178
- stderr: result.stderr.trim(),
179
- preflight: preflight.report,
180
- };
181
-
182
- if (result.code !== 0) {
183
- hooks?.emit?.({
184
- type: "block",
185
- runKey,
186
- patch: {
187
- model: preflight.model,
188
- fallbackModels,
189
- thinking,
190
- boardTaskStatus: input.boardTaskStatus,
191
- checklist: input.checklist,
192
- summary: `Subagent ${input.agent.name} failed.`,
193
- outputText: output || undefined,
194
- logs: [result.stderr || result.stdout || "No output"],
195
- },
196
- });
197
- return dispatchResult;
198
- }
199
-
200
- hooks?.emit?.({
201
- type: "complete",
202
- runKey,
203
- patch: {
204
- model: preflight.model,
205
- fallbackModels,
206
- thinking,
207
- boardTaskStatus: input.boardTaskStatus,
208
- checklist: input.checklist,
209
- summary: output || `Subagent ${input.agent.name} run finished. Checklist-validated task completion is still a board action.`,
210
- outputText: output || undefined,
211
- },
212
- });
213
-
214
- return dispatchResult;
215
- }
1
+ import { mkdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
4
+ import type { TakomiThinkingLevel } from "../../../src/pi-takomi-core";
5
+ import {
6
+ buildTaskPrompt,
7
+ runModelPreflight,
8
+ runPiAgentJson,
9
+ writeTempPrompt,
10
+ type ChecklistInput,
11
+ } from "../takomi-runtime/shared";
12
+ import type {
13
+ TakomiSubagentRuntimeEvent,
14
+ TakomiSubagentRunPatch,
15
+ } from "../takomi-runtime/subagent-types";
16
+ import type { TakomiAgentConfig } from "./agents";
17
+ import {
18
+ buildFallbackModels,
19
+ buildSystemPrompt,
20
+ hasThinkingSuffix,
21
+ } from "./dispatch-helpers";
22
+
23
+ export type TakomiDispatchInput = {
24
+ agent: TakomiAgentConfig;
25
+ task: string;
26
+ rootCwd: string;
27
+ cwd?: string;
28
+ workflow?: string;
29
+ skills?: string[];
30
+ model?: string;
31
+ fallbackModels?: string[];
32
+ thinking?: TakomiThinkingLevel;
33
+ conversationId?: string;
34
+ checklist?: ChecklistInput;
35
+ stage?: string;
36
+ taskLabel?: string;
37
+ parentTaskId?: string;
38
+ parentRunKey?: string;
39
+ boardTaskStatus?: "pending" | "in-progress" | "completed" | "blocked";
40
+ source: "runtime-board" | "takomi-tool";
41
+ rerunInstructions?: string;
42
+ };
43
+
44
+ export type TakomiDispatchResult = {
45
+ agent: string;
46
+ task: string;
47
+ workflow?: string;
48
+ model?: string;
49
+ warning?: string;
50
+ thinking?: TakomiThinkingLevel;
51
+ conversationId: string;
52
+ code: number;
53
+ output: string;
54
+ stderr: string;
55
+ preflight: string;
56
+ startedAt?: number;
57
+ endedAt?: number;
58
+ lastActivityAt?: number;
59
+ currentTool?: string;
60
+ currentToolArgs?: string;
61
+ currentToolStartedAt?: number;
62
+ recentTools?: Array<{ tool: string; args: string; endMs: number }>;
63
+ recentOutput?: string[];
64
+ toolCount?: number;
65
+ sessionFile?: string;
66
+ };
67
+
68
+ export type TakomiDispatchHooks = {
69
+ emit?: (event: TakomiSubagentRuntimeEvent) => void;
70
+ onPatch?: (patch: TakomiSubagentRunPatch, runKey: string) => void | Promise<void>;
71
+ };
72
+
73
+ export async function dispatchTakomiSubagent(
74
+ ctx: ExtensionContext,
75
+ input: TakomiDispatchInput,
76
+ signal?: AbortSignal,
77
+ hooks?: TakomiDispatchHooks,
78
+ ): Promise<TakomiDispatchResult> {
79
+ const subagentCwd = input.cwd ? path.resolve(input.rootCwd, input.cwd) : input.rootCwd;
80
+ const conversationId = input.conversationId || `${input.agent.name}-${Date.now()}`;
81
+ const runKey = conversationId;
82
+ const sessionDir = path.join(input.rootCwd, ".pi", "takomi", "subagents");
83
+ const sessionPath = path.join(sessionDir, `${conversationId}.jsonl`);
84
+ await mkdir(sessionDir, { recursive: true });
85
+ const startedAt = Date.now();
86
+ let lastActivityAt = startedAt;
87
+ let currentTool: string | undefined;
88
+ let currentToolArgs: string | undefined;
89
+ let currentToolStartedAt: number | undefined;
90
+ let toolCount = 0;
91
+ let recentTools: Array<{ tool: string; args: string; endMs: number }> = [];
92
+ let recentOutput: string[] = [];
93
+
94
+ const appendRecentOutput = (text: string) => {
95
+ const lines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
96
+ if (!lines.length) return;
97
+ recentOutput = [...recentOutput, ...lines].slice(-8);
98
+ lastActivityAt = Date.now();
99
+ };
100
+
101
+ hooks?.emit?.({
102
+ type: "start",
103
+ runKey,
104
+ state: {
105
+ agent: input.agent.name,
106
+ taskLabel: input.taskLabel ?? input.task.split(/\r?\n/)[0]?.trim() ?? input.agent.name,
107
+ workflow: input.workflow,
108
+ stage: input.stage,
109
+ conversationId,
110
+ parentTaskId: input.parentTaskId,
111
+ parentRunKey: input.parentRunKey,
112
+ checklist: input.checklist,
113
+ boardTaskStatus: input.boardTaskStatus,
114
+ fallbackModels: input.fallbackModels,
115
+ thinking: input.thinking ?? input.agent.thinking,
116
+ summary: "Preparing delegated run.",
117
+ source: input.source,
118
+ },
119
+ });
120
+
121
+ const fallbackModels = buildFallbackModels(input);
122
+ const preflight = await runModelPreflight(ctx, subagentCwd, input.model, fallbackModels, signal);
123
+ const thinking = input.thinking ?? input.agent.thinking;
124
+
125
+ if (preflight.model) {
126
+ const patch = {
127
+ model: preflight.model,
128
+ fallbackModels,
129
+ thinking,
130
+ boardTaskStatus: input.boardTaskStatus,
131
+ checklist: input.checklist,
132
+ summary: `Model ready: ${preflight.model}${thinking ? ` (${thinking})` : ""}`,
133
+ };
134
+ hooks?.emit?.({ type: "update", runKey, patch });
135
+ await hooks?.onPatch?.(patch, runKey);
136
+ }
137
+
138
+ if (!preflight.model) {
139
+ const result = {
140
+ agent: input.agent.name,
141
+ task: input.task,
142
+ workflow: input.workflow,
143
+ model: "",
144
+ warning: preflight.warning,
145
+ thinking,
146
+ conversationId,
147
+ code: 1,
148
+ output: "",
149
+ stderr: preflight.report,
150
+ preflight: preflight.report,
151
+ startedAt,
152
+ endedAt: Date.now(),
153
+ lastActivityAt,
154
+ recentTools,
155
+ recentOutput,
156
+ toolCount,
157
+ sessionFile: sessionPath,
158
+ };
159
+ hooks?.emit?.({
160
+ type: "block",
161
+ runKey,
162
+ patch: {
163
+ summary: `Subagent ${input.agent.name} blocked before launch.`,
164
+ boardTaskStatus: input.boardTaskStatus,
165
+ checklist: input.checklist,
166
+ fallbackModels,
167
+ thinking,
168
+ logs: [preflight.warning || "No model matched the requested run."],
169
+ },
170
+ });
171
+ return result;
172
+ }
173
+
174
+ const promptPath = await writeTempPrompt(input.agent.name, buildSystemPrompt(input));
175
+ const taskPrompt = buildTaskPrompt({
176
+ task: input.rerunInstructions?.trim() || input.task,
177
+ workflow: input.workflow,
178
+ skills: input.skills,
179
+ checklist: input.checklist,
180
+ stage: input.stage,
181
+ });
182
+ const args = ["--mode", "json", "--append-system-prompt", promptPath, "--session", sessionPath, taskPrompt];
183
+ args.unshift("--model", preflight.model);
184
+ if (thinking && !hasThinkingSuffix(preflight.model)) args.unshift("--thinking", thinking);
185
+ if (input.agent.tools?.length) args.unshift("--tools", input.agent.tools.join(","));
186
+
187
+ const result = await runPiAgentJson(subagentCwd, args, signal, {
188
+ onAssistantText: (text) => {
189
+ appendRecentOutput(text);
190
+ hooks?.emit?.({
191
+ type: "update",
192
+ runKey,
193
+ patch: {
194
+ outputText: text,
195
+ recentOutput,
196
+ currentTool,
197
+ currentToolArgs,
198
+ currentToolStartedAt,
199
+ recentTools,
200
+ toolCount,
201
+ boardTaskStatus: input.boardTaskStatus,
202
+ checklist: input.checklist,
203
+ },
204
+ });
205
+ },
206
+ onEventText: (line) => {
207
+ appendRecentOutput(line);
208
+ hooks?.emit?.({ type: "appendLog", runKey, chunk: line });
209
+ hooks?.emit?.({ type: "update", runKey, patch: { recentOutput, boardTaskStatus: input.boardTaskStatus, checklist: input.checklist } });
210
+ },
211
+ onToolEvent: (event) => {
212
+ lastActivityAt = Date.now();
213
+ if (event.type === "start") {
214
+ currentTool = event.toolName;
215
+ currentToolArgs = event.args;
216
+ currentToolStartedAt = Date.now();
217
+ toolCount += 1;
218
+ } else if (event.type === "end") {
219
+ recentTools = [...recentTools, { tool: event.toolName, args: currentTool === event.toolName ? currentToolArgs ?? "" : "", endMs: Date.now() }].slice(-8);
220
+ if (currentTool === event.toolName) {
221
+ currentTool = undefined;
222
+ currentToolArgs = undefined;
223
+ currentToolStartedAt = undefined;
224
+ }
225
+ }
226
+ hooks?.emit?.({
227
+ type: "update",
228
+ runKey,
229
+ patch: {
230
+ currentTool,
231
+ currentToolArgs,
232
+ currentToolStartedAt,
233
+ recentTools,
234
+ recentOutput,
235
+ toolCount,
236
+ boardTaskStatus: input.boardTaskStatus,
237
+ checklist: input.checklist,
238
+ },
239
+ });
240
+ },
241
+ onStderr: (chunk) => {
242
+ appendRecentOutput(chunk);
243
+ hooks?.emit?.({ type: "appendLog", runKey, chunk });
244
+ hooks?.emit?.({ type: "update", runKey, patch: { recentOutput, boardTaskStatus: input.boardTaskStatus, checklist: input.checklist } });
245
+ },
246
+ });
247
+
248
+ const output = result.stdout.trim();
249
+ const dispatchResult: TakomiDispatchResult = {
250
+ agent: input.agent.name,
251
+ task: input.task,
252
+ workflow: input.workflow,
253
+ model: preflight.model,
254
+ warning: preflight.warning,
255
+ thinking,
256
+ conversationId,
257
+ code: result.code,
258
+ output,
259
+ stderr: result.stderr.trim(),
260
+ preflight: preflight.report,
261
+ startedAt,
262
+ endedAt: Date.now(),
263
+ lastActivityAt,
264
+ currentTool,
265
+ currentToolArgs,
266
+ currentToolStartedAt,
267
+ recentTools,
268
+ recentOutput,
269
+ toolCount,
270
+ sessionFile: sessionPath,
271
+ };
272
+
273
+ if (result.code !== 0) {
274
+ hooks?.emit?.({
275
+ type: "block",
276
+ runKey,
277
+ patch: {
278
+ model: preflight.model,
279
+ fallbackModels,
280
+ thinking,
281
+ boardTaskStatus: input.boardTaskStatus,
282
+ checklist: input.checklist,
283
+ summary: `Subagent ${input.agent.name} failed.`,
284
+ outputText: output || undefined,
285
+ logs: [result.stderr || result.stdout || "No output"],
286
+ },
287
+ });
288
+ return dispatchResult;
289
+ }
290
+
291
+ hooks?.emit?.({
292
+ type: "complete",
293
+ runKey,
294
+ patch: {
295
+ model: preflight.model,
296
+ fallbackModels,
297
+ thinking,
298
+ boardTaskStatus: input.boardTaskStatus,
299
+ checklist: input.checklist,
300
+ summary: output || `Subagent ${input.agent.name} run finished. Checklist-validated task completion is still a board action.`,
301
+ outputText: output || undefined,
302
+ },
303
+ });
304
+
305
+ return dispatchResult;
306
+ }