sneakoscope 0.7.0 → 0.7.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "ㅅㅋㅅ",
4
- "version": "0.7.0",
4
+ "version": "0.7.1",
5
5
  "description": "Sneakoscope Codex: database-safe Codex CLI/App harness with Team, Goal, AutoResearch, TriWiki, and Honest Mode.",
6
6
  "type": "module",
7
7
  "homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
package/src/cli/main.mjs CHANGED
@@ -14,7 +14,7 @@ import { containsUserQuestion, noQuestionContinuationReason } from '../core/no-q
14
14
  import { evaluateDoneGate, defaultDoneGate } from '../core/hproof.mjs';
15
15
  import { emitHook } from '../core/hooks-runtime.mjs';
16
16
  import { storageReport, enforceRetention, pruneWikiArtifacts } from '../core/retention.mjs';
17
- import { classifySql, classifyCommand, checkDbOperation, handleMadSksUserConfirmation } from '../core/db-safety.mjs';
17
+ import { classifySql, classifyCommand, checkDbOperation, handleMadSksUserConfirmation, loadDbSafetyPolicy, scanDbSafety } from '../core/db-safety.mjs';
18
18
  import { checkHarnessModification, harnessGuardStatus, isHarnessSourceProject } from '../core/harness-guard.mjs';
19
19
  import { formatHarnessConflictReport, llmHarnessCleanupPrompt, scanHarnessConflicts } from '../core/harness-conflicts.mjs';
20
20
  import { context7Docs, context7Resolve, context7Text, context7Tools } from '../core/context7-client.mjs';
