sneakoscope 0.6.6 → 0.6.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
@@ -28,6 +28,14 @@ sks setup
28
28
  sks doctor --fix
29
29
  ```
30
30
 
31
+ Use local-only setup when the generated SKS files must never appear in git status:
32
+
33
+ ```bash
34
+ sks setup --local-only
35
+ ```
36
+
37
+ This writes repo-local excludes to `.git/info/exclude` for `.sneakoscope/`, `.codex/`, `.agents/`, and `AGENTS.md`. If `AGENTS.md` already exists, local-only setup does not modify it.
38
+
31
39
  The npm package name is `sneakoscope`; the command is branded as SKS and exposed as lowercase `sks` for shell portability. The package also exposes a `sneakoscope` command alias, so `sks setup` and `sneakoscope setup` are equivalent.
32
40
  Global installation is the default and recommended setup. During `sks setup` or `sks init`, SKS resolves the global binary when possible and writes that absolute path into `.codex/hooks.json`, which avoids PATH issues in GUI or hook execution environments. For a project-only install, use `npm i -D sneakoscope` and initialize hooks with `npx sks setup --install-scope project`; this writes hook commands that call the local `node_modules/sneakoscope` binary.
33
41
 
@@ -378,10 +386,10 @@ sks aliases
378
386
  sks --help
379
387
  sneakoscope --help
380
388
 
381
- sks setup [--install-scope global|project] [--force] [--json]
389
+ sks setup [--install-scope global|project] [--local-only] [--force] [--json]
382
390
  sks fix-path [--install-scope global|project] [--json]
383
- sks doctor [--fix] [--json] [--install-scope global|project]
384
- sks init [--force] [--install-scope global|project]
391
+ sks doctor [--fix] [--local-only] [--json] [--install-scope global|project]
392
+ sks init [--force] [--local-only] [--install-scope global|project]
385
393
  sks selftest [--mock]
386
394
 
387
395
  sks ralph prepare "task"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "Sneakoscope Codex",
4
- "version": "0.6.6",
4
+ "version": "0.6.7",
5
5
  "description": "Sneakoscope Codex: update-aware, database-safe Codex CLI harness with multi-agent Team orchestration, Ralph no-question execution, autoresearch-style loops, and H-Proof gates.",
6
6
  "type": "module",
7
7
  "homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
package/src/cli/main.mjs CHANGED
@@ -50,10 +50,10 @@ const COMMAND_CATALOG = [
50
50
  { name: 'dollar-commands', usage: 'sks dollar-commands [--json]', description: 'List Codex App $ commands such as $DF.' },
51
51
  { name: 'df', usage: 'sks df', description: 'Explain $DF fast design/content fix mode.' },
52
52
  { name: 'aliases', usage: 'sks aliases', description: 'Show command aliases and npm binary names.' },
53
- { name: 'setup', usage: 'sks setup [--install-scope global|project] [--force] [--json]', description: 'Initialize SKS state, Codex App files, hooks, skills, and rules.' },
53
+ { name: 'setup', usage: 'sks setup [--install-scope global|project] [--local-only] [--force] [--json]', description: 'Initialize SKS state, Codex App files, hooks, skills, and rules.' },
54
54
  { name: 'fix-path', usage: 'sks fix-path [--install-scope global|project] [--json]', description: 'Refresh hook commands with the resolved SKS binary path.' },
55
- { name: 'doctor', usage: 'sks doctor [--fix] [--json] [--install-scope global|project]', description: 'Check Node, Codex CLI, install scope, hooks, skills, DB guard, and Codex App files.' },
56
- { name: 'init', usage: 'sks init [--force] [--install-scope global|project]', description: 'Initialize the local SKS control surface.' },
55
+ { name: 'doctor', usage: 'sks doctor [--fix] [--local-only] [--json] [--install-scope global|project]', description: 'Check Node, Codex CLI, install scope, hooks, skills, DB guard, and Codex App files.' },
56
+ { name: 'init', usage: 'sks init [--force] [--local-only] [--install-scope global|project]', description: 'Initialize the local SKS control surface.' },
57
57
  { name: 'selftest', usage: 'sks selftest [--mock]', description: 'Run local smoke tests without calling a model.' },
58
58
  { name: 'ralph', usage: 'sks ralph prepare|answer|run|status ...', description: 'Run mandatory-clarification Ralph missions with a no-question execution loop.' },
59
59
  { name: 'research', usage: 'sks research prepare|run|status ...', description: 'Run frontier-style research missions with novelty and falsification gates.' },
@@ -134,10 +134,10 @@ Usage:
134
134
  sks dollar-commands [--json]
135
135
  sks df
136
136
  sks aliases
137
- sks setup [--install-scope global|project] [--force] [--json]
137
+ sks setup [--install-scope global|project] [--local-only] [--force] [--json]
138
138
  sks fix-path [--install-scope global|project] [--json]
139
- sks doctor [--fix] [--json] [--install-scope global|project]
140
- sks init [--install-scope global|project]
139
+ sks doctor [--fix] [--local-only] [--json] [--install-scope global|project]
140
+ sks init [--install-scope global|project] [--local-only]
141
141
  sks selftest [--mock]
142
142
  sks ralph prepare "task"
143
143
  sks ralph answer <mission-id|latest> <answers.json>
@@ -326,6 +326,11 @@ Project-only install:
326
326
  npm i -D sneakoscope
327
327
  npx sks setup --install-scope project
328
328
 
329
+ Local-only install artifacts:
330
+ sks setup --local-only
331
+ # writes generated SKS files but excludes .sneakoscope/, .codex/, .agents/, AGENTS.md through .git/info/exclude
332
+ # existing AGENTS.md is not modified in local-only mode
333
+
329
334
  GitHub install for unreleased commits:
330
335
  npm i -g git+${REPOSITORY_URL}
331
336
  `);
