sneakoscope 4.2.1 → 4.3.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 +34 -7
- 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 +3 -1
- package/dist/cli/ultra-search-command.js +163 -0
- package/dist/cli/xai-command.js +28 -168
- package/dist/core/agents/agent-codex-cockpit.js +3 -3
- package/dist/core/agents/agent-runner-ollama.js +2 -0
- package/dist/core/agents/agent-wrongness.js +1 -1
- 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/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/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/release-parallel-full-coverage.js +1 -1
- package/dist/core/routes.js +77 -10
- 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/source-intelligence/source-intelligence-policy.js +45 -26
- package/dist/core/source-intelligence/source-intelligence-proof.js +10 -16
- package/dist/core/source-intelligence/source-intelligence-runner.js +56 -42
- package/dist/core/trust-kernel/trust-report.js +3 -5
- package/dist/core/ultra-search/index.js +3 -0
- package/dist/core/ultra-search/runtime.js +502 -0
- package/dist/core/ultra-search/types.js +3 -0
- package/dist/core/version.js +1 -1
- package/dist/scripts/agent-visual-consistency-check.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/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/release-metadata-1-19-check.js +2 -2
- package/dist/scripts/release-parallel-check.js +17 -2
- package/dist/scripts/release-parallel-full-coverage-check.js +1 -1
- package/dist/scripts/release-readiness-report.js +6 -6
- 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-1-18-gate-lib.js +2 -2
- package/dist/scripts/sks-3-1-5-directive-check-lib.js +10 -1
- package/dist/scripts/source-intelligence-all-modes-check.js +9 -19
- package/dist/scripts/source-intelligence-policy-check.js +6 -6
- package/dist/scripts/ultra-search-provider-interface-check.js +27 -0
- package/package.json +21 -3
- 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
- package/dist/core/mcp/xai-mcp-detector.js +0 -157
- package/dist/core/mcp/xai-search-adapter.js +0 -100
- package/dist/scripts/xai-mcp-capability-check.js +0 -14
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { ensureDir, nowIso, readJson, sha256, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
|
|
3
|
+
import { normalizeCodexWebResults, runCodexWebSearch } from '../codex/codex-web-search-adapter.js';
|
|
4
|
+
export async function runUltraSearch(input) {
|
|
5
|
+
const root = path.resolve(input.root || process.cwd());
|
|
6
|
+
const missionDir = path.resolve(input.missionDir);
|
|
7
|
+
const missionId = input.missionId || path.basename(missionDir);
|
|
8
|
+
const artifactDir = path.join(missionDir, 'ultra-search');
|
|
9
|
+
await ensureDir(artifactDir);
|
|
10
|
+
const mode = resolveMode(input.query, input.mode, input.offline === true);
|
|
11
|
+
const intent = classifyIntent(input.query, mode);
|
|
12
|
+
const axes = buildAxes(input.query, mode, intent);
|
|
13
|
+
const queryVariants = buildQueryVariants(input.query, mode, intent);
|
|
14
|
+
const cache = await readCache(artifactDir, input.query, mode);
|
|
15
|
+
if (cache.hit && !cache.stale && cache.result) {
|
|
16
|
+
const cached = cache.result;
|
|
17
|
+
return {
|
|
18
|
+
...cached,
|
|
19
|
+
generated_at: nowIso(),
|
|
20
|
+
cache: { ...cached.cache, hit: true, stale: false, age_ms: cache.age_ms }
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const providerPlan = planProviders(intent, mode, input.offline === true, Boolean(input.context7), Boolean(input.codexWebSearch), input.env);
|
|
24
|
+
const sourceRows = [];
|
|
25
|
+
const warnings = [...providerPlan.warnings];
|
|
26
|
+
const blockers = [...providerPlan.blockers];
|
|
27
|
+
if (input.context7 && providerPlan.selected_providers.includes('context7')) {
|
|
28
|
+
const raw = await input.context7(queryVariants[0] || input.query);
|
|
29
|
+
sourceRows.push(...normalizeGenericSourceRows(raw, 'context7', 'official_docs', intent, 'A0'));
|
|
30
|
+
}
|
|
31
|
+
else if (intent === 'official_documentation' && !input.offline) {
|
|
32
|
+
warnings.push('context7_not_invoked_for_docs_query');
|
|
33
|
+
}
|
|
34
|
+
if (providerPlan.selected_providers.includes('codex_web')) {
|
|
35
|
+
const webEvidence = await runCodexWebSearch(queryVariants[0] || input.query, {
|
|
36
|
+
...(input.codexWebSearch ? { search: input.codexWebSearch } : {}),
|
|
37
|
+
artifactDir,
|
|
38
|
+
...(input.offline === undefined ? {} : { offline: input.offline }),
|
|
39
|
+
...(input.env ? { env: input.env } : {})
|
|
40
|
+
});
|
|
41
|
+
if (webEvidence.blockers.length)
|
|
42
|
+
blockers.push(...webEvidence.blockers);
|
|
43
|
+
warnings.push(...webEvidence.warnings);
|
|
44
|
+
sourceRows.push(...webEvidence.normalized_results.map((row, index) => sourceFromWebRow(row, index, intent)));
|
|
45
|
+
}
|
|
46
|
+
if (mode === 'url_acquisition') {
|
|
47
|
+
const url = extractFirstUrl(input.query);
|
|
48
|
+
if (url)
|
|
49
|
+
sourceRows.push(sourceFromKnownUrl(url, intent));
|
|
50
|
+
else
|
|
51
|
+
blockers.push('url_acquisition_mode_without_url');
|
|
52
|
+
}
|
|
53
|
+
if (mode === 'x_search') {
|
|
54
|
+
sourceRows.push(...buildXDiscoverySources(queryVariants, intent));
|
|
55
|
+
warnings.push('x_public_results_are_discovery_until_post_detail_or_authenticated_source_verifies_full_text');
|
|
56
|
+
}
|
|
57
|
+
const deduped = dedupeSources(sourceRows);
|
|
58
|
+
const leads = buildLeads(deduped, mode);
|
|
59
|
+
const claims = buildClaims(input.query, deduped, mode, intent);
|
|
60
|
+
const convergence = buildConvergence(mode, leads, blockers);
|
|
61
|
+
const proof = buildProof(mode, intent, deduped, claims, convergence, blockers, warnings);
|
|
62
|
+
const synthesis = renderSynthesis(input.query, deduped, claims, proof);
|
|
63
|
+
const result = {
|
|
64
|
+
schema: 'sks.ultra-search-result.v1',
|
|
65
|
+
generated_at: nowIso(),
|
|
66
|
+
ok: proof.ok,
|
|
67
|
+
mission_id: missionId,
|
|
68
|
+
artifact_dir: artifactDir,
|
|
69
|
+
query: input.query,
|
|
70
|
+
mode,
|
|
71
|
+
intent,
|
|
72
|
+
axes,
|
|
73
|
+
query_variants: queryVariants,
|
|
74
|
+
provider_plan: providerPlan,
|
|
75
|
+
sources: deduped,
|
|
76
|
+
leads,
|
|
77
|
+
claims,
|
|
78
|
+
convergence,
|
|
79
|
+
proof,
|
|
80
|
+
synthesis,
|
|
81
|
+
blockers: proof.blockers,
|
|
82
|
+
warnings: proof.warnings,
|
|
83
|
+
cache: {
|
|
84
|
+
key: cache.key,
|
|
85
|
+
hit: false,
|
|
86
|
+
stale: cache.stale,
|
|
87
|
+
ttl_ms: cache.ttl_ms,
|
|
88
|
+
age_ms: cache.age_ms,
|
|
89
|
+
artifact: cache.artifact
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
await writeArtifacts(artifactDir, result);
|
|
93
|
+
await writeJsonAtomic(cache.artifact, result);
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
export function resolveMode(query, explicit, offline = false) {
|
|
97
|
+
if (explicit)
|
|
98
|
+
return explicit;
|
|
99
|
+
if (offline)
|
|
100
|
+
return 'offline_cache';
|
|
101
|
+
if (extractFirstUrl(query))
|
|
102
|
+
return 'url_acquisition';
|
|
103
|
+
if (/\b(?:x\.com|twitter\.com|X\/Twitter|트위터|엑스|site:x\.com|site:twitter\.com)\b/i.test(query))
|
|
104
|
+
return 'x_search';
|
|
105
|
+
if (/(deep research|exhaustive|가능한 전부|누락 없이|완벽하게 조사|due diligence)/i.test(query))
|
|
106
|
+
return 'deep';
|
|
107
|
+
return 'balanced';
|
|
108
|
+
}
|
|
109
|
+
export function classifyIntent(query, mode) {
|
|
110
|
+
if (mode === 'x_search')
|
|
111
|
+
return 'x_specific';
|
|
112
|
+
if (mode === 'url_acquisition')
|
|
113
|
+
return 'known_url_fetch';
|
|
114
|
+
if (/\b(package|npm|SDK|API|MCP|framework|library|docs?|문서|React|Next\.js|Prisma|Tailwind)\b/i.test(query))
|
|
115
|
+
return 'official_documentation';
|
|
116
|
+
if (/\b(error|bug|stack trace|implementation|code|repo|GitHub|테스트|구현)\b/i.test(query))
|
|
117
|
+
return 'code_implementation';
|
|
118
|
+
if (/\b(news|today|latest|최근|오늘|발표)\b/i.test(query))
|
|
119
|
+
return 'news';
|
|
120
|
+
if (/\b(legal|law|policy|규정|법)\b/i.test(query))
|
|
121
|
+
return 'legal_or_policy';
|
|
122
|
+
return 'current_fact';
|
|
123
|
+
}
|
|
124
|
+
export function buildAxes(query, mode, intent) {
|
|
125
|
+
const base = [
|
|
126
|
+
{
|
|
127
|
+
axis_id: 'axis-primary',
|
|
128
|
+
question: `Primary or official evidence for: ${query}`,
|
|
129
|
+
territories: intent === 'official_documentation' ? ['official_docs', 'changelog'] : ['primary_source', 'official_statement'],
|
|
130
|
+
done_when: ['primary source found or explicit blocker recorded', 'date/version checked'],
|
|
131
|
+
priority: 'P0',
|
|
132
|
+
overlap_keys: []
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
axis_id: 'axis-current',
|
|
136
|
+
question: `Current indexed or live evidence for: ${query}`,
|
|
137
|
+
territories: ['web_search', 'freshness', 'source_date'],
|
|
138
|
+
done_when: ['fresh result checked', 'stale evidence warning recorded when needed'],
|
|
139
|
+
priority: 'P0',
|
|
140
|
+
overlap_keys: ['axis-primary']
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
axis_id: 'axis-counter',
|
|
144
|
+
question: `Counter evidence, limitations, or failures for: ${query}`,
|
|
145
|
+
territories: ['counter_search', 'contradictions', 'known_failures'],
|
|
146
|
+
done_when: ['counter query produced evidence or no-source gap recorded'],
|
|
147
|
+
priority: 'P1',
|
|
148
|
+
overlap_keys: []
|
|
149
|
+
}
|
|
150
|
+
];
|
|
151
|
+
if (mode === 'deep' || mode === 'exhaustive') {
|
|
152
|
+
base.push({
|
|
153
|
+
axis_id: 'axis-community',
|
|
154
|
+
question: `Independent implementation or community evidence for: ${query}`,
|
|
155
|
+
territories: ['github', 'issues', 'forums', 'social_discourse'],
|
|
156
|
+
done_when: ['independent domains clustered', 'social-only evidence kept out of primary capability claims'],
|
|
157
|
+
priority: 'P1',
|
|
158
|
+
overlap_keys: ['axis-current']
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (mode === 'x_search') {
|
|
162
|
+
base.push({
|
|
163
|
+
axis_id: 'axis-x-detail',
|
|
164
|
+
question: `Public X post detail and freshness checks for: ${query}`,
|
|
165
|
+
territories: ['x_web_index', 'known_post_detail', 'profile_timeline', 'authenticated_readonly_optional'],
|
|
166
|
+
done_when: ['discovery-only items are not promoted to full evidence', 'auth-required gaps disclosed'],
|
|
167
|
+
priority: 'P0',
|
|
168
|
+
overlap_keys: []
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return base;
|
|
172
|
+
}
|
|
173
|
+
export function buildQueryVariants(query, mode, intent) {
|
|
174
|
+
const clean = query.trim();
|
|
175
|
+
const variants = new Set([clean]);
|
|
176
|
+
if (intent === 'official_documentation')
|
|
177
|
+
variants.add(`${clean} official docs changelog`);
|
|
178
|
+
if (intent === 'code_implementation')
|
|
179
|
+
variants.add(`${clean} GitHub issue fix`);
|
|
180
|
+
variants.add(`${clean} limitations OR failure`);
|
|
181
|
+
if (mode === 'x_search') {
|
|
182
|
+
variants.add(`site:x.com "${clean.replace(/"/g, '')}"`);
|
|
183
|
+
variants.add(`site:twitter.com "${clean.replace(/"/g, '')}"`);
|
|
184
|
+
}
|
|
185
|
+
if (mode === 'deep' || mode === 'exhaustive')
|
|
186
|
+
variants.add(`${clean} counter evidence`);
|
|
187
|
+
return [...variants].slice(0, mode === 'fast' ? 4 : mode === 'exhaustive' ? 12 : 8);
|
|
188
|
+
}
|
|
189
|
+
function planProviders(intent, mode, offline, hasContext7, hasCodexWeb, env = process.env) {
|
|
190
|
+
const selected_capabilities = ['source_normalization', 'claim_ledger', 'citation_graph', 'cache_read_through'];
|
|
191
|
+
const selected_providers = [];
|
|
192
|
+
const blockers = [];
|
|
193
|
+
const warnings = [];
|
|
194
|
+
if (intent === 'official_documentation') {
|
|
195
|
+
selected_capabilities.push('official_docs');
|
|
196
|
+
if (hasContext7)
|
|
197
|
+
selected_providers.push('context7');
|
|
198
|
+
else
|
|
199
|
+
warnings.push('context7_docs_provider_not_bound');
|
|
200
|
+
}
|
|
201
|
+
if (!offline && (hasCodexWeb || env.SKS_CODEX_WEB_SEARCH_AVAILABLE === '1' || env.CODEX_WEB_SEARCH_AVAILABLE === '1')) {
|
|
202
|
+
selected_capabilities.push('web_search');
|
|
203
|
+
selected_providers.push('codex_web');
|
|
204
|
+
}
|
|
205
|
+
else if (!offline) {
|
|
206
|
+
warnings.push('codex_web_search_not_bound_or_unverified');
|
|
207
|
+
}
|
|
208
|
+
if (mode === 'x_search') {
|
|
209
|
+
selected_capabilities.push('social_recency', 'x_public_discovery');
|
|
210
|
+
selected_providers.push('x_public');
|
|
211
|
+
}
|
|
212
|
+
if (offline)
|
|
213
|
+
selected_providers.push('offline_cache');
|
|
214
|
+
return { selected_capabilities, selected_providers: [...new Set(selected_providers)], blockers, warnings };
|
|
215
|
+
}
|
|
216
|
+
function normalizeGenericSourceRows(raw, providerId, family, intent, tier) {
|
|
217
|
+
const rows = Array.isArray(raw) ? raw : Array.isArray(raw?.results) ? raw.results : raw ? [raw] : [];
|
|
218
|
+
return rows.map((row, index) => {
|
|
219
|
+
const url = typeof row.url === 'string' ? row.url : typeof row.link === 'string' ? row.link : null;
|
|
220
|
+
return makeSource({
|
|
221
|
+
providerId,
|
|
222
|
+
family,
|
|
223
|
+
type: intent === 'official_documentation' ? 'official_docs' : 'web_result',
|
|
224
|
+
title: String(row.title || row.name || `${providerId} result ${index + 1}`),
|
|
225
|
+
url,
|
|
226
|
+
snippet: String(row.snippet || row.summary || row.text || ''),
|
|
227
|
+
verdict: providerId === 'context7' ? 'verified_content' : 'weak_content',
|
|
228
|
+
authority: tier,
|
|
229
|
+
primary: providerId === 'context7',
|
|
230
|
+
path: [providerId]
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
function sourceFromWebRow(row, index, intent) {
|
|
235
|
+
return makeSource({
|
|
236
|
+
providerId: 'codex_web',
|
|
237
|
+
family: intent === 'x_specific' ? 'social' : 'web',
|
|
238
|
+
type: 'web_result',
|
|
239
|
+
title: row.title || `Codex Web result ${index + 1}`,
|
|
240
|
+
url: row.url,
|
|
241
|
+
snippet: row.snippet,
|
|
242
|
+
verdict: row.url ? 'weak_content' : 'partial_content',
|
|
243
|
+
authority: classifyAuthority(row.url),
|
|
244
|
+
primary: isOfficialUrl(row.url),
|
|
245
|
+
path: ['codex_web_search']
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
function sourceFromKnownUrl(url, intent) {
|
|
249
|
+
return makeSource({
|
|
250
|
+
providerId: 'direct_url',
|
|
251
|
+
family: intent === 'x_specific' ? 'social' : 'web',
|
|
252
|
+
type: 'known_url',
|
|
253
|
+
title: url,
|
|
254
|
+
url,
|
|
255
|
+
snippet: '',
|
|
256
|
+
verdict: 'weak_content',
|
|
257
|
+
authority: classifyAuthority(url),
|
|
258
|
+
primary: isOfficialUrl(url),
|
|
259
|
+
path: ['url_parse_only']
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
function buildXDiscoverySources(queries, intent) {
|
|
263
|
+
return queries.filter((query) => query.startsWith('site:')).slice(0, 2).map((query, index) => makeSource({
|
|
264
|
+
providerId: 'x_public',
|
|
265
|
+
family: 'social',
|
|
266
|
+
type: 'x_discovery_query',
|
|
267
|
+
title: `X public discovery query ${index + 1}`,
|
|
268
|
+
url: null,
|
|
269
|
+
snippet: query,
|
|
270
|
+
verdict: 'partial_content',
|
|
271
|
+
authority: 'D',
|
|
272
|
+
primary: false,
|
|
273
|
+
path: ['web_index_discovery'],
|
|
274
|
+
warnings: ['discovery_only']
|
|
275
|
+
}));
|
|
276
|
+
}
|
|
277
|
+
function makeSource(opts) {
|
|
278
|
+
const now = nowIso();
|
|
279
|
+
const canonical = opts.url ? canonicalizeUrl(opts.url) : null;
|
|
280
|
+
const domain = canonical ? safeDomain(canonical) : null;
|
|
281
|
+
const content = `${opts.title}\n${opts.snippet}`;
|
|
282
|
+
const verified = opts.verdict === 'verified_content';
|
|
283
|
+
return {
|
|
284
|
+
source_id: `src-${sha256(`${opts.providerId}:${canonical || opts.title}:${opts.snippet}`).slice(0, 12)}`,
|
|
285
|
+
provider_id: opts.providerId,
|
|
286
|
+
source_family: opts.family,
|
|
287
|
+
source_type: opts.type,
|
|
288
|
+
title: opts.title,
|
|
289
|
+
canonical_url: canonical,
|
|
290
|
+
original_url: opts.url,
|
|
291
|
+
domain,
|
|
292
|
+
author: null,
|
|
293
|
+
published_at: null,
|
|
294
|
+
updated_at: null,
|
|
295
|
+
retrieved_at: now,
|
|
296
|
+
language: null,
|
|
297
|
+
snippet: opts.snippet,
|
|
298
|
+
content_artifact: null,
|
|
299
|
+
content_sha256: content.trim() ? sha256(content) : null,
|
|
300
|
+
content_length: content.trim().length || null,
|
|
301
|
+
acquisition_verdict: opts.verdict,
|
|
302
|
+
acquisition_path: opts.path,
|
|
303
|
+
authority_tier: opts.authority,
|
|
304
|
+
freshness_score: 0.5,
|
|
305
|
+
relevance_score: 0.6,
|
|
306
|
+
trust_score: verified ? 0.9 : opts.verdict === 'weak_content' ? 0.55 : 0.35,
|
|
307
|
+
primary_source: opts.primary,
|
|
308
|
+
authenticated_source: false,
|
|
309
|
+
local_only_raw: false,
|
|
310
|
+
duplicate_cluster_id: null,
|
|
311
|
+
independence_cluster_id: domain || opts.providerId,
|
|
312
|
+
warnings: opts.warnings || [],
|
|
313
|
+
blockers: []
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function dedupeSources(sources) {
|
|
317
|
+
const seen = new Map();
|
|
318
|
+
return sources.map((source) => {
|
|
319
|
+
const key = source.canonical_url || source.content_sha256 || source.source_id;
|
|
320
|
+
const cluster = seen.get(key);
|
|
321
|
+
if (cluster)
|
|
322
|
+
return { ...source, duplicate_cluster_id: cluster };
|
|
323
|
+
seen.set(key, source.source_id);
|
|
324
|
+
return { ...source, duplicate_cluster_id: source.source_id };
|
|
325
|
+
}).filter((source) => source.duplicate_cluster_id === source.source_id);
|
|
326
|
+
}
|
|
327
|
+
function buildLeads(sources, mode) {
|
|
328
|
+
if (mode === 'fast')
|
|
329
|
+
return [];
|
|
330
|
+
return sources.filter((source) => source.acquisition_verdict !== 'verified_content').slice(0, 4).map((source, index) => ({
|
|
331
|
+
event_id: `lead-event-${index + 1}`,
|
|
332
|
+
parent_task_id: 'wave-001',
|
|
333
|
+
wave: 1,
|
|
334
|
+
lead_id: `lead-${sha256(source.source_id).slice(0, 10)}`,
|
|
335
|
+
kind: source.blockers.length ? 'dead_end' : 'source',
|
|
336
|
+
summary: `Hydrate or verify ${source.title}`,
|
|
337
|
+
why_it_matters: 'Weak or partial source cannot support final high-risk claims.',
|
|
338
|
+
suggested_query: source.canonical_url || source.title,
|
|
339
|
+
source_ids: [source.source_id],
|
|
340
|
+
priority: source.source_family === 'social' ? 'P1' : 'P0'
|
|
341
|
+
}));
|
|
342
|
+
}
|
|
343
|
+
function buildClaims(query, sources, mode, intent) {
|
|
344
|
+
const verifiedSources = sources.filter((source) => source.acquisition_verdict === 'verified_content');
|
|
345
|
+
const primary = verifiedSources.filter((source) => source.primary_source);
|
|
346
|
+
const domains = [...new Set(verifiedSources.map((source) => source.domain).filter(Boolean))];
|
|
347
|
+
const highRisk = ['legal_or_policy', 'market_or_financial', 'news'].includes(intent);
|
|
348
|
+
const status = highRisk
|
|
349
|
+
? (domains.length >= 2 && primary.length >= 1 ? 'supported' : 'unresolved')
|
|
350
|
+
: verifiedSources.length ? 'supported' : sources.length && mode !== 'x_search' ? 'unresolved' : 'unresolved';
|
|
351
|
+
const sourceIds = status === 'supported' ? verifiedSources.map((source) => source.source_id) : sources.map((source) => source.source_id);
|
|
352
|
+
return [{
|
|
353
|
+
claim_id: `claim-${sha256(query).slice(0, 12)}`,
|
|
354
|
+
text: `Evidence gathered for query: ${query}`,
|
|
355
|
+
claim_type: intent === 'code_implementation' ? 'code_behavior' : intent === 'x_specific' ? 'social_signal' : 'capability',
|
|
356
|
+
risk: highRisk ? 'high' : 'normal',
|
|
357
|
+
source_ids: sourceIds,
|
|
358
|
+
independent_domains: domains,
|
|
359
|
+
primary_source_ids: primary.map((source) => source.source_id),
|
|
360
|
+
counter_search_ids: [],
|
|
361
|
+
verification_artifacts: [],
|
|
362
|
+
status
|
|
363
|
+
}];
|
|
364
|
+
}
|
|
365
|
+
function buildConvergence(mode, leads, blockers) {
|
|
366
|
+
const minimum = mode === 'deep' || mode === 'exhaustive' ? 2 : 1;
|
|
367
|
+
const waves = mode === 'deep' || mode === 'exhaustive' ? 2 : 1;
|
|
368
|
+
const open = leads.filter((lead) => lead.kind !== 'dead_end').length;
|
|
369
|
+
return {
|
|
370
|
+
schema: 'sks.ultra-search-convergence.v1',
|
|
371
|
+
waves_completed: waves,
|
|
372
|
+
minimum_waves_required: minimum,
|
|
373
|
+
new_leads_per_wave: waves === 2 ? [leads.length, 0] : [leads.length],
|
|
374
|
+
unchecked_leads: open,
|
|
375
|
+
consecutive_zero_lead_waves: waves === 2 ? 1 : 0,
|
|
376
|
+
max_depth: mode === 'exhaustive' ? 5 : 3,
|
|
377
|
+
status: blockers.length ? 'blocked_by_source_access' : open ? 'bounded_with_open_leads' : 'converged',
|
|
378
|
+
reason: blockers.length ? 'source_access_blocker_recorded' : open ? 'bounded_runtime_left_weak_sources_as_open_leads' : 'all_leads_closed'
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
function buildProof(mode, intent, sources, claims, convergence, blockers, warnings) {
|
|
382
|
+
const unresolvedHighRisk = claims.filter((claim) => claim.risk === 'high' && claim.status === 'unresolved').length;
|
|
383
|
+
const weakContentFinalClaims = claims.filter((claim) => claim.status === 'supported' && claim.source_ids.some((id) => {
|
|
384
|
+
const source = sources.find((candidate) => candidate.source_id === id);
|
|
385
|
+
return source?.acquisition_verdict === 'weak_content' || source?.acquisition_verdict === 'partial_content';
|
|
386
|
+
})).length;
|
|
387
|
+
const proofBlockers = [...blockers];
|
|
388
|
+
if (unresolvedHighRisk)
|
|
389
|
+
proofBlockers.push('high_risk_claim_unresolved');
|
|
390
|
+
if (weakContentFinalClaims)
|
|
391
|
+
proofBlockers.push('weak_content_used_for_supported_claim');
|
|
392
|
+
if (mode === 'x_search' && sources.every((source) => source.acquisition_verdict !== 'verified_content')) {
|
|
393
|
+
proofBlockers.push('x_search_parity_not_proven');
|
|
394
|
+
}
|
|
395
|
+
return {
|
|
396
|
+
schema: 'sks.ultra-search-proof.v1',
|
|
397
|
+
ok: proofBlockers.length === 0,
|
|
398
|
+
mode,
|
|
399
|
+
intent,
|
|
400
|
+
provider_independent: true,
|
|
401
|
+
xai_runtime_dependency: false,
|
|
402
|
+
snippet_only_final_claims: weakContentFinalClaims,
|
|
403
|
+
weak_content_final_claims: weakContentFinalClaims,
|
|
404
|
+
source_count: sources.length,
|
|
405
|
+
verified_source_count: sources.filter((source) => source.acquisition_verdict === 'verified_content').length,
|
|
406
|
+
claim_count: claims.length,
|
|
407
|
+
unresolved_high_risk_claims: unresolvedHighRisk,
|
|
408
|
+
convergence,
|
|
409
|
+
blockers: [...new Set(proofBlockers)],
|
|
410
|
+
warnings: [...new Set(warnings)]
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
function renderSynthesis(query, sources, claims, proof) {
|
|
414
|
+
const usable = claims.filter((claim) => claim.status === 'verified' || (claim.status === 'supported' && claim.risk !== 'high'));
|
|
415
|
+
return [
|
|
416
|
+
'# UltraSearch Synthesis',
|
|
417
|
+
'',
|
|
418
|
+
`Query: ${query}`,
|
|
419
|
+
`Status: ${proof.ok ? 'usable' : 'blocked_or_partial'}`,
|
|
420
|
+
'',
|
|
421
|
+
`Usable claims: ${usable.length}`,
|
|
422
|
+
`Sources: ${sources.length}`,
|
|
423
|
+
`Verified sources: ${proof.verified_source_count}`,
|
|
424
|
+
'',
|
|
425
|
+
proof.blockers.length ? `Blockers: ${proof.blockers.join(', ')}` : 'Blockers: none'
|
|
426
|
+
].join('\n');
|
|
427
|
+
}
|
|
428
|
+
async function writeArtifacts(artifactDir, result) {
|
|
429
|
+
await writeJsonAtomic(path.join(artifactDir, 'intent.json'), { schema: 'sks.ultra-search-intent.v1', intent: result.intent, mode: result.mode });
|
|
430
|
+
await writeJsonAtomic(path.join(artifactDir, 'axes.json'), { schema: 'sks.ultra-search-axes.v1', axes: result.axes });
|
|
431
|
+
await writeJsonAtomic(path.join(artifactDir, 'query-variants.json'), { schema: 'sks.ultra-search-query-variants.v1', query_variants: result.query_variants });
|
|
432
|
+
await writeJsonAtomic(path.join(artifactDir, 'provider-plan.json'), { schema: 'sks.ultra-search-provider-plan.v1', ...result.provider_plan });
|
|
433
|
+
await writeJsonAtomic(path.join(artifactDir, 'source-ledger.json'), { schema: 'sks.ultra-search-source-ledger.v1', sources: result.sources });
|
|
434
|
+
await writeJsonAtomic(path.join(artifactDir, 'lead-ledger.json'), { schema: 'sks.ultra-search-lead-ledger.v1', leads: result.leads });
|
|
435
|
+
await writeJsonAtomic(path.join(artifactDir, 'claim-ledger.json'), { schema: 'sks.ultra-search-claim-ledger.v1', claims: result.claims });
|
|
436
|
+
await writeJsonAtomic(path.join(artifactDir, 'convergence.json'), result.convergence);
|
|
437
|
+
await writeJsonAtomic(path.join(artifactDir, 'ultra-search-proof.json'), result.proof);
|
|
438
|
+
await writeJsonAtomic(path.join(artifactDir, 'ultra-search-gate.json'), {
|
|
439
|
+
schema: 'sks.ultra-search-gate.v1',
|
|
440
|
+
ok: result.proof.ok,
|
|
441
|
+
replacement_state: result.proof.ok ? 'usable_provider_independent_runtime' : 'replacement_incomplete',
|
|
442
|
+
blockers: result.proof.blockers,
|
|
443
|
+
warnings: result.proof.warnings
|
|
444
|
+
});
|
|
445
|
+
await writeTextAtomic(path.join(artifactDir, 'synthesis.md'), result.synthesis);
|
|
446
|
+
await writeJsonAtomic(path.join(artifactDir, 'ultra-search-result.json'), result);
|
|
447
|
+
}
|
|
448
|
+
async function readCache(artifactDir, query, mode) {
|
|
449
|
+
const key = sha256(JSON.stringify({ query: query.trim().toLowerCase(), mode, adapter: 'ultra-search-runtime-v1' })).slice(0, 16);
|
|
450
|
+
const artifact = path.join(artifactDir, 'cache', `${key}.json`);
|
|
451
|
+
const ttl_ms = mode === 'x_search' ? 2 * 60 * 1000 : mode === 'offline_cache' ? 7 * 24 * 60 * 60 * 1000 : 10 * 60 * 1000;
|
|
452
|
+
const cached = await readJson(artifact, null);
|
|
453
|
+
if (!cached?.generated_at)
|
|
454
|
+
return { key, artifact, ttl_ms, hit: false, stale: false, age_ms: null, result: null };
|
|
455
|
+
const age_ms = Date.now() - Date.parse(cached.generated_at);
|
|
456
|
+
return { key, artifact, ttl_ms, hit: true, stale: age_ms > ttl_ms, age_ms, result: cached };
|
|
457
|
+
}
|
|
458
|
+
function extractFirstUrl(text) {
|
|
459
|
+
return text.match(/https?:\/\/[^\s)"']+/i)?.[0] || null;
|
|
460
|
+
}
|
|
461
|
+
function canonicalizeUrl(raw) {
|
|
462
|
+
try {
|
|
463
|
+
const url = new URL(raw);
|
|
464
|
+
url.hash = '';
|
|
465
|
+
for (const key of [...url.searchParams.keys()]) {
|
|
466
|
+
if (/^(utm_|fbclid|gclid|mc_cid|mc_eid)/i.test(key))
|
|
467
|
+
url.searchParams.delete(key);
|
|
468
|
+
}
|
|
469
|
+
url.hostname = url.hostname.toLowerCase();
|
|
470
|
+
return url.toString();
|
|
471
|
+
}
|
|
472
|
+
catch {
|
|
473
|
+
return raw;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
function safeDomain(raw) {
|
|
477
|
+
try {
|
|
478
|
+
return new URL(raw).hostname.toLowerCase();
|
|
479
|
+
}
|
|
480
|
+
catch {
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
function isOfficialUrl(raw) {
|
|
485
|
+
if (!raw)
|
|
486
|
+
return false;
|
|
487
|
+
const domain = safeDomain(raw);
|
|
488
|
+
return Boolean(domain && /(docs\.|developer|github\.com|npmjs\.com|nodejs\.org|w3\.org|ietf\.org|gov$|\.gov$)/i.test(domain));
|
|
489
|
+
}
|
|
490
|
+
function classifyAuthority(raw) {
|
|
491
|
+
if (!raw)
|
|
492
|
+
return 'E';
|
|
493
|
+
if (isOfficialUrl(raw))
|
|
494
|
+
return 'A0';
|
|
495
|
+
const domain = safeDomain(raw);
|
|
496
|
+
if (domain && /(github\.com|npmjs\.com|arxiv\.org|doi\.org)/i.test(domain))
|
|
497
|
+
return 'A1';
|
|
498
|
+
if (domain && /(x\.com|twitter\.com|reddit\.com|news\.ycombinator\.com)/i.test(domain))
|
|
499
|
+
return 'D';
|
|
500
|
+
return 'C';
|
|
501
|
+
}
|
|
502
|
+
//# sourceMappingURL=runtime.js.map
|
package/dist/core/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '4.
|
|
1
|
+
export const PACKAGE_VERSION = '4.3.0';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// @ts-nocheck
|
|
3
3
|
import { assertGate, emitGate, readText } from './sks-1-18-gate-lib.js';
|
|
4
4
|
const cockpit = readText('src/core/agents/agent-codex-cockpit.ts');
|
|
5
|
-
for (const token of ['source_intelligence_status', '
|
|
5
|
+
for (const token of ['source_intelligence_status', 'ultra_search_status', 'codex_web_search_status', 'goal_mode_status', 'terminal_session_status', 'zellij_attach_command']) {
|
|
6
6
|
assertGate(cockpit.includes(token), `Codex App cockpit missing ${token}`);
|
|
7
7
|
}
|
|
8
8
|
emitGate('agent:visual-consistency', { dashboard_fields: 6 });
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// @ts-nocheck
|
|
3
2
|
import fs from 'node:fs';
|
|
4
3
|
import path from 'node:path';
|
|
5
4
|
import { spawnSync } from 'node:child_process';
|
|
6
5
|
const root = process.cwd();
|
|
7
6
|
const failures = [];
|
|
8
7
|
const waivers = loadWaivers();
|
|
8
|
+
const changedFiles = changedFileSet();
|
|
9
9
|
runGate('pipeline-budget:check');
|
|
10
10
|
runGate('pipeline-runtime:check');
|
|
11
11
|
checkFacade('src/core/pipeline-runtime.ts', 300);
|
|
@@ -44,10 +44,16 @@ function checkLargeFiles() {
|
|
|
44
44
|
if (isWaivedGenerated(relPath))
|
|
45
45
|
continue;
|
|
46
46
|
const max = architectureLineLimit(relPath);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
const baselineLines = changedFiles.has(relPath) ? baseLineCount(relPath) : lines;
|
|
48
|
+
if (lines >= 3000)
|
|
49
|
+
failures.push(`${relPath}: handwritten file ${lines} lines >= 3000 split-review risk`);
|
|
50
|
+
if (baselineLines === null && lines > 400)
|
|
51
|
+
failures.push(`${relPath}: new source file ${lines} lines > 400`);
|
|
52
|
+
if (changedFiles.has(relPath) && lines > max && (baselineLines === null || lines - baselineLines > 80)) {
|
|
53
|
+
failures.push(`${relPath}: changed file grew to ${lines} lines > ${max} architecture gate`);
|
|
54
|
+
}
|
|
55
|
+
if (changedFiles.has(relPath) && !isRouteDomainAggregator(relPath) && importsUnrelatedRouteDomains(file))
|
|
56
|
+
failures.push(`${relPath}: changed file imports 5+ unrelated route domains`);
|
|
51
57
|
}
|
|
52
58
|
}
|
|
53
59
|
function architectureLineLimit(relPath) {
|
|
@@ -79,8 +85,11 @@ function importSpecs(text) {
|
|
|
79
85
|
const specs = [];
|
|
80
86
|
const re = /^\s*import\s+(?:[^'"]*?\s+from\s+)?['"]([^'"]+)['"]/gm;
|
|
81
87
|
let match;
|
|
82
|
-
while ((match = re.exec(text)))
|
|
83
|
-
|
|
88
|
+
while ((match = re.exec(text))) {
|
|
89
|
+
const spec = match[1];
|
|
90
|
+
if (spec)
|
|
91
|
+
specs.push(spec);
|
|
92
|
+
}
|
|
84
93
|
return specs;
|
|
85
94
|
}
|
|
86
95
|
function walk(dir, out) {
|
|
@@ -132,4 +141,28 @@ function isWaivedGenerated(relPath) {
|
|
|
132
141
|
&& waiver.reason === 'generated'
|
|
133
142
|
&& waiver.expires_version);
|
|
134
143
|
}
|
|
144
|
+
function changedFileSet() {
|
|
145
|
+
const out = new Set();
|
|
146
|
+
for (const line of gitLines(['diff', '--name-only', 'HEAD', '--']))
|
|
147
|
+
out.add(normalize(line));
|
|
148
|
+
for (const line of gitLines(['ls-files', '--others', '--exclude-standard']))
|
|
149
|
+
out.add(normalize(line));
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
152
|
+
function baseLineCount(relPath) {
|
|
153
|
+
const result = spawnSync('git', ['show', `HEAD:${relPath}`], { cwd: root, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 });
|
|
154
|
+
if (result.status !== 0)
|
|
155
|
+
return null;
|
|
156
|
+
const text = String(result.stdout || '');
|
|
157
|
+
return text ? text.split(/\r?\n/).length : 0;
|
|
158
|
+
}
|
|
159
|
+
function gitLines(args) {
|
|
160
|
+
const result = spawnSync('git', args, { cwd: root, encoding: 'utf8' });
|
|
161
|
+
if (result.status !== 0)
|
|
162
|
+
return [];
|
|
163
|
+
return String(result.stdout || '').split(/\r?\n/).map(normalize).filter(Boolean);
|
|
164
|
+
}
|
|
165
|
+
function normalize(file) {
|
|
166
|
+
return String(file || '').replace(/\\/g, '/');
|
|
167
|
+
}
|
|
135
168
|
//# sourceMappingURL=check-architecture.js.map
|
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// @ts-nocheck
|
|
3
2
|
import fs from 'node:fs';
|
|
4
3
|
import path from 'node:path';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
5
|
const root = process.cwd();
|
|
6
6
|
const dir = path.join(root, 'src', 'core', 'commands');
|
|
7
7
|
const failures = [];
|
|
8
|
+
const changedFiles = changedFileSet();
|
|
8
9
|
for (const file of fs.readdirSync(dir).filter((name) => name.endsWith('-command.ts'))) {
|
|
9
10
|
const absolute = path.join(dir, file);
|
|
11
|
+
const relPath = rel(absolute);
|
|
10
12
|
const text = fs.readFileSync(absolute, 'utf8');
|
|
11
13
|
const lines = text.split(/\r?\n/).length;
|
|
12
14
|
const imports = [...text.matchAll(/^\s*import\s+/gm)].length;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (
|
|
16
|
-
failures.push(`${file}:
|
|
15
|
+
const changed = changedFiles.has(relPath);
|
|
16
|
+
const baselineLines = baseLineCount(relPath);
|
|
17
|
+
if (lines > 1800)
|
|
18
|
+
failures.push(`${file}: line count ${lines} > 1800 hard ceiling`);
|
|
19
|
+
if (baselineLines === null && lines > 400)
|
|
20
|
+
failures.push(`${file}: new command module ${lines} lines > 400`);
|
|
21
|
+
if (changed && lines > 1200 && (baselineLines === null || lines - baselineLines > 50)) {
|
|
22
|
+
failures.push(`${file}: changed command module grew to ${lines} lines > 1200`);
|
|
23
|
+
}
|
|
24
|
+
if (imports > 60)
|
|
25
|
+
failures.push(`${file}: import count ${imports} > 60 hard ceiling`);
|
|
26
|
+
if (changed && imports > 35)
|
|
27
|
+
failures.push(`${file}: changed command module import count ${imports} > 35`);
|
|
17
28
|
}
|
|
18
29
|
if (failures.length) {
|
|
19
30
|
console.error('Command module budget check failed:');
|
|
@@ -22,4 +33,31 @@ if (failures.length) {
|
|
|
22
33
|
process.exit(1);
|
|
23
34
|
}
|
|
24
35
|
console.log('Command module budget check passed');
|
|
36
|
+
function changedFileSet() {
|
|
37
|
+
const out = new Set();
|
|
38
|
+
for (const line of gitLines(['diff', '--name-only', 'HEAD', '--']))
|
|
39
|
+
out.add(normalize(line));
|
|
40
|
+
for (const line of gitLines(['ls-files', '--others', '--exclude-standard']))
|
|
41
|
+
out.add(normalize(line));
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
function baseLineCount(relPath) {
|
|
45
|
+
const result = spawnSync('git', ['show', `HEAD:${relPath}`], { cwd: root, encoding: 'utf8', maxBuffer: 8 * 1024 * 1024 });
|
|
46
|
+
if (result.status !== 0)
|
|
47
|
+
return null;
|
|
48
|
+
const text = String(result.stdout || '');
|
|
49
|
+
return text ? text.split(/\r?\n/).length : 0;
|
|
50
|
+
}
|
|
51
|
+
function gitLines(args) {
|
|
52
|
+
const result = spawnSync('git', args, { cwd: root, encoding: 'utf8' });
|
|
53
|
+
if (result.status !== 0)
|
|
54
|
+
return [];
|
|
55
|
+
return String(result.stdout || '').split(/\r?\n/).map(normalize).filter(Boolean);
|
|
56
|
+
}
|
|
57
|
+
function rel(file) {
|
|
58
|
+
return normalize(path.relative(root, file));
|
|
59
|
+
}
|
|
60
|
+
function normalize(file) {
|
|
61
|
+
return String(file || '').replace(/\\/g, '/');
|
|
62
|
+
}
|
|
25
63
|
//# sourceMappingURL=check-command-module-budget.js.map
|