sneakoscope 0.6.35 → 0.6.36

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 CHANGED
@@ -45,7 +45,7 @@ Prompt routes use one canonical name each: `$DFix`, `$Answer`, `$SKS`, `$Team`,
45
45
 
46
46
  Run `sks setup` once. SKS creates hooks/skills plus `.sneakoscope/` mission/wiki/policy state. Hooks inject context/status or block a turn; Team status is mirrored to `team-live.md`, `team-transcript.jsonl`, and `sks team watch latest`.
47
47
 
48
- Codex CLI parity is gated on Codex App because App-provisioned MCP/plugin tools are shared with CLI sessions. `sks` opens the tmux runtime after `sks codex-app check` and `sks tmux check` pass. `sks --Auto-review --high` enables Codex `auto_review` approval review and launches the ㅅㅋㅅ tmux runtime with a high-reasoning profile. QA-LOOP prioritizes Browser Use for local browser targets and Computer Use for desktop/browser evidence.
48
+ Codex CLI parity is gated on Codex App because App-provisioned MCP/plugin tools are shared with CLI sessions. `sks` opens the tmux runtime after `sks codex-app check` and `sks tmux check` pass. `sks --Auto-review --high` enables the Codex `guardian_subagent` approvals reviewer and launches the ㅅㅋㅅ tmux runtime with a high-reasoning profile. QA-LOOP prioritizes Browser Use for local browser targets and Computer Use for desktop/browser evidence.
49
49
 
50
50
  ## TriWiki
51
51
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "Sneakoscope Codex",
4
- "version": "0.6.35",
4
+ "version": "0.6.36",
5
5
  "description": "Sneakoscope Codex: update-aware, database-safe Codex CLI harness with multi-agent Team orchestration, Ralph no-question execution, autoresearch-style loops, and H-Proof gates.",
6
6
  "type": "module",
7
7
  "homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
package/src/cli/main.mjs CHANGED
@@ -1149,7 +1149,7 @@ Inspect or disable:
1149
1149
  sks auto-review disable
1150
1150
 
1151
1151
  Effect:
1152
- Writes approvals_reviewer = "auto_review" to Codex config and creates sks-auto-review / sks-auto-review-high profiles.
1152
+ Writes approvals_reviewer = "guardian_subagent" to Codex config and creates sks-auto-review / sks-auto-review-high profiles.
1153
1153
  Automatic review applies only to approval prompts that are already interactive under approval_policy = "on-request" or granular approval policies.
1154
1154
  `,
1155
1155
  team: `Team Workflow
