sneakoscope 10.1.1 → 10.1.2

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
@@ -16,7 +16,7 @@
16
16
  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.
17
17
  <!-- END SKS SEARCH VISIBILITY MARKETING -->
18
18
 
19
- Current package: **SKS 10.1.1**. Install the latest stable release from npm.
19
+ Current package: **SKS 10.1.2**. Install the latest stable release from npm.
20
20
 
21
21
  [Quick start](#install-in-one-command) · [Commands](#everyday-commands) · [SKS Center](#sks-center-macos) · [Documentation](#documentation) · [Changelog](CHANGELOG.md)
22
22
 
@@ -56,6 +56,13 @@ for setup boundaries and reported execution evidence.
56
56
 
57
57
  ## Everyday commands
58
58
 
59
+ SKS enables experimental Astra context management by default during setup and
60
+ repair. Turn it off in **SKS Center → Settings → Astra context management**, or
61
+ use `sks codex-app context-management off`. Updates preserve an explicit opt-out.
62
+ Start a new task after changing the setting. Availability depends on a supported
63
+ Codex client and eligible ChatGPT sign-in; API-key and custom-provider sessions
64
+ may not activate it. See [OpenAI's context management guidance](https://learn.chatgpt.com/docs/models#experimental-context-management).
65
+
59
66
  Use these inside a Codex conversation:
60
67
 
61
68
  | Command | Purpose |
@@ -259,7 +259,7 @@ dependencies = [
259
259
 
260
260
  [[package]]
261
261
  name = "sks-core"
262
- version = "10.1.1"
262
+ version = "10.1.2"
263
263
  dependencies = [
264
264
  "globset",
265
265
  "grep-matcher",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "sks-core"
3
- version = "10.1.1"
3
+ version = "10.1.2"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -302,7 +302,7 @@ export function safeReadOnlySubcommand(command, args) {
302
302
  if (command === 'mcp' && sub === 'config' && ['list', 'test', 'backups', 'show'].includes(nested)) {
303
303
  return !args.some((arg) => ['--fix', '--yes', '-y', '--write', '--apply', '--execute', '--force', '--real'].includes(String(arg)));
304
304
  }
305
- if (command === 'codex-app' && sub === 'context-1m' && (nested === 'status' || nested === '' || nested.startsWith('--'))) {
305
+ if (command === 'codex-app' && ['context-1m', 'context-management'].includes(sub) && (nested === 'status' || nested === '' || nested.startsWith('--'))) {
306
306
  return !args.some((arg) => ['--fix', '--yes', '-y', '--write', '--apply', '--execute', '--force', '--real'].includes(String(arg)));
307
307
  }
308
308
  if (command === 'remote' && ['readiness', 'status', 'show'].includes(sub)) {
@@ -14,6 +14,17 @@ import { restartCodexApp } from '../core/codex-app/codex-app-restart.js';
14
14
  import { resetRoleModelPreference, roleModelPreferencesStatus, setRoleModelPreference } from '../core/subagents/role-model-preferences.js';
15
15
  export async function run(_command, args = []) {
16
16
  const action = args[0] || 'check';
17
+ if (action === 'context-management') {
18
+ const { contextManagementCommand } = await import('../core/codex-app/context-management-command.js');
19
+ const result = await contextManagementCommand(args.slice(1));
20
+ if (flag(args, '--json'))
21
+ printJson(result);
22
+ else
23
+ console.log(`${result.ok ? (result.enabled ? 'Enabled' : 'Disabled') : 'Unavailable'}: ${result.message}`);
24
+ if (!result.ok)
25
+ process.exitCode = 1;
26
+ return;
27
+ }
17
28
  if (action === 'restart')
18
29
  return printCodexAppResult(args, await restartCodexApp());
19
30
  if (action === 'context-1m') {
@@ -137,7 +148,7 @@ export async function run(_command, args = []) {
137
148
  process.exitCode = 1;
138
149
  return;
139
150
  }
140
- console.error('Usage: sks codex-app check|status|restart|context-1m [status|on|off] [--no-restart]|harness-matrix|skill-sync|agent-role-sync|init-deep|hook-lifecycle|execution-profile|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]');
151
+ console.error('Usage: sks codex-app check|status|restart|context-management [status|on|off]|context-1m [status|on|off] [--no-restart]|harness-matrix|skill-sync|agent-role-sync|init-deep|hook-lifecycle|execution-profile|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]');
141
152
  console.error('Provider routing moved to: sks bridge provider configure|validate|enable; sks bridge catalog sync; sks bridge route set-default.');
142
153
  process.exitCode = 1;
143
154
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": "sks.skills-manifest.v1",
3
- "package_version": "10.1.1",
3
+ "package_version": "10.1.2",
4
4
  "skills": [
5
5
  {
6
6
  "canonical_name": "sks",
@@ -0,0 +1,55 @@
1
+ import { parse } from 'smol-toml';
2
+ import { isDeepStrictEqual } from 'node:util';
3
+ export function contextManagementValue(text) {
4
+ const value = parse(text).features?.context_management?.experimental_mode;
5
+ if (value !== undefined && typeof value !== 'boolean')
6
+ throw new Error('context_management_invalid_boolean');
7
+ return value;
8
+ }
9
+ export function setContextManagement(text, enabled, onlyIfAbsent = false) {
10
+ const before = parse(text);
11
+ const current = contextManagementValue(text);
12
+ if (current === enabled || (onlyIfAbsent && current !== undefined))
13
+ return text;
14
+ const expected = structuredClone(before);
15
+ expected.features ??= {};
16
+ expected.features.context_management ??= {};
17
+ expected.features.context_management.experimental_mode = enabled;
18
+ const valid = (candidate) => {
19
+ try {
20
+ return isDeepStrictEqual(parse(candidate), expected);
21
+ }
22
+ catch {
23
+ return false;
24
+ }
25
+ };
26
+ if (current !== undefined) {
27
+ for (const match of text.matchAll(/\b(?:true|false)\b/g)) {
28
+ const candidate = text.slice(0, match.index) + String(enabled) + text.slice(match.index + match[0].length);
29
+ if (valid(candidate))
30
+ return candidate;
31
+ }
32
+ }
33
+ else {
34
+ const suffix = `\n[features.context_management]\nexperimental_mode = ${enabled}\n`;
35
+ if (valid(text + suffix))
36
+ return text + suffix;
37
+ const candidates = [
38
+ `features.context_management.experimental_mode = ${enabled}\n${text}`,
39
+ ...[...text.matchAll(/\{/g)].flatMap(match => {
40
+ const offset = match.index + 1;
41
+ const separator = /^\s*\}/.test(text.slice(offset)) ? '' : ', ';
42
+ return [`experimental_mode = ${enabled}`, `context_management = { experimental_mode = ${enabled} }`]
43
+ .map(value => text.slice(0, offset) + value + separator + text.slice(offset));
44
+ }),
45
+ ...[...text.matchAll(/^\s*\[[^\n]+\][^\n]*(?:\n|$)/gm)].flatMap(match => {
46
+ const offset = match.index + match[0].length;
47
+ return ['experimental_mode', 'context_management.experimental_mode'].map(key => text.slice(0, offset) + `\n${key} = ${enabled}\n` + text.slice(offset));
48
+ }),
49
+ ];
50
+ for (const candidate of candidates)
51
+ if (valid(candidate))
52
+ return candidate;
53
+ }
54
+ throw new Error('context_management_config_edit_unsupported');
55
+ }
@@ -0,0 +1,38 @@
1
+ import fs from 'node:fs/promises';
2
+ import { codexUserConfigPath } from './codex-model-catalog.js';
3
+ import { writeCodexConfigGuarded } from '../codex/codex-config-guard.js';
4
+ import { contextManagementValue, setContextManagement } from '../codex/context-management.js';
5
+ export async function contextManagementCommand(args, options = {}) {
6
+ const configPath = codexUserConfigPath(options);
7
+ const action = args[0] || 'status';
8
+ try {
9
+ if (!['status', 'on', 'off'].includes(action) || args.slice(1).some(arg => arg !== '--json'))
10
+ throw new Error('context_management_invalid_arguments');
11
+ let exists = true;
12
+ const before = await fs.readFile(configPath, 'utf8').catch(error => { if (error.code !== 'ENOENT')
13
+ throw error; exists = false; return ''; });
14
+ let after = before;
15
+ let changed = false;
16
+ if (action !== 'status') {
17
+ const next = setContextManagement(before, action === 'on');
18
+ const write = await writeCodexConfigGuarded({
19
+ configPath, before, cause: 'context-management', removeTopLevelModeLocks: false,
20
+ verifyUnchangedBeforeWrite: true, expectedBeforeExists: exists, mutate: () => next,
21
+ });
22
+ if (!write.ok)
23
+ throw new Error(`context_management_write_${write.status}`);
24
+ after = await fs.readFile(configPath, 'utf8');
25
+ if (contextManagementValue(after) !== (action === 'on'))
26
+ throw new Error('context_management_readback_mismatch');
27
+ changed = write.changed;
28
+ }
29
+ const value = contextManagementValue(after);
30
+ return { schema: 'sks.context-management.v1', ok: true, enabled: value === true, configured: value !== undefined,
31
+ default_enabled: true, changed, config_path: configPath,
32
+ message: 'Applies to new tasks on supported Codex clients with eligible ChatGPT sign-in. API-key and custom-provider sessions may not activate it.' };
33
+ }
34
+ catch {
35
+ return { schema: 'sks.context-management.v1', ok: false, enabled: null, config_path: configPath,
36
+ message: 'Could not read or update the setting. Check the Codex configuration; existing content was not replaced without validation.' };
37
+ }
38
+ }
@@ -1,4 +1,5 @@
1
1
  import os from 'node:os';
2
+ import { setContextManagement } from '../codex/context-management.js';
2
3
  import path from 'node:path';
3
4
  import { DEFAULT_CODEX_APP_PLUGINS } from '../routes.js';
4
5
  import { ensureDir, PACKAGE_VERSION, readText, writeTextAtomic } from '../fsx.js';
@@ -95,6 +96,7 @@ function normalizeCodexFastModeUiConfigOnce(text = '', opts = {}) {
95
96
  next = upsertTomlTable(next, table, `[${table}]\nenabled = true`);
96
97
  }
97
98
  }
99
+ next = setContextManagement(next, true, true);
98
100
  return ensureTrailingNewline(next);
99
101
  }
100
102
  function removeTopLevelTomlKey(text = '', key = '') {
@@ -644,7 +644,7 @@ export const COMMAND_CATALOG = [
644
644
  { name: 'uninstall', usage: 'sks uninstall [--dry-run] [--yes] [--keep-config] [--keep-data] [--purge-projects] [--json]', description: 'Remove SKS global skills, hooks, menu bar, state, temp files, and optional project residue while preserving user-owned content by default.' },
645
645
  { name: 'deps', usage: 'sks deps check [--json] [--yes]', description: 'Check Node/npm and Codex CLI readiness; pass --yes to repair missing Codex CLI tooling when supported.' },
646
646
  { name: 'codex', usage: 'sks codex compatibility|version|update-status [--refresh]|update|doctor|schema|current [--json]', description: 'Check Codex CLI compatibility/version/update status, run the official `codex update`, and inspect current manifest, capability, and hook-schema evidence.' },
647
- { name: 'codex-app', usage: 'sks codex-app [check|status|restart|context-1m [status|on|off]|product-design|chrome-extension|pat status|remote-control]', description: 'Check Codex App integration, Desktop Bridge readiness, Product Design plugin readiness, Codex Chrome Extension web verification readiness, PAT-safe status, first-party MCP/plugin readiness, Codex CLI remote-control availability, and the opt-in GPT-5.6 Sol 1M context window toggle with automatic Codex restart. Provider routing is managed only by sks bridge.' },
647
+ { name: 'codex-app', usage: 'sks codex-app [check|status|restart|context-management [status|on|off]|context-1m [status|on|off]|product-design|chrome-extension|pat status|remote-control]', description: 'Check Codex App integration, Desktop Bridge readiness, Product Design plugin readiness, Codex Chrome Extension web verification readiness, PAT-safe status, first-party MCP/plugin readiness, Codex CLI remote-control availability, and the opt-in GPT-5.6 Sol 1M context window toggle with automatic Codex restart. Provider routing is managed only by sks bridge.' },
648
648
  { name: 'codex-native', usage: 'sks codex-native status|feature-broker|invocation-plan|init-deep [--json]', description: 'Inspect Codex Native feature broker readiness, invocation routing, pattern evidence, and managed memory setup.' },
649
649
  { name: 'hooks', usage: 'sks hooks explain|status|trust-report|replay|codex-validate|warning-check ... [--json]', description: 'Explain Codex hook events, validate current vendored event output schemas, replay fixtures, and enforce warning-zero SKS hook policies.' },
650
650
  { name: 'remote', usage: 'sks remote readiness|machines|worker ... [--json]', description: 'Inspect official Codex Remote readiness and the allowlisted proof-aware SSH stdio worker surface.' },
@@ -1 +1 @@
1
- export const PACKAGE_VERSION = '10.1.1';
1
+ export const PACKAGE_VERSION = '10.1.2';
@@ -19,6 +19,11 @@ final class SettingsViewController: NSViewController, ControlCenterPage {
19
19
  private var contextEnabled: Bool?
20
20
  private var contextBusy = false
21
21
  private var contextGeneration = 0
22
+ private let memoryToggle = NSSwitch()
23
+ private let memoryStatus = NativeView.detail("Checking saved preference…")
24
+ private var memoryEnabled: Bool?
25
+ private var memoryBusy = false
26
+ private var memoryGeneration = 0
22
27
  init(processClient: ProcessClient, operations: OperationCoordinator, notifications: NotificationCoordinator) {
23
28
  self.processClient = processClient
24
29
  self.operations = operations
@@ -28,6 +33,17 @@ final class SettingsViewController: NSViewController, ControlCenterPage {
28
33
  required init?(coder: NSCoder) { nil }
29
34
 
30
35
  override func loadView() {
36
+ memoryToggle.target = self
37
+ memoryToggle.action = #selector(toggleContextManagement)
38
+ memoryToggle.isEnabled = false
39
+ memoryToggle.setAccessibilityLabel("Experimental context management")
40
+ memoryToggle.setAccessibilityIdentifier("sks-context-management-toggle")
41
+ memoryStatus.setAccessibilityIdentifier("sks-context-management-status")
42
+ let memoryCard = NativeView.card(
43
+ title: "Astra context management",
44
+ subtitle: "Experimental · Keep notes and retrieve earlier messages and tool results. Enabled by default in SKS. Applies to new tasks with supported Codex and eligible ChatGPT sign-in; API-key and custom-provider sessions may not activate it.",
45
+ views: [NativeView.row([memoryToggle, NativeView.detail("Enable experimental context management")]), memoryStatus]
46
+ )
31
47
  followCodexLifecycle.target = self; followCodexLifecycle.action = #selector(save)
32
48
  followCodexLifecycle.setAccessibilityLabel("Show SKS Menu only while Codex is running")
33
49
  notificationButton = NativeView.button("Enable Notifications", target: self, action: #selector(enableNotifications))
@@ -50,11 +66,12 @@ final class SettingsViewController: NSViewController, ControlCenterPage {
50
66
  )
51
67
  view = NativeView.page([
52
68
  ControlKit.header("Settings", "Choose how SKS works on this Mac."),
53
- lifecycleCard, notificationsCard, NativeDisclosure("Advanced", views: [contextCard])
69
+ memoryCard, lifecycleCard, notificationsCard, NativeDisclosure("Advanced", views: [contextCard])
54
70
  ])
55
71
  }
56
72
 
57
73
  func refreshOnAppear() {
74
+ refreshContextManagement()
58
75
  refreshContext1m()
59
76
  let configResult = readConfig()
60
77
  switch configResult {
@@ -87,6 +104,53 @@ final class SettingsViewController: NSViewController, ControlCenterPage {
87
104
  }
88
105
  }
89
106
 
107
+ private func refreshContextManagement() {
108
+ guard !memoryBusy else { return }
109
+ memoryGeneration += 1
110
+ let generation = memoryGeneration
111
+ processClient.run(["codex-app", "context-management", "status", "--json"], timeout: NativeView.statusTimeout) { [weak self] result in
112
+ guard let self = self, !self.memoryBusy, generation == self.memoryGeneration else { return }
113
+ guard result.code == 0, let payload = self.json(result.output),
114
+ payload["schema"] as? String == "sks.context-management.v1",
115
+ payload["ok"] as? Bool == true, let enabled = payload["enabled"] as? Bool else {
116
+ self.memoryEnabled = nil
117
+ self.memoryToggle.isEnabled = false
118
+ self.memoryStatus.stringValue = "Saved setting unavailable. Check Codex configuration, then reopen Settings."
119
+ return
120
+ }
121
+ self.memoryEnabled = enabled
122
+ self.memoryToggle.state = enabled ? .on : .off
123
+ self.memoryToggle.isEnabled = true
124
+ self.memoryStatus.stringValue = enabled
125
+ ? "Setting enabled · start a new task to apply. Availability depends on Codex and your sign-in."
126
+ : "Setting disabled · your choice is preserved during updates."
127
+ }
128
+ }
129
+
130
+ @objc private func toggleContextManagement() {
131
+ guard !memoryBusy, let previous = memoryEnabled else { return }
132
+ let desired = memoryToggle.state == .on
133
+ guard let operation = operations.begin(kind: "context-management", mutationGroup: "codex-config", summary: "Change experimental context management") else {
134
+ memoryToggle.state = previous ? .on : .off
135
+ memoryStatus.stringValue = "Another configuration change is running. Try again when it finishes."
136
+ return
137
+ }
138
+ memoryBusy = true
139
+ memoryGeneration += 1
140
+ memoryToggle.isEnabled = false
141
+ memoryStatus.stringValue = "Saving preference…"
142
+ processClient.run(["codex-app", "context-management", desired ? "on" : "off", "--json"], timeout: NativeView.mutationTimeout) { [weak self] result in
143
+ guard let self = self else { return }
144
+ self.memoryBusy = false
145
+ let payload = self.json(result.output)
146
+ let ok = result.code == 0 && payload?["schema"] as? String == "sks.context-management.v1"
147
+ && payload?["ok"] as? Bool == true && payload?["enabled"] as? Bool == desired
148
+ _ = self.operations.update(operation, state: ok ? .succeeded : .failed, stage: "complete", progress: 1,
149
+ summary: ok ? "Preference saved. Start a new Codex task to apply." : "Save could not be confirmed. Rechecking the setting.")
150
+ self.refreshContextManagement()
151
+ }
152
+ }
153
+
90
154
  private func refreshContext1m(preserveStatusText: Bool = false) {
91
155
  contextGeneration += 1
92
156
  let requestGeneration = contextGeneration
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "ㅅㅋㅅ",
4
- "version": "10.1.1",
4
+ "version": "10.1.2",
5
5
  "description": "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.",
6
6
  "type": "module",
7
7
  "homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
@@ -196,7 +196,7 @@
196
196
  "dependencies": {
197
197
  "@modelcontextprotocol/client": "2.0.0",
198
198
  "@modelcontextprotocol/server": "2.0.0",
199
- "@openai/codex-sdk": "0.150.1",
199
+ "@openai/codex-sdk": "0.153.4",
200
200
  "smol-toml": "^1.7.0",
201
201
  "typescript": "^5.9.3",
202
202
  "ws": "^8.21.3"