takomi 2.1.27 → 2.1.28

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.
@@ -84,6 +84,9 @@ const STATE_ENTRY = "takomi-runtime-state";
84
84
 
85
85
  let activeProfile: TakomiProfile = DEFAULT_TAKOMI_PROFILE;
86
86
  let activeSubagentLabel: string | undefined;
87
+ let activeSubagentAgent: string | undefined;
88
+ let activeSubagentTask: string | undefined;
89
+ let activeSubagentStatus: string | undefined;
87
90
 
88
91
  const ThinkingSchema = Type.Union([
89
92
  Type.Literal("off"),
@@ -665,18 +668,27 @@ export default function takomiRuntime(pi: ExtensionAPI) {
665
668
  launchMode: state.launchMode,
666
669
  planMode: state.planMode,
667
670
  activeSubagent: activeSubagentLabel,
671
+ activeSubagentAgent,
672
+ activeSubagentTask,
673
+ activeSubagentStatus,
668
674
  });
669
675
  }
670
676
 
671
677
  async function applySubagentRuntimeEvent(event: TakomiSubagentRuntimeEvent, ctx: ExtensionContext): Promise<void> {
672
678
  if (event.type === "start") {
673
679
  activeSubagentLabel = `${event.state.agent}: ${event.state.taskLabel}`;
680
+ activeSubagentAgent = event.state.agent;
681
+ activeSubagentTask = event.state.taskLabel;
682
+ activeSubagentStatus = event.state.status ?? "running";
674
683
  syncContextPanelState();
675
684
  } else if ((event.type === "update" || event.type === "complete" || event.type === "block") && event.patch) {
676
685
  const model = event.patch.model ? ` @ ${event.patch.model}` : "";
677
686
  const thinking = event.patch.thinking ? ` (${event.patch.thinking})` : "";
678
687
  const label = event.patch.summary?.split(/\r?\n/).find(Boolean);
679
688
  if (label) activeSubagentLabel = `${label}${model}${thinking}`;
689
+ if (event.patch.agent) activeSubagentAgent = event.patch.agent;
690
+ if (event.patch.taskLabel) activeSubagentTask = event.patch.taskLabel;
691
+ activeSubagentStatus = event.type === "complete" ? "completed" : event.type === "block" ? "blocked" : event.patch.status ?? activeSubagentStatus;
680
692
  syncContextPanelState();
681
693
  }
682
694
  switch (event.type) {
@@ -761,6 +773,9 @@ export default function takomiRuntime(pi: ExtensionAPI) {
761
773
  await updateState(ctx, () => {
762
774
  state = cloneState(DEFAULT_STATE);
763
775
  activeSubagentLabel = undefined;
776
+ activeSubagentAgent = undefined;
777
+ activeSubagentTask = undefined;
778
+ activeSubagentStatus = undefined;
764
779
  }, "Takomi runtime state reset");
765
780
  subagentController.reset(ctx);
766
781
  contextPanel.resetSession();
@@ -1202,6 +1217,24 @@ ${stateJson}`
1202
1217
  }
1203
1218
 
1204
1219
  const routingPolicy = await resolveTakomiRoutingPolicy(runtimeCwd);
1220
+ const optionalFeatureContext = (() => {
1221
+ try {
1222
+ const tools = typeof (pi as { getAllTools?: () => Array<{ name?: string }> }).getAllTools === "function"
1223
+ ? (pi as { getAllTools: () => Array<{ name?: string }> }).getAllTools()
1224
+ : [];
1225
+ const toolNames = new Set(tools.map((tool) => tool.name).filter(Boolean));
1226
+ const guidance: string[] = [];
1227
+ if (toolNames.has("ask_user_question")) {
1228
+ guidance.push("Takomi Interview is available: when Genesis, Design, or ambiguous planning would otherwise require guessing, use ask_user_question to ask concise structured questions before proceeding.");
1229
+ }
1230
+ if (toolNames.has("todo")) {
1231
+ guidance.push("Takomi Todo is available as an optional live overlay. You may use todo for short-lived execution visibility, but takomi_board remains the durable lifecycle/task source of truth.");
1232
+ }
1233
+ return guidance.join("\n");
1234
+ } catch {
1235
+ return "";
1236
+ }
1237
+ })();
1205
1238
  const modelPreflightContext = (() => {
1206
1239
  try {
1207
1240
  const available = typeof (ctx as { modelRegistry?: { getAvailable?: () => Array<{ provider?: string; id?: string; name?: string }> } }).modelRegistry?.getAvailable === "function"
@@ -1223,6 +1256,7 @@ ${stateJson}`
1223
1256
  routingPolicy.text
1224
1257
  ? `${routingPolicy.source === "bundled" ? "Bundled" : "Project"} Takomi model routing policy is active. Apply it when choosing parent/subagent models and escalation levels:\n\n${routingPolicy.text}`
1225
1258
  : "No Takomi routing policy file was found. Users can install one with `/takomi routing <policy>` or by saying `Update Takomi routing logic: \"\"\"...\"\"\"`.",
1259
+ optionalFeatureContext,
1226
1260
  modelPreflightContext,
1227
1261
  `Execution mode: ${route.executionMode}. Session recommendation: ${route.sessionRecommendation}.`,
1228
1262
  `Takomi execution gate: ${effectiveState.launchMode === "manual" ? "review" : "auto"}. In review gate mode, show the delegation plan before launching and return to the user after each task with results, verification guidance, and the recommended next step.`,
@@ -1257,8 +1291,10 @@ ${stateJson}`
1257
1291
  runtimeCtx = ctx;
1258
1292
  activeProfile = await loadTakomiProfile(ctx.cwd);
1259
1293
  activeSubagentLabel = undefined;
1294
+ activeSubagentAgent = undefined;
1295
+ activeSubagentTask = undefined;
1296
+ activeSubagentStatus = undefined;
1260
1297
  subagentController.reset(ctx);
1261
- contextPanel.resetSession();
1262
1298
  const entries = ctx.sessionManager.getEntries();
1263
1299
  for (let i = entries.length - 1; i >= 0; i--) {
1264
1300
  const entry = entries[i] as { type: string; customType?: string; data?: TakomiState };
@@ -1278,6 +1314,7 @@ ${stateJson}`
1278
1314
  }
1279
1315
 
1280
1316
  syncContextPanelState();
1317
+ contextPanel.rebuildFromSession(ctx);
1281
1318
  await refreshUi(ctx, state);
1282
1319
  contextPanel.show(ctx);
1283
1320
  flushPendingSubagentEvents();
@@ -40,6 +40,28 @@ function cost(model, input, cache, output, additiveCache = true) { const p = PRI
40
40
  function fmtTokens(n) { if (n >= 1e9) return `${(n/1e9).toFixed(2)}B`; if (n >= 1e6) return `${(n/1e6).toFixed(1)}M`; if (n >= 1e3) return `${(n/1e3).toFixed(1)}K`; return String(Math.round(n || 0)); }
41
41
  function fmtMoney(n) { return `$${(n || 0).toFixed(n > 100 ? 0 : 2)}`; }
42
42
  function ms(n) { if (!n) return '-'; const s = Math.round(n/1000); if (s < 60) return `${s}s`; const m = Math.floor(s/60); if (m < 60) return `${m}m ${s%60}s`; const h = Math.floor(m/60); return `${h}h ${m%60}m`; }
43
+ const ACTIVE_GAP_THRESHOLD_MS = 15 * 60 * 1000;
44
+ function timestampMs(value) {
45
+ if (typeof value === 'number') return Number.isFinite(value) ? value : null;
46
+ if (typeof value === 'string' && value) {
47
+ const parsed = Date.parse(value);
48
+ return Number.isFinite(parsed) ? parsed : null;
49
+ }
50
+ return null;
51
+ }
52
+ function addTimestamp(target, value) {
53
+ const parsed = timestampMs(value);
54
+ if (parsed !== null) target.push(parsed);
55
+ }
56
+ function activeDuration(timestamps, maxGapMs = ACTIVE_GAP_THRESHOLD_MS) {
57
+ const sorted = [...new Set((timestamps || []).filter(Number.isFinite))].sort((a, b) => a - b);
58
+ let total = 0;
59
+ for (let i = 1; i < sorted.length; i += 1) {
60
+ const delta = sorted[i] - sorted[i - 1];
61
+ if (delta > 0 && delta <= maxGapMs) total += delta;
62
+ }
63
+ return total;
64
+ }
43
65
  function parseSince(value) {
44
66
  if (!value) return null;
45
67
  const raw = String(value).trim().toLowerCase();
@@ -88,14 +110,20 @@ async function files(root, suffix = '.jsonl') {
88
110
  await walk(root); return out;
89
111
  }
90
112
 
113
+ function pushTask(taskRows, task) {
114
+ if (!task?.end || task.end === task.start) return;
115
+ task.activeMs = activeDuration(task.activityTimestamps || []);
116
+ taskRows.push(task);
117
+ }
118
+
91
119
  async function scanPiSessions(root, source, events, sessionRows = [], taskRows = []) {
92
120
  for (const file of await files(root)) {
93
121
  let provider = 'unknown', model = 'unknown', session = path.basename(file, '.jsonl'), cwd = '', currentTask = null;
94
- const row = { key: session, session, source, file, project: projectKey(file), cwd, start: '', end: '', turns: 0, messages: 0, toolCalls: 0, subagentCalls: 0, roles: new Map(), stages: new Map(), workflows: new Map(), activeMs: 0 };
122
+ const row = { key: session, session, source, file, project: projectKey(file), cwd, start: '', end: '', turns: 0, messages: 0, toolCalls: 0, subagentCalls: 0, roles: new Map(), stages: new Map(), workflows: new Map(), activeMs: 0, activityTimestamps: [] };
95
123
  const text = await fs.readFile(file, 'utf8').catch(() => '');
96
124
  for (const line of text.split(/\r?\n/)) {
97
125
  const obj = safeJson(line); if (!obj) continue;
98
- if (obj.timestamp) { row.start ||= obj.timestamp; row.end = obj.timestamp; }
126
+ if (obj.timestamp) { row.start ||= obj.timestamp; row.end = obj.timestamp; addTimestamp(row.activityTimestamps, obj.timestamp); }
99
127
  if (obj.type === 'session') { session = obj.id || session; cwd = obj.cwd || cwd; row.key = session; row.session = session; row.cwd = cwd; }
100
128
  if (obj.type === 'model_change') { provider = obj.provider || provider; model = obj.modelId || model; }
101
129
  if (obj.type === 'custom' && obj.customType === 'takomi-runtime-state' && obj.data) {
@@ -112,12 +140,14 @@ async function scanPiSessions(root, source, events, sessionRows = [], taskRows =
112
140
  row.messages += 1;
113
141
  const ts = obj.timestamp || msg.timestamp || '';
114
142
  if (msg.role === 'user') {
115
- if (currentTask?.end && currentTask.end !== currentTask.start) taskRows.push(currentTask);
143
+ pushTask(taskRows, currentTask);
116
144
  row.turns += 1;
117
145
  const textPart = (msg.content || []).find(p => p?.type === 'text')?.text || '';
118
- currentTask = { source, file, session, project: projectKey(file), cwd, start: ts, end: ts, provider, model, turns: 1, toolCalls: 0, title: String(textPart).replace(/\s+/g, ' ').trim() };
146
+ currentTask = { source, file, session, project: projectKey(file), cwd, start: ts, end: ts, provider, model, turns: 1, toolCalls: 0, title: String(textPart).replace(/\s+/g, ' ').trim(), activityTimestamps: [] };
147
+ addTimestamp(currentTask.activityTimestamps, ts);
119
148
  } else if (currentTask && ts) {
120
149
  currentTask.end = ts;
150
+ addTimestamp(currentTask.activityTimestamps, ts);
121
151
  }
122
152
  for (const part of msg.content || []) {
123
153
  if (!part || part.type !== 'toolCall') continue;
@@ -135,8 +165,8 @@ async function scanPiSessions(root, source, events, sessionRows = [], taskRows =
135
165
  const u = msg && msg.usage;
136
166
  if (u) events.push({ source, file, timestamp: obj.timestamp, day: dayOf(obj.timestamp), session, provider, model, project: projectKey(file), kind: 'usage', input: +u.input||0, cache: +u.cacheRead||0, output: +u.output||0, total: +u.totalTokens||0, cost: cost(model, +u.input||0, +u.cacheRead||0, +u.output||0, true) });
137
167
  }
138
- if (currentTask?.end && currentTask.end !== currentTask.start) taskRows.push(currentTask);
139
- row.activeMs = taskRows.filter(t => t.file === file).reduce((sum, t) => sum + taskDuration(t), 0);
168
+ pushTask(taskRows, currentTask);
169
+ row.activeMs = activeDuration(row.activityTimestamps);
140
170
  if (row.messages || row.toolCalls || row.turns) sessionRows.push(row);
141
171
  }
142
172
  }
@@ -336,9 +366,7 @@ function sessionDuration(row) {
336
366
  return row?.activeMs || 0;
337
367
  }
338
368
  function taskDuration(row) {
339
- const start = Date.parse(row?.start || '');
340
- const end = Date.parse(row?.end || '');
341
- return Number.isFinite(start) && Number.isFinite(end) && end >= start ? end - start : 0;
369
+ return row?.activeMs ?? activeDuration(row?.activityTimestamps || []);
342
370
  }
343
371
  function taskLabel(row, width = 34) {
344
372
  const label = row?.title || row?.project || row?.session || 'unknown';
@@ -379,7 +407,7 @@ function renderFocusedView(stats, opts = {}) {
379
407
  ` ${pc.cyan(ms(sessionDuration(r)))} ${pc.dim(r.turns + ' turns')} ${pc.dim(r.toolCalls + ' tools')}`,
380
408
  ` ${pc.dim(r.file || '')}`,
381
409
  ].join('\n'), limit);
382
- if (view === 'tasks-full' || view === 'task-full') return renderFullList('Longest Tasks — Full Prompts', stats.topTasks || [], (r, i) => [
410
+ if (view === 'tasks-full' || view === 'task-full') return renderFullList('Longest Active Turns — Full Prompts', stats.topTasks || [], (r, i) => [
383
411
  ` ${pc.dim(String(i + 1).padStart(2, '0') + '.')} ${pc.cyan(ms(taskDuration(r)))} ${pc.magenta(r.toolCalls + ' tools')} ${pc.dim(dayOf(r.start))}`,
384
412
  ` ${pc.white(indentWrap(r.title || r.project || r.session || 'unknown'))}`,
385
413
  ` ${pc.dim(r.project || '')}`,
@@ -426,7 +454,7 @@ function renderFocusedView(stats, opts = {}) {
426
454
  { width: 8, align: 'right', get: r => pc.cyan(String(r.toolCalls)) },
427
455
  { width: 8, align: 'left', get: () => pc.dim('tools') },
428
456
  ]],
429
- tasks: ['Longest Tasks', stats.topTasks || [], [
457
+ tasks: ['Longest Active Turns', stats.topTasks || [], [
430
458
  { width: 6, align: 'left', get: r => pc.dim(dayOf(r.start).slice(5)) },
431
459
  { width: 9, align: 'right', get: r => pc.cyan(ms(taskDuration(r))) },
432
460
  { width: 11, align: 'right', get: r => pc.magenta(`${r.toolCalls} tools`) },
@@ -518,9 +546,9 @@ export function renderTakomiStats(stats, opts = {}) {
518
546
  // ── Duration Cards ────────────────────────────────────────────────────
519
547
  lines.push('');
520
548
  const cards3 = [
521
- statCard(longestSession ? ms(sessionDuration(longestSession)) : '-', 'Active Session', pc.cyan),
549
+ statCard(longestSession ? ms(sessionDuration(longestSession)) : '-', 'Top Active Session', pc.cyan),
522
550
  statCard(longestSession ? String(longestSession.turns) : '-', 'Turns in Session', pc.cyan),
523
- statCard(longestTask ? ms(taskDuration(longestTask)) : '-', 'Longest Task', pc.magenta),
551
+ statCard(longestTask ? ms(taskDuration(longestTask)) : '-', 'Longest Active Turn', pc.magenta),
524
552
  statCard(longestTask ? String(longestTask.toolCalls) : '-', 'Tools in Task', pc.magenta),
525
553
  statCard(stats.mostSubagentsSession ? String(stats.mostSubagentsSession.subagentCalls) : '0', 'Max Subagents', pc.blue),
526
554
  ];
@@ -530,7 +558,7 @@ export function renderTakomiStats(stats, opts = {}) {
530
558
 
531
559
  // ── Info line ─────────────────────────────────────────────────────────
532
560
  lines.push('');
533
- const infoText = `Peak: ${peak?.key || '-'} · ${streaks.quietDays} quiet days · ${stats.totals.events.toLocaleString()} events${stats.since ? ` · since ${stats.since}` : ''}`;
561
+ const infoText = `Peak: ${peak?.key || '-'} · ${streaks.quietDays} quiet days · ${stats.totals.events.toLocaleString()} events · active gaps ≤15m${stats.since ? ` · since ${stats.since}` : ''}`;
534
562
  lines.push(center(pc.dim(infoText), W));
535
563
 
536
564
  lines.push('');
@@ -586,10 +614,10 @@ export function renderTakomiStats(stats, opts = {}) {
586
614
  ]));
587
615
  }
588
616
 
589
- // ── Longest Tasks ──────────────────────────────────────────────────────
617
+ // ── Longest Active Turns ───────────────────────────────────────────────
590
618
  if (stats.topTasks?.length) {
591
619
  lines.push('');
592
- lines.push(renderTable('Longest Tasks', stats.topTasks.slice(0, 5), [
620
+ lines.push(renderTable('Longest Active Turns', stats.topTasks.slice(0, 5), [
593
621
  { width: 6, align: 'left', get: r => pc.dim(dayOf(r.start).slice(5)) },
594
622
  { width: 9, align: 'right', get: r => pc.cyan(ms(taskDuration(r))) },
595
623
  { width: 11, align: 'right', get: r => pc.magenta(`${r.toolCalls} tools`) },
package/README.md CHANGED
@@ -29,6 +29,11 @@ Optional global skills:
29
29
 
30
30
  ```bash
31
31
  takomi setup skills
32
+ # First install defaults to Core Skills.
33
+ # Repeat installs default to Leave As Is so existing selections are not pruned accidentally.
34
+ # Custom opens a color-coded category TUI with expandable skill rows when a TTY is available.
35
+ # Optional Pi feature packs can also be managed later:
36
+ takomi setup pi-features
32
37
  ```
33
38
 
34
39
  Useful management commands:
@@ -43,6 +48,8 @@ takomi setup project
43
48
 
44
49
  Legacy commands like `takomi install pi`, `takomi sync pi`, `takomi upgrade`, and `takomi init` still work, but the simpler mental model is: **setup once, refresh when stale, run `takomi` to use it.**
45
50
 
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
+
46
53
  ### Context Manager
47
54
 
48
55
  Takomi now ships a Pi-native `takomi-context-manager` extension. It reduces prompt bloat with progressive context loading:
@@ -69,7 +76,8 @@ npx takomi install
69
76
  What happens next:
70
77
  - 🔍 **Auto-detects** every AI harness on your machine
71
78
  - 📦 **Creates your command center** at `~/.takomi/`
72
- - 📡 **Syncs your entire toolkit** to every IDE automatically
79
+ - 🧰 **Lets you choose Core, Present Custom, Custom, All, or Leave As Is for skills**
80
+ - 📡 **Syncs your selected toolkit** to every IDE automatically
73
81
  - 🔄 **Keeps KiloCode in sync** across CLI and VS Code
74
82
 
75
83
  ### Option B: Per-Project Setup
@@ -118,7 +126,9 @@ Original Takomi-authored skills in this bundle include `21st-dev-components`, `t
118
126
 
119
127
  Think of skills as specialized team members you can summon on demand. From security audits to AI video generation — there's a skill for that.
120
128
 
121
- The published bundle currently ships **69 top-level skills**, including the original `21st-dev-components` workflow for guided 21st.dev integration. The `pr-comment-fix` skill is sourced from https://gist.github.com/GSonofNun/35c67304c35dac7d6b43308b5371f671.
129
+ Takomi's own installer no longer installs every bundled skill by default. `takomi setup skills` uses **Core Skills** for first-time installs, **Leave As Is** for repeat installs, and ownership-safe cleanup when you explicitly deselect Takomi-managed skills. Manual/user-added skills are preserved. Custom selection opens a color-coded category browser with expandable rows on capable terminals, and falls back to simple prompts elsewhere. The global store/harness sync path uses the same ownership model so deselected Takomi-managed skills and workflows can be pruned from `~/.takomi/` and synced harness folders without touching manual or imported resources.
130
+
131
+ The published bundle currently ships **72 top-level skills**, including the original `21st-dev-components` workflow for guided 21st.dev integration. The `pr-comment-fix` skill is sourced from https://gist.github.com/GSonofNun/35c67304c35dac7d6b43308b5371f671.
122
132
 
123
133
  ### Interactive Search & Install
124
134
  ```bash
@@ -130,7 +140,22 @@ npx -y skills add https://github.com/JStaRFilms/VibeCode-Protocol-Suite
130
140
  ```
131
141
 
132
142
  ### Core Essentials (Start Here)
133
- The non-negotiables for daily development:
143
+ The recommended Takomi installer defaults are:
144
+
145
+ ```txt
146
+ takomi
147
+ sync-docs
148
+ code-review
149
+ security-audit
150
+ optimize-agent-context
151
+ agent-recovery
152
+ avoid-feature-creep
153
+ ai-sdk
154
+ git-commit-generation
155
+ ```
156
+
157
+ For the external `skills` CLI, install only the router skill if you want the smallest possible footprint:
158
+
134
159
  ```bash
135
160
  npx -y skills add https://github.com/JStaRFilms/VibeCode-Protocol-Suite --skill takomi
136
161
  ```
@@ -466,8 +491,9 @@ This is a living system. If you discover improvements:
466
491
 
467
492
  ## 🙏 Acknowledgements
468
493
 
469
- Externally sourced skills in this bundle retain credit to their upstream creators. Takomi-original skills and workflows in this repository, including `21st-dev-components`, remain authored and maintained by J StaR Films Studios.
494
+ Externally sourced skills and optional Pi packages retain credit to their upstream creators. Takomi-original skills, workflows, and Takomi runtime/orchestration extensions in this repository, including `21st-dev-components`, remain authored and maintained by J StaR Films Studios.
470
495
 
496
+ - **Pi Coding Agent**: Built for [Pi](https://github.com/earendil-works/pi) / `@earendil-works/pi-coding-agent` by **Mario Zechner** and Earendil Works — the MIT-licensed coding-agent runtime and extension API that powers the Pi-native Takomi harness.
471
497
  - **Anthropic Skills**: From [anthropics/skills](https://github.com/anthropics/skills) — a massive collection including **Office Suite** (PDF/DOCX/PPTX/XLSX), **Frontend Design**, **Webapp Testing**, **Algorithmic Art**, **Monorepo Management**, and **Skill Creator**.
472
498
  - **Inference.sh Skills**: From [inference.sh/skills](https://github.com/inference-sh/skills) — complete media & automation suite including **Marketing Videos**, **Voice Cloning**, **Social Content**, **Twitter Automation**, **Product Photography**, and **Prompt Engineering**.
473
499
  - **Marketing Skills**: From [coreyhaines31/marketingskills](https://github.com/coreyhaines31/marketingskills) — the complete marketer's toolkit: **Copywriting**, **Pricing Strategy**, **Social Strategy**, **Programmatic SEO**, and **Marketing Ideas**.
@@ -483,6 +509,10 @@ Externally sourced skills in this bundle retain credit to their upstream creator
483
509
  - **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**.
484
510
  - **Jules**: From [sanjay3290/ai-skills](https://github.com/sanjay3290/ai-skills) — delegate coding tasks to Google Jules AI agent.
485
511
  - **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.
512
+ - **Takomi Interview / Todo Optional Packs**: Optional setup integrates **[`@juicesharp/rpiv-ask-user-question`](https://github.com/juicesharp/rpiv-mono/tree/main/packages/rpiv-ask-user-question)** and **[`@juicesharp/rpiv-todo`](https://github.com/juicesharp/rpiv-mono/tree/main/packages/rpiv-todo)** by **juicesharp** — MIT-licensed Pi extensions for structured user questions and live todo overlays.
513
+ - **Takomi Browser QA Optional Pack**: Optional setup can install **[`pi-chrome`](https://github.com/tianrendong/pi-chrome)** by **tianrendong** — an MIT-licensed Pi extension for explicitly authorized Chrome/browser automation.
514
+ - **Takomi Doc Preview Optional Pack**: Optional setup can install **[`pi-markdown-preview`](https://github.com/omaclaren/pi-markdown-preview)** by **omaclaren** — an MIT-licensed Pi extension for terminal/browser/PDF markdown and LaTeX previews.
515
+ - **Context Mode Research / Optional Power User Tooling**: **[`context-mode`](https://github.com/mksglu/context-mode)** by **Mert Koseoğlu** is credited as an external context-window and session-continuity project. It is not bundled as a Takomi default; users can install/evaluate it separately under its own license.
486
516
  - **Git Commit Generation**: From the **[`kilocode`](https://github.com/Kilo-Org/kilocode)** repository by **Kilo-Org** (specifically, [git-commit-generation.md](https://github.com/Kilo-Org/kilocode/blob/main/packages/kilo-docs/pages/code-with-ai/features/git-commit-generation.md)) — enabling automated, high-quality conventional git commit messages based on staged changes.
487
517
 
488
518
  ## 📄 License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "takomi",
3
- "version": "2.1.27",
3
+ "version": "2.1.28",
4
4
  "description": "🎯 Stop wrestling with AI. Start building with purpose. The artisan's toolkit for agent workflows, Codex skills, and original Takomi capabilities like 21st.dev integration.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -22,7 +22,9 @@
22
22
  ".pi/takomi/policies"
23
23
  ],
24
24
  "scripts": {
25
- "test": "echo \"Error: no test specified\" && exit 1"
25
+ "postinstall": "node src/postinstall.js",
26
+ "test": "echo \"Error: no test specified\" && exit 1",
27
+ "test:skills": "node scripts/test-skill-selection.js"
26
28
  },
27
29
  "repository": {
28
30
  "type": "git",