sneakoscope 10.3.6 → 10.3.7

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.3.6**. Install the latest stable release from npm.
19
+ Current package: **SKS 10.3.7**. 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
 
@@ -195,7 +195,7 @@ also picks the pipeline for each prompt; an explicit SKS `<div align="center">
195
195
  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.
196
196
  <!-- END SKS SEARCH VISIBILITY MARKETING -->
197
197
 
198
- Current package: **SKS 10.3.6**. Install the latest stable release from npm.
198
+ Current package: **SKS 10.3.7**. Install the latest stable release from npm.
199
199
 
200
200
  [Quick start](#install-in-one-command) · [Commands](#everyday-commands) · [SKS Center](#sks-center-macos) · [Documentation](#documentation) · [Changelog](CHANGELOG.md)
201
201
 
@@ -259,7 +259,7 @@ dependencies = [
259
259
 
260
260
  [[package]]
261
261
  name = "sks-core"
262
- version = "10.3.6"
262
+ version = "10.3.7"
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.3.6"
3
+ version = "10.3.7"
4
4
  edition = "2021"
5
5
 
6
6
  [dependencies]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": "sks.skills-manifest.v1",
3
- "package_version": "10.3.6",
3
+ "package_version": "10.3.7",
4
4
  "skills": [
5
5
  {
6
6
  "canonical_name": "sks",
@@ -302,6 +302,7 @@ function emptySkillLegacySurface(fix) {
302
302
  removed_other_harness_skill_count: 0,
303
303
  preserved_other_harness_skill_count: 0,
304
304
  preserved_user_skill_count: 0,
305
+ quarantined_sks_residue_count: 0,
305
306
  remaining_count: 0,
306
307
  preserved_clean_count: 0,
307
308
  error_count: 0,
@@ -309,6 +310,7 @@ function emptySkillLegacySurface(fix) {
309
310
  removed_other_harness_skills: [],
310
311
  preserved_other_harness_skills: [],
311
312
  preserved_user_skills: [],
313
+ quarantined_sks_residue: [],
312
314
  remaining: [],
313
315
  errors: [],
314
316
  cleanup_prompt_command: 'sks conflicts cleanup --yes'
@@ -1,13 +1,14 @@
1
1
  import fsp from 'node:fs/promises';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
- import { LEGACY_DOLLAR_SKILL_NAMES } from '../routes.js';
4
+ import { LEGACY_DOLLAR_SKILL_NAMES, routeByDollarCommand } from '../routes.js';
5
5
  import { legacyCoreSkillNames } from '../codex-native/core-skill-manifest.js';
6
6
  import { prefixKnownSksDollarReferences } from '../routes/dollar-prefix.js';
7
7
  import { inspectConfinedPath } from '../managed-path-safety.js';
8
8
  import { messageOf as errorMessage } from '../errors/message.js';
9
9
  import { collectNestedProjectRoots } from './current-project-guidance-nested.js';
10
10
  import { containsRetiredPublicSurface } from './current-project-guidance.js';
11
+ import { quarantineUserPath } from './retired-managed-residue-private.js';
11
12
  export const SKILL_LEGACY_SURFACE_SCHEMA = 'sks.skill-legacy-surface.v1';
12
13
  export const OTHER_HARNESS_SKILL_DIR_NAMES = ['omx', 'dcodex', 'omx-codex', 'dcodex-codex'];
13
14
  const TOKEN = 'A-Za-z0-9_.\\-';
@@ -111,6 +112,32 @@ const PREFIX_LEGACY_NAMES = Array.from(new Set([
111
112
  'prompt-pipeline',
112
113
  'pipeline-runner'
113
114
  ]));
115
+ async function isSksRouteSkillResidue(dir, name, text) {
116
+ if (!routeByDollarCommand(name) && !PREFIX_LEGACY_NAMES.includes(name))
117
+ return false;
118
+ const frontmatterName = /^---\n[\s\S]*?^name:\s*(.+?)\s*$[\s\S]*?^---/m.exec(text)?.[1];
119
+ if (frontmatterName !== name)
120
+ return false;
121
+ const files = [];
122
+ const walk = async (current, relative) => {
123
+ for (const entry of await fsp.readdir(current, { withFileTypes: true })) {
124
+ const rel = relative ? `${relative}/${entry.name}` : entry.name;
125
+ if (entry.isSymbolicLink())
126
+ return false;
127
+ if (entry.isDirectory()) {
128
+ if (!await walk(path.join(current, entry.name), rel))
129
+ return false;
130
+ }
131
+ else
132
+ files.push(rel);
133
+ }
134
+ return true;
135
+ };
136
+ if (!await walk(dir, ''))
137
+ return false;
138
+ return files.every((file) => SKS_SKILL_LAYOUT_FILES.has(file));
139
+ }
140
+ const SKS_SKILL_LAYOUT_FILES = new Set(['SKILL.md', 'agents/openai.yaml']);
114
141
  export function rewriteSkillLegacySurface(input) {
115
142
  let text = String(input || '');
116
143
  const hits = [];
@@ -173,6 +200,7 @@ export async function reconcileSkillLegacySurface(opts) {
173
200
  const removedOtherHarness = [];
174
201
  const preservedOtherHarness = [];
175
202
  const preservedUserSkills = [];
203
+ const quarantinedResidue = [];
176
204
  const remaining = [];
177
205
  const errors = [];
178
206
  let scanned = 0;
@@ -262,6 +290,21 @@ export async function reconcileSkillLegacySurface(opts) {
262
290
  remaining.push(display);
263
291
  continue;
264
292
  }
293
+ if (await isSksRouteSkillResidue(dir, row.name, before).catch(() => false)) {
294
+ if (!fix) {
295
+ remaining.push(display);
296
+ continue;
297
+ }
298
+ try {
299
+ await quarantineUserPath(ownerRoot, dir, path.join(ownerRoot, '.sneakoscope', 'quarantine', 'skill-legacy-surface'));
300
+ quarantinedResidue.push(display);
301
+ }
302
+ catch (error) {
303
+ errors.push(`${display}:${errorMessage(error)}`);
304
+ remaining.push(display);
305
+ }
306
+ continue;
307
+ }
265
308
  preservedUserSkills.push(display);
266
309
  remaining.push(display);
267
310
  }
@@ -275,6 +318,7 @@ export async function reconcileSkillLegacySurface(opts) {
275
318
  removed_other_harness_skill_count: removedOtherHarness.length,
276
319
  preserved_other_harness_skill_count: preservedOtherHarness.length,
277
320
  preserved_user_skill_count: preservedUserSkills.length,
321
+ quarantined_sks_residue_count: quarantinedResidue.length,
278
322
  remaining_count: remaining.length,
279
323
  preserved_clean_count: preservedClean,
280
324
  error_count: errors.length,
@@ -282,6 +326,7 @@ export async function reconcileSkillLegacySurface(opts) {
282
326
  removed_other_harness_skills: Array.from(new Set(removedOtherHarness)).sort(),
283
327
  preserved_other_harness_skills: Array.from(new Set(preservedOtherHarness)).sort(),
284
328
  preserved_user_skills: Array.from(new Set(preservedUserSkills)).sort(),
329
+ quarantined_sks_residue: Array.from(new Set(quarantinedResidue)).sort(),
285
330
  remaining: Array.from(new Set(remaining)).sort(),
286
331
  errors: Array.from(new Set(errors)).sort(),
287
332
  cleanup_prompt_command: 'sks conflicts cleanup --yes'
@@ -0,0 +1,58 @@
1
+ import { compareSemVer } from './semver.js';
2
+ export async function versionDownloadability(input) {
3
+ const env = input.env || process.env;
4
+ if (!probeEnabled(env))
5
+ return 'unknown';
6
+ const fetchImpl = input.fetchImpl || fetch;
7
+ const timeoutMs = input.timeoutMs ?? 4000;
8
+ const base = input.registry.replace(/\/+$/, '');
9
+ const name = input.packageName.replace('/', '%2F');
10
+ try {
11
+ const doc = await timed(fetchImpl, `${base}/${name}/${encodeURIComponent(input.version)}`, { headers: { accept: 'application/json' } }, timeoutMs);
12
+ if (doc.status === 404)
13
+ return 'not_yet_downloadable';
14
+ if (!doc.ok)
15
+ return 'unknown';
16
+ const tarball = (await doc.json().catch(() => null))?.dist?.tarball;
17
+ if (typeof tarball !== 'string' || !/^https?:\/\//.test(tarball))
18
+ return 'unknown';
19
+ const head = await timed(fetchImpl, tarball, { method: 'HEAD' }, timeoutMs);
20
+ if (head.ok)
21
+ return 'downloadable';
22
+ return head.status === 404 ? 'not_yet_downloadable' : 'unknown';
23
+ }
24
+ catch {
25
+ return 'unknown';
26
+ }
27
+ }
28
+ export async function offeredUpdateVersion(input) {
29
+ const { listed, current } = input;
30
+ if (!listed || (compareSemVer(listed, current) ?? 0) <= 0)
31
+ return { latest: listed, pending: null };
32
+ const state = await versionDownloadability({
33
+ registry: input.registry,
34
+ packageName: input.packageName,
35
+ version: listed,
36
+ ...(input.env ? { env: input.env } : {}),
37
+ ...(input.fetchImpl ? { fetchImpl: input.fetchImpl } : {})
38
+ });
39
+ return state === 'not_yet_downloadable' ? { latest: current, pending: listed } : { latest: listed, pending: null };
40
+ }
41
+ function probeEnabled(env) {
42
+ const flag = env.SKS_UPDATE_TARBALL_PROBE;
43
+ if (flag === '0')
44
+ return false;
45
+ if (flag === '1')
46
+ return true;
47
+ return !(env.NODE_TEST_CONTEXT || env.SKS_TEST_ISOLATION === '1');
48
+ }
49
+ async function timed(fetchImpl, url, init, timeoutMs) {
50
+ const controller = new AbortController();
51
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
52
+ try {
53
+ return await fetchImpl(url, { ...init, signal: controller.signal });
54
+ }
55
+ finally {
56
+ clearTimeout(timer);
57
+ }
58
+ }
@@ -12,6 +12,7 @@ import { compareSemVer, extractSemVer, parseSemVer } from './update/semver.js';
12
12
  import { countUpdates, emptyUpdateStatus, resolveSksUpdateStatus, UpdateStatusRefreshError } from './update/update-status.js';
13
13
  import { acquireUpdateOperationLock, authorizeUpdateRollback, buildUpdateNowCommand, buildUpdateRollbackCommand, canonicalUpdateRegistry, UpdateOperationRecorder, updateOperationLastInstallPath, updateReceiptHasConfirmedGlobalInstall } from './update/update-operation.js';
14
14
  import { runTemporaryInstallSmoke } from './update/temporary-install-smoke.js';
15
+ import { offeredUpdateVersion } from './update/registry-availability.js';
15
16
  import { npmGlobalInstallTargets, repairManagedPermissions } from './update/managed-permission-repair.js';
16
17
  import { updateStageFailureDiagnostics } from './update/update-stage-diagnostics.js';
17
18
  import { executableOnInjectedPath, inspectInstalledCliResolution } from './update/installed-cli-resolution.js';
@@ -150,7 +151,7 @@ async function runSksUpdateCheckLive(options = {}) {
150
151
  });
151
152
  }
152
153
  const result = await latestPromise;
153
- if (!result) {
154
+ if (!result || result.code !== 0) {
154
155
  return buildResult({
155
156
  packageName,
156
157
  current,
@@ -160,33 +161,14 @@ async function runSksUpdateCheckLive(options = {}) {
160
161
  npmBin,
161
162
  projectRoot: options.projectRoot,
162
163
  commandRegistry: options.registry,
163
- error: 'npm view failed'
164
+ error: result ? `${result.stderr || result.stdout || 'npm view failed'}`.trim() : 'npm view failed'
164
165
  });
165
166
  }
166
- if (result.code !== 0) {
167
- return buildResult({
168
- packageName,
169
- current,
170
- effective,
171
- latest: null,
172
- registry,
173
- npmBin,
174
- projectRoot: options.projectRoot,
175
- commandRegistry: options.registry,
176
- error: `${result.stderr || result.stdout || 'npm view failed'}`.trim()
177
- });
178
- }
179
- const latest = extractSemVer(String(result.stdout || '').trim().split(/\s+/).pop() || '');
180
- return buildResult({
181
- packageName,
182
- current,
183
- effective,
184
- latest,
185
- registry,
186
- npmBin,
187
- projectRoot: options.projectRoot,
188
- commandRegistry: options.registry
189
- });
167
+ const offered = await offeredUpdateVersion({ listed: extractSemVer(String(result.stdout || '').trim().split(/\s+/).pop() || ''), current, registry, packageName, env });
168
+ return {
169
+ ...buildResult({ packageName, current, effective, latest: offered.latest, registry, npmBin, projectRoot: options.projectRoot, commandRegistry: options.registry }),
170
+ pending_latest: offered.pending
171
+ };
190
172
  }
191
173
  function buildUpdateStatusSnapshot(input) {
192
174
  const currentParsed = parseSemVer(input.check.current);
@@ -1 +1 @@
1
- export const PACKAGE_VERSION = '10.3.6';
1
+ export const PACKAGE_VERSION = '10.3.7';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "ㅅㅋㅅ",
4
- "version": "10.3.6",
4
+ "version": "10.3.7",
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",