@minhpnq1807/contextos 0.5.30 → 0.5.32
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.32
|
|
4
|
+
|
|
5
|
+
- **Fix Windows terminal hang during skillshare/ruler install:** `execSync` with `stdio: "pipe"` creates a stdin pipe whose write-end is held by Node while it blocks on `waitpid`. If the child process (PowerShell installer, npm, etc.) reads from stdin, it blocks waiting for data/EOF that never comes — classic deadlock. Fixed by normalizing `stdio: "pipe"` to `["ignore", "pipe", "pipe"]` in both `runCommand` and `runShell`. This routes stdin to NUL (`/dev/null`) for immediate EOF, while still capturing stdout/stderr through pipes for `◇`/`│` formatting.
|
|
6
|
+
|
|
7
|
+
## 0.5.31
|
|
8
|
+
|
|
9
|
+
- **Complete stdio audit — eliminate all output leakage:** Changed every remaining `stdio: "inherit"` in `skillshare-sync.js` and `ruler-sync.js` to `stdio: "pipe"`. When subprocess calls use `inherit`, child processes write directly to the parent's fd — bypassing both `console.log` and `process.stderr.write` interception in `captureSetupOutput`. With `pipe`, all subprocess output is captured as return values and re-emitted through `console.log`, ensuring the `◇`/`│` formatting is applied consistently. Also changed `runShell` default from `"inherit"` to `"pipe"` to prevent future regressions.
|
|
10
|
+
|
|
3
11
|
## 0.5.30
|
|
4
12
|
|
|
5
13
|
- **Fix Windows skillshare post-install hang:** After the PowerShell installer adds skillshare to PATH, the current Node.js process still has the old `process.env.PATH`. Now injects the known Windows install directory (`%LOCALAPPDATA%\\Programs\\skillshare`) into `process.env.PATH` immediately after install, so `skillshare --version`, `skillshare init`, and subsequent calls resolve without restarting the terminal.
|
package/package.json
CHANGED
|
@@ -22,9 +22,13 @@ function statusLine(label, value) {
|
|
|
22
22
|
return `[ctx] ${label.padEnd(38)} ${value}`;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
function normalizeStdio(stdio) {
|
|
26
|
+
return stdio === "pipe" ? ["ignore", "pipe", "pipe"] : stdio;
|
|
27
|
+
}
|
|
28
|
+
|
|
25
29
|
function runCommand(command, args, { cwd = process.cwd(), stdio = "pipe", dryRun = false } = {}) {
|
|
26
30
|
if (dryRun) return { stdout: "", skipped: true };
|
|
27
|
-
const stdout = execFileSync(command, args, { cwd, stdio, encoding: "utf8", shell: true });
|
|
31
|
+
const stdout = execFileSync(command, args, { cwd, stdio: normalizeStdio(stdio), encoding: "utf8", shell: true });
|
|
28
32
|
return { stdout: stdout || "" };
|
|
29
33
|
}
|
|
30
34
|
|
|
@@ -94,13 +98,13 @@ export async function installRuler({ run = runCommand, yes = false, dryRun = fal
|
|
|
94
98
|
if (!accepted) {
|
|
95
99
|
throw new Error("Ruler is required for ctx sync --rules. Install it with `npm install -g @intellectronica/ruler` or rerun with --yes.");
|
|
96
100
|
}
|
|
97
|
-
run("npm", ["install", "-g", "@intellectronica/ruler"], { stdio: "
|
|
101
|
+
run("npm", ["install", "-g", "@intellectronica/ruler"], { stdio: "pipe", dryRun });
|
|
98
102
|
}
|
|
99
103
|
|
|
100
104
|
export function ensureRulerInit({ cwd = process.cwd(), run = runCommand, dryRun = false } = {}) {
|
|
101
105
|
const tomlPath = rulerTomlPath(cwd);
|
|
102
106
|
if (fs.existsSync(tomlPath)) return { created: false, tomlPath };
|
|
103
|
-
run("ruler", ["init"], { cwd, stdio: "
|
|
107
|
+
run("ruler", ["init"], { cwd, stdio: "pipe", dryRun });
|
|
104
108
|
return { created: true, tomlPath };
|
|
105
109
|
}
|
|
106
110
|
|
|
@@ -444,7 +448,7 @@ export function injectCtxMcp({ tomlPath, mcpServerPath, agents = DEFAULT_AGENTS,
|
|
|
444
448
|
}
|
|
445
449
|
|
|
446
450
|
export function runRulerApply({ agents = DEFAULT_AGENTS, cwd = process.cwd(), run = runCommand, dryRun = false } = {}) {
|
|
447
|
-
run("ruler", ["apply", "--agents", normalizeAgentList(agents).join(",")], { cwd, stdio: "
|
|
451
|
+
run("ruler", ["apply", "--agents", normalizeAgentList(agents).join(",")], { cwd, stdio: "pipe", dryRun });
|
|
448
452
|
}
|
|
449
453
|
|
|
450
454
|
function fileContains(filePath, pattern) {
|
|
@@ -19,15 +19,23 @@ function statusLine(label, value) {
|
|
|
19
19
|
return `[ctx] ${label.padEnd(38)} ${value}`;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
function normalizeStdio(stdio) {
|
|
23
|
+
// "pipe" creates a stdin pipe whose write-end is held by Node while
|
|
24
|
+
// execSync/execFileSync blocks on waitpid — if the child reads stdin
|
|
25
|
+
// it deadlocks. Route stdin to NUL (/dev/null) so the child sees
|
|
26
|
+
// immediate EOF, while still piping stdout/stderr for capture.
|
|
27
|
+
return stdio === "pipe" ? ["ignore", "pipe", "pipe"] : stdio;
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
function runCommand(command, args = [], { cwd = process.cwd(), stdio = "pipe", dryRun = false } = {}) {
|
|
23
31
|
if (dryRun) return { stdout: "", skipped: true };
|
|
24
|
-
const stdout = execFileSync(command, args, { cwd, stdio, encoding: "utf8", shell: true });
|
|
32
|
+
const stdout = execFileSync(command, args, { cwd, stdio: normalizeStdio(stdio), encoding: "utf8", shell: true });
|
|
25
33
|
return { stdout: stdout || "" };
|
|
26
34
|
}
|
|
27
35
|
|
|
28
|
-
function runShell(command, { cwd = process.cwd(), stdio = "
|
|
36
|
+
function runShell(command, { cwd = process.cwd(), stdio = "pipe", dryRun = false } = {}) {
|
|
29
37
|
if (dryRun) return { stdout: "", skipped: true };
|
|
30
|
-
const stdout = execSync(command, { cwd, stdio, encoding: "utf8" });
|
|
38
|
+
const stdout = execSync(command, { cwd, stdio: normalizeStdio(stdio), encoding: "utf8" });
|
|
31
39
|
return { stdout: stdout || "" };
|
|
32
40
|
}
|
|
33
41
|
|
|
@@ -120,7 +128,7 @@ export async function installSkillshare({
|
|
|
120
128
|
|
|
121
129
|
const osName = detectOS(platform);
|
|
122
130
|
if (osName === "windows") {
|
|
123
|
-
runShellCommand(`powershell -NoProfile -ExecutionPolicy Bypass -Command "irm ${INSTALL_PS_URL} | iex"`, { stdio: "
|
|
131
|
+
runShellCommand(`powershell -NoProfile -ExecutionPolicy Bypass -Command "irm ${INSTALL_PS_URL} | iex"`, { stdio: "pipe", dryRun });
|
|
124
132
|
// The installer adds to the system PATH, but the current Node process
|
|
125
133
|
// still has the old PATH. Inject the known install dir so subsequent
|
|
126
134
|
// skillshare calls in this session can resolve the binary.
|
|
@@ -129,7 +137,7 @@ export async function installSkillshare({
|
|
|
129
137
|
process.env.PATH = `${winInstallDir}${path.delimiter}${process.env.PATH}`;
|
|
130
138
|
}
|
|
131
139
|
} else {
|
|
132
|
-
runShellCommand(`curl -fsSL ${INSTALL_SH_URL} | sh`, { stdio: "
|
|
140
|
+
runShellCommand(`curl -fsSL ${INSTALL_SH_URL} | sh`, { stdio: "pipe", dryRun });
|
|
133
141
|
}
|
|
134
142
|
|
|
135
143
|
const check = checkSkillshareInstalled({ run });
|
|
@@ -352,13 +360,13 @@ export async function syncSkills({
|
|
|
352
360
|
logger("[ctx] No existing skills found.");
|
|
353
361
|
}
|
|
354
362
|
|
|
355
|
-
run("skillshare", ["init"], { cwd, stdio: "
|
|
363
|
+
run("skillshare", ["init"], { cwd, stdio: "pipe", dryRun: options.dryRun });
|
|
356
364
|
logger(statusLine("Initializing skillshare...", options.dryRun ? "dry-run" : "✓ initialized"));
|
|
357
365
|
|
|
358
366
|
if (existing.length && !options.noCollect) {
|
|
359
|
-
run("skillshare", ["backup"], { cwd, stdio: "
|
|
367
|
+
run("skillshare", ["backup"], { cwd, stdio: "pipe", dryRun: options.dryRun });
|
|
360
368
|
logger(statusLine("Backing up...", options.dryRun ? "dry-run" : "✓ backup created"));
|
|
361
|
-
run("skillshare", ["collect", "--all"], { cwd, stdio: "
|
|
369
|
+
run("skillshare", ["collect", "--all"], { cwd, stdio: "pipe", dryRun: options.dryRun });
|
|
362
370
|
const collected = countSkillFiles(skillshareSourceDir({ home }));
|
|
363
371
|
logger(statusLine("Collecting from all agents...", options.dryRun ? "dry-run" : `✓ ${collected} skills collected`));
|
|
364
372
|
}
|