sneakoscope 8.2.1 → 8.3.1
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/README.md +50 -112
- package/config/skills-hash-ledger.v1.json +3 -0
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/cli/command-manifest-lite.js +0 -2
- package/dist/cli/command-registry.js +0 -2
- package/dist/commands/codex.js +3 -3
- package/dist/commands/doctor.js +5 -157
- package/dist/config/skills-manifest.json +7 -4
- package/dist/core/codex/codex-cli-syntax-builder.js +0 -8
- package/dist/core/codex-app/codex-models-cache.js +2 -1
- package/dist/core/codex-app/menubar/config.js +4 -4
- package/dist/core/codex-app/menubar/constants.js +2 -9
- package/dist/core/codex-app/menubar/global-install.js +16 -0
- package/dist/core/codex-app/menubar/installer.js +15 -2
- package/dist/core/codex-app/menubar/launch-agent.js +23 -9
- package/dist/core/codex-app/menubar/rollback.js +12 -2
- package/dist/core/codex-compat/codex-capability-matrix.js +7 -7
- package/dist/core/codex-compat/codex-compat-report.js +8 -12
- package/dist/core/codex-compat/codex-runtime-contract.js +62 -0
- package/dist/core/codex-compat/codex-version-policy.js +7 -7
- package/dist/core/codex-control/codex-current-app-capability.js +3 -3
- package/dist/core/codex-control/codex-current-capability.js +67 -94
- package/dist/core/codex-control/codex-current-core-capability.js +3 -3
- package/dist/core/codex-control/codex-current-core-probe-runner.js +4 -4
- package/dist/core/codex-control/codex-current-core-real-probes.js +2 -2
- package/dist/core/codex-control/codex-current-feature-capability.js +4 -4
- package/dist/core/codex-control/codex-current-image-path-real-probe.js +1 -1
- package/dist/core/codex-control/codex-current-web-search-probe.js +1 -1
- package/dist/core/codex-control/codex-sdk-capability.js +2 -2
- package/dist/core/codex-lb/combined-catalog/normalize.js +36 -3
- package/dist/core/codex-lb/desktop-bridge/header-policy.js +5 -3
- package/dist/core/codex-lb/desktop-bridge/http-forward.js +48 -3
- package/dist/core/codex-lb/desktop-bridge/server.js +13 -7
- package/dist/core/codex-lb/desktop-bridge-migration/historical-config.js +2 -1
- package/dist/core/codex-lb/desktop-bridge-migration/retired-runtime-cleanup.js +46 -8
- package/dist/core/codex-lb/desktop-controller-v3/lifecycle-commands.js +12 -2
- package/dist/core/codex-lb/desktop-controller-v3/live-probes.js +34 -8
- package/dist/core/codex-lb/desktop-controller-v3/preflight-probes.js +13 -4
- package/dist/core/codex-lb/desktop-controller-v3/shared.js +2 -1
- package/dist/core/codex-lb/desktop-controller-v3/verification.js +10 -9
- package/dist/core/codex-lb/desktop-service.js +57 -4
- package/dist/core/codex-lb/route-index.js +1 -0
- package/dist/core/commands/remote-command.js +2 -2
- package/dist/core/context7-client.js +5 -2
- package/dist/core/doctor/codex-current-core-probe-doctor.js +2 -2
- package/dist/core/doctor/doctor-dirty-planner.js +1 -1
- package/dist/core/doctor/doctor-readiness-matrix.js +0 -7
- package/dist/core/feature-fixtures.js +0 -4
- package/dist/core/feature-registry.js +0 -1
- package/dist/core/image-ux-review.js +3 -3
- package/dist/core/install/installed-package-smoke.js +2 -3
- package/dist/core/mad-sks/sql-plane/mcp-executor.js +4 -3
- package/dist/core/managed-assets/managed-assets-manifest.js +1 -0
- package/dist/core/mcp/modern-protocol.js +36 -0
- package/dist/core/mcp-config/health-check.js +45 -30
- package/dist/core/perf/release-latency-slo.js +1 -2
- package/dist/core/proof/runtime-truth-matrix.js +1 -1
- package/dist/core/release/canonical-test-proof.js +9 -3
- package/dist/core/release/gate-manifest.js +1 -2
- package/dist/core/release/physical-release-gates.js +0 -26
- package/dist/core/release/release-gate-affected-selector.js +0 -1
- package/dist/core/release/release-gate-contract.js +1 -1
- package/dist/core/release/release-pack-receipt.js +0 -1
- package/dist/core/release/stage-publish.js +1 -1
- package/dist/core/routes/evidence.js +1 -1
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/AppDelegate.swift +1 -12
- package/dist/native/sks-menubar/Sources/CodexLifecyclePolicy.swift +18 -0
- package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +2 -6
- package/dist/native/sks-menubar/Sources/ProcessClient.swift +3 -1
- package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +86 -2
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +49 -15
- package/dist/native/sks-menubar/Sources/RemoteCodingViewController.swift +28 -470
- package/dist/native/sks-menubar/Sources/SKSKeychainStore.swift +21 -1
- package/dist/native/sks-menubar/Sources/SecureProcessEnvelope.swift +1 -43
- package/dist/native/sks-menubar/Sources/SettingsViewController.swift +18 -17
- package/dist/native/sks-menubar/Sources/StatusItemController.swift +14 -14
- package/dist/scripts/canonical-test-runner.js +83 -3
- package/dist/scripts/codex-current-app-server-v2-check.js +9 -8
- package/dist/scripts/codex-current-binary-identity-check.js +2 -2
- package/dist/scripts/codex-current-capability-check.js +9 -7
- package/dist/scripts/codex-current-dependency-check.js +21 -0
- package/dist/scripts/docs-truthfulness-check.js +4 -19
- package/dist/scripts/fast-codex-service-tier-proof-check.js +0 -1
- package/dist/scripts/latest-version-guidance-check.js +1 -1
- package/dist/scripts/packlist-performance-check.js +0 -1
- package/dist/scripts/release-metadata-check.js +1 -1
- package/dist/vendor/openai-codex/latest/hooks/permission-request.command.input.schema.json +6 -0
- package/dist/vendor/openai-codex/latest/hooks/permission-request.command.output.schema.json +2 -16
- package/dist/vendor/openai-codex/latest/hooks/post-compact.command.input.schema.json +6 -0
- package/dist/vendor/openai-codex/latest/hooks/post-tool-use.command.input.schema.json +6 -0
- package/dist/vendor/openai-codex/latest/hooks/post-tool-use.command.output.schema.json +2 -16
- package/dist/vendor/openai-codex/latest/hooks/pre-compact.command.input.schema.json +6 -0
- package/dist/vendor/openai-codex/latest/hooks/pre-tool-use.command.input.schema.json +6 -0
- package/dist/vendor/openai-codex/latest/hooks/pre-tool-use.command.output.schema.json +2 -16
- package/dist/vendor/openai-codex/latest/hooks/session-start.command.output.schema.json +2 -16
- package/dist/vendor/openai-codex/latest/hooks/snapshot-metadata.json +7 -5
- package/dist/vendor/openai-codex/latest/hooks/subagent-start.command.output.schema.json +4 -18
- package/dist/vendor/openai-codex/latest/hooks/user-prompt-submit.command.input.schema.json +6 -0
- package/dist/vendor/openai-codex/latest/hooks/user-prompt-submit.command.output.schema.json +2 -16
- package/package.json +3 -7
- package/release-gates.v2.json +10 -17
- package/config/codex-releases/rust-v0.146.0.json +0 -45
- package/dist/core/agents/agent-runner-codex-exec.js +0 -177
- package/dist/core/codex-compat/codex-release-manifest.js +0 -72
- package/dist/core/commands/telegram-command.js +0 -447
- package/dist/core/telegram/access.js +0 -58
- package/dist/core/telegram/client.js +0 -157
- package/dist/core/telegram/confirmation.js +0 -37
- package/dist/core/telegram/doctor.js +0 -159
- package/dist/core/telegram/index.js +0 -9
- package/dist/core/telegram/keychain.js +0 -317
- package/dist/core/telegram/liveness.js +0 -124
- package/dist/core/telegram/poller.js +0 -90
- package/dist/core/telegram/redaction.js +0 -15
- package/dist/core/telegram/state-lock.js +0 -416
- package/dist/core/telegram/types.js +0 -1
- package/dist/native/sks-menubar/Sources/RemoteCodingSettingsControls.swift +0 -160
- package/dist/native/sks-menubar/Sources/TelegramPrivateFileStore.swift +0 -498
- package/dist/native/sks-menubar/Sources/TelegramPrivateFileSupport.swift +0 -236
- package/dist/native/sks-menubar/Sources/TelegramProcessGateway.swift +0 -454
- package/dist/native/sks-menubar/Sources/TelegramRuntimeSupport.swift +0 -56
- package/dist/native/sks-menubar/Sources/TelegramStateLock.swift +0 -448
- package/dist/native/sks-menubar/Sources/TelegramSupport.swift +0 -244
- package/dist/native/sks-menubar/Sources/TelegramTransport.swift +0 -499
- package/dist/scripts/codex-current-manifest-check.js +0 -29
- package/schemas/codex/app-server-0.146/codex_app_server_protocol.v2.schemas.json +0 -19858
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
export function buildCodexExecArgs(opts) {
|
|
2
|
-
if (opts.fullAuto && opts.danger) {
|
|
3
|
-
throw new Error('codex exec cannot combine full auto and danger modes');
|
|
4
|
-
}
|
|
5
2
|
if (opts.danger && !opts.allowDanger) {
|
|
6
3
|
throw new Error('codex exec danger mode requires explicit allowDanger=true');
|
|
7
4
|
}
|
|
8
|
-
if (opts.fullAuto && !opts.allowFullAuto) {
|
|
9
|
-
throw new Error('codex exec full-auto mode requires explicit allowFullAuto=true');
|
|
10
|
-
}
|
|
11
5
|
if (opts.profile && opts.ignoreUserConfig) {
|
|
12
6
|
throw new Error('codex exec cannot combine --profile with --ignore-user-config');
|
|
13
7
|
}
|
|
@@ -30,8 +24,6 @@ export function buildCodexExecArgs(opts) {
|
|
|
30
24
|
args.push('--ignore-user-config');
|
|
31
25
|
if (opts.ignoreRules)
|
|
32
26
|
args.push('--ignore-rules');
|
|
33
|
-
if (opts.fullAuto)
|
|
34
|
-
args.push('--full-auto');
|
|
35
27
|
if (opts.danger)
|
|
36
28
|
args.push('--dangerously-bypass-approvals-and-sandbox');
|
|
37
29
|
else if (opts.sandbox)
|
|
@@ -2,6 +2,7 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { writeTextAtomic } from '../fsx.js';
|
|
4
4
|
import { codexHomePath } from './codex-model-catalog.js';
|
|
5
|
+
import { CURRENT_CODEX_RUNTIME_CONTRACT } from '../codex-compat/codex-runtime-contract.js';
|
|
5
6
|
export const CODEX_MODELS_CACHE_STALE_FETCHED_AT = '2000-01-01T00:00:00Z';
|
|
6
7
|
export const CODEX_MODELS_CACHE_FILENAME = 'models_cache.json';
|
|
7
8
|
export function codexModelsCachePath(input = {}) {
|
|
@@ -116,7 +117,7 @@ export async function invalidateCodexModelsCache(input = {}) {
|
|
|
116
117
|
const existingClient = typeof existing?.client_version === 'string' ? existing.client_version.trim() : '';
|
|
117
118
|
const clientVersion = existingClient && existingClient !== '0.0.0'
|
|
118
119
|
? existingClient
|
|
119
|
-
:
|
|
120
|
+
: CURRENT_CODEX_RUNTIME_CONTRACT.requiredCliVersion;
|
|
120
121
|
const wrapper = {
|
|
121
122
|
fetched_at: CODEX_MODELS_CACHE_STALE_FETCHED_AT,
|
|
122
123
|
client_version: clientVersion,
|
|
@@ -4,18 +4,18 @@ import { readJson, runProcess, which, writeJsonAtomic } from '../../fsx.js';
|
|
|
4
4
|
export async function readMenuBarConfig(configPath) {
|
|
5
5
|
const value = await readJson(configPath, null);
|
|
6
6
|
return {
|
|
7
|
-
schema: 'sks.sks-menubar-config.
|
|
7
|
+
schema: 'sks.sks-menubar-config.v2',
|
|
8
8
|
codex_bundle_id: typeof value?.codex_bundle_id === 'string' && value.codex_bundle_id.trim()
|
|
9
9
|
? value.codex_bundle_id.trim() : null,
|
|
10
|
-
|
|
10
|
+
follow_codex_lifecycle: value?.follow_codex_lifecycle === true || value?.quit_with_codex === true
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
13
|
export async function writeDefaultMenuBarConfig(configPath, codexBundleId) {
|
|
14
14
|
const previous = await readMenuBarConfig(configPath);
|
|
15
15
|
const value = {
|
|
16
|
-
schema: 'sks.sks-menubar-config.
|
|
16
|
+
schema: 'sks.sks-menubar-config.v2',
|
|
17
17
|
codex_bundle_id: codexBundleId || previous.codex_bundle_id,
|
|
18
|
-
|
|
18
|
+
follow_codex_lifecycle: previous.follow_codex_lifecycle
|
|
19
19
|
};
|
|
20
20
|
await writeJsonAtomic(configPath, value);
|
|
21
21
|
return value;
|
|
@@ -6,12 +6,13 @@ export const MENU_ITEMS = [
|
|
|
6
6
|
'Pending approvals',
|
|
7
7
|
'Check for Updates',
|
|
8
8
|
'View Last Operation',
|
|
9
|
-
'
|
|
9
|
+
'Hide Until Codex Opens'
|
|
10
10
|
];
|
|
11
11
|
export const NATIVE_SOURCE_FILES = [
|
|
12
12
|
'main.swift',
|
|
13
13
|
'AppDelegate.swift',
|
|
14
14
|
'StatusItemController.swift',
|
|
15
|
+
'CodexLifecyclePolicy.swift',
|
|
15
16
|
'ControlCenterWindowController.swift',
|
|
16
17
|
'SidebarItem.swift',
|
|
17
18
|
'ControlKit.swift',
|
|
@@ -25,7 +26,6 @@ export const NATIVE_SOURCE_FILES = [
|
|
|
25
26
|
'ProvidersOpenRouter.swift',
|
|
26
27
|
'ProvidersBridgeCatalog.swift',
|
|
27
28
|
'RemoteCodingViewController.swift',
|
|
28
|
-
'RemoteCodingSettingsControls.swift',
|
|
29
29
|
'DiagnosticsViewController.swift',
|
|
30
30
|
'SettingsViewController.swift',
|
|
31
31
|
'OperationModels.swift',
|
|
@@ -36,13 +36,6 @@ export const NATIVE_SOURCE_FILES = [
|
|
|
36
36
|
'ProcessIdentityGuard.swift',
|
|
37
37
|
'SecureProcessEnvelope.swift',
|
|
38
38
|
'SKSKeychainStore.swift',
|
|
39
|
-
'TelegramStateLock.swift',
|
|
40
|
-
'TelegramPrivateFileSupport.swift',
|
|
41
|
-
'TelegramPrivateFileStore.swift',
|
|
42
|
-
'TelegramSupport.swift',
|
|
43
|
-
'TelegramRuntimeSupport.swift',
|
|
44
|
-
'TelegramTransport.swift',
|
|
45
|
-
'TelegramProcessGateway.swift',
|
|
46
39
|
'NotificationCoordinator.swift',
|
|
47
40
|
'AlertFactory.swift',
|
|
48
41
|
'AppIdentity.swift',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { exists, nowIso, readJson, readText, runProcess, writeJsonAtomic } from '../../fsx.js';
|
|
3
3
|
import { ensureConfinedDirectory, inspectConfinedPath, removeManagedPathVerified } from '../../managed-path-safety.js';
|
|
4
|
+
import { realUserHome } from './installer/runtime.js';
|
|
4
5
|
const MENU_BAR_EXECUTABLE_SUFFIX = path.join('SKSMenuBar.app', 'Contents', 'MacOS', 'SKSMenuBar');
|
|
5
6
|
const MENU_BAR_PROCESS_DISCOVERY_TIMEOUT_MS = 5_000;
|
|
6
7
|
export function projectMenuBarDuplicateInstallDirs(input) {
|
|
@@ -21,6 +22,8 @@ export async function verifiedProjectMenuBarDuplicateExecutablePaths(input) {
|
|
|
21
22
|
const executables = [];
|
|
22
23
|
const candidates = await discoverProjectMenuBarDuplicateCandidates(input);
|
|
23
24
|
for (const candidate of candidates.inspected) {
|
|
25
|
+
if (isOutsideScopeReapingRefused(candidate, root, home))
|
|
26
|
+
continue;
|
|
24
27
|
const confinementRoot = confinementRootForCandidate(root, home, candidate);
|
|
25
28
|
const state = await inspectConfinedPath(confinementRoot, candidate).catch(() => null);
|
|
26
29
|
if (!state?.exists || state.leafSymlink || !state.stat?.isDirectory())
|
|
@@ -96,6 +99,11 @@ export async function cleanupProjectMenuBarDuplicates(input) {
|
|
|
96
99
|
const blockers = [];
|
|
97
100
|
const warnings = [];
|
|
98
101
|
for (const candidate of inspected) {
|
|
102
|
+
if (isOutsideScopeReapingRefused(candidate, root, input.paths.home)) {
|
|
103
|
+
preserved.push(candidate);
|
|
104
|
+
warnings.push(`menubar_project_duplicate_outside_scope_preserved:${candidate}`);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
99
107
|
const confinementRoot = confinementRootForCandidate(root, input.paths.home, candidate);
|
|
100
108
|
const state = await inspectConfinedPath(confinementRoot, candidate).catch(() => null);
|
|
101
109
|
if (!state) {
|
|
@@ -254,6 +262,14 @@ function duplicateInstallDirForExecutable(executablePath, canonicalInstallDir) {
|
|
|
254
262
|
return null;
|
|
255
263
|
return executable.slice(0, -suffix.length);
|
|
256
264
|
}
|
|
265
|
+
function isOutsideScopeReapingRefused(candidateInput, rootInput, homeInput) {
|
|
266
|
+
const candidate = path.resolve(candidateInput);
|
|
267
|
+
const root = path.resolve(rootInput);
|
|
268
|
+
const home = path.resolve(homeInput);
|
|
269
|
+
if (isWithin(root, candidate) || isWithin(home, candidate))
|
|
270
|
+
return false;
|
|
271
|
+
return home !== realUserHome();
|
|
272
|
+
}
|
|
257
273
|
function confinementRootForCandidate(rootInput, homeInput, candidate) {
|
|
258
274
|
const root = path.resolve(rootInput);
|
|
259
275
|
const home = path.resolve(homeInput);
|
|
@@ -6,7 +6,7 @@ import { aggregateFileHashes, createSksMenuBarBuildStamp, menuBarBuildStampsEqua
|
|
|
6
6
|
import { SKS_MENUBAR_LABEL } from './constants.js';
|
|
7
7
|
import { resolveCodexBundleId, writeDefaultMenuBarConfig } from './config.js';
|
|
8
8
|
import { applyMenuBarGenerationTransaction, commitMenuBarGenerationTransaction, installGenerationPairs, MenuBarGenerationTransactionError, recoverMenuBarGenerationTransaction, rollbackGenerationPairs } from './generation-transaction.js';
|
|
9
|
-
import { launchAgentSource, launchMenuBar, inspectRunningMenuBarProcess, seedMenuBarPreferredPosition, stopMenuBarForReplacement, terminateMenuBarProcesses } from './launch-agent.js';
|
|
9
|
+
import { launchAgentSource, launchMenuBar, inspectRunningMenuBarProcess, menuBarLaunchdTouchAllowed, seedMenuBarPreferredPosition, stopMenuBarForReplacement, terminateMenuBarProcesses } from './launch-agent.js';
|
|
10
10
|
import { cleanupProjectMenuBarDuplicates, verifiedProjectMenuBarDuplicateExecutablePaths } from './global-install.js';
|
|
11
11
|
import { cleanupRetiredRemoteBridgeLaunchAgent, quarantineRetiredRemoteBridgeBindings } from './migration.js';
|
|
12
12
|
import { sksMenuBarPaths } from './paths.js';
|
|
@@ -114,6 +114,11 @@ export async function installSksMenuBar(opts = {}) {
|
|
|
114
114
|
return blocked('sks_entry_unresolved');
|
|
115
115
|
if (targetCheck.project_local)
|
|
116
116
|
warnings.push('sks_entry_project_local');
|
|
117
|
+
const macosProtectedRoots = ['Desktop', 'Documents', 'Downloads']
|
|
118
|
+
.map((dir) => `${path.join(paths.home, dir)}${path.sep}`);
|
|
119
|
+
if (targetCheck.resolved && macosProtectedRoots.some((root) => targetCheck.resolved.startsWith(root))) {
|
|
120
|
+
warnings.push('sks_entry_macos_protected_folder');
|
|
121
|
+
}
|
|
117
122
|
const previousActionScript = await readText(paths.action_script_path, '');
|
|
118
123
|
const previousLaunchAgent = await readText(paths.launch_agent_path, '');
|
|
119
124
|
const previousRaw = await readJson(paths.build_stamp_path, null);
|
|
@@ -256,7 +261,15 @@ export async function installSksMenuBar(opts = {}) {
|
|
|
256
261
|
});
|
|
257
262
|
const mustStopCanonical = !upToDate || (launchWanted && launchAllowed);
|
|
258
263
|
let canonicalStopped = false;
|
|
259
|
-
if (mustStopCanonical) {
|
|
264
|
+
if (mustStopCanonical && !menuBarLaunchdTouchAllowed(paths, env)) {
|
|
265
|
+
const stopped = await terminateMenuBarProcesses([paths.executable_path, ...duplicateExecutablePaths], env);
|
|
266
|
+
if (!stopped.ok) {
|
|
267
|
+
return blocked('menubar_stop_before_replace_failed', `Remaining PIDs: ${stopped.remaining_pids.join(',')}`);
|
|
268
|
+
}
|
|
269
|
+
warnings.push('launchd_stop_skipped_non_user_home');
|
|
270
|
+
actions.push('verified canonical/project duplicate processes stopped without touching the user launchd service');
|
|
271
|
+
}
|
|
272
|
+
else if (mustStopCanonical) {
|
|
260
273
|
const stopped = await stopMenuBarForReplacement({
|
|
261
274
|
launchctl,
|
|
262
275
|
paths,
|
|
@@ -2,6 +2,7 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { exists, readJson, runProcess, which, writeJsonAtomic } from '../../fsx.js';
|
|
4
4
|
import { CONTROL_CENTER_DOMAIN, CONTROL_CENTER_PREFERRED_POSITION, SKS_MENUBAR_LABEL } from './constants.js';
|
|
5
|
+
import { realUserHome } from './installer/runtime.js';
|
|
5
6
|
export function launchAgentSource(executablePath, installDir) {
|
|
6
7
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
7
8
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -9,11 +10,15 @@ export function launchAgentSource(executablePath, installDir) {
|
|
|
9
10
|
<key>Label</key><string>${SKS_MENUBAR_LABEL}</string>
|
|
10
11
|
<key>ProgramArguments</key><array><string>${xml(executablePath)}</string></array>
|
|
11
12
|
<key>RunAtLoad</key><true/>
|
|
13
|
+
<key>KeepAlive</key><true/>
|
|
12
14
|
<key>ProcessType</key><string>Interactive</string>
|
|
13
15
|
<key>StandardOutPath</key><string>${xml(path.join(installDir, 'menubar.out.log'))}</string>
|
|
14
16
|
<key>StandardErrorPath</key><string>${xml(path.join(installDir, 'menubar.err.log'))}</string>
|
|
15
17
|
</dict></plist>\n`;
|
|
16
18
|
}
|
|
19
|
+
export function menuBarLaunchdTouchAllowed(paths, env) {
|
|
20
|
+
return Boolean(env.SKS_MENUBAR_LAUNCHCTL) || path.resolve(paths.home) === realUserHome();
|
|
21
|
+
}
|
|
17
22
|
export async function seedMenuBarPreferredPosition(env) {
|
|
18
23
|
const defaults = env.SKS_MENUBAR_DEFAULTS || await which('defaults').catch(() => null) || '/usr/bin/defaults';
|
|
19
24
|
const writes = [
|
|
@@ -304,15 +309,24 @@ export async function removeLaunchAgent(paths, env) {
|
|
|
304
309
|
const actions = [];
|
|
305
310
|
const warnings = [];
|
|
306
311
|
const blockers = [];
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
312
|
+
if (menuBarLaunchdTouchAllowed(paths, env)) {
|
|
313
|
+
const launchctl = env.SKS_MENUBAR_LAUNCHCTL || await which('launchctl').catch(() => null) || '/bin/launchctl';
|
|
314
|
+
const stopped = await stopMenuBarForReplacement({
|
|
315
|
+
launchctl,
|
|
316
|
+
paths,
|
|
317
|
+
executablePaths: [paths.executable_path],
|
|
318
|
+
env
|
|
319
|
+
});
|
|
320
|
+
if (!stopped.ok)
|
|
321
|
+
blockers.push(stopped.error || 'menubar_process_stop_failed');
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
const terminated = await terminateMenuBarProcesses([paths.executable_path], env);
|
|
325
|
+
if (!terminated.ok)
|
|
326
|
+
blockers.push('menubar_process_stop_failed');
|
|
327
|
+
else
|
|
328
|
+
warnings.push('launchd_stop_skipped_non_user_home');
|
|
329
|
+
}
|
|
316
330
|
if (blockers.length > 0)
|
|
317
331
|
return { actions, warnings, blockers };
|
|
318
332
|
await fs.rm(paths.launch_agent_path, { force: true }).catch((error) => blockers.push(`remove_launch_agent_failed:${String(error)}`));
|
|
@@ -2,7 +2,7 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { readJson, sha256, which } from '../../fsx.js';
|
|
4
4
|
import { applyMenuBarGenerationTransaction, commitMenuBarGenerationTransaction, installGenerationPairs, MenuBarGenerationTransactionError, recoverMenuBarGenerationTransaction, rollbackGenerationPairs } from './generation-transaction.js';
|
|
5
|
-
import { launchMenuBar, stopMenuBarForReplacement } from './launch-agent.js';
|
|
5
|
+
import { launchMenuBar, menuBarLaunchdTouchAllowed, stopMenuBarForReplacement, terminateMenuBarProcesses } from './launch-agent.js';
|
|
6
6
|
import { sksMenuBarPaths } from './paths.js';
|
|
7
7
|
import { aggregateFileHashes } from './build-stamp.js';
|
|
8
8
|
import { inspectInstalledResources } from './resources.js';
|
|
@@ -286,7 +286,7 @@ export async function rollbackSksMenuBar(opts = {}) {
|
|
|
286
286
|
else {
|
|
287
287
|
transaction = committed;
|
|
288
288
|
}
|
|
289
|
-
if (opts.launch === false || env.SKS_SKIP_SKS_MENUBAR_LAUNCH === '1') {
|
|
289
|
+
if (opts.launch === false || env.SKS_SKIP_SKS_MENUBAR_LAUNCH === '1' || !menuBarLaunchdTouchAllowed(paths, env)) {
|
|
290
290
|
return result('rolled_back_launch_skipped', true, verificationBefore.package_version, replacedStamp?.package_version || null, verificationBefore, verificationAfter, { requested: false, method: 'skipped', ok: true }, [], warnings);
|
|
291
291
|
}
|
|
292
292
|
const launch = await launchMenuBar({
|
|
@@ -307,6 +307,16 @@ export async function rollbackSksMenuBar(opts = {}) {
|
|
|
307
307
|
async function stopBeforeReplacement() {
|
|
308
308
|
if (replacementStopped)
|
|
309
309
|
return null;
|
|
310
|
+
if (!menuBarLaunchdTouchAllowed(paths, env)) {
|
|
311
|
+
const terminated = await terminateMenuBarProcesses([paths.executable_path], env);
|
|
312
|
+
if (!terminated.ok) {
|
|
313
|
+
return result('failed', false, null, null, null, null, { requested: false, method: 'none', ok: false, error: 'menubar_rollback_stop_failed' }, ['menubar_rollback_stop_failed'], warnings);
|
|
314
|
+
}
|
|
315
|
+
replacementStopped = true;
|
|
316
|
+
warnings.push('launchd_stop_skipped_non_user_home');
|
|
317
|
+
actions.push('verified process termination without touching the user launchd service before journaled rollback replacement');
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
310
320
|
const stopped = await stopMenuBarForReplacement({
|
|
311
321
|
launchctl,
|
|
312
322
|
paths,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { runProcess } from '../fsx.js';
|
|
2
|
-
import {
|
|
2
|
+
import { CURRENT_CODEX_RUNTIME_CONTRACT, NARUTO_REQUIRED_CODEX_VERSION } from './codex-runtime-contract.js';
|
|
3
3
|
import { compareSemverLike, parseCodexVersionText } from './codex-version-policy.js';
|
|
4
4
|
export const CODEX_CAPABILITY_MATRIX_SCHEMA = 'sks.codex-capability-matrix.v1';
|
|
5
5
|
export const SKS_CODEX_CAPABILITY_IDS = [
|
|
@@ -13,10 +13,10 @@ export const SKS_CODEX_CAPABILITY_IDS = [
|
|
|
13
13
|
];
|
|
14
14
|
const UPDATE_CTA = 'Update Codex CLI to the preferred latest: `sks codex update` or Menu Bar / SKS Center → Update Codex CLI Now.';
|
|
15
15
|
export function preferredCodexCliVersion() {
|
|
16
|
-
return
|
|
16
|
+
return CURRENT_CODEX_RUNTIME_CONTRACT.preferredCliVersion || CURRENT_CODEX_RUNTIME_CONTRACT.requiredCliVersion;
|
|
17
17
|
}
|
|
18
18
|
export function softMinimumCodexCliVersion() {
|
|
19
|
-
return
|
|
19
|
+
return CURRENT_CODEX_RUNTIME_CONTRACT.minimumSupportedVersion;
|
|
20
20
|
}
|
|
21
21
|
export function narutoCodexFloorVersion() {
|
|
22
22
|
return NARUTO_REQUIRED_CODEX_VERSION;
|
|
@@ -26,7 +26,7 @@ export function buildCodexCapabilityMatrix(input = {}) {
|
|
|
26
26
|
const help = String(input.helpText || '');
|
|
27
27
|
const config = String(input.configText || '');
|
|
28
28
|
const schema = String(input.schemaText || '');
|
|
29
|
-
const policies =
|
|
29
|
+
const policies = CURRENT_CODEX_RUNTIME_CONTRACT.featurePolicies;
|
|
30
30
|
const warnings = [];
|
|
31
31
|
if (detected && compareSemverLike(detected, preferredCodexCliVersion()) < 0) {
|
|
32
32
|
warnings.push(`detected Codex ${detected} is below preferred ${preferredCodexCliVersion()}; prefer latest via SKS update inducement`);
|
|
@@ -122,8 +122,8 @@ export async function probeNarutoCodexCapability(input) {
|
|
|
122
122
|
return { matrix, naruto: assertNarutoMultiAgentV2Capability(matrix) };
|
|
123
123
|
}
|
|
124
124
|
function resolveMultiAgentV2(input) {
|
|
125
|
-
const policy =
|
|
126
|
-
||
|
|
125
|
+
const policy = CURRENT_CODEX_RUNTIME_CONTRACT.featurePolicies.multiAgentV2
|
|
126
|
+
|| CURRENT_CODEX_RUNTIME_CONTRACT.featurePolicies.multiAgentMode
|
|
127
127
|
|| 'delegate';
|
|
128
128
|
const evidence = [];
|
|
129
129
|
const helpHit = /\bmulti_agent_v2\b/.test(input.help);
|
|
@@ -167,7 +167,7 @@ function resolveMultiAgentV2(input) {
|
|
|
167
167
|
};
|
|
168
168
|
}
|
|
169
169
|
function resolveAgentsConcurrency(input) {
|
|
170
|
-
const policy =
|
|
170
|
+
const policy = CURRENT_CODEX_RUNTIME_CONTRACT.featurePolicies.agentsMaxConcurrentThreads || 'delegate';
|
|
171
171
|
const hit = /max_concurrent_threads_per_session/.test(input.help)
|
|
172
172
|
|| /max_concurrent_threads_per_session/.test(input.config);
|
|
173
173
|
const available = hit || input.multiAgentV2;
|
|
@@ -2,21 +2,18 @@ import { projectRoot } from '../fsx.js';
|
|
|
2
2
|
import { detectCodexCurrentCapability } from '../codex-control/codex-current-capability.js';
|
|
3
3
|
import { codexVersionReport } from './codex-version.js';
|
|
4
4
|
import { CODEX_COMPAT_SCHEMA, CODEX_HOOK_SCHEMA_BASELINE_TAG, CODEX_REQUIRED_BASELINE_TAG } from './codex-version-policy.js';
|
|
5
|
-
import {
|
|
5
|
+
import { CURRENT_CODEX_RUNTIME_CONTRACT } from './codex-runtime-contract.js';
|
|
6
6
|
import { codexSchemaSnapshotReport } from './codex-schema-snapshot.js';
|
|
7
7
|
import { codexHookWarningCheck } from './codex-hook-warning-detector.js';
|
|
8
8
|
export async function codexCompatibilityReport(opts = {}) {
|
|
9
9
|
const root = opts.root || await projectRoot();
|
|
10
10
|
const requiredBaseline = opts.requiredBaseline || opts.require || CODEX_REQUIRED_BASELINE_TAG;
|
|
11
11
|
const version = await codexVersionReport({ ...opts, requiredBaseline });
|
|
12
|
-
const
|
|
13
|
-
ok:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
manifest_sha256: null,
|
|
18
|
-
error: err?.message || String(err)
|
|
19
|
-
}));
|
|
12
|
+
const releaseContract = {
|
|
13
|
+
ok: true,
|
|
14
|
+
dependency_source: CURRENT_CODEX_RUNTIME_CONTRACT.dependencySource,
|
|
15
|
+
contract: CURRENT_CODEX_RUNTIME_CONTRACT
|
|
16
|
+
};
|
|
20
17
|
const snapshot = await codexSchemaSnapshotReport();
|
|
21
18
|
const hooks = await codexHookWarningCheck(root, { recordWrongness: false });
|
|
22
19
|
const current = await detectCodexCurrentCapability({
|
|
@@ -24,11 +21,11 @@ export async function codexCompatibilityReport(opts = {}) {
|
|
|
24
21
|
codexBin: opts.codexBin || null,
|
|
25
22
|
requireReal: opts.requireReal === true
|
|
26
23
|
});
|
|
27
|
-
const ok = Boolean(version.policy.ok &&
|
|
24
|
+
const ok = Boolean(version.policy.ok && snapshot.ok && hooks.ok && current.ok);
|
|
28
25
|
return {
|
|
29
26
|
schema: CODEX_COMPAT_SCHEMA,
|
|
30
27
|
required_baseline: requiredBaseline,
|
|
31
|
-
|
|
28
|
+
release_contract: releaseContract,
|
|
32
29
|
detected: version.detected,
|
|
33
30
|
current_capability: current,
|
|
34
31
|
capabilities: current.feature_states,
|
|
@@ -58,7 +55,6 @@ export async function codexCompatibilityReport(opts = {}) {
|
|
|
58
55
|
],
|
|
59
56
|
blockers: [
|
|
60
57
|
...(version.policy.ok ? [] : ['codex_version_policy_failed']),
|
|
61
|
-
...(releaseManifest.ok ? [] : ['codex_release_manifest_mismatch']),
|
|
62
58
|
...(snapshot.ok ? [] : ['codex_hook_schema_snapshot_invalid']),
|
|
63
59
|
...(hooks.ok ? [] : ['codex_hook_semantic_warning']),
|
|
64
60
|
...current.blockers
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { packageRoot } from '../fsx.js';
|
|
4
|
+
export const CODEX_RUNTIME_CONTRACT_SCHEMA = 'sks.codex-runtime-contract.v2';
|
|
5
|
+
const sdkVersion = codexSdkDependencyVersion();
|
|
6
|
+
export const CURRENT_CODEX_RUNTIME_CONTRACT = {
|
|
7
|
+
schema: CODEX_RUNTIME_CONTRACT_SCHEMA,
|
|
8
|
+
targetTag: `rust-v${sdkVersion}`,
|
|
9
|
+
requiredCliVersion: sdkVersion,
|
|
10
|
+
preferredCliVersion: sdkVersion,
|
|
11
|
+
sdkVersion,
|
|
12
|
+
minimumSupportedVersion: sdkVersion,
|
|
13
|
+
narutoCapabilityFloorVersion: sdkVersion,
|
|
14
|
+
protocolMode: 'app-server-v2',
|
|
15
|
+
dependencySource: 'package.json#dependencies.@openai/codex-sdk',
|
|
16
|
+
featurePolicies: {
|
|
17
|
+
multiAgentMode: 'delegate',
|
|
18
|
+
multiAgentV2: 'delegate',
|
|
19
|
+
agentsMaxConcurrentThreads: 'delegate',
|
|
20
|
+
indexedWebSearch: 'probe',
|
|
21
|
+
currentTimeRead: 'wrap',
|
|
22
|
+
threadListSearchRead: 'probe',
|
|
23
|
+
pluginCatalogRefresh: 'probe',
|
|
24
|
+
terminalSubagentErrorPropagation: 'probe',
|
|
25
|
+
execMcpTransientRecovery: 'probe',
|
|
26
|
+
remoteNativeEnvironment: 'probe',
|
|
27
|
+
rolloutTokenBudget: 'probe',
|
|
28
|
+
mcpStartupToolTimeouts: 'wrap',
|
|
29
|
+
gpt56TerraLunaSolRouting: 'delegate',
|
|
30
|
+
mcpPaginatedDiscovery: 'wrap',
|
|
31
|
+
portableAgentPlugins: 'delegate',
|
|
32
|
+
automaticApprovalReview: 'delegate'
|
|
33
|
+
},
|
|
34
|
+
requiredRealProbes: [
|
|
35
|
+
'runtime_identity',
|
|
36
|
+
'protocol_schema_generation',
|
|
37
|
+
'multi_agent_mode_schema',
|
|
38
|
+
'indexed_web_search_schema',
|
|
39
|
+
'current_time_read_schema',
|
|
40
|
+
'thread_list_search_schema',
|
|
41
|
+
'terminal_error_schema',
|
|
42
|
+
'rollout_budget_schema'
|
|
43
|
+
],
|
|
44
|
+
supportedPlatforms: [
|
|
45
|
+
'darwin-arm64',
|
|
46
|
+
'darwin-x64',
|
|
47
|
+
'linux-arm64',
|
|
48
|
+
'linux-x64',
|
|
49
|
+
'win32-arm64',
|
|
50
|
+
'win32-x64'
|
|
51
|
+
]
|
|
52
|
+
};
|
|
53
|
+
export const NARUTO_REQUIRED_CODEX_VERSION = CURRENT_CODEX_RUNTIME_CONTRACT.narutoCapabilityFloorVersion;
|
|
54
|
+
export function codexSdkDependencyVersion(root = packageRoot()) {
|
|
55
|
+
const packagePath = path.join(root, 'package.json');
|
|
56
|
+
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
57
|
+
const value = String(pkg.dependencies?.['@openai/codex-sdk'] || '').trim();
|
|
58
|
+
if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(value)) {
|
|
59
|
+
throw new Error(`@openai/codex-sdk must be an exact semver in ${packagePath}`);
|
|
60
|
+
}
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CURRENT_CODEX_RUNTIME_CONTRACT } from './codex-runtime-contract.js';
|
|
2
2
|
export const CODEX_COMPAT_SCHEMA = 'sks.codex-compat.v2';
|
|
3
|
-
export const CODEX_REQUIRED_BASELINE_TAG =
|
|
4
|
-
export const CODEX_REQUIRED_VERSION =
|
|
5
|
-
||
|
|
3
|
+
export const CODEX_REQUIRED_BASELINE_TAG = CURRENT_CODEX_RUNTIME_CONTRACT.targetTag;
|
|
4
|
+
export const CODEX_REQUIRED_VERSION = CURRENT_CODEX_RUNTIME_CONTRACT.preferredCliVersion
|
|
5
|
+
|| CURRENT_CODEX_RUNTIME_CONTRACT.requiredCliVersion;
|
|
6
6
|
export const CODEX_PREFERRED_VERSION = CODEX_REQUIRED_VERSION;
|
|
7
|
-
export const CODEX_MINIMUM_SUPPORTED_VERSION =
|
|
8
|
-
export const CODEX_HOOK_SCHEMA_BASELINE_TAG =
|
|
9
|
-
export const CODEX_HOOK_SCHEMA_VERSION =
|
|
7
|
+
export const CODEX_MINIMUM_SUPPORTED_VERSION = CURRENT_CODEX_RUNTIME_CONTRACT.minimumSupportedVersion;
|
|
8
|
+
export const CODEX_HOOK_SCHEMA_BASELINE_TAG = 'latest';
|
|
9
|
+
export const CODEX_HOOK_SCHEMA_VERSION = 'latest';
|
|
10
10
|
const UPDATE_CTA = 'prefer latest Codex CLI via `sks codex update` or Menu Bar / SKS Center → Update Codex CLI Now';
|
|
11
11
|
export function compareSemverLike(a, b) {
|
|
12
12
|
const pa = parseVersionParts(a);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { findCodexBinary } from '../codex-adapter.js';
|
|
3
3
|
import { compareSemverLike, parseCodexVersionText } from '../codex-compat/codex-version-policy.js';
|
|
4
|
-
import {
|
|
4
|
+
import { CURRENT_CODEX_RUNTIME_CONTRACT } from '../codex-compat/codex-runtime-contract.js';
|
|
5
5
|
import { nowIso, runProcess, writeJsonAtomic } from '../fsx.js';
|
|
6
6
|
export async function detectCodexCurrentAppCapability(input = {}) {
|
|
7
7
|
const fake = process.env.SKS_CODEX_CURRENT_APP_FAKE === '1';
|
|
@@ -9,10 +9,10 @@ export async function detectCodexCurrentAppCapability(input = {}) {
|
|
|
9
9
|
? input.codexBin || process.env.CODEX_BIN || 'codex'
|
|
10
10
|
: input.codexBin || process.env.CODEX_BIN || await findCodexBinary();
|
|
11
11
|
const versionText = fake
|
|
12
|
-
? String(process.env.SKS_CODEX_VERSION_FAKE || `codex-cli ${
|
|
12
|
+
? String(process.env.SKS_CODEX_VERSION_FAKE || `codex-cli ${CURRENT_CODEX_RUNTIME_CONTRACT.requiredCliVersion}`)
|
|
13
13
|
: await readCodexVersionText(codexBin);
|
|
14
14
|
const parsed = parseCodexVersion(versionText);
|
|
15
|
-
const currentRelease = Boolean(parsed && semverGte(parsed,
|
|
15
|
+
const currentRelease = Boolean(parsed && semverGte(parsed, CURRENT_CODEX_RUNTIME_CONTRACT.requiredCliVersion));
|
|
16
16
|
const probeMode = process.env.SKS_CODEX_CURRENT_APP_PROBE === '1' ? 'feature-probe' : 'version-only';
|
|
17
17
|
const featureProbeResults = probeMode === 'feature-probe'
|
|
18
18
|
? await probeCodexCurrentAppFeatures(codexBin, { fake })
|