fellow-agents 0.0.22 → 0.0.28
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/config.js +2 -2
- package/dist/commands/start.js +3 -2
- package/dist/lib/preferences.js +34 -5
- package/package.json +1 -1
package/dist/commands/config.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readPreferences, writePreferences, lookupCli, preferencesFile, KNOWN_KEYS, } from "../lib/preferences.js";
|
|
1
|
+
import { readPreferences, writePreferences, lookupCli, preferencesFile, stripMatchedQuotes, KNOWN_KEYS, } from "../lib/preferences.js";
|
|
2
2
|
function printHelp() {
|
|
3
3
|
console.log(`fellow-agents config — read or write user preferences
|
|
4
4
|
|
|
@@ -75,7 +75,7 @@ function handleSet(args) {
|
|
|
75
75
|
process.exit(1);
|
|
76
76
|
}
|
|
77
77
|
const key = args[0];
|
|
78
|
-
const value = args.slice(1).join(" ");
|
|
78
|
+
const value = stripMatchedQuotes(args.slice(1).join(" ").trim()).trim();
|
|
79
79
|
if (!isKnownKey(key)) {
|
|
80
80
|
console.error(`Unknown key: ${key}`);
|
|
81
81
|
console.error(`Known keys: ${KNOWN_KEYS.join(", ")}`);
|
package/dist/commands/start.js
CHANGED
|
@@ -10,7 +10,7 @@ import { startEmcomServer, startPtyWin, stopAll, logPath } from "../lib/services
|
|
|
10
10
|
import { scaffoldWorkspaces, registerAgents, writeHooks } from "../lib/workspaces.js";
|
|
11
11
|
import { installSkills } from "../lib/skills.js";
|
|
12
12
|
import { binarySuffix } from "../lib/platform.js";
|
|
13
|
-
import { readPreferences, writePreferences, autoDetectClis, lookupCli, } from "../lib/preferences.js";
|
|
13
|
+
import { readPreferences, writePreferences, autoDetectClis, lookupCli, stripMatchedQuotes, } from "../lib/preferences.js";
|
|
14
14
|
// Minimal engines.node range check — handles ">=N", "<N", and combinations.
|
|
15
15
|
function nodeInRange(version, range) {
|
|
16
16
|
const major = parseInt(version.split(".")[0], 10);
|
|
@@ -63,7 +63,8 @@ async function promptForCliPreference() {
|
|
|
63
63
|
return detected[num - 1];
|
|
64
64
|
}
|
|
65
65
|
if (!isNaN(num) && num === customIdx) {
|
|
66
|
-
const
|
|
66
|
+
const raw = (await rl.question(" Enter command or full path: ")).trim();
|
|
67
|
+
const value = stripMatchedQuotes(raw).trim();
|
|
67
68
|
if (!value) {
|
|
68
69
|
console.log(" Empty input — skipped.");
|
|
69
70
|
return null;
|
package/dist/lib/preferences.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync, renameSync, mkdirSync, unlinkSync } from "fs";
|
|
2
2
|
import { join } from "path";
|
|
3
|
-
import {
|
|
3
|
+
import { execFileSync } from "child_process";
|
|
4
4
|
import { dataDir } from "./paths.js";
|
|
5
5
|
/** ~/.fellow-agents/preferences.json */
|
|
6
6
|
export const preferencesFile = join(dataDir, "preferences.json");
|
|
@@ -42,16 +42,39 @@ export function readPreferences() {
|
|
|
42
42
|
return null;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Strip a single pair of matched leading/trailing single or double quotes.
|
|
47
|
+
* Defensive helper for user inputs where a shell-style quoted value
|
|
48
|
+
* (`'agency cp'` or `"agency cp"`) gets typed literally — e.g. into a
|
|
49
|
+
* readline prompt or a config-set value after the outer shell has already
|
|
50
|
+
* consumed its own quote layer.
|
|
51
|
+
*
|
|
52
|
+
* Unmatched, mixed, or absent quotes pass through unchanged.
|
|
53
|
+
*/
|
|
54
|
+
export function stripMatchedQuotes(s) {
|
|
55
|
+
if (s.length < 2)
|
|
56
|
+
return s;
|
|
57
|
+
const first = s[0];
|
|
58
|
+
const last = s[s.length - 1];
|
|
59
|
+
if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
|
|
60
|
+
return s.slice(1, -1);
|
|
61
|
+
}
|
|
62
|
+
return s;
|
|
63
|
+
}
|
|
45
64
|
/**
|
|
46
65
|
* Write preferences atomically (temp + renameSync — atomic on Windows from Node 10+).
|
|
47
66
|
* Always stamps `updatedAt` to now and `updatedBy` to the supplied value.
|
|
48
67
|
* Ensures dataDir exists. Cleans up the temp file on failure.
|
|
68
|
+
*
|
|
69
|
+
* Preserves forward-compat keys from `prefs` that aren't in the current
|
|
70
|
+
* Preferences type — callers spreading an existing file with future schema:2
|
|
71
|
+
* fields can rely on those fields surviving a schema:1-aware writer.
|
|
49
72
|
*/
|
|
50
73
|
export function writePreferences(prefs) {
|
|
51
74
|
mkdirSync(dataDir, { recursive: true });
|
|
52
75
|
const next = {
|
|
76
|
+
...prefs,
|
|
53
77
|
schema: prefs.schema ?? CURRENT_SCHEMA,
|
|
54
|
-
cliPreference: prefs.cliPreference,
|
|
55
78
|
updatedAt: new Date().toISOString(),
|
|
56
79
|
updatedBy: prefs.updatedBy,
|
|
57
80
|
};
|
|
@@ -72,12 +95,18 @@ export function writePreferences(prefs) {
|
|
|
72
95
|
}
|
|
73
96
|
/**
|
|
74
97
|
* Look up a CLI on PATH. Returns the resolved full path (first hit), or null if not found.
|
|
75
|
-
* Uses `where.exe` on Windows and `which
|
|
98
|
+
* Uses `where.exe` on Windows and `which` on Unix. Never throws.
|
|
99
|
+
*
|
|
100
|
+
* Uses execFileSync with shell: false so user-controlled `name` values
|
|
101
|
+
* (e.g. a cliPreference set by config-set) cannot inject shell metacharacters.
|
|
102
|
+
* Values containing spaces or shell-special chars (`;`, `&`, `|`, `$`, etc.) are
|
|
103
|
+
* passed verbatim as a single argv to where.exe/which — which will simply not
|
|
104
|
+
* find a match and return null, rather than execute arbitrary commands.
|
|
76
105
|
*/
|
|
77
106
|
export function lookupCli(name) {
|
|
78
|
-
const
|
|
107
|
+
const bin = process.platform === "win32" ? "where.exe" : "which";
|
|
79
108
|
try {
|
|
80
|
-
const out =
|
|
109
|
+
const out = execFileSync(bin, [name], { stdio: ["ignore", "pipe", "ignore"] })
|
|
81
110
|
.toString()
|
|
82
111
|
.split(/\r?\n/)
|
|
83
112
|
.map((s) => s.trim())
|