@goodandready/dsh-goal 0.2.9 → 0.2.10
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/lib/client.js +350 -13
- package/lib/engine-git-branch.js +105 -0
- package/lib/engine-intervention.js +150 -0
- package/lib/engine-issue-sync.js +66 -0
- package/lib/engine-milestones.js +42 -3
- package/lib/engine-prompt.js +28 -4
- package/lib/engine-retrospective.js +79 -0
- package/lib/engine-sessions.js +82 -0
- package/lib/engine-templates.js +167 -0
- package/lib/goal-engine-constants.js +30 -0
- package/lib/goal-engine.js +198 -233
- package/lib/index.js +36 -0
- package/lib/routes.js +52 -0
- package/lib/tools.js +11 -1
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -1484,6 +1484,102 @@ window.__ModuleLoader__.load({
|
|
|
1484
1484
|
|
|
1485
1485
|
}
|
|
1486
1486
|
|
|
1487
|
+
|
|
1488
|
+
.dsh-goal-intervene-card {
|
|
1489
|
+
padding: 12px;
|
|
1490
|
+
border-radius: 8px;
|
|
1491
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
1492
|
+
border: 1px solid var(--dsw-alias-state-warning-primary);
|
|
1493
|
+
margin-bottom: 12px;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
.dsh-goal-preplan-card {
|
|
1497
|
+
padding: 12px;
|
|
1498
|
+
border-radius: 8px;
|
|
1499
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
1500
|
+
border: 1px solid var(--dsw-alias-state-info-primary, var(--dsw-alias-border-l2));
|
|
1501
|
+
margin-bottom: 12px;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
.dsh-goal-activity-feed {
|
|
1505
|
+
padding: 10px 12px;
|
|
1506
|
+
border-radius: 8px;
|
|
1507
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
1508
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
1509
|
+
margin-top: 12px;
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
.dsh-goal-activity-list {
|
|
1513
|
+
max-height: 140px;
|
|
1514
|
+
overflow-y: auto;
|
|
1515
|
+
display: flex;
|
|
1516
|
+
flex-direction: column;
|
|
1517
|
+
gap: 6px;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
.dsh-goal-activity-row {
|
|
1521
|
+
display: flex;
|
|
1522
|
+
align-items: center;
|
|
1523
|
+
gap: 8px;
|
|
1524
|
+
font-size: 11px;
|
|
1525
|
+
color: var(--dsw-alias-label-secondary);
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
.dsh-goal-activity-dot {
|
|
1529
|
+
width: 6px;
|
|
1530
|
+
height: 6px;
|
|
1531
|
+
border-radius: 50%;
|
|
1532
|
+
background: var(--dsw-alias-state-info-primary, var(--dsw-alias-primary));
|
|
1533
|
+
flex-shrink: 0;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
.dsh-goal-activity-time {
|
|
1537
|
+
font-size: 10px;
|
|
1538
|
+
color: var(--dsw-alias-label-tertiary);
|
|
1539
|
+
flex-shrink: 0;
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
.dsh-goal-activity-text {
|
|
1543
|
+
overflow: hidden;
|
|
1544
|
+
text-overflow: ellipsis;
|
|
1545
|
+
white-space: nowrap;
|
|
1546
|
+
flex: 1;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
.dsh-goal-retrospective-card {
|
|
1550
|
+
padding: 12px;
|
|
1551
|
+
border-radius: 8px;
|
|
1552
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
1553
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
1554
|
+
margin-top: 12px;
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
.dsh-goal-chip-btn {
|
|
1558
|
+
padding: 3px 8px;
|
|
1559
|
+
border-radius: 9999px;
|
|
1560
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
1561
|
+
border: 1px solid var(--dsw-alias-border-l2);
|
|
1562
|
+
color: var(--dsw-alias-label-primary);
|
|
1563
|
+
font-size: 11px;
|
|
1564
|
+
cursor: pointer;
|
|
1565
|
+
transition: all 0.15s ease;
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
.dsh-goal-chip-btn:hover {
|
|
1569
|
+
background: var(--dsw-alias-bg-hover);
|
|
1570
|
+
border-color: var(--dsw-alias-border-l1);
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
.dsh-goal-lock-badge {
|
|
1574
|
+
font-size: 10px;
|
|
1575
|
+
padding: 1px 6px;
|
|
1576
|
+
border-radius: 4px;
|
|
1577
|
+
background: var(--dsw-alias-state-warning-bg, var(--dsw-alias-bg-layer-4));
|
|
1578
|
+
color: var(--dsw-alias-state-warning-primary);
|
|
1579
|
+
border: 1px solid var(--dsw-alias-state-warning-primary);
|
|
1580
|
+
margin-left: 6px;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1487
1583
|
`;
|
|
1488
1584
|
|
|
1489
1585
|
function injectStylesOnce() {
|
|
@@ -1504,27 +1600,48 @@ window.__ModuleLoader__.load({
|
|
|
1504
1600
|
|
|
1505
1601
|
}
|
|
1506
1602
|
|
|
1507
|
-
// Synthesize audio chimes via Web Audio API (Item 6)
|
|
1508
|
-
|
|
1509
|
-
function playGoalChime(isSuccess = true) {
|
|
1603
|
+
// Synthesize audio chimes via Web Audio API (Item 6) & soundScheme (#92)
|
|
1510
1604
|
|
|
1605
|
+
function playGoalChime(isSuccess = true, scheme = 'default') {
|
|
1511
1606
|
if (typeof window === 'undefined') return;
|
|
1512
|
-
|
|
1513
1607
|
try {
|
|
1514
|
-
|
|
1515
1608
|
const AudioCtx = window.AudioContext || window.webkitAudioContext;
|
|
1516
|
-
|
|
1517
1609
|
if (!AudioCtx) return;
|
|
1518
|
-
|
|
1519
1610
|
const actx = new AudioCtx();
|
|
1520
|
-
|
|
1521
1611
|
if (actx.state === 'suspended') {
|
|
1522
|
-
|
|
1523
1612
|
actx.resume().catch(() => {});
|
|
1524
|
-
|
|
1525
1613
|
}
|
|
1526
|
-
|
|
1527
1614
|
const now = actx.currentTime;
|
|
1615
|
+
if (scheme === 'retro') {
|
|
1616
|
+
const notes = isSuccess ? [330, 440, 554, 659] : [300, 220, 160];
|
|
1617
|
+
notes.forEach((freq, idx) => {
|
|
1618
|
+
const osc = actx.createOscillator();
|
|
1619
|
+
const gain = actx.createGain();
|
|
1620
|
+
osc.type = 'square';
|
|
1621
|
+
osc.frequency.setValueAtTime(freq, now + idx * 0.08);
|
|
1622
|
+
gain.gain.setValueAtTime(0.08, now + idx * 0.08);
|
|
1623
|
+
gain.gain.exponentialRampToValueAtTime(0.001, now + idx * 0.08 + 0.1);
|
|
1624
|
+
osc.connect(gain);
|
|
1625
|
+
gain.connect(actx.destination);
|
|
1626
|
+
osc.start(now + idx * 0.08);
|
|
1627
|
+
osc.stop(now + idx * 0.08 + 0.12);
|
|
1628
|
+
});
|
|
1629
|
+
return;
|
|
1630
|
+
}
|
|
1631
|
+
if (scheme === 'minimal') {
|
|
1632
|
+
const osc = actx.createOscillator();
|
|
1633
|
+
const gain = actx.createGain();
|
|
1634
|
+
osc.type = 'triangle';
|
|
1635
|
+
osc.frequency.setValueAtTime(isSuccess ? 880 : 330, now);
|
|
1636
|
+
gain.gain.setValueAtTime(0.001, now);
|
|
1637
|
+
gain.gain.exponentialRampToValueAtTime(0.12, now + 0.02);
|
|
1638
|
+
gain.gain.exponentialRampToValueAtTime(0.0001, now + 0.35);
|
|
1639
|
+
osc.connect(gain);
|
|
1640
|
+
gain.connect(actx.destination);
|
|
1641
|
+
osc.start(now);
|
|
1642
|
+
osc.stop(now + 0.4);
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1528
1645
|
|
|
1529
1646
|
// Pentatonic chords: success ascending C5-E5-G5-C6; failure descending G4-Eb4-C4
|
|
1530
1647
|
|
|
@@ -1570,6 +1687,17 @@ window.__ModuleLoader__.load({
|
|
|
1570
1687
|
|
|
1571
1688
|
}
|
|
1572
1689
|
|
|
1690
|
+
// Voice announcement via Web Speech API (#92)
|
|
1691
|
+
function speakGoalAnnouncement(text, enabled = false) {
|
|
1692
|
+
if (!enabled || typeof window === 'undefined' || !window.speechSynthesis) return;
|
|
1693
|
+
try {
|
|
1694
|
+
const utter = new SpeechSynthesisUtterance(text);
|
|
1695
|
+
utter.rate = 1.0;
|
|
1696
|
+
utter.pitch = 1.0;
|
|
1697
|
+
window.speechSynthesis.speak(utter);
|
|
1698
|
+
} catch (err) { /* defensive */ }
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1573
1701
|
// --- REPORT GENERATOR FOR GITHUB / GITEA PR COMMENT ---
|
|
1574
1702
|
|
|
1575
1703
|
function generateGitHubPRComment(state) {
|
|
@@ -1742,6 +1870,10 @@ window.__ModuleLoader__.load({
|
|
|
1742
1870
|
|
|
1743
1871
|
const [nudgeSent, setNudgeSent] = useState(false);
|
|
1744
1872
|
|
|
1873
|
+
const [interveneText, setInterveneText] = useState('');
|
|
1874
|
+
|
|
1875
|
+
const [interveneSent, setInterveneSent] = useState(false);
|
|
1876
|
+
|
|
1745
1877
|
const totalTokens = state.tokensUsage?.totalTokens || 0;
|
|
1746
1878
|
|
|
1747
1879
|
const promptTokens = state.tokensUsage?.promptTokens || 0;
|
|
@@ -1982,6 +2114,64 @@ window.__ModuleLoader__.load({
|
|
|
1982
2114
|
|
|
1983
2115
|
: null,
|
|
1984
2116
|
|
|
2117
|
+
// Smart Pre-planning Draft Card (#85)
|
|
2118
|
+
state.preplan && state.preplan.active && Array.isArray(state.preplan.draftMilestones) && state.preplan.draftMilestones.length > 0
|
|
2119
|
+
? React.createElement(
|
|
2120
|
+
'div',
|
|
2121
|
+
{ className: 'dsh-goal-preplan-card' },
|
|
2122
|
+
React.createElement('div', { style: { fontWeight: 600, fontSize: 13, marginBottom: 4, display: 'flex', alignItems: 'center', gap: 6 } },
|
|
2123
|
+
React.createElement('span', null, '📋'),
|
|
2124
|
+
React.createElement('span', null, t('preplanTitle') || 'Smart Pre-plan Ready')
|
|
2125
|
+
),
|
|
2126
|
+
React.createElement('div', { style: { fontSize: 12, color: 'var(--dsw-alias-label-secondary)', marginBottom: 8 } },
|
|
2127
|
+
`Generated ${state.preplan.draftMilestones.length} draft milestone(s). Review and approve to start.`
|
|
2128
|
+
),
|
|
2129
|
+
React.createElement('div', { style: { display: 'flex', gap: 8 } },
|
|
2130
|
+
React.createElement('button', {
|
|
2131
|
+
type: 'button',
|
|
2132
|
+
className: 'dsh-goal-btn dsh-goal-btn-primary',
|
|
2133
|
+
onClick: () => onAction('preplan_approve', { sessionId: state.sessionId, approvedMilestones: state.preplan.draftMilestones })
|
|
2134
|
+
}, t('preplanApprove') || 'Approve & Start Plan')
|
|
2135
|
+
)
|
|
2136
|
+
)
|
|
2137
|
+
: null,
|
|
2138
|
+
|
|
2139
|
+
// Pause & Intervene Card (#83)
|
|
2140
|
+
state.state === 'PAUSED'
|
|
2141
|
+
? React.createElement(
|
|
2142
|
+
'div',
|
|
2143
|
+
{ className: 'dsh-goal-intervene-card' },
|
|
2144
|
+
React.createElement('div', { style: { fontWeight: 600, fontSize: 13, marginBottom: 4, display: 'flex', alignItems: 'center', gap: 6 } },
|
|
2145
|
+
React.createElement('span', null, '⏸️'),
|
|
2146
|
+
React.createElement('span', null, t('interveneTitle') || 'Pause & Intervene')
|
|
2147
|
+
),
|
|
2148
|
+
React.createElement('div', { style: { fontSize: 12, color: 'var(--dsw-alias-label-secondary)', marginBottom: 8 } },
|
|
2149
|
+
t('interveneDesc') || 'Goal is paused. Steer agent behavior with direct guidance before resuming.'
|
|
2150
|
+
),
|
|
2151
|
+
React.createElement('textarea', {
|
|
2152
|
+
className: 'dsh-goal-card-input',
|
|
2153
|
+
style: { width: '100%', minHeight: 60, fontSize: 12, resize: 'vertical', marginBottom: 8 },
|
|
2154
|
+
placeholder: t('interveneDirectivePlaceholder') || 'Enter directive instructions for the agent...',
|
|
2155
|
+
value: interveneText,
|
|
2156
|
+
onChange: (e) => setInterveneText(e.target.value),
|
|
2157
|
+
}),
|
|
2158
|
+
React.createElement('div', { style: { display: 'flex', gap: 8, justifyContent: 'flex-end' } },
|
|
2159
|
+
React.createElement('button', {
|
|
2160
|
+
type: 'button',
|
|
2161
|
+
className: 'dsh-goal-btn dsh-goal-btn-primary',
|
|
2162
|
+
disabled: !interveneText.trim() && !interveneSent,
|
|
2163
|
+
onClick: () => {
|
|
2164
|
+
if (interveneText.trim()) {
|
|
2165
|
+
onAction('intervene', { directive: interveneText.trim() });
|
|
2166
|
+
setInterveneSent(true);
|
|
2167
|
+
setTimeout(() => setInterveneSent(false), 2000);
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
}, interveneSent ? (t('interveneApplied') || '✅ Applied') : (t('interveneApply') || 'Apply Directive & Resume'))
|
|
2171
|
+
)
|
|
2172
|
+
)
|
|
2173
|
+
: null,
|
|
2174
|
+
|
|
1985
2175
|
React.createElement(
|
|
1986
2176
|
|
|
1987
2177
|
'div',
|
|
@@ -2097,6 +2287,12 @@ window.__ModuleLoader__.load({
|
|
|
2097
2287
|
},
|
|
2098
2288
|
|
|
2099
2289
|
`${i + 1}. ${m.title}`,
|
|
2290
|
+
Array.isArray(m.dependsOn) && m.dependsOn.some((depId) => {
|
|
2291
|
+
const prereq = milestones.find((x) => x.id === depId || x.title === depId);
|
|
2292
|
+
return prereq && prereq.status !== 'completed';
|
|
2293
|
+
})
|
|
2294
|
+
? React.createElement('span', { className: 'dsh-goal-lock-badge' }, `🔒 ${t('waitingPrereq') || 'waiting for prereq'}`)
|
|
2295
|
+
: null,
|
|
2100
2296
|
|
|
2101
2297
|
),
|
|
2102
2298
|
|
|
@@ -2155,6 +2351,96 @@ window.__ModuleLoader__.load({
|
|
|
2155
2351
|
|
|
2156
2352
|
),
|
|
2157
2353
|
|
|
2354
|
+
// Git Branch Action Controls (#86)
|
|
2355
|
+
state.gitBranch
|
|
2356
|
+
? React.createElement(
|
|
2357
|
+
'div',
|
|
2358
|
+
{ style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, padding: '8px 10px', borderRadius: 8, background: 'var(--dsw-alias-bg-layer-2)', border: '1px solid var(--dsw-alias-border-l2)', marginTop: 8 } },
|
|
2359
|
+
React.createElement('span', { className: 'dsh-goal-git-badge', style: { margin: 0 } }, `🌿 ${state.gitBranch}`),
|
|
2360
|
+
(isCompleted || state.state === 'CANCELLED')
|
|
2361
|
+
? React.createElement(
|
|
2362
|
+
'div',
|
|
2363
|
+
{ style: { display: 'flex', gap: 6 } },
|
|
2364
|
+
React.createElement('button', {
|
|
2365
|
+
type: 'button',
|
|
2366
|
+
className: 'dsh-goal-btn',
|
|
2367
|
+
style: { fontSize: 11, padding: '2px 8px' },
|
|
2368
|
+
onClick: () => onAction('branch_action', { action: 'merge', sessionId: state.sessionId })
|
|
2369
|
+
}, t('mergeBranch') || 'Merge Branch'),
|
|
2370
|
+
React.createElement('button', {
|
|
2371
|
+
type: 'button',
|
|
2372
|
+
className: 'dsh-goal-btn',
|
|
2373
|
+
style: { fontSize: 11, padding: '2px 8px' },
|
|
2374
|
+
onClick: () => onAction('branch_action', { action: 'discard', sessionId: state.sessionId })
|
|
2375
|
+
}, t('discardBranch') || 'Discard Branch')
|
|
2376
|
+
)
|
|
2377
|
+
: null
|
|
2378
|
+
)
|
|
2379
|
+
: null,
|
|
2380
|
+
|
|
2381
|
+
// Live Activity Mini-Feed (#84)
|
|
2382
|
+
state.enableLiveActivityFeed !== false && Array.isArray(state.activityFeed) && state.activityFeed.length > 0
|
|
2383
|
+
? React.createElement(
|
|
2384
|
+
'div',
|
|
2385
|
+
{ className: 'dsh-goal-activity-feed' },
|
|
2386
|
+
React.createElement('div', { style: { fontWeight: 600, fontSize: 12, marginBottom: 6, color: 'var(--dsw-alias-label-primary)', display: 'flex', alignItems: 'center', gap: 6 } },
|
|
2387
|
+
React.createElement('span', null, '⚡'),
|
|
2388
|
+
React.createElement('span', null, t('liveActivityTitle') || 'Live Activity Feed'),
|
|
2389
|
+
React.createElement('span', { style: { fontSize: 10, color: 'var(--dsw-alias-label-tertiary)', fontWeight: 400 } }, `(${state.activityFeed.length})`)
|
|
2390
|
+
),
|
|
2391
|
+
React.createElement(
|
|
2392
|
+
'div',
|
|
2393
|
+
{ className: 'dsh-goal-activity-list' },
|
|
2394
|
+
state.activityFeed.slice(-6).reverse().map((act, actIdx) =>
|
|
2395
|
+
React.createElement('div', { key: act.id || actIdx, className: 'dsh-goal-activity-row' },
|
|
2396
|
+
React.createElement('span', { className: 'dsh-goal-activity-dot' }),
|
|
2397
|
+
React.createElement('span', { className: 'dsh-goal-activity-text' }, act.details || act.tool || act.type)
|
|
2398
|
+
)
|
|
2399
|
+
)
|
|
2400
|
+
)
|
|
2401
|
+
)
|
|
2402
|
+
: null,
|
|
2403
|
+
|
|
2404
|
+
// Post-Goal Retrospective Card (#88)
|
|
2405
|
+
isCompleted && state.retrospective
|
|
2406
|
+
? React.createElement(
|
|
2407
|
+
'div',
|
|
2408
|
+
{ className: 'dsh-goal-retrospective-card' },
|
|
2409
|
+
React.createElement('div', { style: { fontWeight: 600, fontSize: 13, marginBottom: 8, display: 'flex', alignItems: 'center', gap: 6 } },
|
|
2410
|
+
React.createElement('span', null, '📊'),
|
|
2411
|
+
React.createElement('span', null, t('retrospectiveTitle') || 'Goal Retrospective')
|
|
2412
|
+
),
|
|
2413
|
+
React.createElement(
|
|
2414
|
+
'div',
|
|
2415
|
+
{ style: { display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 8, fontSize: 11 } },
|
|
2416
|
+
React.createElement('div', null,
|
|
2417
|
+
React.createElement('div', { style: { color: 'var(--dsw-alias-label-tertiary)' } }, 'Duration'),
|
|
2418
|
+
React.createElement('div', { style: { fontWeight: 600 } }, state.retrospective.formattedDuration || state.formattedElapsed || '0s')
|
|
2419
|
+
),
|
|
2420
|
+
React.createElement('div', null,
|
|
2421
|
+
React.createElement('div', { style: { color: 'var(--dsw-alias-label-tertiary)' } }, 'Tokens'),
|
|
2422
|
+
React.createElement('div', { style: { fontWeight: 600 } }, state.retrospective.tokensTotal ? `${state.retrospective.tokensTotal}` : '—')
|
|
2423
|
+
),
|
|
2424
|
+
React.createElement('div', null,
|
|
2425
|
+
React.createElement('div', { style: { color: 'var(--dsw-alias-label-tertiary)' } }, 'Files Modified'),
|
|
2426
|
+
React.createElement('div', { style: { fontWeight: 600 } }, `${state.retrospective.filesModifiedCount || 0}`)
|
|
2427
|
+
),
|
|
2428
|
+
React.createElement('div', null,
|
|
2429
|
+
React.createElement('div', { style: { color: 'var(--dsw-alias-label-tertiary)' } }, 'Tool Calls'),
|
|
2430
|
+
React.createElement('div', { style: { fontWeight: 600 } }, `${state.retrospective.toolCallsCount || 0}`)
|
|
2431
|
+
),
|
|
2432
|
+
React.createElement('div', null,
|
|
2433
|
+
React.createElement('div', { style: { color: 'var(--dsw-alias-label-tertiary)' } }, 'Stall Recoveries'),
|
|
2434
|
+
React.createElement('div', { style: { fontWeight: 600 } }, `${state.retrospective.stallsEncountered || 0}`)
|
|
2435
|
+
),
|
|
2436
|
+
React.createElement('div', null,
|
|
2437
|
+
React.createElement('div', { style: { color: 'var(--dsw-alias-label-tertiary)' } }, 'Milestones'),
|
|
2438
|
+
React.createElement('div', { style: { fontWeight: 600 } }, `${state.retrospective.milestonesCompleted || 0}/${state.retrospective.milestonesTotal || 0}`)
|
|
2439
|
+
)
|
|
2440
|
+
)
|
|
2441
|
+
)
|
|
2442
|
+
: null,
|
|
2443
|
+
|
|
2158
2444
|
),
|
|
2159
2445
|
|
|
2160
2446
|
React.createElement(
|
|
@@ -2475,6 +2761,29 @@ window.__ModuleLoader__.load({
|
|
|
2475
2761
|
|
|
2476
2762
|
}),
|
|
2477
2763
|
|
|
2764
|
+
React.createElement(
|
|
2765
|
+
'div',
|
|
2766
|
+
{ style: { display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 8 } },
|
|
2767
|
+
[
|
|
2768
|
+
{ id: 'quickfix', label: '⚡ Quick Fix', template: 'Fix issue: ' },
|
|
2769
|
+
{ id: 'feature', label: '✨ Feature', template: 'Implement feature: ' },
|
|
2770
|
+
{ id: 'refactor', label: '♻️ Refactor', template: 'Refactor module: ' },
|
|
2771
|
+
{ id: 'repro', label: '🐛 Bug Repro', template: 'Reproduce and resolve bug: ' },
|
|
2772
|
+
{ id: 'audit', label: '🔍 Audit', template: 'Deep audit codebase: ' },
|
|
2773
|
+
{ id: 'security', label: '🛡️ Security', template: 'Security hardening for: ' },
|
|
2774
|
+
].map((tpl) =>
|
|
2775
|
+
React.createElement(
|
|
2776
|
+
'button',
|
|
2777
|
+
{
|
|
2778
|
+
key: tpl.id,
|
|
2779
|
+
type: 'button',
|
|
2780
|
+
className: 'dsh-goal-chip-btn',
|
|
2781
|
+
onClick: () => setTitle(tpl.template),
|
|
2782
|
+
},
|
|
2783
|
+
tpl.label
|
|
2784
|
+
)
|
|
2785
|
+
)
|
|
2786
|
+
),
|
|
2478
2787
|
),
|
|
2479
2788
|
|
|
2480
2789
|
React.createElement(
|
|
@@ -2701,11 +3010,13 @@ window.__ModuleLoader__.load({
|
|
|
2701
3010
|
|
|
2702
3011
|
if (nextState.state === 'COMPLETED') {
|
|
2703
3012
|
|
|
2704
|
-
playGoalChime(true);
|
|
3013
|
+
playGoalChime(true, nextState.soundScheme || 'default');
|
|
3014
|
+
speakGoalAnnouncement('Goal completed: ' + (nextState.title || ''), Boolean(nextState.enableVoiceAnnouncements));
|
|
2705
3015
|
|
|
2706
3016
|
} else if (nextState.state === 'FAILED') {
|
|
2707
3017
|
|
|
2708
|
-
playGoalChime(false);
|
|
3018
|
+
playGoalChime(false, nextState.soundScheme || 'default');
|
|
3019
|
+
speakGoalAnnouncement('Goal failed: ' + (nextState.title || ''), Boolean(nextState.enableVoiceAnnouncements));
|
|
2709
3020
|
|
|
2710
3021
|
}
|
|
2711
3022
|
|
|
@@ -4456,6 +4767,19 @@ window.__ModuleLoader__.load({
|
|
|
4456
4767
|
rollbackBtn: 'Rollback to Checkpoint',
|
|
4457
4768
|
rollbackConfirm: 'Rollback working tree to this checkpoint?',
|
|
4458
4769
|
rollbackSuccess: 'Rolled back to checkpoint',
|
|
4770
|
+
interveneTitle: 'Pause & Intervene',
|
|
4771
|
+
interveneDesc: 'Goal is paused. Steer agent behavior with direct guidance before resuming.',
|
|
4772
|
+
interveneDirectivePlaceholder: 'Enter directive instructions for the agent...',
|
|
4773
|
+
interveneApply: 'Apply Directive & Resume',
|
|
4774
|
+
interveneApplied: 'Directive Applied',
|
|
4775
|
+
liveActivityTitle: 'Live Activity Feed',
|
|
4776
|
+
preplanTitle: 'Smart Pre-plan Ready',
|
|
4777
|
+
preplanApprove: 'Approve & Start Plan',
|
|
4778
|
+
mergeBranch: 'Merge Branch',
|
|
4779
|
+
discardBranch: 'Discard Branch',
|
|
4780
|
+
retrospectiveTitle: 'Goal Retrospective',
|
|
4781
|
+
templatesTitle: 'Goal Templates',
|
|
4782
|
+
waitingPrereq: 'waiting for prereq',
|
|
4459
4783
|
|
|
4460
4784
|
goalCompleted: 'Goal completed',
|
|
4461
4785
|
|
|
@@ -4582,6 +4906,19 @@ window.__ModuleLoader__.load({
|
|
|
4582
4906
|
rollbackBtn: '回滚到该检查点',
|
|
4583
4907
|
rollbackConfirm: '确定将工作区代码回滚至该里程碑检查点吗?',
|
|
4584
4908
|
rollbackSuccess: '已成功回滚到检查点',
|
|
4909
|
+
interveneTitle: '暂停并干预',
|
|
4910
|
+
interveneDesc: '目标已暂停。在恢复前向智能体发送直接指引。',
|
|
4911
|
+
interveneDirectivePlaceholder: '输入给智能体的指导指令...',
|
|
4912
|
+
interveneApply: '应用指引并继续',
|
|
4913
|
+
interveneApplied: '已应用干预',
|
|
4914
|
+
liveActivityTitle: '实时动态',
|
|
4915
|
+
preplanTitle: '智能预规划就绪',
|
|
4916
|
+
preplanApprove: '批准并启动计划',
|
|
4917
|
+
mergeBranch: '合并分支',
|
|
4918
|
+
discardBranch: '放弃分支',
|
|
4919
|
+
retrospectiveTitle: '目标复盘报告',
|
|
4920
|
+
templatesTitle: '目标模板',
|
|
4921
|
+
waitingPrereq: '等待前置依赖',
|
|
4585
4922
|
|
|
4586
4923
|
goalCompleted: '目标已完成',
|
|
4587
4924
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Format a sanitized git branch name from goal title
|
|
5
|
+
* @param {string} title
|
|
6
|
+
* @returns {string} branch name
|
|
7
|
+
*/
|
|
8
|
+
export function sanitizeBranchSlug(title) {
|
|
9
|
+
const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
10
|
+
const slug = String(title || 'task')
|
|
11
|
+
.toLowerCase()
|
|
12
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
13
|
+
.replace(/^-+|-+$/g, '')
|
|
14
|
+
.slice(0, 30) || 'goal';
|
|
15
|
+
return `goal/${dateStr}-${slug}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get current git branch
|
|
20
|
+
* @param {string} cwd
|
|
21
|
+
* @returns {string} branch name or 'HEAD'
|
|
22
|
+
*/
|
|
23
|
+
export function getCurrentGitBranch(cwd = process.cwd()) {
|
|
24
|
+
try {
|
|
25
|
+
return execFileSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
|
26
|
+
cwd,
|
|
27
|
+
encoding: 'utf8',
|
|
28
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
29
|
+
}).trim();
|
|
30
|
+
} catch (err) {
|
|
31
|
+
return 'main';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create a dedicated git branch for a goal
|
|
37
|
+
* @param {string} cwd
|
|
38
|
+
* @param {string} branchName
|
|
39
|
+
* @returns {boolean} success
|
|
40
|
+
*/
|
|
41
|
+
export function createGoalBranch(cwd = process.cwd(), branchName) {
|
|
42
|
+
if (!branchName) return false;
|
|
43
|
+
try {
|
|
44
|
+
execFileSync('git', ['checkout', '-b', branchName], {
|
|
45
|
+
cwd,
|
|
46
|
+
encoding: 'utf8',
|
|
47
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
48
|
+
});
|
|
49
|
+
return true;
|
|
50
|
+
} catch (err) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Merge goal branch back into parent target branch
|
|
57
|
+
* @param {string} cwd
|
|
58
|
+
* @param {string} branchName
|
|
59
|
+
* @param {string} targetBranch
|
|
60
|
+
* @returns {boolean} success
|
|
61
|
+
*/
|
|
62
|
+
export function mergeGoalBranch(cwd = process.cwd(), branchName, targetBranch = 'main') {
|
|
63
|
+
if (!branchName) return false;
|
|
64
|
+
try {
|
|
65
|
+
execFileSync('git', ['checkout', targetBranch], {
|
|
66
|
+
cwd,
|
|
67
|
+
encoding: 'utf8',
|
|
68
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
69
|
+
});
|
|
70
|
+
execFileSync('git', ['merge', '--no-ff', '-m', `chore(goal): merge ${branchName}`, branchName], {
|
|
71
|
+
cwd,
|
|
72
|
+
encoding: 'utf8',
|
|
73
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
74
|
+
});
|
|
75
|
+
return true;
|
|
76
|
+
} catch (err) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Discard / delete a goal branch
|
|
83
|
+
* @param {string} cwd
|
|
84
|
+
* @param {string} branchName
|
|
85
|
+
* @param {string} targetBranch
|
|
86
|
+
* @returns {boolean} success
|
|
87
|
+
*/
|
|
88
|
+
export function discardGoalBranch(cwd = process.cwd(), branchName, targetBranch = 'main') {
|
|
89
|
+
if (!branchName) return false;
|
|
90
|
+
try {
|
|
91
|
+
execFileSync('git', ['checkout', targetBranch], {
|
|
92
|
+
cwd,
|
|
93
|
+
encoding: 'utf8',
|
|
94
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
95
|
+
});
|
|
96
|
+
execFileSync('git', ['branch', '-D', branchName], {
|
|
97
|
+
cwd,
|
|
98
|
+
encoding: 'utf8',
|
|
99
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
100
|
+
});
|
|
101
|
+
return true;
|
|
102
|
+
} catch (err) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|