takomi 2.1.36 → 2.1.38
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/agents/orchestrator.md +9 -5
- 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-subagents/index.ts +30 -3
- package/.pi/extensions/takomi-subagents/native-render.ts +3 -1
- package/.pi/extensions/takomi-subagents/pi-subagents-engine.ts +18 -3
- package/.pi/extensions/takomi-subagents/tool-runner.ts +38 -3
- package/.pi/prompts/takomi-prompt.md +6 -4
- package/.pi/takomi/policies/subagent-routing.md +9 -1
- package/.pi/takomi/policies/takomi-lifecycle-routing.md +3 -1
- package/README.md +22 -11
- 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 +38 -1
- package/src/doctor.js +7 -1
- package/src/pi-harness.js +96 -0
package/.pi/README.md
CHANGED
|
@@ -37,7 +37,8 @@ Inside Pi, use:
|
|
|
37
37
|
- `/takomi gate auto` to continue approved plans automatically
|
|
38
38
|
- `/takomi gate review` to return to the user after each task with results and verification guidance
|
|
39
39
|
- `/takomi subagents on` or `/takomi subagents off` to allow or disable delegated subagents
|
|
40
|
-
- `/takomi subagents
|
|
40
|
+
- `/takomi subagents list` to list available Takomi agents without exposing the raw `subagent` tool
|
|
41
|
+
- `/takomi subagents status` to inspect active subagent state
|
|
41
42
|
- `/takomi-status` to show lifecycle, gate, session, and active subagent state
|
|
42
43
|
- `/takomi-reset` to reset session-local Takomi runtime state
|
|
43
44
|
- `/context-report` to inspect prompt compaction, skill loading, policy gates, model routing corrections, and duplicate extension diagnostics
|
|
@@ -107,9 +108,9 @@ So when working on packaging, agents should distinguish between:
|
|
|
107
108
|
- Task packets can carry `workflow`, `skills`, `preferredModel`, `fallbackModels`, `preferredThinking`, `executionHint`, `conversationId`, and `checklist` metadata.
|
|
108
109
|
- Direct `takomi_subagent` calls build a `TakomiDelegationPlan` before launch. In auto mode the plan launches immediately; in manual mode the plan is returned for review until `confirmLaunch=true` is supplied.
|
|
109
110
|
- The subagent tool supports `conversationId`, so reviewed work can be sent back to the same agent for continuation instead of restarting from scratch.
|
|
110
|
-
- The subagent tool supports Pi-style single, parallel `tasks`,
|
|
111
|
+
- The subagent tool supports Pi-style single, parallel `tasks`, sequential `chain`, explicit `context=fork|fresh`, `async=true`, and native read/control actions such as `action=list`, `action=status`, `action=doctor`, `action=interrupt`, and `action=resume`.
|
|
111
112
|
- The subagent tool supports `agentScope` values of `user`, `project`, and `both`; project-local agents require confirmation by default.
|
|
112
|
-
- The subagent tool also supports per-run `workflow`, `skills`, `model`, `fallbackModels`, `thinking`, and `
|
|
113
|
+
- The subagent tool also supports per-run `workflow`, `skills`, `model`, `fallbackModels`, `thinking`, `checklist`, `concurrency`, and `worktree` overrides.
|
|
113
114
|
- `takomi_board` records session/state/markdown artifacts only; it does not run subagents.
|
|
114
115
|
- Pi's default `subagent` tool remains owned by the user-level/default subagent extension to avoid tool-name conflicts; Takomi uses `takomi_subagent` as the preferred lifecycle-aware execution interface and renders it with the native Pi-style result surface.
|
|
115
116
|
- Treat raw `subagent` usage as advanced/internal. Normal Takomi lifecycle execution should go through `takomi_subagent`, then `takomi_board update_task` should record the outcome.
|
|
@@ -121,6 +122,8 @@ So when working on packaging, agents should distinguish between:
|
|
|
121
122
|
- `takomi-context-manager` gates `takomi_subagent` when model-routing context has not been loaded, provides the routing policy, and tells the agent to retry.
|
|
122
123
|
- `takomi-context-manager` can correct safe wrong-provider model requests, block or pause on policy violations, and ask the user whether to retry with an approved model or stop.
|
|
123
124
|
- `takomi-context-manager` detects known duplicate global/project Takomi extension paths in `context_report` to help diagnose tool registration conflicts.
|
|
125
|
+
- `context_report` restores context-manager snapshots and Pi tool-result history after reload/restart and explicitly labels gaps; it is not a replacement for Pi's Alt-C token/session stats.
|
|
126
|
+
- `context_report` defaults to compact `mode: "summary"`; use `mode: "verbose"` for full diagnostics or `mode: "problems"` for attention-only output. `verbose: true` remains a compatibility alias. `/context-report` exposes `summary`, `verbose`, and `problems` as slash-command argument completions.
|
|
124
127
|
- `takomi_board` can:
|
|
125
128
|
- create a Genesis-first lifecycle session by default
|
|
126
129
|
- preserve authored `master_plan.md` and task packet markdown
|
|
@@ -106,11 +106,15 @@ Before calling `takomi_board expand_stage`:
|
|
|
106
106
|
- Do not leave generated task files with `Scope: None specified`, `Definition Of Done: None specified`, or `Expected Artifacts: None specified`.
|
|
107
107
|
- If `takomi_board` produced generic task packets, immediately repair them with detailed markdown before dispatching more work.
|
|
108
108
|
|
|
109
|
-
## Phase 4: Delegation
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
-
|
|
113
|
-
|
|
109
|
+
## Phase 4: Delegation
|
|
110
|
+
After decomposition, delegation is the default execution path. Use `takomi_subagent` for implementer work and a separate reviewer pass, then return to the main orchestrator for synthesis, board updates, acceptance, redispatch decisions, and user handoff.
|
|
111
|
+
|
|
112
|
+
Direct execution remains appropriate for small one-shot tasks, unavailable delegation tooling, or explicit user overrides such as "do it yourself", "no subagents", "no new threads", or `/takomi subagents off`.
|
|
113
|
+
|
|
114
|
+
When delegating:
|
|
115
|
+
- send self-contained task instructions
|
|
116
|
+
- include required workflow and relevant context
|
|
117
|
+
- preserve conversation IDs for review loops
|
|
114
118
|
- keep retries scoped and actionable
|
|
115
119
|
- do not overload a subagent with unrelated work
|
|
116
120
|
|
|
@@ -273,13 +273,14 @@ export function formatUsageRawReport(runtime: RouterRuntime, accountId?: string)
|
|
|
273
273
|
return ["# oauth-router usage raw", "", ...rows].join("\n");
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
-
function emitReport(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
});
|
|
276
|
+
function emitReport(ctx: ExtensionCommandContext, text: string) {
|
|
277
|
+
const lines = text.split(/\r?\n/);
|
|
278
|
+
const visibleLines = [
|
|
279
|
+
"oauth-router report (UI-only; not sent to the agent)",
|
|
280
|
+
...lines,
|
|
281
|
+
];
|
|
282
|
+
ctx.ui.setWidget("oauth-router-report", visibleLines, { placement: "belowEditor" });
|
|
283
|
+
ctx.ui.notify(lines[0] || "oauth-router report updated", "info");
|
|
283
284
|
}
|
|
284
285
|
|
|
285
286
|
async function pickUpstream(runtime: RouterRuntime, ctx: ExtensionCommandContext, requestedId?: string) {
|
|
@@ -388,12 +389,12 @@ function setFooterStatus(ctx: ExtensionCommandContext, runtime: RouterRuntime) {
|
|
|
388
389
|
ctx.ui.setStatus("oauth-router", `oauth-router ${healthy}/${rows.length || 0} healthy | ${runtime.getPolicy()}`);
|
|
389
390
|
}
|
|
390
391
|
|
|
391
|
-
function showCommandHint(
|
|
392
|
-
emitReport(
|
|
392
|
+
function showCommandHint(ctx: ExtensionCommandContext, title: string, lines: string[]) {
|
|
393
|
+
emitReport(ctx, [`# ${title}`, "", ...lines].join("\n"));
|
|
393
394
|
ctx.ui.notify(title, "info");
|
|
394
395
|
}
|
|
395
396
|
|
|
396
|
-
async function handleRouterLogin(
|
|
397
|
+
async function handleRouterLogin(runtime: RouterRuntime, args: string, ctx: ExtensionCommandContext) {
|
|
397
398
|
const [command = "help", first, ...rest] = parseArgs(args);
|
|
398
399
|
|
|
399
400
|
switch (command) {
|
|
@@ -418,18 +419,18 @@ async function handleRouterLogin(pi: ExtensionAPI, runtime: RouterRuntime, args:
|
|
|
418
419
|
runtime.clearAccountHealth(duplicate.id);
|
|
419
420
|
const usageMessage = await refreshUsageAfterCredentialChange(runtime, duplicate.id);
|
|
420
421
|
setFooterStatus(ctx, runtime);
|
|
421
|
-
emitReport(
|
|
422
|
+
emitReport(ctx, `Updated existing account ${duplicate.id} (${duplicate.label}) with fresh credentials instead of adding a duplicate.${usageMessage}`);
|
|
422
423
|
return;
|
|
423
424
|
}
|
|
424
425
|
runtime.addAccount(account);
|
|
425
426
|
const usageMessage = await refreshUsageAfterCredentialChange(runtime, account.id);
|
|
426
427
|
setFooterStatus(ctx, runtime);
|
|
427
|
-
emitReport(
|
|
428
|
+
emitReport(ctx, `Added account ${account.id} (${account.label}) for upstream ${upstream.id}.${usageMessage}`);
|
|
428
429
|
ctx.ui.notify(`Added ${account.id}`, "info");
|
|
429
430
|
return;
|
|
430
431
|
}
|
|
431
432
|
case "list": {
|
|
432
|
-
emitReport(
|
|
433
|
+
emitReport(ctx, formatAccountsReport(runtime));
|
|
433
434
|
setFooterStatus(ctx, runtime);
|
|
434
435
|
return;
|
|
435
436
|
}
|
|
@@ -442,7 +443,7 @@ async function handleRouterLogin(pi: ExtensionAPI, runtime: RouterRuntime, args:
|
|
|
442
443
|
}
|
|
443
444
|
runtime.removeAccount(account.id);
|
|
444
445
|
setFooterStatus(ctx, runtime);
|
|
445
|
-
emitReport(
|
|
446
|
+
emitReport(ctx, `Removed account ${account.id}.`);
|
|
446
447
|
return;
|
|
447
448
|
}
|
|
448
449
|
case "rename": {
|
|
@@ -450,7 +451,7 @@ async function handleRouterLogin(pi: ExtensionAPI, runtime: RouterRuntime, args:
|
|
|
450
451
|
const label = await getRequiredLabel(ctx, account.label, rest.join(" "));
|
|
451
452
|
runtime.renameAccount(account.id, label);
|
|
452
453
|
setFooterStatus(ctx, runtime);
|
|
453
|
-
emitReport(
|
|
454
|
+
emitReport(ctx, `Renamed account ${account.id} to ${label}.`);
|
|
454
455
|
return;
|
|
455
456
|
}
|
|
456
457
|
case "relogin": {
|
|
@@ -475,7 +476,7 @@ async function handleRouterLogin(pi: ExtensionAPI, runtime: RouterRuntime, args:
|
|
|
475
476
|
runtime.clearAccountHealth(existing.id);
|
|
476
477
|
const usageMessage = await refreshUsageAfterCredentialChange(runtime, existing.id);
|
|
477
478
|
setFooterStatus(ctx, runtime);
|
|
478
|
-
emitReport(
|
|
479
|
+
emitReport(ctx, `Re-logged account ${existing.id} (${existing.label}) and cleared auth state.${usageMessage}`);
|
|
479
480
|
return;
|
|
480
481
|
}
|
|
481
482
|
case "refresh": {
|
|
@@ -483,13 +484,13 @@ async function handleRouterLogin(pi: ExtensionAPI, runtime: RouterRuntime, args:
|
|
|
483
484
|
const refreshed = await runtime.refreshAccount(account.id);
|
|
484
485
|
const usageMessage = await refreshUsageAfterCredentialChange(runtime, refreshed.id);
|
|
485
486
|
setFooterStatus(ctx, runtime);
|
|
486
|
-
emitReport(
|
|
487
|
+
emitReport(ctx, `Refreshed account ${refreshed.id} (${refreshed.label}).${usageMessage}`);
|
|
487
488
|
return;
|
|
488
489
|
}
|
|
489
490
|
case "help":
|
|
490
491
|
default: {
|
|
491
492
|
emitReport(
|
|
492
|
-
|
|
493
|
+
ctx,
|
|
493
494
|
[
|
|
494
495
|
"# oauth-router commands",
|
|
495
496
|
"",
|
|
@@ -519,13 +520,13 @@ async function handleRouterLogin(pi: ExtensionAPI, runtime: RouterRuntime, args:
|
|
|
519
520
|
export function registerRouterCommands(pi: ExtensionAPI, runtime: RouterRuntime) {
|
|
520
521
|
pi.registerCommand("router-login", {
|
|
521
522
|
description: "Manage oauth-router accounts",
|
|
522
|
-
handler: async (args, ctx) => handleRouterLogin(
|
|
523
|
+
handler: async (args, ctx) => handleRouterLogin(runtime, args || "", ctx),
|
|
523
524
|
});
|
|
524
525
|
|
|
525
526
|
pi.registerCommand("router-status", {
|
|
526
527
|
description: "Show oauth-router health and routing state",
|
|
527
528
|
handler: async (_args, ctx) => {
|
|
528
|
-
emitReport(
|
|
529
|
+
emitReport(ctx, formatStatusReport(runtime));
|
|
529
530
|
setFooterStatus(ctx, runtime);
|
|
530
531
|
},
|
|
531
532
|
});
|
|
@@ -533,7 +534,7 @@ export function registerRouterCommands(pi: ExtensionAPI, runtime: RouterRuntime)
|
|
|
533
534
|
pi.registerCommand("router-accounts", {
|
|
534
535
|
description: "Show compact oauth-router account list",
|
|
535
536
|
handler: async (_args, ctx) => {
|
|
536
|
-
emitReport(
|
|
537
|
+
emitReport(ctx, formatAccountsReport(runtime));
|
|
537
538
|
setFooterStatus(ctx, runtime);
|
|
538
539
|
},
|
|
539
540
|
});
|
|
@@ -542,7 +543,7 @@ export function registerRouterCommands(pi: ExtensionAPI, runtime: RouterRuntime)
|
|
|
542
543
|
description: "Show oauth-router visual provider quota and local usage",
|
|
543
544
|
handler: async (args, ctx) => {
|
|
544
545
|
const [id] = parseArgs(args || "");
|
|
545
|
-
emitReport(
|
|
546
|
+
emitReport(ctx, formatUsageReport(runtime, id));
|
|
546
547
|
setFooterStatus(ctx, runtime);
|
|
547
548
|
},
|
|
548
549
|
});
|
|
@@ -551,7 +552,7 @@ export function registerRouterCommands(pi: ExtensionAPI, runtime: RouterRuntime)
|
|
|
551
552
|
description: "Show raw oauth-router usage/provider quota details",
|
|
552
553
|
handler: async (args, ctx) => {
|
|
553
554
|
const [id] = parseArgs(args || "");
|
|
554
|
-
emitReport(
|
|
555
|
+
emitReport(ctx, formatUsageRawReport(runtime, id));
|
|
555
556
|
setFooterStatus(ctx, runtime);
|
|
556
557
|
},
|
|
557
558
|
});
|
|
@@ -560,7 +561,7 @@ export function registerRouterCommands(pi: ExtensionAPI, runtime: RouterRuntime)
|
|
|
560
561
|
description: "Alias for visual oauth-router usage/quota",
|
|
561
562
|
handler: async (args, ctx) => {
|
|
562
563
|
const [id] = parseArgs(args || "");
|
|
563
|
-
emitReport(
|
|
564
|
+
emitReport(ctx, formatUsageReport(runtime, id));
|
|
564
565
|
setFooterStatus(ctx, runtime);
|
|
565
566
|
},
|
|
566
567
|
});
|
|
@@ -583,7 +584,7 @@ export function registerRouterCommands(pi: ExtensionAPI, runtime: RouterRuntime)
|
|
|
583
584
|
}
|
|
584
585
|
|
|
585
586
|
const report = formatUsageReport(runtime, target === "all" ? undefined : target);
|
|
586
|
-
emitReport(
|
|
587
|
+
emitReport(ctx, failures.length ? [report, "", "## Refresh failures", ...failures].join("\n") : report);
|
|
587
588
|
if (failures.length) ctx.ui.notify(`oauth-router usage refreshed with ${failures.length} failure(s)`, "error");
|
|
588
589
|
setFooterStatus(ctx, runtime);
|
|
589
590
|
},
|
|
@@ -597,7 +598,7 @@ export function registerRouterCommands(pi: ExtensionAPI, runtime: RouterRuntime)
|
|
|
597
598
|
const label = await getRequiredLabel(ctx, account.label, labelParts.join(" "));
|
|
598
599
|
runtime.renameAccount(account.id, label);
|
|
599
600
|
setFooterStatus(ctx, runtime);
|
|
600
|
-
emitReport(
|
|
601
|
+
emitReport(ctx, `Renamed account ${account.id} to ${label}.`);
|
|
601
602
|
},
|
|
602
603
|
});
|
|
603
604
|
|
|
@@ -612,13 +613,13 @@ export function registerRouterCommands(pi: ExtensionAPI, runtime: RouterRuntime)
|
|
|
612
613
|
}
|
|
613
614
|
runtime.removeAccount(account.id);
|
|
614
615
|
setFooterStatus(ctx, runtime);
|
|
615
|
-
emitReport(
|
|
616
|
+
emitReport(ctx, `Deleted account ${account.id}.`);
|
|
616
617
|
},
|
|
617
618
|
});
|
|
618
619
|
|
|
619
620
|
pi.registerCommand("router-relogin", {
|
|
620
621
|
description: "Re-login and recover an oauth-router account",
|
|
621
|
-
handler: async (args, ctx) => handleRouterLogin(
|
|
622
|
+
handler: async (args, ctx) => handleRouterLogin(runtime, `relogin ${args || ""}`, ctx),
|
|
622
623
|
});
|
|
623
624
|
|
|
624
625
|
pi.registerCommand("router-enable", {
|
|
@@ -628,7 +629,7 @@ export function registerRouterCommands(pi: ExtensionAPI, runtime: RouterRuntime)
|
|
|
628
629
|
const account = await pickAccount(runtime, ctx, id, "Choose account to enable");
|
|
629
630
|
runtime.setEnabled(account.id, true);
|
|
630
631
|
setFooterStatus(ctx, runtime);
|
|
631
|
-
emitReport(
|
|
632
|
+
emitReport(ctx, `Enabled account ${account.id}.`);
|
|
632
633
|
},
|
|
633
634
|
});
|
|
634
635
|
|
|
@@ -639,7 +640,7 @@ export function registerRouterCommands(pi: ExtensionAPI, runtime: RouterRuntime)
|
|
|
639
640
|
const account = await pickAccount(runtime, ctx, id, "Choose account to disable");
|
|
640
641
|
runtime.setEnabled(account.id, false);
|
|
641
642
|
setFooterStatus(ctx, runtime);
|
|
642
|
-
emitReport(
|
|
643
|
+
emitReport(ctx, `Disabled account ${account.id}.`);
|
|
643
644
|
},
|
|
644
645
|
});
|
|
645
646
|
|
|
@@ -649,7 +650,7 @@ export function registerRouterCommands(pi: ExtensionAPI, runtime: RouterRuntime)
|
|
|
649
650
|
const raw = (args || "").trim();
|
|
650
651
|
const policy = normalizePolicy(raw);
|
|
651
652
|
if (!raw) {
|
|
652
|
-
showCommandHint(
|
|
653
|
+
showCommandHint(ctx, "router-policy", [
|
|
653
654
|
`Current policy: ${runtime.getPolicy()}`,
|
|
654
655
|
"",
|
|
655
656
|
"Usage: /router-policy <round-robin|weighted-round-robin>",
|
|
@@ -658,7 +659,7 @@ export function registerRouterCommands(pi: ExtensionAPI, runtime: RouterRuntime)
|
|
|
658
659
|
return;
|
|
659
660
|
}
|
|
660
661
|
if (!policy) {
|
|
661
|
-
showCommandHint(
|
|
662
|
+
showCommandHint(ctx, "router-policy", [
|
|
662
663
|
`Unrecognized policy: ${raw}`,
|
|
663
664
|
"",
|
|
664
665
|
`Current policy: ${runtime.getPolicy()}`,
|
|
@@ -668,7 +669,7 @@ export function registerRouterCommands(pi: ExtensionAPI, runtime: RouterRuntime)
|
|
|
668
669
|
}
|
|
669
670
|
runtime.setPolicy(policy);
|
|
670
671
|
setFooterStatus(ctx, runtime);
|
|
671
|
-
emitReport(
|
|
672
|
+
emitReport(ctx, `Routing policy set to ${policy}.`);
|
|
672
673
|
},
|
|
673
674
|
});
|
|
674
675
|
|
|
@@ -683,12 +684,12 @@ export function registerRouterCommands(pi: ExtensionAPI, runtime: RouterRuntime)
|
|
|
683
684
|
weight = Number(response);
|
|
684
685
|
}
|
|
685
686
|
if (!Number.isFinite(weight)) {
|
|
686
|
-
showCommandHint(
|
|
687
|
+
showCommandHint(ctx, "router-weight", ["Usage: /router-weight <id> <n>", "Example: /router-weight acct_ab12cd34 3"]);
|
|
687
688
|
return;
|
|
688
689
|
}
|
|
689
690
|
runtime.setWeight(account.id, weight);
|
|
690
691
|
setFooterStatus(ctx, runtime);
|
|
691
|
-
emitReport(
|
|
692
|
+
emitReport(ctx, `Updated weight for ${account.id} to ${Math.max(1, Math.floor(weight))}.`);
|
|
692
693
|
},
|
|
693
694
|
});
|
|
694
695
|
}
|
|
@@ -117,14 +117,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
117
117
|
installRouterUiBridge(pi, runtime, false);
|
|
118
118
|
|
|
119
119
|
pi.registerCommand("router-debug-report", {
|
|
120
|
-
description: "
|
|
121
|
-
handler: async () => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
120
|
+
description: "Show a detailed oauth-router report in the UI only",
|
|
121
|
+
handler: async (_args, ctx) => {
|
|
122
|
+
const report = formatStatusReport(runtime);
|
|
123
|
+
ctx.ui.setWidget("oauth-router-report", [
|
|
124
|
+
"oauth-router debug report (UI-only; not sent to the agent)",
|
|
125
|
+
...report.split(/\r?\n/),
|
|
126
|
+
], { placement: "belowEditor" });
|
|
127
|
+
ctx.ui.notify("oauth-router debug report updated", "info");
|
|
128
128
|
},
|
|
129
129
|
});
|
|
130
130
|
}
|
|
@@ -1,28 +1,61 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { AutocompleteItem } from "@earendil-works/pi-tui";
|
|
2
3
|
import { Type } from "typebox";
|
|
3
4
|
import type { ContextManagerState } from "./state";
|
|
4
|
-
import { renderReport } from "./diagnostics";
|
|
5
|
+
import { renderReport, type ContextReportMode } from "./diagnostics";
|
|
6
|
+
import { discoverSkillsFromFilesystem, mergeSkills } from "./skill-registry";
|
|
7
|
+
import { persistReportSnapshot, restoreReportFromSession } from "./session-state";
|
|
5
8
|
|
|
6
9
|
export function registerDiagnostics(pi: ExtensionAPI, state: ContextManagerState): void {
|
|
7
10
|
pi.registerTool({
|
|
8
11
|
name: "context_report",
|
|
9
12
|
label: "Context Report",
|
|
10
|
-
description: "Show takomi-context-manager diagnostics
|
|
13
|
+
description: "Show takomi-context-manager diagnostics. Defaults to compact summary; use mode='verbose' for full details or mode='problems' for attention-only output.",
|
|
11
14
|
promptSnippet: "Show context manager diagnostics and prompt composition decisions",
|
|
12
|
-
parameters: Type.Object({
|
|
15
|
+
parameters: Type.Object({
|
|
16
|
+
mode: Type.Optional(Type.Union([
|
|
17
|
+
Type.Literal("summary"),
|
|
18
|
+
Type.Literal("verbose"),
|
|
19
|
+
Type.Literal("problems"),
|
|
20
|
+
], { description: "Report layout mode. Defaults to summary. Use verbose for full diagnostics or problems for attention-only output." })),
|
|
21
|
+
verbose: Type.Optional(Type.Boolean({ description: "Deprecated compatibility alias for mode='verbose'." })),
|
|
22
|
+
}),
|
|
13
23
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
24
|
+
restoreReportFromSession(state, ctx);
|
|
25
|
+
if (state.skills.size === 0) state.skills = mergeSkills(await discoverSkillsFromFilesystem(ctx.cwd));
|
|
26
|
+
state.report.timestamp = new Date().toISOString();
|
|
14
27
|
state.report.cwd = ctx.cwd;
|
|
28
|
+
state.report.skillCount = state.skills.size;
|
|
15
29
|
state.report.toolCalls.contextReport += 1;
|
|
16
|
-
|
|
30
|
+
persistReportSnapshot(pi, state, "context_report");
|
|
31
|
+
const mode = (params.verbose ? "verbose" : params.mode ?? "summary") as ContextReportMode;
|
|
32
|
+
return { content: [{ type: "text", text: renderReport(state, mode) }], details: { ...state.report, mode } };
|
|
17
33
|
},
|
|
18
34
|
});
|
|
19
35
|
|
|
20
36
|
pi.registerCommand("context-report", {
|
|
21
|
-
description: "Show takomi-context-manager diagnostics",
|
|
22
|
-
|
|
37
|
+
description: "Show takomi-context-manager diagnostics. Optional args: summary, verbose, problems",
|
|
38
|
+
getArgumentCompletions: (prefix: string): AutocompleteItem[] | null => {
|
|
39
|
+
const modes: AutocompleteItem[] = [
|
|
40
|
+
{ value: "summary", label: "summary — compact health report" },
|
|
41
|
+
{ value: "verbose", label: "verbose — full diagnostics" },
|
|
42
|
+
{ value: "problems", label: "problems — only issues requiring attention" },
|
|
43
|
+
];
|
|
44
|
+
const normalized = prefix.trim().toLowerCase();
|
|
45
|
+
const filtered = modes.filter((mode) => mode.value.startsWith(normalized));
|
|
46
|
+
return filtered.length ? filtered : null;
|
|
47
|
+
},
|
|
48
|
+
handler: async (args, ctx) => {
|
|
49
|
+
restoreReportFromSession(state, ctx);
|
|
50
|
+
if (state.skills.size === 0) state.skills = mergeSkills(await discoverSkillsFromFilesystem(ctx.cwd));
|
|
51
|
+
state.report.timestamp = new Date().toISOString();
|
|
23
52
|
state.report.cwd = ctx.cwd;
|
|
53
|
+
state.report.skillCount = state.skills.size;
|
|
24
54
|
state.report.toolCalls.contextReport += 1;
|
|
25
|
-
|
|
55
|
+
persistReportSnapshot(pi, state, "context-report-command");
|
|
56
|
+
const requested = args.trim();
|
|
57
|
+
const mode: ContextReportMode = requested === "verbose" || requested === "problems" || requested === "summary" ? requested : "summary";
|
|
58
|
+
ctx.ui.notify(renderReport(state, mode), "info");
|
|
26
59
|
},
|
|
27
60
|
});
|
|
28
61
|
}
|