sneakoscope 0.9.9 → 0.9.10
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/package.json +1 -1
- package/src/cli/install-helpers.mjs +10 -2
- package/src/cli/main.mjs +14 -5
- package/src/core/codex-app.mjs +59 -0
- package/src/core/fsx.mjs +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.10",
|
|
5
5
|
"description": "Sneakoscope Codex: database-safe Codex CLI/App harness with Team, Goal, AutoResearch, TriWiki, and Honest Mode.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
|
|
@@ -9,6 +9,7 @@ import { formatHarnessConflictReport, llmHarnessCleanupPrompt, scanHarnessConfli
|
|
|
9
9
|
import { initProject, installSkills } from '../core/init.mjs';
|
|
10
10
|
import { context7ConfigToml, DOLLAR_SKILL_NAMES, GETDESIGN_REFERENCE, hasContext7ConfigText, RECOMMENDED_SKILLS } from '../core/routes.mjs';
|
|
11
11
|
import { codexLaunchCommand, platformTmuxInstallHint, tmuxReadiness } from '../core/tmux-ui.mjs';
|
|
12
|
+
import { reconcileCodexAppUpgradeProcesses } from '../core/codex-app.mjs';
|
|
12
13
|
|
|
13
14
|
const DEFAULT_CODEX_APP_PLUGINS = [
|
|
14
15
|
['browser', 'openai-bundled'],
|
|
@@ -46,6 +47,11 @@ export async function postinstall({ bootstrap }) {
|
|
|
46
47
|
else if (fastModeRepair.status === 'present') console.log('Codex App Fast mode: config already compatible.');
|
|
47
48
|
else if (fastModeRepair.status === 'skipped') console.log(`Codex App Fast mode: skipped (${fastModeRepair.reason}).`);
|
|
48
49
|
else if (fastModeRepair.status === 'failed') console.log(`Codex App Fast mode: auto repair failed. Run \`sks setup\`. ${fastModeRepair.error || ''}`.trim());
|
|
50
|
+
const appProcessRepair = await reconcileCodexAppUpgradeProcesses();
|
|
51
|
+
if (appProcessRepair.status === 'repaired') console.log(`Codex App reconnect repair: stopped ${appProcessRepair.killed.length} stale orphan app-server process(es). Restart Codex App to reconnect cleanly.`);
|
|
52
|
+
else if (appProcessRepair.status === 'partial') console.log(`Codex App reconnect repair: stopped ${appProcessRepair.killed.length} stale orphan app-server process(es); ${appProcessRepair.failed.length} could not be stopped. Restart Codex App if reconnecting continues.`);
|
|
53
|
+
else if (appProcessRepair.status === 'skipped' && appProcessRepair.reason !== 'platform') console.log(`Codex App reconnect repair: skipped (${appProcessRepair.reason}).`);
|
|
54
|
+
else if (appProcessRepair.status === 'failed') console.log(`Codex App reconnect repair: skipped (${appProcessRepair.error || appProcessRepair.reason || 'process check failed'}).`);
|
|
49
55
|
const globalSkills = await ensureGlobalCodexSkillsDuringInstall();
|
|
50
56
|
if (globalSkills.status === 'installed') {
|
|
51
57
|
const removed = globalSkills.removed_stale_generated_skills || [];
|
|
@@ -1766,6 +1772,7 @@ function codexLbPostinstallEnv(baseEnv, overrides = {}) {
|
|
|
1766
1772
|
SKS_SKIP_POSTINSTALL_GLOBAL_SKILLS: '1',
|
|
1767
1773
|
SKS_SKIP_POSTINSTALL_CODEX_LB_AUTH: '0',
|
|
1768
1774
|
SKS_SKIP_CODEX_LB_LAUNCH_ENV: '1',
|
|
1775
|
+
SKS_SKIP_CODEX_APP_UPGRADE_REPAIR: '1',
|
|
1769
1776
|
...overrides
|
|
1770
1777
|
};
|
|
1771
1778
|
}
|
|
@@ -1838,7 +1845,7 @@ export async function selftestCodexLb(tmp) {
|
|
|
1838
1845
|
const codexLbPostinstallAuth = await safeReadText(path.join(codexLbHome, '.codex', 'auth.json'));
|
|
1839
1846
|
const codexLbLoginCallsAfterPostinstall = await codexLbLoginCallCount(codexLbHome);
|
|
1840
1847
|
if (!String(codexLbPostinstall.stdout || '').includes('codex-lb auth: preserved') || !codexLbPostinstallAuth.includes('"auth_mode":"browser"') || codexLbPostinstallAuth.includes('sk-test') || codexLbLoginCallsAfterPostinstall !== codexLbLoginCallsBeforePostinstall) throw new Error('selftest: postinstall auth');
|
|
1841
|
-
const postinstallEnvKeys = ['HOME', 'PATH', 'INIT_CWD', 'SKS_GLOBAL_ROOT', 'SKS_POSTINSTALL_BOOTSTRAP', 'SKS_POSTINSTALL_NO_BOOTSTRAP', 'SKS_SKIP_POSTINSTALL_SHIM', 'SKS_SKIP_POSTINSTALL_CONTEXT7', 'SKS_SKIP_POSTINSTALL_GETDESIGN', 'SKS_SKIP_POSTINSTALL_GLOBAL_SKILLS', 'SKS_SKIP_POSTINSTALL_CODEX_LB_AUTH', 'SKS_SKIP_CODEX_LB_LAUNCH_ENV', 'SKS_CODEX_LB_SYNC_CODEX_LOGIN'];
|
|
1848
|
+
const postinstallEnvKeys = ['HOME', 'PATH', 'INIT_CWD', 'SKS_GLOBAL_ROOT', 'SKS_POSTINSTALL_BOOTSTRAP', 'SKS_POSTINSTALL_NO_BOOTSTRAP', 'SKS_SKIP_POSTINSTALL_SHIM', 'SKS_SKIP_POSTINSTALL_CONTEXT7', 'SKS_SKIP_POSTINSTALL_GETDESIGN', 'SKS_SKIP_POSTINSTALL_GLOBAL_SKILLS', 'SKS_SKIP_POSTINSTALL_CODEX_LB_AUTH', 'SKS_SKIP_CODEX_LB_LAUNCH_ENV', 'SKS_SKIP_CODEX_APP_UPGRADE_REPAIR', 'SKS_CODEX_LB_SYNC_CODEX_LOGIN'];
|
|
1842
1849
|
const postinstallEnvBefore = Object.fromEntries(postinstallEnvKeys.map((key) => [key, process.env[key]]));
|
|
1843
1850
|
const codexLbLoginCallsBeforeBootstrap = await codexLbLoginCallCount(codexLbHome);
|
|
1844
1851
|
try {
|
|
@@ -1854,7 +1861,8 @@ export async function selftestCodexLb(tmp) {
|
|
|
1854
1861
|
SKS_SKIP_POSTINSTALL_GETDESIGN: '1',
|
|
1855
1862
|
SKS_SKIP_POSTINSTALL_GLOBAL_SKILLS: '1',
|
|
1856
1863
|
SKS_SKIP_POSTINSTALL_CODEX_LB_AUTH: '0',
|
|
1857
|
-
SKS_SKIP_CODEX_LB_LAUNCH_ENV: '1'
|
|
1864
|
+
SKS_SKIP_CODEX_LB_LAUNCH_ENV: '1',
|
|
1865
|
+
SKS_SKIP_CODEX_APP_UPGRADE_REPAIR: '1'
|
|
1858
1866
|
});
|
|
1859
1867
|
await postinstall({
|
|
1860
1868
|
bootstrap: async () => {
|
package/src/cli/main.mjs
CHANGED
|
@@ -73,7 +73,7 @@ import { MISTAKE_RECALL_ARTIFACT, contractConsumesMistakeRecall } from '../core/
|
|
|
73
73
|
import { buildPromptContext } from '../core/prompt-context-builder.mjs';
|
|
74
74
|
import { renderTeamDashboardState, writeTeamDashboardState } from '../core/team-dashboard-renderer.mjs';
|
|
75
75
|
import { GOAL_WORKFLOW_ARTIFACT } from '../core/goal-workflow.mjs';
|
|
76
|
-
import { CODEX_APP_DOCS_URL, codexAccessTokenStatus, codexAppIntegrationStatus, formatCodexAppStatus } from '../core/codex-app.mjs';
|
|
76
|
+
import { CODEX_APP_DOCS_URL, codexAccessTokenStatus, codexAppIntegrationStatus, findCodexAppUpgradeRepairTargets, formatCodexAppStatus, parseProcessRows } from '../core/codex-app.mjs';
|
|
77
77
|
import { buildAllFeaturesSelftest, buildFeatureRegistry, validateFeatureRegistry } from '../core/feature-registry.mjs';
|
|
78
78
|
import { codexAppRemoteControlCommand } from './codex-app-command.mjs';
|
|
79
79
|
import { allFeaturesCommand, featuresCommand, hooksCommand, hooksExplainReport } from './feature-commands.mjs';
|
|
@@ -2289,11 +2289,11 @@ async function selftest() {
|
|
|
2289
2289
|
await ensureDir(path.join(conflictTmp, '.omx'));
|
|
2290
2290
|
const conflictScan = await scanHarnessConflicts(conflictTmp, { home: path.join(conflictTmp, 'home') });
|
|
2291
2291
|
if (!conflictScan.hard_block || !formatHarnessConflictReport(conflictScan).includes('GPT-5.5')) throw new Error('selftest: OMX conflict did not block with cleanup prompt');
|
|
2292
|
-
const postinstallConflict = await runProcess(process.execPath, [path.join(packageRoot(), 'bin', 'sks.mjs'), 'postinstall'], { cwd: conflictTmp, env: { INIT_CWD: conflictTmp, HOME: path.join(conflictTmp, 'home'), SKS_SKIP_POSTINSTALL_SHIM: '1', SKS_SKIP_POSTINSTALL_CONTEXT7: '1', SKS_SKIP_POSTINSTALL_GETDESIGN: '1' }, timeoutMs: 15000, maxOutputBytes: 128 * 1024 });
|
|
2292
|
+
const postinstallConflict = await runProcess(process.execPath, [path.join(packageRoot(), 'bin', 'sks.mjs'), 'postinstall'], { cwd: conflictTmp, env: { INIT_CWD: conflictTmp, HOME: path.join(conflictTmp, 'home'), SKS_SKIP_POSTINSTALL_SHIM: '1', SKS_SKIP_POSTINSTALL_CONTEXT7: '1', SKS_SKIP_POSTINSTALL_GETDESIGN: '1', SKS_SKIP_CODEX_APP_UPGRADE_REPAIR: '1' }, timeoutMs: 15000, maxOutputBytes: 128 * 1024 });
|
|
2293
2293
|
if (postinstallConflict.code !== 0) throw new Error('selftest: postinstall conflict notice should not make npm install fail');
|
|
2294
2294
|
const postinstallConflictOutput = String(`${postinstallConflict.stdout}\n${postinstallConflict.stderr}`);
|
|
2295
2295
|
if (!postinstallConflictOutput.includes('SKS setup is blocked') || postinstallConflictOutput.includes('Cleanup prompt:')) throw new Error('selftest: postinstall conflict notice did not stay informational');
|
|
2296
|
-
const postinstallConflictPrompt = await runProcess(process.execPath, [path.join(packageRoot(), 'bin', 'sks.mjs'), 'postinstall'], { cwd: conflictTmp, input: 'y\n', env: { INIT_CWD: conflictTmp, HOME: path.join(conflictTmp, 'home'), SKS_SKIP_POSTINSTALL_SHIM: '1', SKS_SKIP_POSTINSTALL_CONTEXT7: '1', SKS_SKIP_POSTINSTALL_GETDESIGN: '1', SKS_POSTINSTALL_PROMPT: '1' }, timeoutMs: 15000, maxOutputBytes: 128 * 1024 });
|
|
2296
|
+
const postinstallConflictPrompt = await runProcess(process.execPath, [path.join(packageRoot(), 'bin', 'sks.mjs'), 'postinstall'], { cwd: conflictTmp, input: 'y\n', env: { INIT_CWD: conflictTmp, HOME: path.join(conflictTmp, 'home'), SKS_SKIP_POSTINSTALL_SHIM: '1', SKS_SKIP_POSTINSTALL_CONTEXT7: '1', SKS_SKIP_POSTINSTALL_GETDESIGN: '1', SKS_SKIP_CODEX_APP_UPGRADE_REPAIR: '1', SKS_POSTINSTALL_PROMPT: '1' }, timeoutMs: 15000, maxOutputBytes: 128 * 1024 });
|
|
2297
2297
|
if (postinstallConflictPrompt.code !== 0 || !String(postinstallConflictPrompt.stdout || '').includes('Goal: completely remove the conflicting Codex harnesses')) throw new Error('selftest: conflict prompt');
|
|
2298
2298
|
const postinstallSetupTmp = tmpdir();
|
|
2299
2299
|
await writeJsonAtomic(path.join(postinstallSetupTmp, 'package.json'), { name: 'postinstall-setup-smoke', version: '0.0.0' });
|
|
@@ -2303,7 +2303,7 @@ async function selftest() {
|
|
|
2303
2303
|
await ensureDir(path.join(postinstallSetupHome, '.agents', 'skills', name));
|
|
2304
2304
|
await writeTextAtomic(path.join(postinstallSetupHome, '.agents', 'skills', name, 'SKILL.md'), stalePluginSkillContent(name));
|
|
2305
2305
|
}
|
|
2306
|
-
const postinstallSetup = await runProcess(process.execPath, [path.join(packageRoot(), 'bin', 'sks.mjs'), 'postinstall'], { cwd: postinstallSetupTmp, env: { INIT_CWD: postinstallSetupTmp, HOME: path.join(postinstallSetupTmp, 'home'), SKS_SKIP_POSTINSTALL_SHIM: '1', SKS_SKIP_POSTINSTALL_CONTEXT7: '1', SKS_SKIP_POSTINSTALL_GETDESIGN: '1', SKS_SKIP_CLI_TOOLS: '1' }, timeoutMs: 30000, maxOutputBytes: 256 * 1024 });
|
|
2306
|
+
const postinstallSetup = await runProcess(process.execPath, [path.join(packageRoot(), 'bin', 'sks.mjs'), 'postinstall'], { cwd: postinstallSetupTmp, env: { INIT_CWD: postinstallSetupTmp, HOME: path.join(postinstallSetupTmp, 'home'), SKS_SKIP_POSTINSTALL_SHIM: '1', SKS_SKIP_POSTINSTALL_CONTEXT7: '1', SKS_SKIP_POSTINSTALL_GETDESIGN: '1', SKS_SKIP_CODEX_APP_UPGRADE_REPAIR: '1', SKS_SKIP_CLI_TOOLS: '1' }, timeoutMs: 30000, maxOutputBytes: 256 * 1024 });
|
|
2307
2307
|
if (postinstallSetup.code !== 0) throw new Error(`selftest: postinstall setup exited ${postinstallSetup.code}: ${postinstallSetup.stderr}`);
|
|
2308
2308
|
if (await exists(path.join(postinstallSetupTmp, '.agents', 'skills', 'agent-team', 'SKILL.md'))) throw new Error('selftest: postinstall installed deprecated agent-team fallback skill');
|
|
2309
2309
|
if (!String(postinstallSetup.stdout || '').includes('SKS bootstrap: auto-running sks setup --bootstrap --install-scope global --force') || !String(postinstallSetup.stdout || '').includes('SKS Ready')) throw new Error('selftest: postinstall bootstrap');
|
|
@@ -2341,7 +2341,7 @@ async function selftest() {
|
|
|
2341
2341
|
const postinstallNoMarkerCwd = path.join(postinstallNoMarkerTmp, 'cwd');
|
|
2342
2342
|
const postinstallNoMarkerGlobalRoot = path.join(postinstallNoMarkerTmp, 'global-root');
|
|
2343
2343
|
await ensureDir(postinstallNoMarkerCwd);
|
|
2344
|
-
const postinstallNoMarker = await runProcess(process.execPath, [path.join(packageRoot(), 'bin', 'sks.mjs'), 'postinstall'], { cwd: postinstallNoMarkerCwd, env: { INIT_CWD: postinstallNoMarkerCwd, HOME: postinstallNoMarkerHome, SKS_GLOBAL_ROOT: postinstallNoMarkerGlobalRoot, SKS_SKIP_POSTINSTALL_SHIM: '1', SKS_SKIP_POSTINSTALL_CONTEXT7: '1', SKS_SKIP_POSTINSTALL_GETDESIGN: '1', SKS_SKIP_CLI_TOOLS: '1' }, timeoutMs: 30000, maxOutputBytes: 256 * 1024 });
|
|
2344
|
+
const postinstallNoMarker = await runProcess(process.execPath, [path.join(packageRoot(), 'bin', 'sks.mjs'), 'postinstall'], { cwd: postinstallNoMarkerCwd, env: { INIT_CWD: postinstallNoMarkerCwd, HOME: postinstallNoMarkerHome, SKS_GLOBAL_ROOT: postinstallNoMarkerGlobalRoot, SKS_SKIP_POSTINSTALL_SHIM: '1', SKS_SKIP_POSTINSTALL_CONTEXT7: '1', SKS_SKIP_POSTINSTALL_GETDESIGN: '1', SKS_SKIP_CODEX_APP_UPGRADE_REPAIR: '1', SKS_SKIP_CLI_TOOLS: '1' }, timeoutMs: 30000, maxOutputBytes: 256 * 1024 });
|
|
2345
2345
|
if (postinstallNoMarker.code !== 0) throw new Error(`selftest: no-marker postinstall bootstrap exited ${postinstallNoMarker.code}: ${postinstallNoMarker.stderr}`);
|
|
2346
2346
|
if (!String(postinstallNoMarker.stdout || '').includes('no project marker found; auto-running global SKS runtime bootstrap')) throw new Error('selftest: no-marker bootstrap');
|
|
2347
2347
|
if (!(await exists(path.join(postinstallNoMarkerGlobalRoot, '.sneakoscope', 'manifest.json')))) throw new Error('selftest: no-marker postinstall did not bootstrap global runtime root');
|
|
@@ -3182,6 +3182,15 @@ async function selftest() {
|
|
|
3182
3182
|
const codexAppFixtureOpts = { codex: { bin: fakeCodex, version: 'codex-cli 99.0.0' }, home: appFeatureTmp, cwd: appFeatureTmp, env: { SKS_CODEX_APP_PATH: fakeCodexApp } };
|
|
3183
3183
|
const codexAppFeatureStatus = await codexAppIntegrationStatus(codexAppFixtureOpts);
|
|
3184
3184
|
if (!codexAppFeatureStatus.ok || !codexAppFeatureStatus.features?.required_flags_ok || !codexAppFeatureStatus.features?.codex_git_commit || !codexAppFeatureStatus.features?.remote_control || !codexAppFeatureStatus.features?.git_actions?.ok || !codexAppFeatureStatus.features?.fast_mode_config?.ok) throw new Error('selftest: codex-app check did not accept required app feature flags, git actions, remote_control, and unlocked Fast UI config');
|
|
3185
|
+
const codexAppProcessRows = parseProcessRows([
|
|
3186
|
+
'101 1 /Applications/Codex.app/Contents/Resources/codex app-server --analytics-default-enabled',
|
|
3187
|
+
'200 1 /Applications/Codex.app/Contents/MacOS/Codex',
|
|
3188
|
+
'201 200 /Applications/Codex.app/Contents/Resources/codex app-server --analytics-default-enabled',
|
|
3189
|
+
'202 1 /Applications/Codex.app/Contents/Resources/codex app-server --listen stdio://',
|
|
3190
|
+
'203 1 /Users/me/.nvm/versions/node/bin/codex --model gpt-5.5'
|
|
3191
|
+
].join('\n'));
|
|
3192
|
+
const codexAppRepairTargets = findCodexAppUpgradeRepairTargets(codexAppProcessRows);
|
|
3193
|
+
if (codexAppRepairTargets.length !== 1 || codexAppRepairTargets[0].pid !== 101) throw new Error('selftest: Codex App upgrade repair target selection is not limited to orphan desktop app-server processes');
|
|
3185
3194
|
const codexAppOldCliStatus = await codexAppIntegrationStatus({ codex: { bin: fakeCodex, version: 'codex-cli 0.129.0' }, home: appFeatureTmp, cwd: appFeatureTmp, env: { SKS_CODEX_APP_PATH: fakeCodexApp } });
|
|
3186
3195
|
if (codexAppOldCliStatus.ok || codexAppOldCliStatus.features?.git_actions?.ok || !codexAppOldCliStatus.guidance.some((line) => line.includes('git commit/push actions are blocked'))) throw new Error('selftest: codex-app check did not block commit/push actions on old Codex CLI remote-control');
|
|
3187
3196
|
const missingDefaultPluginTmp = tmpdir();
|
package/src/core/codex-app.mjs
CHANGED
|
@@ -238,6 +238,65 @@ export function codexSupportsRemoteControl(versionText) {
|
|
|
238
238
|
return Boolean(current && compareVersions(current, CODEX_REMOTE_CONTROL_MIN_VERSION) >= 0);
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
+
export function parseProcessRows(text = '') {
|
|
242
|
+
return String(text || '')
|
|
243
|
+
.split(/\r?\n/)
|
|
244
|
+
.map((line) => line.trim())
|
|
245
|
+
.filter(Boolean)
|
|
246
|
+
.map((line) => {
|
|
247
|
+
const match = line.match(/^(\d+)\s+(\d+)\s+(.+)$/);
|
|
248
|
+
if (!match) return null;
|
|
249
|
+
return {
|
|
250
|
+
pid: Number.parseInt(match[1], 10),
|
|
251
|
+
ppid: Number.parseInt(match[2], 10),
|
|
252
|
+
command: match[3]
|
|
253
|
+
};
|
|
254
|
+
})
|
|
255
|
+
.filter((row) => Number.isFinite(row?.pid) && Number.isFinite(row?.ppid) && row.command);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export function findCodexAppUpgradeRepairTargets(rows = []) {
|
|
259
|
+
return rows.filter((row) => (
|
|
260
|
+
row?.ppid === 1
|
|
261
|
+
&& /\/Codex\.app\/Contents\/Resources\/codex\s+app-server\s+--analytics-default-enabled(?:\s|$)/.test(String(row.command || ''))
|
|
262
|
+
));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export async function reconcileCodexAppUpgradeProcesses(opts = {}) {
|
|
266
|
+
const platform = opts.platform || process.platform;
|
|
267
|
+
const env = opts.env || process.env;
|
|
268
|
+
if (platform !== 'darwin') return { status: 'skipped', reason: 'platform', killed: [] };
|
|
269
|
+
if (env.SKS_SKIP_CODEX_APP_UPGRADE_REPAIR === '1') return { status: 'skipped', reason: 'SKS_SKIP_CODEX_APP_UPGRADE_REPAIR=1', killed: [] };
|
|
270
|
+
const run = opts.runProcess || runProcess;
|
|
271
|
+
const ps = await run('ps', ['-axo', 'pid=', '-o', 'ppid=', '-o', 'command='], {
|
|
272
|
+
timeoutMs: opts.timeoutMs || 5000,
|
|
273
|
+
maxOutputBytes: opts.maxOutputBytes || 256 * 1024
|
|
274
|
+
}).catch((err) => ({ code: 1, stdout: '', stderr: err.message }));
|
|
275
|
+
if (ps.code !== 0) return { status: 'failed', reason: 'ps_failed', error: ps.stderr || ps.stdout || 'ps exited non-zero', killed: [] };
|
|
276
|
+
const rows = parseProcessRows(ps.stdout);
|
|
277
|
+
const targets = findCodexAppUpgradeRepairTargets(rows);
|
|
278
|
+
const killed = [];
|
|
279
|
+
const failed = [];
|
|
280
|
+
for (const target of targets) {
|
|
281
|
+
if (opts.dryRun) {
|
|
282
|
+
killed.push({ pid: target.pid, command: target.command, dry_run: true });
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
const kill = await run('kill', ['-TERM', String(target.pid)], {
|
|
286
|
+
timeoutMs: opts.timeoutMs || 5000,
|
|
287
|
+
maxOutputBytes: 8 * 1024
|
|
288
|
+
}).catch((err) => ({ code: 1, stdout: '', stderr: err.message }));
|
|
289
|
+
if (kill.code === 0) killed.push({ pid: target.pid, command: target.command });
|
|
290
|
+
else failed.push({ pid: target.pid, command: target.command, error: kill.stderr || kill.stdout || 'kill exited non-zero' });
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
293
|
+
status: failed.length ? 'partial' : killed.length ? 'repaired' : 'clean',
|
|
294
|
+
killed,
|
|
295
|
+
failed,
|
|
296
|
+
checked: rows.length
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
241
300
|
export function formatCodexRemoteControlStatus(status) {
|
|
242
301
|
const lines = [
|
|
243
302
|
'Codex remote-control',
|
package/src/core/fsx.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import os from 'node:os';
|
|
|
5
5
|
import crypto from 'node:crypto';
|
|
6
6
|
import { spawn } from 'node:child_process';
|
|
7
7
|
|
|
8
|
-
export const PACKAGE_VERSION = '0.9.
|
|
8
|
+
export const PACKAGE_VERSION = '0.9.10';
|
|
9
9
|
export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
|
|
10
10
|
export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
|
|
11
11
|
|