sneakoscope 7.1.0 → 7.1.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.
Files changed (57) hide show
  1. package/README.md +7 -1
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/dist/cli/command-manifest-lite.js +1 -1
  5. package/dist/cli/command-registry.js +1 -1
  6. package/dist/commands/codex-app.js +28 -1
  7. package/dist/commands/doctor-profile.js +78 -0
  8. package/dist/commands/doctor.js +20 -68
  9. package/dist/config/skills-manifest.json +52 -52
  10. package/dist/core/agent-bridge/host-capability-runtime.js +34 -23
  11. package/dist/core/codex-app/codex-model-catalog.js +371 -0
  12. package/dist/core/codex-app/menubar/constants.js +1 -0
  13. package/dist/core/codex-app/menubar/installer.js +11 -1
  14. package/dist/core/codex-app/multi-provider-router-support.js +206 -0
  15. package/dist/core/codex-app/multi-provider-router.js +317 -0
  16. package/dist/core/codex-control/codex-app-server-v2-client.js +39 -2
  17. package/dist/core/codex-runtime/codex-desktop-config-policy.js +2 -0
  18. package/dist/core/commands/telegram-command.js +224 -108
  19. package/dist/core/managed-assets/managed-assets-manifest.js +1 -1
  20. package/dist/core/release/macos-menubar-proof.js +58 -1
  21. package/dist/core/release/main-push-guard.js +287 -10
  22. package/dist/core/release/main-push-receipt.js +8 -1
  23. package/dist/core/release/package-size-budget.js +1 -1
  24. package/dist/core/release/runtime-script-pack-closure.js +67 -3
  25. package/dist/core/remote/index.js +2 -0
  26. package/dist/core/remote/local-worker-client.js +35 -0
  27. package/dist/core/remote/machine-registry.js +17 -10
  28. package/dist/core/remote/session-binding.js +153 -0
  29. package/dist/core/remote/types.js +1 -0
  30. package/dist/core/remote/worker.js +230 -14
  31. package/dist/core/routes.js +1 -1
  32. package/dist/core/subagents/official-subagent-preparation.js +37 -1
  33. package/dist/core/subagents/official-subagent-prompt.js +4 -2
  34. package/dist/core/subagents/official-subagent-runner.js +5 -0
  35. package/dist/core/subagents/role-model-preferences.js +176 -40
  36. package/dist/core/telegram/config.js +28 -9
  37. package/dist/core/telegram/hub.js +8 -2
  38. package/dist/core/telegram/index.js +2 -0
  39. package/dist/core/telegram/messages.js +8 -2
  40. package/dist/core/telegram/runtime-projection.js +6 -2
  41. package/dist/core/telegram/runtime.js +19 -9
  42. package/dist/core/telegram/service.js +181 -0
  43. package/dist/core/telegram/setup.js +220 -0
  44. package/dist/core/update-check.js +13 -5
  45. package/dist/core/version.js +1 -1
  46. package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +1 -1
  47. package/dist/native/sks-menubar/Sources/ProcessClient.swift +1 -1
  48. package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +271 -0
  49. package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +14 -3
  50. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +4 -1
  51. package/dist/native/sks-menubar/Sources/RemoteTelegramViewController.swift +157 -50
  52. package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +4 -1
  53. package/dist/scripts/postinstall-global-doctor-blackbox.js +10 -0
  54. package/dist/scripts/release-macos-menubar-proof.js +38 -3
  55. package/dist/scripts/release-provenance-check.js +3 -1
  56. package/package.json +3 -1
  57. package/runtime-required-scripts.json +9 -0
package/README.md CHANGED
@@ -22,7 +22,7 @@ Proof-first orchestration for Codex CLI, ChatGPT Desktop, AI coding agents, mult
22
22
  Sneakoscope Codex (`sks`) is an open-source trust layer for Codex CLI and ChatGPT Desktop. It coordinates bounded AI coding agents, records machine-verifiable evidence, preserves project memory, and blocks release claims that are not supported by current tests or artifacts. Search visibility outcomes are measured separately; SKS does not promise rankings or traffic.
