sneakoscope 4.4.0 → 4.6.1
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 +28 -2
- 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 -0
- package/dist/core/agents/agent-runner-ollama.js +2 -0
- package/dist/core/agents/native-worker-backend-router.js +3 -0
- package/dist/core/bench.js +115 -0
- package/dist/core/code-structure.js +399 -11
- package/dist/core/codex-control/codex-fake-sdk-adapter.js +67 -9
- package/dist/core/codex-control/gpt-final-arbiter.js +4 -1
- package/dist/core/codex-control/gpt-final-review-schema.js +58 -0
- package/dist/core/codex-native/core-skill-manifest.js +23 -0
- package/dist/core/commands/bench-command.js +11 -2
- package/dist/core/commands/code-structure-command.js +34 -2
- package/dist/core/commands/run-command.js +92 -2
- package/dist/core/commands/seo-command.js +130 -0
- package/dist/core/db-safety.js +8 -6
- package/dist/core/feature-fixtures.js +6 -0
- package/dist/core/feature-registry.js +3 -1
- package/dist/core/fsx.js +1 -1
- package/dist/core/hooks-runtime.js +8 -0
- package/dist/core/init.js +8 -6
- package/dist/core/lean-engineering-policy.js +159 -0
- package/dist/core/mad-db/mad-db-policy-resolver.js +23 -2
- package/dist/core/pipeline-internals/runtime-core.js +15 -5
- package/dist/core/proof/auto-finalize.js +3 -2
- package/dist/core/proof/proof-schema.js +2 -1
- package/dist/core/proof/proof-writer.js +1 -0
- package/dist/core/proof/route-adapter.js +4 -2
- package/dist/core/proof/route-finalizer.js +35 -3
- package/dist/core/routes.js +75 -9
- package/dist/core/search-visibility/adapter-registry.js +26 -0
- package/dist/core/search-visibility/adapters/next-app.js +6 -0
- package/dist/core/search-visibility/adapters/next-pages.js +6 -0
- package/dist/core/search-visibility/adapters/static-site.js +6 -0
- package/dist/core/search-visibility/analyzers.js +377 -0
- package/dist/core/search-visibility/artifacts.js +183 -0
- package/dist/core/search-visibility/discovery.js +347 -0
- package/dist/core/search-visibility/index.js +199 -0
- package/dist/core/search-visibility/mission.js +67 -0
- package/dist/core/search-visibility/mutation.js +314 -0
- package/dist/core/search-visibility/types.js +2 -0
- package/dist/core/search-visibility/verifier.js +60 -0
- package/dist/core/version.js +1 -1
- package/dist/scripts/check-architecture.js +40 -7
- package/dist/scripts/check-command-module-budget.js +43 -5
- package/dist/scripts/check-pipeline-budget.js +17 -30
- package/dist/scripts/check-publish-tag.js +33 -6
- package/dist/scripts/check-route-modularity.js +25 -33
- package/dist/scripts/check-runtime-schemas.js +22 -0
- package/dist/scripts/config-managed-merge-callsite-coverage-check.js +2 -2
- package/dist/scripts/core-skill-immutable-sync-check.js +3 -2
- package/dist/scripts/core-skill-integrity-blackbox.js +3 -2
- package/dist/scripts/core-skill-manifest-check.js +7 -2
- package/dist/scripts/geo-claim-evidence-check.js +18 -0
- package/dist/scripts/geo-cli-blackbox-check.js +18 -0
- package/dist/scripts/geo-crawler-policy-check.js +16 -0
- package/dist/scripts/geo-llms-txt-optional-check.js +19 -0
- package/dist/scripts/gpt-final-arbiter-check.js +4 -1
- package/dist/scripts/mad-db-direct-apply-migration-hook-check.js +50 -0
- package/dist/scripts/release-dag-full-coverage-check.js +1 -0
- package/dist/scripts/release-parallel-check.js +15 -0
- package/dist/scripts/release-registry-check.js +33 -14
- package/dist/scripts/search-visibility-gate-lib.js +124 -0
- package/dist/scripts/seo-audit-fixture-check.js +16 -0
- package/dist/scripts/seo-canonical-locale-check.js +19 -0
- package/dist/scripts/seo-cli-blackbox-check.js +18 -0
- package/dist/scripts/seo-geo-feature-fixture-quality-check.js +18 -0
- package/dist/scripts/seo-geo-geo-disambiguation-check.js +12 -0
- package/dist/scripts/seo-geo-no-unsupported-ranking-claims-check.js +18 -0
- package/dist/scripts/seo-geo-route-identity-check.js +12 -0
- package/dist/scripts/seo-geo-skill-rich-content-check.js +22 -0
- package/dist/scripts/seo-mutation-rollback-check.js +23 -0
- package/dist/scripts/seo-no-mutation-by-default-check.js +17 -0
- package/dist/scripts/seo-structured-data-visible-content-check.js +19 -0
- package/dist/scripts/sks-3-1-5-directive-check-lib.js +10 -1
- package/package.json +21 -2
- package/schemas/search-visibility/finding-ledger.schema.json +36 -0
- package/schemas/search-visibility/gate.schema.json +22 -0
- package/schemas/search-visibility/mutation-plan.schema.json +27 -0
- package/schemas/search-visibility/site-inventory.schema.json +21 -0
- package/schemas/search-visibility/verification-report.schema.json +23 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LEAN_SOLUTION_RUNGS } from '../lean-engineering-policy.js';
|
|
1
2
|
export const GPT_FINAL_ARBITER_RESULT_SCHEMA_ID = 'sks.gpt-final-arbiter-result.v1';
|
|
2
3
|
export const GPT_FINAL_ARBITER_INPUT_SCHEMA = 'sks.gpt-final-arbiter-input.v1';
|
|
3
4
|
const reviewItemSchema = {
|
|
@@ -20,6 +21,32 @@ const patchDecisionSchema = {
|
|
|
20
21
|
},
|
|
21
22
|
additionalProperties: false
|
|
22
23
|
};
|
|
24
|
+
const leanReviewSchema = {
|
|
25
|
+
type: 'object',
|
|
26
|
+
required: [
|
|
27
|
+
'status',
|
|
28
|
+
'selected_rung',
|
|
29
|
+
'unnecessary_files',
|
|
30
|
+
'unnecessary_dependencies',
|
|
31
|
+
'unnecessary_abstractions',
|
|
32
|
+
'fallback_findings',
|
|
33
|
+
'root_cause_review',
|
|
34
|
+
'verification_minimum_present',
|
|
35
|
+
'net_lines'
|
|
36
|
+
],
|
|
37
|
+
properties: {
|
|
38
|
+
status: { enum: ['pass', 'modified', 'rejected', 'needs_more_work'] },
|
|
39
|
+
selected_rung: { enum: [...LEAN_SOLUTION_RUNGS, 'unknown'] },
|
|
40
|
+
unnecessary_files: { type: 'array', items: { type: 'string' } },
|
|
41
|
+
unnecessary_dependencies: { type: 'array', items: { type: 'string' } },
|
|
42
|
+
unnecessary_abstractions: { type: 'array', items: { type: 'string' } },
|
|
43
|
+
fallback_findings: { type: 'array', items: { type: 'string' } },
|
|
44
|
+
root_cause_review: { type: 'array', items: { type: 'string' } },
|
|
45
|
+
verification_minimum_present: { type: 'boolean' },
|
|
46
|
+
net_lines: { type: ['number', 'null'] }
|
|
47
|
+
},
|
|
48
|
+
additionalProperties: false
|
|
49
|
+
};
|
|
23
50
|
export const gptFinalArbiterResultSchema = {
|
|
24
51
|
type: 'object',
|
|
25
52
|
required: [
|
|
@@ -34,6 +61,7 @@ export const gptFinalArbiterResultSchema = {
|
|
|
34
61
|
'verification_plan',
|
|
35
62
|
'rollback_notes',
|
|
36
63
|
'blockers',
|
|
64
|
+
'lean_review',
|
|
37
65
|
'confidence'
|
|
38
66
|
],
|
|
39
67
|
properties: {
|
|
@@ -48,6 +76,7 @@ export const gptFinalArbiterResultSchema = {
|
|
|
48
76
|
verification_plan: { type: 'array', items: { type: 'string' } },
|
|
49
77
|
rollback_notes: { type: 'array', items: { type: 'string' } },
|
|
50
78
|
blockers: { type: 'array', items: { type: 'string' } },
|
|
79
|
+
lean_review: leanReviewSchema,
|
|
51
80
|
confidence: { enum: ['low', 'medium', 'high'] }
|
|
52
81
|
},
|
|
53
82
|
additionalProperties: false
|
|
@@ -66,6 +95,7 @@ export function normalizeGptFinalArbiterResult(value) {
|
|
|
66
95
|
verification_plan: stringArray(value?.verification_plan),
|
|
67
96
|
rollback_notes: stringArray(value?.rollback_notes),
|
|
68
97
|
blockers: stringArray(value?.blockers),
|
|
98
|
+
lean_review: normalizeLeanReview(value?.lean_review, status),
|
|
69
99
|
confidence: normalizeConfidence(value?.confidence)
|
|
70
100
|
};
|
|
71
101
|
}
|
|
@@ -107,6 +137,34 @@ function patchDecisionItems(value) {
|
|
|
107
137
|
function stringArray(value) {
|
|
108
138
|
return Array.isArray(value) ? value.map((entry) => String(entry || '').trim()).filter(Boolean) : [];
|
|
109
139
|
}
|
|
140
|
+
function normalizeLeanReview(value, arbiterStatus) {
|
|
141
|
+
const raw = typeof value === 'object' && value !== null ? value : {};
|
|
142
|
+
return {
|
|
143
|
+
status: normalizeLeanReviewStatus(raw.status, arbiterStatus),
|
|
144
|
+
selected_rung: normalizeLeanRung(raw.selected_rung),
|
|
145
|
+
unnecessary_files: stringArray(raw.unnecessary_files),
|
|
146
|
+
unnecessary_dependencies: stringArray(raw.unnecessary_dependencies),
|
|
147
|
+
unnecessary_abstractions: stringArray(raw.unnecessary_abstractions),
|
|
148
|
+
fallback_findings: stringArray(raw.fallback_findings),
|
|
149
|
+
root_cause_review: stringArray(raw.root_cause_review),
|
|
150
|
+
verification_minimum_present: typeof raw.verification_minimum_present === 'boolean' ? raw.verification_minimum_present : arbiterStatus === 'approved' || arbiterStatus === 'modified',
|
|
151
|
+
net_lines: Number.isFinite(Number(raw.net_lines)) ? Number(raw.net_lines) : null
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function normalizeLeanReviewStatus(value, arbiterStatus) {
|
|
155
|
+
if (value === 'pass' || value === 'modified' || value === 'rejected' || value === 'needs_more_work')
|
|
156
|
+
return value;
|
|
157
|
+
if (arbiterStatus === 'approved')
|
|
158
|
+
return 'pass';
|
|
159
|
+
if (arbiterStatus === 'modified')
|
|
160
|
+
return 'modified';
|
|
161
|
+
if (arbiterStatus === 'rejected')
|
|
162
|
+
return 'rejected';
|
|
163
|
+
return 'needs_more_work';
|
|
164
|
+
}
|
|
165
|
+
function normalizeLeanRung(value) {
|
|
166
|
+
return typeof value === 'string' && [...LEAN_SOLUTION_RUNGS, 'unknown'].includes(value) ? value : 'unknown';
|
|
167
|
+
}
|
|
110
168
|
function normalizeSeverity(value) {
|
|
111
169
|
return value === 'low' || value === 'medium' || value === 'high' ? value : 'medium';
|
|
112
170
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PACKAGE_VERSION, nowIso, sha256 } from '../fsx.js';
|
|
2
|
+
import { leanPolicyReference } from '../lean-engineering-policy.js';
|
|
2
3
|
import { canonicalSkillName } from './skill-name-canonicalizer.js';
|
|
3
4
|
export const CORE_SKILL_TEMPLATE_VERSION = 'sks-core-skill-template.v1';
|
|
4
5
|
export const CORE_SKILL_MANAGED_BEGIN = '<!-- BEGIN SKS IMMUTABLE CORE SKILL -->';
|
|
@@ -83,6 +84,26 @@ const CORE_SKILL_DEFINITIONS = [
|
|
|
83
84
|
when: 'Use when deeper local context or directory-specific recall is required.',
|
|
84
85
|
evidence: '.sneakoscope/context/AGENTS.generated.md and managed memory artifacts.',
|
|
85
86
|
fallback: 'Preserve user content and skip directories that cannot be safely updated.'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: 'sks-core-search-visibility-core',
|
|
90
|
+
canonical_name: 'search-visibility-core',
|
|
91
|
+
display_name: 'search-visibility-core',
|
|
92
|
+
route: '$SEO-GEO-OPTIMIZER',
|
|
93
|
+
purpose: 'provide the shared search-visibility kernel for SEO and GEO audit, plan, explicit apply, verify, rollback, and Completion Proof without ranking, traffic, or citation guarantees.',
|
|
94
|
+
when: 'Use when $SEO-GEO-OPTIMIZER or sks seo-geo-optimizer needs typed mode-specific evidence, gates, artifacts, or safe mutation planning.',
|
|
95
|
+
evidence: 'search-visibility artifacts, seo-gate.json or geo-gate.json, mutation-plan.json, rollback-manifest.json, verification-report.json, and completion-proof.json.',
|
|
96
|
+
fallback: 'Keep unsupported frameworks plan-only, record unverified production/browser/Search Console/AI citation outcomes, and never invent guarantee evidence.'
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'sks-core-seo-geo-optimizer',
|
|
100
|
+
canonical_name: 'seo-geo-optimizer',
|
|
101
|
+
display_name: 'seo-geo-optimizer',
|
|
102
|
+
route: '$SEO-GEO-OPTIMIZER',
|
|
103
|
+
purpose: 'run the unified SEO/GEO optimizer route for Search Engine Optimization and Generative Engine Optimization, not geolocation or GeoIP, with no ranking, traffic, indexing, rich-result, answer inclusion, or AI citation guarantee.',
|
|
104
|
+
when: 'Use the CLI entrypoint: sks seo-geo-optimizer doctor|audit|plan|apply|verify|status|rollback|fixture --mode seo|geo for SEO and GEO visibility work.',
|
|
105
|
+
evidence: 'site inventory, route graph, seo-findings.json or geo-findings.json, claim-evidence-ledger.json, ai-crawler-policy.json, llms-txt-plan.json, verification report, route gate, and Completion Proof.',
|
|
106
|
+
fallback: 'Do not auto-allow training crawlers or fabricate AI answer visibility; mark missing live outcomes unverified and keep recovery on the unified optimizer route.'
|
|
86
107
|
}
|
|
87
108
|
];
|
|
88
109
|
export function coreSkillDefinitions() {
|
|
@@ -97,6 +118,7 @@ export function renderCoreSkillTemplate(name) {
|
|
|
97
118
|
const skill = CORE_SKILL_DEFINITIONS.find((entry) => entry.canonical_name === canonical);
|
|
98
119
|
if (!skill)
|
|
99
120
|
throw new Error(`Unknown SKS core skill: ${name}`);
|
|
121
|
+
const lean = leanPolicyReference();
|
|
100
122
|
return [
|
|
101
123
|
'---',
|
|
102
124
|
`name: ${skill.display_name}`,
|
|
@@ -117,6 +139,7 @@ export function renderCoreSkillTemplate(name) {
|
|
|
117
139
|
`Command: ${skill.route}`,
|
|
118
140
|
`Purpose: ${skill.purpose}`,
|
|
119
141
|
`Use when: ${skill.when}`,
|
|
142
|
+
`Lean policy: ${lean.policy_id}/${lean.policy_hash}`,
|
|
120
143
|
`Proof paths: ${skill.evidence}`,
|
|
121
144
|
'Safety rules: preserve user-authored skills, keep route state bounded, and stop on hard blockers instead of fabricating fallback behavior.',
|
|
122
145
|
`Failure recovery: ${skill.fallback}`,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TRUST_VALIDATE_BENCH_COMMAND, benchRoot, runCoreBench } from '../bench.js';
|
|
1
|
+
import { TRUST_VALIDATE_BENCH_COMMAND, benchRoot, runCoreBench, runLeanPolicyBench } from '../bench.js';
|
|
2
2
|
import { runProcess } from '../fsx.js';
|
|
3
3
|
import { flag, readFlagValue } from './command-utils.js';
|
|
4
4
|
export async function benchCommand(args = []) {
|
|
@@ -18,9 +18,18 @@ export async function benchCommand(args = []) {
|
|
|
18
18
|
}
|
|
19
19
|
if (action === 'route-fixtures')
|
|
20
20
|
return commandBench('sks.route-fixture-bench.v1', ['all-features', 'selftest', '--mock', '--execute-fixtures', '--strict-artifacts', '--json'], args);
|
|
21
|
+
if (action === 'lean-policy') {
|
|
22
|
+
const report = await runLeanPolicyBench(root);
|
|
23
|
+
if (!report.ok)
|
|
24
|
+
process.exitCode = 1;
|
|
25
|
+
if (flag(args, '--json'))
|
|
26
|
+
return console.log(JSON.stringify(report, null, 2));
|
|
27
|
+
console.log(`lean-policy: ${report.ok ? 'pass' : 'blocked'}`);
|
|
28
|
+
return report;
|
|
29
|
+
}
|
|
21
30
|
if (action === 'blackbox')
|
|
22
31
|
return commandBench('sks.blackbox-bench.v1', ['blackbox-matrix-placeholder'], args);
|
|
23
|
-
console.error('Usage: sks bench core|route-fixtures|blackbox|trust-kernel [--json] [--iterations N]');
|
|
32
|
+
console.error('Usage: sks bench core|route-fixtures|lean-policy|blackbox|trust-kernel [--json] [--iterations N]');
|
|
24
33
|
process.exitCode = 2;
|
|
25
34
|
}
|
|
26
35
|
async function commandBench(schema, commandArgs, args = []) {
|
|
@@ -4,18 +4,50 @@ import { flag } from './command-utils.js';
|
|
|
4
4
|
export async function codeStructureCommand(sub, args = []) {
|
|
5
5
|
const action = sub || 'scan';
|
|
6
6
|
if (action !== 'scan') {
|
|
7
|
-
console.error('Usage: sks code-structure scan [--json]');
|
|
7
|
+
console.error('Usage: sks code-structure scan [--json] [--all] [--changed [ref|file[,file]]] [--changed-since <ref>]');
|
|
8
8
|
process.exitCode = 1;
|
|
9
9
|
return;
|
|
10
10
|
}
|
|
11
11
|
const root = await sksRoot();
|
|
12
|
-
const
|
|
12
|
+
const changedArg = valueAfter(args, '--changed');
|
|
13
|
+
const changedSince = valueAfter(args, '--changed-since');
|
|
14
|
+
const changedArgLooksLikeFiles = Boolean(changedArg && (changedArg.includes(',')
|
|
15
|
+
|| changedArg.includes('/')
|
|
16
|
+
|| changedArg.includes('\\')
|
|
17
|
+
|| /\.(js|ts|tsx|jsx|mjs|cjs|json|md|rs|toml)$/i.test(changedArg)));
|
|
18
|
+
const changedFiles = changedArg && changedArgLooksLikeFiles
|
|
19
|
+
? changedArg.split(',').map((file) => file.trim()).filter(Boolean)
|
|
20
|
+
: [];
|
|
21
|
+
const report = await scanCodeStructure(root, {
|
|
22
|
+
includeOk: flag(args, '--all'),
|
|
23
|
+
changed: flag(args, '--changed') ? (changedFiles.length ? true : changedArg || true) : false,
|
|
24
|
+
changedSince,
|
|
25
|
+
changedFiles
|
|
26
|
+
});
|
|
13
27
|
if (flag(args, '--json'))
|
|
14
28
|
return console.log(JSON.stringify(report, null, 2));
|
|
15
29
|
console.log('SKS Code Structure');
|
|
30
|
+
if (report.changed_scope?.mode !== 'full') {
|
|
31
|
+
console.log(`Changed scope: ${report.changed_scope.changed_files.length} files, ${report.changed_scope.net_lines} net lines`);
|
|
32
|
+
console.log(`Lean semantic review: ${report.semantic_review?.status || 'unknown'}`);
|
|
33
|
+
}
|
|
16
34
|
for (const file of report.files.slice(0, 20))
|
|
17
35
|
console.log(`${file.status} ${file.line_count} ${file.path}`);
|
|
18
36
|
if (report.remaining_risks.length)
|
|
19
37
|
console.log(`Risks: ${report.remaining_risks.join(', ')}`);
|
|
38
|
+
if (report.semantic_review?.findings?.length) {
|
|
39
|
+
for (const finding of report.semantic_review.findings.slice(0, 8)) {
|
|
40
|
+
console.log(`Lean ${finding.severity}: ${finding.file ? `${finding.file}: ` : ''}${finding.summary}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function valueAfter(args, name) {
|
|
45
|
+
const index = args.indexOf(name);
|
|
46
|
+
if (index === -1)
|
|
47
|
+
return null;
|
|
48
|
+
const value = args[index + 1];
|
|
49
|
+
if (!value || String(value).startsWith('--'))
|
|
50
|
+
return null;
|
|
51
|
+
return String(value);
|
|
20
52
|
}
|
|
21
53
|
//# sourceMappingURL=code-structure-command.js.map
|
|
@@ -4,6 +4,7 @@ import { createMission, missionDir, setCurrent } from '../mission.js';
|
|
|
4
4
|
import { maybeFinalizeRoute } from '../proof/auto-finalize.js';
|
|
5
5
|
import { routePrompt } from '../routes.js';
|
|
6
6
|
import { latestTrustReport } from '../trust-kernel/trust-report.js';
|
|
7
|
+
import { normalizeTrustStatus, TRUST_REPORT_SCHEMA, trustKernelMetadata } from '../trust-kernel/trust-kernel-schema.js';
|
|
7
8
|
import { flag, positionalArgs } from './command-utils.js';
|
|
8
9
|
export async function runCommand(args = []) {
|
|
9
10
|
const root = await projectRoot();
|
|
@@ -135,8 +136,11 @@ async function executeRunRoute(root, context) {
|
|
|
135
136
|
blockers: execution.ok ? [] : execution.blockers,
|
|
136
137
|
unverified: execution.unverified,
|
|
137
138
|
command: { cmd: execution.command || `sks run "${prompt}" --execute`, status: execution.exit_code ?? (execution.ok ? 0 : 2) },
|
|
139
|
+
lightweightEvidence: execution.execution_kind === 'safe_deterministic',
|
|
138
140
|
});
|
|
139
|
-
const trust =
|
|
141
|
+
const trust = execution.execution_kind === 'safe_deterministic'
|
|
142
|
+
? await writeLightweightTrustReport(root, id, route.command, statusHint, proof.ok)
|
|
143
|
+
: await loadTrustReport(root, id);
|
|
140
144
|
const autoVerification = auto ? await runAutoVerification(root, id) : null;
|
|
141
145
|
const autoOk = autoVerification?.ok ?? true;
|
|
142
146
|
await setCurrent(root, {
|
|
@@ -231,7 +235,7 @@ async function executeRouteCommand(root, route, prompt, { auto = false } = {}) {
|
|
|
231
235
|
return routeExecutionResult(route, ['sks', ...commandArgs].join(' '), result, {
|
|
232
236
|
okStatus: 'completed',
|
|
233
237
|
trustStatus: 'verified_partial',
|
|
234
|
-
executionKind: route.command === '$DB' || route.command === '$Wiki' || route.command === '$Fast-Mode' || route.command === '$with-local-llm-on' || route.command === '$Commit' || route.command === '$Commit-And-Push' ? 'safe_deterministic' : 'mock_safe',
|
|
238
|
+
executionKind: route.command === '$DB' || route.command === '$Wiki' || route.command === '$Fast-Mode' || route.command === '$with-local-llm-on' || route.command === '$Commit' || route.command === '$Commit-And-Push' || route.command === '$Ultra-Search' || route.command === '$SEO-GEO-OPTIMIZER' ? 'safe_deterministic' : 'mock_safe',
|
|
235
239
|
});
|
|
236
240
|
}
|
|
237
241
|
async function runAutoVerification(root, missionId) {
|
|
@@ -342,6 +346,10 @@ function runNextAction(route, id, args) {
|
|
|
342
346
|
function safeRouteExecutionArgs(route, prompt, { auto = false } = {}) {
|
|
343
347
|
if (route.command === '$DB')
|
|
344
348
|
return ['db', 'check', '--sql', 'SELECT 1', '--json'];
|
|
349
|
+
if (route.command === '$Ultra-Search')
|
|
350
|
+
return ultraSearchExecutionArgs(prompt);
|
|
351
|
+
if (route.command === '$SEO-GEO-OPTIMIZER')
|
|
352
|
+
return ['seo-geo-optimizer', searchVisibilityActionFromPrompt(prompt), '--mode', searchVisibilityModeFromPrompt(prompt), '--target', searchVisibilityTargetFromPrompt(prompt), '--offline', '--json'];
|
|
345
353
|
if (route.command === '$Wiki')
|
|
346
354
|
return ['wiki', 'refresh', '--json'];
|
|
347
355
|
if (route.command === '$Fast-Mode')
|
|
@@ -354,6 +362,58 @@ function safeRouteExecutionArgs(route, prompt, { auto = false } = {}) {
|
|
|
354
362
|
return ['commit-and-push', '--json'];
|
|
355
363
|
return ['team', prompt, '--mock', '--json', ...(auto ? ['--no-open-zellij'] : [])];
|
|
356
364
|
}
|
|
365
|
+
function ultraSearchExecutionArgs(prompt = '') {
|
|
366
|
+
const stripped = stripUltraSearchPrompt(prompt);
|
|
367
|
+
const lower = stripped.toLowerCase();
|
|
368
|
+
if (!stripped || /^(?:doctor|check|status)\b/.test(lower))
|
|
369
|
+
return ['ultra-search', 'doctor', '--json'];
|
|
370
|
+
if (/^(?:x|x-search|x_search)\b/.test(lower)) {
|
|
371
|
+
const query = stripped.replace(/^(?:x|x-search|x_search)\b[:\s-]*/i, '').trim() || 'source intelligence fixture';
|
|
372
|
+
return ['ultra-search', 'x', query, '--json'];
|
|
373
|
+
}
|
|
374
|
+
const url = stripped.match(/\bhttps?:\/\/\S+/)?.[0];
|
|
375
|
+
if (/^(?:fetch|url)\b/.test(lower) || url)
|
|
376
|
+
return ['ultra-search', 'fetch', url || stripped.replace(/^(?:fetch|url)\b[:\s-]*/i, '').trim() || 'https://example.com', '--json'];
|
|
377
|
+
const query = stripped.replace(/^run\b[:\s-]*/i, '').trim() || 'source intelligence fixture';
|
|
378
|
+
return ['ultra-search', 'run', query, '--mode', 'balanced', '--json'];
|
|
379
|
+
}
|
|
380
|
+
function stripUltraSearchPrompt(prompt = '') {
|
|
381
|
+
return String(prompt || '')
|
|
382
|
+
.trim()
|
|
383
|
+
.replace(/^\[\$Ultra-Search\]\([^)]+\)(?:\s|:)?\s*/i, '')
|
|
384
|
+
.replace(/^\[\$UltraSearch\]\([^)]+\)(?:\s|:)?\s*/i, '')
|
|
385
|
+
.replace(/^\$Ultra-Search(?:\s|:)?\s*/i, '')
|
|
386
|
+
.replace(/^\$UltraSearch(?:\s|:)?\s*/i, '')
|
|
387
|
+
.trim();
|
|
388
|
+
}
|
|
389
|
+
function searchVisibilityActionFromPrompt(prompt = '') {
|
|
390
|
+
const text = String(prompt || '').toLowerCase();
|
|
391
|
+
if (/\bdoctor\b|진단/.test(text))
|
|
392
|
+
return 'doctor';
|
|
393
|
+
if (/\bverify\b|검증/.test(text))
|
|
394
|
+
return 'fixture';
|
|
395
|
+
if (/\bplan\b|계획/.test(text))
|
|
396
|
+
return 'audit';
|
|
397
|
+
if (/\bapply\b|--apply\b|적용/.test(text))
|
|
398
|
+
return 'audit';
|
|
399
|
+
return 'audit';
|
|
400
|
+
}
|
|
401
|
+
function searchVisibilityTargetFromPrompt(prompt = '') {
|
|
402
|
+
const text = String(prompt || '').toLowerCase();
|
|
403
|
+
if (/\bpackage\b|npm|readme|github/.test(text))
|
|
404
|
+
return 'package';
|
|
405
|
+
if (/\bdocs?\b|documentation/.test(text))
|
|
406
|
+
return 'docs';
|
|
407
|
+
if (/\bwebsite\b|site\b|페이지|사이트/.test(text))
|
|
408
|
+
return 'website';
|
|
409
|
+
return 'auto';
|
|
410
|
+
}
|
|
411
|
+
function searchVisibilityModeFromPrompt(prompt = '') {
|
|
412
|
+
const text = String(prompt || '');
|
|
413
|
+
if (/generative\s+engine\s+optimization|AI\s+(?:answer|search)\s+(?:visibility|discoverability)|LLM\s+(?:citation|answer|visibility|discoverability)|answerability|entity\s+(?:facts?|clarity)|claim\s+evidence|crawler\s+policy|OAI-SearchBot|GPTBot|ChatGPT-User|Claude-SearchBot|ClaudeBot|Claude-User|llms\.txt|AI\s*검색\s*가시성|AI\s*답변\s*가시성|생성형\s*엔진\s*최적화/i.test(text))
|
|
414
|
+
return 'geo';
|
|
415
|
+
return 'seo';
|
|
416
|
+
}
|
|
357
417
|
function fastModeActionFromPrompt(prompt = '') {
|
|
358
418
|
const text = String(prompt || '');
|
|
359
419
|
const lower = text.toLowerCase();
|
|
@@ -468,4 +528,34 @@ async function loadTrustReport(root, missionId) {
|
|
|
468
528
|
return report;
|
|
469
529
|
return { status: 'not_verified', ok: false, issues: ['trust_report_invalid'] };
|
|
470
530
|
}
|
|
531
|
+
async function writeLightweightTrustReport(root, missionId, route, statusHint, proofOk) {
|
|
532
|
+
const status = normalizeTrustStatus(statusHint);
|
|
533
|
+
const issues = proofOk ? [] : ['completion_proof_not_ok'];
|
|
534
|
+
const report = {
|
|
535
|
+
schema: TRUST_REPORT_SCHEMA,
|
|
536
|
+
...trustKernelMetadata(),
|
|
537
|
+
ok: proofOk && !['blocked', 'failed', 'not_verified'].includes(status),
|
|
538
|
+
mission_id: missionId,
|
|
539
|
+
route,
|
|
540
|
+
status,
|
|
541
|
+
proof_status: status,
|
|
542
|
+
evidence_status: 'verified_partial',
|
|
543
|
+
route_contract_status: 'verified_partial',
|
|
544
|
+
issues,
|
|
545
|
+
route_state_machine: {
|
|
546
|
+
state: 'trust_report',
|
|
547
|
+
lightweight: true,
|
|
548
|
+
reason: 'safe_deterministic_run_wrapper'
|
|
549
|
+
},
|
|
550
|
+
evidence: {
|
|
551
|
+
completion_proof: `.sneakoscope/missions/${missionId}/completion-proof.json`,
|
|
552
|
+
route_contract: null,
|
|
553
|
+
evidence_index: null,
|
|
554
|
+
evidence_records: 0,
|
|
555
|
+
lightweight: true
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
await writeJsonAtomic(path.join(missionDir(root, missionId), 'trust-report.json'), report);
|
|
559
|
+
return report;
|
|
560
|
+
}
|
|
471
561
|
//# sourceMappingURL=run-command.js.map
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { printJson } from '../../cli/output.js';
|
|
3
|
+
import { projectRoot } from '../fsx.js';
|
|
4
|
+
import { flag, readOption } from './command-utils.js';
|
|
5
|
+
import { runSearchVisibilityApply, runSearchVisibilityAudit, runSearchVisibilityDoctor, runSearchVisibilityFixture, runSearchVisibilityPlan, runSearchVisibilityRollback, runSearchVisibilityStatus, runSearchVisibilityVerify, } from '../search-visibility/index.js';
|
|
6
|
+
export async function seoCommand(args = []) {
|
|
7
|
+
return runSearchVisibilityCommand('seo', args, 'seo');
|
|
8
|
+
}
|
|
9
|
+
export async function seoGeoOptimizerCommand(args = []) {
|
|
10
|
+
const normalized = normalizeOptimizerArgs(args);
|
|
11
|
+
return runSearchVisibilityCommand(normalized.mode, normalized.args, 'seo-geo-optimizer');
|
|
12
|
+
}
|
|
13
|
+
export async function runSearchVisibilityCommand(mode, args = [], displayCommand = mode) {
|
|
14
|
+
const action = args[0] || 'doctor';
|
|
15
|
+
const rest = args.slice(1);
|
|
16
|
+
const options = await parseOptions(rest);
|
|
17
|
+
let result;
|
|
18
|
+
if (action === 'doctor')
|
|
19
|
+
result = await runSearchVisibilityDoctor(mode, options);
|
|
20
|
+
else if (action === 'audit')
|
|
21
|
+
result = await runSearchVisibilityAudit(mode, options);
|
|
22
|
+
else if (action === 'plan')
|
|
23
|
+
result = await runSearchVisibilityPlan(mode, firstPositional(rest) || 'latest', options);
|
|
24
|
+
else if (action === 'apply')
|
|
25
|
+
result = await runSearchVisibilityApply(mode, firstPositional(rest) || 'latest', options);
|
|
26
|
+
else if (action === 'verify')
|
|
27
|
+
result = await runSearchVisibilityVerify(mode, firstPositional(rest) || 'latest', options);
|
|
28
|
+
else if (action === 'status')
|
|
29
|
+
result = await runSearchVisibilityStatus(mode, firstPositional(rest) || 'latest', options);
|
|
30
|
+
else if (action === 'rollback')
|
|
31
|
+
result = await runSearchVisibilityRollback(mode, firstPositional(rest) || 'latest', options);
|
|
32
|
+
else if (action === 'fixture')
|
|
33
|
+
result = await runSearchVisibilityFixture(mode, options);
|
|
34
|
+
else
|
|
35
|
+
return usage(mode, 2, displayCommand);
|
|
36
|
+
if (isBlocked(result))
|
|
37
|
+
process.exitCode = 1;
|
|
38
|
+
if (options.json) {
|
|
39
|
+
printJson(result);
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
printHuman(mode, action, result);
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
function normalizeOptimizerArgs(args) {
|
|
46
|
+
const out = [...args];
|
|
47
|
+
const first = String(out[0] || '').toLowerCase();
|
|
48
|
+
if (first === 'seo' || first === 'geo')
|
|
49
|
+
return { mode: first, args: out.slice(1) };
|
|
50
|
+
const modeIndex = out.findIndex((item) => item === '--mode');
|
|
51
|
+
if (modeIndex >= 0) {
|
|
52
|
+
const value = String(out[modeIndex + 1] || '').toLowerCase();
|
|
53
|
+
out.splice(modeIndex, value ? 2 : 1);
|
|
54
|
+
return { mode: value === 'geo' ? 'geo' : 'seo', args: out };
|
|
55
|
+
}
|
|
56
|
+
if (out.includes('--include-llms-txt') || out.includes('--observe-queries') || out.includes('--query-file'))
|
|
57
|
+
return { mode: 'geo', args: out };
|
|
58
|
+
return { mode: 'seo', args: out };
|
|
59
|
+
}
|
|
60
|
+
async function parseOptions(args) {
|
|
61
|
+
const root = path.resolve(readOption(args, '--root', await projectRoot()));
|
|
62
|
+
return {
|
|
63
|
+
root,
|
|
64
|
+
url: readOption(args, '--url', null),
|
|
65
|
+
target: targetOption(readOption(args, '--target', 'auto')),
|
|
66
|
+
framework: frameworkOption(readOption(args, '--framework', 'auto')),
|
|
67
|
+
offline: flag(args, '--offline'),
|
|
68
|
+
strict: flag(args, '--strict'),
|
|
69
|
+
json: flag(args, '--json'),
|
|
70
|
+
apply: flag(args, '--apply'),
|
|
71
|
+
yes: flag(args, '--yes'),
|
|
72
|
+
allowDirtyTouched: flag(args, '--allow-dirty-touched'),
|
|
73
|
+
browser: flag(args, '--browser'),
|
|
74
|
+
includeLlmsTxt: flag(args, '--include-llms-txt'),
|
|
75
|
+
observeQueries: flag(args, '--observe-queries'),
|
|
76
|
+
queryFile: readOption(args, '--query-file', null),
|
|
77
|
+
scope: String(readOption(args, '--scope', '') || '').split(',').map((item) => item.trim()).filter(Boolean),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function targetOption(value) {
|
|
81
|
+
return ['auto', 'website', 'docs', 'package'].includes(value) ? value : 'auto';
|
|
82
|
+
}
|
|
83
|
+
function frameworkOption(value) {
|
|
84
|
+
return ['auto', 'next-app', 'next-pages', 'static', 'package', 'unsupported'].includes(value) ? value : 'auto';
|
|
85
|
+
}
|
|
86
|
+
function firstPositional(args) {
|
|
87
|
+
const valueFlags = new Set(['--root', '--url', '--target', '--framework', '--scope', '--query-file']);
|
|
88
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
89
|
+
const value = args[i] || '';
|
|
90
|
+
if (valueFlags.has(value)) {
|
|
91
|
+
i += 1;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (!value.startsWith('--'))
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
function usage(mode, exitCode, displayCommand = mode) {
|
|
100
|
+
if (displayCommand === 'seo-geo-optimizer') {
|
|
101
|
+
console.error('Usage: sks seo-geo-optimizer [seo|geo] doctor|audit|plan|apply|verify|status|rollback|fixture [mission|latest] [--mode seo|geo] [--root <path>] [--url <origin>] [--target auto|website|docs|package] [--framework auto|next-app|next-pages|static] [--offline] [--strict] [--json]');
|
|
102
|
+
console.error(' sks seo-geo-optimizer apply <mission|latest> --mode seo|geo --apply [--include-llms-txt] [--scope <rule-or-path,...>] [--yes] [--json]');
|
|
103
|
+
console.error(' sks seo-geo-optimizer rollback <mission|latest> --mode seo|geo --apply [--yes] [--json]');
|
|
104
|
+
process.exitCode = exitCode;
|
|
105
|
+
return { schema: 'sks.search-visibility.usage.v1', ok: false, status: 'blocked', mode, command: displayCommand, reason: 'invalid_subcommand' };
|
|
106
|
+
}
|
|
107
|
+
const applyFlag = mode === 'geo' ? ' [--include-llms-txt]' : '';
|
|
108
|
+
console.error(`Usage: sks ${mode} doctor|audit|plan|apply|verify|status|rollback|fixture [mission|latest] [--root <path>] [--url <origin>] [--target auto|website|docs|package] [--framework auto|next-app|next-pages|static] [--offline] [--strict] [--json]`);
|
|
109
|
+
console.error(` sks ${mode} apply <mission|latest> --apply${applyFlag} [--scope <rule-or-path,...>] [--yes] [--json]`);
|
|
110
|
+
console.error(` sks ${mode} rollback <mission|latest> --apply [--yes] [--json]`);
|
|
111
|
+
process.exitCode = exitCode;
|
|
112
|
+
return { schema: 'sks.search-visibility.usage.v1', ok: false, status: 'blocked', mode, reason: 'invalid_subcommand' };
|
|
113
|
+
}
|
|
114
|
+
function isBlocked(value) {
|
|
115
|
+
if (!value || typeof value !== 'object')
|
|
116
|
+
return false;
|
|
117
|
+
const rec = value;
|
|
118
|
+
return rec.ok === false || rec.status === 'blocked';
|
|
119
|
+
}
|
|
120
|
+
function printHuman(mode, action, value) {
|
|
121
|
+
const rec = value && typeof value === 'object' ? value : {};
|
|
122
|
+
console.log(`SKS ${mode.toUpperCase()} ${action}: ${rec.status || (rec.ok === false ? 'blocked' : 'ok')}`);
|
|
123
|
+
if (rec.mission_id)
|
|
124
|
+
console.log(`Mission: ${rec.mission_id}`);
|
|
125
|
+
if (rec.artifacts_dir)
|
|
126
|
+
console.log(`Artifacts: ${rec.artifacts_dir}`);
|
|
127
|
+
if (Array.isArray(rec.blockers) && rec.blockers.length)
|
|
128
|
+
console.log(`Blockers: ${rec.blockers.join(', ')}`);
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=seo-command.js.map
|
package/dist/core/db-safety.js
CHANGED
|
@@ -510,15 +510,16 @@ export async function checkDbOperation(root, state, payload, { duringNoQuestion
|
|
|
510
510
|
const contract = await loadMissionContract(root, state);
|
|
511
511
|
const classification = classifyToolPayload(payload);
|
|
512
512
|
const madDb = await resolveMadDbMutationPolicy(root, state, classification);
|
|
513
|
-
if (madDb.allowed === true &&
|
|
513
|
+
if (madDb.allowed === true && madDb.mission_id) {
|
|
514
514
|
const madDbDecision = madDb;
|
|
515
|
+
const madDbMissionId = String(madDbDecision.mission_id);
|
|
515
516
|
const sqlText = classification.sql?.statements?.length ? String(classification.sql.statements.join('\n')) : null;
|
|
516
517
|
const sqlHash = sqlText ? sha256(sqlText) : null;
|
|
517
518
|
const toolCallId = extractCanonicalToolCallId(payload) || `payload-${sha256(JSON.stringify({ tool: classification.toolName || '', sqlHash, level: classification.level })).slice(0, 16)}`;
|
|
518
519
|
const operationClasses = madDbDecision.operation_classes?.length ? madDbDecision.operation_classes : madDbOperationClassesFromClassification(classification);
|
|
519
520
|
const reservation = await reserveMadDbOperation({
|
|
520
521
|
root,
|
|
521
|
-
missionId:
|
|
522
|
+
missionId: madDbMissionId,
|
|
522
523
|
capability: madDbDecision.capability,
|
|
523
524
|
toolCallId,
|
|
524
525
|
toolName: classification.toolName || 'unknown_database_tool',
|
|
@@ -527,12 +528,12 @@ export async function checkDbOperation(root, state, payload, { duringNoQuestion
|
|
|
527
528
|
});
|
|
528
529
|
await transitionMadDbOperation({
|
|
529
530
|
root,
|
|
530
|
-
missionId:
|
|
531
|
+
missionId: madDbMissionId,
|
|
531
532
|
toolCallId,
|
|
532
533
|
state: 'started'
|
|
533
534
|
});
|
|
534
535
|
const lifecycleHook = {
|
|
535
|
-
mission_id:
|
|
536
|
+
mission_id: madDbMissionId,
|
|
536
537
|
operation_id: reservation.operation.operation_id,
|
|
537
538
|
tool_call_id: toolCallId,
|
|
538
539
|
cycle_id: madDbDecision.cycle_id || null,
|
|
@@ -560,12 +561,13 @@ export async function checkDbOperation(root, state, payload, { duringNoQuestion
|
|
|
560
561
|
lifecycle_result_pending: true,
|
|
561
562
|
ledger_result_hook: lifecycleHook,
|
|
562
563
|
operation_classes: operationClasses,
|
|
564
|
+
state_source: madDbDecision.state_source || 'hook_state',
|
|
563
565
|
counters: reservation.capability.counters,
|
|
564
566
|
idempotent_reservation_reused: reservation.reused
|
|
565
567
|
}
|
|
566
568
|
};
|
|
567
|
-
await appendMadDbLedgerEvent(root,
|
|
568
|
-
await appendJsonlBounded(path.join(missionDir(root,
|
|
569
|
+
await appendMadDbLedgerEvent(root, madDbMissionId, { type: 'db_mutation.allowed', cycle_id: madDbDecision.cycle_id, mode: madDbDecision.mode, classification, operation_id: reservation.operation.operation_id, tool_call_id: toolCallId });
|
|
570
|
+
await appendJsonlBounded(path.join(missionDir(root, madDbMissionId), 'db-safety.jsonl'), { ts: nowIso(), decision });
|
|
569
571
|
return decision;
|
|
570
572
|
}
|
|
571
573
|
const madSks = await madSksOverrideState(root, state);
|
|
@@ -36,6 +36,7 @@ const FIXTURES = Object.freeze({
|
|
|
36
36
|
'cli-selftest': fixture('execute', 'sks selftest --mock', [], 'pass'),
|
|
37
37
|
'cli-git': fixture('execute', 'sks git policy --json', [], 'pass'),
|
|
38
38
|
'cli-goal': fixture('mock', 'sks goal status latest --json', ['goal-workflow.json'], 'pass'),
|
|
39
|
+
'cli-seo-geo-optimizer': fixture('execute_and_validate_artifacts', 'sks seo-geo-optimizer fixture --mode seo --json', ['search-visibility/site-inventory.json', 'search-visibility/seo-findings.json', 'search-visibility/verification-report.json', 'seo-gate.json', 'completion-proof.json'], 'pass'),
|
|
39
40
|
'cli-research': fixture('mock', 'sks research status latest --json', ['research-gate.json', 'completion-proof.json'], 'pass'),
|
|
40
41
|
'cli-qa-loop': fixture('mock', 'sks qa-loop status latest --json', ['qa-loop-proof.json', 'completion-proof.json'], 'pass'),
|
|
41
42
|
'cli-ppt': fixture('mock', 'sks ppt fixture --mock --json', ['ppt-imagegen-review-gate.json', 'completion-proof.json'], 'pass'),
|
|
@@ -75,6 +76,7 @@ const FIXTURES = Object.freeze({
|
|
|
75
76
|
'cli-commit': fixture('mock', 'sks commit --dry-run', [], 'pass'),
|
|
76
77
|
'cli-commit-and-push': fixture('mock', 'sks commit-and-push --dry-run', [], 'pass'),
|
|
77
78
|
'cli-context7': fixture('real_optional', 'sks context7 check --json', [], 'pass'),
|
|
79
|
+
'cli-ultra-search': fixture('execute', 'sks ultra-search doctor --json', [], 'pass'),
|
|
78
80
|
'cli-xai': fixture('real_optional', 'sks xai check --json', [], 'pass'),
|
|
79
81
|
'cli-all-features': fixture('mock', 'sks all-features complete --json', [`.sneakoscope/reports/all-feature-completion-${PACKAGE_VERSION}.json`], 'pass'),
|
|
80
82
|
'cli-init': fixture('mock', 'sks init --local-only --dry-run', [], 'pass'),
|
|
@@ -88,6 +90,7 @@ const FIXTURES = Object.freeze({
|
|
|
88
90
|
'skill-imagegen': fixture('mock', 'sks image-ux-review fixture --mock --json', ['image-ux-generated-review-ledger.json', 'image-voxel-ledger.json'], 'pass'),
|
|
89
91
|
'skill-gx-visual-validate': fixture('mock', 'sks gx validate fixture --mock --json', ['gx-validation.json'], 'pass'),
|
|
90
92
|
'skill-context7-docs': fixture('real_optional', 'sks context7 check --json', [], 'pass'),
|
|
93
|
+
'skill-seo-geo-optimizer': fixture('mock', 'sks seo-geo-optimizer fixture --mode geo --json', ['search-visibility/site-inventory.json', 'search-visibility/geo-findings.json', 'geo-gate.json', 'completion-proof.json'], 'pass'),
|
|
91
94
|
'cli-proof': fixture('execute_and_validate_artifacts', 'sks proof smoke --json', ['.sneakoscope/proof/latest.json'], 'pass'),
|
|
92
95
|
'cli-trust': fixture('execute_and_validate_artifacts', 'sks trust report latest --json', ['trust-report.json'], 'pass'),
|
|
93
96
|
'cli-wrongness': fixture('execute_and_validate_artifacts', 'sks wrongness add --kind missing_evidence --claim "fixture wrongness" --json', ['.sneakoscope/wiki/wrongness-ledger.json'], 'pass'),
|
|
@@ -104,6 +107,9 @@ const FIXTURES = Object.freeze({
|
|
|
104
107
|
'route-dfix': fixture('execute_and_validate_artifacts', 'sks dfix fixture --json', ['completion-proof.json', 'dfix-gate.json', 'dfix-verification.json'], 'pass'),
|
|
105
108
|
'route-answer': fixture('mock', '$Answer answer-only route policy', [], 'pass'),
|
|
106
109
|
'route-goal': fixture('mock', '$Goal bridge route', ['goal-workflow.json', 'completion-proof.json'], 'pass'),
|
|
110
|
+
'route-ultra-search': fixture('execute', 'sks run "$Ultra-Search source intelligence fixture" --execute --json', [], 'pass'),
|
|
111
|
+
'route-ultrasearch': fixture('execute', 'sks run "$UltraSearch source intelligence fixture" --execute --json', [], 'pass'),
|
|
112
|
+
'route-seo-geo-optimizer': fixture('execute_and_validate_artifacts', 'sks seo-geo-optimizer fixture --mode geo --json', ['search-visibility/site-inventory.json', 'search-visibility/geo-findings.json', 'search-visibility/verification-report.json', 'geo-gate.json', 'completion-proof.json'], 'pass'),
|
|
107
113
|
'route-autoresearch': fixture('mock', '$AutoResearch fixture route', ['research-gate.json', 'completion-proof.json'], 'pass'),
|
|
108
114
|
'route-mad-sks': fixture('mock', '$MAD-SKS permission gate route', ['mad-sks-gate.json', 'completion-proof.json'], 'pass'),
|
|
109
115
|
'route-from-chat-img': fixture('mock', '$From-Chat-IMG visual work order route', ['from-chat-img-work-order.md', 'image-voxel-ledger.json', 'completion-proof.json'], 'pass'),
|
|
@@ -461,6 +461,7 @@ const SAFE_EXECUTABLE_FIXTURE_ARGS = Object.freeze({
|
|
|
461
461
|
'cli-fix-path': ['fix-path', '--json'],
|
|
462
462
|
'cli-selftest': ['selftest', '--mock'],
|
|
463
463
|
'cli-git': ['git', 'policy', '--json'],
|
|
464
|
+
'cli-seo-geo-optimizer': ['seo-geo-optimizer', 'fixture', '--mode', 'seo', '--json'],
|
|
464
465
|
'cli-paths': ['paths', 'managed', '--json'],
|
|
465
466
|
'cli-rollback': ['rollback', 'list', '--json'],
|
|
466
467
|
'cli-proof-field': ['proof-field', 'scan', '--json', '--intent', 'fixture'],
|
|
@@ -493,6 +494,7 @@ const SAFE_EXECUTABLE_FIXTURE_ARGS = Object.freeze({
|
|
|
493
494
|
'route-image-ux-review': ['image-ux-review', 'fixture', '--mock', '--json'],
|
|
494
495
|
'route-computer-use': ['computer-use', 'import-fixture', '--mock', '--json'],
|
|
495
496
|
'route-dfix': ['dfix', 'fixture', '--json'],
|
|
497
|
+
'route-seo-geo-optimizer': ['seo-geo-optimizer', 'fixture', '--mode', 'geo', '--json'],
|
|
496
498
|
'route-fast-mode': ['fast-mode', 'status', '--json'],
|
|
497
499
|
'route-db': ['db', 'check', '--sql', 'SELECT 1', '--json'],
|
|
498
500
|
'route-wiki': ['wiki', 'image-ingest', 'test/fixtures/images/one-by-one.png', '--json'],
|
|
@@ -826,7 +828,7 @@ function commandCategory(name) {
|
|
|
826
828
|
function commandMaturity(name) {
|
|
827
829
|
if (['help', 'version', 'commands', 'usage', 'root', 'quickstart', 'setup', 'doctor', 'selftest', 'update-check', 'fast-mode'].includes(name))
|
|
828
830
|
return 'stable';
|
|
829
|
-
if (['codex', 'codex-app', 'codex-native', 'codex-lb', 'hooks', 'features', 'all-features', 'wiki', 'wrongness', 'team', 'pipeline', 'goal', 'db', 'guard', 'computer-use', 'mad-sks'].includes(name))
|
|
831
|
+
if (['codex', 'codex-app', 'codex-native', 'codex-lb', 'hooks', 'features', 'all-features', 'wiki', 'wrongness', 'team', 'pipeline', 'goal', 'db', 'guard', 'computer-use', 'mad-sks', 'seo-geo-optimizer'].includes(name))
|
|
830
832
|
return 'beta';
|
|
831
833
|
return 'labs';
|
|
832
834
|
}
|
package/dist/core/fsx.js
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
|
import { fileURLToPath } from 'node:url';
|
|
8
|
-
export const PACKAGE_VERSION = '4.
|
|
8
|
+
export const PACKAGE_VERSION = '4.6.1';
|
|
9
9
|
export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
|
|
10
10
|
export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
|
|
11
11
|
export function nowIso() {
|
|
@@ -12,6 +12,7 @@ import { localizedFinalizationReason } from './language-preference.js';
|
|
|
12
12
|
import { classifyToolError } from './evaluation.js';
|
|
13
13
|
import { REQUIRED_CODEX_MODEL, isForbiddenCodexModel } from './codex-model-guard.js';
|
|
14
14
|
import { dollarCommand, routeRequiresSubagents, stripVisibleDecisionAnswerBlocks } from './routes.js';
|
|
15
|
+
import { leanEngineeringCompactText } from './lean-engineering-policy.js';
|
|
15
16
|
import { appendMissionStatus } from './recallpulse.js';
|
|
16
17
|
import { scanAgentTextForRecursion } from './agents/agent-recursion-guard.js';
|
|
17
18
|
import { evaluateLoopContinuation } from './loops/loop-continuation-enforcer.js';
|
|
@@ -194,8 +195,15 @@ export async function evaluateHookPayload(name, payload = {}, opts = {}) {
|
|
|
194
195
|
return hookPermission(root, state, payload, noQuestion);
|
|
195
196
|
if (name === 'stop')
|
|
196
197
|
return hookStop(root, state, payload, noQuestion);
|
|
198
|
+
if (name === 'subagent-start')
|
|
199
|
+
return hookSubagentStart(root, state);
|
|
197
200
|
return { continue: true };
|
|
198
201
|
}
|
|
202
|
+
async function hookSubagentStart(root, state) {
|
|
203
|
+
const active = await activeRouteContext(root, state).catch(() => '');
|
|
204
|
+
const additionalContext = [leanEngineeringCompactText(), active].filter(Boolean).join('\n\n');
|
|
205
|
+
return { continue: true, additionalContext };
|
|
206
|
+
}
|
|
199
207
|
function blockForbiddenClientModel(payload = {}) {
|
|
200
208
|
const model = forbiddenClientModelFromPayload(payload);
|
|
201
209
|
if (!model || !isForbiddenCodexModel(model))
|