sneakoscope 0.9.13 → 0.9.14

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.
Files changed (88) hide show
  1. package/README.md +30 -39
  2. package/crates/sks-core/Cargo.lock +99 -1
  3. package/crates/sks-core/Cargo.toml +2 -1
  4. package/crates/sks-core/src/main.rs +77 -43
  5. package/package.json +8 -5
  6. package/src/cli/command-registry.mjs +73 -114
  7. package/src/cli/feature-commands.mjs +44 -5
  8. package/src/cli/install-helpers.mjs +2 -2
  9. package/src/cli/router.mjs +2 -3
  10. package/src/commands/aliases.mjs +2 -0
  11. package/src/commands/auto-review.mjs +5 -0
  12. package/src/commands/autoresearch.mjs +5 -0
  13. package/src/commands/bootstrap.mjs +2 -0
  14. package/src/commands/code-structure.mjs +5 -0
  15. package/src/commands/codex-lb.mjs +61 -3
  16. package/src/commands/commands.mjs +5 -0
  17. package/src/commands/commit-and-push.mjs +5 -0
  18. package/src/commands/commit.mjs +5 -0
  19. package/src/commands/computer-use.mjs +31 -0
  20. package/src/commands/conflicts.mjs +13 -0
  21. package/src/commands/context7.mjs +5 -0
  22. package/src/commands/db.mjs +1 -1
  23. package/src/commands/deps.mjs +5 -0
  24. package/src/commands/dfix.mjs +2 -0
  25. package/src/commands/doctor.mjs +2 -2
  26. package/src/commands/dollar-commands.mjs +2 -0
  27. package/src/commands/eval.mjs +5 -0
  28. package/src/commands/fix-path.mjs +2 -0
  29. package/src/commands/gc.mjs +2 -0
  30. package/src/commands/goal.mjs +5 -0
  31. package/src/commands/guard.mjs +10 -0
  32. package/src/commands/gx.mjs +5 -0
  33. package/src/commands/harness.mjs +5 -0
  34. package/src/commands/help.mjs +3 -74
  35. package/src/commands/hook.mjs +8 -0
  36. package/src/commands/hproof.mjs +5 -0
  37. package/src/commands/image-ux-review.mjs +38 -0
  38. package/src/commands/init.mjs +2 -0
  39. package/src/commands/mad-sks.mjs +14 -0
  40. package/src/commands/memory.mjs +5 -0
  41. package/src/commands/openclaw.mjs +2 -0
  42. package/src/commands/perf.mjs +2 -2
  43. package/src/commands/pipeline.mjs +25 -0
  44. package/src/commands/postinstall.mjs +2 -0
  45. package/src/commands/ppt.mjs +44 -0
  46. package/src/commands/profile.mjs +5 -0
  47. package/src/commands/proof-field.mjs +5 -0
  48. package/src/commands/proof.mjs +22 -1
  49. package/src/commands/qa-loop.mjs +5 -0
  50. package/src/commands/quickstart.mjs +2 -0
  51. package/src/commands/reasoning.mjs +2 -0
  52. package/src/commands/recallpulse.mjs +5 -0
  53. package/src/commands/research.mjs +5 -0
  54. package/src/commands/selftest.mjs +2 -0
  55. package/src/commands/setup.mjs +2 -0
  56. package/src/commands/skill-dream.mjs +5 -0
  57. package/src/commands/stats.mjs +2 -0
  58. package/src/commands/team.mjs +2 -0
  59. package/src/commands/tmux.mjs +5 -0
  60. package/src/commands/update-check.mjs +2 -0
  61. package/src/commands/usage.mjs +2 -0
  62. package/src/commands/validate-artifacts.mjs +2 -0
  63. package/src/commands/versioning.mjs +16 -0
  64. package/src/commands/wiki.mjs +2 -2
  65. package/src/core/codex-lb-circuit.mjs +18 -0
  66. package/src/core/commands/basic-cli.mjs +315 -0
  67. package/src/{cli/maintenance-commands.mjs → core/commands/route-cli.mjs} +37 -37
  68. package/src/core/feature-fixture-runner.mjs +109 -0
  69. package/src/core/feature-fixtures.mjs +1 -1
  70. package/src/core/feature-registry.mjs +19 -7
  71. package/src/core/fsx.mjs +1 -1
  72. package/src/core/git-simple.mjs +118 -0
  73. package/src/core/pipeline.mjs +1 -1
  74. package/src/core/proof/route-finalizer-fixtures.mjs +21 -0
  75. package/src/core/proof/route-finalizer-policy.mjs +13 -0
  76. package/src/core/proof/route-finalizer.mjs +82 -0
  77. package/src/core/proof-field.mjs +2 -2
  78. package/src/core/routes.mjs +31 -1
  79. package/src/core/rust-accelerator.mjs +8 -3
  80. package/src/core/version.mjs +1 -1
  81. package/src/core/wiki-image/before-after-relation.mjs +1 -0
  82. package/src/core/wiki-image/computer-use-evidence.mjs +1 -0
  83. package/src/core/wiki-image/generated-review-parser.mjs +1 -0
  84. package/src/core/wiki-image/image-ux-evidence.mjs +1 -0
  85. package/src/core/wiki-image/image-voxel-ledger.mjs +10 -3
  86. package/src/core/wiki-image/ppt-image-evidence.mjs +1 -0
  87. package/src/core/wiki-image/route-image-evidence.mjs +107 -0
  88. package/src/cli/legacy-main.mjs +0 -4147
@@ -0,0 +1,44 @@
1
+ import path from 'node:path';
2
+ import { projectRoot, readJson, writeJsonAtomic } from '../core/fsx.mjs';
3
+ import { findLatestMission, loadMission } from '../core/mission.mjs';
4
+ import { flag } from '../cli/args.mjs';
5
+ import { printJson } from '../cli/output.mjs';
6
+ import { writePptBuildArtifacts, writePptRouteArtifacts } from '../core/ppt.mjs';
7
+ import { finalizeRouteWithProof } from '../core/proof/route-finalizer.mjs';
8
+
9
+ export async function run(_command, args = []) {
10
+ const root = await projectRoot();
11
+ const action = args[0] || 'status';
12
+ const missionArg = args[1] && !String(args[1]).startsWith('--') ? args[1] : 'latest';
13
+ const missionId = missionArg === 'latest' ? await findLatestMission(root) : missionArg;
14
+ if (!missionId) {
15
+ const result = { schema: 'sks.ppt-status.v1', ok: false, status: 'missing_mission' };
16
+ if (flag(args, '--json')) return printJson(result);
17
+ console.error('No mission found.');
18
+ process.exitCode = 1;
19
+ return;
20
+ }
21
+ const { dir, mission } = await loadMission(root, missionId);
22
+ const contract = await readJson(path.join(dir, 'decision-contract.json'), { prompt: mission.prompt, answers: {}, sealed_hash: null });
23
+ if (action === 'build') {
24
+ await writePptRouteArtifacts(dir, contract);
25
+ const build = await writePptBuildArtifacts(dir, contract);
26
+ const proof = await finalizeRouteWithProof(root, { missionId, route: '$PPT', mock: flag(args, '--mock'), artifacts: build.files || [], claims: [{ id: 'ppt-build-fixture', status: 'verified_partial' }] });
27
+ const result = { schema: 'sks.ppt-build.v1', ok: proof.ok, mission_id: missionId, build, proof: proof.validation };
28
+ if (flag(args, '--json')) return printJson(result);
29
+ console.log(`PPT build: ${proof.ok ? 'ok' : 'blocked'} ${missionId}`);
30
+ if (!proof.ok) process.exitCode = 1;
31
+ return;
32
+ }
33
+ if (action === 'status') {
34
+ const gate = await readJson(path.join(dir, 'ppt-gate.json'), null);
35
+ const result = { schema: 'sks.ppt-status.v1', ok: true, mission_id: missionId, gate };
36
+ if (flag(args, '--json')) return printJson(result);
37
+ console.log(`PPT mission: ${missionId}`);
38
+ console.log(`Gate: ${gate?.passed ? 'passed' : gate ? 'present' : 'missing'}`);
39
+ return;
40
+ }
41
+ await writeJsonAtomic(path.join(dir, 'ppt-command-error.json'), { action, args });
42
+ console.error('Usage: sks ppt build|status <mission-id|latest> [--json] [--mock]');
43
+ process.exitCode = 1;
44
+ }
@@ -0,0 +1,5 @@
1
+ import { profileCommand } from '../core/commands/route-cli.mjs';
2
+ export async function run(_command, args = []) {
3
+ const [sub = 'show', ...rest] = args;
4
+ return profileCommand(sub, rest);
5
+ }
@@ -0,0 +1,5 @@
1
+ import { proofFieldCommand } from '../core/commands/route-cli.mjs';
2
+ export async function run(_command, args = []) {
3
+ const [sub = 'scan', ...rest] = args;
4
+ return proofFieldCommand(sub, rest);
5
+ }
@@ -5,6 +5,7 @@ import { collectProofEvidence } from '../core/proof/evidence-collector.mjs';
5
5
  import { findLatestMission } from '../core/mission.mjs';
6
6
  import { readLatestProof, readLatestProofMarkdown, readRouteProof } from '../core/proof/proof-reader.mjs';
7
7
  import { writeRouteCompletionProof } from '../core/proof/route-adapter.mjs';
8
+ import { finalizeRouteWithProof } from '../core/proof/route-finalizer.mjs';
8
9
  import { renderProofMarkdown, writeCompletionProof } from '../core/proof/proof-writer.mjs';
9
10
  import { validateCompletionProof } from '../core/proof/validation.mjs';
10
11
 
@@ -41,6 +42,26 @@ export async function run(_command, args = []) {
41
42
  if (!result.ok) process.exitCode = 1;
42
43
  return;
43
44
  }
45
+ if (action === 'finalize') {
46
+ const missionArg = rest.find((arg) => !String(arg).startsWith('--')) || 'latest';
47
+ const missionId = missionArg === 'latest' ? await findLatestMission(root) : missionArg;
48
+ const routeIndex = args.indexOf('--route');
49
+ const route = routeIndex >= 0 && args[routeIndex + 1] ? args[routeIndex + 1] : '$SKS';
50
+ const result = await finalizeRouteWithProof(root, {
51
+ missionId,
52
+ route,
53
+ strict: flag(args, '--strict'),
54
+ mock: flag(args, '--mock'),
55
+ requireRelation: flag(args, '--require-relation'),
56
+ statusHint: flag(args, '--strict') ? 'verified_partial' : 'verified_partial',
57
+ claims: [{ id: 'proof-finalize', status: 'supported', evidence: `.sneakoscope/missions/${missionId}/completion-proof.json` }],
58
+ unverified: flag(args, '--mock') ? ['Finalizer ran in mock fixture mode.'] : []
59
+ });
60
+ if (flag(args, '--json')) return printJson({ schema: 'sks.completion-proof-finalize.v1', ok: result.ok, mission_id: missionId, validation: result.validation, files: result.files, proof: result.proof });
61
+ console.log(`Completion proof finalized: ${result.files.latest_json}`);
62
+ if (!result.ok) process.exitCode = 1;
63
+ return;
64
+ }
44
65
  if (action === 'export' && (flag(rest, '--md') || flag(args, '--md'))) {
45
66
  process.stdout.write(await readLatestProofMarkdown(root));
46
67
  return;
@@ -86,7 +107,7 @@ export async function run(_command, args = []) {
86
107
  console.log(`Completion proof written: ${result.files.latest_json}`);
87
108
  return;
88
109
  }
89
- console.error('Usage: sks proof show|latest|validate|route <mission-id|latest>|export --md|repair latest|smoke [--json]');
110
+ console.error('Usage: sks proof show|latest|validate|route <mission-id|latest>|finalize <mission-id|latest> [--route route] [--strict] [--mock] [--json]|export --md|repair latest|smoke [--json]');
90
111
  process.exitCode = 1;
91
112
  }
92
113
 
@@ -0,0 +1,5 @@
1
+ import { qaLoopCommand } from '../core/commands/route-cli.mjs';
2
+ export async function run(_command, args = []) {
3
+ const [sub, ...rest] = args;
4
+ return qaLoopCommand(sub, rest);
5
+ }
@@ -0,0 +1,2 @@
1
+ import { quickstartCommand } from '../core/commands/basic-cli.mjs';
2
+ export async function run() { return quickstartCommand(); }
@@ -0,0 +1,2 @@
1
+ import { reasoningCommand } from '../core/commands/basic-cli.mjs';
2
+ export async function run(_command, args = []) { return reasoningCommand(args); }
@@ -0,0 +1,5 @@
1
+ import { recallPulseCommand } from '../cli/recallpulse-command.mjs';
2
+ export async function run(_command, args = []) {
3
+ const [sub = 'status', ...rest] = args;
4
+ return recallPulseCommand(sub, rest);
5
+ }
@@ -0,0 +1,5 @@
1
+ import { researchCommand } from '../core/commands/route-cli.mjs';
2
+ export async function run(_command, args = []) {
3
+ const [sub, ...rest] = args;
4
+ return researchCommand(sub, rest);
5
+ }
@@ -0,0 +1,2 @@
1
+ import { selftestCommand } from '../core/commands/basic-cli.mjs';
2
+ export async function run(_command, args = []) { return selftestCommand(args); }
@@ -0,0 +1,2 @@
1
+ import { setupCommand } from '../core/commands/basic-cli.mjs';
2
+ export async function run(_command, args = []) { return setupCommand(args); }
@@ -0,0 +1,5 @@
1
+ import { skillDreamCommand } from '../core/commands/route-cli.mjs';
2
+ export async function run(_command, args = []) {
3
+ const [sub = 'status', ...rest] = args;
4
+ return skillDreamCommand(sub, rest);
5
+ }
@@ -0,0 +1,2 @@
1
+ import { statsCommand } from '../core/commands/route-cli.mjs';
2
+ export async function run(_command, args = []) { return statsCommand(args); }
@@ -0,0 +1,2 @@
1
+ import { team } from '../core/commands/route-cli.mjs';
2
+ export async function run(_command, args = []) { return team(args); }
@@ -0,0 +1,5 @@
1
+ import { tmuxCommand } from '../core/commands/basic-cli.mjs';
2
+ export async function run(_command, args = []) {
3
+ const [sub = 'check', ...rest] = args;
4
+ return tmuxCommand(sub, rest);
5
+ }
@@ -0,0 +1,2 @@
1
+ import { updateCheckCommand } from '../core/commands/basic-cli.mjs';
2
+ export async function run(_command, args = []) { return updateCheckCommand(args); }
@@ -0,0 +1,2 @@
1
+ import { usageCommand } from '../core/commands/basic-cli.mjs';
2
+ export async function run(_command, args = []) { return usageCommand(args); }
@@ -0,0 +1,2 @@
1
+ import { validateArtifactsCommand } from '../core/commands/route-cli.mjs';
2
+ export async function run(_command, args = []) { return validateArtifactsCommand(args); }
@@ -0,0 +1,16 @@
1
+ import { projectRoot } from '../core/fsx.mjs';
2
+ import { bumpProjectVersion, disableVersionGitHook, versioningStatus } from '../core/version-manager.mjs';
3
+ import { flag } from '../cli/args.mjs';
4
+ import { printJson } from '../cli/output.mjs';
5
+ export async function run(_command, args = []) {
6
+ const root = await projectRoot();
7
+ const action = args[0] || 'status';
8
+ const result = action === 'bump'
9
+ ? await bumpProjectVersion(root, { force: true })
10
+ : ['disable', 'off', 'remove-hook', 'unhook'].includes(action)
11
+ ? await disableVersionGitHook(root)
12
+ : await versioningStatus(root);
13
+ if (flag(args, '--json')) return printJson(result);
14
+ console.log(JSON.stringify(result, null, 2));
15
+ if (result.ok === false) process.exitCode = 1;
16
+ }
@@ -85,8 +85,8 @@ export async function run(_command, args = []) {
85
85
  if (!result.ok) process.exitCode = 1;
86
86
  return;
87
87
  }
88
- const legacy = await import('../cli/legacy-main.mjs');
89
- return legacy.main(['wiki', ...args]);
88
+ const { wikiCommand } = await import('../core/commands/route-cli.mjs');
89
+ return wikiCommand(action, args.slice(1));
90
90
  }
91
91
 
92
92
  function parseBbox(raw) {
@@ -99,6 +99,24 @@ export function codexLbMetrics(circuit = emptyCircuit()) {
99
99
  };
100
100
  }
101
101
 