@@ -563,6 +568,11 @@ Project-only install:
563
568
  npm i -D sneakoscope
564
569
  npx sks setup --install-scope project
565
570
 
571
+ Local-only install artifacts:
572
+ sks setup --local-only
573
+ # excludes .sneakoscope/, .codex/, .agents/, AGENTS.md through .git/info/exclude
574
+ # existing AGENTS.md is not modified in local-only mode
575
+
566
576
  GitHub install for unreleased commits:
567
577
  npm i -g git+${REPOSITORY_URL}
568
578
  sks setup
@@ -750,8 +760,9 @@ Render and verify:
750
760
  async function setup(args) {
751
761
  const root = await projectRoot();
752
762
  const installScope = installScopeFromArgs(args);
763
+ const localOnly = flag(args, '--local-only');
753
764
  const globalCommand = await globalSksCommand();
754
- const res = await initProject(root, { force: flag(args, '--force'), installScope, globalCommand });
765
+ const res = await initProject(root, { force: flag(args, '--force'), installScope, globalCommand, localOnly });
755
766
  const install = await installStatus(root, installScope, { globalCommand });
756
767
  const hooksPath = path.join(root, '.codex', 'hooks.json');
757
768
  const result = {
@@ -767,6 +778,7 @@ async function setup(args) {
767
778
  agents_rules: path.join(root, 'AGENTS.md')
768
779
  },
769
780
  created: res.created,
781
+ local_only: localOnly,
770
782
  next: ['sks selftest --mock', 'sks doctor', 'sks commands']
771
783
  };
772
784
  if (flag(args, '--json')) return console.log(JSON.stringify(result, null, 2));
@@ -774,6 +786,7 @@ async function setup(args) {
774
786
  console.log(`Project: ${root}`);
775
787
  console.log(`Install: ${install.ok ? 'ok' : 'missing'} ${install.scope} (${install.command_prefix})`);
776
788
  console.log(`Hooks: ${path.relative(root, hooksPath)}`);
789
+ if (localOnly) console.log('Git: local-only (.git/info/exclude; existing AGENTS.md not modified)');
777
790
  console.log(`Codex App: .codex/config.toml, .codex/hooks.json, .codex/skills, .codex/agents, .codex/SNEAKOSCOPE.md`);
778
791
  console.log(`Prompt: default optimization pipeline, $DF fast design/content route`);
779
792
  console.log(`Skills: .codex/skills, .agents/skills`);
@@ -789,7 +802,7 @@ async function fixPath(args) {
789
802
  ? installScopeFromArgs(args)
790
803
  : normalizeInstallScope(manifest?.installation?.scope || 'global');
791
804
  const globalCommand = await globalSksCommand();
792
- await initProject(root, { installScope, globalCommand });
805
+ await initProject(root, { installScope, globalCommand, localOnly: flag(args, '--local-only') || Boolean(manifest?.git?.local_only) });
793
806
  const install = await installStatus(root, installScope, { globalCommand });
794
807
  const result = {
795
808
  root,
@@ -814,7 +827,8 @@ async function doctor(args) {
814
827
  : null;
815
828
  if (flag(args, '--fix')) {
816
829
  const fixScope = requestedScope || 'global';
817
- await initProject(root, { installScope: fixScope, globalCommand: await globalSksCommand() });
830
+ const existingManifest = await readJson(path.join(root, '.sneakoscope', 'manifest.json'), null);
831
+ await initProject(root, { installScope: fixScope, globalCommand: await globalSksCommand(), localOnly: flag(args, '--local-only') || Boolean(existingManifest?.git?.local_only) });
818
832
  }
819
833
  const codex = await getCodexInfo();
820
834
  const rust = await rustInfo();
@@ -872,10 +886,12 @@ async function doctor(args) {
872
886
  async function init(args) {
873
887
  const root = await projectRoot();
874
888
  const installScope = installScopeFromArgs(args);
889
+ const localOnly = flag(args, '--local-only');
875
890
  const globalCommand = await globalSksCommand();
876
- const res = await initProject(root, { force: flag(args, '--force'), installScope, globalCommand });
891
+ const res = await initProject(root, { force: flag(args, '--force'), installScope, globalCommand, localOnly });
877
892
  console.log(`Initialized Sneakoscope Codex in ${root}`);
878
893
  console.log(`Install scope: ${installScope} (${sksCommandPrefix(installScope, { globalCommand })})`);
894
+ if (localOnly) console.log('Git mode: local-only (.git/info/exclude)');
879
895
  for (const x of res.created) console.log(`- ${x}`);
880
896
  }
881
897
 
@@ -1207,6 +1223,16 @@ async function selftest() {
1207
1223
  await initProject(projectScopeTmp, { installScope: 'project' });
1208
1224
  const projectHooks = await readJson(path.join(projectScopeTmp, '.codex', 'hooks.json'));
1209
1225
  if (projectHooks.hooks.PreToolUse[0].hooks[0].command !== 'node ./node_modules/sneakoscope/bin/sks.mjs hook pre-tool') throw new Error('selftest failed: project install hook command missing');
1226
+ const localOnlyTmp = tmpdir();
1227
+ await ensureDir(path.join(localOnlyTmp, '.git'));
1228
+ await writeTextAtomic(path.join(localOnlyTmp, 'AGENTS.md'), 'existing local rules\n');
1229
+ await initProject(localOnlyTmp, { localOnly: true });
1230
+ const localExclude = await safeReadText(path.join(localOnlyTmp, '.git', 'info', 'exclude'));
1231
+ if (!localExclude.includes('.codex/') || !localExclude.includes('AGENTS.md')) throw new Error('selftest failed: local-only git excludes missing');
1232
+ const localAgents = await safeReadText(path.join(localOnlyTmp, 'AGENTS.md'));
1233
+ if (localAgents.trim() !== 'existing local rules') throw new Error('selftest failed: local-only modified existing AGENTS.md');
1234
+ const localManifest = await readJson(path.join(localOnlyTmp, '.sneakoscope', 'manifest.json'));
1235
+ if (!localManifest.git?.local_only) throw new Error('selftest failed: local-only manifest missing');
1210
1236
  if (!isTransientNpmBinPath('/tmp/.npm/_npx/abc/node_modules/.bin/sks')) throw new Error('selftest failed: npx bin path not recognized as transient');
1211
1237
  if (!isTransientNpmBinPath('/tmp/.npm-cache/_cacache/tmp/git-cloneabc/bin/sks.mjs')) throw new Error('selftest failed: npm cache git clone path not recognized as transient');
1212
1238
  if (isTransientNpmBinPath('/usr/local/bin/sks')) throw new Error('selftest failed: stable global bin marked transient');
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.6.6';
8
+ export const PACKAGE_VERSION = '0.6.7';
9
9
  export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
10
10
  export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
11
11
 
package/src/core/init.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import path from 'node:path';
2
- import { ensureDir, readJson, writeJsonAtomic, writeTextAtomic, mergeManagedBlock, nowIso, PACKAGE_VERSION, exists } from './fsx.mjs';
2
+ import { ensureDir, readJson, readText, writeJsonAtomic, writeTextAtomic, mergeManagedBlock, nowIso, PACKAGE_VERSION, exists } from './fsx.mjs';
3
3
  import { DEFAULT_RETENTION_POLICY } from './retention.mjs';
4
4
  import { DEFAULT_DB_SAFETY_POLICY } from './db-safety.mjs';
5
5
 
@@ -98,12 +98,15 @@ A task is not done until relevant tests are run or justified, unsupported critic
98
98
  export async function initProject(root, opts = {}) {
99
99
  const created = [];
100
100
  const installScope = normalizeInstallScope(opts.installScope || 'global');
101
+ const localOnly = Boolean(opts.localOnly);
101
102
  const hookCommandPrefix = opts.hookCommandPrefix || sksCommandPrefix(installScope, { globalCommand: opts.globalCommand });
102
103
  const sine = path.join(root, '.sneakoscope');
103
104
  const dirs = [
104
105
  '.sneakoscope/state', '.sneakoscope/missions', '.sneakoscope/db', '.sneakoscope/bus', '.sneakoscope/hproof', '.sneakoscope/db', '.sneakoscope/wiki', '.sneakoscope/memory/q0_raw', '.sneakoscope/memory/q1_evidence', '.sneakoscope/memory/q2_facts', '.sneakoscope/memory/q3_tags', '.sneakoscope/memory/q4_bits', '.sneakoscope/gx/cartridges', '.sneakoscope/model/fingerprints', '.sneakoscope/genome/candidates', '.sneakoscope/trajectories/raw', '.sneakoscope/locks', '.sneakoscope/tmp', '.sneakoscope/arenas', '.sneakoscope/reports', '.codex', '.codex/skills', '.codex/agents', '.agents/skills'
105
106
  ];
106
107
  for (const d of dirs) await ensureDir(path.join(root, d));
108
+ const localExclude = localOnly ? await ensureLocalOnlyGitExclude(root) : null;
109
+ if (localExclude?.path) created.push(`${path.relative(root, localExclude.path)} local-only excludes`);
107
110
 
108
111
  await writeJsonAtomic(path.join(sine, 'manifest.json'), {
109
112
  package: 'sneakoscope',
@@ -138,6 +141,11 @@ export async function initProject(root, opts = {}) {
138
141
  channel_map: { r: 'domainAngle', g: 'layerRadius', b: 'phase', a: 'concentration' },
139
142
  continuity_model: 'selected_text_plus_hydratable_rgba_trig_anchors'
140
143
  },
144
+ git: {
145
+ local_only: localOnly,
146
+ exclude_path: localExclude?.path ? path.relative(root, localExclude.path) : null,
147
+ excluded_patterns: localExclude?.patterns || []
148
+ },
141
149
  database_safety: 'destructive_db_operations_denied_always',
142
150
  gx_renderer: 'deterministic_svg_html'
143
151
  });
@@ -157,7 +165,13 @@ export async function initProject(root, opts = {}) {
157
165
  const policy = await readJson(policyPath, {});
158
166
  await writeJsonAtomic(policyPath, {
159
167
  ...policy,
160
- installation: installPolicy(installScope, hookCommandPrefix)
168
+ installation: installPolicy(installScope, hookCommandPrefix),
169
+ git: {
170
+ ...(policy.git || {}),
171
+ local_only: localOnly || Boolean(policy.git?.local_only),
172
+ exclude_path: localExclude?.path ? path.relative(root, localExclude.path) : policy.git?.exclude_path || null,
173
+ excluded_patterns: localExclude?.patterns || policy.git?.excluded_patterns || []
174
+ }
161
175
  });
162
176
  }
163
177
 
@@ -165,6 +179,11 @@ export async function initProject(root, opts = {}) {
165
179
  return {
166
180
  schema_version: 1,
167
181
  installation: installPolicy(scope, commandPrefix),
182
+ git: {
183
+ local_only: localOnly,
184
+ exclude_path: localExclude?.path ? path.relative(root, localExclude.path) : null,
185
+ excluded_patterns: localExclude?.patterns || []
186
+ },
168
187
  retention: DEFAULT_RETENTION_POLICY,
169
188
  update_check: {
170
189
  enabled: true,
@@ -244,8 +263,13 @@ export async function initProject(root, opts = {}) {
244
263
  created.push('.sneakoscope/state/current.json');
245
264
  }
246
265
 
247
- await mergeManagedBlock(path.join(root, 'AGENTS.md'), 'Sneakoscope Codex GX MANAGED BLOCK', AGENTS_BLOCK);
248
- created.push('AGENTS.md managed block');
266
+ const agentsMdPath = path.join(root, 'AGENTS.md');
267
+ if (localOnly && await exists(agentsMdPath)) {
268
+ created.push('AGENTS.md skipped (local-only existing file)');
269
+ } else {
270
+ await mergeManagedBlock(agentsMdPath, 'Sneakoscope Codex GX MANAGED BLOCK', AGENTS_BLOCK);
271
+ created.push('AGENTS.md managed block');
272
+ }
249
273
 
250
274
  await writeTextAtomic(path.join(root, '.codex', 'config.toml'), `[features]\ncodex_hooks = true\nmulti_agent = true\n\n[agents]\nmax_threads = 6\nmax_depth = 1\n\n[agents.team_consensus]\ndescription = "Planning and debate agent for SKS Team mode. Maps options, constraints, risks, and proposes the agreed objective before implementation starts."\nconfig_file = "./agents/team-consensus.toml"\nnickname_candidates = ["Consensus", "Atlas"]\n\n[agents.implementation_worker]\ndescription = "Implementation worker for SKS Team mode. Owns a clearly bounded write set and coordinates with other workers without reverting their edits."\nconfig_file = "./agents/implementation-worker.toml"\nnickname_candidates = ["Builder", "Mason"]\n\n[agents.db_safety_reviewer]\ndescription = "Read-only database safety reviewer for SQL, migrations, RLS, destructive-operation risk, and rollback safety."\nconfig_file = "./agents/db-safety-reviewer.toml"\nnickname_candidates = ["Sentinel", "Ledger"]\n\n[agents.qa_reviewer]\ndescription = "Read-only verification reviewer for correctness, tests, regressions, and missing evidence."\nconfig_file = "./agents/qa-reviewer.toml"\nnickname_candidates = ["Verifier", "Scout"]\n\n[profiles.sks-ralph]\nmodel = "gpt-5.5"\napproval_policy = "never"\nsandbox_mode = "workspace-write"\nmodel_reasoning_effort = "high"\n\n[profiles.sks-research]\nmodel = "gpt-5.5"\napproval_policy = "never"\nsandbox_mode = "workspace-write"\nmodel_reasoning_effort = "xhigh"\n\n[profiles.sks-team]\nmodel = "gpt-5.5"\napproval_policy = "on-request"\nsandbox_mode = "workspace-write"\nmodel_reasoning_effort = "high"\n\n[profiles.sks-default]\nmodel = "gpt-5.5"\napproval_policy = "on-request"\nsandbox_mode = "workspace-write"\nmodel_reasoning_effort = "medium"\n`);
251
275
  created.push('.codex/config.toml');
@@ -272,6 +296,32 @@ export async function initProject(root, opts = {}) {
272
296
  return { created };
273
297
  }
274
298
 
299
+ async function ensureLocalOnlyGitExclude(root) {
300
+ const gitDir = await resolveGitDir(root);
301
+ if (!gitDir) return { path: null, patterns: [] };
302
+ const patterns = ['.sneakoscope/', '.codex/', '.agents/', 'AGENTS.md'];
303
+ const excludePath = path.join(gitDir, 'info', 'exclude');
304
+ await ensureDir(path.dirname(excludePath));
305
+ const markerStart = '# Sneakoscope Codex local-only generated files';
306
+ const current = await readText(excludePath, '');
307
+ if (!current.includes(markerStart)) {
308
+ const block = `${markerStart}\n${patterns.join('\n')}\n`;
309
+ await writeTextAtomic(excludePath, `${current.trimEnd()}${current.trim() ? '\n\n' : ''}${block}`);
310
+ }
311
+ return { path: excludePath, patterns };
312
+ }
313
+
314
+ async function resolveGitDir(root) {
315
+ const dotGit = path.join(root, '.git');
316
+ if (!(await exists(dotGit))) return null;
317
+ const text = await readText(dotGit, null);
318
+ if (typeof text === 'string') {
319
+ const match = text.match(/^gitdir:\s*(.+)\s*$/m);
320
+ if (match) return path.resolve(root, match[1]);
321
+ }
322
+ return dotGit;
323
+ }
324
+
275
325
  function codexAppQuickReference(scope, commandPrefix) {
276
326
  return `# Sneakoscope Codex for Codex App
277
327