session-orchestrator 3.16.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/.claude-plugin/marketplace.json +29 -0
- package/.claude-plugin/plugin.json +18 -0
- package/.codex-plugin/agents/explorer.toml +14 -0
- package/.codex-plugin/agents/session-reviewer.toml +23 -0
- package/.codex-plugin/agents/wave-worker.toml +15 -0
- package/.codex-plugin/config.toml +20 -0
- package/.codex-plugin/plugin.json +37 -0
- package/.cursor/rules/000-session-orchestrator.mdc +73 -0
- package/.cursor/rules/010-session-workflow.mdc +170 -0
- package/.cursor/rules/020-quality-gates.mdc +128 -0
- package/.cursor/rules/030-wave-execution.mdc +216 -0
- package/.cursor/rules/040-discovery.mdc +242 -0
- package/.cursor/rules/050-plan.mdc +235 -0
- package/.cursor/rules/060-evolve.mdc +232 -0
- package/.cursor/rules/070-gitlab-ops.mdc +246 -0
- package/.cursor/rules/080-ecosystem-health.mdc +145 -0
- package/.mcp.json +8 -0
- package/CHANGELOG.md +1544 -0
- package/LICENSE +21 -0
- package/NOTICE +64 -0
- package/README.md +242 -0
- package/SECURITY.md +90 -0
- package/agents/AGENTS.md +136 -0
- package/agents/analyst.md +99 -0
- package/agents/architect-reviewer.md +93 -0
- package/agents/code-implementer.md +106 -0
- package/agents/db-specialist.md +104 -0
- package/agents/dialectic-deriver.md +139 -0
- package/agents/docs-writer.md +113 -0
- package/agents/eval-judge.md +146 -0
- package/agents/memory-proposal-collector.md +297 -0
- package/agents/qa-strategist.md +102 -0
- package/agents/schemas/analyst.schema.json +46 -0
- package/agents/schemas/architect-reviewer.schema.json +50 -0
- package/agents/schemas/code-implementer.schema.json +61 -0
- package/agents/schemas/db-specialist.schema.json +80 -0
- package/agents/schemas/docs-writer.schema.json +56 -0
- package/agents/schemas/persona-panel-sidecar.schema.json +245 -0
- package/agents/schemas/qa-strategist.schema.json +46 -0
- package/agents/schemas/security-reviewer.schema.json +86 -0
- package/agents/schemas/session-reviewer.schema.json +69 -0
- package/agents/schemas/test-writer.schema.json +69 -0
- package/agents/schemas/ui-developer.schema.json +90 -0
- package/agents/schemas/ux-evaluator.schema.json +51 -0
- package/agents/security-reviewer.md +236 -0
- package/agents/session-reviewer.md +201 -0
- package/agents/skill-applied-judge.md +122 -0
- package/agents/test-writer.md +123 -0
- package/agents/ui-developer.md +109 -0
- package/agents/ux-evaluator.md +161 -0
- package/assets/icon.svg +11 -0
- package/assets/og-card.png +0 -0
- package/assets/og-card.svg +47 -0
- package/commands/autopilot-multi.md +74 -0
- package/commands/autopilot.md +80 -0
- package/commands/bootstrap.md +56 -0
- package/commands/brainstorm.md +48 -0
- package/commands/close.md +24 -0
- package/commands/debug.md +36 -0
- package/commands/discovery.md +32 -0
- package/commands/dispatcher.md +59 -0
- package/commands/eval.md +28 -0
- package/commands/evolve.md +10 -0
- package/commands/go.md +41 -0
- package/commands/grill.md +45 -0
- package/commands/harness-audit.md +26 -0
- package/commands/memory-cleanup.md +25 -0
- package/commands/persona-panel.md +121 -0
- package/commands/plan.md +15 -0
- package/commands/portfolio.md +97 -0
- package/commands/reconcile.md +23 -0
- package/commands/repo-audit.md +24 -0
- package/commands/session.md +30 -0
- package/commands/spinout.md +15 -0
- package/commands/sunset-review.md +27 -0
- package/commands/templates-ack.md +96 -0
- package/commands/test.md +97 -0
- package/docs/README.md +105 -0
- package/docs/USER-GUIDE.md +1403 -0
- package/docs/ci-setup.md +81 -0
- package/docs/codex-setup.md +142 -0
- package/docs/components.md +74 -0
- package/docs/cursor-setup.md +104 -0
- package/docs/events-schema.md +81 -0
- package/docs/migration-v3.md +148 -0
- package/docs/owner-config-schema.md +154 -0
- package/docs/persona-panel.md +433 -0
- package/docs/pi-setup.md +115 -0
- package/docs/plugin-architecture-v3.md +296 -0
- package/docs/pm-skills-marketplace.md +114 -0
- package/docs/policy-cache-validation-2026-04-28.md +118 -0
- package/docs/rule-authoring.md +316 -0
- package/docs/session-config-reference.md +1439 -0
- package/docs/session-config-template.md +961 -0
- package/docs/vault-docs-architecture.md +297 -0
- package/hooks/_lib/lock-bootstrap.mjs +272 -0
- package/hooks/_lib/lock-reconcile.mjs +93 -0
- package/hooks/_lib/profile-gate.mjs +95 -0
- package/hooks/_lib/transcript-history.mjs +211 -0
- package/hooks/agent-teams-h3-test.sh +362 -0
- package/hooks/config-protection.mjs +0 -0
- package/hooks/cwd-change-restore.mjs +131 -0
- package/hooks/enforce-commands.mjs +179 -0
- package/hooks/enforce-scope.mjs +273 -0
- package/hooks/hooks-codex.json +60 -0
- package/hooks/hooks-cursor.json +15 -0
- package/hooks/hooks-pi.json +115 -0
- package/hooks/hooks.json +215 -0
- package/hooks/loop-guard.mjs +260 -0
- package/hooks/on-session-end.mjs +217 -0
- package/hooks/on-session-start.mjs +660 -0
- package/hooks/on-stop.mjs +294 -0
- package/hooks/operator-steer.mjs +64 -0
- package/hooks/post-edit-validate.mjs +225 -0
- package/hooks/post-subagent-discovery-validator.mjs +398 -0
- package/hooks/post-tool-batch-wave-signal.mjs +328 -0
- package/hooks/post-tool-failure-corrective-context.mjs +248 -0
- package/hooks/post-tooluse-frontend-slop.mjs +184 -0
- package/hooks/pre-bash-destructive-guard.mjs +515 -0
- package/hooks/pre-bash-memory-propose-audit.mjs +206 -0
- package/hooks/pre-bash-staging-fence.mjs +223 -0
- package/hooks/pre-bash-templates-first.mjs +404 -0
- package/hooks/run-node.sh +72 -0
- package/hooks/skill-invocation-telemetry.mjs +99 -0
- package/hooks/subagent-telemetry.mjs +249 -0
- package/hooks/wave-scope-commit-guard.mjs +191 -0
- package/monitors/monitors.json +14 -0
- package/output-styles/finding-report.md +48 -0
- package/output-styles/session-report.md +53 -0
- package/output-styles/wave-summary.md +38 -0
- package/package.json +94 -0
- package/pi/extensions/session-orchestrator.ts +25 -0
- package/pi/prompts/autopilot-multi.md +12 -0
- package/pi/prompts/autopilot.md +12 -0
- package/pi/prompts/bootstrap.md +12 -0
- package/pi/prompts/brainstorm.md +12 -0
- package/pi/prompts/close.md +11 -0
- package/pi/prompts/debug.md +12 -0
- package/pi/prompts/discovery.md +12 -0
- package/pi/prompts/dispatcher.md +12 -0
- package/pi/prompts/eval.md +12 -0
- package/pi/prompts/evolve.md +12 -0
- package/pi/prompts/go.md +12 -0
- package/pi/prompts/grill.md +12 -0
- package/pi/prompts/harness-audit.md +12 -0
- package/pi/prompts/memory-cleanup.md +12 -0
- package/pi/prompts/persona-panel.md +12 -0
- package/pi/prompts/plan.md +12 -0
- package/pi/prompts/portfolio.md +12 -0
- package/pi/prompts/reconcile.md +12 -0
- package/pi/prompts/repo-audit.md +12 -0
- package/pi/prompts/session.md +12 -0
- package/pi/prompts/spinout.md +12 -0
- package/pi/prompts/sunset-review.md +12 -0
- package/pi/prompts/templates-ack.md +12 -0
- package/pi/prompts/test.md +12 -0
- package/rules/_index.md +51 -0
- package/rules/always-on/commit-discipline.md +26 -0
- package/rules/always-on/npm-quality-gates.md +26 -0
- package/rules/always-on/parallel-sessions.md +43 -0
- package/rules/opt-in-domain/prompt-caching.md +270 -0
- package/rules/opt-in-stack/backend-data.md +188 -0
- package/rules/opt-in-stack/backend.md +390 -0
- package/rules/opt-in-stack/frontend.md +98 -0
- package/rules/opt-in-stack/security-web.md +194 -0
- package/rules/opt-in-stack/swift.md +65 -0
- package/scripts/archive-closed-prds.mjs +416 -0
- package/scripts/autopilot-multi.mjs +802 -0
- package/scripts/autopilot.mjs +383 -0
- package/scripts/backfill-abandoned-sessions.mjs +265 -0
- package/scripts/backfill-learnings-expires.mjs +196 -0
- package/scripts/backfill-learnings.mjs +203 -0
- package/scripts/backfill-sessions.mjs +282 -0
- package/scripts/check-doc-consistency.sh +279 -0
- package/scripts/check-package-manager.mjs +445 -0
- package/scripts/ci/assert-vitest-green.mjs +267 -0
- package/scripts/codex-install.mjs +435 -0
- package/scripts/compute-grounding-injection.sh +186 -0
- package/scripts/cursor-install.mjs +113 -0
- package/scripts/dialectic-deriver.mjs +573 -0
- package/scripts/emit-event.mjs +160 -0
- package/scripts/emit-session.mjs +212 -0
- package/scripts/eval-session.mjs +262 -0
- package/scripts/export-hw-learnings.mjs +437 -0
- package/scripts/gc-stale-worktrees.mjs +666 -0
- package/scripts/generate-pi-prompts.mjs +127 -0
- package/scripts/harness-audit.mjs +287 -0
- package/scripts/lib/agent-frontmatter.mjs +266 -0
- package/scripts/lib/agent-output-schema.mjs +166 -0
- package/scripts/lib/agent-status.mjs +303 -0
- package/scripts/lib/ajv-loader.mjs +34 -0
- package/scripts/lib/auto-dialectic.mjs +382 -0
- package/scripts/lib/auto-dream.mjs +471 -0
- package/scripts/lib/autonomy/suitability.mjs +212 -0
- package/scripts/lib/autopilot/dep-graph.mjs +417 -0
- package/scripts/lib/autopilot/durable-telemetry.mjs +121 -0
- package/scripts/lib/autopilot/flags.mjs +104 -0
- package/scripts/lib/autopilot/kill-switches.mjs +174 -0
- package/scripts/lib/autopilot/loop.mjs +320 -0
- package/scripts/lib/autopilot/mr-draft.mjs +520 -0
- package/scripts/lib/autopilot/multi-killswitch.mjs +184 -0
- package/scripts/lib/autopilot/recent-runs.mjs +106 -0
- package/scripts/lib/autopilot/stall-sampler.mjs +97 -0
- package/scripts/lib/autopilot/telemetry.mjs +224 -0
- package/scripts/lib/autopilot/worktree-pipeline.mjs +605 -0
- package/scripts/lib/autopilot-telemetry.mjs +11 -0
- package/scripts/lib/autopilot.mjs +39 -0
- package/scripts/lib/backlog-scan.mjs +179 -0
- package/scripts/lib/bootstrap-lock-freshness.mjs +260 -0
- package/scripts/lib/bootstrap-lock-refresh.mjs +186 -0
- package/scripts/lib/build-live-signals.mjs +150 -0
- package/scripts/lib/ci-status-banner.mjs +425 -0
- package/scripts/lib/claude-md-budget-lint.mjs +246 -0
- package/scripts/lib/cli-flags.mjs +158 -0
- package/scripts/lib/codex/plugin-contract.mjs +610 -0
- package/scripts/lib/cold-start-detector.mjs +240 -0
- package/scripts/lib/command-blocker.mjs +458 -0
- package/scripts/lib/common.mjs +333 -0
- package/scripts/lib/config/auto-dream.mjs +77 -0
- package/scripts/lib/config/block-header.mjs +94 -0
- package/scripts/lib/config/broken-window.mjs +114 -0
- package/scripts/lib/config/coercers.mjs +248 -0
- package/scripts/lib/config/cold-start.mjs +92 -0
- package/scripts/lib/config/config-protection.mjs +120 -0
- package/scripts/lib/config/cross-repo.mjs +104 -0
- package/scripts/lib/config/custom-phases.mjs +213 -0
- package/scripts/lib/config/dialectic.mjs +92 -0
- package/scripts/lib/config/discovery-validator.mjs +75 -0
- package/scripts/lib/config/dispatcher-autonomy-capture.mjs +240 -0
- package/scripts/lib/config/dispatcher-autonomy.mjs +152 -0
- package/scripts/lib/config/docs-orchestrator.mjs +90 -0
- package/scripts/lib/config/docs-staleness.mjs +96 -0
- package/scripts/lib/config/drift-check.mjs +155 -0
- package/scripts/lib/config/eval.mjs +130 -0
- package/scripts/lib/config/events-rotation.mjs +74 -0
- package/scripts/lib/config/evolve.mjs +308 -0
- package/scripts/lib/config/frontend-slop-hook.mjs +104 -0
- package/scripts/lib/config/gitlab-portfolio.mjs +150 -0
- package/scripts/lib/config/handover-gate.mjs +106 -0
- package/scripts/lib/config/host-paths.mjs +76 -0
- package/scripts/lib/config/io.mjs +54 -0
- package/scripts/lib/config/loop-guard.mjs +117 -0
- package/scripts/lib/config/memory.mjs +150 -0
- package/scripts/lib/config/persona-gate-wave.mjs +258 -0
- package/scripts/lib/config/reconcile.mjs +205 -0
- package/scripts/lib/config/section-extractor.mjs +100 -0
- package/scripts/lib/config/skill-evolution.mjs +112 -0
- package/scripts/lib/config/slopcheck.mjs +99 -0
- package/scripts/lib/config/state-md-lock.mjs +83 -0
- package/scripts/lib/config/templates-first.mjs +94 -0
- package/scripts/lib/config/test.mjs +113 -0
- package/scripts/lib/config/vault-integration.mjs +201 -0
- package/scripts/lib/config/vault-mirror-quality.mjs +99 -0
- package/scripts/lib/config/vault-staleness.mjs +84 -0
- package/scripts/lib/config/vault-sync.mjs +96 -0
- package/scripts/lib/config/verification-auto-fix.mjs +84 -0
- package/scripts/lib/config/wave-reviewers.mjs +133 -0
- package/scripts/lib/config-schema.mjs +345 -0
- package/scripts/lib/config.mjs +474 -0
- package/scripts/lib/convergence-monitor.mjs +389 -0
- package/scripts/lib/coordinator-snapshot.mjs +371 -0
- package/scripts/lib/crypto-digest-utils.mjs +91 -0
- package/scripts/lib/discovery/helpers.mjs +127 -0
- package/scripts/lib/discovery/triage-state.mjs +279 -0
- package/scripts/lib/dispatcher/cli.mjs +257 -0
- package/scripts/lib/dispatcher/enumerate.mjs +243 -0
- package/scripts/lib/dispatcher/rank.mjs +363 -0
- package/scripts/lib/ecosystem-health.mjs +224 -0
- package/scripts/lib/ecosystem-wizard/ci-detector.mjs +18 -0
- package/scripts/lib/ecosystem-wizard/config-parser.mjs +54 -0
- package/scripts/lib/ecosystem-wizard/config-writer.mjs +287 -0
- package/scripts/lib/ecosystem-wizard/package-manager-detector.mjs +42 -0
- package/scripts/lib/ecosystem-wizard/wizard-prompt.mjs +246 -0
- package/scripts/lib/ecosystem-wizard.mjs +48 -0
- package/scripts/lib/env-check.mjs +89 -0
- package/scripts/lib/eval/engine.mjs +605 -0
- package/scripts/lib/eval/judge.mjs +433 -0
- package/scripts/lib/eval/report.mjs +367 -0
- package/scripts/lib/eval/schema.mjs +618 -0
- package/scripts/lib/eval/session-resolve.mjs +137 -0
- package/scripts/lib/eval/sink.mjs +77 -0
- package/scripts/lib/events-rotation.mjs +86 -0
- package/scripts/lib/events-schema.mjs +81 -0
- package/scripts/lib/events.mjs +80 -0
- package/scripts/lib/evolve/autonomy-verdict.mjs +461 -0
- package/scripts/lib/evolve/autopilot-effectiveness.mjs +293 -0
- package/scripts/lib/exclusivity-matrix.mjs +68 -0
- package/scripts/lib/fetch-baseline.mjs +311 -0
- package/scripts/lib/file-lock.mjs +512 -0
- package/scripts/lib/frontend-detect/detect.mjs +138 -0
- package/scripts/lib/frontend-detect/rules.mjs +295 -0
- package/scripts/lib/frontmatter-guard.mjs +241 -0
- package/scripts/lib/gates/echo-stub-detect.mjs +39 -0
- package/scripts/lib/gates/gate-baseline.mjs +42 -0
- package/scripts/lib/gates/gate-full.mjs +85 -0
- package/scripts/lib/gates/gate-helpers.mjs +231 -0
- package/scripts/lib/gates/gate-incremental.mjs +76 -0
- package/scripts/lib/gates/gate-per-file.mjs +55 -0
- package/scripts/lib/gitlab-ops/stale-mr-sweep.mjs +447 -0
- package/scripts/lib/gitlab-portfolio/aggregator.mjs +383 -0
- package/scripts/lib/gitlab-portfolio/cli.mjs +428 -0
- package/scripts/lib/gitlab-portfolio/markdown-writer.mjs +289 -0
- package/scripts/lib/gitlab-portfolio/vcs-detect.mjs +182 -0
- package/scripts/lib/handover-gate.mjs +222 -0
- package/scripts/lib/hardening.mjs +43 -0
- package/scripts/lib/hardware-pattern-detector.mjs +238 -0
- package/scripts/lib/harness-audit/categories/category1.mjs +123 -0
- package/scripts/lib/harness-audit/categories/category2.mjs +145 -0
- package/scripts/lib/harness-audit/categories/category3.mjs +143 -0
- package/scripts/lib/harness-audit/categories/category4.mjs +202 -0
- package/scripts/lib/harness-audit/categories/category5.mjs +152 -0
- package/scripts/lib/harness-audit/categories/category6.mjs +211 -0
- package/scripts/lib/harness-audit/categories/category7.mjs +125 -0
- package/scripts/lib/harness-audit/categories/category8.mjs +328 -0
- package/scripts/lib/harness-audit/categories/category9.mjs +294 -0
- package/scripts/lib/harness-audit/categories/helpers.mjs +165 -0
- package/scripts/lib/harness-audit/categories.mjs +19 -0
- package/scripts/lib/historical-guard.mjs +15 -0
- package/scripts/lib/host-identity.mjs +262 -0
- package/scripts/lib/instruction-budget-guard.mjs +332 -0
- package/scripts/lib/io.mjs +304 -0
- package/scripts/lib/issue-close-strip-labels.mjs +161 -0
- package/scripts/lib/language-mappers/README.md +57 -0
- package/scripts/lib/language-mappers/index.mjs +165 -0
- package/scripts/lib/language-mappers/markdown.mjs +149 -0
- package/scripts/lib/language-mappers/python.mjs +249 -0
- package/scripts/lib/language-mappers/swift.mjs +201 -0
- package/scripts/lib/language-mappers/typescript.mjs +433 -0
- package/scripts/lib/learnings/expiry-sweep.mjs +164 -0
- package/scripts/lib/learnings/filters.mjs +43 -0
- package/scripts/lib/learnings/io.mjs +255 -0
- package/scripts/lib/learnings/schema.mjs +518 -0
- package/scripts/lib/learnings/surface.mjs +207 -0
- package/scripts/lib/learnings.mjs +42 -0
- package/scripts/lib/lock-reaper.mjs +648 -0
- package/scripts/lib/locks/index.mjs +31 -0
- package/scripts/lib/locks/lock-body.mjs +62 -0
- package/scripts/lib/locks/staging-fence-lock.mjs +267 -0
- package/scripts/lib/locks/state-md-lock.mjs +351 -0
- package/scripts/lib/loop-readiness-banner.mjs +144 -0
- package/scripts/lib/memory-banner.mjs +478 -0
- package/scripts/lib/memory-cleanup/worktree-sweep.mjs +108 -0
- package/scripts/lib/memory-cleanup-stamp.mjs +56 -0
- package/scripts/lib/memory-paths.mjs +31 -0
- package/scripts/lib/memory-proposals/collector.mjs +334 -0
- package/scripts/lib/memory-proposals/schema.mjs +289 -0
- package/scripts/lib/memory-proposals/sink.mjs +507 -0
- package/scripts/lib/memory-proposals/store.mjs +441 -0
- package/scripts/lib/mission-status-schema.mjs +114 -0
- package/scripts/lib/mode-selector/alternatives.mjs +64 -0
- package/scripts/lib/mode-selector/constants.mjs +29 -0
- package/scripts/lib/mode-selector/context-pressure.mjs +157 -0
- package/scripts/lib/mode-selector/rationale.mjs +55 -0
- package/scripts/lib/mode-selector/scoring.mjs +221 -0
- package/scripts/lib/mode-selector-accuracy.mjs +121 -0
- package/scripts/lib/mode-selector.mjs +160 -0
- package/scripts/lib/multi-provider-build/providers.mjs +64 -0
- package/scripts/lib/multi-provider-build/templating.mjs +130 -0
- package/scripts/lib/named-baseline-resolver.mjs +233 -0
- package/scripts/lib/named-vault-resolver.mjs +433 -0
- package/scripts/lib/owner-config/coerce.mjs +29 -0
- package/scripts/lib/owner-config/constants.mjs +21 -0
- package/scripts/lib/owner-config/defaults.mjs +50 -0
- package/scripts/lib/owner-config/error.mjs +19 -0
- package/scripts/lib/owner-config/index.mjs +13 -0
- package/scripts/lib/owner-config/merge.mjs +52 -0
- package/scripts/lib/owner-config/validate.mjs +259 -0
- package/scripts/lib/owner-config-banner.mjs +126 -0
- package/scripts/lib/owner-config-loader.mjs +159 -0
- package/scripts/lib/owner-config.example.yaml +72 -0
- package/scripts/lib/owner-config.mjs +28 -0
- package/scripts/lib/owner-interview.mjs +243 -0
- package/scripts/lib/owner-yaml.mjs +571 -0
- package/scripts/lib/package-manager.mjs +160 -0
- package/scripts/lib/path-utils.mjs +217 -0
- package/scripts/lib/peer-cards/merger.mjs +310 -0
- package/scripts/lib/peer-cards/reader.mjs +125 -0
- package/scripts/lib/peer-cards/schema.mjs +230 -0
- package/scripts/lib/peer-cards/staleness-banner.mjs +86 -0
- package/scripts/lib/peer-cards/writer.mjs +138 -0
- package/scripts/lib/peer-discovery.mjs +200 -0
- package/scripts/lib/persona-panel/catalog-loader.mjs +577 -0
- package/scripts/lib/persona-panel/consolidator.mjs +370 -0
- package/scripts/lib/persona-panel/persona-runner.mjs +375 -0
- package/scripts/lib/persona-panel/threshold.mjs +130 -0
- package/scripts/lib/pi-hook-bridge.mjs +328 -0
- package/scripts/lib/platform.mjs +266 -0
- package/scripts/lib/playwright-driver/runner.mjs +297 -0
- package/scripts/lib/plugin-root.mjs +210 -0
- package/scripts/lib/pre-dispatch-check.mjs +126 -0
- package/scripts/lib/product-repo-detect.mjs +121 -0
- package/scripts/lib/profiles/registry.mjs +176 -0
- package/scripts/lib/profiles/schema.mjs +209 -0
- package/scripts/lib/qg-command-drift-banner.mjs +88 -0
- package/scripts/lib/quality-gate/diagnostics.mjs +92 -0
- package/scripts/lib/quality-gate.mjs +536 -0
- package/scripts/lib/quality-gates-cache.mjs +228 -0
- package/scripts/lib/quality-gates-policy.mjs +95 -0
- package/scripts/lib/recommendations-v0.mjs +156 -0
- package/scripts/lib/reconcile/eligibility.mjs +203 -0
- package/scripts/lib/reconcile/emitter.mjs +244 -0
- package/scripts/lib/reconcile/engine.mjs +412 -0
- package/scripts/lib/reconcile/idempotency.mjs +239 -0
- package/scripts/lib/reconcile/renderer.mjs +211 -0
- package/scripts/lib/reconcile/writer.mjs +293 -0
- package/scripts/lib/reconcile-nudge-banner.mjs +284 -0
- package/scripts/lib/resource-probe/evaluate.mjs +190 -0
- package/scripts/lib/resource-probe/parsers.mjs +181 -0
- package/scripts/lib/resource-probe/probe-platform.mjs +300 -0
- package/scripts/lib/resource-probe.mjs +95 -0
- package/scripts/lib/rule-loader.mjs +552 -0
- package/scripts/lib/rules-sync.mjs +439 -0
- package/scripts/lib/scope-gate.mjs +496 -0
- package/scripts/lib/session-close-backfill.mjs +539 -0
- package/scripts/lib/session-discovery.mjs +256 -0
- package/scripts/lib/session-end/phase-skip.mjs +357 -0
- package/scripts/lib/session-end/worktree-cleanup.mjs +112 -0
- package/scripts/lib/session-id.mjs +362 -0
- package/scripts/lib/session-lock.mjs +703 -0
- package/scripts/lib/session-registry.mjs +355 -0
- package/scripts/lib/session-schema/aliases.mjs +71 -0
- package/scripts/lib/session-schema/constants.mjs +115 -0
- package/scripts/lib/session-schema/normalizer.mjs +66 -0
- package/scripts/lib/session-schema/timestamps.mjs +64 -0
- package/scripts/lib/session-schema/validator.mjs +453 -0
- package/scripts/lib/session-schema.mjs +71 -0
- package/scripts/lib/session-token-rollup.mjs +137 -0
- package/scripts/lib/sessions-staleness-banner.mjs +247 -0
- package/scripts/lib/skill-evolution/blast-radius-classifier.mjs +114 -0
- package/scripts/lib/skill-evolution/candidate-intake.mjs +270 -0
- package/scripts/lib/skill-evolution/config-validation-gate.mjs +279 -0
- package/scripts/lib/skill-evolution/engine.mjs +719 -0
- package/scripts/lib/skill-evolution/idempotency.mjs +279 -0
- package/scripts/lib/skill-evolution/mr-opener.mjs +507 -0
- package/scripts/lib/skill-health/join.mjs +181 -0
- package/scripts/lib/skill-health/score.mjs +123 -0
- package/scripts/lib/skill-invocations-schema.mjs +214 -0
- package/scripts/lib/skill-judge.mjs +348 -0
- package/scripts/lib/skill-judgments-schema.mjs +264 -0
- package/scripts/lib/slopcheck.mjs +501 -0
- package/scripts/lib/soul-resolve.mjs +118 -0
- package/scripts/lib/spiral-carryover.mjs +495 -0
- package/scripts/lib/state-md/body-sections.mjs +851 -0
- package/scripts/lib/state-md/frontmatter-mutators.mjs +453 -0
- package/scripts/lib/state-md/mission-status.mjs +247 -0
- package/scripts/lib/state-md/recommendations.mjs +57 -0
- package/scripts/lib/state-md/yaml-parser.mjs +234 -0
- package/scripts/lib/state-md-peer-guard.mjs +232 -0
- package/scripts/lib/state-md.mjs +53 -0
- package/scripts/lib/subagents-schema.mjs +309 -0
- package/scripts/lib/sunset/walker.mjs +1192 -0
- package/scripts/lib/test-runner/artifact-paths.mjs +94 -0
- package/scripts/lib/test-runner/fingerprint.mjs +33 -0
- package/scripts/lib/test-runner/issue-reconcile.mjs +770 -0
- package/scripts/lib/tmux-layout/layouts.mjs +224 -0
- package/scripts/lib/tmux-layout/telemetry-stats.mjs +100 -0
- package/scripts/lib/tmux-layout/telemetry.mjs +88 -0
- package/scripts/lib/tmux-layout/tmux-shell.mjs +82 -0
- package/scripts/lib/tmux-layout/vcs-detector.mjs +88 -0
- package/scripts/lib/validate/check-agents.mjs +457 -0
- package/scripts/lib/validate/check-codex-plugin.mjs +37 -0
- package/scripts/lib/validate/check-commands.mjs +148 -0
- package/scripts/lib/validate/check-component-paths.mjs +112 -0
- package/scripts/lib/validate/check-dead-bridge.mjs +180 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +258 -0
- package/scripts/lib/validate/check-json-files.mjs +116 -0
- package/scripts/lib/validate/check-owner-leakage.mjs +1011 -0
- package/scripts/lib/validate/check-path-utils-canary.mjs +175 -0
- package/scripts/lib/validate/check-peekaboo-driver-canary.mjs +201 -0
- package/scripts/lib/validate/check-pi-package.mjs +110 -0
- package/scripts/lib/validate/check-pi-prompts.mjs +43 -0
- package/scripts/lib/validate/check-playwright-mcp-canary.mjs +154 -0
- package/scripts/lib/validate/check-plugin-json.mjs +96 -0
- package/scripts/lib/validate/check-plugin-monitors.mjs +206 -0
- package/scripts/lib/validate/check-plugin-schema.mjs +137 -0
- package/scripts/lib/validate/check-rules.mjs +143 -0
- package/scripts/lib/validate/check-session-plan-routing.mjs +154 -0
- package/scripts/lib/validate/check-test-fixture-shapes.mjs +280 -0
- package/scripts/lib/validate/check-unicode-safety.mjs +533 -0
- package/scripts/lib/validate/confidential-names.mjs +169 -0
- package/scripts/lib/validate/dead-bridge-corpus.mjs +141 -0
- package/scripts/lib/validate/dead-bridge-detectors.mjs +568 -0
- package/scripts/lib/validate/tier-inference.mjs +100 -0
- package/scripts/lib/validate-vendored-rules.mjs +519 -0
- package/scripts/lib/vault-archive.mjs +404 -0
- package/scripts/lib/vault-backfill/glab.mjs +164 -0
- package/scripts/lib/vault-backfill/manifest.mjs +75 -0
- package/scripts/lib/vault-backfill/template.mjs +130 -0
- package/scripts/lib/vault-consolidate-fs.mjs +331 -0
- package/scripts/lib/vault-migration-rules.mjs +155 -0
- package/scripts/lib/vault-mirror/auto-commit.mjs +203 -0
- package/scripts/lib/vault-mirror/namespace.mjs +152 -0
- package/scripts/lib/vault-mirror/process.mjs +567 -0
- package/scripts/lib/vault-mirror/pseudonym-map.mjs +164 -0
- package/scripts/lib/vault-mirror/render-learnings.mjs +201 -0
- package/scripts/lib/vault-mirror/render-sessions.mjs +367 -0
- package/scripts/lib/vault-mirror/render.mjs +8 -0
- package/scripts/lib/vault-mirror/utils.mjs +217 -0
- package/scripts/lib/vault-relocation-rules.mjs +555 -0
- package/scripts/lib/vault-repo-backfill.mjs +235 -0
- package/scripts/lib/vault-staleness-banner.mjs +142 -0
- package/scripts/lib/vault-status/board-writer.mjs +769 -0
- package/scripts/lib/vault-status/narrative-mirror.mjs +544 -0
- package/scripts/lib/vault-sync-baseline.mjs +152 -0
- package/scripts/lib/wave-context.mjs +29 -0
- package/scripts/lib/wave-executor/pool.mjs +248 -0
- package/scripts/lib/wave-resource-gate.mjs +204 -0
- package/scripts/lib/wave-sizing.mjs +75 -0
- package/scripts/lib/webhook-url.mjs +105 -0
- package/scripts/lib/workspace.mjs +198 -0
- package/scripts/lib/worktree/constants.mjs +35 -0
- package/scripts/lib/worktree/index.mjs +17 -0
- package/scripts/lib/worktree/lifecycle.mjs +287 -0
- package/scripts/lib/worktree/listing.mjs +118 -0
- package/scripts/lib/worktree/meta.mjs +64 -0
- package/scripts/lib/worktree-freshness.mjs +313 -0
- package/scripts/lib/worktree.mjs +15 -0
- package/scripts/lifecycle-sim-v6.mjs +347 -0
- package/scripts/lock-reaper.mjs +185 -0
- package/scripts/mcp-server.sh +241 -0
- package/scripts/measure-policy-cache-effectiveness.mjs +427 -0
- package/scripts/memory-propose.mjs +464 -0
- package/scripts/migrate-cold-start-seed.mjs +404 -0
- package/scripts/migrate-learnings-jsonl.mjs +189 -0
- package/scripts/migrate-legacy-learnings.sh +61 -0
- package/scripts/migrate-sessions-jsonl.mjs +448 -0
- package/scripts/migrate-subagents-jsonl.mjs +196 -0
- package/scripts/migrate-vault-paths.mjs +796 -0
- package/scripts/parse-config.mjs +149 -0
- package/scripts/pi-install.mjs +117 -0
- package/scripts/print-applicable-rules.mjs +247 -0
- package/scripts/promote-vault-strict.mjs +496 -0
- package/scripts/relocate-vault-corpus.mjs +1178 -0
- package/scripts/run-migrate-v2-cross-repo.mjs +385 -0
- package/scripts/run-quality-gate.mjs +216 -0
- package/scripts/spikes/h3-agent-teams/preflight.sh +53 -0
- package/scripts/spikes/h3-agent-teams/run-h3.sh +112 -0
- package/scripts/spikes/h3-agent-teams/setup.sh +137 -0
- package/scripts/spikes/h3-agent-teams/toggle.sh +38 -0
- package/scripts/sweep-expired-learnings.mjs +135 -0
- package/scripts/sync-vault-schema.mjs +376 -0
- package/scripts/tests/fixtures/fetch-baseline/sample-rule.md +8 -0
- package/scripts/tmux-layout.mjs +245 -0
- package/scripts/token-audit.sh +191 -0
- package/scripts/typecheck.mjs +42 -0
- package/scripts/upload-social-preview.mjs +316 -0
- package/scripts/validate-config.mjs +46 -0
- package/scripts/validate-plugin-manifests.mjs +163 -0
- package/scripts/validate-plugin.mjs +264 -0
- package/scripts/validate-wave-scope.mjs +289 -0
- package/scripts/vault-backfill.mjs +404 -0
- package/scripts/vault-consolidate.mjs +596 -0
- package/scripts/vault-integration-watcher.mjs +394 -0
- package/scripts/vault-mirror.mjs +430 -0
- package/skills/_shared/bootstrap-gate.md +111 -0
- package/skills/_shared/config-reading.md +226 -0
- package/skills/_shared/instruction-file-resolution.md +79 -0
- package/skills/_shared/model-selection.md +64 -0
- package/skills/_shared/monitor-patterns.md +300 -0
- package/skills/_shared/parallel-aware-auq.md +121 -0
- package/skills/_shared/parallel-aware-preamble.md +185 -0
- package/skills/_shared/platform-tools.md +96 -0
- package/skills/_shared/state-ownership.md +221 -0
- package/skills/architecture/DEEPENING.md +37 -0
- package/skills/architecture/INTERFACE-DESIGN.md +44 -0
- package/skills/architecture/LANGUAGE.md +53 -0
- package/skills/architecture/SKILL.md +92 -0
- package/skills/autopilot/SKILL.md +419 -0
- package/skills/bootstrap/SKILL.md +592 -0
- package/skills/bootstrap/STATE.md.template +24 -0
- package/skills/bootstrap/_shared-template.md +243 -0
- package/skills/bootstrap/deep-template.md +659 -0
- package/skills/bootstrap/fast-template.md +251 -0
- package/skills/bootstrap/intensity-heuristic.md +80 -0
- package/skills/bootstrap/public-fallback.md +342 -0
- package/skills/bootstrap/standard-template.md +736 -0
- package/skills/bootstrap/templates/agents/project-code-review.md +18 -0
- package/skills/bootstrap/templates/agents/project-discovery.md +18 -0
- package/skills/bootstrap/templates/agents/project-quality-gate.md +18 -0
- package/skills/brainstorm/SKILL.md +268 -0
- package/skills/brainstorm/soul.md +49 -0
- package/skills/claude-md-drift-check/SKILL.md +186 -0
- package/skills/claude-md-drift-check/checker.mjs +1380 -0
- package/skills/claude-md-drift-check/checker.sh +37 -0
- package/skills/claude-md-drift-check/package.json +16 -0
- package/skills/convergence-monitoring/README.md +39 -0
- package/skills/convergence-monitoring/SIGNALS.md +246 -0
- package/skills/convergence-monitoring/SKILL.md +285 -0
- package/skills/daily/SKILL.md +222 -0
- package/skills/daily/generate.sh +92 -0
- package/skills/daily/templates/daily.md.tpl +36 -0
- package/skills/debug/SKILL.md +188 -0
- package/skills/debug/soul.md +35 -0
- package/skills/discovery/SKILL.md +567 -0
- package/skills/discovery/issue-templates.md +237 -0
- package/skills/discovery/probes/docs-staleness.mjs +195 -0
- package/skills/discovery/probes/frontend-slop.mjs +186 -0
- package/skills/discovery/probes/ssot-code-diff.mjs +310 -0
- package/skills/discovery/probes/supply-chain-slopcheck.mjs +440 -0
- package/skills/discovery/probes/vault-narrative-staleness.mjs +355 -0
- package/skills/discovery/probes/vault-staleness.mjs +272 -0
- package/skills/discovery/probes-arch.md +252 -0
- package/skills/discovery/probes-audit.md +95 -0
- package/skills/discovery/probes-code.md +329 -0
- package/skills/discovery/probes-docs.md +76 -0
- package/skills/discovery/probes-feature.md +150 -0
- package/skills/discovery/probes-infra.md +138 -0
- package/skills/discovery/probes-intro.md +25 -0
- package/skills/discovery/probes-session.md +495 -0
- package/skills/discovery/probes-supply-chain.md +94 -0
- package/skills/discovery/probes-ui.md +147 -0
- package/skills/discovery/probes-vault.md +64 -0
- package/skills/discovery/slop-patterns.md +115 -0
- package/skills/dispatcher/SKILL.md +173 -0
- package/skills/docs-orchestrator/SKILL.md +362 -0
- package/skills/docs-orchestrator/audience-mapping.md +140 -0
- package/skills/domain-model/ADR-FORMAT.md +47 -0
- package/skills/domain-model/CONTEXT-FORMAT.md +77 -0
- package/skills/domain-model/SKILL.md +85 -0
- package/skills/ecosystem-health/SKILL.md +119 -0
- package/skills/ecosystem-health/wizard.md +193 -0
- package/skills/eval/SKILL.md +293 -0
- package/skills/eval/rubric-v1.md +218 -0
- package/skills/evolve/SKILL.md +546 -0
- package/skills/frontmatter-guard/SKILL.md +126 -0
- package/skills/gitlab-ops/SKILL.md +368 -0
- package/skills/gitlab-portfolio/SKILL.md +196 -0
- package/skills/grill/SKILL.md +185 -0
- package/skills/grill/soul.md +55 -0
- package/skills/hook-development/SKILL.md +413 -0
- package/skills/mcp-builder/SKILL.md +260 -0
- package/skills/memory-cleanup/SKILL.md +310 -0
- package/skills/mode-selector/SKILL.md +226 -0
- package/skills/peekaboo-driver/SKILL.md +237 -0
- package/skills/peekaboo-driver/soul.md +32 -0
- package/skills/persona-panel/SKILL.md +365 -0
- package/skills/persona-panel/persona-format.md +205 -0
- package/skills/persona-panel/presets/designer-lens.md +87 -0
- package/skills/persona-panel/presets/engineer-lens.md +88 -0
- package/skills/persona-panel/presets/pm-lens.md +86 -0
- package/skills/plan/SKILL.md +496 -0
- package/skills/plan/mode-feature.md +141 -0
- package/skills/plan/mode-new.md +297 -0
- package/skills/plan/mode-retro.md +271 -0
- package/skills/plan/prd-feature-template.md +132 -0
- package/skills/plan/prd-full-template.md +151 -0
- package/skills/plan/prd-reviewer-prompt.md +103 -0
- package/skills/plan/retro-template.md +75 -0
- package/skills/plan/soul.md +62 -0
- package/skills/playwright-driver/SKILL.md +226 -0
- package/skills/playwright-driver/soul.md +30 -0
- package/skills/quality-gates/SKILL.md +212 -0
- package/skills/reconcile/SKILL.md +324 -0
- package/skills/repo-audit/SKILL.md +272 -0
- package/skills/session-end/SKILL.md +1044 -0
- package/skills/session-end/discovery-scan.md +37 -0
- package/skills/session-end/drift-operations.md +97 -0
- package/skills/session-end/learning-patterns.md +78 -0
- package/skills/session-end/metrics-collection.md +175 -0
- package/skills/session-end/phase-3-2-docs-verification.md +148 -0
- package/skills/session-end/phase-3-6-tail.md +344 -0
- package/skills/session-end/phase-3-7a-recommendations.md +86 -0
- package/skills/session-end/plan-verification.md +288 -0
- package/skills/session-end/session-metrics-write.md +223 -0
- package/skills/session-end/vault-operations.md +50 -0
- package/skills/session-end/verification-checklist.md +20 -0
- package/skills/session-plan/SKILL.md +554 -0
- package/skills/session-plan/wave-template.md +37 -0
- package/skills/session-start/SKILL.md +1043 -0
- package/skills/session-start/phase-2-5-docs-planning.md +119 -0
- package/skills/session-start/phase-4-5-resource-health.md +49 -0
- package/skills/session-start/phase-7-1-premise-check.md +47 -0
- package/skills/session-start/phase-7-5-mode-selector.md +237 -0
- package/skills/session-start/phase-8-5-express-path.md +61 -0
- package/skills/session-start/presentation-format.md +81 -0
- package/skills/session-start/soul.md +57 -0
- package/skills/skill-creator/SKILL.md +168 -0
- package/skills/spinout/SKILL.md +76 -0
- package/skills/sunset-review/SKILL.md +96 -0
- package/skills/test-runner/SKILL.md +362 -0
- package/skills/test-runner/rubric-v1.md +388 -0
- package/skills/test-runner/soul.md +46 -0
- package/skills/tmux-layout/SKILL.md +104 -0
- package/skills/ubiquitous-language/SKILL.md +97 -0
- package/skills/using-orchestrator/SKILL.md +144 -0
- package/skills/vault-mirror/SKILL.md +234 -0
- package/skills/vault-sync/SKILL.md +319 -0
- package/skills/vault-sync/package-lock.json +40 -0
- package/skills/vault-sync/package.json +11 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/90-archive/bad-archived.md +8 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/live-note.md +8 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/bad-type.md +8 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/good-note.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/.obsidian/config.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/01-projects/foo/projects-baseline.md +10 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/03-daily/daily-2026-04-13.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/README.md +3 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/hello-world.md +11 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/has-dangling.md +9 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/real-target.md +8 -0
- package/skills/vault-sync/tests/fixtures/empty-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/missing-field-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/missing-field-vault/missing-id.md +7 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/03-daily/daily-2026-04-13.md +9 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/nested-tags-note.md +11 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/README.md +3 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_MOC.md +3 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/_MOC.md +11 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/hello-world.md +11 -0
- package/skills/vault-sync/tests/schema-drift.test.mjs +133 -0
- package/skills/vault-sync/validator.mjs +658 -0
- package/skills/vault-sync/validator.sh +55 -0
- package/skills/wave-executor/SKILL.md +496 -0
- package/skills/wave-executor/circuit-breaker.md +169 -0
- package/skills/wave-executor/wave-loop.md +1043 -0
- package/skills/write-executable-plan/SKILL.md +237 -0
- package/skills/write-executable-plan/plan-template.md +154 -0
- package/templates/_minimal/CLAUDE.md.tmpl +41 -0
- package/templates/_minimal/README.md.tmpl +15 -0
- package/templates/_minimal/gitignore.tmpl +47 -0
- package/templates/_shared/harte-regeln.md +16 -0
- package/templates/_shared/loop.md +90 -0
- package/templates/_shared/rules/parallel-sessions.md +77 -0
- package/templates/nextjs-minimal/README.md +30 -0
- package/templates/nextjs-minimal/app/layout.tsx +18 -0
- package/templates/nextjs-minimal/app/page.tsx +7 -0
- package/templates/nextjs-minimal/eslint.config.mjs +16 -0
- package/templates/nextjs-minimal/next.config.mjs +4 -0
- package/templates/nextjs-minimal/package.json +27 -0
- package/templates/nextjs-minimal/tsconfig.json +23 -0
- package/templates/node-minimal/README.md +33 -0
- package/templates/node-minimal/eslint.config.mjs +10 -0
- package/templates/node-minimal/package.json +21 -0
- package/templates/node-minimal/src/index.ts +1 -0
- package/templates/node-minimal/tests/sanity.test.ts +5 -0
- package/templates/node-minimal/tsconfig.json +17 -0
- package/templates/personas/README.md +150 -0
- package/templates/personas/accounting-compliance.v1.md +120 -0
- package/templates/personas/accounting-tax-advisor.v1.md +116 -0
- package/templates/personas/buyer-p1-cto.v1.md +125 -0
- package/templates/personas/buyer-p2-kanzlei.v1.md +134 -0
- package/templates/personas/buyer-p3-build.v1.md +130 -0
- package/templates/personas/buyer-p4-tech-veto.v1.md +130 -0
- package/templates/personas/buyer-p5-solo.v1.md +132 -0
- package/templates/personas/buyer-p6-ld.v1.md +130 -0
- package/templates/personas/klima-ai-expert.v1.md +114 -0
- package/templates/personas/klima-physicist.v1.md +117 -0
- package/templates/python-uv/README.md +28 -0
- package/templates/python-uv/pyproject.toml +32 -0
- package/templates/python-uv/src/__PROJECT_NAME__/__init__.py +0 -0
- package/templates/python-uv/src/__PROJECT_NAME__/main.py +6 -0
- package/templates/python-uv/tests/test_sanity.py +2 -0
- package/templates/static-html/README.md +19 -0
- package/templates/static-html/index.html +15 -0
- package/templates/static-html/script.js +1 -0
- package/templates/static-html/styles.css +26 -0
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* export-hw-learnings.mjs — anonymize + render hardware-pattern learnings.
|
|
4
|
+
*
|
|
5
|
+
* Part of Sub-Epic #160 / Epic #157 v3.1.0 (C3). Issue #172.
|
|
6
|
+
*
|
|
7
|
+
* Reads `.orchestrator/metrics/learnings.jsonl`, filters to
|
|
8
|
+
* `type: hardware-pattern AND scope: public`, anonymizes per the hard
|
|
9
|
+
* requirements in issue #172, and writes a human-readable markdown doc.
|
|
10
|
+
*
|
|
11
|
+
* Default output target: Epic #774 (docs Public-Split) removed the prior
|
|
12
|
+
* in-repo generated telemetry doc — the default `--output` path now resolves
|
|
13
|
+
* to the private Meta-Vault (`<vault-dir>/01-projects/session-orchestrator/
|
|
14
|
+
* research/hardware-patterns.md`), via the same `vault-integration.vault-dir`
|
|
15
|
+
* resolution `scripts/archive-closed-prds.mjs` uses (findProjectRoot →
|
|
16
|
+
* CLAUDE.md/AGENTS.md → parseSessionConfig; host-resolved: SO_VAULT_DIR env >
|
|
17
|
+
* owner.yaml paths.vault-dir > committed default). Pass `--output <path>` to
|
|
18
|
+
* override.
|
|
19
|
+
*
|
|
20
|
+
* Idempotent: running without new data rewrites the same file byte-for-byte
|
|
21
|
+
* modulo the generated-at line.
|
|
22
|
+
*
|
|
23
|
+
* ## Anonymization pipeline (enforced; no opt-out)
|
|
24
|
+
*
|
|
25
|
+
* - Strip all absolute paths (macOS, Linux system paths, Windows)
|
|
26
|
+
* - Redact IPv4 addresses
|
|
27
|
+
* - Redact GitHub/GitLab URLs containing org/repo paths
|
|
28
|
+
* - Replace hostname references with `host_class` label
|
|
29
|
+
* - Redact email, git author, token patterns
|
|
30
|
+
* - No free-form text from user — only structured fields
|
|
31
|
+
* - Round ram/cpu to 1 GB / 10% buckets
|
|
32
|
+
*
|
|
33
|
+
* ## Invocation
|
|
34
|
+
*
|
|
35
|
+
* node scripts/export-hw-learnings.mjs # default paths
|
|
36
|
+
* node scripts/export-hw-learnings.mjs --dry-run # emit to stdout, no write
|
|
37
|
+
* node scripts/export-hw-learnings.mjs --input X --output Y
|
|
38
|
+
* node scripts/export-hw-learnings.mjs --promote # promote private→public + render
|
|
39
|
+
* node scripts/export-hw-learnings.mjs --promote --dry-run # promote without writing
|
|
40
|
+
*
|
|
41
|
+
* npm script: `npm run share:hw-learnings`
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
45
|
+
import { readFileSync } from 'node:fs';
|
|
46
|
+
import path from 'node:path';
|
|
47
|
+
import {
|
|
48
|
+
readLearnings,
|
|
49
|
+
filterByScope,
|
|
50
|
+
filterByType,
|
|
51
|
+
normalizeLearning,
|
|
52
|
+
validateLearning,
|
|
53
|
+
rewriteLearnings,
|
|
54
|
+
CURRENT_ANONYMIZATION_VERSION,
|
|
55
|
+
} from './lib/learnings.mjs';
|
|
56
|
+
import { findProjectRoot, resolveInstructionFile, expandTilde } from './lib/common.mjs';
|
|
57
|
+
import { parseSessionConfig } from './lib/config.mjs';
|
|
58
|
+
|
|
59
|
+
// Vault-relative default write target (Epic #774 — docs Public-Split removed
|
|
60
|
+
// the prior in-repo generated telemetry doc in favor of the private Meta-Vault).
|
|
61
|
+
const DEFAULT_VAULT_SUBPATH = path.join('01-projects', 'session-orchestrator', 'research', 'hardware-patterns.md');
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Resolve the default `--output` path when the CLI caller does not pass one
|
|
65
|
+
* explicitly. Mirrors the vault-dir resolution `scripts/archive-closed-prds.mjs`
|
|
66
|
+
* uses: findProjectRoot → CLAUDE.md/AGENTS.md → parseSessionConfig →
|
|
67
|
+
* vault-integration.vault-dir (host-resolved: SO_VAULT_DIR env > owner.yaml
|
|
68
|
+
* paths.vault-dir > committed default).
|
|
69
|
+
*
|
|
70
|
+
* @param {object} [opts]
|
|
71
|
+
* @param {string} [opts.repoRoot] — override for findProjectRoot() (tests).
|
|
72
|
+
* @param {{ env?: Record<string, string|undefined>, ownerConfig?: object }} [opts.hostPaths]
|
|
73
|
+
* — forwarded to parseSessionConfig (tests pass `{ env: {}, ownerConfig: undefined }`
|
|
74
|
+
* for hermetic, owner.yaml-free resolution — issue #653 bleed guard).
|
|
75
|
+
* @returns {string|null} the resolved output path, or null when vault-dir is
|
|
76
|
+
* unconfigured/unresolvable.
|
|
77
|
+
*/
|
|
78
|
+
export function resolveDefaultOutput({ repoRoot, hostPaths } = {}) {
|
|
79
|
+
const root = repoRoot ?? findProjectRoot();
|
|
80
|
+
const instr = resolveInstructionFile(root);
|
|
81
|
+
if (!instr) return null;
|
|
82
|
+
|
|
83
|
+
let vaultDir;
|
|
84
|
+
try {
|
|
85
|
+
const content = readFileSync(instr.path, 'utf8');
|
|
86
|
+
const config = parseSessionConfig(content, hostPaths ? { hostPaths } : undefined);
|
|
87
|
+
vaultDir = config?.['vault-integration']?.['vault-dir'];
|
|
88
|
+
} catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
if (!vaultDir || typeof vaultDir !== 'string' || vaultDir.trim() === '') return null;
|
|
92
|
+
|
|
93
|
+
// Expand a `~`-prefixed vault-dir (e.g. the committed Session Config default
|
|
94
|
+
// `~/Projects/vault`) — this path does NOT route through vault-archive.mjs,
|
|
95
|
+
// so it needs its own expansion seam (issue: architect review finding).
|
|
96
|
+
return path.join(expandTilde(vaultDir), DEFAULT_VAULT_SUBPATH);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// Anonymization
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
// Unix absolute paths: covers macOS /Users, Linux home dirs, and Linux system
|
|
104
|
+
// paths (/root, /var, /opt, /tmp, /mnt, /srv, /etc, /usr, /proc, /run).
|
|
105
|
+
// Character class [^\s"'<>]+ after the root prefix captures path components
|
|
106
|
+
// including @, +, ~, spaces are explicitly excluded as path terminators.
|
|
107
|
+
const UNIX_PATH_RE = /(?:\/(?:Users|home|root|var|opt|tmp|mnt|srv|etc|usr|proc|run))[/A-Za-z0-9._@+~-][^\s"'<>]*/g;
|
|
108
|
+
|
|
109
|
+
// Windows paths: both backslash (`C:\Program Files\...`) and forward-slash
|
|
110
|
+
// normalized variants (`C:/Users/foo`). Spaces allowed in path components.
|
|
111
|
+
const WIN_PATH_RE = /[A-Z]:[/\\][^\s"'<>]*/g;
|
|
112
|
+
|
|
113
|
+
const ABS_PATH_RES = [UNIX_PATH_RE, WIN_PATH_RE];
|
|
114
|
+
|
|
115
|
+
// IPv4 address: four dot-separated octets, word-boundary anchored.
|
|
116
|
+
const IPV4_RE = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g;
|
|
117
|
+
|
|
118
|
+
// GitHub / GitLab URLs that expose an org/repo path. Redact the full URL to
|
|
119
|
+
// avoid leaking username or private repo names. The pattern matches
|
|
120
|
+
// https://(github|gitlab).<tld>/<org>/<repo> (with optional trailing path).
|
|
121
|
+
const VCS_URL_RE = /https?:\/\/(?:github|gitlab)\.[^/\s]+\/[\w.-]+\/[\w.-][^\s"']*/g;
|
|
122
|
+
|
|
123
|
+
const EMAIL_RE = /[A-Za-z0-9._+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g;
|
|
124
|
+
|
|
125
|
+
// Token-shape heuristic: base64-ish/hex-ish runs ≥ 20 chars with at least one
|
|
126
|
+
// digit and one letter. Intentionally broad — it's better to over-redact.
|
|
127
|
+
const TOKEN_RE = /\b(?=[A-Za-z0-9_-]*[A-Za-z])(?=[A-Za-z0-9_-]*\d)[A-Za-z0-9_-]{20,}\b/g;
|
|
128
|
+
|
|
129
|
+
// Common git-author patterns: "First Last <email@...>" or "Signed-off-by: X"
|
|
130
|
+
const GIT_AUTHOR_RE = /\b([A-Z][a-zA-Z-]+ ){1,3}<[^>]+>/g;
|
|
131
|
+
const SIGNED_OFF_RE = /Signed-off-by:[^\n]+/g;
|
|
132
|
+
|
|
133
|
+
// Bare hostname patterns (mDNS / private LAN TLDs that are user-chosen and
|
|
134
|
+
// identifying). Keeps `host_class` strings like 'macos-arm64-m3pro' safe —
|
|
135
|
+
// those never appear with a .local/.lan/.home suffix.
|
|
136
|
+
const HOSTNAME_RE = /\b[A-Za-z0-9]+(?:[-.][A-Za-z0-9]+)*\.(?:local|lan|home|internal|corp)\b/g;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Scrub a free-form string of PII / host-identifying content.
|
|
140
|
+
* Order matters: author/signoff patterns first (they contain emails), then
|
|
141
|
+
* emails, then paths/IPs/VCS-URLs, then hostnames, then tokens.
|
|
142
|
+
* @param {string} s
|
|
143
|
+
* @returns {string}
|
|
144
|
+
*/
|
|
145
|
+
export function anonymizeString(s) {
|
|
146
|
+
if (typeof s !== 'string') return s;
|
|
147
|
+
let out = s;
|
|
148
|
+
out = out.replace(GIT_AUTHOR_RE, '<redacted-author>');
|
|
149
|
+
out = out.replace(SIGNED_OFF_RE, '<redacted-signoff>');
|
|
150
|
+
out = out.replace(EMAIL_RE, '<redacted-email>');
|
|
151
|
+
// VCS URLs before generic path handling (they start with https://, not a path root)
|
|
152
|
+
out = out.replace(VCS_URL_RE, '<VCS-URL>');
|
|
153
|
+
for (const re of ABS_PATH_RES) out = out.replace(re, '<redacted-path>');
|
|
154
|
+
out = out.replace(IPV4_RE, '<IP>');
|
|
155
|
+
out = out.replace(HOSTNAME_RE, '<redacted-hostname>');
|
|
156
|
+
out = out.replace(TOKEN_RE, '<redacted-token>');
|
|
157
|
+
return out;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Round to 1 GB bucket (nearest integer).
|
|
162
|
+
*/
|
|
163
|
+
export function bucketRamGb(gb) {
|
|
164
|
+
if (typeof gb !== 'number' || Number.isNaN(gb)) return null;
|
|
165
|
+
return Math.round(gb);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Round to 10% bucket.
|
|
170
|
+
*/
|
|
171
|
+
export function bucketCpuPct(pct) {
|
|
172
|
+
if (typeof pct !== 'number' || Number.isNaN(pct)) return null;
|
|
173
|
+
return Math.round(pct / 10) * 10;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Anonymize a single learning entry's free-form fields.
|
|
178
|
+
* Drops `source_session` entirely (session IDs are host-correlated).
|
|
179
|
+
* Stamps `anonymized: true` and `anonymization_version` so the result passes
|
|
180
|
+
* the privacy-contract check in `validateLearning` for scope=public entries.
|
|
181
|
+
* @param {object} entry
|
|
182
|
+
* @returns {object} anonymized entry (safe for public export)
|
|
183
|
+
*/
|
|
184
|
+
export function anonymizeLearning(entry) {
|
|
185
|
+
const e = normalizeLearning(entry);
|
|
186
|
+
const out = {
|
|
187
|
+
...e,
|
|
188
|
+
insight: anonymizeString(e.insight),
|
|
189
|
+
evidence: anonymizeString(e.evidence),
|
|
190
|
+
// Stamp after redaction so callers that write back through validateLearning
|
|
191
|
+
// do not hit the scope=public contract check.
|
|
192
|
+
anonymized: true,
|
|
193
|
+
anonymization_version: CURRENT_ANONYMIZATION_VERSION,
|
|
194
|
+
};
|
|
195
|
+
// Session IDs contain branch names + timestamps → host-correlated, remove
|
|
196
|
+
delete out.source_session;
|
|
197
|
+
// Round numeric buckets if present in anonymization samples
|
|
198
|
+
if (Array.isArray(out.samples)) {
|
|
199
|
+
out.samples = out.samples.map((s) => ({
|
|
200
|
+
...s,
|
|
201
|
+
ram_free_gb: bucketRamGb(s.ram_free_gb),
|
|
202
|
+
cpu_load_pct: bucketCpuPct(s.cpu_load_pct),
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
// Rendering
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Group learnings by host_class, then by signal inside each host.
|
|
214
|
+
* Returns a map keyed on host_class with ordered signal entries.
|
|
215
|
+
*/
|
|
216
|
+
export function groupByHost(entries) {
|
|
217
|
+
const byHost = new Map();
|
|
218
|
+
for (const e of entries) {
|
|
219
|
+
const host = e.host_class ?? '<unknown>';
|
|
220
|
+
let entry = byHost.get(host);
|
|
221
|
+
if (!entry) {
|
|
222
|
+
entry = { host_class: host, report_count: 0, signals: new Map() };
|
|
223
|
+
byHost.set(host, entry);
|
|
224
|
+
}
|
|
225
|
+
entry.report_count += 1;
|
|
226
|
+
const sig = (e.subject.split('::')[0]) || 'unknown';
|
|
227
|
+
const sigBucket = entry.signals.get(sig) || { signal: sig, items: [] };
|
|
228
|
+
sigBucket.items.push(e);
|
|
229
|
+
entry.signals.set(sig, sigBucket);
|
|
230
|
+
}
|
|
231
|
+
return byHost;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Render the grouped map as a human-readable markdown document.
|
|
236
|
+
* Deterministic ordering: host_class alphabetical, signals alphabetical within.
|
|
237
|
+
* @param {Map<string, object>} grouped
|
|
238
|
+
* @param {string} generatedAt — ISO 8601 timestamp (caller-provided for determinism in tests)
|
|
239
|
+
* @returns {string} markdown body
|
|
240
|
+
*/
|
|
241
|
+
export function renderMarkdown(grouped, generatedAt) {
|
|
242
|
+
const lines = [];
|
|
243
|
+
lines.push('# Hardware Pattern Telemetry');
|
|
244
|
+
lines.push('');
|
|
245
|
+
lines.push('> Anonymized community-shared hardware patterns. Generated from opt-in learnings.');
|
|
246
|
+
lines.push('> See CONTRIBUTING.md for how to opt-in / opt-out / inspect before share.');
|
|
247
|
+
lines.push('');
|
|
248
|
+
lines.push(`_Generated: ${generatedAt}_`);
|
|
249
|
+
lines.push('');
|
|
250
|
+
|
|
251
|
+
const hosts = Array.from(grouped.keys()).sort();
|
|
252
|
+
if (hosts.length === 0) {
|
|
253
|
+
lines.push('_No public hardware-pattern learnings to report._');
|
|
254
|
+
lines.push('');
|
|
255
|
+
return lines.join('\n');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
for (const host of hosts) {
|
|
259
|
+
const h = grouped.get(host);
|
|
260
|
+
lines.push(`## ${host} (${h.report_count} reports)`);
|
|
261
|
+
lines.push('');
|
|
262
|
+
const signals = Array.from(h.signals.keys()).sort();
|
|
263
|
+
for (const sig of signals) {
|
|
264
|
+
const bucket = h.signals.get(sig);
|
|
265
|
+
const occurrences = bucket.items.reduce((n, e) => {
|
|
266
|
+
const m = /occurrences=(\d+)/.exec(e.evidence || '');
|
|
267
|
+
return n + (m ? parseInt(m[1], 10) : 1);
|
|
268
|
+
}, 0);
|
|
269
|
+
lines.push(`- **${sig}** — ${occurrences} occurrences across ${bucket.items.length} report${bucket.items.length === 1 ? '' : 's'}`);
|
|
270
|
+
for (const item of bucket.items) {
|
|
271
|
+
lines.push(` - ${item.insight}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
lines.push('');
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return lines.join('\n');
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// ---------------------------------------------------------------------------
|
|
281
|
+
// Main
|
|
282
|
+
// ---------------------------------------------------------------------------
|
|
283
|
+
|
|
284
|
+
function parseArgs(argv) {
|
|
285
|
+
const out = {
|
|
286
|
+
dryRun: false,
|
|
287
|
+
promote: false,
|
|
288
|
+
input: '.orchestrator/metrics/learnings.jsonl',
|
|
289
|
+
output: undefined, // resolved lazily below (default = vault-dir target)
|
|
290
|
+
generatedAt: new Date().toISOString(),
|
|
291
|
+
};
|
|
292
|
+
for (let i = 0; i < argv.length; i++) {
|
|
293
|
+
const a = argv[i];
|
|
294
|
+
if (a === '--dry-run') out.dryRun = true;
|
|
295
|
+
else if (a === '--promote') out.promote = true;
|
|
296
|
+
else if (a === '--input') out.input = argv[++i];
|
|
297
|
+
else if (a === '--output') out.output = argv[++i];
|
|
298
|
+
else if (a === '--generated-at') out.generatedAt = argv[++i];
|
|
299
|
+
else if (a === '--help' || a === '-h') {
|
|
300
|
+
process.stdout.write(
|
|
301
|
+
'Usage: export-hw-learnings.mjs [--dry-run] [--promote] [--input FILE] [--output FILE]\n' +
|
|
302
|
+
'\n' +
|
|
303
|
+
' (no flags) Render already-public hardware-pattern entries to markdown.\n' +
|
|
304
|
+
' --promote Anonymize scope=private hardware-pattern entries and promote\n' +
|
|
305
|
+
' them to scope=public, then render. Writes back to learnings.jsonl\n' +
|
|
306
|
+
' (backup created first). Use with --dry-run to preview.\n' +
|
|
307
|
+
' --dry-run Print markdown to stdout; do not write any files.\n' +
|
|
308
|
+
' --output FILE Override the default write target. Default: resolved from\n' +
|
|
309
|
+
' vault-integration.vault-dir (see script header doc).\n'
|
|
310
|
+
);
|
|
311
|
+
process.exit(0);
|
|
312
|
+
} else {
|
|
313
|
+
process.stderr.write(`unknown arg: ${a}\n`);
|
|
314
|
+
process.exit(2);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (!out.output && !out.dryRun) {
|
|
318
|
+
const resolved = resolveDefaultOutput();
|
|
319
|
+
if (!resolved) {
|
|
320
|
+
process.stderr.write(
|
|
321
|
+
'export-hw-learnings: could not resolve vault-integration.vault-dir for the default ' +
|
|
322
|
+
'--output path (no CLAUDE.md/AGENTS.md found, or vault-dir is unset). ' +
|
|
323
|
+
'Pass --output <path> explicitly.\n'
|
|
324
|
+
);
|
|
325
|
+
process.exit(1);
|
|
326
|
+
}
|
|
327
|
+
out.output = resolved;
|
|
328
|
+
}
|
|
329
|
+
return out;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// ---------------------------------------------------------------------------
|
|
333
|
+
// Promotion pipeline (Part C)
|
|
334
|
+
// ---------------------------------------------------------------------------
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Promote scope=private hardware-pattern entries to scope=public after
|
|
338
|
+
* anonymization. Creates a twin public entry; the original private entry is
|
|
339
|
+
* preserved. Backs up the JSONL before writing.
|
|
340
|
+
*
|
|
341
|
+
* @param {object} opts
|
|
342
|
+
* @param {string} opts.input — path to learnings.jsonl
|
|
343
|
+
* @param {boolean} opts.dryRun — if true, do not write any files
|
|
344
|
+
* @returns {Promise<{promoted: number, skipped: number, flags: string[]}>}
|
|
345
|
+
*/
|
|
346
|
+
export async function promoteHwLearnings(opts) {
|
|
347
|
+
const { entries, malformed } = await readLearnings(opts.input);
|
|
348
|
+
|
|
349
|
+
const hwPrivate = filterByScope(filterByType(entries, 'hardware-pattern'), 'private');
|
|
350
|
+
const hwPublicExisting = filterByScope(filterByType(entries, 'hardware-pattern'), 'public');
|
|
351
|
+
|
|
352
|
+
const flags = [];
|
|
353
|
+
if (malformed.length > 0) {
|
|
354
|
+
flags.push(`${malformed.length} malformed line(s) in learnings.jsonl were skipped`);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (hwPrivate.length === 0) {
|
|
358
|
+
return { promoted: 0, skipped: hwPublicExisting.length, flags };
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Build promoted entries: anonymize + flip scope to public.
|
|
362
|
+
// Validate EACH entry through validateLearning before any write — a contract
|
|
363
|
+
// violation is a fatal error; we do not partial-write.
|
|
364
|
+
const promotedEntries = [];
|
|
365
|
+
for (const e of hwPrivate) {
|
|
366
|
+
const anon = anonymizeLearning(e);
|
|
367
|
+
const candidate = {
|
|
368
|
+
...anon,
|
|
369
|
+
// anonymizeLearning strips source_session (host-correlated), but
|
|
370
|
+
// validateLearning requires it as a legacy field. Restore a redacted
|
|
371
|
+
// placeholder so the validator accepts the promoted entry.
|
|
372
|
+
source_session: '<redacted>',
|
|
373
|
+
scope: 'public',
|
|
374
|
+
anonymized: true,
|
|
375
|
+
anonymization_version: CURRENT_ANONYMIZATION_VERSION,
|
|
376
|
+
};
|
|
377
|
+
if (!candidate.host_class) {
|
|
378
|
+
throw new Error(
|
|
379
|
+
`Cannot promote learning id=${e.id}: host_class is not set (required for scope=public). ` +
|
|
380
|
+
'Set host_class on the private entry before promoting.'
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
// validateLearning throws ValidationError on any contract violation.
|
|
384
|
+
// We let it propagate — no partial writes.
|
|
385
|
+
validateLearning(candidate);
|
|
386
|
+
promotedEntries.push(candidate);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (!opts.dryRun) {
|
|
390
|
+
// Rewrite: all original entries + new public twins appended at the end.
|
|
391
|
+
// Original private entries are preserved (the twin is a new record).
|
|
392
|
+
// The `.bak-<ISO>` backup (keep 3) is created inside rewriteLearnings (#721);
|
|
393
|
+
// the script-level dryRun gate above is what suppresses it on a dry run.
|
|
394
|
+
const allEntries = [...entries, ...promotedEntries];
|
|
395
|
+
await rewriteLearnings(opts.input, allEntries);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return { promoted: promotedEntries.length, skipped: hwPublicExisting.length, flags };
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export async function exportHwLearnings(opts) {
|
|
402
|
+
const { entries } = await readLearnings(opts.input);
|
|
403
|
+
const hwPublic = filterByScope(filterByType(entries, 'hardware-pattern'), 'public');
|
|
404
|
+
const anonymized = hwPublic.map((e) => anonymizeLearning(e));
|
|
405
|
+
const grouped = groupByHost(anonymized);
|
|
406
|
+
const md = renderMarkdown(grouped, opts.generatedAt);
|
|
407
|
+
if (!opts.dryRun) {
|
|
408
|
+
await mkdir(path.dirname(opts.output), { recursive: true });
|
|
409
|
+
await writeFile(opts.output, md, 'utf8');
|
|
410
|
+
}
|
|
411
|
+
return { markdown: md, count: hwPublic.length };
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Run as CLI when invoked directly
|
|
415
|
+
const isMain = import.meta.url === `file://${process.argv[1]}`;
|
|
416
|
+
if (isMain) {
|
|
417
|
+
const opts = parseArgs(process.argv.slice(2));
|
|
418
|
+
|
|
419
|
+
const run = async () => {
|
|
420
|
+
if (opts.promote) {
|
|
421
|
+
const { promoted, skipped, flags } = await promoteHwLearnings(opts);
|
|
422
|
+
const label = opts.dryRun ? '[dry-run] ' : '';
|
|
423
|
+
process.stdout.write(
|
|
424
|
+
`${label}Promotion complete: ${promoted} promoted, ${skipped} already public (skipped).\n`
|
|
425
|
+
);
|
|
426
|
+
for (const f of flags) process.stdout.write(` warning: ${f}\n`);
|
|
427
|
+
}
|
|
428
|
+
const { markdown, count } = await exportHwLearnings(opts);
|
|
429
|
+
if (opts.dryRun) process.stdout.write(markdown);
|
|
430
|
+
else process.stdout.write(`Wrote ${count} hardware-pattern learnings to ${opts.output}\n`);
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
run().catch((err) => {
|
|
434
|
+
process.stderr.write(`export failed: ${err.message}\n`);
|
|
435
|
+
process.exit(1);
|
|
436
|
+
});
|
|
437
|
+
}
|