23
23
  <!-- END SKS SEARCH VISIBILITY MARKETING -->
24
24
 
25
- Current release: **SKS 7.1.0**, with the package preferred Codex channel at **CLI 0.145.0**. SKS stays version-agnostic: older hosts keep working where capabilities allow, while Menu Bar / Center induce updates to the preferred latest. It resolves managed SKS skills from the authoritative global install, preserves a runnable Naruto child slot when `max_threads=2`, and keeps current-version Menu Bar repair transactional so stamped generations remain verifiable. Naruto uses stable opt-in multi-agent V2 when the host exposes it. See [CHANGELOG.md](CHANGELOG.md).
25
+ Current release: **SKS 7.1.1**, with the package preferred Codex channel at **CLI 0.145.0**. SKS stays version-agnostic: older hosts keep working where capabilities allow, while Menu Bar / Center induce updates to the preferred latest. It resolves managed SKS skills from the authoritative global install, preserves a runnable Naruto child slot when `max_threads=2`, and keeps current-version Menu Bar repair transactional so stamped generations remain verifiable. Naruto uses stable opt-in multi-agent V2 when the host exposes it. See [CHANGELOG.md](CHANGELOG.md).
26
26
 
27
27
  ## What 7.0.0 Ships
28
28
 
@@ -54,6 +54,12 @@ The SKS menu bar shows the installed Codex CLI version and latest known version.
54
54
 
55
55
  **Manage MCP Servers…** opens a native macOS manager for the global `~/.codex/config.toml`. It can add remote URL or local stdio servers, enable/disable existing entries, remove entries after confirmation, and refresh the current state. Mutations are lock-protected, backed up, TOML-validated, and written with mode `0600`; configured environment values and command arguments are never rendered in the list. Changes apply to new Codex sessions. The same plumbing is available through the canonical `sks mcp config list|get|add|edit|duplicate|enable|disable|remove|test|login|logout|backups|restore` surface for diagnostics and automation.
56
56
 
57
+ ### Telegram remote coding on this Mac
58
+
59
+ Open **SKS Center → Remote & Telegram**, create a private bot with BotFather, send `/start` to that bot from the Telegram account you want to pair, then choose **Connect Bot & Register Coding Session…** and paste the token. SKS verifies the bot, stores the token only in macOS Keychain, pairs only that private chat/user, and registers one dedicated session bound to the current project. Choose **Start Hub**, then send ordinary text to the bot. On the first real message, the Hub creates the Codex thread and starts its first turn in the same App Server connection so the thread is durably resumable; later messages resume that exact thread and return the final response to Telegram.
60
+
61
+ The Hub runs as a user LaunchAgent and uses `caffeinate -i` while the logged-in Mac is available. The Mac still needs to remain powered on, logged in, awake, and network-connected; closing the lid or logging out can stop access. Telegram input has no arbitrary shell path, runs with approvals disabled and network access disabled inside the Codex workspace sandbox, and cannot target an unpaired chat or another project.
62
+
57
63
  ## The Front Door
58
64
 
59
65
  | Command | What it does |
