@event4u/agent-config 14.22.0 → 15.0.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/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +333 -356
- package/README.md +1 -1
- package/dist/agent-src/commands/agent-handoff.md +8 -7
- package/dist/agent-src/commands/agents/init.md +1 -1
- package/dist/agent-src/commands/agents/user/accept.md +4 -4
- package/dist/agent-src/commands/agents/user/delete.md +2 -2
- package/dist/agent-src/commands/agents/user/init.md +3 -3
- package/dist/agent-src/commands/agents/user/review.md +3 -3
- package/dist/agent-src/commands/agents/user/show.md +3 -3
- package/dist/agent-src/commands/agents/user/update.md +2 -2
- package/dist/agent-src/commands/agents/user.md +6 -6
- package/dist/agent-src/commands/analytics/prune.md +1 -1
- package/dist/agent-src/commands/analytics/show.md +2 -2
- package/dist/agent-src/commands/analyze/decision.md +2 -2
- package/dist/agent-src/commands/analyze/inbox.md +5 -5
- package/dist/agent-src/commands/analyze/incident.md +3 -3
- package/dist/agent-src/commands/analyze/near-miss.md +3 -3
- package/dist/agent-src/commands/analyze/postmortem.md +4 -4
- package/dist/agent-src/commands/analyze/premortem.md +2 -2
- package/dist/agent-src/commands/analyze.md +2 -2
- package/dist/agent-src/commands/bug/fix.md +1 -1
- package/dist/agent-src/commands/bug/investigate.md +2 -2
- package/dist/agent-src/commands/cost/profile.md +3 -3
- package/dist/agent-src/commands/design.md +1 -1
- package/dist/agent-src/commands/feature/explore.md +1 -1
- package/dist/agent-src/commands/feature/plan.md +2 -2
- package/dist/agent-src/commands/feature/roadmap.md +2 -2
- package/dist/agent-src/commands/ghostwriter/fetch.md +4 -4
- package/dist/agent-src/commands/ghostwriter/list.md +1 -1
- package/dist/agent-src/commands/ghostwriter/show.md +1 -1
- package/dist/agent-src/commands/ghostwriter/write.md +9 -9
- package/dist/agent-src/commands/humanize.md +6 -6
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/judge/solo.md +1 -1
- package/dist/agent-src/commands/judge.md +1 -1
- package/dist/agent-src/commands/knowledge/cross-repo.md +1 -1
- package/dist/agent-src/commands/knowledge/forget.md +1 -1
- package/dist/agent-src/commands/knowledge/ingest.md +2 -2
- package/dist/agent-src/commands/knowledge/list.md +1 -1
- package/dist/agent-src/commands/memory/add.md +3 -3
- package/dist/agent-src/commands/memory/load.md +4 -4
- package/dist/agent-src/commands/memory/mine-session.md +1 -1
- package/dist/agent-src/commands/memory/promote.md +4 -4
- package/dist/agent-src/commands/memory/propose.md +2 -2
- package/dist/agent-src/commands/mode.md +5 -5
- package/dist/agent-src/commands/post-as/ghostwriter.md +3 -3
- package/dist/agent-src/commands/post-as/me.md +7 -7
- package/dist/agent-src/commands/pr/create.md +1 -1
- package/dist/agent-src/commands/pr/merge.md +48 -39
- package/dist/agent-src/commands/profile/activate.md +1 -1
- package/dist/agent-src/commands/profile/show.md +1 -1
- package/dist/agent-src/commands/research/deep.md +2 -2
- package/dist/agent-src/commands/research/report.md +2 -2
- package/dist/agent-src/commands/review/changes.md +1 -1
- package/dist/agent-src/commands/review/routing.md +1 -1
- package/dist/agent-src/commands/roadmap/create.md +1 -1
- package/dist/agent-src/commands/roadmap/materialize.md +2 -2
- package/dist/agent-src/commands/roadmap/next.md +9 -1
- package/dist/agent-src/commands/roadmap/process-full.md +2 -2
- package/dist/agent-src/commands/security-audit-config.md +3 -3
- package/dist/agent-src/commands/skill/preview.md +1 -1
- package/dist/agent-src/commands/skills/discover.md +1 -1
- package/dist/agent-src/commands/sync/agent-settings.md +2 -2
- package/dist/agent-src/commands/sync/gitignore/fix.md +1 -1
- package/dist/agent-src/commands/tests/create.md +1 -1
- package/dist/agent-src/commands/tests/e2e-heal.md +1 -1
- package/dist/agent-src/commands/tests/e2e-plan.md +1 -1
- package/dist/agent-src/contexts/authority/kernel-rule-edits.md +6 -6
- package/dist/agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +1 -2
- package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +2 -2
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +88 -1
- package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +1 -1
- package/dist/agent-src/contexts/contracts/frugality-charter.md +1 -1
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +1 -1
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +1 -1
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +13 -1
- package/dist/agent-src/contexts/execution/cheap-question-mechanics.md +1 -1
- package/dist/agent-src/contexts/execution/contract-decision-sheet.md +3 -3
- package/dist/agent-src/contexts/execution/mandated-lines.md +1 -1
- package/dist/agent-src/contexts/execution/non-interactive-contract.md +1 -1
- package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -1
- package/dist/agent-src/contexts/execution/plan-confidence-gate.md +5 -5
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +1 -1
- package/dist/agent-src/contexts/execution/subagent-modes-detail.md +1 -1
- package/dist/agent-src/contexts/execution/subagent-routing.md +2 -2
- package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +1 -1
- package/dist/agent-src/contexts/execution/user-memory-channels.md +3 -3
- package/dist/agent-src/contexts/execution/verification-mechanics.md +1 -1
- package/dist/agent-src/contexts/judges/persona-voice-rubric.md +2 -2
- package/dist/agent-src/guidelines/abstraction-thresholds.md +88 -0
- package/dist/agent-src/guidelines/agent-infra/5w2h-analysis.md +260 -0
- package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +99 -0
- package/dist/agent-src/guidelines/agent-infra/agent-interaction-and-decision-quality.md +325 -0
- package/dist/agent-src/guidelines/agent-infra/api-cost-levers.md +177 -0
- package/dist/agent-src/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +222 -0
- package/dist/agent-src/guidelines/agent-infra/ask-when-uncertain-demos.md +134 -0
- package/dist/agent-src/guidelines/agent-infra/asking-and-brevity-examples.md +198 -0
- package/dist/agent-src/guidelines/agent-infra/break-glass-usage.md +113 -0
- package/dist/agent-src/guidelines/agent-infra/carve-out-predicates.md +17 -0
- package/dist/agent-src/guidelines/agent-infra/comparison-matrix.md +179 -0
- package/dist/agent-src/guidelines/agent-infra/context-hygiene-mechanics.md +165 -0
- package/dist/agent-src/guidelines/agent-infra/corpus-grounding-authoring.md +91 -0
- package/dist/agent-src/guidelines/agent-infra/critical-thinking.md +156 -0
- package/dist/agent-src/guidelines/agent-infra/cross-source-consistency-mechanics.md +109 -0
- package/dist/agent-src/guidelines/agent-infra/developer-judgment.md +82 -0
- package/dist/agent-src/guidelines/agent-infra/direct-answers-demos.md +142 -0
- package/dist/agent-src/guidelines/agent-infra/domain-adoption-gates.md +112 -0
- package/dist/agent-src/guidelines/agent-infra/domain-eval-anti-pattern.md +53 -0
- package/dist/agent-src/guidelines/agent-infra/domain-pack-architecture.md +56 -0
- package/dist/agent-src/guidelines/agent-infra/downstream-changes-mechanics.md +91 -0
- package/dist/agent-src/guidelines/agent-infra/emphasis-budget.md +45 -0
- package/dist/agent-src/guidelines/agent-infra/engineering-memory-data-format.md +210 -0
- package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
- package/dist/agent-src/guidelines/agent-infra/existence-question-verdicts.md +80 -0
- package/dist/agent-src/guidelines/agent-infra/failure-signatures.md +70 -0
- package/dist/agent-src/guidelines/agent-infra/false-green.md +233 -0
- package/dist/agent-src/guidelines/agent-infra/first-principles.md +192 -0
- package/dist/agent-src/guidelines/agent-infra/framework-neutrality-patterns.md +66 -0
- package/dist/agent-src/guidelines/agent-infra/frontier-reasoning-operating-profile.md +169 -0
- package/dist/agent-src/guidelines/agent-infra/gate-authoring.md +177 -0
- package/dist/agent-src/guidelines/agent-infra/guarded-baseline.md +39 -0
- package/dist/agent-src/guidelines/agent-infra/installed-tools-manifest.md +142 -0
- package/dist/agent-src/guidelines/agent-infra/inversion-thinking.md +388 -0
- package/dist/agent-src/guidelines/agent-infra/ios-simulator-guide.md +378 -0
- package/dist/agent-src/guidelines/agent-infra/language-and-tone-examples.md +141 -0
- package/dist/agent-src/guidelines/agent-infra/layered-settings.md +317 -0
- package/dist/agent-src/guidelines/agent-infra/linked-projects-onboarding-gate.md +80 -0
- package/dist/agent-src/guidelines/agent-infra/mcp-request-signing.md +197 -0
- package/dist/agent-src/guidelines/agent-infra/memory-access.md +149 -0
- package/dist/agent-src/guidelines/agent-infra/mental-models.md +314 -0
- package/dist/agent-src/guidelines/agent-infra/minimal-safe-diff-mechanics.md +241 -0
- package/dist/agent-src/guidelines/agent-infra/missing-tool-handling.md +66 -0
- package/dist/agent-src/guidelines/agent-infra/model-recommendation.md +101 -0
- package/dist/agent-src/guidelines/agent-infra/naming.md +69 -0
- package/dist/agent-src/guidelines/agent-infra/notes-horizon-mechanics.md +90 -0
- package/dist/agent-src/guidelines/agent-infra/output-patterns.md +117 -0
- package/dist/agent-src/guidelines/agent-infra/recurring-criticism-mechanics.md +96 -0
- package/dist/agent-src/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
- package/dist/agent-src/guidelines/agent-infra/review-routing-data-format.md +143 -0
- package/dist/agent-src/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
- package/dist/agent-src/guidelines/agent-infra/roadmap-progress-mechanics.md +274 -0
- package/dist/agent-src/guidelines/agent-infra/role-contracts.md +209 -0
- package/dist/agent-src/guidelines/agent-infra/role-mode-router.md +89 -0
- package/dist/agent-src/guidelines/agent-infra/rule-body-migration-inventory.md +241 -0
- package/dist/agent-src/guidelines/agent-infra/rule-type-governance.md +73 -0
- package/dist/agent-src/guidelines/agent-infra/runtime-layer.md +89 -0
- package/dist/agent-src/guidelines/agent-infra/scqa-framework.md +526 -0
- package/dist/agent-src/guidelines/agent-infra/security-lint-containment.md +121 -0
- package/dist/agent-src/guidelines/agent-infra/self-improvement-pipeline.md +134 -0
- package/dist/agent-src/guidelines/agent-infra/simplicity-and-goal-demos.md +211 -0
- package/dist/agent-src/guidelines/agent-infra/six-hats.md +353 -0
- package/dist/agent-src/guidelines/agent-infra/size-and-scope.md +229 -0
- package/dist/agent-src/guidelines/agent-infra/skill-quality-checklist.md +157 -0
- package/dist/agent-src/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
- package/dist/agent-src/guidelines/agent-infra/symptom-driven-harvest-loop.md +104 -0
- package/dist/agent-src/guidelines/agent-infra/systems-thinking.md +220 -0
- package/dist/agent-src/guidelines/agent-infra/tool-description-as-policy.md +35 -0
- package/dist/agent-src/guidelines/agent-infra/tool-integration.md +73 -0
- package/dist/agent-src/guidelines/agent-infra/traceability-field-mechanics.md +50 -0
- package/dist/agent-src/guidelines/agent-infra/untrusted-input-spotlighting.md +166 -0
- package/dist/agent-src/guidelines/agent-infra/verify-before-complete-demos.md +128 -0
- package/dist/agent-src/guidelines/augment-portability-patterns.md +70 -0
- package/dist/agent-src/guidelines/code-clarity.md +350 -0
- package/dist/agent-src/guidelines/component-oriented-and-oop-development.md +189 -0
- package/dist/agent-src/guidelines/cross-role-handoff.md +127 -0
- package/dist/agent-src/guidelines/design-antipatterns-triggers.json +18 -0
- package/dist/agent-src/guidelines/design-antipatterns.md +327 -0
- package/dist/agent-src/guidelines/design-asset-discipline.md +38 -0
- package/dist/agent-src/guidelines/design-canon.md +63 -0
- package/dist/agent-src/guidelines/design-fidelity-mechanics.md +293 -0
- package/dist/agent-src/guidelines/design-fidelity-routing.md +78 -0
- package/dist/agent-src/guidelines/design-handover-extraction.md +117 -0
- package/dist/agent-src/guidelines/design-modes.md +143 -0
- package/dist/agent-src/guidelines/design-reconciliation.md +172 -0
- package/dist/agent-src/guidelines/docs/readme-size-and-splitting.md +209 -0
- package/dist/agent-src/guidelines/e2e/playwright.md +363 -0
- package/dist/agent-src/guidelines/gtm-handoff.md +114 -0
- package/dist/agent-src/guidelines/monorepo-antipatterns.md +141 -0
- package/dist/agent-src/guidelines/php/api-design.md +115 -0
- package/dist/agent-src/guidelines/php/artisan-commands.md +81 -0
- package/dist/agent-src/guidelines/php/blade-ui.md +78 -0
- package/dist/agent-src/guidelines/php/controllers.md +90 -0
- package/dist/agent-src/guidelines/php/database.md +194 -0
- package/dist/agent-src/guidelines/php/eloquent.md +208 -0
- package/dist/agent-src/guidelines/php/flux.md +80 -0
- package/dist/agent-src/guidelines/php/general.md +207 -0
- package/dist/agent-src/guidelines/php/git.md +164 -0
- package/dist/agent-src/guidelines/php/jobs.md +111 -0
- package/dist/agent-src/guidelines/php/livewire.md +71 -0
- package/dist/agent-src/guidelines/php/logging.md +79 -0
- package/dist/agent-src/guidelines/php/naming.md +89 -0
- package/dist/agent-src/guidelines/php/patterns/dependency-injection.md +57 -0
- package/dist/agent-src/guidelines/php/patterns/dtos.md +199 -0
- package/dist/agent-src/guidelines/php/patterns/events.md +67 -0
- package/dist/agent-src/guidelines/php/patterns/factory.md +53 -0
- package/dist/agent-src/guidelines/php/patterns/pipelines.md +66 -0
- package/dist/agent-src/guidelines/php/patterns/policies.md +66 -0
- package/dist/agent-src/guidelines/php/patterns/repositories.md +122 -0
- package/dist/agent-src/guidelines/php/patterns/service-layer.md +64 -0
- package/dist/agent-src/guidelines/php/patterns/strategy.md +247 -0
- package/dist/agent-src/guidelines/php/patterns.md +28 -0
- package/dist/agent-src/guidelines/php/performance.md +92 -0
- package/dist/agent-src/guidelines/php/php-coding-patterns.md +80 -0
- package/dist/agent-src/guidelines/php/resources.md +100 -0
- package/dist/agent-src/guidelines/php/security.md +110 -0
- package/dist/agent-src/guidelines/php/sql.md +97 -0
- package/dist/agent-src/guidelines/php/validations.md +119 -0
- package/dist/agent-src/guidelines/php/websocket.md +100 -0
- package/dist/agent-src/guidelines/prompt-templates.md +189 -0
- package/dist/agent-src/guidelines/redundancy-taxonomy.md +208 -0
- package/dist/agent-src/guidelines/wing4-handoff.md +127 -0
- package/dist/agent-src/personas/README.md +1 -1
- package/dist/agent-src/personas/_template-specialist/persona.md +1 -1
- package/dist/agent-src/personas/product-owner.md +1 -1
- package/dist/agent-src/rules/active-remediation.md +1 -1
- package/dist/agent-src/rules/architecture.md +2 -2
- package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
- package/dist/agent-src/rules/ask-when-uncertain.md +2 -2
- package/dist/agent-src/rules/brand-source-of-truth.md +9 -7
- package/dist/agent-src/rules/code-comment-discipline.md +2 -2
- package/dist/agent-src/rules/code-provenance.md +1 -1
- package/dist/agent-src/rules/content-quoting-floor.md +1 -1
- package/dist/agent-src/rules/context-hygiene.md +5 -5
- package/dist/agent-src/rules/cross-source-consistency.md +1 -1
- package/dist/agent-src/rules/design-fidelity.md +36 -46
- package/dist/agent-src/rules/direct-answers.md +2 -2
- package/dist/agent-src/rules/domain-adoption-policy.md +1 -1
- package/dist/agent-src/rules/evaluator-independence.md +1 -1
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +1 -1
- package/dist/agent-src/rules/icon-consistency.md +5 -1
- package/dist/agent-src/rules/improve-before-implement.md +1 -1
- package/dist/agent-src/rules/language-and-tone.md +3 -3
- package/dist/agent-src/rules/minimal-safe-diff.md +1 -1
- package/dist/agent-src/rules/notes-first-reasoning.md +36 -25
- package/dist/agent-src/rules/recurring-criticism.md +1 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
- package/dist/agent-src/rules/role-mode-adherence.md +2 -2
- package/dist/agent-src/rules/security-sensitive-stop.md +1 -1
- package/dist/agent-src/rules/size-enforcement.md +1 -1
- package/dist/agent-src/rules/source-confidentiality.md +2 -2
- package/dist/agent-src/rules/think-before-action.md +1 -1
- package/dist/agent-src/rules/token-efficiency.md +7 -5
- package/dist/agent-src/rules/ui-audit-gate.md +3 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +3 -3
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +106 -4
- package/dist/agent-src/skills/activation-design/SKILL.md +2 -2
- package/dist/agent-src/skills/adr-create/SKILL.md +5 -5
- package/dist/agent-src/skills/ai-council/SKILL.md +1 -1
- package/dist/agent-src/skills/ai-council/references/advanced-modes.md +1 -1
- package/dist/agent-src/skills/blade-ui/SKILL.md +1 -1
- package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +1 -1
- package/dist/agent-src/skills/brand-to-tokens/SKILL.md +24 -3
- package/dist/agent-src/skills/bug-analyzer/SKILL.md +1 -1
- package/dist/agent-src/skills/build-buy-partner/SKILL.md +1 -1
- package/dist/agent-src/skills/churn-prevention/SKILL.md +2 -2
- package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -1
- package/dist/agent-src/skills/code-refactoring/SKILL.md +3 -3
- package/dist/agent-src/skills/code-review/SKILL.md +3 -3
- package/dist/agent-src/skills/command-writing/SKILL.md +3 -3
- package/dist/agent-src/skills/comp-banding/SKILL.md +1 -1
- package/dist/agent-src/skills/competitive-moat-analysis/SKILL.md +1 -1
- package/dist/agent-src/skills/competitive-positioning/SKILL.md +2 -2
- package/dist/agent-src/skills/complexity-first-planning/SKILL.md +1 -1
- package/dist/agent-src/skills/condense-memory/SKILL.md +1 -1
- package/dist/agent-src/skills/content-funnel-design/SKILL.md +2 -2
- package/dist/agent-src/skills/contracts-cognition/SKILL.md +1 -1
- package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +2 -2
- package/dist/agent-src/skills/corpus-grounding/SKILL.md +2 -2
- package/dist/agent-src/skills/customer-research/SKILL.md +2 -2
- package/dist/agent-src/skills/dashboard-design/SKILL.md +1 -1
- package/dist/agent-src/skills/data-handling-judgment/SKILL.md +1 -1
- package/dist/agent-src/skills/deal-qualification-meddic/SKILL.md +2 -2
- package/dist/agent-src/skills/decision-record/SKILL.md +3 -3
- package/dist/agent-src/skills/decision-review/SKILL.md +8 -8
- package/dist/agent-src/skills/deep-reading-analyst/SKILL.md +22 -22
- package/dist/agent-src/skills/design-intelligence/SKILL.md +4 -4
- package/dist/agent-src/skills/design-intelligence/references/context-and-registers.md +2 -2
- package/dist/agent-src/skills/design-review/SKILL.md +4 -4
- package/dist/agent-src/skills/design-system-capture/references/design-system-json.md +20 -1
- package/dist/agent-src/skills/design-tokens/SKILL.md +17 -2
- package/dist/agent-src/skills/design-variations/SKILL.md +2 -2
- package/dist/agent-src/skills/developer-like-execution/SKILL.md +2 -2
- package/dist/agent-src/skills/discovery-interview/SKILL.md +2 -2
- package/dist/agent-src/skills/doc-coauthoring/SKILL.md +3 -3
- package/dist/agent-src/skills/editorial-calendar/SKILL.md +2 -2
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +44 -1
- package/dist/agent-src/skills/existing-ui-audit/references/anti-slop-cross-reference.md +2 -2
- package/dist/agent-src/skills/expansion-playbook/SKILL.md +2 -2
- package/dist/agent-src/skills/experiment-loop/SKILL.md +1 -1
- package/dist/agent-src/skills/experiment-loop/references/protocol.md +1 -1
- package/dist/agent-src/skills/fe-design/SKILL.md +3 -3
- package/dist/agent-src/skills/fe-design/references/design-patterns.md +1 -1
- package/dist/agent-src/skills/fe-design/references/design-read-and-memory.md +3 -3
- package/dist/agent-src/skills/fe-design/references/source-led-port.md +1 -1
- package/dist/agent-src/skills/feature-planning/SKILL.md +1 -1
- package/dist/agent-src/skills/flux/SKILL.md +1 -1
- package/dist/agent-src/skills/forecast-accuracy/SKILL.md +2 -2
- package/dist/agent-src/skills/forecasting/SKILL.md +2 -2
- package/dist/agent-src/skills/fundraising-narrative/SKILL.md +2 -2
- package/dist/agent-src/skills/funnel-analysis/SKILL.md +2 -2
- package/dist/agent-src/skills/git-workflow/references/push-closes-its-loop.md +9 -0
- package/dist/agent-src/skills/gtm-launch/SKILL.md +2 -2
- package/dist/agent-src/skills/hiring-loop-design/SKILL.md +1 -1
- package/dist/agent-src/skills/html-deck/SKILL.md +5 -5
- package/dist/agent-src/skills/humanizer/SKILL.md +1 -1
- package/dist/agent-src/skills/humanizer/data/patterns.md +1 -1
- package/dist/agent-src/skills/iconography/SKILL.md +3 -3
- package/dist/agent-src/skills/judge-synthesis/SKILL.md +1 -1
- package/dist/agent-src/skills/laravel-api-endpoint/SKILL.md +2 -2
- package/dist/agent-src/skills/launch-readiness/SKILL.md +3 -3
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +6 -6
- package/dist/agent-src/skills/livewire/SKILL.md +1 -1
- package/dist/agent-src/skills/market-entry-analysis/SKILL.md +1 -1
- package/dist/agent-src/skills/mcp-builder/SKILL.md +1 -1
- package/dist/agent-src/skills/memory-consolidation/SKILL.md +3 -3
- package/dist/agent-src/skills/messaging-architecture/SKILL.md +2 -2
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
- package/dist/agent-src/skills/onboarding-design/SKILL.md +2 -2
- package/dist/agent-src/skills/onboarding-program/SKILL.md +1 -1
- package/dist/agent-src/skills/one-on-one-cadence/SKILL.md +1 -1
- package/dist/agent-src/skills/org-design/SKILL.md +1 -1
- package/dist/agent-src/skills/overbuild-review-lens/SKILL.md +3 -3
- package/dist/agent-src/skills/override-management/SKILL.md +1 -1
- package/dist/agent-src/skills/perf-feedback-craft/SKILL.md +1 -1
- package/dist/agent-src/skills/persona-writing/SKILL.md +1 -1
- package/dist/agent-src/skills/php-coder/SKILL.md +1 -1
- package/dist/agent-src/skills/pipeline-strategy/SKILL.md +2 -2
- package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -3
- package/dist/agent-src/skills/po-discovery/SKILL.md +1 -1
- package/dist/agent-src/skills/positioning-strategy/SKILL.md +2 -2
- package/dist/agent-src/skills/privacy-review/SKILL.md +1 -1
- package/dist/agent-src/skills/prompt-optimizer/SKILL.md +3 -3
- package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
- package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +2 -2
- package/dist/agent-src/skills/receiving-code-review/SKILL.md +1 -1
- package/dist/agent-src/skills/refine-ticket/SKILL.md +2 -2
- package/dist/agent-src/skills/release-comms/SKILL.md +2 -2
- package/dist/agent-src/skills/retention-loops/SKILL.md +2 -2
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-management/SKILL.md +1 -1
- package/dist/agent-src/skills/roadmap-management/references/archival.md +1 -1
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +5 -5
- package/dist/agent-src/skills/rule-writing/SKILL.md +6 -6
- package/dist/agent-src/skills/runway-cognition/SKILL.md +2 -2
- package/dist/agent-src/skills/scenario-modeling/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-writing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-writing/references/procedure.md +1 -1
- package/dist/agent-src/skills/skill-writing/references/section-patterns.md +3 -3
- package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +1 -1
- package/dist/agent-src/skills/stakeholder-tradeoff/SKILL.md +3 -3
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
- package/dist/agent-src/skills/supply-chain-intake/SKILL.md +1 -1
- package/dist/agent-src/skills/systematic-debugging/SKILL.md +2 -2
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +60 -4
- package/dist/agent-src/skills/throughput-vs-morale-tradeoff/SKILL.md +1 -1
- package/dist/agent-src/skills/token-optimizer/SKILL.md +1 -1
- package/dist/agent-src/skills/typography-system/SKILL.md +2 -2
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +28 -8
- package/dist/agent-src/skills/unit-economics-modeling/SKILL.md +2 -2
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +1 -1
- package/dist/agent-src/skills/validate-feature-fit/SKILL.md +2 -2
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +2 -2
- package/dist/agent-src/skills/vision-articulation/SKILL.md +1 -1
- package/dist/agent-src/skills/voc-extract/SKILL.md +2 -2
- package/dist/agent-src/skills/voice-and-tone-design/SKILL.md +2 -2
- package/dist/agent-src/skills/wireframe/SKILL.md +1 -1
- package/dist/agent-src/skills/workspace-link/SKILL.md +1 -1
- package/dist/agent-src/templates/agent-settings.md +6 -6
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/contexts/knowledge-pages.md +2 -3
- package/dist/agent-src/templates/copilot-instructions.md +1 -1
- package/dist/agent-src/templates/roadmaps.md +1 -1
- package/dist/agent-src/templates/scripts/README.md +2 -2
- package/dist/agent-src/user-types/_template/user-type.md +1 -1
- package/dist/cli/registry.js +1 -1
- package/dist/cli-delegate/archive_completed_roadmaps.js +52 -4
- package/dist/cli-delegate/check_update_banner.js +12 -1
- package/dist/cli-delegate/{chunk-TGIPZBCW.js → chunk-2KKXJW25.js} +22 -8
- package/dist/cli-delegate/{chunk-NLP54U3J.js → chunk-2XY7ILBT.js} +13 -1
- package/dist/cli-delegate/{chunk-4FS4WRXP.js → chunk-3FKR64R5.js} +34 -6
- package/dist/cli-delegate/{chunk-J3RFNKG4.js → chunk-55ACLDUE.js} +2 -2
- package/dist/cli-delegate/{chunk-PKOBQADP.js → chunk-57PN4GYJ.js} +1 -1
- package/dist/cli-delegate/{chunk-BIXEDQPZ.js → chunk-AK6HODNQ.js} +4 -4
- package/dist/cli-delegate/{chunk-2FTMENJL.js → chunk-GYC3VRYN.js} +1 -1
- package/dist/cli-delegate/{chunk-LWTYTX6F.js → chunk-HZ52BRGG.js} +24 -18
- package/dist/cli-delegate/{chunk-6RJA2F5A.js → chunk-IVBPRCQO.js} +1 -1
- package/dist/cli-delegate/{chunk-I6RHFQEG.js → chunk-YUM5KURG.js} +17 -1
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_explain.js +2 -2
- package/dist/cli-delegate/cmd_export.js +4 -4
- package/dist/cli-delegate/cmd_handoff.js +24 -16
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_memory_get.js +1 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +4 -4
- package/dist/cli-delegate/cmd_route_audit.js +3 -3
- package/dist/cli-delegate/cmd_route_explain.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +4 -14
- package/dist/cli-delegate/cmd_settings_get.js +15 -9
- package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
- package/dist/cli-delegate/cmd_settings_set.js +41 -11
- package/dist/cli-delegate/cmd_sync.js +4 -4
- package/dist/cli-delegate/cmd_uninstall.js +4 -4
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +1 -1
- package/dist/cli-delegate/cmd_validate.js +4 -4
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +27 -80
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +5 -7
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +4 -6
- package/dist/hooks/dispatch.js +9249 -8981
- package/dist/install/install.mjs +47 -8
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +5496 -2400
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +73 -0
- package/dist/scripts/_lib/agent_src.js +20 -0
- package/dist/scripts/_lib/guidelines_lane.js +158 -0
- package/dist/scripts/_lib/lean_projection_mode.js +108 -0
- package/dist/scripts/_lib/router_match.js +243 -0
- package/dist/scripts/_lib/rule_injection.js +216 -0
- package/dist/scripts/condense.js +22 -25
- package/dist/scripts/project_thin_rules.js +139 -19
- package/dist/server/io/yamlIO.js +125 -17
- package/dist/server/schemas/settings.js +32 -5
- package/dist/shared/settingsSurface.js +6 -1
- package/docs/MIGRATION.md +56 -0
- package/docs/contracts/settings-classes.md +48 -7
- package/docs/guidelines/abstraction-thresholds.md +35 -0
- package/docs/guidelines/agent-infra/active-remediation-mechanics.md +3 -3
- package/docs/guidelines/agent-infra/false-green.md +2 -2
- package/docs/guidelines/agent-infra/notes-horizon-mechanics.md +90 -0
- package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
- package/docs/guidelines/agent-infra/skill-quality-checklist.md +1 -1
- package/docs/guidelines/design-fidelity-mechanics.md +4 -0
- package/docs/guidelines/design-fidelity-routing.md +78 -0
- package/docs/guidelines/design-reconciliation.md +172 -0
- package/docs/guidelines/gtm-handoff.md +2 -2
- package/docs/guidelines/wing4-handoff.md +2 -2
- package/llms.txt +1 -1
- package/package.json +7 -3
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +106 -4
- package/src/config/agent-settings.template.yml +94 -1
- package/src/config/ci-local-parity.yml +34 -0
- package/src/config/continuity-surface.json +8 -29
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +31 -8
- package/src/config/gate-reachability-exemptions.json +1 -0
- package/src/config/gate-violation-baselines.json +3 -3
- package/src/config/hook-token-budget.json +8 -7
- package/src/config/host-injection-effect.json +2 -2
- package/src/config/pack-size-budget.json +55 -4
- package/src/config/packed-binary-manifest.json +1 -1
- package/src/config/platform-anchor.json +47 -0
- package/src/config/preamble-payload-budget.json +2 -3
- package/src/config/publish-surface.json +4 -2
- package/src/config/ratification-policy.json +7 -0
- package/src/config/routing-coverage-seed.json +9 -2
- package/src/config/rule-stub-ceilings.json +16 -9
- package/src/scripts/_cli/cmd_session_recycle.ts +2 -25
- package/src/scripts/_cli/cmd_settings_get.ts +22 -7
- package/src/scripts/_cli/handoff_sessions.ts +14 -44
- package/src/scripts/_lib/agent_settings.ts +85 -0
- package/src/scripts/_lib/agent_src.ts +21 -0
- package/src/scripts/_lib/artifact_maturity.ts +242 -0
- package/src/scripts/_lib/conformance_report.ts +403 -0
- package/src/scripts/_lib/continuity_slot.ts +295 -0
- package/src/scripts/_lib/continuity_writer.ts +312 -0
- package/src/scripts/_lib/design_system_import.ts +20 -0
- package/src/scripts/_lib/design_tolerance.ts +281 -0
- package/src/scripts/_lib/guidelines_lane.ts +164 -0
- package/src/scripts/_lib/hook_settings.ts +85 -0
- package/src/scripts/_lib/lean_projection_mode.ts +127 -0
- package/src/scripts/_lib/obligation_frequency.ts +2 -3
- package/src/scripts/_lib/packed_binary_predicate.ts +37 -0
- package/src/scripts/_lib/platform_anchor.ts +1053 -0
- package/src/scripts/_lib/ratification_artifact.ts +278 -0
- package/src/scripts/_lib/recycle_envelope_paths.ts +109 -21
- package/src/scripts/_lib/regression_neighbourhood.ts +159 -22
- package/src/scripts/_lib/security_lint.ts +23 -2
- package/src/scripts/_lib/self_repair.ts +21 -0
- package/src/scripts/_lib/session_eol.ts +44 -0
- package/src/scripts/_lib/session_index_trust.ts +387 -0
- package/src/scripts/_lib/standing_bound_ratchet.ts +220 -0
- package/src/scripts/_lib/tolerance_shadow.ts +177 -0
- package/src/scripts/_lib/vendored_grammar_upstream.ts +280 -0
- package/src/scripts/ai_council/redact_low_impact_entry.ts +8 -0
- package/src/scripts/audit_mcp_tools.ts +69 -25
- package/src/scripts/autonomy_friction_traffic.ts +379 -0
- package/src/scripts/build_mcp_catalog.ts +24 -1
- package/src/scripts/check_host_tree_parity.ts +291 -0
- package/src/scripts/check_kernel_edit_ratified.ts +462 -0
- package/src/scripts/check_loss_class_declared.ts +793 -46
- package/src/scripts/check_platform_anchor.ts +390 -0
- package/src/scripts/check_preamble_payload_budget.ts +424 -7
- package/src/scripts/check_projected_rule_routes.ts +395 -0
- package/src/scripts/check_rule_projection_integrity.ts +102 -2
- package/src/scripts/ci_settle.ts +205 -5
- package/src/scripts/code_graph/build.ts +79 -0
- package/src/scripts/code_graph/cli.ts +264 -7
- package/src/scripts/code_graph/detect.ts +38 -0
- package/src/scripts/code_graph/query.ts +25 -2
- package/src/scripts/code_graph/sqlite_store.ts +16 -1
- package/src/scripts/code_graph/types.ts +52 -3
- package/src/scripts/code_graph/validate.ts +3 -1
- package/src/scripts/code_graph/verbs.ts +590 -0
- package/src/scripts/condense.ts +22 -26
- package/src/scripts/generate_host_cost_table.ts +354 -0
- package/src/scripts/handoff_context_hook.ts +39 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +59 -28
- package/src/scripts/hooks/block_speaking_inbox_dir.ts +182 -16
- package/src/scripts/hooks/category_a.ts +1 -1
- package/src/scripts/hooks/chain_nudge_hook.ts +311 -25
- package/src/scripts/hooks/code_graph_context_hook.ts +7 -18
- package/src/scripts/hooks/push_settle_hook.ts +3 -2
- package/src/scripts/hooks/rule_inject_hook.ts +107 -20
- package/src/scripts/hooks/session_eol_hook.ts +177 -145
- package/src/scripts/hooks/source_first_gate_hook.ts +12 -0
- package/src/scripts/hooks/ui_route_nudge_hook.ts +52 -15
- package/src/scripts/hot_context_hook.ts +103 -408
- package/src/scripts/lint_evidence_artifacts.ts +1 -0
- package/src/scripts/lint_knowledge_scale.ts +0 -26
- package/src/scripts/lint_roadmap_blockers.ts +164 -1
- package/src/scripts/mcp_server/consumer_tool_catalog.json +152 -2
- package/src/scripts/mcp_server/graph_tools.ts +294 -0
- package/src/scripts/mcp_server/path_util.ts +31 -0
- package/src/scripts/mcp_server/tool_catalog_source.ts +7 -1
- package/src/scripts/mcp_server/tools.ts +3 -13
- package/src/scripts/memory_lookup.ts +9 -9
- package/src/scripts/model_rule_injection.ts +61 -4
- package/src/scripts/project_thin_rules.ts +149 -16
- package/src/scripts/report_standing_payload_by_host.ts +650 -0
- package/src/scripts/schemas/agent-settings.schema.json +7 -1
- package/src/scripts/session_memory_index.ts +86 -8
- package/src/scripts/sync_agent_settings.ts +270 -10
- package/src/server/io/yamlIO.ts +127 -17
- package/src/server/schemas/settings.ts +45 -6
- package/src/shared/settingsSurface.ts +13 -2
- package/src/templates/compact-instructions.md +8 -3
- package/src/vendor/grammars/README.md +27 -2
- package/dist/agent-src/commands/chat-history/import.md +0 -170
- package/dist/agent-src/commands/chat-history.md +0 -63
|
@@ -149,18 +149,39 @@ export function path_weight(rel_path: string): number {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
const PROJECTION_PREFIX = 'dist/agent-src/';
|
|
152
|
+
/**
|
|
153
|
+
* Lanes whose source does NOT live under `src/`. The projection folds several
|
|
154
|
+
* trees into one output directory, so the `src/` default below is right for
|
|
155
|
+
* most of it and wrong for these.
|
|
156
|
+
*/
|
|
157
|
+
const PROJECTION_SOURCE_LANES: ReadonlyArray<readonly [string, string]> = [
|
|
158
|
+
// The guidelines lane copies `docs/guidelines/` (`_lib/guidelines_lane.ts`),
|
|
159
|
+
// not `src/guidelines/`, which does not exist. Without this row a projected
|
|
160
|
+
// guideline gets a DIFFERENT identity from its own source, so a bound
|
|
161
|
+
// pragma written in the source cannot suppress the projection's copy of the
|
|
162
|
+
// very same line — measured on
|
|
163
|
+
// `untrusted-input-spotlighting.md`, a defense guideline that quotes
|
|
164
|
+
// role-takeover phrases to teach refusal and carries three accepted
|
|
165
|
+
// fingerprints for exactly that.
|
|
166
|
+
['guidelines/', 'docs/guidelines/'],
|
|
167
|
+
];
|
|
152
168
|
|
|
153
169
|
/**
|
|
154
170
|
* Fold a projected path back onto the source it was copied from.
|
|
155
171
|
*
|
|
156
|
-
* `dist/agent-src/` is a byte-for-byte copy of
|
|
172
|
+
* `dist/agent-src/` is a byte-for-byte copy of its sources with paths rewritten
|
|
157
173
|
* (ADR-201), so an artifact and its projection are the same artifact for the
|
|
158
174
|
* purpose of "which evidence did a human accept". Two identities would mean two
|
|
159
175
|
* fingerprints for one accepted line, and only one of them could be written
|
|
160
176
|
* into the pragma the projection copies verbatim.
|
|
161
177
|
*/
|
|
162
178
|
export function source_identity(rel: string): string {
|
|
163
|
-
|
|
179
|
+
if (!rel.startsWith(PROJECTION_PREFIX)) return rel;
|
|
180
|
+
const tail = rel.slice(PROJECTION_PREFIX.length);
|
|
181
|
+
for (const [lane, sourceRoot] of PROJECTION_SOURCE_LANES) {
|
|
182
|
+
if (tail.startsWith(lane)) return sourceRoot + tail.slice(lane.length);
|
|
183
|
+
}
|
|
184
|
+
return `src/${tail}`;
|
|
164
185
|
}
|
|
165
186
|
|
|
166
187
|
/** A file pre-split into lines with a fence/pragma mask the linters reuse. */
|
|
@@ -24,6 +24,27 @@
|
|
|
24
24
|
*
|
|
25
25
|
* Everything in this module is pure and clock-injected so the detectors can be
|
|
26
26
|
* unit-tested without a host, a transcript, or a network.
|
|
27
|
+
*
|
|
28
|
+
* loss_class: ephemeral-lossy
|
|
29
|
+
*
|
|
30
|
+
* `sanitizeEvidence` replaces home paths and e-mail addresses with placeholders
|
|
31
|
+
* and hard-cuts the span at `MAX_EVIDENCE`. It owes no recovery locator and
|
|
32
|
+
* must not have one: storing what was dropped for privacy would defeat the
|
|
33
|
+
* reason it was dropped, which is the same ruling the retired `hot_context_hook`
|
|
34
|
+
* carried. `egressBlockedReason` is the gate; this is a narrowing pass.
|
|
35
|
+
*
|
|
36
|
+
* THE GATE DOES NOT SEE THAT CAP, and the declaration is here anyway.
|
|
37
|
+
* `check_loss_class_declared`'s cap pattern requires a unit word followed by a
|
|
38
|
+
* size noun (`ROW_CAP`, `WORD_CHARS`), so `MAX_EVIDENCE` does not match it.
|
|
39
|
+
* What pulls this module into the corpus is `\bredact` firing on the
|
|
40
|
+
* `redact_low_impact_entry` identifier imported just below — for the EGRESS
|
|
41
|
+
* gate, which loses nothing. So the real lossy operation in this file is
|
|
42
|
+
* declared and unenforced, and the enforcement rests on an unrelated import:
|
|
43
|
+
* rename or drop that import and this module leaves the corpus while still
|
|
44
|
+
* cutting the span. Widening the pattern to any `MAX_<WORD>` was measured and
|
|
45
|
+
* refused (it admits seven constants that cut nothing — see that gate's
|
|
46
|
+
* docstring), so the mismatch is recorded rather than closed. Keep this
|
|
47
|
+
* declaration on its own merits, not because the gate is watching.
|
|
27
48
|
*/
|
|
28
49
|
import { createHash } from 'node:crypto';
|
|
29
50
|
|
|
@@ -269,6 +269,50 @@ export function readEolCounters(
|
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Committed substantive-content floor, in parsed transcript tokens (billable
|
|
274
|
+
* input of the last main-chain assistant record, per `cc_transcript.ts`) — the
|
|
275
|
+
* OR-arm for a session that produced real discussion without ever calling a
|
|
276
|
+
* tool.
|
|
277
|
+
*
|
|
278
|
+
* Derivation (`agents/evidence/analysis/handoff-substantive-threshold.md`, code-comment-allow provenance-comment -- unchanged relocation of a docblock whose whole point is that this threshold may only move on cited evidence
|
|
279
|
+
* 217 sessions of the local Claude store, 2026-08-10): 206 of the 207 sessions
|
|
280
|
+
* carrying an assistant record also carry a `tool_use` block, so this arm
|
|
281
|
+
* serves the ~0.5 % tail and the hosts whose transcripts log no tool blocks at
|
|
282
|
+
* all. 10 000 sits **25× below** the p10 of real working sessions (254 939),
|
|
283
|
+
* so it cannot hide one, and above a single trivial exchange. Changing it is a
|
|
284
|
+
* PR citing evidence, never a drive-by edit.
|
|
285
|
+
*/
|
|
286
|
+
export const SUBSTANTIVE_TOKEN_FLOOR = 10_000;
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Does this session hold anything worth resuming?
|
|
290
|
+
*
|
|
291
|
+
* `≥ 1 assistant turn AND (≥ 1 tool call OR parsed tokens ≥ the committed
|
|
292
|
+
* floor)`, read from the counts-only session-eol state.
|
|
293
|
+
*
|
|
294
|
+
* **Fail-open, deliberately** (Phase 1.2): absent, unreadable or mis-shaped
|
|
295
|
+
* state LISTS the candidate rather than filtering it, and a `tool_calls` key
|
|
296
|
+
* missing from a state file written before that counter existed reads as
|
|
297
|
+
* *unknown*, never as zero. A wrongly listed candidate is noise the user
|
|
298
|
+
* scrolls past; a wrongly hidden one is data loss they cannot even see.
|
|
299
|
+
*/
|
|
300
|
+
export function is_substantive(counters: StoredEolCounters | null): boolean {
|
|
301
|
+
if (counters === null) return true;
|
|
302
|
+
// Every "unknown" below is a NUMBER test, not an `=== undefined` test.
|
|
303
|
+
// Absent, null and NaN are all unknown, and each one reaches this code by
|
|
304
|
+
// a real path: a state file written before the counter existed is absent,
|
|
305
|
+
// `JSON.stringify` turns NaN into null on the way to disk, and a
|
|
306
|
+
// half-written file yields a parseable object with missing keys. Reading
|
|
307
|
+
// any of them as "counted zero" hides a session that did real work.
|
|
308
|
+
if (!Number.isFinite(counters.assistant_records)) return true;
|
|
309
|
+
if ((counters.assistant_records as number) < 1) return false;
|
|
310
|
+
if (!Number.isFinite(counters.tool_calls)) return true;
|
|
311
|
+
if ((counters.tool_calls as number) >= 1) return true;
|
|
312
|
+
if (!Number.isFinite(counters.final_context_tokens)) return true;
|
|
313
|
+
return (counters.final_context_tokens as number) >= SUBSTANTIVE_TOKEN_FLOOR;
|
|
314
|
+
}
|
|
315
|
+
|
|
272
316
|
export interface NewLinesRead {
|
|
273
317
|
/** The complete lines appended since `fromByte` (possibly empty). */
|
|
274
318
|
text: string;
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The trust contract for the session-start memory index.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS, AND WHOSE RULING IT IMPLEMENTS.
|
|
5
|
+
*
|
|
6
|
+
* The `memory.session_index` block injects curated memory at `session_start`.
|
|
7
|
+
* Restored memory is UNTRUSTED CONTEXT arriving on an injection surface, and an
|
|
8
|
+
* AI council (2026-09-07, ruling D3, recorded in
|
|
9
|
+
* `road-to-continuity-writer-activation` step 3.1) required six properties —
|
|
10
|
+
* repository and worktree identity, path canonicalization, freshness, ordering,
|
|
11
|
+
* duplicate invocation and size limits — each with a test, BEFORE the restore
|
|
12
|
+
* moves off the `hot-context` concern. Five of the six did not exist: measured
|
|
13
|
+
* at HEAD, `session_memory_index.ts` implemented size limits only. This module
|
|
14
|
+
* is those six in one place, so the relocation has something to move.
|
|
15
|
+
*
|
|
16
|
+
* THE THREAT, STATED CONCRETELY RATHER THAN AS A CATEGORY.
|
|
17
|
+
*
|
|
18
|
+
* `MEMORY_ROOT` in `memory_lookup.ts` is the RELATIVE path `agents/memory`, so
|
|
19
|
+
* it resolves against the process cwd. The hook therefore chdirs to a workspace
|
|
20
|
+
* root it received from a host payload and reads memory from wherever that
|
|
21
|
+
* landed. Nothing checked that the root was the workspace the session belongs
|
|
22
|
+
* to, nothing resolved symlinks before trusting it, and nothing stopped a second
|
|
23
|
+
* `session_start` in one session from injecting the block twice. So the
|
|
24
|
+
* attacker this module answers is not an intruder: it is a wrong or stale root —
|
|
25
|
+
* a sibling checkout, a worktree pointed at another tree, a leftover directory,
|
|
26
|
+
* a symlink out of the workspace — serving another repository's curated memory
|
|
27
|
+
* into this session as though it were this repository's.
|
|
28
|
+
*
|
|
29
|
+
* WHAT IT DOES NOT CLAIM.
|
|
30
|
+
*
|
|
31
|
+
* It does not authenticate the memory's CONTENT. A curated entry that is wrong,
|
|
32
|
+
* or hostile, and sits at the correct path inside the correct workspace passes
|
|
33
|
+
* every property here — that is the review boundary of `agents/memory/`, not a
|
|
34
|
+
* check's. Nor does it make the index trustworthy in the sense that a model may
|
|
35
|
+
* act on it: the block stays spotlighted as DATA, per `untrusted-input-defense`,
|
|
36
|
+
* and this module bounds only WHICH bytes reach that block.
|
|
37
|
+
*
|
|
38
|
+
* loss_class: recoverable-lossy
|
|
39
|
+
* loss_recovery: agents/memory/ — every row the P6 cap drops is a projection of
|
|
40
|
+
* a curated entry that stays on disk untouched and stays addressable by id
|
|
41
|
+
* through `agent-config memory:lookup` / `memory:get`.
|
|
42
|
+
*
|
|
43
|
+
* The cap bounds what the index ADVERTISES, never what the corpus holds, which
|
|
44
|
+
* is why this is not `ephemeral-lossy`: nothing is destroyed, and the drop is a
|
|
45
|
+
* cost bound rather than a privacy one. The retired `hot_context_hook` went the
|
|
46
|
+
* other way for exactly that reason — storing a recovery for a line dropped for
|
|
47
|
+
* privacy would have defeated the reason it was dropped. Nothing here is
|
|
48
|
+
* dropped for privacy.
|
|
49
|
+
*/
|
|
50
|
+
import * as fs from 'node:fs';
|
|
51
|
+
import * as path from 'node:path';
|
|
52
|
+
|
|
53
|
+
/** P6 — the row cap. Owned here so all six properties read from one place. */
|
|
54
|
+
export const SESSION_INDEX_ROW_CAP = 30;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* P3 — the abandonment bound, in days.
|
|
58
|
+
*
|
|
59
|
+
* A STATED DEFAULT, NOT A MEASURED OPTIMUM, said plainly because a number that
|
|
60
|
+
* looks derived and is not is worse than an admitted guess. Curated memory is
|
|
61
|
+
* deliberately long-lived — a stable `product-rules.yml` is not stale at 90
|
|
62
|
+
* days — so the bound is set well beyond any legitimate quiet period and exists
|
|
63
|
+
* to catch an ABANDONED root, not an inactive one. The two conditions that
|
|
64
|
+
* would falsify it are recorded in `road-to-continuity-writer-activation`
|
|
65
|
+
* step 3.1 rather than here.
|
|
66
|
+
*/
|
|
67
|
+
export const MAX_ROOT_AGE_DAYS = 400;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* P3's other direction — how far ahead of now a source mtime may sit.
|
|
71
|
+
*
|
|
72
|
+
* A STATED DEFAULT, on the same terms as `MAX_ROOT_AGE_DAYS` above, and written
|
|
73
|
+
* down because a 14.23.0 self-review finding named it as the one threshold in
|
|
74
|
+
* this module carrying no threat model while its neighbour carried one. That
|
|
75
|
+
* asymmetry was the real defect; the number was not.
|
|
76
|
+
*
|
|
77
|
+
* What the grace is FOR: ordinary clock disagreement. An NTP correction, a
|
|
78
|
+
* resumed VM snapshot, or a filesystem whose mtime comes from a host with a
|
|
79
|
+
* slightly different clock can date a file a few seconds ahead of this process
|
|
80
|
+
* without anything being wrong. Zero grace would refuse those, and a refusal
|
|
81
|
+
* there costs the session its memory index for a reason the operator cannot act
|
|
82
|
+
* on.
|
|
83
|
+
*
|
|
84
|
+
* What it is NOT for, stated because the finding read it as an attack window:
|
|
85
|
+
* it buys an attacker nothing. Writing a curated source requires write access
|
|
86
|
+
* INSIDE the workspace, and an attacker holding that can date the file at `now`
|
|
87
|
+
* and pass P3 outright — a future date is strictly worse for them. Freshness
|
|
88
|
+
* here bounds an ABANDONED root, not a hostile one; the module's own docblock
|
|
89
|
+
* says content authenticity is out of scope and that boundary is unchanged.
|
|
90
|
+
*
|
|
91
|
+
* The grace is only harmless while that reading holds. If this check is ever
|
|
92
|
+
* repurposed as a content-integrity control, or a measured population of
|
|
93
|
+
* legitimate skew exceeds the value, the number has to be derived rather than
|
|
94
|
+
* stated.
|
|
95
|
+
*/
|
|
96
|
+
export const MAX_FUTURE_SKEW_MS = 60_000;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Curated sources, matching the layouts `memory_lookup._iter_curated_entries`
|
|
100
|
+
* actually reads: `<root>/<type>.yml` AND `<root>/<type>/**\/*.yml`, plus the
|
|
101
|
+
* agent-written `intake/*.jsonl`. Reading only the first of those is what made
|
|
102
|
+
* P3 silently no-op on two of the three layouts — R2 finding 4.
|
|
103
|
+
*/
|
|
104
|
+
const CURATED_SUFFIXES = ['.yml', '.yaml', '.jsonl'] as const;
|
|
105
|
+
|
|
106
|
+
/** Depth bound on the walk. A memory root is shallow; a cycle is not. */
|
|
107
|
+
const MAX_WALK_DEPTH = 8;
|
|
108
|
+
|
|
109
|
+
export type TrustRefusalCode =
|
|
110
|
+
| 'workspace-root-unresolvable'
|
|
111
|
+
| 'memory-root-absent'
|
|
112
|
+
| 'memory-root-escapes-workspace'
|
|
113
|
+
| 'curated-source-escapes-workspace'
|
|
114
|
+
| 'source-mtime-in-future'
|
|
115
|
+
| 'memory-root-abandoned'
|
|
116
|
+
| 'already-injected-this-session';
|
|
117
|
+
|
|
118
|
+
export interface TrustRefusal {
|
|
119
|
+
readonly ok: false;
|
|
120
|
+
readonly code: TrustRefusalCode;
|
|
121
|
+
readonly detail: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface TrustGrant {
|
|
125
|
+
readonly ok: true;
|
|
126
|
+
/** Canonical, containment-checked absolute path to the memory root. */
|
|
127
|
+
readonly memoryRoot: string;
|
|
128
|
+
/** Canonical absolute path to the workspace the root was checked against. */
|
|
129
|
+
readonly workspaceRoot: string;
|
|
130
|
+
/** P3 — mtime of the newest curated source read, epoch ms; 0 when none. */
|
|
131
|
+
readonly newestSourceMs: number;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export type TrustVerdict = TrustGrant | TrustRefusal;
|
|
135
|
+
|
|
136
|
+
function refuse(code: TrustRefusalCode, detail: string): TrustRefusal {
|
|
137
|
+
return { ok: false, code, detail };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* P2 — canonicalize, then compare by SEGMENTS.
|
|
142
|
+
*
|
|
143
|
+
* A string prefix test says `/a/bc` is inside `/a/b`, which is how a
|
|
144
|
+
* containment check passes something it should refuse. Splitting on the
|
|
145
|
+
* separator makes the comparison mean what it says.
|
|
146
|
+
*/
|
|
147
|
+
export function isContained(child: string, parent: string): boolean {
|
|
148
|
+
const rel = path.relative(parent, child);
|
|
149
|
+
if (rel === '') return true;
|
|
150
|
+
if (path.isAbsolute(rel)) return false;
|
|
151
|
+
return !rel.split(path.sep).includes('..');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Canonicalize a path, following symlinks. `null` when it does not resolve. */
|
|
155
|
+
export function canonical(p: string): string | null {
|
|
156
|
+
try {
|
|
157
|
+
return fs.realpathSync(p);
|
|
158
|
+
} catch {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface SourceWalk {
|
|
164
|
+
/** Newest mtime across every curated source read, epoch ms; 0 when none. */
|
|
165
|
+
readonly newestMs: number;
|
|
166
|
+
/** Sources whose canonical path lies outside the workspace. P1's other half. */
|
|
167
|
+
readonly escaped: readonly string[];
|
|
168
|
+
/** How many sources the walk actually read — 0 means "nothing to judge". */
|
|
169
|
+
readonly count: number;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* One recursive walk serving P1's file half and P3's reading, because R2 found
|
|
174
|
+
* both defects in the same omission: the previous version read only `*.yml`
|
|
175
|
+
* directly at the root, which is one of the three layouts
|
|
176
|
+
* `memory_lookup._iter_curated_entries` supports. So freshness silently
|
|
177
|
+
* no-opped on a type-directory corpus (a 3-year-old one was served past the
|
|
178
|
+
* 400-day bound), and containment was never checked below the root at all.
|
|
179
|
+
*
|
|
180
|
+
* The containment half is the sharper of the two. Canonicalizing the ROOT does
|
|
181
|
+
* not stop a symlinked FILE inside it from resolving into another tree, and
|
|
182
|
+
* that is the exact threat this module's docblock names — proven by the
|
|
183
|
+
* reviewer, who read a donor workspace's entry out of a victim session.
|
|
184
|
+
*
|
|
185
|
+
* Per-entry timestamps do not exist (a curated entry is `{id, key, body}`), so
|
|
186
|
+
* freshness stays a property of the source files rather than something invented
|
|
187
|
+
* per row.
|
|
188
|
+
*/
|
|
189
|
+
export function walkCuratedSources(memoryRoot: string, workspaceRoot: string): SourceWalk {
|
|
190
|
+
let newestMs = 0;
|
|
191
|
+
let count = 0;
|
|
192
|
+
const escaped: string[] = [];
|
|
193
|
+
|
|
194
|
+
const visit = (dir: string, depth: number): void => {
|
|
195
|
+
if (depth > MAX_WALK_DEPTH) return;
|
|
196
|
+
let names: fs.Dirent[];
|
|
197
|
+
try {
|
|
198
|
+
names = fs.readdirSync(dir, { withFileTypes: true });
|
|
199
|
+
} catch {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
for (const ent of names) {
|
|
203
|
+
const full = path.join(dir, ent.name);
|
|
204
|
+
// `withFileTypes` reports a symlink as a symlink, so a directory
|
|
205
|
+
// reached through one is followed only after it canonicalizes
|
|
206
|
+
// inside the workspace — which is the containment check itself.
|
|
207
|
+
const resolved = canonical(full);
|
|
208
|
+
if (resolved === null) continue;
|
|
209
|
+
if (!isContained(resolved, workspaceRoot)) {
|
|
210
|
+
escaped.push(full);
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
let st: fs.Stats;
|
|
214
|
+
try {
|
|
215
|
+
st = fs.statSync(resolved);
|
|
216
|
+
} catch {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (st.isDirectory()) {
|
|
220
|
+
visit(resolved, depth + 1);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (!CURATED_SUFFIXES.some((sfx) => ent.name.endsWith(sfx))) continue;
|
|
224
|
+
count += 1;
|
|
225
|
+
if (st.mtimeMs > newestMs) newestMs = st.mtimeMs;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
visit(memoryRoot, 0);
|
|
230
|
+
return { newestMs, escaped, count };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export interface TrustInput {
|
|
234
|
+
/** The workspace root the session belongs to, as the host reported it. */
|
|
235
|
+
readonly workspaceRoot: string;
|
|
236
|
+
/** Relative memory root, matching `memory_lookup.MEMORY_ROOT`. */
|
|
237
|
+
readonly relativeMemoryRoot?: string;
|
|
238
|
+
/** Injected for tests; defaults to now. */
|
|
239
|
+
readonly now?: Date;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* P1 + P2 + P3 — decide whether a memory root may be read at all.
|
|
244
|
+
*
|
|
245
|
+
* Ordered cheapest-first, and each refusal names itself: a caller that logs the
|
|
246
|
+
* code can tell "this workspace has no memory" from "this root pointed
|
|
247
|
+
* somewhere else", which is the distinction the whole module exists for.
|
|
248
|
+
*/
|
|
249
|
+
export function verifyMemoryRoot(input: TrustInput): TrustVerdict {
|
|
250
|
+
const now = input.now ?? new Date();
|
|
251
|
+
const rel = input.relativeMemoryRoot ?? path.join('agents', 'memory');
|
|
252
|
+
|
|
253
|
+
// P2 — the workspace root is canonicalized FIRST. Everything downstream
|
|
254
|
+
// compares against the resolved form, never the reported one.
|
|
255
|
+
const workspaceRoot = canonical(input.workspaceRoot);
|
|
256
|
+
if (workspaceRoot === null) {
|
|
257
|
+
return refuse('workspace-root-unresolvable', `workspace root does not resolve: ${input.workspaceRoot}`);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// P1 — identity, checked LEXICALLY first and on the canonical path second.
|
|
261
|
+
// The order is load-bearing and a test found it: a `..` root whose target
|
|
262
|
+
// does not exist would otherwise be reported as merely absent, which reads
|
|
263
|
+
// as "this workspace has no memory" when the truth is "this root pointed
|
|
264
|
+
// outside the tree". The escape is the more important fact, so it is the
|
|
265
|
+
// one reported, whether or not the target happens to exist.
|
|
266
|
+
const lexical = path.resolve(workspaceRoot, rel);
|
|
267
|
+
if (!isContained(lexical, workspaceRoot)) {
|
|
268
|
+
return refuse(
|
|
269
|
+
'memory-root-escapes-workspace',
|
|
270
|
+
`${lexical} is not inside ${workspaceRoot} — refusing to serve another tree's memory`,
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const memoryRoot = canonical(lexical);
|
|
275
|
+
if (memoryRoot === null) {
|
|
276
|
+
return refuse('memory-root-absent', `no memory root at ${path.join(input.workspaceRoot, rel)}`);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// The second half of P1, and the half a lexical check cannot see: the path
|
|
280
|
+
// is inside the tree and the SYMLINK it resolves through is not.
|
|
281
|
+
if (!isContained(memoryRoot, workspaceRoot)) {
|
|
282
|
+
return refuse(
|
|
283
|
+
'memory-root-escapes-workspace',
|
|
284
|
+
`${memoryRoot} is not inside ${workspaceRoot} — refusing to serve another tree's memory`,
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// P1's file half + P3, from one walk. R2 findings 3 and 4.
|
|
289
|
+
const walk = walkCuratedSources(memoryRoot, workspaceRoot);
|
|
290
|
+
if (walk.escaped.length > 0) {
|
|
291
|
+
return refuse(
|
|
292
|
+
'curated-source-escapes-workspace',
|
|
293
|
+
`${walk.escaped.length} curated source(s) resolve outside ${workspaceRoot}, first ${walk.escaped[0]} — refusing to serve another tree's memory`,
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// P3 — freshness, in the two directions it can fail.
|
|
298
|
+
const newestSourceMs = walk.newestMs;
|
|
299
|
+
if (newestSourceMs > now.getTime() + MAX_FUTURE_SKEW_MS) {
|
|
300
|
+
return refuse(
|
|
301
|
+
'source-mtime-in-future',
|
|
302
|
+
`newest curated source is dated in the future (${new Date(newestSourceMs).toISOString()}) — clock skew or tampering`,
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
if (newestSourceMs > 0) {
|
|
306
|
+
const ageDays = (now.getTime() - newestSourceMs) / 86_400_000;
|
|
307
|
+
if (ageDays > MAX_ROOT_AGE_DAYS) {
|
|
308
|
+
return refuse(
|
|
309
|
+
'memory-root-abandoned',
|
|
310
|
+
`newest curated source is ${ageDays.toFixed(0)}d old, past the ${MAX_ROOT_AGE_DAYS}d abandonment bound`,
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return { ok: true, memoryRoot, workspaceRoot, newestSourceMs };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export interface OrderableRow {
|
|
319
|
+
readonly id: string;
|
|
320
|
+
readonly title: string;
|
|
321
|
+
readonly tokens_estimate: number;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* P4 — the declared total order.
|
|
326
|
+
*
|
|
327
|
+
* Ordering is a trust property because the CAP truncates: without a declared
|
|
328
|
+
* order, which 30 of 200 entries reach the model is whatever the filesystem
|
|
329
|
+
* happened to yield, and two runs over the same tree can advertise different
|
|
330
|
+
* corpora. Cheapest row first (`tokens_estimate` ascending) so a fixed cap
|
|
331
|
+
* carries the most entries it can, with `id` ascending as the tie-break that
|
|
332
|
+
* makes the order TOTAL rather than merely defined — a comparator with ties is
|
|
333
|
+
* not deterministic under an unstable sort.
|
|
334
|
+
*/
|
|
335
|
+
export function orderRows<T extends OrderableRow>(rows: readonly T[]): T[] {
|
|
336
|
+
return [...rows].sort((a, b) => {
|
|
337
|
+
if (a.tokens_estimate !== b.tokens_estimate) return a.tokens_estimate - b.tokens_estimate;
|
|
338
|
+
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** P6 — apply the cap after ordering, never before. */
|
|
343
|
+
export function capRows<T>(rows: readonly T[], cap: number = SESSION_INDEX_ROW_CAP): T[] {
|
|
344
|
+
const limit = Number.isFinite(cap) && cap > 0 ? Math.min(cap, SESSION_INDEX_ROW_CAP) : SESSION_INDEX_ROW_CAP;
|
|
345
|
+
return rows.slice(0, limit);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** Where the P5 latch lives. Gitignored runtime state, one file per session. */
|
|
349
|
+
export function latchPath(workspaceRoot: string, sessionId: string): string {
|
|
350
|
+
const safe = sessionId.replace(/[^A-Za-z0-9._-]/gu, '_').slice(0, 128);
|
|
351
|
+
return path.join(workspaceRoot, 'agents', 'runtime', 'state', 'session-index-latch', `${safe}.json`);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* P5 — duplicate invocation.
|
|
356
|
+
*
|
|
357
|
+
* `session_start` can fire more than once for one session (a resume, a
|
|
358
|
+
* host-side reconnect, a compaction boundary on some hosts). Two injections
|
|
359
|
+
* double the fixed cost and can present two different corpora as the same
|
|
360
|
+
* session's memory. The latch is create-exclusive (`wx`), so the FIRST caller
|
|
361
|
+
* wins and every later one refuses — an ordering that matters, because
|
|
362
|
+
* check-then-write would let two concurrent starts both pass.
|
|
363
|
+
*
|
|
364
|
+
* Fails OPEN on an unwritable state directory: a hook that cannot latch must
|
|
365
|
+
* still be able to serve the index once, and refusing there would make a
|
|
366
|
+
* read-only workspace lose the feature entirely. That is a deliberate trade and
|
|
367
|
+
* it is the reason this property is a latch rather than a gate.
|
|
368
|
+
*/
|
|
369
|
+
export function claimSessionOnce(workspaceRoot: string, sessionId: string): TrustVerdict | { ok: true } {
|
|
370
|
+
if (sessionId.length === 0) {
|
|
371
|
+
// No session id to key on — cannot latch, so do not pretend to.
|
|
372
|
+
return { ok: true };
|
|
373
|
+
}
|
|
374
|
+
const target = latchPath(workspaceRoot, sessionId);
|
|
375
|
+
try {
|
|
376
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
377
|
+
fs.writeFileSync(target, JSON.stringify({ claimed_at: new Date().toISOString() }), { flag: 'wx' });
|
|
378
|
+
return { ok: true };
|
|
379
|
+
} catch (exc) {
|
|
380
|
+
const code = (exc as { code?: string }).code;
|
|
381
|
+
if (code === 'EEXIST') {
|
|
382
|
+
return refuse('already-injected-this-session', `session ${sessionId} already received the index`);
|
|
383
|
+
}
|
|
384
|
+
// fail-open — see the docblock
|
|
385
|
+
return { ok: true };
|
|
386
|
+
}
|
|
387
|
+
}
|