diff --git a/src/Polyphony/Commands/BranchCommands.cs b/src/Polyphony/Commands/BranchCommands.cs index aad8ef9..d3337ad 100644 --- a/src/Polyphony/Commands/BranchCommands.cs +++ b/src/Polyphony/Commands/BranchCommands.cs @@ -209,9 +209,11 @@ private static IReadOnlyList ExtractPredecessors(JsonNode item) private static (string State, string Title) ExtractStateAndTitle(JsonNode item) { - var fields = item["fields"]; - var state = fields?["System.State"]?.GetValue() ?? string.Empty; - var title = fields?["System.Title"]?.GetValue() ?? string.Empty; + // twig >= v0.81.0 promotes state/title to top-level cells on + // `twig show --output json`. The fields[] subobject no longer + // redundantly carries System.State / System.Title. + var state = item["state"]?.GetValue() ?? string.Empty; + var title = item["title"]?.GetValue() ?? string.Empty; return (state, title); } diff --git a/src/Polyphony/Commands/PrCommands.OpenEvidencePr.cs b/src/Polyphony/Commands/PrCommands.OpenEvidencePr.cs index 4683101..970cbfe 100644 --- a/src/Polyphony/Commands/PrCommands.OpenEvidencePr.cs +++ b/src/Polyphony/Commands/PrCommands.OpenEvidencePr.cs @@ -329,7 +329,9 @@ private async Task ResolveEvidencePrTitleAsync(int workItem, Cancellatio try { var tree = await twig.ShowTreeAsync(workItem, ct).ConfigureAwait(false); - var workItemTitle = tree?["title"]?.GetValue(); + // twig >= v0.81.0 tree root is {parentChain, focus, children, …}; + // the active item's title lives under `focus`. + var workItemTitle = tree?["focus"]?["title"]?.GetValue(); return string.IsNullOrWhiteSpace(workItemTitle) ? fallback : $"Evidence: {workItemTitle} (#{workItem})"; diff --git a/src/Polyphony/Commands/PrCommands.OpenImplPr.cs b/src/Polyphony/Commands/PrCommands.OpenImplPr.cs index ffa7da3..b60ff28 100644 --- a/src/Polyphony/Commands/PrCommands.OpenImplPr.cs +++ b/src/Polyphony/Commands/PrCommands.OpenImplPr.cs @@ -325,7 +325,9 @@ private async Task ResolveImplPrTitleAsync(int itemId, CancellationToken try { var tree = await twig.ShowTreeAsync(itemId, ct).ConfigureAwait(false); - var workItemTitle = tree?["title"]?.GetValue(); + // twig >= v0.81.0 tree root is {parentChain, focus, children, …}; + // the active item's title lives under `focus`. + var workItemTitle = tree?["focus"]?["title"]?.GetValue(); return string.IsNullOrWhiteSpace(workItemTitle) ? fallback : $"{workItemTitle} AB#{itemId}"; } catch diff --git a/src/Polyphony/Commands/PrCommands.OpenPlanPr.cs b/src/Polyphony/Commands/PrCommands.OpenPlanPr.cs index 9382c9b..cf13579 100644 --- a/src/Polyphony/Commands/PrCommands.OpenPlanPr.cs +++ b/src/Polyphony/Commands/PrCommands.OpenPlanPr.cs @@ -526,7 +526,9 @@ private async Task ResolvePlanPrTitleAsync(int itemId, bool isRootPlan, try { var tree = await twig.ShowTreeAsync(itemId, ct).ConfigureAwait(false); - var workItemTitle = tree?["title"]?.GetValue(); + // twig >= v0.81.0 tree root is {parentChain, focus, children, …}; + // the active item's title lives under `focus`. + var workItemTitle = tree?["focus"]?["title"]?.GetValue(); if (string.IsNullOrWhiteSpace(workItemTitle)) return fallback; return $"plan: {workItemTitle} AB#{itemId}"; } diff --git a/src/Polyphony/Commands/PrCommands.cs b/src/Polyphony/Commands/PrCommands.cs index df58626..443540d 100644 --- a/src/Polyphony/Commands/PrCommands.cs +++ b/src/Polyphony/Commands/PrCommands.cs @@ -268,7 +268,9 @@ private async Task ResolvePrTitleAsync(int workItem, CancellationToken c try { var tree = await twig.ShowTreeAsync(workItem, ct).ConfigureAwait(false); - var title = tree?["title"]?.GetValue(); + // twig >= v0.81.0 tree root is {parentChain, focus, children, …}; + // the active item's title lives under `focus`. + var title = tree?["focus"]?["title"]?.GetValue(); return string.IsNullOrWhiteSpace(title) ? fallback : $"feat: {title} AB#{workItem}"; } catch diff --git a/tests/Polyphony.Tests/Commands/BranchCommandsCheckDepsTests.cs b/tests/Polyphony.Tests/Commands/BranchCommandsCheckDepsTests.cs index 7ae9212..e7ec941 100644 --- a/tests/Polyphony.Tests/Commands/BranchCommandsCheckDepsTests.cs +++ b/tests/Polyphony.Tests/Commands/BranchCommandsCheckDepsTests.cs @@ -74,8 +74,8 @@ public async Task CheckDeps_AllPredecessorsTerminal_EmitsNotBlocked() ] } """); - StubShow(runner, 200, """{"id":200,"fields":{"System.State":"Done","System.Title":"Pred A"}}"""); - StubShow(runner, 201, """{"id":201,"fields":{"System.State":"Closed","System.Title":"Pred B"}}"""); + StubShow(runner, 200, """{"id":200,"state":"Done","title":"Pred A"}"""); + StubShow(runner, 201, """{"id":201,"state":"Closed","title":"Pred B"}"""); var (exit, output) = await CaptureConsoleAsync(() => cmd.CheckDeps(100)); @@ -103,9 +103,9 @@ public async Task CheckDeps_PartiallyBlocked_EmitsBlockedListWithPendingItems() ] } """); - StubShow(runner, 200, """{"id":200,"fields":{"System.State":"Done","System.Title":"Pred A"}}"""); - StubShow(runner, 201, """{"id":201,"fields":{"System.State":"Doing","System.Title":"Pred B"}}"""); - StubShow(runner, 202, """{"id":202,"fields":{"System.State":"To Do","System.Title":"Pred C"}}"""); + StubShow(runner, 200, """{"id":200,"state":"Done","title":"Pred A"}"""); + StubShow(runner, 201, """{"id":201,"state":"Doing","title":"Pred B"}"""); + StubShow(runner, 202, """{"id":202,"state":"To Do","title":"Pred C"}"""); var (exit, output) = await CaptureConsoleAsync(() => cmd.CheckDeps(100)); @@ -133,7 +133,7 @@ public async Task CheckDeps_PredecessorsByAttributesName_AlsoCounted() ] } """); - StubShow(runner, 300, """{"id":300,"fields":{"System.State":"Done","System.Title":"Pred X"}}"""); + StubShow(runner, 300, """{"id":300,"state":"Done","title":"Pred X"}"""); var (_, output) = await CaptureConsoleAsync(() => cmd.CheckDeps(100)); var result = Deserialize(output); diff --git a/tests/Polyphony.Tests/Commands/PrCommandsJournalTests.cs b/tests/Polyphony.Tests/Commands/PrCommandsJournalTests.cs index 4028167..6b84317 100644 --- a/tests/Polyphony.Tests/Commands/PrCommandsJournalTests.cs +++ b/tests/Polyphony.Tests/Commands/PrCommandsJournalTests.cs @@ -657,7 +657,7 @@ private static void StubLsRemoteHas(FakeProcessRunner runner, string remote, str private static void StubTwigShowTree(FakeProcessRunner runner, int id, string? title) { - var json = title is null ? "" : $$"""{"title":"{{title}}","id":{{id}}}"""; + var json = title is null ? "" : $$$"""{"focus":{"title":"{{{title}}}","id":{{{id}}}}}"""; runner.WhenExact("twig", ["show", id.ToString(), "--tree", "--output", "json"], new ProcessResult(title is null ? 1 : 0, json, "")); } diff --git a/tests/Polyphony.Tests/Commands/PrCommandsOpenImplPrTests.cs b/tests/Polyphony.Tests/Commands/PrCommandsOpenImplPrTests.cs index 4dd644d..f62df28 100644 --- a/tests/Polyphony.Tests/Commands/PrCommandsOpenImplPrTests.cs +++ b/tests/Polyphony.Tests/Commands/PrCommandsOpenImplPrTests.cs @@ -32,7 +32,7 @@ private static void StubLsRemoteHas(FakeProcessRunner runner, string pattern, bo private static void StubTwigShowTree(FakeProcessRunner runner, int id, string? title) { - var json = title is null ? "" : $$"""{"title":"{{title}}","id":{{id}}}"""; + var json = title is null ? "" : $$$"""{"focus":{"title":"{{{title}}}","id":{{{id}}}}}"""; runner.WhenExact("twig", ["show", id.ToString(), "--tree", "--output", "json"], new ProcessResult(title is null ? 1 : 0, json, "")); } diff --git a/tests/Polyphony.Tests/Commands/PrCommandsOpenPlanAdoTests.cs b/tests/Polyphony.Tests/Commands/PrCommandsOpenPlanAdoTests.cs index 9d6da7f..bff243b 100644 --- a/tests/Polyphony.Tests/Commands/PrCommandsOpenPlanAdoTests.cs +++ b/tests/Polyphony.Tests/Commands/PrCommandsOpenPlanAdoTests.cs @@ -72,7 +72,7 @@ private static void StubManifestMissing(FakeProcessRunner runner, int rootId, st private static void StubTwigShow(FakeProcessRunner runner, int id, string? title) { - var json = title is null ? "" : $$"""{"title":"{{title}}","id":{{id}}}"""; + var json = title is null ? "" : $$$"""{"focus":{"title":"{{{title}}}","id":{{{id}}}}}"""; runner.WhenExact("twig", ["show", id.ToString(), "--tree", "--output", "json"], new ProcessResult(title is null ? 1 : 0, json, "")); } diff --git a/tests/Polyphony.Tests/Commands/PrCommandsOpenPlanPrTests.cs b/tests/Polyphony.Tests/Commands/PrCommandsOpenPlanPrTests.cs index 00f56e6..8c35a21 100644 --- a/tests/Polyphony.Tests/Commands/PrCommandsOpenPlanPrTests.cs +++ b/tests/Polyphony.Tests/Commands/PrCommandsOpenPlanPrTests.cs @@ -67,7 +67,7 @@ private static void StubGitOriginUrl(FakeProcessRunner runner, string url) private static void StubTwigShow(FakeProcessRunner runner, int id, string? title) { - var json = title is null ? "" : $$"""{"title":"{{title}}","id":{{id}}}"""; + var json = title is null ? "" : $$$"""{"focus":{"title":"{{{title}}}","id":{{{id}}}}}"""; runner.WhenExact("twig", ["show", id.ToString(), "--tree", "--output", "json"], new ProcessResult(title is null ? 1 : 0, json, "")); } diff --git a/tests/Polyphony.Tests/Commands/PrCommandsTests.cs b/tests/Polyphony.Tests/Commands/PrCommandsTests.cs index 0ac1cf4..d50939b 100644 --- a/tests/Polyphony.Tests/Commands/PrCommandsTests.cs +++ b/tests/Polyphony.Tests/Commands/PrCommandsTests.cs @@ -28,7 +28,7 @@ private static void StubLsRemoteHas(FakeProcessRunner runner, string remote, str private static void StubTwigShowTree(FakeProcessRunner runner, int id, string? title) { - var json = title is null ? "" : $$"""{"title":"{{title}}","id":{{id}}}"""; + var json = title is null ? "" : $$$"""{"focus":{"title":"{{{title}}}","id":{{{id}}}}}"""; runner.WhenExact("twig", new[] { "show", id.ToString(), "--tree", "--output", "json" }, new ProcessResult(title is null ? 1 : 0, json, "")); } diff --git a/tests/Polyphony.Tests/Commands/PrOpenEvidenceTests.cs b/tests/Polyphony.Tests/Commands/PrOpenEvidenceTests.cs index cfb7f87..e42e1ad 100644 --- a/tests/Polyphony.Tests/Commands/PrOpenEvidenceTests.cs +++ b/tests/Polyphony.Tests/Commands/PrOpenEvidenceTests.cs @@ -38,7 +38,7 @@ private static void StubLsRemoteHas(FakeProcessRunner runner, string pattern, bo private static void StubTwigShowTree(FakeProcessRunner runner, int id, string? title) { - var json = title is null ? "" : $$"""{"title":"{{title}}","id":{{id}}}"""; + var json = title is null ? "" : $$$"""{"focus":{"title":"{{{title}}}","id":{{{id}}}}}"""; runner.WhenExact("twig", ["show", id.ToString(), "--tree", "--output", "json"], new ProcessResult(title is null ? 1 : 0, json, "")); }