linkshell-cli 0.5.24 → 0.5.26
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/src/runtime/acp/agent-workspace.d.ts +7 -0
- package/dist/cli/src/runtime/acp/agent-workspace.js +81 -1
- package/dist/cli/src/runtime/acp/agent-workspace.js.map +1 -1
- package/dist/cli/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/runtime/acp/agent-workspace.ts +75 -1
- package/web/assets/index-IawebWL8.js +94 -0
- package/web/index.html +1 -1
- package/web/assets/index-Bh3kcNhP.js +0 -94
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync, watch } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { basename, join, relative } from "node:path";
|
|
4
4
|
import {
|
|
@@ -1944,12 +1944,83 @@ export class AgentWorkspaceProxy {
|
|
|
1944
1944
|
}
|
|
1945
1945
|
|
|
1946
1946
|
stop(): void {
|
|
1947
|
+
for (const watcher of this.fsWatchers) {
|
|
1948
|
+
try { watcher.close(); } catch { /* already closed */ }
|
|
1949
|
+
}
|
|
1950
|
+
this.fsWatchers = [];
|
|
1951
|
+
if (this.fsSyncTimer) {
|
|
1952
|
+
clearTimeout(this.fsSyncTimer);
|
|
1953
|
+
this.fsSyncTimer = undefined;
|
|
1954
|
+
}
|
|
1947
1955
|
for (const client of this.clients.values()) {
|
|
1948
1956
|
client.stop();
|
|
1949
1957
|
}
|
|
1950
1958
|
this.clients.clear();
|
|
1951
1959
|
}
|
|
1952
1960
|
|
|
1961
|
+
// ── External-session live refresh ────────────────────────────────────
|
|
1962
|
+
// The console requests the session list only once, at connect. Without this,
|
|
1963
|
+
// a session another `claude`/`codex` process starts (or whose status changes)
|
|
1964
|
+
// after connect never shows up — the tree is frozen at connect time. Watch the
|
|
1965
|
+
// on-disk session stores and re-sync + push when they change, so externally-
|
|
1966
|
+
// driven sessions surface live (this is what CodeIsland does). Event-driven:
|
|
1967
|
+
// zero cost while idle, throttled to at most one re-scan per window during a
|
|
1968
|
+
// burst of writes (an active turn appends constantly).
|
|
1969
|
+
private fsWatchers: ReturnType<typeof watch>[] = [];
|
|
1970
|
+
private fsSyncTimer: ReturnType<typeof setTimeout> | undefined;
|
|
1971
|
+
private fsSyncRunning = false;
|
|
1972
|
+
private static readonly FS_SYNC_THROTTLE_MS = 1500;
|
|
1973
|
+
|
|
1974
|
+
private startSessionWatchers(): void {
|
|
1975
|
+
if (this.fsWatchers.length > 0) return; // already watching
|
|
1976
|
+
const roots = [
|
|
1977
|
+
join(homedir(), ".claude", "projects"),
|
|
1978
|
+
join(homedir(), ".codex", "sessions"),
|
|
1979
|
+
];
|
|
1980
|
+
for (const root of roots) {
|
|
1981
|
+
if (!existsSync(root)) continue;
|
|
1982
|
+
try {
|
|
1983
|
+
// recursive is supported on macOS/Windows; on Linux this throws, and we
|
|
1984
|
+
// simply don't get live updates (the connect-time scan still works).
|
|
1985
|
+
const watcher = watch(root, { recursive: true, persistent: false }, () => this.scheduleSessionSync());
|
|
1986
|
+
watcher.on("error", () => { /* transient watch error — ignore */ });
|
|
1987
|
+
this.fsWatchers.push(watcher);
|
|
1988
|
+
} catch {
|
|
1989
|
+
// recursive watch unavailable on this platform — skip silently.
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
private scheduleSessionSync(): void {
|
|
1995
|
+
if (this.fsSyncTimer) return; // a sync is already scheduled in this window
|
|
1996
|
+
this.fsSyncTimer = setTimeout(() => {
|
|
1997
|
+
this.fsSyncTimer = undefined;
|
|
1998
|
+
void this.syncAndPushSessions();
|
|
1999
|
+
}, AgentWorkspaceProxy.FS_SYNC_THROTTLE_MS);
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
private async syncAndPushSessions(): Promise<void> {
|
|
2003
|
+
if (this.fsSyncRunning) return; // don't overlap with an in-flight sync
|
|
2004
|
+
this.fsSyncRunning = true;
|
|
2005
|
+
try {
|
|
2006
|
+
await this.syncProviderSessions();
|
|
2007
|
+
// Push the conversation list (statuses) — lighter than a full snapshot and
|
|
2008
|
+
// exactly what refreshes the tree. The web handles an unsolicited
|
|
2009
|
+
// conversation.list.result the same as a requested one.
|
|
2010
|
+
this.input.send(createEnvelope({
|
|
2011
|
+
type: "agent.v2.conversation.list.result",
|
|
2012
|
+
sessionId: this.input.sessionId,
|
|
2013
|
+
payload: { conversations: [...this.conversations.values()].filter((c) => !c.archived) },
|
|
2014
|
+
}));
|
|
2015
|
+
} catch (error) {
|
|
2016
|
+
if (this.input.verbose) {
|
|
2017
|
+
process.stderr.write(`[agent:v2] fs-watch sync failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
2018
|
+
}
|
|
2019
|
+
} finally {
|
|
2020
|
+
this.fsSyncRunning = false;
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
|
|
1953
2024
|
private clientForProvider(provider: AgentProvider): AcpClient | ClaudeSdkClient | ClaudeStreamJsonClient | undefined {
|
|
1954
2025
|
return this.clients.get(provider);
|
|
1955
2026
|
}
|
|
@@ -1996,6 +2067,9 @@ export class AgentWorkspaceProxy {
|
|
|
1996
2067
|
this.status = "idle";
|
|
1997
2068
|
this.error = undefined;
|
|
1998
2069
|
this.sendCapabilities();
|
|
2070
|
+
// Start watching the on-disk session stores so externally-started sessions
|
|
2071
|
+
// and status changes surface live, not just at connect time.
|
|
2072
|
+
this.startSessionWatchers();
|
|
1999
2073
|
}
|
|
2000
2074
|
|
|
2001
2075
|
private async ensureProviderClient(provider: AgentProvider): Promise<AcpClient | ClaudeSdkClient | ClaudeStreamJsonClient | undefined> {
|