@phenx-inc/ctlsurf 0.3.14 → 0.3.16
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/out/headless/index.mjs +57 -8
- package/out/headless/index.mjs.map +2 -2
- package/out/main/index.js +56 -7
- package/out/preload/index.js +6 -0
- package/out/renderer/assets/{cssMode-G_SDogBL.js → cssMode-D5dPwEy5.js} +3 -3
- package/out/renderer/assets/{freemarker2-BzEus0h2.js → freemarker2-c5jJjQ9s.js} +1 -1
- package/out/renderer/assets/{handlebars-Et995f6O.js → handlebars-BTbmOxx9.js} +1 -1
- package/out/renderer/assets/{html-D4wgKxPD.js → html-3cIIQcxO.js} +1 -1
- package/out/renderer/assets/{htmlMode-DSxpefzL.js → htmlMode-DYbpW1yY.js} +3 -3
- package/out/renderer/assets/{index-AQ346NMi.css → index-6KvOnYL1.css} +18 -0
- package/out/renderer/assets/{index-ByJTqkiQ.js → index-D2MUZin7.js} +36 -23
- package/out/renderer/assets/{javascript-CzLoo8aq.js → javascript-CDuCMm-6.js} +2 -2
- package/out/renderer/assets/{jsonMode-BrwPy7fY.js → jsonMode-COLqbq0s.js} +3 -3
- package/out/renderer/assets/{liquid-BsfPf6YG.js → liquid-BFcqZizB.js} +1 -1
- package/out/renderer/assets/{lspLanguageFeatures-CxLZ421s.js → lspLanguageFeatures-CbkEcL-z.js} +1 -1
- package/out/renderer/assets/{mdx-CPvHIsAR.js → mdx-DyK93oEE.js} +1 -1
- package/out/renderer/assets/{python-Dr7dCUjG.js → python-D4lCwSVr.js} +1 -1
- package/out/renderer/assets/{razor-a7zjD7Y3.js → razor-DdkE9XVt.js} +1 -1
- package/out/renderer/assets/{tsMode-B7KLV2X6.js → tsMode-BrQ4Fsc-.js} +1 -1
- package/out/renderer/assets/{typescript-Cjuzf37q.js → typescript-BakbYMnC.js} +1 -1
- package/out/renderer/assets/{xml-Yz9xINtk.js → xml-DHDW9Xhp.js} +1 -1
- package/out/renderer/assets/{yaml-DtKnp5J0.js → yaml-1Ayv_J3q.js} +1 -1
- package/out/renderer/index.html +2 -2
- package/package.json +1 -1
- package/src/main/agents.ts +36 -1
- package/src/main/headless.ts +5 -3
- package/src/main/index.ts +4 -2
- package/src/main/orchestrator.ts +29 -0
- package/src/main/workerWs.ts +8 -6
- package/src/preload/index.ts +7 -0
- package/src/renderer/App.tsx +19 -1
- package/src/renderer/styles.css +18 -0
package/out/headless/index.mjs
CHANGED
|
@@ -5471,7 +5471,7 @@ var require_package = __commonJS({
|
|
|
5471
5471
|
"package.json"(exports, module) {
|
|
5472
5472
|
module.exports = {
|
|
5473
5473
|
name: "@phenx-inc/ctlsurf",
|
|
5474
|
-
version: "0.3.
|
|
5474
|
+
version: "0.3.16",
|
|
5475
5475
|
description: "Agent-agnostic terminal and desktop app for ctlsurf \u2014 run Claude Code, Codex, or any coding agent with live session logging and remote control",
|
|
5476
5476
|
main: "out/main/index.js",
|
|
5477
5477
|
bin: {
|
|
@@ -5619,10 +5619,27 @@ var PtyManager = class {
|
|
|
5619
5619
|
};
|
|
5620
5620
|
|
|
5621
5621
|
// src/main/agents.ts
|
|
5622
|
+
import { accessSync, constants } from "fs";
|
|
5623
|
+
import { join, delimiter } from "path";
|
|
5622
5624
|
function getShellCommand() {
|
|
5623
5625
|
if (process.platform === "win32") return "powershell.exe";
|
|
5624
5626
|
return process.env.SHELL || "/bin/zsh";
|
|
5625
5627
|
}
|
|
5628
|
+
function isCommandAvailable(command) {
|
|
5629
|
+
const dirs = (process.env.PATH || "").split(delimiter).filter(Boolean);
|
|
5630
|
+
const isWin = process.platform === "win32";
|
|
5631
|
+
const exts = isWin ? (process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM").split(";").filter(Boolean) : [""];
|
|
5632
|
+
for (const dir of dirs) {
|
|
5633
|
+
for (const ext of exts) {
|
|
5634
|
+
try {
|
|
5635
|
+
accessSync(join(dir, command + ext), isWin ? constants.F_OK : constants.X_OK);
|
|
5636
|
+
return true;
|
|
5637
|
+
} catch {
|
|
5638
|
+
}
|
|
5639
|
+
}
|
|
5640
|
+
}
|
|
5641
|
+
return false;
|
|
5642
|
+
}
|
|
5626
5643
|
function getBuiltinAgents() {
|
|
5627
5644
|
return [
|
|
5628
5645
|
{
|
|
@@ -5649,6 +5666,12 @@ function getBuiltinAgents() {
|
|
|
5649
5666
|
}
|
|
5650
5667
|
];
|
|
5651
5668
|
}
|
|
5669
|
+
function getAvailableAgents() {
|
|
5670
|
+
const all = getBuiltinAgents();
|
|
5671
|
+
const coding = all.filter((a) => isCodingAgent(a) && isCommandAvailable(a.command));
|
|
5672
|
+
const shell = all.filter((a) => !isCodingAgent(a));
|
|
5673
|
+
return [...coding, ...shell];
|
|
5674
|
+
}
|
|
5652
5675
|
function isCodingAgent(agent) {
|
|
5653
5676
|
return agent.id !== "shell";
|
|
5654
5677
|
}
|
|
@@ -6087,11 +6110,9 @@ var WorkerWsClient = class {
|
|
|
6087
6110
|
workerId = null;
|
|
6088
6111
|
_status = "disconnected";
|
|
6089
6112
|
shouldReconnect = false;
|
|
6090
|
-
fingerprint;
|
|
6091
6113
|
constructor(events, baseUrl) {
|
|
6092
6114
|
this.events = events;
|
|
6093
6115
|
this.baseUrl = baseUrl || "wss://app.ctlsurf.com";
|
|
6094
|
-
this.fingerprint = this.generateFingerprint();
|
|
6095
6116
|
}
|
|
6096
6117
|
get status() {
|
|
6097
6118
|
return this._status;
|
|
@@ -6105,8 +6126,12 @@ var WorkerWsClient = class {
|
|
|
6105
6126
|
setBaseUrl(url) {
|
|
6106
6127
|
this.baseUrl = url;
|
|
6107
6128
|
}
|
|
6108
|
-
|
|
6109
|
-
|
|
6129
|
+
// Per-directory fingerprint: each working directory is a distinct worker, so
|
|
6130
|
+
// multiple instances on the same machine (one per project) don't collide as a
|
|
6131
|
+
// single worker server-side. cwd is included so the same folder maps to the
|
|
6132
|
+
// same worker across restarts.
|
|
6133
|
+
generateFingerprint(cwd) {
|
|
6134
|
+
const data = `${os.hostname()}:${os.userInfo().username}:${os.platform()}:${os.arch()}:${cwd}`;
|
|
6110
6135
|
return crypto.createHash("sha256").update(data).digest("hex").slice(0, 32);
|
|
6111
6136
|
}
|
|
6112
6137
|
setStatus(status) {
|
|
@@ -6116,7 +6141,8 @@ var WorkerWsClient = class {
|
|
|
6116
6141
|
}
|
|
6117
6142
|
}
|
|
6118
6143
|
connect(registration) {
|
|
6119
|
-
|
|
6144
|
+
const fingerprint = this.generateFingerprint(registration.cwd);
|
|
6145
|
+
this.registration = { ...registration, fingerprint };
|
|
6120
6146
|
this.shouldReconnect = true;
|
|
6121
6147
|
this.doConnect();
|
|
6122
6148
|
}
|
|
@@ -6857,6 +6883,7 @@ var Orchestrator = class {
|
|
|
6857
6883
|
};
|
|
6858
6884
|
noProjectPollTimer = null;
|
|
6859
6885
|
noProjectPollCwd = null;
|
|
6886
|
+
currentProjectName = null;
|
|
6860
6887
|
constructor(settingsDir, events) {
|
|
6861
6888
|
this.settingsDir = settingsDir;
|
|
6862
6889
|
this.events = events;
|
|
@@ -6881,12 +6908,14 @@ var Orchestrator = class {
|
|
|
6881
6908
|
log(`[worker-ws] Registered: worker_id=${data.worker_id}, folder_id=${data.folder_id}, status=${data.status}`);
|
|
6882
6909
|
events.onWorkerRegistered(data);
|
|
6883
6910
|
if (!data.folder_id) {
|
|
6911
|
+
this.setProjectName(null);
|
|
6884
6912
|
events.onWorkerStatus("no_project");
|
|
6885
6913
|
if (this.currentCwd && data.status !== "pending_approval") {
|
|
6886
6914
|
this.startNoProjectPolling(this.currentCwd);
|
|
6887
6915
|
}
|
|
6888
6916
|
} else {
|
|
6889
6917
|
this.stopNoProjectPolling();
|
|
6918
|
+
this.resolveProjectName(data.folder_id);
|
|
6890
6919
|
}
|
|
6891
6920
|
},
|
|
6892
6921
|
onTerminalInput: (data) => {
|
|
@@ -6921,6 +6950,26 @@ var Orchestrator = class {
|
|
|
6921
6950
|
get cwd() {
|
|
6922
6951
|
return this.currentCwd;
|
|
6923
6952
|
}
|
|
6953
|
+
// Name of the connected ctlsurf project (folder) for the desktop header.
|
|
6954
|
+
get projectName() {
|
|
6955
|
+
return this.currentProjectName;
|
|
6956
|
+
}
|
|
6957
|
+
setProjectName(name) {
|
|
6958
|
+
if (this.currentProjectName === name) return;
|
|
6959
|
+
this.currentProjectName = name;
|
|
6960
|
+
this.events.onProjectChanged?.(name);
|
|
6961
|
+
}
|
|
6962
|
+
// Resolve the connected folder's human-readable name. Best-effort: a failed
|
|
6963
|
+
// lookup just leaves the project name unset rather than blocking anything.
|
|
6964
|
+
async resolveProjectName(folderId) {
|
|
6965
|
+
try {
|
|
6966
|
+
const folder = await this.ctlsurfApi.getFolder(folderId);
|
|
6967
|
+
const name = folder?.name ?? folder?.title;
|
|
6968
|
+
this.setProjectName(typeof name === "string" && name ? name : null);
|
|
6969
|
+
} catch (err) {
|
|
6970
|
+
log(`[worker-ws] Failed to resolve project name for folder ${folderId}: ${err}`);
|
|
6971
|
+
}
|
|
6972
|
+
}
|
|
6924
6973
|
get agent() {
|
|
6925
6974
|
return this.currentAgent;
|
|
6926
6975
|
}
|
|
@@ -7711,7 +7760,7 @@ async function main() {
|
|
|
7711
7760
|
const settingsDir = getSettingsDir(false);
|
|
7712
7761
|
await checkVersionAndNotify();
|
|
7713
7762
|
const tui = new Tui();
|
|
7714
|
-
const agents =
|
|
7763
|
+
const agents = getAvailableAgents();
|
|
7715
7764
|
const orchestrator = new Orchestrator(settingsDir, {
|
|
7716
7765
|
onPtyData: (_tabId, data) => {
|
|
7717
7766
|
tui.writePtyData(data);
|
|
@@ -7740,7 +7789,7 @@ async function main() {
|
|
|
7740
7789
|
let agent;
|
|
7741
7790
|
let trackTimeOverride;
|
|
7742
7791
|
if (args.agent) {
|
|
7743
|
-
const found =
|
|
7792
|
+
const found = getBuiltinAgents().find((a) => a.id === args.agent);
|
|
7744
7793
|
agent = found || {
|
|
7745
7794
|
id: args.agent,
|
|
7746
7795
|
name: args.agent,
|