mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-04 09:13:08 +00:00
Merge pull request #493 from AutoMaker-Org/feature/v0.11.0rc-1768413909856-a0al
fix: agent output modal ui/ux and task list with spec/full plan mode
This commit is contained in:
@@ -230,7 +230,7 @@ export function TaskProgressPanel({
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="overflow-hidden">
|
<div className="overflow-hidden">
|
||||||
<div className="p-4 pt-2 relative max-h-[300px] overflow-y-auto scrollbar-visible">
|
<div className="p-4 pt-2 relative max-h-[200px] overflow-y-auto scrollbar-visible">
|
||||||
{/* Vertical Connector Line */}
|
{/* Vertical Connector Line */}
|
||||||
<div className="absolute left-[2.35rem] top-4 bottom-8 w-px bg-linear-to-b from-border/80 via-border/40 to-transparent" />
|
<div className="absolute left-[2.35rem] top-4 bottom-8 w-px bg-linear-to-b from-border/80 via-border/40 to-transparent" />
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState, useMemo } from 'react';
|
||||||
import { Feature, ThinkingLevel } from '@/store/app-store';
|
import { Feature, ThinkingLevel, ParsedTask } from '@/store/app-store';
|
||||||
import type { ReasoningEffort } from '@automaker/types';
|
import type { ReasoningEffort } from '@automaker/types';
|
||||||
import { getProviderFromModel } from '@/lib/utils';
|
import { getProviderFromModel } from '@/lib/utils';
|
||||||
import {
|
import {
|
||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
DEFAULT_MODEL,
|
DEFAULT_MODEL,
|
||||||
} from '@/lib/agent-context-parser';
|
} from '@/lib/agent-context-parser';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
import type { AutoModeEvent } from '@/types/electron';
|
||||||
import {
|
import {
|
||||||
Brain,
|
Brain,
|
||||||
ListTodo,
|
ListTodo,
|
||||||
@@ -71,6 +72,66 @@ export function AgentInfoPanel({
|
|||||||
const [agentInfo, setAgentInfo] = useState<AgentTaskInfo | null>(null);
|
const [agentInfo, setAgentInfo] = useState<AgentTaskInfo | null>(null);
|
||||||
const [isSummaryDialogOpen, setIsSummaryDialogOpen] = useState(false);
|
const [isSummaryDialogOpen, setIsSummaryDialogOpen] = useState(false);
|
||||||
const [isTodosExpanded, setIsTodosExpanded] = useState(false);
|
const [isTodosExpanded, setIsTodosExpanded] = useState(false);
|
||||||
|
// Track real-time task status updates from WebSocket events
|
||||||
|
const [taskStatusMap, setTaskStatusMap] = useState<
|
||||||
|
Map<string, 'pending' | 'in_progress' | 'completed'>
|
||||||
|
>(new Map());
|
||||||
|
// Fresh planSpec data fetched from API (store data is stale for task progress)
|
||||||
|
const [freshPlanSpec, setFreshPlanSpec] = useState<{
|
||||||
|
tasks?: ParsedTask[];
|
||||||
|
tasksCompleted?: number;
|
||||||
|
currentTaskId?: string;
|
||||||
|
} | null>(null);
|
||||||
|
|
||||||
|
// Derive effective todos from planSpec.tasks when available, fallback to agentInfo.todos
|
||||||
|
// Uses freshPlanSpec (from API) for accurate progress, with taskStatusMap for real-time updates
|
||||||
|
const effectiveTodos = useMemo(() => {
|
||||||
|
// Use freshPlanSpec if available (fetched from API), fallback to store's feature.planSpec
|
||||||
|
const planSpec = freshPlanSpec?.tasks?.length ? freshPlanSpec : feature.planSpec;
|
||||||
|
|
||||||
|
// First priority: use planSpec.tasks if available (modern approach)
|
||||||
|
if (planSpec?.tasks && planSpec.tasks.length > 0) {
|
||||||
|
const completedCount = planSpec.tasksCompleted || 0;
|
||||||
|
const currentTaskId = planSpec.currentTaskId;
|
||||||
|
|
||||||
|
return planSpec.tasks.map((task: ParsedTask, index: number) => {
|
||||||
|
// Use real-time status from WebSocket events if available
|
||||||
|
const realtimeStatus = taskStatusMap.get(task.id);
|
||||||
|
|
||||||
|
// Calculate status: WebSocket status > index-based status > task.status
|
||||||
|
let effectiveStatus: 'pending' | 'in_progress' | 'completed';
|
||||||
|
if (realtimeStatus) {
|
||||||
|
effectiveStatus = realtimeStatus;
|
||||||
|
} else if (index < completedCount) {
|
||||||
|
effectiveStatus = 'completed';
|
||||||
|
} else if (task.id === currentTaskId) {
|
||||||
|
effectiveStatus = 'in_progress';
|
||||||
|
} else {
|
||||||
|
// Fallback to task.status if available, otherwise pending
|
||||||
|
effectiveStatus =
|
||||||
|
task.status === 'completed'
|
||||||
|
? 'completed'
|
||||||
|
: task.status === 'in_progress'
|
||||||
|
? 'in_progress'
|
||||||
|
: 'pending';
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: task.description,
|
||||||
|
status: effectiveStatus,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Fallback: use parsed agentInfo.todos from agent-output.md
|
||||||
|
return agentInfo?.todos || [];
|
||||||
|
}, [
|
||||||
|
freshPlanSpec,
|
||||||
|
feature.planSpec?.tasks,
|
||||||
|
feature.planSpec?.tasksCompleted,
|
||||||
|
feature.planSpec?.currentTaskId,
|
||||||
|
agentInfo?.todos,
|
||||||
|
taskStatusMap,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadContext = async () => {
|
const loadContext = async () => {
|
||||||
@@ -82,6 +143,7 @@ export function AgentInfoPanel({
|
|||||||
|
|
||||||
if (feature.status === 'backlog') {
|
if (feature.status === 'backlog') {
|
||||||
setAgentInfo(null);
|
setAgentInfo(null);
|
||||||
|
setFreshPlanSpec(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +153,21 @@ export function AgentInfoPanel({
|
|||||||
if (!currentProject?.path) return;
|
if (!currentProject?.path) return;
|
||||||
|
|
||||||
if (api.features) {
|
if (api.features) {
|
||||||
|
// Fetch fresh feature data to get up-to-date planSpec (store data is stale)
|
||||||
|
try {
|
||||||
|
const featureResult = await api.features.get(currentProject.path, feature.id);
|
||||||
|
const freshFeature: any = (featureResult as any).feature;
|
||||||
|
if (featureResult.success && freshFeature?.planSpec) {
|
||||||
|
setFreshPlanSpec({
|
||||||
|
tasks: freshFeature.planSpec.tasks,
|
||||||
|
tasksCompleted: freshFeature.planSpec.tasksCompleted || 0,
|
||||||
|
currentTaskId: freshFeature.planSpec.currentTaskId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Ignore errors fetching fresh planSpec
|
||||||
|
}
|
||||||
|
|
||||||
const result = await api.features.getAgentOutput(currentProject.path, feature.id);
|
const result = await api.features.getAgentOutput(currentProject.path, feature.id);
|
||||||
|
|
||||||
if (result.success && result.content) {
|
if (result.success && result.content) {
|
||||||
@@ -113,13 +190,62 @@ export function AgentInfoPanel({
|
|||||||
|
|
||||||
loadContext();
|
loadContext();
|
||||||
|
|
||||||
if (isCurrentAutoTask) {
|
// Poll for updates when feature is in_progress (not just isCurrentAutoTask)
|
||||||
|
// This ensures planSpec progress stays in sync
|
||||||
|
if (isCurrentAutoTask || feature.status === 'in_progress') {
|
||||||
const interval = setInterval(loadContext, 3000);
|
const interval = setInterval(loadContext, 3000);
|
||||||
return () => {
|
return () => {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, [feature.id, feature.status, contextContent, isCurrentAutoTask]);
|
}, [feature.id, feature.status, contextContent, isCurrentAutoTask]);
|
||||||
|
|
||||||
|
// Listen to WebSocket events for real-time task status updates
|
||||||
|
// This ensures the Kanban card shows the same progress as the Agent Output modal
|
||||||
|
// Listen for ANY in-progress feature with planSpec tasks, not just isCurrentAutoTask
|
||||||
|
const hasPlanSpecTasks =
|
||||||
|
(freshPlanSpec?.tasks?.length ?? 0) > 0 || (feature.planSpec?.tasks?.length ?? 0) > 0;
|
||||||
|
const shouldListenToEvents = feature.status === 'in_progress' && hasPlanSpecTasks;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!shouldListenToEvents) return;
|
||||||
|
|
||||||
|
const api = getElectronAPI();
|
||||||
|
if (!api?.autoMode) return;
|
||||||
|
|
||||||
|
const unsubscribe = api.autoMode.onEvent((event: AutoModeEvent) => {
|
||||||
|
// Only handle events for this feature
|
||||||
|
if (!('featureId' in event) || event.featureId !== feature.id) return;
|
||||||
|
|
||||||
|
switch (event.type) {
|
||||||
|
case 'auto_mode_task_started':
|
||||||
|
if ('taskId' in event) {
|
||||||
|
const taskEvent = event as Extract<AutoModeEvent, { type: 'auto_mode_task_started' }>;
|
||||||
|
setTaskStatusMap((prev) => {
|
||||||
|
const newMap = new Map(prev);
|
||||||
|
// Mark current task as in_progress
|
||||||
|
newMap.set(taskEvent.taskId, 'in_progress');
|
||||||
|
return newMap;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'auto_mode_task_complete':
|
||||||
|
if ('taskId' in event) {
|
||||||
|
const taskEvent = event as Extract<AutoModeEvent, { type: 'auto_mode_task_complete' }>;
|
||||||
|
setTaskStatusMap((prev) => {
|
||||||
|
const newMap = new Map(prev);
|
||||||
|
newMap.set(taskEvent.taskId, 'completed');
|
||||||
|
return newMap;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return unsubscribe;
|
||||||
|
}, [feature.id, shouldListenToEvents]);
|
||||||
|
|
||||||
// Model/Preset Info for Backlog Cards
|
// Model/Preset Info for Backlog Cards
|
||||||
if (feature.status === 'backlog') {
|
if (feature.status === 'backlog') {
|
||||||
const provider = getProviderFromModel(feature.model);
|
const provider = getProviderFromModel(feature.model);
|
||||||
@@ -158,7 +284,9 @@ export function AgentInfoPanel({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Agent Info Panel for non-backlog cards
|
// Agent Info Panel for non-backlog cards
|
||||||
if (feature.status !== 'backlog' && agentInfo) {
|
// Show panel if we have agentInfo OR planSpec.tasks (for spec/full mode)
|
||||||
|
// Note: hasPlanSpecTasks is already defined above and includes freshPlanSpec
|
||||||
|
if (feature.status !== 'backlog' && (agentInfo || hasPlanSpecTasks)) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="mb-3 space-y-2 overflow-hidden">
|
<div className="mb-3 space-y-2 overflow-hidden">
|
||||||
@@ -171,7 +299,7 @@ export function AgentInfoPanel({
|
|||||||
})()}
|
})()}
|
||||||
<span className="font-medium">{formatModelName(feature.model ?? DEFAULT_MODEL)}</span>
|
<span className="font-medium">{formatModelName(feature.model ?? DEFAULT_MODEL)}</span>
|
||||||
</div>
|
</div>
|
||||||
{agentInfo.currentPhase && (
|
{agentInfo?.currentPhase && (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'px-1.5 py-0.5 rounded-md text-[10px] font-medium',
|
'px-1.5 py-0.5 rounded-md text-[10px] font-medium',
|
||||||
@@ -189,13 +317,13 @@ export function AgentInfoPanel({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Task List Progress */}
|
{/* Task List Progress */}
|
||||||
{agentInfo.todos.length > 0 && (
|
{effectiveTodos.length > 0 && (
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<div className="flex items-center gap-1 text-[10px] text-muted-foreground/70">
|
<div className="flex items-center gap-1 text-[10px] text-muted-foreground/70">
|
||||||
<ListTodo className="w-3 h-3" />
|
<ListTodo className="w-3 h-3" />
|
||||||
<span>
|
<span>
|
||||||
{agentInfo.todos.filter((t) => t.status === 'completed').length}/
|
{effectiveTodos.filter((t) => t.status === 'completed').length}/
|
||||||
{agentInfo.todos.length} tasks
|
{effectiveTodos.length} tasks
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -204,7 +332,7 @@ export function AgentInfoPanel({
|
|||||||
isTodosExpanded ? 'max-h-40' : 'max-h-16'
|
isTodosExpanded ? 'max-h-40' : 'max-h-16'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{(isTodosExpanded ? agentInfo.todos : agentInfo.todos.slice(0, 3)).map(
|
{(isTodosExpanded ? effectiveTodos : effectiveTodos.slice(0, 3)).map(
|
||||||
(todo, idx) => (
|
(todo, idx) => (
|
||||||
<div key={idx} className="flex items-center gap-1.5 text-[10px]">
|
<div key={idx} className="flex items-center gap-1.5 text-[10px]">
|
||||||
{todo.status === 'completed' ? (
|
{todo.status === 'completed' ? (
|
||||||
@@ -227,7 +355,7 @@ export function AgentInfoPanel({
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
{agentInfo.todos.length > 3 && (
|
{effectiveTodos.length > 3 && (
|
||||||
<button
|
<button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -237,7 +365,7 @@ export function AgentInfoPanel({
|
|||||||
onMouseDown={(e) => e.stopPropagation()}
|
onMouseDown={(e) => e.stopPropagation()}
|
||||||
className="text-[10px] text-muted-foreground/60 pl-4 hover:text-muted-foreground transition-colors cursor-pointer"
|
className="text-[10px] text-muted-foreground/60 pl-4 hover:text-muted-foreground transition-colors cursor-pointer"
|
||||||
>
|
>
|
||||||
{isTodosExpanded ? 'Show less' : `+${agentInfo.todos.length - 3} more`}
|
{isTodosExpanded ? 'Show less' : `+${effectiveTodos.length - 3} more`}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -247,7 +375,7 @@ export function AgentInfoPanel({
|
|||||||
{/* Summary for waiting_approval and verified */}
|
{/* Summary for waiting_approval and verified */}
|
||||||
{(feature.status === 'waiting_approval' || feature.status === 'verified') && (
|
{(feature.status === 'waiting_approval' || feature.status === 'verified') && (
|
||||||
<>
|
<>
|
||||||
{(feature.summary || summary || agentInfo.summary) && (
|
{(feature.summary || summary || agentInfo?.summary) && (
|
||||||
<div className="space-y-1.5 pt-2 border-t border-border/30 overflow-hidden">
|
<div className="space-y-1.5 pt-2 border-t border-border/30 overflow-hidden">
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<div className="flex items-center gap-1 text-[10px] text-[var(--status-success)] min-w-0">
|
<div className="flex items-center gap-1 text-[10px] text-[var(--status-success)] min-w-0">
|
||||||
@@ -273,23 +401,23 @@ export function AgentInfoPanel({
|
|||||||
onPointerDown={(e) => e.stopPropagation()}
|
onPointerDown={(e) => e.stopPropagation()}
|
||||||
onMouseDown={(e) => e.stopPropagation()}
|
onMouseDown={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
{feature.summary || summary || agentInfo.summary}
|
{feature.summary || summary || agentInfo?.summary}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!feature.summary &&
|
{!feature.summary &&
|
||||||
!summary &&
|
!summary &&
|
||||||
!agentInfo.summary &&
|
!agentInfo?.summary &&
|
||||||
agentInfo.toolCallCount > 0 && (
|
(agentInfo?.toolCallCount ?? 0) > 0 && (
|
||||||
<div className="flex items-center gap-2 text-[10px] text-muted-foreground/60 pt-2 border-t border-border/30">
|
<div className="flex items-center gap-2 text-[10px] text-muted-foreground/60 pt-2 border-t border-border/30">
|
||||||
<span className="flex items-center gap-1">
|
<span className="flex items-center gap-1">
|
||||||
<Wrench className="w-2.5 h-2.5" />
|
<Wrench className="w-2.5 h-2.5" />
|
||||||
{agentInfo.toolCallCount} tool calls
|
{agentInfo?.toolCallCount ?? 0} tool calls
|
||||||
</span>
|
</span>
|
||||||
{agentInfo.todos.length > 0 && (
|
{effectiveTodos.length > 0 && (
|
||||||
<span className="flex items-center gap-1">
|
<span className="flex items-center gap-1">
|
||||||
<CheckCircle2 className="w-2.5 h-2.5 text-[var(--status-success)]" />
|
<CheckCircle2 className="w-2.5 h-2.5 text-[var(--status-success)]" />
|
||||||
{agentInfo.todos.filter((t) => t.status === 'completed').length} tasks done
|
{effectiveTodos.filter((t) => t.status === 'completed').length} tasks done
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -380,11 +380,11 @@ export function AgentOutputModal({
|
|||||||
<TaskProgressPanel
|
<TaskProgressPanel
|
||||||
featureId={featureId}
|
featureId={featureId}
|
||||||
projectPath={projectPath}
|
projectPath={projectPath}
|
||||||
className="flex-shrink-0 mx-1"
|
className="flex-shrink-0 mx-3 my-2"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{effectiveViewMode === 'changes' ? (
|
{effectiveViewMode === 'changes' ? (
|
||||||
<div className="flex-1 min-h-0 sm:min-h-[400px] sm:max-h-[60vh] overflow-y-auto scrollbar-visible">
|
<div className="flex-1 min-h-0 sm:min-h-[200px] sm:max-h-[60vh] overflow-y-auto scrollbar-visible">
|
||||||
{projectPath ? (
|
{projectPath ? (
|
||||||
<GitDiffPanel
|
<GitDiffPanel
|
||||||
projectPath={projectPath}
|
projectPath={projectPath}
|
||||||
@@ -401,7 +401,7 @@ export function AgentOutputModal({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : effectiveViewMode === 'summary' && summary ? (
|
) : effectiveViewMode === 'summary' && summary ? (
|
||||||
<div className="flex-1 min-h-0 sm:min-h-[400px] sm:max-h-[60vh] overflow-y-auto bg-card border border-border/50 rounded-lg p-4 scrollbar-visible">
|
<div className="flex-1 min-h-0 sm:min-h-[200px] sm:max-h-[60vh] overflow-y-auto bg-card border border-border/50 rounded-lg p-4 scrollbar-visible">
|
||||||
<Markdown>{summary}</Markdown>
|
<Markdown>{summary}</Markdown>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -409,7 +409,7 @@ export function AgentOutputModal({
|
|||||||
<div
|
<div
|
||||||
ref={scrollRef}
|
ref={scrollRef}
|
||||||
onScroll={handleScroll}
|
onScroll={handleScroll}
|
||||||
className="flex-1 min-h-0 sm:min-h-[400px] sm:max-h-[60vh] overflow-y-auto bg-zinc-950 rounded-lg p-4 font-mono text-xs scrollbar-visible"
|
className="flex-1 min-h-0 sm:min-h-[200px] sm:max-h-[60vh] overflow-y-auto bg-zinc-950 rounded-lg p-4 font-mono text-xs scrollbar-visible"
|
||||||
>
|
>
|
||||||
{isLoading && !output ? (
|
{isLoading && !output ? (
|
||||||
<div className="flex items-center justify-center h-full text-muted-foreground">
|
<div className="flex items-center justify-center h-full text-muted-foreground">
|
||||||
|
|||||||
10
package-lock.json
generated
10
package-lock.json
generated
@@ -11595,7 +11595,6 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11617,7 +11616,6 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"darwin"
|
"darwin"
|
||||||
],
|
],
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11660,7 +11658,6 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11682,7 +11679,6 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11704,7 +11700,6 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11726,7 +11721,6 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11748,7 +11742,6 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
],
|
],
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11770,7 +11763,6 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -11792,7 +11784,6 @@
|
|||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 12.0.0"
|
"node": ">= 12.0.0"
|
||||||
},
|
},
|
||||||
@@ -17015,7 +17006,6 @@
|
|||||||
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
|
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"yaml": "bin.mjs"
|
"yaml": "bin.mjs"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user