fix(gsd): normalize list inputs in complete-task + fix roadmap dep parsing
Two fixes: 1. gsd_complete_task now normalizes keyFiles/keyDecisions from strings (newline-delimited bullet lists) into arrays at the tool boundary, preventing type mismatch rejections on first call (#3361) 2. Legacy roadmap table parser now detects the dependency column from the header and only parses deps from that column or cells with explicit depends/deps keywords — prevents false deps from slice titles that mention other S-IDs (#3383, #3336) Closes #3361 Closes #3383 Closes #3336 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b4c6229360
commit
09acec6dce
2 changed files with 35 additions and 7 deletions
|
|
@ -66,6 +66,17 @@ function parseTableSlices(section: string): RoadmapSliceEntry[] {
|
|||
const lines = section.split("\n");
|
||||
const slices: RoadmapSliceEntry[] = [];
|
||||
|
||||
// Detect dependency column index from the header row (#3383, #3336).
|
||||
// Only parse deps from this column (or cells with explicit "depends"/"deps" keywords).
|
||||
let depColumnIndex = -1;
|
||||
for (const line of lines) {
|
||||
if (!line.includes("|")) continue;
|
||||
if (/S\d+/.test(line)) break; // reached data rows
|
||||
const headerCells = line.split("|").map(c => c.trim()).filter(Boolean);
|
||||
depColumnIndex = headerCells.findIndex(c => /^(depends|deps|depend)/i.test(c));
|
||||
if (depColumnIndex >= 0) break;
|
||||
}
|
||||
|
||||
for (const line of lines) {
|
||||
// Skip non-table lines, separator lines (|---|---|), and header rows
|
||||
if (!line.includes("|")) continue;
|
||||
|
|
@ -95,12 +106,17 @@ function parseTableSlices(section: string): RoadmapSliceEntry[] {
|
|||
if (/\bmedium\b/.test(cellLower) || /\bmed\b/.test(cellLower)) { risk = "medium"; break; }
|
||||
}
|
||||
|
||||
// Extract dependencies from cells containing S-prefixed IDs (excluding the slice's own ID)
|
||||
// Extract dependencies only from the dependency column or cells with
|
||||
// explicit "depends"/"deps" keywords — never from title cells (#3383).
|
||||
let depends: string[] = [];
|
||||
for (const cell of cells) {
|
||||
if (/depends|deps/i.test(cell) || (cell.match(/S\d+/g)?.length ?? 0) > 0) {
|
||||
const depIds = (cell.match(/S\d+/g) ?? []).filter(d => d !== id);
|
||||
if (depIds.length > 0 || /none|—|-/i.test(cell)) {
|
||||
if (depColumnIndex >= 0 && cells[depColumnIndex]) {
|
||||
const depCell = cells[depColumnIndex]!;
|
||||
const depIds = (depCell.match(/S\d+/g) ?? []).filter(d => d !== id);
|
||||
depends = expandDependencies(depIds);
|
||||
} else {
|
||||
for (const cell of cells) {
|
||||
if (/depends|deps/i.test(cell)) {
|
||||
const depIds = (cell.match(/S\d+/g) ?? []).filter(d => d !== id);
|
||||
depends = expandDependencies(depIds);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,18 @@ export interface CompleteTaskResult {
|
|||
|
||||
import type { TaskRow } from "../gsd-db.js";
|
||||
|
||||
/**
|
||||
* Normalize a list parameter that may arrive as a string (newline-delimited
|
||||
* bullet list from the LLM) into a string array (#3361).
|
||||
*/
|
||||
function normalizeListParam(value: unknown): string[] {
|
||||
if (Array.isArray(value)) return value.map(String);
|
||||
if (typeof value === "string" && value.trim()) {
|
||||
return value.split(/\n/).map(s => s.replace(/^[\s\-*•]+/, "").trim()).filter(Boolean);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a TaskRow-shaped object from CompleteTaskParams so the unified
|
||||
* renderSummaryContent() can be used at completion time (#2720).
|
||||
|
|
@ -63,8 +75,8 @@ function paramsToTaskRow(params: CompleteTaskParams, completedAt: string): TaskR
|
|||
blocker_discovered: params.blockerDiscovered ?? false,
|
||||
deviations: params.deviations ?? "",
|
||||
known_issues: params.knownIssues ?? "",
|
||||
key_files: params.keyFiles ?? [],
|
||||
key_decisions: params.keyDecisions ?? [],
|
||||
key_files: normalizeListParam(params.keyFiles),
|
||||
key_decisions: normalizeListParam(params.keyDecisions),
|
||||
full_summary_md: "",
|
||||
description: "",
|
||||
estimate: "",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue