sneakoscope 0.6.87 → 0.6.89
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 +4 -0
- package/package.json +1 -1
- package/src/cli/main.mjs +15 -1
- package/src/cli/maintenance-commands.mjs +2 -0
- package/src/core/fsx.mjs +1 -1
- package/src/core/init.mjs +34 -1
package/README.md
CHANGED
|
@@ -90,6 +90,8 @@ sks bootstrap
|
|
|
90
90
|
|
|
91
91
|
`sks` commands work even when no project root is present. Project-aware commands use the nearest `.sneakoscope`, `.dcodex`, or `.git` root; if none exists, SKS uses a per-user global runtime root. `sks bootstrap` still initializes the current project when you want project-local hooks, skills, and TriWiki state.
|
|
92
92
|
|
|
93
|
+
Project setup writes shared `.gitignore` entries for generated SKS files: `.sneakoscope/`, `.codex/`, `.agents/`, and managed `AGENTS.md`. Use `sks setup --local-only` when you want those excludes kept only in `.git/info/exclude`.
|
|
94
|
+
|
|
93
95
|
### One-Shot Install
|
|
94
96
|
|
|
95
97
|
Use this when you do not want to keep a global install:
|
|
@@ -256,6 +258,8 @@ Generated app files include:
|
|
|
256
258
|
| `.codex/config.toml` | Codex profiles, agents, and MCP configuration. |
|
|
257
259
|
| `.sneakoscope/` | Runtime state, missions, wiki packs, policies, and artifacts. |
|
|
258
260
|
|
|
261
|
+
Default setup adds these generated SKS paths to the project `.gitignore`; `--local-only` uses `.git/info/exclude` instead.
|
|
262
|
+
|
|
259
263
|
Use `sks dollar-commands` to confirm that terminal discovery and Codex App prompt commands agree.
|
|
260
264
|
|
|
261
265
|
TriWiki is intentionally sparse: `sks wiki sweep` records demote, soft-forget, archive, delete, promote-to-skill, and promote-to-rule candidates instead of injecting every old claim into future prompts. `sks harness fixture` validates the broader Harness Growth Factory contract: deliberate forgetting fixtures, skill card metadata, experiment schema, tool-error taxonomy, permission profiles, MultiAgentV2 defaults, and Warp cockpit view coverage. `sks code-structure scan` flags handwritten files above 1000/2000/3000-line thresholds so new logic can be extracted before command files become harder to maintain.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.89",
|
|
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
|
@@ -1385,6 +1385,7 @@ async function codexAppHelp(args = []) {
|
|
|
1385
1385
|
`Skills: project=${skills.project.ok ? 'ok' : `missing ${skills.project.missing.length}`} global=${skills.global.ok ? 'ok' : `missing ${skills.global.missing.length}`}`, '',
|
|
1386
1386
|
'Setup:', ' sks bootstrap', ' sks deps check', ' sks codex-app check', ' sks warp check', '',
|
|
1387
1387
|
'Generated files:', ' .codex/config.toml', ' .codex/hooks.json', ' .agents/skills/', ' .codex/agents/', ' .codex/SNEAKOSCOPE.md', ' AGENTS.md', '',
|
|
1388
|
+
'Git ignore:', ' default setup writes .gitignore entries for .sneakoscope/, .codex/, .agents/, AGENTS.md', ' --local-only writes those patterns to .git/info/exclude instead', '',
|
|
1388
1389
|
'Prompt routes:', formatDollarCommandsCompact(' ')
|
|
1389
1390
|
].join('\n'));
|
|
1390
1391
|
}
|
|
@@ -1564,6 +1565,7 @@ async function setup(args) {
|
|
|
1564
1565
|
console.log(`Hooks: ${path.relative(root, hooksPath)}`);
|
|
1565
1566
|
console.log(`Version: ${versioningInfo.enabled ? (versioningInfo.hook_installed ? 'auto-bump enabled' : 'auto-bump hook missing') : 'not enabled'}${versioningInfo.package_version ? ` (${versioningInfo.package_version})` : ''}`);
|
|
1566
1567
|
if (localOnly) console.log('Git: local-only (.git/info/exclude; user AGENTS preserved, SKS managed block refreshed)');
|
|
1568
|
+
else console.log('Git: .gitignore ignores SKS generated files');
|
|
1567
1569
|
console.log(`Codex App: .codex/config.toml, .codex/hooks.json, .agents/skills, .codex/agents, .codex/SNEAKOSCOPE.md`);
|
|
1568
1570
|
console.log(`Global $: ${globalSkills.status === 'installed' ? 'ok' : globalSkills.status} ${globalSkills.root || ''}`.trimEnd());
|
|
1569
1571
|
console.log(`App tools: ${appRuntime.ok ? 'ok' : 'needs setup'} Codex App=${appRuntime.app.installed ? 'ok' : 'missing'} Browser Use=${appRuntime.mcp.has_browser_use ? 'ok' : 'missing'} Computer Use=${appRuntime.mcp.has_computer_use ? 'ok' : 'missing'}`);
|
|
@@ -1759,6 +1761,7 @@ async function init(args) {
|
|
|
1759
1761
|
console.log(`Initialized ㅅㅋㅅ in ${root}`);
|
|
1760
1762
|
console.log(`Install scope: ${installScope} (${sksCommandPrefix(installScope, { globalCommand })})`);
|
|
1761
1763
|
if (localOnly) console.log('Git mode: local-only (.git/info/exclude)');
|
|
1764
|
+
else console.log('Git mode: shared .gitignore');
|
|
1762
1765
|
for (const x of res.created) console.log(`- ${x}`);
|
|
1763
1766
|
}
|
|
1764
1767
|
|
|
@@ -1967,9 +1970,11 @@ async function selftest() {
|
|
|
1967
1970
|
await writeJsonAtomic(path.join(postinstallBootstrapTmp, 'package.json'), { name: 'postinstall-bootstrap-smoke', version: '0.0.0' });
|
|
1968
1971
|
const postinstallBootstrap = await runProcess(process.execPath, [path.join(packageRoot(), 'bin', 'sks.mjs'), 'postinstall'], { cwd: postinstallBootstrapTmp, input: 'y\n', env: { INIT_CWD: postinstallBootstrapTmp, HOME: path.join(postinstallBootstrapTmp, 'home'), SKS_SKIP_POSTINSTALL_SHIM: '1', SKS_SKIP_POSTINSTALL_CONTEXT7: '1', SKS_SKIP_POSTINSTALL_GLOBAL_SKILLS: '1', SKS_SKIP_CLI_TOOLS: '1', SKS_POSTINSTALL_PROMPT: '1' }, timeoutMs: 30000, maxOutputBytes: 256 * 1024 });
|
|
1969
1972
|
if (postinstallBootstrap.code !== 0 || !String(postinstallBootstrap.stdout || '').includes('SKS Ready')) throw new Error(`selftest failed: approved postinstall bootstrap did not run: ${postinstallBootstrap.stderr}`);
|
|
1970
|
-
for (const rel of ['.agents/skills/team/SKILL.md', '.codex/config.toml', '.codex/hooks.json', '.sneakoscope/harness-guard.json', '.codex/SNEAKOSCOPE.md', 'AGENTS.md']) {
|
|
1973
|
+
for (const rel of ['.agents/skills/team/SKILL.md', '.codex/config.toml', '.codex/hooks.json', '.sneakoscope/harness-guard.json', '.codex/SNEAKOSCOPE.md', 'AGENTS.md', '.gitignore']) {
|
|
1971
1974
|
if (!(await exists(path.join(postinstallBootstrapTmp, rel)))) throw new Error(`selftest failed: bootstrap did not create ${rel}`);
|
|
1972
1975
|
}
|
|
1976
|
+
const postinstallBootstrapGitignore = await safeReadText(path.join(postinstallBootstrapTmp, '.gitignore'));
|
|
1977
|
+
if (!postinstallBootstrapGitignore.includes('.sneakoscope/') || !postinstallBootstrapGitignore.includes('.codex/') || !postinstallBootstrapGitignore.includes('.agents/') || !postinstallBootstrapGitignore.includes('AGENTS.md')) throw new Error('selftest failed: bootstrap did not ignore SKS generated files');
|
|
1973
1978
|
const bootstrapJsonTmp = tmpdir();
|
|
1974
1979
|
await writeJsonAtomic(path.join(bootstrapJsonTmp, 'package.json'), { name: 'bootstrap-json-smoke', version: '0.0.0' });
|
|
1975
1980
|
const bootstrapJson = await runProcess(process.execPath, [path.join(packageRoot(), 'bin', 'sks.mjs'), 'bootstrap', '--json'], { cwd: bootstrapJsonTmp, env: { HOME: path.join(bootstrapJsonTmp, 'home'), SKS_SKIP_POSTINSTALL_GLOBAL_SKILLS: '1', SKS_SKIP_CLI_TOOLS: '1' }, timeoutMs: 30000, maxOutputBytes: 256 * 1024 });
|
|
@@ -2090,10 +2095,19 @@ async function selftest() {
|
|
|
2090
2095
|
await initProject(localOnlyTmp, { localOnly: true });
|
|
2091
2096
|
const localExclude = await safeReadText(path.join(localOnlyTmp, '.git', 'info', 'exclude'));
|
|
2092
2097
|
if (!localExclude.includes('.codex/') || !localExclude.includes('AGENTS.md')) throw new Error('selftest failed: local-only git excludes missing');
|
|
2098
|
+
if (await exists(path.join(localOnlyTmp, '.gitignore'))) throw new Error('selftest failed: local-only wrote shared .gitignore');
|
|
2093
2099
|
const localAgents = await safeReadText(path.join(localOnlyTmp, 'AGENTS.md'));
|
|
2094
2100
|
if (localAgents.trim() !== 'existing local rules') throw new Error('selftest failed: local-only modified existing AGENTS.md');
|
|
2095
2101
|
const localManifest = await readJson(path.join(localOnlyTmp, '.sneakoscope', 'manifest.json'));
|
|
2096
2102
|
if (!localManifest.git?.local_only) throw new Error('selftest failed: local-only manifest missing');
|
|
2103
|
+
const gitignoreTmp = tmpdir();
|
|
2104
|
+
await writeTextAtomic(path.join(gitignoreTmp, '.gitignore'), 'node_modules/\n.sneakoscope/\n');
|
|
2105
|
+
await initProject(gitignoreTmp, {});
|
|
2106
|
+
const gitignoreText = await safeReadText(path.join(gitignoreTmp, '.gitignore'));
|
|
2107
|
+
if (!gitignoreText.includes('node_modules/') || !gitignoreText.includes('# BEGIN Sneakoscope Codex generated files') || !gitignoreText.includes('.codex/') || !gitignoreText.includes('.agents/') || !gitignoreText.includes('AGENTS.md')) throw new Error('selftest failed: shared .gitignore did not preserve existing entries and add SKS patterns');
|
|
2108
|
+
await initProject(gitignoreTmp, {});
|
|
2109
|
+
const gitignoreTextSecond = await safeReadText(path.join(gitignoreTmp, '.gitignore'));
|
|
2110
|
+
if ((gitignoreTextSecond.match(/BEGIN Sneakoscope Codex generated files/g) || []).length !== 1) throw new Error('selftest failed: shared .gitignore managed block duplicated');
|
|
2097
2111
|
const managedAgentsTmp = tmpdir();
|
|
2098
2112
|
await ensureDir(path.join(managedAgentsTmp, '.git'));
|
|
2099
2113
|
await writeTextAtomic(path.join(managedAgentsTmp, 'AGENTS.md'), '<!-- BEGIN Sneakoscope Codex GX MANAGED BLOCK -->\nold managed rules\n<!-- END Sneakoscope Codex GX MANAGED BLOCK -->\n');
|
|
@@ -89,6 +89,8 @@ Local-only install artifacts:
|
|
|
89
89
|
# writes generated SKS files but excludes .sneakoscope/, .codex/, .agents/, AGENTS.md through .git/info/exclude
|
|
90
90
|
# user-owned AGENTS.md is preserved; an existing SKS managed block is refreshed
|
|
91
91
|
|
|
92
|
+
Default project setup writes the same SKS generated-file patterns into the project .gitignore.
|
|
93
|
+
|
|
92
94
|
GitHub install for unreleased commits:
|
|
93
95
|
npm i -g git+${REPOSITORY_URL}
|
|
94
96
|
sks bootstrap
|
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.
|
|
8
|
+
export const PACKAGE_VERSION = '0.6.89';
|
|
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
|
@@ -9,6 +9,8 @@ import { installVersionGitHook } from './version-manager.mjs';
|
|
|
9
9
|
import { CODEX_COMPUTER_USE_ONLY_POLICY, DOLLAR_COMMANDS, DOLLAR_COMMAND_ALIASES, DOLLAR_SKILL_NAMES, FROM_CHAT_IMG_CHECKLIST_ARTIFACT, FROM_CHAT_IMG_COVERAGE_ARTIFACT, FROM_CHAT_IMG_QA_LOOP_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS, RECOMMENDED_MCP_SERVERS, RECOMMENDED_SKILLS, chatCaptureIntakeText, context7ConfigToml, stackCurrentDocsPolicyText, triwikiContextTracking, triwikiContextTrackingText, triwikiStagePolicyText } from './routes.mjs';
|
|
10
10
|
|
|
11
11
|
const REFLECTION_MEMORY_PATH = '.sneakoscope/memory/q2_facts/post-route-reflection.md';
|
|
12
|
+
const SKS_GENERATED_GIT_PATTERNS = ['.sneakoscope/', '.codex/', '.agents/', 'AGENTS.md'];
|
|
13
|
+
|
|
12
14
|
function reflectionInstructionText(commandPrefix = 'sks') {
|
|
13
15
|
return `Post-route reflection: full routes load \`reflection\` after work/tests and before final; DFix/Answer/Help/Wiki/SKS discovery are exempt. Write reflection.md; record only real misses/gaps, or no_issue_acknowledged. For lessons, append TriWiki claim rows to ${REFLECTION_MEMORY_PATH}. Run "${commandPrefix} wiki refresh" or pack, validate, then pass reflection-gate.json.`;
|
|
14
16
|
}
|
|
@@ -107,7 +109,9 @@ export async function initProject(root, opts = {}) {
|
|
|
107
109
|
];
|
|
108
110
|
for (const d of dirs) await ensureDir(path.join(root, d));
|
|
109
111
|
const localExclude = localOnly ? await ensureLocalOnlyGitExclude(root) : null;
|
|
112
|
+
const sharedIgnore = localOnly ? null : await ensureSharedGitIgnore(root);
|
|
110
113
|
if (localExclude?.path) created.push(`${path.relative(root, localExclude.path)} local-only excludes`);
|
|
114
|
+
if (sharedIgnore?.changed) created.push(`${path.relative(root, sharedIgnore.path)} SKS generated files ignore`);
|
|
111
115
|
|
|
112
116
|
await writeJsonAtomic(path.join(sine, 'manifest.json'), {
|
|
113
117
|
package: 'sneakoscope',
|
|
@@ -165,6 +169,8 @@ export async function initProject(root, opts = {}) {
|
|
|
165
169
|
},
|
|
166
170
|
git: {
|
|
167
171
|
local_only: localOnly,
|
|
172
|
+
ignore_path: sharedIgnore?.path ? path.relative(root, sharedIgnore.path) : null,
|
|
173
|
+
ignored_patterns: sharedIgnore?.patterns || [],
|
|
168
174
|
exclude_path: localExclude?.path ? path.relative(root, localExclude.path) : null,
|
|
169
175
|
excluded_patterns: localExclude?.patterns || [],
|
|
170
176
|
versioning: {
|
|
@@ -198,6 +204,8 @@ export async function initProject(root, opts = {}) {
|
|
|
198
204
|
git: {
|
|
199
205
|
...(policy.git || {}),
|
|
200
206
|
local_only: localOnly || Boolean(policy.git?.local_only),
|
|
207
|
+
ignore_path: sharedIgnore?.path ? path.relative(root, sharedIgnore.path) : policy.git?.ignore_path || null,
|
|
208
|
+
ignored_patterns: sharedIgnore?.patterns || policy.git?.ignored_patterns || [],
|
|
201
209
|
exclude_path: localExclude?.path ? path.relative(root, localExclude.path) : policy.git?.exclude_path || null,
|
|
202
210
|
excluded_patterns: localExclude?.patterns || policy.git?.excluded_patterns || [],
|
|
203
211
|
versioning: {
|
|
@@ -267,6 +275,8 @@ export async function initProject(root, opts = {}) {
|
|
|
267
275
|
installation: installPolicy(scope, commandPrefix),
|
|
268
276
|
git: {
|
|
269
277
|
local_only: localOnly,
|
|
278
|
+
ignore_path: sharedIgnore?.path ? path.relative(root, sharedIgnore.path) : null,
|
|
279
|
+
ignored_patterns: sharedIgnore?.patterns || [],
|
|
270
280
|
exclude_path: localExclude?.path ? path.relative(root, localExclude.path) : null,
|
|
271
281
|
excluded_patterns: localExclude?.patterns || [],
|
|
272
282
|
versioning: {
|
|
@@ -445,10 +455,33 @@ policy = "Deny destructive database operations, credential exfiltration, persist
|
|
|
445
455
|
return { created };
|
|
446
456
|
}
|
|
447
457
|
|
|
458
|
+
async function ensureSharedGitIgnore(root) {
|
|
459
|
+
const patterns = SKS_GENERATED_GIT_PATTERNS;
|
|
460
|
+
const ignorePath = path.join(root, '.gitignore');
|
|
461
|
+
const markerStart = '# BEGIN Sneakoscope Codex generated files';
|
|
462
|
+
const markerEnd = '# END Sneakoscope Codex generated files';
|
|
463
|
+
const managedBlock = `${markerStart}\n${patterns.join('\n')}\n${markerEnd}\n`;
|
|
464
|
+
const current = await readText(ignorePath, '');
|
|
465
|
+
if (current.includes(markerStart)) {
|
|
466
|
+
const re = new RegExp(`${escapeRegExp(markerStart)}[\\s\\S]*?${escapeRegExp(markerEnd)}\\n?`);
|
|
467
|
+
const next = current.replace(re, managedBlock);
|
|
468
|
+
if (next !== current) await writeTextAtomic(ignorePath, next.endsWith('\n') ? next : `${next}\n`);
|
|
469
|
+
return { path: ignorePath, patterns, changed: next !== current };
|
|
470
|
+
}
|
|
471
|
+
const existing = new Set(current.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
|
|
472
|
+
const missing = patterns.filter((pattern) => !existing.has(pattern));
|
|
473
|
+
if (!missing.length) return { path: ignorePath, patterns, changed: false };
|
|
474
|
+
const block = missing.length === patterns.length
|
|
475
|
+
? managedBlock
|
|
476
|
+
: `${markerStart}\n${missing.join('\n')}\n${markerEnd}\n`;
|
|
477
|
+
await writeTextAtomic(ignorePath, `${current.trimEnd()}${current.trim() ? '\n\n' : ''}${block}`);
|
|
478
|
+
return { path: ignorePath, patterns, changed: true };
|
|
479
|
+
}
|
|
480
|
+
|
|
448
481
|
async function ensureLocalOnlyGitExclude(root) {
|
|
449
482
|
const gitDir = await resolveGitDir(root);
|
|
450
483
|
if (!gitDir) return { path: null, patterns: [] };
|
|
451
|
-
const patterns =
|
|
484
|
+
const patterns = SKS_GENERATED_GIT_PATTERNS;
|
|
452
485
|
const excludePath = path.join(gitDir, 'info', 'exclude');
|
|
453
486
|
await ensureDir(path.dirname(excludePath));
|
|
454
487
|
const markerStart = '# Sneakoscope Codex local-only generated files';
|