polydev-ai 1.9.26 → 1.9.27
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/mcp/stdio-wrapper.js +97 -79
- package/package.json +1 -1
package/mcp/stdio-wrapper.js
CHANGED
|
@@ -1566,76 +1566,64 @@ To re-login: /polydev:login`
|
|
|
1566
1566
|
</html>`;
|
|
1567
1567
|
}
|
|
1568
1568
|
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
if (!response.ok) {
|
|
1591
|
-
const errorText = await response.text();
|
|
1592
|
-
console.error(`[Stdio Wrapper] Remote server error: ${response.status} - ${errorText}`);
|
|
1593
|
-
|
|
1594
|
-
// Handle 401 specifically - token expired/invalid, trigger re-auth
|
|
1595
|
-
if (response.status === 401) {
|
|
1596
|
-
console.error('[Polydev] Remote API returned 401, auto-triggering re-authentication...');
|
|
1597
|
-
return await this.triggerReAuth(request.id, 'Authentication expired. Re-authenticating...');
|
|
1598
|
-
}
|
|
1599
|
-
|
|
1600
|
-
return {
|
|
1601
|
-
jsonrpc: '2.0',
|
|
1602
|
-
id: request.id,
|
|
1603
|
-
error: {
|
|
1604
|
-
code: -32603,
|
|
1605
|
-
message: `Remote server error: ${response.status} - ${errorText}`
|
|
1606
|
-
}
|
|
1607
|
-
};
|
|
1569
|
+
/**
|
|
1570
|
+
* Send an MCP progress notification to the client
|
|
1571
|
+
* This is a JSON-RPC notification (no id) that compatible clients use to:
|
|
1572
|
+
* 1. Display progress UI (status bar, spinners)
|
|
1573
|
+
* 2. Reset their tool call timeout (if resetTimeoutOnProgress is enabled)
|
|
1574
|
+
* @param {string|number} progressToken - Token from request's _meta.progressToken
|
|
1575
|
+
* @param {number} progress - Current progress value (must increase monotonically)
|
|
1576
|
+
* @param {number} total - Total expected progress value
|
|
1577
|
+
* @param {string} message - Human-readable status message
|
|
1578
|
+
*/
|
|
1579
|
+
sendProgressNotification(progressToken, progress, total, message) {
|
|
1580
|
+
if (!progressToken) return; // Client didn't request progress
|
|
1581
|
+
|
|
1582
|
+
const notification = {
|
|
1583
|
+
jsonrpc: '2.0',
|
|
1584
|
+
method: 'notifications/progress',
|
|
1585
|
+
params: {
|
|
1586
|
+
progressToken,
|
|
1587
|
+
progress,
|
|
1588
|
+
total,
|
|
1589
|
+
message
|
|
1608
1590
|
}
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
jsonrpc: '2.0',
|
|
1617
|
-
id: request.id,
|
|
1618
|
-
error: {
|
|
1619
|
-
code: -32603,
|
|
1620
|
-
message: `Network error: ${error.message}`
|
|
1621
|
-
}
|
|
1622
|
-
};
|
|
1591
|
+
};
|
|
1592
|
+
|
|
1593
|
+
try {
|
|
1594
|
+
process.stdout.write(JSON.stringify(notification) + '\n');
|
|
1595
|
+
console.error(`[Polydev] Progress: ${progress}/${total} - ${message}`);
|
|
1596
|
+
} catch (err) {
|
|
1597
|
+
console.error(`[Polydev] Failed to send progress notification:`, err.message);
|
|
1623
1598
|
}
|
|
1624
1599
|
}
|
|
1625
1600
|
|
|
1626
1601
|
/**
|
|
1627
|
-
*
|
|
1602
|
+
* Start a periodic progress heartbeat to prevent client-side timeouts.
|
|
1603
|
+
* Sends a progress notification every intervalMs to signal the server is still working.
|
|
1604
|
+
* Compatible MCP clients will reset their timeout clock on each notification.
|
|
1605
|
+
* @param {string|number} progressToken - Token from request's _meta.progressToken
|
|
1606
|
+
* @param {number} intervalMs - Heartbeat interval in milliseconds (default: 10s)
|
|
1607
|
+
* @returns {{ stop: Function, tick: Function }} Controller to stop heartbeat and manually tick progress
|
|
1628
1608
|
*/
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1609
|
+
startProgressHeartbeat(progressToken, intervalMs = 10000) {
|
|
1610
|
+
if (!progressToken) return { stop: () => {}, tick: () => {} };
|
|
1611
|
+
|
|
1612
|
+
let currentProgress = 0;
|
|
1613
|
+
const total = 100; // Use percentage-style progress
|
|
1614
|
+
|
|
1615
|
+
const interval = setInterval(() => {
|
|
1616
|
+
currentProgress = Math.min(currentProgress + 5, 95); // Never reach 100 until done
|
|
1617
|
+
this.sendProgressNotification(progressToken, currentProgress, total, 'Processing perspectives...');
|
|
1618
|
+
}, intervalMs);
|
|
1619
|
+
|
|
1620
|
+
return {
|
|
1621
|
+
stop: () => clearInterval(interval),
|
|
1622
|
+
tick: (progress, message) => {
|
|
1623
|
+
currentProgress = progress;
|
|
1624
|
+
this.sendProgressNotification(progressToken, progress, total, message);
|
|
1625
|
+
}
|
|
1626
|
+
};
|
|
1639
1627
|
}
|
|
1640
1628
|
|
|
1641
1629
|
/**
|
|
@@ -1644,12 +1632,30 @@ To re-login: /polydev:login`
|
|
|
1644
1632
|
async handleGetPerspectivesWithCLIs(params, id) {
|
|
1645
1633
|
console.error(`[Stdio Wrapper] Handling get_perspectives with local CLIs + remote`);
|
|
1646
1634
|
|
|
1635
|
+
// Extract progress token from request metadata (MCP spec)
|
|
1636
|
+
// Clients that want progress updates include this in _meta.progressToken
|
|
1637
|
+
const progressToken = params?._meta?.progressToken;
|
|
1638
|
+
if (progressToken) {
|
|
1639
|
+
console.error(`[Stdio Wrapper] Client requested progress updates (token: ${progressToken})`);
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
// Start periodic heartbeat to prevent client-side timeouts
|
|
1643
|
+
// Sends progress notification every 10s to keep the connection alive
|
|
1644
|
+
const heartbeat = this.startProgressHeartbeat(progressToken);
|
|
1645
|
+
|
|
1647
1646
|
try {
|
|
1647
|
+
// Send initial progress
|
|
1648
|
+
heartbeat.tick(5, 'Initializing perspectives engine...');
|
|
1649
|
+
|
|
1648
1650
|
// Use existing localSendCliPrompt logic which already:
|
|
1649
1651
|
// 1. Checks all local CLIs
|
|
1650
1652
|
// 2. Calls remote perspectives
|
|
1651
1653
|
// 3. Combines results
|
|
1652
|
-
const result = await this.localSendCliPrompt(params.arguments);
|
|
1654
|
+
const result = await this.localSendCliPrompt(params.arguments, progressToken);
|
|
1655
|
+
|
|
1656
|
+
// Stop heartbeat before sending final response
|
|
1657
|
+
heartbeat.stop();
|
|
1658
|
+
heartbeat.tick(100, 'Complete');
|
|
1653
1659
|
|
|
1654
1660
|
// Check if result indicates auth failure (from forwardToRemoteServer 401 handling)
|
|
1655
1661
|
if (result?.result?.content?.[0]?.text?.includes('RE-AUTHENTICATION REQUIRED')) {
|
|
@@ -1678,6 +1684,7 @@ To re-login: /polydev:login`
|
|
|
1678
1684
|
};
|
|
1679
1685
|
|
|
1680
1686
|
} catch (error) {
|
|
1687
|
+
heartbeat.stop(); // Always clean up heartbeat
|
|
1681
1688
|
console.error(`[Stdio Wrapper] get_perspectives error:`, error);
|
|
1682
1689
|
|
|
1683
1690
|
// Check if error is auth-related
|
|
@@ -1704,9 +1711,13 @@ To re-login: /polydev:login`
|
|
|
1704
1711
|
async handleLocalCliTool(request) {
|
|
1705
1712
|
const { method, params, id } = request;
|
|
1706
1713
|
const { name: toolName, arguments: args } = params;
|
|
1714
|
+
const progressToken = params?._meta?.progressToken;
|
|
1707
1715
|
|
|
1708
1716
|
console.error(`[Stdio Wrapper] Handling local CLI tool: ${toolName}`);
|
|
1709
1717
|
|
|
1718
|
+
// Start heartbeat for long-running CLI operations
|
|
1719
|
+
const heartbeat = this.startProgressHeartbeat(progressToken);
|
|
1720
|
+
|
|
1710
1721
|
try {
|
|
1711
1722
|
let result;
|
|
1712
1723
|
|
|
@@ -1723,13 +1734,14 @@ To re-login: /polydev:login`
|
|
|
1723
1734
|
|
|
1724
1735
|
case 'send_cli_prompt':
|
|
1725
1736
|
case 'polydev.send_cli_prompt':
|
|
1726
|
-
result = await this.localSendCliPrompt(args);
|
|
1737
|
+
result = await this.localSendCliPrompt(args, progressToken);
|
|
1727
1738
|
break;
|
|
1728
1739
|
|
|
1729
1740
|
default:
|
|
1730
1741
|
throw new Error(`Unknown CLI tool: ${toolName}`);
|
|
1731
1742
|
}
|
|
1732
1743
|
|
|
1744
|
+
heartbeat.stop();
|
|
1733
1745
|
return {
|
|
1734
1746
|
jsonrpc: '2.0',
|
|
1735
1747
|
id,
|
|
@@ -1745,6 +1757,7 @@ To re-login: /polydev:login`
|
|
|
1745
1757
|
|
|
1746
1758
|
} catch (error) {
|
|
1747
1759
|
console.error(`[Stdio Wrapper] CLI tool error:`, error);
|
|
1760
|
+
heartbeat.stop();
|
|
1748
1761
|
return {
|
|
1749
1762
|
jsonrpc: '2.0',
|
|
1750
1763
|
id,
|
|
@@ -1885,7 +1898,7 @@ To re-login: /polydev:login`
|
|
|
1885
1898
|
* Respects user's perspectives_per_message setting for total perspectives
|
|
1886
1899
|
* Uses allProviders from dashboard - tries CLI first, falls back to API
|
|
1887
1900
|
*/
|
|
1888
|
-
async localSendCliPrompt(args) {
|
|
1901
|
+
async localSendCliPrompt(args, progressToken) {
|
|
1889
1902
|
console.error(`[Stdio Wrapper] Local CLI prompt sending with perspectives`);
|
|
1890
1903
|
|
|
1891
1904
|
try {
|
|
@@ -1912,6 +1925,8 @@ To re-login: /polydev:login`
|
|
|
1912
1925
|
} catch (prefError) {
|
|
1913
1926
|
console.error('[Stdio Wrapper] Model preferences fetch failed (will use CLI defaults):', prefError.message);
|
|
1914
1927
|
}
|
|
1928
|
+
|
|
1929
|
+
this.sendProgressNotification(progressToken, 15, 100, 'Loaded model preferences');
|
|
1915
1930
|
|
|
1916
1931
|
// Get the user's perspectives_per_message setting (default 2)
|
|
1917
1932
|
const maxPerspectives = this.perspectivesPerMessage || 2;
|
|
@@ -1920,14 +1935,11 @@ To re-login: /polydev:login`
|
|
|
1920
1935
|
let localResults = [];
|
|
1921
1936
|
|
|
1922
1937
|
if (provider_id) {
|
|
1923
|
-
//
|
|
1938
|
+
// Single provider requested - use only that one
|
|
1924
1939
|
console.error(`[Stdio Wrapper] Using specific provider: ${provider_id}`);
|
|
1925
1940
|
const model = modelPreferences[provider_id] || null;
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
} else {
|
|
1929
|
-
console.error(`[Stdio Wrapper] No model preference for ${provider_id}, using CLI default`);
|
|
1930
|
-
}
|
|
1941
|
+
console.error(`[Stdio Wrapper] Using user's preferred model for ${provider_id}: ${model}`);
|
|
1942
|
+
this.sendProgressNotification(progressToken, 20, 100, `Querying ${provider_id}...`);
|
|
1931
1943
|
const result = await this.cliManager.sendCliPrompt(provider_id, prompt, mode, gracefulTimeout, model);
|
|
1932
1944
|
localResults = [{ provider_id, ...result }];
|
|
1933
1945
|
} else {
|
|
@@ -1939,6 +1951,7 @@ To re-login: /polydev:login`
|
|
|
1939
1951
|
// Get available CLIs for checking
|
|
1940
1952
|
const { available: availableClis } = await this.getAllAvailableProviders();
|
|
1941
1953
|
console.error(`[Stdio Wrapper] Available CLIs: ${availableClis.join(', ') || 'none'}`);
|
|
1954
|
+
this.sendProgressNotification(progressToken, 25, 100, `Found ${availableClis.length} CLIs: ${availableClis.join(', ') || 'none'}`);
|
|
1942
1955
|
|
|
1943
1956
|
// Get all providers from dashboard (user's configured providers + CLI-only)
|
|
1944
1957
|
const allProviders = this.allProviders || [];
|
|
@@ -1983,7 +1996,7 @@ To re-login: /polydev:login`
|
|
|
1983
1996
|
for (const cliId of cliPriorityOrder) {
|
|
1984
1997
|
if (!availableClis.includes(cliId)) continue;
|
|
1985
1998
|
if (cliId === excludedCli) {
|
|
1986
|
-
console.error(`[Stdio Wrapper] [CLI-FIRST] Skipping ${
|
|
1999
|
+
console.error(`[Stdio Wrapper] [CLI-FIRST] Skipping ${excludedCli} (same as current IDE — would cause recursive call)`);
|
|
1987
2000
|
continue;
|
|
1988
2001
|
}
|
|
1989
2002
|
|
|
@@ -2041,6 +2054,7 @@ To re-login: /polydev:login`
|
|
|
2041
2054
|
// Run ALL CLI prompts concurrently with fast-collect pattern
|
|
2042
2055
|
// Resolves once we have maxPerspectives successes OR all complete
|
|
2043
2056
|
if (cliProviderEntries.length > 0) {
|
|
2057
|
+
this.sendProgressNotification(progressToken, 30, 100, `Querying ${cliProviderEntries.length} CLIs in parallel...`);
|
|
2044
2058
|
const cliPromises = cliProviderEntries.map(async (providerEntry) => {
|
|
2045
2059
|
try {
|
|
2046
2060
|
// ONLY use the model from providerEntry (which is filtered to user's own API keys, not credits)
|
|
@@ -2094,6 +2108,7 @@ To re-login: /polydev:login`
|
|
|
2094
2108
|
// Fast-collect: resolve early once we have maxPerspectives successes OR all complete
|
|
2095
2109
|
localResults = await this.collectFirstNSuccesses(cliPromises, maxPerspectives);
|
|
2096
2110
|
console.error(`[Stdio Wrapper] Fast-collect: got ${localResults.filter(r => r.success).length} successful, ${localResults.filter(r => !r.success).length} failed out of ${cliPromises.length} CLIs`);
|
|
2111
|
+
this.sendProgressNotification(progressToken, 55, 100, `Got ${localResults.filter(r => r.success).length} CLI responses`);
|
|
2097
2112
|
}
|
|
2098
2113
|
|
|
2099
2114
|
// Store API-only providers info for remote API call
|
|
@@ -2116,6 +2131,7 @@ To re-login: /polydev:login`
|
|
|
2116
2131
|
// Get remote perspectives for API-only providers and failed CLIs
|
|
2117
2132
|
let perspectivesResult;
|
|
2118
2133
|
if (remainingPerspectives > 0) {
|
|
2134
|
+
this.sendProgressNotification(progressToken, 65, 100, `Fetching ${remainingPerspectives} more perspectives from API...`);
|
|
2119
2135
|
console.error(`[Stdio Wrapper] Calling remote API for ${remainingPerspectives} more perspectives (have ${successfulLocalCount}/${maxPerspectives})`);
|
|
2120
2136
|
|
|
2121
2137
|
// Pass API-only provider info to help remote API choose correct models
|
|
@@ -2155,6 +2171,7 @@ To re-login: /polydev:login`
|
|
|
2155
2171
|
}
|
|
2156
2172
|
|
|
2157
2173
|
// Combine all results
|
|
2174
|
+
this.sendProgressNotification(progressToken, 90, 100, 'Combining all perspectives...');
|
|
2158
2175
|
return this.combineAllCliAndPerspectives(localResults, perspectivesResult, args);
|
|
2159
2176
|
|
|
2160
2177
|
} catch (error) {
|
|
@@ -2462,7 +2479,7 @@ To re-login: /polydev:login`
|
|
|
2462
2479
|
user_token: this.userToken,
|
|
2463
2480
|
// Exclude providers that succeeded locally
|
|
2464
2481
|
exclude_providers: excludeProviders,
|
|
2465
|
-
// NEW: Specific providers to request (from API-only
|
|
2482
|
+
// NEW: Specific providers to request (from API-only providers)
|
|
2466
2483
|
request_providers: requestProviders.length > 0 ? requestProviders : undefined,
|
|
2467
2484
|
// Pass CLI responses for dashboard logging
|
|
2468
2485
|
cli_responses: cliResponses,
|
|
@@ -2849,11 +2866,11 @@ To re-login: /polydev:login`
|
|
|
2849
2866
|
try {
|
|
2850
2867
|
const homeDir = require('os').homedir();
|
|
2851
2868
|
const polydevevDir = path.join(homeDir, '.polydev');
|
|
2852
|
-
const usageFile = path.join(
|
|
2869
|
+
const usageFile = path.join(polydeveevDir, 'cli-usage.json');
|
|
2853
2870
|
|
|
2854
2871
|
// Ensure directory exists
|
|
2855
|
-
if (!fs.existsSync(
|
|
2856
|
-
fs.mkdirSync(
|
|
2872
|
+
if (!fs.existsSync(polydeveevDir)) {
|
|
2873
|
+
fs.mkdirSync(polydeveevDir, { recursive: true });
|
|
2857
2874
|
}
|
|
2858
2875
|
|
|
2859
2876
|
// Add new usage record
|
|
@@ -2963,7 +2980,7 @@ To re-login: /polydev:login`
|
|
|
2963
2980
|
this.userModelPreferences = result.modelPreferences;
|
|
2964
2981
|
this.modelPreferencesCacheTime = Date.now();
|
|
2965
2982
|
|
|
2966
|
-
// Also cache
|
|
2983
|
+
// Also cache perspectivesPerMessage setting (default 2)
|
|
2967
2984
|
this.perspectivesPerMessage = result.perspectivesPerMessage || 2;
|
|
2968
2985
|
|
|
2969
2986
|
// Cache provider order from user's dashboard (respects display_order)
|
|
@@ -3141,6 +3158,7 @@ To re-login: /polydev:login`
|
|
|
3141
3158
|
return this.localForceCliDetection({});
|
|
3142
3159
|
}).then(() => {
|
|
3143
3160
|
this._cliDetectionComplete = true;
|
|
3161
|
+
// Display CLI status after detection
|
|
3144
3162
|
return this.displayCliStatus();
|
|
3145
3163
|
}).catch((error) => {
|
|
3146
3164
|
console.error('[Polydev] Auto-login flow error:', error.message);
|