* Build tool list from YAML manifest with predicate filtering.
(manifest: ResolvedManifest)
| 92 | * Build tool list from YAML manifest with predicate filtering. |
| 93 | */ |
| 94 | async function buildToolList(manifest: ResolvedManifest): Promise<ToolListItem[]> { |
| 95 | const tools: ToolListItem[] = []; |
| 96 | const seenToolIds = new Set<string>(); |
| 97 | const ctx = await buildCliPredicateContext(); |
| 98 | |
| 99 | // Get all CLI-available workflows that pass predicate checks |
| 100 | const cliWorkflows = Array.from(manifest.workflows.values()).filter( |
| 101 | (wf) => !CLI_EXCLUDED_WORKFLOWS.has(wf.id) && isWorkflowEnabledForRuntime(wf, ctx), |
| 102 | ); |
| 103 | |
| 104 | for (const workflow of cliWorkflows) { |
| 105 | for (const toolId of workflow.tools) { |
| 106 | const tool = manifest.tools.get(toolId); |
| 107 | if (!tool) continue; |
| 108 | |
| 109 | // Check tool availability and predicates for CLI |
| 110 | if (!isToolExposedForRuntime(tool, ctx)) continue; |
| 111 | |
| 112 | const cliName = getEffectiveCliName(tool); |
| 113 | |
| 114 | // Determine if this is a canonical tool or re-export |
| 115 | const isCanonical = isToolCanonicalInWorkflow(tool, workflow.id); |
| 116 | const originWorkflow = isCanonical ? undefined : getCanonicalWorkflow(tool); |
| 117 | |
| 118 | // Track seen tools to avoid duplicates |
| 119 | const toolKey = `${workflow.id}:${toolId}`; |
| 120 | if (seenToolIds.has(toolKey)) continue; |
| 121 | seenToolIds.add(toolKey); |
| 122 | |
| 123 | tools.push({ |
| 124 | cliName, |
| 125 | command: `${workflow.id} ${cliName}`, |
| 126 | workflow: workflow.id, |
| 127 | description: tool.description ?? '', |
| 128 | stateful: tool.routing?.stateful ?? false, |
| 129 | isCanonical, |
| 130 | originWorkflow, |
| 131 | }); |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | return tools; |
| 136 | } |
| 137 | |
| 138 | /** |
| 139 | * Determine if a tool is canonical in a given workflow. |
no test coverage detected