principles-disciple 1.13.0 → 1.14.0
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/openclaw.plugin.json +4 -4
- package/package.json +1 -1
- package/scripts/sync-plugin.mjs +1 -156
- package/src/commands/nocturnal-train.ts +12 -11
- package/src/core/evolution-reducer.ts +4 -31
- package/src/core/nocturnal-trinity.ts +4 -19
- package/src/core/principle-tree-ledger.ts +7 -27
- package/src/core/thinking-os-parser.ts +44 -36
- package/src/index.ts +3 -7
- package/src/service/nocturnal-service.ts +7 -11
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +3 -18
- package/templates/langs/en/principles/THINKING_OS.md +0 -13
- package/templates/langs/zh/principles/THINKING_OS.md +0 -13
- package/ui/src/i18n/ui.ts +52 -0
- package/ui/src/pages/EvolutionPage.tsx +38 -57
- package/ui/src/pages/FeedbackPage.tsx +0 -2
- package/ui/src/pages/GateMonitorPage.tsx +3 -3
- package/ui/src/pages/LoginPage.tsx +2 -1
- package/ui/src/pages/OverviewPage.tsx +10 -9
- package/ui/src/pages/SamplesPage.tsx +3 -3
- package/ui/src/pages/ThinkingModelsPage.tsx +444 -95
- package/ui/src/styles.css +316 -0
- package/src/core/principle-tree-migration.ts +0 -195
package/ui/src/styles.css
CHANGED
|
@@ -1702,3 +1702,319 @@ pre {
|
|
|
1702
1702
|
grid-template-columns: 1fr !important;
|
|
1703
1703
|
}
|
|
1704
1704
|
}
|
|
1705
|
+
|
|
1706
|
+
/* ==========================================================================
|
|
1707
|
+
Thinking Models Page — New styles for v1.10 polish pass
|
|
1708
|
+
========================================================================== */
|
|
1709
|
+
|
|
1710
|
+
/* Typography utility classes */
|
|
1711
|
+
.text-xs { font-size: var(--text-xs, 0.65rem); }
|
|
1712
|
+
.text-sm { font-size: var(--text-sm, 0.7rem); }
|
|
1713
|
+
.text-base { font-size: var(--text-base, 0.75rem); }
|
|
1714
|
+
.text-lg { font-size: var(--text-lg, 0.8rem); }
|
|
1715
|
+
.text-xl { font-size: var(--text-xl, 0.85rem); }
|
|
1716
|
+
.text-semibold { font-weight: 600; }
|
|
1717
|
+
.text-error { color: var(--error); }
|
|
1718
|
+
|
|
1719
|
+
/* Section title (replaces inline fontWeight + fontSize on h3/h4) */
|
|
1720
|
+
.section-title {
|
|
1721
|
+
font-size: var(--text-xl, 0.85rem);
|
|
1722
|
+
font-weight: 600;
|
|
1723
|
+
color: var(--text-primary);
|
|
1724
|
+
margin-bottom: var(--space-2);
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
/* Search + Sort + Filter controls */
|
|
1728
|
+
.sort-button {
|
|
1729
|
+
display: flex;
|
|
1730
|
+
align-items: center;
|
|
1731
|
+
gap: var(--space-1);
|
|
1732
|
+
padding: 6px 10px;
|
|
1733
|
+
border: 1px solid var(--border);
|
|
1734
|
+
border-radius: 6px;
|
|
1735
|
+
background: var(--bg-panel, var(--bg-elevated));
|
|
1736
|
+
color: var(--text-secondary);
|
|
1737
|
+
cursor: pointer;
|
|
1738
|
+
font-size: var(--text-base);
|
|
1739
|
+
transition: all var(--duration-fast) var(--ease-out);
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
.sort-button:hover {
|
|
1743
|
+
border-color: var(--border-hover);
|
|
1744
|
+
color: var(--text-primary);
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
.filter-button {
|
|
1748
|
+
padding: 3px 8px;
|
|
1749
|
+
border: 1px solid var(--border);
|
|
1750
|
+
border-radius: 4px;
|
|
1751
|
+
background: transparent;
|
|
1752
|
+
color: var(--text-secondary);
|
|
1753
|
+
cursor: pointer;
|
|
1754
|
+
font-size: var(--text-sm);
|
|
1755
|
+
transition: all var(--duration-fast) var(--ease-out);
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
.filter-button:hover {
|
|
1759
|
+
border-color: var(--border-hover);
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
.filter-button.active {
|
|
1763
|
+
border-color: var(--accent);
|
|
1764
|
+
background: rgba(91, 139, 160, 0.15);
|
|
1765
|
+
color: var(--accent);
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
/* Compare button bar */
|
|
1769
|
+
.compare-bar {
|
|
1770
|
+
display: flex;
|
|
1771
|
+
justify-content: space-between;
|
|
1772
|
+
align-items: center;
|
|
1773
|
+
padding: var(--space-2) var(--space-3);
|
|
1774
|
+
margin-bottom: var(--space-2);
|
|
1775
|
+
background: rgba(91, 139, 160, 0.08);
|
|
1776
|
+
border-radius: 6px;
|
|
1777
|
+
border: 1px solid var(--border);
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
.compare-button {
|
|
1781
|
+
display: flex;
|
|
1782
|
+
align-items: center;
|
|
1783
|
+
gap: var(--space-1);
|
|
1784
|
+
padding: 4px 12px;
|
|
1785
|
+
border: none;
|
|
1786
|
+
border-radius: 4px;
|
|
1787
|
+
background: var(--accent);
|
|
1788
|
+
color: #fff;
|
|
1789
|
+
cursor: pointer;
|
|
1790
|
+
font-size: var(--text-base);
|
|
1791
|
+
font-weight: 600;
|
|
1792
|
+
transition: background var(--duration-fast) var(--ease-out);
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
.compare-button:hover {
|
|
1796
|
+
background: var(--accent-hover);
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
/* Model list button (replaces inline style button) */
|
|
1800
|
+
.model-list-button {
|
|
1801
|
+
flex: 1;
|
|
1802
|
+
display: flex;
|
|
1803
|
+
justify-content: space-between;
|
|
1804
|
+
align-items: center;
|
|
1805
|
+
background: none;
|
|
1806
|
+
border: none;
|
|
1807
|
+
cursor: pointer;
|
|
1808
|
+
padding: 0;
|
|
1809
|
+
color: inherit;
|
|
1810
|
+
text-align: left;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
.hits-count {
|
|
1814
|
+
font-weight: 600;
|
|
1815
|
+
font-size: var(--text-xl, 0.85rem);
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
.scenario-ellipsis {
|
|
1819
|
+
overflow: hidden;
|
|
1820
|
+
text-overflow: ellipsis;
|
|
1821
|
+
white-space: nowrap;
|
|
1822
|
+
max-width: 180px;
|
|
1823
|
+
display: block;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
/* Code blocks for trigger / anti-pattern */
|
|
1827
|
+
.code-block {
|
|
1828
|
+
font-size: var(--text-base);
|
|
1829
|
+
white-space: pre-wrap;
|
|
1830
|
+
word-break: break-word;
|
|
1831
|
+
padding: var(--space-2) var(--space-3);
|
|
1832
|
+
border-radius: 6px;
|
|
1833
|
+
display: block;
|
|
1834
|
+
line-height: 1.5;
|
|
1835
|
+
font-family: var(--font-mono);
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
.code-block-trigger {
|
|
1839
|
+
background: var(--bg-sunken);
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
.code-block-antipattern {
|
|
1843
|
+
background: rgba(220, 53, 69, 0.08);
|
|
1844
|
+
color: var(--error);
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
/* Event context helpers */
|
|
1848
|
+
.event-context-tool {
|
|
1849
|
+
font-size: var(--text-sm);
|
|
1850
|
+
color: var(--text-secondary);
|
|
1851
|
+
display: flex;
|
|
1852
|
+
align-items: center;
|
|
1853
|
+
gap: var(--space-1);
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
.event-context-pain {
|
|
1857
|
+
font-size: var(--text-sm);
|
|
1858
|
+
color: var(--error);
|
|
1859
|
+
display: flex;
|
|
1860
|
+
align-items: center;
|
|
1861
|
+
gap: var(--space-1);
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
.event-context-principle {
|
|
1865
|
+
font-size: var(--text-sm);
|
|
1866
|
+
color: var(--info);
|
|
1867
|
+
display: flex;
|
|
1868
|
+
align-items: center;
|
|
1869
|
+
gap: var(--space-1);
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
.matched-pattern {
|
|
1873
|
+
font-size: var(--text-xs);
|
|
1874
|
+
color: var(--text-secondary);
|
|
1875
|
+
background: var(--bg-sunken);
|
|
1876
|
+
padding: 2px 6px;
|
|
1877
|
+
border-radius: 3px;
|
|
1878
|
+
font-family: var(--font-mono);
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
.event-trigger-excerpt {
|
|
1882
|
+
font-size: var(--text-sm);
|
|
1883
|
+
white-space: pre-wrap;
|
|
1884
|
+
word-break: break-word;
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
/* Heatmap table */
|
|
1888
|
+
.heatmap-table {
|
|
1889
|
+
border-collapse: collapse;
|
|
1890
|
+
width: 100%;
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
.heatmap-header {
|
|
1894
|
+
text-align: center;
|
|
1895
|
+
padding: 4px 6px;
|
|
1896
|
+
border-bottom: 1px solid var(--border);
|
|
1897
|
+
color: var(--text-secondary);
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
.heatmap-scenario {
|
|
1901
|
+
font-size: var(--text-xs);
|
|
1902
|
+
writing-mode: vertical-lr;
|
|
1903
|
+
transform: rotate(180deg);
|
|
1904
|
+
height: 80px;
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
.heatmap-sticky {
|
|
1908
|
+
position: sticky;
|
|
1909
|
+
left: 0;
|
|
1910
|
+
background: var(--bg-panel, var(--bg-elevated));
|
|
1911
|
+
z-index: 1;
|
|
1912
|
+
text-align: left;
|
|
1913
|
+
padding: 6px 8px;
|
|
1914
|
+
font-size: var(--text-base);
|
|
1915
|
+
font-weight: 600;
|
|
1916
|
+
min-width: 100px;
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
.heatmap-model {
|
|
1920
|
+
font-weight: 500;
|
|
1921
|
+
font-size: var(--text-base);
|
|
1922
|
+
padding: 4px 8px;
|
|
1923
|
+
border-top: 1px solid var(--border);
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
.heatmap-cell {
|
|
1927
|
+
text-align: center;
|
|
1928
|
+
padding: 4px 6px;
|
|
1929
|
+
font-size: var(--text-sm);
|
|
1930
|
+
border-top: 1px solid var(--border);
|
|
1931
|
+
color: var(--text-primary);
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
/* Loader spin animation (reuses existing .spinner keyframes) */
|
|
1935
|
+
.spin {
|
|
1936
|
+
animation: spin 0.8s linear infinite;
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
/* Loading placeholder for empty model definitions grid */
|
|
1940
|
+
.loading-placeholder {
|
|
1941
|
+
display: flex;
|
|
1942
|
+
flex-direction: column;
|
|
1943
|
+
align-items: center;
|
|
1944
|
+
justify-content: center;
|
|
1945
|
+
padding: var(--space-6);
|
|
1946
|
+
color: var(--text-secondary);
|
|
1947
|
+
gap: var(--space-2);
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
/* Text alignment utility */
|
|
1951
|
+
.text-center { text-align: center; }
|
|
1952
|
+
|
|
1953
|
+
/* Stage badge (EvolutionPage) */
|
|
1954
|
+
.stage-badge {
|
|
1955
|
+
display: inline-flex;
|
|
1956
|
+
align-items: center;
|
|
1957
|
+
gap: var(--space-1);
|
|
1958
|
+
padding: var(--space-2) var(--space-4);
|
|
1959
|
+
border-radius: var(--radius-lg);
|
|
1960
|
+
font-size: var(--text-lg, 0.8rem);
|
|
1961
|
+
font-weight: 600;
|
|
1962
|
+
background: var(--accent);
|
|
1963
|
+
color: #fff;
|
|
1964
|
+
border: 2px solid var(--accent);
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1967
|
+
.stage-badge svg {
|
|
1968
|
+
width: 16px;
|
|
1969
|
+
height: 16px;
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
/* Sample pre blocks (SamplesPage) */
|
|
1973
|
+
.sample-pre {
|
|
1974
|
+
white-space: pre-wrap;
|
|
1975
|
+
word-break: break-word;
|
|
1976
|
+
background: var(--bg-sunken);
|
|
1977
|
+
padding: var(--space-3);
|
|
1978
|
+
border-radius: var(--radius-md);
|
|
1979
|
+
font-family: var(--font-mono);
|
|
1980
|
+
font-size: var(--text-sm);
|
|
1981
|
+
overflow-x: auto;
|
|
1982
|
+
max-width: 100%;
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
/* GFI big number (FeedbackPage) */
|
|
1986
|
+
.gfi-big-number {
|
|
1987
|
+
font-size: 3rem;
|
|
1988
|
+
font-weight: 700;
|
|
1989
|
+
line-height: 1;
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
/* Progress bar (shared component pattern) */
|
|
1993
|
+
.progress-bar {
|
|
1994
|
+
width: 100%;
|
|
1995
|
+
height: 8px;
|
|
1996
|
+
background: var(--bg-sunken);
|
|
1997
|
+
border-radius: 4px;
|
|
1998
|
+
overflow: hidden;
|
|
1999
|
+
margin-top: var(--space-2);
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
.progress-bar-fill {
|
|
2003
|
+
height: 100%;
|
|
2004
|
+
border-radius: 4px;
|
|
2005
|
+
transition: width 0.3s ease;
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
/* GateMonitor trust/EP big numbers */
|
|
2009
|
+
.stat-big-number {
|
|
2010
|
+
font-size: 1.5rem;
|
|
2011
|
+
font-weight: 700;
|
|
2012
|
+
line-height: 1;
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
/* EvolutionPage icon alignment */
|
|
2016
|
+
.panel h3 svg {
|
|
2017
|
+
vertical-align: middle;
|
|
2018
|
+
margin-right: var(--space-1);
|
|
2019
|
+
}
|
|
2020
|
+
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Principle Tree Migration — Migrates trainingStore to tree.principles
|
|
3
|
-
*
|
|
4
|
-
* This migration handles the Phase 11 gap: existing principles in trainingStore
|
|
5
|
-
* were never written to tree.principles, blocking the Rule/Implementation layer.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* - Called automatically by migratePrincipleTree() during plugin initialization
|
|
9
|
-
* - Or run manually: node scripts/migrate-principle-tree.mjs <workspace-dir>
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import * as fs from 'fs';
|
|
13
|
-
import * as path from 'path';
|
|
14
|
-
import {
|
|
15
|
-
loadLedger,
|
|
16
|
-
createPrinciple,
|
|
17
|
-
type LedgerPrinciple,
|
|
18
|
-
} from './principle-tree-ledger.js';
|
|
19
|
-
import type { LegacyPrincipleTrainingState } from './principle-tree-ledger.js';
|
|
20
|
-
import { SystemLogger } from './system-logger.js';
|
|
21
|
-
|
|
22
|
-
export interface PrincipleTreeMigrationResult {
|
|
23
|
-
migratedCount: number;
|
|
24
|
-
skippedCount: number;
|
|
25
|
-
errorCount: number;
|
|
26
|
-
details: Array<{
|
|
27
|
-
principleId: string;
|
|
28
|
-
status: 'migrated' | 'skipped' | 'error';
|
|
29
|
-
reason?: string;
|
|
30
|
-
}>;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Check if migration is needed by comparing trainingStore and tree.principles
|
|
35
|
-
*/
|
|
36
|
-
export function needsMigration(stateDir: string): boolean {
|
|
37
|
-
const ledger = loadLedger(stateDir);
|
|
38
|
-
const trainingStoreCount = Object.keys(ledger.trainingStore).length;
|
|
39
|
-
const treePrinciplesCount = Object.keys(ledger.tree.principles).length;
|
|
40
|
-
|
|
41
|
-
// Migration needed if trainingStore has more principles than tree.principles
|
|
42
|
-
return trainingStoreCount > treePrinciplesCount;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Create a minimal LedgerPrinciple from LegacyPrincipleTrainingState
|
|
47
|
-
*/
|
|
48
|
-
function trainingStateToTreePrinciple(
|
|
49
|
-
principleId: string,
|
|
50
|
-
state: LegacyPrincipleTrainingState,
|
|
51
|
-
now: string
|
|
52
|
-
): LedgerPrinciple {
|
|
53
|
-
return {
|
|
54
|
-
id: principleId,
|
|
55
|
-
version: 1,
|
|
56
|
-
text: `Principle ${principleId}`, // Minimal text, will be enriched from PRINCIPLES.md if available
|
|
57
|
-
triggerPattern: '', // Unknown from legacy data
|
|
58
|
-
action: '', // Unknown from legacy data
|
|
59
|
-
status: mapInternalizationStatusToPrincipleStatus(state.internalizationStatus),
|
|
60
|
-
priority: 'P1', // Default priority
|
|
61
|
-
scope: 'general',
|
|
62
|
-
evaluability: state.evaluability,
|
|
63
|
-
valueScore: 0,
|
|
64
|
-
adherenceRate: state.complianceRate * 100, // Convert 0-1 to 0-100
|
|
65
|
-
painPreventedCount: 0,
|
|
66
|
-
derivedFromPainIds: [],
|
|
67
|
-
ruleIds: [],
|
|
68
|
-
conflictsWithPrincipleIds: [],
|
|
69
|
-
createdAt: now,
|
|
70
|
-
updatedAt: now,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Map internalization status to principle status
|
|
76
|
-
*/
|
|
77
|
-
function mapInternalizationStatusToPrincipleStatus(
|
|
78
|
-
status: LegacyPrincipleTrainingState['internalizationStatus']
|
|
79
|
-
): 'candidate' | 'active' | 'deprecated' {
|
|
80
|
-
switch (status) {
|
|
81
|
-
case 'internalized':
|
|
82
|
-
case 'deployed_pending_eval':
|
|
83
|
-
return 'active';
|
|
84
|
-
case 'regressed':
|
|
85
|
-
case 'needs_training':
|
|
86
|
-
return 'candidate';
|
|
87
|
-
case 'prompt_only':
|
|
88
|
-
case 'in_training':
|
|
89
|
-
return 'candidate';
|
|
90
|
-
default:
|
|
91
|
-
return 'candidate';
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Migrate trainingStore principles to tree.principles
|
|
97
|
-
*
|
|
98
|
-
* This function is idempotent: it only migrates principles that don't exist
|
|
99
|
-
* in tree.principles yet.
|
|
100
|
-
*/
|
|
101
|
-
export function migratePrincipleTree(
|
|
102
|
-
stateDir: string,
|
|
103
|
-
workspaceDir?: string
|
|
104
|
-
): PrincipleTreeMigrationResult {
|
|
105
|
-
const result: PrincipleTreeMigrationResult = {
|
|
106
|
-
migratedCount: 0,
|
|
107
|
-
skippedCount: 0,
|
|
108
|
-
errorCount: 0,
|
|
109
|
-
details: [],
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
try {
|
|
113
|
-
const ledger = loadLedger(stateDir);
|
|
114
|
-
const now = new Date().toISOString();
|
|
115
|
-
|
|
116
|
-
for (const [principleId, state] of Object.entries(ledger.trainingStore)) {
|
|
117
|
-
// Skip if already exists in tree.principles
|
|
118
|
-
if (ledger.tree.principles[principleId]) {
|
|
119
|
-
result.skippedCount++;
|
|
120
|
-
result.details.push({
|
|
121
|
-
principleId,
|
|
122
|
-
status: 'skipped',
|
|
123
|
-
reason: 'Already exists in tree.principles',
|
|
124
|
-
});
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
try {
|
|
129
|
-
const treePrinciple = trainingStateToTreePrinciple(principleId, state, now);
|
|
130
|
-
createPrinciple(stateDir, treePrinciple);
|
|
131
|
-
|
|
132
|
-
result.migratedCount++;
|
|
133
|
-
result.details.push({
|
|
134
|
-
principleId,
|
|
135
|
-
status: 'migrated',
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
if (workspaceDir) {
|
|
139
|
-
SystemLogger.log(
|
|
140
|
-
workspaceDir,
|
|
141
|
-
'PRINCIPLE_TREE_MIGRATED',
|
|
142
|
-
`Migrated ${principleId} from trainingStore to tree.principles`
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
} catch (err) {
|
|
146
|
-
result.errorCount++;
|
|
147
|
-
result.details.push({
|
|
148
|
-
principleId,
|
|
149
|
-
status: 'error',
|
|
150
|
-
reason: String(err),
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
if (workspaceDir) {
|
|
154
|
-
SystemLogger.log(
|
|
155
|
-
workspaceDir,
|
|
156
|
-
'PRINCIPLE_TREE_MIGRATION_ERROR',
|
|
157
|
-
`Failed to migrate ${principleId}: ${String(err)}`
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (workspaceDir && result.migratedCount > 0) {
|
|
164
|
-
SystemLogger.log(
|
|
165
|
-
workspaceDir,
|
|
166
|
-
'PRINCIPLE_TREE_MIGRATION_COMPLETE',
|
|
167
|
-
`Migrated ${result.migratedCount} principles to tree.principles (${result.skippedCount} skipped, ${result.errorCount} errors)`
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
} catch (err) {
|
|
171
|
-
if (workspaceDir) {
|
|
172
|
-
SystemLogger.log(
|
|
173
|
-
workspaceDir,
|
|
174
|
-
'PRINCIPLE_TREE_MIGRATION_FAILED',
|
|
175
|
-
`Migration failed: ${String(err)}`
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return result;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Run migration if needed (called during plugin initialization)
|
|
185
|
-
*/
|
|
186
|
-
export function runMigrationIfNeeded(
|
|
187
|
-
stateDir: string,
|
|
188
|
-
workspaceDir?: string
|
|
189
|
-
): PrincipleTreeMigrationResult | null {
|
|
190
|
-
if (!needsMigration(stateDir)) {
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return migratePrincipleTree(stateDir, workspaceDir);
|
|
195
|
-
}
|