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.
Files changed (50) hide show
  1. package/.pi/README.md +9 -8
  2. package/.pi/agents/architect.md +2 -2
  3. package/.pi/agents/designer.md +2 -2
  4. package/.pi/agents/worker.md +32 -0
  5. package/.pi/extensions/oauth-router/commands.ts +66 -35
  6. package/.pi/extensions/oauth-router/index.ts +51 -7
  7. package/.pi/extensions/oauth-router/report-ui.ts +205 -0
  8. package/.pi/extensions/takomi-context-manager/diagnostics-tools.ts +41 -3
  9. package/.pi/extensions/takomi-context-manager/diagnostics.ts +26 -0
  10. package/.pi/extensions/takomi-context-manager/index.ts +3 -2
  11. package/.pi/extensions/takomi-context-manager/model-policy-gate.ts +50 -117
  12. package/.pi/extensions/takomi-context-manager/policy-tools.ts +93 -42
  13. package/.pi/extensions/takomi-context-manager/skill-categories.d.ts +11 -0
  14. package/.pi/extensions/takomi-context-manager/skill-categories.js +212 -0
  15. package/.pi/extensions/takomi-context-manager/skill-registry.ts +179 -8
  16. package/.pi/extensions/takomi-context-manager/skill-tools.ts +208 -103
  17. package/.pi/extensions/takomi-context-manager/tool-renderers.ts +112 -0
  18. package/.pi/extensions/takomi-context-manager/types.ts +6 -0
  19. package/.pi/extensions/takomi-runtime/command-text.ts +5 -4
  20. package/.pi/extensions/takomi-runtime/commands.ts +58 -25
  21. package/.pi/extensions/takomi-runtime/gate-provenance.ts +24 -0
  22. package/.pi/extensions/takomi-runtime/index.ts +385 -124
  23. package/.pi/extensions/takomi-runtime/model-routing-defaults.ts +262 -326
  24. package/.pi/extensions/takomi-runtime/profile.ts +9 -8
  25. package/.pi/extensions/takomi-runtime/routing-policy.ts +97 -66
  26. package/.pi/extensions/takomi-runtime/shared.ts +7 -30
  27. package/.pi/extensions/takomi-runtime/takomi-stats.js +46 -26
  28. package/.pi/extensions/takomi-runtime/tool-renderers.ts +234 -0
  29. package/.pi/extensions/takomi-runtime/workflow-catalog.ts +54 -0
  30. package/.pi/extensions/takomi-subagents/agents.ts +9 -0
  31. package/.pi/extensions/takomi-subagents/async-lifecycle.ts +401 -0
  32. package/.pi/extensions/takomi-subagents/detached-results.ts +940 -0
  33. package/.pi/extensions/takomi-subagents/index.ts +50 -1
  34. package/.pi/extensions/takomi-subagents/native-render.ts +250 -188
  35. package/.pi/extensions/takomi-subagents/pi-subagents-engine.ts +62 -47
  36. package/.pi/extensions/takomi-subagents/pi-subagents-internal.ts +11 -5
  37. package/.pi/extensions/takomi-subagents/result-heartbeat.ts +55 -0
  38. package/.pi/extensions/takomi-subagents/subagent-ux.ts +162 -0
  39. package/.pi/extensions/takomi-subagents/tool-runner.ts +198 -29
  40. package/.pi/settings.json +39 -36
  41. package/.pi/takomi/model-routing.md +288 -3
  42. package/.pi/takomi-profile.json +54 -50
  43. package/assets/.agent/skills/shared-resend-portfolio/SKILL.md +124 -0
  44. package/package.json +4 -3
  45. package/src/pi-takomi-core/orchestration.ts +39 -21
  46. package/src/pi-takomi-core/routing.ts +8 -8
  47. package/src/pi-takomi-core/types.ts +35 -5
  48. package/src/pi-takomi-core/workflows.ts +86 -45
  49. package/src/skills-catalog.js +2 -202
  50. 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 !== "direct" && mode !== "orchestrate" && mode !== "review") {
51
- ctx.ui.notify("Usage: /takomi mode <direct|orchestrate|review>", "warning");
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 === "direct") {
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
- state.role = "review";
79
- state.stage = undefined;
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 = gate === "review" ? "manual" : "auto";
96
- state.autoOrch = gate === "auto";
97
- }, () => `Takomi execution gate set to ${gate}`);
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 preview = previewTakomiRoutingPolicy(ctx.cwd, policyText, { scope });
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 policy extraction before it is saved.",
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 like GPT-5.5 are routing intent unless a preferred provider/router is declared.",
183
- "- Valid Takomi roles are: general, orchestrator, architect, designer, coder, reviewer.",
184
- "- If the extraction is correct and safe, call takomi_apply_routing_policy with the exact policyText and scope below.",
185
- "- If it is ambiguous or wrong, explain what the user should clarify and do not call the tool.",
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 extraction prepared. Sending it to the active model for review before saving.", "info");
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
+ }