import { buildShellPracticeAuditMetadata, createShellBaseToolDefinition, injectRuntimeInvocationMetadata, jsonSchema } from "../../_shared/baseToolAdapter.js";
import { anthropicShellProcessStatusTrackingPractice } from "./anthropic.js";
import { deepmindShellProcessStatusTrackingPractice } from "./deepmind.js";
import { openaiShellProcessStatusTrackingPractice } from "./openai.js";
import { trackShellProcessStatus as trackShellProcessStatusCore, } from "./core.js";
import { shellProcessStatusTrackingDependencyDeclarations, } from "./dependencies.js";
export * from "./core.js";
export const shellProcessStatusTrackingProviderPractices = [anthropicShellProcessStatusTrackingPractice, openaiShellProcessStatusTrackingPractice, deepmindShellProcessStatusTrackingPractice];
export const shellProcessStatusTrackingBestPracticeDescriptor = { toolId: "shell.processStatusTracking", bestPractice: "runtime-execEngine-shellExecution-monitorProcessStatus", sourcePriority: ["cli", "agent-sdk", "api-sdk", "praxis-native"], providerOrder: ["anthropic", "openai", "deepmind"], dependencies: shellProcessStatusTrackingDependencyDeclarations };
function orderedPractices(preferredProvider) {
    if (preferredProvider === undefined)
        return shellProcessStatusTrackingProviderPractices;
    return [...shellProcessStatusTrackingProviderPractices.filter((practice) => practice.providerName === preferredProvider), ...shellProcessStatusTrackingProviderPractices.filter((practice) => practice.providerName !== preferredProvider)];
}
export function selectShellProcessStatusTrackingPractice(dependencies = {}) {
    for (const practice of orderedPractices(dependencies.preferredProvider)) {
        const provider = practice.createProvider(dependencies);
        if (provider !== undefined)
            return { providerName: practice.providerName, practice, provider };
    }
    return { providerName: "praxis-native", practice: { providerName: "praxis-native", source: { kind: "praxis-native", label: "Praxis dry-run fallback" }, directCliSupport: false, sideEffectPolicy: "runtime-governed", notes: ["No injected or host shell process monitor provider is currently available; dry-run remains available."], createProvider: () => undefined } };
}
function practiceAuditMetadata(selection) {
    return buildShellPracticeAuditMetadata({ providerName: selection.providerName, sourceLabel: selection.practice.source.label, sourceKind: selection.practice.source.kind, sourcePath: selection.practice.source.path, directCliSupport: selection.practice.directCliSupport, sideEffectPolicy: selection.practice.sideEffectPolicy, notes: selection.practice.notes });
}
function stringValue(value) {
    return typeof value === "string" ? value.trim() || undefined : undefined;
}
function hasAffirmativeGuard(context) {
    if (typeof context !== "object" || context === null)
        return false;
    const guard = context.guard;
    return guard?.allowed === true || guard?.accepted === true;
}
function runtimeFailure(code, message, boundary, request) {
    return { ok: false, toolId: "shell.processStatusTracking", error: { code, message, boundary, publicSafe: true, safeForRuntimeInspection: true, internalDetailExposed: false }, audit: [{ type: "agentCore.basicTool.shell.processStatusTracking.rejected", toolId: "shell.processStatusTracking", invocationId: stringValue(request.context?.invocationId) ?? "shell.processStatusTracking:runtime", dryRun: request.context?.dryRun !== false, executionId: stringValue(request.executionId), metadata: { ...(request.context?.auditMetadata ?? {}), code, boundary } }], events: ["basicTool.shell.processStatusTracking.rejected"] };
}
function hasCallerStatusMaterial(request) {
    return request.snapshot !== undefined || request.expectedStatuses !== undefined || request.staleAfterMs !== undefined;
}
function validateCallerProcessStatusMaterial(request, executionId, auditMetadata) {
    if (!hasCallerStatusMaterial(request))
        return undefined;
    const validation = trackShellProcessStatusCore({
        ...request,
        executionId,
        snapshot: request.snapshot === undefined ? { status: "running" } : request.snapshot,
        context: { ...request.context, dryRun: true, auditMetadata },
    });
    return validation.ok ? undefined : validation;
}
export async function executeShellProcessStatusTracking(request = {}) {
    const selection = selectShellProcessStatusTrackingPractice({ executor: request.executor, provider: request.provider, preferredProvider: request.preferredProvider });
    const auditMetadata = { ...(request.context?.auditMetadata ?? {}), ...practiceAuditMetadata(selection) };
    if (request.context?.dryRun !== false)
        return trackShellProcessStatusCore({ ...request, context: { ...request.context, auditMetadata } });
    const executionId = stringValue(request.executionId);
    if (executionId === undefined)
        return runtimeFailure("MISSING_EXECUTION_ID", "shell.processStatusTracking requires an executionId", "input", request);
    if (Array.isArray(request.context?.grantedPermissions) && !request.context.grantedPermissions.includes("shell:observe"))
        return runtimeFailure("PERMISSION_DENIED", "shell.processStatusTracking is missing permission: shell:observe", "permission", request);
    if (!hasAffirmativeGuard(request.context))
        return runtimeFailure("GOVERNANCE_REJECTED", "shell.processStatusTracking requires an affirmative runtime guard before real provider dispatch", "runtime", request);
    const callerMaterialFailure = validateCallerProcessStatusMaterial(request, executionId, auditMetadata);
    if (callerMaterialFailure !== undefined)
        return callerMaterialFailure;
    if (selection.provider === undefined)
        return runtimeFailure("PROVIDER_UNAVAILABLE", "shell.processStatusTracking requires a runtime shell monitor provider for real dispatch", "runtime", request);
    try {
        const providerOutput = await selection.provider({ executionId, command: stringValue(request.command), snapshot: request.snapshot, expectedStatuses: request.expectedStatuses, staleAfterMs: request.staleAfterMs }, { ...request.context, auditMetadata });
        const result = trackShellProcessStatusCore({ ...request, ...providerOutput, executionId, context: { ...request.context, dryRun: true, auditMetadata } });
        if (!result.ok)
            return result;
        return { ...result, output: { ...result.output, dryRun: false, providerCalled: true }, events: [`basicTool.shell.processStatusTracking.${result.output.status}`] };
    }
    catch {
        return runtimeFailure("PROVIDER_REJECTED", "shell.processStatusTracking provider rejected the request", "runtime", request);
    }
}
export const shellProcessStatusTrackingBaseToolDefinition = createShellBaseToolDefinition({
    toolId: "shell.processStatusTracking", title: "Shell Process Status Tracking", description: "Normalize a runtime-owned shell process status snapshot.", summary: "Use shell.processStatusTracking to inspect runtime-supplied process status.", storageGroup: "executionMonitoring", riskLevel: "normal", permissionHints: ["shell:observe"], dependencies: shellProcessStatusTrackingDependencyDeclarations,
    inputSchema: jsonSchema("shell.processStatusTracking.input", { type: "object", additionalProperties: true, properties: { executionId: { type: "string" }, command: { type: "string" }, snapshot: { type: "object", additionalProperties: true }, expectedStatuses: { type: "array", items: { type: "string" } }, staleAfterMs: { type: "integer", minimum: 1 }, context: { type: "object", additionalProperties: true }, preferredProvider: { type: "string", enum: ["anthropic", "openai", "deepmind", "praxis-native"] } } }),
    outputSchema: jsonSchema("shell.processStatusTracking.output", { type: "object", additionalProperties: true }),
});
export const shellProcessStatusTrackingHandler = {
    definition: shellProcessStatusTrackingBaseToolDefinition,
    async invoke(request) {
        const result = await executeShellProcessStatusTracking({ ...request.input, executor: request.executor, context: { ...request.input.context, runtimeId: request.input.context?.runtimeId ?? request.runtimeId, invocationId: request.input.context?.invocationId ?? request.toolCallId, auditMetadata: injectRuntimeInvocationMetadata(request.metadata, request.input.context?.auditMetadata, request) } });
        if (!result.ok)
            return { ok: false, toolId: result.toolId, error: { code: result.error.code, message: result.error.message, publicSafe: true }, events: result.events };
        return { ok: true, toolId: result.toolId, output: result.output, events: result.events, metadata: { audit: result.audit } };
    },
};
