@adhdev/daemon-core 0.9.82-rc.317 → 0.9.82-rc.319
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/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
- package/dist/detection/ide-detector.d.ts +13 -0
- package/dist/detection/win32-ide-version.d.ts +37 -0
- package/dist/index.js +1547 -1375
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1570 -1398
- package/dist/index.mjs.map +1 -1
- package/dist/providers/spec/adapter.d.ts +10 -0
- package/dist/providers/working-dir.d.ts +17 -0
- package/package.json +2 -2
- package/src/cli-adapters/provider-cli-runtime.ts +54 -7
- package/src/cli-adapters/resolve-executable.ts +46 -1
- package/src/detection/cli-detector.ts +28 -9
- package/src/detection/ide-detector.ts +31 -2
- package/src/detection/win32-ide-version.ts +106 -0
- package/src/mesh/mesh-events-coordinator.ts +124 -22
- package/src/providers/acp-provider-instance.ts +4 -3
- package/src/providers/cli-provider-instance.ts +5 -4
- package/src/providers/spec/adapter.ts +14 -1
- package/src/providers/spec/fsm-driver.ts +29 -8
- package/src/providers/version-archive.ts +28 -6
- package/src/providers/working-dir.ts +23 -0
|
@@ -52,6 +52,7 @@ import { assertProviderSupportsDeclaredInput, getEffectiveMessageInputSupport }
|
|
|
52
52
|
import type { ProviderInstance, ProviderState, AcpProviderState, ProviderErrorReason, ProviderEvent, InstanceContext, SessionModalState } from './provider-instance.js';
|
|
53
53
|
import { StatusMonitor } from './status-monitor.js';
|
|
54
54
|
import { buildLegacyModelModeSummaryMetadata } from './summary-metadata.js';
|
|
55
|
+
import { workingDirBasename } from './working-dir.js';
|
|
55
56
|
import {
|
|
56
57
|
buildAssistantChatMessage,
|
|
57
58
|
buildChatMessage,
|
|
@@ -345,7 +346,7 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
345
346
|
}
|
|
346
347
|
|
|
347
348
|
getSessionModalState(): SessionModalState {
|
|
348
|
-
const dirName = this.workingDir
|
|
349
|
+
const dirName = workingDirBasename(this.workingDir);
|
|
349
350
|
return {
|
|
350
351
|
id: this.instanceId,
|
|
351
352
|
status: this.currentStatus,
|
|
@@ -358,7 +359,7 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
358
359
|
}
|
|
359
360
|
|
|
360
361
|
getState(): AcpProviderState {
|
|
361
|
-
const dirName = this.workingDir
|
|
362
|
+
const dirName = workingDirBasename(this.workingDir);
|
|
362
363
|
|
|
363
364
|
const recentMessages = normalizeChatMessages(this.messages.map(m => {
|
|
364
365
|
const content = m.content;
|
|
@@ -1504,7 +1505,7 @@ export class AcpProviderInstance implements ProviderInstance {
|
|
|
1504
1505
|
private detectStatusTransition(): void {
|
|
1505
1506
|
const now = Date.now();
|
|
1506
1507
|
const newStatus = this.currentStatus;
|
|
1507
|
-
const dirName = this.workingDir
|
|
1508
|
+
const dirName = workingDirBasename(this.workingDir);
|
|
1508
1509
|
const chatTitle = `${this.provider.name} · ${dirName}`;
|
|
1509
1510
|
const progressFingerprint = newStatus === 'generating'
|
|
1510
1511
|
? `${this.partialContent}::${JSON.stringify(this.partialBlocks)}::${JSON.stringify(this.activeToolCalls.map(t => ({ name: t.name, status: t.status })))}`.slice(-2000)
|
|
@@ -28,6 +28,7 @@ import { getCliScriptCommand, parseCliScriptResult } from './cli-script-results.
|
|
|
28
28
|
import { mergeProviderPatchState, resolveProviderStateSurface } from './provider-patch-state.js';
|
|
29
29
|
import { normalizeProviderSessionId } from './provider-session-id.js';
|
|
30
30
|
import { buildChatMessage, buildRuntimeSystemChatMessage, isUserFacingChatMessage, normalizeChatMessages, resolveChatMessageKind, extractFinalSummaryFromMessages } from './chat-message-normalization.js';
|
|
31
|
+
import { workingDirBasename } from './working-dir.js';
|
|
31
32
|
|
|
32
33
|
type PersistableCliHistoryMessage = {
|
|
33
34
|
role: string;
|
|
@@ -685,7 +686,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
685
686
|
}))
|
|
686
687
|
: mergedMessages;
|
|
687
688
|
|
|
688
|
-
const dirName = this.workingDir
|
|
689
|
+
const dirName = workingDirBasename(this.workingDir);
|
|
689
690
|
const parsedChatStatus = typeof parsedStatus?.status === 'string' && parsedStatus.status.trim()
|
|
690
691
|
? parsedStatus.status.trim()
|
|
691
692
|
: undefined;
|
|
@@ -827,7 +828,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
827
828
|
const autoApproveActive = adapterStatus.status === 'waiting_approval' && this.shouldAutoApprove();
|
|
828
829
|
const autoApproveHoldIdle = this.autoApproveBusy && adapterStatus.status === 'idle';
|
|
829
830
|
const visibleStatus = autoApproveActive || autoApproveHoldIdle ? 'generating' : adapterStatus.status;
|
|
830
|
-
const dirName = this.workingDir
|
|
831
|
+
const dirName = workingDirBasename(this.workingDir);
|
|
831
832
|
return {
|
|
832
833
|
// Honor the caller-supplied sessionId — InstanceMgr rejects the
|
|
833
834
|
// projection when projected.id !== requested sessionId, and
|
|
@@ -1541,7 +1542,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
1541
1542
|
// transcript shape does NOT override the FSM's busy/idle decision.
|
|
1542
1543
|
const autoApproveHoldIdle = this.autoApproveBusy && rawStatus === 'idle';
|
|
1543
1544
|
const newStatus = autoApproveActive || autoApproveHoldIdle ? 'generating' : rawStatus;
|
|
1544
|
-
const dirName = this.workingDir
|
|
1545
|
+
const dirName = workingDirBasename(this.workingDir);
|
|
1545
1546
|
const chatTitle = `${this.provider.name} · ${dirName}`;
|
|
1546
1547
|
const partial = this.adapter.getPartialResponse();
|
|
1547
1548
|
const progressFingerprint = newStatus === 'generating'
|
|
@@ -2053,7 +2054,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
2053
2054
|
receivedAt: normalizedMessage.receivedAt || normalizedMessage.timestamp,
|
|
2054
2055
|
historyDedupKey: dedupKey,
|
|
2055
2056
|
}],
|
|
2056
|
-
this.adapter.getScriptParsedStatus?.()?.title || this.workingDir
|
|
2057
|
+
this.adapter.getScriptParsedStatus?.()?.title || workingDirBasename(this.workingDir),
|
|
2057
2058
|
this.instanceId,
|
|
2058
2059
|
this.providerSessionId,
|
|
2059
2060
|
);
|
|
@@ -25,6 +25,16 @@ export interface TerminalAdapterOpts {
|
|
|
25
25
|
args?: string[];
|
|
26
26
|
cwd?: string;
|
|
27
27
|
env?: Record<string, string>;
|
|
28
|
+
/**
|
|
29
|
+
* When true, `env` is already a COMPLETE, sanitized environment (the spawn
|
|
30
|
+
* planner merged + stripped process.env already) and must be passed to the
|
|
31
|
+
* PTY verbatim — NOT overlaid on top of process.env. Overlaying would
|
|
32
|
+
* re-introduce the npm_/PNPM_/parent-session keys the planner explicitly
|
|
33
|
+
* stripped, so the spec path's spawn env would diverge from the legacy
|
|
34
|
+
* path's. Defaults to false (legacy overlay behaviour) for any caller that
|
|
35
|
+
* still passes a partial env.
|
|
36
|
+
*/
|
|
37
|
+
envIsComplete?: boolean;
|
|
28
38
|
cols?: number;
|
|
29
39
|
rows?: number;
|
|
30
40
|
/** Coalesce screen snapshots: emit on_screen_changed at most this often. */
|
|
@@ -76,9 +86,12 @@ export class TerminalAdapter {
|
|
|
76
86
|
}
|
|
77
87
|
|
|
78
88
|
start(): void {
|
|
89
|
+
const env = this.opts.envIsComplete
|
|
90
|
+
? ((this.opts.env ?? {}) as Record<string, string>)
|
|
91
|
+
: ({ ...process.env, ...(this.opts.env ?? {}) } as Record<string, string>);
|
|
79
92
|
this.pty = this.factory.spawn(this.opts.binary, this.opts.args ?? [], {
|
|
80
93
|
cwd: this.opts.cwd ?? process.cwd(),
|
|
81
|
-
env
|
|
94
|
+
env,
|
|
82
95
|
cols: this.cols,
|
|
83
96
|
rows: this.rows,
|
|
84
97
|
});
|
|
@@ -22,6 +22,7 @@ import * as fs from 'node:fs';
|
|
|
22
22
|
import * as os from 'node:os';
|
|
23
23
|
import * as path from 'node:path';
|
|
24
24
|
import { TerminalAdapter, type TerminalAdapterOpts } from './adapter.js';
|
|
25
|
+
import { resolveCliSpawnPlanFromParts } from '../../cli-adapters/provider-cli-runtime.js';
|
|
25
26
|
import type { PtyTransportFactory } from '../../cli-adapters/pty-transport.js';
|
|
26
27
|
import { DEFAULT_SESSION_HOST_COLS, DEFAULT_SESSION_HOST_ROWS } from '@adhdev/session-host-core';
|
|
27
28
|
import {
|
|
@@ -389,15 +390,35 @@ export class FsmDriver implements ISpecDriver {
|
|
|
389
390
|
}
|
|
390
391
|
|
|
391
392
|
private buildAdapterOpts(): TerminalAdapterOpts {
|
|
392
|
-
|
|
393
|
-
|
|
393
|
+
// Single-source spawn resolution: route the spec's binary/args/env
|
|
394
|
+
// through the SAME planner the legacy ProviderCliAdapter uses
|
|
395
|
+
// (resolveCliSpawnPlanFromParts). This gives the spec/FSM path
|
|
396
|
+
// findBinary (PATH + npm-global / Node-dir fallback so an off-PATH
|
|
397
|
+
// `codex`/`claude` resolves), `{{workingDir}}` token substitution, shell
|
|
398
|
+
// wrapping for script-shims / non-absolute / non-native binaries, and a
|
|
399
|
+
// sanitized env with TERMINAL_CWD — none of which it had when it passed
|
|
400
|
+
// `this.spec.binary` straight to the PTY.
|
|
401
|
+
const cols = this.opts.cols ?? DEFAULT_SESSION_HOST_COLS;
|
|
402
|
+
const rows = this.opts.rows ?? DEFAULT_SESSION_HOST_ROWS;
|
|
403
|
+
const plan = resolveCliSpawnPlanFromParts({
|
|
404
|
+
command: this.spec.binary,
|
|
405
|
+
baseArgs: this.spec.spawn_args ?? [],
|
|
406
|
+
baseEnv: this.spec.env ?? {},
|
|
407
|
+
workingDir: this.opts.workingDir,
|
|
408
|
+
extraArgs: this.opts.extraCliArgs ?? [],
|
|
409
|
+
extraEnv: this.opts.extraEnv ?? {},
|
|
410
|
+
geometry: { cols, rows },
|
|
411
|
+
});
|
|
394
412
|
return {
|
|
395
|
-
binary:
|
|
396
|
-
args:
|
|
397
|
-
cwd:
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
413
|
+
binary: plan.shellCmd,
|
|
414
|
+
args: plan.shellArgs,
|
|
415
|
+
cwd: plan.ptyOptions.cwd,
|
|
416
|
+
// plan.ptyOptions.env is already a complete, sanitized environment —
|
|
417
|
+
// pass it verbatim, do not overlay process.env (see envIsComplete).
|
|
418
|
+
env: plan.ptyOptions.env,
|
|
419
|
+
envIsComplete: true,
|
|
420
|
+
cols,
|
|
421
|
+
rows,
|
|
401
422
|
transportFactory: this.opts.transportFactory,
|
|
402
423
|
};
|
|
403
424
|
}
|
|
@@ -16,6 +16,7 @@ import * as os from 'os';
|
|
|
16
16
|
import { platform } from 'os';
|
|
17
17
|
import type { ProviderLoader } from './provider-loader.js';
|
|
18
18
|
import type { ProviderModule } from './contracts.js';
|
|
19
|
+
import { isKnownWin32GuiExe, readWin32IdeVersionFromDisk } from '../detection/win32-ide-version.js';
|
|
19
20
|
|
|
20
21
|
// ─── Types ──────────────────────────────────────
|
|
21
22
|
|
|
@@ -226,6 +227,10 @@ export async function detectAllVersions(
|
|
|
226
227
|
): Promise<ProviderVersionInfo[]> {
|
|
227
228
|
const results: ProviderVersionInfo[] = [];
|
|
228
229
|
const currentOs = platform() as string;
|
|
230
|
+
// Map of provider type → GUI exe names (win32), used to refuse spawning a
|
|
231
|
+
// GUI executable for version detection (which would boot the IDE window).
|
|
232
|
+
const win32ProcessNames: Record<string, string[]> =
|
|
233
|
+
typeof loader.getWinProcessNames === 'function' ? loader.getWinProcessNames() : {};
|
|
229
234
|
|
|
230
235
|
for (const provider of loader.getAll()) {
|
|
231
236
|
const info: ProviderVersionInfo = {
|
|
@@ -258,12 +263,29 @@ export async function detectAllVersions(
|
|
|
258
263
|
info.path = appPath || null;
|
|
259
264
|
info.binary = resolvedBin || null;
|
|
260
265
|
|
|
261
|
-
// Version
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
266
|
+
// Version detection for IDEs must avoid spawning the GUI executable.
|
|
267
|
+
// On Windows the resolved binary is frequently the GUI Electron exe
|
|
268
|
+
// (case-insensitive FS), and `<exe> --version` boots the IDE window.
|
|
269
|
+
// Strategy (all spawn-free where possible):
|
|
270
|
+
// 1. win32: read bundled product.json/package.json next to the exe.
|
|
271
|
+
// 2. darwin: read Info.plist via PlistBuddy (read-only).
|
|
272
|
+
// 3. Fallback to `<bin> --version` ONLY when the binary is not a
|
|
273
|
+
// known GUI exe — the safety-net guard (#4).
|
|
274
|
+
if (currentOs === 'win32') {
|
|
275
|
+
info.version = readWin32IdeVersionFromDisk(resolvedBin || appPath || '');
|
|
276
|
+
if (!info.version && resolvedBin && !isKnownWin32GuiExe(resolvedBin, win32ProcessNames)) {
|
|
277
|
+
info.version = await getVersion(resolvedBin, versionCommand);
|
|
278
|
+
}
|
|
279
|
+
} else if (currentOs === 'darwin') {
|
|
280
|
+
if (appPath) info.version = await getMacAppVersion(appPath);
|
|
281
|
+
if (!info.version && resolvedBin) {
|
|
282
|
+
info.version = await getVersion(resolvedBin, versionCommand);
|
|
283
|
+
}
|
|
284
|
+
} else {
|
|
285
|
+
// linux and others: bundled CLI wrappers are real CLIs, safe to exec.
|
|
286
|
+
if (resolvedBin) {
|
|
287
|
+
info.version = await getVersion(resolvedBin, versionCommand);
|
|
288
|
+
}
|
|
267
289
|
}
|
|
268
290
|
|
|
269
291
|
} else if (provider.category === 'cli' || provider.category === 'acp') {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* working-dir — shared helpers for deriving display names from a session's
|
|
3
|
+
* working directory. Used by CLI/ACP provider instances to build session/tab
|
|
4
|
+
* titles.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* OS-aware basename of a working directory path.
|
|
9
|
+
*
|
|
10
|
+
* Splits on BOTH POSIX (`/`) and Windows (`\`) separators so a win32 path like
|
|
11
|
+
* `D:\gh\adhdev-cloud` resolves to `adhdev-cloud` even when the daemon's own
|
|
12
|
+
* `path.basename` is POSIX-only — and a path that mixes separators still works.
|
|
13
|
+
* Trailing separators and root-only paths fall back to `'session'`, matching
|
|
14
|
+
* the historical `.split('/').filter(Boolean).pop() || 'session'` behavior.
|
|
15
|
+
*
|
|
16
|
+
* Mirrors the web dashboard's `getWorkspaceName` (`ws.split(/[/\\]/)`).
|
|
17
|
+
*/
|
|
18
|
+
export function workingDirBasename(p: string): string {
|
|
19
|
+
return (p || '')
|
|
20
|
+
.split(/[\\/]/)
|
|
21
|
+
.filter(Boolean)
|
|
22
|
+
.pop() || 'session';
|
|
23
|
+
}
|