sneakoscope 10.3.5 → 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 +2 -2
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/config/skills-manifest.json +1 -1
- package/dist/core/doctor/command-alias-cleanup.js +2 -0
- package/dist/core/doctor/skill-legacy-surface.js +46 -1
- package/dist/core/init/skills.js +34 -4
- package/dist/core/update/registry-availability.js +58 -0
- package/dist/core/update/temporary-install-smoke.js +42 -13
- package/dist/core/update-check.js +10 -28
- package/dist/core/version.js +1 -1
- package/package.json +1 -1
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.
|
|
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.
|
|
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
|
|
|
@@ -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'
|
package/dist/core/init/skills.js
CHANGED
|
@@ -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
|
-
|
|
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
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -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
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
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());
|
|
@@ -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
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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);
|
|
@@ -823,7 +805,7 @@ async function runSksUpdateNowInternal(options, rollbackAuthorization) {
|
|
|
823
805
|
registry,
|
|
824
806
|
env: nestedProcessEnv,
|
|
825
807
|
...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
|
|
826
|
-
...(options.maxOutputBytes === undefined ? {} : { maxOutputBytes: options.maxOutputBytes })
|
|
808
|
+
...(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
809
|
});
|
|
828
810
|
stage('temporary_install_smoke', temporaryInstallSmoke.ok, temporaryInstallSmoke.status, {
|
|
829
811
|
install_code: temporaryInstallSmoke.install_code,
|
|
@@ -846,7 +828,7 @@ async function runSksUpdateNowInternal(options, rollbackAuthorization) {
|
|
|
846
828
|
projectRoot: projectReceiptRoot,
|
|
847
829
|
registry,
|
|
848
830
|
globalRoot,
|
|
849
|
-
status: 'failed',
|
|
831
|
+
status: temporaryInstallSmoke.status === 'not_yet_downloadable' ? 'unavailable' : 'failed',
|
|
850
832
|
ok: false,
|
|
851
833
|
installCode: null,
|
|
852
834
|
oldVersionDoctor,
|
package/dist/core/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '10.3.
|
|
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.
|
|
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",
|