sneakoscope 7.0.2 → 7.0.3

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.
Files changed (468) hide show
  1. package/README.md +7 -5
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/dist/bin/sks-dispatch.js +0 -3
  5. package/dist/cli/command-registry.js +0 -2
  6. package/dist/cli/install-helpers-codex-lb-chain.js +24 -2
  7. package/dist/cli/install-helpers-codex-lb-config.js +0 -7
  8. package/dist/cli/install-helpers-codex-lb-selftest-chain.js +0 -3
  9. package/dist/cli/install-helpers-codex-lb-selftest.js +0 -17
  10. package/dist/cli/install-helpers.js +81 -96
  11. package/dist/cli/router.js +0 -22
  12. package/dist/commands/codex-lb.js +176 -22
  13. package/dist/commands/codex.js +3 -8
  14. package/dist/commands/doctor.js +4 -14
  15. package/dist/commands/perf.js +5 -1
  16. package/dist/commands/zellij-slot-column-anchor.js +0 -2
  17. package/dist/commands/zellij-slot-pane.js +0 -7
  18. package/dist/commands/zellij.js +0 -2
  19. package/dist/config/skills-manifest.json +52 -52
  20. package/dist/core/agent-bridge/agent-manifest.js +192 -1
  21. package/dist/core/agent-bridge/agent-mode.js +0 -5
  22. package/dist/core/agent-bridge/host-capability-policy.js +189 -0
  23. package/dist/core/agent-bridge/host-capability-runtime.js +1395 -0
  24. package/dist/core/agent-bridge/mcp-server.js +1 -11
  25. package/dist/core/agents/agent-effort-policy.js +0 -3
  26. package/dist/core/agents/agent-orchestrator.js +0 -4
  27. package/dist/core/agents/agent-proof-evidence.js +0 -2
  28. package/dist/core/agents/agent-runner-ollama.js +0 -3
  29. package/dist/core/agents/agent-scheduler.js +0 -5
  30. package/dist/core/agents/native-cli-worker-runtime.js +5 -17
  31. package/dist/core/agents/work-partition/repo-inventory.js +0 -2
  32. package/dist/core/auto-review.js +0 -13
  33. package/dist/core/bench.js +0 -14
  34. package/dist/core/code-structure.js +0 -3
  35. package/dist/core/codex/agent-config-file-repair.js +0 -8
  36. package/dist/core/codex/codex-cli-update.js +122 -20
  37. package/dist/core/codex/codex-config-eperm-repair.js +0 -4
  38. package/dist/core/codex/codex-config-guard.js +0 -3
  39. package/dist/core/codex/codex-config-readability.js +0 -13
  40. package/dist/core/codex/codex-project-config-policy.js +0 -33
  41. package/dist/core/codex/official-goal-mode.js +0 -2
  42. package/dist/core/codex-app/codex-app-fast-ui-repair.js +5 -7
  43. package/dist/core/codex-app/codex-app-ui-state-snapshot.js +44 -7
  44. package/dist/core/codex-app/sks-menubar.js +0 -1
  45. package/dist/core/codex-app.js +0 -9
  46. package/dist/core/codex-compat/codex-hook-output-builders.js +9 -1
  47. package/dist/core/codex-compat/codex-hook-output-normalizer.js +1 -1
  48. package/dist/core/codex-compat/codex-hook-semantic-validator.js +3 -2
  49. package/dist/core/codex-compat/codex-hook-warning-detector.js +10 -2
  50. package/dist/core/codex-control/codex-lb-launch-recovery.js +0 -3
  51. package/dist/core/codex-control/codex-reliability-shield.js +0 -8
  52. package/dist/core/codex-control/codex-sdk-adapter.js +0 -3
  53. package/dist/core/codex-control/codex-sdk-config-policy.js +0 -2
  54. package/dist/core/codex-control/codex-sdk-env-policy.js +61 -16
  55. package/dist/core/codex-control/codex-task-runner.js +0 -7
  56. package/dist/core/codex-control/codex-thread-registry.js +0 -4
  57. package/dist/core/codex-lb/codex-lb-env.js +118 -20
  58. package/dist/core/codex-lb/codex-lb-tool-catalog.js +0 -4
  59. package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +1 -1
  60. package/dist/core/codex-model-guard.js +0 -14
  61. package/dist/core/codex-native/codex-native-feature-broker.js +67 -22
  62. package/dist/core/codex-native/codex-native-interop-policy.js +81 -9
  63. package/dist/core/codex-native/confined-report-writer.js +21 -0
  64. package/dist/core/codex-native/core-skill-integrity.js +169 -20
  65. package/dist/core/codex-native/project-skill-dedupe.js +55 -13
  66. package/dist/core/codex-native/skill-registry-ledger.js +137 -16
  67. package/dist/core/codex-native/sks-skill-paths.js +185 -0
  68. package/dist/core/codex-runtime/codex-desktop-config-policy.js +0 -2
  69. package/dist/core/commands/agent-bridge-command.js +28 -8
  70. package/dist/core/commands/basic-cli.js +67 -26
  71. package/dist/core/commands/bench-command.js +5 -1
  72. package/dist/core/commands/command-utils.js +0 -5
  73. package/dist/core/commands/image-ux-review-command.js +0 -9
  74. package/dist/core/commands/mad-sks-command.js +0 -38
  75. package/dist/core/commands/naruto-command.js +46 -12
  76. package/dist/core/commands/ppt-command.js +0 -9
  77. package/dist/core/commands/run-command.js +8 -2
  78. package/dist/core/commands/seo-command.js +0 -6
  79. package/dist/core/commands/wiki-command.js +0 -14
  80. package/dist/core/computer-use-live-evidence.js +0 -5
  81. package/dist/core/config/secret-preservation.js +0 -11
  82. package/dist/core/daemon/sksd-hook-daemon-entrypoint.js +0 -2
  83. package/dist/core/daemon/sksd-hook-daemon.js +1 -29
  84. package/dist/core/daemon/sksd-hook-dispatch.js +0 -17
  85. package/dist/core/db-safety.js +0 -7
  86. package/dist/core/doctor/browser-use-repair.js +0 -2
  87. package/dist/core/doctor/doctor-codex-startup-repair.js +0 -3
  88. package/dist/core/doctor/doctor-readiness-matrix.js +12 -0
  89. package/dist/core/doctor/doctor-skill-reconcile.js +32 -0
  90. package/dist/core/doctor/imagegen-repair.js +0 -2
  91. package/dist/core/doctor/mcp-transport-collision-repair.js +0 -3
  92. package/dist/core/doctor/retired-managed-residue-private.js +0 -1
  93. package/dist/core/doctor/supabase-mcp-repair.js +0 -11
  94. package/dist/core/feature-fixture-executor.js +0 -48
  95. package/dist/core/feature-fixtures.js +0 -5
  96. package/dist/core/fsx.js +11 -12
  97. package/dist/core/hooks-runtime/code-pack-freshness-preflight.js +0 -5
  98. package/dist/core/hooks-runtime/hook-context.js +202 -0
  99. package/dist/core/hooks-runtime/hook-io.js +1 -12
  100. package/dist/core/hooks-runtime/light-turn.js +0 -2
  101. package/dist/core/hooks-runtime/naruto-decision-gate.js +4 -1
  102. package/dist/core/hooks-runtime/naruto-terminal-finalization.js +91 -0
  103. package/dist/core/hooks-runtime/official-subagent-lifecycle.js +370 -0
  104. package/dist/core/hooks-runtime/standalone-parent-host-capability.js +98 -0
  105. package/dist/core/hooks-runtime/subagent-context.js +59 -0
  106. package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +29 -0
  107. package/dist/core/hooks-runtime/subagent-skill-availability-evidence.js +195 -0
  108. package/dist/core/hooks-runtime/subagent-skill-availability-guards.js +316 -0
  109. package/dist/core/hooks-runtime/subagent-skill-availability.js +217 -0
  110. package/dist/core/hooks-runtime.js +259 -535
  111. package/dist/core/image-ux-review/codex-app-generated-image-discovery.js +0 -17
  112. package/dist/core/image-ux-review/imagegen-adapter.js +0 -14
  113. package/dist/core/imagegen/imagegen-auth-readiness.js +0 -9
  114. package/dist/core/imagegen/imagegen-capability.js +0 -3
  115. package/dist/core/init/managed-skill-install.js +42 -0
  116. package/dist/core/init/skills.js +247 -74
  117. package/dist/core/init.js +15 -40
  118. package/dist/core/lean-engineering-policy.js +0 -2
  119. package/dist/core/locks/file-lock.js +0 -21
  120. package/dist/core/loops/loop-planner.js +0 -6
  121. package/dist/core/loops/loop-runtime.js +0 -1
  122. package/dist/core/loops/loop-worker-runtime.js +0 -19
  123. package/dist/core/mad-sks/executors/db-write-executor.js +0 -4
  124. package/dist/core/mad-sks/executors/executor-base.js +0 -10
  125. package/dist/core/mad-sks/immutable-harness-guard.js +0 -5
  126. package/dist/core/mad-sks/sql-plane/coordinator.js +0 -5
  127. package/dist/core/mad-sks/sql-plane/ledger.js +0 -4
  128. package/dist/core/mad-sks/sql-plane/lock.js +0 -4
  129. package/dist/core/mad-sks/sql-plane/mcp-executor.js +0 -9
  130. package/dist/core/mad-sks/sql-plane/policy-resolver.js +0 -2
  131. package/dist/core/mad-sks/sql-plane/postconditions.js +0 -4
  132. package/dist/core/mad-sks/sql-plane/recovery.js +0 -2
  133. package/dist/core/mad-sks/sql-plane/runtime-profile.js +0 -8
  134. package/dist/core/managed-assets/managed-assets-manifest.js +1 -7
  135. package/dist/core/mcp-config/health-check.js +10 -3
  136. package/dist/core/migration/migration-transaction-journal.js +0 -8
  137. package/dist/core/mission.js +0 -2
  138. package/dist/core/naruto/naruto-active-pool.js +0 -2
  139. package/dist/core/naruto/naruto-concurrency-governor.js +0 -1
  140. package/dist/core/naruto/naruto-real-write-proof.js +0 -4
  141. package/dist/core/naruto/naruto-write-e2e.js +0 -1
  142. package/dist/core/perf/perf-budget.js +0 -5
  143. package/dist/core/permission-gates.js +0 -2
  144. package/dist/core/pipeline-internals/runtime-core.js +15 -5
  145. package/dist/core/pipeline-internals/runtime-gates.js +0 -12
  146. package/dist/core/preflight/parallel-preflight-engine.js +0 -11
  147. package/dist/core/proof/evidence-collector.js +0 -2
  148. package/dist/core/proof/route-finalizer.js +0 -1
  149. package/dist/core/proof/selftest-proof-fixtures.js +0 -5
  150. package/dist/core/providers/glm/bench/glm-benchmark-runner.js +0 -2
  151. package/dist/core/providers/glm/glm-request-cache.js +0 -3
  152. package/dist/core/providers/glm/naruto/glm-naruto-command.js +0 -1
  153. package/dist/core/providers/glm/naruto/glm-naruto-decomposer.js +0 -1
  154. package/dist/core/providers/glm/naruto/glm-naruto-orchestrator.js +0 -6
  155. package/dist/core/providers/glm/naruto/glm-naruto-trace.js +0 -1
  156. package/dist/core/providers/glm/naruto/glm-naruto-worker-pool.js +0 -1
  157. package/dist/core/providers/glm/naruto/glm-naruto-worktree.js +0 -1
  158. package/dist/core/providers/openrouter/openrouter-secret-store.js +0 -1
  159. package/dist/core/providers/openrouter/openrouter-stream.js +0 -2
  160. package/dist/core/questions.js +3 -3
  161. package/dist/core/release/gate-manifest.js +0 -5
  162. package/dist/core/release/package-size-budget.js +1 -1
  163. package/dist/core/release/release-gate-batch-runner.js +11 -2
  164. package/dist/core/release/release-gate-cache-v2.js +0 -4
  165. package/dist/core/release/release-gate-hermetic-env.js +0 -5
  166. package/dist/core/release-parallel-full-coverage.js +0 -2
  167. package/dist/core/remote/ssh-worker-client.js +0 -3
  168. package/dist/core/research/research-adversarial-review.js +6 -2
  169. package/dist/core/responses-retry-policy.js +0 -10
  170. package/dist/core/retention.js +0 -7
  171. package/dist/core/routes/constants.js +0 -3
  172. package/dist/core/routes.js +89 -15
  173. package/dist/core/safety/command-contract/contracts.js +2 -0
  174. package/dist/core/safety/mutation-guard.js +0 -25
  175. package/dist/core/safety/mutation-ledger.js +0 -9
  176. package/dist/core/safety/requested-scope-contract.js +0 -0
  177. package/dist/core/security/high-risk-contracts.js +0 -1
  178. package/dist/core/skills/core-skill-card.js +0 -0
  179. package/dist/core/skills/core-skill-deployment.js +0 -13
  180. package/dist/core/skills/core-skill-epoch.js +0 -11
  181. package/dist/core/skills/core-skill-meta-update.js +0 -6
  182. package/dist/core/skills/core-skill-patch-apply.js +0 -7
  183. package/dist/core/skills/core-skill-patch.js +0 -8
  184. package/dist/core/skills/core-skill-reflection.js +0 -16
  185. package/dist/core/skills/core-skill-runtime.js +0 -6
  186. package/dist/core/skills/core-skill-scorer.js +0 -7
  187. package/dist/core/skills/core-skill-trainer.js +0 -11
  188. package/dist/core/skills/core-skill-types.js +0 -9
  189. package/dist/core/skills/core-skill-validation.js +0 -5
  190. package/dist/core/skills/rejected-skill-patch-buffer.js +0 -2
  191. package/dist/core/stop-gate/stop-gate-check.js +0 -8
  192. package/dist/core/stop-gate/stop-gate-resolver.js +0 -7
  193. package/dist/core/stop-gate/stop-gate-writer.js +0 -5
  194. package/dist/core/subagents/model-policy.js +0 -7
  195. package/dist/core/subagents/naruto-help-contract.js +1 -1
  196. package/dist/core/subagents/naruto-proof-projection.js +580 -12
  197. package/dist/core/subagents/official-subagent-config.js +0 -8
  198. package/dist/core/subagents/official-subagent-preparation.js +6 -5
  199. package/dist/core/subagents/official-subagent-prompt.js +29 -0
  200. package/dist/core/subagents/official-subagent-runner.js +343 -37
  201. package/dist/core/subagents/subagent-evidence.js +378 -9
  202. package/dist/core/subagents/thread-budget.js +5 -2
  203. package/dist/core/subagents/triwiki-attention.js +0 -4
  204. package/dist/core/subagents/wave-parent-guidance.js +54 -9
  205. package/dist/core/telegram/runtime.js +0 -1
  206. package/dist/core/triwiki/code-index-scanner.js +0 -3
  207. package/dist/core/triwiki/code-pack-head-freshness.js +0 -10
  208. package/dist/core/triwiki/code-pack.js +0 -2
  209. package/dist/core/triwiki/triwiki-cache-key.js +0 -1
  210. package/dist/core/triwiki/triwiki-proof-bank.js +0 -1
  211. package/dist/core/triwiki-attention.js +0 -10
  212. package/dist/core/triwiki-provenance.js +0 -5
  213. package/dist/core/triwiki-runtime.js +0 -12
  214. package/dist/core/triwiki-wrongness/wrongness-ledger.js +0 -7
  215. package/dist/core/triwiki-wrongness/wrongness-schema.js +0 -3
  216. package/dist/core/trust-kernel/trust-report.js +0 -7
  217. package/dist/core/update/update-migration-state.js +21 -39
  218. package/dist/core/update-check.js +2 -14
  219. package/dist/core/version-manager.js +2 -0
  220. package/dist/core/version.js +1 -1
  221. package/dist/core/work-order-ledger.js +0 -17
  222. package/dist/core/zellij/zellij-clipboard-config.js +0 -18
  223. package/dist/core/zellij/zellij-lane-renderer.js +5 -46
  224. package/dist/core/zellij/zellij-lane-runtime.js +0 -1
  225. package/dist/core/zellij/zellij-launcher.js +0 -26
  226. package/dist/core/zellij/zellij-official-subagent-activity.js +0 -5
  227. package/dist/core/zellij/zellij-official-subagent-telemetry.js +0 -5
  228. package/dist/core/zellij/zellij-screen-proof.js +0 -7
  229. package/dist/core/zellij/zellij-slot-column-anchor.js +0 -1
  230. package/dist/core/zellij/zellij-slot-pane-renderer.js +0 -9
  231. package/dist/core/zellij/zellij-slot-telemetry.js +0 -12
  232. package/dist/core/zellij/zellij-ui-mode.js +0 -7
  233. package/dist/core/zellij/zellij-update.js +0 -29
  234. package/dist/core/zellij/zellij-worker-pane-manager.js +0 -39
  235. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +213 -27
  236. package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +95 -12
  237. package/dist/scripts/agent-message-bus-reader-check.js +0 -1
  238. package/dist/scripts/all-feature-deep-completion-check.js +0 -1
  239. package/dist/scripts/appshots-thread-attachment-discovery-check.js +0 -1
  240. package/dist/scripts/architecture-guard-check.js +0 -1
  241. package/dist/scripts/build-dist.js +0 -1
  242. package/dist/scripts/build-once-runner-check.js +0 -1
  243. package/dist/scripts/canonical-test-runner.js +0 -2
  244. package/dist/scripts/certificate-sla-check.js +0 -1
  245. package/dist/scripts/changelog-check.js +0 -1
  246. package/dist/scripts/check-cli-entrypoint.js +0 -1
  247. package/dist/scripts/check-command-module-budget.js +0 -7
  248. package/dist/scripts/check-feature-quality.js +0 -1
  249. package/dist/scripts/check-legacy-free.js +0 -1
  250. package/dist/scripts/check-pipeline-runtime.js +0 -1
  251. package/dist/scripts/check-runtime-schemas.js +0 -1
  252. package/dist/scripts/codex-0-134-runner-truth-check.js +0 -1
  253. package/dist/scripts/codex-0-137-compat-check.js +0 -1
  254. package/dist/scripts/codex-0138-capability-artifact-check.js +0 -1
  255. package/dist/scripts/codex-0138-capability-check.js +0 -1
  256. package/dist/scripts/codex-0138-doctor-check.js +0 -1
  257. package/dist/scripts/codex-0138-feature-probes-check.js +0 -1
  258. package/dist/scripts/codex-0144-core-real-probes-check.js +0 -1
  259. package/dist/scripts/codex-app-handoff-check.js +0 -1
  260. package/dist/scripts/codex-app-handoff-launch-check.js +0 -1
  261. package/dist/scripts/codex-config-load-probe.js +0 -5
  262. package/dist/scripts/codex-control-all-pipelines-check.js +0 -1
  263. package/dist/scripts/codex-control-event-stream-ledger-check.js +0 -1
  264. package/dist/scripts/codex-control-tool-output-continuity-audit-check.js +0 -1
  265. package/dist/scripts/codex-permission-profiles-check.js +0 -1
  266. package/dist/scripts/codex-plugin-app-template-policy-check.js +0 -1
  267. package/dist/scripts/codex-project-config-policy-splitter-check.js +0 -1
  268. package/dist/scripts/codex-sdk-all-pipelines-check.js +0 -1
  269. package/dist/scripts/codex-sdk-backend-router-check.js +0 -1
  270. package/dist/scripts/codex-sdk-capability-check.js +0 -1
  271. package/dist/scripts/codex-sdk-event-stream-ledger-check.js +0 -1
  272. package/dist/scripts/codex-sdk-real-smoke-check.js +0 -1
  273. package/dist/scripts/concurrent-session-collision-check.js +9 -0
  274. package/dist/scripts/context7-evidence-dedupe-check.js +0 -1
  275. package/dist/scripts/core-skill-card-schema-check.js +0 -11
  276. package/dist/scripts/core-skill-deployment-snapshot-check.js +0 -10
  277. package/dist/scripts/core-skill-heldout-validation-check.js +0 -11
  278. package/dist/scripts/core-skill-no-inference-optimizer-check.js +0 -11
  279. package/dist/scripts/core-skill-patch-check.js +0 -11
  280. package/dist/scripts/core-skill-route-runtime-integration-check.js +0 -11
  281. package/dist/scripts/current-surface-update-e2e-check.js +0 -4
  282. package/dist/scripts/current-upgrade-matrix-check.js +0 -1
  283. package/dist/scripts/dfix-fixture-check.js +0 -1
  284. package/dist/scripts/dfix-patch-handoff-check.js +0 -1
  285. package/dist/scripts/dfix-verification-check.js +0 -1
  286. package/dist/scripts/dfix-verification-recommendation-check.js +0 -1
  287. package/dist/scripts/docs-truthfulness-check.js +3 -3
  288. package/dist/scripts/doctor-fastpath-check.js +0 -1
  289. package/dist/scripts/doctor-fix-proves-codex-read-check.js +0 -11
  290. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +0 -4
  291. package/dist/scripts/doctor-idempotence-check.js +0 -1
  292. package/dist/scripts/doctor-ops-semantics-check.js +0 -1
  293. package/dist/scripts/ensure-bin-executable.js +0 -1
  294. package/dist/scripts/evidence-flagship-coverage-check.js +0 -1
  295. package/dist/scripts/fast-codex-service-tier-proof-check.js +0 -1
  296. package/dist/scripts/fixtures/fake-codex-config-loader.js +0 -5
  297. package/dist/scripts/fsx-hotpath-check.js +0 -1
  298. package/dist/scripts/gate-policy-audit-check.js +1 -1
  299. package/dist/scripts/geo-claim-evidence-check.js +0 -1
  300. package/dist/scripts/geo-cli-blackbox-check.js +0 -1
  301. package/dist/scripts/geo-crawler-policy-check.js +0 -1
  302. package/dist/scripts/git-worktree-diff-envelope-check.js +0 -1
  303. package/dist/scripts/git-worktree-dirty-lock-check.js +0 -1
  304. package/dist/scripts/git-worktree-dirty-main-detection-check.js +0 -1
  305. package/dist/scripts/git-worktree-integration-primary-check.js +0 -1
  306. package/dist/scripts/git-worktree-manifest-append-check.js +0 -1
  307. package/dist/scripts/git-worktree-untracked-diff-check.js +0 -1
  308. package/dist/scripts/high-risk-contracts-check.js +0 -1
  309. package/dist/scripts/hook-latency-budget-check.js +0 -1
  310. package/dist/scripts/hook-latency-quantum-check.js +0 -1
  311. package/dist/scripts/image-artifact-path-contract-check.js +0 -1
  312. package/dist/scripts/imagegen-real-smoke-check.js +0 -1
  313. package/dist/scripts/import-graph-budget-check.js +0 -1
  314. package/dist/scripts/installed-package-smoke-check.js +0 -1
  315. package/dist/scripts/legacy-gate-purge-check.js +0 -1
  316. package/dist/scripts/lib/codex-sdk-gate-lib.js +0 -3
  317. package/dist/scripts/lib/ensure-dist-fresh.js +0 -1
  318. package/dist/scripts/lib/valid-png-fixture.js +0 -1
  319. package/dist/scripts/local-collab-all-pipelines-final-gpt-check.js +0 -1
  320. package/dist/scripts/loop-directive-check-lib.js +0 -1
  321. package/dist/scripts/loop-worker-fixture-child.js +0 -1
  322. package/dist/scripts/mad-preflight-blocks-unreadable-config-check.js +0 -10
  323. package/dist/scripts/mad-sks-sql-plane-lifecycle-hook-decision-check.js +0 -1
  324. package/dist/scripts/mad-sks-sql-plane-result-lifecycle-check.js +0 -1
  325. package/dist/scripts/mcp-plugin-inventory-check.js +0 -1
  326. package/dist/scripts/mcp-tool-naming-parity-check.js +0 -1
  327. package/dist/scripts/model-call-concurrency-check.js +0 -1
  328. package/dist/scripts/mutation-callsite-coverage-check.js +0 -5
  329. package/dist/scripts/naruto-codex-e2e-check.js +0 -1
  330. package/dist/scripts/naruto-worktree-coding-blackbox.js +0 -1
  331. package/dist/scripts/official-subagent-workflow-check.js +3 -1
  332. package/dist/scripts/ops-diagnostics-bundle-check.js +0 -1
  333. package/dist/scripts/packlist-performance-check.js +1 -3
  334. package/dist/scripts/perf-budget-check.js +0 -1
  335. package/dist/scripts/ppt-full-e2e-blackbox-check.js +0 -1
  336. package/dist/scripts/ppt-real-export-adapter-check.js +0 -1
  337. package/dist/scripts/ppt-real-imagegen-smoke-check.js +0 -1
  338. package/dist/scripts/ppt-real-imagegen-wiring-check.js +0 -1
  339. package/dist/scripts/ppt-reexport-rereview-check.js +0 -1
  340. package/dist/scripts/prepublish-fast-check.js +0 -23
  341. package/dist/scripts/prepublish-release-check-or-fast.js +0 -7
  342. package/dist/scripts/probe-memoization-check.js +0 -1
  343. package/dist/scripts/product-design-plugin-routing-check.js +0 -1
  344. package/dist/scripts/project-skill-dedupe-blackbox.js +36 -9
  345. package/dist/scripts/prompt-placeholder-guard-check.js +0 -1
  346. package/dist/scripts/python-codex-sdk-all-pipelines-check.js +0 -3
  347. package/dist/scripts/qa-loop-app-handoff-capability-check.js +0 -1
  348. package/dist/scripts/qa-loop-app-handoff-check.js +0 -1
  349. package/dist/scripts/qa-loop-app-handoff-cli-check.js +0 -1
  350. package/dist/scripts/qa-loop-app-handoff-confirmation-check.js +0 -1
  351. package/dist/scripts/qa-loop-app-handoff-gate-lifecycle-check.js +0 -1
  352. package/dist/scripts/qa-loop-app-handoff-launch-check.js +0 -1
  353. package/dist/scripts/qa-loop-app-handoff-status-lifecycle-check.js +0 -1
  354. package/dist/scripts/qa-loop-budget-policy-check.js +0 -1
  355. package/dist/scripts/qa-loop-effort-escalation-check.js +0 -1
  356. package/dist/scripts/qa-loop-image-path-exposure-check.js +0 -1
  357. package/dist/scripts/qa-loop-image-path-prompt-injection-check.js +0 -1
  358. package/dist/scripts/release-cache-glob-hashing-check.js +0 -1
  359. package/dist/scripts/release-cache-input-classifier-check.js +0 -1
  360. package/dist/scripts/release-cache-neutralization-report-check.js +0 -1
  361. package/dist/scripts/release-cache-version-neutral-fixture-check.js +0 -1
  362. package/dist/scripts/release-check-stamp.js +0 -4
  363. package/dist/scripts/release-dist-freshness-check.js +0 -1
  364. package/dist/scripts/release-full-parallelism-blackbox.js +3 -3
  365. package/dist/scripts/release-gate-batch-runner-check.js +22 -0
  366. package/dist/scripts/release-gate-budget-check.js +0 -6
  367. package/dist/scripts/release-gate-dag-runner-check.js +0 -1
  368. package/dist/scripts/release-latency-slo-check.js +0 -1
  369. package/dist/scripts/release-metadata-1-19-check.js +0 -1
  370. package/dist/scripts/release-metadata-check.js +0 -3
  371. package/dist/scripts/release-parallel-speed-budget-check.js +0 -5
  372. package/dist/scripts/release-proof-truth-check.js +0 -1
  373. package/dist/scripts/release-provenance-check.js +0 -1
  374. package/dist/scripts/release-real-check.js +0 -1
  375. package/dist/scripts/release-runtime-truth-matrix-check.js +0 -1
  376. package/dist/scripts/release-version-truth-check.js +0 -1
  377. package/dist/scripts/research-blueprint-densifier-check.js +0 -1
  378. package/dist/scripts/research-claim-builder-check.js +0 -1
  379. package/dist/scripts/research-complete-package-fixture-check.js +0 -1
  380. package/dist/scripts/research-final-reviewer-blackbox.js +0 -1
  381. package/dist/scripts/responses-retry-policy-centralized-check.js +0 -1
  382. package/dist/scripts/retention-apply-smoke-check.js +0 -1
  383. package/dist/scripts/retention-budget-check.js +0 -1
  384. package/dist/scripts/retention-dry-run-check.js +0 -1
  385. package/dist/scripts/rollback-recovery-smoke-check.js +0 -1
  386. package/dist/scripts/route-intent-regression-check.js +0 -1
  387. package/dist/scripts/runtime-current-terminal-check.js +0 -1
  388. package/dist/scripts/runtime-dist-parity-check.js +0 -1
  389. package/dist/scripts/runtime-no-src-mjs-check.js +0 -1
  390. package/dist/scripts/runtime-proof-summary-check.js +0 -1
  391. package/dist/scripts/runtime-ts-rust-boundary-check.js +0 -15
  392. package/dist/scripts/runtime-ts-source-of-truth-check.js +0 -1
  393. package/dist/scripts/scheduler-batch-dispatch-check.js +0 -1
  394. package/dist/scripts/scheduler-parallel-proof-consistency-check.js +0 -1
  395. package/dist/scripts/scheduler-utilization-integral-check.js +0 -1
  396. package/dist/scripts/search-visibility-gate-lib.js +0 -1
  397. package/dist/scripts/seo-audit-fixture-check.js +0 -1
  398. package/dist/scripts/seo-cli-blackbox-check.js +0 -1
  399. package/dist/scripts/seo-geo-geo-disambiguation-check.js +0 -1
  400. package/dist/scripts/seo-geo-route-identity-check.js +0 -1
  401. package/dist/scripts/seo-geo-skill-rich-content-check.js +0 -1
  402. package/dist/scripts/seo-marketing-truthfulness-check.js +0 -1
  403. package/dist/scripts/seo-metadata-sync-check.js +0 -1
  404. package/dist/scripts/seo-no-mutation-by-default-check.js +0 -1
  405. package/dist/scripts/shared-memory-fixture-check.js +0 -1
  406. package/dist/scripts/side-effect-runtime-report-check.js +0 -1
  407. package/dist/scripts/sizecheck.js +0 -1
  408. package/dist/scripts/sks-1-11-gate-lib.js +0 -1
  409. package/dist/scripts/sks-1-12-real-execution-check-lib.js +0 -1
  410. package/dist/scripts/sks-1-18-gate-lib.js +0 -1
  411. package/dist/scripts/sks-menubar-install-check.js +0 -3
  412. package/dist/scripts/sksd-daemon-check.js +0 -1
  413. package/dist/scripts/super-search-live-smoke-check.js +0 -1
  414. package/dist/scripts/super-search-local-http-smoke-check.js +0 -1
  415. package/dist/scripts/super-search-offline-contract-check.js +0 -1
  416. package/dist/scripts/super-search-provider-interface-check.js +0 -1
  417. package/dist/scripts/triwiki-cache-key-check.js +0 -1
  418. package/dist/scripts/triwiki-proof-bank-blackbox.js +0 -1
  419. package/dist/scripts/triwiki-proof-bank-check.js +0 -1
  420. package/dist/scripts/triwiki-proof-card-check.js +0 -1
  421. package/dist/scripts/trust-fixture-check.js +0 -1
  422. package/dist/scripts/ultra-router-auto-router-check.js +0 -1
  423. package/dist/scripts/update-fastpath-check.js +0 -1
  424. package/dist/scripts/upgrade-migration-matrix-check.js +0 -1
  425. package/dist/scripts/ux-review-extract-wires-real-extractor-check.js +0 -1
  426. package/dist/scripts/ux-review-imagegen-blackbox-check.js +0 -1
  427. package/dist/scripts/ux-review-patch-diff-recheck-check.js +0 -1
  428. package/dist/scripts/ux-review-real-imagegen-smoke-check.js +0 -1
  429. package/dist/scripts/ux-review-run-wires-imagegen-check.js +0 -1
  430. package/dist/scripts/write-build-manifest.js +0 -1
  431. package/dist/scripts/wrongness-fixture-check.js +0 -1
  432. package/dist/scripts/zellij-capability-check.js +0 -1
  433. package/dist/scripts/zellij-developer-controls-check.js +0 -1
  434. package/dist/scripts/zellij-doctor-readiness-check.js +0 -13
  435. package/dist/scripts/zellij-dynamic-pane-lifecycle-check.js +0 -1
  436. package/dist/scripts/zellij-fake-adapter-check.js +0 -1
  437. package/dist/scripts/zellij-initial-main-only-blackbox.js +0 -1
  438. package/dist/scripts/zellij-lane-renderer-check.js +0 -1
  439. package/dist/scripts/zellij-launch-command-truth-check.js +0 -12
  440. package/dist/scripts/zellij-layout-valid-check.js +0 -1
  441. package/dist/scripts/zellij-pane-creation-lock-metrics-check.js +0 -1
  442. package/dist/scripts/zellij-pane-lock-concurrency-blackbox.js +0 -1
  443. package/dist/scripts/zellij-pane-lock-does-not-block-worker-check.js +0 -1
  444. package/dist/scripts/zellij-pane-lock-open-worker-integration-blackbox.js +0 -1
  445. package/dist/scripts/zellij-pane-proof-check.js +0 -1
  446. package/dist/scripts/zellij-qa-app-handoff-status-check.js +0 -1
  447. package/dist/scripts/zellij-real-session-cleanup-check.js +0 -1
  448. package/dist/scripts/zellij-real-session-launch-check.js +0 -1
  449. package/dist/scripts/zellij-right-column-geometry-proof.js +0 -1
  450. package/dist/scripts/zellij-right-column-headless-overflow-check.js +0 -1
  451. package/dist/scripts/zellij-right-column-manager-check.js +0 -1
  452. package/dist/scripts/zellij-screen-proof-check.js +0 -1
  453. package/dist/scripts/zellij-slot-only-ui-check.js +0 -1
  454. package/dist/scripts/zellij-slot-pane-renderer-check.js +0 -1
  455. package/dist/scripts/zellij-slot-pane-stale-detection-check.js +0 -7
  456. package/dist/scripts/zellij-slot-telemetry-incremental-check.js +0 -1
  457. package/dist/scripts/zellij-slot-telemetry-live-flush-check.js +0 -1
  458. package/dist/scripts/zellij-slot-telemetry-performance-check.js +0 -1
  459. package/dist/scripts/zellij-stacked-capability-routing-check.js +0 -1
  460. package/dist/scripts/zellij-stacked-fallback-integration-blackbox.js +0 -1
  461. package/dist/scripts/zellij-stacked-version-matrix-check.js +0 -1
  462. package/dist/scripts/zellij-stacked-version-parser-check.js +0 -1
  463. package/dist/scripts/zellij-ui-design-check.js +0 -12
  464. package/dist/scripts/zellij-update-prompt-matrix-check.js +0 -1
  465. package/dist/scripts/zellij-update-prompt-mode-check.js +0 -1
  466. package/dist/scripts/zellij-update-prompt-safety-check.js +0 -1
  467. package/dist/scripts/zellij-worker-pane-real-ui-blackbox.js +0 -2
  468. package/package.json +1 -1
