forkit-connect 0.1.1 → 0.1.3
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/dist/cli.js +83 -36
- package/dist/launcher.js +1451 -15
- package/dist/v1/service.d.ts +2 -0
- package/dist/v1/service.js +32 -15
- package/package.json +8 -8
package/dist/launcher.js
CHANGED
|
@@ -793,7 +793,7 @@ function buildDiscovery(service) {
|
|
|
793
793
|
return {
|
|
794
794
|
id: entry.item_id,
|
|
795
795
|
kind: 'runtime',
|
|
796
|
-
selector:
|
|
796
|
+
selector: runtimeGaid,
|
|
797
797
|
inboxGroup: group,
|
|
798
798
|
name: runtime.runtime_name,
|
|
799
799
|
subtitle: `${formatRuntimeType(runtime.runtime_type)} • ${formatEndpointLabel(runtime.source_endpoint_label)}`,
|
|
@@ -1680,6 +1680,379 @@ function renderLauncherHtml(launcherToken) {
|
|
|
1680
1680
|
z-index: 130;
|
|
1681
1681
|
}
|
|
1682
1682
|
|
|
1683
|
+
.quick-review-anchor {
|
|
1684
|
+
position: relative;
|
|
1685
|
+
flex: 0 1 344px;
|
|
1686
|
+
min-width: 0;
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
.quick-review-chip {
|
|
1690
|
+
width: 100%;
|
|
1691
|
+
min-height: 74px;
|
|
1692
|
+
border: 1px solid rgba(241, 235, 223, 0.22);
|
|
1693
|
+
border-radius: 24px;
|
|
1694
|
+
background:
|
|
1695
|
+
radial-gradient(circle at 100% 0%, rgba(106, 167, 171, 0.2), transparent 36%),
|
|
1696
|
+
linear-gradient(135deg, rgba(30, 25, 47, 0.97) 0%, rgba(17, 20, 31, 0.985) 100%);
|
|
1697
|
+
color: #f7efe4;
|
|
1698
|
+
display: flex;
|
|
1699
|
+
align-items: center;
|
|
1700
|
+
gap: 14px;
|
|
1701
|
+
padding: 14px 16px;
|
|
1702
|
+
cursor: pointer;
|
|
1703
|
+
box-shadow:
|
|
1704
|
+
0 22px 38px rgba(7, 10, 24, 0.3),
|
|
1705
|
+
inset 0 1px 0 rgba(255,255,255,0.08);
|
|
1706
|
+
text-align: left;
|
|
1707
|
+
transition: transform 160ms ease, border-color 160ms ease, box-shadow 160ms ease;
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
.quick-review-chip:hover {
|
|
1711
|
+
border-color: rgba(157, 238, 245, 0.34);
|
|
1712
|
+
transform: translateY(-1px);
|
|
1713
|
+
box-shadow:
|
|
1714
|
+
0 26px 46px rgba(7, 10, 24, 0.34),
|
|
1715
|
+
inset 0 1px 0 rgba(255,255,255,0.1);
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
.quick-review-chip:focus-visible,
|
|
1719
|
+
.quick-review-primary:focus-visible,
|
|
1720
|
+
.quick-review-options-button:focus-visible,
|
|
1721
|
+
.quick-review-field select:focus-visible,
|
|
1722
|
+
.quick-review-options-menu button:focus-visible {
|
|
1723
|
+
outline: 2px solid rgba(157, 238, 245, 0.72);
|
|
1724
|
+
outline-offset: 2px;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
.quick-review-count {
|
|
1728
|
+
width: 34px;
|
|
1729
|
+
height: 34px;
|
|
1730
|
+
border-radius: 12px;
|
|
1731
|
+
display: inline-flex;
|
|
1732
|
+
align-items: center;
|
|
1733
|
+
justify-content: center;
|
|
1734
|
+
font-family: "Sora", sans-serif;
|
|
1735
|
+
font-size: 0.92rem;
|
|
1736
|
+
font-weight: 700;
|
|
1737
|
+
color: #0b1220;
|
|
1738
|
+
background: linear-gradient(135deg, rgba(157, 238, 245, 0.96) 0%, rgba(244, 147, 85, 0.92) 100%);
|
|
1739
|
+
flex: 0 0 auto;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
.quick-review-chip-copy {
|
|
1743
|
+
min-width: 0;
|
|
1744
|
+
display: flex;
|
|
1745
|
+
flex-direction: column;
|
|
1746
|
+
gap: 3px;
|
|
1747
|
+
flex: 1 1 auto;
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
.quick-review-chip-title {
|
|
1751
|
+
font-family: "Sora", sans-serif;
|
|
1752
|
+
font-size: 0.98rem;
|
|
1753
|
+
line-height: 1.15;
|
|
1754
|
+
letter-spacing: -0.01em;
|
|
1755
|
+
color: #fff7ea;
|
|
1756
|
+
white-space: nowrap;
|
|
1757
|
+
overflow: hidden;
|
|
1758
|
+
text-overflow: ellipsis;
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
.quick-review-chip-meta {
|
|
1762
|
+
font-size: 0.8rem;
|
|
1763
|
+
line-height: 1.25;
|
|
1764
|
+
color: rgba(241, 235, 223, 0.72);
|
|
1765
|
+
white-space: nowrap;
|
|
1766
|
+
overflow: hidden;
|
|
1767
|
+
text-overflow: ellipsis;
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
.quick-review-chip-caret {
|
|
1771
|
+
font-size: 0.82rem;
|
|
1772
|
+
color: rgba(241, 235, 223, 0.7);
|
|
1773
|
+
flex: 0 0 auto;
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
.quick-review-panel-shell {
|
|
1777
|
+
position: absolute;
|
|
1778
|
+
top: calc(100% + 10px);
|
|
1779
|
+
right: 0;
|
|
1780
|
+
width: min(420px, calc(100vw - 48px));
|
|
1781
|
+
z-index: 260;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
.quick-review-card {
|
|
1785
|
+
display: grid;
|
|
1786
|
+
gap: 14px;
|
|
1787
|
+
padding: 18px;
|
|
1788
|
+
border-radius: 26px;
|
|
1789
|
+
border: 1px solid rgba(241, 235, 223, 0.16);
|
|
1790
|
+
background:
|
|
1791
|
+
radial-gradient(circle at 100% 0%, rgba(106, 167, 171, 0.18), transparent 38%),
|
|
1792
|
+
linear-gradient(135deg, rgba(24, 22, 38, 0.98) 0%, rgba(17, 19, 30, 0.985) 100%);
|
|
1793
|
+
box-shadow:
|
|
1794
|
+
0 28px 56px rgba(7, 10, 24, 0.42),
|
|
1795
|
+
inset 0 1px 0 rgba(255,255,255,0.07);
|
|
1796
|
+
color: #f7efe4;
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
.quick-review-summary-grid {
|
|
1800
|
+
display: grid;
|
|
1801
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
1802
|
+
gap: 10px;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
.quick-review-summary-pill {
|
|
1806
|
+
display: grid;
|
|
1807
|
+
gap: 4px;
|
|
1808
|
+
padding: 11px 12px;
|
|
1809
|
+
border-radius: 16px;
|
|
1810
|
+
border: 1px solid rgba(241, 235, 223, 0.1);
|
|
1811
|
+
background: rgba(255,255,255,0.045);
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
.quick-review-summary-label {
|
|
1815
|
+
font-size: 0.68rem;
|
|
1816
|
+
text-transform: uppercase;
|
|
1817
|
+
letter-spacing: 0.12em;
|
|
1818
|
+
font-weight: 700;
|
|
1819
|
+
color: rgba(241, 235, 223, 0.55);
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
.quick-review-summary-value {
|
|
1823
|
+
font-size: 0.86rem;
|
|
1824
|
+
line-height: 1.35;
|
|
1825
|
+
color: #fff7ea;
|
|
1826
|
+
font-weight: 600;
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
.quick-review-topline {
|
|
1830
|
+
display: flex;
|
|
1831
|
+
align-items: flex-start;
|
|
1832
|
+
justify-content: space-between;
|
|
1833
|
+
gap: 10px;
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
.quick-review-kicker {
|
|
1837
|
+
margin: 0;
|
|
1838
|
+
font-size: 0.72rem;
|
|
1839
|
+
text-transform: uppercase;
|
|
1840
|
+
letter-spacing: 0.12em;
|
|
1841
|
+
font-weight: 700;
|
|
1842
|
+
color: rgba(157, 238, 245, 0.84);
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
.quick-review-title {
|
|
1846
|
+
margin: 4px 0 0;
|
|
1847
|
+
font-family: "Sora", sans-serif;
|
|
1848
|
+
font-size: 1.22rem;
|
|
1849
|
+
line-height: 1.12;
|
|
1850
|
+
letter-spacing: -0.02em;
|
|
1851
|
+
color: #fff8ef;
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
.quick-review-badge {
|
|
1855
|
+
flex: 0 0 auto;
|
|
1856
|
+
display: inline-flex;
|
|
1857
|
+
align-items: center;
|
|
1858
|
+
gap: 6px;
|
|
1859
|
+
min-height: 36px;
|
|
1860
|
+
padding: 0 14px;
|
|
1861
|
+
border-radius: 999px;
|
|
1862
|
+
border: 1px solid rgba(157, 238, 245, 0.26);
|
|
1863
|
+
background: rgba(55, 68, 86, 0.42);
|
|
1864
|
+
color: rgba(157, 238, 245, 0.96);
|
|
1865
|
+
font-family: "Sora", sans-serif;
|
|
1866
|
+
font-size: 0.88rem;
|
|
1867
|
+
font-weight: 700;
|
|
1868
|
+
letter-spacing: 0.08em;
|
|
1869
|
+
text-transform: uppercase;
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
.quick-review-meta,
|
|
1873
|
+
.quick-review-detail {
|
|
1874
|
+
margin: 0;
|
|
1875
|
+
font-size: 0.92rem;
|
|
1876
|
+
line-height: 1.5;
|
|
1877
|
+
color: rgba(241, 235, 223, 0.78);
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
.quick-review-status {
|
|
1881
|
+
border-radius: 16px;
|
|
1882
|
+
padding: 12px 14px;
|
|
1883
|
+
border: 1px solid rgba(202, 188, 255, 0.12);
|
|
1884
|
+
background: rgba(255,255,255,0.04);
|
|
1885
|
+
color: rgba(241, 235, 223, 0.8);
|
|
1886
|
+
font-size: 0.88rem;
|
|
1887
|
+
line-height: 1.45;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
.quick-review-status.ok {
|
|
1891
|
+
color: #c7ffe4;
|
|
1892
|
+
border-color: rgba(63, 208, 143, 0.3);
|
|
1893
|
+
background: rgba(63, 208, 143, 0.12);
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
.quick-review-status.warn {
|
|
1897
|
+
color: #ffe0be;
|
|
1898
|
+
border-color: rgba(244, 147, 85, 0.28);
|
|
1899
|
+
background: rgba(244, 147, 85, 0.12);
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
.quick-review-status.error {
|
|
1903
|
+
color: #ffd1d7;
|
|
1904
|
+
border-color: rgba(255, 108, 134, 0.28);
|
|
1905
|
+
background: rgba(255, 108, 134, 0.12);
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
.quick-review-scope {
|
|
1909
|
+
display: grid;
|
|
1910
|
+
gap: 10px;
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
.quick-review-scope-grid {
|
|
1914
|
+
display: grid;
|
|
1915
|
+
grid-template-columns: 1fr 1fr;
|
|
1916
|
+
gap: 10px;
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
.quick-review-field {
|
|
1920
|
+
display: grid;
|
|
1921
|
+
gap: 6px;
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
.quick-review-field label {
|
|
1925
|
+
font-size: 0.74rem;
|
|
1926
|
+
text-transform: uppercase;
|
|
1927
|
+
letter-spacing: 0.08em;
|
|
1928
|
+
font-weight: 700;
|
|
1929
|
+
color: rgba(241, 235, 223, 0.62);
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
.quick-review-field select {
|
|
1933
|
+
appearance: none;
|
|
1934
|
+
width: 100%;
|
|
1935
|
+
min-height: 46px;
|
|
1936
|
+
border-radius: 14px;
|
|
1937
|
+
border: 1px solid rgba(202, 188, 255, 0.16);
|
|
1938
|
+
background: rgba(23, 19, 48, 0.66);
|
|
1939
|
+
color: #fff8ef;
|
|
1940
|
+
padding: 0 14px;
|
|
1941
|
+
font-size: 0.92rem;
|
|
1942
|
+
outline: none;
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
.quick-review-actions {
|
|
1946
|
+
display: grid;
|
|
1947
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
1948
|
+
gap: 10px;
|
|
1949
|
+
align-items: start;
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
.quick-review-primary {
|
|
1953
|
+
min-height: 52px;
|
|
1954
|
+
border: 1px solid rgba(157, 238, 245, 0.2);
|
|
1955
|
+
border-radius: 16px;
|
|
1956
|
+
background: linear-gradient(135deg, rgba(157, 238, 245, 0.92) 0%, rgba(244, 147, 85, 0.88) 100%);
|
|
1957
|
+
color: #1e1638;
|
|
1958
|
+
font-family: "Sora", sans-serif;
|
|
1959
|
+
font-size: 0.95rem;
|
|
1960
|
+
font-weight: 700;
|
|
1961
|
+
cursor: pointer;
|
|
1962
|
+
padding: 0 16px;
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
.quick-review-primary:disabled,
|
|
1966
|
+
.quick-review-options-button:disabled {
|
|
1967
|
+
opacity: 0.45;
|
|
1968
|
+
cursor: not-allowed;
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
.quick-review-options-wrap {
|
|
1972
|
+
position: relative;
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
.quick-review-options-button {
|
|
1976
|
+
min-height: 52px;
|
|
1977
|
+
padding: 0 16px;
|
|
1978
|
+
border-radius: 16px;
|
|
1979
|
+
border: 1px solid rgba(241, 235, 223, 0.14);
|
|
1980
|
+
background: rgba(255,255,255,0.05);
|
|
1981
|
+
color: #fff7ea;
|
|
1982
|
+
font-size: 0.92rem;
|
|
1983
|
+
font-weight: 600;
|
|
1984
|
+
cursor: pointer;
|
|
1985
|
+
min-width: 122px;
|
|
1986
|
+
transition: background 160ms ease, border-color 160ms ease;
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
.quick-review-options-button:hover {
|
|
1990
|
+
background: rgba(255,255,255,0.08);
|
|
1991
|
+
border-color: rgba(157, 238, 245, 0.22);
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
.quick-review-options-menu {
|
|
1995
|
+
position: absolute;
|
|
1996
|
+
top: calc(100% + 8px);
|
|
1997
|
+
right: 0;
|
|
1998
|
+
min-width: 214px;
|
|
1999
|
+
display: grid;
|
|
2000
|
+
gap: 6px;
|
|
2001
|
+
padding: 10px;
|
|
2002
|
+
border-radius: 18px;
|
|
2003
|
+
border: 1px solid rgba(241, 235, 223, 0.12);
|
|
2004
|
+
background: rgba(19, 20, 31, 0.98);
|
|
2005
|
+
box-shadow: 0 22px 44px rgba(7, 10, 24, 0.38);
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
.quick-review-options-menu button {
|
|
2009
|
+
min-height: 46px;
|
|
2010
|
+
border-radius: 12px;
|
|
2011
|
+
border: 1px solid transparent;
|
|
2012
|
+
background: rgba(255,255,255,0.04);
|
|
2013
|
+
color: #f7efe4;
|
|
2014
|
+
text-align: left;
|
|
2015
|
+
padding: 10px 12px;
|
|
2016
|
+
font-size: 0.9rem;
|
|
2017
|
+
font-weight: 600;
|
|
2018
|
+
cursor: pointer;
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
.quick-review-options-menu button[hidden] {
|
|
2022
|
+
display: none;
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
.quick-review-menu-copy {
|
|
2026
|
+
display: grid;
|
|
2027
|
+
gap: 2px;
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
.quick-review-menu-label {
|
|
2031
|
+
font-size: 0.9rem;
|
|
2032
|
+
line-height: 1.25;
|
|
2033
|
+
color: #fff7ea;
|
|
2034
|
+
font-weight: 600;
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
.quick-review-menu-meta {
|
|
2038
|
+
font-size: 0.76rem;
|
|
2039
|
+
line-height: 1.3;
|
|
2040
|
+
color: rgba(241, 235, 223, 0.58);
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
.quick-review-options-menu button:hover {
|
|
2044
|
+
background: rgba(106, 167, 171, 0.14);
|
|
2045
|
+
border-color: rgba(106, 167, 171, 0.26);
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
.quick-review-options-menu button.danger {
|
|
2049
|
+
color: #ffd4da;
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
.quick-review-options-menu button.danger .quick-review-menu-label {
|
|
2053
|
+
color: #ffd4da;
|
|
2054
|
+
}
|
|
2055
|
+
|
|
1683
2056
|
.status-chip {
|
|
1684
2057
|
display: flex;
|
|
1685
2058
|
align-items: center;
|
|
@@ -4315,13 +4688,144 @@ function renderLauncherHtml(launcherToken) {
|
|
|
4315
4688
|
text-align: right;
|
|
4316
4689
|
}
|
|
4317
4690
|
|
|
4318
|
-
.discovery-review-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
border:
|
|
4324
|
-
|
|
4691
|
+
.discovery-review-panel {
|
|
4692
|
+
display: flex;
|
|
4693
|
+
flex-direction: column;
|
|
4694
|
+
gap: 14px;
|
|
4695
|
+
padding: 16px;
|
|
4696
|
+
border-radius: 22px;
|
|
4697
|
+
border: 1px solid rgba(202, 188, 255, 0.16);
|
|
4698
|
+
background:
|
|
4699
|
+
radial-gradient(circle at 100% 0%, rgba(126,214,224,0.14), transparent 28%),
|
|
4700
|
+
linear-gradient(180deg, rgba(255,255,255,0.07), rgba(255,255,255,0.03));
|
|
4701
|
+
box-shadow: inset 0 1px 0 rgba(255,255,255,0.07);
|
|
4702
|
+
}
|
|
4703
|
+
|
|
4704
|
+
.discovery-review-kicker {
|
|
4705
|
+
margin: 0;
|
|
4706
|
+
font-size: 0.72rem;
|
|
4707
|
+
text-transform: uppercase;
|
|
4708
|
+
letter-spacing: 0.12em;
|
|
4709
|
+
font-weight: 700;
|
|
4710
|
+
color: rgba(157, 238, 245, 0.84);
|
|
4711
|
+
}
|
|
4712
|
+
|
|
4713
|
+
.discovery-review-title {
|
|
4714
|
+
margin: 0;
|
|
4715
|
+
font-family: "Sora", sans-serif;
|
|
4716
|
+
font-size: 1.22rem;
|
|
4717
|
+
line-height: 1.15;
|
|
4718
|
+
color: #fff8ef;
|
|
4719
|
+
}
|
|
4720
|
+
|
|
4721
|
+
.discovery-review-meta {
|
|
4722
|
+
margin: 0;
|
|
4723
|
+
color: rgba(241, 235, 223, 0.72);
|
|
4724
|
+
font-size: 0.92rem;
|
|
4725
|
+
line-height: 1.45;
|
|
4726
|
+
}
|
|
4727
|
+
|
|
4728
|
+
.discovery-review-detail {
|
|
4729
|
+
margin: 0;
|
|
4730
|
+
color: rgba(241, 235, 223, 0.84);
|
|
4731
|
+
font-size: 0.96rem;
|
|
4732
|
+
line-height: 1.55;
|
|
4733
|
+
}
|
|
4734
|
+
|
|
4735
|
+
.discovery-review-status {
|
|
4736
|
+
border-radius: 16px;
|
|
4737
|
+
padding: 12px 14px;
|
|
4738
|
+
border: 1px solid rgba(202, 188, 255, 0.12);
|
|
4739
|
+
background: rgba(255,255,255,0.04);
|
|
4740
|
+
color: rgba(241, 235, 223, 0.78);
|
|
4741
|
+
font-size: 0.9rem;
|
|
4742
|
+
line-height: 1.45;
|
|
4743
|
+
}
|
|
4744
|
+
|
|
4745
|
+
.discovery-review-status.ok {
|
|
4746
|
+
color: #c7ffe4;
|
|
4747
|
+
border-color: rgba(63, 208, 143, 0.3);
|
|
4748
|
+
background: rgba(63, 208, 143, 0.12);
|
|
4749
|
+
}
|
|
4750
|
+
|
|
4751
|
+
.discovery-review-status.warn {
|
|
4752
|
+
color: #ffe0be;
|
|
4753
|
+
border-color: rgba(244, 147, 85, 0.28);
|
|
4754
|
+
background: rgba(244, 147, 85, 0.12);
|
|
4755
|
+
}
|
|
4756
|
+
|
|
4757
|
+
.discovery-review-status.error {
|
|
4758
|
+
color: #ffd1d7;
|
|
4759
|
+
border-color: rgba(255, 108, 134, 0.28);
|
|
4760
|
+
background: rgba(255, 108, 134, 0.12);
|
|
4761
|
+
}
|
|
4762
|
+
|
|
4763
|
+
.discovery-review-scope {
|
|
4764
|
+
display: grid;
|
|
4765
|
+
gap: 12px;
|
|
4766
|
+
}
|
|
4767
|
+
|
|
4768
|
+
.discovery-review-scope-grid {
|
|
4769
|
+
display: grid;
|
|
4770
|
+
grid-template-columns: 1fr 1fr;
|
|
4771
|
+
gap: 10px;
|
|
4772
|
+
}
|
|
4773
|
+
|
|
4774
|
+
.discovery-review-field {
|
|
4775
|
+
display: grid;
|
|
4776
|
+
gap: 6px;
|
|
4777
|
+
}
|
|
4778
|
+
|
|
4779
|
+
.discovery-review-field label {
|
|
4780
|
+
font-size: 0.78rem;
|
|
4781
|
+
text-transform: uppercase;
|
|
4782
|
+
letter-spacing: 0.08em;
|
|
4783
|
+
font-weight: 700;
|
|
4784
|
+
color: rgba(241, 235, 223, 0.64);
|
|
4785
|
+
}
|
|
4786
|
+
|
|
4787
|
+
.discovery-review-field select {
|
|
4788
|
+
appearance: none;
|
|
4789
|
+
width: 100%;
|
|
4790
|
+
min-height: 48px;
|
|
4791
|
+
border-radius: 14px;
|
|
4792
|
+
border: 1px solid rgba(202, 188, 255, 0.16);
|
|
4793
|
+
background: rgba(23, 19, 48, 0.64);
|
|
4794
|
+
color: #fff8ef;
|
|
4795
|
+
padding: 0 14px;
|
|
4796
|
+
font-size: 0.94rem;
|
|
4797
|
+
outline: none;
|
|
4798
|
+
}
|
|
4799
|
+
|
|
4800
|
+
.discovery-review-actions {
|
|
4801
|
+
display: grid;
|
|
4802
|
+
grid-template-columns: 1fr 1fr;
|
|
4803
|
+
gap: 10px;
|
|
4804
|
+
}
|
|
4805
|
+
|
|
4806
|
+
.discovery-review-actions .primary {
|
|
4807
|
+
min-height: 52px;
|
|
4808
|
+
}
|
|
4809
|
+
|
|
4810
|
+
.discovery-review-actions .secondary {
|
|
4811
|
+
min-height: 52px;
|
|
4812
|
+
}
|
|
4813
|
+
|
|
4814
|
+
.discovery-review-actions .danger {
|
|
4815
|
+
min-height: 48px;
|
|
4816
|
+
border-radius: 14px;
|
|
4817
|
+
border: 1px solid rgba(255, 108, 134, 0.28);
|
|
4818
|
+
background: linear-gradient(180deg, rgba(110, 28, 46, 0.72), rgba(70, 18, 33, 0.88));
|
|
4819
|
+
color: #fff0f3;
|
|
4820
|
+
}
|
|
4821
|
+
|
|
4822
|
+
.discovery-review-button {
|
|
4823
|
+
width: 100%;
|
|
4824
|
+
margin-top: auto;
|
|
4825
|
+
min-height: 54px;
|
|
4826
|
+
border-radius: 18px;
|
|
4827
|
+
border: 1px solid rgba(249, 193, 140, 0.35);
|
|
4828
|
+
background: linear-gradient(90deg, rgba(111, 91, 198, 0.72), rgba(244, 147, 85, 0.72));
|
|
4325
4829
|
color: #fff8ef;
|
|
4326
4830
|
}
|
|
4327
4831
|
|
|
@@ -5818,6 +6322,79 @@ function renderLauncherHtml(launcherToken) {
|
|
|
5818
6322
|
<div class="launch-scope-menu" id="project-select-menu" role="menu" hidden></div>
|
|
5819
6323
|
</div>
|
|
5820
6324
|
|
|
6325
|
+
<div class="quick-review-anchor" id="quick-review-anchor" hidden>
|
|
6326
|
+
<button class="quick-review-chip" id="quick-review-toggle" type="button" aria-expanded="false" aria-controls="quick-review-panel">
|
|
6327
|
+
<span class="quick-review-count" id="quick-review-count">0</span>
|
|
6328
|
+
<span class="quick-review-chip-copy">
|
|
6329
|
+
<span class="quick-review-chip-title" id="quick-review-chip-title">No review needed</span>
|
|
6330
|
+
<span class="quick-review-chip-meta" id="quick-review-chip-meta">Everything looks clear</span>
|
|
6331
|
+
</span>
|
|
6332
|
+
<span class="quick-review-chip-caret">▾</span>
|
|
6333
|
+
</button>
|
|
6334
|
+
<div class="quick-review-panel-shell" id="quick-review-panel" hidden>
|
|
6335
|
+
<section class="quick-review-card">
|
|
6336
|
+
<div class="quick-review-topline">
|
|
6337
|
+
<div>
|
|
6338
|
+
<p class="quick-review-kicker" id="quick-review-kicker">Review item</p>
|
|
6339
|
+
<h3 class="quick-review-title" id="quick-review-title">Open Connect review</h3>
|
|
6340
|
+
</div>
|
|
6341
|
+
<span class="quick-review-badge" id="quick-review-badge">Review</span>
|
|
6342
|
+
</div>
|
|
6343
|
+
<p class="quick-review-meta" id="quick-review-meta">Open Connect to approve or defer this item.</p>
|
|
6344
|
+
<p class="quick-review-detail" id="quick-review-detail">Nothing is registered automatically.</p>
|
|
6345
|
+
<div class="quick-review-summary-grid">
|
|
6346
|
+
<div class="quick-review-summary-pill">
|
|
6347
|
+
<span class="quick-review-summary-label">Action</span>
|
|
6348
|
+
<span class="quick-review-summary-value" id="quick-review-action-summary">Approve and register</span>
|
|
6349
|
+
</div>
|
|
6350
|
+
<div class="quick-review-summary-pill">
|
|
6351
|
+
<span class="quick-review-summary-label">Scope</span>
|
|
6352
|
+
<span class="quick-review-summary-value" id="quick-review-scope-summary">Account scope</span>
|
|
6353
|
+
</div>
|
|
6354
|
+
</div>
|
|
6355
|
+
<div class="quick-review-status" id="quick-review-status">Waiting for review.</div>
|
|
6356
|
+
<div class="quick-review-scope" id="quick-review-scope" hidden>
|
|
6357
|
+
<div class="quick-review-scope-grid">
|
|
6358
|
+
<div class="quick-review-field">
|
|
6359
|
+
<label for="quick-review-workspace">Workspace</label>
|
|
6360
|
+
<select id="quick-review-workspace"></select>
|
|
6361
|
+
</div>
|
|
6362
|
+
<div class="quick-review-field">
|
|
6363
|
+
<label for="quick-review-project">Project</label>
|
|
6364
|
+
<select id="quick-review-project"></select>
|
|
6365
|
+
</div>
|
|
6366
|
+
</div>
|
|
6367
|
+
</div>
|
|
6368
|
+
<div class="quick-review-actions">
|
|
6369
|
+
<button class="quick-review-primary" id="quick-review-primary" type="button" disabled>Approve and register</button>
|
|
6370
|
+
<div class="quick-review-options-wrap">
|
|
6371
|
+
<button class="quick-review-options-button" id="quick-review-options" type="button" aria-expanded="false" aria-controls="quick-review-options-menu" disabled>Options ▾</button>
|
|
6372
|
+
<div class="quick-review-options-menu" id="quick-review-options-menu" hidden>
|
|
6373
|
+
<button id="quick-review-open-discovery" type="button">
|
|
6374
|
+
<span class="quick-review-menu-copy">
|
|
6375
|
+
<span class="quick-review-menu-label">Open full review</span>
|
|
6376
|
+
<span class="quick-review-menu-meta">See the full local discovery context.</span>
|
|
6377
|
+
</span>
|
|
6378
|
+
</button>
|
|
6379
|
+
<button id="quick-review-defer" type="button">
|
|
6380
|
+
<span class="quick-review-menu-copy">
|
|
6381
|
+
<span class="quick-review-menu-label">Not now (24h)</span>
|
|
6382
|
+
<span class="quick-review-menu-meta">Hide this prompt until tomorrow.</span>
|
|
6383
|
+
</span>
|
|
6384
|
+
</button>
|
|
6385
|
+
<button id="quick-review-ignore" class="danger" type="button">
|
|
6386
|
+
<span class="quick-review-menu-copy">
|
|
6387
|
+
<span class="quick-review-menu-label">Ignore locally</span>
|
|
6388
|
+
<span class="quick-review-menu-meta">Keep it out of this device review queue.</span>
|
|
6389
|
+
</span>
|
|
6390
|
+
</button>
|
|
6391
|
+
</div>
|
|
6392
|
+
</div>
|
|
6393
|
+
</div>
|
|
6394
|
+
</section>
|
|
6395
|
+
</div>
|
|
6396
|
+
</div>
|
|
6397
|
+
|
|
5821
6398
|
<div class="launch-account">
|
|
5822
6399
|
<button class="launch-account-btn" id="user-chip-btn" type="button" aria-expanded="false" aria-controls="account-dropdown-menu">
|
|
5823
6400
|
<span class="user-chip" id="header-avatar">
|
|
@@ -6170,6 +6747,31 @@ function renderLauncherHtml(launcherToken) {
|
|
|
6170
6747
|
<h3 class="discovery-side-title">Discovery intelligence</h3>
|
|
6171
6748
|
<p class="discovery-side-copy">We automatically scan your environment and understand the systems running locally.</p>
|
|
6172
6749
|
|
|
6750
|
+
<section class="discovery-review-panel" id="discovery-review-panel">
|
|
6751
|
+
<p class="discovery-review-kicker" id="discovery-review-kicker">Review item</p>
|
|
6752
|
+
<h4 class="discovery-review-title" id="discovery-review-title">Select a discovery item</h4>
|
|
6753
|
+
<p class="discovery-review-meta" id="discovery-review-meta">Choose a model, agent, or runtime to review it here.</p>
|
|
6754
|
+
<p class="discovery-review-detail" id="discovery-review-detail">Registering creates or updates a Forkit Passport. Nothing is published automatically.</p>
|
|
6755
|
+
<div class="discovery-review-status" id="discovery-review-status">Select an item to continue.</div>
|
|
6756
|
+
<div class="discovery-review-scope" id="discovery-review-scope" hidden>
|
|
6757
|
+
<div class="discovery-review-scope-grid">
|
|
6758
|
+
<div class="discovery-review-field">
|
|
6759
|
+
<label for="discovery-review-workspace">Workspace</label>
|
|
6760
|
+
<select id="discovery-review-workspace"></select>
|
|
6761
|
+
</div>
|
|
6762
|
+
<div class="discovery-review-field">
|
|
6763
|
+
<label for="discovery-review-project">Project</label>
|
|
6764
|
+
<select id="discovery-review-project"></select>
|
|
6765
|
+
</div>
|
|
6766
|
+
</div>
|
|
6767
|
+
</div>
|
|
6768
|
+
<div class="discovery-review-actions">
|
|
6769
|
+
<button class="primary" id="discovery-review-primary" type="button" disabled>Review</button>
|
|
6770
|
+
<button class="secondary" id="discovery-review-defer" type="button" disabled>Defer 24h</button>
|
|
6771
|
+
<button class="danger" id="discovery-review-ignore" type="button" disabled>Ignore</button>
|
|
6772
|
+
</div>
|
|
6773
|
+
</section>
|
|
6774
|
+
|
|
6173
6775
|
<ul class="discovery-note-list">
|
|
6174
6776
|
<li><span class="discovery-note-label"><span class="discovery-note-icon ok">✓</span>Local detection</span><span class="discovery-note-value" id="disc-check-local">-</span></li>
|
|
6175
6777
|
<li><span class="discovery-note-label"><span class="discovery-note-icon ok">✓</span>Metadata extraction</span><span class="discovery-note-value" id="disc-check-meta">-</span></li>
|
|
@@ -6611,16 +7213,21 @@ function renderLauncherHtml(launcherToken) {
|
|
|
6611
7213
|
let settingsTab = 'profile';
|
|
6612
7214
|
let currentView = 'command';
|
|
6613
7215
|
let initialRouteApplied = false;
|
|
7216
|
+
let initialRouteFocusApplied = false;
|
|
6614
7217
|
const ALL_SCOPE_VALUE = '__all__';
|
|
6615
7218
|
let selectedWorkspaceScope = ALL_SCOPE_VALUE;
|
|
6616
7219
|
let selectedProjectScope = ALL_SCOPE_VALUE;
|
|
6617
7220
|
let scopeAccessSnapshot = null;
|
|
7221
|
+
let reviewScopeCacheKey = null;
|
|
7222
|
+
let quickReviewScopeCacheKey = null;
|
|
6618
7223
|
|
|
6619
7224
|
function setText(id, value, className) {
|
|
6620
7225
|
const element = document.getElementById(id);
|
|
6621
7226
|
if (!element) return;
|
|
6622
7227
|
element.textContent = value;
|
|
6623
|
-
|
|
7228
|
+
if (className !== undefined) {
|
|
7229
|
+
element.className = className ? className : '';
|
|
7230
|
+
}
|
|
6624
7231
|
}
|
|
6625
7232
|
|
|
6626
7233
|
function setActivityMessage(message, tone) {
|
|
@@ -6651,6 +7258,14 @@ function renderLauncherHtml(launcherToken) {
|
|
|
6651
7258
|
window.history.replaceState({}, '', nextUrl);
|
|
6652
7259
|
}
|
|
6653
7260
|
|
|
7261
|
+
function readSelectedOptionLabel(select) {
|
|
7262
|
+
if (!select) return '';
|
|
7263
|
+
const option = select.options && select.selectedIndex >= 0
|
|
7264
|
+
? select.options[select.selectedIndex]
|
|
7265
|
+
: null;
|
|
7266
|
+
return option ? String(option.textContent || '').trim() : '';
|
|
7267
|
+
}
|
|
7268
|
+
|
|
6654
7269
|
function focusPassportByGaid(passportGaid, options) {
|
|
6655
7270
|
const gaid = String(passportGaid || '').trim();
|
|
6656
7271
|
if (!gaid) return false;
|
|
@@ -6683,6 +7298,562 @@ function renderLauncherHtml(launcherToken) {
|
|
|
6683
7298
|
return false;
|
|
6684
7299
|
}
|
|
6685
7300
|
|
|
7301
|
+
function getSelectedDiscoveryItem(itemsOverride) {
|
|
7302
|
+
const items = Array.isArray(itemsOverride)
|
|
7303
|
+
? itemsOverride
|
|
7304
|
+
: latestDiscovery && Array.isArray(latestDiscovery.items)
|
|
7305
|
+
? latestDiscovery.items
|
|
7306
|
+
: [];
|
|
7307
|
+
if (!items.length) return null;
|
|
7308
|
+
if (selectedDiscoveryId) {
|
|
7309
|
+
const selected = items.find((entry) => entry.id === selectedDiscoveryId);
|
|
7310
|
+
if (selected) return selected;
|
|
7311
|
+
}
|
|
7312
|
+
selectedDiscoveryId = items[0].id;
|
|
7313
|
+
return items[0];
|
|
7314
|
+
}
|
|
7315
|
+
|
|
7316
|
+
function setDiscoveryReviewStatus(message, tone) {
|
|
7317
|
+
const status = document.getElementById('discovery-review-status');
|
|
7318
|
+
if (!status) return;
|
|
7319
|
+
status.textContent = message || '';
|
|
7320
|
+
status.className = 'discovery-review-status' + (tone ? ' ' + tone : '');
|
|
7321
|
+
}
|
|
7322
|
+
|
|
7323
|
+
function canReviewRegister(item) {
|
|
7324
|
+
return Boolean(item && (item.kind === 'model' || item.kind === 'agent') && item.inboxGroup !== 'ignored');
|
|
7325
|
+
}
|
|
7326
|
+
|
|
7327
|
+
function canReviewDefer(item) {
|
|
7328
|
+
return Boolean(item && (item.kind === 'model' || item.kind === 'runtime') && item.inboxGroup !== 'ignored');
|
|
7329
|
+
}
|
|
7330
|
+
|
|
7331
|
+
function canReviewIgnore(item) {
|
|
7332
|
+
return Boolean(item && (item.kind === 'model' || item.kind === 'runtime') && item.inboxGroup !== 'ignored');
|
|
7333
|
+
}
|
|
7334
|
+
|
|
7335
|
+
function getQuickReviewItems() {
|
|
7336
|
+
const items = latestDiscovery && Array.isArray(latestDiscovery.items) ? latestDiscovery.items : [];
|
|
7337
|
+
return items.filter((item) => item && item.inboxGroup !== 'ignored' && (item.kind === 'model' || item.kind === 'agent' || item.kind === 'runtime'));
|
|
7338
|
+
}
|
|
7339
|
+
|
|
7340
|
+
function getQuickReviewItem() {
|
|
7341
|
+
const items = getQuickReviewItems();
|
|
7342
|
+
if (selectedDiscoveryId) {
|
|
7343
|
+
const selected = items.find((item) => item.id === selectedDiscoveryId);
|
|
7344
|
+
if (selected) return selected;
|
|
7345
|
+
}
|
|
7346
|
+
return items.find((item) => item.statusTone === 'error')
|
|
7347
|
+
|| items.find((item) => item.inboxGroup === 'needs_confirmation')
|
|
7348
|
+
|| items.find((item) => item.statusTone === 'warn')
|
|
7349
|
+
|| items[0]
|
|
7350
|
+
|| null;
|
|
7351
|
+
}
|
|
7352
|
+
|
|
7353
|
+
function setQuickReviewStatus(message, tone) {
|
|
7354
|
+
const status = document.getElementById('quick-review-status');
|
|
7355
|
+
if (!status) return;
|
|
7356
|
+
status.textContent = message || '';
|
|
7357
|
+
status.className = 'quick-review-status' + (tone ? ' ' + tone : '');
|
|
7358
|
+
}
|
|
7359
|
+
|
|
7360
|
+
function setQuickReviewOptionsOpen(open) {
|
|
7361
|
+
const button = document.getElementById('quick-review-options');
|
|
7362
|
+
const menu = document.getElementById('quick-review-options-menu');
|
|
7363
|
+
if (!button || !menu) return;
|
|
7364
|
+
menu.hidden = !open;
|
|
7365
|
+
button.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
7366
|
+
}
|
|
7367
|
+
|
|
7368
|
+
function setQuickReviewPanelOpen(open) {
|
|
7369
|
+
const toggle = document.getElementById('quick-review-toggle');
|
|
7370
|
+
const panel = document.getElementById('quick-review-panel');
|
|
7371
|
+
if (!toggle || !panel) return;
|
|
7372
|
+
panel.hidden = !open;
|
|
7373
|
+
toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
7374
|
+
if (currentView === 'command') {
|
|
7375
|
+
const item = getQuickReviewItem();
|
|
7376
|
+
updateRoute('command', open
|
|
7377
|
+
? {
|
|
7378
|
+
focus: 'review',
|
|
7379
|
+
...(item ? { item: item.id } : {}),
|
|
7380
|
+
}
|
|
7381
|
+
: {});
|
|
7382
|
+
}
|
|
7383
|
+
if (!open) {
|
|
7384
|
+
setQuickReviewOptionsOpen(false);
|
|
7385
|
+
}
|
|
7386
|
+
}
|
|
7387
|
+
|
|
7388
|
+
function updateQuickReviewScopeSummary(governedMode) {
|
|
7389
|
+
const workspaceSelect = document.getElementById('quick-review-workspace');
|
|
7390
|
+
const projectSelect = document.getElementById('quick-review-project');
|
|
7391
|
+
const workspaceId = workspaceSelect ? String(workspaceSelect.value || '').trim() : '';
|
|
7392
|
+
const projectId = projectSelect ? String(projectSelect.value || '').trim() : '';
|
|
7393
|
+
const workspaceLabel = readSelectedOptionLabel(workspaceSelect);
|
|
7394
|
+
const projectLabel = readSelectedOptionLabel(projectSelect);
|
|
7395
|
+
if (!workspaceId) {
|
|
7396
|
+
setText('quick-review-scope-summary', governedMode ? 'Choose governed scope' : 'Account scope');
|
|
7397
|
+
return;
|
|
7398
|
+
}
|
|
7399
|
+
if (!projectId) {
|
|
7400
|
+
setText('quick-review-scope-summary', workspaceLabel ? (workspaceLabel + ' · choose project') : 'Choose project');
|
|
7401
|
+
return;
|
|
7402
|
+
}
|
|
7403
|
+
setText('quick-review-scope-summary', [workspaceLabel, projectLabel].filter(Boolean).join(' · ') || 'Governed project');
|
|
7404
|
+
}
|
|
7405
|
+
|
|
7406
|
+
async function loadQuickReviewProjects(workspaceId, selectedProjectId, governedMode) {
|
|
7407
|
+
const projectSelect = document.getElementById('quick-review-project');
|
|
7408
|
+
const primaryButton = document.getElementById('quick-review-primary');
|
|
7409
|
+
if (!projectSelect) return;
|
|
7410
|
+
if (!workspaceId) {
|
|
7411
|
+
setScopeOptions(projectSelect, [{ id: '', label: governedMode ? 'Choose workspace first' : 'Account scope / no project' }], '');
|
|
7412
|
+
if (primaryButton) primaryButton.disabled = governedMode;
|
|
7413
|
+
updateQuickReviewScopeSummary(governedMode);
|
|
7414
|
+
return;
|
|
7415
|
+
}
|
|
7416
|
+
setScopeOptions(projectSelect, [{ id: '', label: 'Loading projects...' }], '');
|
|
7417
|
+
try {
|
|
7418
|
+
const response = await apiFetch('/api/scope/projects?workspaceId=' + encodeURIComponent(workspaceId));
|
|
7419
|
+
const payload = await response.json();
|
|
7420
|
+
const projects = payload.ok && Array.isArray(payload.projects) ? payload.projects : [];
|
|
7421
|
+
const options = projects.length
|
|
7422
|
+
? projects.map((project) => ({ id: project.id, label: project.name || project.id }))
|
|
7423
|
+
: [{ id: '', label: 'No projects found' }];
|
|
7424
|
+
setScopeOptions(projectSelect, options, selectedProjectId || (options[0] && options[0].id) || '');
|
|
7425
|
+
if (!payload.ok) {
|
|
7426
|
+
setQuickReviewStatus(payload.message || 'Project list is unavailable right now.', 'warn');
|
|
7427
|
+
} else if (!projects.length) {
|
|
7428
|
+
setQuickReviewStatus('Create a project in this workspace before registering here.', 'warn');
|
|
7429
|
+
}
|
|
7430
|
+
if (primaryButton) {
|
|
7431
|
+
primaryButton.disabled = !projects.length;
|
|
7432
|
+
}
|
|
7433
|
+
updateQuickReviewScopeSummary(governedMode);
|
|
7434
|
+
} catch {
|
|
7435
|
+
setScopeOptions(projectSelect, [{ id: '', label: 'Project list unavailable' }], '');
|
|
7436
|
+
setQuickReviewStatus('Project list is unavailable right now.', 'warn');
|
|
7437
|
+
if (primaryButton) {
|
|
7438
|
+
primaryButton.disabled = true;
|
|
7439
|
+
}
|
|
7440
|
+
updateQuickReviewScopeSummary(governedMode);
|
|
7441
|
+
}
|
|
7442
|
+
}
|
|
7443
|
+
|
|
7444
|
+
async function renderQuickReviewNotice() {
|
|
7445
|
+
const anchor = document.getElementById('quick-review-anchor');
|
|
7446
|
+
const item = getQuickReviewItem();
|
|
7447
|
+
const total = getQuickReviewItems().length;
|
|
7448
|
+
const scopeWrap = document.getElementById('quick-review-scope');
|
|
7449
|
+
const workspaceSelect = document.getElementById('quick-review-workspace');
|
|
7450
|
+
const projectSelect = document.getElementById('quick-review-project');
|
|
7451
|
+
const primaryButton = document.getElementById('quick-review-primary');
|
|
7452
|
+
const optionsButton = document.getElementById('quick-review-options');
|
|
7453
|
+
const openDiscoveryButton = document.getElementById('quick-review-open-discovery');
|
|
7454
|
+
const deferButton = document.getElementById('quick-review-defer');
|
|
7455
|
+
const ignoreButton = document.getElementById('quick-review-ignore');
|
|
7456
|
+
|
|
7457
|
+
if (!anchor) return;
|
|
7458
|
+
if (!item || !total) {
|
|
7459
|
+
anchor.hidden = true;
|
|
7460
|
+
setQuickReviewPanelOpen(false);
|
|
7461
|
+
quickReviewScopeCacheKey = null;
|
|
7462
|
+
return;
|
|
7463
|
+
}
|
|
7464
|
+
|
|
7465
|
+
anchor.hidden = false;
|
|
7466
|
+
setText('quick-review-count', String(total));
|
|
7467
|
+
setText('quick-review-chip-title', item.name);
|
|
7468
|
+
setText('quick-review-chip-meta', total > 1 ? (String(total) + ' items need review') : (item.statusMeta || item.statusLabel));
|
|
7469
|
+
setText('quick-review-kicker', item.typeLabel || item.kind);
|
|
7470
|
+
setText('quick-review-title', item.name);
|
|
7471
|
+
setText('quick-review-badge', item.kind === 'runtime' ? 'Runtime' : item.kind === 'agent' ? 'Agent' : 'Model');
|
|
7472
|
+
setText('quick-review-meta', item.subtitle + ' · ' + item.source);
|
|
7473
|
+
setText('quick-review-detail', item.detailSummary || item.statusMeta || 'Review local metadata, then decide what happens next.');
|
|
7474
|
+
setQuickReviewStatus(item.statusLabel + (item.statusMeta ? ' · ' + item.statusMeta : ''), item.statusTone === 'muted' ? '' : item.statusTone);
|
|
7475
|
+
|
|
7476
|
+
const opensExisting = item.kind === 'runtime' || item.actionLabel === 'Open' || item.actionLabel === 'Review';
|
|
7477
|
+
const primaryLabel = item.kind === 'runtime'
|
|
7478
|
+
? 'Open runtime review'
|
|
7479
|
+
: opensExisting
|
|
7480
|
+
? (item.passportGaid || item.matchedPassportGaid ? 'Open passport' : 'Review in context')
|
|
7481
|
+
: 'Approve & register';
|
|
7482
|
+
setText(
|
|
7483
|
+
'quick-review-action-summary',
|
|
7484
|
+
item.kind === 'runtime'
|
|
7485
|
+
? 'Open runtime lane'
|
|
7486
|
+
: opensExisting
|
|
7487
|
+
? (item.passportGaid || item.matchedPassportGaid ? 'Open linked passport' : 'Open full review')
|
|
7488
|
+
: 'Approve and register here',
|
|
7489
|
+
);
|
|
7490
|
+
if (primaryButton) {
|
|
7491
|
+
primaryButton.textContent = primaryLabel;
|
|
7492
|
+
primaryButton.disabled = item.inboxGroup === 'ignored';
|
|
7493
|
+
}
|
|
7494
|
+
if (optionsButton) {
|
|
7495
|
+
optionsButton.disabled = false;
|
|
7496
|
+
}
|
|
7497
|
+
if (openDiscoveryButton) {
|
|
7498
|
+
openDiscoveryButton.hidden = false;
|
|
7499
|
+
}
|
|
7500
|
+
if (deferButton) {
|
|
7501
|
+
deferButton.hidden = !canReviewDefer(item);
|
|
7502
|
+
}
|
|
7503
|
+
if (ignoreButton) {
|
|
7504
|
+
ignoreButton.hidden = !canReviewIgnore(item);
|
|
7505
|
+
}
|
|
7506
|
+
|
|
7507
|
+
const needsScope = canReviewRegister(item);
|
|
7508
|
+
if (!needsScope) {
|
|
7509
|
+
if (scopeWrap) scopeWrap.hidden = true;
|
|
7510
|
+
quickReviewScopeCacheKey = null;
|
|
7511
|
+
setText('quick-review-scope-summary', item.kind === 'runtime' ? 'Open runtime review' : 'Full review available');
|
|
7512
|
+
return;
|
|
7513
|
+
}
|
|
7514
|
+
|
|
7515
|
+
if (scopeWrap) scopeWrap.hidden = false;
|
|
7516
|
+
if (!workspaceSelect || !projectSelect) return;
|
|
7517
|
+
const cacheKey = item.id + ':' + String(item.workspaceId || '') + ':' + String(item.projectId || '');
|
|
7518
|
+
if (quickReviewScopeCacheKey === cacheKey) {
|
|
7519
|
+
return;
|
|
7520
|
+
}
|
|
7521
|
+
quickReviewScopeCacheKey = cacheKey;
|
|
7522
|
+
setQuickReviewStatus('Loading available workspaces…', 'warn');
|
|
7523
|
+
setScopeOptions(workspaceSelect, [{ id: '', label: 'Loading workspaces...' }], '');
|
|
7524
|
+
setScopeOptions(projectSelect, [{ id: '', label: 'Loading projects...' }], '');
|
|
7525
|
+
|
|
7526
|
+
try {
|
|
7527
|
+
const response = await apiFetch('/api/scope/access');
|
|
7528
|
+
const payload = await response.json();
|
|
7529
|
+
scopeAccessSnapshot = payload;
|
|
7530
|
+
const governedMode = payload && payload.operatingMode === 'governed';
|
|
7531
|
+
const workspaces = payload.ok && Array.isArray(payload.workspaces) ? payload.workspaces : [];
|
|
7532
|
+
const options = [
|
|
7533
|
+
...(governedMode ? [] : [{ id: '', label: 'Account scope / no workspace' }]),
|
|
7534
|
+
...workspaces.map((workspace) => ({ id: workspace.id, label: workspace.name || workspace.id })),
|
|
7535
|
+
];
|
|
7536
|
+
if (governedMode && !options.length) {
|
|
7537
|
+
options.push({ id: '', label: 'No governed workspaces yet' });
|
|
7538
|
+
}
|
|
7539
|
+
const selectedWorkspace = item.workspaceId || payload.currentWorkspaceId || (options[0] && options[0].id) || '';
|
|
7540
|
+
setScopeOptions(workspaceSelect, options, selectedWorkspace);
|
|
7541
|
+
await loadQuickReviewProjects(selectedWorkspace, item.projectId || payload.currentProjectId || '', governedMode);
|
|
7542
|
+
setQuickReviewStatus(
|
|
7543
|
+
payload.ok
|
|
7544
|
+
? (governedMode
|
|
7545
|
+
? 'Choose the governed workspace and project for this registration.'
|
|
7546
|
+
: 'Account scope stays available. Choose governed scope only when needed.')
|
|
7547
|
+
: (payload.message || 'Workspace access is unavailable right now.'),
|
|
7548
|
+
payload.ok ? '' : 'warn',
|
|
7549
|
+
);
|
|
7550
|
+
updateQuickReviewScopeSummary(governedMode);
|
|
7551
|
+
} catch {
|
|
7552
|
+
setScopeOptions(workspaceSelect, [{ id: '', label: 'Workspace list unavailable' }], '');
|
|
7553
|
+
setScopeOptions(projectSelect, [{ id: '', label: 'Project list unavailable' }], '');
|
|
7554
|
+
setQuickReviewStatus('Workspace access is unavailable right now.', 'warn');
|
|
7555
|
+
if (primaryButton) {
|
|
7556
|
+
primaryButton.disabled = true;
|
|
7557
|
+
}
|
|
7558
|
+
setText('quick-review-scope-summary', 'Scope unavailable');
|
|
7559
|
+
}
|
|
7560
|
+
}
|
|
7561
|
+
|
|
7562
|
+
async function submitQuickReviewPrimary() {
|
|
7563
|
+
const item = getQuickReviewItem();
|
|
7564
|
+
if (!item) return;
|
|
7565
|
+
selectedDiscoveryId = item.id;
|
|
7566
|
+
if (item.kind === 'runtime' || item.actionLabel === 'Open' || item.actionLabel === 'Review') {
|
|
7567
|
+
await openDiscoveryContext(item);
|
|
7568
|
+
setQuickReviewPanelOpen(false);
|
|
7569
|
+
return;
|
|
7570
|
+
}
|
|
7571
|
+
if (!canReviewRegister(item)) {
|
|
7572
|
+
setQuickReviewStatus('Registration is not available for this item.', 'warn');
|
|
7573
|
+
return;
|
|
7574
|
+
}
|
|
7575
|
+
const workspaceSelect = document.getElementById('quick-review-workspace');
|
|
7576
|
+
const projectSelect = document.getElementById('quick-review-project');
|
|
7577
|
+
const primaryButton = document.getElementById('quick-review-primary');
|
|
7578
|
+
const workspaceId = workspaceSelect ? String(workspaceSelect.value || '').trim() : '';
|
|
7579
|
+
const projectId = projectSelect ? String(projectSelect.value || '').trim() : '';
|
|
7580
|
+
const governedMode = scopeAccessSnapshot && scopeAccessSnapshot.operatingMode === 'governed';
|
|
7581
|
+
if (workspaceId && !projectId) {
|
|
7582
|
+
setQuickReviewStatus('Select a project for the chosen workspace, or switch back to account scope.', 'warn');
|
|
7583
|
+
return;
|
|
7584
|
+
}
|
|
7585
|
+
if (!workspaceId && governedMode) {
|
|
7586
|
+
setQuickReviewStatus('Choose the governed workspace and project before registering here.', 'warn');
|
|
7587
|
+
return;
|
|
7588
|
+
}
|
|
7589
|
+
if (primaryButton) primaryButton.disabled = true;
|
|
7590
|
+
const endpoint = item.kind === 'agent' ? '/api/discovery/connect-agent' : '/api/discovery/connect-model';
|
|
7591
|
+
const result = await postAction(endpoint, 'Registering with Forkit Connect...', {
|
|
7592
|
+
method: 'POST',
|
|
7593
|
+
body: JSON.stringify({ selector: item.selector, workspaceId, projectId }),
|
|
7594
|
+
});
|
|
7595
|
+
if (primaryButton) primaryButton.disabled = false;
|
|
7596
|
+
if (!result.ok) {
|
|
7597
|
+
setQuickReviewStatus(result.message || 'Registration failed.', 'warn');
|
|
7598
|
+
setActivityMessage(result.message || 'Registration failed.', 'warn');
|
|
7599
|
+
return;
|
|
7600
|
+
}
|
|
7601
|
+
setQuickReviewStatus(result.message || 'Registration updated.', 'ok');
|
|
7602
|
+
setActivityMessage(result.message || 'Registration updated.', 'ok');
|
|
7603
|
+
await refreshAll();
|
|
7604
|
+
setQuickReviewPanelOpen(false);
|
|
7605
|
+
if (result.gaid || result.passportGaid) {
|
|
7606
|
+
await openDiscoveryContext(item);
|
|
7607
|
+
}
|
|
7608
|
+
}
|
|
7609
|
+
|
|
7610
|
+
async function submitQuickReviewDefer() {
|
|
7611
|
+
const item = getQuickReviewItem();
|
|
7612
|
+
if (!item || !canReviewDefer(item)) {
|
|
7613
|
+
setQuickReviewStatus('Not now is not available for this item.', 'warn');
|
|
7614
|
+
return;
|
|
7615
|
+
}
|
|
7616
|
+
const result = await postAction('/api/discovery/review/defer', 'Deferring this review...', {
|
|
7617
|
+
method: 'POST',
|
|
7618
|
+
body: JSON.stringify({ kind: item.kind, selector: item.selector, hours: 24 }),
|
|
7619
|
+
});
|
|
7620
|
+
setQuickReviewStatus(result.message || 'Review deferred.', result.ok ? 'ok' : 'warn');
|
|
7621
|
+
setActivityMessage(result.message || 'Review deferred.', result.ok ? 'ok' : 'warn');
|
|
7622
|
+
await refreshAll();
|
|
7623
|
+
setQuickReviewOptionsOpen(false);
|
|
7624
|
+
}
|
|
7625
|
+
|
|
7626
|
+
async function submitQuickReviewIgnore() {
|
|
7627
|
+
const item = getQuickReviewItem();
|
|
7628
|
+
if (!item || !canReviewIgnore(item)) {
|
|
7629
|
+
setQuickReviewStatus('Ignore is not available for this item.', 'warn');
|
|
7630
|
+
return;
|
|
7631
|
+
}
|
|
7632
|
+
const result = await postAction('/api/discovery/review/ignore', 'Ignoring this review item...', {
|
|
7633
|
+
method: 'POST',
|
|
7634
|
+
body: JSON.stringify({ kind: item.kind, selector: item.selector }),
|
|
7635
|
+
});
|
|
7636
|
+
setQuickReviewStatus(result.message || 'Item ignored locally.', result.ok ? 'ok' : 'warn');
|
|
7637
|
+
setActivityMessage(result.message || 'Item ignored locally.', result.ok ? 'ok' : 'warn');
|
|
7638
|
+
await refreshAll();
|
|
7639
|
+
setQuickReviewOptionsOpen(false);
|
|
7640
|
+
}
|
|
7641
|
+
|
|
7642
|
+
function setDiscoveryReviewButtons(config) {
|
|
7643
|
+
const primary = document.getElementById('discovery-review-primary');
|
|
7644
|
+
const defer = document.getElementById('discovery-review-defer');
|
|
7645
|
+
const ignore = document.getElementById('discovery-review-ignore');
|
|
7646
|
+
if (primary) {
|
|
7647
|
+
primary.textContent = config.primaryLabel || 'Review';
|
|
7648
|
+
primary.disabled = !config.primaryEnabled;
|
|
7649
|
+
}
|
|
7650
|
+
if (defer) {
|
|
7651
|
+
defer.disabled = !config.deferEnabled;
|
|
7652
|
+
}
|
|
7653
|
+
if (ignore) {
|
|
7654
|
+
ignore.disabled = !config.ignoreEnabled;
|
|
7655
|
+
}
|
|
7656
|
+
}
|
|
7657
|
+
|
|
7658
|
+
async function loadDiscoveryReviewProjects(workspaceId, selectedProjectId, governedMode) {
|
|
7659
|
+
const projectSelect = document.getElementById('discovery-review-project');
|
|
7660
|
+
const primaryButton = document.getElementById('discovery-review-primary');
|
|
7661
|
+
if (!projectSelect) return;
|
|
7662
|
+
if (!workspaceId) {
|
|
7663
|
+
setScopeOptions(projectSelect, [{ id: '', label: governedMode ? 'Choose workspace first' : 'Account scope / no project' }], '');
|
|
7664
|
+
if (primaryButton) primaryButton.disabled = governedMode;
|
|
7665
|
+
return;
|
|
7666
|
+
}
|
|
7667
|
+
setScopeOptions(projectSelect, [{ id: '', label: 'Loading projects...' }], '');
|
|
7668
|
+
try {
|
|
7669
|
+
const response = await apiFetch('/api/scope/projects?workspaceId=' + encodeURIComponent(workspaceId));
|
|
7670
|
+
const payload = await response.json();
|
|
7671
|
+
const projects = payload.ok && Array.isArray(payload.projects) ? payload.projects : [];
|
|
7672
|
+
const options = projects.length
|
|
7673
|
+
? projects.map((project) => ({ id: project.id, label: project.name || project.id }))
|
|
7674
|
+
: [{ id: '', label: 'No projects found' }];
|
|
7675
|
+
setScopeOptions(projectSelect, options, selectedProjectId || (options[0] && options[0].id) || '');
|
|
7676
|
+
if (!payload.ok) {
|
|
7677
|
+
setDiscoveryReviewStatus(payload.message || 'Project list is unavailable right now.', 'warn');
|
|
7678
|
+
} else if (!projects.length) {
|
|
7679
|
+
setDiscoveryReviewStatus('Create a project in this workspace before registering here.', 'warn');
|
|
7680
|
+
}
|
|
7681
|
+
if (primaryButton) {
|
|
7682
|
+
primaryButton.disabled = !projects.length;
|
|
7683
|
+
}
|
|
7684
|
+
} catch {
|
|
7685
|
+
setScopeOptions(projectSelect, [{ id: '', label: 'Project list unavailable' }], '');
|
|
7686
|
+
setDiscoveryReviewStatus('Project list is unavailable right now.', 'warn');
|
|
7687
|
+
if (primaryButton) {
|
|
7688
|
+
primaryButton.disabled = true;
|
|
7689
|
+
}
|
|
7690
|
+
}
|
|
7691
|
+
}
|
|
7692
|
+
|
|
7693
|
+
async function renderDiscoveryReviewPanel() {
|
|
7694
|
+
const item = getSelectedDiscoveryItem();
|
|
7695
|
+
const scopeWrap = document.getElementById('discovery-review-scope');
|
|
7696
|
+
const workspaceSelect = document.getElementById('discovery-review-workspace');
|
|
7697
|
+
const projectSelect = document.getElementById('discovery-review-project');
|
|
7698
|
+
|
|
7699
|
+
if (!item) {
|
|
7700
|
+
setText('discovery-review-kicker', 'Review item');
|
|
7701
|
+
setText('discovery-review-title', 'Select a discovery item');
|
|
7702
|
+
setText('discovery-review-meta', 'Choose a model, agent, or runtime to review it here.');
|
|
7703
|
+
setText('discovery-review-detail', 'Registering creates or updates a Forkit Passport. Nothing is published automatically.');
|
|
7704
|
+
if (scopeWrap) scopeWrap.hidden = true;
|
|
7705
|
+
setDiscoveryReviewStatus('Select an item to continue.', '');
|
|
7706
|
+
setDiscoveryReviewButtons({ primaryLabel: 'Review', primaryEnabled: false, deferEnabled: false, ignoreEnabled: false });
|
|
7707
|
+
return;
|
|
7708
|
+
}
|
|
7709
|
+
|
|
7710
|
+
const typeLabel = item.typeLabel || item.kind;
|
|
7711
|
+
const needsScope = canReviewRegister(item);
|
|
7712
|
+
const opensExisting = item.actionLabel === 'Open' || item.actionLabel === 'Review';
|
|
7713
|
+
const primaryLabel = item.kind === 'runtime'
|
|
7714
|
+
? 'Open runtime review'
|
|
7715
|
+
: opensExisting
|
|
7716
|
+
? (item.passportGaid || item.matchedPassportGaid ? 'Open passport' : 'Review in context')
|
|
7717
|
+
: 'Approve and register';
|
|
7718
|
+
|
|
7719
|
+
setText('discovery-review-kicker', typeLabel);
|
|
7720
|
+
setText('discovery-review-title', item.name);
|
|
7721
|
+
setText('discovery-review-meta', item.subtitle + ' · ' + item.source);
|
|
7722
|
+
setText('discovery-review-detail', item.detailSummary || item.statusMeta || 'Review local metadata, then decide what happens next.');
|
|
7723
|
+
setDiscoveryReviewStatus(item.statusLabel + (item.statusMeta ? ' · ' + item.statusMeta : ''), item.statusTone === 'muted' ? '' : item.statusTone);
|
|
7724
|
+
setDiscoveryReviewButtons({
|
|
7725
|
+
primaryLabel,
|
|
7726
|
+
primaryEnabled: item.inboxGroup !== 'ignored',
|
|
7727
|
+
deferEnabled: canReviewDefer(item),
|
|
7728
|
+
ignoreEnabled: canReviewIgnore(item),
|
|
7729
|
+
});
|
|
7730
|
+
|
|
7731
|
+
if (!needsScope) {
|
|
7732
|
+
if (scopeWrap) scopeWrap.hidden = true;
|
|
7733
|
+
reviewScopeCacheKey = null;
|
|
7734
|
+
return;
|
|
7735
|
+
}
|
|
7736
|
+
|
|
7737
|
+
if (scopeWrap) scopeWrap.hidden = false;
|
|
7738
|
+
if (!workspaceSelect || !projectSelect) return;
|
|
7739
|
+
|
|
7740
|
+
const cacheKey = item.id + ':' + String(item.workspaceId || '') + ':' + String(item.projectId || '');
|
|
7741
|
+
if (reviewScopeCacheKey === cacheKey) {
|
|
7742
|
+
return;
|
|
7743
|
+
}
|
|
7744
|
+
reviewScopeCacheKey = cacheKey;
|
|
7745
|
+
|
|
7746
|
+
setDiscoveryReviewStatus('Loading available workspaces…', 'warn');
|
|
7747
|
+
setScopeOptions(workspaceSelect, [{ id: '', label: 'Loading workspaces...' }], '');
|
|
7748
|
+
setScopeOptions(projectSelect, [{ id: '', label: 'Loading projects...' }], '');
|
|
7749
|
+
|
|
7750
|
+
try {
|
|
7751
|
+
const response = await apiFetch('/api/scope/access');
|
|
7752
|
+
const payload = await response.json();
|
|
7753
|
+
scopeAccessSnapshot = payload;
|
|
7754
|
+
const governedMode = payload && payload.operatingMode === 'governed';
|
|
7755
|
+
const workspaces = payload.ok && Array.isArray(payload.workspaces) ? payload.workspaces : [];
|
|
7756
|
+
const options = [
|
|
7757
|
+
...(governedMode ? [] : [{ id: '', label: 'Account scope / no workspace' }]),
|
|
7758
|
+
...workspaces.map((workspace) => ({ id: workspace.id, label: workspace.name || workspace.id })),
|
|
7759
|
+
];
|
|
7760
|
+
if (governedMode && !options.length) {
|
|
7761
|
+
options.push({ id: '', label: 'No governed workspaces yet' });
|
|
7762
|
+
}
|
|
7763
|
+
const selectedWorkspace = item.workspaceId || payload.currentWorkspaceId || (options[0] && options[0].id) || '';
|
|
7764
|
+
setScopeOptions(workspaceSelect, options, selectedWorkspace);
|
|
7765
|
+
await loadDiscoveryReviewProjects(selectedWorkspace, item.projectId || payload.currentProjectId || '', governedMode);
|
|
7766
|
+
setDiscoveryReviewStatus(
|
|
7767
|
+
payload.ok
|
|
7768
|
+
? (governedMode
|
|
7769
|
+
? 'Choose the governed workspace and project for this registration.'
|
|
7770
|
+
: 'Account scope stays available. Choose governed scope only when needed.')
|
|
7771
|
+
: (payload.message || 'Workspace access is unavailable right now.'),
|
|
7772
|
+
payload.ok ? '' : 'warn',
|
|
7773
|
+
);
|
|
7774
|
+
} catch {
|
|
7775
|
+
setScopeOptions(workspaceSelect, [{ id: '', label: 'Workspace list unavailable' }], '');
|
|
7776
|
+
setScopeOptions(projectSelect, [{ id: '', label: 'Project list unavailable' }], '');
|
|
7777
|
+
setDiscoveryReviewStatus('Workspace access is unavailable right now.', 'warn');
|
|
7778
|
+
setDiscoveryReviewButtons({
|
|
7779
|
+
primaryLabel,
|
|
7780
|
+
primaryEnabled: false,
|
|
7781
|
+
deferEnabled: canReviewDefer(item),
|
|
7782
|
+
ignoreEnabled: canReviewIgnore(item),
|
|
7783
|
+
});
|
|
7784
|
+
}
|
|
7785
|
+
}
|
|
7786
|
+
|
|
7787
|
+
async function submitDiscoveryReviewPrimary() {
|
|
7788
|
+
const item = getSelectedDiscoveryItem();
|
|
7789
|
+
if (!item) return;
|
|
7790
|
+
if (item.kind === 'runtime' || item.actionLabel === 'Open' || item.actionLabel === 'Review') {
|
|
7791
|
+
await openDiscoveryContext(item);
|
|
7792
|
+
return;
|
|
7793
|
+
}
|
|
7794
|
+
if (!canReviewRegister(item)) {
|
|
7795
|
+
setDiscoveryReviewStatus('Registration is not available for this item.', 'warn');
|
|
7796
|
+
return;
|
|
7797
|
+
}
|
|
7798
|
+
const workspaceSelect = document.getElementById('discovery-review-workspace');
|
|
7799
|
+
const projectSelect = document.getElementById('discovery-review-project');
|
|
7800
|
+
const primaryButton = document.getElementById('discovery-review-primary');
|
|
7801
|
+
const workspaceId = workspaceSelect ? String(workspaceSelect.value || '').trim() : '';
|
|
7802
|
+
const projectId = projectSelect ? String(projectSelect.value || '').trim() : '';
|
|
7803
|
+
if (workspaceId && !projectId) {
|
|
7804
|
+
setDiscoveryReviewStatus('Select a project for the chosen workspace, or switch back to account scope.', 'warn');
|
|
7805
|
+
return;
|
|
7806
|
+
}
|
|
7807
|
+
if (primaryButton) primaryButton.disabled = true;
|
|
7808
|
+
const endpoint = item.kind === 'agent' ? '/api/discovery/connect-agent' : '/api/discovery/connect-model';
|
|
7809
|
+
const result = await postAction(endpoint, 'Registering with Forkit Connect...', {
|
|
7810
|
+
method: 'POST',
|
|
7811
|
+
body: JSON.stringify({ selector: item.selector, workspaceId, projectId }),
|
|
7812
|
+
});
|
|
7813
|
+
if (primaryButton) primaryButton.disabled = false;
|
|
7814
|
+
if (!result.ok) {
|
|
7815
|
+
setDiscoveryReviewStatus(result.message || 'Registration failed.', 'warn');
|
|
7816
|
+
setActivityMessage(result.message || 'Registration failed.', 'warn');
|
|
7817
|
+
return;
|
|
7818
|
+
}
|
|
7819
|
+
setDiscoveryReviewStatus(result.message || 'Registration updated.', 'ok');
|
|
7820
|
+
setActivityMessage(result.message || 'Registration updated.', 'ok');
|
|
7821
|
+
await refreshAll();
|
|
7822
|
+
if (result.gaid || result.passportGaid) {
|
|
7823
|
+
await openDiscoveryContext(item);
|
|
7824
|
+
}
|
|
7825
|
+
}
|
|
7826
|
+
|
|
7827
|
+
async function submitDiscoveryReviewDefer() {
|
|
7828
|
+
const item = getSelectedDiscoveryItem();
|
|
7829
|
+
if (!item || !canReviewDefer(item)) {
|
|
7830
|
+
setDiscoveryReviewStatus('Defer is not available for this item.', 'warn');
|
|
7831
|
+
return;
|
|
7832
|
+
}
|
|
7833
|
+
const result = await postAction('/api/discovery/review/defer', 'Deferring this review...', {
|
|
7834
|
+
method: 'POST',
|
|
7835
|
+
body: JSON.stringify({ kind: item.kind, selector: item.selector, hours: 24 }),
|
|
7836
|
+
});
|
|
7837
|
+
setDiscoveryReviewStatus(result.message || 'Review deferred.', result.ok ? 'ok' : 'warn');
|
|
7838
|
+
setActivityMessage(result.message || 'Review deferred.', result.ok ? 'ok' : 'warn');
|
|
7839
|
+
await refreshAll();
|
|
7840
|
+
}
|
|
7841
|
+
|
|
7842
|
+
async function submitDiscoveryReviewIgnore() {
|
|
7843
|
+
const item = getSelectedDiscoveryItem();
|
|
7844
|
+
if (!item || !canReviewIgnore(item)) {
|
|
7845
|
+
setDiscoveryReviewStatus('Ignore is not available for this item.', 'warn');
|
|
7846
|
+
return;
|
|
7847
|
+
}
|
|
7848
|
+
const result = await postAction('/api/discovery/review/ignore', 'Ignoring this review item...', {
|
|
7849
|
+
method: 'POST',
|
|
7850
|
+
body: JSON.stringify({ kind: item.kind, selector: item.selector }),
|
|
7851
|
+
});
|
|
7852
|
+
setDiscoveryReviewStatus(result.message || 'Item ignored locally.', result.ok ? 'ok' : 'warn');
|
|
7853
|
+
setActivityMessage(result.message || 'Item ignored locally.', result.ok ? 'ok' : 'warn');
|
|
7854
|
+
await refreshAll();
|
|
7855
|
+
}
|
|
7856
|
+
|
|
6686
7857
|
function setProfileAvatar(rootId, imageId, initialsId, initials, avatarUrl) {
|
|
6687
7858
|
const root = document.getElementById(rootId);
|
|
6688
7859
|
const image = document.getElementById(imageId);
|
|
@@ -7067,9 +8238,13 @@ function renderLauncherHtml(launcherToken) {
|
|
|
7067
8238
|
setMetricValue('cmd-health-sync', formatRelativeTime(summary && summary.heartbeat && summary.heartbeat.lastSentAt), heartbeatCanSend ? 'ok' : 'warn');
|
|
7068
8239
|
|
|
7069
8240
|
const boundCount = scopedPassports.filter((item) => String(item.bindingStatus || '').toLowerCase() === 'bound').length;
|
|
7070
|
-
const subtitle =
|
|
8241
|
+
const subtitle = boundCount > 0
|
|
8242
|
+
? boundCount === 1
|
|
8243
|
+
? '1 registration is already linked to the current scope.'
|
|
8244
|
+
: boundCount + ' registrations are already linked to the current scope.'
|
|
8245
|
+
: 'Current scope is ready for new registrations.';
|
|
7071
8246
|
if (currentView === 'command') {
|
|
7072
|
-
setText('activity-message', subtitle);
|
|
8247
|
+
setText('activity-message', subtitle, '');
|
|
7073
8248
|
}
|
|
7074
8249
|
|
|
7075
8250
|
const accountName = toDisplayName(workspaceLabel, 'Operator');
|
|
@@ -7710,6 +8885,33 @@ function renderLauncherHtml(launcherToken) {
|
|
|
7710
8885
|
}
|
|
7711
8886
|
}
|
|
7712
8887
|
|
|
8888
|
+
async function applyRouteFocusIfNeeded() {
|
|
8889
|
+
if (initialRouteFocusApplied) return;
|
|
8890
|
+
const route = resolveRouteState();
|
|
8891
|
+
if (route.view === 'command' && route.focus === 'review') {
|
|
8892
|
+
const reviewItems = getQuickReviewItems();
|
|
8893
|
+
if (!reviewItems.length) return;
|
|
8894
|
+
setView('command', { skipRouteUpdate: true });
|
|
8895
|
+
await renderQuickReviewNotice();
|
|
8896
|
+
setQuickReviewPanelOpen(true);
|
|
8897
|
+
setActivityMessage('Review the next item directly in Forkit Connect.', '');
|
|
8898
|
+
initialRouteFocusApplied = true;
|
|
8899
|
+
return;
|
|
8900
|
+
}
|
|
8901
|
+
if (route.view === 'discovery' && route.focus === 'item') {
|
|
8902
|
+
setView('discovery', { skipRouteUpdate: true });
|
|
8903
|
+
renderDiscoveryRows();
|
|
8904
|
+
initialRouteFocusApplied = true;
|
|
8905
|
+
return;
|
|
8906
|
+
}
|
|
8907
|
+
if (route.view === 'runtime' && route.focus === 'c2') {
|
|
8908
|
+
setView('runtime', { skipRouteUpdate: true });
|
|
8909
|
+
initialRouteFocusApplied = true;
|
|
8910
|
+
return;
|
|
8911
|
+
}
|
|
8912
|
+
initialRouteFocusApplied = true;
|
|
8913
|
+
}
|
|
8914
|
+
|
|
7713
8915
|
function renderDiscoveryRows() {
|
|
7714
8916
|
const rowsHost = document.getElementById('discovery-rows');
|
|
7715
8917
|
const empty = document.getElementById('discovery-empty');
|
|
@@ -7729,6 +8931,13 @@ function renderLauncherHtml(launcherToken) {
|
|
|
7729
8931
|
|
|
7730
8932
|
const visible = filtered;
|
|
7731
8933
|
|
|
8934
|
+
if (selectedDiscoveryId && !visible.some((item) => item.id === selectedDiscoveryId)) {
|
|
8935
|
+
selectedDiscoveryId = visible.length ? visible[0].id : null;
|
|
8936
|
+
reviewScopeCacheKey = null;
|
|
8937
|
+
} else if (!selectedDiscoveryId && visible.length) {
|
|
8938
|
+
selectedDiscoveryId = visible[0].id;
|
|
8939
|
+
}
|
|
8940
|
+
|
|
7732
8941
|
rowsHost.innerHTML = visible.map((item) => '<div class="discovery-item-row' + (item.id === selectedDiscoveryId ? ' active' : '') + '" data-discovery-id="' + escapeHtml(item.id) + '">'
|
|
7733
8942
|
+ '<div><button class="discovery-check" type="button" aria-label="Select ' + escapeHtml(item.name) + '"></button></div>'
|
|
7734
8943
|
+ '<div class="discovery-item-main">'
|
|
@@ -7744,22 +8953,48 @@ function renderLauncherHtml(launcherToken) {
|
|
|
7744
8953
|
+ '<div class="discovery-action-group"><button class="discovery-action-btn" data-discovery-action="primary" data-tone="' + escapeHtml(item.actionTone || 'primary') + '" type="button">' + escapeHtml(item.actionLabel) + '</button><button class="discovery-more-btn" data-discovery-action="inspect" type="button" aria-label="More actions for ' + escapeHtml(item.name) + '">…</button></div>'
|
|
7745
8954
|
+ '</div>').join('');
|
|
7746
8955
|
|
|
8956
|
+
rowsHost.querySelectorAll('.discovery-item-row').forEach((row) => {
|
|
8957
|
+
row.addEventListener('click', async (event) => {
|
|
8958
|
+
const target = event.target;
|
|
8959
|
+
if (target && (target.closest('[data-discovery-action]') || target.closest('.discovery-check'))) {
|
|
8960
|
+
return;
|
|
8961
|
+
}
|
|
8962
|
+
selectedDiscoveryId = row.getAttribute('data-discovery-id');
|
|
8963
|
+
reviewScopeCacheKey = null;
|
|
8964
|
+
renderDiscoveryRows();
|
|
8965
|
+
});
|
|
8966
|
+
});
|
|
8967
|
+
rowsHost.querySelectorAll('.discovery-check').forEach((button) => {
|
|
8968
|
+
button.addEventListener('click', (event) => {
|
|
8969
|
+
event.stopPropagation();
|
|
8970
|
+
const row = button.closest('.discovery-item-row');
|
|
8971
|
+
if (!row) return;
|
|
8972
|
+
selectedDiscoveryId = row.getAttribute('data-discovery-id');
|
|
8973
|
+
reviewScopeCacheKey = null;
|
|
8974
|
+
renderDiscoveryRows();
|
|
8975
|
+
});
|
|
8976
|
+
});
|
|
8977
|
+
|
|
7747
8978
|
rowsHost.querySelectorAll('[data-discovery-action="primary"]').forEach((button) => {
|
|
7748
|
-
button.addEventListener('click', async () => {
|
|
8979
|
+
button.addEventListener('click', async (event) => {
|
|
8980
|
+
event.stopPropagation();
|
|
7749
8981
|
const row = button.closest('.discovery-item-row');
|
|
7750
8982
|
const item = row ? visible.find((entry) => entry.id === row.getAttribute('data-discovery-id')) : null;
|
|
7751
8983
|
if (!item) return;
|
|
7752
8984
|
selectedDiscoveryId = item.id;
|
|
8985
|
+
reviewScopeCacheKey = null;
|
|
7753
8986
|
await handleDiscoveryPrimaryAction(item);
|
|
7754
8987
|
});
|
|
7755
8988
|
});
|
|
7756
8989
|
rowsHost.querySelectorAll('[data-discovery-action="inspect"]').forEach((button) => {
|
|
7757
|
-
button.addEventListener('click', async () => {
|
|
8990
|
+
button.addEventListener('click', async (event) => {
|
|
8991
|
+
event.stopPropagation();
|
|
7758
8992
|
const row = button.closest('.discovery-item-row');
|
|
7759
8993
|
const item = row ? visible.find((entry) => entry.id === row.getAttribute('data-discovery-id')) : null;
|
|
7760
8994
|
if (!item) return;
|
|
7761
8995
|
selectedDiscoveryId = item.id;
|
|
7762
|
-
|
|
8996
|
+
reviewScopeCacheKey = null;
|
|
8997
|
+
renderDiscoveryRows();
|
|
7763
8998
|
});
|
|
7764
8999
|
});
|
|
7765
9000
|
|
|
@@ -7768,6 +9003,8 @@ function renderLauncherHtml(launcherToken) {
|
|
|
7768
9003
|
if (showMoreButton) {
|
|
7769
9004
|
showMoreButton.hidden = true;
|
|
7770
9005
|
}
|
|
9006
|
+
void renderDiscoveryReviewPanel();
|
|
9007
|
+
void renderQuickReviewNotice();
|
|
7771
9008
|
}
|
|
7772
9009
|
|
|
7773
9010
|
function updateKindTabs() {
|
|
@@ -7797,6 +9034,7 @@ function renderLauncherHtml(launcherToken) {
|
|
|
7797
9034
|
setText('disc-check-passport', discovery.checks.passportReadiness, 'muted');
|
|
7798
9035
|
|
|
7799
9036
|
renderDiscoveryRows();
|
|
9037
|
+
void renderQuickReviewNotice();
|
|
7800
9038
|
renderCommandOverview();
|
|
7801
9039
|
renderGlobalLaunchHeaderAndCards();
|
|
7802
9040
|
return discovery;
|
|
@@ -8385,6 +9623,133 @@ function renderLauncherHtml(launcherToken) {
|
|
|
8385
9623
|
setView('discovery');
|
|
8386
9624
|
renderDiscoveryRows();
|
|
8387
9625
|
});
|
|
9626
|
+
const quickReviewToggle = document.getElementById('quick-review-toggle');
|
|
9627
|
+
if (quickReviewToggle) {
|
|
9628
|
+
quickReviewToggle.addEventListener('click', () => {
|
|
9629
|
+
const panel = document.getElementById('quick-review-panel');
|
|
9630
|
+
const nextOpen = Boolean(panel && panel.hidden);
|
|
9631
|
+
setQuickReviewPanelOpen(nextOpen);
|
|
9632
|
+
if (nextOpen) {
|
|
9633
|
+
void renderQuickReviewNotice();
|
|
9634
|
+
}
|
|
9635
|
+
});
|
|
9636
|
+
}
|
|
9637
|
+
const quickReviewPrimary = document.getElementById('quick-review-primary');
|
|
9638
|
+
if (quickReviewPrimary) {
|
|
9639
|
+
quickReviewPrimary.addEventListener('click', () => {
|
|
9640
|
+
void submitQuickReviewPrimary();
|
|
9641
|
+
});
|
|
9642
|
+
}
|
|
9643
|
+
const quickReviewOptionsButton = document.getElementById('quick-review-options');
|
|
9644
|
+
if (quickReviewOptionsButton) {
|
|
9645
|
+
quickReviewOptionsButton.addEventListener('click', (event) => {
|
|
9646
|
+
event.stopPropagation();
|
|
9647
|
+
const menu = document.getElementById('quick-review-options-menu');
|
|
9648
|
+
setQuickReviewOptionsOpen(Boolean(menu && menu.hidden));
|
|
9649
|
+
});
|
|
9650
|
+
}
|
|
9651
|
+
const quickReviewOpenDiscovery = document.getElementById('quick-review-open-discovery');
|
|
9652
|
+
if (quickReviewOpenDiscovery) {
|
|
9653
|
+
quickReviewOpenDiscovery.addEventListener('click', () => {
|
|
9654
|
+
setQuickReviewOptionsOpen(false);
|
|
9655
|
+
setQuickReviewPanelOpen(false);
|
|
9656
|
+
setView('discovery');
|
|
9657
|
+
renderDiscoveryRows();
|
|
9658
|
+
});
|
|
9659
|
+
}
|
|
9660
|
+
const quickReviewDefer = document.getElementById('quick-review-defer');
|
|
9661
|
+
if (quickReviewDefer) {
|
|
9662
|
+
quickReviewDefer.addEventListener('click', () => {
|
|
9663
|
+
void submitQuickReviewDefer();
|
|
9664
|
+
});
|
|
9665
|
+
}
|
|
9666
|
+
const quickReviewIgnore = document.getElementById('quick-review-ignore');
|
|
9667
|
+
if (quickReviewIgnore) {
|
|
9668
|
+
quickReviewIgnore.addEventListener('click', () => {
|
|
9669
|
+
void submitQuickReviewIgnore();
|
|
9670
|
+
});
|
|
9671
|
+
}
|
|
9672
|
+
const quickReviewWorkspaceSelect = document.getElementById('quick-review-workspace');
|
|
9673
|
+
if (quickReviewWorkspaceSelect) {
|
|
9674
|
+
quickReviewWorkspaceSelect.addEventListener('change', () => {
|
|
9675
|
+
const selectedWorkspaceId = String(quickReviewWorkspaceSelect.value || '').trim();
|
|
9676
|
+
const governedMode = scopeAccessSnapshot && scopeAccessSnapshot.operatingMode === 'governed';
|
|
9677
|
+
quickReviewScopeCacheKey = null;
|
|
9678
|
+
void loadQuickReviewProjects(selectedWorkspaceId, '', governedMode);
|
|
9679
|
+
updateQuickReviewScopeSummary(governedMode);
|
|
9680
|
+
setQuickReviewStatus(
|
|
9681
|
+
selectedWorkspaceId
|
|
9682
|
+
? 'Choose the governed project for this registration.'
|
|
9683
|
+
: 'Account scope stays available. Choose governed scope only when needed.',
|
|
9684
|
+
'',
|
|
9685
|
+
);
|
|
9686
|
+
});
|
|
9687
|
+
}
|
|
9688
|
+
const quickReviewProjectSelect = document.getElementById('quick-review-project');
|
|
9689
|
+
if (quickReviewProjectSelect) {
|
|
9690
|
+
quickReviewProjectSelect.addEventListener('change', () => {
|
|
9691
|
+
const primaryButton = document.getElementById('quick-review-primary');
|
|
9692
|
+
const selectedWorkspaceId = quickReviewWorkspaceSelect
|
|
9693
|
+
? String(quickReviewWorkspaceSelect.value || '').trim()
|
|
9694
|
+
: '';
|
|
9695
|
+
const selectedProjectId = String(quickReviewProjectSelect.value || '').trim();
|
|
9696
|
+
const governedMode = scopeAccessSnapshot && scopeAccessSnapshot.operatingMode === 'governed';
|
|
9697
|
+
updateQuickReviewScopeSummary(governedMode);
|
|
9698
|
+
if (primaryButton) {
|
|
9699
|
+
primaryButton.disabled = Boolean(selectedWorkspaceId && !selectedProjectId && governedMode);
|
|
9700
|
+
}
|
|
9701
|
+
});
|
|
9702
|
+
}
|
|
9703
|
+
const discoveryReviewPrimaryBtn = document.getElementById('discovery-review-primary');
|
|
9704
|
+
if (discoveryReviewPrimaryBtn) {
|
|
9705
|
+
discoveryReviewPrimaryBtn.addEventListener('click', () => {
|
|
9706
|
+
void submitDiscoveryReviewPrimary();
|
|
9707
|
+
});
|
|
9708
|
+
}
|
|
9709
|
+
const discoveryReviewDeferBtn = document.getElementById('discovery-review-defer');
|
|
9710
|
+
if (discoveryReviewDeferBtn) {
|
|
9711
|
+
discoveryReviewDeferBtn.addEventListener('click', () => {
|
|
9712
|
+
void submitDiscoveryReviewDefer();
|
|
9713
|
+
});
|
|
9714
|
+
}
|
|
9715
|
+
const discoveryReviewIgnoreBtn = document.getElementById('discovery-review-ignore');
|
|
9716
|
+
if (discoveryReviewIgnoreBtn) {
|
|
9717
|
+
discoveryReviewIgnoreBtn.addEventListener('click', () => {
|
|
9718
|
+
void submitDiscoveryReviewIgnore();
|
|
9719
|
+
});
|
|
9720
|
+
}
|
|
9721
|
+
const discoveryReviewWorkspaceSelect = document.getElementById('discovery-review-workspace');
|
|
9722
|
+
if (discoveryReviewWorkspaceSelect) {
|
|
9723
|
+
discoveryReviewWorkspaceSelect.addEventListener('change', () => {
|
|
9724
|
+
const selectedItem = getSelectedDiscoveryItem();
|
|
9725
|
+
const selectedWorkspaceId = String(discoveryReviewWorkspaceSelect.value || '').trim();
|
|
9726
|
+
const governedMode = scopeAccessSnapshot && scopeAccessSnapshot.operatingMode === 'governed';
|
|
9727
|
+
void loadDiscoveryReviewProjects(selectedWorkspaceId, '', governedMode);
|
|
9728
|
+
if (selectedItem && canReviewRegister(selectedItem)) {
|
|
9729
|
+
setDiscoveryReviewStatus(
|
|
9730
|
+
selectedWorkspaceId
|
|
9731
|
+
? 'Choose the governed project for this registration.'
|
|
9732
|
+
: 'Account scope stays available. Choose governed scope only when needed.',
|
|
9733
|
+
'',
|
|
9734
|
+
);
|
|
9735
|
+
}
|
|
9736
|
+
});
|
|
9737
|
+
}
|
|
9738
|
+
const discoveryReviewProjectSelect = document.getElementById('discovery-review-project');
|
|
9739
|
+
if (discoveryReviewProjectSelect) {
|
|
9740
|
+
discoveryReviewProjectSelect.addEventListener('change', () => {
|
|
9741
|
+
const selectedItem = getSelectedDiscoveryItem();
|
|
9742
|
+
const primaryButton = document.getElementById('discovery-review-primary');
|
|
9743
|
+
const selectedWorkspaceId = discoveryReviewWorkspaceSelect
|
|
9744
|
+
? String(discoveryReviewWorkspaceSelect.value || '').trim()
|
|
9745
|
+
: '';
|
|
9746
|
+
const selectedProjectId = String(discoveryReviewProjectSelect.value || '').trim();
|
|
9747
|
+
const governedMode = scopeAccessSnapshot && scopeAccessSnapshot.operatingMode === 'governed';
|
|
9748
|
+
if (primaryButton && selectedItem && canReviewRegister(selectedItem)) {
|
|
9749
|
+
primaryButton.disabled = Boolean(selectedWorkspaceId && !selectedProjectId && governedMode);
|
|
9750
|
+
}
|
|
9751
|
+
});
|
|
9752
|
+
}
|
|
8388
9753
|
document.getElementById('runtime-send-heartbeat').addEventListener('click', handleHeartbeat);
|
|
8389
9754
|
document.getElementById('diag-action-scan').addEventListener('click', handleScan);
|
|
8390
9755
|
document.getElementById('diag-action-heartbeat').addEventListener('click', handleHeartbeat);
|
|
@@ -8412,6 +9777,7 @@ function renderLauncherHtml(launcherToken) {
|
|
|
8412
9777
|
|
|
8413
9778
|
const accountDropdownBtn = document.getElementById('user-chip-btn');
|
|
8414
9779
|
const accountDropdownMenu = document.getElementById('account-dropdown-menu');
|
|
9780
|
+
const quickReviewAnchor = document.getElementById('quick-review-anchor');
|
|
8415
9781
|
if (accountDropdownBtn && accountDropdownMenu) {
|
|
8416
9782
|
accountDropdownBtn.addEventListener('click', () => {
|
|
8417
9783
|
const nextHidden = !accountDropdownMenu.hidden;
|
|
@@ -8424,9 +9790,11 @@ function renderLauncherHtml(launcherToken) {
|
|
|
8424
9790
|
const target = event.target;
|
|
8425
9791
|
if (!target) return;
|
|
8426
9792
|
if (accountDropdownBtn.contains(target) || accountDropdownMenu.contains(target)) return;
|
|
9793
|
+
if (quickReviewAnchor && quickReviewAnchor.contains(target)) return;
|
|
8427
9794
|
closeScopeMenus();
|
|
8428
9795
|
accountDropdownMenu.hidden = true;
|
|
8429
9796
|
accountDropdownBtn.setAttribute('aria-expanded', 'false');
|
|
9797
|
+
setQuickReviewPanelOpen(false);
|
|
8430
9798
|
});
|
|
8431
9799
|
}
|
|
8432
9800
|
|
|
@@ -8612,8 +9980,9 @@ function renderLauncherHtml(launcherToken) {
|
|
|
8612
9980
|
setView('command', { skipRouteUpdate: true });
|
|
8613
9981
|
applyInitialRouteIfNeeded();
|
|
8614
9982
|
|
|
8615
|
-
refreshAll().then(() => {
|
|
9983
|
+
refreshAll().then(async () => {
|
|
8616
9984
|
applyInitialRouteIfNeeded();
|
|
9985
|
+
await applyRouteFocusIfNeeded();
|
|
8617
9986
|
}).catch((error) => {
|
|
8618
9987
|
setText('activity-message', error instanceof Error ? error.message : 'Launcher failed to load', 'error');
|
|
8619
9988
|
});
|
|
@@ -9115,6 +10484,73 @@ function createLauncherApp(options) {
|
|
|
9115
10484
|
response.status(400).json({ ok: false, message });
|
|
9116
10485
|
}
|
|
9117
10486
|
});
|
|
10487
|
+
app.post('/api/discovery/review/defer', (request, response) => {
|
|
10488
|
+
try {
|
|
10489
|
+
const kind = typeof request.body?.kind === 'string' ? request.body.kind.trim() : '';
|
|
10490
|
+
const selector = typeof request.body?.selector === 'string' ? request.body.selector.trim() : '';
|
|
10491
|
+
const hours = typeof request.body?.hours === 'number'
|
|
10492
|
+
? request.body.hours
|
|
10493
|
+
: Number.parseInt(String(request.body?.hours ?? '24'), 10);
|
|
10494
|
+
if (!selector) {
|
|
10495
|
+
response.status(400).json({ ok: false, message: 'Missing review selector.' });
|
|
10496
|
+
return;
|
|
10497
|
+
}
|
|
10498
|
+
if (kind === 'model') {
|
|
10499
|
+
options.service.deferDetectedModel(selector, Number.isFinite(hours) ? hours : 24);
|
|
10500
|
+
response.json({ ok: true, message: 'Model review deferred for 24 hours.' });
|
|
10501
|
+
return;
|
|
10502
|
+
}
|
|
10503
|
+
if (kind === 'runtime') {
|
|
10504
|
+
options.service.deferRuntimeSuggestion(selector, Number.isFinite(hours) ? hours : 24);
|
|
10505
|
+
response.json({ ok: true, message: 'Runtime review deferred for 24 hours.' });
|
|
10506
|
+
return;
|
|
10507
|
+
}
|
|
10508
|
+
if (kind === 'agent') {
|
|
10509
|
+
response.status(400).json({
|
|
10510
|
+
ok: false,
|
|
10511
|
+
message: 'Agent defer is not available yet in the local review surface.',
|
|
10512
|
+
});
|
|
10513
|
+
return;
|
|
10514
|
+
}
|
|
10515
|
+
response.status(400).json({ ok: false, message: 'Unsupported review kind.' });
|
|
10516
|
+
}
|
|
10517
|
+
catch (error) {
|
|
10518
|
+
const message = error instanceof Error ? error.message : 'discovery_review_defer_failed';
|
|
10519
|
+
response.status(400).json({ ok: false, message });
|
|
10520
|
+
}
|
|
10521
|
+
});
|
|
10522
|
+
app.post('/api/discovery/review/ignore', (request, response) => {
|
|
10523
|
+
try {
|
|
10524
|
+
const kind = typeof request.body?.kind === 'string' ? request.body.kind.trim() : '';
|
|
10525
|
+
const selector = typeof request.body?.selector === 'string' ? request.body.selector.trim() : '';
|
|
10526
|
+
if (!selector) {
|
|
10527
|
+
response.status(400).json({ ok: false, message: 'Missing review selector.' });
|
|
10528
|
+
return;
|
|
10529
|
+
}
|
|
10530
|
+
if (kind === 'model') {
|
|
10531
|
+
options.service.ignoreDetectedModel(selector);
|
|
10532
|
+
response.json({ ok: true, message: 'Model review ignored locally.' });
|
|
10533
|
+
return;
|
|
10534
|
+
}
|
|
10535
|
+
if (kind === 'runtime') {
|
|
10536
|
+
options.service.ignoreRuntimeSuggestion(selector);
|
|
10537
|
+
response.json({ ok: true, message: 'Runtime review ignored locally.' });
|
|
10538
|
+
return;
|
|
10539
|
+
}
|
|
10540
|
+
if (kind === 'agent') {
|
|
10541
|
+
response.status(400).json({
|
|
10542
|
+
ok: false,
|
|
10543
|
+
message: 'Agent ignore is not available yet in the local review surface.',
|
|
10544
|
+
});
|
|
10545
|
+
return;
|
|
10546
|
+
}
|
|
10547
|
+
response.status(400).json({ ok: false, message: 'Unsupported review kind.' });
|
|
10548
|
+
}
|
|
10549
|
+
catch (error) {
|
|
10550
|
+
const message = error instanceof Error ? error.message : 'discovery_review_ignore_failed';
|
|
10551
|
+
response.status(400).json({ ok: false, message });
|
|
10552
|
+
}
|
|
10553
|
+
});
|
|
9118
10554
|
app.get('/api/passports', (_request, response) => {
|
|
9119
10555
|
try {
|
|
9120
10556
|
response.json(buildPassports(options.service));
|