fix: fixed prompt parsing, startup tracing, and help-command behavior

- Fixed help rendering so `--help` no longer triggers unrelated command loaders.
- Fixed startup span logging to emit markers only with PI_DEBUG_STARTUP set.
- Fixed logger startup trace behavior for `:start`, `:done`, and `:fail` phases.
- Fixed prompt template processing with cached raw-template compilation and safer formatting.
- Optimized symbol and tag parsing in prompt templates via manual parsers.
This commit is contained in:
can1357
2026-06-10 02:17:35 +02:00
parent 9615418ca9
commit f2137becb8
23 changed files with 966 additions and 138 deletions
+33 -2
View File
@@ -43,7 +43,7 @@ import type { LocalProtocolOptions } from "../internal-urls";
import { loadOverallPlanReference } from "../plan-mode/plan-handoff";
import { generateCommitMessage } from "../utils/commit-message-generator";
import * as git from "../utils/git";
import { discoverAgents, getAgent } from "./discovery";
import { type DiscoveryResult, discoverAgents, getAgent } from "./discovery";
import { runSubprocess } from "./executor";
import { AgentOutputManager } from "./output-manager";
import { mapWithConcurrencyLimit, Semaphore } from "./parallel";
@@ -293,6 +293,37 @@ function validateTaskIds(tasks: TaskParams["tasks"]): string | undefined {
return `Invalid tasks: ${problems.join(". ")}`;
}
/**
* Process-level memo for create-time agent discovery, keyed by resolved cwd.
*
* `TaskTool.create` runs for every (sub)agent session in this process and the
* walk-up + plugin-registry scan in `discoverAgents` is identical for a given
* cwd, so repeat creations reuse the first scan. Execution-time discovery
* (`#executeSync`) intentionally stays fresh. The memo also tracks the live
* `discoverAgents` binding: test spies swap that binding, which invalidates
* the memo automatically.
*/
const discoveryMemo = new Map<string, Promise<DiscoveryResult>>();
let discoveryMemoFn: typeof discoverAgents | undefined;
function discoverAgentsForCreate(cwd: string): Promise<DiscoveryResult> {
const fn = discoverAgents;
if (discoveryMemoFn !== fn) {
discoveryMemoFn = fn;
discoveryMemo.clear();
}
const key = path.resolve(cwd);
let pending = discoveryMemo.get(key);
if (!pending) {
pending = fn(cwd);
discoveryMemo.set(key, pending);
pending.catch(() => {
if (discoveryMemo.get(key) === pending) discoveryMemo.delete(key);
});
}
return pending;
}
// ═══════════════════════════════════════════════════════════════════════════
// Tool Class
// ═══════════════════════════════════════════════════════════════════════════
@@ -376,7 +407,7 @@ export class TaskTool implements AgentTool<TaskToolSchemaInstance, TaskToolDetai
* Create a TaskTool instance with async agent discovery.
*/
static async create(session: ToolSession): Promise<TaskTool> {
const { agents } = await discoverAgents(session.cwd);
const { agents } = await discoverAgentsForCreate(session.cwd);
return new TaskTool(session, agents);
}