@@ -1711,10 +1711,11 @@ async function doctor(args) {
1711
1711
  let conflictScan = await scanHarnessConflicts(root);
1712
1712
  let repairApplied = false;
1713
1713
  let globalSkillsRepair = null;
1714
+ const globalCommand = await globalSksCommand();
1714
1715
  if (flag(args, '--fix') && !conflictScan.hard_block) {
1715
- const fixScope = requestedScope || 'global';
1716
1716
  const existingManifest = await readJson(path.join(root, '.sneakoscope', 'manifest.json'), null);
1717
- await initProject(root, { installScope: fixScope, globalCommand: await globalSksCommand(), localOnly: flag(args, '--local-only') || Boolean(existingManifest?.git?.local_only), force: true, repair: true });
1717
+ const fixScope = requestedScope || normalizeInstallScope(existingManifest?.installation?.scope || 'global');
1718
+ await initProject(root, { installScope: fixScope, globalCommand, localOnly: flag(args, '--local-only') || Boolean(existingManifest?.git?.local_only), force: true, repair: true });
1718
1719
  if (!flag(args, '--local-only')) globalSkillsRepair = await ensureGlobalCodexSkillsDuringInstall({ force: true });
1719
1720
  repairApplied = true;
1720
1721
  conflictScan = await scanHarnessConflicts(root);
@@ -1726,7 +1727,7 @@ async function doctor(args) {
1726
1727
  const pkgBytes = await dirSize(packageRoot()).catch(() => 0);
1727
1728
  const manifest = await readJson(path.join(root, '.sneakoscope', 'manifest.json'), null);
1728
1729
  const installScope = requestedScope || normalizeInstallScope(manifest?.installation?.scope || 'global');
1729
- const install = await installStatus(root, installScope);
1730
+ const install = await installStatus(root, installScope, { globalCommand });
1730
1731
  const dbPolicyExists = await exists(path.join(root, '.sneakoscope', 'db-safety.json'));
1731
1732
  const dbScan = await scanDbSafety(root).catch((err) => ({ ok: false, findings: [{ id: 'db_safety_scan_failed', severity: 'high', reason: err.message }] }));
1732
1733
  const context7Status = await checkContext7(root);
@@ -1868,7 +1869,10 @@ async function installStatus(root, scope, opts = {}) {
1868
1869
  const discoveredGlobalBin = await discoverGlobalSksCommand();
1869
1870
  const configuredGlobalBin = await configuredSksBin(opts.globalCommand);
1870
1871
  const globalBin = configuredGlobalBin || discoveredGlobalBin;
1871
- const commandPrefix = sksCommandPrefix(scope, { globalCommand: globalBin || undefined });
1872
+ const sourceProject = await isHarnessSourceProject(root).catch(() => false);
1873
+ const sourceBin = path.join(root, 'bin', 'sks.mjs');
1874
+ const sourceBinExists = sourceProject && await exists(sourceBin);
1875
+ const commandPrefix = sourceBinExists ? 'node ./bin/sks.mjs' : sksCommandPrefix(scope, { globalCommand: globalBin || undefined });
1872
1876
  const projectBin = path.join(root, 'node_modules', 'sneakoscope', 'bin', 'sks.mjs');
1873
1877
  const projectBinExists = await exists(projectBin);
1874
1878
  return {
@@ -1877,7 +1881,9 @@ async function installStatus(root, scope, opts = {}) {
1877
1881
  command_prefix: commandPrefix,
1878
1882
  global_bin: globalBin,
1879
1883
  project_bin: projectBin,
1880
- ok: scope === 'project' ? projectBinExists : Boolean(globalBin)
1884
+ source_project: sourceProject,
1885
+ source_bin: sourceBinExists ? sourceBin : null,
1886
+ ok: sourceBinExists || (scope === 'project' ? projectBinExists : Boolean(globalBin))
1881
1887
  };
1882
1888
  }
1883
1889
 
@@ -2038,18 +2044,47 @@ async function selftest() {
2038
2044
  const guardStatus = await harnessGuardStatus(tmp);
2039
2045
  if (!guardStatus.ok || !guardStatus.locked || guardStatus.source_exception) throw new Error('selftest failed: harness guard not locked in installed project');
2040
2046
  const repairTmp = tmpdir();
2041
- await initProject(repairTmp, {});
2047
+ await writeJsonAtomic(path.join(repairTmp, 'package.json'), { name: 'sneakoscope', version: '0.0.0', type: 'module' });
2048
+ await ensureDir(path.join(repairTmp, 'bin'));
2049
+ await writeTextAtomic(path.join(repairTmp, 'bin', 'sks.mjs'), '#!/usr/bin/env node\n');
2050
+ await ensureDir(path.join(repairTmp, 'src', 'core'));
2051
+ await writeTextAtomic(path.join(repairTmp, 'src', 'core', 'init.mjs'), '// source-project marker\n');
2052
+ await writeTextAtomic(path.join(repairTmp, 'src', 'core', 'hooks-runtime.mjs'), '// source-project marker\n');
2053
+ await initProject(repairTmp, { installScope: 'project', localOnly: true });
2042
2054
  await writeTextAtomic(path.join(repairTmp, '.agents', 'skills', 'team', 'SKILL.md'), 'tampered\n');
2043
2055
  await writeTextAtomic(path.join(repairTmp, '.agents', 'skills', 'agent-team', 'SKILL.md'), '---\nname: agent-team\ndescription: Fallback Codex App picker alias for $Team.\n---\n');
2044
2056
  await ensureDir(path.join(repairTmp, '.agents', 'skills', 'custom-keep'));
2045
2057
  await writeTextAtomic(path.join(repairTmp, '.agents', 'skills', 'custom-keep', 'SKILL.md'), '---\nname: custom-keep\ndescription: User custom skill, not generated by SKS.\n---\n');
2046
2058
  await writeTextAtomic(path.join(repairTmp, '.codex', 'skills', 'team', 'SKILL.md'), 'legacy mirror\n');
2047
- await initProject(repairTmp, { force: true, repair: true });
2059
+ await writeTextAtomic(path.join(repairTmp, '.codex', 'hooks.json'), '{ "hooks": { "Stop": [{ "hooks": [{ "type": "command", "command": "tampered hook" }] }] } }\n');
2060
+ await writeTextAtomic(path.join(repairTmp, '.codex', 'SNEAKOSCOPE.md'), 'tampered quick reference\n');
2061
+ await writeJsonAtomic(path.join(repairTmp, '.sneakoscope', 'policy.json'), { broken: true });
2062
+ const existingAgentsMd = await safeReadText(path.join(repairTmp, 'AGENTS.md'));
2063
+ await writeTextAtomic(path.join(repairTmp, 'AGENTS.md'), existingAgentsMd.replace(/<!-- BEGIN Sneakoscope Codex GX MANAGED BLOCK -->[\s\S]*?<!-- END Sneakoscope Codex GX MANAGED BLOCK -->\n?/, '<!-- BEGIN Sneakoscope Codex GX MANAGED BLOCK -->\ntampered managed block\n<!-- END Sneakoscope Codex GX MANAGED BLOCK -->\n'));
2064
+ const doctorRepair = await runProcess(process.execPath, [path.join(packageRoot(), 'bin', 'sks.mjs'), 'doctor', '--fix', '--local-only', '--json'], {
2065
+ cwd: repairTmp,
2066
+ env: { HOME: path.join(repairTmp, 'home'), SKS_DISABLE_UPDATE_CHECK: '1' },
2067
+ timeoutMs: 30000,
2068
+ maxOutputBytes: 1024 * 1024
2069
+ });
2070
+ if (doctorRepair.code !== 0) throw new Error(`selftest failed: doctor --fix exited ${doctorRepair.code}: ${doctorRepair.stderr}`);
2071
+ const doctorRepairJson = JSON.parse(doctorRepair.stdout || '{}');
2072
+ if (!doctorRepairJson.repair?.applied || doctorRepairJson.install?.scope !== 'project' || !doctorRepairJson.install?.ok || !doctorRepairJson.install?.source_project) throw new Error('selftest failed: doctor --fix did not preserve project source install scope');
2073
+ const repairedManifest = await readJson(path.join(repairTmp, '.sneakoscope', 'manifest.json'));
2074
+ if (repairedManifest.installation?.scope !== 'project' || repairedManifest.installation?.hook_command_prefix !== 'node ./bin/sks.mjs') throw new Error('selftest failed: doctor --fix rewrote project source install scope to the wrong command prefix');
2048
2075
  const repairedTeamSkill = await safeReadText(path.join(repairTmp, '.agents', 'skills', 'team', 'SKILL.md'));
2049
2076
  if (!repairedTeamSkill.includes('SKS Team orchestration') || repairedTeamSkill.includes('tampered')) throw new Error('selftest failed: doctor repair did not regenerate team skill');
2050
2077
  if (await exists(path.join(repairTmp, '.agents', 'skills', 'agent-team', 'SKILL.md'))) throw new Error('selftest failed: doctor repair did not remove deprecated agent-team alias skill');
2051
2078
  if (!(await exists(path.join(repairTmp, '.agents', 'skills', 'custom-keep', 'SKILL.md')))) throw new Error('selftest failed: doctor repair removed a user-owned custom skill');
2052
2079
  if (await exists(path.join(repairTmp, '.codex', 'skills', 'team', 'SKILL.md'))) throw new Error('selftest failed: doctor repair did not remove legacy .codex/skills');
2080
+ const repairedQuickReference = await safeReadText(path.join(repairTmp, '.codex', 'SNEAKOSCOPE.md'));
2081
+ if (!repairedQuickReference.includes('Install scope: `project`') || repairedQuickReference.includes('tampered')) throw new Error('selftest failed: doctor --fix did not regenerate quick reference');
2082
+ const repairedHooks = await safeReadText(path.join(repairTmp, '.codex', 'hooks.json'));
2083
+ if (!repairedHooks.includes('node ./bin/sks.mjs hook stop') || repairedHooks.includes('tampered hook')) throw new Error('selftest failed: doctor --fix did not regenerate Codex hooks');
2084
+ const repairedPolicy = await readJson(path.join(repairTmp, '.sneakoscope', 'policy.json'));
2085
+ if (repairedPolicy.broken || repairedPolicy.installation?.scope !== 'project' || !repairedPolicy.prompt_pipeline?.dollar_commands?.includes('$Team')) throw new Error('selftest failed: doctor --fix did not regenerate policy');
2086
+ const repairedAgentsMd = await safeReadText(path.join(repairTmp, 'AGENTS.md'));
2087
+ if (!repairedAgentsMd.includes('Do not create unrequested fallback implementation code') || repairedAgentsMd.includes('tampered managed block')) throw new Error('selftest failed: doctor --fix did not repair AGENTS managed block');
2053
2088
  const conflictTmp = tmpdir();
2054
2089
  await ensureDir(path.join(conflictTmp, '.omx'));
2055
2090
  const conflictScan = await scanHarnessConflicts(conflictTmp, { home: path.join(conflictTmp, 'home') });
package/src/core/fsx.mjs 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
 
8
- export const PACKAGE_VERSION = '0.7.0';
8
+ export const PACKAGE_VERSION = '0.7.1';
9
9
  export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
10
10
  export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
11
11