sneakoscope 0.6.85 → 0.6.87
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 +3 -1
- package/package.json +1 -1
- package/src/cli/main.mjs +41 -123
- package/src/cli/maintenance-commands.mjs +155 -5
- package/src/core/db-safety.mjs +43 -7
- package/src/core/decision-contract.mjs +8 -6
- package/src/core/fsx.mjs +1 -1
- package/src/core/init.mjs +1 -1
- package/src/core/perf-bench.mjs +87 -0
- package/src/core/pipeline.mjs +3 -3
- package/src/core/proof-field.mjs +219 -0
- package/src/core/questions.mjs +7 -7
- package/src/core/routes.mjs +6 -5
package/README.md
CHANGED
|
@@ -215,6 +215,8 @@ sks gx init homepage
|
|
|
215
215
|
sks gx render homepage --format html
|
|
216
216
|
sks validate-artifacts latest --json
|
|
217
217
|
sks perf run --json
|
|
218
|
+
sks perf workflow --json --intent "small CLI change" --changed src/cli/main.mjs,src/core/routes.mjs
|
|
219
|
+
sks proof-field scan --json --intent "small CLI change"
|
|
218
220
|
sks code-structure scan --json
|
|
219
221
|
```
|
|
220
222
|
|
|
@@ -274,7 +276,7 @@ Use these inside Codex App or another agent prompt. They are prompt commands, no
|
|
|
274
276
|
| `$Research` | You need frontier-style research with hypotheses and falsification. |
|
|
275
277
|
| `$AutoResearch` | You want iterative improve/test/keep-or-discard optimization. |
|
|
276
278
|
| `$DB` | You need database, Supabase, migration, SQL, or MCP safety checks. |
|
|
277
|
-
| `$MAD-SKS` | You explicitly authorize
|
|
279
|
+
| `$MAD-SKS` | You explicitly authorize scoped Supabase MCP DB cleanup/write permissions for the active invocation only, while keeping catastrophic wipe safeguards. |
|
|
278
280
|
| `$GX` | You need deterministic visual context cartridges. |
|
|
279
281
|
| `$Wiki` | You want TriWiki refresh, pack, prune, validate, or maintenance. |
|
|
280
282
|
| `$Help` | You want installed command and workflow explanation. |
|
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.87",
|
|
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,
|
|
17
|
+
import { classifySql, classifyCommand, checkDbOperation, handleMadSksUserConfirmation } 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';
|
|
@@ -36,6 +36,8 @@ import { buildFromChatImgVisualMap } from '../core/from-chat-img-forensics.mjs';
|
|
|
36
36
|
import { classifyDogfoodFinding, createDogfoodReport, writeDogfoodReport } from '../core/dogfood-loop.mjs';
|
|
37
37
|
import { createSkillCandidate, decideSkillInjection, writeSkillCandidate, writeSkillForgeReport, writeSkillInjectionDecision } from '../core/skill-forge.mjs';
|
|
38
38
|
import { classifyToolError, harnessGrowthReport } from '../core/evaluation.mjs';
|
|
39
|
+
import { runWorkflowPerfBench, validateWorkflowPerfReport } from '../core/perf-bench.mjs';
|
|
40
|
+
import { proofFieldFixture, validateProofFieldReport } from '../core/proof-field.mjs';
|
|
39
41
|
import { recordMistake, writeMistakeMemoryReport } from '../core/mistake-memory.mjs';
|
|
40
42
|
import { buildPromptContext } from '../core/prompt-context-builder.mjs';
|
|
41
43
|
import { renderTeamDashboardState, writeTeamDashboardState } from '../core/team-dashboard-renderer.mjs';
|
|
@@ -43,11 +45,10 @@ import { GOAL_WORKFLOW_ARTIFACT } from '../core/goal-workflow.mjs';
|
|
|
43
45
|
import { CODEX_APP_DOCS_URL, codexAppIntegrationStatus, formatCodexAppStatus } from '../core/codex-app.mjs';
|
|
44
46
|
import { buildWarpLaunchConfigYaml, buildWarpLaunchPlan, buildWarpOpenArgs, runWarpLaunchConfigSyntaxCheck, warpReadiness, warpStatusKind, defaultWarpWorkspaceName, formatWarpBanner, launchWarpTeamView, launchWarpUi, platformWarpInstallHint, runWarpStatus, sanitizeWarpWorkspaceName, teamLaneStyle, writeWarpLaunchConfig } from '../core/warp-ui.mjs';
|
|
45
47
|
import { autoReviewProfileName, autoReviewStatus, autoReviewSummary, enableAutoReview, disableAutoReview, enableMadHighProfile, madHighProfileName } from '../core/auto-review.mjs';
|
|
46
|
-
import { buildTeamPlan, codeStructureCommand, defaultBeta, defaultVGraph, evalCommand, gcCommand, goalCommand, gxCommand, harnessCommand, hproofCommand, memoryCommand, migrateWikiContextPack, parseTeamCreateArgs, perfCommand, profileCommand, projectWikiClaims, qaLoopCommand, researchCommand, statsCommand, team, teamWorkflowMarkdown, validateArtifactsCommand, wikiCommand, wikiVoxelRowCount, writeWikiContextPack } from './maintenance-commands.mjs';
|
|
48
|
+
import { buildTeamPlan, codeStructureCommand, dbCommand, defaultBeta, defaultVGraph, evalCommand, gcCommand, goalCommand, gxCommand, harnessCommand, hproofCommand, memoryCommand, migrateWikiContextPack, parseTeamCreateArgs, perfCommand, profileCommand, projectWikiClaims, proofFieldCommand, qaLoopCommand, quickstartCommand, researchCommand, statsCommand, team, teamWorkflowMarkdown, validateArtifactsCommand, wikiCommand, wikiVoxelRowCount, writeWikiContextPack } from './maintenance-commands.mjs';
|
|
47
49
|
|
|
48
50
|
const flag = (args, name) => args.includes(name);
|
|
49
51
|
const promptOf = (args) => args.filter((x) => !String(x).startsWith('--')).join(' ').trim();
|
|
50
|
-
const REPOSITORY_URL = 'https://github.com/mandarange/Sneakoscope-Codex.git';
|
|
51
52
|
const REFLECTION_ARTIFACT = 'reflection.md';
|
|
52
53
|
const REFLECTION_GATE = 'reflection-gate.json';
|
|
53
54
|
const TEAM_SESSION_CLEANUP_ARTIFACT = 'team-session-cleanup.json';
|
|
@@ -76,7 +77,7 @@ export async function main(args) {
|
|
|
76
77
|
if (cmd === 'commands') return commands(tail);
|
|
77
78
|
if (cmd === 'usage') return usage(tail);
|
|
78
79
|
if (cmd === 'root') return rootCommand(tail);
|
|
79
|
-
if (cmd === 'quickstart') return
|
|
80
|
+
if (cmd === 'quickstart') return quickstartCommand();
|
|
80
81
|
if (cmd === 'codex-app') return codexAppHelp(tail);
|
|
81
82
|
if (cmd === 'bootstrap') return bootstrap(tail);
|
|
82
83
|
if (cmd === 'deps') return deps(sub, rest);
|
|
@@ -102,11 +103,12 @@ export async function main(args) {
|
|
|
102
103
|
if (cmd === 'hproof') return hproofCommand(sub, rest);
|
|
103
104
|
if (cmd === 'validate-artifacts') return validateArtifactsCommand(tail);
|
|
104
105
|
if (cmd === 'perf') return perfCommand(sub, rest);
|
|
106
|
+
if (cmd === 'proof-field') return proofFieldCommand(sub, rest);
|
|
105
107
|
if (cmd === 'code-structure') return codeStructureCommand(sub, rest);
|
|
106
108
|
if (cmd === 'memory') return memoryCommand(sub, rest);
|
|
107
109
|
if (cmd === 'gx') return gxCommand(sub, rest);
|
|
108
110
|
if (cmd === 'team') return team(tail);
|
|
109
|
-
if (cmd === 'db') return
|
|
111
|
+
if (cmd === 'db') return dbCommand(sub, rest);
|
|
110
112
|
if (cmd === 'eval') return evalCommand(sub, rest);
|
|
111
113
|
if (cmd === 'harness') return harnessCommand(sub, rest);
|
|
112
114
|
if (cmd === 'wiki') return wikiCommand(sub, rest);
|
|
@@ -178,7 +180,8 @@ Usage:
|
|
|
178
180
|
sks validate-artifacts [mission-id|latest] [--json]
|
|
179
181
|
sks eval run [--json] [--out report.json]
|
|
180
182
|
sks eval compare --baseline old.json --candidate new.json [--json]
|
|
181
|
-
sks perf run [--json]
|
|
183
|
+
sks perf run|workflow [--json] [--intent "task"] [--changed file1,file2]
|
|
184
|
+
sks proof-field scan [--json] [--intent "task"]
|
|
182
185
|
sks harness fixture [--json]
|
|
183
186
|
sks code-structure scan [--json]
|
|
184
187
|
sks wiki coords --rgba 12,34,56,255
|
|
@@ -812,15 +815,16 @@ async function materializeAfterPipelineAnswer(root, id, dir, mission, route, rou
|
|
|
812
815
|
passed: false,
|
|
813
816
|
mad_sks_permission_active: true,
|
|
814
817
|
permissions_deactivated: false,
|
|
815
|
-
|
|
816
|
-
|
|
818
|
+
supabase_mcp_schema_cleanup_allowed: true,
|
|
819
|
+
direct_execute_sql_allowed: true,
|
|
820
|
+
catastrophic_safety_guard_active: true,
|
|
817
821
|
contract_hash: contract.sealed_hash || null
|
|
818
822
|
});
|
|
819
823
|
await appendJsonlBounded(path.join(dir, 'events.jsonl'), {
|
|
820
824
|
ts: nowIso(),
|
|
821
825
|
type: 'mad_sks.scoped_permission_opened',
|
|
822
826
|
route: route.id,
|
|
823
|
-
|
|
827
|
+
catastrophic_safety_guard_active: true
|
|
824
828
|
});
|
|
825
829
|
return {
|
|
826
830
|
phase: 'MADSKS_SCOPED_PERMISSION_ACTIVE',
|
|
@@ -830,7 +834,9 @@ async function materializeAfterPipelineAnswer(root, id, dir, mission, route, rou
|
|
|
830
834
|
mad_sks_modifier: true,
|
|
831
835
|
mad_sks_gate_file: 'mad-sks-gate.json',
|
|
832
836
|
mad_sks_gate_ready: true,
|
|
833
|
-
|
|
837
|
+
supabase_mcp_schema_cleanup_allowed: true,
|
|
838
|
+
direct_execute_sql_allowed: true,
|
|
839
|
+
catastrophic_safety_guard_active: true
|
|
834
840
|
}
|
|
835
841
|
};
|
|
836
842
|
}
|
|
@@ -901,8 +907,9 @@ async function materializeMadSksAuthorization(dir, id, route, routeContext = {},
|
|
|
901
907
|
status: 'active',
|
|
902
908
|
active_only_for_current_route: true,
|
|
903
909
|
deactivates_when_gate_passed: gateFile,
|
|
904
|
-
|
|
905
|
-
|
|
910
|
+
supabase_mcp_schema_cleanup_allowed: true,
|
|
911
|
+
direct_execute_sql_allowed: true,
|
|
912
|
+
catastrophic_safety_guard_active: true,
|
|
906
913
|
contract_hash: contract.sealed_hash || null
|
|
907
914
|
};
|
|
908
915
|
await writeJsonAtomic(path.join(dir, 'mad-sks-authorization.json'), artifact);
|
|
@@ -911,13 +918,15 @@ async function materializeMadSksAuthorization(dir, id, route, routeContext = {},
|
|
|
911
918
|
type: 'mad_sks.modifier_authorization_opened',
|
|
912
919
|
route: route?.id || null,
|
|
913
920
|
gate: gateFile,
|
|
914
|
-
|
|
921
|
+
catastrophic_safety_guard_active: true
|
|
915
922
|
});
|
|
916
923
|
return {
|
|
917
924
|
mad_sks_active: true,
|
|
918
925
|
mad_sks_modifier: true,
|
|
919
926
|
mad_sks_gate_file: gateFile,
|
|
920
|
-
|
|
927
|
+
supabase_mcp_schema_cleanup_allowed: true,
|
|
928
|
+
direct_execute_sql_allowed: true,
|
|
929
|
+
catastrophic_safety_guard_active: true
|
|
921
930
|
};
|
|
922
931
|
}
|
|
923
932
|
|
|
@@ -1346,60 +1355,6 @@ async function autoReviewCommand(sub = 'status', args = []) {
|
|
|
1346
1355
|
process.exitCode = 1;
|
|
1347
1356
|
}
|
|
1348
1357
|
|
|
1349
|
-
function quickstart() {
|
|
1350
|
-
console.log(`ㅅㅋㅅ Quickstart
|
|
1351
|
-
|
|
1352
|
-
First install and bootstrap this project:
|
|
1353
|
-
npm i -g sneakoscope
|
|
1354
|
-
sks root
|
|
1355
|
-
sks bootstrap
|
|
1356
|
-
sks
|
|
1357
|
-
|
|
1358
|
-
Use outside a project:
|
|
1359
|
-
sks root
|
|
1360
|
-
sks deps check
|
|
1361
|
-
sks team "global mission"
|
|
1362
|
-
|
|
1363
|
-
If warp is missing:
|
|
1364
|
-
sks deps install warp
|
|
1365
|
-
|
|
1366
|
-
Initialize this project for CLI and Codex App:
|
|
1367
|
-
sks setup --bootstrap
|
|
1368
|
-
|
|
1369
|
-
Open from terminal:
|
|
1370
|
-
sks
|
|
1371
|
-
sks --auto-review --high
|
|
1372
|
-
sks auto-review start --high
|
|
1373
|
-
|
|
1374
|
-
Verify:
|
|
1375
|
-
sks deps check
|
|
1376
|
-
sks codex-app check
|
|
1377
|
-
sks warp check
|
|
1378
|
-
sks auto-review status
|
|
1379
|
-
sks doctor --fix
|
|
1380
|
-
sks context7 check
|
|
1381
|
-
sks selftest --mock
|
|
1382
|
-
sks commands
|
|
1383
|
-
sks dollar-commands
|
|
1384
|
-
|
|
1385
|
-
If hooks cannot find the command:
|
|
1386
|
-
sks fix-path
|
|
1387
|
-
|
|
1388
|
-
Project-only install:
|
|
1389
|
-
npm i -D sneakoscope
|
|
1390
|
-
npx sks setup --install-scope project
|
|
1391
|
-
|
|
1392
|
-
Local-only install artifacts:
|
|
1393
|
-
sks setup --local-only
|
|
1394
|
-
# writes generated SKS files but excludes .sneakoscope/, .codex/, .agents/, AGENTS.md through .git/info/exclude
|
|
1395
|
-
# user-owned AGENTS.md is preserved; an existing SKS managed block is refreshed
|
|
1396
|
-
|
|
1397
|
-
GitHub install for unreleased commits:
|
|
1398
|
-
npm i -g git+${REPOSITORY_URL}
|
|
1399
|
-
sks bootstrap
|
|
1400
|
-
`);
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
1358
|
async function codexAppHelp(args = []) {
|
|
1404
1359
|
const action = args[0] || 'help';
|
|
1405
1360
|
if (action === 'check' || action === 'status') {
|
|
@@ -2904,17 +2859,17 @@ async function selftest() {
|
|
|
2904
2859
|
const madMission = await createMission(tmp, { mode: 'mad-sks', prompt: '$MAD-SKS selftest scoped DB override' });
|
|
2905
2860
|
await writeJsonAtomic(path.join(madMission.dir, 'team-gate.json'), { schema_version: 1, passed: false, team_roster_confirmed: true });
|
|
2906
2861
|
const madState = { mission_id: madMission.id, mode: 'TEAM', route_command: '$Team', stop_gate: 'team-gate.json', mad_sks_active: true, mad_sks_modifier: true, mad_sks_gate_file: 'team-gate.json' };
|
|
2862
|
+
const columnCleanupSql = 'alter table users ' + 'dr' + 'op column legacy_name;';
|
|
2863
|
+
const madColumnCleanupDecision = await checkDbOperation(tmp, madState, { tool_name: 'mcp__supabase__execute_sql', sql: columnCleanupSql }, { duringNoQuestion: false });
|
|
2864
|
+
if (madColumnCleanupDecision.action !== 'allow') throw new Error('selftest failed: MAD-SKS column cleanup was not allowed');
|
|
2907
2865
|
const tableRemovalSql = 'dr' + 'op table users;';
|
|
2908
|
-
const
|
|
2909
|
-
if (
|
|
2910
|
-
|
|
2911
|
-
const
|
|
2912
|
-
if (
|
|
2913
|
-
const madConfirmedState = await readJson(stateFile(tmp), {});
|
|
2914
|
-
const madConfirmedDecision = await checkDbOperation(tmp, madConfirmedState, { tool_name: 'mcp__supabase__execute_sql', sql: tableRemovalSql }, { duringNoQuestion: false });
|
|
2915
|
-
if (madConfirmedDecision.action !== 'allow') throw new Error('selftest failed: MAD-SKS confirmed table deletion was not allowed in the short confirmation window');
|
|
2866
|
+
const madTableRemovalDecision = await checkDbOperation(tmp, madState, { tool_name: 'mcp__supabase__execute_sql', sql: tableRemovalSql }, { duringNoQuestion: false });
|
|
2867
|
+
if (madTableRemovalDecision.action !== 'block') throw new Error('selftest failed: MAD-SKS catastrophic table removal was not blocked');
|
|
2868
|
+
const allRowsSql = 'de' + 'lete from users;';
|
|
2869
|
+
const madAllRowsDecision = await checkDbOperation(tmp, madState, { tool_name: 'mcp__supabase__execute_sql', sql: allRowsSql }, { duringNoQuestion: false });
|
|
2870
|
+
if (madAllRowsDecision.action !== 'block') throw new Error('selftest failed: MAD-SKS all-row DML was not blocked');
|
|
2916
2871
|
await writeJsonAtomic(path.join(madMission.dir, 'team-gate.json'), { schema_version: 1, passed: true, team_roster_confirmed: true, permissions_deactivated: true });
|
|
2917
|
-
const madClosedDecision = await checkDbOperation(tmp,
|
|
2872
|
+
const madClosedDecision = await checkDbOperation(tmp, madState, { tool_name: 'mcp__supabase__execute_sql', sql: columnCleanupSql }, { duringNoQuestion: false });
|
|
2918
2873
|
if (madClosedDecision.action !== 'block') throw new Error('selftest failed: MAD-SKS permission persisted after gate close');
|
|
2919
2874
|
const nonDbDecision = await checkDbOperation(tmp, {}, { command: 'npm test' }, { duringNoQuestion: true });
|
|
2920
2875
|
if (nonDbDecision.action !== 'allow') throw new Error('selftest failed: non-DB command blocked by DB guard');
|
|
@@ -2924,6 +2879,15 @@ async function selftest() {
|
|
|
2924
2879
|
if (evalReport.candidate.wiki?.voxel_schema !== 'sks.wiki-voxel.v1' || evalReport.candidate.wiki?.voxel_rows < 1) throw new Error('selftest failed: eval did not include voxel overlay metrics');
|
|
2925
2880
|
const harnessReport = harnessGrowthReport({});
|
|
2926
2881
|
if (!harnessReport.forgetting.fixture.passed || !harnessReport.warp.views.includes('Harness Experiments View') || !harnessReport.reliability.tool_error_taxonomy.includes('Unknown')) throw new Error('selftest failed: harness growth fixture incomplete');
|
|
2882
|
+
const proofField = await proofFieldFixture();
|
|
2883
|
+
if (!proofField.validation.ok || !validateProofFieldReport(proofField.report).ok) throw new Error('selftest failed: proof field report invalid');
|
|
2884
|
+
if (!proofField.checks.route_cone_selected || !proofField.checks.cli_cone_selected || !proofField.checks.catastrophic_guard_present || !proofField.checks.negative_release_work_recorded) throw new Error('selftest failed: proof field fixture checks incomplete');
|
|
2885
|
+
const workflowPerf = await runWorkflowPerfBench(tmp, {
|
|
2886
|
+
iterations: 2,
|
|
2887
|
+
intent: 'small CLI help surface update',
|
|
2888
|
+
changedFiles: ['src/cli/maintenance-commands.mjs', 'src/core/routes.mjs']
|
|
2889
|
+
});
|
|
2890
|
+
if (!validateWorkflowPerfReport(workflowPerf).ok || workflowPerf.metrics.decision_mode !== 'fast_lane' || !workflowPerf.metrics.fast_lane_eligible) throw new Error('selftest failed: workflow perf proof field did not produce a valid fast lane report');
|
|
2927
2891
|
if (classifyToolError({ message: 'operation timed out' }) !== 'Timeout' || classifyToolError({ message: 'unclassified weirdness' }) !== 'Unknown') throw new Error('selftest failed: tool error taxonomy classification');
|
|
2928
2892
|
const coord = rgbaToWikiCoord({ r: 12, g: 34, b: 56, a: 255 });
|
|
2929
2893
|
if (coord.schema !== 'sks.wiki-coordinate.v1' || coord.xyzw.length !== 4) throw new Error('selftest failed: RGBA wiki coordinate conversion');
|
|
@@ -2995,49 +2959,3 @@ async function selftest() {
|
|
|
2995
2959
|
console.log('ㅅㅋㅅ selftest passed.');
|
|
2996
2960
|
console.log(`temp: ${tmp}`);
|
|
2997
2961
|
}
|
|
2998
|
-
|
|
2999
|
-
async function db(sub, args) {
|
|
3000
|
-
const root = await sksRoot();
|
|
3001
|
-
if (sub === 'policy') {
|
|
3002
|
-
console.log(JSON.stringify(await loadDbSafetyPolicy(root), null, 2));
|
|
3003
|
-
return;
|
|
3004
|
-
}
|
|
3005
|
-
if (sub === 'scan') {
|
|
3006
|
-
const report = await scanDbSafety(root, { includeMigrations: flag(args, '--migrations') });
|
|
3007
|
-
console.log(JSON.stringify(report, null, 2));
|
|
3008
|
-
process.exitCode = report.ok ? 0 : 2;
|
|
3009
|
-
return;
|
|
3010
|
-
}
|
|
3011
|
-
if (sub === 'mcp-config') {
|
|
3012
|
-
const projectIdx = args.indexOf('--project-ref');
|
|
3013
|
-
const featuresIdx = args.indexOf('--features');
|
|
3014
|
-
const projectRef = projectIdx >= 0 ? args[projectIdx + 1] : '<project_ref>';
|
|
3015
|
-
const features = featuresIdx >= 0 ? args[featuresIdx + 1] : 'database,docs';
|
|
3016
|
-
console.log(JSON.stringify(safeSupabaseMcpConfig({ projectRef, readOnly: true, features }), null, 2));
|
|
3017
|
-
return;
|
|
3018
|
-
}
|
|
3019
|
-
if (sub === 'classify' || sub === 'check') {
|
|
3020
|
-
const sqlIdx = args.indexOf('--sql');
|
|
3021
|
-
const commandIdx = args.indexOf('--command');
|
|
3022
|
-
const fileIdx = args.indexOf('--file');
|
|
3023
|
-
let result;
|
|
3024
|
-
if (fileIdx >= 0 && args[fileIdx + 1]) result = await checkSqlFile(path.resolve(args[fileIdx + 1]));
|
|
3025
|
-
else if (commandIdx >= 0 && args[commandIdx + 1]) result = classifyCommand(args[commandIdx + 1]);
|
|
3026
|
-
else if (sqlIdx >= 0 && args[sqlIdx + 1]) result = classifySql(args[sqlIdx + 1]);
|
|
3027
|
-
else if (sub === 'check' && args[0]) result = await checkSqlFile(path.resolve(args[0]));
|
|
3028
|
-
else result = classifySql(args.join(' ').trim());
|
|
3029
|
-
console.log(JSON.stringify(result, null, 2));
|
|
3030
|
-
process.exitCode = ['destructive', 'write', 'possible_db'].includes(result.level) ? 2 : 0;
|
|
3031
|
-
return;
|
|
3032
|
-
}
|
|
3033
|
-
if (sub === 'scan-payload') {
|
|
3034
|
-
const raw = await fsp.readFile(0, 'utf8');
|
|
3035
|
-
const payload = raw.trim() ? JSON.parse(raw) : {};
|
|
3036
|
-
const decision = await checkDbOperation(root, {}, payload, { duringNoQuestion: false });
|
|
3037
|
-
console.log(JSON.stringify(decision, null, 2));
|
|
3038
|
-
process.exitCode = decision.action === 'block' ? 2 : 0;
|
|
3039
|
-
return;
|
|
3040
|
-
}
|
|
3041
|
-
console.error('Usage: sks db policy | db scan [--migrations] | db mcp-config --project-ref <id> | db check --sql "..." | db check --command "..." | db check --file file.sql');
|
|
3042
|
-
process.exitCode = 1;
|
|
3043
|
-
}
|
|
@@ -23,22 +23,78 @@ import { writeEffortDecision } from '../core/effort-orchestrator.mjs';
|
|
|
23
23
|
import { createWorkOrderLedger, writeWorkOrderLedger } from '../core/work-order-ledger.mjs';
|
|
24
24
|
import { writeFromChatImgArtifacts } from '../core/from-chat-img-forensics.mjs';
|
|
25
25
|
import { renderTeamDashboardState, writeTeamDashboardState } from '../core/team-dashboard-renderer.mjs';
|
|
26
|
-
import { runPerfBench } from '../core/perf-bench.mjs';
|
|
26
|
+
import { runPerfBench, runWorkflowPerfBench } from '../core/perf-bench.mjs';
|
|
27
|
+
import { writeProofFieldReport } from '../core/proof-field.mjs';
|
|
27
28
|
import { GOAL_BRIDGE_ARTIFACT, GOAL_WORKFLOW_ARTIFACT, updateGoalWorkflow, writeGoalWorkflow } from '../core/goal-workflow.mjs';
|
|
28
29
|
import { scanCodeStructure, writeCodeStructureReport } from '../core/code-structure.mjs';
|
|
29
30
|
import { writeMemorySweepReport } from '../core/memory-governor.mjs';
|
|
30
31
|
import { cleanupWarpTeamView, launchWarpTeamView } from '../core/warp-ui.mjs';
|
|
31
32
|
import { writeSkillForgeReport } from '../core/skill-forge.mjs';
|
|
32
33
|
import { writeMistakeMemoryReport } from '../core/mistake-memory.mjs';
|
|
33
|
-
import { scanDbSafety } from '../core/db-safety.mjs';
|
|
34
|
+
import { checkDbOperation, checkSqlFile, classifyCommand, classifySql, loadDbSafetyPolicy, safeSupabaseMcpConfig, scanDbSafety } from '../core/db-safety.mjs';
|
|
34
35
|
import { harnessGrowthReport, writeHarnessGrowthReport } from '../core/evaluation.mjs';
|
|
35
36
|
|
|
36
37
|
const flag = (args, name) => args.includes(name);
|
|
37
38
|
const promptOf = (args) => args.filter((x) => !String(x).startsWith('--')).join(' ').trim();
|
|
38
39
|
const TEAM_SESSION_CLEANUP_ARTIFACT = 'team-session-cleanup.json';
|
|
40
|
+
const REPOSITORY_URL = 'https://github.com/mandarange/Sneakoscope-Codex.git';
|
|
39
41
|
|
|
40
42
|
async function resolveMissionId(root, arg) { return (!arg || arg === 'latest') ? findLatestMission(root) : arg; }
|
|
41
43
|
|
|
44
|
+
export function quickstartCommand() {
|
|
45
|
+
console.log(`ㅅㅋㅅ Quickstart
|
|
46
|
+
|
|
47
|
+
First install and bootstrap this project:
|
|
48
|
+
npm i -g sneakoscope
|
|
49
|
+
sks root
|
|
50
|
+
sks bootstrap
|
|
51
|
+
sks
|
|
52
|
+
|
|
53
|
+
Use outside a project:
|
|
54
|
+
sks root
|
|
55
|
+
sks deps check
|
|
56
|
+
sks team "global mission"
|
|
57
|
+
|
|
58
|
+
If warp is missing:
|
|
59
|
+
sks deps install warp
|
|
60
|
+
|
|
61
|
+
Initialize this project for CLI and Codex App:
|
|
62
|
+
sks setup --bootstrap
|
|
63
|
+
|
|
64
|
+
Open from terminal:
|
|
65
|
+
sks
|
|
66
|
+
sks --auto-review --high
|
|
67
|
+
sks auto-review start --high
|
|
68
|
+
|
|
69
|
+
Verify:
|
|
70
|
+
sks deps check
|
|
71
|
+
sks codex-app check
|
|
72
|
+
sks warp check
|
|
73
|
+
sks auto-review status
|
|
74
|
+
sks doctor --fix
|
|
75
|
+
sks context7 check
|
|
76
|
+
sks selftest --mock
|
|
77
|
+
sks commands
|
|
78
|
+
sks dollar-commands
|
|
79
|
+
|
|
80
|
+
If hooks cannot find the command:
|
|
81
|
+
sks fix-path
|
|
82
|
+
|
|
83
|
+
Project-only install:
|
|
84
|
+
npm i -D sneakoscope
|
|
85
|
+
npx sks setup --install-scope project
|
|
86
|
+
|
|
87
|
+
Local-only install artifacts:
|
|
88
|
+
sks setup --local-only
|
|
89
|
+
# writes generated SKS files but excludes .sneakoscope/, .codex/, .agents/, AGENTS.md through .git/info/exclude
|
|
90
|
+
# user-owned AGENTS.md is preserved; an existing SKS managed block is refreshed
|
|
91
|
+
|
|
92
|
+
GitHub install for unreleased commits:
|
|
93
|
+
npm i -g git+${REPOSITORY_URL}
|
|
94
|
+
sks bootstrap
|
|
95
|
+
`);
|
|
96
|
+
}
|
|
97
|
+
|
|
42
98
|
export async function researchCommand(sub, args) {
|
|
43
99
|
if (sub === 'prepare') return researchPrepare(args);
|
|
44
100
|
if (sub === 'run') return researchRun(args);
|
|
@@ -385,6 +441,52 @@ export async function hproofCommand(sub, args) {
|
|
|
385
441
|
console.log(JSON.stringify(await evaluateDoneGate(root, id), null, 2));
|
|
386
442
|
}
|
|
387
443
|
|
|
444
|
+
export async function dbCommand(sub, args = []) {
|
|
445
|
+
const root = await sksRoot();
|
|
446
|
+
if (sub === 'policy') {
|
|
447
|
+
console.log(JSON.stringify(await loadDbSafetyPolicy(root), null, 2));
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
if (sub === 'scan') {
|
|
451
|
+
const report = await scanDbSafety(root, { includeMigrations: flag(args, '--migrations') });
|
|
452
|
+
console.log(JSON.stringify(report, null, 2));
|
|
453
|
+
process.exitCode = report.ok ? 0 : 2;
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
if (sub === 'mcp-config') {
|
|
457
|
+
const projectIdx = args.indexOf('--project-ref');
|
|
458
|
+
const featuresIdx = args.indexOf('--features');
|
|
459
|
+
const projectRef = projectIdx >= 0 ? args[projectIdx + 1] : '<project_ref>';
|
|
460
|
+
const features = featuresIdx >= 0 ? args[featuresIdx + 1] : 'database,docs';
|
|
461
|
+
console.log(JSON.stringify(safeSupabaseMcpConfig({ projectRef, readOnly: true, features }), null, 2));
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
if (sub === 'classify' || sub === 'check') {
|
|
465
|
+
const sqlIdx = args.indexOf('--sql');
|
|
466
|
+
const commandIdx = args.indexOf('--command');
|
|
467
|
+
const fileIdx = args.indexOf('--file');
|
|
468
|
+
let result;
|
|
469
|
+
if (fileIdx >= 0 && args[fileIdx + 1]) result = await checkSqlFile(path.resolve(args[fileIdx + 1]));
|
|
470
|
+
else if (commandIdx >= 0 && args[commandIdx + 1]) result = classifyCommand(args[commandIdx + 1]);
|
|
471
|
+
else if (sqlIdx >= 0 && args[sqlIdx + 1]) result = classifySql(args[sqlIdx + 1]);
|
|
472
|
+
else if (sub === 'check' && args[0]) result = await checkSqlFile(path.resolve(args[0]));
|
|
473
|
+
else result = classifySql(args.join(' ').trim());
|
|
474
|
+
console.log(JSON.stringify(result, null, 2));
|
|
475
|
+
process.exitCode = ['destructive', 'write', 'possible_db'].includes(result.level) ? 2 : 0;
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
if (sub === 'scan-payload') {
|
|
479
|
+
const raw = await fsp.readFile(0, 'utf8');
|
|
480
|
+
const payload = raw.trim() ? JSON.parse(raw) : {};
|
|
481
|
+
const decision = await checkDbOperation(root, {}, payload, { duringNoQuestion: false });
|
|
482
|
+
console.log(JSON.stringify(decision, null, 2));
|
|
483
|
+
process.exitCode = decision.action === 'block' ? 2 : 0;
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
console.error('Usage: sks db policy | db scan [--migrations] | db mcp-config --project-ref <id> | db check --sql "..." | db check --command "..." | db check --file file.sql');
|
|
487
|
+
process.exitCode = 1;
|
|
488
|
+
}
|
|
489
|
+
|
|
388
490
|
export async function validateArtifactsCommand(args = []) {
|
|
389
491
|
const root = await sksRoot();
|
|
390
492
|
const missionArg = args[0] && !String(args[0]).startsWith('--') ? args[0] : 'latest';
|
|
@@ -404,12 +506,32 @@ export async function validateArtifactsCommand(args = []) {
|
|
|
404
506
|
}
|
|
405
507
|
|
|
406
508
|
export async function perfCommand(sub, args = []) {
|
|
407
|
-
if (
|
|
408
|
-
console.error('Usage: sks perf run [--json] [--iterations N]');
|
|
509
|
+
if (!['run', 'workflow'].includes(sub)) {
|
|
510
|
+
console.error('Usage: sks perf run|workflow [--json] [--iterations N] [--intent "task"] [--changed file1,file2]');
|
|
409
511
|
process.exitCode = 1;
|
|
410
512
|
return;
|
|
411
513
|
}
|
|
412
514
|
const root = await sksRoot();
|
|
515
|
+
if (sub === 'workflow') {
|
|
516
|
+
const changedRaw = readFlagValue(args, '--changed', null);
|
|
517
|
+
const report = await runWorkflowPerfBench(root, {
|
|
518
|
+
iterations: readFlagValue(args, '--iterations', 3),
|
|
519
|
+
intent: readFlagValue(args, '--intent', positionalArgs(args).join(' ')),
|
|
520
|
+
changedFiles: changedRaw ? changedRaw.split(',').filter(Boolean) : undefined
|
|
521
|
+
});
|
|
522
|
+
const outPath = path.join(root, '.sneakoscope', 'reports', `workflow-perf-${Date.now()}.json`);
|
|
523
|
+
await writeJsonAtomic(outPath, report);
|
|
524
|
+
if (flag(args, '--json')) return console.log(JSON.stringify({ ...report, report_path: outPath }, null, 2));
|
|
525
|
+
console.log('SKS Workflow Performance');
|
|
526
|
+
console.log(`Mode: ${report.metrics.decision_mode}`);
|
|
527
|
+
console.log(`Fast lane: ${report.metrics.fast_lane_eligible ? 'yes' : 'no'}`);
|
|
528
|
+
console.log(`Proof Field p95: ${report.metrics.proof_field_build_ms_p95}ms`);
|
|
529
|
+
console.log(`Proof cones: ${report.metrics.proof_cone_count}`);
|
|
530
|
+
console.log(`Negative work skipped: ${report.metrics.negative_work_skipped_count}`);
|
|
531
|
+
console.log(`Next: ${report.recommendation.next.join('; ')}`);
|
|
532
|
+
console.log(`Report: ${path.relative(root, outPath)}`);
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
413
535
|
const report = await runPerfBench(root, { iterations: readFlagValue(args, '--iterations', 3) });
|
|
414
536
|
const outPath = path.join(root, '.sneakoscope', 'reports', `perf-${Date.now()}.json`);
|
|
415
537
|
await writeJsonAtomic(outPath, report);
|
|
@@ -421,6 +543,34 @@ export async function perfCommand(sub, args = []) {
|
|
|
421
543
|
console.log(`Report: ${path.relative(root, outPath)}`);
|
|
422
544
|
}
|
|
423
545
|
|
|
546
|
+
export async function proofFieldCommand(sub, args = []) {
|
|
547
|
+
const action = sub || 'scan';
|
|
548
|
+
if (!['scan', 'help', '--help'].includes(action)) {
|
|
549
|
+
console.error('Usage: sks proof-field scan [--json] [--intent "task"] [--changed file1,file2]');
|
|
550
|
+
process.exitCode = 1;
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
if (action === 'help' || action === '--help') {
|
|
554
|
+
console.log('Usage: sks proof-field scan [--json] [--intent "task"] [--changed file1,file2]');
|
|
555
|
+
console.log('Build a Potential Proof Field report: proof cones, negative-work cache, and fast-lane eligibility for the current change set.');
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
const root = await sksRoot();
|
|
559
|
+
const changedRaw = readFlagValue(args, '--changed', null);
|
|
560
|
+
const report = await writeProofFieldReport(root, {
|
|
561
|
+
intent: readFlagValue(args, '--intent', positionalArgs(args).join(' ')),
|
|
562
|
+
changedFiles: changedRaw ? changedRaw.split(',').filter(Boolean) : undefined
|
|
563
|
+
});
|
|
564
|
+
if (flag(args, '--json')) return console.log(JSON.stringify(report, null, 2));
|
|
565
|
+
console.log('SKS Proof Field');
|
|
566
|
+
console.log(`Mode: ${report.fast_lane_decision.mode}`);
|
|
567
|
+
console.log(`Eligible: ${report.fast_lane_decision.eligible ? 'yes' : 'no'}`);
|
|
568
|
+
if (report.fast_lane_decision.blockers.length) console.log(`Blockers: ${report.fast_lane_decision.blockers.join(', ')}`);
|
|
569
|
+
console.log(`Proof cones: ${report.proof_cones.map((cone) => cone.id).join(', ')}`);
|
|
570
|
+
console.log(`Verification: ${report.fast_lane_decision.verification.join('; ')}`);
|
|
571
|
+
console.log(`Report: ${path.relative(root, report.report_path)}`);
|
|
572
|
+
}
|
|
573
|
+
|
|
424
574
|
export async function harnessCommand(sub, args = []) {
|
|
425
575
|
const action = sub || 'fixture';
|
|
426
576
|
if (!['fixture', 'review'].includes(action)) {
|
|
@@ -1084,7 +1234,7 @@ export async function statsCommand(args) {
|
|
|
1084
1234
|
|
|
1085
1235
|
function positionalArgs(args = []) {
|
|
1086
1236
|
const out = [];
|
|
1087
|
-
const valueFlags = new Set(['--format', '--iterations', '--out', '--baseline', '--candidate', '--install-scope', '--max-cycles', '--depth', '--scope', '--transport', '--query', '--topic', '--tokens', '--timeout-ms', '--sql', '--command', '--project-ref', '--agent', '--phase', '--message', '--role', '--max-anchors', '--lines']);
|
|
1237
|
+
const valueFlags = new Set(['--format', '--iterations', '--out', '--baseline', '--candidate', '--install-scope', '--max-cycles', '--depth', '--scope', '--transport', '--query', '--topic', '--tokens', '--timeout-ms', '--sql', '--command', '--project-ref', '--agent', '--phase', '--message', '--role', '--max-anchors', '--lines', '--intent', '--changed']);
|
|
1088
1238
|
for (let i = 0; i < args.length; i++) {
|
|
1089
1239
|
const arg = String(args[i]);
|
|
1090
1240
|
if (valueFlags.has(arg)) {
|
package/src/core/db-safety.mjs
CHANGED
|
@@ -226,7 +226,27 @@ function hasTableRemovalRisk(cls = {}) {
|
|
|
226
226
|
...(cls.sql?.reasons || []),
|
|
227
227
|
...(cls.command?.reasons || [])
|
|
228
228
|
]);
|
|
229
|
-
return ['drop_table', '
|
|
229
|
+
return ['drop_table', 'truncate'].some((reason) => reasons.has(reason));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function hasMadSksCatastrophicDbRisk(cls = {}) {
|
|
233
|
+
const reasons = new Set([
|
|
234
|
+
...(cls.reasons || []),
|
|
235
|
+
...(cls.sql?.reasons || []),
|
|
236
|
+
...(cls.command?.reasons || [])
|
|
237
|
+
]);
|
|
238
|
+
return [
|
|
239
|
+
'drop_database',
|
|
240
|
+
'drop_schema',
|
|
241
|
+
'drop_table',
|
|
242
|
+
'truncate',
|
|
243
|
+
'delete_without_where',
|
|
244
|
+
'update_without_where',
|
|
245
|
+
'supabase_db_reset',
|
|
246
|
+
'prisma_migrate_reset',
|
|
247
|
+
'postgres_database_admin_command'
|
|
248
|
+
].some((reason) => reasons.has(reason))
|
|
249
|
+
|| cls.toolReasons?.includes?.('dangerous_supabase_management_tool');
|
|
230
250
|
}
|
|
231
251
|
|
|
232
252
|
function isMadSksRouteState(state = {}) {
|
|
@@ -259,23 +279,32 @@ export function evaluateDbSafety({ classification, policy = DEFAULT_DB_SAFETY_PO
|
|
|
259
279
|
if (cls.level === 'safe') return { allowed: true, action: 'allow', reasons: ['read_only_operation'], classification: cls };
|
|
260
280
|
if (cls.level === 'possible_db') return { allowed: !noQuestion, action: noQuestion ? 'block' : 'warn', reasons: noQuestion ? ['unknown_database_operation_blocked_during_no_question_run'] : ['unknown_database_operation'], classification: cls };
|
|
261
281
|
if (madSks?.active && (cls.level === 'write' || cls.level === 'destructive')) {
|
|
262
|
-
if (
|
|
282
|
+
if (hasMadSksCatastrophicDbRisk(cls)) {
|
|
263
283
|
return {
|
|
264
284
|
allowed: false,
|
|
265
|
-
action: '
|
|
266
|
-
reasons: ['
|
|
285
|
+
action: 'block',
|
|
286
|
+
reasons: ['mad_sks_catastrophic_db_operation_blocked'],
|
|
267
287
|
classification: cls,
|
|
268
288
|
effective,
|
|
269
|
-
mad_sks: {
|
|
289
|
+
mad_sks: {
|
|
290
|
+
active: true,
|
|
291
|
+
catastrophic_safety_guard_active: true,
|
|
292
|
+
blocked_categories: ['whole_database_or_table_removal', 'all_rows_delete_or_update', 'dangerous_project_management']
|
|
293
|
+
}
|
|
270
294
|
};
|
|
271
295
|
}
|
|
272
296
|
return {
|
|
273
297
|
allowed: true,
|
|
274
298
|
action: 'allow',
|
|
275
|
-
reasons:
|
|
299
|
+
reasons: ['mad_sks_scoped_override_active'],
|
|
276
300
|
classification: cls,
|
|
277
301
|
effective,
|
|
278
|
-
mad_sks: {
|
|
302
|
+
mad_sks: {
|
|
303
|
+
active: true,
|
|
304
|
+
sks_db_constraints_removed: true,
|
|
305
|
+
catastrophic_safety_guard_active: true,
|
|
306
|
+
supabase_mcp_schema_cleanup_allowed: true
|
|
307
|
+
}
|
|
279
308
|
};
|
|
280
309
|
}
|
|
281
310
|
if (cls.level === 'destructive') reasons.push('destructive_database_operation_blocked_always');
|
|
@@ -384,6 +413,13 @@ export async function checkSqlFile(file) {
|
|
|
384
413
|
}
|
|
385
414
|
|
|
386
415
|
export function dbBlockReason(decision) {
|
|
416
|
+
if ((decision.reasons || []).includes('mad_sks_catastrophic_db_operation_blocked')) {
|
|
417
|
+
return [
|
|
418
|
+
'Sneakoscope Codex MAD-SKS catastrophic database safeguard blocked this operation.',
|
|
419
|
+
'MAD-SKS opens Supabase MCP column/schema cleanup, direct execute SQL, and normal DB writes only while the mission gate is active.',
|
|
420
|
+
'Whole database/table removal, all-row value wipes, database reset, and dangerous project or branch management remain blocked.'
|
|
421
|
+
].join(' ');
|
|
422
|
+
}
|
|
387
423
|
if ((decision.reasons || []).includes('mad_sks_table_delete_requires_user_confirmation_30s')) {
|
|
388
424
|
return [
|
|
389
425
|
'Sneakoscope Codex MAD-SKS gate paused a table deletion operation.',
|
|
@@ -87,21 +87,23 @@ export function buildDecisionContract({ mission, schema, answers }) {
|
|
|
87
87
|
mad_sks_mode: madSks ? 'explicit_invocation_only' : false,
|
|
88
88
|
production_database_writes_allowed: madSks ? 'mad_sks_scoped' : false,
|
|
89
89
|
mcp_direct_execute_sql_writes_allowed: madSks ? 'mad_sks_scoped' : false,
|
|
90
|
-
db_reset_allowed:
|
|
91
|
-
db_drop_allowed: madSks ? '
|
|
92
|
-
db_truncate_allowed:
|
|
90
|
+
db_reset_allowed: false,
|
|
91
|
+
db_drop_allowed: madSks ? 'column_and_non_catastrophic_schema_cleanup_only' : false,
|
|
92
|
+
db_truncate_allowed: false,
|
|
93
93
|
db_mass_delete_update_allowed: madSks ? 'mad_sks_scoped' : false
|
|
94
94
|
},
|
|
95
95
|
database_safety: {
|
|
96
|
-
policy: madSks ? '
|
|
96
|
+
policy: madSks ? 'mad_sks_scoped_override_with_catastrophic_db_guard' : 'destructive_denied_always',
|
|
97
97
|
supabase_mcp_recommended_url: 'https://mcp.supabase.com/mcp?project_ref=<project_ref>&read_only=true&features=database,docs',
|
|
98
98
|
allowed_targets_for_write: madSks ? ['main_branch', 'production', 'local_dev', 'preview_branch', 'supabase_branch'] : ['local_dev', 'preview_branch', 'supabase_branch'],
|
|
99
|
-
forbidden_operations: madSks ? ['
|
|
99
|
+
forbidden_operations: madSks ? ['DROP_DATABASE', 'DROP_SCHEMA', 'DROP_TABLE', 'TRUNCATE', 'DELETE_WITHOUT_WHERE', 'UPDATE_WITHOUT_WHERE', 'DB_RESET', 'PROJECT_DELETE', 'BRANCH_RESET_OR_MERGE_OR_DELETE'] : ['DROP', 'TRUNCATE', 'DELETE_WITHOUT_WHERE', 'UPDATE_WITHOUT_WHERE', 'DB_RESET', 'DB_PUSH', 'PROJECT_DELETE', 'BRANCH_RESET_OR_MERGE_OR_DELETE', 'DISABLE_RLS', 'BROAD_GRANT_REVOKE'],
|
|
100
100
|
mad_sks_scope: madSks ? {
|
|
101
101
|
active_only_when_prompt_contains: '$MAD-SKS',
|
|
102
102
|
may_combine_with_primary_route: true,
|
|
103
103
|
deactivates_when_active_mission_gate_passes: true,
|
|
104
|
-
|
|
104
|
+
supabase_mcp_schema_cleanup_allowed: true,
|
|
105
|
+
direct_execute_sql_allowed: true,
|
|
106
|
+
catastrophic_safety_guard_active: true
|
|
105
107
|
} : null,
|
|
106
108
|
migration_apply_allowed: answers.DB_MIGRATION_APPLY_ALLOWED || 'no',
|
|
107
109
|
read_only_query_limit: answers.DB_READ_ONLY_QUERY_LIMIT || '1000'
|
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.87';
|
|
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
|
@@ -505,7 +505,7 @@ export async function installSkills(root) {
|
|
|
505
505
|
'research': `---\nname: research\ndescription: Dollar-command route for $Research or $research frontier discovery workflows.\n---\n\nUse when the user invokes $Research/$research or asks for research, hypotheses, new mechanisms, falsification, or testable predictions. Prefer sks research prepare and sks research run. Do not use for ordinary code edits.\n`,
|
|
506
506
|
'autoresearch': `---\nname: autoresearch\ndescription: Dollar-command route for $AutoResearch or $autoresearch iterative experiment loops.\n---\n\nUse for $AutoResearch, iterative improvement, SEO/GEO, ranking, workflow, benchmark, or experiments. Define program, hypothesis, experiment, metric, keep/discard, falsification, next step, and Honest Mode. Load seo-geo-optimizer for README/npm/GitHub/schema/AI-search work.\n`,
|
|
507
507
|
'db': `---\nname: db\ndescription: Dollar-command route for $DB or $db database and Supabase safety checks.\n---\n\nUse when the user invokes $DB/$db or the task touches SQL, Supabase, Postgres, migrations, Prisma, Drizzle, Knex, MCP database tools, or production data. Run or follow sks db policy, sks db scan, sks db classify, and sks db check. Destructive database operations remain forbidden.\n`,
|
|
508
|
-
'mad-sks': `---\nname: mad-sks\ndescription: Explicit high-risk authorization modifier for $MAD-SKS scoped Supabase MCP DB permission widening.\n---\n\nUse only when the user explicitly invokes $MAD-SKS. It can be combined with another route, such as $MAD-SKS $Team or $DB ... $MAD-SKS; in that case the other command remains the primary workflow and MAD-SKS is only the temporary permission grant. The widened DB permission applies only while the active mission gate is open,
|
|
508
|
+
'mad-sks': `---\nname: mad-sks\ndescription: Explicit high-risk authorization modifier for $MAD-SKS scoped Supabase MCP DB permission widening.\n---\n\nUse only when the user explicitly invokes $MAD-SKS. It can be combined with another route, such as $MAD-SKS $Team or $DB ... $MAD-SKS; in that case the other command remains the primary workflow and MAD-SKS is only the temporary permission grant. The widened DB permission applies only while the active mission gate is open, must be deactivated when the task ends, and opens Supabase MCP column/schema cleanup, direct execute SQL, and normal DB write permissions. Keep only catastrophic database-wipe safeguards: whole database/table removal, all-row delete/update, reset, and dangerous project/branch management remain blocked. Do not carry MAD-SKS permission into later prompts or routes.\n`,
|
|
509
509
|
'gx': `---\nname: gx\ndescription: Dollar-command route for $GX or $gx deterministic GX visual context cartridges.\n---\n\nUse when the user invokes $GX/$gx or asks for architecture/context visualization through SKS. Prefer sks gx init, render, validate, drift, and snapshot. vgraph.json remains the source of truth.\n`,
|
|
510
510
|
'help': `---\nname: help\ndescription: Dollar-command route for $Help or $help explaining installed SKS commands and workflows.\n---\n\nUse when the user invokes $Help/$help or asks what commands exist. Prefer concise output from sks commands, sks usage <topic>, sks quickstart, sks aliases, and sks codex-app.\n`,
|
|
511
511
|
'prompt-pipeline': `---\nname: prompt-pipeline\ndescription: Default SKS prompt optimization pipeline for execution prompts; Answer and DFix bypass it.\n---\n\nClassify intent: Answer only for real questions; question-shaped implicit instructions, complaints, and mandatory-policy statements route to Team. DFix handles tiny design/content; code defaults to Team unless safety/research/GX route fits. Infer goal, target, constraints, acceptance, risk, and smallest safe route. Ask only scope/safety/behavior/acceptance-changing questions; otherwise seal inferred answers. Code work surfaces route/guard/scopes, materializes team-roster.json from default or explicit counts before implementation, compiles concrete Team runtime graph/inbox artifacts after consensus, and parent owns integration/tests/Context7/Honest Mode.\n\n${chatCaptureIntakeText()}\n\nDesign: read design.md; if missing use design-system-builder; use imagegen for image/logo/raster. TriWiki context-tracking SSOT: .sneakoscope/wiki/context-pack.json; read only the latest coordinate+voxel overlay pack before every route stage, run sks wiki refresh/pack after changes, validate before handoffs/final.\n`,
|
package/src/core/perf-bench.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { performance } from 'node:perf_hooks';
|
|
3
3
|
import { dirSize, fileSize, nowIso, packageRoot, runProcess, writeJsonAtomic } from './fsx.mjs';
|
|
4
|
+
import { buildProofField, validateProofFieldReport } from './proof-field.mjs';
|
|
4
5
|
|
|
5
6
|
export const DEFAULT_PERF_BUDGETS = {
|
|
6
7
|
cli_startup_ms_p95: 250,
|
|
@@ -8,6 +9,8 @@ export const DEFAULT_PERF_BUDGETS = {
|
|
|
8
9
|
context_build_ms_p95: 500,
|
|
9
10
|
artifact_validation_ms_p95: 150,
|
|
10
11
|
dashboard_render_ms_p95: 100,
|
|
12
|
+
proof_field_build_ms_p95: 150,
|
|
13
|
+
workflow_scan_ms_p95: 1000,
|
|
11
14
|
fast_selftest_ms_p95: 5000,
|
|
12
15
|
package_size_kb_max: 1024,
|
|
13
16
|
notes: 'Package payload budget is 1024KB because the current low-dependency CLI payload is already above 512KB; reduce only with measured justification.'
|
|
@@ -52,6 +55,90 @@ export async function runPerfBench(root, opts = {}) {
|
|
|
52
55
|
};
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
export async function runWorkflowPerfBench(root, opts = {}) {
|
|
59
|
+
const iterations = Math.max(1, Math.min(20, Number(opts.iterations || 3)));
|
|
60
|
+
const intent = String(opts.intent || '').trim();
|
|
61
|
+
const changedFiles = normalizeChangedFiles(opts.changedFiles);
|
|
62
|
+
const proofFieldBuild = [];
|
|
63
|
+
let proofField = null;
|
|
64
|
+
for (let i = 0; i < iterations; i++) {
|
|
65
|
+
const t0 = performance.now();
|
|
66
|
+
proofField = await buildProofField(root, {
|
|
67
|
+
intent,
|
|
68
|
+
changedFiles: changedFiles.length ? changedFiles : undefined
|
|
69
|
+
});
|
|
70
|
+
proofFieldBuild.push(performance.now() - t0);
|
|
71
|
+
}
|
|
72
|
+
const proofValidation = validateProofFieldReport(proofField);
|
|
73
|
+
const verification = proofField?.fast_lane_decision?.verification || [];
|
|
74
|
+
const negativeWork = proofField?.negative_work_cache || [];
|
|
75
|
+
const estimatedSavedWork = negativeWork.filter((item) => item.disposition === 'skip_with_evidence').length;
|
|
76
|
+
const proofFieldMsP95 = Math.round(percentile(proofFieldBuild, 95));
|
|
77
|
+
const workflowScanMsP95 = proofFieldMsP95;
|
|
78
|
+
return {
|
|
79
|
+
schema_version: 1,
|
|
80
|
+
measured_at: nowIso(),
|
|
81
|
+
theory: 'Potential Proof Field',
|
|
82
|
+
iterations,
|
|
83
|
+
intent: intent || null,
|
|
84
|
+
budgets: DEFAULT_PERF_BUDGETS,
|
|
85
|
+
metrics: {
|
|
86
|
+
proof_field_build_ms_p95: proofFieldMsP95,
|
|
87
|
+
workflow_scan_ms_p95: workflowScanMsP95,
|
|
88
|
+
decision_mode: proofField?.fast_lane_decision?.mode || null,
|
|
89
|
+
fast_lane_eligible: Boolean(proofField?.fast_lane_decision?.eligible),
|
|
90
|
+
proof_cone_count: proofField?.proof_cones?.length || 0,
|
|
91
|
+
verification_count: verification.length,
|
|
92
|
+
negative_work_skipped_count: estimatedSavedWork,
|
|
93
|
+
proof_field_valid: proofValidation.ok
|
|
94
|
+
},
|
|
95
|
+
proof_field: proofField,
|
|
96
|
+
recommendation: workflowRecommendation(proofField, proofValidation),
|
|
97
|
+
raw: {
|
|
98
|
+
proof_field_build_ms: proofFieldBuild.map((value) => Math.round(value))
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function validateWorkflowPerfReport(report = {}) {
|
|
104
|
+
const issues = [];
|
|
105
|
+
if (report.schema_version !== 1) issues.push('schema_version');
|
|
106
|
+
if (report.theory !== 'Potential Proof Field') issues.push('theory');
|
|
107
|
+
if (!report.metrics || !Number.isFinite(Number(report.metrics.proof_field_build_ms_p95))) issues.push('proof_field_build_ms_p95');
|
|
108
|
+
if (!report.metrics?.decision_mode) issues.push('decision_mode');
|
|
109
|
+
if (!report.proof_field || !validateProofFieldReport(report.proof_field).ok) issues.push('proof_field');
|
|
110
|
+
if (!report.recommendation?.mode) issues.push('recommendation');
|
|
111
|
+
return { ok: issues.length === 0, issues };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function normalizeChangedFiles(files) {
|
|
115
|
+
return [...new Set((files || []).flatMap((value) => String(value || '').split(',')).map((file) => file.trim()).filter(Boolean))]
|
|
116
|
+
.sort();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function workflowRecommendation(proofField, validation) {
|
|
120
|
+
if (!validation.ok) {
|
|
121
|
+
return {
|
|
122
|
+
mode: 'full_proof',
|
|
123
|
+
reason: `proof field invalid: ${validation.issues.join(', ')}`,
|
|
124
|
+
next: ['repair proof-field report generation', 'rerun sks perf workflow --json']
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const decision = proofField.fast_lane_decision;
|
|
128
|
+
if (decision.eligible) {
|
|
129
|
+
return {
|
|
130
|
+
mode: 'fast_lane',
|
|
131
|
+
reason: 'selected proof cones are narrow and all unrelated work is safely cached as negative work',
|
|
132
|
+
next: decision.verification
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
mode: decision.mode,
|
|
137
|
+
reason: decision.blockers.length ? `blocked by ${decision.blockers.join(', ')}` : 'balanced proof required',
|
|
138
|
+
next: decision.verification
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
55
142
|
async function packagePayloadSize(root) {
|
|
56
143
|
let total = 0;
|
|
57
144
|
for (const rel of ['bin', 'src']) total += await dirSize(path.join(root, rel));
|
package/src/core/pipeline.mjs
CHANGED
|
@@ -258,16 +258,16 @@ function applyMadSksAuthorizationToSchema(schema = {}) {
|
|
|
258
258
|
DATABASE_TARGET_ENVIRONMENT: 'main_branch',
|
|
259
259
|
DATABASE_WRITE_MODE: 'mad_sks_full_mcp_write_for_invocation',
|
|
260
260
|
SUPABASE_MCP_POLICY: 'mad_sks_project_scoped_write_for_invocation',
|
|
261
|
-
DESTRUCTIVE_DB_OPERATIONS_ALLOWED: '
|
|
261
|
+
DESTRUCTIVE_DB_OPERATIONS_ALLOWED: 'mad_sks_scoped_except_catastrophic_db_wipe',
|
|
262
262
|
DB_BACKUP_OR_BRANCH_REQUIRED: 'recommended_but_not_required_in_mad_sks',
|
|
263
|
-
DB_MAX_BLAST_RADIUS: '
|
|
263
|
+
DB_MAX_BLAST_RADIUS: 'mad_sks_active_invocation_only_catastrophic_wipe_blocked',
|
|
264
264
|
DB_MIGRATION_APPLY_ALLOWED: 'mad_sks_active_invocation_only',
|
|
265
265
|
DB_READ_ONLY_QUERY_LIMIT: '100'
|
|
266
266
|
};
|
|
267
267
|
schema.inference_notes = {
|
|
268
268
|
...(schema.inference_notes || {}),
|
|
269
269
|
MAD_SKS_MODE: 'explicit dollar command modifier is the permission boundary',
|
|
270
|
-
DESTRUCTIVE_DB_OPERATIONS_ALLOWED: 'MAD-SKS
|
|
270
|
+
DESTRUCTIVE_DB_OPERATIONS_ALLOWED: 'MAD-SKS opens Supabase MCP DB cleanup while blocking only catastrophic database wipe operations'
|
|
271
271
|
};
|
|
272
272
|
schema.slots = (schema.slots || []).filter((slot) => !/^(DB_|DATABASE_|DESTRUCTIVE_DB_|SUPABASE_MCP_POLICY$)/.test(slot.id));
|
|
273
273
|
return schema;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { nowIso, readText, rel, runProcess, sha256, writeJsonAtomic } from './fsx.mjs';
|
|
3
|
+
|
|
4
|
+
export const PROOF_FIELD_SCHEMA_VERSION = 1;
|
|
5
|
+
|
|
6
|
+
export const INVARIANT_LEDGER = Object.freeze([
|
|
7
|
+
{ id: 'db-catastrophic-guard', severity: 'critical', description: 'Database/table wipe, all-row DML, reset, and dangerous project/branch operations remain blocked.' },
|
|
8
|
+
{ id: 'honest-evidence', severity: 'critical', description: 'Final claims must be backed by current code, tests, artifacts, or explicitly marked unverified.' },
|
|
9
|
+
{ id: 'route-surface-consistency', severity: 'high', description: 'User-visible route surfaces must agree across CLI help, command catalog, generated skills, and docs.' },
|
|
10
|
+
{ id: 'triwiki-hydratable-context', severity: 'high', description: 'TriWiki context must remain coordinate+voxel backed and hydratable by source/hash/anchor.' },
|
|
11
|
+
{ id: 'no-unrequested-fallback-code', severity: 'high', description: 'Do not add substitute paths, mocks, shims, or fallback behavior unless explicitly requested.' }
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
export const PROOF_CONE_DEFINITIONS = Object.freeze([
|
|
15
|
+
{
|
|
16
|
+
id: 'db_safety',
|
|
17
|
+
surfaces: ['database', 'supabase', 'mad-sks'],
|
|
18
|
+
match: [/db-safety|supabase|migration|rls|schema|sql/i],
|
|
19
|
+
verification: ['npm run packcheck', 'npm run selftest -- --mock', 'sks db scan --json'],
|
|
20
|
+
negative_work: ['browser_ui_e2e', 'visual_snapshot']
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: 'route_surface',
|
|
24
|
+
surfaces: ['routes', 'skills', 'cli-help', 'docs'],
|
|
25
|
+
match: [/routes\.mjs|init\.mjs|codex-app|README|AGENTS|skills/i],
|
|
26
|
+
verification: ['npm run packcheck', 'npm run selftest -- --mock', 'sks commands --json'],
|
|
27
|
+
negative_work: ['database_migration', 'from_chat_img_forensics']
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: 'cli_runtime',
|
|
31
|
+
surfaces: ['cli', 'commands', 'runtime'],
|
|
32
|
+
match: [/src\/cli|bin\/sks|maintenance-commands|fsx|codex-adapter/i],
|
|
33
|
+
verification: ['npm run packcheck', 'node ./bin/sks.mjs commands --json', 'node ./bin/sks.mjs proof-field scan --json'],
|
|
34
|
+
negative_work: ['browser_ui_e2e']
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'context_memory',
|
|
38
|
+
surfaces: ['triwiki', 'memory', 'evaluation'],
|
|
39
|
+
match: [/triwiki|wiki|memory|evaluation|perf-bench|proof-field/i],
|
|
40
|
+
verification: ['npm run packcheck', 'node ./bin/sks.mjs eval run --json', 'node ./bin/sks.mjs wiki validate .sneakoscope/wiki/context-pack.json'],
|
|
41
|
+
negative_work: ['database_migration', 'browser_ui_e2e']
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'release_surface',
|
|
45
|
+
surfaces: ['package', 'changelog', 'release'],
|
|
46
|
+
match: [/package\.json|package-lock\.json|CHANGELOG|README/i],
|
|
47
|
+
verification: ['npm run release:check'],
|
|
48
|
+
negative_work: []
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'visual_forensic',
|
|
52
|
+
surfaces: ['from-chat-img', 'visual', 'qa-loop'],
|
|
53
|
+
match: [/from-chat-img|visual|screenshot|qa-loop|dogfood/i],
|
|
54
|
+
verification: ['npm run packcheck', 'npm run selftest -- --mock'],
|
|
55
|
+
negative_work: ['database_migration']
|
|
56
|
+
}
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
export async function buildProofField(root, opts = {}) {
|
|
60
|
+
const changedFiles = normalizeChangedFiles(opts.changedFiles || await gitChangedFiles(root));
|
|
61
|
+
const intent = String(opts.intent || '').trim();
|
|
62
|
+
const selectedCones = selectProofCones(changedFiles, intent);
|
|
63
|
+
const risk = riskSummary(changedFiles, selectedCones, intent);
|
|
64
|
+
const negativeWork = buildNegativeWorkCache(selectedCones, risk);
|
|
65
|
+
const fastLane = fastLaneDecision({ changedFiles, selectedCones, risk, negativeWork });
|
|
66
|
+
const sourceHash = await sourceDigest(root, changedFiles);
|
|
67
|
+
return {
|
|
68
|
+
schema_version: PROOF_FIELD_SCHEMA_VERSION,
|
|
69
|
+
generated_at: nowIso(),
|
|
70
|
+
theory: 'Potential Proof Field',
|
|
71
|
+
intent: intent || null,
|
|
72
|
+
source_hash: sourceHash,
|
|
73
|
+
changed_files: changedFiles,
|
|
74
|
+
invariant_ledger: INVARIANT_LEDGER,
|
|
75
|
+
proof_cones: selectedCones,
|
|
76
|
+
negative_work_cache: negativeWork,
|
|
77
|
+
fast_lane_decision: fastLane,
|
|
78
|
+
next_action: nextAction(fastLane)
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function writeProofFieldReport(root, opts = {}) {
|
|
83
|
+
const report = await buildProofField(root, opts);
|
|
84
|
+
const file = path.join(root, '.sneakoscope', 'reports', `proof-field-${Date.now()}.json`);
|
|
85
|
+
await writeJsonAtomic(file, report);
|
|
86
|
+
return { ...report, report_path: file };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function validateProofFieldReport(report = {}) {
|
|
90
|
+
const issues = [];
|
|
91
|
+
if (report.schema_version !== PROOF_FIELD_SCHEMA_VERSION) issues.push('schema_version');
|
|
92
|
+
if (!Array.isArray(report.invariant_ledger) || !report.invariant_ledger.length) issues.push('invariant_ledger');
|
|
93
|
+
if (!Array.isArray(report.proof_cones)) issues.push('proof_cones');
|
|
94
|
+
if (!Array.isArray(report.negative_work_cache)) issues.push('negative_work_cache');
|
|
95
|
+
if (!report.fast_lane_decision?.mode) issues.push('fast_lane_decision');
|
|
96
|
+
if (report.fast_lane_decision?.mode === 'fast_lane' && report.fast_lane_decision?.escalate_on?.length < 1) issues.push('fast_lane_escalation');
|
|
97
|
+
return { ok: issues.length === 0, issues };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export async function proofFieldFixture() {
|
|
101
|
+
const report = await buildProofField(process.cwd(), {
|
|
102
|
+
intent: 'small CLI help surface update',
|
|
103
|
+
changedFiles: ['src/cli/maintenance-commands.mjs', 'src/core/routes.mjs']
|
|
104
|
+
});
|
|
105
|
+
return {
|
|
106
|
+
report,
|
|
107
|
+
validation: validateProofFieldReport(report),
|
|
108
|
+
checks: {
|
|
109
|
+
route_cone_selected: report.proof_cones.some((cone) => cone.id === 'route_surface'),
|
|
110
|
+
cli_cone_selected: report.proof_cones.some((cone) => cone.id === 'cli_runtime'),
|
|
111
|
+
catastrophic_guard_present: report.invariant_ledger.some((item) => item.id === 'db-catastrophic-guard'),
|
|
112
|
+
negative_release_work_recorded: report.negative_work_cache.some((item) => item.id === 'full_release_gate' && item.disposition === 'skip_with_evidence')
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function gitChangedFiles(root) {
|
|
118
|
+
const result = await runProcess('git', ['diff', '--name-only', 'HEAD', '--'], { cwd: root, timeoutMs: 10000, maxOutputBytes: 128 * 1024 });
|
|
119
|
+
if (result.code !== 0) return [];
|
|
120
|
+
return result.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function normalizeChangedFiles(files = []) {
|
|
124
|
+
return [...new Set((files || []).flatMap((value) => String(value || '').split(',')).map((file) => file.trim()).filter(Boolean))]
|
|
125
|
+
.sort();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function selectProofCones(files, intent) {
|
|
129
|
+
const haystack = `${files.join('\n')}\n${intent || ''}`;
|
|
130
|
+
const selected = PROOF_CONE_DEFINITIONS
|
|
131
|
+
.filter((cone) => cone.match.some((re) => re.test(haystack)))
|
|
132
|
+
.map((cone) => ({
|
|
133
|
+
id: cone.id,
|
|
134
|
+
surfaces: cone.surfaces,
|
|
135
|
+
verification: cone.verification,
|
|
136
|
+
matched_files: files.filter((file) => cone.match.some((re) => re.test(file)))
|
|
137
|
+
}));
|
|
138
|
+
if (!selected.length) {
|
|
139
|
+
selected.push({
|
|
140
|
+
id: 'generic_local_change',
|
|
141
|
+
surfaces: ['unknown'],
|
|
142
|
+
verification: ['npm run packcheck', 'focused relevant tests or documented justification'],
|
|
143
|
+
matched_files: files
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return selected;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function riskSummary(files, cones, intent) {
|
|
150
|
+
const text = `${files.join('\n')}\n${intent || ''}`;
|
|
151
|
+
const flags = {
|
|
152
|
+
database: /\b(db|database|supabase|sql|migration|rls|schema)\b/i.test(text),
|
|
153
|
+
security: /\b(auth|permission|token|secret|security|권한|보안)\b/i.test(text),
|
|
154
|
+
visual_forensic: /from-chat-img|screenshot|visual|이미지|스크린샷/i.test(text),
|
|
155
|
+
release: /package\.json|package-lock\.json|CHANGELOG|release|publish/i.test(text),
|
|
156
|
+
broad_change: files.length > 3,
|
|
157
|
+
unknown_surface: cones.some((cone) => cone.id === 'generic_local_change')
|
|
158
|
+
};
|
|
159
|
+
const score = Object.values(flags).filter(Boolean).length;
|
|
160
|
+
const level = score >= 3 ? 'high' : score === 2 ? 'medium' : score === 1 ? 'low' : 'minimal';
|
|
161
|
+
return { level, score, flags };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function buildNegativeWorkCache(cones, risk) {
|
|
165
|
+
const required = new Set(cones.flatMap((cone) => cone.verification));
|
|
166
|
+
const candidates = new Set(cones.flatMap((cone) => cone.negative_work || []));
|
|
167
|
+
const out = [];
|
|
168
|
+
for (const id of candidates) {
|
|
169
|
+
const blockedByRisk = (id === 'database_migration' && risk.flags.database)
|
|
170
|
+
|| (id === 'browser_ui_e2e' && risk.flags.visual_forensic);
|
|
171
|
+
out.push({
|
|
172
|
+
id,
|
|
173
|
+
disposition: blockedByRisk ? 'not_skipped_risk_present' : 'skip_with_evidence',
|
|
174
|
+
reason: blockedByRisk ? 'risk flag requires explicit verification' : 'selected proof cones do not touch this surface'
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (!required.has('npm run release:check') && !risk.flags.release) {
|
|
178
|
+
out.push({ id: 'full_release_gate', disposition: 'skip_with_evidence', reason: 'no package/release surface in selected cones' });
|
|
179
|
+
}
|
|
180
|
+
return out.sort((a, b) => a.id.localeCompare(b.id));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function fastLaneDecision({ changedFiles, selectedCones, risk, negativeWork }) {
|
|
184
|
+
const verification = [...new Set(selectedCones.flatMap((cone) => cone.verification))];
|
|
185
|
+
const safeSkips = negativeWork.filter((item) => item.disposition === 'skip_with_evidence').map((item) => item.id);
|
|
186
|
+
const blockers = [];
|
|
187
|
+
if (!changedFiles.length) blockers.push('no_changed_files');
|
|
188
|
+
if (changedFiles.length > 3) blockers.push('broad_change_set');
|
|
189
|
+
if (risk.flags.database) blockers.push('database_surface');
|
|
190
|
+
if (risk.flags.security) blockers.push('security_surface');
|
|
191
|
+
if (risk.flags.visual_forensic) blockers.push('visual_forensic_surface');
|
|
192
|
+
if (risk.flags.unknown_surface) blockers.push('unknown_surface');
|
|
193
|
+
const mode = blockers.length ? (risk.level === 'high' ? 'full_proof' : 'balanced') : 'fast_lane';
|
|
194
|
+
return {
|
|
195
|
+
mode,
|
|
196
|
+
eligible: mode === 'fast_lane',
|
|
197
|
+
blockers,
|
|
198
|
+
verification,
|
|
199
|
+
negative_work: safeSkips,
|
|
200
|
+
escalate_on: ['verification_failed', 'proof_cone_unknown', 'source_hash_changed', 'unsupported_claim', 'user_scope_expanded']
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function nextAction(decision) {
|
|
205
|
+
if (decision.mode === 'fast_lane') return 'apply minimal patch, run listed verification, then Honest Mode against the proof field report';
|
|
206
|
+
if (decision.mode === 'balanced') return 'narrow the change set or run parent-led implementation with listed verification and reviewer escalation if checks fail';
|
|
207
|
+
return 'use full Team/Honest proof path; fast lane is intentionally blocked for this risk state';
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async function sourceDigest(root, files) {
|
|
211
|
+
const rows = [];
|
|
212
|
+
for (const file of files) {
|
|
213
|
+
const abs = path.resolve(root, file);
|
|
214
|
+
if (!abs.startsWith(path.resolve(root))) continue;
|
|
215
|
+
const text = await readText(abs, null);
|
|
216
|
+
rows.push([rel(root, abs), text == null ? null : sha256(text).slice(0, 16)]);
|
|
217
|
+
}
|
|
218
|
+
return sha256(JSON.stringify(rows)).slice(0, 24);
|
|
219
|
+
}
|
package/src/core/questions.mjs
CHANGED
|
@@ -13,16 +13,16 @@ function buildMadSksQuestionSchema(prompt) {
|
|
|
13
13
|
const task = String(prompt || '').trim() || 'MAD-SKS scoped database override';
|
|
14
14
|
return {
|
|
15
15
|
schema_version: 1,
|
|
16
|
-
description: 'MAD-SKS is explicit-invocation-only. It auto-seals because the dollar command itself is the permission boundary;
|
|
16
|
+
description: 'MAD-SKS is explicit-invocation-only. It auto-seals because the dollar command itself is the permission boundary; while active, SKS opens Supabase MCP schema cleanup and direct DB write permissions, leaving only catastrophic database-wipe safeguards.',
|
|
17
17
|
prompt,
|
|
18
18
|
domain_hints: ['db', 'mad-sks'],
|
|
19
19
|
inferred_answers: {
|
|
20
20
|
GOAL_PRECISE: `명시적인 MAD-SKS 호출 범위에서만 DB 권한 조건을 넓혀 작업한다: ${task}`,
|
|
21
21
|
ACCEPTANCE_CRITERIA: [
|
|
22
22
|
'$MAD-SKS is listed in dollar commands and routes to MADSKS mode',
|
|
23
|
-
'
|
|
23
|
+
'Supabase MCP column cleanup, schema cleanup, direct execute SQL, and normal DB writes are allowed only while the active MAD-SKS mission gate remains open',
|
|
24
24
|
'the widened permission is inactive after the MAD-SKS gate is passed or permissions_deactivated is true',
|
|
25
|
-
'table
|
|
25
|
+
'whole database/table removal and all-row delete/update operations remain blocked as non-sensible catastrophic operations'
|
|
26
26
|
],
|
|
27
27
|
NON_GOALS: [],
|
|
28
28
|
PUBLIC_API_CHANGE_ALLOWED: 'yes_if_needed',
|
|
@@ -33,21 +33,21 @@ function buildMadSksQuestionSchema(prompt) {
|
|
|
33
33
|
RISK_BOUNDARY: [
|
|
34
34
|
'MAD-SKS permission widening is explicit-invocation-only',
|
|
35
35
|
'MAD-SKS permission widening does not persist after the active task gate closes',
|
|
36
|
-
'
|
|
36
|
+
'catastrophic database wipe operations remain blocked even in MAD-SKS'
|
|
37
37
|
],
|
|
38
38
|
MAD_SKS_MODE: 'explicit_invocation_only',
|
|
39
39
|
DATABASE_TARGET_ENVIRONMENT: 'main_branch',
|
|
40
40
|
DATABASE_WRITE_MODE: 'mad_sks_full_mcp_write_for_invocation',
|
|
41
41
|
SUPABASE_MCP_POLICY: 'mad_sks_project_scoped_write_for_invocation',
|
|
42
|
-
DESTRUCTIVE_DB_OPERATIONS_ALLOWED: '
|
|
42
|
+
DESTRUCTIVE_DB_OPERATIONS_ALLOWED: 'mad_sks_scoped_except_catastrophic_db_wipe',
|
|
43
43
|
DB_BACKUP_OR_BRANCH_REQUIRED: 'recommended_but_not_required_in_mad_sks',
|
|
44
|
-
DB_MAX_BLAST_RADIUS: '
|
|
44
|
+
DB_MAX_BLAST_RADIUS: 'mad_sks_active_invocation_only_catastrophic_wipe_blocked',
|
|
45
45
|
DB_MIGRATION_APPLY_ALLOWED: 'mad_sks_active_invocation_only',
|
|
46
46
|
DB_READ_ONLY_QUERY_LIMIT: '100'
|
|
47
47
|
},
|
|
48
48
|
inference_notes: {
|
|
49
49
|
MAD_SKS_MODE: 'explicit dollar command is the permission boundary',
|
|
50
|
-
DESTRUCTIVE_DB_OPERATIONS_ALLOWED: 'MAD-SKS
|
|
50
|
+
DESTRUCTIVE_DB_OPERATIONS_ALLOWED: 'MAD-SKS opens Supabase MCP DB cleanup while blocking only catastrophic database wipe operations'
|
|
51
51
|
},
|
|
52
52
|
slots: []
|
|
53
53
|
};
|
package/src/core/routes.mjs
CHANGED
|
@@ -7,7 +7,7 @@ export const FROM_CHAT_IMG_CHECKLIST_ARTIFACT = 'from-chat-img-checklist.md';
|
|
|
7
7
|
export const FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT = 'from-chat-img-temp-triwiki.json';
|
|
8
8
|
export const FROM_CHAT_IMG_QA_LOOP_ARTIFACT = 'from-chat-img-qa-loop.json';
|
|
9
9
|
export const FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS = 5;
|
|
10
|
-
export const USAGE_TOPICS = 'install|setup|bootstrap|root|deps|warp|auto-review|team|qa-loop|goal|research|db|codex-app|dfix|design|imagegen|dollar|context7|pipeline|reasoning|guard|conflicts|versioning|eval|harness|hproof|gx|wiki|code-structure';
|
|
10
|
+
export const USAGE_TOPICS = 'install|setup|bootstrap|root|deps|warp|auto-review|team|qa-loop|goal|research|db|codex-app|dfix|design|imagegen|dollar|context7|pipeline|reasoning|guard|conflicts|versioning|eval|harness|hproof|gx|wiki|code-structure|proof-field';
|
|
11
11
|
export const CODEX_COMPUTER_USE_EVIDENCE_SOURCE = 'codex_computer_use';
|
|
12
12
|
export const CODEX_COMPUTER_USE_ONLY_POLICY = 'Pipeline UI/browser verification and visual inspection must use Codex Computer Use only. Do not use Playwright, Chrome MCP, Browser Use, Selenium, Puppeteer, or any other browser automation substitute; if Codex Computer Use is unavailable, mark the UI/browser evidence unverified instead of substituting another tool.';
|
|
13
13
|
export const FORBIDDEN_BROWSER_AUTOMATION_RE = /\b(playwright|chrome\s+mcp|browser\s+use|selenium|puppeteer)\b/i;
|
|
@@ -276,14 +276,14 @@ export const ROUTES = [
|
|
|
276
276
|
command: '$MAD-SKS',
|
|
277
277
|
mode: 'MADSKS',
|
|
278
278
|
route: 'explicit scoped database authorization modifier',
|
|
279
|
-
description: 'Explicit high-risk authorization modifier that can be combined with other $ commands to temporarily
|
|
279
|
+
description: 'Explicit high-risk authorization modifier that can be combined with other $ commands to temporarily open Supabase MCP column/schema cleanup, direct execute SQL, and normal DB write permissions for the active invocation, while blocking only catastrophic database-wipe operations.',
|
|
280
280
|
requiredSkills: ['mad-sks', 'db-safety-guard', 'pipeline-runner', 'context7-docs', REFLECTION_SKILL_NAME, 'honest-mode'],
|
|
281
|
-
lifecycle: ['explicit_invocation', 'auto_sealed_permission_scope', '
|
|
281
|
+
lifecycle: ['explicit_invocation', 'auto_sealed_permission_scope', 'scoped_db_cleanup_override', 'catastrophic_db_guard', 'permission_deactivation', 'post_route_reflection', 'honest_mode'],
|
|
282
282
|
context7Policy: 'required',
|
|
283
283
|
reasoningPolicy: 'high',
|
|
284
284
|
stopGate: 'mad-sks-gate.json',
|
|
285
285
|
cliEntrypoint: 'Codex App prompt route only: $MAD-SKS <task>',
|
|
286
|
-
examples: ['$MAD-SKS $Team Supabase MCP로 main 대상 DB
|
|
286
|
+
examples: ['$MAD-SKS $Team Supabase MCP로 main 대상 DB 컬럼 정리를 수행해', '$DB Supabase 점검 $MAD-SKS']
|
|
287
287
|
},
|
|
288
288
|
{
|
|
289
289
|
id: 'GX',
|
|
@@ -376,7 +376,8 @@ export const COMMAND_CATALOG = [
|
|
|
376
376
|
{ name: 'db', usage: 'sks db policy|scan|mcp-config|classify|check ...', description: 'Inspect and enforce database/Supabase safety policy.' },
|
|
377
377
|
{ name: 'eval', usage: 'sks eval run|compare|thresholds ...', description: 'Run deterministic context-quality and performance evidence checks.' },
|
|
378
378
|
{ name: 'harness', usage: 'sks harness fixture|review [--json]', description: 'Run Harness Growth Factory fixtures for forgetting, skills, experiments, tool taxonomy, permissions, MultiAgentV2, and Warp views.' },
|
|
379
|
-
{ name: 'perf', usage: 'sks perf run [--json] [--iterations N]', description: 'Measure structured GPT-5.5/SKS performance budgets
|
|
379
|
+
{ name: 'perf', usage: 'sks perf run|workflow [--json] [--iterations N] [--intent "task"] [--changed file1,file2]', description: 'Measure structured GPT-5.5/SKS performance budgets, including Proof Field workflow decisions and fast-lane evidence.' },
|
|
380
|
+
{ name: 'proof-field', usage: 'sks proof-field scan [--json] [--intent "task"] [--changed file1,file2]', description: 'Analyze Potential Proof Field cones, negative-work cache, and fast-lane eligibility for a change set.' },
|
|
380
381
|
{ name: 'code-structure', usage: 'sks code-structure scan [--json]', description: 'Scan handwritten source files for 1000/2000/3000-line structure gates and split-review exceptions.' },
|
|
381
382
|
{ name: 'validate-artifacts', usage: 'sks validate-artifacts [mission-id|latest] [--json]', description: 'Validate schema-backed mission artifacts for work orders, effort decisions, visual maps, dogfood reports, skills, mistake memory, Team dashboard state, and Honest Mode.' },
|
|
382
383
|
{ name: 'wiki', usage: 'sks wiki coords|pack|refresh|prune|validate ...', description: 'Build, refresh, prune, and validate RGBA/trig LLM Wiki context packs with attention.use_first and attention.hydrate_first for compact recall plus source hydration.' },
|