sneakoscope 4.8.0 → 4.8.1
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/crates/sks-core/src/main.rs +1 -1
- package/dist/bin/sks.js +1 -1
- package/dist/core/codex-app/sks-menubar.js +20 -10
- package/dist/core/codex-native/core-skill-manifest.js +16 -5
- package/dist/core/fsx.js +1 -1
- package/dist/core/managed-assets/managed-assets-manifest.js +1 -1
- package/dist/core/update/update-migration-state.js +1 -1
- package/dist/core/version.js +1 -1
- package/dist/scripts/seo-geo-skill-rich-content-check.js +16 -0
- package/dist/scripts/sks-menubar-install-check.js +28 -6
- package/dist/scripts/update-first-command-migration-check.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ sks seo-geo-optimizer apply latest --mode seo --apply --json
|
|
|
49
49
|
sks seo-geo-optimizer audit --mode geo --target package --offline --json
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
> 📋 **Current release: `v4.8.
|
|
52
|
+
> 📋 **Current release: `v4.8.1`** — full release history lives in [CHANGELOG.md](CHANGELOG.md). This README documents how Sneakoscope works today, not its version-by-version changes. Release readiness is tracked in [docs/release-readiness.md](docs/release-readiness.md).
|
|
53
53
|
|
|
54
54
|
## 🍥 Parallelism, UX, And Integrations
|
|
55
55
|
|
|
@@ -363,7 +363,7 @@ sks codex-app set-openrouter-key --api-key-stdin
|
|
|
363
363
|
sks codex-app glm-profile install
|
|
364
364
|
```
|
|
365
365
|
|
|
366
|
-
This writes the OpenRouter key to the SKS user secret store, writes redacted metadata only, and installs Codex Desktop-compatible `openrouter` provider plus selectable `sks-glm-52-*` reasoning profiles. The npm package does not patch the Codex Desktop macOS menu binary; a top-level menu between Window and Help requires upstream Codex Desktop UI support. On macOS, `sks doctor --fix` installs or refreshes a right-side SKS menu bar companion
|
|
366
|
+
This writes the OpenRouter key to the SKS user secret store, writes redacted metadata only, and installs Codex Desktop-compatible `openrouter` provider plus selectable `sks-glm-52-*` reasoning profiles. The npm package does not patch the Codex Desktop macOS menu binary; a top-level menu between Window and Help requires upstream Codex Desktop UI support. On macOS, `sks doctor --fix` installs or refreshes a right-side `SKS` menu bar companion with codex-lb, ChatGPT OAuth, OpenRouter/GLM, Fast Check, SKS Version Check, Update SKS Now, settings, and Codex restart actions.
|
|
367
367
|
|
|
368
368
|
### Switching auth mode: codex-lb ↔ ChatGPT OAuth
|
|
369
369
|
|
|
@@ -4,7 +4,7 @@ use std::io::{self, Read, Seek, SeekFrom};
|
|
|
4
4
|
fn main() {
|
|
5
5
|
let mut args = std::env::args().skip(1);
|
|
6
6
|
match args.next().as_deref() {
|
|
7
|
-
Some("--version") => println!("sks-rs 4.8.
|
|
7
|
+
Some("--version") => println!("sks-rs 4.8.1"),
|
|
8
8
|
Some("compact-info") => {
|
|
9
9
|
let mut input = String::new();
|
|
10
10
|
let _ = io::stdin().read_to_string(&mut input);
|
package/dist/bin/sks.js
CHANGED
|
@@ -105,7 +105,11 @@ export async function installSksMenuBar(opts = {}) {
|
|
|
105
105
|
actions.push(`compiled ${executablePath}`);
|
|
106
106
|
await writeTextAtomic(launchAgentPath, launchAgentSource(executablePath, installDir));
|
|
107
107
|
actions.push(`wrote ${launchAgentPath}`);
|
|
108
|
-
const
|
|
108
|
+
const launchWanted = opts.launch !== false && env.SKS_SKIP_SKS_MENUBAR_LAUNCH !== '1';
|
|
109
|
+
const launchAllowedForHome = path.resolve(home) === realUserHome();
|
|
110
|
+
if (launchWanted && !launchAllowedForHome)
|
|
111
|
+
warnings.push('launch_skipped_non_user_home');
|
|
112
|
+
const launchRequested = launchWanted && launchAllowedForHome;
|
|
109
113
|
const launch = launchRequested && launchctl
|
|
110
114
|
? await launchWithLaunchctl({ launchctl, open, appPath, executablePath, launchAgentPath })
|
|
111
115
|
: {
|
|
@@ -169,6 +173,17 @@ export async function installSksMenuBar(opts = {}) {
|
|
|
169
173
|
async function fallbackTool(candidate) {
|
|
170
174
|
return await exists(candidate).then((ok) => ok ? candidate : null).catch(() => null);
|
|
171
175
|
}
|
|
176
|
+
function realUserHome() {
|
|
177
|
+
try {
|
|
178
|
+
const userHome = os.userInfo().homedir;
|
|
179
|
+
if (userHome)
|
|
180
|
+
return path.resolve(userHome);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// Fall back below for platforms where userInfo is unavailable.
|
|
184
|
+
}
|
|
185
|
+
return path.resolve(os.homedir());
|
|
186
|
+
}
|
|
172
187
|
function resolveSksEntry(explicit) {
|
|
173
188
|
if (explicit)
|
|
174
189
|
return path.resolve(explicit);
|
|
@@ -222,7 +237,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
|
|
|
222
237
|
|
|
223
238
|
func applicationDidFinishLaunching(_ notification: Notification) {
|
|
224
239
|
NSApp.setActivationPolicy(.accessory)
|
|
225
|
-
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.
|
|
240
|
+
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
|
|
226
241
|
if let button = statusItem.button {
|
|
227
242
|
configureStatusButton(button)
|
|
228
243
|
}
|
|
@@ -244,14 +259,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
|
|
|
244
259
|
}
|
|
245
260
|
|
|
246
261
|
func configureStatusButton(_ button: NSStatusBarButton) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
button.imagePosition = .imageOnly
|
|
251
|
-
button.title = ""
|
|
252
|
-
} else {
|
|
253
|
-
button.title = "S"
|
|
254
|
-
}
|
|
262
|
+
button.image = nil
|
|
263
|
+
button.title = "SKS"
|
|
264
|
+
button.font = NSFont.systemFont(ofSize: NSFont.systemFontSize, weight: .semibold)
|
|
255
265
|
button.toolTip = "SKS - Sneakoscope Codex settings"
|
|
256
266
|
button.setAccessibilityLabel("SKS")
|
|
257
267
|
button.setAccessibilityHelp("Open SKS menu")
|
|
@@ -90,9 +90,12 @@ const CORE_SKILL_DEFINITIONS = [
|
|
|
90
90
|
canonical_name: 'search-visibility-core',
|
|
91
91
|
display_name: 'search-visibility-core',
|
|
92
92
|
route: '$SEO-GEO-OPTIMIZER',
|
|
93
|
-
purpose: 'provide the shared search-visibility kernel for SEO and GEO audit, plan, explicit apply, verify, rollback, and Completion Proof without ranking, traffic, or citation guarantees.',
|
|
94
|
-
when: 'Use when $SEO-GEO-OPTIMIZER or sks seo-geo-optimizer needs typed mode-specific evidence, gates, artifacts, or safe mutation planning.',
|
|
95
|
-
|
|
93
|
+
purpose: 'provide the shared search-visibility kernel for SEO and GEO audit, plan, explicit apply, verify, rollback, and Completion Proof without ranking, traffic, indexing, rich-result, answer inclusion, or AI citation guarantees.',
|
|
94
|
+
when: 'Use when $SEO-GEO-OPTIMIZER or sks seo-geo-optimizer needs typed mode-specific evidence, gates, artifacts, or safe mutation planning for websites, docs, packages, README/npm/GitHub surfaces, or storefront SEO architecture.',
|
|
95
|
+
workflow: 'Read the touched search-visibility flow before planning: SEO constants/source-of-truth, metadata builders, route topology, sitemap/robots, llms.txt, structured-data builders, target route files, internal-link sources, and SEO tests. Inventory canonical URLs, alternates/hreflang, crawlable localized sitemap rows, JSON-LD, crawler hints, claim evidence, and verification commands before compiling mutation-plan.json.',
|
|
96
|
+
safety: 'Treat SEO/GEO as an architecture compiler, not scattered page copy. Prefer existing project helpers and constants; never duplicate public route strings across files. JSON-LD must describe visible or source-of-truth facts only. Do not invent prices, reviews, ratings, availability, shipping terms, rankings, traffic, rich-result eligibility, indexing, or AI-answer outcomes.',
|
|
97
|
+
cli: 'sks seo-geo-optimizer doctor|audit|plan|apply|verify|status|rollback|fixture --mode seo|geo',
|
|
98
|
+
evidence: 'search-visibility/intake.json, adapter-detection.json, site-inventory.json, route-graph.json, robots-policy.json, structured-data-ledger.json, sitemap coverage, llms.txt plan/evidence, mutation-plan.json, rollback-manifest.json, verification-report.json, seo-gate.json or geo-gate.json, and completion-proof.json.',
|
|
96
99
|
fallback: 'Keep unsupported frameworks plan-only, record unverified production/browser/Search Console/AI citation outcomes, and never invent guarantee evidence.'
|
|
97
100
|
},
|
|
98
101
|
{
|
|
@@ -101,8 +104,11 @@ const CORE_SKILL_DEFINITIONS = [
|
|
|
101
104
|
display_name: 'seo-geo-optimizer',
|
|
102
105
|
route: '$SEO-GEO-OPTIMIZER',
|
|
103
106
|
purpose: 'run the unified SEO/GEO optimizer route for Search Engine Optimization and Generative Engine Optimization, not geolocation or GeoIP, with no ranking, traffic, indexing, rich-result, answer inclusion, or AI citation guarantee.',
|
|
104
|
-
when: 'Use the CLI entrypoint: sks seo-geo-optimizer doctor|audit|plan|apply|verify|status|rollback|fixture --mode seo|geo for SEO and GEO visibility work.',
|
|
105
|
-
|
|
107
|
+
when: 'Use the single CLI entrypoint: sks seo-geo-optimizer doctor|audit|plan|apply|verify|status|rollback|fixture --mode seo|geo for SEO and GEO visibility work. Legacy seo-geo wording, SEO, GEO, search visibility, AI visibility, sitemap, canonical, JSON-LD, llms.txt, metadata, keyword/intent, or crawler-policy requests should converge here.',
|
|
108
|
+
workflow: 'Follow the architecture-first playbook: identify target intent and market, locate the central SEO source of truth, update/reuse canonical helpers before page code, build metadata through project helpers, emit independently crawlable localized sitemap rows plus alternates when applicable, add factual JSON-LD only from visible/source data, add internal crawl links, update AI/GEO documentation surfaces such as llms.txt when strategic, add focused tests/guards, then verify. For CELIMAX-style storefronts, prefer STOREFRONT_PATH, buildSeoMetadata, buildSeoPath, buildSeoUrl, app/sitemap.ts, proxy.ts, public/llms.txt, and market-specific tests when those files exist.',
|
|
109
|
+
safety: 'Separate implemented, verified, and unverified claims. Competitor/retailer intent pages must be factual, helpful, and non-deceptive; block keyword stuffing, doorway pages, hidden AI-only text, fake ratings/reviews/prices/availability/shipping, competitor defamation, and unsupported "official retailer", "cheapest", "best", "exclusive", first-page, traffic, Search Console, or AI-citation claims.',
|
|
110
|
+
cli: 'sks seo-geo-optimizer doctor|audit|plan|apply|verify|status|rollback|fixture --mode seo|geo',
|
|
111
|
+
evidence: 'SEO intent map, canonical URL map, metadata summary, JSON-LD summary, sitemap coverage summary, internal link plan, unsupported claims ledger, Search Console/analytics follow-up plan, site inventory, route graph, seo-findings.json or geo-findings.json, claim-evidence-ledger.json, ai-crawler-policy.json, llms-txt-plan.json, verification report, route gate, and Completion Proof.',
|
|
106
112
|
fallback: 'Do not auto-allow training crawlers or fabricate AI answer visibility; mark missing live outcomes unverified and keep recovery on the unified optimizer route.'
|
|
107
113
|
}
|
|
108
114
|
];
|
|
@@ -139,9 +145,14 @@ export function renderCoreSkillTemplate(name) {
|
|
|
139
145
|
`Command: ${skill.route}`,
|
|
140
146
|
`Purpose: ${skill.purpose}`,
|
|
141
147
|
`Use when: ${skill.when}`,
|
|
148
|
+
`Workflow: ${skill.workflow || 'Run the selected route lifecycle, read source evidence before mutation planning, keep changes scoped, verify with the cheapest sufficient check, and record blockers honestly.'}`,
|
|
149
|
+
`CLI entrypoint: ${skill.cli || skill.route}`,
|
|
142
150
|
`Lean policy: ${lean.policy_id}/${lean.policy_hash}`,
|
|
151
|
+
`Safety: ${skill.safety || 'Preserve user-authored content, keep route state bounded, avoid unsupported guarantees, and stop on hard blockers instead of fabricating fallback behavior.'}`,
|
|
152
|
+
`Evidence/artifacts: ${skill.evidence}`,
|
|
143
153
|
`Proof paths: ${skill.evidence}`,
|
|
144
154
|
'Safety rules: preserve user-authored skills, keep route state bounded, and stop on hard blockers instead of fabricating fallback behavior.',
|
|
155
|
+
`Failure/recovery: ${skill.fallback}`,
|
|
145
156
|
`Failure recovery: ${skill.fallback}`,
|
|
146
157
|
''
|
|
147
158
|
].join('\n');
|
package/dist/core/fsx.js
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
|
import { fileURLToPath } from 'node:url';
|
|
8
|
-
export const PACKAGE_VERSION = '4.8.
|
|
8
|
+
export const PACKAGE_VERSION = '4.8.1';
|
|
9
9
|
export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
|
|
10
10
|
export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
|
|
11
11
|
export function nowIso() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { REQUIRED_CODEX_MODEL } from '../codex-model-guard.js';
|
|
2
2
|
export const MANAGED_ASSET_SCHEMA_VERSION = 1;
|
|
3
|
-
export const MANAGED_ASSET_VERSION = '4.8.
|
|
3
|
+
export const MANAGED_ASSET_VERSION = '4.8.1';
|
|
4
4
|
export const MANAGED_ASSET_MARKER = 'SKS-MANAGED-ASSET';
|
|
5
5
|
export const MANAGED_AGENT_ROLES = Object.freeze([
|
|
6
6
|
role('sks-explorer', 'analysis-scout.toml', 'analysis_scout', 'SKS analysis scout for bounded read/write slices retained for stale Codex agent-role config repair.', 'workspace-write', ['analysis-scout', 'analysis_scout']),
|
|
@@ -237,7 +237,7 @@ export async function ensureCurrentMigrationBeforeCommand(input) {
|
|
|
237
237
|
SKS_UPDATE_MIGRATION_GATE_DISABLED: '1',
|
|
238
238
|
SKS_DISABLE_UPDATE_CHECK: '1'
|
|
239
239
|
},
|
|
240
|
-
timeoutMs:
|
|
240
|
+
timeoutMs: 30_000,
|
|
241
241
|
maxOutputBytes: 32 * 1024
|
|
242
242
|
});
|
|
243
243
|
if (!doctor.ok) {
|
package/dist/core/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '4.8.
|
|
1
|
+
export const PACKAGE_VERSION = '4.8.1';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -7,6 +7,7 @@ import { assertGate, emitGate, importDist } from './sks-1-18-gate-lib.js';
|
|
|
7
7
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-seo-geo-skills-'));
|
|
8
8
|
const init = await importDist('core/init.js');
|
|
9
9
|
await init.installSkills(root);
|
|
10
|
+
assertGate(!fs.existsSync(path.join(root, '.agents', 'skills', 'seo-geo', 'SKILL.md')), 'generated skills must not recreate legacy seo-geo alias');
|
|
10
11
|
for (const name of ['search-visibility-core', 'seo-geo-optimizer']) {
|
|
11
12
|
const file = path.join(root, '.agents', 'skills', name, 'SKILL.md');
|
|
12
13
|
assertGate(fs.existsSync(file), `generated skill missing: ${name}`);
|
|
@@ -18,5 +19,20 @@ for (const name of ['search-visibility-core', 'seo-geo-optimizer']) {
|
|
|
18
19
|
assertGate(/CLI entrypoint:/i.test(text), `skill missing CLI entrypoint: ${name}`, text);
|
|
19
20
|
assertGate(/ranking|citation|traffic|guarantee|보장/i.test(text), `skill must name forbidden guarantee boundary: ${name}`, text);
|
|
20
21
|
}
|
|
22
|
+
const optimizer = fs.readFileSync(path.join(root, '.agents', 'skills', 'seo-geo-optimizer', 'SKILL.md'), 'utf8');
|
|
23
|
+
for (const token of [
|
|
24
|
+
'SEO intent map',
|
|
25
|
+
'canonical URL map',
|
|
26
|
+
'JSON-LD summary',
|
|
27
|
+
'sitemap coverage summary',
|
|
28
|
+
'internal link plan',
|
|
29
|
+
'unsupported claims ledger',
|
|
30
|
+
'llms.txt',
|
|
31
|
+
'Search Console',
|
|
32
|
+
'STOREFRONT_PATH',
|
|
33
|
+
'buildSeoMetadata'
|
|
34
|
+
]) {
|
|
35
|
+
assertGate(optimizer.includes(token), `seo-geo-optimizer skill missing CELIMAX architecture token: ${token}`, optimizer);
|
|
36
|
+
}
|
|
21
37
|
emitGate('seo-geo:skill-rich-content', { skills_checked: 2 });
|
|
22
38
|
//# sourceMappingURL=seo-geo-skill-rich-content-check.js.map
|
|
@@ -3,21 +3,29 @@ import os from 'node:os';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { installSksMenuBar } from '../core/codex-app/sks-menubar.js';
|
|
5
5
|
const temp = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-menubar-check-'));
|
|
6
|
+
const envHomeTemp = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-menubar-env-home-check-'));
|
|
6
7
|
const result = await installSksMenuBar({
|
|
7
8
|
apply: true,
|
|
8
|
-
launch:
|
|
9
|
+
launch: true,
|
|
9
10
|
home: temp,
|
|
10
11
|
root: temp,
|
|
11
12
|
sksEntry: path.join(process.cwd(), 'dist', 'bin', 'sks.js')
|
|
12
13
|
});
|
|
14
|
+
const envHomeResult = await installSksMenuBar({
|
|
15
|
+
apply: true,
|
|
16
|
+
launch: true,
|
|
17
|
+
root: envHomeTemp,
|
|
18
|
+
sksEntry: path.join(process.cwd(), 'dist', 'bin', 'sks.js'),
|
|
19
|
+
env: { ...process.env, HOME: envHomeTemp }
|
|
20
|
+
});
|
|
13
21
|
const executableExists = result.executable_path ? await exists(result.executable_path) : false;
|
|
14
22
|
const launchAgentExists = result.launch_agent_path ? await exists(result.launch_agent_path) : false;
|
|
15
23
|
const actionScriptExists = result.action_script_path ? await exists(result.action_script_path) : false;
|
|
16
24
|
const generatedSourcePath = result.app_path ? path.join(path.dirname(result.app_path), 'SKSMenuBar.swift') : null;
|
|
17
25
|
const generatedSource = generatedSourcePath ? await fs.readFile(generatedSourcePath, 'utf8').catch(() => '') : '';
|
|
18
|
-
const
|
|
19
|
-
&& generatedSource.includes('
|
|
20
|
-
&& generatedSource.includes('
|
|
26
|
+
const hasVisibleLabelSource = generatedSource.includes('NSStatusItem.variableLength')
|
|
27
|
+
&& generatedSource.includes('button.title = "SKS"')
|
|
28
|
+
&& generatedSource.includes('button.image = nil');
|
|
21
29
|
const expectedMenuItems = [
|
|
22
30
|
'Use codex-lb',
|
|
23
31
|
'Use ChatGPT OAuth',
|
|
@@ -28,25 +36,39 @@ const expectedMenuItems = [
|
|
|
28
36
|
];
|
|
29
37
|
const missingExpectedItems = expectedMenuItems.filter((item) => !result.menu_items.includes(item));
|
|
30
38
|
const hasExpectedItems = missingExpectedItems.length === 0;
|
|
39
|
+
const launchSkippedForTempHome = result.launch?.requested === false
|
|
40
|
+
&& result.launch?.method === 'skipped'
|
|
41
|
+
&& result.warnings.includes('launch_skipped_non_user_home');
|
|
42
|
+
const launchSkippedForEnvHome = envHomeResult.launch?.requested === false
|
|
43
|
+
&& envHomeResult.launch?.method === 'skipped'
|
|
44
|
+
&& envHomeResult.warnings.includes('launch_skipped_non_user_home');
|
|
31
45
|
const ok = process.platform === 'darwin'
|
|
32
46
|
? result.ok === true
|
|
33
47
|
&& result.status === 'installed_launch_skipped'
|
|
48
|
+
&& envHomeResult.ok === true
|
|
49
|
+
&& envHomeResult.status === 'installed_launch_skipped'
|
|
34
50
|
&& executableExists
|
|
35
51
|
&& launchAgentExists
|
|
36
52
|
&& actionScriptExists
|
|
37
53
|
&& hasExpectedItems
|
|
38
|
-
&&
|
|
54
|
+
&& hasVisibleLabelSource
|
|
55
|
+
&& launchSkippedForTempHome
|
|
56
|
+
&& launchSkippedForEnvHome
|
|
39
57
|
: result.ok === true && result.status === 'unsupported_platform';
|
|
40
58
|
const report = {
|
|
41
59
|
schema: 'sks.sks-menubar-install-check.v1',
|
|
42
60
|
ok,
|
|
43
61
|
temp,
|
|
62
|
+
env_home_temp: envHomeTemp,
|
|
44
63
|
result,
|
|
64
|
+
env_home_result: envHomeResult,
|
|
45
65
|
executable_exists: executableExists,
|
|
46
66
|
launch_agent_exists: launchAgentExists,
|
|
47
67
|
action_script_exists: actionScriptExists,
|
|
48
68
|
generated_source_path: generatedSourcePath,
|
|
49
|
-
|
|
69
|
+
has_visible_label_source: hasVisibleLabelSource,
|
|
70
|
+
launch_skipped_for_temp_home: launchSkippedForTempHome,
|
|
71
|
+
launch_skipped_for_env_home: launchSkippedForEnvHome,
|
|
50
72
|
expected_menu_items: expectedMenuItems,
|
|
51
73
|
missing_expected_items: missingExpectedItems,
|
|
52
74
|
has_expected_items: hasExpectedItems,
|
|
@@ -7,6 +7,7 @@ assertGate(router.includes('ensureCurrentMigrationBeforeCommand'), 'router must
|
|
|
7
7
|
assertGate(helper.includes('INSTALLATION_EPOCH_SCHEMA') && helper.includes('installationEpochPath'), 'migration helper must keep a persistent installation epoch');
|
|
8
8
|
assertGate(helper.includes('projectUpdateMigrationReceiptPath'), 'migration helper must keep a project receipt');
|
|
9
9
|
assertGate(helper.includes("'--profile', 'migration'") && helper.includes("'--machine-only'") && helper.includes("'--report-file'"), 'first normal command must repair through package-local migration Doctor machine report before continuing');
|
|
10
|
+
assertGate(helper.includes('timeoutMs: 30_000'), 'first normal command migration Doctor timeout must allow slow but successful macOS repair profiles');
|
|
10
11
|
assertGate(helper.includes('isProjectReceiptCurrentForEpoch'), 'project receipts must be compared against the current installation epoch');
|
|
11
12
|
assertGate(helper.includes('runUpdateRetentionCleanup') && helper.includes('retention_cleanup'), 'project update migration receipt must run mission retention cleanup and record its receipt');
|
|
12
13
|
assertGate(helper.includes('clearPendingUpdateMigration') && helper.includes('one project must not consume global migration state'), 'legacy clear helper must preserve the persistent epoch contract');
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "4.8.
|
|
4
|
+
"version": "4.8.1",
|
|
5
5
|
"description": "Sneakoscope Codex: fast proof-first Codex trust layer with image-based Voxel TriWiki.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
|