102
+ export async function codexLbProofEvidence(root = packageRoot()) {
103
+ const circuit = await readCodexLbCircuit(root);
104
+ const metrics = codexLbMetrics(circuit);
105
+ return {
106
+ schema: 'sks.codex-lb-proof-evidence.v1',
107
+ ok: metrics.ok,
108
+ status: circuit.state === 'open' ? 'blocked' : 'verified_partial',
109
+ circuit_state: circuit.state,
110
+ report_path: codexLbReportPath(root),
111
+ last_ok_at: circuit.last_ok_at,
112
+ last_failure_at: circuit.last_failure_at,
113
+ last_warning_at: circuit.last_warning_at,
114
+ recent_failures: circuit.recent_failures?.length || 0,
115
+ recent_warnings: circuit.recent_warnings?.length || 0,
116
+ policy: metrics.policy
117
+ };
118
+ }
119
+
102
120
  function emptyCircuit() {
103
121
  return {
104
122
  schema: CODEX_LB_CIRCUIT_SCHEMA,
@@ -0,0 +1,315 @@
1
+ import path from 'node:path';
2
+ import { spawnSync } from 'node:child_process';
3
+ import { COMMANDS } from '../../cli/command-registry.mjs';
4
+ import { flag } from '../../cli/args.mjs';
5
+ import { printJson, sksTextLogo } from '../../cli/output.mjs';
6
+ import { PACKAGE_VERSION, ensureDir, exists, nowIso, projectRoot, readJson, runProcess, sksRoot, tmpdir, writeJsonAtomic } from '../fsx.mjs';
7
+ import { COMMAND_CATALOG, DOLLAR_COMMAND_ALIASES, DOLLAR_COMMANDS, USAGE_TOPICS, routePrompt, routeReasoning, reasoningInstruction } from '../routes.mjs';
8
+ import { initProject, normalizeInstallScope, sksCommandPrefix } from '../init.mjs';
9
+ import { buildFeatureRegistry, validateFeatureRegistry } from '../feature-registry.mjs';
10
+ import { hooksExplainReport } from '../../cli/feature-commands.mjs';
11
+ import { writeSelftestRouteProof } from '../proof/selftest-proof-fixtures.mjs';
12
+ import { createMission } from '../mission.mjs';
13
+
14
+ export async function helpCommand(args = []) {
15
+ const topic = args[0];
16
+ if (topic) return usageCommand([topic]);
17
+ console.log(`${sksTextLogo()}\n\nUsage\n`);
18
+ console.log(' sks');
19
+ console.log(' sks help [topic]');
20
+ console.log(' sks commands [--json]');
21
+ console.log(' sks dollar-commands [--json]');
22
+ console.log(' sks proof show --json');
23
+ console.log('');
24
+ for (const row of commandRows().filter((entry) => entry.maturity !== 'labs')) {
25
+ console.log(` ${row.usage.padEnd(58)} ${row.description}`);
26
+ }
27
+ console.log('\nThree core promises: Completion Proof for serious routes, Image Voxel TriWiki for visual routes, and release-gated Codex App/codex-lb/hooks/Rust evidence.');
28
+ }
29
+
30
+ export function commandsCommand(args = []) {
31
+ const commands = commandRows();
32
+ if (flag(args, '--json')) {
33
+ return printJson({
34
+ schema: 'sks.command-registry.v1',
35
+ aliases: ['sks', 'sneakoscope'],
36
+ commands
37
+ });
38
+ }
39
+ console.log(`${sksTextLogo()}\n\nCommands\n`);
40
+ const width = Math.max(...commands.map((entry) => entry.usage.length));
41
+ for (const entry of commands) console.log(`${entry.usage.padEnd(width)} ${entry.description}`);
42
+ }
43
+
44
+ export function dollarCommandsCommand(args = []) {
45
+ const out = { dollar_commands: DOLLAR_COMMANDS, app_skill_aliases: DOLLAR_COMMAND_ALIASES };
46
+ if (flag(args, '--json')) return printJson(out);
47
+ console.log(`${sksTextLogo()}\n\n$ Commands\n`);
48
+ const width = Math.max(...DOLLAR_COMMANDS.map((entry) => entry.command.length));
49
+ for (const entry of DOLLAR_COMMANDS) console.log(`${entry.command.padEnd(width)} ${entry.route}: ${entry.description}`);
50
+ console.log(`\nCanonical Codex App picker skills: ${DOLLAR_COMMAND_ALIASES.map((entry) => entry.app_skill).join(', ')}`);
51
+ }
52
+
53
+ export function aliasesCommand() {
54
+ console.log('Aliases');
55
+ console.log('- sks, sneakoscope');
56
+ console.log('- $ aliases:');
57
+ for (const entry of DOLLAR_COMMAND_ALIASES) console.log(` ${entry.app_skill} -> ${entry.canonical}`);
58
+ }
59
+
60
+ export function dfixCommand() {
61
+ console.log(`SKS Direct Fix Mode
62
+
63
+ Prompt command:
64
+ $DFix <tiny direct fix request>
65
+
66
+ Rules:
67
+ Apply only the requested tiny copy/config/docs/labels/spacing/translation/simple mechanical edit.
68
+ Keep verification cheap and explicit.
69
+ Finish with a DFix completion summary and one Honest check line.`);
70
+ }
71
+
72
+ export function usageCommand(args = []) {
73
+ const topic = args[0] || 'overview';
74
+ if (topic === 'overview') {
75
+ console.log(`Usage topics: ${USAGE_TOPICS}`);
76
+ console.log('Try: sks usage goal, sks usage team, sks usage image-ux-review');
77
+ return;
78
+ }
79
+ const row = commandRows().find((entry) => entry.name === topic);
80
+ if (row) {
81
+ console.log(`${row.name}\n`);
82
+ console.log(`Usage: ${row.usage}`);
83
+ console.log(row.description);
84
+ return;
85
+ }
86
+ const route = DOLLAR_COMMANDS.find((entry) => entry.command.toLowerCase() === `$${topic}`.toLowerCase());
87
+ if (route) {
88
+ console.log(`${route.command}\n`);
89
+ console.log(`${route.route}: ${route.description}`);
90
+ return;
91
+ }
92
+ console.log(`Unknown usage topic: ${topic}`);
93
+ console.log(`Known topics: ${USAGE_TOPICS}`);
94
+ }
95
+
96
+ export function quickstartCommand() {
97
+ console.log(`Sneakoscope Codex Quickstart
98
+
99
+ sks setup --local-only
100
+ sks doctor
101
+ sks commands
102
+ sks dollar-commands
103
+ sks all-features selftest --mock --execute-fixtures --strict-artifacts --json
104
+
105
+ For implementation work, use Codex App prompt routes such as $Team, $Goal, $QA-LOOP, $Image-UX-Review, and $Computer-Use.`);
106
+ }
107
+
108
+ export async function updateCheckCommand(args = []) {
109
+ const latest = await npmViewVersion('sneakoscope');
110
+ const result = {
111
+ package: 'sneakoscope',
112
+ current: PACKAGE_VERSION,
113
+ runtime_current: PACKAGE_VERSION,
114
+ latest: latest.version,
115
+ update_available: latest.version ? compareVersions(latest.version, PACKAGE_VERSION) > 0 : false,
116
+ error: latest.error || null
117
+ };
118
+ if (flag(args, '--json')) return printJson(result);
119
+ console.log(`${sksTextLogo()}\n\nUpdate Check`);
120
+ console.log(`Current: ${result.current}`);
121
+ console.log(`Latest: ${result.latest || 'unknown'}`);
122
+ console.log(`Update: ${result.update_available ? 'available' : 'not needed'}`);
123
+ if (result.error) console.log(`Error: ${result.error}`);
124
+ if (result.update_available) console.log(`Run: npm i -g sneakoscope@${result.latest}`);
125
+ }
126
+
127
+ export async function setupCommand(args = []) {
128
+ const root = await projectRoot();
129
+ const installScope = installScopeFromArgs(args);
130
+ const res = await initProject(root, {
131
+ force: flag(args, '--force'),
132
+ installScope,
133
+ localOnly: flag(args, '--local-only'),
134
+ globalCommand: 'sks'
135
+ });
136
+ const result = {
137
+ schema: 'sks.setup.v1',
138
+ ok: true,
139
+ root,
140
+ install_scope: installScope,
141
+ command_prefix: sksCommandPrefix(installScope, { globalCommand: 'sks' }),
142
+ created: res.created || [],
143
+ local_only: flag(args, '--local-only')
144
+ };
145
+ if (flag(args, '--json')) return printJson(result);
146
+ console.log(`Setup complete: ${root}`);
147
+ console.log(`Install scope: ${installScope}`);
148
+ for (const file of result.created) console.log(`- ${file}`);
149
+ }
150
+
151
+ export async function bootstrapCommand(args = []) {
152
+ return setupCommand(['--local-only', ...args]);
153
+ }
154
+
155
+ export async function initCommand(args = []) {
156
+ return setupCommand(args);
157
+ }
158
+
159
+ export async function fixPathCommand(args = []) {
160
+ const root = await projectRoot();
161
+ const installScope = installScopeFromArgs(args);
162
+ await initProject(root, { installScope, localOnly: flag(args, '--local-only'), globalCommand: 'sks', force: true });
163
+ const result = {
164
+ schema: 'sks.fix-path.v1',
165
+ ok: true,
166
+ root,
167
+ install_scope: installScope,
168
+ hook_command_prefix: sksCommandPrefix(installScope, { globalCommand: 'sks' }),
169
+ hooks: path.join(root, '.codex', 'hooks.json')
170
+ };
171
+ if (flag(args, '--json')) return printJson(result);
172
+ console.log(`SKS hook path refreshed: ${path.relative(root, result.hooks)}`);
173
+ }
174
+
175
+ export async function depsCommand(sub = 'check', args = []) {
176
+ const action = sub || 'check';
177
+ if (action !== 'check' && action !== 'status') {
178
+ console.error('Usage: sks deps check [--json]');
179
+ process.exitCode = 1;
180
+ return;
181
+ }
182
+ const npm = whichSync('npm');
183
+ const nodeOk = Number(process.versions.node.split('.')[0]) >= 20;
184
+ const root = await sksRoot();
185
+ const result = {
186
+ schema: 'sks.deps-status.v1',
187
+ root,
188
+ ready: Boolean(nodeOk && npm),
189
+ node: { ok: nodeOk, version: process.version },
190
+ npm: { ok: Boolean(npm), bin: npm },
191
+ next_actions: [
192
+ ...(!nodeOk ? ['Install Node.js 20.11+.'] : []),
193
+ ...(!npm ? ['Install npm or a Node.js distribution that includes npm.'] : [])
194
+ ]
195
+ };
196
+ if (flag(args, '--json')) return printJson(result);
197
+ console.log('SKS Dependencies');
198
+ console.log(`Node: ${result.node.ok ? 'ok' : 'missing'} ${result.node.version}`);
199
+ console.log(`npm: ${result.npm.ok ? 'ok' : 'missing'} ${result.npm.bin || ''}`.trim());
200
+ if (!result.ready) process.exitCode = 1;
201
+ }
202
+
203
+ export async function postinstallCommand(args = []) {
204
+ const { postinstall } = await import('../../cli/install-helpers.mjs');
205
+ return postinstall({ bootstrap: flag(args, '--bootstrap') });
206
+ }
207
+
208
+ export async function selftestCommand(args = []) {
209
+ process.env.CI = 'true';
210
+ const root = await projectRoot();
211
+ const tmp = tmpdir();
212
+ await ensureDir(tmp);
213
+ const registry = await buildFeatureRegistry({ root });
214
+ const coverage = validateFeatureRegistry(registry);
215
+ if (!coverage.ok) throw new Error(`selftest: feature registry blocked: ${coverage.blockers.join(', ')}`);
216
+ const mission = await createMission(tmp, { mode: 'team', prompt: 'selftest route proof fixture' });
217
+ await writeSelftestRouteProof(tmp, { missionId: mission.id, kind: 'team_gate' });
218
+ const proof = await readJson(path.join(tmp, '.sneakoscope', 'missions', mission.id, 'completion-proof.json'), null);
219
+ if (!proof?.mission_id) throw new Error('selftest: completion proof fixture missing');
220
+ const hookExplain = hooksExplainReport();
221
+ if (!hookExplain.events.includes('Stop')) throw new Error('selftest: hook explain missing Stop');
222
+ const result = {
223
+ schema: 'sks.selftest.v1',
224
+ ok: true,
225
+ version: PACKAGE_VERSION,
226
+ generated_at: nowIso(),
227
+ checks: ['feature_registry', 'route_completion_proof_fixture', 'hooks_policy_surface'],
228
+ tmp_root: tmp
229
+ };
230
+ if (flag(args, '--json')) return printJson(result);
231
+ console.log('SKS selftest passed');
232
+ }
233
+
234
+ export async function reasoningCommand(args = []) {
235
+ const prompt = args.filter((arg) => !String(arg).startsWith('--')).join(' ').trim();
236
+ const route = routePrompt(prompt || '$SKS');
237
+ const info = routeReasoning(route, prompt);
238
+ const result = {
239
+ route: route?.command || '$SKS',
240
+ effort: info.effort,
241
+ profile: info.profile,
242
+ reason: info.reason,
243
+ temporary: true,
244
+ instruction: reasoningInstruction(info)
245
+ };
246
+ if (flag(args, '--json')) return printJson(result);
247
+ console.log('SKS Reasoning Route');
248
+ console.log(`Route: ${result.route}`);
249
+ console.log(`Effort: ${result.effort}`);
250
+ console.log(`Profile: ${result.profile}`);
251
+ }
252
+
253
+ export async function tmuxCommand(sub = 'check', args = []) {
254
+ const { runTmuxStatus, tmuxReadiness } = await import('../tmux-ui.mjs');
255
+ const action = sub || 'check';
256
+ if (action === 'status' || action === 'banner') return runTmuxStatus(action === 'banner' ? ['--once', ...args] : args);
257
+ const status = await tmuxReadiness().catch((err) => ({ ok: false, error: err.message }));
258
+ if (flag(args, '--json')) return printJson({ schema: 'sks.tmux-status.v1', ...status });
259
+ console.log(`tmux: ${status.ok ? 'ok' : 'missing'} ${status.version || status.error || ''}`.trim());
260
+ if (!status.ok) process.exitCode = 1;
261
+ }
262
+
263
+ export async function autoReviewCommand(sub = 'status', args = []) {
264
+ const { autoReviewStatus, enableAutoReview, disableAutoReview } = await import('../auto-review.mjs');
265
+ const action = sub || 'status';
266
+ const result = action === 'enable' || action === 'start'
267
+ ? await enableAutoReview({ high: flag(args, '--high') })
268
+ : action === 'disable'
269
+ ? await disableAutoReview()
270
+ : await autoReviewStatus();
271
+ if (flag(args, '--json')) return printJson(result);
272
+ console.log(JSON.stringify(result, null, 2));
273
+ }
274
+
275
+ function commandRows() {
276
+ const registry = new Map(Object.entries(COMMANDS).map(([name, meta]) => [name, meta]));
277
+ return COMMAND_CATALOG.map((entry) => ({
278
+ name: entry.name,
279
+ usage: entry.usage,
280
+ description: entry.description,
281
+ maturity: registry.get(entry.name)?.maturity || entry.maturity || 'labs'
282
+ })).sort((a, b) => a.name.localeCompare(b.name));
283
+ }
284
+
285
+ function installScopeFromArgs(args = [], fallback = 'global') {
286
+ if (flag(args, '--project')) return 'project';
287
+ if (flag(args, '--global')) return 'global';
288
+ const index = args.indexOf('--install-scope');
289
+ return normalizeInstallScope(index >= 0 && args[index + 1] ? args[index + 1] : fallback);
290
+ }
291
+
292
+ async function npmViewVersion(name) {
293
+ const npm = whichSync('npm');
294
+ if (!npm) return { version: null, error: 'npm not found on PATH' };
295
+ const result = await runProcess(npm, ['view', name, 'version', '--silent'], { timeoutMs: 15000, maxOutputBytes: 4096 }).catch((err) => ({ code: 1, stdout: '', stderr: err.message }));
296
+ if (result.code !== 0) return { version: null, error: (result.stderr || result.stdout || 'npm view failed').trim() };
297
+ return { version: String(result.stdout || '').trim().split(/\s+/).pop() || null };
298
+ }
299
+
300
+ function compareVersions(a, b) {
301
+ const pa = String(a || '').split('.').map((x) => Number.parseInt(x, 10) || 0);
302
+ const pb = String(b || '').split('.').map((x) => Number.parseInt(x, 10) || 0);
303
+ for (let i = 0; i < Math.max(pa.length, pb.length); i += 1) {
304
+ if ((pa[i] || 0) !== (pb[i] || 0)) return (pa[i] || 0) - (pb[i] || 0);
305
+ }
306
+ return 0;
307
+ }
308
+
309
+ function whichSync(command) {
310
+ const result = spawnSync(process.platform === 'win32' ? 'where' : 'command', process.platform === 'win32' ? [command] : ['-v', command], {
311
+ encoding: 'utf8',
312
+ shell: process.platform !== 'win32'
313
+ });
314
+ return result.status === 0 ? String(result.stdout || '').trim().split(/\r?\n/)[0] : null;
315
+ }
@@ -1,43 +1,43 @@
1
1
  import path from 'node:path';
2
2
  import fsp from 'node:fs/promises';
3
3
  import { createHash } from 'node:crypto';
4
- import { readJson, readText, writeJsonAtomic, writeTextAtomic, appendJsonlBounded, nowIso, exists, ensureDir, packageRoot, dirSize, formatBytes, PACKAGE_VERSION, sksRoot, readStdin, runProcess } from '../core/fsx.mjs';
5
- import { initProject } from '../core/init.mjs';
6
- import { getCodexInfo, runCodexExec } from '../core/codex-adapter.mjs';
7
- import { createMission, loadMission, findLatestMission, missionDir, setCurrent, stateFile } from '../core/mission.mjs';
8
- import { buildQuestionSchema, writeQuestions } from '../core/questions.mjs';
9
- import { sealContract } from '../core/decision-contract.mjs';
10
- import { buildQaLoopQuestionSchema, buildQaLoopPrompt, evaluateQaGate, qaStatus, writeMockQaResult, writeQaLoopArtifacts } from '../core/qa-loop.mjs';
11
- import { containsUserQuestion, noQuestionContinuationReason } from '../core/no-question-guard.mjs';
12
- import { RESEARCH_GENIUS_SUMMARY_ARTIFACT, RESEARCH_SOURCE_SKILL_ARTIFACT, countGeniusOpinionSummaries, countResearchPaperSections, buildResearchPrompt, evaluateResearchGate, findResearchPaperArtifact, researchPaperArtifactForPlan, writeMockResearchResult, writeResearchPlan } from '../core/research.mjs';
13
- import { storageReport, enforceRetention, pruneWikiArtifacts } from '../core/retention.mjs';
14
- import { evaluateDoneGate } from '../core/hproof.mjs';
15
- import { renderCartridge, validateCartridge, driftCartridge, snapshotCartridge } from '../core/gx-renderer.mjs';
16
- import { DEFAULT_EVAL_THRESHOLDS, compareEvaluationReports, runEvaluationBenchmark } from '../core/evaluation.mjs';
17
- import { contextCapsule } from '../core/triwiki-attention.mjs';
18
- import { rgbaKey, rgbaToWikiCoord, validateWikiCoordinateIndex } from '../core/wiki-coordinate.mjs';
19
- import { ALLOWED_REASONING_EFFORTS, CODEX_COMPUTER_USE_ONLY_POLICY, DOLLAR_SKILL_NAMES, FROM_CHAT_IMG_CHECKLIST_ARTIFACT, FROM_CHAT_IMG_COVERAGE_ARTIFACT, FROM_CHAT_IMG_QA_LOOP_ARTIFACT, FROM_CHAT_IMG_SOURCE_INVENTORY_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS, FROM_CHAT_IMG_VISUAL_MAP_ARTIFACT, FROM_CHAT_IMG_WORK_ORDER_ARTIFACT, RECOMMENDED_SKILLS, ROUTES, hasFromChatImgSignal, reflectionRequiredForRoute, routeNeedsContext7, routePrompt, routeReasoning, routeRequiresSubagents, stackCurrentDocsPolicy, stripVisibleDecisionAnswerBlocks, triwikiContextTracking } from '../core/routes.mjs';
20
- import { TEAM_DECOMPOSITION_ARTIFACT, TEAM_GRAPH_ARTIFACT, TEAM_INBOX_DIR, TEAM_RUNTIME_TASKS_ARTIFACT, teamRuntimePlanMetadata, teamRuntimeRequiredArtifacts, writeTeamRuntimeArtifacts } from '../core/team-dag.mjs';
21
- import { appendTeamEvent, formatAgentReasoning, formatRoleCounts, initTeamLive, isTerminalTeamAgentStatus, normalizeTeamSpec, parseTeamSpecArgs, readTeamControl, readTeamDashboard, readTeamLive, readTeamTranscriptTail, renderTeamAgentLane, renderTeamCleanupSummary, renderTeamWatch, requestTeamSessionCleanup, teamCleanupRequested, teamReasoningPolicy } from '../core/team-live.mjs';
22
- import { evaluateTeamReviewPolicyGate, MIN_TEAM_REVIEWER_LANES, MIN_TEAM_REVIEW_POLICY_TEXT, teamReviewPolicy } from '../core/team-review-policy.mjs';
23
- import { ARTIFACT_FILES, writeValidationReport } from '../core/artifact-schemas.mjs';
24
- import { writeEffortDecision } from '../core/effort-orchestrator.mjs';
25
- import { createWorkOrderLedger, writeWorkOrderLedger } from '../core/work-order-ledger.mjs';
26
- import { writeFromChatImgArtifacts } from '../core/from-chat-img-forensics.mjs';
27
- import { renderTeamDashboardState, writeTeamDashboardState } from '../core/team-dashboard-renderer.mjs';
28
- import { runPerfBench, runWorkflowPerfBench } from '../core/perf-bench.mjs';
29
- import { writeProofFieldReport } from '../core/proof-field.mjs';
30
- import { PIPELINE_PLAN_ARTIFACT, validatePipelinePlan, writePipelinePlan } from '../core/pipeline.mjs';
31
- import { GOAL_BRIDGE_ARTIFACT, GOAL_WORKFLOW_ARTIFACT, updateGoalWorkflow, writeGoalWorkflow } from '../core/goal-workflow.mjs';
32
- import { scanCodeStructure, writeCodeStructureReport } from '../core/code-structure.mjs';
33
- import { writeMemorySweepReport } from '../core/memory-governor.mjs';
34
- import { cleanupTmuxTeamView, defaultTmuxSessionName, launchMadTmuxUi, launchTmuxTeamView, reconcileTmuxTeamCockpit, sanitizeTmuxSessionName } from '../core/tmux-ui.mjs';
35
- import { loadSkillDreamState, recordSkillDreamEvent, runSkillDream, writeSkillForgeReport } from '../core/skill-forge.mjs';
36
- import { writeMistakeMemoryReport } from '../core/mistake-memory.mjs';
37
- import { checkDbOperation, checkSqlFile, classifyCommand, classifySql, loadDbSafetyPolicy, safeSupabaseMcpConfig, scanDbSafety } from '../core/db-safety.mjs';
38
- import { harnessGrowthReport, writeHarnessGrowthReport } from '../core/evaluation.mjs';
39
- import { enableMadHighProfile, madHighProfileName } from '../core/auto-review.mjs';
40
- import { permissionGateSummary } from '../core/permission-gates.mjs';
4
+ import { readJson, readText, writeJsonAtomic, writeTextAtomic, appendJsonlBounded, nowIso, exists, ensureDir, packageRoot, dirSize, formatBytes, PACKAGE_VERSION, sksRoot, readStdin, runProcess } from '../fsx.mjs';
5
+ import { initProject } from '../init.mjs';
6
+ import { getCodexInfo, runCodexExec } from '../codex-adapter.mjs';
7
+ import { createMission, loadMission, findLatestMission, missionDir, setCurrent, stateFile } from '../mission.mjs';
8
+ import { buildQuestionSchema, writeQuestions } from '../questions.mjs';
9
+ import { sealContract } from '../decision-contract.mjs';
10
+ import { buildQaLoopQuestionSchema, buildQaLoopPrompt, evaluateQaGate, qaStatus, writeMockQaResult, writeQaLoopArtifacts } from '../qa-loop.mjs';
11
+ import { containsUserQuestion, noQuestionContinuationReason } from '../no-question-guard.mjs';
12
+ import { RESEARCH_GENIUS_SUMMARY_ARTIFACT, RESEARCH_SOURCE_SKILL_ARTIFACT, countGeniusOpinionSummaries, countResearchPaperSections, buildResearchPrompt, evaluateResearchGate, findResearchPaperArtifact, researchPaperArtifactForPlan, writeMockResearchResult, writeResearchPlan } from '../research.mjs';
13
+ import { storageReport, enforceRetention, pruneWikiArtifacts } from '../retention.mjs';
14
+ import { evaluateDoneGate } from '../hproof.mjs';
15
+ import { renderCartridge, validateCartridge, driftCartridge, snapshotCartridge } from '../gx-renderer.mjs';
16
+ import { DEFAULT_EVAL_THRESHOLDS, compareEvaluationReports, runEvaluationBenchmark } from '../evaluation.mjs';
17
+ import { contextCapsule } from '../triwiki-attention.mjs';
18
+ import { rgbaKey, rgbaToWikiCoord, validateWikiCoordinateIndex } from '../wiki-coordinate.mjs';
19
+ import { ALLOWED_REASONING_EFFORTS, CODEX_COMPUTER_USE_ONLY_POLICY, DOLLAR_SKILL_NAMES, FROM_CHAT_IMG_CHECKLIST_ARTIFACT, FROM_CHAT_IMG_COVERAGE_ARTIFACT, FROM_CHAT_IMG_QA_LOOP_ARTIFACT, FROM_CHAT_IMG_SOURCE_INVENTORY_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS, FROM_CHAT_IMG_VISUAL_MAP_ARTIFACT, FROM_CHAT_IMG_WORK_ORDER_ARTIFACT, RECOMMENDED_SKILLS, ROUTES, hasFromChatImgSignal, reflectionRequiredForRoute, routeNeedsContext7, routePrompt, routeReasoning, routeRequiresSubagents, stackCurrentDocsPolicy, stripVisibleDecisionAnswerBlocks, triwikiContextTracking } from '../routes.mjs';
20
+ import { TEAM_DECOMPOSITION_ARTIFACT, TEAM_GRAPH_ARTIFACT, TEAM_INBOX_DIR, TEAM_RUNTIME_TASKS_ARTIFACT, teamRuntimePlanMetadata, teamRuntimeRequiredArtifacts, writeTeamRuntimeArtifacts } from '../team-dag.mjs';
21
+ import { appendTeamEvent, formatAgentReasoning, formatRoleCounts, initTeamLive, isTerminalTeamAgentStatus, normalizeTeamSpec, parseTeamSpecArgs, readTeamControl, readTeamDashboard, readTeamLive, readTeamTranscriptTail, renderTeamAgentLane, renderTeamCleanupSummary, renderTeamWatch, requestTeamSessionCleanup, teamCleanupRequested, teamReasoningPolicy } from '../team-live.mjs';
22
+ import { evaluateTeamReviewPolicyGate, MIN_TEAM_REVIEWER_LANES, MIN_TEAM_REVIEW_POLICY_TEXT, teamReviewPolicy } from '../team-review-policy.mjs';
23
+ import { ARTIFACT_FILES, writeValidationReport } from '../artifact-schemas.mjs';
24
+ import { writeEffortDecision } from '../effort-orchestrator.mjs';
25
+ import { createWorkOrderLedger, writeWorkOrderLedger } from '../work-order-ledger.mjs';
26
+ import { writeFromChatImgArtifacts } from '../from-chat-img-forensics.mjs';
27
+ import { renderTeamDashboardState, writeTeamDashboardState } from '../team-dashboard-renderer.mjs';
28
+ import { runPerfBench, runWorkflowPerfBench } from '../perf-bench.mjs';
29
+ import { writeProofFieldReport } from '../proof-field.mjs';
30
+ import { PIPELINE_PLAN_ARTIFACT, validatePipelinePlan, writePipelinePlan } from '../pipeline.mjs';
31
+ import { GOAL_BRIDGE_ARTIFACT, GOAL_WORKFLOW_ARTIFACT, updateGoalWorkflow, writeGoalWorkflow } from '../goal-workflow.mjs';
32
+ import { scanCodeStructure, writeCodeStructureReport } from '../code-structure.mjs';
33
+ import { writeMemorySweepReport } from '../memory-governor.mjs';
34
+ import { cleanupTmuxTeamView, defaultTmuxSessionName, launchMadTmuxUi, launchTmuxTeamView, reconcileTmuxTeamCockpit, sanitizeTmuxSessionName } from '../tmux-ui.mjs';
35
+ import { loadSkillDreamState, recordSkillDreamEvent, runSkillDream, writeSkillForgeReport } from '../skill-forge.mjs';
36
+ import { writeMistakeMemoryReport } from '../mistake-memory.mjs';
37
+ import { checkDbOperation, checkSqlFile, classifyCommand, classifySql, loadDbSafetyPolicy, safeSupabaseMcpConfig, scanDbSafety } from '../db-safety.mjs';
38
+ import { harnessGrowthReport, writeHarnessGrowthReport } from '../evaluation.mjs';
39
+ import { enableMadHighProfile, madHighProfileName } from '../auto-review.mjs';
40
+ import { permissionGateSummary } from '../permission-gates.mjs';
41
41
 
42
42
  const flag = (args, name) => args.includes(name);
43
43
  const promptOf = (args) => args.filter((x) => !String(x).startsWith('--')).join(' ').trim();