Skip to content

Commit 551d9b2

Browse files
committed
Add TradingView shortcut capability layer
1 parent b30eaef commit 551d9b2

File tree

8 files changed

+838
-194
lines changed

8 files changed

+838
-194
lines changed

scripts/test-bug-fixes.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,16 +202,18 @@ test('ui-watcher exposes active window capability snapshot', () => {
202202

203203
test('message-builder injects active app capability context', () => {
204204
const messageBuilderPath = path.join(__dirname, '..', 'src', 'main', 'ai-service', 'message-builder.js');
205+
const capabilityPolicyPath = path.join(__dirname, '..', 'src', 'main', 'capability-policy.js');
205206
const fs = require('fs');
206207

207208
const messageBuilderContent = fs.readFileSync(messageBuilderPath, 'utf8');
209+
const capabilityPolicyContent = fs.readFileSync(capabilityPolicyPath, 'utf8');
208210

209211
assert(messageBuilderContent.includes('classifyActiveAppCapability'), 'Message builder should classify active app capability');
210-
assert(messageBuilderContent.includes('## Active App Capability'), 'Message builder should inject active app capability context');
212+
assert(messageBuilderContent.includes('buildCapabilityPolicySystemMessage'), 'Message builder should inject active app capability context');
211213
assert(messageBuilderContent.includes('visual-first-low-uia'), 'Capability context should recognize low-UIA visual-first apps');
212-
assert(messageBuilderContent.includes('uia-rich'), 'Capability context should recognize UIA-rich apps');
213-
assert(messageBuilderContent.includes('namedInteractiveElementCount'), 'Capability context should include UIA inventory counts');
214-
assert(messageBuilderContent.includes('answer-shape:'), 'Capability context should shape control-surface answers');
214+
assert(capabilityPolicyContent.includes('uia-rich'), 'Capability context should recognize UIA-rich apps');
215+
assert(messageBuilderContent.includes('watcherSnapshot'), 'Capability context should include watcher/UIA inventory input');
216+
assert(capabilityPolicyContent.includes('answer-shape:'), 'Capability context should shape control-surface answers');
215217
assert(messageBuilderContent.includes('## Pine Evidence Bounds'), 'Message builder should inject a bounded Pine diagnostics evidence block when relevant');
216218
assert(messageBuilderContent.includes('inferPineEvidenceRequestKind'), 'Message builder should classify Pine evidence request kinds');
217219
assert(messageBuilderContent.includes('runtime correctness, strategy validity, profitability, or market insight'), 'Pine evidence bounds should prevent compile success from being overclaimed');
@@ -280,7 +282,7 @@ test('pine workflow encodes diagnostics and compile-result evidence modes', () =
280282
assert(shortcutProfileContent.includes("'create-alert'"), 'TradingView shortcut profile should define stable alert guidance');
281283
assert(shortcutProfileContent.includes("'drawing-tool-binding'"), 'TradingView shortcut profile should mark drawing bindings as customizable');
282284
assert(shortcutProfileContent.includes("'open-dom-panel'"), 'TradingView shortcut profile should classify DOM shortcuts explicitly');
283-
assert(shortcutProfileContent.includes('No stable native default should be assumed for opening Pine Editor'), 'TradingView shortcut profile should stop treating Pine Editor as a stable native shortcut');
285+
assert(shortcutProfileContent.includes('No dedicated official Pine Editor opener is exposed in the PDF'), 'TradingView shortcut profile should stop treating Pine Editor as a stable native shortcut');
284286
assert(shortcutProfileContent.includes('buildTradingViewShortcutRoute'), 'TradingView shortcut profile should expose TradingView-specific route helpers for non-native shortcuts');
285287
assert(shortcutProfileContent.includes("'take-snapshot'"), 'TradingView shortcut profile should include grounded reference-only snapshot guidance');
286288
assert(shortcutProfileContent.includes("'add-symbol-to-watchlist'"), 'TradingView shortcut profile should include grounded watchlist shortcut guidance');
@@ -600,7 +602,7 @@ test('TradingView shortcut profile and drawing bounds are wired through promptin
600602
assert(alertWorkflowContent.includes("require('./shortcut-profile')"), 'Alert workflow should consume TradingView shortcut profile');
601603
assert(pineWorkflowContent.includes("require('./shortcut-profile')"), 'Pine workflow should consume TradingView shortcut profile');
602604
assert(indicatorWorkflowContent.includes("buildSearchSurfaceSelectionContract"), 'Indicator workflow should consume the shared search-surface selection contract');
603-
assert(shortcutProfileContent.includes("buildSearchSurfaceSelectionContract"), 'Shortcut profile should reuse the shared search-surface selection contract for Pine quick-search routes');
605+
assert(shortcutProfileContent.includes("buildTradingViewShortcutSequenceRoute"), 'Shortcut profile should expose reusable shortcut sequencing for official TradingView routes');
604606
assert(searchSurfaceContractsContent.includes("type: 'click_element'"), 'Shared search-surface contracts should perform semantic result selection');
605607
assert(claimBoundsContent.includes('buildProofCarryingAnswerPrompt'), 'Claim-bounds helper should build proof-carrying answer prompts');
606608
assert(messageBuilderContent.includes('buildClaimBoundConstraint'), 'Message builder should inject the answer claim contract on degraded or low-trust paths');

scripts/test-tradingview-pine-data-workflows.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,16 @@ test('clipboard-only pine authoring plan rewrites into guarded continuation afte
255255
assert(inspectStep, 'safe authoring should inspect Pine Editor state first');
256256
assert.strictEqual(inspectStep.continueOnPineEditorState, 'empty-or-starter');
257257
assert(Array.isArray(inspectStep.continueActions) && inspectStep.continueActions.length > 0, 'safe authoring inspect step should carry continuation actions');
258-
assert(inspectStep.continueActions.some((action) => action?.type === 'run_command' && /set-clipboard/i.test(String(action?.command || ''))), 'continuation should preserve clipboard preparation');
259-
assert(inspectStep.continueActions.some((action) => action?.type === 'key' && String(action?.key || '').toLowerCase() === 'ctrl+v'), 'continuation should paste the prepared script');
260-
assert(inspectStep.continueActions.some((action) => action?.type === 'key' && String(action?.key || '').toLowerCase() === 'ctrl+enter'), 'continuation should add the script to the chart');
261-
assert(inspectStep.continueActions.some((action) => action?.type === 'get_text' && action?.pineEvidenceMode === 'compile-result'), 'continuation should gather compile-result feedback after add-to-chart');
258+
assert(inspectStep.continueActions.some((action) => action?.type === 'key' && String(action?.key || '').toLowerCase() === 'ctrl+i'), 'continuation should create a fresh Pine indicator through the official shortcut chord');
259+
const freshInspect = inspectStep.continueActions.find((action) => action?.type === 'get_text' && action?.pineEvidenceMode === 'safe-authoring-inspect' && Array.isArray(action?.continueActions));
260+
assert(freshInspect, 'continuation should verify a fresh Pine script surface after creating a new indicator');
261+
assert(freshInspect.continueActions.some((action) => action?.type === 'run_command' && /set-clipboard/i.test(String(action?.command || ''))), 'fresh-script continuation should preserve clipboard preparation');
262+
assert(freshInspect.continueActions.some((action) => action?.type === 'key' && String(action?.key || '').toLowerCase() === 'ctrl+v'), 'fresh-script continuation should paste the prepared script');
263+
const saveInspect = freshInspect.continueActions.find((action) => action?.type === 'get_text' && action?.pineEvidenceMode === 'save-status');
264+
assert(saveInspect, 'fresh-script continuation should verify visible save status before applying');
265+
assert.strictEqual(saveInspect.continueOnPineLifecycleState, 'saved-state-verified');
266+
assert(saveInspect.continueActions.some((action) => action?.type === 'key' && String(action?.key || '').toLowerCase() === 'ctrl+enter'), 'save-verified continuation should add the script to the chart');
267+
assert(saveInspect.continueActions.some((action) => action?.type === 'get_text' && action?.pineEvidenceMode === 'compile-result'), 'save-verified continuation should gather compile-result feedback after add-to-chart');
262268
});
263269

264270
test('full ai-service rewrite handles the transcript Pine prompt without browser or timeframe derailment', () => {

scripts/test-tradingview-shortcut-profile.js

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,22 @@ test('stable default TradingView shortcuts are exposed through the profile helpe
3232
const indicatorSearch = getTradingViewShortcut('indicator-search');
3333
const createAlert = getTradingViewShortcut('create-alert');
3434
const quickSearch = getTradingViewShortcut('command palette');
35+
const dataWindow = getTradingViewShortcut('open-data-window');
3536

3637
assert(indicatorSearch, 'indicator-search shortcut should exist');
3738
assert.strictEqual(indicatorSearch.key, '/');
3839
assert.strictEqual(indicatorSearch.category, 'stable-default');
40+
assert.deepStrictEqual(indicatorSearch.keySequence, ['/']);
41+
assert.strictEqual(indicatorSearch.automationRoutable, true);
3942
assert(createAlert, 'create-alert shortcut should exist');
4043
assert.strictEqual(createAlert.key, 'alt+a');
4144
assert.strictEqual(createAlert.category, 'stable-default');
4245
assert.strictEqual(getTradingViewShortcutKey('symbol-search'), 'ctrl+k');
4346
assert(quickSearch, 'symbol-search alias should resolve through the profile helper');
4447
assert.strictEqual(quickSearch.id, 'symbol-search');
4548
assert.strictEqual(quickSearch.surface, 'quick-search');
49+
assert(dataWindow, 'data window shortcut should exist');
50+
assert.strictEqual(dataWindow.key, 'alt+d');
4651
});
4752

4853
test('drawing shortcuts are marked customizable rather than universal', () => {
@@ -81,18 +86,18 @@ test('buildTradingViewShortcutAction preserves shortcut metadata for workflow ac
8186
test('listTradingViewShortcuts returns the categorized TradingView profile inventory', () => {
8287
const shortcuts = listTradingViewShortcuts();
8388
assert(Array.isArray(shortcuts), 'shortcut inventory should be an array');
84-
assert(shortcuts.length >= 12, 'shortcut inventory should include the grounded TradingView shortcut inventory');
89+
assert(shortcuts.length >= 20, 'shortcut inventory should include the expanded TradingView shortcut inventory');
8590
});
8691

87-
test('shortcut profile exposes reference-only chart shortcuts with source provenance', () => {
92+
test('shortcut profile exposes official chart shortcuts with source provenance', () => {
8893
const snapshot = getTradingViewShortcut('take snapshot');
8994
const watchlist = getTradingViewShortcut('add-symbol-to-watchlist');
9095

9196
assert(snapshot, 'snapshot shortcut should resolve by alias');
9297
assert.strictEqual(snapshot.key, 'alt+s');
9398
assert.strictEqual(snapshot.category, 'reference-only');
94-
assert.strictEqual(snapshot.sourceConfidence, 'secondary-reference');
95-
assert(snapshot.sourceUrls.includes(TRADINGVIEW_SHORTCUTS_SECONDARY_URL));
99+
assert.strictEqual(snapshot.sourceConfidence, 'official-pdf');
100+
assert(snapshot.sourceUrls.includes(TRADINGVIEW_SHORTCUTS_OFFICIAL_URL));
96101
assert(watchlist, 'watchlist shortcut should exist');
97102
assert.strictEqual(watchlist.key, 'alt+w');
98103
assert.strictEqual(watchlist.surface, 'watchlist');
@@ -105,7 +110,7 @@ test('shortcut profile resolves aliases and documents official shortcut referenc
105110

106111
const indicatorSearch = getTradingViewShortcut('indicator-search');
107112
assert(indicatorSearch.sourceUrls.includes(TRADINGVIEW_SHORTCUTS_OFFICIAL_URL));
108-
assert(indicatorSearch.sourceUrls.includes(TRADINGVIEW_SHORTCUTS_SECONDARY_URL));
113+
assert.strictEqual(indicatorSearch.sourceConfidence, 'official-pdf');
109114
});
110115

111116
test('shortcut profile exposes reusable phrase matching helpers for workflow inference', () => {
@@ -138,3 +143,29 @@ test('pine editor opener is routed through TradingView quick search instead of a
138143
assert.strictEqual(routeActions[4].type, 'key');
139144
assert.strictEqual(routeActions[4].key, 'enter');
140145
});
146+
147+
test('pine authoring shortcuts expose normalized capability metadata and chorded sequences', () => {
148+
const newIndicator = getTradingViewShortcut('new-pine-indicator');
149+
const saveScript = getTradingViewShortcut('save-pine-script');
150+
const addToChart = getTradingViewShortcut('add-pine-to-chart');
151+
152+
assert(newIndicator, 'new pine indicator shortcut should exist');
153+
assert.deepStrictEqual(newIndicator.keySequence, ['ctrl+k', 'ctrl+i']);
154+
assert.strictEqual(newIndicator.key, null);
155+
assert.strictEqual(newIndicator.automationRoutable, true);
156+
assert.strictEqual(newIndicator.fallbackPolicy, 'none');
157+
assert.strictEqual(saveScript.key, 'ctrl+s');
158+
assert.strictEqual(saveScript.verificationContract.kind, 'status-visible');
159+
assert.strictEqual(addToChart.key, 'ctrl+enter');
160+
assert.strictEqual(addToChart.automationRoutable, true);
161+
});
162+
163+
test('generic shortcut route builder emits a chord sequence with final verification metadata', () => {
164+
const routeActions = buildTradingViewShortcutRoute('new-pine-indicator');
165+
const keyActions = routeActions.filter((action) => action?.type === 'key');
166+
167+
assert(Array.isArray(routeActions) && routeActions.length >= 4, 'new indicator route should emit multiple steps');
168+
assert.deepStrictEqual(keyActions.map((action) => action.key), ['ctrl+k', 'ctrl+i']);
169+
assert.strictEqual(keyActions[1].verify.kind, 'editor-active');
170+
assert.strictEqual(keyActions[1].tradingViewShortcut.id, 'new-pine-indicator');
171+
});

0 commit comments

Comments
 (0)