fellow-agents 0.0.18 → 0.0.19
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/commands/start.js +13 -10
- package/dist/commands/uninstall.js +10 -4
- package/dist/lib/services.js +54 -0
- package/package.json +1 -1
package/dist/commands/start.js
CHANGED
|
@@ -97,17 +97,20 @@ export async function start(opts) {
|
|
|
97
97
|
// 5. Install AI skills (SKILL.md files) to known CLI paths
|
|
98
98
|
console.log("[5/8] Installing skills...");
|
|
99
99
|
const skillResult = installSkills();
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
const skillTotal = skillResult.written.length + skillResult.refreshed.length + skillResult.skipped.length;
|
|
101
|
+
if (skillTotal === 0) {
|
|
102
|
+
console.log(" No bundled skills");
|
|
102
103
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
104
|
+
else {
|
|
105
|
+
if (skillResult.written.length > 0) {
|
|
106
|
+
console.log(` Installed ${skillResult.written.length} skill file(s)`);
|
|
107
|
+
}
|
|
108
|
+
if (skillResult.refreshed.length > 0) {
|
|
109
|
+
console.log(` Refreshed ${skillResult.refreshed.length} skill file(s) to latest`);
|
|
110
|
+
}
|
|
111
|
+
if (skillResult.skipped.length > 0) {
|
|
112
|
+
console.log(` Preserved ${skillResult.skipped.length} existing skill file(s) — customized or unowned`);
|
|
113
|
+
}
|
|
111
114
|
}
|
|
112
115
|
// PATH trick: prepend bin dir so agents find emcom/tracker
|
|
113
116
|
const env = { ...process.env, PATH: `${binDir}${process.platform === "win32" ? ";" : ":"}${process.env.PATH}` };
|
|
@@ -86,11 +86,17 @@ export function uninstall(opts) {
|
|
|
86
86
|
// Remove skills we installed (only the ones that match the shipped bytes —
|
|
87
87
|
// user-customized files are preserved).
|
|
88
88
|
const skillResult = uninstallSkills();
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
const skillTotal = skillResult.removed.length + skillResult.preserved.length;
|
|
90
|
+
if (skillTotal === 0) {
|
|
91
|
+
console.log(" No fellow-agents-tracked skill files found");
|
|
91
92
|
}
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
else {
|
|
94
|
+
if (skillResult.removed.length > 0) {
|
|
95
|
+
console.log(` Removed ${skillResult.removed.length} skill file(s)`);
|
|
96
|
+
}
|
|
97
|
+
if (skillResult.preserved.length > 0) {
|
|
98
|
+
console.log(` Preserved ${skillResult.preserved.length} customized/unowned skill file(s)`);
|
|
99
|
+
}
|
|
94
100
|
}
|
|
95
101
|
for (const t of targets) {
|
|
96
102
|
try {
|
package/dist/lib/services.js
CHANGED
|
@@ -89,6 +89,52 @@ function killTree(pid) {
|
|
|
89
89
|
process.kill(pid);
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
+
// Scan a port for any listening PID and kill it. Used as a fallback when our
|
|
93
|
+
// PID files are missing (e.g., user ran clean) but a previous service is still
|
|
94
|
+
// holding the port — produces orphans that block re-start and re-uninstall.
|
|
95
|
+
function killOnPort(port) {
|
|
96
|
+
const killed = [];
|
|
97
|
+
try {
|
|
98
|
+
if (process.platform === "win32") {
|
|
99
|
+
const output = execSync(`netstat -ano -p tcp`, { stdio: ["ignore", "pipe", "ignore"] }).toString();
|
|
100
|
+
const pids = new Set();
|
|
101
|
+
for (const line of output.split("\n")) {
|
|
102
|
+
const trimmed = line.trim();
|
|
103
|
+
// Match "127.0.0.1:8800 ... LISTENING <pid>"
|
|
104
|
+
if (trimmed.includes(`:${port}`) && trimmed.includes("LISTENING")) {
|
|
105
|
+
const parts = trimmed.split(/\s+/);
|
|
106
|
+
const pid = parseInt(parts[parts.length - 1], 10);
|
|
107
|
+
if (!isNaN(pid) && pid > 4)
|
|
108
|
+
pids.add(pid); // skip system PIDs 0/4
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
for (const pid of pids) {
|
|
112
|
+
try {
|
|
113
|
+
execSync(`taskkill /F /T /PID ${pid}`, { stdio: "ignore" });
|
|
114
|
+
killed.push(pid);
|
|
115
|
+
}
|
|
116
|
+
catch { }
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
const output = execSync(`lsof -ti:${port}`, { stdio: ["ignore", "pipe", "ignore"] }).toString();
|
|
121
|
+
for (const line of output.split("\n")) {
|
|
122
|
+
const pid = parseInt(line.trim(), 10);
|
|
123
|
+
if (!isNaN(pid)) {
|
|
124
|
+
try {
|
|
125
|
+
process.kill(pid, "SIGKILL");
|
|
126
|
+
killed.push(pid);
|
|
127
|
+
}
|
|
128
|
+
catch { }
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// No output (no process listening) or command failed — return empty
|
|
135
|
+
}
|
|
136
|
+
return killed;
|
|
137
|
+
}
|
|
92
138
|
export function stopAll() {
|
|
93
139
|
for (const name of ["emcom-server", "pty-win"]) {
|
|
94
140
|
const pid = readPid(name);
|
|
@@ -106,6 +152,14 @@ export function stopAll() {
|
|
|
106
152
|
}
|
|
107
153
|
removePid(name);
|
|
108
154
|
}
|
|
155
|
+
// Fallback: scan default ports for orphans whose PID files have been lost.
|
|
156
|
+
// Common after `fellow-agents clean` or manual `Remove-Item` of pid/ dir.
|
|
157
|
+
for (const port of [3700, 8800]) {
|
|
158
|
+
const orphans = killOnPort(port);
|
|
159
|
+
if (orphans.length > 0) {
|
|
160
|
+
console.log(` Killed orphan(s) on :${port} (pid ${orphans.join(", ")})`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
109
163
|
}
|
|
110
164
|
export function waitForHealth(url, timeoutMs = 30000) {
|
|
111
165
|
const mod = url.startsWith("https") ? https : http;
|