sneakoscope 6.1.0 → 6.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 +35 -11
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/bin/fast-inline.js +18 -9
- package/dist/bin/sks-dispatch.js +2 -2
- package/dist/cli/args.js +2 -0
- package/dist/cli/command-manifest-lite.js +2 -3
- package/dist/cli/command-registry.js +3 -4
- package/dist/cli/help-fast.js +1 -1
- package/dist/cli/install-helpers.js +116 -306
- package/dist/cli/install-tool-helpers.js +287 -0
- package/dist/cli/router.js +40 -4
- package/dist/commands/codex-lb.js +51 -20
- package/dist/commands/codex.js +39 -1
- package/dist/commands/doctor.js +242 -20
- package/dist/commands/tmux.js +5 -1
- package/dist/commands/zellij-monitor-pane.js +2 -0
- package/dist/commands/zellij-viewport-pane.js +3 -1
- package/dist/commands/zellij.js +1 -1
- package/dist/config/skills-manifest.json +59 -59
- package/dist/core/agent-bridge/agent-manifest.js +48 -0
- package/dist/core/agents/agent-command-surface.js +2 -1
- package/dist/core/agents/agent-effort-policy.js +38 -35
- package/dist/core/agents/agent-plan.js +100 -21
- package/dist/core/agents/agent-role-config.js +43 -46
- package/dist/core/agents/agent-runner-codex-exec.js +16 -3
- package/dist/core/agents/agent-schema.js +3 -2
- package/dist/core/agents/native-cli-session-swarm.js +1 -1
- package/dist/core/agents/zellij-right-lane-cockpit.js +2 -2
- package/dist/core/codex/agent-config-file-repair.js +94 -193
- package/dist/core/codex/codex-cli-update.js +723 -0
- package/dist/core/codex/codex-config-guard.js +185 -9
- package/dist/core/codex/codex-config-readability.js +21 -8
- package/dist/core/codex/codex-config-toml.js +14 -11
- package/dist/core/codex/codex-project-config-policy.js +3 -6
- package/dist/core/codex/codex-startup-config-postcheck.js +52 -42
- package/dist/core/codex-adapter.js +35 -22
- package/dist/core/codex-app/codex-agent-role-sync.js +13 -54
- package/dist/core/codex-app/codex-app-launcher.js +48 -17
- package/dist/core/codex-app/codex-app-restart.js +23 -2
- package/dist/core/codex-app/mcp-manager.js +679 -0
- package/dist/core/codex-app/sks-menubar.js +533 -8
- package/dist/core/codex-control/codex-0139-image-path-real-probe.js +15 -4
- package/dist/core/codex-control/codex-0139-web-search-probe.js +17 -6
- package/dist/core/codex-control/codex-lb-launch-recovery.js +293 -0
- package/dist/core/codex-control/codex-reliability-shield.js +89 -29
- package/dist/core/codex-control/codex-sdk-adapter.js +44 -8
- package/dist/core/codex-control/codex-task-runner.js +62 -9
- package/dist/core/codex-control/python-codex-sdk-adapter.js +30 -3
- package/dist/core/codex-exec-output-schema.js +35 -6
- package/dist/core/codex-lb/codex-lb-env.js +1 -1
- package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +291 -0
- package/dist/core/codex-native/codex-native-feature-broker.js +9 -16
- package/dist/core/codex-native/codex-native-repair-transaction.js +1 -1
- package/dist/core/codex-native/core-skill-manifest.js +8 -4
- package/dist/core/codex-runtime/codex-desktop-config-policy.js +2 -3
- package/dist/core/commands/agent-bridge-command.js +23 -2
- package/dist/core/commands/agent-command.js +19 -5
- package/dist/core/commands/basic-cli.js +47 -6
- package/dist/core/commands/command-utils.js +1 -1
- package/dist/core/commands/mad-sks-command.js +76 -10
- package/dist/core/commands/menubar-command.js +94 -0
- package/dist/core/commands/naruto-command.js +645 -1156
- package/dist/core/commands/research-command.js +293 -231
- package/dist/core/commands/run-command.js +100 -23
- package/dist/core/commands/team-command.js +2 -3
- package/dist/core/commands/team-legacy-observe-command.js +94 -359
- package/dist/core/commands/wiki-command.js +11 -5
- package/dist/core/db-safety.js +2 -2
- package/dist/core/decision-lattice.js +6 -6
- package/dist/core/doctor/codex-startup-config-repair.js +8 -3
- package/dist/core/doctor/doctor-codex-startup-repair.js +6 -141
- package/dist/core/feature-fixture-executor.js +71 -7
- package/dist/core/feature-fixture-runner.js +53 -12
- package/dist/core/feature-fixtures.js +47 -14
- package/dist/core/feature-registry.js +28 -27
- package/dist/core/fsx.js +1 -0
- package/dist/core/harness-conflicts.js +18 -9
- package/dist/core/hooks-runtime/code-pack-freshness-preflight.js +14 -8
- package/dist/core/hooks-runtime/hook-io.js +8 -4
- package/dist/core/hooks-runtime/light-turn.js +70 -0
- package/dist/core/hooks-runtime/naruto-decision-gate.js +184 -0
- package/dist/core/hooks-runtime/payload-signals.js +270 -0
- package/dist/core/hooks-runtime/stop-repeat-guard.js +89 -0
- package/dist/core/hooks-runtime/team-digest.js +0 -1
- package/dist/core/hooks-runtime/tool-output-quarantine.js +93 -0
- package/dist/core/hooks-runtime.js +438 -354
- package/dist/core/init/skills.js +16 -30
- package/dist/core/init.js +144 -36
- package/dist/core/managed-assets/managed-assets-manifest.js +566 -10
- package/dist/core/mission.js +24 -1
- package/dist/core/pipeline-internals/runtime-core.js +570 -177
- package/dist/core/pipeline-internals/runtime-gates.js +174 -48
- package/dist/core/preflight/parallel-preflight-engine.js +66 -4
- package/dist/core/proof/route-adapter.js +1 -1
- package/dist/core/proof/route-proof-gate.js +7 -2
- package/dist/core/proof/selftest-proof-fixtures.js +3 -5
- package/dist/core/proof-field.js +1 -1
- package/dist/core/provider/model-router.js +42 -31
- package/dist/core/recallpulse/policy.js +12 -28
- package/dist/core/recallpulse.js +11 -6
- package/dist/core/release/npm-pack-proof.js +247 -0
- package/dist/core/release/package-dist-snapshot.js +151 -0
- package/dist/core/release/package-size-budget.js +4 -1
- package/dist/core/release/release-authorization-snapshot.js +115 -0
- package/dist/core/release/release-gate-affected-selector.js +14 -2
- package/dist/core/release/release-gate-cache-v2.js +30 -0
- package/dist/core/release/release-gate-contract.js +161 -0
- package/dist/core/release/release-gate-dag.js +1 -0
- package/dist/core/release/release-real-contract.js +90 -10
- package/dist/core/release-parallel-full-coverage.js +31 -143
- package/dist/core/research/claim-evidence-matrix.js +41 -6
- package/dist/core/research/experiment-plan.js +14 -10
- package/dist/core/research/falsification.js +9 -2
- package/dist/core/research/implementation-blueprint-densifier.js +82 -60
- package/dist/core/research/implementation-blueprint.js +32 -26
- package/dist/core/research/mock-result.js +122 -11
- package/dist/core/research/replication-pack.js +15 -8
- package/dist/core/research/research-adversarial-review.js +1068 -0
- package/dist/core/research/research-claim-builder.js +69 -17
- package/dist/core/research/research-claim-synthesizer.js +343 -0
- package/dist/core/research/research-cycle-runner.js +53 -3
- package/dist/core/research/research-falsification-runner.js +176 -0
- package/dist/core/research/research-final-reviewer.js +44 -125
- package/dist/core/research/research-plan-markdown.js +123 -0
- package/dist/core/research/research-realistic-report.js +14 -6
- package/dist/core/research/research-review-artifact-digest.js +66 -0
- package/dist/core/research/research-source-evidence.js +144 -0
- package/dist/core/research/research-source-layer-catalog.js +68 -0
- package/dist/core/research/research-source-ledger-merge.js +250 -12
- package/dist/core/research/research-source-shards.js +26 -70
- package/dist/core/research/research-stage-runner.js +237 -247
- package/dist/core/research/research-super-search.js +188 -0
- package/dist/core/research/research-synthesis-prompt.js +20 -1
- package/dist/core/research/research-synthesis-writer.js +86 -5
- package/dist/core/research/research-work-graph.js +25 -18
- package/dist/core/research/source-quality-report.js +21 -0
- package/dist/core/research.js +424 -390
- package/dist/core/retention.js +70 -2
- package/dist/core/routes/constants.js +1 -1
- package/dist/core/routes/dollar-manifest-lite.js +11 -11
- package/dist/core/routes.js +149 -69
- package/dist/core/runtime/task-profile.js +66 -0
- package/dist/core/runtime/verification-budget.js +12 -0
- package/dist/core/security/high-risk-contracts.js +6 -6
- package/dist/core/stop-gate/stop-gate-check.js +49 -12
- package/dist/core/subagents/agent-catalog.js +287 -0
- package/dist/core/subagents/model-policy.js +259 -0
- package/dist/core/subagents/naruto-help-contract.js +47 -0
- package/dist/core/subagents/official-subagent-config.js +488 -0
- package/dist/core/subagents/official-subagent-preparation.js +297 -0
- package/dist/core/subagents/official-subagent-prompt.js +159 -0
- package/dist/core/subagents/official-subagent-runner.js +129 -0
- package/dist/core/subagents/subagent-evidence.js +663 -0
- package/dist/core/subagents/terminology.js +16 -0
- package/dist/core/subagents/thread-budget.js +21 -0
- package/dist/core/subagents/triwiki-attention.js +168 -0
- package/dist/core/super-search/runtime-helpers.js +173 -19
- package/dist/core/super-search/runtime.js +140 -15
- package/dist/core/super-search/source-records.js +49 -8
- package/dist/core/team-review-policy.js +15 -0
- package/dist/core/triwiki/code-pack-head-freshness.js +291 -0
- package/dist/core/triwiki/triwiki-module-card.js +1 -1
- package/dist/core/triwiki-wrongness/wrongness-ledger.js +9 -2
- package/dist/core/version-manager.js +51 -1
- package/dist/core/version.js +1 -1
- package/dist/core/work-order-ledger.js +40 -1
- package/dist/core/zellij/zellij-fake-adapter.js +3 -1
- package/dist/core/zellij/zellij-launcher.js +49 -10
- package/dist/core/zellij/zellij-layout-builder.js +14 -5
- package/dist/core/zellij/zellij-official-subagent-activity.js +477 -0
- package/dist/core/zellij/zellij-official-subagent-telemetry.js +264 -0
- package/dist/core/zellij/zellij-pane-proof.js +9 -1
- package/dist/core/zellij/zellij-slot-pane-renderer.js +17 -5
- package/dist/core/zellij/zellij-slot-telemetry.js +15 -3
- package/dist/core/zellij/zellij-ui-mode.js +1 -1
- package/dist/core/zellij/zellij-update.js +14 -1
- package/dist/core/zellij/zellij-viewport-binder.js +3 -0
- package/dist/scripts/agent-role-config-repair-check.js +14 -16
- package/dist/scripts/architecture-guard-check.js +8 -1
- package/dist/scripts/canonical-test-runner.js +7 -1
- package/dist/scripts/check-route-modularity.js +0 -1
- package/dist/scripts/check-ts-contracts.js +1 -1
- package/dist/scripts/codex-control-all-pipelines-check.js +7 -3
- package/dist/scripts/codex-control-tool-output-continuity-audit-check.js +27 -0
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +11 -1
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +9 -2
- package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +13 -2
- package/dist/scripts/codex-native-agent-role-content-check.js +27 -7
- package/dist/scripts/codex-native-repair-transaction-check.js +3 -1
- package/dist/scripts/codex-sdk-all-pipelines-check.js +7 -4
- package/dist/scripts/codex-sdk-backend-router-check.js +2 -0
- package/dist/scripts/codex-sdk-research-pipeline-check.js +30 -8
- package/dist/scripts/db-route-materialization-check.js +33 -0
- package/dist/scripts/docs-truthfulness-check.js +3 -1
- package/dist/scripts/doctor-codex-startup-repair-check.js +12 -15
- package/dist/scripts/doctor-fix-production-blackbox.js +12 -2
- package/dist/scripts/doctor-startup-config-repair-blackbox.js +8 -2
- package/dist/scripts/doctor-startup-config-repair-check.js +12 -2
- package/dist/scripts/install-update-preserves-config-check.js +6 -1
- package/dist/scripts/lib/codex-sdk-gate-lib.js +4 -0
- package/dist/scripts/mad-sks-app-ui-no-mutation-check.js +0 -1
- package/dist/scripts/managed-role-manifest-parity-check.js +5 -4
- package/dist/scripts/naruto-codex-e2e-check.js +14 -7
- package/dist/scripts/naruto-shadow-clone-swarm-check.js +4 -201
- package/dist/scripts/npm-publish-performance-check.js +20 -12
- package/dist/scripts/official-subagent-workflow-check.js +145 -0
- package/dist/scripts/package-published-contract-check.js +6 -29
- package/dist/scripts/packlist-performance-check.js +18 -21
- package/dist/scripts/parallel-verification-engine-check.js +2 -2
- package/dist/scripts/prepublish-release-check-or-fast.js +23 -86
- package/dist/scripts/python-codex-sdk-all-pipelines-check.js +8 -0
- package/dist/scripts/release-affected-selector-check.js +74 -1
- package/dist/scripts/release-check-stamp.js +153 -248
- package/dist/scripts/release-dag-full-coverage-check.js +7 -15
- package/dist/scripts/release-dynamic-presets-check.js +2 -1
- package/dist/scripts/release-gate-dag-runner-check.js +0 -1
- package/dist/scripts/release-gate-dag-runner.js +12 -1
- package/dist/scripts/release-gate-existence-audit.js +1 -2
- package/dist/scripts/release-parallel-full-coverage-check.js +12 -6
- package/dist/scripts/release-parallel-speed-budget-check.js +18 -2
- package/dist/scripts/release-real-check.js +26 -4
- package/dist/scripts/release-registry-check.js +61 -16
- package/dist/scripts/research-blueprint-densifier-check.js +2 -2
- package/dist/scripts/research-real-cycle-no-legacy-final-md-check.js +11 -7
- package/dist/scripts/sizecheck.js +2 -2
- package/dist/scripts/sks-3-1-4-directive-check-lib.js +8 -2
- package/dist/scripts/sks-3-1-5-directive-check-lib.js +3 -2
- package/dist/scripts/sks-3-1-6-directive-check-lib.js +5 -3
- package/dist/scripts/sks-menubar-install-check.js +14 -1
- package/dist/scripts/super-search-provider-interface-check.js +31 -18
- package/dist/scripts/trust-fixture-check.js +32 -10
- package/dist/scripts/wrongness-fixture-check.js +1 -1
- package/dist/scripts/zellij-layout-valid-check.js +5 -5
- package/dist/scripts/zellij-spawn-on-demand-layout-check.js +3 -3
- package/docs/demo.tape +1 -1
- package/infra-harness-gates.json +1486 -0
- package/package.json +15 -10
- package/release-gates.v2.json +4060 -0
- package/runtime-required-scripts.json +9 -0
- package/dist/commands/db.js +0 -6
- package/dist/core/commands/db-command.js +0 -146
- package/dist/core/research/prompt.js +0 -15
- package/dist/scripts/codex-0139-feature-probes-check.js +0 -30
- package/dist/scripts/codex-0139-marketplace-source-check.js +0 -13
- package/dist/scripts/codex-control-tool-call-sequence-repair-check.js +0 -14
|
@@ -48,7 +48,7 @@ export const RECALLPULSE_POLICY = Object.freeze({
|
|
|
48
48
|
'generated_skill_installation',
|
|
49
49
|
'codex_app_stop_hooks',
|
|
50
50
|
'dfix_ultralight_behavior',
|
|
51
|
-
'
|
|
51
|
+
'official_subagent_risk_scoped_review_with_legacy_team_compatibility',
|
|
52
52
|
'research_xhigh_agent_requirements',
|
|
53
53
|
'db_destructive_operation_blocking',
|
|
54
54
|
'imagegen_evidence_requirements'
|
|
@@ -176,37 +176,19 @@ export const RESEARCH_AGENT_PERSONA_CONTRACT = Object.freeze([
|
|
|
176
176
|
id: 'einstein',
|
|
177
177
|
display_name: 'Einstein Agent',
|
|
178
178
|
historical_inspiration: 'Albert Einstein',
|
|
179
|
-
persona: 'first-principles reframer',
|
|
180
|
-
role: '
|
|
181
|
-
mandate: 'Strip assumptions, identify invariants, and build decisive thought experiments.',
|
|
182
|
-
required_outputs: ['eureka_moment', 'assumptions_removed', 'invariant_or_simplifying_frame', 'decisive_thought_experiment']
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
id: 'feynman',
|
|
186
|
-
display_name: 'Feynman Agent',
|
|
187
|
-
historical_inspiration: 'Richard Feynman',
|
|
188
|
-
persona: 'explanation experimentalist',
|
|
189
|
-
role: 'explanation_experimentalist',
|
|
190
|
-
mandate: 'Make the idea teachable, testable, and hard to hide behind jargon.',
|
|
191
|
-
required_outputs: ['eureka_moment', 'plain_language_mechanism', 'toy_model', 'cheap_empirical_probe']
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
id: 'turing',
|
|
195
|
-
display_name: 'Turing Agent',
|
|
196
|
-
historical_inspiration: 'Alan Turing',
|
|
197
|
-
persona: 'formalization and adversarial cases',
|
|
198
|
-
role: 'formalization_and_adversarial_cases',
|
|
199
|
-
mandate: 'Formalize inputs, outputs, algorithms, limits, and countercases.',
|
|
200
|
-
required_outputs: ['eureka_moment', 'formal_definition', 'algorithmic_shape', 'adversarial_case']
|
|
179
|
+
persona: 'first-principles reframer and explanation experimentalist',
|
|
180
|
+
role: 'first_principles_experimental_reframer',
|
|
181
|
+
mandate: 'Strip assumptions, identify invariants, explain the mechanism plainly, and build decisive thought experiments and cheap probes.',
|
|
182
|
+
required_outputs: ['eureka_moment', 'assumptions_removed', 'invariant_or_simplifying_frame', 'plain_language_mechanism', 'decisive_thought_experiment', 'cheap_empirical_probe']
|
|
201
183
|
},
|
|
202
184
|
{
|
|
203
185
|
id: 'von_neumann',
|
|
204
186
|
display_name: 'von Neumann Agent',
|
|
205
187
|
historical_inspiration: 'John von Neumann',
|
|
206
|
-
persona: 'systems strategy agent',
|
|
207
|
-
role: '
|
|
208
|
-
mandate: '
|
|
209
|
-
required_outputs: ['eureka_moment', 'system_model', 'scaling_risk', 'robustness_condition']
|
|
188
|
+
persona: 'formal systems and strategy agent',
|
|
189
|
+
role: 'formal_systems_strategy_agent',
|
|
190
|
+
mandate: 'Formalize inputs, outputs, algorithms, limits, system dynamics, scaling behavior, incentives, and worst-case interactions.',
|
|
191
|
+
required_outputs: ['eureka_moment', 'formal_definition', 'algorithmic_shape', 'adversarial_case', 'system_model', 'scaling_risk', 'robustness_condition']
|
|
210
192
|
},
|
|
211
193
|
{
|
|
212
194
|
id: 'skeptic',
|
|
@@ -220,7 +202,9 @@ export const RESEARCH_AGENT_PERSONA_CONTRACT = Object.freeze([
|
|
|
220
202
|
].map((agent) => Object.freeze({
|
|
221
203
|
...agent,
|
|
222
204
|
persona_boundary: 'persona-inspired cognitive lens only; do not impersonate the historical person',
|
|
223
|
-
|
|
205
|
+
custom_agent: 'research_reviewer',
|
|
206
|
+
model: 'gpt-5.6-sol',
|
|
207
|
+
reasoning_effort: 'max',
|
|
224
208
|
service_tier: 'fast'
|
|
225
209
|
})));
|
|
226
210
|
//# sourceMappingURL=policy.js.map
|
package/dist/core/recallpulse.js
CHANGED
|
@@ -199,7 +199,7 @@ export async function evaluateRecallPulseFixtures(root, opts = {}) {
|
|
|
199
199
|
fixture('repeated-stop-hook-blocker', true, 'Duplicate suppression keys collapse repeated blocker text into one durable status row.'),
|
|
200
200
|
fixture('hook-only-status-visibility', true, 'mission-status-ledger.json preserves recoverable user-visible status.'),
|
|
201
201
|
fixture('research-persona-missing', true, 'Research validation blocks missing agent display_name/persona/persona_boundary.'),
|
|
202
|
-
fixture('research-
|
|
202
|
+
fixture('research-model-policy-not-sol-max', true, 'Research validation blocks reviewer rows that are not bound to the research_reviewer GPT-5.6 Sol Max policy.'),
|
|
203
203
|
fixture('research-eureka-missing', true, 'Research validation blocks missing literal Eureka! ideas.'),
|
|
204
204
|
fixture('research-impersonation', true, 'Research validation blocks persona-boundary violations.'),
|
|
205
205
|
fixture('oversized-l1', true, 'L1 token and item limits reject oversized active recall.'),
|
|
@@ -368,7 +368,7 @@ export async function buildRecallPulseGovernanceReport(root, opts = {}) {
|
|
|
368
368
|
],
|
|
369
369
|
migration_paths: {
|
|
370
370
|
existing_missions: 'Run sks recallpulse run <mission-id> and sks recallpulse governance <mission-id> to add report-only artifacts.',
|
|
371
|
-
existing_research_artifacts: 'Research gates
|
|
371
|
+
existing_research_artifacts: 'Research gates require agent display_name/persona/persona_boundary fields and the research_reviewer GPT-5.6 Sol Max binding; old ledgers must be migrated before claiming pass.',
|
|
372
372
|
generated_skills: 'Do not edit generated installed skills directly; rerun init/bootstrap from engine source when generated text needs refreshing.'
|
|
373
373
|
},
|
|
374
374
|
release_gate: '0.8.0 remains report-only unless packcheck, selftest, sizecheck, registry metadata check, TriWiki validate, and RecallPulse fixture eval pass.'
|
|
@@ -397,8 +397,13 @@ export function validateResearchAgentPersonas(agentLedger = {}, geniusSummaryTex
|
|
|
397
397
|
issues.push(`${expected.id}:persona_boundary_missing`);
|
|
398
398
|
if (row.persona_boundary && !/do not impersonate|not impersonat|lens only/i.test(row.persona_boundary))
|
|
399
399
|
issues.push(`${expected.id}:persona_boundary_not_enforced`);
|
|
400
|
-
|
|
401
|
-
|
|
400
|
+
const modelPolicy = row.model_policy && typeof row.model_policy === 'object' ? row.model_policy : row;
|
|
401
|
+
if (modelPolicy.custom_agent !== 'research_reviewer')
|
|
402
|
+
issues.push(`${expected.id}:custom_agent_not_research_reviewer`);
|
|
403
|
+
if (modelPolicy.model !== 'gpt-5.6-sol')
|
|
404
|
+
issues.push(`${expected.id}:model_not_sol`);
|
|
405
|
+
if (modelPolicy.reasoning_effort !== 'max' && modelPolicy.model_reasoning_effort !== 'max')
|
|
406
|
+
issues.push(`${expected.id}:effort_not_max`);
|
|
402
407
|
if (row.service_tier && row.service_tier !== 'fast')
|
|
403
408
|
issues.push(`${expected.id}:service_tier_not_fast`);
|
|
404
409
|
if (!row.eureka?.idea || row.eureka?.exclamation !== 'Eureka!')
|
|
@@ -923,13 +928,13 @@ function preservedRoutePersonality(routeId = '', routeName = '') {
|
|
|
923
928
|
DFix: 'ultralight direct-fix path stays tiny and does not start the full pipeline',
|
|
924
929
|
Answer: 'answer-only path stays conversational and does not start implementation',
|
|
925
930
|
SKS: 'general SKS discovery/help personality stays simple',
|
|
926
|
-
Team: 'Team
|
|
931
|
+
Team: 'Team redirects to the bounded official Naruto workflow with parent-owned integration and risk-scoped review',
|
|
927
932
|
QALoop: 'QA-LOOP keeps dogfood, checklist, remediation, and reverification identity',
|
|
928
933
|
PPT: 'PPT keeps restrained information-first HTML/PDF delivery identity',
|
|
929
934
|
ImageUXReview: 'Image UX Review keeps gpt-image-2 annotated raster review identity',
|
|
930
935
|
ComputerUse: 'Computer Use keeps maximum-speed native Mac/non-web visual lane identity',
|
|
931
936
|
Goal: 'Goal stays a native /goal persistence bridge, not a heavyweight route',
|
|
932
|
-
Research: 'Research keeps
|
|
937
|
+
Research: 'Research keeps Super Search evidence, three composite Sol Max adversarial lenses, bounded revision, paper, and falsification identity',
|
|
933
938
|
AutoResearch: 'AutoResearch keeps iterative experiment loop identity',
|
|
934
939
|
DB: 'DB keeps conservative read-first destructive-operation safety identity',
|
|
935
940
|
MadSKS: 'MAD-SKS keeps explicit scoped high-risk authorization identity',
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
export const NPM_PACK_PROOF_SCHEMA = 'sks.npm-pack-proof.v1';
|
|
5
|
+
export const NPM_PACK_PROOF_COMMAND = Object.freeze(['npm', 'pack', '--dry-run', '--ignore-scripts', '--json']);
|
|
6
|
+
export const PACKLIST_PERFORMANCE_REPORT_SCHEMA = 'sks.packlist-performance.v1';
|
|
7
|
+
export const PACKAGE_SURFACE_BUDGET_REPORT_SCHEMA = 'sks.package-surface-budget.v1';
|
|
8
|
+
export function npmPackProofPath(root) {
|
|
9
|
+
return path.join(root, '.sneakoscope', 'reports', 'npm-pack-proof.json');
|
|
10
|
+
}
|
|
11
|
+
export function writeNpmPackProof(root, info, packMs) {
|
|
12
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
13
|
+
const inputDigest = currentNpmPackInputDigest(root);
|
|
14
|
+
const normalizedInfo = normalizeNpmPackInfo(info);
|
|
15
|
+
const infoDigest = sha256Json(normalizedInfo);
|
|
16
|
+
const fileListDigest = sha256Json(normalizedInfo.files);
|
|
17
|
+
const proof = {
|
|
18
|
+
schema: NPM_PACK_PROOF_SCHEMA,
|
|
19
|
+
ok: true,
|
|
20
|
+
generated_at: new Date().toISOString(),
|
|
21
|
+
command: NPM_PACK_PROOF_COMMAND,
|
|
22
|
+
input_digest: inputDigest,
|
|
23
|
+
info_digest: infoDigest,
|
|
24
|
+
file_list_digest: fileListDigest,
|
|
25
|
+
proof_id: sha256Text(`${NPM_PACK_PROOF_SCHEMA}\n${inputDigest}\n${infoDigest}\n${fileListDigest}\n${String(pkg.name || '')}@${String(pkg.version || '')}`),
|
|
26
|
+
package_name: String(pkg.name || ''),
|
|
27
|
+
package_version: String(pkg.version || ''),
|
|
28
|
+
pack_ms: Math.max(0, Math.floor(Number(packMs) || 0)),
|
|
29
|
+
info
|
|
30
|
+
};
|
|
31
|
+
const file = npmPackProofPath(root);
|
|
32
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
33
|
+
fs.writeFileSync(file, `${JSON.stringify(proof, null, 2)}\n`);
|
|
34
|
+
return proof;
|
|
35
|
+
}
|
|
36
|
+
export function readCurrentNpmPackProof(root) {
|
|
37
|
+
const blockers = [];
|
|
38
|
+
const file = npmPackProofPath(root);
|
|
39
|
+
let proof = null;
|
|
40
|
+
try {
|
|
41
|
+
proof = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
blockers.push('npm_pack_proof_missing_or_invalid');
|
|
45
|
+
return { ok: false, proof: null, blockers };
|
|
46
|
+
}
|
|
47
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
48
|
+
if (proof?.schema !== NPM_PACK_PROOF_SCHEMA || proof?.ok !== true)
|
|
49
|
+
blockers.push('npm_pack_proof_schema_invalid');
|
|
50
|
+
if (!sameStringList([...(proof?.command || [])], [...NPM_PACK_PROOF_COMMAND]))
|
|
51
|
+
blockers.push('npm_pack_proof_command_invalid');
|
|
52
|
+
if (proof?.package_name !== pkg.name || proof?.package_version !== pkg.version)
|
|
53
|
+
blockers.push('npm_pack_proof_package_identity_mismatch');
|
|
54
|
+
if (proof?.input_digest !== currentNpmPackInputDigest(root))
|
|
55
|
+
blockers.push('npm_pack_proof_stale');
|
|
56
|
+
if (!proof?.info || !Array.isArray(proof.info.files))
|
|
57
|
+
blockers.push('npm_pack_proof_files_missing');
|
|
58
|
+
if (proof?.info) {
|
|
59
|
+
const normalizedInfo = normalizeNpmPackInfo(proof.info);
|
|
60
|
+
const infoDigest = sha256Json(normalizedInfo);
|
|
61
|
+
const fileListDigest = sha256Json(normalizedInfo.files);
|
|
62
|
+
const expectedProofId = sha256Text(`${NPM_PACK_PROOF_SCHEMA}\n${proof.input_digest}\n${infoDigest}\n${fileListDigest}\n${String(pkg.name || '')}@${String(pkg.version || '')}`);
|
|
63
|
+
if (proof.info_digest !== infoDigest)
|
|
64
|
+
blockers.push('npm_pack_proof_info_digest_mismatch');
|
|
65
|
+
if (proof.file_list_digest !== fileListDigest)
|
|
66
|
+
blockers.push('npm_pack_proof_file_list_digest_mismatch');
|
|
67
|
+
if (proof.proof_id !== expectedProofId)
|
|
68
|
+
blockers.push('npm_pack_proof_id_mismatch');
|
|
69
|
+
}
|
|
70
|
+
return { ok: blockers.length === 0, proof, blockers };
|
|
71
|
+
}
|
|
72
|
+
export function readCurrentNpmPackGateArtifacts(root) {
|
|
73
|
+
const proofResult = readCurrentNpmPackProof(root);
|
|
74
|
+
const blockers = [...proofResult.blockers];
|
|
75
|
+
const packlistReport = readJsonReport(path.join(root, '.sneakoscope', 'reports', 'packlist-performance.json'));
|
|
76
|
+
const packageSurfaceReport = readJsonReport(path.join(root, '.sneakoscope', 'reports', 'package-surface-budget.json'));
|
|
77
|
+
if (!packlistReport)
|
|
78
|
+
blockers.push('packlist_performance_report_missing_or_invalid');
|
|
79
|
+
else {
|
|
80
|
+
if (packlistReport.schema !== PACKLIST_PERFORMANCE_REPORT_SCHEMA || packlistReport.ok !== true)
|
|
81
|
+
blockers.push('packlist_performance_report_schema_invalid');
|
|
82
|
+
if (Array.isArray(packlistReport.blockers) && packlistReport.blockers.length > 0)
|
|
83
|
+
blockers.push('packlist_performance_report_has_blockers');
|
|
84
|
+
if (Array.isArray(packlistReport.forbidden) && packlistReport.forbidden.length > 0)
|
|
85
|
+
blockers.push('packlist_performance_report_forbidden_files');
|
|
86
|
+
if (Array.isArray(packlistReport.runtime_required_missing) && packlistReport.runtime_required_missing.length > 0)
|
|
87
|
+
blockers.push('packlist_performance_report_runtime_files_missing');
|
|
88
|
+
}
|
|
89
|
+
if (!packageSurfaceReport)
|
|
90
|
+
blockers.push('package_surface_report_missing_or_invalid');
|
|
91
|
+
else {
|
|
92
|
+
if (packageSurfaceReport.schema !== PACKAGE_SURFACE_BUDGET_REPORT_SCHEMA || packageSurfaceReport.ok !== true)
|
|
93
|
+
blockers.push('package_surface_report_schema_invalid');
|
|
94
|
+
if (Array.isArray(packageSurfaceReport.blockers) && packageSurfaceReport.blockers.length > 0)
|
|
95
|
+
blockers.push('package_surface_report_has_blockers');
|
|
96
|
+
if (Array.isArray(packageSurfaceReport.forbidden_findings) && packageSurfaceReport.forbidden_findings.length > 0)
|
|
97
|
+
blockers.push('package_surface_report_forbidden_files');
|
|
98
|
+
}
|
|
99
|
+
const info = proofResult.proof?.info;
|
|
100
|
+
if (info && packlistReport) {
|
|
101
|
+
if (packlistReport.pack_proof_id !== proofResult.proof?.proof_id)
|
|
102
|
+
blockers.push('packlist_performance_report_proof_id_mismatch');
|
|
103
|
+
if (packlistReport.pack_info_sha256 !== proofResult.proof?.info_digest)
|
|
104
|
+
blockers.push('packlist_performance_report_info_digest_mismatch');
|
|
105
|
+
if (packlistReport.pack_file_list_sha256 !== proofResult.proof?.file_list_digest)
|
|
106
|
+
blockers.push('packlist_performance_report_file_list_digest_mismatch');
|
|
107
|
+
if (!sameNumber(packlistReport.entryCount, info.entryCount))
|
|
108
|
+
blockers.push('packlist_performance_report_entry_count_mismatch');
|
|
109
|
+
if (!sameNumber(packlistReport.size, info.size))
|
|
110
|
+
blockers.push('packlist_performance_report_size_mismatch');
|
|
111
|
+
if (!sameNumber(packlistReport.unpackedSize, info.unpackedSize))
|
|
112
|
+
blockers.push('packlist_performance_report_unpacked_size_mismatch');
|
|
113
|
+
}
|
|
114
|
+
if (info && packageSurfaceReport) {
|
|
115
|
+
if (packageSurfaceReport.pack_proof_id !== proofResult.proof?.proof_id)
|
|
116
|
+
blockers.push('package_surface_report_proof_id_mismatch');
|
|
117
|
+
if (packageSurfaceReport.pack_info_sha256 !== proofResult.proof?.info_digest)
|
|
118
|
+
blockers.push('package_surface_report_info_digest_mismatch');
|
|
119
|
+
if (packageSurfaceReport.pack_file_list_sha256 !== proofResult.proof?.file_list_digest)
|
|
120
|
+
blockers.push('package_surface_report_file_list_digest_mismatch');
|
|
121
|
+
if (!sameNumber(packageSurfaceReport.actual_file_count, info.entryCount))
|
|
122
|
+
blockers.push('package_surface_report_entry_count_mismatch');
|
|
123
|
+
if (!sameNumber(packageSurfaceReport.actual_tarball_bytes, info.size))
|
|
124
|
+
blockers.push('package_surface_report_size_mismatch');
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
ok: blockers.length === 0,
|
|
128
|
+
proof: proofResult.proof,
|
|
129
|
+
packlist_report: packlistReport,
|
|
130
|
+
package_surface_report: packageSurfaceReport,
|
|
131
|
+
blockers: [...new Set(blockers)]
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
export function currentNpmPackInputDigest(root) {
|
|
135
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
136
|
+
const roots = new Set(['package.json', 'package-lock.json', 'npm-shrinkwrap.json', '.npmignore', '.gitignore']);
|
|
137
|
+
for (const entry of fs.readdirSync(root)) {
|
|
138
|
+
if (/^(?:README|LICEN[CS]E|NOTICE)(?:\.|$)/i.test(entry))
|
|
139
|
+
roots.add(entry);
|
|
140
|
+
}
|
|
141
|
+
for (const raw of Array.isArray(pkg.files) ? pkg.files : []) {
|
|
142
|
+
const value = String(raw || '').trim();
|
|
143
|
+
if (!value || value.startsWith('!'))
|
|
144
|
+
continue;
|
|
145
|
+
const prefix = value.split(/[*?]/, 1)[0]?.replace(/\/+$/, '') || '';
|
|
146
|
+
if (prefix)
|
|
147
|
+
roots.add(prefix);
|
|
148
|
+
}
|
|
149
|
+
addPackagePath(roots, pkg.main);
|
|
150
|
+
addPackagePath(roots, pkg.browser);
|
|
151
|
+
if (typeof pkg.bin === 'string')
|
|
152
|
+
addPackagePath(roots, pkg.bin);
|
|
153
|
+
else if (pkg.bin && typeof pkg.bin === 'object')
|
|
154
|
+
for (const value of Object.values(pkg.bin))
|
|
155
|
+
addPackagePath(roots, value);
|
|
156
|
+
if (typeof pkg.man === 'string')
|
|
157
|
+
addPackagePath(roots, pkg.man);
|
|
158
|
+
else if (Array.isArray(pkg.man))
|
|
159
|
+
for (const value of pkg.man)
|
|
160
|
+
addPackagePath(roots, value);
|
|
161
|
+
addPackagePath(roots, pkg.directories?.bin);
|
|
162
|
+
const files = new Set();
|
|
163
|
+
for (const relative of roots)
|
|
164
|
+
collectRoot(root, relative, files);
|
|
165
|
+
const hash = crypto.createHash('sha256');
|
|
166
|
+
for (const relative of [...files].sort()) {
|
|
167
|
+
const file = path.join(root, relative);
|
|
168
|
+
const stat = fs.statSync(file);
|
|
169
|
+
hash.update(relative.replace(/\\/g, '/'));
|
|
170
|
+
hash.update('\0');
|
|
171
|
+
hash.update(String(stat.size));
|
|
172
|
+
hash.update('\0');
|
|
173
|
+
hash.update(crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex'));
|
|
174
|
+
hash.update('\0');
|
|
175
|
+
}
|
|
176
|
+
return hash.digest('hex');
|
|
177
|
+
}
|
|
178
|
+
export function normalizeNpmPackInfo(info = {}) {
|
|
179
|
+
const files = (Array.isArray(info.files) ? info.files : [])
|
|
180
|
+
.map((file) => ({
|
|
181
|
+
path: String(file?.path || '').replace(/\\/g, '/'),
|
|
182
|
+
size: Number(file?.size || 0),
|
|
183
|
+
mode: Number(file?.mode || 0)
|
|
184
|
+
}))
|
|
185
|
+
.filter((file) => file.path)
|
|
186
|
+
.sort((left, right) => left.path.localeCompare(right.path));
|
|
187
|
+
return {
|
|
188
|
+
id: String(info.id || ''),
|
|
189
|
+
name: String(info.name || ''),
|
|
190
|
+
version: String(info.version || ''),
|
|
191
|
+
filename: String(info.filename || ''),
|
|
192
|
+
size: Number(info.size || 0),
|
|
193
|
+
unpackedSize: Number(info.unpackedSize || 0),
|
|
194
|
+
shasum: String(info.shasum || ''),
|
|
195
|
+
integrity: String(info.integrity || ''),
|
|
196
|
+
entryCount: Number(info.entryCount || files.length),
|
|
197
|
+
files
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
function addPackagePath(roots, value) {
|
|
201
|
+
const relative = String(value || '').trim().replace(/^\.\//, '');
|
|
202
|
+
if (relative && !path.isAbsolute(relative) && !relative.startsWith('../'))
|
|
203
|
+
roots.add(relative);
|
|
204
|
+
}
|
|
205
|
+
function sha256Json(value) {
|
|
206
|
+
return sha256Text(JSON.stringify(value));
|
|
207
|
+
}
|
|
208
|
+
function sha256Text(value) {
|
|
209
|
+
return crypto.createHash('sha256').update(value).digest('hex');
|
|
210
|
+
}
|
|
211
|
+
function collectRoot(root, relative, out) {
|
|
212
|
+
const target = path.join(root, relative);
|
|
213
|
+
if (!fs.existsSync(target))
|
|
214
|
+
return;
|
|
215
|
+
const stat = fs.statSync(target);
|
|
216
|
+
if (stat.isFile()) {
|
|
217
|
+
out.add(path.relative(root, target));
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (!stat.isDirectory())
|
|
221
|
+
return;
|
|
222
|
+
for (const entry of fs.readdirSync(target, { withFileTypes: true })) {
|
|
223
|
+
const child = path.join(relative, entry.name);
|
|
224
|
+
if (entry.isDirectory())
|
|
225
|
+
collectRoot(root, child, out);
|
|
226
|
+
else if (entry.isFile())
|
|
227
|
+
out.add(child);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function sameStringList(left, right) {
|
|
231
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
232
|
+
}
|
|
233
|
+
function readJsonReport(file) {
|
|
234
|
+
try {
|
|
235
|
+
const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
236
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
function sameNumber(left, right) {
|
|
243
|
+
const leftNumber = Number(left);
|
|
244
|
+
const rightNumber = Number(right);
|
|
245
|
+
return Number.isFinite(leftNumber) && Number.isFinite(rightNumber) && leftNumber === rightNumber;
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=npm-pack-proof.js.map
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
export function packageDistSnapshot(root, pkg) {
|
|
5
|
+
const distRoot = path.join(root, 'dist');
|
|
6
|
+
if (!fs.existsSync(distRoot))
|
|
7
|
+
return { digest: null, file_count: 0 };
|
|
8
|
+
const entries = packageFileEntries(pkg);
|
|
9
|
+
const files = [];
|
|
10
|
+
collectFiles(distRoot, files);
|
|
11
|
+
const included = files
|
|
12
|
+
.filter((file) => packageFileIncluded(`dist/${path.relative(distRoot, file).split(path.sep).join('/')}`, entries))
|
|
13
|
+
.sort();
|
|
14
|
+
const hash = crypto.createHash('sha256');
|
|
15
|
+
for (const file of included) {
|
|
16
|
+
const rel = path.relative(distRoot, file).split(path.sep).join('/');
|
|
17
|
+
const bytes = fs.readFileSync(file);
|
|
18
|
+
hash.update(rel);
|
|
19
|
+
hash.update('\0');
|
|
20
|
+
hash.update(String(bytes.length));
|
|
21
|
+
hash.update('\0');
|
|
22
|
+
hash.update(crypto.createHash('sha256').update(bytes).digest('hex'));
|
|
23
|
+
hash.update('\0');
|
|
24
|
+
}
|
|
25
|
+
return { digest: hash.digest('hex'), file_count: included.length };
|
|
26
|
+
}
|
|
27
|
+
export function packageFilesSnapshot(root, pkg) {
|
|
28
|
+
const entries = packageFileEntries(pkg);
|
|
29
|
+
const candidates = new Set();
|
|
30
|
+
const missingEntries = [];
|
|
31
|
+
for (const entry of entries) {
|
|
32
|
+
if (entry.negated || hasGlob(entry.pattern))
|
|
33
|
+
continue;
|
|
34
|
+
const full = path.join(root, entry.pattern);
|
|
35
|
+
if (!fs.existsSync(full)) {
|
|
36
|
+
missingEntries.push(entry.pattern);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const stat = fs.statSync(full);
|
|
40
|
+
if (stat.isDirectory()) {
|
|
41
|
+
const found = [];
|
|
42
|
+
collectFiles(full, found);
|
|
43
|
+
for (const file of found)
|
|
44
|
+
candidates.add(path.relative(root, file).split(path.sep).join('/'));
|
|
45
|
+
}
|
|
46
|
+
else if (stat.isFile()) {
|
|
47
|
+
candidates.add(entry.pattern);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const files = [...candidates].filter((file) => packageFileIncluded(file, entries)).sort();
|
|
51
|
+
const hash = crypto.createHash('sha256');
|
|
52
|
+
for (const entry of missingEntries.sort()) {
|
|
53
|
+
hash.update(entry);
|
|
54
|
+
hash.update('\0missing\0');
|
|
55
|
+
}
|
|
56
|
+
for (const file of files) {
|
|
57
|
+
const bytes = fs.readFileSync(path.join(root, file));
|
|
58
|
+
hash.update(file);
|
|
59
|
+
hash.update('\0');
|
|
60
|
+
hash.update(String(bytes.length));
|
|
61
|
+
hash.update('\0');
|
|
62
|
+
hash.update(crypto.createHash('sha256').update(bytes).digest('hex'));
|
|
63
|
+
hash.update('\0');
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
digest: crypto.createHash('sha256').update(hash.digest('hex')).digest('hex'),
|
|
67
|
+
file_count: files.length,
|
|
68
|
+
missing_entries: missingEntries
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function collectFiles(dir, out) {
|
|
72
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
73
|
+
const file = path.join(dir, entry.name);
|
|
74
|
+
if (entry.isDirectory())
|
|
75
|
+
collectFiles(file, out);
|
|
76
|
+
else if (entry.isFile())
|
|
77
|
+
out.push(file);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function packageFileEntries(pkg) {
|
|
81
|
+
return (Array.isArray(pkg.files) ? pkg.files : [])
|
|
82
|
+
.map((raw) => {
|
|
83
|
+
const value = String(raw || '').trim();
|
|
84
|
+
const negated = value.startsWith('!');
|
|
85
|
+
const pattern = normalizeRel(negated ? value.slice(1) : value);
|
|
86
|
+
return pattern ? { negated, pattern } : null;
|
|
87
|
+
})
|
|
88
|
+
.filter((entry) => entry !== null);
|
|
89
|
+
}
|
|
90
|
+
function packageFileIncluded(file, entries) {
|
|
91
|
+
let included = false;
|
|
92
|
+
for (const entry of entries) {
|
|
93
|
+
if (matchesPackagePattern(file, entry.pattern))
|
|
94
|
+
included = !entry.negated;
|
|
95
|
+
}
|
|
96
|
+
return included;
|
|
97
|
+
}
|
|
98
|
+
function matchesPackagePattern(file, pattern) {
|
|
99
|
+
const rel = normalizeRel(file);
|
|
100
|
+
const normalized = normalizeRel(pattern);
|
|
101
|
+
if (!rel || !normalized)
|
|
102
|
+
return false;
|
|
103
|
+
if (!hasGlob(normalized))
|
|
104
|
+
return rel === normalized || rel.startsWith(`${normalized}/`);
|
|
105
|
+
const re = globPatternToRegExp(normalized);
|
|
106
|
+
if (re.test(rel))
|
|
107
|
+
return true;
|
|
108
|
+
const parts = rel.split('/');
|
|
109
|
+
parts.pop();
|
|
110
|
+
while (parts.length) {
|
|
111
|
+
if (re.test(parts.join('/')))
|
|
112
|
+
return true;
|
|
113
|
+
parts.pop();
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
function globPatternToRegExp(pattern) {
|
|
118
|
+
let out = '^';
|
|
119
|
+
for (let i = 0; i < pattern.length; i += 1) {
|
|
120
|
+
const char = pattern[i];
|
|
121
|
+
if (char === '*') {
|
|
122
|
+
if (pattern[i + 1] === '*') {
|
|
123
|
+
if (pattern[i + 2] === '/') {
|
|
124
|
+
out += '(?:[^/]+/)*';
|
|
125
|
+
i += 2;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
out += '.*';
|
|
129
|
+
i += 1;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
out += '[^/]*';
|
|
134
|
+
}
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (char === '?') {
|
|
138
|
+
out += '[^/]';
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
out += char.replace(/[|\\{}()[\]^$+?.]/g, '\\$&');
|
|
142
|
+
}
|
|
143
|
+
return new RegExp(`${out}$`);
|
|
144
|
+
}
|
|
145
|
+
function hasGlob(value) {
|
|
146
|
+
return /[*?]/.test(value);
|
|
147
|
+
}
|
|
148
|
+
function normalizeRel(value) {
|
|
149
|
+
return String(value || '').split(path.sep).join('/').replace(/^\.\/+/, '').replace(/\/+$/, '');
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=package-dist-snapshot.js.map
|
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
// 6.2.0 measured ceiling: next narrow packed boundary.
|
|
2
|
+
export const DEFAULT_MAX_PACK_BYTES = 2428 * 1024;
|
|
3
|
+
// 6.2.0 measured ceiling: next narrow unpacked boundary.
|
|
4
|
+
export const DEFAULT_MAX_UNPACKED_BYTES = 11_141_120;
|
|
2
5
|
//# sourceMappingURL=package-size-budget.js.map
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import crypto from 'node:crypto';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { packageDistSnapshot, packageFilesSnapshot } from './package-dist-snapshot.js';
|
|
6
|
+
export const RELEASE_AUTHORIZATION_SNAPSHOT_KEYS = Object.freeze([
|
|
7
|
+
'git_commit',
|
|
8
|
+
'source_digest',
|
|
9
|
+
'source_file_count',
|
|
10
|
+
'package_files_sha256',
|
|
11
|
+
'package_file_count',
|
|
12
|
+
'release_gate_sha256',
|
|
13
|
+
'dist_build_sha256',
|
|
14
|
+
'dist_file_count'
|
|
15
|
+
]);
|
|
16
|
+
export function releaseAuthorizationSnapshot(root, pkg) {
|
|
17
|
+
const source = releaseSourceSnapshot(root);
|
|
18
|
+
const packageFiles = packageFilesSnapshot(root, pkg);
|
|
19
|
+
const dist = packageDistSnapshot(root, pkg);
|
|
20
|
+
return {
|
|
21
|
+
git_commit: gitCommit(root),
|
|
22
|
+
package_files_sha256: packageFiles.digest,
|
|
23
|
+
package_file_count: packageFiles.file_count,
|
|
24
|
+
dist_build_sha256: dist.digest,
|
|
25
|
+
dist_file_count: dist.file_count,
|
|
26
|
+
release_gate_sha256: releaseGateHash(root, pkg),
|
|
27
|
+
source_digest: source.digest,
|
|
28
|
+
source_file_count: source.file_count
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function sameReleaseAuthorizationSnapshot(left, right) {
|
|
32
|
+
return RELEASE_AUTHORIZATION_SNAPSHOT_KEYS.every((key) => left?.[key] === right?.[key]);
|
|
33
|
+
}
|
|
34
|
+
function gitCommit(root) {
|
|
35
|
+
const result = spawnSync('git', ['rev-parse', 'HEAD'], { cwd: root, encoding: 'utf8' });
|
|
36
|
+
return result.status === 0 ? result.stdout.trim() : null;
|
|
37
|
+
}
|
|
38
|
+
function releaseGateHash(root, pkg) {
|
|
39
|
+
const manifests = ['release-gates.v2.json', 'infra-harness-gates.json'].map((rel) => {
|
|
40
|
+
const file = path.join(root, rel);
|
|
41
|
+
return fs.existsSync(file) ? `${rel}\0${fs.readFileSync(file, 'utf8')}` : `${rel}\0missing`;
|
|
42
|
+
}).join('\0');
|
|
43
|
+
return sha256(`${pkg.scripts?.['release:check'] || ''}\0${pkg.scripts?.['prepublishOnly'] || ''}\0${manifests}`);
|
|
44
|
+
}
|
|
45
|
+
function releaseSourceSnapshot(root) {
|
|
46
|
+
const files = gitFiles(root).filter(releaseRelevant).sort();
|
|
47
|
+
const hash = crypto.createHash('sha256');
|
|
48
|
+
for (const file of files) {
|
|
49
|
+
const full = path.join(root, file);
|
|
50
|
+
let stat;
|
|
51
|
+
try {
|
|
52
|
+
stat = fs.statSync(full);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (!stat.isFile())
|
|
58
|
+
continue;
|
|
59
|
+
const bytes = fs.readFileSync(full);
|
|
60
|
+
hash.update(file);
|
|
61
|
+
hash.update('\0');
|
|
62
|
+
hash.update(String(bytes.length));
|
|
63
|
+
hash.update('\0');
|
|
64
|
+
hash.update(sha256(bytes));
|
|
65
|
+
hash.update('\0');
|
|
66
|
+
}
|
|
67
|
+
return { digest: hash.digest('hex'), file_count: files.length };
|
|
68
|
+
}
|
|
69
|
+
function gitFiles(root) {
|
|
70
|
+
const result = spawnSync('git', ['ls-files', '-z', '--cached', '--others', '--exclude-standard'], {
|
|
71
|
+
cwd: root,
|
|
72
|
+
encoding: 'utf8',
|
|
73
|
+
maxBuffer: 64 * 1024 * 1024
|
|
74
|
+
});
|
|
75
|
+
if (result.status !== 0)
|
|
76
|
+
throw new Error(`unable_to_list_release_files:${result.stderr || result.stdout}`);
|
|
77
|
+
return result.stdout.split('\0').filter(Boolean);
|
|
78
|
+
}
|
|
79
|
+
function releaseRelevant(file) {
|
|
80
|
+
if (!file || file.startsWith('.sneakoscope/') || file.startsWith('.codex/') || file.startsWith('.agents/'))
|
|
81
|
+
return false;
|
|
82
|
+
if (file.startsWith('node_modules/') || file.startsWith('dist/') || file.startsWith('coverage/'))
|
|
83
|
+
return false;
|
|
84
|
+
if (file.startsWith('crates/sks-core/target/'))
|
|
85
|
+
return false;
|
|
86
|
+
if (/\.tgz$|\.log$/i.test(file))
|
|
87
|
+
return false;
|
|
88
|
+
if (/^(package|package-lock)\.json$/.test(file))
|
|
89
|
+
return true;
|
|
90
|
+
if (file === 'release-gates.v2.json' || file === 'infra-harness-gates.json' || file === 'runtime-required-scripts.json')
|
|
91
|
+
return true;
|
|
92
|
+
if (file === '.npmignore' || file === '.npmrc' || file === 'LICENSE')
|
|
93
|
+
return true;
|
|
94
|
+
if (file.startsWith('config/'))
|
|
95
|
+
return true;
|
|
96
|
+
if (/^tsconfig.*\.json$/.test(file))
|
|
97
|
+
return true;
|
|
98
|
+
if (/^(README|CHANGELOG|LICENSE)(\.md)?$/i.test(file))
|
|
99
|
+
return true;
|
|
100
|
+
return [
|
|
101
|
+
'.github/workflows/',
|
|
102
|
+
'bin/',
|
|
103
|
+
'src/',
|
|
104
|
+
'scripts/',
|
|
105
|
+
'test/',
|
|
106
|
+
'docs/',
|
|
107
|
+
'schemas/',
|
|
108
|
+
'crates/sks-core/Cargo.',
|
|
109
|
+
'crates/sks-core/src/'
|
|
110
|
+
].some((prefix) => file.startsWith(prefix));
|
|
111
|
+
}
|
|
112
|
+
function sha256(value) {
|
|
113
|
+
return crypto.createHash('sha256').update(value).digest('hex');
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=release-authorization-snapshot.js.map
|
|
@@ -113,8 +113,8 @@ function selectionResult(all, selected, changedFiles, mode, reasons, skipped) {
|
|
|
113
113
|
}
|
|
114
114
|
};
|
|
115
115
|
}
|
|
116
|
-
function resolveChangedFiles(root, changedSince) {
|
|
117
|
-
const base = changedSince === 'auto' ?
|
|
116
|
+
export function resolveChangedFiles(root, changedSince) {
|
|
117
|
+
const base = changedSince === 'auto' ? autoChangedFilesBase(root) : changedSince;
|
|
118
118
|
const args = base === 'HEAD'
|
|
119
119
|
? ['diff', '--name-only', 'HEAD']
|
|
120
120
|
: ['diff', '--name-only', String(base)];
|
|
@@ -126,6 +126,18 @@ function resolveChangedFiles(root, changedSince) {
|
|
|
126
126
|
].map((file) => file.trim()).filter(Boolean);
|
|
127
127
|
return [...new Set(files)].sort();
|
|
128
128
|
}
|
|
129
|
+
function autoChangedFilesBase(root) {
|
|
130
|
+
const upstream = spawnSync('git', ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}'], {
|
|
131
|
+
cwd: root,
|
|
132
|
+
encoding: 'utf8'
|
|
133
|
+
});
|
|
134
|
+
const upstreamRef = upstream.status === 0 ? String(upstream.stdout || '').trim() : '';
|
|
135
|
+
if (!upstreamRef)
|
|
136
|
+
return 'HEAD';
|
|
137
|
+
const mergeBase = spawnSync('git', ['merge-base', 'HEAD', upstreamRef], { cwd: root, encoding: 'utf8' });
|
|
138
|
+
const base = mergeBase.status === 0 ? String(mergeBase.stdout || '').trim() : '';
|
|
139
|
+
return base || 'HEAD';
|
|
140
|
+
}
|
|
129
141
|
function gateCommandReferencesScript(gate, file) {
|
|
130
142
|
const base = file.replace(/\\/g, '/').split('/').pop()?.replace(/\.(ts|tsx)$/, '') || '';
|
|
131
143
|
if (!base)
|