}
return {
type: CustomizationType.Hook,
id: buildChildId(hookUri),
uri: hookUri.toString(),
name: basename(hookUri),
};
}
/**
Frontier kind: Code frontier
unlabeled · c_9f203d7ff5c5
13 tests · 18731 LOC · 66 files · introduces 0 tests · 87 LOC · 1 file
The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.
Introduced files, introduced tests, and structurally relevant concept specialization
In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.
Graph controls are ready.
Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.
Every exact file and test below is linked only from the concept that introduces it.
mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/plugins/agentPluginFormatDetection.test|title=AgentPlugin format detection manifest hooks field pointing to a specific file|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/chat/test/common/plugins/agentPluginFormatDetection.test|title=AgentPlugin format detection reads hooks from custom path in manifest|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/customizations/scan/claudeHookScan.test|title=claudeHookScan reads settings.local.json (project scope) ahead of user settings|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/customizations/scan/claudeHookScan.test|title=claudeHookScan surfaces one hook entry per settings file that declares hooks, with the real settings URI|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/charCode.test|title=CharCode has good values|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/path.test|title=Paths (Node Implementation) path|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/uri.test|title=URI File paths containing apostrophes break URI parsing and cannot be opened #276075|occurrence=1mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/base/test/common/uri.test|title=URI URI#file, win-speciale|occurrence=1Every collected test enters the hierarchy at exactly one concept.
No tests are introduced at this concept. Its intent tests are introduced by other concepts.
Every collected source range enters the hierarchy at exactly one concept.
1 file ranked by introduced lines: 87 introduced LOC across 15 ranges. Expand a file to inspect source; the > gutter marks introduced lines.
}
return {
type: CustomizationType.Hook,
id: buildChildId(hookUri),
uri: hookUri.toString(),
name: basename(hookUri),
};
}
/**
* legacy `bash`/`powershell` fields to platform-specific overrides.
*/
function normalizeHookCommand(raw: Record<string, unknown>): IParsedHookCommand | undefined {
pluginParsers.ts
// Allow omitted type (Claude compatibility) — treat as 'command'
if (raw.type !== undefined && raw.type !== 'command') {
return undefined;
}
const hasCommand = typeof raw.command === 'string' && raw.command.length > 0;
const hasBash = typeof raw.bash === 'string' && (raw.bash as string).length > 0;
const hasPowerShell = typeof raw.powershell === 'string' && (raw.powershell as string).length > 0;
const hasWindows = typeof raw.windows === 'string' && (raw.windows as string).length > 0;
const hasLinux = typeof raw.linux === 'string' && (raw.linux as string).length > 0;
const hasOsx = typeof raw.osx === 'string' && (raw.osx as string).length > 0;
if (!hasCommand && !hasBash && !hasPowerShell && !hasWindows && !hasLinux && !hasOsx) {
return undefined;
}
const windows = hasWindows ? raw.windows as string : (hasPowerShell ? raw.powershell as string : undefined);
const linux = hasLinux ? raw.linux as string : (hasBash ? raw.bash as string : undefined);
const osx = hasOsx ? raw.osx as string : (hasBash ? raw.bash as string : undefined);
const timeout = typeof raw.timeout === 'number'
? raw.timeout
return {
...(hasCommand && { command: raw.command as string }),
...(windows && { windows }),
...(linux && { linux }),
...(osx && { osx }),
...(typeof raw.env === 'object' && raw.env !== null && { env: raw.env as Record<string, string> }),
...(timeout !== undefined && { timeout }),
};
}
/**
* normalizing fields and resolving the working directory.
*/
function resolveHookCommand(raw: Record<string, unknown>, workspaceRoot: URI | undefined, userHome: URI): IParsedHookCommand | undefined {
pluginParsers.ts
const normalized = normalizeHookCommand(raw);
if (!normalized) {
return undefined;
}
let cwdUri: URI | undefined;
const rawCwd = typeof raw.cwd === 'string' ? raw.cwd : undefined;
if (rawCwd) {
if (rawCwd.startsWith('~/')) {
cwdUri = URI.joinPath(userHome, rawCwd.substring(2));
cwdUri = joinPath(workspaceRoot, rawCwd);
}
cwdUri = workspaceRoot;
}
return { ...normalized, cwd: cwdUri };
}
/**
* or a nested structure with a `matcher` (Claude format).
*/
function extractHookCommands(item: unknown, workspaceRoot: URI | undefined, userHome: URI): IParsedHookCommand[] {
pluginParsers.ts
if (!item || typeof item !== 'object') {
return [];
}
const itemObj = item as Record<string, unknown>;
const commands: IParsedHookCommand[] = [];
// Nested hooks with matcher (Claude style): { matcher: "...", hooks: [...] }
const nestedHooks = itemObj.hooks;
if (nestedHooks !== undefined && Array.isArray(nestedHooks)) {
for (const nested of nestedHooks) {
if (!nested || typeof nested !== 'object') {
}
}
const resolved = resolveHookCommand(itemObj, workspaceRoot, userHome);
if (resolved) {
return [];
}
const hooksObj = hooks as Record<string, unknown>;
const result: IParsedHookGroup[] = [];
const customization = makeHookCustomization(hookUri);
for (const originalId of Object.keys(hooksObj)) {
const canonicalType = HOOK_TYPE_MAP[originalId];
if (!canonicalType) {
continue;
}
const hookArray = hooksObj[originalId];
if (!Array.isArray(hookArray)) {
continue;
}
const commands: IParsedHookCommand[] = [];
for (const item of hookArray) {
commands.push(...extractHookCommands(item, workspaceRoot, userHome));
}
if (commands.length > 0) {
result.push({ type: canonicalType, commands, uri: hookUri, originalId, customization });
}
}
return result;
}
/**