@@ -2517,9 +2517,11 @@ async function selftest() {
2517
2517
  const autoReviewEnabled = await enableAutoReview({ env: autoReviewEnv, high: true });
2518
2518
  if (!autoReviewEnabled.enabled || autoReviewEnabled.profile_name !== 'sks-auto-review-high' || !autoReviewEnabled.high_profile) throw new Error('selftest failed: auto-review high profile was not enabled');
2519
2519
  const autoReviewConfig = await safeReadText(path.join(autoReviewHome, '.codex', 'config.toml'));
2520
- if (!autoReviewConfig.includes('approvals_reviewer = "auto_review"') || !autoReviewConfig.includes('[profiles.sks-auto-review-high]')) throw new Error('selftest failed: auto-review config not written');
2520
+ if (!autoReviewConfig.includes('approvals_reviewer = "guardian_subagent"') || autoReviewConfig.includes('approvals_reviewer = "auto_review"') || !autoReviewConfig.includes('[profiles.sks-auto-review-high]')) throw new Error('selftest failed: auto-review config not written');
2521
2521
  const autoReviewDisabled = await disableAutoReview({ env: autoReviewEnv });
2522
2522
  if (autoReviewDisabled.enabled || autoReviewDisabled.approvals_reviewer !== 'user') throw new Error('selftest failed: auto-review disable did not restore user reviewer');
2523
+ const autoReviewDisabledConfig = await safeReadText(path.join(autoReviewHome, '.codex', 'config.toml'));
2524
+ if (autoReviewDisabledConfig.includes('approvals_reviewer = "auto_review"')) throw new Error('selftest failed: auto-review disable left legacy invalid reviewer values');
2523
2525
  const analysisAgentExists = await exists(path.join(tmp, '.codex', 'agents', 'analysis-scout.toml'));
2524
2526
  if (!analysisAgentExists) throw new Error('selftest failed: analysis scout agent not installed');
2525
2527
  const teamAgentExists = await exists(path.join(tmp, '.codex', 'agents', 'team-consensus.toml'));
@@ -2,7 +2,8 @@ import os from 'node:os';
2
2
  import path from 'node:path';
3
3
  import { ensureDir, exists, readText, writeTextAtomic } from './fsx.mjs';
4
4
 
5
- export const AUTO_REVIEW_REVIEWER = 'auto_review';
5
+ export const AUTO_REVIEW_REVIEWER = 'guardian_subagent';
6
+ export const LEGACY_AUTO_REVIEW_REVIEWER = 'auto_review';
6
7
  export const AUTO_REVIEW_PROFILE = 'sks-auto-review';
7
8
  export const AUTO_REVIEW_HIGH_PROFILE = 'sks-auto-review-high';
8
9
 
@@ -21,13 +22,17 @@ export function autoReviewProfileName(opts = {}) {
21
22
  export async function autoReviewStatus(opts = {}) {
22
23
  const configPath = opts.configPath || codexConfigPath(opts.env || process.env);
23
24
  const text = await readText(configPath, '');
25
+ const approvalsReviewer = readTomlString(text, 'approvals_reviewer');
26
+ const profileReviewer = readTableString(text, `profiles.${AUTO_REVIEW_PROFILE}`, 'approvals_reviewer');
27
+ const highProfileReviewer = readTableString(text, `profiles.${AUTO_REVIEW_HIGH_PROFILE}`, 'approvals_reviewer');
24
28
  return {
25
29
  config_path: configPath,
26
30
  exists: await exists(configPath),
27
- approvals_reviewer: readTomlString(text, 'approvals_reviewer'),
28
- enabled: readTomlString(text, 'approvals_reviewer') === AUTO_REVIEW_REVIEWER,
29
- profile: tableHasString(text, `profiles.${AUTO_REVIEW_PROFILE}`, 'approvals_reviewer', AUTO_REVIEW_REVIEWER),
30
- high_profile: tableHasString(text, `profiles.${AUTO_REVIEW_HIGH_PROFILE}`, 'approvals_reviewer', AUTO_REVIEW_REVIEWER),
31
+ approvals_reviewer: approvalsReviewer,
32
+ enabled: approvalsReviewer === AUTO_REVIEW_REVIEWER,
33
+ profile: profileReviewer === AUTO_REVIEW_REVIEWER,
34
+ high_profile: highProfileReviewer === AUTO_REVIEW_REVIEWER,
35
+ legacy_invalid: [approvalsReviewer, profileReviewer, highProfileReviewer].includes(LEGACY_AUTO_REVIEW_REVIEWER),
31
36
  policy: readTableString(text, 'auto_review', 'policy') || ''
32
37
  };
33
38
  }
@@ -55,6 +60,8 @@ export async function disableAutoReview(opts = {}) {
55
60
  const configPath = opts.configPath || codexConfigPath(opts.env || process.env);
56
61
  const current = await readText(configPath, '');
57
62
  let next = upsertTopLevelString(current, 'approvals_reviewer', 'user');
63
+ if (tableBody(next, `profiles.${AUTO_REVIEW_PROFILE}`)) next = upsertProfile(next, AUTO_REVIEW_PROFILE, 'medium', 'user');
64
+ if (tableBody(next, `profiles.${AUTO_REVIEW_HIGH_PROFILE}`)) next = upsertProfile(next, AUTO_REVIEW_HIGH_PROFILE, 'high', 'user');
58
65
  if (!next.endsWith('\n')) next += '\n';
59
66
  await writeTextAtomic(configPath, next);
60
67
  return autoReviewStatus({ configPath });
@@ -74,6 +81,9 @@ export function autoReviewSummary(status = {}) {
74
81
  lines.push('', 'Enable with: sks auto-review enable');
75
82
  lines.push('Launch high mode with: sks --Auto-review --high');
76
83
  }
84
+ if (status.legacy_invalid) {
85
+ lines.push('', 'Legacy invalid reviewer value found: run sks auto-review enable or sks auto-review disable to rewrite Codex config.');
86
+ }
77
87
  return lines.join('\n');
78
88
  }
79
89
 
@@ -123,12 +133,12 @@ function upsertTopLevelString(text, key, value) {
123
133
  return lines.join('\n').replace(/^\n+/, '').replace(/\n{3,}/g, '\n\n');
124
134
  }
125
135
 
126
- function upsertProfile(text, profile, effort) {
136
+ function upsertProfile(text, profile, effort, reviewer = AUTO_REVIEW_REVIEWER) {
127
137
  const block = [
128
138
  `[profiles.${profile}]`,
129
139
  'model = "gpt-5.5"',
130
140
  'approval_policy = "on-request"',
131
- 'approvals_reviewer = "auto_review"',
141
+ `approvals_reviewer = "${reviewer}"`,
132
142
  'sandbox_mode = "workspace-write"',
133
143
  `model_reasoning_effort = "${effort}"`
134
144
  ].join('\n');
@@ -111,17 +111,21 @@ export async function codexAppIntegrationStatus(opts = {}) {
111
111
  computer_use_cache: computerUsePath,
112
112
  browser_use_cache: browserUsePath
113
113
  },
114
- guidance: codexAppGuidance({ appInstalled, codex, computerUseReady, browserUseReady })
114
+ guidance: codexAppGuidance({ appInstalled, codex, mcpList, computerUseReady, browserUseReady })
115
115
  };
116
116
  }
117
117
 
118
- export function codexAppGuidance({ appInstalled, codex, computerUseReady, browserUseReady }) {
118
+ export function codexAppGuidance({ appInstalled, codex, mcpList, computerUseReady, browserUseReady }) {
119
119
  const lines = [];
120
120
  if (!appInstalled) {
121
121
  lines.push('Install and open Codex App first. SKS CLI blocks tmux launch until Codex App is present because first-party MCP/plugin tools are App-provisioned.');
122
122
  lines.push(`Docs: ${CODEX_APP_DOCS_URL}`);
123
123
  }
124
124
  if (!codex?.bin) lines.push('Install Codex CLI too: npm i -g @openai/codex, or set SKS_CODEX_BIN.');
125
+ if (mcpList?.checked && !mcpList.ok) {
126
+ lines.push(`Codex MCP/config check failed: ${summarizeCodexMcpError(mcpList.stderr || mcpList.stdout)}`);
127
+ lines.push('Verify with: codex mcp list');
128
+ }
125
129
  if (appInstalled && (!computerUseReady || !browserUseReady)) {
126
130
  lines.push('Open Codex App settings, enable recommended MCP/plugin tools, then restart Codex CLI sessions.');
127
131
  lines.push('Required for SKS QA-LOOP priority order: Browser Use for local browser targets, Computer Use for desktop/app/browser evidence.');
@@ -146,3 +150,15 @@ export function formatCodexAppStatus(status, { includeRaw = false } = {}) {
146
150
  if (includeRaw && status.mcp.stdout) lines.push('', status.mcp.stdout.trim());
147
151
  return lines.join('\n');
148
152
  }
153
+
154
+ function summarizeCodexMcpError(text) {
155
+ const cleanLines = String(text || '')
156
+ .split(/\r?\n/)
157
+ .map((line) => line.trim())
158
+ .filter(Boolean)
159
+ .filter((line) => !line.startsWith('WARNING: proceeding'));
160
+ const variantLine = cleanLines.find((line) => line.includes('unknown variant'));
161
+ const errorLine = cleanLines.find((line) => line.startsWith('Error:'));
162
+ if (errorLine && variantLine && errorLine !== variantLine) return `${errorLine}; ${variantLine}`;
163
+ return variantLine || errorLine || cleanLines[0] || 'codex mcp list failed';
164
+ }
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.6.35';
8
+ export const PACKAGE_VERSION = '0.6.36';
9
9
  export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
10
10
  export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
11
11