sneakoscope 10.3.5 → 10.3.6

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.5**. Install the latest stable release from npm.
19
+ Current package: **SKS 10.3.6**. 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.5**. Install the latest stable release from npm.
198
+ Current package: **SKS 10.3.6**. 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.5"
262
+ version = "10.3.6"
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.5"
3
+ version = "10.3.6"
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.5",
3
+ "package_version": "10.3.6",
4
4
  "skills": [
5
5
  {
6
6
  "canonical_name": "sks",
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import fsp from 'node:fs/promises';
3
3
  import os from 'node:os';
4
- import { exists, nowIso, PACKAGE_VERSION, readJson, readText, sha256, withScratchDir, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
4
+ import { exists, nowIso, PACKAGE_VERSION, packageRoot, readJson, readText, sha256, which, withScratchDir, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
5
5
  import { buildSksCoreSkillManifest, isCoreSkillName, legacyCoreSkillNames } from '../codex-native/core-skill-manifest.js';
6
6
  import { syncCoreSkillsIntegrity } from '../codex-native/core-skill-integrity.js';
7
7
  import { managedSkillGenerationLockPath, withManagedSkillGenerationLock } from '../codex-native/managed-skill-generation-lock.js';
@@ -682,11 +682,14 @@ async function reconcileSkillsUnlocked(opts) {
682
682
  if (installedMarker?.generated_by === 'sneakoscope') {
683
683
  const installedVersion = String(installedMarker?.version || '').trim();
684
684
  const versionOrder = compareSemVer(installedVersion, PACKAGE_VERSION);
685
- if (versionOrder === 1) {
685
+ const activeNewer = versionOrder === 1 ? await activeNewerSksOnPath(PACKAGE_VERSION) : null;
686
+ if (activeNewer) {
686
687
  report.ok = false;
687
- report.warnings.push(`managed_skill_generation_downgrade_refused:${installedVersion}:runtime_${PACKAGE_VERSION}`);
688
+ report.warnings.push(`managed_skill_generation_downgrade_refused:${installedVersion}:runtime_${PACKAGE_VERSION}:path_${activeNewer}`);
688
689
  return report;
689
690
  }
691
+ if (versionOrder === 1)
692
+ report.warnings.push(`managed_skill_generation_reclaimed_from_${installedVersion}`);
690
693
  const installedBuildTime = Number(installedMarker?.runtime_build_source_time);
691
694
  const currentBuildTime = await runtimeBuildSourceTime();
692
695
  const installedGeneration = String(installedMarker?.skill_generation_sha256 || '');
@@ -697,7 +700,8 @@ async function reconcileSkillsUnlocked(opts) {
697
700
  && Number.isFinite(installedBuildTime)
698
701
  && installedBuildTime > 0
699
702
  && currentBuildTime !== null
700
- && installedBuildTime > currentBuildTime) {
703
+ && installedBuildTime > currentBuildTime
704
+ && await activeNewerSksOnPath(PACKAGE_VERSION, installedBuildTime)) {
701
705
  report.ok = false;
702
706
  report.warnings.push(`managed_skill_same_version_older_build_refused:${currentBuildTime}:installed_${installedBuildTime}`);
703
707
  return report;
@@ -1384,3 +1388,29 @@ async function removeEmptyGeneratedParents(root, rel) {
1384
1388
  if (rel.startsWith('.codex/skills/'))
1385
1389
  await removeDirIfEmpty(path.join(root, '.codex', 'skills'));
1386
1390
  }
1391
+ async function activeNewerSksOnPath(runtimeVersion, sameVersionBuildTime = null) {
1392
+ const bin = await which('sks').catch(() => null);
1393
+ if (!bin)
1394
+ return null;
1395
+ let dir = path.dirname(await fsp.realpath(bin).catch(() => bin));
1396
+ for (let depth = 0; depth < 5; depth += 1) {
1397
+ const manifest = await readJson(path.join(dir, 'package.json'), null).catch(() => null);
1398
+ if (manifest?.name === 'sneakoscope' && typeof manifest.version === 'string') {
1399
+ const order = compareSemVer(manifest.version, runtimeVersion);
1400
+ if (order === 1)
1401
+ return manifest.version;
1402
+ if (order === 0 && sameVersionBuildTime !== null && path.resolve(dir) !== path.resolve(packageRoot())) {
1403
+ const stamp = await readJson(path.join(dir, 'dist', '.sks-build-stamp.json'), null).catch(() => null);
1404
+ const built = Number(stamp?.built_at_source_time);
1405
+ if (Number.isFinite(built) && built >= sameVersionBuildTime)
1406
+ return manifest.version;
1407
+ }
1408
+ return null;
1409
+ }
1410
+ const parent = path.dirname(dir);
1411
+ if (parent === dir)
1412
+ break;
1413
+ dir = parent;
1414
+ }
1415
+ return null;
1416
+ }
@@ -4,6 +4,11 @@ import path from 'node:path';
4
4
  import { readJson, runProcess } from '../fsx.js';
5
5
  import { runPackageLocalDoctor } from './update-migration-state.js';
6
6
  import { compareSemVer, extractSemVer } from './semver.js';
7
+ export function isPublishPropagationError(text) {
8
+ return /\bE404\b|\bETARGET\b|No matching version found|404 Not Found - GET [^\s]+\.tgz/i.test(text);
9
+ }
10
+ export const PUBLISH_PROPAGATION_WAIT_MS = 6 * 60 * 1000;
11
+ const PUBLISH_PROPAGATION_RETRY_MS = 20 * 1000;
7
12
  export async function runTemporaryInstallSmoke(input) {
8
13
  const npmArgs = [];
9
14
  if (input.env.SKS_UPDATE_SKIP_TEMP_INSTALL_SMOKE === '1') {
@@ -19,21 +24,38 @@ export async function runTemporaryInstallSmoke(input) {
19
24
  entrypoint = path.resolve(fixtureEntrypoint);
20
25
  }
21
26
  else {
22
- npmArgs.push('install', '--prefix', temp, `${input.packageName}@${input.version}`, '--registry', input.registry, '--ignore-scripts', '--no-audit', '--no-fund');
23
- const install = await runProcess(input.npmBin, npmArgs, {
24
- cwd: temp,
25
- env: input.env,
26
- timeoutMs: input.timeoutMs ?? 3 * 60 * 1000,
27
- maxOutputBytes: input.maxOutputBytes ?? 128 * 1024
28
- }).catch((error) => ({
29
- code: 1,
30
- stdout: '',
31
- stderr: error instanceof Error ? error.message : String(error),
32
- timedOut: false
33
- }));
27
+ npmArgs.push('install', '--prefix', temp, `${input.packageName}@${input.version}`, '--registry', input.registry, '--ignore-scripts', '--no-audit', '--no-fund', '--prefer-online');
28
+ const waitBudget = publishWaitBudgetMs(input.env);
29
+ const sleep = input.sleep || ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
30
+ const started = Date.now();
31
+ let install;
32
+ for (;;) {
33
+ install = await runProcess(input.npmBin, npmArgs, {
34
+ cwd: temp,
35
+ env: input.env,
36
+ timeoutMs: input.timeoutMs ?? 3 * 60 * 1000,
37
+ maxOutputBytes: input.maxOutputBytes ?? 128 * 1024
38
+ }).catch((error) => ({
39
+ code: 1,
40
+ stdout: '',
41
+ stderr: error instanceof Error ? error.message : String(error),
42
+ timedOut: false
43
+ }));
44
+ const output = `${install.stderr || ''}\n${install.stdout || ''}`;
45
+ const waited = Date.now() - started;
46
+ if (install.code === 0 || !isPublishPropagationError(output) || waited >= waitBudget)
47
+ break;
48
+ input.onPublishWait?.(waited);
49
+ await sleep(Math.min(PUBLISH_PROPAGATION_RETRY_MS, waitBudget - waited));
50
+ }
34
51
  installCode = install.code;
52
+ const waitedMs = Date.now() - started;
35
53
  if (install.code !== 0) {
36
- return result(input, npmArgs, false, 'install_failed', installCode, null, null, null, null, String(install.stderr || install.stdout || 'temporary npm install failed').trim());
54
+ const output = String(install.stderr || install.stdout || 'temporary npm install failed').trim();
55
+ const pendingMessage = `${input.packageName}@${input.version} is published but npm has not finished distributing it (waited ${Math.round(waitedMs / 1000)}s). Your current version keeps working; run sks update again in a few minutes.`;
56
+ return isPublishPropagationError(output)
57
+ ? { ...result(input, npmArgs, false, 'not_yet_downloadable', installCode, null, null, null, null, pendingMessage), publish_wait_ms: waitedMs }
58
+ : { ...result(input, npmArgs, false, 'install_failed', installCode, null, null, null, null, output), publish_wait_ms: waitedMs };
37
59
  }
38
60
  const packageRoot = path.join(temp, 'node_modules', input.packageName);
39
61
  const manifest = await readJson(path.join(packageRoot, 'package.json'), null).catch(() => null);
@@ -89,6 +111,13 @@ function result(input, npmArgs, ok, status, installCode, entrypoint, manifestVer
89
111
  error
90
112
  };
91
113
  }
114
+ function publishWaitBudgetMs(env) {
115
+ const raw = env.SKS_UPDATE_PUBLISH_WAIT_MS;
116
+ if (raw === undefined || raw === '')
117
+ return PUBLISH_PROPAGATION_WAIT_MS;
118
+ const value = Number(raw);
119
+ return Number.isFinite(value) && value >= 0 ? value : PUBLISH_PROPAGATION_WAIT_MS;
120
+ }
92
121
  async function regularFile(file) {
93
122
  const stat = await fs.stat(file).catch(() => null);
94
123
  return Boolean(stat?.isFile());
@@ -823,7 +823,7 @@ async function runSksUpdateNowInternal(options, rollbackAuthorization) {
823
823
  registry,
824
824
  env: nestedProcessEnv,
825
825
  ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
826
- ...(options.maxOutputBytes === undefined ? {} : { maxOutputBytes: options.maxOutputBytes })
826
+ ...(options.maxOutputBytes === undefined ? {} : { maxOutputBytes: options.maxOutputBytes }), ...(machineOutput ? {} : { onPublishWait: (waited) => process.stderr.write(` npm is still publishing ${packageName}@${installVersion}; waiting (${Math.round(waited / 1000)}s)...\n`) })
827
827
  });
828
828
  stage('temporary_install_smoke', temporaryInstallSmoke.ok, temporaryInstallSmoke.status, {
829
829
  install_code: temporaryInstallSmoke.install_code,
@@ -846,7 +846,7 @@ async function runSksUpdateNowInternal(options, rollbackAuthorization) {
846
846
  projectRoot: projectReceiptRoot,
847
847
  registry,
848
848
  globalRoot,
849
- status: 'failed',
849
+ status: temporaryInstallSmoke.status === 'not_yet_downloadable' ? 'unavailable' : 'failed',
850
850
  ok: false,
851
851
  installCode: null,
852
852
  oldVersionDoctor,
@@ -1 +1 @@
1
- export const PACKAGE_VERSION = '10.3.5';
1
+ export const PACKAGE_VERSION = '10.3.6';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "ㅅㅋㅅ",
4
- "version": "10.3.5",
4
+ "version": "10.3.6",
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",