@pasko70/pibo 2.5.2 → 3.0.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/context/pibo-native-tooling.md +1 -0
- package/dist/agent-runtime/contract.js +2 -1
- package/dist/agent-runtime/history.js +53 -1
- package/dist/agent-runtime/routed-session.js +100 -26
- package/dist/agent-runtimes/codex-native/adapter.js +304 -30
- package/dist/agent-runtimes/codex-native/client.js +22 -3
- package/dist/agent-runtimes/codex-native/first-use.js +294 -0
- package/dist/agent-runtimes/codex-native/history.js +26 -7
- package/dist/agent-runtimes/codex-native/process.js +14 -0
- package/dist/agent-runtimes/codex-native/thread.js +59 -25
- package/dist/agent-runtimes/codex-native/turn.js +27 -0
- package/dist/agent-runtimes/history-proof.js +8 -0
- package/dist/agent-runtimes/omp/adapter.js +61 -14
- package/dist/agent-runtimes/omp/history.js +189 -34
- package/dist/agent-runtimes/omp/thread.js +82 -36
- package/dist/agent-runtimes/pi/adapter.js +30 -3
- package/dist/agent-runtimes/pi/history.js +66 -5
- package/dist/agent-runtimes/pi/openai-response-observer.js +102 -0
- package/dist/agent-runtimes/pi/routed-session.js +344 -37
- package/dist/apps/chat/chat-api-routes.js +1 -1
- package/dist/apps/chat/chat-files.js +130 -9
- package/dist/apps/chat/chat-settings-routes.js +27 -2
- package/dist/apps/chat/chat-speech.js +100 -0
- package/dist/apps/chat/data/chat-data-mappers.js +25 -5
- package/dist/apps/chat/data/timeline-query-service.js +89 -1
- package/dist/apps/chat/trace-v2.js +210 -8
- package/dist/apps/chat/trace.js +3 -0
- package/dist/apps/chat/web-app.js +108 -3
- package/dist/apps/chat-ui/assets/{dist-DTWJf37A.js → dist-BBDMeU5-.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CkYWKnvy.js → dist-BDIATCQt.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DZ8Wpj-H.js → dist-JnW4v8UE.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-Dmblz15N.js → dist-lRiLP9rr.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DjcwoyNY.js → dist-mqCviI-c.js} +1 -1
- package/dist/apps/chat-ui/assets/index-0XOOVxLP.js +228 -0
- package/dist/apps/chat-ui/assets/index-DV7_CgsC.css +1 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/index-Dtw2Z7jz.js +43 -0
- package/dist/apps/chat-vscode-web/assets/{index-CF1-9PKU.css → index-SluZr_-r.css} +1 -1
- package/dist/apps/chat-vscode-web/index.html +2 -2
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-3.0.0.vsix +0 -0
- package/dist/cli.js +49 -5
- package/dist/config/config.js +59 -8
- package/dist/core/preview-server-settings.js +20 -0
- package/dist/core/session-router.js +457 -37
- package/dist/core/user-settings.js +10 -0
- package/dist/data/payload-store.js +57 -1
- package/dist/data/schema.js +18 -1
- package/dist/debug/trace.js +5 -0
- package/dist/gateway/client.js +368 -65
- package/dist/gateway/protocol.js +2 -0
- package/dist/gateway/server.js +8 -0
- package/dist/gateway/web.js +2 -0
- package/dist/index.js +1 -1
- package/dist/loops/store.js +6 -4
- package/dist/mcp/config.js +89 -17
- package/dist/mcp/daemon-client.js +473 -153
- package/dist/mcp/daemon.js +401 -37
- package/dist/plugins/builtin.js +2 -2
- package/dist/plugins/codex-native.js +2 -0
- package/dist/plugins/registry.js +259 -1
- package/dist/previews/cli.js +345 -0
- package/dist/previews/config.js +61 -0
- package/dist/previews/manager.js +644 -0
- package/dist/previews/network.js +198 -0
- package/dist/previews/plugin.js +11 -0
- package/dist/previews/process-supervisor.js +38 -0
- package/dist/previews/proxy.js +387 -0
- package/dist/previews/store.js +750 -0
- package/dist/previews/types.js +1 -0
- package/dist/previews/web-app.js +446 -0
- package/dist/runs/registry.js +22 -0
- package/dist/runs/tools.js +46 -7
- package/dist/session-ui/terminalRows.js +187 -13
- package/dist/sessions/pibo-data-store.js +37 -0
- package/dist/sessions/runtime-binding-persistence.js +34 -0
- package/dist/sessions/runtime-binding.js +6 -0
- package/dist/sessions/sqlite-store.js +37 -0
- package/dist/shared/trace-engine.js +12 -64
- package/dist/shared/trace-event-projection.js +16 -0
- package/dist/shared/trace-history.js +684 -184
- package/dist/shared/trace-limits.js +7 -0
- package/dist/shared/trace-live-patch.js +61 -0
- package/dist/shared/trace-tool-identity.js +43 -0
- package/dist/speech/openai-codex-realtime-call-proxy.js +248 -0
- package/dist/speech/openai-codex.js +407 -0
- package/dist/speech/types.js +8 -0
- package/dist/subagents/context.js +5 -3
- package/dist/subagents/observations.js +94 -6
- package/dist/subagents/tool.js +103 -20
- package/dist/tools/codex-image-artifacts.js +24 -0
- package/dist/tools/codex-image-generation.js +4 -22
- package/dist/web/channel.js +88 -4
- package/dist/web/http.js +2 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/apps/chat-ui/assets/index-0WZI2phJ.css +0 -1
- package/dist/apps/chat-ui/assets/index-DsgTm1Aw.js +0 -228
- package/dist/apps/chat-vscode-web/assets/index-DvTSSvzN.js +0 -43
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.5.2.vsix +0 -0
package/dist/gateway/server.js
CHANGED
|
@@ -209,6 +209,8 @@ export class PiboGatewayServer {
|
|
|
209
209
|
for (const app of registry.getWebApps())
|
|
210
210
|
await app.dispose?.();
|
|
211
211
|
}
|
|
212
|
+
await Promise.allSettled([...new Set([this.pluginRegistry, this.compatibilityRuntimeRegistry].filter((registry) => Boolean(registry)))]
|
|
213
|
+
.map(async (registry) => await registry.disposeSpeechProviders()));
|
|
212
214
|
if (this.ownsSessionStore) {
|
|
213
215
|
this.sessionStore?.close?.();
|
|
214
216
|
}
|
|
@@ -419,6 +421,7 @@ export class PiboGatewayServer {
|
|
|
419
421
|
rebindSessionRuntime: (piboSessionId, input) => this.requireRouter().rebindSessionRuntime(piboSessionId, input),
|
|
420
422
|
getSessionRuntimeStatus: (piboSessionId) => this.requireRouter().getSessionRuntimeStatus(piboSessionId),
|
|
421
423
|
getSessionStatusSnapshot: (piboSessionId) => this.requireRouter().getSessionStatusSnapshot(piboSessionId),
|
|
424
|
+
getSessionForkCandidates: (piboSessionId) => this.requireRouter().getSessionForkCandidates(piboSessionId),
|
|
422
425
|
listSessionRuntimeStatuses: () => this.requireRouter().listSessionRuntimeStatuses(),
|
|
423
426
|
listRuns: (options) => this.requireRouter().listRuns(options),
|
|
424
427
|
snapshotSignalSession: (piboSessionId) => this.requireRouter().snapshotSignalSession(piboSessionId),
|
|
@@ -432,6 +435,11 @@ export class PiboGatewayServer {
|
|
|
432
435
|
getCapabilityCatalog: () => this.pluginRegistry.getCapabilityCatalog(),
|
|
433
436
|
getTranscriptionProviderInfos: () => this.pluginRegistry.getTranscriptionProviderInfos(),
|
|
434
437
|
transcribe: (providerId, input) => this.pluginRegistry.transcribe(providerId, input),
|
|
438
|
+
getSpeechProviderIds: () => this.pluginRegistry.getSpeechProviderIds(),
|
|
439
|
+
getSpeechProviderInfos: () => this.pluginRegistry.getSpeechProviderInfos(),
|
|
440
|
+
startSpeechSession: (providerId, input, options) => this.pluginRegistry.startSpeechSession(providerId, input, options),
|
|
441
|
+
speakSpeechSession: (sessionId, input) => this.pluginRegistry.speakSpeechSession(sessionId, input),
|
|
442
|
+
stopSpeechSession: (sessionId) => this.pluginRegistry.stopSpeechSession(sessionId),
|
|
435
443
|
inspectAgentRuntimeInstances: () => this.pluginRegistry.inspectAgentRuntimeInstances(),
|
|
436
444
|
getAgentRuntimeAuthStatus: (runtimeInstanceId) => this.requireRouter().getAgentRuntimeAuthStatus(runtimeInstanceId),
|
|
437
445
|
startAgentRuntimeAuth: (runtimeInstanceId, input) => this.requireRouter().startAgentRuntimeAuth(runtimeInstanceId, input),
|
package/dist/gateway/web.js
CHANGED
|
@@ -6,6 +6,7 @@ import { createPiboChatUserSkillsPlugin } from "../plugins/chat-user-skills.js";
|
|
|
6
6
|
import { createPiboChatWebPlugin } from "../plugins/chat-web.js";
|
|
7
7
|
import { createPiboChatVscodeWebPlugin } from "../plugins/chat-vscode-web.js";
|
|
8
8
|
import { createPiboContextFilesPlugin } from "../plugins/context-files.js";
|
|
9
|
+
import { createPiboPreviewPlugin } from "../previews/plugin.js";
|
|
9
10
|
import { createPiboCronPlugin } from "../cron/plugin.js";
|
|
10
11
|
import { createPiboLoopPlugin } from "../loops/plugin.js";
|
|
11
12
|
import { createPiboDevAuthPlugin } from "../plugins/dev-auth.js";
|
|
@@ -160,6 +161,7 @@ export function createWebPiboPluginRegistry(options = {}) {
|
|
|
160
161
|
createPiboChatCustomAgentProfilesPlugin({ agentStorePath: resolvedOptions.chat?.agentStorePath }),
|
|
161
162
|
createPiboLoopPlugin({ loopStorePath: resolvedOptions.chat?.ralphStorePath, dataStorePath: resolvedOptions.chat?.dataStorePath, dataPayloadRootDir: resolvedOptions.chat?.dataPayloadRootDir }),
|
|
162
163
|
createPiboContextFilesPlugin(resolvedOptions.contextFiles),
|
|
164
|
+
createPiboPreviewPlugin(),
|
|
163
165
|
createPiboChatWebPlugin(resolvedOptions.chat),
|
|
164
166
|
createPiboChatVscodeWebPlugin(),
|
|
165
167
|
],
|
package/dist/index.js
CHANGED
|
@@ -41,7 +41,7 @@ export { runGatewayClient } from "./gateway/client.js";
|
|
|
41
41
|
export { LOCAL_TUI_CHANNEL_NAME, LocalRoutedTuiClient, createLocalRoutedTuiClient, createLocalRoutedTuiExtension, runLocalRoutedTui, } from "./local/tui.js";
|
|
42
42
|
export { createWebHostChannel, DEFAULT_WEB_CHANNEL_HOST, DEFAULT_WEB_CHANNEL_PORT, WEB_CHANNEL_NAME } from "./web/channel.js";
|
|
43
43
|
export { sendGatewayEvent, sendGatewayMessageAndWaitForReply } from "./gateway/request.js";
|
|
44
|
-
export { createAgentToolDefinitions, createSubagentToolDefinitions, createSubagentToolName, formatAvailableAgentsForPrompt, listAvailableAgents, PIBO_AGENT_TOOL_NAMES, } from "./subagents/tool.js";
|
|
44
|
+
export { createAgentToolDefinitions, createSubagentToolDefinitions, createSubagentToolName, formatAvailableAgentsForPrompt, listAvailableAgents, normalizePiboAgentSessionName, PIBO_AGENT_SESSION_NAME_MAX_LENGTH, PIBO_AGENT_TOOL_NAMES, } from "./subagents/tool.js";
|
|
45
45
|
export { PiboSteeringUnavailableError } from "./core/events.js";
|
|
46
46
|
export { RuntimeSessionBindingConflictError, RuntimeSessionBindingTransitionError, assertRuntimeSessionBindingTransition, createInitialRuntimeSessionBinding, createLegacyPiRuntimeSessionBinding, nextRuntimeSessionBinding, } from "./sessions/runtime-binding.js";
|
|
47
47
|
export { InMemoryPiboSessionStore, createPiSessionId, createPiboSessionId, createPiboSession, } from "./sessions/store.js";
|
package/dist/loops/store.js
CHANGED
|
@@ -299,7 +299,7 @@ export class PiboLoopStore {
|
|
|
299
299
|
const enabled = input.enabled === true;
|
|
300
300
|
const state = {
|
|
301
301
|
completedIterations: 0,
|
|
302
|
-
...(mode === 'goal' ? { goalStatus: enabled ? 'active' : 'paused', tokenAccounting: newGoalTokenAccounting(), tokensUsed: 0, activeTimeSeconds: 0, ...(enabled ? { goalStartedAt: timestamp } : {}) } : {}),
|
|
302
|
+
...(mode === 'goal' ? { goalStatus: enabled ? 'active' : 'paused', tokenAccounting: newGoalTokenAccounting(), tokensUsed: 0, activeTimeSeconds: 0, activeTimeRunningAt: null, ...(enabled ? { goalStartedAt: timestamp } : {}) } : {}),
|
|
303
303
|
...(input.initialPiboSessionId?.trim() ? { lastPiboSessionId: input.initialPiboSessionId.trim() } : {}),
|
|
304
304
|
};
|
|
305
305
|
const job = { id: mode === 'ralph' ? `ralph_${randomUUID()}` : `loop_${randomUUID()}`, mode, name: (input.name ?? defaultName(input.prompt)).trim(), description: input.description?.trim() || undefined, enabled, target, profile: input.profile, prompt: input.prompt, maxIterations: normalizeMaxIterations(input.maxIterations), tokenBudget: normalizeTokenBudget(input.tokenBudget), tokenReserve: normalizeTokenReserve(input.tokenReserve), stopPolicy: normalizeLoopStopPolicy(input.stopPolicy), ...runtimeOptions, ...(resources ? { resources } : {}), state, createdAt: timestamp, updatedAt: timestamp };
|
|
@@ -373,7 +373,7 @@ export class PiboLoopStore {
|
|
|
373
373
|
createdAt: timestamp,
|
|
374
374
|
};
|
|
375
375
|
this.db.prepare('INSERT INTO pibo_ralph_run_facts (id, job_id, run_id, pibo_session_id, type, source, payload_json, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)').run(fact.id, fact.jobId, null, piboSessionId, fact.type, fact.source, JSON.stringify(fact.payload), fact.createdAt);
|
|
376
|
-
const state = { ...job.state, goalStatus: 'active', goalEndedAt: undefined, stopRequestedAt: undefined, cancelRequestedAt: undefined, runningAt: undefined };
|
|
376
|
+
const state = { ...job.state, goalStatus: 'active', goalEndedAt: undefined, stopRequestedAt: undefined, cancelRequestedAt: undefined, activeTimeRunningAt: null, runningAt: undefined };
|
|
377
377
|
this.db.prepare('UPDATE pibo_ralph_jobs SET enabled = 1, state_json = ?, updated_at = ? WHERE id = ?').run(JSON.stringify(state), timestamp, job.id);
|
|
378
378
|
this.db.exec('COMMIT');
|
|
379
379
|
return this.getJob(id);
|
|
@@ -483,6 +483,7 @@ export class PiboLoopStore {
|
|
|
483
483
|
try {
|
|
484
484
|
const job = this.recordGoalProgress(id, { activeTimeSeconds: seconds }, now);
|
|
485
485
|
if (job?.mode === 'goal') {
|
|
486
|
+
this.updateJobStateLocked(id, { ...job.state, activeTimeRunningAt: null }, nowIso(now));
|
|
486
487
|
const row = this.db.prepare('SELECT * FROM pibo_ralph_runs WHERE id = ? AND job_id = ?').get(runId, id);
|
|
487
488
|
if (row) {
|
|
488
489
|
const accounting = { ...(parseRunAccounting(row.accounting_json) ?? { tokenAccounting: normalizeLoopTokenAccounting(job.state.tokenAccounting) }), activeTimeSeconds: seconds };
|
|
@@ -490,7 +491,7 @@ export class PiboLoopStore {
|
|
|
490
491
|
}
|
|
491
492
|
}
|
|
492
493
|
this.db.exec('COMMIT');
|
|
493
|
-
return job;
|
|
494
|
+
return this.getJob(id) ?? job;
|
|
494
495
|
}
|
|
495
496
|
catch (error) {
|
|
496
497
|
this.db.exec('ROLLBACK');
|
|
@@ -681,6 +682,7 @@ export class PiboLoopStore {
|
|
|
681
682
|
const shouldDisable = terminalGoalStatus || reachedMaxIterations || input.stopAfterRun === true || input.stopEvaluation?.finalAction === 'stop-after-run' || input.stopEvaluation?.finalAction === 'cancel-current-run';
|
|
682
683
|
const state = {
|
|
683
684
|
...job.state,
|
|
685
|
+
...(job.mode === 'goal' ? { activeTimeRunningAt: null } : {}),
|
|
684
686
|
runningAt: undefined,
|
|
685
687
|
completedIterations,
|
|
686
688
|
lastRunAt: timestamp,
|
|
@@ -789,7 +791,7 @@ export class PiboLoopStore {
|
|
|
789
791
|
}
|
|
790
792
|
}
|
|
791
793
|
const run = this.createRunLocked(job, timestamp);
|
|
792
|
-
const state = { ...job.state, runningAt: timestamp, lastRunAt: timestamp, lastRunId: run.id, nextAttemptAt: undefined, retryBackoffMs: undefined };
|
|
794
|
+
const state = { ...job.state, ...(job.mode === 'goal' ? { activeTimeRunningAt: timestamp } : {}), runningAt: timestamp, lastRunAt: timestamp, lastRunId: run.id, nextAttemptAt: undefined, retryBackoffMs: undefined };
|
|
793
795
|
this.updateJobStateLocked(job.id, state, timestamp);
|
|
794
796
|
this.db.exec('COMMIT');
|
|
795
797
|
return { job: { ...job, state, updatedAt: timestamp }, run };
|
package/dist/mcp/config.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { createHash } from 'node:crypto';
|
|
5
5
|
import { existsSync } from 'node:fs';
|
|
6
6
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
7
|
-
import { homedir } from 'node:os';
|
|
7
|
+
import { homedir, tmpdir } from 'node:os';
|
|
8
8
|
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
9
9
|
import { ErrorCode, configInvalidJsonError, configMissingFieldError, configNotFoundError, configSearchError, formatCliError, serverNotFoundError, } from './errors.js';
|
|
10
10
|
export const DEFAULT_MCP_CONFIG_FILE = 'mcp_servers.json';
|
|
@@ -207,34 +207,106 @@ export function getDaemonRequestTimeoutMs() {
|
|
|
207
207
|
}
|
|
208
208
|
return DEFAULT_DAEMON_REQUEST_TIMEOUT_SECONDS * 1000;
|
|
209
209
|
}
|
|
210
|
+
function getDaemonUserKey(platform) {
|
|
211
|
+
const uid = process.getuid?.();
|
|
212
|
+
if (platform !== 'win32' && uid !== undefined) {
|
|
213
|
+
return String(uid);
|
|
214
|
+
}
|
|
215
|
+
const identity = `${homedir()}\0${process.env.USERNAME ?? process.env.USER ?? ''}`;
|
|
216
|
+
return createHash('sha256').update(identity).digest('hex').slice(0, 12);
|
|
217
|
+
}
|
|
218
|
+
function getDaemonServerKey(serverName) {
|
|
219
|
+
// Node replaces unpaired UTF-16 surrogates when encoding a string as UTF-8.
|
|
220
|
+
// Hash those names as explicit code units so distinct JavaScript strings do
|
|
221
|
+
// not collapse onto the same daemon endpoint.
|
|
222
|
+
const hasUnpairedSurrogate = Array.from({ length: serverName.length }, (_, index) => serverName.charCodeAt(index)).some((codeUnit, index, codeUnits) => {
|
|
223
|
+
if (codeUnit >= 0xd800 && codeUnit <= 0xdbff) {
|
|
224
|
+
const next = codeUnits[index + 1];
|
|
225
|
+
return next === undefined || next < 0xdc00 || next > 0xdfff;
|
|
226
|
+
}
|
|
227
|
+
if (codeUnit >= 0xdc00 && codeUnit <= 0xdfff) {
|
|
228
|
+
const previous = codeUnits[index - 1];
|
|
229
|
+
return previous === undefined || previous < 0xd800 || previous > 0xdbff;
|
|
230
|
+
}
|
|
231
|
+
return false;
|
|
232
|
+
});
|
|
233
|
+
const hash = createHash('sha256');
|
|
234
|
+
if (hasUnpairedSurrogate) {
|
|
235
|
+
hash.update('pibo-mcp-utf16\0');
|
|
236
|
+
const codeUnits = Buffer.allocUnsafe(serverName.length * 2);
|
|
237
|
+
for (let index = 0; index < serverName.length; index += 1) {
|
|
238
|
+
codeUnits.writeUInt16LE(serverName.charCodeAt(index), index * 2);
|
|
239
|
+
}
|
|
240
|
+
hash.update(codeUnits);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
hash.update(serverName);
|
|
244
|
+
}
|
|
245
|
+
return hash.digest('hex').slice(0, 16);
|
|
246
|
+
}
|
|
247
|
+
function getDaemonFileName(serverName) {
|
|
248
|
+
// Keep every filesystem path bounded. Unix-domain socket limits are much
|
|
249
|
+
// shorter than ordinary filesystem path limits, and server names are input.
|
|
250
|
+
return getDaemonServerKey(serverName);
|
|
251
|
+
}
|
|
210
252
|
/**
|
|
211
|
-
* Get the
|
|
212
|
-
* Uses platform-appropriate temp directory
|
|
253
|
+
* Get the directory for daemon PID files and POSIX sockets.
|
|
213
254
|
*/
|
|
214
|
-
export function getSocketDir() {
|
|
215
|
-
|
|
216
|
-
// macOS uses /var/folders which is auto-cleaned, Linux uses /tmp
|
|
217
|
-
const base = process.platform === 'darwin' ? '/tmp' : '/tmp';
|
|
218
|
-
return join(base, `mcp-cli-${uid}`);
|
|
255
|
+
export function getSocketDir(platform = process.platform) {
|
|
256
|
+
return join(tmpdir(), `mcp-cli-${getDaemonUserKey(platform)}`);
|
|
219
257
|
}
|
|
220
258
|
/**
|
|
221
|
-
*
|
|
259
|
+
* Whether the platform represents daemon IPC as a filesystem socket.
|
|
222
260
|
*/
|
|
223
|
-
export function
|
|
224
|
-
return
|
|
261
|
+
export function usesFilesystemSocket(platform = process.platform) {
|
|
262
|
+
return platform !== 'win32';
|
|
225
263
|
}
|
|
226
264
|
/**
|
|
227
|
-
* Get
|
|
265
|
+
* Get the IPC endpoint for a specific server.
|
|
266
|
+
* POSIX uses Unix domain sockets; Windows uses named pipes.
|
|
228
267
|
*/
|
|
229
|
-
export function
|
|
230
|
-
|
|
268
|
+
export function getSocketPath(serverName, platform = process.platform) {
|
|
269
|
+
if (platform === 'win32') {
|
|
270
|
+
const userKey = getDaemonUserKey(platform);
|
|
271
|
+
return `\\\\.\\pipe\\pibo-mcp-${userKey}-${getDaemonServerKey(serverName)}`;
|
|
272
|
+
}
|
|
273
|
+
return join(getSocketDir(platform), `${getDaemonFileName(serverName)}.sock`);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Get PID file path for a specific server daemon.
|
|
277
|
+
*/
|
|
278
|
+
export function getPidPath(serverName, platform = process.platform) {
|
|
279
|
+
return join(getSocketDir(platform), `${getDaemonFileName(serverName)}.pid`);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Get the atomic startup-election claim path for a server daemon.
|
|
283
|
+
*/
|
|
284
|
+
export function getDaemonClaimPath(serverName, platform = process.platform) {
|
|
285
|
+
return join(getSocketDir(platform), `${getDaemonFileName(serverName)}.lock`);
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Get the prefix shared by active client lease files for a server daemon.
|
|
289
|
+
*/
|
|
290
|
+
export function getDaemonLeasePrefix(serverName, platform = process.platform) {
|
|
291
|
+
return join(getSocketDir(platform), `${getDaemonFileName(serverName)}.lease-`);
|
|
292
|
+
}
|
|
293
|
+
function normalizeForHash(value) {
|
|
294
|
+
if (Array.isArray(value)) {
|
|
295
|
+
return value.map(normalizeForHash);
|
|
296
|
+
}
|
|
297
|
+
if (value && typeof value === 'object') {
|
|
298
|
+
return Object.fromEntries(Object.entries(value)
|
|
299
|
+
.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
|
|
300
|
+
.map(([key, nestedValue]) => [key, normalizeForHash(nestedValue)]));
|
|
301
|
+
}
|
|
302
|
+
return value;
|
|
231
303
|
}
|
|
232
304
|
/**
|
|
233
|
-
* Generate a hash of server config for stale detection
|
|
234
|
-
*
|
|
305
|
+
* Generate a hash of server config for stale detection.
|
|
306
|
+
* Nested object key order does not affect the hash.
|
|
235
307
|
*/
|
|
236
308
|
export function getConfigHash(config) {
|
|
237
|
-
const str = JSON.stringify(
|
|
309
|
+
const str = JSON.stringify(normalizeForHash(config));
|
|
238
310
|
return createHash('sha256').update(str).digest('hex').slice(0, 16);
|
|
239
311
|
}
|
|
240
312
|
/**
|