takomi 2.1.44 → 2.5.1
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 +9 -8
- package/.pi/agents/architect.md +2 -2
- package/.pi/agents/designer.md +2 -2
- package/.pi/agents/worker.md +32 -0
- package/.pi/extensions/oauth-router/commands.ts +66 -35
- package/.pi/extensions/oauth-router/index.ts +51 -7
- package/.pi/extensions/oauth-router/report-ui.ts +205 -0
- package/.pi/extensions/takomi-context-manager/diagnostics-tools.ts +41 -3
- package/.pi/extensions/takomi-context-manager/diagnostics.ts +26 -0
- package/.pi/extensions/takomi-context-manager/index.ts +3 -2
- package/.pi/extensions/takomi-context-manager/model-policy-gate.ts +50 -117
- package/.pi/extensions/takomi-context-manager/policy-tools.ts +93 -42
- package/.pi/extensions/takomi-context-manager/skill-categories.d.ts +11 -0
- package/.pi/extensions/takomi-context-manager/skill-categories.js +212 -0
- package/.pi/extensions/takomi-context-manager/skill-registry.ts +179 -8
- package/.pi/extensions/takomi-context-manager/skill-tools.ts +208 -103
- package/.pi/extensions/takomi-context-manager/tool-renderers.ts +112 -0
- package/.pi/extensions/takomi-context-manager/types.ts +6 -0
- package/.pi/extensions/takomi-runtime/command-text.ts +5 -4
- package/.pi/extensions/takomi-runtime/commands.ts +58 -25
- package/.pi/extensions/takomi-runtime/gate-provenance.ts +24 -0
- package/.pi/extensions/takomi-runtime/index.ts +385 -124
- package/.pi/extensions/takomi-runtime/model-routing-defaults.ts +262 -326
- package/.pi/extensions/takomi-runtime/profile.ts +9 -8
- package/.pi/extensions/takomi-runtime/routing-policy.ts +97 -66
- package/.pi/extensions/takomi-runtime/shared.ts +7 -30
- package/.pi/extensions/takomi-runtime/takomi-stats.js +46 -26
- package/.pi/extensions/takomi-runtime/tool-renderers.ts +234 -0
- package/.pi/extensions/takomi-runtime/workflow-catalog.ts +54 -0
- package/.pi/extensions/takomi-subagents/agents.ts +9 -0
- package/.pi/extensions/takomi-subagents/async-lifecycle.ts +401 -0
- package/.pi/extensions/takomi-subagents/detached-results.ts +940 -0
- package/.pi/extensions/takomi-subagents/index.ts +50 -1
- package/.pi/extensions/takomi-subagents/native-render.ts +250 -188
- package/.pi/extensions/takomi-subagents/pi-subagents-engine.ts +62 -47
- package/.pi/extensions/takomi-subagents/pi-subagents-internal.ts +11 -5
- package/.pi/extensions/takomi-subagents/result-heartbeat.ts +55 -0
- package/.pi/extensions/takomi-subagents/subagent-ux.ts +162 -0
- package/.pi/extensions/takomi-subagents/tool-runner.ts +198 -29
- package/.pi/settings.json +39 -36
- package/.pi/takomi/model-routing.md +288 -3
- package/.pi/takomi-profile.json +54 -50
- package/assets/.agent/skills/shared-resend-portfolio/SKILL.md +124 -0
- package/package.json +4 -3
- package/src/pi-takomi-core/orchestration.ts +39 -21
- package/src/pi-takomi-core/routing.ts +8 -8
- package/src/pi-takomi-core/types.ts +35 -5
- package/src/pi-takomi-core/workflows.ts +86 -45
- package/src/skills-catalog.js +2 -202
- package/src/skills-installer.js +4 -1
|
@@ -28,6 +28,7 @@ export type TakomiRuntimeCommandState = {
|
|
|
28
28
|
type RegisterTakomiCommandOptions = {
|
|
29
29
|
getState(): TakomiRuntimeCommandState;
|
|
30
30
|
updateState(ctx: ExtensionContext, mutator: () => void, message?: string | (() => string)): Promise<void>;
|
|
31
|
+
recordUserGateAutoProvenance(authorized: boolean): void;
|
|
31
32
|
resetRuntime(ctx: ExtensionCommandContext): Promise<void>;
|
|
32
33
|
setStageAndWorkflow(stage: VibeLifecycleStage, options?: { preserveRole?: boolean }): void;
|
|
33
34
|
createPlanSession(ctx: ExtensionCommandContext, title?: string): Promise<string>;
|
|
@@ -36,6 +37,13 @@ type RegisterTakomiCommandOptions = {
|
|
|
36
37
|
};
|
|
37
38
|
|
|
38
39
|
export function registerTakomiCommands(pi: ExtensionAPI, options: RegisterTakomiCommandOptions): void {
|
|
40
|
+
// The custom runtime widget is intentionally absent in idle/direct mode, so
|
|
41
|
+
// suppress routine notifications only while the changed state remains visible.
|
|
42
|
+
function hasVisibleRuntimeWidget(): boolean {
|
|
43
|
+
const state = options.getState();
|
|
44
|
+
return state.enabled && (state.modeSource ?? "idle") !== "idle";
|
|
45
|
+
}
|
|
46
|
+
|
|
39
47
|
async function handleStage(ctx: ExtensionCommandContext, stage: VibeLifecycleStage, prompt?: string): Promise<void> {
|
|
40
48
|
await options.updateState(ctx, () => {
|
|
41
49
|
options.getState().enabled = true;
|
|
@@ -47,54 +55,58 @@ export function registerTakomiCommands(pi: ExtensionAPI, options: RegisterTakomi
|
|
|
47
55
|
}
|
|
48
56
|
|
|
49
57
|
async function handleMode(ctx: ExtensionCommandContext, mode?: string): Promise<void> {
|
|
50
|
-
if (mode
|
|
51
|
-
|
|
58
|
+
if (mode === "direct") mode = "code";
|
|
59
|
+
if (mode !== "idle" && mode !== "code" && mode !== "orchestrate" && mode !== "review") {
|
|
60
|
+
ctx.ui.notify("Usage: /takomi mode <idle|code|review|orchestrate>", "warning");
|
|
52
61
|
return;
|
|
53
62
|
}
|
|
54
|
-
const hasGenesis = await options.hasGenesisArtifacts(ctx.cwd);
|
|
55
63
|
await options.updateState(ctx, () => {
|
|
56
64
|
const state = options.getState();
|
|
57
65
|
state.enabled = true;
|
|
58
|
-
if (mode === "
|
|
66
|
+
if (mode === "idle") {
|
|
59
67
|
state.autoOrch = false;
|
|
60
68
|
state.planMode = false;
|
|
61
69
|
state.role = "general";
|
|
62
|
-
state.stage = undefined;
|
|
63
|
-
state.workflow = undefined;
|
|
64
70
|
state.modeSource = "idle";
|
|
65
71
|
state.modeReason = undefined;
|
|
72
|
+
} else if (mode === "code") {
|
|
73
|
+
state.autoOrch = false;
|
|
74
|
+
state.planMode = false;
|
|
75
|
+
state.role = "coder";
|
|
76
|
+
state.modeSource = "manual";
|
|
77
|
+
state.modeReason = "/takomi mode code";
|
|
66
78
|
} else if (mode === "orchestrate") {
|
|
67
79
|
state.autoOrch = true;
|
|
68
80
|
state.planMode = true;
|
|
69
81
|
state.role = "orchestrator";
|
|
70
|
-
state.stage = hasGenesis ? "build" : "genesis";
|
|
71
|
-
state.workflow = hasGenesis ? "vibe-build" : "vibe-genesis";
|
|
72
82
|
state.modeSource = "manual";
|
|
73
83
|
state.modeReason = "/takomi mode orchestrate";
|
|
74
84
|
} else {
|
|
75
85
|
state.autoOrch = false;
|
|
76
86
|
state.planMode = true;
|
|
77
87
|
state.launchMode = "manual";
|
|
78
|
-
|
|
79
|
-
state.
|
|
80
|
-
state.workflow = undefined;
|
|
88
|
+
options.recordUserGateAutoProvenance(false);
|
|
89
|
+
state.role = "reviewer";
|
|
81
90
|
state.modeSource = "manual";
|
|
82
91
|
state.modeReason = "/takomi mode review";
|
|
83
92
|
}
|
|
84
|
-
}, () => `Takomi mode set to ${mode}`);
|
|
93
|
+
}, () => hasVisibleRuntimeWidget() ? "" : `Takomi mode set to ${mode}`);
|
|
85
94
|
}
|
|
86
95
|
|
|
87
96
|
async function handleGate(ctx: ExtensionCommandContext, gate?: string): Promise<void> {
|
|
88
|
-
if (gate !== "auto" && gate !== "review") {
|
|
89
|
-
ctx.ui.notify("Usage: /takomi gate <auto|review>", "warning");
|
|
97
|
+
if (gate !== "auto" && gate !== "review" && gate !== "manual") {
|
|
98
|
+
ctx.ui.notify("Usage: /takomi gate <auto|review|manual>", "warning");
|
|
90
99
|
return;
|
|
91
100
|
}
|
|
101
|
+
const auto = gate === "auto";
|
|
92
102
|
await options.updateState(ctx, () => {
|
|
93
103
|
const state = options.getState();
|
|
94
104
|
state.enabled = true;
|
|
95
|
-
state.launchMode =
|
|
96
|
-
state.autoOrch =
|
|
97
|
-
|
|
105
|
+
state.launchMode = auto ? "auto" : "manual";
|
|
106
|
+
state.autoOrch = auto;
|
|
107
|
+
// This dedicated entry is the only user-gate authorization signal.
|
|
108
|
+
options.recordUserGateAutoProvenance(auto);
|
|
109
|
+
}, () => hasVisibleRuntimeWidget() ? "" : `Takomi execution gate set to ${auto ? "auto" : "review"}`);
|
|
98
110
|
}
|
|
99
111
|
|
|
100
112
|
async function handleRouting(ctx: ExtensionCommandContext, body?: string): Promise<void> {
|
|
@@ -173,20 +185,41 @@ export function registerTakomiCommands(pi: ExtensionAPI, options: RegisterTakomi
|
|
|
173
185
|
const policyText = scopeMatch?.[2] ?? trimmed.replace(/^set\s+/i, "");
|
|
174
186
|
|
|
175
187
|
try {
|
|
176
|
-
const
|
|
188
|
+
const availableModels = (() => {
|
|
189
|
+
try {
|
|
190
|
+
const available = (ctx as ExtensionCommandContext & { modelRegistry?: { getAvailable?: () => Array<{ provider?: string; id?: string; name?: string }> } }).modelRegistry?.getAvailable?.() ?? [];
|
|
191
|
+
return available.map((model) => `${model.provider ? `${model.provider}/` : ""}${model.id ?? model.name ?? ""}`).filter(Boolean);
|
|
192
|
+
} catch {
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
})();
|
|
196
|
+
const [preview, activePolicy] = await Promise.all([
|
|
197
|
+
Promise.resolve(previewTakomiRoutingPolicy(ctx.cwd, policyText, { scope, availableModels })),
|
|
198
|
+
resolveTakomiRoutingPolicy(ctx.cwd),
|
|
199
|
+
]);
|
|
200
|
+
const replacementWarning = activePolicy.text && activePolicy.text.trim().length > preview.policy.trim().length * 2
|
|
201
|
+
? `WARNING: This input is much shorter than the active policy (${preview.policy.length} vs ${activePolicy.text.length} characters). It will replace the file, not merge into it. If the user referred to a full source file or prior policy, inspect and use that complete text instead.`
|
|
202
|
+
: "This input replaces the selected policy file exactly; it is not merged with the active policy.";
|
|
177
203
|
const reviewPrompt = [
|
|
178
|
-
"Review this Takomi routing
|
|
204
|
+
"Review this advisory Takomi model-routing guidance before it is saved.",
|
|
179
205
|
"",
|
|
180
206
|
"Rules:",
|
|
181
207
|
"- Do not invent providers or model IDs not grounded in the policy.",
|
|
182
|
-
"- Providerless names
|
|
183
|
-
"-
|
|
184
|
-
"-
|
|
185
|
-
"-
|
|
208
|
+
"- Providerless names such as Sol, Terra, and Luna are valid advisory routing concepts.",
|
|
209
|
+
"- Do not infer executable providers, allowlists, fallbacks, or persona defaults from this prose.",
|
|
210
|
+
"- Executable changes belong in takomi.routing settings through takomi_config_routing.",
|
|
211
|
+
"- Canonical Takomi personas are: architect, designer, coder, worker, reviewer, orchestrator.",
|
|
212
|
+
"- Preserve the user's full authored policy. If this looks like a summary/excerpt and a richer referenced source exists, inspect that source and apply the complete intended text instead of overwriting it with the excerpt.",
|
|
213
|
+
"- If the extraction is correct and safe, call takomi_apply_routing_policy with the complete intended policyText and scope below.",
|
|
214
|
+
"- Ask only for unresolved provider/account choices or genuine policy ambiguity; do not ask for facts available from the registry or files.",
|
|
186
215
|
"",
|
|
187
216
|
"Deterministic extraction:",
|
|
188
217
|
renderRoutingPolicyPreview(preview),
|
|
189
218
|
"",
|
|
219
|
+
replacementWarning,
|
|
220
|
+
"",
|
|
221
|
+
availableModels.length ? `Available Pi models:\n${availableModels.map((model) => `- ${model}`).join("\n")}` : "Available Pi models: registry unavailable; inspect it before asking the user if possible.",
|
|
222
|
+
"",
|
|
190
223
|
"Original policy text:",
|
|
191
224
|
"```",
|
|
192
225
|
preview.policy,
|
|
@@ -194,7 +227,7 @@ export function registerTakomiCommands(pi: ExtensionAPI, options: RegisterTakomi
|
|
|
194
227
|
"",
|
|
195
228
|
`Tool call to apply if safe: takomi_apply_routing_policy({ scope: ${JSON.stringify(scope)}, policyText: <original policy text> })`,
|
|
196
229
|
].join("\n");
|
|
197
|
-
ctx.ui.notify("Takomi routing
|
|
230
|
+
ctx.ui.notify("Takomi routing guidance prepared. Sending it to the active model for preservation review before saving.", "info");
|
|
198
231
|
pi.sendUserMessage(reviewPrompt);
|
|
199
232
|
} catch (error) {
|
|
200
233
|
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
@@ -217,7 +250,7 @@ export function registerTakomiCommands(pi: ExtensionAPI, options: RegisterTakomi
|
|
|
217
250
|
if (action === "on" || action === "off") {
|
|
218
251
|
await options.updateState(ctx, () => {
|
|
219
252
|
options.getState().subagentsEnabled = action === "on";
|
|
220
|
-
}, `Takomi subagents ${action}`);
|
|
253
|
+
}, () => hasVisibleRuntimeWidget() ? "" : `Takomi subagents ${action}`);
|
|
221
254
|
return;
|
|
222
255
|
}
|
|
223
256
|
if (action === "status" || !action) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const USER_GATE_AUTO_PROVENANCE_ENTRY = "takomi-user-gate-auto-provenance";
|
|
2
|
+
|
|
3
|
+
type SessionEntry = {
|
|
4
|
+
type?: unknown;
|
|
5
|
+
customType?: unknown;
|
|
6
|
+
data?: unknown;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
function isAuthorizedData(value: unknown): value is { authorized: true } {
|
|
10
|
+
return typeof value === "object" && value !== null && (value as { authorized?: unknown }).authorized === true;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Reads the latest explicit user gate decision from session history.
|
|
15
|
+
* This deliberately ignores generic runtime state and profile defaults.
|
|
16
|
+
*/
|
|
17
|
+
export function hasUserGateAutoProvenance(entries: readonly SessionEntry[]): boolean {
|
|
18
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
19
|
+
const entry = entries[index];
|
|
20
|
+
if (entry?.type !== "custom" || entry.customType !== USER_GATE_AUTO_PROVENANCE_ENTRY) continue;
|
|
21
|
+
return isAuthorizedData(entry.data);
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|