sneakoscope 4.1.1 → 4.2.0
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 +12 -9
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/bin/sks.js +1 -1
- package/dist/cli/command-registry.js +1 -1
- package/dist/core/auto-review.js +1 -1
- package/dist/core/commands/mad-db-command.js +146 -51
- package/dist/core/commands/mad-sks-command.js +15 -31
- package/dist/core/db-safety.js +35 -37
- package/dist/core/doctor/supabase-mcp-repair.js +2 -2
- package/dist/core/feature-registry.js +1 -1
- package/dist/core/fsx.js +1 -1
- package/dist/core/init.js +5 -4
- package/dist/core/mad-db/mad-db-capability.js +203 -74
- package/dist/core/mad-db/mad-db-coordinator.js +287 -0
- package/dist/core/mad-db/mad-db-executor.js +156 -0
- package/dist/core/mad-db/mad-db-ledger.js +1 -1
- package/dist/core/mad-db/mad-db-lock.js +40 -0
- package/dist/core/mad-db/mad-db-operation-store.js +140 -0
- package/dist/core/mad-db/mad-db-policy-resolver.js +42 -22
- package/dist/core/mad-db/mad-db-policy.js +195 -0
- package/dist/core/mad-db/mad-db-postconditions.js +30 -0
- package/dist/core/mad-db/mad-db-recovery.js +27 -0
- package/dist/core/mad-db/mad-db-result-lifecycle.js +31 -102
- package/dist/core/mad-db/mad-db-runtime-profile.js +121 -0
- package/dist/core/mad-db/mad-db-target.js +64 -0
- package/dist/core/managed-assets/managed-assets-manifest.js +1 -1
- package/dist/core/pipeline-internals/runtime-core.js +40 -0
- package/dist/core/providers/glm/bench/glm-benchmark-types.js +1 -1
- package/dist/core/release/release-gate-dag.js +6 -5
- package/dist/core/routes.js +23 -8
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-slot-column-anchor.js +5 -1
- package/dist/scripts/check-dist-runtime.js +3 -2
- package/dist/scripts/codex-0142-manifest-check.js +2 -1
- package/dist/scripts/mad-db-capability-check.js +13 -2
- package/dist/scripts/mad-db-command-check.js +7 -5
- package/dist/scripts/mad-db-hook-idempotency-check.js +21 -0
- package/dist/scripts/mad-db-ledger-check.js +2 -1
- package/dist/scripts/mad-db-lifecycle-hook-decision-check.js +5 -4
- package/dist/scripts/mad-db-mad-command-check.js +29 -16
- package/dist/scripts/mad-db-mcp-result-lifecycle-check.js +11 -10
- package/dist/scripts/mad-db-one-cycle-bounded-check.js +15 -18
- package/dist/scripts/mad-db-one-cycle-consumption-check.js +3 -3
- package/dist/scripts/mad-db-operation-lifecycle-blackbox.js +9 -9
- package/dist/scripts/mad-db-operation-lifecycle-ledger-check.js +6 -6
- package/dist/scripts/mad-db-parallel-lifecycle-check.js +24 -0
- package/dist/scripts/mad-db-policy-v2-check.js +20 -0
- package/dist/scripts/mad-db-priority-resolver-check.js +5 -5
- package/dist/scripts/mad-db-real-supabase-e2e.js +166 -0
- package/dist/scripts/mad-db-route-identity-check.js +28 -0
- package/dist/scripts/mad-db-runtime-profile-lifecycle-check.js +24 -0
- package/dist/scripts/mad-db-safety-conflict-matrix-check.js +3 -3
- package/dist/scripts/mad-db-skill-policy-snapshot-check.js +15 -0
- package/dist/scripts/release-dag-full-coverage-check.js +6 -0
- package/dist/scripts/release-triwiki-first-runner-blackbox.js +5 -1
- package/package.json +13 -3
- package/schemas/mad-db/mad-db-capability.schema.json +92 -19
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { exists, readText, sha256 } from '../fsx.js';
|
|
3
|
+
export async function resolveMadDbTarget(root, input = {}) {
|
|
4
|
+
const args = input.args || [];
|
|
5
|
+
const explicit = input.projectRef || readOption(args, '--project-ref', '') || process.env.SKS_MAD_DB_PROJECT_REF || process.env.SKS_MAD_DB_E2E_PROJECT_REF || '';
|
|
6
|
+
const candidates = explicit ? [explicit] : await projectRefCandidates(root);
|
|
7
|
+
const projectRef = explicit || (candidates.length === 1 ? candidates[0] || '' : '');
|
|
8
|
+
const target = normalizeTarget(input.target || readOption(args, '--target', '') || process.env.SKS_MAD_DB_TARGET || process.env.SKS_MAD_DB_E2E_TARGET || 'production');
|
|
9
|
+
const allowedSchemas = input.allowedSchemas?.length
|
|
10
|
+
? input.allowedSchemas
|
|
11
|
+
: splitCsv(readOption(args, '--schema', readOption(args, '--schemas', process.env.SKS_MAD_DB_SCHEMAS || 'public')));
|
|
12
|
+
const blockers = [];
|
|
13
|
+
if (!projectRef)
|
|
14
|
+
blockers.push(candidates.length > 1 ? 'mad_db_project_ref_ambiguous' : 'mad_db_project_ref_missing');
|
|
15
|
+
return {
|
|
16
|
+
schema: 'sks.mad-db-target.v1',
|
|
17
|
+
project_ref: projectRef || null,
|
|
18
|
+
project_ref_hash: projectRef ? sha256(projectRef).slice(0, 16) : null,
|
|
19
|
+
target_environment: target,
|
|
20
|
+
allowed_schemas: allowedSchemas.length ? allowedSchemas : ['public'],
|
|
21
|
+
source: explicit ? 'explicit_or_environment' : candidates.length === 1 ? 'managed_config_single_candidate' : 'unresolved',
|
|
22
|
+
blockers,
|
|
23
|
+
candidates: candidates.map((candidate) => `${sha256(candidate).slice(0, 8)}:${candidate.slice(0, 2)}...`)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export async function projectRootHash(root) {
|
|
27
|
+
return sha256(path.resolve(root)).slice(0, 24);
|
|
28
|
+
}
|
|
29
|
+
async function projectRefCandidates(root) {
|
|
30
|
+
const files = ['.codex/config.toml', '.mcp.json', 'mcp.json', '.cursor/mcp.json', '.vscode/mcp.json'];
|
|
31
|
+
const out = new Set();
|
|
32
|
+
for (const rel of files) {
|
|
33
|
+
const file = path.join(root, rel);
|
|
34
|
+
if (!(await exists(file)))
|
|
35
|
+
continue;
|
|
36
|
+
const text = await readText(file, '');
|
|
37
|
+
for (const match of String(text).matchAll(/project_ref=([a-z0-9_-]+)/gi))
|
|
38
|
+
out.add(match[1] || '');
|
|
39
|
+
for (const match of String(text).matchAll(/project_ref["']?\s*[:=]\s*["']([a-z0-9_-]+)["']/gi))
|
|
40
|
+
out.add(match[1] || '');
|
|
41
|
+
}
|
|
42
|
+
return [...out].filter(Boolean);
|
|
43
|
+
}
|
|
44
|
+
function normalizeTarget(value) {
|
|
45
|
+
const text = String(value || '').toLowerCase();
|
|
46
|
+
if (text === 'local')
|
|
47
|
+
return 'local';
|
|
48
|
+
if (text === 'branch')
|
|
49
|
+
return 'branch';
|
|
50
|
+
if (text === 'preview')
|
|
51
|
+
return 'preview';
|
|
52
|
+
return 'production';
|
|
53
|
+
}
|
|
54
|
+
function splitCsv(value) {
|
|
55
|
+
return String(value || '').split(',').map((entry) => entry.trim()).filter(Boolean);
|
|
56
|
+
}
|
|
57
|
+
function readOption(args, name, fallback) {
|
|
58
|
+
const index = args.indexOf(name);
|
|
59
|
+
if (index >= 0 && args[index + 1] && !String(args[index + 1]).startsWith('--'))
|
|
60
|
+
return String(args[index + 1]);
|
|
61
|
+
const prefixed = args.find((arg) => String(arg).startsWith(`${name}=`));
|
|
62
|
+
return prefixed ? prefixed.slice(name.length + 1) : fallback;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=mad-db-target.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { REQUIRED_CODEX_MODEL } from '../codex-model-guard.js';
|
|
2
2
|
export const MANAGED_ASSET_SCHEMA_VERSION = 1;
|
|
3
|
-
export const MANAGED_ASSET_VERSION = '4.
|
|
3
|
+
export const MANAGED_ASSET_VERSION = '4.2.0';
|
|
4
4
|
export const MANAGED_ASSET_MARKER = 'SKS-MANAGED-ASSET';
|
|
5
5
|
export const MANAGED_AGENT_ROLES = Object.freeze([
|
|
6
6
|
role('sks-explorer', 'analysis-scout.toml', 'analysis_scout', 'Read-only SKS analysis scout retained for stale Codex agent-role config repair.', 'read-only', ['analysis-scout', 'analysis_scout', 'native_agent']),
|
|
@@ -22,6 +22,7 @@ import { SPEED_LANE_POLICY } from '../proof-field.js';
|
|
|
22
22
|
import { validateRouteCompletionProof } from '../proof/route-proof-gate.js';
|
|
23
23
|
import { routeFromState, routeRequiresCompletionProof } from '../proof/route-proof-policy.js';
|
|
24
24
|
import { permissionGateSummary } from '../permission-gates.js';
|
|
25
|
+
import { prepareMadDbMission } from '../mad-db/mad-db-coordinator.js';
|
|
25
26
|
import { AGENT_INTAKE_STAGE_ID, AGENT_COUNT } from '../agents/agent-schema.js';
|
|
26
27
|
import { normalizeAgentPolicy, routeRequiresAgentIntake, agentPipelineStage } from '../agents/agent-plan.js';
|
|
27
28
|
import { readAgentGateStatus } from '../agents/agent-gate.js';
|
|
@@ -458,6 +459,8 @@ export function promptPipelineContext(prompt, route = null) {
|
|
|
458
459
|
lines.push('AutoResearch route: load autoresearch-loop plus seo-geo-optimizer when SEO/GEO, discoverability, README, npm, GitHub stars, ranking, or AI-search visibility is relevant.');
|
|
459
460
|
if (route?.id === 'DB')
|
|
460
461
|
lines.push('DB route: scan/check database risk first; destructive DB operations remain forbidden.');
|
|
462
|
+
if (route?.id === 'MadDB')
|
|
463
|
+
lines.push('MadDB route: explicit invocation is the SQL-plane approval boundary. Use the mission-local write-capable Supabase MCP profile only for the bound cycle, verify execute_sql/apply_migration inventory before claiming ready, execute requested SQL-plane mutations, read back postconditions, then close the capability/profile and prove normal read-only restoration. Supabase project/account/billing/credential control-plane actions remain denied.');
|
|
461
464
|
if (route?.id === 'GX')
|
|
462
465
|
lines.push('GX route: use deterministic vgraph/beta render, validate, drift, and snapshot artifacts.');
|
|
463
466
|
return lines.join('\n');
|
|
@@ -517,6 +520,8 @@ export async function prepareRoute(root, prompt, state = {}) {
|
|
|
517
520
|
return withSkillDreamContext(await prepareGoal(root, route, task, routeNeedsContext7(route, cleanPrompt)), dreamContext);
|
|
518
521
|
if (route.id === 'ImageUXReview')
|
|
519
522
|
return withSkillDreamContext(await prepareImageUxReview(root, route, task, routeNeedsContext7(route, cleanPrompt)), dreamContext);
|
|
523
|
+
if (route.id === 'MadDB')
|
|
524
|
+
return withSkillDreamContext(await prepareMadDb(root, route, task, routeNeedsContext7(route, cleanPrompt)), dreamContext);
|
|
520
525
|
const required = routeNeedsContext7(route, cleanPrompt);
|
|
521
526
|
const reasoning = routeReasoning(route, cleanPrompt);
|
|
522
527
|
const nativeSessionsRequired = routeRequiresSubagents(route, cleanPrompt);
|
|
@@ -1111,6 +1116,41 @@ async function prepareDb(root, route, task, required) {
|
|
|
1111
1116
|
await setCurrent(root, routeState(id, route, 'DB_REVIEW_REQUIRED', required, { prompt: task, pipeline_plan_ready: validatePipelinePlan(pipelinePlan).ok, pipeline_plan_path: PIPELINE_PLAN_ARTIFACT }));
|
|
1112
1117
|
return routeContext(route, id, task, required, 'Run sks db policy/scan/check as needed, keep DB operations read-only, record safe MCP policy, and pass db-review.json.');
|
|
1113
1118
|
}
|
|
1119
|
+
async function prepareMadDb(root, route, task, required) {
|
|
1120
|
+
const prepared = await prepareMadDbMission({ root, task, verifyTools: false });
|
|
1121
|
+
const dir = missionDir(root, prepared.mission_id);
|
|
1122
|
+
const pipelinePlan = await writePipelinePlan(dir, {
|
|
1123
|
+
missionId: prepared.mission_id,
|
|
1124
|
+
route,
|
|
1125
|
+
task,
|
|
1126
|
+
required,
|
|
1127
|
+
ambiguity: { required: true, slots: 0, auto_sealed: true, passed: true, contract_hash: prepared.capability.operator_intent_hash }
|
|
1128
|
+
});
|
|
1129
|
+
await appendJsonl(path.join(dir, 'events.jsonl'), {
|
|
1130
|
+
ts: nowIso(),
|
|
1131
|
+
type: 'mad_db.route_prepared',
|
|
1132
|
+
mission_id: prepared.mission_id,
|
|
1133
|
+
cycle_id: prepared.cycle_id,
|
|
1134
|
+
blockers: prepared.blockers
|
|
1135
|
+
});
|
|
1136
|
+
await setCurrent(root, routeState(prepared.mission_id, route, prepared.ok ? 'MADDB_SQL_PLANE_CAPABILITY_ACTIVE' : 'MADDB_BLOCKED', required, {
|
|
1137
|
+
prompt: task,
|
|
1138
|
+
questions_allowed: false,
|
|
1139
|
+
implementation_allowed: prepared.ok,
|
|
1140
|
+
ambiguity_gate_required: true,
|
|
1141
|
+
ambiguity_gate_passed: true,
|
|
1142
|
+
mad_db_active: prepared.ok,
|
|
1143
|
+
mad_db_cycle_id: prepared.cycle_id,
|
|
1144
|
+
mad_db_runtime_session_id: prepared.capability.runtime_session_id,
|
|
1145
|
+
mad_db_profile_sha256: prepared.capability.transport.profile_sha256,
|
|
1146
|
+
mad_db_capability_mission_id: prepared.mission_id,
|
|
1147
|
+
mad_db_capability_file: 'mad-db-capability.json',
|
|
1148
|
+
stop_gate: 'mad-db-gate.json',
|
|
1149
|
+
pipeline_plan_ready: validatePipelinePlan(pipelinePlan).ok,
|
|
1150
|
+
pipeline_plan_path: PIPELINE_PLAN_ARTIFACT
|
|
1151
|
+
}));
|
|
1152
|
+
return routeContext(route, prepared.mission_id, task, required, `MadDB mission/capability/profile were created atomically for cycle ${prepared.cycle_id}. Verify Supabase MCP tool inventory exposes execute_sql and apply_migration before claiming ready; after execution require read-back proof, finally close the profile/capability and prove read-only restoration.`);
|
|
1153
|
+
}
|
|
1114
1154
|
async function prepareGx(root, route, task, required) {
|
|
1115
1155
|
const { id, dir } = await createMission(root, { mode: 'gx', prompt: task });
|
|
1116
1156
|
await writeJsonAtomic(path.join(dir, 'gx-gate.json'), { passed: false, vgraph_beta_render: false, validation: false, drift_snapshot: false, context7_evidence: false });
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const GLM_BENCHMARK_VERSION = '4.
|
|
1
|
+
export const GLM_BENCHMARK_VERSION = '4.2.0';
|
|
2
2
|
//# sourceMappingURL=glm-benchmark-types.js.map
|
|
@@ -28,15 +28,16 @@ export async function runReleaseGateDag(input) {
|
|
|
28
28
|
const preset = input.preset || 'release';
|
|
29
29
|
const manifest = loadReleaseGateManifest(root);
|
|
30
30
|
const presetGates = selectReleaseGatePreset(manifest, preset);
|
|
31
|
-
const triwikiGraph = input.triwiki !== false && (preset === 'affected' || preset === 'fast' || preset === 'confidence') && input.full !== true
|
|
32
|
-
? computeTriWikiAffectedGraph({ root, tier: preset === 'fast' ? 'affected' : 'confidence', changedSince: input.changedSince || 'auto', ...(input.changedFiles ? { changedFiles: input.changedFiles } : {}) })
|
|
33
|
-
: null;
|
|
34
31
|
const affected = (preset === 'affected' || preset === 'fast' || preset === 'confidence') && input.full !== true
|
|
35
32
|
? selectAffectedReleaseGates(root, manifest, presetGates, { changedSince: input.changedSince || 'auto', ...(input.changedFiles ? { changedFiles: input.changedFiles } : {}), preset })
|
|
36
33
|
: selectAffectedReleaseGates(root, manifest, presetGates, { full: true, preset });
|
|
34
|
+
const rootReleaseSurfaceChanged = affected.selection.changed_files.some((file) => file === 'package.json' || file === 'package-lock.json' || file === 'release-gates.v2.json');
|
|
35
|
+
const triwikiGraph = input.triwiki !== false && !rootReleaseSurfaceChanged && (preset === 'affected' || preset === 'fast' || preset === 'confidence') && input.full !== true
|
|
36
|
+
? computeTriWikiAffectedGraph({ root, tier: preset === 'fast' ? 'affected' : 'confidence', changedSince: input.changedSince || 'auto', ...(input.changedFiles ? { changedFiles: input.changedFiles } : {}) })
|
|
37
|
+
: null;
|
|
37
38
|
const triwikiSelectionUsed = Boolean(triwikiGraph);
|
|
38
39
|
const triwikiConservative = Boolean(triwikiGraph?.conservative_reason);
|
|
39
|
-
const triwikiSelectedIds = new Set(triwikiGraph && !triwikiConservative ? triwikiGraph.gates :
|
|
40
|
+
const triwikiSelectedIds = new Set(triwikiGraph && !triwikiConservative ? triwikiGraph.gates : affected.gates.map((gate) => gate.id));
|
|
40
41
|
const selected = triwikiGraph
|
|
41
42
|
? presetGates.filter((gate) => triwikiSelectedIds.has(gate.id))
|
|
42
43
|
: affected.gates;
|
|
@@ -45,7 +46,7 @@ export async function runReleaseGateDag(input) {
|
|
|
45
46
|
affected.selection.mode = 'affected';
|
|
46
47
|
affected.selection.selected_gate_ids = selected.map((gate) => gate.id);
|
|
47
48
|
affected.selection.skipped_gate_ids = triwikiSkippedGates;
|
|
48
|
-
affected.selection.reasons = Object.fromEntries(selected.map((gate) => [gate.id, triwikiConservative ? `
|
|
49
|
+
affected.selection.reasons = Object.fromEntries(selected.map((gate) => [gate.id, triwikiConservative ? `triwiki_conservative_fallback:${triwikiGraph.conservative_reason}` : 'triwiki-affected']));
|
|
49
50
|
}
|
|
50
51
|
const selectedIds = new Set(selected.map((gate) => gate.id));
|
|
51
52
|
const affectedExternalSatisfiedDeps = affected.selection.mode === 'affected'
|
package/dist/core/routes.js
CHANGED
|
@@ -231,7 +231,7 @@ export function stackCurrentDocsPolicy(commandPrefix = 'sks') {
|
|
|
231
231
|
validate_command: `${prefix} wiki validate .sneakoscope/wiki/context-pack.json`,
|
|
232
232
|
priority: 'must_precede_coding_style_defaults',
|
|
233
233
|
examples: [
|
|
234
|
-
'Supabase hosted projects should prefer sb_publishable_ and sb_secret_ keys over legacy anon
|
|
234
|
+
'Supabase hosted projects should prefer sb_publishable_ and sb_secret_ keys over legacy anon and service role keys when current docs apply.',
|
|
235
235
|
'Next.js 16 deprecates the middleware file convention in favor of proxy.ts/proxy.js.',
|
|
236
236
|
'Vercel Function duration limits, including the 300s default with Fluid Compute, are deployment constraints that must shape long-running server work.'
|
|
237
237
|
]
|
|
@@ -239,7 +239,7 @@ export function stackCurrentDocsPolicy(commandPrefix = 'sks') {
|
|
|
239
239
|
}
|
|
240
240
|
export function stackCurrentDocsPolicyText(commandPrefix = 'sks') {
|
|
241
241
|
const policy = stackCurrentDocsPolicy(commandPrefix);
|
|
242
|
-
return `Stack current-docs policy: whenever project tech stack is added or a framework/package/runtime/platform version changes, fetch current docs with Context7 (resolve-library-id then query-docs) or official vendor web docs before coding, record the syntax/limits/security guidance as high-priority TriWiki claims in ${policy.memory_path}, run "${policy.refresh_command}", then "${policy.validate_command}". Treat these claims as higher priority than model-memory defaults. Examples include Supabase publishable/secret keys replacing legacy anon
|
|
242
|
+
return `Stack current-docs policy: whenever project tech stack is added or a framework/package/runtime/platform version changes, fetch current docs with Context7 (resolve-library-id then query-docs) or official vendor web docs before coding, record the syntax/limits/security guidance as high-priority TriWiki claims in ${policy.memory_path}, run "${policy.refresh_command}", then "${policy.validate_command}". Treat these claims as higher priority than model-memory defaults. Examples include Supabase publishable/secret keys replacing legacy anon and service role guidance for hosted projects, Next.js 16 proxy.ts/proxy.js replacing the deprecated middleware file convention, avoiding stale webpack defaults when newer framework guidance says otherwise, and Vercel Function duration limits such as the 300s default under Fluid Compute.`;
|
|
243
243
|
}
|
|
244
244
|
export function triwikiContextTrackingText(commandPrefix = 'sks') {
|
|
245
245
|
const ctx = triwikiContextTracking(commandPrefix);
|
|
@@ -549,21 +549,34 @@ export const ROUTES = [
|
|
|
549
549
|
cliEntrypoint: 'sks db scan',
|
|
550
550
|
examples: ['$DB check this migration safely']
|
|
551
551
|
},
|
|
552
|
+
{
|
|
553
|
+
id: 'MadDB',
|
|
554
|
+
command: '$MAD-DB',
|
|
555
|
+
mode: 'MADDB',
|
|
556
|
+
route: 'first-class MadDB SQL-plane execution',
|
|
557
|
+
description: 'Explicit one-cycle MadDB route. When invoked by $MAD-DB or sks mad-db run|exec|apply-migration, SQL-plane mutations such as CREATE, ALTER, table/schema DROP, column add/drop/rename, INSERT, UPDATE, DELETE including all-row mutations, TRUNCATE, execute_sql, and apply_migration are authorized for the bound Supabase project and must be executed with tool-result plus read-back proof. Supabase project/account/billing/credential control-plane actions remain denied.',
|
|
558
|
+
requiredSkills: ['mad-db', 'db-safety-guard', 'pipeline-runner', 'context7-docs', REFLECTION_SKILL_NAME, 'honest-mode'],
|
|
559
|
+
appSkillAliases: ['mad-db'],
|
|
560
|
+
lifecycle: ['explicit_invocation', 'single_mission_capability_v2', 'ephemeral_write_profile', 'tool_inventory', 'execute_sql_or_apply_migration', 'read_back_verification', 'close_and_read_only_restore', 'post_route_reflection', 'honest_mode'],
|
|
561
|
+
context7Policy: 'required',
|
|
562
|
+
reasoningPolicy: 'xhigh',
|
|
563
|
+
stopGate: 'mad-db-gate.json',
|
|
564
|
+
cliEntrypoint: 'sks mad-db run|exec|apply-migration|status|close|revoke|doctor',
|
|
565
|
+
examples: ['$MAD-DB public.users legacy_code 컬럼 삭제', '$MAD-DB truncate public.staging_events']
|
|
566
|
+
},
|
|
552
567
|
{
|
|
553
568
|
id: 'MadSKS',
|
|
554
569
|
command: '$MAD-SKS',
|
|
555
570
|
mode: 'MADSKS',
|
|
556
571
|
route: 'explicit scoped permission-widening modifier',
|
|
557
|
-
description: 'Explicit high-risk authorization modifier that can be combined with other $ commands to temporarily open approved target-project scopes such as files, shell, package installs, services, network, Computer Use/browser workflows, generated assets, file permissions, migrations, Supabase MCP DB writes, direct execute SQL, schema cleanup, and normal targeted DB writes for the active invocation, while preserving catastrophic wipe/all-row/project-management, credential-exfiltration, persistent security-weakening, and unrequested fallback safeguards.',
|
|
572
|
+
description: 'Explicit high-risk authorization modifier that can be combined with other $ commands to temporarily open approved target-project scopes such as files, shell, package installs, services, network, Computer Use/browser workflows, generated assets, file permissions, migrations, Supabase MCP DB writes, direct execute SQL, schema cleanup, and normal targeted DB writes for the active invocation, while preserving catastrophic wipe/all-row/project-management, credential-exfiltration, persistent security-weakening, and unrequested fallback safeguards. It is not the first-class MadDB destructive SQL-plane route.',
|
|
558
573
|
requiredSkills: ['mad-sks', 'db-safety-guard', 'pipeline-runner', 'context7-docs', REFLECTION_SKILL_NAME, 'honest-mode'],
|
|
559
|
-
dollarAliases: ['$MAD-DB'],
|
|
560
|
-
appSkillAliases: ['mad-db'],
|
|
561
574
|
lifecycle: ['explicit_invocation', 'auto_sealed_permission_scope', 'scoped_permission_override', 'catastrophic_guard', 'permission_deactivation', 'post_route_reflection', 'honest_mode'],
|
|
562
575
|
context7Policy: 'required',
|
|
563
576
|
reasoningPolicy: 'xhigh',
|
|
564
577
|
stopGate: 'mad-sks-gate.json',
|
|
565
578
|
cliEntrypoint: 'Codex App prompt route only: $MAD-SKS <task>',
|
|
566
|
-
examples: ['$MAD-SKS $Team target project maintenance with package/service/file and DB scopes', '$DB Supabase 점검 $MAD-SKS'
|
|
579
|
+
examples: ['$MAD-SKS $Team target project maintenance with package/service/file and DB scopes', '$DB Supabase 점검 $MAD-SKS']
|
|
567
580
|
},
|
|
568
581
|
{
|
|
569
582
|
id: 'GX',
|
|
@@ -964,6 +977,8 @@ export function routeRequiresSubagents(route, prompt = '') {
|
|
|
964
977
|
return false;
|
|
965
978
|
if (route.id === 'ImageUXReview')
|
|
966
979
|
return false;
|
|
980
|
+
if (route.id === 'MadDB')
|
|
981
|
+
return false;
|
|
967
982
|
if (route.id === 'Research' || route.id === 'AutoResearch')
|
|
968
983
|
return true;
|
|
969
984
|
if (route.id === 'Goal')
|
|
@@ -996,7 +1011,7 @@ export function simpleGitOnlyRouteId(prompt = '') {
|
|
|
996
1011
|
}
|
|
997
1012
|
export function reflectionRequiredForRoute(route) {
|
|
998
1013
|
const id = String(route?.id || route?.mode || route?.route || route || '').replace(/^\$/, '');
|
|
999
|
-
return /^(team|naruto|shadowclone|shadow-clone|kagebunshin|kage-bunshin|qaloop|qa-loop|ppt|imageuxreview|image-ux-review|research|autoresearch|db|database|madsks|mad-sks|gx)$/i.test(id);
|
|
1014
|
+
return /^(team|naruto|shadowclone|shadow-clone|kagebunshin|kage-bunshin|qaloop|qa-loop|ppt|imageuxreview|image-ux-review|research|autoresearch|db|database|madsks|mad-sks|maddb|mad-db|gx)$/i.test(id);
|
|
1000
1015
|
}
|
|
1001
1016
|
export function looksLikeCodeChangingWork(prompt = '') {
|
|
1002
1017
|
const text = String(prompt || '');
|
|
@@ -1038,7 +1053,7 @@ export function routeReasoning(route, prompt = '') {
|
|
|
1038
1053
|
const base = ALLOWED_REASONING_EFFORTS.has(route?.reasoningPolicy) ? route.reasoningPolicy : 'medium';
|
|
1039
1054
|
if (hasFromChatImgSignal(text))
|
|
1040
1055
|
return reasoning('xhigh', 'from_chat_img_image_work_order_analysis');
|
|
1041
|
-
if (/(?:^|\s)sks\s+--mad\b|(?:^|\s)--mad\b|\$MAD-SKS\b|\bmad-sks\b|\bmadsks\b/i.test(text))
|
|
1056
|
+
if (/(?:^|\s)sks\s+--mad\b|(?:^|\s)--mad\b|\$MAD-SKS\b|\$MAD-DB\b|\bmad-sks\b|\bmadsks\b|\bmad-db\b|\bmaddb\b/i.test(text))
|
|
1042
1057
|
return reasoning('xhigh', 'mad_sks_or_mad_launch_default');
|
|
1043
1058
|
if (route?.id === 'Team' || route?.id === 'Naruto')
|
|
1044
1059
|
return teamRouteReasoning(text);
|
package/dist/core/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '4.
|
|
1
|
+
export const PACKAGE_VERSION = '4.2.0';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -115,7 +115,11 @@ function renderTelemetrySlotRows(snapshot) {
|
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
117
|
function isMadDbActive(capability) {
|
|
118
|
-
if (!capability
|
|
118
|
+
if (!capability)
|
|
119
|
+
return false;
|
|
120
|
+
if (capability.schema === 'sks.mad-db-capability.v2' && !['transport_ready', 'active'].includes(String(capability.status || '')))
|
|
121
|
+
return false;
|
|
122
|
+
if (capability.schema !== 'sks.mad-db-capability.v2' && (capability.enabled !== true || capability.consumed === true))
|
|
119
123
|
return false;
|
|
120
124
|
const expires = Date.parse(capability.expires_at || '');
|
|
121
125
|
return Number.isFinite(expires) && expires > Date.now();
|
|
@@ -8,6 +8,7 @@ import { sourceSnapshot } from './lib/ensure-dist-fresh.js';
|
|
|
8
8
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
9
9
|
const distRoot = path.join(root, 'dist');
|
|
10
10
|
const issues = [];
|
|
11
|
+
const contractOnlyMarker = 'contract' + '_only';
|
|
11
12
|
if (!fs.existsSync(distRoot))
|
|
12
13
|
issues.push('dist_missing');
|
|
13
14
|
requiredFile('dist/bin/sks.js');
|
|
@@ -63,8 +64,8 @@ if (fs.existsSync(distRoot)) {
|
|
|
63
64
|
if (!rel.endsWith('.js'))
|
|
64
65
|
continue;
|
|
65
66
|
const text = fs.readFileSync(file, 'utf8');
|
|
66
|
-
if (text.includes(
|
|
67
|
-
issues.push(
|
|
67
|
+
if (text.includes(contractOnlyMarker))
|
|
68
|
+
issues.push(`${contractOnlyMarker}:${rel}`);
|
|
68
69
|
if (/from\s+['"][^'"]+\.mjs['"]|import\(\s*['"][^'"]+\.mjs['"]\s*\)/.test(text)) {
|
|
69
70
|
issues.push(`imports_mjs:${rel}`);
|
|
70
71
|
}
|
|
@@ -8,11 +8,12 @@ const manifest = parity.manifest;
|
|
|
8
8
|
const dep = pkg.dependencies?.['@openai/codex-sdk'];
|
|
9
9
|
const lockSdk = lock.packages?.['node_modules/@openai/codex-sdk']?.version;
|
|
10
10
|
const lockCli = lock.packages?.['node_modules/@openai/codex']?.version;
|
|
11
|
+
const lockRootVersion = lock.packages?.['']?.version || lock.version;
|
|
11
12
|
assertGate(parity.ok, 'Codex release manifest TS/JSON parity must hold', parity);
|
|
12
13
|
assertGate(dep === manifest.sdkVersion, 'package.json must pin @openai/codex-sdk exactly to manifest sdkVersion', { dep, sdkVersion: manifest.sdkVersion });
|
|
13
14
|
assertGate(lockSdk === manifest.sdkVersion, 'package-lock must resolve @openai/codex-sdk to manifest sdkVersion', { lockSdk, sdkVersion: manifest.sdkVersion });
|
|
14
15
|
assertGate(lockCli === manifest.requiredCliVersion, 'package-lock must resolve @openai/codex to manifest requiredCliVersion', { lockCli, requiredCliVersion: manifest.requiredCliVersion });
|
|
15
|
-
assertGate(pkg.version ===
|
|
16
|
+
assertGate(pkg.version === lockRootVersion, 'package version must match package-lock root version', { version: pkg.version, lockRootVersion });
|
|
16
17
|
emitGate('codex:0142:manifest', {
|
|
17
18
|
manifest_sha256: parity.manifest_sha256,
|
|
18
19
|
target_tag: manifest.targetTag,
|
|
@@ -7,9 +7,20 @@ const missionMod = await importDist('core/mission.js');
|
|
|
7
7
|
const capMod = await importDist('core/mad-db/mad-db-capability.js');
|
|
8
8
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-mad-db-cap-'));
|
|
9
9
|
const mission = await missionMod.createMission(root, { mode: 'mad-db', prompt: 'fixture' });
|
|
10
|
-
const cap = await capMod.createMadDbCapability(root, {
|
|
10
|
+
const cap = await capMod.createMadDbCapability(root, {
|
|
11
|
+
missionId: mission.id,
|
|
12
|
+
ack: capMod.MAD_DB_ACK,
|
|
13
|
+
cwd: root,
|
|
14
|
+
projectRef: 'fixture-project-ref',
|
|
15
|
+
runtimeSessionId: 'fixture-session',
|
|
16
|
+
profilePath: '.sneakoscope/missions/M/mad-db/runtime/codex-mad-db.config.toml',
|
|
17
|
+
profileSha256: 'fixture-profile-sha',
|
|
18
|
+
status: 'active'
|
|
19
|
+
});
|
|
11
20
|
assertGate(cap.schema === capMod.MAD_DB_CAPABILITY_SCHEMA, 'Mad-DB capability schema mismatch', cap);
|
|
12
|
-
assertGate(cap.
|
|
21
|
+
assertGate(cap.legacy_compat?.one_cycle_only === true && cap.legacy_compat?.priority === 'highest', 'Mad-DB capability must retain legacy one-cycle priority metadata', cap);
|
|
22
|
+
assertGate(cap.project_ref === 'fixture-project-ref' && cap.runtime_session_id === 'fixture-session' && cap.transport.profile_sha256 === 'fixture-profile-sha', 'Mad-DB capability v2 must bind project/session/profile', cap);
|
|
23
|
+
assertGate(cap.scope.sql_plane === 'all_mutations' && cap.scope.control_plane === 'deny' && cap.scope.operations.includes('truncate'), 'Mad-DB capability v2 must authorize SQL-plane operation classes only', cap);
|
|
13
24
|
assertGate(capMod.isMadDbCapabilityActive(cap) === true, 'Mad-DB capability must be active before consumption', cap);
|
|
14
25
|
emitGate('mad-db:capability', { mission_id: mission.id, cycle_id: cap.cycle_id });
|
|
15
26
|
//# sourceMappingURL=mad-db-capability-check.js.map
|
|
@@ -3,11 +3,13 @@ import { DOLLAR_COMMAND_ALIASES, DOLLAR_COMMANDS, routeByDollarCommand } from '.
|
|
|
3
3
|
import { assertGate, emitGate, readText } from './sks-1-18-gate-lib.js';
|
|
4
4
|
assertGate(readText('src/cli/command-registry.ts').includes("'mad-db'"), 'mad-db command must be registered');
|
|
5
5
|
assertGate(readText('src/commands/mad-db.ts').includes('madDbCommand'), 'mad-db command wrapper missing');
|
|
6
|
-
assertGate(readText('src/core/commands/mad-db-command.ts').includes('
|
|
6
|
+
assertGate(readText('src/core/commands/mad-db-command.ts').includes('deprecated_enable_no_capability'), 'legacy mad-db enable must be deprecated and must not create capabilities');
|
|
7
7
|
assertGate(DOLLAR_COMMANDS.some((entry) => entry.command === '$MAD-DB'), '$MAD-DB dollar command must be visible in sks dollar-commands');
|
|
8
|
-
assertGate(DOLLAR_COMMAND_ALIASES.some((entry) => entry.canonical === '$MAD-
|
|
9
|
-
assertGate(routeByDollarCommand('MAD-DB')?.command === '$MAD-
|
|
10
|
-
assertGate(routeByDollarCommand('mad-db')?.command === '$MAD-
|
|
11
|
-
|
|
8
|
+
assertGate(DOLLAR_COMMAND_ALIASES.some((entry) => entry.canonical === '$MAD-DB' && entry.app_skill === '$mad-db'), '$mad-db app skill alias must point at first-class $MAD-DB');
|
|
9
|
+
assertGate(routeByDollarCommand('MAD-DB')?.command === '$MAD-DB', '$MAD-DB must resolve to the first-class MadDB route');
|
|
10
|
+
assertGate(routeByDollarCommand('mad-db')?.command === '$MAD-DB', '$mad-db must resolve to the first-class MadDB route');
|
|
11
|
+
const initText = readText('src/core/init.ts');
|
|
12
|
+
assertGate(initText.includes("'mad-db':") && initText.includes('madDbSkillText()') && initText.includes('dbSafetyGuardSkillText()'), 'mad-db generated picker skill template must come from typed SSOT');
|
|
13
|
+
assertGate(readText('src/core/commands/mad-db-command.ts').includes('run|exec|apply-migration'), 'mad-db command must expose execution subcommands');
|
|
12
14
|
emitGate('mad-db:command', { command: 'sks mad-db', dollar_command: '$MAD-DB', app_skill_alias: '$mad-db' });
|
|
13
15
|
//# sourceMappingURL=mad-db-command-check.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { createMission } from '../core/mission.js';
|
|
6
|
+
import { checkDbOperation } from '../core/db-safety.js';
|
|
7
|
+
import { createMadDbCapability, MAD_DB_ACK, readMadDbCapability } from '../core/mad-db/mad-db-capability.js';
|
|
8
|
+
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
9
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-mad-db-idempotency-'));
|
|
10
|
+
const mission = await createMission(root, { mode: 'mad-db', prompt: 'idempotency fixture' });
|
|
11
|
+
await createMadDbCapability(root, { missionId: mission.id, ack: MAD_DB_ACK, cwd: root, projectRef: 'fixture-project-ref', status: 'active' });
|
|
12
|
+
const payload = { tool_name: 'supabase.execute_sql', tool_call_id: 'canonical-call-id-1', sql: 'delete from public.fixture;' };
|
|
13
|
+
const first = await checkDbOperation(root, { mission_id: mission.id }, payload);
|
|
14
|
+
const second = await checkDbOperation(root, { mission_id: mission.id }, payload);
|
|
15
|
+
const cap = await readMadDbCapability(root, mission.id);
|
|
16
|
+
assertGate(first.allowed === true && second.allowed === true, 'same canonical call should be allowed while active', { first, second });
|
|
17
|
+
assertGate(first.mad_db.operation_id === second.mad_db.operation_id, 'same canonical tool_call_id must map to the same operation', { first, second });
|
|
18
|
+
assertGate(second.mad_db.idempotent_reservation_reused === true, 'second reservation must be marked reused', second);
|
|
19
|
+
assertGate(Boolean(cap) && cap.counters.attempts === 1 && cap.counters.reserved === 1, 'PreToolUse/PermissionRequest duplicate handling must not double-count one call', cap || {});
|
|
20
|
+
emitGate('mad-db:hook-idempotency', { operation_id: first.mad_db.operation_id, counters: cap.counters });
|
|
21
|
+
//# sourceMappingURL=mad-db-hook-idempotency-check.js.map
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { assertGate, emitGate, readText } from './sks-1-18-gate-lib.js';
|
|
3
3
|
const ledger = readText('src/core/mad-db/mad-db-ledger.ts');
|
|
4
4
|
const cap = readText('src/core/mad-db/mad-db-capability.ts');
|
|
5
|
-
assertGate(ledger.includes('mad-db-ledger.jsonl') && cap.includes('capability.
|
|
5
|
+
assertGate(ledger.includes('mad-db-ledger.jsonl') && cap.includes('mad-db-capability.closed.json'), 'Mad-DB ledger must record lifecycle and closed capability events');
|
|
6
|
+
assertGate(!ledger.includes('unknown_pending_tool_result'), 'Mad-DB ledger must not use old pending-latest fallback wording');
|
|
6
7
|
emitGate('mad-db:ledger', { file: 'mad-db-ledger.jsonl' });
|
|
7
8
|
//# sourceMappingURL=mad-db-ledger-check.js.map
|
|
@@ -5,13 +5,14 @@ import os from 'node:os';
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { checkDbOperation, madDbLifecycleHookFromDecision } from '../core/db-safety.js';
|
|
7
7
|
import { createMadDbCapability, MAD_DB_ACK } from '../core/mad-db/mad-db-capability.js';
|
|
8
|
+
import { createMission } from '../core/mission.js';
|
|
8
9
|
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
9
10
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-mad-db-hook-decision-'));
|
|
10
|
-
const
|
|
11
|
-
await createMadDbCapability(root, { missionId, ack: MAD_DB_ACK, ttlMs: 60000 });
|
|
12
|
-
const decision = await checkDbOperation(root, { mission_id:
|
|
11
|
+
const mission = await createMission(root, { mode: 'mad-db', prompt: 'hook fixture' });
|
|
12
|
+
await createMadDbCapability(root, { missionId: mission.id, ack: MAD_DB_ACK, ttlMs: 60000, projectRef: 'fixture-project-ref', status: 'active' });
|
|
13
|
+
const decision = await checkDbOperation(root, { mission_id: mission.id }, { tool_name: 'supabase.execute_sql', tool_call_id: 'hook-decision-call-1', sql: 'insert into audit_log(id) values (1)' });
|
|
13
14
|
const hook = madDbLifecycleHookFromDecision(decision);
|
|
14
15
|
assertGate(decision.allowed === true && decision.mad_db?.lifecycle_result_pending === true, 'Mad-DB decision must mark pending lifecycle result', decision);
|
|
15
|
-
assertGate(Boolean(hook?.mission_id ===
|
|
16
|
+
assertGate(Boolean(hook?.mission_id === mission.id && hook?.operation_id && hook?.tool_call_id === 'hook-decision-call-1' && hook?.cycle_id && hook?.tool_name), 'Mad-DB decision must expose canonical tool_call_id ledger result hook', { decision, hook });
|
|
16
17
|
emitGate('mad-db:lifecycle-hook-decision', { operation_id: hook.operation_id, cycle_id: hook.cycle_id });
|
|
17
18
|
//# sourceMappingURL=mad-db-lifecycle-hook-decision-check.js.map
|
|
@@ -3,7 +3,7 @@ import assert from 'node:assert/strict';
|
|
|
3
3
|
import fs from 'node:fs/promises';
|
|
4
4
|
import os from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
|
-
import { madHighCommand } from '../core/commands/mad-sks-command.js';
|
|
6
|
+
import { madHighCommand, resolveMadLaunchMadDbGrant } from '../core/commands/mad-sks-command.js';
|
|
7
7
|
import { checkDbOperation } from '../core/db-safety.js';
|
|
8
8
|
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
9
9
|
const original = {
|
|
@@ -53,27 +53,29 @@ try {
|
|
|
53
53
|
assertGate(launch?.ok === true && launch.status === 'headless-fallback', 'sks --mad fixture launch must complete headless', launch);
|
|
54
54
|
const state = await readJson(path.join(tmp, '.sneakoscope', 'state', 'current.json'));
|
|
55
55
|
assert.equal(state.mad_sks_active, true);
|
|
56
|
-
assert.
|
|
57
|
-
assert.
|
|
58
|
-
assert.
|
|
56
|
+
assert.notEqual(state.mad_db_active, true);
|
|
57
|
+
assert.notEqual(state.mad_db_grant_source, 'sks_mad_default');
|
|
58
|
+
assert.notEqual(state.mad_db_priority_override_active, true);
|
|
59
59
|
const missionDir = path.join(tmp, '.sneakoscope', 'missions', state.mission_id);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
assert.equal(grants.mad_sks_active, true);
|
|
63
|
-
assert.equal(grants.mad_db_active, true);
|
|
64
|
-
assert.equal(grants.mad_db_default_grant, true);
|
|
65
|
-
assert.equal(capability.enabled, true);
|
|
66
|
-
assert.equal(capability.one_cycle_only, true);
|
|
67
|
-
assert.equal(capability.consumed, false);
|
|
60
|
+
await assertMissing(path.join(missionDir, 'mad-db-capability.json'), 'bare sks --mad must not create a MadDB capability');
|
|
61
|
+
await assertMissing(path.join(missionDir, 'mad-sks-launch-grants.json'), 'bare sks --mad must not create MadDB grant artifacts');
|
|
68
62
|
const decision = await checkDbOperation(tmp, state, {
|
|
69
63
|
tool_name: 'supabase.execute_sql',
|
|
70
|
-
|
|
64
|
+
tool_call_id: 'mad-sks-default-does-not-open-maddb',
|
|
65
|
+
sql: 'truncate sks_mad_db_probe;'
|
|
71
66
|
});
|
|
72
|
-
assertGate(decision.allowed ===
|
|
67
|
+
assertGate(decision.allowed === false && decision.mad_db?.active !== true, 'sks --mad default must not satisfy MadDB mutation policy locally', decision);
|
|
68
|
+
const defaultGrant = resolveMadLaunchMadDbGrant([]);
|
|
69
|
+
const explicitGrant = resolveMadLaunchMadDbGrant(['--mad-db']);
|
|
70
|
+
assert.equal(defaultGrant.enabled, false);
|
|
71
|
+
assert.equal(defaultGrant.requested, false);
|
|
72
|
+
assert.equal(explicitGrant.enabled, false);
|
|
73
|
+
assert.equal(explicitGrant.requested, true);
|
|
74
|
+
assert.equal(explicitGrant.source, 'mad_db_first_class_route_required');
|
|
73
75
|
emitGate('mad-db:mad-command', {
|
|
74
76
|
mission_id: state.mission_id,
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
default_mad_db_active: state.mad_db_active === true,
|
|
78
|
+
explicit_flag_source: explicitGrant.source
|
|
77
79
|
});
|
|
78
80
|
}
|
|
79
81
|
finally {
|
|
@@ -91,6 +93,17 @@ finally {
|
|
|
91
93
|
async function readJson(file) {
|
|
92
94
|
return JSON.parse(await fs.readFile(file, 'utf8'));
|
|
93
95
|
}
|
|
96
|
+
async function assertMissing(file, message) {
|
|
97
|
+
try {
|
|
98
|
+
await fs.access(file);
|
|
99
|
+
assertGate(false, message, { file });
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
if (err?.code === 'ENOENT')
|
|
103
|
+
return;
|
|
104
|
+
throw err;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
94
107
|
function restoreEnv(key, value) {
|
|
95
108
|
if (value == null)
|
|
96
109
|
delete process.env[key];
|
|
@@ -6,25 +6,26 @@ import path from 'node:path';
|
|
|
6
6
|
import { checkDbOperation, madDbLifecycleHookFromDecision } from '../core/db-safety.js';
|
|
7
7
|
import { evaluateHookPayload } from '../core/hooks-runtime.js';
|
|
8
8
|
import { createMadDbCapability, MAD_DB_ACK } from '../core/mad-db/mad-db-capability.js';
|
|
9
|
-
import { missionDir } from '../core/mission.js';
|
|
9
|
+
import { createMission, missionDir } from '../core/mission.js';
|
|
10
10
|
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
11
11
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-mad-db-mcp-result-'));
|
|
12
|
-
const
|
|
13
|
-
await createMadDbCapability(root, { missionId, ack: MAD_DB_ACK, ttlMs: 60000 });
|
|
14
|
-
const successPayload = { tool_name: 'supabase.execute_sql', sql: 'insert into audit_log(id) values (1)' };
|
|
15
|
-
const successDecision = await checkDbOperation(root, { mission_id:
|
|
12
|
+
const mission = await createMission(root, { mode: 'mad-db', prompt: 'mcp result fixture' });
|
|
13
|
+
await createMadDbCapability(root, { missionId: mission.id, ack: MAD_DB_ACK, ttlMs: 60000, projectRef: 'fixture-project-ref', status: 'active' });
|
|
14
|
+
const successPayload = { tool_name: 'supabase.execute_sql', tool_call_id: 'mcp-success-call', sql: 'insert into audit_log(id) values (1)' };
|
|
15
|
+
const successDecision = await checkDbOperation(root, { mission_id: mission.id }, successPayload);
|
|
16
16
|
const successHook = madDbLifecycleHookFromDecision(successDecision);
|
|
17
17
|
assertGate(Boolean(successHook), 'Mad-DB lifecycle hook missing before post-tool success result', successDecision);
|
|
18
|
-
await evaluateHookPayload('post-tool', { tool_name: successPayload.tool_name, success: true, row_count: 1 }, { root, state: { mission_id:
|
|
19
|
-
const failurePayload = { tool_name: 'supabase.execute_sql', sql: 'update audit_log set id = 2 where id = 1' };
|
|
20
|
-
const failureDecision = await checkDbOperation(root, { mission_id:
|
|
18
|
+
await evaluateHookPayload('post-tool', { tool_name: successPayload.tool_name, tool_call_id: successHook.tool_call_id, success: true, row_count: 1 }, { root, state: { mission_id: mission.id } });
|
|
19
|
+
const failurePayload = { tool_name: 'supabase.execute_sql', tool_call_id: 'mcp-failure-call', sql: 'update audit_log set id = 2 where id = 1' };
|
|
20
|
+
const failureDecision = await checkDbOperation(root, { mission_id: mission.id }, failurePayload);
|
|
21
21
|
const failureHook = madDbLifecycleHookFromDecision(failureDecision);
|
|
22
22
|
assertGate(Boolean(failureHook), 'Mad-DB lifecycle hook missing before post-tool MCP isError result', failureDecision);
|
|
23
23
|
await evaluateHookPayload('post-tool', {
|
|
24
24
|
tool_name: failurePayload.tool_name,
|
|
25
|
+
tool_call_id: failureHook.tool_call_id,
|
|
25
26
|
result: { isError: true, content: [{ type: 'text', text: 'fixture MCP error' }] }
|
|
26
|
-
}, { root, state: { mission_id:
|
|
27
|
-
const ledger = await fs.readFile(path.join(missionDir(root,
|
|
27
|
+
}, { root, state: { mission_id: mission.id } });
|
|
28
|
+
const ledger = await fs.readFile(path.join(missionDir(root, mission.id), 'mad-db-ledger.jsonl'), 'utf8');
|
|
28
29
|
assertGate(ledger.includes('db_operation.succeeded') && ledger.includes('db_operation.failed') && ledger.includes('fixture MCP error'), 'PostToolUse must append succeeded and MCP isError failed lifecycle events', { ledger });
|
|
29
30
|
emitGate('mad-db:mcp-result-lifecycle', { success_operation_id: successHook.operation_id, failure_operation_id: failureHook.operation_id, status: 'succeeded_and_failed_checked' });
|
|
30
31
|
//# sourceMappingURL=mad-db-mcp-result-lifecycle-check.js.map
|
|
@@ -3,25 +3,22 @@
|
|
|
3
3
|
import fs from 'node:fs/promises';
|
|
4
4
|
import os from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
|
-
import { closeMadDbCycle, createMadDbCapability, MAD_DB_ACK, readMadDbCapability } from '../core/mad-db/mad-db-capability.js';
|
|
6
|
+
import { closeMadDbCycle, createMadDbCapability, isMadDbCapabilityActive, MAD_DB_ACK, readMadDbCapability } from '../core/mad-db/mad-db-capability.js';
|
|
7
7
|
import { checkDbOperation } from '../core/db-safety.js';
|
|
8
|
+
import { createMission } from '../core/mission.js';
|
|
8
9
|
import { assertGate, emitGate } from './sks-1-18-gate-lib.js';
|
|
9
10
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'sks-mad-db-bounded-'));
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const closeCap = await createMadDbCapability(root, { missionId: closeMissionId, ack: MAD_DB_ACK, ttlMs: 60000 });
|
|
24
|
-
const closed = await closeMadDbCycle(root, closeMissionId, closeCap.cycle_id);
|
|
25
|
-
assertGate(closed?.consumed === true && closed?.consumed_by === 'mad-db-cycle-close', 'explicit cycle close must consume active capability', closed);
|
|
26
|
-
emitGate('mad-db:one-cycle-bounded', { cycle_id: cap.cycle_id, operation_count: afterSecond.operation_count, max_operations: afterSecond.max_operations, close_cycle: closed?.consumed === true });
|
|
11
|
+
const mission = await createMission(root, { mode: 'mad-db', prompt: 'bounded fixture' });
|
|
12
|
+
const cap = await createMadDbCapability(root, { missionId: mission.id, ack: MAD_DB_ACK, ttlMs: 60000, projectRef: 'fixture-project-ref', status: 'active' });
|
|
13
|
+
assertGate(isMadDbCapabilityActive(cap) === true && Date.parse(cap.expires_at) > Date.now(), 'capability must start active with bounded TTL', cap);
|
|
14
|
+
const payload = { tool_name: 'supabase.execute_sql', tool_call_id: 'bounded-call-1', sql: 'update users set flag = true where id = 1' };
|
|
15
|
+
const first = await checkDbOperation(root, { mission_id: mission.id }, payload);
|
|
16
|
+
const afterFirst = await readMadDbCapability(root, mission.id);
|
|
17
|
+
assertGate(first.allowed === true && afterFirst.counters.reserved === 1 && afterFirst.status === 'active', 'capability must reserve one operation and remain active before final close', { first, afterFirst });
|
|
18
|
+
const second = await checkDbOperation(root, { mission_id: mission.id }, payload);
|
|
19
|
+
const afterSecond = await readMadDbCapability(root, mission.id);
|
|
20
|
+
assertGate(second.allowed === true && second.mad_db?.idempotent_reservation_reused === true && afterSecond.counters.reserved === 1, 'same canonical tool_call_id must be idempotent and not double-counted', { second, afterSecond });
|
|
21
|
+
const closed = await closeMadDbCycle(root, mission.id, cap.cycle_id);
|
|
22
|
+
assertGate(closed?.status === 'closed' && isMadDbCapabilityActive(closed) === false, 'explicit cycle close must deactivate active capability', closed);
|
|
23
|
+
emitGate('mad-db:one-cycle-bounded', { cycle_id: cap.cycle_id, reserved: afterSecond.counters.reserved, close_cycle: closed?.status === 'closed' });
|
|
27
24
|
//# sourceMappingURL=mad-db-one-cycle-bounded-check.js.map
|
|
@@ -7,10 +7,10 @@ const missionMod = await importDist('core/mission.js');
|
|
|
7
7
|
const capMod = await importDist('core/mad-db/mad-db-capability.js');
|
|
8
8
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sks-mad-db-consume-'));
|
|
9
9
|
const mission = await missionMod.createMission(root, { mode: 'mad-db', prompt: 'fixture' });
|
|
10
|
-
const cap = await capMod.createMadDbCapability(root, { missionId: mission.id, ack: capMod.MAD_DB_ACK, cwd: root });
|
|
10
|
+
const cap = await capMod.createMadDbCapability(root, { missionId: mission.id, ack: capMod.MAD_DB_ACK, cwd: root, projectRef: 'fixture-project-ref', status: 'active' });
|
|
11
11
|
await capMod.consumeMadDbCapability(root, mission.id, { consumedBy: 'fixture' });
|
|
12
12
|
const consumed = await capMod.readMadDbCapability(root, mission.id);
|
|
13
|
-
assertGate(capMod.isMadDbCapabilityActive(consumed) === false && consumed.
|
|
14
|
-
assertGate(fs.existsSync(path.join(root, '.sneakoscope', 'missions', mission.id, 'mad-db-capability.
|
|
13
|
+
assertGate(capMod.isMadDbCapabilityActive(consumed) === false && consumed.status === 'closed' && Boolean(consumed.closed_at), 'Mad-DB capability must be inactive after close/consumption compatibility call', consumed);
|
|
14
|
+
assertGate(fs.existsSync(path.join(root, '.sneakoscope', 'missions', mission.id, 'mad-db-capability.closed.json')), 'closed proof artifact missing');
|
|
15
15
|
emitGate('mad-db:one-cycle-consumption', { cycle_id: cap.cycle_id });
|
|
16
16
|
//# sourceMappingURL=mad-db-one-cycle-consumption-check.js.map
|