feat(server): improve task CLI with steering, execution order, and planner guidance
- Fix steering notes to check scope task instead of leaf task
- Fix NOT_DONE replan to use scope for bird's eye view
- Pass reason to planner prompt ("Why you were called" section)
- Add execution-order.ts with reusable computeExecutionOrder and buildSortedChildrenMap
- Make 'tree' an alias for 'plan' command
- Add comprehensive help text for run command and acceptance criteria
- Add planner guidance for propagating requirements to subtasks
This commit is contained in:
@@ -1067,6 +1067,7 @@ interface ExpandableBadgeProps {
|
||||
isError?: boolean;
|
||||
isLastInSequence?: boolean;
|
||||
disableOuterSpacing?: boolean;
|
||||
testID?: string;
|
||||
}
|
||||
|
||||
const ExpandableBadge = memo(function ExpandableBadge({
|
||||
@@ -1081,6 +1082,7 @@ const ExpandableBadge = memo(function ExpandableBadge({
|
||||
isError = false,
|
||||
isLastInSequence = false,
|
||||
disableOuterSpacing,
|
||||
testID,
|
||||
}: ExpandableBadgeProps) {
|
||||
const { theme } = useUnistyles();
|
||||
const resolvedDisableOuterSpacing =
|
||||
@@ -1140,7 +1142,7 @@ const ExpandableBadge = memo(function ExpandableBadge({
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[expandableBadgeStylesheet.container, style]}>
|
||||
<View style={[expandableBadgeStylesheet.container, style]} testID={testID}>
|
||||
<Pressable
|
||||
onPress={hasDetails ? onToggle : undefined}
|
||||
disabled={!hasDetails}
|
||||
@@ -1495,6 +1497,7 @@ export const ToolCall = memo(function ToolCall({
|
||||
|
||||
return (
|
||||
<ExpandableBadge
|
||||
testID="tool-call-badge"
|
||||
label={toolName}
|
||||
secondaryLabel={principalParam}
|
||||
icon={IconComponent}
|
||||
|
||||
@@ -65,19 +65,6 @@ function toolTimeline(
|
||||
};
|
||||
}
|
||||
|
||||
function permissionTimeline(id: string, status: string): AgentStreamEventPayload {
|
||||
return {
|
||||
type: "timeline",
|
||||
provider: "claude",
|
||||
item: {
|
||||
type: "tool_call",
|
||||
name: "permission_request",
|
||||
status,
|
||||
callId: id,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function todoTimeline(items: { text: string; completed: boolean }[]): AgentStreamEventPayload {
|
||||
return {
|
||||
type: "timeline",
|
||||
@@ -643,21 +630,7 @@ function testHydratedUserMessagesPersist() {
|
||||
});
|
||||
}
|
||||
|
||||
// Test 8: Permission tool calls should not show in the timeline
|
||||
function testPermissionToolCallFiltering() {
|
||||
const timestamp = new Date('2025-01-01T12:00:00Z');
|
||||
const updates = [
|
||||
{ event: permissionTimeline('permission-1', 'pending'), timestamp },
|
||||
{ event: permissionTimeline('permission-1', 'granted'), timestamp },
|
||||
];
|
||||
|
||||
const state = hydrateStreamState(updates);
|
||||
const permissionEntries = state.filter(isAgentToolCallItem);
|
||||
|
||||
assert.strictEqual(permissionEntries.length, 0);
|
||||
}
|
||||
|
||||
// Test 9: Todo lists should consolidate into a single entry and update completions
|
||||
// Test 8: Todo lists should consolidate into a single entry and update completions
|
||||
function testTodoListConsolidation() {
|
||||
const timestamp1 = new Date('2025-01-01T12:30:00Z');
|
||||
const timestamp2 = new Date('2025-01-01T12:31:00Z');
|
||||
@@ -1064,7 +1037,6 @@ describe('stream timeline reducers', () => {
|
||||
it('preserves whitespace in assistant chunk concatenation', testAssistantWhitespacePreservation);
|
||||
it('hydrates user messages and deduplicates optimistic/live entries', testUserMessageHydration);
|
||||
it('retains hydrated user messages across providers', testHydratedUserMessagesPersist);
|
||||
it('filters permission tool calls from the stream', testPermissionToolCallFiltering);
|
||||
it('consolidates todo list updates', testTodoListConsolidation);
|
||||
it('keeps timeline ids stable after list shrinkage', testTimelineIdStabilityAfterRemovals);
|
||||
it('deduplicates live tool call entries', testToolCallDeduplicationLive);
|
||||
|
||||
@@ -480,14 +480,6 @@ function appendAgentToolCall(
|
||||
return [...state, item];
|
||||
}
|
||||
|
||||
function isPermissionToolCall(raw: unknown): boolean {
|
||||
if (!raw || typeof raw !== "object") {
|
||||
return false;
|
||||
}
|
||||
const candidate = raw as { name?: string };
|
||||
return candidate.name === "permission_request";
|
||||
}
|
||||
|
||||
const FAILED_STATUS_PATTERN =
|
||||
/fail|error|deny|reject|cancel|abort|exception|refus/;
|
||||
const COMPLETED_STATUS_PATTERN =
|
||||
@@ -762,9 +754,6 @@ export function reduceStreamUpdate(
|
||||
case "reasoning":
|
||||
return appendThought(state, item.text, timestamp);
|
||||
case "tool_call": {
|
||||
if (isPermissionToolCall(item)) {
|
||||
return state;
|
||||
}
|
||||
nextState = appendAgentToolCall(
|
||||
state,
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user