@@ -76,7 +76,7 @@ dependencies = [
76
76
 
77
77
  [[package]]
78
78
  name = "sks-core"
79
- version = "7.1.0"
79
+ version = "7.1.1"
80
80
  dependencies = [
81
81
  "serde_json",
82
82
  ]
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "7.1.0"
3
+ version = "7.1.1"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -36,7 +36,7 @@ export const COMMAND_MANIFEST_LITE = [
36
36
  { name: 'codex-lb', summary: 'Inspect codex-lb status and circuit health', maturity: 'beta' },
37
37
  { name: 'menubar', summary: 'Inspect/install/restart/uninstall SKS menu bar', maturity: 'beta', skipMigrationGate: true, allowedDuringActiveRoute: true, diagnostic: true },
38
38
  { name: 'remote', summary: 'Inspect official Remote readiness and run the proof-aware SSH stdio worker', maturity: 'beta' },
39
- { name: 'telegram', summary: 'Inspect and run the private proof-aware Telegram Hub', maturity: 'beta' },
39
+ { name: 'telegram', summary: 'Pair and run the private local Codex Telegram Hub', maturity: 'beta' },
40
40
  { name: 'hooks', summary: 'Explain and inspect Codex hooks', maturity: 'beta', skipMigrationGate: true },
41
41
  { name: 'zellij-lane', summary: 'Render a Zellij lane frame for SKS sessions', maturity: 'beta' },
42
42
  { name: 'zellij-slot-pane', summary: 'Render a compact Zellij worker slot pane', maturity: 'beta' },
@@ -155,7 +155,7 @@ const COMMAND_DEFINITIONS = {
155
155
  'codex-lb': entry('beta', 'Inspect codex-lb status and circuit health', 'dist/commands/codex-lb.js', directCommand(() => import('../commands/codex-lb.js'), 'dist/commands/codex-lb.js')),
156
156
  menubar: activeRouteDiagnostic(entry('beta', 'Inspect/install/restart/uninstall SKS menu bar', 'dist/core/commands/menubar-command.js', subcommand(() => import('../core/commands/menubar-command.js'), 'menubarCommand', 'dist/core/commands/menubar-command.js', 'status'))),
157
157
  remote: entry('beta', 'Inspect official Remote readiness and run the proof-aware SSH stdio worker', 'dist/core/commands/remote-command.js', argsCommand(() => import('../core/commands/remote-command.js'), 'remoteCommand', 'dist/core/commands/remote-command.js')),
158
- telegram: entry('beta', 'Inspect and run the private proof-aware Telegram Hub', 'dist/core/commands/telegram-command.js', argsCommand(() => import('../core/commands/telegram-command.js'), 'telegramCommand', 'dist/core/commands/telegram-command.js')),
158
+ telegram: entry('beta', 'Pair and run the private local Codex Telegram Hub', 'dist/core/commands/telegram-command.js', argsCommand(() => import('../core/commands/telegram-command.js'), 'telegramCommand', 'dist/core/commands/telegram-command.js')),
159
159
  hooks: skipMigrationGate(entry('beta', 'Explain and inspect Codex hooks', 'dist/commands/hooks.js', directCommand(() => import('../commands/hooks.js'), 'dist/commands/hooks.js'))),
160
160
  'zellij-lane': entry('beta', 'Render a Zellij lane frame for SKS sessions', 'dist/commands/zellij-lane.js', directCommand(() => import('../commands/zellij-lane.js'), 'dist/commands/zellij-lane.js')),
161
161
  'zellij-slot-pane': entry('beta', 'Render a compact Zellij worker slot pane', 'dist/commands/zellij-slot-pane.js', directCommand(() => import('../commands/zellij-slot-pane.js'), 'dist/commands/zellij-slot-pane.js')),
@@ -16,6 +16,7 @@ import { OPENROUTER_DEFAULT_MODEL } from '../core/codex-app/openrouter-provider.
16
16
  import { promptForOpenRouterKeyHidden, writeStoredOpenRouterKey } from '../core/providers/openrouter/openrouter-secret-store.js';
17
17
  import { compactOpenRouterModelsResult, listOpenRouterModels, testOpenRouterConnection } from '../core/providers/openrouter/openrouter-account.js';
18
18
  import { restartCodexApp } from '../core/codex-app/codex-app-restart.js';
19
+ import { MULTI_PROVIDER_ROUTER_DEFAULT_BASE_URL, multiProviderRouterStatus, testMultiProviderRouter, useMultiProviderRouter } from '../core/codex-app/multi-provider-router.js';
19
20
  import { resetRoleModelPreference, roleModelPreferencesStatus, setRoleModelPreference } from '../core/subagents/role-model-preferences.js';
20
21
  export async function run(_command, args = []) {
21
22
  const action = args[0] || 'check';
@@ -93,12 +94,38 @@ export async function run(_command, args = []) {
93
94
  const result = await testOpenRouterConnection({ model: readOption(args, '--model', '') });
94
95
  return printCodexAppResult(args, result);
95
96
  }
97
+ if (action === 'router-status' || action === 'multi-provider-status' || action === 'opencodex-status') {
98
+ const result = await multiProviderRouterStatus({
99
+ baseUrl: readOption(args, '--base-url', ''),
100
+ catalogPath: readOption(args, '--catalog', '')
101
+ });
102
+ return printCodexAppResult(args, result);
103
+ }
104
+ if (action === 'router-test' || action === 'multi-provider-test' || action === 'opencodex-test') {
105
+ const result = await testMultiProviderRouter({
106
+ baseUrl: readOption(args, '--base-url', MULTI_PROVIDER_ROUTER_DEFAULT_BASE_URL),
107
+ catalogPath: readOption(args, '--catalog', ''),
108
+ model: readOption(args, '--model', '')
109
+ });
110
+ return printCodexAppResult(args, result);
111
+ }
112
+ if (action === 'use-router' || action === 'use-multi-provider' || action === 'use-opencodex') {
113
+ const result = await useMultiProviderRouter({
114
+ model: readOption(args, '--model', ''),
115
+ baseUrl: readOption(args, '--base-url', MULTI_PROVIDER_ROUTER_DEFAULT_BASE_URL),
116
+ catalogPath: readOption(args, '--catalog', ''),
117
+ replaceCatalog: flag(args, '--replace-catalog'),
118
+ restartApp: flag(args, '--restart-app') || flag(args, '--restart') || !flag(args, '--no-restart-app')
119
+ });
120
+ return printCodexAppResult(args, result);
121
+ }
96
122
  if (action === 'role-models') {
97
123
  return printCodexAppResult(args, await roleModelPreferencesStatus());
98
124
  }
99
125
  if (action === 'set-role-model') {
100
126
  const result = await setRoleModelPreference({
101
127
  role: readOption(args, '--role', ''),
128
+ provider: readOption(args, '--provider', ''),
102
129
  model: readOption(args, '--model', ''),
103
130
  reasoning: readOption(args, '--reasoning', '')
104
131
  });
@@ -168,7 +195,7 @@ export async function run(_command, args = []) {
168
195
  process.exitCode = 1;
169
196
  return;
170
197
  }
171
- console.error('Usage: sks codex-app check|status|harness-matrix|skill-sync|agent-role-sync|init-deep|hook-lifecycle|execution-profile|set-openrouter-key [--api-key-stdin]|use-openrouter --model <id>|openrouter-status|openrouter-models [--ids-only]|openrouter-test [--model <id>]|role-models|set-role-model --role <name> --model <id> --reasoning <effort>|reset-role-model --role <name>|product-design [--check-only]|ensure-product-design|chrome-extension|pat status|remote-control [--json]');
198
+ console.error('Usage: sks codex-app check|status|harness-matrix|skill-sync|agent-role-sync|init-deep|hook-lifecycle|execution-profile|set-openrouter-key [--api-key-stdin]|use-openrouter --model <id>|openrouter-status|openrouter-models [--ids-only]|openrouter-test [--model <id>]|router-status [--base-url <loopback-url>] [--catalog <path>]|router-test --model <provider/model> [--base-url <loopback-url>] [--catalog <path>]|use-router --model <provider/model> [--base-url <loopback-url>] [--catalog <path>] [--replace-catalog]|role-models|set-role-model --role <name> [--provider <id>] --model <catalog-slug> --reasoning <effort>|reset-role-model --role <name>|product-design [--check-only]|ensure-product-design|chrome-extension|pat status|remote-control [--json]');
172
199
  console.error('Note: glm-profile is retired (strips leftover Desktop GLM profiles); use set-openrouter-key / use-openrouter.');
173
200
  process.exitCode = 1;
174
201
  }
@@ -0,0 +1,78 @@
1
+ import { flag } from '../cli/args.js';
2
+ import { sksMenuBarRestartDeferred } from '../core/codex-app/sks-menubar.js';
3
+ export function doctorProfileFromArgs(args = [], doctorFix = false) {
4
+ const explicit = readOption(args, '--profile');
5
+ if (isDoctorProfile(explicit))
6
+ return explicit;
7
+ if (flag(args, '--full'))
8
+ return 'full';
9
+ if (flag(args, '--capabilities'))
10
+ return 'capabilities';
11
+ return doctorFix ? 'fix' : 'fast';
12
+ }
13
+ export function doctorArgWarnings(args = []) {
14
+ const warnings = [];
15
+ const explicit = readOption(args, '--profile');
16
+ if (explicit && !isDoctorProfile(explicit)) {
17
+ warnings.push(`unknown_profile:${explicit}; supported profiles: migration, full, capabilities, fast, fix`);
18
+ }
19
+ for (const value of unknownDoctorFlags(args))
20
+ warnings.push(`unknown_flag:${value}`);
21
+ return warnings;
22
+ }
23
+ export function doctorMenuBarInstallPolicy(args = [], doctorFix = false, env = process.env) {
24
+ const profile = doctorProfileFromArgs(args, doctorFix);
25
+ const phaseEnabled = doctorPhaseIdsForProfile(profile).includes('sks_menubar');
26
+ const apply = doctorFix && phaseEnabled;
27
+ return {
28
+ profile,
29
+ phase_enabled: phaseEnabled,
30
+ apply,
31
+ launch: apply && !sksMenuBarRestartDeferred(env)
32
+ };
33
+ }
34
+ export function doctorPhaseIdsForProfile(profile) {
35
+ const required = [
36
+ 'codex_startup_repair',
37
+ 'startup_config_repair',
38
+ 'context7_repair',
39
+ 'context7_mcp_repair',
40
+ 'hook_trust_repair',
41
+ 'command_alias_cleanup'
42
+ ];
43
+ if (profile === 'migration')
44
+ return required;
45
+ const optional = ['supabase_mcp_repair', 'native_capability_repair', 'sks_menubar'];
46
+ if (profile === 'full' || profile === 'capabilities')
47
+ return ['setup', ...required, ...optional];
48
+ return [...required, ...optional];
49
+ }
50
+ function unknownDoctorFlags(args) {
51
+ const knownBoolean = new Set([
52
+ '--fix', '--yes', '-y', '--machine-only', '--actual-codex', '--require-actual-codex',
53
+ '--full', '--capabilities', '--repair-codex-app-ui', '--repair-zellij', '--install-homebrew',
54
+ '--repair-native-capabilities', '--repair-codex-native', '--local-only', '--global-only', '--project', '--global',
55
+ '--dry-run', '--json'
56
+ ]);
57
+ const knownValue = new Set(['--profile', '--report-file', '--codex-bin', '--install-scope']);
58
+ const unknown = [];
59
+ for (let index = 0; index < args.length; index += 1) {
60
+ const arg = String(args[index] || '');
61
+ if (!arg.startsWith('-'))
62
+ continue;
63
+ if (knownValue.has(arg)) {
64
+ index += 1;
65
+ continue;
66
+ }
67
+ if (!knownBoolean.has(arg))
68
+ unknown.push(arg);
69
+ }
70
+ return unknown;
71
+ }
72
+ function isDoctorProfile(value) {
73
+ return ['migration', 'full', 'capabilities', 'fast', 'fix'].includes(String(value || ''));
74
+ }
75
+ function readOption(args, name) {
76
+ const index = args.indexOf(name);
77
+ return index >= 0 && args[index + 1] ? String(args[index + 1]) : null;
78
+ }
@@ -25,11 +25,13 @@ import { buildCodexNativeFeatureMatrix } from '../core/codex-native/codex-native
25
25
  import { withSecretPreservationGuard } from '../core/config/config-migration-journal.js';
26
26
  import { reconcileDoctorSkills } from '../core/doctor/doctor-skill-reconcile.js';
27
27
  import { isUpdateMigrationReceiptCurrent, projectUpdateMigrationReceiptPath, writeProjectUpdateMigrationReceipt } from '../core/update/update-migration-state.js';
28
- import { inspectSksMenuBarStatus, installSksMenuBar } from '../core/codex-app/sks-menubar.js';
28
+ import { inspectSksMenuBarStatus, installSksMenuBar, sksMenuBarRestartDeferred } from '../core/codex-app/sks-menubar.js';
29
29
  import { sweepSksTempDirs } from '../core/retention.js';
30
30
  import { detectImagegenCapability } from '../core/imagegen/imagegen-capability.js';
31
31
  import { CURRENT_CODEX_RELEASE_MANIFEST } from '../core/codex-compat/codex-release-manifest.js';
32
32
  import { formatHarnessConflictReport, scanHarnessConflicts } from '../core/harness-conflicts.js';
33
+ import { doctorArgWarnings, doctorMenuBarInstallPolicy, doctorPhaseIdsForProfile, doctorProfileFromArgs } from './doctor-profile.js';
34
+ export { doctorArgWarnings, doctorMenuBarInstallPolicy, doctorProfileFromArgs } from './doctor-profile.js';
33
35
  export async function run(_command, args = [], deps = {}) {
34
36
  const root = await projectRoot();
35
37
  const doctorFix = flag(args, '--fix');
@@ -88,6 +90,9 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
88
90
  || (await import('../cli/install-helpers.js')).ensureStoredOpenRouterProviderDuringInstall;
89
91
  const installMenuBarImpl = deps.installSksMenuBarImpl || installSksMenuBar;
90
92
  const codexLbStatusImpl = deps.codexLbStatusImpl || codexLbStatus;
93
+ const doctorEnv = deps.env || (deps.home
94
+ ? { ...process.env, HOME: home }
95
+ : process.env);
91
96
  const providerStatus = await codexLbStatusImpl({
92
97
  probeToolOutputRecovery: true,
93
98
  allowUnverifiedToolOutputRecovery: codexLbToolOutputRecoveryOverrideAcknowledged({ args })
@@ -128,9 +133,11 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
128
133
  status: 'failed',
129
134
  error: err?.message || String(err)
130
135
  }));
131
- const openRouterEnv = deps.env || (deps.home
132
- ? { ...process.env, HOME: home, SKS_HOME: path.join(home, '.sneakoscope') }
133
- : { ...process.env, HOME: home });
136
+ const openRouterEnv = {
137
+ ...doctorEnv,
138
+ HOME: home,
139
+ SKS_HOME: path.join(home, '.sneakoscope')
140
+ };
134
141
  const openRouterProvider = await ensureStoredOpenRouterProviderImpl({ home, env: openRouterEnv }).catch((err) => ({
135
142
  schema: 'sks.openrouter-provider-upgrade-repair.v1',
136
143
  ok: false,
@@ -142,7 +149,8 @@ export async function executeDoctorGlobalOnlyFix(args = [], root, deps = {}) {
142
149
  home,
143
150
  root: home,
144
151
  apply: true,
145
- launch: true,
152
+ launch: !sksMenuBarRestartDeferred(doctorEnv),
153
+ env: doctorEnv,
146
154
  quiet: flag(args, '--json') || flag(args, '--machine-only')
147
155
  }).catch((err) => ({
148
156
  schema: 'sks.codex-app-sks-menubar.v1',
@@ -674,15 +682,18 @@ async function runDoctor(args = [], root, doctorFix) {
674
682
  blockers: [err?.message || String(err)]
675
683
  }))
676
684
  : codexAppUiPlan;
685
+ const menuBarPolicy = doctorMenuBarInstallPolicy(args, doctorFix, process.env);
686
+ const menuBarLaunchRequested = menuBarPolicy.launch;
677
687
  const sksMenuBar = await installSksMenuBar({
678
688
  root,
679
- apply: doctorFix,
680
- launch: doctorFix,
689
+ apply: menuBarPolicy.apply,
690
+ launch: menuBarLaunchRequested,
691
+ env: process.env,
681
692
  quiet: machineOnly || flag(args, '--json')
682
693
  }).catch((err) => ({
683
694
  schema: 'sks.codex-app-sks-menubar.v1',
684
695
  ok: false,
685
- apply: doctorFix,
696
+ apply: menuBarPolicy.apply,
686
697
  status: 'blocked',
687
698
  platform: process.platform,
688
699
  app_path: null,
@@ -693,7 +704,7 @@ async function runDoctor(args = [], root, doctorFix) {
693
704
  report_path: `${root}/.sneakoscope/reports/sks-menubar.json`,
694
705
  menu_items: [],
695
706
  actions: [],
696
- launch: { requested: doctorFix, method: 'none', ok: false, error: err?.message || String(err) },
707
+ launch: { requested: menuBarLaunchRequested, method: 'none', ok: false, error: err?.message || String(err) },
697
708
  tcc_automation_status: 'unknown',
698
709
  next_actions: [
699
710
  'Run: sks menubar status',
@@ -1708,65 +1719,6 @@ function fallbackCodexNativeFeatureMatrix(codex, blockers = [], warnings = []) {
1708
1719
  warnings
1709
1720
  };
1710
1721
  }
1711
- export function doctorProfileFromArgs(args = [], doctorFix = false) {
1712
- const explicit = readOption(args, '--profile', null);
1713
- if (explicit === 'migration' || explicit === 'full' || explicit === 'capabilities' || explicit === 'fast' || explicit === 'fix')
1714
- return explicit;
1715
- if (flag(args, '--full'))
1716
- return 'full';
1717
- if (flag(args, '--capabilities'))
1718
- return 'capabilities';
1719
- return doctorFix ? 'fix' : 'fast';
1720
- }
1721
- export function doctorArgWarnings(args = []) {
1722
- const warnings = [];
1723
- const explicit = readOption(args, '--profile', null);
1724
- if (explicit && !['migration', 'full', 'capabilities', 'fast', 'fix'].includes(String(explicit))) {
1725
- warnings.push(`unknown_profile:${explicit}; supported profiles: migration, full, capabilities, fast, fix`);
1726
- }
1727
- for (const flag of unknownDoctorFlags(args))
1728
- warnings.push(`unknown_flag:${flag}`);
1729
- return warnings;
1730
- }
1731
- function unknownDoctorFlags(args = []) {
1732
- const knownBoolean = new Set([
1733
- '--fix', '--yes', '-y', '--machine-only', '--actual-codex', '--require-actual-codex',
1734
- '--full', '--capabilities', '--repair-codex-app-ui', '--repair-zellij', '--install-homebrew',
1735
- '--repair-native-capabilities', '--repair-codex-native', '--local-only', '--global-only', '--project', '--global',
1736
- '--dry-run', '--json'
1737
- ]);
1738
- const knownValue = new Set(['--profile', '--report-file', '--codex-bin', '--install-scope']);
1739
- const unknown = [];
1740
- for (let index = 0; index < args.length; index += 1) {
1741
- const arg = String(args[index] || '');
1742
- if (!arg.startsWith('-'))
1743
- continue;
1744
- if (knownValue.has(arg)) {
1745
- index += 1;
1746
- continue;
1747
- }
1748
- if (knownBoolean.has(arg))
1749
- continue;
1750
- unknown.push(arg);
1751
- }
1752
- return unknown;
1753
- }
1754
- function doctorPhaseIdsForProfile(profile) {
1755
- const required = [
1756
- 'codex_startup_repair',
1757
- 'startup_config_repair',
1758
- 'context7_repair',
1759
- 'context7_mcp_repair',
1760
- 'hook_trust_repair',
1761
- 'command_alias_cleanup'
1762
- ];
1763
- if (profile === 'migration')
1764
- return required;
1765
- const optional = ['supabase_mcp_repair', 'native_capability_repair', 'sks_menubar'];
1766
- if (profile === 'full' || profile === 'capabilities')
1767
- return ['setup', ...required, ...optional];
1768
- return [...required, ...optional];
1769
- }
1770
1722
  async function writeJsonReportFile(file, value) {
1771
1723
  const fsp = await import('node:fs/promises');
1772
1724
  const path = await import('node:path');