@@ -1,11 +1,13 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
- import { ensureDir, nowIso, readText, sha256, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
4
- import { CORE_SKILL_TEMPLATE_VERSION, buildSksCoreSkillManifest, currentCoreSkillName, isSksManagedCoreSkillContent, renderCoreSkillTemplate } from './core-skill-manifest.js';
3
+ import { nowIso, sha256, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
4
+ import { ensureConfinedDirectory, inspectConfinedPath, isLexicallyConfined } from '../managed-path-safety.js';
5
+ import { CORE_SKILL_TEMPLATE_VERSION, buildSksCoreSkillManifest, currentCoreSkillName, isCoreSkillName, isSksManagedCoreSkillContent, renderCoreSkillTemplate } from './core-skill-manifest.js';
5
6
  import { canonicalSkillName } from './skill-name-canonicalizer.js';
6
7
  export async function syncCoreSkillsIntegrity(input) {
7
8
  const root = path.resolve(input.root);
8
- const skillsRoot = input.skillsRoot || path.join(root, '.agents', 'skills');
9
+ const skillsRoot = path.resolve(input.skillsRoot || path.join(root, '.agents', 'skills'));
10
+ const skillsBoundary = coreSkillsBoundary(root, skillsRoot);
9
11
  const apply = input.apply === true;
10
12
  const manifest = buildSksCoreSkillManifest();
11
13
  const rows = [];
@@ -13,19 +15,36 @@ export async function syncCoreSkillsIntegrity(input) {
13
15
  const restored = [];
14
16
  const skippedUserAuthored = [];
15
17
  const blockers = [];
18
+ const reportPath = input.reportPath === null
19
+ ? null
20
+ : path.resolve(input.reportPath || path.join(root, '.sneakoscope', 'reports', 'core-skill-integrity.json'));
21
+ const backupRoot = path.join(root, '.sneakoscope', 'backups', 'core-skills');
22
+ const reportPathBlocker = reportPath
23
+ ? await inspectCoreSkillArtifactTarget(root, reportPath, 'report', 'file')
24
+ : null;
25
+ const backupPathBlocker = apply
26
+ ? await inspectCoreSkillArtifactTarget(root, backupRoot, 'backup', 'directory')
27
+ : null;
28
+ const artifactPathBlockers = [reportPathBlocker, backupPathBlocker].filter((value) => Boolean(value));
29
+ blockers.push(...artifactPathBlockers);
30
+ const mutationAllowed = apply && artifactPathBlockers.length === 0;
16
31
  for (const skill of manifest.skills) {
17
32
  const skillDir = path.join(skillsRoot, skill.canonical_name);
18
33
  const file = path.join(skillDir, 'SKILL.md');
19
34
  const desired = renderCoreSkillTemplate(skill.canonical_name);
20
- const current = await readText(file, null);
35
+ const safeCurrent = await readConfinedCoreSkill(skillsBoundary, skill.canonical_name, skillDir, file);
36
+ const current = safeCurrent.text;
21
37
  const beforeSha = typeof current === 'string' ? sha256(current) : null;
22
38
  let action = 'already-current';
23
39
  let backupPath = null;
24
- let blocker = null;
25
- if (current === null) {
40
+ let blocker = safeCurrent.blocker;
41
+ if (blocker) {
42
+ action = 'blocked';
43
+ }
44
+ else if (current === null) {
26
45
  action = 'install-missing-managed-copy';
27
- if (apply) {
28
- await ensureDir(skillDir);
46
+ if (mutationAllowed) {
47
+ await ensureConfinedDirectory(skillsBoundary, skillDir);
29
48
  await writeTextAtomic(file, desired);
30
49
  installed.push(file);
31
50
  }
@@ -35,12 +54,19 @@ export async function syncCoreSkillsIntegrity(input) {
35
54
  }
36
55
  else if (isSksManagedCoreSkillContent(current)) {
37
56
  action = 'restore-corrupted-managed-copy';
38
- if (apply) {
39
- backupPath = path.join(root, '.sneakoscope', 'backups', 'core-skills', skill.canonical_name, `${Date.now()}-${process.pid}.SKILL.md.bak`);
40
- await ensureDir(path.dirname(backupPath));
41
- await fs.writeFile(backupPath, current, 'utf8');
42
- await writeTextAtomic(file, desired);
43
- restored.push(file);
57
+ if (mutationAllowed) {
58
+ const candidateBackupPath = path.join(backupRoot, skill.canonical_name, `${Date.now()}-${process.pid}.SKILL.md.bak`);
59
+ const backupWriteBlocker = await writeConfinedCoreSkillArtifact(root, candidateBackupPath, current, 'backup');
60
+ if (backupWriteBlocker) {
61
+ action = 'blocked';
62
+ blocker = backupWriteBlocker;
63
+ }
64
+ else {
65
+ backupPath = candidateBackupPath;
66
+ await ensureConfinedDirectory(skillsBoundary, skillDir);
67
+ await writeTextAtomic(file, desired);
68
+ restored.push(file);
69
+ }
44
70
  }
45
71
  }
46
72
  else {
@@ -48,7 +74,14 @@ export async function syncCoreSkillsIntegrity(input) {
48
74
  blocker = `user_authored_core_skill_collision:${skill.canonical_name}`;
49
75
  skippedUserAuthored.push(file);
50
76
  }
51
- const after = await readText(file, null);
77
+ const afterInspection = blocker && action === 'blocked'
78
+ ? { text: null, blocker }
79
+ : await readConfinedCoreSkill(skillsBoundary, skill.canonical_name, skillDir, file);
80
+ if (!blocker && afterInspection.blocker) {
81
+ action = 'blocked';
82
+ blocker = afterInspection.blocker;
83
+ }
84
+ const after = afterInspection.text;
52
85
  const afterSha = typeof after === 'string' ? sha256(after) : null;
53
86
  rows.push({
54
87
  canonical_name: skill.canonical_name,
@@ -81,13 +114,129 @@ export async function syncCoreSkillsIntegrity(input) {
81
114
  skipped_user_authored: skippedUserAuthored,
82
115
  blockers
83
116
  };
84
- const reportPath = input.reportPath === null
85
- ? null
86
- : input.reportPath || path.join(root, '.sneakoscope', 'reports', 'core-skill-integrity.json');
87
- if (reportPath)
88
- await writeJsonAtomic(reportPath, report).catch(() => undefined);
117
+ if (reportPath && !reportPathBlocker) {
118
+ const reportWriteBlocker = await writeConfinedCoreSkillReport(root, reportPath, report);
119
+ if (reportWriteBlocker) {
120
+ blockers.push(reportWriteBlocker);
121
+ report.ok = false;
122
+ }
123
+ }
89
124
  return report;
90
125
  }
91
126
  export function coreSkillPath(skillsRoot, name) {
92
127
  return path.join(skillsRoot, currentCoreSkillName(canonicalSkillName(name)), 'SKILL.md');
93
128
  }
129
+ function coreSkillsBoundary(root, skillsRoot) {
130
+ if (isLexicallyConfined(root, skillsRoot))
131
+ return root;
132
+ const parent = path.dirname(skillsRoot);
133
+ return ['.agents', '.codex'].includes(path.basename(parent)) ? path.dirname(parent) : parent;
134
+ }
135
+ async function readConfinedCoreSkill(boundary, skillName, skillDir, file) {
136
+ try {
137
+ const dirInspection = await inspectConfinedPath(boundary, skillDir);
138
+ if (dirInspection.exists && (dirInspection.leafSymlink || !dirInspection.stat?.isDirectory())) {
139
+ return { text: null, blocker: coreSkillPathBlocker(skillName, 'skill_directory_not_safe') };
140
+ }
141
+ const fileInspection = await inspectConfinedPath(boundary, file);
142
+ if (!fileInspection.exists)
143
+ return { text: null, blocker: null };
144
+ if (fileInspection.leafSymlink || !fileInspection.stat?.isFile()) {
145
+ return { text: null, blocker: coreSkillPathBlocker(skillName, 'skill_file_not_safe') };
146
+ }
147
+ return { text: await fs.readFile(file, 'utf8'), blocker: null };
148
+ }
149
+ catch (error) {
150
+ return {
151
+ text: null,
152
+ blocker: coreSkillPathBlocker(skillName, coreSkillPathFailureReason(error))
153
+ };
154
+ }
155
+ }
156
+ function coreSkillPathBlocker(skillName, reason) {
157
+ const canonical = canonicalSkillName(skillName);
158
+ const safeSkillName = isCoreSkillName(canonical) ? canonical : 'unknown';
159
+ return `core_skill_path_unsafe:${safeSkillName}:${reason}`;
160
+ }
161
+ function coreSkillPathFailureReason(error) {
162
+ const code = error && typeof error === 'object' && 'code' in error ? error.code : null;
163
+ if (code === 'managed_path_boundary_missing')
164
+ return 'boundary_missing';
165
+ if (code === 'managed_path_boundary_symlink_refused')
166
+ return 'boundary_symlink';
167
+ if (code === 'managed_path_boundary_not_directory')
168
+ return 'boundary_not_directory';
169
+ if (code === 'managed_path_escape_refused')
170
+ return 'escape_refused';
171
+ if (code === 'managed_path_ancestor_symlink_refused')
172
+ return 'ancestor_symlink';
173
+ if (code === 'managed_path_ancestor_not_directory')
174
+ return 'ancestor_not_directory';
175
+ return 'inspection_failed';
176
+ }
177
+ async function inspectCoreSkillArtifactTarget(root, target, scope, expected) {
178
+ if (!isLexicallyConfined(root, target))
179
+ return coreSkillArtifactBlocker(scope, 'escape_refused');
180
+ try {
181
+ const inspection = await inspectConfinedPath(root, target);
182
+ if (!inspection.exists)
183
+ return null;
184
+ if (inspection.leafSymlink)
185
+ return coreSkillArtifactBlocker(scope, 'leaf_symlink');
186
+ if (expected === 'directory' && !inspection.stat?.isDirectory()) {
187
+ return coreSkillArtifactBlocker(scope, 'not_directory');
188
+ }
189
+ if (expected === 'file' && !inspection.stat?.isFile()) {
190
+ return coreSkillArtifactBlocker(scope, 'not_file');
191
+ }
192
+ return null;
193
+ }
194
+ catch (error) {
195
+ return coreSkillArtifactBlocker(scope, coreSkillArtifactFailureReason(error));
196
+ }
197
+ }
198
+ async function writeConfinedCoreSkillArtifact(root, target, text, scope) {
199
+ try {
200
+ await ensureConfinedDirectory(root, path.dirname(target));
201
+ const blocker = await inspectCoreSkillArtifactTarget(root, target, scope, 'file');
202
+ if (blocker)
203
+ return blocker;
204
+ await writeTextAtomic(target, text);
205
+ return null;
206
+ }
207
+ catch {
208
+ return coreSkillArtifactBlocker(scope, 'write_failed');
209
+ }
210
+ }
211
+ async function writeConfinedCoreSkillReport(root, target, report) {
212
+ try {
213
+ await ensureConfinedDirectory(root, path.dirname(target));
214
+ const blocker = await inspectCoreSkillArtifactTarget(root, target, 'report', 'file');
215
+ if (blocker)
216
+ return blocker;
217
+ await writeJsonAtomic(target, report);
218
+ return null;
219
+ }
220
+ catch {
221
+ return coreSkillArtifactBlocker('report', 'write_failed');
222
+ }
223
+ }
224
+ function coreSkillArtifactBlocker(scope, reason) {
225
+ return `core_skill_artifact_path_unsafe:${scope}:${reason}`;
226
+ }
227
+ function coreSkillArtifactFailureReason(error) {
228
+ const code = error && typeof error === 'object' && 'code' in error ? error.code : null;
229
+ if (code === 'managed_path_boundary_missing')
230
+ return 'boundary_missing';
231
+ if (code === 'managed_path_boundary_symlink_refused')
232
+ return 'boundary_symlink';
233
+ if (code === 'managed_path_boundary_not_directory')
234
+ return 'boundary_not_directory';
235
+ if (code === 'managed_path_escape_refused')
236
+ return 'escape_refused';
237
+ if (code === 'managed_path_ancestor_symlink_refused')
238
+ return 'ancestor_symlink';
239
+ if (code === 'managed_path_ancestor_not_directory')
240
+ return 'ancestor_not_directory';
241
+ return 'inspection_failed';
242
+ }
@@ -1,19 +1,20 @@
1
- import fs from 'node:fs/promises';
2
1
  import path from 'node:path';
3
- import { ensureDir, nowIso, writeJsonAtomic } from '../fsx.js';
2
+ import { nowIso, writeJsonAtomic } from '../fsx.js';
3
+ import { ensureConfinedDirectory, inspectConfinedPath, isLexicallyConfined, moveConfinedPath, removeConfinedDirectoryIfEmpty, removeManagedPathVerified, uniqueConfinedPath } from '../managed-path-safety.js';
4
4
  import { buildSkillRegistryLedger, groupByCanonical } from './skill-registry-ledger.js';
5
+ import { writeRootConfinedJsonReport } from './confined-report-writer.js';
5
6
  export async function dedupeProjectSkills(input) {
6
7
  const root = path.resolve(input.root);
7
8
  const fix = input.fix === true;
8
9
  const yes = input.yes === true;
9
- const ledger = await buildSkillRegistryLedger({ root });
10
+ const ledger = await buildSkillRegistryLedger({ root, reportPath: null });
10
11
  const grouped = groupByCanonical(ledger.entries);
11
12
  const actions = [];
12
13
  const unresolvedUserDuplicates = [];
13
14
  for (const [canonical, group] of grouped.entries()) {
14
15
  if (group.length <= 1)
15
16
  continue;
16
- group.sort(compareSkillPriority);
17
+ group.sort((a, b) => compareSkillPriority(root, a, b));
17
18
  const userEntries = group.filter((entry) => !entry.managed_by_sks);
18
19
  const managedEntries = group.filter((entry) => entry.managed_by_sks);
19
20
  if (userEntries.length > 0 && managedEntries.length > 0) {
@@ -59,7 +60,9 @@ export async function dedupeProjectSkills(input) {
59
60
  const duplicateNames = [...new Set(actions.filter((action) => action.action !== 'kept').map((action) => action.canonical_name))].sort();
60
61
  const afterLedger = await buildSkillRegistryLedger({ root, reportPath: null });
61
62
  const blockers = [
63
+ ...ledger.blockers.filter((blocker) => !blocker.startsWith('duplicate_active_skill_name:')),
62
64
  ...unresolvedUserDuplicates.map((name) => `user_duplicate_requires_confirmation:${name}`),
65
+ ...afterLedger.blockers.filter((blocker) => !blocker.startsWith('duplicate_active_skill_name:')),
63
66
  ...afterLedger.duplicate_active_canonical_names.map((name) => `duplicate_active_skill_name:${name}`)
64
67
  ];
65
68
  const report = {
@@ -75,16 +78,25 @@ export async function dedupeProjectSkills(input) {
75
78
  duplicate_active_canonical_names: afterLedger.duplicate_active_canonical_names,
76
79
  duplicate_canonical_names: duplicateNames,
77
80
  unresolved_user_duplicates: unresolvedUserDuplicates,
78
- blockers
81
+ blockers: [...new Set(blockers)].sort()
79
82
  };
80
83
  const reportPath = input.reportPath === null
81
84
  ? null
82
85
  : input.reportPath || path.join(root, '.sneakoscope', 'reports', 'project-skill-dedupe.json');
83
- if (reportPath)
84
- await writeJsonAtomic(reportPath, report).catch(() => undefined);
86
+ if (reportPath) {
87
+ const written = await writeRootConfinedJsonReport({ root, reportPath, value: report });
88
+ if (!written) {
89
+ report.ok = false;
90
+ report.blockers = [...new Set([...report.blockers, 'project_skill_dedupe_report_path_unsafe'])].sort();
91
+ }
92
+ }
85
93
  return report;
86
94
  }
87
- function compareSkillPriority(a, b) {
95
+ function compareSkillPriority(root, a, b) {
96
+ const confinedA = skillEntryIsLexicallyConfined(root, a) ? 1 : 0;
97
+ const confinedB = skillEntryIsLexicallyConfined(root, b) ? 1 : 0;
98
+ if (confinedA !== confinedB)
99
+ return confinedB - confinedA;
88
100
  const currentA = a.status === 'managed-current' ? 1 : 0;
89
101
  const currentB = b.status === 'managed-current' ? 1 : 0;
90
102
  return currentB - currentA || b.active_priority - a.active_priority || a.path.localeCompare(b.path);
@@ -104,13 +116,23 @@ async function maybeQuarantine(root, canonical, entry, fix, reason) {
104
116
  return quarantineSkill(root, canonical, entry, reason);
105
117
  }
106
118
  async function quarantineSkill(root, canonical, entry, reason) {
119
+ const boundary = path.resolve(root);
107
120
  const sourceDir = path.dirname(entry.path);
121
+ if (!skillEntryIsProjectOwned(boundary, entry))
122
+ return null;
123
+ const sourceInspection = await inspectConfinedPath(boundary, sourceDir);
124
+ if (!sourceInspection.exists)
125
+ return null;
126
+ if (sourceInspection.leafSymlink || !sourceInspection.stat?.isDirectory()) {
127
+ throw new Error(`project_skill_source_not_safe_directory:${sourceDir}`);
128
+ }
108
129
  const stamp = `${Date.now()}-${process.pid}`;
109
- const target = path.join(root, '.sneakoscope', 'quarantine', 'skills', canonical, stamp, path.basename(sourceDir));
110
- await ensureDir(path.dirname(target));
111
- await fs.cp(sourceDir, target, { recursive: true, force: false });
112
- await fs.rm(sourceDir, { recursive: true, force: true });
113
- await writeJsonAtomic(path.join(target, 'quarantine-record.json'), {
130
+ const base = path.join(boundary, '.sneakoscope', 'quarantine', 'skills', canonical, stamp);
131
+ const container = await uniqueConfinedPath(boundary, base);
132
+ const target = path.join(container, path.basename(sourceDir));
133
+ await ensureConfinedDirectory(boundary, container);
134
+ const recordPath = path.join(container, 'quarantine-record.json');
135
+ await writeJsonAtomic(recordPath, {
114
136
  schema: 'sks.skill-quarantine-record.v1',
115
137
  generated_at: nowIso(),
116
138
  source_path: sourceDir,
@@ -119,5 +141,25 @@ async function quarantineSkill(root, canonical, entry, reason) {
119
141
  reason,
120
142
  content_sha256: entry.content_sha256
121
143
  });
144
+ try {
145
+ await moveConfinedPath(boundary, sourceDir, target);
146
+ }
147
+ catch (error) {
148
+ await removeManagedPathVerified(boundary, recordPath).catch(() => undefined);
149
+ await removeConfinedDirectoryIfEmpty(boundary, container).catch(() => undefined);
150
+ throw error;
151
+ }
122
152
  return target;
123
153
  }
154
+ function skillEntryIsLexicallyConfined(root, entry) {
155
+ return isLexicallyConfined(root, path.dirname(entry.path));
156
+ }
157
+ function skillEntryIsProjectOwned(root, entry) {
158
+ if (entry.scope !== 'project')
159
+ return false;
160
+ const sourceDir = path.dirname(entry.path);
161
+ return [
162
+ path.join(root, '.agents', 'skills'),
163
+ path.join(root, '.codex', 'skills')
164
+ ].some((scanRoot) => isLexicallyConfined(scanRoot, sourceDir));
165
+ }
@@ -1,27 +1,54 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import os from 'node:os';
4
- import { nowIso, readText, sha256, writeJsonAtomic } from '../fsx.js';
4
+ import { canonicalFilesystemPath, nowIso, readText, sha256 } from '../fsx.js';
5
+ import { inspectConfinedPath, isLexicallyConfined } from '../managed-path-safety.js';
5
6
  import { buildSksCoreSkillManifest, isSksManagedCoreSkillContent } from './core-skill-manifest.js';
6
7
  import { canonicalSkillName, skillDisplayNameFromMarkdown } from './skill-name-canonicalizer.js';
7
8
  import { loadSkillsManifest } from '../init/skills.js';
9
+ import { writeRootConfinedJsonReport } from './confined-report-writer.js';
8
10
  export async function buildSkillRegistryLedger(input) {
9
11
  const root = path.resolve(input.root);
10
12
  const codexHome = process.env.CODEX_HOME || path.join(os.homedir(), '.codex');
11
- const scanRoots = [
12
- { root: path.join(root, '.agents', 'skills'), scope: 'project', priority: 100 },
13
- { root: path.join(root, '.codex', 'skills'), scope: 'project', priority: 80 },
14
- { root: path.join(os.homedir(), '.agents', 'skills'), scope: 'global', priority: 60 },
15
- { root: path.join(codexHome, 'skills'), scope: 'codex-home', priority: 60 },
13
+ const home = os.homedir();
14
+ const codexHomeBoundary = isLexicallyConfined(home, codexHome) ? home : path.dirname(path.resolve(codexHome));
15
+ const scanRootResolution = await dedupeSkillRegistryScanRoots([
16
+ { root: path.join(root, '.agents', 'skills'), boundary: root, scope: 'project', priority: 100 },
17
+ { root: path.join(root, '.codex', 'skills'), boundary: root, scope: 'project', priority: 80 },
18
+ { root: path.join(home, '.agents', 'skills'), boundary: home, scope: 'global', priority: 60 },
19
+ { root: path.join(codexHome, 'skills'), boundary: codexHomeBoundary, scope: 'codex-home', priority: 60 },
16
20
  ...(input.extraRoots || [])
17
- ];
21
+ ]);
22
+ const scanRoots = scanRootResolution.roots;
18
23
  const manifest = await loadSkillsManifest().catch(() => null);
19
24
  const officialNames = new Set((manifest?.skills || []).map((skill) => canonicalSkillName(skill.canonical_name)));
20
25
  const aliasNames = new Set((manifest?.skills || []).flatMap((skill) => (skill.deprecated_aliases || []).map((name) => canonicalSkillName(name))));
21
- const manifestByName = new Map([
22
- ...buildSksCoreSkillManifest().skills.map((skill) => [skill.canonical_name, skill.content_sha256]),
23
- ...(manifest?.skills || []).map((skill) => [canonicalSkillName(skill.canonical_name), String(skill.content_sha256 || '')])
24
- ]);
26
+ const manifestByName = new Map();
27
+ const managedDigestsByName = new Map();
28
+ const addManagedDigest = (name, digest) => {
29
+ const canonical = canonicalSkillName(String(name || ''));
30
+ const boundedDigest = String(digest || '').toLowerCase();
31
+ if (!canonical || !/^[a-f0-9]{64}$/.test(boundedDigest))
32
+ return;
33
+ const digests = managedDigestsByName.get(canonical) || new Set();
34
+ digests.add(boundedDigest);
35
+ managedDigestsByName.set(canonical, digests);
36
+ };
37
+ for (const skill of buildSksCoreSkillManifest().skills) {
38
+ manifestByName.set(skill.canonical_name, skill.content_sha256);
39
+ addManagedDigest(skill.canonical_name, skill.content_sha256);
40
+ }
41
+ for (const skill of manifest?.skills || []) {
42
+ const canonical = canonicalSkillName(skill?.canonical_name);
43
+ const currentDigest = String(skill?.content_sha256 || '').toLowerCase();
44
+ if (canonical && /^[a-f0-9]{64}$/.test(currentDigest))
45
+ manifestByName.set(canonical, currentDigest);
46
+ for (const name of [canonical, ...(skill?.deprecated_aliases || []).map((alias) => canonicalSkillName(String(alias || '')))]) {
47
+ addManagedDigest(name, currentDigest);
48
+ for (const digest of skill?.hash_history || [])
49
+ addManagedDigest(name, digest);
50
+ }
51
+ }
25
52
  const entries = [];
26
53
  for (const scanRoot of scanRoots) {
27
54
  const rows = await fs.readdir(scanRoot.root, { withFileTypes: true }).catch(() => []);
@@ -29,6 +56,11 @@ export async function buildSkillRegistryLedger(input) {
29
56
  if (!row.isDirectory())
30
57
  continue;
31
58
  const skillPath = path.join(scanRoot.root, row.name, 'SKILL.md');
59
+ if (scanRoot.boundary) {
60
+ const inspection = await inspectConfinedPath(scanRoot.boundary, skillPath).catch(() => null);
61
+ if (!inspection?.exists || inspection.leafSymlink || !inspection.stat?.isFile())
62
+ continue;
63
+ }
32
64
  const text = await readText(skillPath, null);
33
65
  if (typeof text !== 'string')
34
66
  continue;
@@ -36,7 +68,8 @@ export async function buildSkillRegistryLedger(input) {
36
68
  const canonical = canonicalSkillName(displayName || row.name);
37
69
  const hash = sha256(text);
38
70
  const officialName = officialNames.has(canonical) || aliasNames.has(canonical);
39
- const managed = isSksManagedCoreSkillContent(text) || text.includes('BEGIN SKS MANAGED SKILL') || officialName;
71
+ const managed = isRecognizedSksManagedSkillContent(text)
72
+ || Boolean(officialName && managedDigestsByName.get(canonical)?.has(hash));
40
73
  const expected = manifestByName.get(canonical);
41
74
  const status = managed
42
75
  ? expected && expected === hash ? 'managed-current' : 'managed-drift'
@@ -70,11 +103,14 @@ export async function buildSkillRegistryLedger(input) {
70
103
  const activeGrouped = groupByCanonical(activeEntries);
71
104
  const duplicateActiveNames = [...activeGrouped.entries()].filter(([, group]) => group.length > 1).map(([name]) => name).sort();
72
105
  const activeUnique = duplicateActiveNames.length === 0;
73
- const blockers = duplicateActiveNames.map((name) => `duplicate_active_skill_name:${name}`);
106
+ const blockers = [
107
+ ...scanRootResolution.blockers,
108
+ ...duplicateActiveNames.map((name) => `duplicate_active_skill_name:${name}`)
109
+ ];
74
110
  const ledger = {
75
111
  schema: 'sks.skill-registry-ledger.v1',
76
112
  generated_at: nowIso(),
77
- ok: activeUnique,
113
+ ok: activeUnique && blockers.length === 0,
78
114
  root,
79
115
  entries,
80
116
  active_unique_by_canonical_name: activeUnique,
@@ -86,10 +122,95 @@ export async function buildSkillRegistryLedger(input) {
86
122
  const reportPath = input.reportPath === null
87
123
  ? null
88
124
  : input.reportPath || path.join(root, '.sneakoscope', 'reports', 'skill-registry-ledger.json');
89
- if (reportPath)
90
- await writeJsonAtomic(reportPath, ledger).catch(() => undefined);
125
+ if (reportPath) {
126
+ const written = await writeRootConfinedJsonReport({ root, reportPath, value: ledger });
127
+ if (!written) {
128
+ ledger.ok = false;
129
+ ledger.blockers = [...new Set([...ledger.blockers, 'skill_registry_report_path_unsafe'])].sort();
130
+ }
131
+ }
91
132
  return ledger;
92
133
  }
134
+ const SKS_MANAGED_SKILL_MARKER_RE = /BEGIN SKS (?:IMMUTABLE CORE|MANAGED) SKILL/;
135
+ function isRecognizedSksManagedSkillContent(text) {
136
+ return isSksManagedCoreSkillContent(text) || SKS_MANAGED_SKILL_MARKER_RE.test(text);
137
+ }
138
+ async function dedupeSkillRegistryScanRoots(candidates) {
139
+ const byPath = new Map();
140
+ const blockers = [];
141
+ for (const candidate of candidates) {
142
+ const normalized = {
143
+ ...candidate,
144
+ root: path.resolve(candidate.root),
145
+ ...(candidate.boundary ? { boundary: path.resolve(candidate.boundary) } : {})
146
+ };
147
+ if (normalized.boundary) {
148
+ try {
149
+ await fs.lstat(normalized.root);
150
+ }
151
+ catch (error) {
152
+ if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT')
153
+ continue;
154
+ blockers.push(unsafeSkillScanRootBlocker(normalized.scope, 'lstat_failed'));
155
+ continue;
156
+ }
157
+ try {
158
+ const inspection = await inspectConfinedPath(normalized.boundary, normalized.root);
159
+ if (!inspection.exists)
160
+ continue;
161
+ if (inspection.leafSymlink) {
162
+ blockers.push(unsafeSkillScanRootBlocker(normalized.scope, 'leaf_symlink'));
163
+ continue;
164
+ }
165
+ if (!inspection.stat?.isDirectory()) {
166
+ blockers.push(unsafeSkillScanRootBlocker(normalized.scope, 'not_directory'));
167
+ continue;
168
+ }
169
+ }
170
+ catch (error) {
171
+ blockers.push(unsafeSkillScanRootBlocker(normalized.scope, skillScanRootInspectionFailureReason(error)));
172
+ continue;
173
+ }
174
+ }
175
+ const identity = await canonicalFilesystemPath(candidate.root);
176
+ const current = byPath.get(identity);
177
+ if (!current || skillScanScopeRank(normalized.scope) > skillScanScopeRank(current.scope)) {
178
+ byPath.set(identity, normalized);
179
+ }
180
+ }
181
+ return { roots: [...byPath.values()], blockers: [...new Set(blockers)].sort() };
182
+ }
183
+ function unsafeSkillScanRootBlocker(scope, reason) {
184
+ return `unsafe_skill_scan_root:${skillScanRootScopeCode(scope)}:${reason}`;
185
+ }
186
+ function skillScanRootScopeCode(scope) {
187
+ if (scope === 'project' || scope === 'global' || scope === 'codex-home' || scope === 'user')
188
+ return scope;
189
+ return 'unknown';
190
+ }
191
+ function skillScanRootInspectionFailureReason(error) {
192
+ const code = error && typeof error === 'object' && 'code' in error ? error.code : null;
193
+ if (code === 'managed_path_boundary_missing')
194
+ return 'boundary_missing';
195
+ if (code === 'managed_path_boundary_symlink_refused')
196
+ return 'boundary_symlink';
197
+ if (code === 'managed_path_boundary_not_directory')
198
+ return 'boundary_not_directory';
199
+ if (code === 'managed_path_escape_refused')
200
+ return 'escape_refused';
201
+ if (code === 'managed_path_ancestor_symlink_refused')
202
+ return 'ancestor_symlink';
203
+ if (code === 'managed_path_ancestor_not_directory')
204
+ return 'ancestor_not_directory';
205
+ return 'inspection_failed';
206
+ }
207
+ function skillScanScopeRank(scope) {
208
+ if (scope === 'global' || scope === 'codex-home')
209
+ return 3;
210
+ if (scope === 'project')
211
+ return 2;
212
+ return 1;
213
+ }
93
214
  function compareRegistryPriority(a, b, official) {
94
215
  if (official) {
95
216
  const globalA = a.scope === 'global' || a.scope === 'codex-home' ? 1 : 0;