Skip to content

Commit 0bbfbcc

Browse files
committed
Release Symphony Console 0.1.14
1 parent e865e76 commit 0bbfbcc

12 files changed

Lines changed: 149 additions & 17 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ Download packaged builds from GitHub Releases:
88

99
https://github.com/TerminallyLazy/misconducting/releases/latest
1010

11-
Current app metadata in this checkout is `0.1.13`. The public latest release page may
12-
still show older assets until tag `v0.1.13` is pushed and the desktop release workflow
11+
Current app metadata in this checkout is `0.1.14`. The public latest release page may
12+
still show older assets until tag `v0.1.14` is pushed and the desktop release workflow
1313
publishes new artifacts.
1414

1515
The GitHub Actions workflow `.github/workflows/release-desktop.yml` is configured to build macOS, Windows, Linux x86_64, and Linux ARM64 packages from release tags.

RELEASE_WORKFLOW_NOTE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ It builds:
99
- Linux x86_64 AppImage/DEB
1010
- Linux ARM64 AppImage/DEB
1111

12-
Push tag `v0.1.13` or run the workflow manually from GitHub Actions to produce release artifacts.
12+
Push tag `v0.1.14` or run the workflow manually from GitHub Actions to produce release artifacts.

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "symphony-desktop",
3-
"version": "0.1.13",
3+
"version": "0.1.14",
44
"private": true,
55
"type": "module",
66
"scripts": {

src-tauri/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "symphony_desktop"
3-
version = "0.1.13"
3+
version = "0.1.14"
44
edition = "2021"
55

66
[build-dependencies]

src-tauri/tauri.conf.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"productName": "Symphony Console",
3-
"version": "0.1.13",
3+
"version": "0.1.14",
44
"identifier": "dev.symphony.console",
55
"build": {
66
"beforeDevCommand": "npm run dev",

src/main.tsx

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,57 @@ function makeCardsFromKanban(kanban?: KanbanState): Card[] {
828828
);
829829
}
830830

831+
function upsertMovementRunIntoKanban(kanban: KanbanState | undefined, rawRun: unknown): KanbanState {
832+
const parsed = KanbanCardSchema.safeParse(rawRun);
833+
const run = parsed.success ? parsed.data : (rawRun || {}) as z.infer<typeof KanbanCardSchema>;
834+
const key = String(run.issue_id || run.id || run.linear_identifier || run.identifier || '');
835+
const targetId = kanbanColumnIdForRun(run);
836+
const generatedAt = new Date().toISOString();
837+
const baseColumns = kanban?.columns?.length
838+
? kanban.columns
839+
: [
840+
{ id: 'running', title: 'Running', count: 0, cards: [] },
841+
{ id: 'retrying', title: 'Retrying', count: 0, cards: [] },
842+
{ id: 'completed', title: 'Completed', count: 0, cards: [] }
843+
];
844+
845+
const columns = baseColumns.map(column => ({
846+
...column,
847+
cards: column.cards.filter(card => {
848+
const cardKey = String(card.issue_id || card.id || card.linear_identifier || card.identifier || '');
849+
return !key || cardKey !== key;
850+
})
851+
}));
852+
853+
const targetIndex = columns.findIndex(column => column.id === targetId);
854+
const targetColumn = targetIndex >= 0
855+
? columns[targetIndex]
856+
: { id: targetId, title: kanbanColumnTitle(targetId), count: 0, cards: [] };
857+
const updatedTarget = { ...targetColumn, cards: [run, ...targetColumn.cards], count: targetColumn.cards.length + 1 };
858+
const updatedColumns = targetIndex >= 0
859+
? columns.map((column, index) => index === targetIndex ? updatedTarget : { ...column, count: column.cards.length })
860+
: [...columns.map(column => ({ ...column, count: column.cards.length })), updatedTarget];
861+
862+
return {
863+
...(kanban || {}),
864+
generated_at: generatedAt,
865+
columns: updatedColumns
866+
};
867+
}
868+
869+
function kanbanColumnIdForRun(run: z.infer<typeof KanbanCardSchema>) {
870+
const status = String(run.operator_status || run.status || run.state || run.stage || run.phase || '').toLowerCase();
871+
if (status.includes('retry')) return 'retrying';
872+
if (status.includes('complete') || status.includes('done')) return 'completed';
873+
return 'running';
874+
}
875+
876+
function kanbanColumnTitle(id: string) {
877+
if (id === 'retrying') return 'Retrying';
878+
if (id === 'completed') return 'Completed';
879+
return 'Running';
880+
}
881+
831882
function agentProfileFromCard(raw: z.infer<typeof KanbanCardSchema>) {
832883
const profile = raw.agent_profile;
833884
if (!profile || typeof profile !== 'object' || Array.isArray(profile)) return null;
@@ -1248,7 +1299,11 @@ function App() {
12481299
const createMovement = useMutation({
12491300
mutationFn: (payload: ManualMovementPayload) =>
12501301
api<Record<string, unknown>>(base, '/api/movements', { method: 'POST', body: JSON.stringify(payload) }, 12_000),
1251-
onSuccess: () => {
1302+
onSuccess: data => {
1303+
const run = data && typeof data === 'object' ? data.run : undefined;
1304+
if (run && typeof run === 'object') {
1305+
queryClient.setQueryData<KanbanState>(['kanban', base], current => upsertMovementRunIntoKanban(current, run));
1306+
}
12521307
invalidateLiveData();
12531308
queryClient.invalidateQueries({ queryKey: ['rehearsalCheck', base] });
12541309
}

symphony_elixir/lib/symphony/http/api.ex

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ defmodule Symphony.Http.Api do
5656
count: length(snap.retrying),
5757
cards: Enum.map(snap.retrying, &retry_card/1)
5858
},
59-
%{id: "completed", title: "Completed", count: snap.counts.completed, cards: []}
59+
%{
60+
id: "completed",
61+
title: "Completed",
62+
count: snap.counts.completed,
63+
cards: Enum.map(Map.get(snap, :completed_runs, []), &completed_card/1)
64+
}
6065
],
6166
counts: snap.counts,
6267
codex_totals: snap.codex_totals,
@@ -969,6 +974,17 @@ defmodule Symphony.Http.Api do
969974
defp phase_operator_status("refiner"), do: "refining"
970975
defp phase_operator_status(_), do: "running"
971976

977+
defp completed_card(run) do
978+
run
979+
|> run_card()
980+
|> Map.merge(%{
981+
state: "Completed",
982+
status: "completed",
983+
operator_status: "completed",
984+
operator_summary: run.last_message || "Movement completed."
985+
})
986+
end
987+
972988
defp retry_card(retry) do
973989
agent_profile = retry.agent_profile || %{}
974990
phase = retry.phase || "retry"

symphony_elixir/lib/symphony/orchestrator.ex

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -585,12 +585,14 @@ defmodule Symphony.Orchestrator do
585585
}
586586

587587
defp complete(state, id),
588-
do: %{
589-
state
590-
| running: Map.delete(state.running, id),
591-
claimed: MapSet.put(state.claimed, id),
592-
completed: MapSet.put(state.completed, id)
593-
}
588+
do:
589+
%{
590+
state
591+
| running: Map.delete(state.running, id),
592+
claimed: MapSet.put(state.claimed, id),
593+
completed: MapSet.put(state.completed, id),
594+
completed_runs: completed_runs(state, id)
595+
}
594596

595597
defp retry_id(state, id, error, metadata \\ %{}) do
596598
{issue, attempt, run_metadata} =
@@ -1438,6 +1440,7 @@ defmodule Symphony.Orchestrator do
14381440
},
14391441
running: Enum.map(state.running, fn {_id, e} -> e.run end),
14401442
retrying: Map.values(state.retry_attempts),
1443+
completed_runs: completed_run_values(state.completed_runs),
14411444
codex_totals: state.codex_totals,
14421445
rate_limits: state.codex_rate_limits,
14431446
polling: %{
@@ -1448,4 +1451,40 @@ defmodule Symphony.Orchestrator do
14481451
}
14491452
}
14501453
end
1454+
1455+
defp completed_runs(state, id) do
1456+
case state.running[id] do
1457+
%{run: run} ->
1458+
run =
1459+
%{
1460+
run
1461+
| status: :completed,
1462+
last_event: run.last_event || "completed",
1463+
last_message: run.last_message || "#{phase_label(run.phase)} run completed.",
1464+
last_event_at: run.last_event_at || DateTime.utc_now()
1465+
}
1466+
1467+
state.completed_runs
1468+
|> Map.put(id, run)
1469+
|> trim_completed_runs()
1470+
1471+
_ ->
1472+
state.completed_runs
1473+
end
1474+
end
1475+
1476+
defp completed_run_values(completed_runs) do
1477+
completed_runs
1478+
|> Map.values()
1479+
|> Enum.sort_by(&run_sort_time/1, {:desc, DateTime})
1480+
end
1481+
1482+
defp trim_completed_runs(completed_runs) do
1483+
completed_runs
1484+
|> completed_run_values()
1485+
|> Enum.take(20)
1486+
|> Map.new(&{&1.issue_id, &1})
1487+
end
1488+
1489+
defp run_sort_time(run), do: run.last_event_at || run.started_at || ~U[1970-01-01 00:00:00Z]
14511490
end

0 commit comments

Comments
 (0)