@dsdenes/devboard 0.1.559 → 0.1.562
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +59 -0
- package/README.md +2497 -26
- package/bin/devboard.mjs +352 -118
- package/client/App.svelte +523 -0
- package/client/FeedbackOverlay.svelte +1125 -0
- package/client/FlowMode.svelte +1015 -0
- package/client/app.css +3922 -0
- package/client/env.d.ts +23 -0
- package/client/lib/commands.ts +836 -0
- package/client/lib/components/ActivityBar.svelte +295 -0
- package/client/lib/components/AdrTable.svelte +241 -0
- package/client/lib/components/CommandPalette.svelte +198 -0
- package/client/lib/components/ConceptKind.svelte +66 -0
- package/client/lib/components/ConfirmDialog.svelte +62 -0
- package/client/lib/components/DataTable.svelte +243 -0
- package/client/lib/components/DetailSplit.svelte +68 -0
- package/client/lib/components/DiscoverOverview.svelte +898 -0
- package/client/lib/components/DiscoverWorkspace.svelte +437 -0
- package/client/lib/components/DraftsPage.svelte +186 -0
- package/client/lib/components/GoalWorkspace.svelte +1042 -0
- package/client/lib/components/IssuesAgentFocus.svelte +117 -0
- package/client/lib/components/IssuesAgentLog.svelte +50 -0
- package/client/lib/components/IssuesQuestion.svelte +95 -0
- package/client/lib/components/IssuesWorkspace.svelte +577 -0
- package/client/lib/components/MermaidDiagram.svelte +89 -0
- package/client/lib/components/MonacoEditor.svelte +190 -0
- package/client/lib/components/NotificationRegion.svelte +195 -0
- package/client/lib/components/PaneHandle.svelte +25 -0
- package/client/lib/components/ScoutIssues.svelte +215 -0
- package/client/lib/components/ScoutWorkspace.svelte +180 -0
- package/client/lib/components/Sidebar.svelte +622 -0
- package/client/lib/components/StatusBar.svelte +118 -0
- package/client/lib/components/Terminal.svelte +193 -0
- package/client/lib/components/WatchdogWorkspace.svelte +537 -0
- package/client/lib/components/ui/button.svelte +56 -0
- package/client/lib/components/ui/icon-button.svelte +56 -0
- package/client/lib/components/ui/input.svelte +19 -0
- package/client/lib/components/ui/page-header.svelte +120 -0
- package/client/lib/components/ui/stage-track.svelte +141 -0
- package/client/lib/components/watchdog-indicator.svelte +189 -0
- package/client/lib/connection.svelte.ts +210 -0
- package/client/lib/dependency-diagram.test.ts +90 -0
- package/client/lib/dependency-diagram.ts +75 -0
- package/client/lib/discover-format.test.ts +265 -0
- package/client/lib/discover-format.ts +394 -0
- package/client/lib/discover.svelte.ts +412 -0
- package/client/lib/draft-format.test.ts +48 -0
- package/client/lib/draft-format.ts +13 -0
- package/client/lib/flow-save.test.ts +148 -0
- package/client/lib/flow.svelte.ts +445 -0
- package/client/lib/goal-reconnect.test.ts +282 -0
- package/client/lib/goal.svelte.ts +652 -0
- package/client/lib/issues.svelte.ts +439 -0
- package/client/lib/layout.svelte.ts +234 -0
- package/client/lib/notification-issue.test.ts +53 -0
- package/client/lib/notification-issue.ts +27 -0
- package/client/lib/notifications.svelte.ts +62 -0
- package/client/lib/poll-status.test.ts +141 -0
- package/client/lib/poll-status.ts +88 -0
- package/client/lib/record-status.test.ts +19 -0
- package/client/lib/record-status.ts +25 -0
- package/client/lib/scout.svelte.ts +164 -0
- package/client/lib/skill-document.test.ts +77 -0
- package/client/lib/skill-document.ts +57 -0
- package/client/lib/status-tone.test.ts +40 -0
- package/client/lib/status-tone.ts +33 -0
- package/client/lib/types.ts +578 -0
- package/client/lib/utils.ts +6 -0
- package/client/lib/viewport.svelte.ts +20 -0
- package/client/lib/watchdog.svelte.ts +69 -0
- package/client/main.ts +7 -0
- package/dist/apple-touch-icon.png +0 -0
- package/dist/assets/abnfDiagram-VCTEODGH-CmBSMArZ.js +1 -0
- package/dist/assets/arc-BZgCSX2H.js +1 -0
- package/dist/assets/architecture-7GRP2DOG-CF9MHlfo.js +1 -0
- package/dist/assets/architectureDiagram-5GKGNRK7-DzWB6xiQ.js +36 -0
- package/dist/assets/array-BifhSqXX.js +1 -0
- package/dist/assets/blockDiagram-I7D4REHJ-BtmGJ0hn.js +129 -0
- package/dist/assets/c4Diagram-7LVT6UL2-D5CHrrRX.js +38 -0
- package/dist/assets/channel-CgM4lcUW.js +1 -0
- package/dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/dist/assets/chunk-4HAMMTFA-DeIufjFl.js +62 -0
- package/dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- package/dist/assets/chunk-75Z2AOVW-DbtzyKUg.js +2 -0
- package/dist/assets/chunk-DU6HZSFF-C0fdbx3K.js +127 -0
- package/dist/assets/chunk-F27PBJKO-HObL2IvF.js +1 -0
- package/dist/assets/chunk-FOHPRMQF-DD4dKubD.js +161 -0
- package/dist/assets/chunk-GMAD6QVW-fg8wvtPY.js +72 -0
- package/dist/assets/chunk-GVQU2GXP-C0TaHOrD.js +1 -0
- package/dist/assets/chunk-IMKFNOWR-BVoIdx20.js +231 -0
- package/dist/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/dist/assets/chunk-L3NEJ4N5-B_kmqfk5.js +1 -0
- package/dist/assets/chunk-OSK3NFVY-DO0vhxHH.js +10 -0
- package/dist/assets/chunk-P2QGCYS3-CjljLvFj.js +1 -0
- package/dist/assets/chunk-POPQ4Y6H-BU0C7tw6.js +1 -0
- package/dist/assets/chunk-PWAF6VOD-Dn0OjBt0.js +1 -0
- package/dist/assets/chunk-SHT3W25Y-CMCZE2xx.js +168 -0
- package/dist/assets/chunk-SVP7TREG-BIRmRy_W.js +88 -0
- package/dist/assets/chunk-TICWLB2K-C1bc2CDE.js +206 -0
- package/dist/assets/chunk-XXDRQBXY-Cc38QUmR.js +1 -0
- package/dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/dist/assets/classDiagram-ZZMXUADV-BDh5w6Nc.js +1 -0
- package/dist/assets/classDiagram-v2-VYDZK3BY-BDh5w6Nc.js +1 -0
- package/dist/assets/cose-bilkent-JH36ORCC-B7pU7qhM.js +1 -0
- package/dist/assets/cynefin-OW5HDTMX-76dswSqS.js +1 -0
- package/dist/assets/cynefinDiagram-5FMLGOSQ-2kS4q01d.js +62 -0
- package/dist/assets/cytoscape.esm-BegBNzOV.js +321 -0
- package/dist/assets/dagre-D7JM2Yhv.js +1 -0
- package/dist/assets/dagre-GXQ25YYZ-B5Y21TQM.js +4 -0
- package/dist/assets/defaultLocale-BFoDCU3G.js +1 -0
- package/dist/assets/diagram-S7CK7UJ4-CY6td7Et.js +30 -0
- package/dist/assets/diagram-UQ7AKVKN-DmDqnGZf.js +41 -0
- package/dist/assets/diagram-VSXAHHWV-KGLWOOcE.js +3 -0
- package/dist/assets/diagram-VX7I27RA-D5syUraJ.js +24 -0
- package/dist/assets/diagram-Z3DM3KII-Dtrbs1Om.js +24 -0
- package/dist/assets/dist-Dce-2YbA.js +1 -0
- package/dist/assets/ebnfDiagram-PWID7BFC-CQpJLtU3.js +1 -0
- package/dist/assets/editor.worker-BmdWdrHZ.js +33 -0
- package/dist/assets/erDiagram-RLTQ6QDP-cMTzKLu_.js +99 -0
- package/dist/assets/eventmodeling-NTZA5JFV-CMzLdNaL.js +1 -0
- package/dist/assets/flowDiagram-HODETNUW-BMUajB-G.js +1 -0
- package/dist/assets/ganttDiagram-EL5Y4UJY-DseBS5Fs.js +292 -0
- package/dist/assets/gitGraph-4MIJSDKK-CUQZRpxJ.js +1 -0
- package/dist/assets/gitGraphDiagram-WWUBYQGX-CfMfsJ3b.js +106 -0
- package/dist/assets/graphlib-DS17s2tU.js +1 -0
- package/dist/assets/index-ByQ-XX38.css +1 -0
- package/dist/assets/index-CIf5TpfY.js +214 -0
- package/dist/assets/info-A6RAGUB7-D3nAKZ8M.js +1 -0
- package/dist/assets/infoDiagram-27XIBGKW-zu1O0WOy.js +2 -0
- package/dist/assets/init-C-OQMol4.js +1 -0
- package/dist/assets/ishikawaDiagram-5VMMS53U-DKC7BO9p.js +70 -0
- package/dist/assets/journeyDiagram-3NMN7TZE-Ld5mXse7.js +139 -0
- package/dist/assets/kanban-definition-UXKFOSKX-CH7_QlHL.js +89 -0
- package/dist/assets/katex-DJhrJSbw.js +257 -0
- package/dist/assets/line-N9XiCREw.js +1 -0
- package/dist/assets/linear-C9hnqmJv.js +1 -0
- package/dist/assets/mermaid-parser.core-DgPwV5Bh.js +7 -0
- package/dist/assets/mermaid.core-BKqynXLR.js +44 -0
- package/dist/assets/mindmap-definition-YA3MSWOX-DkiL-wiW.js +96 -0
- package/dist/assets/monaco-DjpsE8to.css +1 -0
- package/dist/assets/monaco-DqzJaNIe.js +908 -0
- package/dist/assets/ordinal-BDEzSJ7C.js +1 -0
- package/dist/assets/packet-AYTQ26CC-DuMTvpEJ.js +1 -0
- package/dist/assets/path-fybaL0A-.js +1 -0
- package/dist/assets/pegDiagram-XKGWAZYB-DvMl_xSe.js +1 -0
- package/dist/assets/pie-WAS4IAKB-Da0xPaD8.js +1 -0
- package/dist/assets/pieDiagram-E7YTZNPT-amANNRJY.js +39 -0
- package/dist/assets/quadrantDiagram-AXDQQJYC-BrgvDMnk.js +7 -0
- package/dist/assets/radar-RG4KPBEZ-Dz3Ih5-N.js +1 -0
- package/dist/assets/railroad-74A4TZTK-CKMW-IV2.js +1 -0
- package/dist/assets/railroad-abnf-HS5TGJTU-ChqmSWSF.js +1 -0
- package/dist/assets/railroad-ebnf-LZEXJU2U-V3R4fFdb.js +1 -0
- package/dist/assets/railroad-peg-WCYAUIDC-B-RuhUQW.js +1 -0
- package/dist/assets/railroadDiagram-O6MQD6OU-FjG-6OLu.js +1 -0
- package/dist/assets/requirementDiagram-BXWQKSXE-Cnj8RfE4.js +84 -0
- package/dist/assets/rolldown-runtime-XKyaHtl9.js +1 -0
- package/dist/assets/rough.esm-Dy-Kn_BL.js +1 -0
- package/dist/assets/sankeyDiagram-P5KCCOFB-DMu1fnEh.js +40 -0
- package/dist/assets/sequenceDiagram-WJ2MYXX4-CtCtaRpW.js +162 -0
- package/dist/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
- package/dist/assets/src-CGp3bfio.js +1 -0
- package/dist/assets/stateDiagram-D77RDMKH-xcJbLNhz.js +1 -0
- package/dist/assets/stateDiagram-v2-MP3YSRHH-DYHrQmJJ.js +1 -0
- package/dist/assets/swimlanes-42K2YHIH-BwLln_ga.js +1 -0
- package/dist/assets/swimlanesDiagram-VR7AAH4N-BcDfUQ0A.js +8 -0
- package/dist/assets/timeline-definition-24CTP7MA-ucNGsUUz.js +120 -0
- package/dist/assets/treeView-Q6P3EWNA-3uOomRue.js +1 -0
- package/dist/assets/treemap-WGGIJYW6-iGK7vwID.js +1 -0
- package/dist/assets/vennDiagram-4TSXK5OY-B9LgGe16.js +34 -0
- package/dist/assets/wardley-WFR3VGLG-FupMOf6k.js +1 -0
- package/dist/assets/wardleyDiagram-VM6X3IG4-CGZdEXM2.js +78 -0
- package/dist/assets/xterm-BrP-ENHg.css +1 -0
- package/dist/assets/xterm-C8zLTNGk.js +16 -0
- package/dist/assets/xychartDiagram-S5SC5T6Z-DafZrSBJ.js +7 -0
- package/dist/favicon.ico +0 -0
- package/dist/favicon.svg +6 -0
- package/dist/index.html +34 -0
- package/extensions/implement-goal-issue.ts +368 -0
- package/extensions/implement-next-epic.ts +835 -0
- package/index.html +28 -0
- package/install.sh +111 -0
- package/issues/control.ts +91 -0
- package/issues/guards.ts +12 -0
- package/issues/ledger.ts +122 -0
- package/issues/legacy.ts +68 -0
- package/issues/lock.ts +305 -0
- package/issues/paths.ts +76 -0
- package/issues/preflight.ts +189 -0
- package/issues/repository.ts +203 -0
- package/issues/scout/actions.ts +255 -0
- package/issues/scout/control.ts +80 -0
- package/issues/scout/github.ts +358 -0
- package/issues/scout/paths.ts +129 -0
- package/issues/scout/preflight.ts +277 -0
- package/issues/scout/recommendation.ts +400 -0
- package/issues/scout/scan.ts +143 -0
- package/issues/scout/state.ts +448 -0
- package/issues/scout/worker.ts +1282 -0
- package/issues/state.ts +584 -0
- package/issues/tracker.ts +271 -0
- package/issues/worker.ts +1065 -0
- package/lib/dependencies.ts +61 -0
- package/lib/forge-auth.ts +953 -0
- package/lib/forge.ts +141 -0
- package/lib/gitea.ts +709 -0
- package/lib/github-release.ts +318 -0
- package/lib/inventory.test.ts +79 -0
- package/lib/inventory.ts +53 -0
- package/lib/release.test.ts +269 -0
- package/lib/release.ts +801 -0
- package/omp/commands/adr-resolve.md +8 -0
- package/omp/commands/discover.md +6 -0
- package/omp/commands/epic-next.md +8 -0
- package/omp/commands/flow-change.md +8 -0
- package/omp/commands/flow-goal.md +8 -0
- package/omp/commands/flow-implement.md +8 -0
- package/omp/commands/flow-widget.md +8 -0
- package/omp/commands/goal-draft.md +8 -0
- package/omp/commands/goal-outcome.md +8 -0
- package/omp/commands/implement-issue.md +8 -0
- package/omp/commands/prepare-skills.md +6 -0
- package/omp/commands/scout-recommendations.md +8 -0
- package/omp/commands/setup-devboard.md +24 -0
- package/omp/config.yml +12 -0
- package/omp/extensions/implement-goal-issue.ts +2 -0
- package/omp/extensions/implement-next-epic.ts +2 -0
- package/omp/mcp.json +9 -0
- package/package.json +86 -7
- package/prompts/adr-resolve.md +130 -0
- package/prompts/discover.md +541 -0
- package/prompts/epic-next.md +533 -0
- package/prompts/flow-change.md +76 -0
- package/prompts/flow-goal.md +126 -0
- package/prompts/flow-implement.md +103 -0
- package/prompts/flow-widget.md +54 -0
- package/prompts/goal-draft.md +147 -0
- package/prompts/goal-outcome.md +87 -0
- package/prompts/implement-issue.md +66 -0
- package/prompts/prepare-skills.md +142 -0
- package/prompts/scout-recommendations.md +143 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/favicon.svg +6 -0
- package/server/acp.ts +540 -0
- package/server/activity.test.ts +96 -0
- package/server/activity.ts +48 -0
- package/server/app.test.ts +882 -0
- package/server/app.ts +6179 -0
- package/server/ask.test.ts +543 -0
- package/server/ask.ts +589 -0
- package/server/dependencies.test.ts +118 -0
- package/server/discover-remote.test.ts +1602 -0
- package/server/discover-sheet.test.ts +176 -0
- package/server/discover.test.ts +1510 -0
- package/server/discover.ts +3198 -0
- package/server/feedback.test.ts +458 -0
- package/server/feedback.ts +369 -0
- package/server/fixtures/adr-source.ts +71 -0
- package/server/fixtures/hang-download.ts +14 -0
- package/server/fixtures/stub-agent.ts +1870 -0
- package/server/fixtures/stub-forge.ts +141 -0
- package/server/fixtures/stub-gh.ts +57 -0
- package/server/flow-pr.test.ts +976 -0
- package/server/flow.test.ts +1632 -0
- package/server/flow.ts +2655 -0
- package/server/forge-pr.ts +387 -0
- package/server/goal-creation.test.ts +957 -0
- package/server/goal-draft.test.ts +348 -0
- package/server/goal-drafts.ts +449 -0
- package/server/goal-proposal.test.ts +479 -0
- package/server/goal-proposal.ts +232 -0
- package/server/goal-revision.test.ts +613 -0
- package/server/goal-slug.test.ts +56 -0
- package/server/goal-slug.ts +96 -0
- package/server/goal.ts +20 -0
- package/server/index.ts +147 -0
- package/server/issue-close.test.ts +100 -0
- package/server/issue-close.ts +178 -0
- package/server/issues.test.ts +167 -0
- package/server/issues.ts +479 -0
- package/server/journal.test.ts +350 -0
- package/server/journal.ts +329 -0
- package/server/lifecycle-pause.test.ts +1795 -0
- package/server/lifecycle.test.ts +1879 -0
- package/server/parallel-lifecycle.test.ts +1029 -0
- package/server/persistence-restart.test.ts +723 -0
- package/server/persistence.test.ts +1935 -0
- package/server/records.test.ts +180 -0
- package/server/records.ts +99 -0
- package/server/reset-implementation.test.ts +997 -0
- package/server/run.test.ts +611 -0
- package/server/scout.test.ts +877 -0
- package/server/scout.ts +459 -0
- package/server/skills-preparation.test.ts +1073 -0
- package/server/state.ts +249 -0
- package/server/tracker.ts +369 -0
- package/server/updates.test.ts +444 -0
- package/server/updates.ts +198 -0
- package/server/version.test.ts +140 -0
- package/server/version.ts +151 -0
- package/server/watchdog.ts +389 -0
- package/svelte.config.js +5 -0
- package/templates/host-AGENTS.md +235 -0
- package/tsconfig.json +21 -0
- package/vite.config.ts +21 -0
- package/watchdog/cleanup-main.ts +98 -0
- package/watchdog/cleanup.ts +301 -0
- package/watchdog/collect.ts +311 -0
- package/watchdog/coordinator.ts +397 -0
- package/watchdog/delivery.ts +107 -0
- package/watchdog/discovery.ts +209 -0
- package/watchdog/findings.ts +211 -0
- package/watchdog/github.ts +189 -0
- package/watchdog/history.ts +138 -0
- package/watchdog/install.ts +103 -0
- package/watchdog/ledger.ts +188 -0
- package/watchdog/lock.ts +63 -0
- package/watchdog/main.ts +106 -0
- package/watchdog/status.ts +71 -0
- package/watchdog/systemd.ts +96 -0
- package/watchdog/uninstall.ts +30 -0
- package/watchdog/units/devboard-watchdog.service +9 -0
- package/watchdog/units/devboard-watchdog.timer +10 -0
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from "svelte";
|
|
3
|
+
import {
|
|
4
|
+
conceptTitle,
|
|
5
|
+
contextTitle,
|
|
6
|
+
labelText,
|
|
7
|
+
labelTexts,
|
|
8
|
+
relativeTime,
|
|
9
|
+
TABS,
|
|
10
|
+
} from "../discover-format";
|
|
11
|
+
import { discover } from "../discover.svelte";
|
|
12
|
+
import type { WorkspaceTab } from "../layout.svelte";
|
|
13
|
+
import ConceptKind from "./ConceptKind.svelte";
|
|
14
|
+
import DataTable from "./DataTable.svelte";
|
|
15
|
+
import DiscoverOverview from "./DiscoverOverview.svelte";
|
|
16
|
+
import MonacoEditor from "./MonacoEditor.svelte";
|
|
17
|
+
import Button from "./ui/button.svelte";
|
|
18
|
+
import Input from "./ui/input.svelte";
|
|
19
|
+
|
|
20
|
+
interface Props {
|
|
21
|
+
tab: WorkspaceTab | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let { tab }: Props = $props();
|
|
25
|
+
|
|
26
|
+
const GLOSSARY_COLUMNS = [
|
|
27
|
+
{ id: "kind", header: "Kind", accessorKey: "kind" },
|
|
28
|
+
{ id: "title", header: "Term", accessorKey: "title" },
|
|
29
|
+
{ id: "significance", header: "Significance", accessorKey: "significance" },
|
|
30
|
+
{ id: "definition", header: "Definition", accessorKey: "definition" },
|
|
31
|
+
{ id: "examples", header: "", accessorKey: "examples" },
|
|
32
|
+
];
|
|
33
|
+
const GLOSSARY_WIDTHS = {
|
|
34
|
+
kind: "92px",
|
|
35
|
+
title: "210px",
|
|
36
|
+
significance: "104px",
|
|
37
|
+
examples: "240px",
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const activeSkill = $derived(tab?.kind === "skill" ? tab.resourceId : null);
|
|
41
|
+
const skill = $derived(activeSkill === null ? null : discover.skill(activeSkill));
|
|
42
|
+
const skillDraft = $derived(activeSkill === null ? "" : discover.skillDraft(activeSkill));
|
|
43
|
+
const skillTab = $derived(
|
|
44
|
+
activeSkill === null ? null : (TABS.find((entry) => entry.skill === activeSkill) ?? null),
|
|
45
|
+
);
|
|
46
|
+
const skillState = $derived(skill?.state ?? "missing");
|
|
47
|
+
const skillDirty = $derived(activeSkill === null ? false : discover.skillDirty(activeSkill));
|
|
48
|
+
|
|
49
|
+
const totalTerms = $derived(
|
|
50
|
+
discover.contexts.reduce(
|
|
51
|
+
(total, context) =>
|
|
52
|
+
total + context.concepts.filter((concept) => concept.status !== "invalidated").length,
|
|
53
|
+
0,
|
|
54
|
+
),
|
|
55
|
+
);
|
|
56
|
+
const visibleTerms = $derived(
|
|
57
|
+
discover.filteredContexts.reduce((total, context) => total + context.concepts.length, 0),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
function clearGlossaryFilters(): void {
|
|
61
|
+
discover.resetGlossaryFilters();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let now = $state(Date.now());
|
|
65
|
+
const startedLabel = $derived(
|
|
66
|
+
discover.startedAt === null ? "" : relativeTime(discover.startedAt, now),
|
|
67
|
+
);
|
|
68
|
+
const lastActivity = $derived(
|
|
69
|
+
[...discover.activity].reverse().find((line) => line.trim().length > 0)?.trim() ?? "",
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
onMount(() => {
|
|
73
|
+
const timer = setInterval(() => (now = Date.now()), 15_000);
|
|
74
|
+
return () => clearInterval(timer);
|
|
75
|
+
});
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
{#snippet runTag()}
|
|
79
|
+
{#if discover.active}
|
|
80
|
+
<div class="discover-run-tag" data-testid="discover-run-tag" role="status" aria-live="polite">
|
|
81
|
+
<span class="discover-run__dot" aria-hidden="true"></span>
|
|
82
|
+
<strong>Discover run in progress</strong>
|
|
83
|
+
{#if discover.startedAt !== null}
|
|
84
|
+
<span class="muted" title={discover.startedAt}>started {startedLabel}</span>
|
|
85
|
+
{/if}
|
|
86
|
+
{#if discover.runId !== null}
|
|
87
|
+
<code class="code-chip">{discover.runId}</code>
|
|
88
|
+
{/if}
|
|
89
|
+
{#if lastActivity.length > 0}
|
|
90
|
+
<span class="discover-run-tag__activity" title={lastActivity}>{lastActivity}</span>
|
|
91
|
+
{/if}
|
|
92
|
+
<button
|
|
93
|
+
type="button"
|
|
94
|
+
class="discover-run__stop"
|
|
95
|
+
title="Stop this Discover run"
|
|
96
|
+
data-command="discover.stop"
|
|
97
|
+
data-testid="discover-run-tag-stop"
|
|
98
|
+
onclick={() => discover.stop()}
|
|
99
|
+
>
|
|
100
|
+
Stop
|
|
101
|
+
</button>
|
|
102
|
+
</div>
|
|
103
|
+
{/if}
|
|
104
|
+
{/snippet}
|
|
105
|
+
|
|
106
|
+
{#snippet glossaryCell(row: Record<string, unknown>, columnId: string)}
|
|
107
|
+
{#if columnId === "kind"}
|
|
108
|
+
<ConceptKind kind={String(row.kind ?? "")} />
|
|
109
|
+
{:else if columnId === "title"}
|
|
110
|
+
<strong>{String(row.title ?? "")}</strong>
|
|
111
|
+
{:else if columnId === "significance"}
|
|
112
|
+
{#if typeof row.significance === "number"}
|
|
113
|
+
<span title={String(row.significanceReason ?? "")}>{row.significance}</span>
|
|
114
|
+
{:else}
|
|
115
|
+
<span class="muted">—</span>
|
|
116
|
+
{/if}
|
|
117
|
+
{:else if columnId === "examples"}
|
|
118
|
+
{#if Array.isArray(row.examples) && row.examples.length > 0}
|
|
119
|
+
{@const examples = row.examples as string[]}
|
|
120
|
+
<span class="discover-examples">
|
|
121
|
+
{#each examples as example, index (example)}
|
|
122
|
+
<span class="discover-examples__item">
|
|
123
|
+
<code class="code-chip">{example}</code>
|
|
124
|
+
{#if index < examples.length - 1}<span aria-hidden="true">,</span>{/if}
|
|
125
|
+
</span>
|
|
126
|
+
{/each}
|
|
127
|
+
</span>
|
|
128
|
+
{:else}
|
|
129
|
+
<span class="muted">—</span>
|
|
130
|
+
{/if}
|
|
131
|
+
{:else}
|
|
132
|
+
{String(row[columnId] ?? "")}
|
|
133
|
+
{/if}
|
|
134
|
+
{/snippet}
|
|
135
|
+
|
|
136
|
+
{#snippet notices()}
|
|
137
|
+
{#if discover.displayError !== null || discover.interrupted || discover.transition !== null}
|
|
138
|
+
<div class="discover-notices">
|
|
139
|
+
{#if discover.displayError !== null}
|
|
140
|
+
<p class="message" data-severity="error" data-testid="discover-error" role="alert">
|
|
141
|
+
{discover.displayError}
|
|
142
|
+
</p>
|
|
143
|
+
{/if}
|
|
144
|
+
{#if discover.interrupted}
|
|
145
|
+
<p class="message" data-severity="warning" data-testid="discover-interrupted">
|
|
146
|
+
The last Discover run was interrupted. Nothing was published; the previous artifacts are
|
|
147
|
+
unchanged.
|
|
148
|
+
</p>
|
|
149
|
+
{/if}
|
|
150
|
+
{#if discover.transition !== null && !discover.active}
|
|
151
|
+
<p class="message" data-severity="notice" data-testid="discover-transition" role="status">
|
|
152
|
+
{discover.transition}
|
|
153
|
+
</p>
|
|
154
|
+
{/if}
|
|
155
|
+
</div>
|
|
156
|
+
{/if}
|
|
157
|
+
{/snippet}
|
|
158
|
+
|
|
159
|
+
{#snippet glossaryPanel()}
|
|
160
|
+
<div
|
|
161
|
+
class="scroll-column discover-page"
|
|
162
|
+
data-testid="discover-panel"
|
|
163
|
+
data-tab="glossary"
|
|
164
|
+
aria-label="Discover glossary"
|
|
165
|
+
>
|
|
166
|
+
<header class="discover-page__header">
|
|
167
|
+
<div class="discover-page__heading">
|
|
168
|
+
<h1 class="discover-page__title">Glossary</h1>
|
|
169
|
+
<p class="discover-page__subtitle">
|
|
170
|
+
{visibleTerms} of {totalTerms} terms
|
|
171
|
+
{#if discover.glossaryHasScores && discover.glossarySignificantOnly}
|
|
172
|
+
at or above a significance floor of {discover.glossaryThreshold}
|
|
173
|
+
{:else if discover.glossaryHasScores}
|
|
174
|
+
with no significance floor applied
|
|
175
|
+
{:else}
|
|
176
|
+
with no significance scores published
|
|
177
|
+
{/if}
|
|
178
|
+
across {discover.contexts.length}
|
|
179
|
+
{discover.contexts.length === 1 ? "bounded context" : "bounded contexts"}.
|
|
180
|
+
</p>
|
|
181
|
+
</div>
|
|
182
|
+
<div class="discover-page__actions discover-glossary-controls">
|
|
183
|
+
<Input
|
|
184
|
+
id="discover-glossary-search"
|
|
185
|
+
class="discover-search"
|
|
186
|
+
type="search"
|
|
187
|
+
value={discover.glossarySearch}
|
|
188
|
+
oninput={(event) => discover.setGlossarySearch(event.currentTarget.value)}
|
|
189
|
+
placeholder="Search terms"
|
|
190
|
+
aria-label="Search glossary terms"
|
|
191
|
+
data-testid="discover-glossary-search"
|
|
192
|
+
/>
|
|
193
|
+
<div class="discover-glossary-filters">
|
|
194
|
+
<label class="discover-toggle">
|
|
195
|
+
<input
|
|
196
|
+
type="checkbox"
|
|
197
|
+
checked={discover.glossarySignificantOnly}
|
|
198
|
+
disabled={!discover.glossaryHasScores}
|
|
199
|
+
aria-label="Significant only"
|
|
200
|
+
data-testid="discover-glossary-significant"
|
|
201
|
+
onchange={(event) => discover.setGlossarySignificantOnly(event.currentTarget.checked)}
|
|
202
|
+
/>
|
|
203
|
+
<span class="discover-toggle__track" aria-hidden="true"></span>
|
|
204
|
+
<span class="discover-toggle__label">Significant only</span>
|
|
205
|
+
</label>
|
|
206
|
+
<span class="discover-glossary-divider" aria-hidden="true"></span>
|
|
207
|
+
<label class="discover-floor">
|
|
208
|
+
<span class="discover-floor__label">Floor</span>
|
|
209
|
+
<input
|
|
210
|
+
class="discover-floor__input"
|
|
211
|
+
type="range"
|
|
212
|
+
min="0"
|
|
213
|
+
max="100"
|
|
214
|
+
step="1"
|
|
215
|
+
value={discover.glossaryThreshold}
|
|
216
|
+
disabled={!discover.glossaryHasScores || !discover.glossarySignificantOnly}
|
|
217
|
+
aria-label="Significance floor a term needs to be listed"
|
|
218
|
+
data-testid="discover-glossary-threshold"
|
|
219
|
+
oninput={(event) => discover.setGlossaryThreshold(event.currentTarget.valueAsNumber)}
|
|
220
|
+
/>
|
|
221
|
+
<output class="discover-floor__value">≥ {discover.glossaryThreshold}</output>
|
|
222
|
+
</label>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
</header>
|
|
226
|
+
|
|
227
|
+
{#if discover.filteredContexts.length === 0}
|
|
228
|
+
<section class="panel discover-filter-empty" data-testid="discover-glossary-empty">
|
|
229
|
+
<div class="panel__body discover-filter-empty__body">
|
|
230
|
+
<p class="empty">
|
|
231
|
+
No term matches the current search and significance filter. The glossary is published;
|
|
232
|
+
only this view is filtered.
|
|
233
|
+
</p>
|
|
234
|
+
<Button variant="outline" onclick={clearGlossaryFilters}>Clear filters</Button>
|
|
235
|
+
</div>
|
|
236
|
+
</section>
|
|
237
|
+
{:else}
|
|
238
|
+
{#each discover.filteredContexts as context (context.boundedContext)}
|
|
239
|
+
<section
|
|
240
|
+
class="panel discover-card"
|
|
241
|
+
data-testid="discover-context"
|
|
242
|
+
data-context={context.boundedContext}
|
|
243
|
+
>
|
|
244
|
+
<div class="panel__header">
|
|
245
|
+
<h2 class="panel__title">{contextTitle(context)}</h2>
|
|
246
|
+
<span class="panel__subtitle">
|
|
247
|
+
{context.concepts.length} {context.concepts.length === 1 ? "term" : "terms"}
|
|
248
|
+
</span>
|
|
249
|
+
</div>
|
|
250
|
+
<div class="panel__body panel__body--flush">
|
|
251
|
+
<DataTable
|
|
252
|
+
columns={GLOSSARY_COLUMNS}
|
|
253
|
+
rows={context.concepts.map((concept) => {
|
|
254
|
+
const usage = discover.usageFor(context.boundedContext, concept.id);
|
|
255
|
+
const score = discover.significanceFor(context.boundedContext, concept.id);
|
|
256
|
+
return {
|
|
257
|
+
...concept,
|
|
258
|
+
title: conceptTitle(concept),
|
|
259
|
+
definition: labelText(concept.definitions) || "No definition recorded.",
|
|
260
|
+
significance: score?.score ?? null,
|
|
261
|
+
significanceReason: score?.reason ?? "",
|
|
262
|
+
examples: usage.examples,
|
|
263
|
+
};
|
|
264
|
+
})}
|
|
265
|
+
rowTestId="discover-term"
|
|
266
|
+
rowAttrs={(row) => ({
|
|
267
|
+
"data-context": context.boundedContext,
|
|
268
|
+
"data-id": String(row.id ?? ""),
|
|
269
|
+
"data-status": String(row.status ?? ""),
|
|
270
|
+
"data-kind": String(row.kind ?? ""),
|
|
271
|
+
"data-significance":
|
|
272
|
+
typeof row.significance === "number" ? String(row.significance) : "",
|
|
273
|
+
"data-examples": Array.isArray(row.examples) ? row.examples.join(",") : "",
|
|
274
|
+
})}
|
|
275
|
+
cell={glossaryCell}
|
|
276
|
+
columnWidths={GLOSSARY_WIDTHS}
|
|
277
|
+
full
|
|
278
|
+
wrap
|
|
279
|
+
/>
|
|
280
|
+
</div>
|
|
281
|
+
</section>
|
|
282
|
+
{/each}
|
|
283
|
+
{/if}
|
|
284
|
+
</div>
|
|
285
|
+
{/snippet}
|
|
286
|
+
|
|
287
|
+
{#snippet skillPanel()}
|
|
288
|
+
{#if activeSkill === null || skillTab === null}
|
|
289
|
+
<p class="empty">No skill selected.</p>
|
|
290
|
+
{:else}
|
|
291
|
+
<div
|
|
292
|
+
class="discover-skill-page"
|
|
293
|
+
data-testid="discover-panel"
|
|
294
|
+
data-tab={skillTab.id}
|
|
295
|
+
aria-label={skillTab.label}
|
|
296
|
+
>
|
|
297
|
+
<header class="discover-page__header discover-page__header--compact">
|
|
298
|
+
<div class="discover-page__heading">
|
|
299
|
+
<h1 class="discover-page__title">{skillTab.label}</h1>
|
|
300
|
+
</div>
|
|
301
|
+
</header>
|
|
302
|
+
|
|
303
|
+
<div class="discover-skill" data-testid="discover-skill" data-name={activeSkill}>
|
|
304
|
+
<div class="panel discover-skill__panel">
|
|
305
|
+
<div class="panel__header discover-skill__header">
|
|
306
|
+
<div class="discover-skill__identity">
|
|
307
|
+
<h2
|
|
308
|
+
class="panel__title mono discover-skill__title"
|
|
309
|
+
title={`${activeSkill}/SKILL.md`}
|
|
310
|
+
>
|
|
311
|
+
<span>{activeSkill}</span><span class="discover-skill__file">/SKILL.md</span>
|
|
312
|
+
</h2>
|
|
313
|
+
{#if skillDirty}
|
|
314
|
+
<span
|
|
315
|
+
class="discover-skill__state"
|
|
316
|
+
data-state="dirty"
|
|
317
|
+
data-testid="discover-skill-dirty"
|
|
318
|
+
>
|
|
319
|
+
Unsaved changes
|
|
320
|
+
</span>
|
|
321
|
+
{:else if skillState === "missing"}
|
|
322
|
+
<span
|
|
323
|
+
class="discover-skill__state"
|
|
324
|
+
data-state="missing"
|
|
325
|
+
data-testid="discover-skill-status"
|
|
326
|
+
>
|
|
327
|
+
Live file missing
|
|
328
|
+
</span>
|
|
329
|
+
{:else}
|
|
330
|
+
<span
|
|
331
|
+
class="discover-skill__state"
|
|
332
|
+
data-state="clean"
|
|
333
|
+
data-testid="discover-skill-status"
|
|
334
|
+
>
|
|
335
|
+
No unsaved changes
|
|
336
|
+
</span>
|
|
337
|
+
{/if}
|
|
338
|
+
</div>
|
|
339
|
+
<div class="row-sm discover-skill__actions">
|
|
340
|
+
<Button
|
|
341
|
+
variant="default"
|
|
342
|
+
data-command={`discover.skill.save.${activeSkill}`}
|
|
343
|
+
data-testid="discover-skill-save"
|
|
344
|
+
disabled={!skillDirty || skillState === "missing"}
|
|
345
|
+
title={skillState === "missing"
|
|
346
|
+
? "Recreate the generated version before saving."
|
|
347
|
+
: skillDirty
|
|
348
|
+
? "Save the skill file."
|
|
349
|
+
: "No unsaved changes."}
|
|
350
|
+
onclick={() => discover.saveSkill(activeSkill)}
|
|
351
|
+
>
|
|
352
|
+
Save
|
|
353
|
+
</Button>
|
|
354
|
+
{#if skillState !== "generated"}
|
|
355
|
+
<Button
|
|
356
|
+
variant="outline"
|
|
357
|
+
data-command={`discover.skill.restore.${activeSkill}`}
|
|
358
|
+
data-testid="discover-skill-restore"
|
|
359
|
+
title={skillState === "missing"
|
|
360
|
+
? "Recreate the skill from its generated version."
|
|
361
|
+
: "Discard your edits and return to the generated version."}
|
|
362
|
+
onclick={() => discover.restoreSkill(activeSkill)}
|
|
363
|
+
>
|
|
364
|
+
{skillState === "missing" ? "Recreate generated version" : "Discard edits"}
|
|
365
|
+
</Button>
|
|
366
|
+
{/if}
|
|
367
|
+
</div>
|
|
368
|
+
</div>
|
|
369
|
+
<div class="grow">
|
|
370
|
+
<MonacoEditor
|
|
371
|
+
value={skillDraft}
|
|
372
|
+
label={`${activeSkill} skill text`}
|
|
373
|
+
data-testid="discover-skill-text"
|
|
374
|
+
dirty={skillDirty}
|
|
375
|
+
onchange={(text) => discover.updateDraft(activeSkill, text)}
|
|
376
|
+
onsave={() => discover.saveSkill(activeSkill)}
|
|
377
|
+
/>
|
|
378
|
+
</div>
|
|
379
|
+
</div>
|
|
380
|
+
</div>
|
|
381
|
+
</div>
|
|
382
|
+
{/if}
|
|
383
|
+
{/snippet}
|
|
384
|
+
|
|
385
|
+
{#snippet warningsPanel()}
|
|
386
|
+
<div
|
|
387
|
+
class="scroll-column discover-page"
|
|
388
|
+
data-testid="discover-panel"
|
|
389
|
+
data-tab="warnings"
|
|
390
|
+
aria-label="Discover warnings"
|
|
391
|
+
>
|
|
392
|
+
<header class="discover-page__header">
|
|
393
|
+
<div class="discover-page__heading">
|
|
394
|
+
<h1 class="discover-page__title">Warnings</h1>
|
|
395
|
+
<p class="discover-page__subtitle">
|
|
396
|
+
{discover.displayedWarnings.length}
|
|
397
|
+
{discover.displayedWarnings.length === 1 ? "warning" : "warnings"} recorded while
|
|
398
|
+
validating the published artifacts.
|
|
399
|
+
</p>
|
|
400
|
+
</div>
|
|
401
|
+
</header>
|
|
402
|
+
|
|
403
|
+
<section class="panel">
|
|
404
|
+
<div class="panel__header">
|
|
405
|
+
<h2 class="panel__title">Artifact warnings</h2>
|
|
406
|
+
</div>
|
|
407
|
+
<div class="panel__body panel__body--flush">
|
|
408
|
+
{#if discover.displayedWarnings.length === 0}
|
|
409
|
+
<p class="empty">No warnings. The published artifacts validated cleanly.</p>
|
|
410
|
+
{:else}
|
|
411
|
+
<ol class="discover-warning-list">
|
|
412
|
+
{#each discover.displayedWarnings as warning, index (index)}
|
|
413
|
+
<li class="discover-warning" data-testid="discover-warning">{warning}</li>
|
|
414
|
+
{/each}
|
|
415
|
+
</ol>
|
|
416
|
+
{/if}
|
|
417
|
+
</div>
|
|
418
|
+
</section>
|
|
419
|
+
</div>
|
|
420
|
+
{/snippet}
|
|
421
|
+
|
|
422
|
+
<div class="mode-body discover-body">
|
|
423
|
+
{@render runTag()}
|
|
424
|
+
{@render notices()}
|
|
425
|
+
|
|
426
|
+
{#if tab === null}
|
|
427
|
+
<p class="empty">No page is open. Choose Overview or Glossary from the sidebar.</p>
|
|
428
|
+
{:else if tab.kind === "overview"}
|
|
429
|
+
<DiscoverOverview />
|
|
430
|
+
{:else if tab.kind === "glossary"}
|
|
431
|
+
{@render glossaryPanel()}
|
|
432
|
+
{:else if tab.kind === "skill"}
|
|
433
|
+
{@render skillPanel()}
|
|
434
|
+
{:else if tab.kind === "warnings"}
|
|
435
|
+
{@render warningsPanel()}
|
|
436
|
+
{/if}
|
|
437
|
+
</div>
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from "svelte";
|
|
3
|
+
import { draftProposal } from "../draft-format";
|
|
4
|
+
import { issues, markDraftsPage } from "../issues.svelte";
|
|
5
|
+
import { statusTone } from "../status-tone";
|
|
6
|
+
import Button from "./ui/button.svelte";
|
|
7
|
+
import IssuesAgentLog from "./IssuesAgentLog.svelte";
|
|
8
|
+
import IssuesQuestion from "./IssuesQuestion.svelte";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The Draft goals surface. It mounts only while the Draft goals tab is active, so its
|
|
12
|
+
* refresh loop stops with the page. Opening the page restores the stored
|
|
13
|
+
* draft path; a path whose file vanished resolves to the list.
|
|
14
|
+
*/
|
|
15
|
+
const proposal = $derived(draftProposal(issues.draft?.text ?? ""));
|
|
16
|
+
|
|
17
|
+
// The header reports this draft's run only; another draft's run is not this draft's state.
|
|
18
|
+
const run = $derived(
|
|
19
|
+
issues.draft !== null && issues.draftRun?.path === issues.draft.path ? issues.draftRun : null,
|
|
20
|
+
);
|
|
21
|
+
const status = $derived(run?.status ?? "idle");
|
|
22
|
+
const running = $derived(run?.status === "running");
|
|
23
|
+
const question = $derived(run?.question ?? null);
|
|
24
|
+
const error = $derived(issues.draftError ?? run?.error ?? null);
|
|
25
|
+
|
|
26
|
+
onMount(() => {
|
|
27
|
+
markDraftsPage(true);
|
|
28
|
+
const restore = (): void => {
|
|
29
|
+
const saved = issues.draftPath;
|
|
30
|
+
if (saved !== null && issues.draft === null) issues.openDraft(saved);
|
|
31
|
+
};
|
|
32
|
+
issues.refreshDrafts();
|
|
33
|
+
restore();
|
|
34
|
+
const timer = setInterval(() => {
|
|
35
|
+
issues.refreshDrafts();
|
|
36
|
+
restore();
|
|
37
|
+
}, 2000);
|
|
38
|
+
return () => {
|
|
39
|
+
clearInterval(timer);
|
|
40
|
+
markDraftsPage(false);
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<section class="issues-drafts-page" data-testid="issues-drafts" aria-label="Goal drafts">
|
|
46
|
+
<header class="issues-overview__header">
|
|
47
|
+
<div>
|
|
48
|
+
<h1 class="issues-overview__title">Draft goals</h1>
|
|
49
|
+
<p class="issues-overview__repo mono">
|
|
50
|
+
{issues.draftStatus} · {issues.drafts.length} draft(s)
|
|
51
|
+
</p>
|
|
52
|
+
</div>
|
|
53
|
+
</header>
|
|
54
|
+
<div class="issues-drafts__body">
|
|
55
|
+
<section class="panel">
|
|
56
|
+
<div class="panel__header">
|
|
57
|
+
<h2 class="panel__title">Proposed goals</h2>
|
|
58
|
+
<span class="panel__subtitle">{issues.repoLabel}</span>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="panel__body panel__body--flush">
|
|
61
|
+
<ol class="issues-drafts" data-testid="issues-draft-list">
|
|
62
|
+
{#each issues.drafts as draft (draft.path)}
|
|
63
|
+
{@const blocker = issues.draftStartBlocker(draft.path)}
|
|
64
|
+
<li>
|
|
65
|
+
<button
|
|
66
|
+
type="button"
|
|
67
|
+
class="issues-draft"
|
|
68
|
+
data-testid="issues-draft"
|
|
69
|
+
data-path={draft.path}
|
|
70
|
+
data-command="issues.draft.open"
|
|
71
|
+
aria-current={issues.draftPath === draft.path}
|
|
72
|
+
onclick={() => issues.openDraft(draft.path)}
|
|
73
|
+
>
|
|
74
|
+
<span class="mono">{draft.name}</span>
|
|
75
|
+
<span class="issues-draft__heading">{draft.heading || "No heading"}</span>
|
|
76
|
+
{#if blocker !== null}
|
|
77
|
+
<span class="issues-draft__blocked" data-testid="issues-draft-blocked">{blocker}</span>
|
|
78
|
+
{/if}
|
|
79
|
+
</button>
|
|
80
|
+
</li>
|
|
81
|
+
{:else}
|
|
82
|
+
<li class="issues-drafts__empty muted" data-testid="issues-drafts-empty">
|
|
83
|
+
No drafts exist.
|
|
84
|
+
</li>
|
|
85
|
+
{/each}
|
|
86
|
+
</ol>
|
|
87
|
+
</div>
|
|
88
|
+
</section>
|
|
89
|
+
|
|
90
|
+
{#if issues.draft !== null}
|
|
91
|
+
<section
|
|
92
|
+
class="panel issues-draft-detail"
|
|
93
|
+
data-testid="issues-draft-detail"
|
|
94
|
+
data-path={issues.draft.path}
|
|
95
|
+
>
|
|
96
|
+
<div class="issues-draft-detail__header">
|
|
97
|
+
<div class="issues-draft-detail__identity">
|
|
98
|
+
<span class="issues-draft-detail__path mono" title={issues.draft.path}>
|
|
99
|
+
{issues.draft.name}
|
|
100
|
+
</span>
|
|
101
|
+
</div>
|
|
102
|
+
<div class="issues-draft-detail__actions">
|
|
103
|
+
{#if status !== "idle"}
|
|
104
|
+
<span
|
|
105
|
+
class="badge"
|
|
106
|
+
data-tone={statusTone(status)}
|
|
107
|
+
data-testid="issues-draft-state"
|
|
108
|
+
>
|
|
109
|
+
{status}
|
|
110
|
+
</span>
|
|
111
|
+
{/if}
|
|
112
|
+
<Button
|
|
113
|
+
variant="default"
|
|
114
|
+
data-testid="issues-draft-start"
|
|
115
|
+
data-command="issues.draft.start"
|
|
116
|
+
disabled={issues.draftRunning}
|
|
117
|
+
title={issues.draftStartBlocker(issues.draft.path) ?? "Start the elaboration agent"}
|
|
118
|
+
onclick={() => issues.startDraft()}
|
|
119
|
+
>
|
|
120
|
+
Start elaboration
|
|
121
|
+
</Button>
|
|
122
|
+
{#if running}
|
|
123
|
+
<Button
|
|
124
|
+
variant="ghost"
|
|
125
|
+
class="issues-draft-detail__stop"
|
|
126
|
+
data-testid="issues-draft-stop"
|
|
127
|
+
data-command="issues.draft.stop"
|
|
128
|
+
onclick={() => issues.stopDraft()}
|
|
129
|
+
>
|
|
130
|
+
Stop
|
|
131
|
+
</Button>
|
|
132
|
+
{/if}
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
<div class="issues-draft-detail__body">
|
|
136
|
+
{#if error !== null}
|
|
137
|
+
<p class="issues-error" data-testid="issues-draft-error" role="alert">{error}</p>
|
|
138
|
+
{/if}
|
|
139
|
+
{#if question !== null}
|
|
140
|
+
<section
|
|
141
|
+
class="issues-draft-detail__question"
|
|
142
|
+
aria-label="Elaboration question"
|
|
143
|
+
>
|
|
144
|
+
<h3 class="issues-draft-detail__label issues-draft-detail__label--warning">
|
|
145
|
+
Elaboration question
|
|
146
|
+
</h3>
|
|
147
|
+
<IssuesQuestion
|
|
148
|
+
question={question}
|
|
149
|
+
testid="issues-draft-question"
|
|
150
|
+
onanswer={(value) => issues.submitDraftAnswer(value)}
|
|
151
|
+
choiceTestid="issues-draft-choice"
|
|
152
|
+
inputTestid="issues-draft-answer-input"
|
|
153
|
+
submitTestid="issues-draft-answer-submit"
|
|
154
|
+
command="issues.draft.answer"
|
|
155
|
+
/>
|
|
156
|
+
</section>
|
|
157
|
+
{/if}
|
|
158
|
+
<section class="issues-draft-detail__section" aria-label="Draft">
|
|
159
|
+
{#if proposal.length > 0}
|
|
160
|
+
<pre class="issues-draft-detail__prose mono">{proposal}</pre>
|
|
161
|
+
{:else}
|
|
162
|
+
<p class="issues-draft-detail__empty">This draft holds no proposal text yet.</p>
|
|
163
|
+
{/if}
|
|
164
|
+
</section>
|
|
165
|
+
{#if run !== null}
|
|
166
|
+
<section
|
|
167
|
+
class="issues-draft-detail__section issues-draft-detail__section--activity"
|
|
168
|
+
aria-label="Elaboration activity"
|
|
169
|
+
>
|
|
170
|
+
<h3 class="issues-draft-detail__label">Elaboration activity</h3>
|
|
171
|
+
<IssuesAgentLog lines={run.activity} testid="issues-draft-activity" />
|
|
172
|
+
</section>
|
|
173
|
+
{/if}
|
|
174
|
+
</div>
|
|
175
|
+
</section>
|
|
176
|
+
{:else}
|
|
177
|
+
<section class="panel">
|
|
178
|
+
<div class="panel__body">
|
|
179
|
+
<p class="muted" data-testid="issues-drafts-selection">
|
|
180
|
+
Select a draft to read it and elaborate it.
|
|
181
|
+
</p>
|
|
182
|
+
</div>
|
|
183
|
+
</section>
|
|
184
|
+
{/if}
|
|
185
|
+
</div>
|
|
186
|
+
</section>
|