takomi 2.1.35 → 2.1.37
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/.pi/README.md +6 -3
- package/.pi/extensions/oauth-router/commands.ts +36 -35
- package/.pi/extensions/oauth-router/index.ts +8 -8
- package/.pi/extensions/takomi-context-manager/diagnostics-tools.ts +40 -7
- package/.pi/extensions/takomi-context-manager/diagnostics.ts +534 -55
- package/.pi/extensions/takomi-context-manager/index.ts +14 -2
- package/.pi/extensions/takomi-context-manager/model-policy-gate.ts +16 -4
- package/.pi/extensions/takomi-context-manager/policy-tools.ts +7 -0
- package/.pi/extensions/takomi-context-manager/prerequisite-gates.ts +2 -0
- package/.pi/extensions/takomi-context-manager/session-state.ts +160 -0
- package/.pi/extensions/takomi-context-manager/skill-registry.ts +120 -0
- package/.pi/extensions/takomi-context-manager/skill-tools.ts +26 -3
- package/.pi/extensions/takomi-context-manager/state.ts +11 -1
- package/.pi/extensions/takomi-context-manager/types.ts +9 -1
- package/.pi/extensions/takomi-runtime/command-text.ts +2 -1
- package/.pi/extensions/takomi-runtime/commands.ts +13 -1
- package/.pi/extensions/takomi-runtime/index.ts +68 -1
- package/.pi/extensions/takomi-runtime/ui.ts +3 -3
- package/.pi/extensions/takomi-subagents/index.ts +37 -4
- package/.pi/extensions/takomi-subagents/native-render.ts +84 -7
- package/.pi/extensions/takomi-subagents/pi-subagents-engine.ts +18 -3
- package/.pi/extensions/takomi-subagents/tool-runner.ts +52 -5
- package/README.md +14 -7
- package/assets/.agent/skills/exam-creator-skill/SKILL.md +182 -0
- package/assets/.agent/skills/exam-creator-skill/references/model-routing-policy.md +48 -0
- package/assets/.agent/skills/exam-creator-skill/references/workflow-rulebook.md +115 -0
- package/package.json +2 -2
- package/src/cli.js +134 -13
- package/src/doctor.js +7 -1
- package/src/harness.js +54 -32
- package/src/owned-tree.js +28 -0
- package/src/pi-harness.js +149 -24
- package/src/store.js +2 -0
|
@@ -81,9 +81,9 @@ export function renderRuntimeStatus(theme: Theme, state: RuntimeHudState): strin
|
|
|
81
81
|
const sourceLabel = source === "manual" ? theme.fg("warning", "manual") : theme.fg("success", source);
|
|
82
82
|
const role = state.stage && state.role !== state.stage ? theme.fg("dim", state.role) : "";
|
|
83
83
|
const plan = state.planMode ? theme.fg("warning", "plan") : theme.fg("dim", "direct");
|
|
84
|
-
const gate = state.launchMode === "manual" ? theme.fg("warning", "review-gate") : "";
|
|
84
|
+
const gate = state.launchMode === "manual" ? theme.fg("warning", "review-gate") : theme.fg("success", "auto-gate");
|
|
85
85
|
const subagents = state.subagentsEnabled === false ? theme.fg("error", "subagents:off") : "";
|
|
86
|
-
return [theme.fg("accent", "Takomi"), sourceLabel, stageBadge, role, gate
|
|
86
|
+
return [theme.fg("accent", "Takomi"), sourceLabel, stageBadge, role, gate, plan, subagents].filter(Boolean).join(" ");
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
export function renderRuntimeWidget(theme: Theme, state: RuntimeHudState): string[] {
|
|
@@ -95,7 +95,7 @@ export function renderRuntimeWidget(theme: Theme, state: RuntimeHudState): strin
|
|
|
95
95
|
sourceLabel,
|
|
96
96
|
badge(theme, primary, stageTone(state.stage)),
|
|
97
97
|
state.stage && state.role !== state.stage ? theme.fg("dim", `role:${state.role}`) : "",
|
|
98
|
-
state.launchMode === "manual" ? theme.fg("warning", "review-gate") : "",
|
|
98
|
+
state.launchMode === "manual" ? theme.fg("warning", "review-gate") : theme.fg("success", "auto-gate"),
|
|
99
99
|
state.planMode ? theme.fg("warning", "plan") : theme.fg("dim", "direct"),
|
|
100
100
|
state.subagentsEnabled === false ? theme.fg("error", "subagents:off") : theme.fg("dim", "subagents:on"),
|
|
101
101
|
state.workflow ? theme.fg("dim", `wf:${state.workflow}`) : "",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { Type } from "typebox";
|
|
3
3
|
import { renderTakomiSubagentCall, renderTakomiSubagentResult } from "./native-render";
|
|
4
|
+
import { loadPiSubagentsInternals } from "./pi-subagents-internal";
|
|
4
5
|
import { executeTakomiSubagentTool } from "./tool-runner";
|
|
5
6
|
|
|
6
7
|
const ChecklistItemSchema = Type.Object({
|
|
@@ -30,8 +31,24 @@ const TaskSchema = Type.Object({
|
|
|
30
31
|
checklist: Type.Optional(Type.Array(Type.Union([Type.String(), ChecklistItemSchema]))),
|
|
31
32
|
});
|
|
32
33
|
|
|
34
|
+
const ContextSchema = Type.Union([
|
|
35
|
+
Type.Literal("fresh"),
|
|
36
|
+
Type.Literal("fork"),
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
const ActionSchema = Type.Union([
|
|
40
|
+
Type.Literal("list"),
|
|
41
|
+
Type.Literal("get"),
|
|
42
|
+
Type.Literal("models"),
|
|
43
|
+
Type.Literal("status"),
|
|
44
|
+
Type.Literal("interrupt"),
|
|
45
|
+
Type.Literal("resume"),
|
|
46
|
+
Type.Literal("doctor"),
|
|
47
|
+
]);
|
|
48
|
+
|
|
33
49
|
const SubagentParameters = Type.Object({
|
|
34
|
-
|
|
50
|
+
action: Type.Optional(ActionSchema),
|
|
51
|
+
agent: Type.Optional(Type.String({ description: "Agent name for single execution, or target agent for get/models actions" })),
|
|
35
52
|
task: Type.Optional(Type.String({ description: "Task for single execution" })),
|
|
36
53
|
workflow: Type.Optional(Type.String({ description: "Workflow or playbook overlay for this task" })),
|
|
37
54
|
skills: Type.Optional(Type.Array(Type.String(), { description: "Extra skills to apply during the task" })),
|
|
@@ -46,6 +63,14 @@ const SubagentParameters = Type.Object({
|
|
|
46
63
|
previewOnly: Type.Optional(Type.Boolean({ description: "Return the delegation plan without launching" })),
|
|
47
64
|
clarify: Type.Optional(Type.Boolean({ description: "Show the native pi-subagents TUI to preview/edit before execution. Especially useful for chains; requires an interactive Pi TUI." })),
|
|
48
65
|
chain: Type.Optional(Type.Array(TaskSchema, { description: "Sequential chain of subagent tasks" })),
|
|
66
|
+
context: Type.Optional(ContextSchema),
|
|
67
|
+
async: Type.Optional(Type.Boolean({ description: "Run through native pi-subagents background/async mode" })),
|
|
68
|
+
concurrency: Type.Optional(Type.Number({ description: "Maximum concurrency for parallel task groups" })),
|
|
69
|
+
worktree: Type.Optional(Type.Boolean({ description: "Use native pi-subagents worktree isolation where supported" })),
|
|
70
|
+
id: Type.Optional(Type.String({ description: "Native async/control run id for status, interrupt, or resume actions" })),
|
|
71
|
+
message: Type.Optional(Type.String({ description: "Follow-up message for resume actions" })),
|
|
72
|
+
index: Type.Optional(Type.Number({ description: "Child index for resume actions when needed" })),
|
|
73
|
+
chainName: Type.Optional(Type.String({ description: "Saved chain name for get actions" })),
|
|
49
74
|
agentScope: Type.Optional(Type.Union([Type.Literal("user"), Type.Literal("project"), Type.Literal("both")])),
|
|
50
75
|
// Project-agent confirmation and hard-stop overrides are enforced server-side;
|
|
51
76
|
// they are intentionally not model-callable parameters.
|
|
@@ -55,11 +80,14 @@ function registerSubagentTool(pi: ExtensionAPI): void {
|
|
|
55
80
|
pi.registerTool({
|
|
56
81
|
name: "takomi_subagent",
|
|
57
82
|
label: "Takomi",
|
|
58
|
-
description: "Run subagents with Pi-style single, parallel,
|
|
59
|
-
promptSnippet: "Delegate lifecycle-aware Takomi work to specialist subagents. Use single, tasks, or
|
|
83
|
+
description: "Run subagents with Pi-style single, parallel, chain, async, fork, and management/status modes plus Takomi lifecycle metadata.",
|
|
84
|
+
promptSnippet: "Delegate lifecycle-aware Takomi work to specialist subagents. Use single, tasks, chain, or action=list/status/doctor; reuse conversationId for review loops.",
|
|
60
85
|
promptGuidelines: [
|
|
61
86
|
"Use this tool during orchestration when a specialist should handle a task.",
|
|
87
|
+
"Use action=list to discover agents and action=status/doctor for native pi-subagents diagnostics/control instead of raw subagent.",
|
|
62
88
|
"Use tasks for independent parallel work and chain for dependent handoffs with {previous}.",
|
|
89
|
+
"Set context=fork only when inherited parent-session history is needed; otherwise prefer fresh or the agent default.",
|
|
90
|
+
"Set async=true for long-running work when the parent can continue safely; keep active worktree writes single-threaded unless worktree isolation is enabled.",
|
|
63
91
|
"Set clarify=true when the user asks to preview/edit a subagent run in the native Pi TUI before launch.",
|
|
64
92
|
"Use model, fallbackModels, and thinking only when deliberate; otherwise let the agent/profile defaults apply.",
|
|
65
93
|
"If review sends work back to the same agent, reuse the same conversationId for continuity.",
|
|
@@ -74,6 +102,11 @@ function registerSubagentTool(pi: ExtensionAPI): void {
|
|
|
74
102
|
});
|
|
75
103
|
}
|
|
76
104
|
|
|
77
|
-
export default function takomiSubagents(pi: ExtensionAPI) {
|
|
105
|
+
export default async function takomiSubagents(pi: ExtensionAPI) {
|
|
106
|
+
// Preload the native pi-subagents renderer before tool registration. Rendering
|
|
107
|
+
// callbacks are synchronous, so if we only lazy-load internals during execution
|
|
108
|
+
// a completed takomi_subagent result can fall back to Takomi's plain text
|
|
109
|
+
// renderer and lose the native compact/expanded details shown by `subagent`.
|
|
110
|
+
await loadPiSubagentsInternals();
|
|
78
111
|
registerSubagentTool(pi);
|
|
79
112
|
}
|
|
@@ -38,12 +38,16 @@ function resultText(result: ToolResult): string {
|
|
|
38
38
|
: JSON.stringify((result as any)?.details ?? {}, null, 2);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function
|
|
41
|
+
function extractPolicyNames(text: string): string[] {
|
|
42
42
|
const policyMatch = text.match(/Required policies:\n((?:- .+\n?)+)/);
|
|
43
|
-
|
|
43
|
+
return policyMatch?.[1]
|
|
44
44
|
?.split("\n")
|
|
45
45
|
.map((line) => line.replace(/^[-\s]+/, "").trim())
|
|
46
46
|
.filter(Boolean) ?? [];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function summarizeCollapsedResult(text: string, status: string, theme: Theme): string {
|
|
50
|
+
const policies = extractPolicyNames(text);
|
|
47
51
|
const lineCount = text ? text.split(/\r?\n/).length : 0;
|
|
48
52
|
const label = policies.length > 0
|
|
49
53
|
? `policy context loaded: ${policies.join(", ")}`
|
|
@@ -53,22 +57,89 @@ function summarizeCollapsedResult(text: string, status: string, theme: Theme): s
|
|
|
53
57
|
return `${theme.fg(color, `${icon} takomi_subagent ${status}`)}${theme.fg("dim", ` · ${label} (ctrl+o to expand)`)}`;
|
|
54
58
|
}
|
|
55
59
|
|
|
60
|
+
function isPolicyGateBlock(text: string): boolean {
|
|
61
|
+
return /^Blocked\s+takomi_subagent:\s+required policy context had not been loaded yet\./m.test(text)
|
|
62
|
+
&& /\nRequired policies:\n/.test(text)
|
|
63
|
+
&& /\nLoaded policy context:\n/.test(text);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function renderPolicyGateBlock(text: string, expanded: boolean | undefined, theme: Theme): string {
|
|
67
|
+
const policies = extractPolicyNames(text);
|
|
68
|
+
const lineCount = text ? text.split(/\r?\n/).length : 0;
|
|
69
|
+
const policyLabel = policies.length ? policies.join(", ") : "required policy";
|
|
70
|
+
if (!expanded) {
|
|
71
|
+
return [
|
|
72
|
+
theme.fg("warning", "⚠ takomi_subagent blocked"),
|
|
73
|
+
theme.fg("dim", `Required policy context loaded for this session: ${policyLabel}.`),
|
|
74
|
+
theme.fg("dim", `Retry the original tool call. ${lineCount} policy lines hidden (ctrl+o to expand).`),
|
|
75
|
+
].join("\n");
|
|
76
|
+
}
|
|
77
|
+
return [
|
|
78
|
+
theme.fg("warning", "⚠ takomi_subagent blocked"),
|
|
79
|
+
theme.fg("dim", "Policy context was loaded and passed back to the model; retry the original call."),
|
|
80
|
+
theme.fg("dim", "Press ctrl+o again to collapse."),
|
|
81
|
+
"",
|
|
82
|
+
text,
|
|
83
|
+
].join("\n");
|
|
84
|
+
}
|
|
85
|
+
|
|
56
86
|
function recentOutputLines(value: unknown): string[] {
|
|
57
87
|
if (Array.isArray(value)) return value.map(String).filter(Boolean).slice(-3);
|
|
58
88
|
if (typeof value === "string") return value.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).slice(-3);
|
|
59
89
|
return [];
|
|
60
90
|
}
|
|
61
91
|
|
|
92
|
+
function normalizeLiveStatus(value: string | undefined): string | undefined {
|
|
93
|
+
if (!value) return undefined;
|
|
94
|
+
if (value === "complete") return "completed";
|
|
95
|
+
if (value === "in-progress") return "running";
|
|
96
|
+
if (value === "timed-out") return "failed";
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function rawLiveStatus(row: any): string {
|
|
101
|
+
const explicit = normalizeLiveStatus(
|
|
102
|
+
typeof row?.progress?.status === "string" ? row.progress.status
|
|
103
|
+
: typeof row?.status === "string" ? row.status
|
|
104
|
+
: undefined,
|
|
105
|
+
);
|
|
106
|
+
if (explicit) return explicit;
|
|
107
|
+
|
|
108
|
+
const exitCode = typeof row?.exitCode === "number" ? row.exitCode
|
|
109
|
+
: typeof row?.code === "number" ? row.code
|
|
110
|
+
: undefined;
|
|
111
|
+
if (exitCode === 0) return "completed";
|
|
112
|
+
if (exitCode === undefined || exitCode === null || exitCode === -1) return "running";
|
|
113
|
+
return "failed";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function isLiveTerminalStatus(status: string): boolean {
|
|
117
|
+
return ["completed", "failed", "blocked", "detached", "paused"].includes(status);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function displayLiveStatus(status: string, allRowsTerminal: boolean): string {
|
|
121
|
+
// Native pi-subagents can emit one last partial update after the child process
|
|
122
|
+
// reaches exitCode 0 but before the takomi_subagent tool result has actually
|
|
123
|
+
// settled. In that window the tool card is still partial/running, so showing a
|
|
124
|
+
// child as "completed" is misleading. Call it finalizing until Pi renders the
|
|
125
|
+
// real final result.
|
|
126
|
+
if (allRowsTerminal && status === "completed") return "finalizing";
|
|
127
|
+
return status;
|
|
128
|
+
}
|
|
129
|
+
|
|
62
130
|
function livePartialText(result: ToolResult, theme: Theme): string {
|
|
63
131
|
const details = (result as any)?.details ?? {};
|
|
64
132
|
const results = Array.isArray(details.results) ? details.results : [];
|
|
65
133
|
const progress = Array.isArray(details.progress) ? details.progress : [];
|
|
134
|
+
const rows = results.length ? results : progress;
|
|
135
|
+
const rawStatuses = rows.map(rawLiveStatus);
|
|
136
|
+
const allRowsTerminal = rows.length > 0 && rawStatuses.every(isLiveTerminalStatus);
|
|
137
|
+
const titleStatus = allRowsTerminal ? "finalizing" : "running";
|
|
66
138
|
const lines = [
|
|
67
|
-
theme.fg("toolTitle", theme.bold(
|
|
139
|
+
theme.fg("toolTitle", theme.bold(`takomi_subagent ${titleStatus}`)),
|
|
68
140
|
theme.fg("dim", "Live detail is bounded while streaming so manual scroll/ctrl+o does not jump on every token."),
|
|
69
141
|
];
|
|
70
142
|
|
|
71
|
-
const rows = results.length ? results : progress;
|
|
72
143
|
if (!rows.length) {
|
|
73
144
|
const text = resultText(result).split(/\r?\n/).find((line) => line.trim())?.trim();
|
|
74
145
|
lines.push(theme.fg("dim", text || "Waiting for subagent progress…"));
|
|
@@ -76,7 +147,7 @@ function livePartialText(result: ToolResult, theme: Theme): string {
|
|
|
76
147
|
}
|
|
77
148
|
|
|
78
149
|
rows.slice(0, 6).forEach((row: any, index: number) => {
|
|
79
|
-
const status =
|
|
150
|
+
const status = displayLiveStatus(rawStatuses[index] ?? rawLiveStatus(row), allRowsTerminal);
|
|
80
151
|
const agent = row.agent ?? `task ${index + 1}`;
|
|
81
152
|
const task = String(row.task ?? "").replace(/\s+/g, " ").trim();
|
|
82
153
|
const currentTool = row.currentTool ?? row.progress?.currentTool;
|
|
@@ -93,15 +164,21 @@ function livePartialText(result: ToolResult, theme: Theme): string {
|
|
|
93
164
|
}
|
|
94
165
|
|
|
95
166
|
export function renderTakomiSubagentResult(result: ToolResult, options: { expanded?: boolean; isPartial?: boolean }, theme: Theme, context: any): any {
|
|
96
|
-
const status = (result as any)?.isError ? "failed" : options.isPartial ? "running" : "completed";
|
|
167
|
+
const status = ((result as any)?.isError || context?.isError) ? "failed" : options.isPartial ? "running" : "completed";
|
|
97
168
|
const text = resultText(result);
|
|
98
169
|
|
|
170
|
+
if (isPolicyGateBlock(text)) {
|
|
171
|
+
return new Text(renderPolicyGateBlock(text, options.expanded, theme), 0, 0);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const native = renderNativeSubagentResult(result, options, theme, context);
|
|
175
|
+
if (options.isPartial && native) return native;
|
|
176
|
+
|
|
99
177
|
if (options.isPartial) {
|
|
100
178
|
if (options.expanded) return new Text(livePartialText(result, theme), 0, 0);
|
|
101
179
|
return new Text(summarizeCollapsedResult(text, status, theme), 0, 0);
|
|
102
180
|
}
|
|
103
181
|
|
|
104
|
-
const native = renderNativeSubagentResult(result, options, theme, context);
|
|
105
182
|
if (native) return native;
|
|
106
183
|
|
|
107
184
|
if (!options.expanded) {
|
|
@@ -54,7 +54,8 @@ function createState(): SubagentState {
|
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
function resolveMode(params: TakomiSubagentToolParams): "single" | "parallel" | "chain" | undefined {
|
|
57
|
+
function resolveMode(params: TakomiSubagentToolParams): "single" | "parallel" | "chain" | "action" | undefined {
|
|
58
|
+
if (params.action) return "action";
|
|
58
59
|
const hasChain = Boolean(params.chain?.length);
|
|
59
60
|
const hasParallel = Boolean(params.tasks?.length);
|
|
60
61
|
const hasSingle = Boolean(params.agent && params.task);
|
|
@@ -205,13 +206,27 @@ function toSubagentParams(params: TakomiSubagentToolParams, rootCwd: string, dis
|
|
|
205
206
|
const base = {
|
|
206
207
|
agentScope: params.agentScope ?? "both",
|
|
207
208
|
cwd: rootCwd,
|
|
208
|
-
context:
|
|
209
|
-
async:
|
|
209
|
+
...(params.context ? { context: params.context } : {}),
|
|
210
|
+
...(params.async !== undefined ? { async: params.async } : {}),
|
|
211
|
+
...(params.concurrency !== undefined ? { concurrency: params.concurrency } : {}),
|
|
212
|
+
...(params.worktree !== undefined ? { worktree: params.worktree } : {}),
|
|
210
213
|
clarify: params.clarify === true,
|
|
211
214
|
includeProgress: true,
|
|
212
215
|
sessionDir: stableConversationSessionDir(rootCwd, tasks),
|
|
213
216
|
};
|
|
214
217
|
|
|
218
|
+
if (mode === "action") {
|
|
219
|
+
return {
|
|
220
|
+
...base,
|
|
221
|
+
action: params.action,
|
|
222
|
+
agent: params.agent,
|
|
223
|
+
chainName: params.chainName,
|
|
224
|
+
id: params.id,
|
|
225
|
+
message: params.message,
|
|
226
|
+
index: params.index,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
215
230
|
if (mode === "single") {
|
|
216
231
|
const task = tasks[0]!;
|
|
217
232
|
const mapped = mapSingleTask(task, names, rootCwd);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
4
|
-
import type { TakomiThinkingLevel } from "../../../src/pi-takomi-core";
|
|
4
|
+
import type { TakomiLaunchMode, TakomiThinkingLevel } from "../../../src/pi-takomi-core";
|
|
5
5
|
import { loadTakomiProfile } from "../takomi-runtime/profile";
|
|
6
6
|
import { applyTakomiRoutingDefaults, loadTakomiModelRoutingSnapshot } from "../takomi-runtime/model-routing-defaults";
|
|
7
7
|
import { resolveAgentName } from "./agent-aliases";
|
|
@@ -25,11 +25,20 @@ export type TakomiSubagentToolTask = {
|
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
export type TakomiSubagentToolParams = Partial<TakomiSubagentToolTask> & {
|
|
28
|
+
action?: "list" | "get" | "models" | "status" | "interrupt" | "resume" | "doctor";
|
|
28
29
|
tasks?: TakomiSubagentToolTask[];
|
|
29
30
|
chain?: TakomiSubagentToolTask[];
|
|
30
31
|
confirmLaunch?: boolean;
|
|
31
32
|
previewOnly?: boolean;
|
|
32
33
|
clarify?: boolean;
|
|
34
|
+
context?: "fresh" | "fork";
|
|
35
|
+
async?: boolean;
|
|
36
|
+
concurrency?: number;
|
|
37
|
+
worktree?: boolean;
|
|
38
|
+
id?: string;
|
|
39
|
+
message?: string;
|
|
40
|
+
index?: number;
|
|
41
|
+
chainName?: string;
|
|
33
42
|
agentScope?: TakomiAgentScope;
|
|
34
43
|
};
|
|
35
44
|
|
|
@@ -192,6 +201,17 @@ function withNativeHardStop(result: any, hardStop: { reason: string; message: st
|
|
|
192
201
|
},
|
|
193
202
|
};
|
|
194
203
|
}
|
|
204
|
+
|
|
205
|
+
function readRuntimeLaunchMode(ctx: ExtensionContext): TakomiLaunchMode | undefined {
|
|
206
|
+
const entries = ctx.sessionManager.getEntries();
|
|
207
|
+
for (let i = entries.length - 1; i >= 0; i -= 1) {
|
|
208
|
+
const entry = entries[i] as { type?: string; customType?: string; data?: { launchMode?: unknown } };
|
|
209
|
+
if (entry.type !== "custom" || entry.customType !== "takomi-runtime-state") continue;
|
|
210
|
+
if (entry.data?.launchMode === "manual" || entry.data?.launchMode === "auto") return entry.data.launchMode;
|
|
211
|
+
}
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
|
|
195
215
|
function resolveMode(params: TakomiSubagentToolParams): "single" | "parallel" | "chain" | undefined {
|
|
196
216
|
const hasChain = Boolean(params.chain?.length);
|
|
197
217
|
const hasParallel = Boolean(params.tasks?.length);
|
|
@@ -234,7 +254,34 @@ export async function executeTakomiSubagentTool(
|
|
|
234
254
|
return textResult(message, { results: [], agentScope: params.agentScope ?? "both" }, true);
|
|
235
255
|
}
|
|
236
256
|
const profile = await loadTakomiProfile(rootCwd);
|
|
257
|
+
const runtimeLaunchMode = readRuntimeLaunchMode(ctx);
|
|
237
258
|
const agentScope = params.agentScope ?? "both";
|
|
259
|
+
|
|
260
|
+
if (params.action) {
|
|
261
|
+
try {
|
|
262
|
+
const nativeResult: any = await engine.execute(
|
|
263
|
+
"takomi-tool",
|
|
264
|
+
{ ...params, cwd: rootCwd, agentScope },
|
|
265
|
+
signal,
|
|
266
|
+
onUpdate as any,
|
|
267
|
+
ctx,
|
|
268
|
+
);
|
|
269
|
+
return {
|
|
270
|
+
...nativeResult,
|
|
271
|
+
details: {
|
|
272
|
+
...(nativeResult?.details ?? {}),
|
|
273
|
+
takomi: {
|
|
274
|
+
action: params.action,
|
|
275
|
+
agentScope,
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
} catch (error) {
|
|
280
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
281
|
+
return textResult(message, { results: [], action: params.action, agentScope }, true);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
238
285
|
const agents = discoverTakomiAgents(rootCwd, agentScope);
|
|
239
286
|
const byName = new Map<string, TakomiAgentConfig>(agents.map((agent) => [agent.name, agent]));
|
|
240
287
|
const mode = resolveMode(params);
|
|
@@ -290,7 +337,7 @@ export async function executeTakomiSubagentTool(
|
|
|
290
337
|
}
|
|
291
338
|
const plan = createTakomiDelegationPlan({
|
|
292
339
|
source: "takomi-tool",
|
|
293
|
-
launchMode: profile.launchMode ?? "auto",
|
|
340
|
+
launchMode: runtimeLaunchMode ?? profile.launchMode ?? "auto",
|
|
294
341
|
profile,
|
|
295
342
|
tasks: tasks.map((task, index) => ({
|
|
296
343
|
id: task.conversationId ?? `direct-${index + 1}`,
|
|
@@ -316,10 +363,10 @@ export async function executeTakomiSubagentTool(
|
|
|
316
363
|
}
|
|
317
364
|
try {
|
|
318
365
|
const nativeParams: TakomiSubagentToolParams = mode === "single"
|
|
319
|
-
? { ...params, ...tasks[0]!, agentScope }
|
|
366
|
+
? { ...params, ...tasks[0]!, cwd: rootCwd, agentScope }
|
|
320
367
|
: mode === "parallel"
|
|
321
|
-
? { ...params, tasks, agentScope }
|
|
322
|
-
: { ...params, chain: tasks, agentScope };
|
|
368
|
+
? { ...params, cwd: rootCwd, tasks, agentScope }
|
|
369
|
+
: { ...params, cwd: rootCwd, chain: tasks, agentScope };
|
|
323
370
|
|
|
324
371
|
const nativeResult: any = await engine.execute(
|
|
325
372
|
"takomi-tool",
|
package/README.md
CHANGED
|
@@ -50,6 +50,8 @@ Legacy commands like `takomi install pi`, `takomi sync pi`, `takomi upgrade`, an
|
|
|
50
50
|
|
|
51
51
|
During `takomi setup pi` or `takomi setup pi-features`, Takomi offers optional Pi feature packs with recommended/manual/select-all/skip choices. Current defaults install **Takomi Interview** (`npm:@juicesharp/rpiv-ask-user-question`) so models can ask structured clarification questions. **Takomi Todo** (`npm:@juicesharp/rpiv-todo`), **Takomi Browser QA** (`npm:pi-chrome`), and **Takomi Doc Preview** (`npm:pi-markdown-preview`) remain opt-in. `takomi refresh` runs Pi's package updater so installed optional, custom, old, and new Pi packages are reconciled together.
|
|
52
52
|
|
|
53
|
+
Takomi keeps `pi-subagents` installed as an internal runtime module, but setup/refresh now detects legacy raw Pi subagent activation (`npm:pi-subagents` in Pi settings or `~/.pi/agent/extensions/subagent`) and offers to disable it so models see `takomi_subagent` instead of two competing subagent tools.
|
|
54
|
+
|
|
53
55
|
### Context Manager
|
|
54
56
|
|
|
55
57
|
Takomi now ships a Pi-native `takomi-context-manager` extension. It reduces prompt bloat with progressive context loading:
|
|
@@ -60,10 +62,11 @@ Takomi now ships a Pi-native `takomi-context-manager` extension. It reduces prom
|
|
|
60
62
|
- `takomi_subagent` is guarded by routing-policy context and can recover from wrong-provider model choices
|
|
61
63
|
- `/context-report` shows prompt compaction, loaded skills/policies, blocked actions, model-routing corrections, and duplicate extension diagnostics
|
|
62
64
|
|
|
65
|
+
`context_report` is context-manager-specific rather than a clone of Pi's Alt-C window. It restores its own hidden snapshots and Pi tool-result history after `/reload`/restart, and labels any remaining gaps instead of reporting fresh in-memory zeros as session truth. It supports `mode: "summary" | "verbose" | "problems"`; `verbose: true` remains a compatibility alias for `mode: "verbose"`. The `/context-report` slash command supports argument completions for `summary`, `verbose`, and `problems`.
|
|
63
66
|
|
|
64
67
|
### Option A: Global Install (Best for Multi-IDE Users) ⭐
|
|
65
68
|
|
|
66
|
-
Install once. Use everywhere. Your skills follow you across
|
|
69
|
+
Install once. Use everywhere. Your skills follow you across detected AI harnesses (Antigravity, Claude Code, Codex, Cursor, Kilo Code, Pi/shared Agent Skills, Windsurf):
|
|
67
70
|
|
|
68
71
|
```bash
|
|
69
72
|
# Using pnpm
|
|
@@ -184,17 +187,21 @@ npx -y skills add https://github.com/JStaRFilms/VibeCode-Protocol-Suite --skill
|
|
|
184
187
|
|
|
185
188
|
**One install. Every IDE. Zero friction.**
|
|
186
189
|
|
|
187
|
-
Takomi v2.0 introduces the **Global Skills Router** — install skills once
|
|
190
|
+
Takomi v2.0 introduces the **Global Skills Router** — install skills once into `~/.takomi/`, and Takomi syncs them into each harness' current global skills directory. You can choose symlink/junction mode for one canonical copy, auto fallback, or plain copy mode. Works on Mac & Windows.
|
|
191
|
+
|
|
192
|
+
Note: `SKILL.md` is portable, but `~/.agents/skills` is **not** a universal global skills directory. Pi does load `~/.agents/skills`, and Takomi keeps that as the Pi/shared Agent Skills target. Other harnesses use their own global paths. See `docs/skills-harness-targets.md` for the current checked path table.
|
|
188
193
|
|
|
189
194
|
### Supported Harnesses
|
|
190
195
|
|
|
191
196
|
| Harness | Global Skills Path | Global Workflows Path |
|
|
192
197
|
|---|---|---|
|
|
193
|
-
| **Antigravity** | `~/.gemini/
|
|
194
|
-
| **
|
|
198
|
+
| **Antigravity** | `~/.gemini/config/skills/` | `~/.gemini/config/global_workflows/` |
|
|
199
|
+
| **Claude Code** | `~/.claude/skills/` | _(skills only)_ |
|
|
200
|
+
| **Codex** | `~/.codex/skills/` | _(skills only)_ |
|
|
201
|
+
| **Cursor** | `~/.cursor/skills/` | _(skills only)_ |
|
|
202
|
+
| **Kilo Code** | `~/.kilocode/skills/` | `~/.kilocode/workflows/` |
|
|
203
|
+
| **Pi / shared Agent Skills** | `~/.agents/skills/` | _(skills only)_ |
|
|
195
204
|
| **Windsurf** | `~/.codeium/windsurf/skills/` | `~/.codeium/windsurf/global_workflows/` |
|
|
196
|
-
| **Global agents-compatible CLIs** _(e.g., Codex, Gemini CLI)_ | `~/.agents/skills/` | _(skills only)_ |
|
|
197
|
-
| **Cursor** | `~/.cursor/skills/` | _(uses rules)_ |
|
|
198
205
|
|
|
199
206
|
### CLI Commands
|
|
200
207
|
|
|
@@ -505,7 +512,7 @@ Externally sourced skills and optional Pi packages retain credit to their upstre
|
|
|
505
512
|
- **Context7**: From [upstash/context7](https://github.com/upstash/context7) — fresh library documentation fetcher.
|
|
506
513
|
- **Audit Website**: From [squirrelscan/skills](https://github.com/squirrelscan/skills) — professional website auditor.
|
|
507
514
|
- **Convex Skills**: From [waynesutton/convexskills](https://github.com/waynesutton/convexskills) — complete Convex development suite including **Functions**, **Schema Validation**, **Realtime**, **Agents**, **File Storage**, **Migrations**, **HTTP Actions**, **Cron Jobs**, **Component Authoring**, **Best Practices**, **Security Audit**, **Security Check**, **Avoid Feature Creep**, and **Optimize Agent Context**.
|
|
508
|
-
- **
|
|
515
|
+
- **Anti-Gravity**: Custom skill for running Google's current Anti-Gravity CLI workflow for large-context review and analysis.
|
|
509
516
|
- **Google Stitch Skills**: From [google-labs-code/stitch-skills](https://github.com/google-labs-code/stitch-skills) — Design-to-code suite including **design-md**, **enhance-prompt**, **stitch-loop**, **react-components**, and **shadcn-ui**.
|
|
510
517
|
- **Jules**: From [sanjay3290/ai-skills](https://github.com/sanjay3290/ai-skills) — delegate coding tasks to Google Jules AI agent.
|
|
511
518
|
- **Subagent Execution**: Built on **[`pi-subagents`](https://github.com/nicobailon/pi-subagents)** by **Nico Bailon** — providing the underlying Pi extension for delegated subagent runs (result rendering, live progress, single/parallel/chain execution, session/artifact handling, and related subagent tooling), upon which Takomi adds its own lifecycle orchestration, model-routing policy, and workflow metadata.
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: exam-creator-skill
|
|
3
|
+
description: Creates and revises school exam papers using Johno's preferred workflow. Use for JSS/Primary exam generation, remixing questions from lesson notes or chat transcripts, building question papers plus marking schemes, creating assets folders for diagrams, applying the 40-mark house style, producing compact DOCX output, and running draft/marking/verification passes with room for user feedback and revisions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Exam Creator Skill
|
|
7
|
+
|
|
8
|
+
Use this skill when building or revising school exam papers, especially for OBHIS / Olive Blessed Crest Academy.
|
|
9
|
+
|
|
10
|
+
See the detailed house rules in [references/workflow-rulebook.md](references/workflow-rulebook.md).
|
|
11
|
+
See the model routing policy in [references/model-routing-policy.md](references/model-routing-policy.md).
|
|
12
|
+
|
|
13
|
+
## Core Principle
|
|
14
|
+
|
|
15
|
+
Follow the user's house style by default, but always leave room for correction. If the user gives a new rule, prefer the new rule and update the working assumptions before generating more papers.
|
|
16
|
+
|
|
17
|
+
Terminology rule: when the user says **Gemini**, treat that as **Gemini via the agy CLI** unless the user explicitly says otherwise.
|
|
18
|
+
|
|
19
|
+
## Default Workflow
|
|
20
|
+
|
|
21
|
+
1. **Identify the subject, class, term, and destination folder.**
|
|
22
|
+
2. **Collect the authority material**:
|
|
23
|
+
- lesson notes
|
|
24
|
+
- ChatGPT transcripts
|
|
25
|
+
- sample exam layout if provided
|
|
26
|
+
- photographed handwritten pages, when provided
|
|
27
|
+
3. **For photographed handwritten pages, extract with multimodal vision first**:
|
|
28
|
+
- use a multimodal model/subagent to read the image directly
|
|
29
|
+
- batch images in small ordered groups, usually 3-5 images per extraction task
|
|
30
|
+
- explicitly forbid OCR/Tesseract/Python preprocessing on the first pass unless the model is not multimodal
|
|
31
|
+
- use OCR only as fallback when direct model vision is unavailable or fails on a specific page
|
|
32
|
+
- preserve image filename/page references for every uncertain item
|
|
33
|
+
4. **Confirm the paper pattern before drafting** if any of these are unclear:
|
|
34
|
+
- subject family (Mathematics/English vs other subjects)
|
|
35
|
+
- mark split
|
|
36
|
+
- question counts
|
|
37
|
+
- whether theory is answer-all or answer-any
|
|
38
|
+
5. **Create or reuse clean folders**:
|
|
39
|
+
- `Questions/`
|
|
40
|
+
- `Marking Scheme/` only when requested
|
|
41
|
+
- `Questions/assets/` for all generated SVG/PNG/image diagrams
|
|
42
|
+
6. **Draft the paper first.**
|
|
43
|
+
7. **Create the marking scheme second only when requested.**
|
|
44
|
+
8. **Run an independent verification pass third.**
|
|
45
|
+
9. **Apply user feedback and rerender** instead of defending the first draft.
|
|
46
|
+
|
|
47
|
+
## Preferred Multi-Agent Pattern
|
|
48
|
+
|
|
49
|
+
Default model split:
|
|
50
|
+
- orchestrator: parent assistant
|
|
51
|
+
- drafting: Gemini via agy CLI by default, escalate to GPT 5.4 High when the paper is tricky
|
|
52
|
+
- marking: Gemini via agy CLI
|
|
53
|
+
- verification: GPT
|
|
54
|
+
|
|
55
|
+
When subagents are available, use this split:
|
|
56
|
+
|
|
57
|
+
- **Drafting agent**: creates the paper and diagram assets.
|
|
58
|
+
- **Marking agent**: creates the marking scheme and validates every objective answer.
|
|
59
|
+
- **Review agent**: independently rechecks answers, numbering, marks, wording, and diagram correctness.
|
|
60
|
+
|
|
61
|
+
If subagents are not available, still preserve the same three-pass logic manually.
|
|
62
|
+
|
|
63
|
+
## House Rules To Hardcode
|
|
64
|
+
|
|
65
|
+
### 1) Marks and paper shape
|
|
66
|
+
|
|
67
|
+
#### Mathematics and English
|
|
68
|
+
Use this as the default unless the user overrides it:
|
|
69
|
+
|
|
70
|
+
- total exam score: **40 marks**
|
|
71
|
+
- **50 objective questions**
|
|
72
|
+
- each objective = **1/2 mark**
|
|
73
|
+
- objective total = **25 marks**
|
|
74
|
+
- **5 theory questions**
|
|
75
|
+
- student answers **any 3**
|
|
76
|
+
- theory total = **15 marks**
|
|
77
|
+
- no separate Section B short-answer block unless the user explicitly asks for one
|
|
78
|
+
|
|
79
|
+
#### Other subjects
|
|
80
|
+
Default assumption:
|
|
81
|
+
|
|
82
|
+
- still over **40 marks** total
|
|
83
|
+
- can include open-ended plus theory sections
|
|
84
|
+
- if the exact split is not stated, ask before finalizing
|
|
85
|
+
|
|
86
|
+
Never silently reuse the old 100-mark structure unless the user explicitly asks for it.
|
|
87
|
+
|
|
88
|
+
### 2) Layout rules
|
|
89
|
+
|
|
90
|
+
For the final paper DOCX, prefer:
|
|
91
|
+
|
|
92
|
+
- **Times New Roman**
|
|
93
|
+
- use one font size consistently within a paper; **start with 14 pt** and only reduce it if layout pressure makes it necessary
|
|
94
|
+
- narrow margins
|
|
95
|
+
- every exam header should include, in this order where possible: school name, academic session, term/exam title, pupil name/date line, examination number/time line, class, arm, subject, and instructions
|
|
96
|
+
- header must be **1-column**
|
|
97
|
+
- body should be **1-column by default**; use 2-column or 3-column only when it genuinely improves fit for dense objective papers
|
|
98
|
+
- do not apply a multi-column body just because the skill mentions compact layout; use judgment per subject
|
|
99
|
+
- bold black headings instead of oversized decorative headings
|
|
100
|
+
- objective options must start on the **same line as the question** whenever possible; keep them inline with about 3 spaces between choices, not vertically stacked unless unavoidable
|
|
101
|
+
- if the paper looks like it will run to **3 pages**, try a **2-column or 3-column body layout** before reducing the font size; use judgment based on content density
|
|
102
|
+
- preserve the school name and student-detail heading fields from the source, or leave clear blanks/placeholders if they are not provided
|
|
103
|
+
- if the source uses an arm/stream/class line, keep it but do not hardcode labels like `Arm:` unless the source explicitly requires them
|
|
104
|
+
- when using separate header/body sections in DOCX, make the body section **continuous** so it does not jump to a new page
|
|
105
|
+
- avoid hard page breaks between the heading block and the paper body unless the user explicitly asks for a new page
|
|
106
|
+
- remove explicit `Total Marks: ...` header line unless requested
|
|
107
|
+
- target about **2 pages** per paper where practical
|
|
108
|
+
|
|
109
|
+
### 3) Diagram and image rules
|
|
110
|
+
|
|
111
|
+
- Keep all generated figures inside `Questions/assets/`.
|
|
112
|
+
- Choose the diagram method by complexity:
|
|
113
|
+
- simple geometric/line diagrams, tables, clocks, arrows, and labels: SVG first; generate PNG copies if DOCX rendering needs them
|
|
114
|
+
- pictorial objects for young pupils, e.g. mango, pot, bucket, moon, table, cup, house, animals, people, classroom objects: prefer Anti-Gravity image generation or another image-generation path, then place the generated PNG/JPG in `Questions/assets/`
|
|
115
|
+
- hybrid diagrams: combine clean SVG labels/structure with generated image assets when useful
|
|
116
|
+
- When using Anti-Gravity for diagrams, explicitly tell it whether to generate images, use SVG, or use a hybrid method, and require it to report which method was used.
|
|
117
|
+
- Never include the teacher's written answer labels in student-facing diagrams. If the source labels a keyboard as "Keyboard" or groups division answers for marking guidance, remove that answer/label from the final exam.
|
|
118
|
+
- Keep diagrams separated when the source has separate question items or separate objects that must be arranged on the paper. Do not combine unrelated drawings into one asset just for convenience; combine only when the source/question explicitly presents them as one group.
|
|
119
|
+
- Preserve the source question order for diagram-heavy nursery/primary papers by rebuilding from the original images, not only from extraction summaries.
|
|
120
|
+
- If an item asks pupils to colour an object or flag, do not colour it in the exam; provide an outline only unless the instruction asks for a sample.
|
|
121
|
+
- Keep angle labels and vertex labels clearly visible for geometry.
|
|
122
|
+
- Avoid placing numbers directly on triangle edges.
|
|
123
|
+
- If labels are cramped, move them outward and add white-backed label boxes if needed.
|
|
124
|
+
|
|
125
|
+
### 4) Feedback loop
|
|
126
|
+
|
|
127
|
+
After each significant draft:
|
|
128
|
+
|
|
129
|
+
- expect user corrections
|
|
130
|
+
- revise quickly
|
|
131
|
+
- update the source files and rerender the DOCX
|
|
132
|
+
- if the DOCX is locked/open, save a `v2` file rather than failing the task
|
|
133
|
+
|
|
134
|
+
## Output Expectations
|
|
135
|
+
|
|
136
|
+
For each subject batch, try to maintain:
|
|
137
|
+
|
|
138
|
+
- editable paper source, usually `questions.md`
|
|
139
|
+
- concise support/source metadata if useful
|
|
140
|
+
- final DOCX for the paper
|
|
141
|
+
- marking scheme source
|
|
142
|
+
- final DOCX for the marking scheme when requested
|
|
143
|
+
- objective-validation notes
|
|
144
|
+
- verification report
|
|
145
|
+
- all diagrams in `Questions/assets/`
|
|
146
|
+
|
|
147
|
+
## Authoring Guidance
|
|
148
|
+
|
|
149
|
+
- Keep questions standard and school-appropriate.
|
|
150
|
+
- Remix questions reasonably from the provided curriculum material.
|
|
151
|
+
- Stay within the authority source unless the user allows expansion.
|
|
152
|
+
- Make objective questions unambiguous.
|
|
153
|
+
- Do not leak answers from teacher notes, source annotations, labels, grouped examples, or marking cues into the student-facing paper.
|
|
154
|
+
- For handwritten sources, try hard to infer unclear words from context, subject vocabulary, options, and neighboring pages before marking `[unclear]`.
|
|
155
|
+
- If uncertainty remains, create a user-review list with image filename/page number, question number, cropped/quoted context if possible, and the competing interpretations. Ask the user instead of leaving unexplained uncertainty in the final paper.
|
|
156
|
+
- Ensure the marking scheme matches final numbering exactly when a marking scheme is requested.
|
|
157
|
+
- For diagrams, refer to them consistently as Diagram A, B, C, etc.
|
|
158
|
+
|
|
159
|
+
## Required Clarifications
|
|
160
|
+
|
|
161
|
+
Ask the user before proceeding when any of the following is missing:
|
|
162
|
+
|
|
163
|
+
- subject
|
|
164
|
+
- class level
|
|
165
|
+
- authority source
|
|
166
|
+
- sample layout path if layout matching matters
|
|
167
|
+
- exact marks pattern for non-Math/non-English subjects
|
|
168
|
+
- desired final format if not obvious
|
|
169
|
+
- final interpretation of handwritten items that remain ambiguous after a multimodal-first extraction pass and contextual inference
|
|
170
|
+
|
|
171
|
+
## Safe Revision Rules
|
|
172
|
+
|
|
173
|
+
When updating an already-generated paper:
|
|
174
|
+
|
|
175
|
+
1. revise the editable source first
|
|
176
|
+
2. revise the marking scheme next if numbering/marks changed
|
|
177
|
+
3. rerun validation/verification if answers, wording, or diagrams changed
|
|
178
|
+
4. rerender DOCX last
|
|
179
|
+
|
|
180
|
+
## Reference
|
|
181
|
+
|
|
182
|
+
Load and follow [references/workflow-rulebook.md](references/workflow-rulebook.md) when you need the exact house style details.
|