kenaz 0.0.0-stage → 0.3.2
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/bin/kenaz.js +3 -0
- package/core/.agents/skills/remotion-best-practices/SKILL.md +61 -0
- package/core/.agents/skills/remotion-best-practices/rules/3d.md +86 -0
- package/core/.agents/skills/remotion-best-practices/rules/animations.md +27 -0
- package/core/.agents/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
- package/core/.agents/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
- package/core/.agents/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +103 -0
- package/core/.agents/skills/remotion-best-practices/rules/assets.md +78 -0
- package/core/.agents/skills/remotion-best-practices/rules/audio-visualization.md +198 -0
- package/core/.agents/skills/remotion-best-practices/rules/audio.md +169 -0
- package/core/.agents/skills/remotion-best-practices/rules/calculate-metadata.md +134 -0
- package/core/.agents/skills/remotion-best-practices/rules/can-decode.md +81 -0
- package/core/.agents/skills/remotion-best-practices/rules/charts.md +120 -0
- package/core/.agents/skills/remotion-best-practices/rules/compositions.md +154 -0
- package/core/.agents/skills/remotion-best-practices/rules/display-captions.md +184 -0
- package/core/.agents/skills/remotion-best-practices/rules/extract-frames.md +229 -0
- package/core/.agents/skills/remotion-best-practices/rules/ffmpeg.md +38 -0
- package/core/.agents/skills/remotion-best-practices/rules/fonts.md +152 -0
- package/core/.agents/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
- package/core/.agents/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
- package/core/.agents/skills/remotion-best-practices/rules/get-video-duration.md +60 -0
- package/core/.agents/skills/remotion-best-practices/rules/gifs.md +141 -0
- package/core/.agents/skills/remotion-best-practices/rules/images.md +134 -0
- package/core/.agents/skills/remotion-best-practices/rules/import-srt-captions.md +69 -0
- package/core/.agents/skills/remotion-best-practices/rules/light-leaks.md +73 -0
- package/core/.agents/skills/remotion-best-practices/rules/lottie.md +70 -0
- package/core/.agents/skills/remotion-best-practices/rules/maps.md +412 -0
- package/core/.agents/skills/remotion-best-practices/rules/measuring-dom-nodes.md +34 -0
- package/core/.agents/skills/remotion-best-practices/rules/measuring-text.md +140 -0
- package/core/.agents/skills/remotion-best-practices/rules/parameters.md +109 -0
- package/core/.agents/skills/remotion-best-practices/rules/sequencing.md +118 -0
- package/core/.agents/skills/remotion-best-practices/rules/sfx.md +30 -0
- package/core/.agents/skills/remotion-best-practices/rules/subtitles.md +36 -0
- package/core/.agents/skills/remotion-best-practices/rules/tailwind.md +11 -0
- package/core/.agents/skills/remotion-best-practices/rules/text-animations.md +20 -0
- package/core/.agents/skills/remotion-best-practices/rules/timing.md +179 -0
- package/core/.agents/skills/remotion-best-practices/rules/transcribe-captions.md +70 -0
- package/core/.agents/skills/remotion-best-practices/rules/transitions.md +197 -0
- package/core/.agents/skills/remotion-best-practices/rules/transparent-videos.md +106 -0
- package/core/.agents/skills/remotion-best-practices/rules/trimming.md +51 -0
- package/core/.agents/skills/remotion-best-practices/rules/videos.md +171 -0
- package/core/.agents/skills/remotion-best-practices/rules/voiceover.md +99 -0
- package/core/.agents/skills/supabase-postgres-best-practices/AGENTS.md +90 -0
- package/core/.agents/skills/supabase-postgres-best-practices/CLAUDE.md +1 -0
- package/core/.agents/skills/supabase-postgres-best-practices/SKILL.md +64 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/query-index-types.md +45 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
- package/core/.agents/skills/supabase-postgres-best-practices/references/security-rls-performance.md +57 -0
- package/core/.agents/skills/typesafe-ai/LICENSE +21 -0
- package/core/.agents/skills/typesafe-ai/SKILL.md +149 -0
- package/core/.agents/skills/vercel-react-best-practices/AGENTS.md +2934 -0
- package/core/.agents/skills/vercel-react-best-practices/SKILL.md +136 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/core/.agents/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/core/.claude/agents/pcb-reviewer.md +146 -0
- package/core/.claude/commands/Amelia.md +5 -0
- package/core/.claude/commands/Ansuz.md +38 -0
- package/core/.claude/commands/Huginn.md +25 -0
- package/core/.claude/commands/agent-worker.md +168 -0
- package/core/.claude/commands/architect.md +24 -0
- package/core/.claude/commands/archive.md +24 -0
- package/core/.claude/commands/canary.md +17 -0
- package/core/.claude/commands/incident.md +15 -0
- package/core/.claude/commands/init.md +112 -0
- package/core/.claude/commands/legacy_dev.md +18 -0
- package/core/.claude/commands/product-review.md +131 -0
- package/core/.claude/commands/review.md +14 -0
- package/core/.claude/commands/security.md +15 -0
- package/core/.claude/commands/spec.md +22 -0
- package/core/.claude/commands/strategy.md +141 -0
- package/core/.claude/commands/sunny.md +1 -0
- package/core/.claude/commands//347/224/242/345/223/201.md +15 -0
- package/core/.claude/commands//347/224/242/345/223/201/346/252/242/350/246/226.md +129 -0
- package/core/.claude/commands//350/250/255/350/250/210.md +14 -0
- package/core/.claude/commands//350/251/225/344/274/260.md +16 -0
- package/core/.claude/commands//351/200/262/345/272/246.md +15 -0
- package/core/.claude/hooks/__tests__/substrate.test.js +122 -0
- package/core/.claude/hooks/__tests__/task-1866-cli-guard.test.js +193 -0
- package/core/.claude/hooks/__tests__/task-1977-dedupe-guard.test.js +125 -0
- package/core/.claude/hooks/__tests__/task-2087-mark-landed-idempotent.test.js +128 -0
- package/core/.claude/hooks/__tests__/task-2253-null-tip-marker-reuse.test.js +84 -0
- package/core/.claude/hooks/__tests__/task-2381-project-guard-walkup.test.js +53 -0
- package/core/.claude/hooks/_ansuz-conversation.js +183 -0
- package/core/.claude/hooks/_ansuz-conversation.test.js +90 -0
- package/core/.claude/hooks/_dedupe-guard.js +75 -0
- package/core/.claude/hooks/_peer-project-root.js +113 -0
- package/core/.claude/hooks/_peer-project-root.test.js +121 -0
- package/core/.claude/hooks/_peer-waiting-line.js +27 -0
- package/core/.claude/hooks/_project-guard.js +45 -0
- package/core/.claude/hooks/_run-user-prompt.js +134 -0
- package/core/.claude/hooks/_run-user-prompt.test.js +80 -0
- package/core/.claude/hooks/_session-identity.js +62 -0
- package/core/.claude/hooks/_session-pin.js +34 -0
- package/core/.claude/hooks/_session-pin.test.js +89 -0
- package/core/.claude/hooks/_signal-fence.js +17 -0
- package/core/.claude/hooks/_substrate-paths.js +95 -0
- package/core/.claude/hooks/_user-scope.js +23 -0
- package/core/.claude/hooks/ansuz-session-pin-via-turn-context.test.js +52 -0
- package/core/.claude/hooks/ansuz-session-pin.js +171 -0
- package/core/.claude/hooks/ansuz-session-pin.test.js +140 -0
- package/core/.claude/hooks/context-check.js +51 -0
- package/core/.claude/hooks/core-resolve.js +230 -0
- package/core/.claude/hooks/daemon-outbox-hook.js +139 -0
- package/core/.claude/hooks/fatigue-check.js +52 -0
- package/core/.claude/hooks/handoff-snapshot-on-commit.js +154 -0
- package/core/.claude/hooks/handoff-snapshot-on-decision.js +188 -0
- package/core/.claude/hooks/handoff-snapshot-on-question.js +158 -0
- package/core/.claude/hooks/handoff-staleness.js +197 -0
- package/core/.claude/hooks/jev-thalamus-context.js +17 -0
- package/core/.claude/hooks/jev-thalamus-context.test.js +41 -0
- package/core/.claude/hooks/lease-release.js +119 -0
- package/core/.claude/hooks/lease-touch.js +96 -0
- package/core/.claude/hooks/memory-guard.js +723 -0
- package/core/.claude/hooks/memory-guard.test.js +574 -0
- package/core/.claude/hooks/reflex-feedback.js +5 -0
- package/core/.claude/hooks/session-init.ps1 +49 -0
- package/core/.claude/hooks/sound-event.js +70 -0
- package/core/.claude/hooks/sound-event.sh +37 -0
- package/core/.claude/hooks/stream-delta.js +169 -0
- package/core/.claude/hooks/synapse-first-investigation.js +326 -0
- package/core/.claude/hooks/synapse-first-investigation.test.js +126 -0
- package/core/.claude/hooks/task-bridge.js +33 -0
- package/core/.claude/hooks/turn-context-peer.test.js +115 -0
- package/core/.claude/hooks/turn-context-session-line.test.js +69 -0
- package/core/.claude/hooks/turn-context.js +215 -0
- package/core/.claude/hooks/worktree-create.js +1232 -0
- package/core/.claude/hooks/worktree-remove.js +181 -0
- package/core/.claude/no-hooks.settings.json +3 -0
- package/core/.claude/settings.json +180 -0
- package/core/.claude/skills/adapt/SKILL.md +199 -0
- package/core/.claude/skills/animate/SKILL.md +190 -0
- package/core/.claude/skills/architect_agent/SKILL.md +408 -0
- package/core/.claude/skills/assessment_agent/SKILL.md +289 -0
- package/core/.claude/skills/audit/SKILL.md +129 -0
- package/core/.claude/skills/backend_agent/SKILL.md +407 -0
- package/core/.claude/skills/backend_engineer/SKILL.md +788 -0
- package/core/.claude/skills/bolder/SKILL.md +132 -0
- package/core/.claude/skills/clarify/SKILL.md +180 -0
- package/core/.claude/skills/code_reviewer/SKILL.md +305 -0
- package/core/.claude/skills/code_reviewer/patterns.yaml +85 -0
- package/core/.claude/skills/colorize/SKILL.md +158 -0
- package/core/.claude/skills/critique/SKILL.md +118 -0
- package/core/.claude/skills/delight/SKILL.md +317 -0
- package/core/.claude/skills/designer/SKILL.md +845 -0
- package/core/.claude/skills/dev_agent/SKILL.md +503 -0
- package/core/.claude/skills/developer/SKILL.md +792 -0
- package/core/.claude/skills/distill/SKILL.md +137 -0
- package/core/.claude/skills/extract/SKILL.md +95 -0
- package/core/.claude/skills/feature_agent/SKILL.md +303 -0
- package/core/.claude/skills/frontend-design/SKILL.md +127 -0
- package/core/.claude/skills/frontend-design/reference/color-and-contrast.md +132 -0
- package/core/.claude/skills/frontend-design/reference/interaction-design.md +123 -0
- package/core/.claude/skills/frontend-design/reference/motion-design.md +99 -0
- package/core/.claude/skills/frontend-design/reference/responsive-design.md +114 -0
- package/core/.claude/skills/frontend-design/reference/spatial-design.md +100 -0
- package/core/.claude/skills/frontend-design/reference/typography.md +131 -0
- package/core/.claude/skills/frontend-design/reference/ux-writing.md +107 -0
- package/core/.claude/skills/frontend_agent/SKILL.md +327 -0
- package/core/.claude/skills/harden/SKILL.md +358 -0
- package/core/.claude/skills/heimdall/SKILL.md +84 -0
- package/core/.claude/skills/huginn/SKILL.md +208 -0
- package/core/.claude/skills/incident_response/SKILL.md +315 -0
- package/core/.claude/skills/legacy_dev/SKILL.md +202 -0
- package/core/.claude/skills/normalize/SKILL.md +67 -0
- package/core/.claude/skills/onboard/SKILL.md +243 -0
- package/core/.claude/skills/optimization_agent/SKILL.md +340 -0
- package/core/.claude/skills/optimize/SKILL.md +269 -0
- package/core/.claude/skills/pcb-review/SKILL.md +39 -0
- package/core/.claude/skills/polish/SKILL.md +202 -0
- package/core/.claude/skills/product_manager/SKILL.md +1091 -0
- package/core/.claude/skills/qa_engineer/SKILL.md +1269 -0
- package/core/.claude/skills/quieter/SKILL.md +118 -0
- package/core/.claude/skills/remotion-best-practices/SKILL.md +61 -0
- package/core/.claude/skills/remotion-best-practices/rules/3d.md +86 -0
- package/core/.claude/skills/remotion-best-practices/rules/animations.md +27 -0
- package/core/.claude/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
- package/core/.claude/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
- package/core/.claude/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +103 -0
- package/core/.claude/skills/remotion-best-practices/rules/assets.md +78 -0
- package/core/.claude/skills/remotion-best-practices/rules/audio-visualization.md +198 -0
- package/core/.claude/skills/remotion-best-practices/rules/audio.md +169 -0
- package/core/.claude/skills/remotion-best-practices/rules/calculate-metadata.md +134 -0
- package/core/.claude/skills/remotion-best-practices/rules/can-decode.md +81 -0
- package/core/.claude/skills/remotion-best-practices/rules/charts.md +120 -0
- package/core/.claude/skills/remotion-best-practices/rules/compositions.md +154 -0
- package/core/.claude/skills/remotion-best-practices/rules/display-captions.md +184 -0
- package/core/.claude/skills/remotion-best-practices/rules/extract-frames.md +229 -0
- package/core/.claude/skills/remotion-best-practices/rules/ffmpeg.md +38 -0
- package/core/.claude/skills/remotion-best-practices/rules/fonts.md +152 -0
- package/core/.claude/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
- package/core/.claude/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
- package/core/.claude/skills/remotion-best-practices/rules/get-video-duration.md +60 -0
- package/core/.claude/skills/remotion-best-practices/rules/gifs.md +141 -0
- package/core/.claude/skills/remotion-best-practices/rules/images.md +134 -0
- package/core/.claude/skills/remotion-best-practices/rules/import-srt-captions.md +69 -0
- package/core/.claude/skills/remotion-best-practices/rules/light-leaks.md +73 -0
- package/core/.claude/skills/remotion-best-practices/rules/lottie.md +70 -0
- package/core/.claude/skills/remotion-best-practices/rules/maps.md +412 -0
- package/core/.claude/skills/remotion-best-practices/rules/measuring-dom-nodes.md +34 -0
- package/core/.claude/skills/remotion-best-practices/rules/measuring-text.md +140 -0
- package/core/.claude/skills/remotion-best-practices/rules/parameters.md +109 -0
- package/core/.claude/skills/remotion-best-practices/rules/sequencing.md +118 -0
- package/core/.claude/skills/remotion-best-practices/rules/sfx.md +30 -0
- package/core/.claude/skills/remotion-best-practices/rules/subtitles.md +36 -0
- package/core/.claude/skills/remotion-best-practices/rules/tailwind.md +11 -0
- package/core/.claude/skills/remotion-best-practices/rules/text-animations.md +20 -0
- package/core/.claude/skills/remotion-best-practices/rules/timing.md +179 -0
- package/core/.claude/skills/remotion-best-practices/rules/transcribe-captions.md +70 -0
- package/core/.claude/skills/remotion-best-practices/rules/transitions.md +197 -0
- package/core/.claude/skills/remotion-best-practices/rules/transparent-videos.md +106 -0
- package/core/.claude/skills/remotion-best-practices/rules/trimming.md +51 -0
- package/core/.claude/skills/remotion-best-practices/rules/videos.md +171 -0
- package/core/.claude/skills/remotion-best-practices/rules/voiceover.md +99 -0
- package/core/.claude/skills/security_agent/SKILL.md +312 -0
- package/core/.claude/skills/spec_optimizer/SKILL.md +299 -0
- package/core/.claude/skills/sre_agent/SKILL.md +1347 -0
- package/core/.claude/skills/sunny/SKILL.md +74 -0
- package/core/.claude/skills/supabase-postgres-best-practices/AGENTS.md +90 -0
- package/core/.claude/skills/supabase-postgres-best-practices/CLAUDE.md +1 -0
- package/core/.claude/skills/supabase-postgres-best-practices/SKILL.md +64 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/query-index-types.md +45 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
- package/core/.claude/skills/supabase-postgres-best-practices/references/security-rls-performance.md +57 -0
- package/core/.claude/skills/synapse_maintain/SKILL.md +84 -0
- package/core/.claude/skills/ui-ux-pro-max/SKILL.md +377 -0
- package/core/.claude/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/core/.claude/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/core/.claude/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/core/.claude/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/core/.claude/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/core/.claude/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/core/.claude/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/core/.claude/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/core/.claude/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/core/.claude/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/core/.claude/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/core/.claude/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/core/.claude/skills/ui-ux-pro-max/scripts/core.py +253 -0
- package/core/.claude/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/core/.claude/skills/ui-ux-pro-max/scripts/search.py +106 -0
- package/core/.claude/skills/vercel-react-best-practices/AGENTS.md +2934 -0
- package/core/.claude/skills/vercel-react-best-practices/SKILL.md +136 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/core/.claude/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/core/.collaboration/README.md +258 -0
- package/core/.collaboration/cli/commands/assign.js +39 -0
- package/core/.collaboration/cli/commands/claim.js +33 -0
- package/core/.collaboration/cli/commands/complete.js +44 -0
- package/core/.collaboration/cli/commands/create.js +110 -0
- package/core/.collaboration/cli/commands/get.js +83 -0
- package/core/.collaboration/cli/commands/index.js +52 -0
- package/core/.collaboration/cli/commands/list.js +51 -0
- package/core/.collaboration/cli/commands/lock.js +45 -0
- package/core/.collaboration/cli/commands/rebuild.js +39 -0
- package/core/.collaboration/cli/commands/search.js +61 -0
- package/core/.collaboration/cli/commands/stats.js +61 -0
- package/core/.collaboration/cli/commands/transfer.js +41 -0
- package/core/.collaboration/cli/commands/unlock.js +48 -0
- package/core/.collaboration/cli/formatters/help-formatter.js +70 -0
- package/core/.collaboration/cli/formatters/index.js +7 -0
- package/core/.collaboration/cli/task-cli.js +46 -0
- package/core/.collaboration/cli/utils/arg-parser.js +74 -0
- package/core/.collaboration/cli/utils/git-user.js +25 -0
- package/core/.collaboration/cli/utils/index.js +9 -0
- package/core/.collaboration/cli/utils/output.js +10 -0
- package/core/.collaboration/config/default.yaml +189 -0
- package/core/.collaboration/core/conflict-resolver.js +461 -0
- package/core/.collaboration/core/conflict-resolver.test.js +389 -0
- package/core/.collaboration/core/id-generator.js +303 -0
- package/core/.collaboration/core/migrate-legacy.js +260 -0
- package/core/.collaboration/core/package.json +1 -0
- package/core/.collaboration/core/task-2257-estimated-hours.test.js +72 -0
- package/core/.collaboration/core/task-2260-dir-layout-move.test.js +60 -0
- package/core/.collaboration/core/task-2264-single-after-capture.test.js +61 -0
- package/core/.collaboration/core/task-2288-followups.test.js +121 -0
- package/core/.collaboration/core/task-api-json.js +211 -0
- package/core/.collaboration/core/task-api.js +3729 -0
- package/core/.collaboration/core/task-api.test.js +1268 -0
- package/core/.collaboration/docs/API.md +787 -0
- package/core/.collaboration/docs/ARCHITECTURE.md +596 -0
- package/core/.collaboration/docs/CLI.md +821 -0
- package/core/.collaboration/docs/FAQ.md +695 -0
- package/core/.collaboration/docs/MIGRATION.md +804 -0
- package/core/.collaboration/docs/examples/README.md +320 -0
- package/core/.collaboration/docs/examples/advanced-queries.js +261 -0
- package/core/.collaboration/docs/examples/basic-usage.js +184 -0
- package/core/.collaboration/docs/examples/team-workflow.js +352 -0
- package/core/.collaboration/hooks/README.md +70 -0
- package/core/.collaboration/hooks/config.json +10 -0
- package/core/.collaboration/hooks/install.js +400 -0
- package/core/.collaboration/hooks/post-merge.js +163 -0
- package/core/.collaboration/hooks/pre-commit.js +264 -0
- package/core/.collaboration/hooks/synapse-hook.js +486 -0
- package/core/.collaboration/hooks/synapse-hook.test.js +69 -0
- package/core/.failure/INDEX.yaml +231 -0
- package/core/.failure/agent-execution/FAIL-001-agent-no-output.yaml +391 -0
- package/core/.failure/agent-execution/FAIL-004_agent_platform_specific_commands.md +194 -0
- package/core/.failure/agent-execution/FAIL-005_background_agent_permission_denied.md +204 -0
- package/core/.failure/agent-execution/FAIL-007-pm-lead-wrong-team-invocation.yaml +0 -0
- package/core/.failure/agent-execution/FAIL-008-bypass-api-direct-yaml-write.yaml +94 -0
- package/core/.failure/agent-execution/FAIL-010-phase0-poem-format-skipped.yaml +28 -0
- package/core/.failure/agent-execution/FAIL-010-skipping-cognitive-checkpoint-after-verification.yaml +59 -0
- package/core/.failure/agent-execution/FAIL-012-grep-shortcut-during-investigation.yaml +85 -0
- package/core/.failure/agent-execution/FAIL-013-search-cwd-drift-and-case-mismatch.yaml +103 -0
- package/core/.failure/agent-execution/FAIL-014-shared-worktree-premature-death-verdict.yaml +35 -0
- package/core/.failure/agent-execution/FAIL-AUTO-TASK_1413.yaml +31 -0
- package/core/.failure/agent-execution/FAIL-AUTO-TASK_1427.yaml +41 -0
- package/core/.failure/agent-execution/FAIL-AUTO-TASK_904.yaml +30 -0
- package/core/.failure/agent-execution/README.md +68 -0
- package/core/.failure/architecture/FAIL-004_session_based_skill_recognition.md +128 -0
- package/core/.failure/architecture/FAIL-006-python-version-compatibility.yaml +445 -0
- package/core/.failure/architecture/README.md +87 -0
- package/core/.failure/code-quality/README.md +89 -0
- package/core/.failure/data-integrity/FAIL-002-json-bom.yaml +220 -0
- package/core/.failure/data-integrity/README.md +141 -0
- package/core/.failure/pipeline/FAIL-003-queue-pollution.yaml +335 -0
- package/core/.failure/pipeline/README.md +95 -0
- package/core/.failure/retired/FAIL-009-skipping-synapse-pulse-before-code-change.yaml +49 -0
- package/core/.failure/tools/README.md +230 -0
- package/core/.failure/tools/USAGE_GUIDE.md +323 -0
- package/core/.failure/tools/check_bom.js +101 -0
- package/core/.failure/tools/check_failures.ps1 +387 -0
- package/core/.failure/tools/fix_json.js +58 -0
- package/core/.failure/tools/log_failure.ps1 +474 -0
- package/core/.failure/tools/remove_bom.js +46 -0
- package/core/.failure/tools/validate_json.js +50 -0
- package/core/.formation/.episode-input.json +10 -0
- package/core/.formation/README.md +188 -0
- package/core/.formation/bifrost/CGDD_hook_lifecycle.js +575 -0
- package/core/.formation/bifrost/HOOK_PARITY_VERIFICATION.md +241 -0
- package/core/.formation/bifrost/README.md +71 -0
- package/core/.formation/bifrost/codex-doctor.js +106 -0
- package/core/.formation/bifrost/codex-doctor.test.js +51 -0
- package/core/.formation/bifrost/launch.js +510 -0
- package/core/.formation/bifrost/launch.test.js +217 -0
- package/core/.formation/bifrost/openai/codex-hook-shim.js +171 -0
- package/core/.formation/bifrost/openai/codex-hook-shim.test.js +107 -0
- package/core/.formation/bifrost/openai/models.json +36 -0
- package/core/.formation/bifrost/openai/relay.js +781 -0
- package/core/.formation/bifrost/openai/relay.test.js +71 -0
- package/core/.formation/bifrost/session.js +382 -0
- package/core/.formation/bifrost/session.test.js +121 -0
- package/core/.formation/bifrost/setup-codex.js +685 -0
- package/core/.formation/bifrost/setup-codex.test.js +102 -0
- package/core/.formation/bifrost/shared/ansuz-boot-policy.js +31 -0
- package/core/.formation/bifrost/shared/ansuz-boot-policy.test.js +40 -0
- package/core/.formation/bifrost/shared/boot-context.js +68 -0
- package/core/.formation/bifrost/shared/boot-context.test.js +67 -0
- package/core/.formation/bifrost/shared/codex-appserver.js +191 -0
- package/core/.formation/bifrost/shared/codex-injection.js +126 -0
- package/core/.formation/bifrost/shared/codex-session-registry.js +105 -0
- package/core/.formation/bifrost/shared/codex-session-registry.test.js +126 -0
- package/core/.formation/bifrost/shared/consolidate.js +286 -0
- package/core/.formation/bifrost/shared/stream-json.js +103 -0
- package/core/.formation/bifrost/shared/tools.js +278 -0
- package/core/.formation/bifrost/sync.js +142 -0
- package/core/.formation/briefs/scheduler-evolution.md +209 -0
- package/core/.formation/lead.yaml +118 -0
- package/core/.formation/legacy.bak/designer.yaml +57 -0
- package/core/.formation/legacy.bak/pm.yaml +57 -0
- package/core/.formation/legacy.bak/qa.yaml +57 -0
- package/core/.formation/legacy.bak/review.yaml +62 -0
- package/core/.formation/legacy.bak/scheduler.yaml +129 -0
- package/core/.formation/legacy.bak/sre.yaml +57 -0
- package/core/.formation/legion/forge.yaml +299 -0
- package/core/.formation/legion/hive.yaml +238 -0
- package/core/.formation/native/claude/README.md +61 -0
- package/core/.formation/native/claude/models.json +42 -0
- package/core/.formation/role-map.yaml +274 -0
- package/core/.formation/roles/_shared/modules/code_review.yaml +98 -0
- package/core/.formation/roles/_shared/modules/security.yaml +103 -0
- package/core/.formation/roles/_shared/modules/testing.yaml +14 -0
- package/core/.formation/roles/backend/role.yaml +93 -0
- package/core/.formation/roles/code_reviewer/role.yaml +102 -0
- package/core/.formation/roles/database_optimizer/role.yaml +107 -0
- package/core/.formation/roles/designer/role.yaml +66 -0
- package/core/.formation/roles/developer/role.yaml +75 -0
- package/core/.formation/roles/frontend/role.yaml +134 -0
- package/core/.formation/roles/incident_response/role.yaml +89 -0
- package/core/.formation/roles/qa/role.yaml +89 -0
- package/core/.formation/roles/security/role.yaml +87 -0
- package/core/.formation/roles/sre/role.yaml +66 -0
- package/core/.formation/skills/coordinator.yaml +52 -0
- package/core/.formation/solo/diagnosis.yaml +78 -0
- package/core/.formation/solo/strategy.yaml +121 -0
- package/core/.formation/spec/task_operations.parity.test.js +426 -0
- package/core/.formation/spec/task_operations.yaml +291 -0
- package/core/.formation/squad/blitz.yaml +192 -0
- package/core/.formation/squad/strategy-tribunal.yaml +354 -0
- package/core/.formation/squad/strategy.yaml +349 -0
- package/core/.formation/squad/sweep.yaml +208 -0
- package/core/.formation/tests/hello.txt +2 -0
- package/core/.formation/tools/__tests__/m1-claim-gate.test.js +175 -0
- package/core/.formation/tools/__tests__/m1-hmap-convid.test.js +216 -0
- package/core/.formation/tools/__tests__/release-lock.test.js +176 -0
- package/core/.formation/tools/__tests__/subagent-bifrost-guard.test.js +234 -0
- package/core/.formation/tools/__tests__/subagent-codex-harness.test.js +96 -0
- package/core/.formation/tools/__tests__/task-1863-claim-late-release.test.js +160 -0
- package/core/.formation/tools/__tests__/task-2265-singleton-identity.test.js +134 -0
- package/core/.formation/tools/__tests__/task-2281-singleton-readers.test.js +64 -0
- package/core/.formation/tools/__tests__/task2030-worktree-node-modules.test.js +221 -0
- package/core/.formation/tools/__tests__/task2067-worktree-branch-reuse.test.js +148 -0
- package/core/.formation/tools/alaya-gate.js +198 -0
- package/core/.formation/tools/analytics.js +172 -0
- package/core/.formation/tools/broadcast.js +103 -0
- package/core/.formation/tools/commit-sync.js +154 -0
- package/core/.formation/tools/coordinator.js +350 -0
- package/core/.formation/tools/dashboard-models-chain.test.js +60 -0
- package/core/.formation/tools/dispatch-cortex-context.test.js +52 -0
- package/core/.formation/tools/dispatch-detail/cross-project-worktree.md +40 -0
- package/core/.formation/tools/dispatch-detail/testing-module.md +53 -0
- package/core/.formation/tools/dispatch-detail/worktree-subagent-mode.md +72 -0
- package/core/.formation/tools/dispatch-dryrun.test.js +54 -0
- package/core/.formation/tools/dispatch-model-policy.test.js +165 -0
- package/core/.formation/tools/dispatch-notifier.js +84 -0
- package/core/.formation/tools/dispatch-registry.js +346 -0
- package/core/.formation/tools/dispatch.js +1931 -0
- package/core/.formation/tools/formations.js +1203 -0
- package/core/.formation/tools/forseti-verify.js +1170 -0
- package/core/.formation/tools/git-salvage.js +269 -0
- package/core/.formation/tools/guard-attribution.js +224 -0
- package/core/.formation/tools/headless-branch-recovery.test.js +64 -0
- package/core/.formation/tools/headless-dryrun.test.js +79 -0
- package/core/.formation/tools/headless-v2.js +659 -0
- package/core/.formation/tools/headless.js +1071 -0
- package/core/.formation/tools/integration.js +528 -0
- package/core/.formation/tools/jev-correction.js +214 -0
- package/core/.formation/tools/jev-correction.test.js +178 -0
- package/core/.formation/tools/legacy-scheduler.js +1994 -0
- package/core/.formation/tools/lib/exec-tree.js +92 -0
- package/core/.formation/tools/lib/exec-tree.test.js +82 -0
- package/core/.formation/tools/loader.js +190 -0
- package/core/.formation/tools/log-reader.js +232 -0
- package/core/.formation/tools/logger.js +273 -0
- package/core/.formation/tools/mcp-allowlist.test.js +40 -0
- package/core/.formation/tools/memory-loader.js +422 -0
- package/core/.formation/tools/merge-lock-heartbeat.test.js +35 -0
- package/core/.formation/tools/no-hooks.settings.json +3 -0
- package/core/.formation/tools/pool-status-push.js +121 -0
- package/core/.formation/tools/pool-status-push.test.js +165 -0
- package/core/.formation/tools/post-complete/bounded-http.js +102 -0
- package/core/.formation/tools/post-complete/bounded-http.test.js +130 -0
- package/core/.formation/tools/post-complete/cognitive.js +270 -0
- package/core/.formation/tools/post-complete/git-merge.js +2845 -0
- package/core/.formation/tools/post-complete/health.js +464 -0
- package/core/.formation/tools/post-complete/integration-gaps.js +98 -0
- package/core/.formation/tools/post-complete/outcome.js +874 -0
- package/core/.formation/tools/post-complete/staging.js +390 -0
- package/core/.formation/tools/post-complete/subagent-transcript-stats.js +460 -0
- package/core/.formation/tools/post-complete/subagent-transcript-stats.test.js +680 -0
- package/core/.formation/tools/post-complete/task1536.test.js +627 -0
- package/core/.formation/tools/post-complete/task1543.test.js +261 -0
- package/core/.formation/tools/post-complete/task1876.test.js +287 -0
- package/core/.formation/tools/post-complete/task1957.test.js +293 -0
- package/core/.formation/tools/post-complete/task1997.test.js +401 -0
- package/core/.formation/tools/post-complete/task2028.test.js +232 -0
- package/core/.formation/tools/post-complete/task2029.test.js +275 -0
- package/core/.formation/tools/post-complete/task2036.test.js +330 -0
- package/core/.formation/tools/post-complete/task2038.test.js +246 -0
- package/core/.formation/tools/post-complete/task2071.test.js +231 -0
- package/core/.formation/tools/post-complete/task2233.test.js +100 -0
- package/core/.formation/tools/post-complete/task2240.test.js +134 -0
- package/core/.formation/tools/post-complete/task2244.test.js +199 -0
- package/core/.formation/tools/post-complete/task2255.test.js +28 -0
- package/core/.formation/tools/post-complete/task2268.test.js +106 -0
- package/core/.formation/tools/post-complete/task2341.test.js +74 -0
- package/core/.formation/tools/post-complete/task2345.test.js +38 -0
- package/core/.formation/tools/post-complete/testing.js +482 -0
- package/core/.formation/tools/post-complete/wish.js +177 -0
- package/core/.formation/tools/post-complete/worktree-rescue.test.js +283 -0
- package/core/.formation/tools/post-complete.js +3660 -0
- package/core/.formation/tools/post-complete.test.js +1002 -0
- package/core/.formation/tools/pre-dispatch-snapshot.test.js +328 -0
- package/core/.formation/tools/process-state.js +33 -0
- package/core/.formation/tools/prompt.js +2183 -0
- package/core/.formation/tools/prompt.test.js +875 -0
- package/core/.formation/tools/remote-conflict.js +98 -0
- package/core/.formation/tools/revert-daemon-state.js +162 -0
- package/core/.formation/tools/route-audit.test.js +55 -0
- package/core/.formation/tools/runner.js +1332 -0
- package/core/.formation/tools/supabase-client.js +104 -0
- package/core/.formation/tools/task-sync.js +236 -0
- package/core/.formation/tools/task-utils.js +344 -0
- package/core/.formation/tools/task2028-headless-worktree.test.js +112 -0
- package/core/.formation/tools/test-drift.js +148 -0
- package/core/.formation/tools/tests/headless-mcp-args-plumbing.test.js +123 -0
- package/core/.formation/tools/tests/relay-mcp-overrides.test.js +112 -0
- package/core/.formation/tools/transcript-recorder.js +574 -0
- package/core/.formation/tools/utils-claude-cmd.test.js +28 -0
- package/core/.formation/tools/utils-worktree-config.test.js +44 -0
- package/core/.formation/tools/utils.js +1020 -0
- package/core/.formation/tools/verify-acceptance.js +585 -0
- package/core/.formation/tools/worktree-leak.test.js +162 -0
- package/core/.formation/tools/worktree-reclaim.js +259 -0
- package/core/.formation/tools/worktree-reclaim.test.js +182 -0
- package/core/.formation/tools/yggdrasil-local.js +97 -0
- package/core/.formation/unit/do.yaml +78 -0
- package/core/.formation/unit/heimdall.yaml +96 -0
- package/core/.formation/unit/plan.yaml +67 -0
- package/core/.formation/unit/think.yaml +58 -0
- package/core/.kenaz/MUNINN_SNAPSHOT9_EPISODE.json +32 -0
- package/core/.kenaz/MUNINN_SNAPSHOT9_RUNE.json +23 -0
- package/core/.kenaz/MUNINN_SNAPSHOT9_SUMMARY.md +89 -0
- package/core/.kenaz/ash_TASK_1428-20260507.json +14 -0
- package/core/.kenaz/cache/native-models/claude.json +42 -0
- package/core/.kenaz/claude-hooks-manifest.json +119 -0
- package/core/.kenaz/cortex.yaml +100 -0
- package/core/.kenaz/curator_state.json +7 -0
- package/core/.kenaz/dashboard-quick-prompts.json +9 -0
- package/core/.kenaz/designs/METAPLASTICITY_CONFIDENCE_DESIGN.md +537 -0
- package/core/.kenaz/designs/REFLEX_INITIATOR_DESIGN.md +501 -0
- package/core/.kenaz/designs/TASK_1385_handoff_mcp_design.md +426 -0
- package/core/.kenaz/designs/TASK_932_hippocampus_consolidation.md +103 -0
- package/core/.kenaz/designs/TASK_934_efe_signal_engine.md +97 -0
- package/core/.kenaz/designs/TASK_935_self_evolution_framework.md +154 -0
- package/core/.kenaz/designs/VISION_cognitive_architecture_roadmap.md +159 -0
- package/core/.kenaz/designs/metaplasticity_simulation_results.json +696 -0
- package/core/.kenaz/docs/INDEX.md +214 -0
- package/core/.kenaz/docs/README.md +290 -0
- package/core/.kenaz/docs/registry.json +962 -0
- package/core/.kenaz/docs/schema.json +144 -0
- package/core/.kenaz/docs/tools/GIT_HOOK_GUIDE.md +203 -0
- package/core/.kenaz/docs/tools/RAG_INTEGRATION_GUIDE.md +306 -0
- package/core/.kenaz/docs/tools/README.md +99 -0
- package/core/.kenaz/docs/tools/TIME_ESTIMATION_GUIDE.md +299 -0
- package/core/.kenaz/docs/tools/package-lock.json +618 -0
- package/core/.kenaz/docs/tools/package.json +34 -0
- package/core/.kenaz/docs/tools/src/cli.ts +365 -0
- package/core/.kenaz/docs/tools/src/field-extractor.ts +152 -0
- package/core/.kenaz/docs/tools/src/index.ts +14 -0
- package/core/.kenaz/docs/tools/src/registry.ts +664 -0
- package/core/.kenaz/docs/tools/src/search.ts +195 -0
- package/core/.kenaz/docs/tools/src/types.ts +88 -0
- package/core/.kenaz/docs/tools/test-git-hook.sh +79 -0
- package/core/.kenaz/docs/tools/tsconfig.json +20 -0
- package/core/.kenaz/docs/tools/verify.sh +106 -0
- package/core/.kenaz/episodes/SESSION_ansuz-prompt-1785087304784.yaml +68 -0
- package/core/.kenaz/huginn-exploration.json +8 -0
- package/core/.kenaz/knowledge/ladybug_2c51da1e_shadow_file_frame_group.patch +163 -0
- package/core/.kenaz/knowledge/ladybug_30cf85690e_shadow_page_read_during_checkpoint.patch +393 -0
- package/core/.kenaz/knowledge/ladybug_7a17858d3a_node_group_delete_lock.patch +102 -0
- package/core/.kenaz/knowledge/ladybug_926a0ba1_column_checkpoint.patch +412 -0
- package/core/.kenaz/knowledge/ladybug_a346c4c4b6_pk_index_header_pages.patch +144 -0
- package/core/.kenaz/knowledge/ladybug_ba5f38815b_csr_node_group.patch +86 -0
- package/core/.kenaz/main-memory/README.md +230 -0
- package/core/.kenaz/main-memory/kenaz/cortex/001_cortex_overview.md +168 -0
- package/core/.kenaz/main-memory/kenaz/cortex/001_rag_engine_overview.md +30 -0
- package/core/.kenaz/main-memory/kenaz/memory-system/001_three_tier_architecture.md +361 -0
- package/core/.kenaz/main-memory/kenaz/pipeline/001_task_execution_flow.md +117 -0
- package/core/.kenaz/main-memory/kenaz/pipeline/001_task_granularity.md +154 -0
- package/core/.kenaz/main-memory/kenaz/pipeline/002_team_priority.md +51 -0
- package/core/.kenaz/main-memory/kenaz/pipeline/003_feature_id_system.md +46 -0
- package/core/.kenaz/main-memory/kenaz/rules/001_gen_007_self_containment.md +108 -0
- package/core/.kenaz/main-memory/kenaz/rules/001_rule_priority_system.md +121 -0
- package/core/.kenaz/main-memory/kenaz/rules/002_agt_006_pre_check.md +0 -0
- package/core/.kenaz/main-memory/kenaz/rules/003_ppl_002_task_archival.md +48 -0
- package/core/.kenaz/main-memory/kenaz/system/001_dual_track_task_system.md +197 -0
- package/core/.kenaz/main-memory/knowledge/patterns/001_json_bom_issue.md +78 -0
- package/core/.kenaz/main-memory/knowledge/patterns/001_leader_worker_pattern.md +0 -0
- package/core/.kenaz/main-memory/knowledge/patterns/002_scope_path_conflict.md +115 -0
- package/core/.kenaz/main-memory/knowledge/patterns/002_task_dependency_resolution.md +223 -0
- package/core/.kenaz/main-memory/knowledge/patterns/003_question_protocol.md +242 -0
- package/core/.kenaz/main-memory/knowledge/patterns/004_user_insight_value.md +111 -0
- package/core/.kenaz/main-memory/knowledge/patterns/005_file_lock_pattern.md +274 -0
- package/core/.kenaz/main-memory/knowledge/references/001_ppl_rules.md +28 -0
- package/core/.kenaz/main-memory/knowledge/solutions/001_json_bom_issue.md +137 -0
- package/core/.kenaz/main-memory/knowledge/solutions/001_team_invocation.md +0 -0
- package/core/.kenaz/main-memory/knowledge/solutions/002_passive_monitoring.md +0 -0
- package/core/.kenaz/main-memory/knowledge/solutions/003_windows_file_race_condition.md +239 -0
- package/core/.kenaz/main-memory/registry.json +326 -0
- package/core/.kenaz/main-memory/version.yaml +58 -0
- package/core/.kenaz/muninn_episode_write.ps1 +17 -0
- package/core/.kenaz/muninn_snapshot11_rune_candidates.md +63 -0
- package/core/.kenaz/muninn_snapshot1_rune_candidates.md +49 -0
- package/core/.kenaz/orphan_audit_2026-05.md +181 -0
- package/core/.kenaz/ownership.yaml +155 -0
- package/core/.kenaz/peer.yaml +72 -0
- package/core/.kenaz/project.yaml +62 -0
- package/core/.kenaz/rune_ansuz_literature_validation_strategy.md +40 -0
- package/core/.kenaz/rune_efe_active_inference_validation.md +36 -0
- package/core/.kenaz/rune_yggdrasil_filesystem_scoped_project.md +41 -0
- package/core/.kenaz/rune_yggdrasil_project_identity_folder_name.md +41 -0
- package/core/.kenaz/rune_yggdrasil_relay_protocol_project_mismatch.md +39 -0
- package/core/.kenaz/runes_TASK_1428.json +57 -0
- package/core/.kenaz/specialist/ansuz_motivational_state.schema.json +138 -0
- package/core/.kenaz/specialist/ansuz_rules.yaml +241 -0
- package/core/.kenaz/specialist/ansuz_session_handoff.schema.json +128 -0
- package/core/.kenaz/specialist/chart_TASK_1657.json +50 -0
- package/core/.kenaz/specialist/cognitive-hub-e2e.test.js +494 -0
- package/core/.kenaz/specialist/daemon-manifest.yaml +168 -0
- package/core/.kenaz/specialist/empty_ac_audit_report.md +63 -0
- package/core/.kenaz/specialist/episode_muninn_completion_1785056865691.json +91 -0
- package/core/.kenaz/specialist/field_report_watermark.json +1 -0
- package/core/.kenaz/specialist/gc1826_driver.js +118 -0
- package/core/.kenaz/specialist/heimdall_proposal_1017c07f.json +13 -0
- package/core/.kenaz/specialist/heimdall_proposal_3dfaa8b9.json +12 -0
- package/core/.kenaz/specialist/heimdall_proposal_57af18f9.json +15 -0
- package/core/.kenaz/specialist/heimdall_proposal_57b1aa1b.json +14 -0
- package/core/.kenaz/specialist/heimdall_proposal_5a3c9473.json +13 -0
- package/core/.kenaz/specialist/identity_verdicts/TASK_1073.json +75 -0
- package/core/.kenaz/specialist/identity_verdicts/TASK_TEST.json +77 -0
- package/core/.kenaz/specialist/memory_guard_fired.json +1 -0
- package/core/.kenaz/specialist/memory_guard_trigger_cache.json +1 -0
- package/core/.kenaz/specialist/memory_source_priority.yaml +260 -0
- package/core/.kenaz/specialist/motivational_state.schema.json +62 -0
- package/core/.kenaz/specialist/prompt_1775.txt +317 -0
- package/core/.kenaz/specialist/prompt_1776.txt +326 -0
- package/core/.kenaz/specialist/prompt_1791.txt +320 -0
- package/core/.kenaz/specialist/prompt_1792.txt +320 -0
- package/core/.kenaz/specialist/prompt_1795.txt +281 -0
- package/core/.kenaz/specialist/prompt_1813.txt +332 -0
- package/core/.kenaz/specialist/prompt_1814.txt +401 -0
- package/core/.kenaz/specialist/prompt_1815.txt +394 -0
- package/core/.kenaz/specialist/prompt_1816.txt +437 -0
- package/core/.kenaz/specialist/prompt_1818.txt +361 -0
- package/core/.kenaz/specialist/prompt_1819.txt +421 -0
- package/core/.kenaz/specialist/prompt_1821.txt +345 -0
- package/core/.kenaz/specialist/prompt_1822.txt +313 -0
- package/core/.kenaz/specialist/prompt_1824.txt +348 -0
- package/core/.kenaz/specialist/prompt_1826.txt +388 -0
- package/core/.kenaz/specialist/retired_organs/README.md +58 -0
- package/core/.kenaz/specialist/rune_calibration_poc.md +175 -0
- package/core/.kenaz/specialist/rune_efe_salience_gap.md +21 -0
- package/core/.kenaz/specialist/rune_ember_autonomous_dispatch_gate.md +24 -0
- package/core/.kenaz/specialist/rune_post_dispatch_verification_pattern.md +31 -0
- package/core/.kenaz/specialist/rune_surprise_proxy_improvement.md +28 -0
- package/core/.kenaz/specialist/rune_worktree_dispatch_pattern.md +31 -0
- package/core/.kenaz/specialist/rune_yaml_filter_desync_fix.md +26 -0
- package/core/.kenaz/specialist/rune_yggdrasil_project_identity_folder_name.md +24 -0
- package/core/.kenaz/specialist/sessions/chart_TASK_1599.json +41 -0
- package/core/.kenaz/specialist/sessions/hmap_028aa781-aad2-48c0-9a61-5540565d4a7f.json +5 -0
- package/core/.kenaz/specialist/sessions/hmap_20210387-0c64-400c-9d0a-53042a0cbd89.json +5 -0
- package/core/.kenaz/specialist/sessions/hmap_c1375c5d-fd9f-44bd-a83e-353ecbb0392f.json +5 -0
- package/core/.kenaz/specialist/sessions/scratch_028aa781-aad2-48c0-9a61-5540565d4a7f.json +6 -0
- package/core/.kenaz/specialist/sessions/scratch_0acc0fb3-24f9-453f-9e92-6ef1cdf03a7c.json +6 -0
- package/core/.kenaz/specialist/sessions/scratch_20210387-0c64-400c-9d0a-53042a0cbd89.json +6 -0
- package/core/.kenaz/specialist/sessions/scratch_2f10623e-b7a1-4647-905e-9dc7c4d99f9c.json +6 -0
- package/core/.kenaz/specialist/sessions/scratch_5a38b62d-608a-488c-82f0-7e47e95e0905.json +6 -0
- package/core/.kenaz/specialist/sessions/scratch_5d9758ef-d9b6-4ffe-a017-3ed26d0a313b.json +6 -0
- package/core/.kenaz/specialist/sessions/scratch_c1375c5d-fd9f-44bd-a83e-353ecbb0392f.json +6 -0
- package/core/.kenaz/specialist/sessions/scratch_c9f3c711-b73d-4fcd-ad2a-7b2bc024ee77.json +6 -0
- package/core/.kenaz/specialist/sessions/scratch_e72e5274-1c81-4655-a05a-f87d1ecb2917.json +6 -0
- package/core/.kenaz/specialist/sessions/scratch_f740cdbe-f756-41fc-98fb-2b1413d51901.json +6 -0
- package/core/.kenaz/specialist/t1777_probe.txt +1 -0
- package/core/.kenaz/specialist/task1825_update.json +43 -0
- package/core/.kenaz/specialist/task1827_update.json +43 -0
- package/core/.kenaz/specialist/task1828_update.json +43 -0
- package/core/.kenaz/specialist/taskgen/consolidation_i.json +38 -0
- package/core/.kenaz/specialist/taskgen/csharp_a.json +44 -0
- package/core/.kenaz/specialist/taskgen/csharp_b.json +40 -0
- package/core/.kenaz/specialist/taskgen/embedding_e.json +34 -0
- package/core/.kenaz/specialist/taskgen/hygiene_fg.json +39 -0
- package/core/.kenaz/specialist/taskgen/pathology_h.json +36 -0
- package/core/.kenaz/specialist/taskgen/unity_noise_d.json +38 -0
- package/core/.kenaz/specialist/taskgen/visibility_c.json +38 -0
- package/core/.kenaz/specialist/verify_1837.js +302 -0
- package/core/.kenaz/specialist/verify_1838.js +124 -0
- package/core/.kenaz/tmp/heimdall_proposal_fc7e0944.json +10 -0
- package/core/.kenaz/tmp_heimdall_proposal_8d3e392.json +13 -0
- package/core/.kenaz/tmp_props.json +1 -0
- package/core/.kenaz/tmp_sounddrop_t1_prompt.txt +371 -0
- package/core/.kenaz/user_model.schema.json +107 -0
- package/core/.matrix/README.md +257 -0
- package/core/.matrix/index.matrix +5 -0
- package/core/.mcp.json +8 -0
- package/core/.prefrontal/.gitkeep +0 -0
- package/core/.prefrontal/proposals/.gitkeep +0 -0
- package/core/.rule/INDEX.yaml +99 -0
- package/core/.rule/MECHANIZED.md +61 -0
- package/core/.rule/code/README.md +211 -0
- package/core/.rule/code/backend.yaml +294 -0
- package/core/.rule/code/checklist.yaml +258 -0
- package/core/.rule/code/maintainability.yaml +227 -0
- package/core/.rule/code/naming.yaml +106 -0
- package/core/.rule/code/principles.yaml +71 -0
- package/core/.rule/code/reusability.yaml +192 -0
- package/core/.rule/code/structure.yaml +218 -0
- package/core/.rule/code/style.yaml +197 -0
- package/core/.rule/design/ui.yaml +79 -0
- package/core/.rule/general/agent-workflow.yaml +572 -0
- package/core/.rule/general/cortex-memory-recall.yaml +446 -0
- package/core/.rule/general/cortex-tools.yaml +181 -0
- package/core/.rule/general/cross-platform.yaml +107 -0
- package/core/.rule/general/ddx-synapse-stack.yaml +162 -0
- package/core/.rule/general/file-size-threshold.yaml +45 -0
- package/core/.rule/general/identity-contract.schema.yaml +251 -0
- package/core/.rule/general/memory-language.yaml +67 -0
- package/core/.rule/general/memory-source-priority.yaml +207 -0
- package/core/.rule/general/pipeline.yaml +246 -0
- package/core/.rule/general/principles.yaml +77 -0
- package/core/.rule/general/project-self-containment.yaml +253 -0
- package/core/.rule/general/rust-verify-target.yaml +80 -0
- package/core/.rule/general/specialist-identity-contract.yaml +153 -0
- package/core/.rule/general/sunny-access-control.yaml +60 -0
- package/core/.rule/general/synapse-code-intelligence.yaml +375 -0
- package/core/.rule/general/synapse-cognitive-fusion.yaml +301 -0
- package/core/.rule/general/system-invariants.yaml +248 -0
- package/core/.rule/general/task-pool-routing.yaml +102 -0
- package/core/.rule/general/worktree-isolation.yaml +79 -0
- package/core/.rule/pipeline/PPL-002-completed-task-archival.yaml +528 -0
- package/core/.rule/pipeline/auto-update.yaml +282 -0
- package/core/.rule/pipeline/task-execution.yaml +368 -0
- package/core/.rule/tools/check-permissions.js +197 -0
- package/core/.specialist/Amelia/README.md +329 -0
- package/core/.specialist/Amelia/capability.yaml +386 -0
- package/core/.specialist/Amelia/knowledge.yaml +217 -0
- package/core/.specialist/Amelia/principles.yaml +10 -0
- package/core/.specialist/Amelia/rule.yaml +79 -0
- package/core/.specialist/Amelia/workflow.yaml +241 -0
- package/core/.specialist/Ansuz/HEURISTIC_BOOT_ROUTING.md +39 -0
- package/core/.specialist/Ansuz/ROUTING.md +35 -0
- package/core/.specialist/Ansuz/RULES.md +79 -0
- package/core/.specialist/Ansuz/SYSTEM_DOC.md +611 -0
- package/core/.specialist/Ansuz/VERIFY.md +38 -0
- package/core/.specialist/Ansuz/capability.yaml +338 -0
- package/core/.specialist/Ansuz/cognitive_principles.yaml +62 -0
- package/core/.specialist/Ansuz/concepts/agent_types.yaml +22 -0
- package/core/.specialist/Ansuz/concepts/autonomous_agenda.yaml +170 -0
- package/core/.specialist/Ansuz/concepts/autonomy_contract.yaml +126 -0
- package/core/.specialist/Ansuz/concepts/boot_ritual.yaml +107 -0
- package/core/.specialist/Ansuz/concepts/boot_rules_summary.yaml +16 -0
- package/core/.specialist/Ansuz/concepts/capability_pointers.yaml +21 -0
- package/core/.specialist/Ansuz/concepts/cognitive_fluency_contract.yaml +264 -0
- package/core/.specialist/Ansuz/concepts/cognitive_systems_competence_map.yaml +14 -0
- package/core/.specialist/Ansuz/concepts/cognitive_systems_hippocampus.yaml +14 -0
- package/core/.specialist/Ansuz/concepts/cognitive_systems_overview.yaml +27 -0
- package/core/.specialist/Ansuz/concepts/cognitive_systems_serendipity.yaml +14 -0
- package/core/.specialist/Ansuz/concepts/cognitive_systems_turn_context.yaml +13 -0
- package/core/.specialist/Ansuz/concepts/commitment_layer.yaml +150 -0
- package/core/.specialist/Ansuz/concepts/completion_tracking.yaml +29 -0
- package/core/.specialist/Ansuz/concepts/deep_knowledge_pointers.yaml +28 -0
- package/core/.specialist/Ansuz/concepts/evolvable_guardrails.yaml +20 -0
- package/core/.specialist/Ansuz/concepts/fatigue_handoff.yaml +84 -0
- package/core/.specialist/Ansuz/concepts/formation_quick_ref.yaml +28 -0
- package/core/.specialist/Ansuz/concepts/guardrails_immutable.yaml +31 -0
- package/core/.specialist/Ansuz/concepts/identity.yaml +48 -0
- package/core/.specialist/Ansuz/concepts/interaction_protocol.yaml +42 -0
- package/core/.specialist/Ansuz/concepts/meta_evolvable_tier.yaml +28 -0
- package/core/.specialist/Ansuz/concepts/mindset.yaml +18 -0
- package/core/.specialist/Ansuz/concepts/phase9_verification.yaml +21 -0
- package/core/.specialist/Ansuz/concepts/phase_protocol.yaml +66 -0
- package/core/.specialist/Ansuz/concepts/principles.yaml +65 -0
- package/core/.specialist/Ansuz/concepts/self_evolution_overview.yaml +53 -0
- package/core/.specialist/Ansuz/concepts/task_first_protocol.yaml +7 -0
- package/core/.specialist/Ansuz/concepts/task_pool.yaml +119 -0
- package/core/.specialist/Ansuz/concepts/task_system.yaml +22 -0
- package/core/.specialist/Ansuz/concepts/write_verification.yaml +26 -0
- package/core/.specialist/Ansuz/core.yaml +224 -0
- package/core/.specialist/Ansuz/decisions/ADR-requirement-graph-layer.md +390 -0
- package/core/.specialist/Ansuz/elixir.yaml +70 -0
- package/core/.specialist/Ansuz/exo_cortex_tools.yaml +13 -0
- package/core/.specialist/Ansuz/experiments/boot_ablation_replay.js +197 -0
- package/core/.specialist/Ansuz/guards/blind_spot_guards.yaml +28 -0
- package/core/.specialist/Ansuz/guards/lesson_guards.yaml +203 -0
- package/core/.specialist/Ansuz/identity_contract.yaml +375 -0
- package/core/.specialist/Ansuz/knowledge.yaml +284 -0
- package/core/.specialist/Ansuz/modules/amelia_review.yaml +112 -0
- package/core/.specialist/Ansuz/modules/ddx.yaml +47 -0
- package/core/.specialist/Ansuz/modules/design_checks.yaml +47 -0
- package/core/.specialist/Ansuz/modules/identity_verification.yaml +119 -0
- package/core/.specialist/Ansuz/modules/loop_guard.yaml +36 -0
- package/core/.specialist/Ansuz/modules/prevention.yaml +84 -0
- package/core/.specialist/Ansuz/modules/prophecy.yaml +95 -0
- package/core/.specialist/Ansuz/modules/pulse_empty.yaml +36 -0
- package/core/.specialist/Ansuz/modules/qa_intake.yaml +29 -0
- package/core/.specialist/Ansuz/modules/recall.yaml +45 -0
- package/core/.specialist/Ansuz/principles.yaml +31 -0
- package/core/.specialist/Ansuz/research/EMBER_architecture_comparison.md +142 -0
- package/core/.specialist/Ansuz/rule.yaml +97 -0
- package/core/.specialist/Ansuz/self_model_seed.backup.json +100 -0
- package/core/.specialist/Ansuz/self_model_seed.json +100 -0
- package/core/.specialist/Ansuz/self_model_seed.sha256 +1 -0
- package/core/.specialist/Ansuz/tools/ansuz-handoff-snapshot.js +626 -0
- package/core/.specialist/Ansuz/tools/ansuz-handoff.js +437 -0
- package/core/.specialist/Ansuz/tools/ansuz-sdk-runner.js +1254 -0
- package/core/.specialist/Ansuz/tools/ansuz-sdk-runner.test.js +137 -0
- package/core/.specialist/Ansuz/tools/ansuz-state.js +288 -0
- package/core/.specialist/Ansuz/tools/bootstrap-anchors.js +289 -0
- package/core/.specialist/Ansuz/tools/handoff-freshness-milestone.test.js +73 -0
- package/core/.specialist/Ansuz/tools/handoff-resolver.js +207 -0
- package/core/.specialist/Ansuz/tools/handoff-session-identity.test.js +333 -0
- package/core/.specialist/Ansuz/tools/handoff-snapshot-args.test.js +25 -0
- package/core/.specialist/Ansuz/tools/install-claude-hooks.js +354 -0
- package/core/.specialist/Ansuz/tools/install-claude-hooks.test.js +110 -0
- package/core/.specialist/Ansuz/tools/package.json +16 -0
- package/core/.specialist/Ansuz/tools/preservation-coordinator.js +504 -0
- package/core/.specialist/Ansuz/tools/verify-and-land.js +1012 -0
- package/core/.specialist/Ansuz/tools/verify-and-land.test.js +1099 -0
- package/core/.specialist/Ansuz/workflow.yaml +1273 -0
- package/core/.specialist/Forseti/capability.yaml +210 -0
- package/core/.specialist/Forseti/core.yaml +176 -0
- package/core/.specialist/Forseti/principles.yaml +88 -0
- package/core/.specialist/Forseti/rule.yaml +86 -0
- package/core/.specialist/Heimdall/SKILL.md +65 -0
- package/core/.specialist/Heimdall/capability.yaml +134 -0
- package/core/.specialist/Heimdall/core.yaml +275 -0
- package/core/.specialist/Heimdall/principles.yaml +66 -0
- package/core/.specialist/Heimdall/rule.yaml +68 -0
- package/core/.specialist/Huginn/capability.yaml +234 -0
- package/core/.specialist/Huginn/core.yaml +482 -0
- package/core/.specialist/Huginn/principles.yaml +57 -0
- package/core/.specialist/Huginn/rule.yaml +121 -0
- package/core/.specialist/REFLECTION_TO_CONTROL.md +347 -0
- package/core/.specialist/ansuz_session_handoff.json +96 -0
- package/core/.specialist/experiments/rg_benchmark.js +523 -0
- package/core/.specialist/experiments/rg_benchmark_results.json +27 -0
- package/core/.specialist/shared/cognitive-primer.md +15 -0
- package/core/.specialist/shared/guard_schema.json +290 -0
- package/core/.specialist/shared/principles.yaml +213 -0
- package/core/.specialist/tests/runtime-discovery/README.md +224 -0
- package/core/.specialist/tests/runtime-discovery/active-project-polling.test.js +495 -0
- package/core/.specialist/tests/runtime-discovery/port-binding.test.js +418 -0
- package/core/.specialist/tests/runtime-discovery/resolver-priority.test.js +693 -0
- package/core/.specialist/tests/runtime-discovery/resolver-skip-on-invalid.test.js +467 -0
- package/core/.specialist/tests/runtime-discovery/resolver-symmetry.test.js +679 -0
- package/core/.specialist/tests/runtime-discovery/tail-cli-project-path.test.js +231 -0
- package/core/.specialist/tools/MEMORY_RECALL_TRIGGERS.md +156 -0
- package/core/.specialist/tools/README.md +129 -0
- package/core/.specialist/tools/__tests__/freya-cli-contract.test.js +156 -0
- package/core/.specialist/tools/__tests__/task-1863-boot-lease-reuse.test.js +99 -0
- package/core/.specialist/tools/__tests__/task-1917-orphan-detection.test.js +175 -0
- package/core/.specialist/tools/__tests__/task-1977-banner-cap.test.js +129 -0
- package/core/.specialist/tools/__tests__/task-1983-lease-project-path.test.js +96 -0
- package/core/.specialist/tools/__tests__/task-2218-boot-session-id.test.js +118 -0
- package/core/.specialist/tools/__tests__/task-2222-session-identity-interleave.test.js +203 -0
- package/core/.specialist/tools/__tests__/task-2246-reap-honesty.test.js +96 -0
- package/core/.specialist/tools/__tests__/task-2254-handoff-archive-contract.test.js +60 -0
- package/core/.specialist/tools/__tests__/task-2272-open-card-status-quote.test.js +26 -0
- package/core/.specialist/tools/__tests__/task-2374-usage-counter.test.js +34 -0
- package/core/.specialist/tools/ansuz-boot-fast.js +1120 -0
- package/core/.specialist/tools/ansuz-boot-fast.test.js +705 -0
- package/core/.specialist/tools/canary.js +501 -0
- package/core/.specialist/tools/context-injection.js +395 -0
- package/core/.specialist/tools/design-reasoning.js +493 -0
- package/core/.specialist/tools/discovery-fixtures.js +308 -0
- package/core/.specialist/tools/discovery-runner.js +460 -0
- package/core/.specialist/tools/failure-detector.js +1132 -0
- package/core/.specialist/tools/identity-scorer.js +714 -0
- package/core/.specialist/tools/jev-optional-context.js +107 -0
- package/core/.specialist/tools/jev-optional-context.test.js +152 -0
- package/core/.specialist/tools/lesson-guard.js +1084 -0
- package/core/.specialist/tools/lib/chart-path.js +159 -0
- package/core/.specialist/tools/lib/chart-path.test.js +171 -0
- package/core/.specialist/tools/lib/project-resolver.js +200 -0
- package/core/.specialist/tools/lib/project-resolver.test.js +241 -0
- package/core/.specialist/tools/memory-action-log.js +839 -0
- package/core/.specialist/tools/phase-gate.js +3754 -0
- package/core/.specialist/tools/phase-gate.test.js +85 -0
- package/core/.specialist/tools/phase9-policy.test.js +109 -0
- package/core/.specialist/tools/precompute-runner.js +444 -0
- package/core/.specialist/tools/prompt-files.test.js +169 -0
- package/core/.specialist/tools/replay-detectors.js +290 -0
- package/core/.specialist/tools/rule-engine.js +621 -0
- package/core/.specialist/tools/session-boot-ownership.test.js +117 -0
- package/core/.specialist/tools/session-project-state.test.js +65 -0
- package/core/.specialist/tools/session.js +1866 -0
- package/core/.specialist/tools/stream-lease.js +263 -0
- package/core/.specialist/tools/task-bridge-jev.test.js +170 -0
- package/core/.specialist/tools/task-bridge.js +765 -0
- package/core/.specialist/tools/verify-identity.js +453 -0
- package/core/.specialist/tools/wish-mandate-delivery.test.js +76 -0
- package/core/.system/README.md +555 -0
- package/core/.system/agent-skills/README.md +724 -0
- package/core/.system/archive/README.md +499 -0
- package/core/.system/assessment/README.md +645 -0
- package/core/.system/cli-tools/README.md +724 -0
- package/core/.system/collaboration/KNOWLEDGE.md +65 -0
- package/core/.system/collaboration/README.md +570 -0
- package/core/.system/cortex/MODULES.md +1046 -0
- package/core/.system/dashboard/FRONTEND.md +812 -0
- package/core/.system/dashboard/README.md +737 -0
- package/core/.system/external-skills/README.md +522 -0
- package/core/.system/failure/README.md +723 -0
- package/core/.system/formation/LEGACY_SKILLS.md +972 -0
- package/core/.system/formation/POST_COMPLETE.md +600 -0
- package/core/.system/formation/README.md +1092 -0
- package/core/.system/formation/TOOLS_REFERENCE.md +1145 -0
- package/core/.system/githooks/README.md +846 -0
- package/core/.system/kenaz/README.md +787 -0
- package/core/.system/memory/README.md +716 -0
- package/core/.system/pipeline/README.md +712 -0
- package/core/.system/rule/README.md +794 -0
- package/core/.system/specialist/README.md +669 -0
- package/core/.system/specialist/STRUCTURE.md +262 -0
- package/core/.system/sunny/README.md +476 -0
- package/core/.system/sunny/RULES.json +89 -0
- package/core/.system/sunny/knowledge/INDEX.md +37 -0
- package/core/.system/sunny/knowledge/agent-teams-api.md +0 -0
- package/core/.system/sunny/knowledge/ansuz-specialist.md +500 -0
- package/core/.system/sunny/knowledge/claude-cli-spawn.md +177 -0
- package/core/.system/sunny/knowledge/collaboration-api.md +925 -0
- package/core/.system/sunny/teammates/README.md +107 -0
- package/core/.system/sunny/teammates/how_to_use.yaml +101 -0
- package/core/.system/sunny/teammates/tools/headless/launcher.js +318 -0
- package/core/.system/sunny/teammates/tools/powershell/launcher.js +241 -0
- package/core/.system/sunny/teammates/tools/powershell/start.bat +50 -0
- package/core/.system/sunny/teammates/tools/utils/env.js +96 -0
- package/core/.system/sunny/teammates/tools/utils/format-output.js +329 -0
- package/core/.system/sunny/tools.json +101 -0
- package/core/.vendor/js-yaml.cjs +2795 -0
- package/core/.vendor/require-yaml.cjs +8 -0
- package/core/CLAUDE.md +172 -0
- package/core/KENAZ_CORE_VERSION +1 -0
- package/core/dev/ALAYA_FIELD_FEEDBACK_DESIGN.md +126 -0
- package/core/dev/ANSUZ_SCAFFOLD_DIET_2026-09-20.md +231 -0
- package/core/dev/ANSUZ_STARTUP_INJECTION_REVIEW.md +355 -0
- package/core/dev/ANSUZ_WORKFLOW_MODERNIZATION.md +143 -0
- package/core/dev/CORTEX_META_GRAPH_ASSESSMENT.md +99 -0
- package/core/dev/FREYA_DOWNSTREAM_BUGS_2026-09-19.md +44 -0
- package/core/dev/GLOBAL_MEMORY_IDENTITY_CONSOLIDATION.md +263 -0
- package/core/dev/GUARD_EFFECTIVENESS_DESIGN.md +180 -0
- package/core/dev/HEALTH_GATE_VARIANCE_ASSESSMENT.md +271 -0
- package/core/dev/HOOK_DIET_2026-09-21.md +126 -0
- package/core/dev/JEV_INTEGRATION_PLAN.md +189 -0
- package/core/dev/KENAZ_AGENT_CONNECT_v1_SPEC.md +139 -0
- package/core/dev/MOBILE_DESIGN_SPEC.md +569 -0
- package/core/dev/MULTI_ANSUZ_SPEC.md +136 -0
- package/core/dev/MUNINN_RETIREMENT.md +115 -0
- package/core/dev/PHASE3_ATTRIBUTION_POPULATION_DIAGNOSIS.md +211 -0
- package/core/dev/PHASE3_P3-2B_TASKLEVEL_PROBE.md +83 -0
- package/core/dev/PHASE3_P3-2_POPULATION_DISJOINTNESS.md +83 -0
- package/core/dev/PHASE3_P3-2_REMEASURE_REPORT.md +231 -0
- package/core/dev/PREDICTION_GROUNDING_DESIGN.md +376 -0
- package/core/dev/PRODUCT_SPEC.md +317 -0
- package/core/dev/PRODUCT_SPEC_FOR_AI_tepmlate.md +716 -0
- package/core/dev/PROJECT_REGISTRY_DUPLICATE_ASSESSMENT.md +86 -0
- package/core/dev/STARTUP_TIMELINE_TASK_1995.md +181 -0
- package/core/dev/SYNAPSE_WORKER_PER_PROJECT.md +881 -0
- package/core/dev/TASK_1680_P3-3_DISPATCH_SPEC.md +96 -0
- package/core/dev/TASK_1684_CALIBRATION_IMPACT_ANALYSIS.md +170 -0
- package/core/dev/TASK_1684_FORK_A_GOODHART_DESIGN.md +171 -0
- package/core/dev/TASK_1684_P3_2_REMEASURE_VALIDATION.md +262 -0
- package/core/dev/TASK_1903_SIGNAL_AUC_MEASUREMENT.md +207 -0
- package/core/dev/TASK_1904_BRANCH_INTEGRITY_AUDIT.md +146 -0
- package/core/dev/ansuz-eval/README.md +38 -0
- package/core/dev/ansuz-eval/build-fixtures.js +87 -0
- package/core/dev/ansuz-eval/grade.js +96 -0
- package/core/dev/ansuz-eval/grader.test.js +117 -0
- package/core/dev/ansuz-eval/tasks.md +32 -0
- package/core/dev/archive/ansuz/BOOT_FULL.md +141 -0
- package/core/dev/archive/ansuz/agents/ansuz-boot.md +176 -0
- package/core/dev/archive/ansuz/designs/alaya-passive-surfacing.md +84 -0
- package/core/dev/archive/ansuz/designs/cc_memory_indexing.md +307 -0
- package/core/dev/archive/ansuz/designs/check_guard.md +322 -0
- package/core/dev/archive/ansuz/designs/consequence_loop.md +227 -0
- package/core/dev/archive/ansuz/designs/mcp_kuzudb_lock_architecture.md +312 -0
- package/core/dev/archive/ansuz/designs/phase0_git_enrichment.md +278 -0
- package/core/dev/archive/ansuz/designs/refactor_mcp_tools_synapse.md +490 -0
- package/core/dev/archive/ansuz/designs/semantic_markdown_extraction.md +167 -0
- package/core/dev/archive/ansuz/designs/task_1372_prompt_injects_into.md +193 -0
- package/core/dev/archive/ansuz/designs/thought_stack.md +286 -0
- package/core/dev/archive/ansuz/investigations/reachability_unified_api_2026-04-11.md +330 -0
- package/core/dev/archive/ansuz/investigations/synapse_orphans_indexing_bug_2026-04-11.md +352 -0
- package/core/dev/archive/ansuz/investigations/synapse_orphans_reindex_verification_2026-04-11.md +48 -0
- package/core/dev/archive/ansuz/investigations/synapse_orphans_verification_2026-04-11.md +170 -0
- package/core/dev/archive/ansuz/legacy/kernel.yaml +399 -0
- package/core/dev/archive/ansuz/legacy/phases/phase_0.yaml +418 -0
- package/core/dev/archive/ansuz/legacy/phases/phase_1.yaml +376 -0
- package/core/dev/archive/ansuz/legacy/phases/phase_10.yaml +35 -0
- package/core/dev/archive/ansuz/legacy/phases/phase_11.yaml +582 -0
- package/core/dev/archive/ansuz/legacy/phases/phase_2.yaml +94 -0
- package/core/dev/archive/ansuz/legacy/phases/phase_3.yaml +274 -0
- package/core/dev/archive/ansuz/legacy/phases/phase_4.yaml +67 -0
- package/core/dev/archive/ansuz/legacy/phases/phase_5.yaml +32 -0
- package/core/dev/archive/ansuz/legacy/phases/phase_6.yaml +91 -0
- package/core/dev/archive/ansuz/legacy/phases/phase_7.yaml +58 -0
- package/core/dev/archive/ansuz/legacy/phases/phase_8.yaml +146 -0
- package/core/dev/archive/ansuz/legacy/phases/phase_9.yaml +424 -0
- package/core/dev/archive/ansuz/specs/INDEX_bifrost_hook_parity.yaml +92 -0
- package/core/dev/archive/ansuz/specs/active-inference-formation.yaml +453 -0
- package/core/dev/archive/ansuz/specs/brief_TASK_1228_userpromptsubmit.yaml +191 -0
- package/core/dev/archive/ansuz/specs/brief_TASK_1229_pretooluse_posttooluse.yaml +250 -0
- package/core/dev/archive/ansuz/specs/brief_TASK_1230_sessionstart_stop.yaml +301 -0
- package/core/dev/archive/ansuz/specs/brief_TASK_1231_verification.yaml +272 -0
- package/core/dev/design/PHASE4_DESIGN.md +559 -0
- package/core/dev/design/dashboard_docs_integration_PLAN.md +388 -0
- package/core/dev/design/matrix_format_ABBREVIATIONS.md +655 -0
- package/core/dev/design/matrix_format_DESIGN_SPEC.md +601 -0
- package/core/dev/design/matrix_format_DISCUSSION_SUMMARY.md +484 -0
- package/core/dev/design/matrix_format_EXAMPLE_memory.matrix +13 -0
- package/core/dev/design/matrix_format_EXAMPLE_project_status.matrix +9 -0
- package/core/dev/design/matrix_format_EXAMPLE_tasks.matrix +14 -0
- package/core/dev/design/matrix_format_SYNTAX_BNF.md +754 -0
- package/core/dev/design/matrix_format_TOKEN_COMPARISON.md +484 -0
- package/core/dev/design/matrix_v2_COGNITIVE_DESIGN.md +503 -0
- package/core/dev/design/matrix_v2_DISCUSSION_SUMMARY.md +414 -0
- package/core/dev/design/matrix_v2_EXAMPLE.matrix +67 -0
- package/core/dev/designs/EXPANDABLE_CARD_DESIGN_SPEC.md +509 -0
- package/core/dev/jev-eval/ACTIVE_CORRECTION.md +52 -0
- package/core/dev/jev-eval/ANNOTATION_GUIDE.md +68 -0
- package/core/dev/jev-eval/BASELINE_COMPARISON.md +45 -0
- package/core/dev/jev-eval/CONTEXT_REVIEW.md +31 -0
- package/core/dev/jev-eval/EVALUATION_STATUS.md +39 -0
- package/core/dev/jev-eval/HISTORICAL_CORPUS.md +33 -0
- package/core/dev/jev-eval/PACKAGING_VERIFICATION.md +42 -0
- package/core/dev/jev-eval/README.md +101 -0
- package/core/dev/jev-eval/THALAMUS_RANKING.md +58 -0
- package/core/dev/jev-eval/VALIDATION_PROGRESS.md +54 -0
- package/core/dev/jev-eval/cli.mjs +50 -0
- package/core/dev/jev-eval/context.mjs +183 -0
- package/core/dev/jev-eval/corpus.mjs +186 -0
- package/core/dev/jev-eval/fixtures/conversation-review.seed.jsonl +6 -0
- package/core/dev/jev-eval/fixtures/synthetic.jsonl +11 -0
- package/core/dev/jev-eval/metrics.mjs +67 -0
- package/core/dev/jev-eval/muninn-baseline.mjs +119 -0
- package/core/dev/jev-eval/providers.mjs +95 -0
- package/core/dev/jev-eval/reports/annotation-pilot-2026-09-20.json +32 -0
- package/core/dev/jev-eval/reports/context-review-2026-09-20.json +48 -0
- package/core/dev/jev-eval/reports/conversation-review.pending.json +151 -0
- package/core/dev/jev-eval/reports/history-corpus-2026-09-20.json +52 -0
- package/core/dev/jev-eval/reports/length-probe-2026-09-20.json +133 -0
- package/core/dev/jev-eval/reports/live-smoke-2026-09-20.json +616 -0
- package/core/dev/jev-eval/reports/muninn-baseline-2026-09-20.json +52 -0
- package/core/dev/jev-eval/reports/resilience-2026-09-20.json +520 -0
- package/core/dev/jev-eval/reports/rules-baseline.json +197 -0
- package/core/dev/jev-eval/reports/synthetic-review.pending.json +357 -0
- package/core/dev/jev-eval/resilience.mjs +71 -0
- package/core/dev/jev-eval/review.mjs +78 -0
- package/core/dev/jev-eval/schema.mjs +87 -0
- package/core/dev/jev-eval/test/context.test.mjs +95 -0
- package/core/dev/jev-eval/test/corpus.test.mjs +102 -0
- package/core/dev/jev-eval/test/eval.test.mjs +146 -0
- package/core/dev/jev-eval/test/muninn-baseline.test.mjs +71 -0
- package/core/dev/jev-eval/test/resilience.test.mjs +72 -0
- package/core/dev/jev-eval/test/review.test.mjs +61 -0
- package/core/dev/pipeline/LOCK_STATE.json +4 -0
- package/core/dev/pipeline/OPTIMIZATION_PROPOSALS.json +32 -0
- package/core/dev/pipeline/PHASE3_PLANNING_SUMMARY.md +338 -0
- package/core/dev/pipeline/PIPELINE_CONFIG.json +46 -0
- package/core/dev/pipeline/PROGRESS.md +113 -0
- package/core/dev/pipeline/PROGRESS_template.md +860 -0
- package/core/dev/pipeline/QA_REPORT_F008.md +431 -0
- package/core/dev/pipeline/QA_REPORT_LOCAL_CLAUDE_DIAGNOSIS.md +583 -0
- package/core/dev/pipeline/README.md +210 -0
- package/core/dev/pipeline/SELF_ENHANCEMENT_STATUS.json.bak +47 -0
- package/core/dev/pipeline/TASK_QUEUE.json +192 -0
- package/core/dev/pipeline/WORKFLOW_GUIDE.md +824 -0
- package/core/dev/pipeline/archived/TASK_015_tauri_init.yaml +53 -0
- package/core/dev/pipeline/archived/TASK_016_tauri_commands.yaml +54 -0
- package/core/dev/pipeline/archived/TASK_017_rust_pty.yaml +54 -0
- package/core/dev/pipeline/archived/TASK_018_tauri_bundle.yaml +53 -0
- package/core/dev/pipeline/archived/TASK_019_release_workflow.yaml +56 -0
- package/core/dev/pipeline/archived/TASK_020_update_ui.yaml +54 -0
- package/core/dev/pipeline/archived/TASK_021_update_notification_ui.yaml +55 -0
- package/core/dev/pipeline/archived/TASK_022_remove_node_pty.yaml +65 -0
- package/core/dev/pipeline/archived/TASK_023_api_routes_migration.yaml +86 -0
- package/core/dev/pipeline/archived/TASK_024_feature_id_system.yaml +51 -0
- package/core/dev/pipeline/archived/TASK_025_executable_acceptance.yaml +66 -0
- package/core/dev/pipeline/archived/TASK_026_spec_versioning.yaml +56 -0
- package/core/dev/pipeline/archived/TASK_027_drift_detection.yaml +60 -0
- package/core/dev/pipeline/archived/TASK_028_tauri_pty_manager.yaml +60 -0
- package/core/dev/pipeline/archived/TASK_029_tauri_pty_commands.yaml +62 -0
- package/core/dev/pipeline/archived/TASK_030_frontend_session_adapter.yaml +54 -0
- package/core/dev/pipeline/archived/TASK_031_terminal_tauri_events.yaml +56 -0
- package/core/dev/pipeline/archived/TASK_041_scheduler_data_models.yaml +54 -0
- package/core/dev/pipeline/archived/TASK_042_path_lock_manager.yaml +53 -0
- package/core/dev/pipeline/archived/TASK_043_process_manager.yaml +57 -0
- package/core/dev/pipeline/archived/TASK_044_git_integration.yaml +85 -0
- package/core/dev/pipeline/archived/TASK_045_task_queue_manager.yaml +54 -0
- package/core/dev/pipeline/archived/TASK_046_scheduler_dispatcher.yaml +60 -0
- package/core/dev/pipeline/archived/TASK_047_tauri_scheduler_commands.yaml +55 -0
- package/core/dev/pipeline/archived/TASK_048_realtime_status_push.yaml +92 -0
- package/core/dev/pipeline/archived/TASK_049_frontend_scheduler_integration.yaml +58 -0
- package/core/dev/pipeline/archived/TASK_050_error_recovery.yaml +56 -0
- package/core/dev/pipeline/archived/TASK_051_optimization_proposals_backend.yaml +53 -0
- package/core/dev/pipeline/archived/TASK_052_optimization_proposals_ui.yaml +58 -0
- package/core/dev/pipeline/archived/TASK_053_optimization_proposals_diff_view.yaml +54 -0
- package/core/dev/pipeline/archived/TASK_054_multi_project_scheduler_state.yaml +76 -0
- package/core/dev/pipeline/archived/TASK_055_scheduler_api_project_scope.yaml +64 -0
- package/core/dev/pipeline/archived/TASK_056_frontend_scheduler_project_scope.yaml +62 -0
- package/core/dev/pipeline/archived/TASK_057_scheduler_module_structure.yaml +54 -0
- package/core/dev/pipeline/archived/TASK_058_scheduler_models_extract.yaml +51 -0
- package/core/dev/pipeline/archived/TASK_059_scheduler_core_extract.yaml +51 -0
- package/core/dev/pipeline/archived/TASK_060_scheduler_commands_extract.yaml +51 -0
- package/core/dev/pipeline/archived/TASK_061_scheduler_specialized_commands.yaml +53 -0
- package/core/dev/pipeline/archived/TASK_062_process_manager_module_structure.yaml +56 -0
- package/core/dev/pipeline/archived/TASK_063_process_manager_core_extract.yaml +56 -0
- package/core/dev/pipeline/archived/TASK_064_recovery_module_structure.yaml +57 -0
- package/core/dev/pipeline/archived/TASK_065_recovery_core_extract.yaml +56 -0
- package/core/dev/pipeline/archived/TASK_066_self_enhancement_scheduler_models.yaml +60 -0
- package/core/dev/pipeline/archived/TASK_067_agents_section_quick_actions.yaml +53 -0
- package/core/dev/pipeline/archived/TASK_067_self_enhancement_scheduler_core.yaml +65 -0
- package/core/dev/pipeline/archived/TASK_068_agent_workflow_rule_enhancement.yaml +46 -0
- package/core/dev/pipeline/archived/TASK_068_self_enhancement_tauri_commands.yaml +61 -0
- package/core/dev/pipeline/archived/TASK_069_agent_wizard_responsive.yaml +46 -0
- package/core/dev/pipeline/archived/TASK_069_self_enhancement_ui.yaml +62 -0
- package/core/dev/pipeline/archived/TASK_070_preview_panel_redesign.yaml +62 -0
- package/core/dev/pipeline/archived/TASK_070_self_enhancement_integration.yaml +57 -0
- package/core/dev/pipeline/archived/TASK_071_preview_panel_qa.yaml +98 -0
- package/core/dev/pipeline/archived/TASK_071_single_agent_config.yaml +57 -0
- package/core/dev/pipeline/archived/TASK_072_preview_modal_esc_fix.yaml +71 -0
- package/core/dev/pipeline/archived/TASK_072_product_review_module.yaml +57 -0
- package/core/dev/pipeline/archived/TASK_073_agents_page_component_refactor.yaml +68 -0
- package/core/dev/pipeline/archived/TASK_073_rename_single_agent.yaml +64 -0
- package/core/dev/pipeline/archived/TASK_074_preview_mode_ui_diagnosis.yaml +71 -0
- package/core/dev/pipeline/archived/TASK_074_single_agent_ui_toggle.yaml +56 -0
- package/core/dev/pipeline/archived/TASK_075_agents_page_component_refactor.yaml +69 -0
- package/core/dev/pipeline/archived/TASK_075_single_agent_integration_test.yaml +75 -0
- package/core/dev/pipeline/archived/TASK_076_preview_mode_ui_diagnosis.yaml +70 -0
- package/core/dev/pipeline/archived/TASK_076_single_agent_continuous_mode.yaml +65 -0
- package/core/dev/pipeline/archived/TASK_077_failure_directory_structure.yaml +51 -0
- package/core/dev/pipeline/archived/TASK_077_single_agent_typescript_types.yaml +59 -0
- package/core/dev/pipeline/archived/TASK_078_fail_001_agent_no_output.yaml +53 -0
- package/core/dev/pipeline/archived/TASK_078_single_agent_ui_simplify.yaml +74 -0
- package/core/dev/pipeline/archived/TASK_079_dashboard_rwd_responsive.yaml +63 -0
- package/core/dev/pipeline/archived/TASK_079_fail_002_json_bom.yaml +56 -0
- package/core/dev/pipeline/archived/TASK_080_fail_003_queue_pollution.yaml +56 -0
- package/core/dev/pipeline/archived/TASK_080_http_server_module.yaml +55 -0
- package/core/dev/pipeline/archived/TASK_081_failure_logging_tools.yaml +57 -0
- package/core/dev/pipeline/archived/TASK_081_http_api_routes.yaml +62 -0
- package/core/dev/pipeline/archived/TASK_082_frontend_api_adapter.yaml +51 -0
- package/core/dev/pipeline/archived/TASK_082_integrate_failure_to_workflow.yaml +60 -0
- package/core/dev/pipeline/archived/TASK_083_cleanup_nextjs_api.yaml +48 -0
- package/core/dev/pipeline/archived/TASK_083_task_queue_cleanup.yaml +67 -0
- package/core/dev/pipeline/archived/TASK_084_rust_dead_code_cleanup.yaml +66 -0
- package/core/dev/pipeline/archived/TASK_084_scheduler_sync_logic_fix.yaml +68 -0
- package/core/dev/pipeline/archived/TASK_085_http_api_web_mode_fixes.yaml +46 -0
- package/core/dev/pipeline/archived/TASK_085_memory_consolidation_0204_0205.yaml +98 -0
- package/core/dev/pipeline/archived/TASK_086_collapsible_preview_panel.yaml +161 -0
- package/core/dev/pipeline/archived/TASK_086_web_mode_feature_parity.yaml +62 -0
- package/core/dev/pipeline/archived/TASK_087_manual_memory_archival.yaml +163 -0
- package/core/dev/pipeline/archived/TASK_087_mobile_http_control.yaml +68 -0
- package/core/dev/pipeline/archived/TASK_088_fail_003_to_ppl_002_rule.yaml +63 -0
- package/core/dev/pipeline/archived/TASK_088_mobile_http_qa.yaml +121 -0
- package/core/dev/pipeline/archived/TASK_089_agent_collaboration_topic.yaml +60 -0
- package/core/dev/pipeline/archived/TASK_089_web_mode_monitor_fix.yaml +58 -0
- package/core/dev/pipeline/archived/TASK_090_cli_detection_fix.yaml +61 -0
- package/core/dev/pipeline/archived/TASK_090_ui_ux_lessons_topic.yaml +63 -0
- package/core/dev/pipeline/archived/TASK_091_expandable_card_design.yaml +56 -0
- package/core/dev/pipeline/archived/TASK_091_move_agent_section_components.yaml +65 -0
- package/core/dev/pipeline/archived/TASK_092_expandable_card_component.yaml +60 -0
- package/core/dev/pipeline/archived/TASK_092_refactor_agent_create_wizard.yaml +84 -0
- package/core/dev/pipeline/archived/TASK_093_taskcard_detail_integration.yaml +57 -0
- package/core/dev/pipeline/archived/TASK_093_update_barrel_exports_test.yaml +84 -0
- package/core/dev/pipeline/archived/TASK_094_ai_agent_generation_enhancement.yaml +115 -0
- package/core/dev/pipeline/archived/TASK_094_proposalcard_detail_integration.yaml +55 -0
- package/core/dev/pipeline/archived/TASK_095_preview_fixes.yaml +129 -0
- package/core/dev/pipeline/archived/TASK_095_single_agent_task_selector.yaml +60 -0
- package/core/dev/pipeline/archived/TASK_096_agents_page_ux_improvements.yaml +163 -0
- package/core/dev/pipeline/archived/TASK_096_single_agent_status_sync.yaml +60 -0
- package/core/dev/pipeline/archived/TASK_097_local_claude_error_logging.yaml +59 -0
- package/core/dev/pipeline/archived/TASK_097_single_agent_monitor_events.yaml +59 -0
- package/core/dev/pipeline/archived/TASK_098_product_manager_team_phase2.yaml +60 -0
- package/core/dev/pipeline/archived/TASK_098_single_agent_refactor_test.yaml +58 -0
- package/core/dev/pipeline/archived/TASK_099_backend_team_creation.yaml +258 -0
- package/core/dev/pipeline/archived/TASK_100_frontend_team_creation.yaml +61 -0
- package/core/dev/pipeline/archived/TASK_101_orchestrator_system.yaml +403 -0
- package/core/dev/pipeline/archived/TASK_102_designer_sre_teams.yaml +90 -0
- package/core/dev/pipeline/archived/TASK_103_integration_testing.yaml +86 -0
- package/core/dev/pipeline/archived/TASK_128_integration_testing.yaml +83 -0
- package/core/dev/pipeline/archived/TASK_134_cortex_v2_phase3_file_watcher.yaml +65 -0
- package/core/dev/pipeline/archived/TASK_134_team_http_api.yaml +96 -0
- package/core/dev/pipeline/archived/TASK_135_cortex_v2_phase3_git_monitor.yaml +63 -0
- package/core/dev/pipeline/archived/TASK_136_cortex_v2_phase3_change_analyzer.yaml +69 -0
- package/core/dev/pipeline/archived/TASK_137_cortex_v2_phase3_cache_invalidator.yaml +67 -0
- package/core/dev/pipeline/archived/TASK_137_team_orchestrator_integration.yaml +93 -0
- package/core/dev/pipeline/archived/TASK_138_cortex_v2_phase3_distributed_cache.yaml +68 -0
- package/core/dev/pipeline/archived/TASK_138_matrix_folder_structure.yaml +61 -0
- package/core/dev/pipeline/archived/TASK_139_cortex_v2_phase3_cache_prewarming.yaml +65 -0
- package/core/dev/pipeline/archived/TASK_146_unified_documentation.yaml +141 -0
- package/core/dev/pipeline/archived/TASK_147_pipeline_execution_rules.yaml +76 -0
- package/core/dev/pipeline/archived/TASK_148_update_claude_md.yaml +77 -0
- package/core/dev/pipeline/archived/TASK_149_fix_nextjs_mdx_serialization.yaml +63 -0
- package/core/dev/pipeline/archived/TASK_149_update_team_docs.yaml +77 -0
- package/core/dev/pipeline/archived/TASK_150_pipeline_workflow_guide.yaml +82 -0
- package/core/dev/pipeline/archived/TASK_164_fix_smart_context_switch.yaml +49 -0
- package/core/dev/pipeline/archived/TASK_165_ctags_symbol_index.yaml +53 -0
- package/core/dev/pipeline/archived/TASK_166_symbol_search_mcp_tool.yaml +48 -0
- package/core/dev/pipeline/archived/TASK_167_llm_module_summary.yaml +55 -0
- package/core/dev/pipeline/archived/TASK_168_map_reduce_context.yaml +51 -0
- package/core/dev/pipeline/archived/TASK_169_v2_integration_testing.yaml +52 -0
- package/core/dev/pipeline/backups/archive_2026-02-04T22-07-22/TASK_QUEUE_backup.json +95 -0
- package/core/dev/pipeline/docs/multi-agent-coordination.md +446 -0
- package/core/dev/pipeline/docs/overview.md +406 -0
- package/core/dev/pipeline/docs/task-management.md +412 -0
- package/core/dev/pipeline/docs/workflows.md +32 -0
- package/core/dev/pipeline/orchestrator/schemas/task_queue_schema.json +58 -0
- package/core/dev/pipeline/orchestrator/schemas/task_schema.json +139 -0
- package/core/dev/pipeline/plans/PLAN_task_cli_refactor.md +281 -0
- package/core/dev/pipeline/tasks/.gitkeep +1 -0
- package/core/dev/pipeline/test_results/TASK_TEST_PARALLEL_002_result.txt +27 -0
- package/core/dev/plans/CLI_FIRST_INSTALL_FLOW.md +128 -0
- package/core/dev/plans/FORMATION_RETIREMENT_PLAN.md +313 -0
- package/core/dev/plans/KUZU_REPLACEMENT_PLAN.md +126 -0
- package/core/dev/schemas/PRODUCT_SPEC.example.yaml +382 -0
- package/core/dev/schemas/PRODUCT_SPEC.schema.json +800 -0
- package/core/dev/schemas/README.md +517 -0
- package/core/dev/schemas/TASK.schema.json +226 -0
- package/core/dev/schemas/dataflows_ground_truth.yaml +173 -0
- package/core/dev/schemas/dataflows_spec.yaml +160 -0
- package/core/dev/schemas/extends_ground_truth.yaml +66 -0
- package/core/dev/schemas/extends_spec.yaml +121 -0
- package/core/dev/schemas/implements_ground_truth.yaml +77 -0
- package/core/dev/schemas/implements_spec.yaml +140 -0
- package/core/dev/scripts/CRASH_DIAGNOSIS.md +47 -0
- package/core/dev/scripts/README.md +142 -0
- package/core/dev/scripts/RUN_ONCE.bat +40 -0
- package/core/dev/scripts/START_DEV_AGENT.bat +63 -0
- package/core/dev/scripts/START_MULTI_AGENT.bat +80 -0
- package/core/dev/scripts/check-alaya-report-isolation.js +255 -0
- package/core/dev/scripts/check-file-size.js +268 -0
- package/core/dev/scripts/ci-feedback.js +251 -0
- package/core/dev/scripts/clean-verify-targets.js +132 -0
- package/core/dev/scripts/cleanup-queue.js +184 -0
- package/core/dev/scripts/cleanup_queue.js +86 -0
- package/core/dev/scripts/dev_agent_scheduler.ps1 +536 -0
- package/core/dev/scripts/dispatch-stats.js +384 -0
- package/core/dev/scripts/dispatch-stats.test.js +162 -0
- package/core/dev/scripts/gc-agent-worktrees.js +461 -0
- package/core/dev/scripts/gc-agent-worktrees.test.js +48 -0
- package/core/dev/scripts/hooks/README.md +148 -0
- package/core/dev/scripts/init_git.ps1 +396 -0
- package/core/dev/scripts/init_git.sh +337 -0
- package/core/dev/scripts/init_project.ps1 +851 -0
- package/core/dev/scripts/init_project.sh +477 -0
- package/core/dev/scripts/js-yaml-resolution.test.js +48 -0
- package/core/dev/scripts/kenaz-session.js +354 -0
- package/core/dev/scripts/kenaz-session.test.js +234 -0
- package/core/dev/scripts/legacy/README.md +39 -0
- package/core/dev/scripts/legacy/dev_agent_scheduler.ps1.bak +536 -0
- package/core/dev/scripts/legacy/multi_agent_scheduler.ps1.bak +1978 -0
- package/core/dev/scripts/matrix/CLI_README.md +214 -0
- package/core/dev/scripts/matrix/README.md +310 -0
- package/core/dev/scripts/matrix/package-lock.json +4266 -0
- package/core/dev/scripts/matrix/package.json +55 -0
- package/core/dev/scripts/matrix/src/abbreviations.ts +295 -0
- package/core/dev/scripts/matrix/src/cli/commands/convert.ts +211 -0
- package/core/dev/scripts/matrix/src/cli/commands/create.ts +95 -0
- package/core/dev/scripts/matrix/src/cli/commands/delete.ts +102 -0
- package/core/dev/scripts/matrix/src/cli/commands/list-tags.ts.wip +140 -0
- package/core/dev/scripts/matrix/src/cli/commands/manage-tags.ts.wip +173 -0
- package/core/dev/scripts/matrix/src/cli/commands/query.ts +261 -0
- package/core/dev/scripts/matrix/src/cli/commands/read.ts +77 -0
- package/core/dev/scripts/matrix/src/cli/commands/stats.ts.wip +168 -0
- package/core/dev/scripts/matrix/src/cli/commands/tokens.ts.wip +126 -0
- package/core/dev/scripts/matrix/src/cli/commands/update.ts +147 -0
- package/core/dev/scripts/matrix/src/cli/commands/validate.ts +275 -0
- package/core/dev/scripts/matrix/src/cli/index.ts +350 -0
- package/core/dev/scripts/matrix/src/cli/utils/file-handler.ts +72 -0
- package/core/dev/scripts/matrix/src/cli/utils/logger.ts +65 -0
- package/core/dev/scripts/matrix/src/index.ts +62 -0
- package/core/dev/scripts/matrix/src/indexer/tag-indexer.ts +165 -0
- package/core/dev/scripts/matrix/src/parser.ts +281 -0
- package/core/dev/scripts/matrix/src/serializer.ts +151 -0
- package/core/dev/scripts/matrix/src/validator.ts +301 -0
- package/core/dev/scripts/matrix/tests/abbreviations.test.ts +122 -0
- package/core/dev/scripts/matrix/tests/cli.test.ts +177 -0
- package/core/dev/scripts/matrix/tests/convert.test.ts +143 -0
- package/core/dev/scripts/matrix/tests/parser.test.ts +203 -0
- package/core/dev/scripts/matrix/tests/query.test.ts +85 -0
- package/core/dev/scripts/matrix/tests/serializer.test.ts +197 -0
- package/core/dev/scripts/matrix/tests/validate.test.ts +141 -0
- package/core/dev/scripts/matrix/tests/validator.test.ts +167 -0
- package/core/dev/scripts/matrix/tsconfig.json +20 -0
- package/core/dev/scripts/matrix/types/index.d.ts +111 -0
- package/core/dev/scripts/matrix/types/index.d.ts.map +1 -0
- package/core/dev/scripts/matrix/types/index.js +8 -0
- package/core/dev/scripts/matrix/types/index.js.map +1 -0
- package/core/dev/scripts/matrix/types/index.ts +124 -0
- package/core/dev/scripts/memory-guard-eval.js +330 -0
- package/core/dev/scripts/memory-usage-report.js +152 -0
- package/core/dev/scripts/migrate-task-dependencies.js +198 -0
- package/core/dev/scripts/multi_agent_scheduler.ps1 +2021 -0
- package/core/dev/scripts/multi_agent_scheduler.sh +1344 -0
- package/core/dev/scripts/probe/ansuz-scaffold-ablation.js +579 -0
- package/core/dev/scripts/probe/ansuz-scaffold-ablation.test.js +244 -0
- package/core/dev/scripts/probe/hippocampus-concurrency.js +247 -0
- package/core/dev/scripts/probe/hook-latency-probe.js +315 -0
- package/core/dev/scripts/probe/hook-latency-probe.test.js +105 -0
- package/core/dev/scripts/probe/prediction-signal-auc.js +483 -0
- package/core/dev/scripts/probe/prediction-signal-auc.test.js +200 -0
- package/core/dev/scripts/reset_tasks.js +99 -0
- package/core/dev/scripts/run-rust-tests.js +207 -0
- package/core/dev/scripts/run-rust-tests.test.js +154 -0
- package/core/dev/scripts/run_once.sh +47 -0
- package/core/dev/scripts/rust-verify-worktree.js +591 -0
- package/core/dev/scripts/rust-verify-worktree.test.js +574 -0
- package/core/dev/scripts/seh_probe.rs +26 -0
- package/core/dev/scripts/setup_mcp.ps1 +192 -0
- package/core/dev/scripts/setup_mcp.sh +159 -0
- package/core/dev/scripts/setup_rag.ps1 +304 -0
- package/core/dev/scripts/setup_rag.sh +230 -0
- package/core/dev/scripts/start_dev_agent.sh +137 -0
- package/core/dev/scripts/start_multi_agent.sh +41 -0
- package/core/dev/scripts/sync_task_queue.ps1 +505 -0
- package/core/dev/scripts/sync_task_queue.sh +392 -0
- package/core/dev/scripts/task1961/RUNBOOK.md +300 -0
- package/core/dev/scripts/task1961/fixtures/never-listens.server.js +54 -0
- package/core/dev/scripts/task1961/fixtures/slow-serve.server.js +134 -0
- package/core/dev/scripts/task1961/run-fixture.js +659 -0
- package/core/dev/scripts/task1961/selftest.js +247 -0
- package/core/dev/scripts/test-pty-ws-tunnel.js +229 -0
- package/core/dev/scripts/validate_pipeline.js +197 -0
- package/core/dev/scripts/verify-isbar-capture.js +100 -0
- package/core/dev/scripts/verify-target-dir.js +69 -0
- package/core/dev/scripts/verify-task-1839.js +141 -0
- package/core/dev/specs/agent-connect/PROTOCOL.md +177 -0
- package/core/dev/specs/agent-connect/SDK_GUIDE.md +915 -0
- package/core/dev/specs/agent-connect/examples/minimal-site/README.md +137 -0
- package/core/dev/specs/agent-connect/examples/minimal-site/package.json +12 -0
- package/core/dev/specs/agent-connect/examples/minimal-site/public/index.html +116 -0
- package/core/dev/specs/agent-connect/examples/minimal-site/public/install-redirect.js +73 -0
- package/core/dev/specs/agent-connect/examples/minimal-site/server.js +516 -0
- package/core/dev/specs/agent-connect/examples/minimal-site/test/smoke.test.mjs +263 -0
- package/core/dev/specs/agent-connect/history/DEFECT_REPORT_kenaz-agent-hub_2026-09-09_v0.4-empty-prompt-no-first-turn.md +77 -0
- package/core/dev/specs/agent-connect/history/DEFECT_REPORT_kenaz-agent-hub_2026-09-09_v0.4-prompt-mojibake.md +90 -0
- package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-07.md +61 -0
- package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-08_relay-v1-conformance.md +76 -0
- package/core/dev/specs/agent-connect/history/FEATURE_REQUEST_kenaz-agent-hub_2026-09-09_v0.4-session-channel.md +87 -0
- package/core/dev/specs/agent-connect/history/FLOWPIX_REPLY_agent-hub_2026-09-08_relay-v1-answers.md +68 -0
- package/core/dev/specs/agent-connect/history/FLOWPIX_bridge_CONTRACT.md +642 -0
- package/core/dev/specs/agent-connect/history/FLOWPIX_spikes_relay_spike_relay.mjs +244 -0
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-07.md +77 -0
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_direction-change-v0.3.md +44 -0
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-answers-ack.md +37 -0
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-08_relay-v1-conformance.md +56 -0
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_annotations-install-coldstart.md +44 -0
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_empty-prompt-first-turn.md +56 -0
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_prompt-mojibake-fixed.md +48 -0
- package/core/dev/specs/agent-connect/history/KENAZ_RESPONSE_agent-hub_2026-09-09_session-channel.md +57 -0
- package/core/dev/specs/agent-connect/history/PROTOCOL_v0.3_snapshot.md +379 -0
- package/core/dev/specs/agent-connect/history/README.md +47 -0
- package/core/dev/specs/peer/CODEX_INTERACTIVE_PUSH.md +65 -0
- package/core/dev/specs/peer/CODEX_PEER_PULL_SPIKE.md +54 -0
- package/core/dev/specs/peer/MODS_SPIKE.md +133 -0
- package/core/dev/specs/peer/PER_PROJECT_ADDRESSING.md +143 -0
- package/core/dev/specs/peer/SWARM_PROTOCOLS.md +256 -0
- package/core/dev/specs/peer/codex-hook-shim-peer.test.js +101 -0
- package/core/dev/specs/peer/codex-push-launcher.test.js +142 -0
- package/core/dev/specs/peer/setup-codex-hooks.test.js +22 -0
- package/core/dev/specs/peer-ansuz/DELIVERY_SPIKE.md +397 -0
- package/core/dev/specs/peer-ansuz/DESIGN.md +109 -0
- package/core/dev/specs/peer-ansuz/spike/claude_poke.js +129 -0
- package/core/dev/specs/peer-ansuz/spike/claude_session_start_hook.js +37 -0
- package/core/dev/specs/peer-ansuz/spike/claude_settings_hook.json +14 -0
- package/core/dev/specs/peer-ansuz/spike/codex_appserver_client.js +105 -0
- package/core/dev/specs/peer-ansuz/spike/codex_appserver_query.js +29 -0
- package/core/dev/specs/peer-ansuz/spike/extract_timeline.js +26 -0
- package/core/dev/specs/synapse/SYMBOL_IDENTITY.md +305 -0
- package/core/dev/spikes/A4-cypher-varlen.md +176 -0
- package/core/dev/spikes/bloat-rounds.sh +25 -0
- package/core/dev/spikes/mods/clean-claude.js +9 -0
- package/core/dev/spikes/mods/drive-probe.js +29 -0
- package/core/dev/spikes/mods/e2e-peer.js +71 -0
- package/core/dev/spikes/mods/evidence/e2e-peer-control.json +17 -0
- package/core/dev/spikes/mods/evidence/e2e-peer-mod.json +17 -0
- package/core/dev/spikes/mods/evidence/probe-006a6e65-d807-4bc1-b648-fd7d1edfe0b4.jsonl +4 -0
- package/core/dev/spikes/mods/evidence/probe-cebdf1f7-f9c4-47a8-83cd-7c0786177404.jsonl +12 -0
- package/core/dev/spikes/mods/evidence/probe-eb21147d-10ce-4c32-93ed-37ca37d88d5a.jsonl +11 -0
- package/core/dev/spikes/mods/evidence/stream-cebdf1f7.jsonl +18 -0
- package/core/dev/spikes/mods/kenaz-mod-probe/.claude-plugin/plugin.json +1 -0
- package/core/dev/spikes/mods/kenaz-mod-probe/hooks/hooks.json +1 -0
- package/core/dev/spikes/mods/kenaz-mod-probe/hooks/register.ts +65 -0
- package/core/dev/spikes/mods/kenaz-mod-probe/tsconfig.json +3 -0
- package/core/k-cli/README.md +423 -0
- package/core/k-cli/package.json +21 -0
- package/core/k-cli/templates/k-cli.md +91 -0
- package/core/k-cli/test/TEST_SPEC.md +134 -0
- package/core/k-cli/test/run.sh +469 -0
- package/core/plugins/kenaz/.claude-plugin/plugin.json +1 -0
- package/core/plugins/kenaz/.mcp.json +5 -0
- package/core/plugins/kenaz/INVENTORY.md +48 -0
- package/core/plugins/kenaz/README.md +55 -0
- package/core/plugins/kenaz/commands/Amelia.md +5 -0
- package/core/plugins/kenaz/commands/Ansuz.md +38 -0
- package/core/plugins/kenaz/commands/architect.md +24 -0
- package/core/plugins/kenaz/commands/incident.md +15 -0
- package/core/plugins/kenaz/commands/kenaz.md +12 -0
- package/core/plugins/kenaz/commands/review.md +14 -0
- package/core/plugins/kenaz/commands/security.md +15 -0
- package/core/plugins/kenaz/commands/spec.md +22 -0
- package/core/plugins/kenaz/commands/strategy.md +141 -0
- package/core/plugins/kenaz/commands//347/224/242/345/223/201.md +15 -0
- package/core/plugins/kenaz/commands//350/250/255/350/250/210.md +14 -0
- package/core/plugins/kenaz/commands//350/251/225/344/274/260.md +16 -0
- package/core/plugins/kenaz/guidance.md +5 -0
- package/core/plugins/kenaz/hooks/core-resolve.js +230 -0
- package/core/plugins/kenaz/hooks/hooks.json +31 -0
- package/core/plugins/kenaz/hooks/kenaz-hook.js +112 -0
- package/core/plugins/kenaz/hooks/mode.js +39 -0
- package/core/plugins/kenaz/scripts/kenaz-mode.js +46 -0
- package/core/plugins/kenaz/scripts/kenaz.test.js +123 -0
- package/core/plugins/kenaz/scripts/sync.js +45 -0
- package/core/plugins/kenaz/scripts/ygg.js +157 -0
- package/core/plugins/kenaz/skills/adapt/SKILL.md +199 -0
- package/core/plugins/kenaz/skills/animate/SKILL.md +190 -0
- package/core/plugins/kenaz/skills/architect_agent/SKILL.md +408 -0
- package/core/plugins/kenaz/skills/assessment_agent/SKILL.md +289 -0
- package/core/plugins/kenaz/skills/audit/SKILL.md +129 -0
- package/core/plugins/kenaz/skills/backend_agent/SKILL.md +407 -0
- package/core/plugins/kenaz/skills/backend_engineer/SKILL.md +788 -0
- package/core/plugins/kenaz/skills/bolder/SKILL.md +132 -0
- package/core/plugins/kenaz/skills/clarify/SKILL.md +180 -0
- package/core/plugins/kenaz/skills/code_reviewer/SKILL.md +305 -0
- package/core/plugins/kenaz/skills/code_reviewer/patterns.yaml +85 -0
- package/core/plugins/kenaz/skills/colorize/SKILL.md +158 -0
- package/core/plugins/kenaz/skills/critique/SKILL.md +118 -0
- package/core/plugins/kenaz/skills/delight/SKILL.md +317 -0
- package/core/plugins/kenaz/skills/designer/SKILL.md +845 -0
- package/core/plugins/kenaz/skills/dev_agent/SKILL.md +503 -0
- package/core/plugins/kenaz/skills/developer/SKILL.md +792 -0
- package/core/plugins/kenaz/skills/distill/SKILL.md +137 -0
- package/core/plugins/kenaz/skills/extract/SKILL.md +95 -0
- package/core/plugins/kenaz/skills/feature_agent/SKILL.md +303 -0
- package/core/plugins/kenaz/skills/frontend-design/SKILL.md +127 -0
- package/core/plugins/kenaz/skills/frontend-design/reference/color-and-contrast.md +132 -0
- package/core/plugins/kenaz/skills/frontend-design/reference/interaction-design.md +123 -0
- package/core/plugins/kenaz/skills/frontend-design/reference/motion-design.md +99 -0
- package/core/plugins/kenaz/skills/frontend-design/reference/responsive-design.md +114 -0
- package/core/plugins/kenaz/skills/frontend-design/reference/spatial-design.md +100 -0
- package/core/plugins/kenaz/skills/frontend-design/reference/typography.md +131 -0
- package/core/plugins/kenaz/skills/frontend-design/reference/ux-writing.md +107 -0
- package/core/plugins/kenaz/skills/frontend_agent/SKILL.md +327 -0
- package/core/plugins/kenaz/skills/harden/SKILL.md +358 -0
- package/core/plugins/kenaz/skills/incident_response/SKILL.md +315 -0
- package/core/plugins/kenaz/skills/normalize/SKILL.md +67 -0
- package/core/plugins/kenaz/skills/onboard/SKILL.md +243 -0
- package/core/plugins/kenaz/skills/optimize/SKILL.md +269 -0
- package/core/plugins/kenaz/skills/polish/SKILL.md +202 -0
- package/core/plugins/kenaz/skills/product_manager/SKILL.md +1091 -0
- package/core/plugins/kenaz/skills/qa_engineer/SKILL.md +1269 -0
- package/core/plugins/kenaz/skills/quieter/SKILL.md +118 -0
- package/core/plugins/kenaz/skills/security_agent/SKILL.md +312 -0
- package/core/plugins/kenaz/skills/spec_optimizer/SKILL.md +299 -0
- package/core/plugins/kenaz/skills/sre_agent/SKILL.md +1347 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/SKILL.md +377 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/scripts/core.py +253 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/core/plugins/kenaz/skills/ui-ux-pro-max/scripts/search.py +106 -0
- package/core/plugins/kenaz-peer/.claude-plugin/plugin.json +1 -0
- package/core/plugins/kenaz-peer/hooks/hooks.json +1 -0
- package/core/plugins/kenaz-peer/hooks/register.test.ts +62 -0
- package/core/plugins/kenaz-peer/hooks/register.ts +146 -0
- package/core/plugins/kenaz-peer/tsconfig.json +3 -0
- package/lib/cli.js +251 -0
- package/lib/cli.test.js +59 -0
- package/lib/dashboard.js +80 -0
- package/lib/dashboard.test.js +59 -0
- package/package.json +28 -4
- package/vendor/install-kenaz-cli.js +268 -0
- package/README.md +0 -3
|
@@ -0,0 +1,1931 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Formation Dispatch — CLI 入口
|
|
4
|
+
*
|
|
5
|
+
* 根據陣型調度 subagent 執行任務。
|
|
6
|
+
* 實際邏輯分散在各模組:loader, prompt, runner, logger, utils。
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* node .formation/tools/dispatch.js --skill=do --task=TASK_172
|
|
10
|
+
* node .formation/tools/dispatch.js --formation=solo --skill=strategy --task=TASK_172
|
|
11
|
+
* node .formation/tools/dispatch.js --formation=squad --skill=blitz --task=TASK_173
|
|
12
|
+
* node .formation/tools/dispatch.js --formation=legion --skill=forge --task=TASK_174 --dry-run
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const { execSync } = require('child_process');
|
|
18
|
+
const { loadSkill, loadTask } = require('./loader');
|
|
19
|
+
const {
|
|
20
|
+
buildPrompt, SUBAGENT_PREFIX, SUBAGENT_PREFIX_DIRECT, buildSubagentWorktreePrefix,
|
|
21
|
+
promptProfile, extractRigor, extractComplexity, splitPromptSections,
|
|
22
|
+
applyRustCheckToPrefix,
|
|
23
|
+
} = require('./prompt');
|
|
24
|
+
const { runSingle, runParallel } = require('./runner');
|
|
25
|
+
const {
|
|
26
|
+
generateSessionId, ensureGitReady, ROOT, loadDashboardModels,
|
|
27
|
+
resolveWorktreeDecision, dispatchLockPath, tryAcquireDispatchLock, dispatchLockStaleness,
|
|
28
|
+
createWorktree, ensureWorktreeDirIgnored, COLLABORATION_API,
|
|
29
|
+
getVerifyOfflineCommand,
|
|
30
|
+
} = require('./utils');
|
|
31
|
+
const { refreshCache, hasRemoteConflict, hasRemoteFileConflict, isCacheStale } = require('./remote-conflict');
|
|
32
|
+
|
|
33
|
+
// TASK_1815: the Agent tool's `model` parameter accepts ONLY these Claude
|
|
34
|
+
// family names — no versions, no [1m] speed modifiers, no full model ids.
|
|
35
|
+
// Measured 2026-07-26 by a direct Agent tool probe from the main thread:
|
|
36
|
+
// model="claude-fable-5" and model="gpt-5-codex" both raise the SAME
|
|
37
|
+
// InputValidationError listing exactly this enum. This is a harness-side
|
|
38
|
+
// constraint that may drift with Claude Code versions — keep the four values
|
|
39
|
+
// in THIS single constant; if subagent dispatch starts failing with
|
|
40
|
+
// InputValidationError on the model field, re-probe the Agent tool and update
|
|
41
|
+
// here (nowhere else).
|
|
42
|
+
// (Declared before the CLI entry point below — module-scope code calls
|
|
43
|
+
// getSubagentDispatchParams during evaluation, so a later `const` would be in
|
|
44
|
+
// its temporal dead zone at call time.)
|
|
45
|
+
const AGENT_TOOL_MODEL_ENUM = ['sonnet', 'opus', 'haiku', 'fable'];
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* TASK_1815: translate a dashboard-models.json dispatchModel string into the
|
|
49
|
+
* Agent tool model enum. Dashboard model ids carry versions and speed
|
|
50
|
+
* modifiers (claude-opus-5[1m], claude-sonnet-4-6, ...) that the Agent tool
|
|
51
|
+
* cannot express — the enum has FAMILY names only. So this translation is
|
|
52
|
+
* structurally LOSSY: claude-opus-5[1m] and claude-opus-4-8[1m] both become
|
|
53
|
+
* 'opus'. Callers must surface that loss, never treat it as equivalence.
|
|
54
|
+
* NOTE: dashboard/src/lib/models.ts `family` ('claude'|'bifrost') is the
|
|
55
|
+
* ADAPTER family and is unrelated to this Claude sub-family mapping.
|
|
56
|
+
* @param {string} rawModel - dashboard model id, possibly with [1m]-style suffix
|
|
57
|
+
* @returns {{ model: string|null, lossless: boolean }} model=null → unmappable
|
|
58
|
+
*/
|
|
59
|
+
function translateModelForAgentTool(rawModel) {
|
|
60
|
+
// Strip Formation-internal speed modifier suffixes like [1m]
|
|
61
|
+
const stripped = String(rawModel || '').replace(/\[.*?\]/g, '').trim();
|
|
62
|
+
if (AGENT_TOOL_MODEL_ENUM.includes(stripped)) {
|
|
63
|
+
// Already a bare family name — lossless only if there was no suffix to strip.
|
|
64
|
+
return { model: stripped, lossless: stripped === String(rawModel).trim() };
|
|
65
|
+
}
|
|
66
|
+
// claude-<family>[-version...] → <family>. Covers every NATIVE id in
|
|
67
|
+
// dashboard/src/lib/models.ts (claude-fable-5-1[1m], claude-opus-5-5[1m],
|
|
68
|
+
// claude-fable-5[1m], claude-opus-4-8[1m], claude-sonnet-5,
|
|
69
|
+
// claude-sonnet-4-6) plus future versions of the same families. 'haiku' has
|
|
70
|
+
// no dashboard source entry today but maps fine if one appears.
|
|
71
|
+
const m = stripped.match(/^claude-(opus|sonnet|haiku|fable)(?:-|$)/);
|
|
72
|
+
if (m) return { model: m[1], lossless: false };
|
|
73
|
+
return { model: null, lossless: false };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// TASK_1998 R3 (spec correction, user decision 2026-09-22 — supersedes an
|
|
77
|
+
// earlier low→haiku/high→opus hard-coded policy that was implemented and then
|
|
78
|
+
// reverted before merge): the model ALWAYS follows the Dashboard setting.
|
|
79
|
+
// For every rigor the model is dashboard-models.json's `dispatchModel`,
|
|
80
|
+
// exactly as before R3 — UNLESS that same file also carries an explicit
|
|
81
|
+
// `dispatchModelByRigor: {low?, medium?, high?}` object (populated from the
|
|
82
|
+
// Dashboard's own settings UI, not hand-edited), in which case the entry for
|
|
83
|
+
// the card's rigor wins for that rigor only (missing keys fall back to
|
|
84
|
+
// dispatchModel). `--dispatch-model` CLI keeps precedence over both. Every
|
|
85
|
+
// source runs through the SAME translateModelForAgentTool below, and
|
|
86
|
+
// TASK_1815's rule applies uniformly: an id that cannot be mapped to the
|
|
87
|
+
// Agent tool enum exits 1 loudly — never a silent substitute.
|
|
88
|
+
/**
|
|
89
|
+
* @param {object} p
|
|
90
|
+
* @param {string|null} p.rigor - card rigor ('low'|'medium'|'high'|null).
|
|
91
|
+
* null/unrecognized normalizes to 'medium' — mirrors promptProfile()'s
|
|
92
|
+
* treatment of missing/unrecognized rigor as the diet(medium) default.
|
|
93
|
+
* @param {object|null} p.models - parsed dashboard-models.json (routing.models)
|
|
94
|
+
* @param {string|null} p.cliDispatchModel - --dispatch-model CLI value, if any
|
|
95
|
+
* @returns {{ rawModel: string, source: 'cli'|'dashboard-by-rigor'|'dashboard', label: string, rigorKey: 'low'|'medium'|'high' }}
|
|
96
|
+
*/
|
|
97
|
+
function resolveDispatchModelForRigor({ rigor, models, cliDispatchModel }) {
|
|
98
|
+
const rigorKey = (rigor === 'low' || rigor === 'high') ? rigor : 'medium';
|
|
99
|
+
// 1. CLI flag wins over everything.
|
|
100
|
+
if (cliDispatchModel) {
|
|
101
|
+
return { rawModel: cliDispatchModel, source: 'cli', label: '--dispatch-model', rigorKey };
|
|
102
|
+
}
|
|
103
|
+
// 2. dashboard-models.json dispatchModelByRigor — only when the Dashboard
|
|
104
|
+
// has set an entry for THIS rigor; unset keys fall through to dispatchModel.
|
|
105
|
+
const byRigor = (models && typeof models.dispatchModelByRigor === 'object' && models.dispatchModelByRigor) || null;
|
|
106
|
+
const overrideRaw = byRigor && typeof byRigor[rigorKey] === 'string' ? byRigor[rigorKey].trim() : '';
|
|
107
|
+
if (overrideRaw) {
|
|
108
|
+
return { rawModel: overrideRaw, source: 'dashboard-by-rigor', label: `dashboard-models.json dispatchModelByRigor.${rigorKey}`, rigorKey };
|
|
109
|
+
}
|
|
110
|
+
// 3. Default for every rigor: the dashboard dispatchModel, unchanged fallback
|
|
111
|
+
// ('claude-sonnet-4-6', mirrors DEFAULT_DISPATCH_MODEL in dashboard/src/lib/models.ts).
|
|
112
|
+
const rawModel = (models && typeof models.dispatchModel === 'string' && models.dispatchModel) || 'claude-sonnet-4-6';
|
|
113
|
+
return { rawModel, source: 'dashboard', label: 'dashboard-models.json dispatchModel', rigorKey };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ─────────────────────────────────────────
|
|
117
|
+
// -----------------------------------------
|
|
118
|
+
// M1 (TASK_1758): Dispatch-time scope gate + resource lease
|
|
119
|
+
// Spec: dev/MULTI_ANSUZ_SPEC.md §2.3 + §2.5
|
|
120
|
+
// -----------------------------------------
|
|
121
|
+
|
|
122
|
+
function normalizeScopePath(p_) {
|
|
123
|
+
if (!p_) return '';
|
|
124
|
+
let s = String(p_).split(String.fromCharCode(92)).join("/").trim();
|
|
125
|
+
if (process.platform === 'win32') s = s.toLowerCase();
|
|
126
|
+
return s;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function pathsCollide(a, b) {
|
|
130
|
+
const na = normalizeScopePath(a);
|
|
131
|
+
const nb = normalizeScopePath(b);
|
|
132
|
+
if (!na || !nb) return false;
|
|
133
|
+
if (na === nb) return true;
|
|
134
|
+
const naSlash = na.endsWith('/') ? na : na + '/';
|
|
135
|
+
const nbSlash = nb.endsWith('/') ? nb : nb + '/';
|
|
136
|
+
if (nb.startsWith(naSlash)) return true;
|
|
137
|
+
if (na.startsWith(nbSlash)) return true;
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function _dispPidAlive(pid) {
|
|
142
|
+
if (!pid || pid <= 0) return false;
|
|
143
|
+
try { process.kill(pid, 0); return true; }
|
|
144
|
+
catch (e) { if (e.code === 'EPERM') return true; return false; }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// TASK_2263: identity + provenance. source 'hmap' = resolved via this process's own
|
|
148
|
+
// CLAUDE_CODE_SESSION_ID (provable); 'current_stream' = the singleton file that may
|
|
149
|
+
// name ANOTHER live session (unprovable, best-effort label only).
|
|
150
|
+
function _getOwnSessionId(projectRoot) { return _resolveOwnSession(projectRoot).id; }
|
|
151
|
+
|
|
152
|
+
// TASK_2265: id usable as "self" for filtering OTHER sessions' leases/claims and as an
|
|
153
|
+
// authoritative owner in written records. Only hmap-proven identity qualifies; the
|
|
154
|
+
// current_stream singleton may name a foreign live session, so it yields null (callers
|
|
155
|
+
// fail closed: nothing is treated as self, writers fall back to the 'unknown' sentinel).
|
|
156
|
+
function _getProvenSessionId(projectRoot) {
|
|
157
|
+
var o = _resolveOwnSession(projectRoot);
|
|
158
|
+
return o.source === 'hmap' ? o.id : null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function _resolveOwnSession(projectRoot) {
|
|
162
|
+
// TASK_1764 AMEND: use CLAUDE_CODE_SESSION_ID (= conversation UUID, stable across compact/resume).
|
|
163
|
+
// CLAUDE_SESSION_ID does not exist; CLAUDE_CODE_SESSION_ID is the correct env variable.
|
|
164
|
+
// hmap key is now convId (transcript_path basename = conversation id), consistent with hooks.
|
|
165
|
+
try {
|
|
166
|
+
var sessId = process.env.CLAUDE_CODE_SESSION_ID;
|
|
167
|
+
if (sessId) {
|
|
168
|
+
var hmapF = require('path').join(projectRoot, '.kenaz', 'specialist', 'sessions', 'hmap_' + sessId + '.json');
|
|
169
|
+
try {
|
|
170
|
+
var hmap = JSON.parse(require('fs').readFileSync(hmapF, 'utf8'));
|
|
171
|
+
if (hmap && hmap.boot_sid) return { id: hmap.boot_sid, source: 'hmap' };
|
|
172
|
+
} catch (_e2) {}
|
|
173
|
+
}
|
|
174
|
+
// Fallback: current_stream.json (solo session, headless, or hmap not yet written)
|
|
175
|
+
var sf = require('path').join(projectRoot, '.kenaz', 'specialist', 'current_stream.json');
|
|
176
|
+
var parsed = JSON.parse(require('fs').readFileSync(sf, 'utf8'));
|
|
177
|
+
var fid = (parsed && parsed.session_id) || null;
|
|
178
|
+
return { id: fid, source: fid ? 'current_stream' : null };
|
|
179
|
+
} catch (_e) { return { id: null, source: null }; }
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// TASK_1863: own conversation id — the STABLE self-identity anchor (TASK_1764;
|
|
183
|
+
// ash rune_cfc898ca: session ids rotate/alias, conversation id does not).
|
|
184
|
+
// Env CLAUDE_CODE_SESSION_ID (= transcript basename, stable across compact/resume)
|
|
185
|
+
// only (TASK_2281: the current_stream.json conversation_id is NOT trusted — singleton).
|
|
186
|
+
function _getOwnConversationId(projectRoot) {
|
|
187
|
+
try {
|
|
188
|
+
var envId = process.env.CLAUDE_CODE_SESSION_ID;
|
|
189
|
+
// TASK_2281: no current_stream fallback — the singleton may name another live
|
|
190
|
+
// conversation; unproven identity fails closed (null = no marker is "ours").
|
|
191
|
+
return envId || null;
|
|
192
|
+
} catch (_e) { return null; }
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// TASK_1787/2281: is this claim marker ours? Anchor: owner_conversation_id; fallback
|
|
196
|
+
// owner_session when the marker has no conv id; never owner_pid. (headless auto-claim guard)
|
|
197
|
+
function _isOwnClaimMarker(marker, projectRoot) {
|
|
198
|
+
// TASK_2281: proven identity only (env conv id / hmap). The current_stream.json singleton
|
|
199
|
+
// may name another live session -> unproven -> never "ours" (fail closed).
|
|
200
|
+
if (!marker) return false;
|
|
201
|
+
if (marker.owner_conversation_id) {
|
|
202
|
+
var conv = _getOwnConversationId(projectRoot);
|
|
203
|
+
return !!conv && marker.owner_conversation_id === conv;
|
|
204
|
+
}
|
|
205
|
+
var sid = _getProvenSessionId(projectRoot);
|
|
206
|
+
return !!sid && !!marker.owner_session && marker.owner_session === sid;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// TASK_1863: late-failure claim rollback — the same guarantee TASK_1833 gave
|
|
210
|
+
// resource leases. dispatch.js does not WRITE claim markers (task-api does, on
|
|
211
|
+
// the chain's pre-claim / move→active), but a dispatch that fails AFTER the
|
|
212
|
+
// scope gate must not leave that marker behind: the leaked marker blocks the
|
|
213
|
+
// same conversation's retry when its owner_session is a live alias (measured
|
|
214
|
+
// 2026-08-13: claim_TASK_1861 owned by ghost stream-D blocked the retry with
|
|
215
|
+
// '<same-task>' until hand-deleted), and blocks every other session for the
|
|
216
|
+
// full 8h liveness window if this session dies. Adoption is strictly
|
|
217
|
+
// self-scoped: only a marker provably owned by this session OR this
|
|
218
|
+
// conversation is ever released. Foreign markers are never touched — orphan
|
|
219
|
+
// arbitration stays in task-api (never auto-steal, rune_0378754d).
|
|
220
|
+
function adoptSelfClaimMarker(taskId, projectRoot, ownSessionId) {
|
|
221
|
+
const adoption = { markerPath: null, adopted: false };
|
|
222
|
+
if (!taskId || !/^TASK_/.test(taskId)) return adoption;
|
|
223
|
+
adoption.markerPath = require('path').join(projectRoot, '.kenaz', 'locks', 'claim_' + taskId + '.json');
|
|
224
|
+
let mk = null;
|
|
225
|
+
try { mk = JSON.parse(require('fs').readFileSync(adoption.markerPath, 'utf8')); } catch (_e) { return adoption; }
|
|
226
|
+
if (!mk) return adoption;
|
|
227
|
+
const ownConvId = _getOwnConversationId(projectRoot);
|
|
228
|
+
adoption.adopted =
|
|
229
|
+
(!!ownSessionId && mk.owner_session === ownSessionId) ||
|
|
230
|
+
(!!ownConvId && mk.owner_conversation_id === ownConvId);
|
|
231
|
+
return adoption;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function releaseAdoptedClaimMarker(adoption) {
|
|
235
|
+
if (!adoption || !adoption.adopted || !adoption.markerPath) return;
|
|
236
|
+
try { require('fs').unlinkSync(adoption.markerPath); } catch (_e) { /* already gone */ }
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* TASK_1859: explicit release for the serial dispatch lock (utils.dispatchLockPath).
|
|
241
|
+
* The previous release contract was "delete the lock file" — structurally
|
|
242
|
+
* unexecutable in orchestrator environments that deny Bash(rm *) (deny wins
|
|
243
|
+
* over every allow), leaving 60min staleness as the only exit. This gives the
|
|
244
|
+
* lock a first-class release interface: `--release-lock` on this CLI.
|
|
245
|
+
*
|
|
246
|
+
* Ownership rule (never silent): a release without --force requires PROVABLE
|
|
247
|
+
* same-session ownership — both the holder's sessionId and our own resolved
|
|
248
|
+
* session must exist, neither may be the 'unknown' sentinel (locks are written
|
|
249
|
+
* with sessionId `_getOwnSessionId(ROOT) || 'unknown'`), and they must match.
|
|
250
|
+
* Any unprovable case (holder corrupt, holder sessionId missing/'unknown',
|
|
251
|
+
* own session unresolvable) REFUSES and requires --force — an 'unknown' holder
|
|
252
|
+
* is exactly the case where we cannot know whose live agent we would unlock.
|
|
253
|
+
*
|
|
254
|
+
* Deliberately NOT pid-based: pid:null is the designed holder shape (the
|
|
255
|
+
* dispatch CLI exits right after emitting params — its pid proves nothing
|
|
256
|
+
* about the agent's liveness). Staleness info comes from the single authority
|
|
257
|
+
* utils.dispatchLockStaleness and is surfaced for the operator, but this
|
|
258
|
+
* function never auto-releases on staleness — the next tryAcquireDispatchLock
|
|
259
|
+
* already breaks stale locks; release stays an explicit human/orchestrator act.
|
|
260
|
+
*
|
|
261
|
+
* @param {object} [opts]
|
|
262
|
+
* @param {string|null} [opts.projectPath] - target project (lock key), null = core
|
|
263
|
+
* @param {boolean} [opts.force] - allow releasing a lock we cannot prove we own
|
|
264
|
+
* @param {string|null} [opts.ownSessionId] - test injection point ONLY; when the
|
|
265
|
+
* key is absent the real _getOwnSessionId(ROOT) is used (same source as the
|
|
266
|
+
* lock writer). Explicit null models "own session resolution failed".
|
|
267
|
+
* @returns {{ released: boolean, existed: boolean, lockFile: string,
|
|
268
|
+
* holder: object|null, staleness: object|null, ownSessionId: string|null,
|
|
269
|
+
* reason: string }}
|
|
270
|
+
*/
|
|
271
|
+
function releaseDispatchLock(opts = {}) {
|
|
272
|
+
const { projectPath = null, force = false } = opts;
|
|
273
|
+
const lockFile = dispatchLockPath(projectPath);
|
|
274
|
+
// TASK_2263: an identity from the singleton current_stream.json fallback can name
|
|
275
|
+
// another live session, so it is not ownership proof (injected ids count as proven).
|
|
276
|
+
const _own = ('ownSessionId' in opts) ? { id: opts.ownSessionId, source: 'injected' } : _resolveOwnSession(ROOT);
|
|
277
|
+
const ownSessionId = _own.id;
|
|
278
|
+
let raw = null;
|
|
279
|
+
try { raw = fs.readFileSync(lockFile, 'utf8'); }
|
|
280
|
+
catch (e) {
|
|
281
|
+
if (e.code === 'ENOENT') {
|
|
282
|
+
return { released: false, existed: false, lockFile, holder: null, staleness: null, ownSessionId, reason: 'not-held' };
|
|
283
|
+
}
|
|
284
|
+
return { released: false, existed: true, lockFile, holder: null, staleness: null, ownSessionId, reason: 'read-error: ' + e.message };
|
|
285
|
+
}
|
|
286
|
+
let holder = null;
|
|
287
|
+
try { holder = JSON.parse(raw); } catch { /* corrupt — unprovable ownership below */ }
|
|
288
|
+
const staleness = dispatchLockStaleness(holder);
|
|
289
|
+
const holderSession = holder && typeof holder.sessionId === 'string' && holder.sessionId.trim() ? holder.sessionId.trim() : null;
|
|
290
|
+
// Defined-behavior ladder for unprovable ownership (acceptance: never silent):
|
|
291
|
+
let refusal = null;
|
|
292
|
+
if (!holder) refusal = 'holder-unreadable';
|
|
293
|
+
else if (!holderSession || holderSession === 'unknown') refusal = 'holder-session-unknown';
|
|
294
|
+
else if (!ownSessionId) refusal = 'own-session-unresolved';
|
|
295
|
+
else if (holderSession !== ownSessionId) refusal = 'session-mismatch';
|
|
296
|
+
else if (_own.source === 'current_stream') refusal = 'own-session-unproven';
|
|
297
|
+
if (refusal && !force) {
|
|
298
|
+
return { released: false, existed: true, lockFile, holder, staleness, ownSessionId, reason: refusal };
|
|
299
|
+
}
|
|
300
|
+
try { fs.unlinkSync(lockFile); }
|
|
301
|
+
catch (e) {
|
|
302
|
+
if (e.code === 'ENOENT') {
|
|
303
|
+
// Racing releaser/breaker got there first — the desired end state holds.
|
|
304
|
+
return { released: false, existed: false, lockFile, holder, staleness, ownSessionId, reason: 'not-held' };
|
|
305
|
+
}
|
|
306
|
+
return { released: false, existed: true, lockFile, holder, staleness, ownSessionId, reason: 'unlink-failed: ' + e.message };
|
|
307
|
+
}
|
|
308
|
+
return { released: true, existed: true, lockFile, holder, staleness, ownSessionId, reason: refusal ? 'forced (' + refusal + ')' : 'own-session' };
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function checkDispatchScopeGate(targetScopePaths, projectRoot, currentSessionId, force, targetTaskId) {
|
|
312
|
+
targetScopePaths = targetScopePaths || [];
|
|
313
|
+
// TASK_1767: empty scope_paths must not bypass the TASK_1764 same-task-id guard --
|
|
314
|
+
// early-return only when there is neither scope to compare nor a target task id.
|
|
315
|
+
if (targetScopePaths.length === 0 && !targetTaskId) return { blocked: false, collisions: [] };
|
|
316
|
+
let readAllLeases, isPidAlive, isSessionLive;
|
|
317
|
+
try {
|
|
318
|
+
const sl = require(require('path').join(projectRoot, '.specialist', 'tools', 'stream-lease.js'));
|
|
319
|
+
readAllLeases = sl.readAllLeases;
|
|
320
|
+
isPidAlive = sl.isPidAlive;
|
|
321
|
+
isSessionLive = sl.isSessionLive;
|
|
322
|
+
} catch (_e) { return { blocked: false, collisions: [] }; }
|
|
323
|
+
const locksDir = require('path').join(projectRoot, '.kenaz', 'locks');
|
|
324
|
+
const fsL = require('fs');
|
|
325
|
+
const pathMod = require('path');
|
|
326
|
+
const _ownConvForLease = process.env.CLAUDE_CODE_SESSION_ID || null;
|
|
327
|
+
const leases = readAllLeases().filter(function(l) {
|
|
328
|
+
// M1.5 (TASK_1761): use isSessionLive (pid-alive OR heartbeat-fresh) not just isPidAlive
|
|
329
|
+
// TASK_2265: own conversation's lease is self even when session identity is unproven
|
|
330
|
+
// (currentSessionId null); a foreign conversation's lease never is.
|
|
331
|
+
if (_ownConvForLease && l.conversation_id === _ownConvForLease) return false;
|
|
332
|
+
return l.session_id !== currentSessionId && (isSessionLive ? isSessionLive(l) : isPidAlive(l.pid));
|
|
333
|
+
});
|
|
334
|
+
if (leases.length === 0) return { blocked: false, collisions: [] };
|
|
335
|
+
// TASK_1863: self-recognition anchor for claim markers. A marker whose
|
|
336
|
+
// owner_conversation_id matches OUR conversation is a self-claim recorded
|
|
337
|
+
// under a session ALIAS (e.g. a boot ghost lease clobbered current_stream.json
|
|
338
|
+
// before task-api attributed the claim) — never a foreign stream. Skipping it
|
|
339
|
+
// lets a retry proceed after a mid-dispatch failure leaked our own claim.
|
|
340
|
+
// Foreign claims (different conversation, or no conversation id) still block.
|
|
341
|
+
const ownConvId = _getOwnConversationId(projectRoot);
|
|
342
|
+
const collisions = [];
|
|
343
|
+
for (const lease of leases) {
|
|
344
|
+
const claimedTaskIds = [];
|
|
345
|
+
try {
|
|
346
|
+
for (const lf of fsL.readdirSync(locksDir)) {
|
|
347
|
+
if (!lf.startsWith('claim_TASK_') || !lf.endsWith('.json')) continue;
|
|
348
|
+
try {
|
|
349
|
+
const mk = JSON.parse(fsL.readFileSync(pathMod.join(locksDir, lf), 'utf8'));
|
|
350
|
+
if (ownConvId && mk.owner_conversation_id === ownConvId) continue; // TASK_1863: self-claim via alias
|
|
351
|
+
// M1.5 (TASK_1761): liveness via owner SESSION lease, not just owner_pid
|
|
352
|
+
if (mk.owner_session === lease.session_id) {
|
|
353
|
+
const mkLive = isSessionLive ? isSessionLive(lease) : _dispPidAlive(mk.owner_pid);
|
|
354
|
+
if (mkLive) claimedTaskIds.push(lf.slice(6, -5));
|
|
355
|
+
}
|
|
356
|
+
} catch (_e2) {}
|
|
357
|
+
}
|
|
358
|
+
} catch (_e3) {}
|
|
359
|
+
// TASK_1764: same-task-id guard -- if another live stream already claimed this task, block.
|
|
360
|
+
if (targetTaskId && claimedTaskIds.indexOf(targetTaskId) !== -1) {
|
|
361
|
+
collisions.push({ stream_label: lease.label || lease.session_id, task_id: targetTaskId, paths: ['<same-task>'], sameTaskId: true });
|
|
362
|
+
}
|
|
363
|
+
for (const cid of claimedTaskIds) {
|
|
364
|
+
const claimedSP = [];
|
|
365
|
+
try {
|
|
366
|
+
const activeDir = pathMod.join(projectRoot, '.kenaz', 'tasks', 'active');
|
|
367
|
+
for (const e of fsL.readdirSync(activeDir)) {
|
|
368
|
+
if (e.startsWith(cid + '_') || e.startsWith(cid + '.')) {
|
|
369
|
+
const raw = fsL.readFileSync(pathMod.join(activeDir, e), 'utf8');
|
|
370
|
+
const spIdx = raw.indexOf('scope_paths:');
|
|
371
|
+
if (spIdx !== -1) {
|
|
372
|
+
const itemLines = raw.slice(spIdx + 12).split(String.fromCharCode(10));
|
|
373
|
+
for (const il of itemLines) {
|
|
374
|
+
const trimmed = il.trim();
|
|
375
|
+
if (!trimmed.startsWith('-')) break;
|
|
376
|
+
const val = trimmed.slice(1).trim().replace(/^['"]|['"]$/g, '');
|
|
377
|
+
if (val) claimedSP.push(val);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
} catch (_e4) {}
|
|
384
|
+
const cp = targetScopePaths.filter(function(tp) {
|
|
385
|
+
return claimedSP.some(function(csp) { return pathsCollide(tp, csp); });
|
|
386
|
+
});
|
|
387
|
+
if (cp.length > 0) {
|
|
388
|
+
collisions.push({ stream_label: lease.label || lease.session_id, task_id: cid, paths: cp });
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return { blocked: collisions.length > 0 && !force, collisions: collisions };
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function acquireResourceLocks(resources, projectRoot, sessionId, taskId) {
|
|
396
|
+
if (!resources || resources.length === 0) return { acquired: [], failed: [] };
|
|
397
|
+
const locksDir = require('path').join(projectRoot, '.kenaz', 'locks');
|
|
398
|
+
const fsL = require('fs');
|
|
399
|
+
const pathMod = require('path');
|
|
400
|
+
try { fsL.mkdirSync(locksDir, { recursive: true }); } catch (_e) {}
|
|
401
|
+
const acquired = [];
|
|
402
|
+
const failed = [];
|
|
403
|
+
for (const name of resources) {
|
|
404
|
+
const lp = pathMod.join(locksDir, 'resource_' + name + '.lock');
|
|
405
|
+
const content = JSON.stringify({
|
|
406
|
+
owner_session: sessionId || 'unknown',
|
|
407
|
+
owner_pid: process.pid,
|
|
408
|
+
task_id: taskId || null,
|
|
409
|
+
acquired_at: new Date().toISOString()
|
|
410
|
+
}, null, 2);
|
|
411
|
+
try { fsL.writeFileSync(lp, content, { flag: 'wx', encoding: 'utf8' }); acquired.push(name); }
|
|
412
|
+
catch (err) {
|
|
413
|
+
if (err.code !== 'EEXIST') throw err;
|
|
414
|
+
let holder = null;
|
|
415
|
+
try { holder = JSON.parse(fsL.readFileSync(lp, 'utf8')); } catch (_e2) {}
|
|
416
|
+
if (holder && _dispPidAlive(holder.owner_pid)) {
|
|
417
|
+
failed.push({ name: name, holder: holder });
|
|
418
|
+
} else {
|
|
419
|
+
process.stderr.write('WARNING: resource ' + name + ' ORPHAN lock (pid=' +
|
|
420
|
+
(holder && holder.owner_pid) + ' dead). Release: node .specialist/tools/stream-lease.js resource-release --name=' + name + String.fromCharCode(10));
|
|
421
|
+
failed.push({ name: name, holder: holder, orphan: true });
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return { acquired: acquired, failed: failed };
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function releaseResourceLocks(resources, projectRoot) {
|
|
429
|
+
if (!resources || resources.length === 0) return;
|
|
430
|
+
const locksDir = require('path').join(projectRoot, '.kenaz', 'locks');
|
|
431
|
+
for (const name of resources) {
|
|
432
|
+
try { require('fs').unlinkSync(require('path').join(locksDir, 'resource_' + name + '.lock')); } catch (_e) {}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
// TASK_1710: path comparison helper — normalises separators and drive-letter case on Windows
|
|
436
|
+
// so that forward-slash paths (C:/...) match backslash paths (C:...) and mixed-case drives.
|
|
437
|
+
// Uses path.resolve (canonicalises separators) + toLowerCase on win32 + path.relative === ''
|
|
438
|
+
// to confirm identity (also handles trailing-slash edge cases).
|
|
439
|
+
function samePath(a, b) {
|
|
440
|
+
if (!a || !b) return false;
|
|
441
|
+
let ra = path.resolve(a);
|
|
442
|
+
let rb = path.resolve(b);
|
|
443
|
+
if (process.platform === 'win32') {
|
|
444
|
+
ra = ra.toLowerCase();
|
|
445
|
+
rb = rb.toLowerCase();
|
|
446
|
+
}
|
|
447
|
+
return path.relative(ra, rb) === '';
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// ─────────────────────────────────────────
|
|
451
|
+
// Yggdrasil 廣播(lazy load, fire-and-forget)
|
|
452
|
+
// ─────────────────────────────────────────
|
|
453
|
+
|
|
454
|
+
let _supabaseClient = null;
|
|
455
|
+
let _taskSync = null;
|
|
456
|
+
let _commitSync = null;
|
|
457
|
+
function getSupabaseClient(projectPath) {
|
|
458
|
+
if (_supabaseClient === undefined) return null;
|
|
459
|
+
if (!_supabaseClient) try { _supabaseClient = require('./supabase-client'); } catch { _supabaseClient = undefined; return null; }
|
|
460
|
+
return _supabaseClient.getClient(projectPath);
|
|
461
|
+
}
|
|
462
|
+
function getTaskSync() {
|
|
463
|
+
if (_taskSync === undefined) return null;
|
|
464
|
+
if (!_taskSync) try { _taskSync = require('./task-sync'); } catch { _taskSync = undefined; return null; }
|
|
465
|
+
return _taskSync;
|
|
466
|
+
}
|
|
467
|
+
function getCommitSync() {
|
|
468
|
+
if (_commitSync === undefined) return null;
|
|
469
|
+
if (!_commitSync) try { _commitSync = require('./commit-sync'); } catch { _commitSync = undefined; return null; }
|
|
470
|
+
return _commitSync;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* 同步 commit 到 kenaz_commits。
|
|
475
|
+
* 回傳 Promise(await 時確保完成,或 fire-and-forget)。
|
|
476
|
+
*/
|
|
477
|
+
function syncCommit(taskId, projectPath) {
|
|
478
|
+
try {
|
|
479
|
+
const cs = getCommitSync();
|
|
480
|
+
if (!cs) return Promise.resolve();
|
|
481
|
+
return cs.syncLatestCommit({ taskId, projectPath }).catch(() => {});
|
|
482
|
+
} catch { return Promise.resolve(); }
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* 廣播 kenaz_status。
|
|
487
|
+
* 回傳 Promise — caller 可 await 確保完成(cleanup 場景),
|
|
488
|
+
* 或 fire-and-forget(上線廣播場景)。
|
|
489
|
+
*/
|
|
490
|
+
function broadcastStatus(projectPath, updates) {
|
|
491
|
+
try {
|
|
492
|
+
const sb = getSupabaseClient(projectPath);
|
|
493
|
+
if (!sb) return Promise.resolve();
|
|
494
|
+
const { client, config } = sb;
|
|
495
|
+
const ts = getTaskSync();
|
|
496
|
+
const project = ts?.resolveProjectName?.(projectPath || ROOT) || path.basename(ROOT);
|
|
497
|
+
return client.from('kenaz_status').upsert({
|
|
498
|
+
node_name: config.node_name,
|
|
499
|
+
project,
|
|
500
|
+
...updates,
|
|
501
|
+
}, { onConflict: 'node_name,project' }).then(() => {}).catch(() => {});
|
|
502
|
+
} catch { return Promise.resolve(); }
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// ─────────────────────────────────────────
|
|
506
|
+
// Active dispatch registry(Dashboard Agent Monitor 用)
|
|
507
|
+
// ─────────────────────────────────────────
|
|
508
|
+
|
|
509
|
+
const ACTIVE_DISPATCH_FILE = path.join(ROOT, '.formation', '.active-dispatches.json');
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* TASK_1833: THE single isolation-routing decision for a dispatch. Consumed by
|
|
513
|
+
* the real sub-agent path — do not copy the check:
|
|
514
|
+
* - getSubagentDispatchParams (real sub-agent routing — ENFORCED)
|
|
515
|
+
* History: the cross-project check has been duplicated/decorative twice before
|
|
516
|
+
* (TASK_1672 omitted isolation on the real path; the old selectDispatchPath
|
|
517
|
+
* cross_project_cwd guard never influenced routing). Third recurrence of
|
|
518
|
+
* copy-the-check documented in rune_9fe1bdb57d834750ac443b1d7f09e965 /
|
|
519
|
+
* rune_eb53038640e246dea32764f89b18bfa1's point (5) — call this, never copy it.
|
|
520
|
+
* Modes:
|
|
521
|
+
* agent_tool_worktree — same-project: Agent tool isolation:'worktree'
|
|
522
|
+
* (harness-managed worktree in the conversation repo).
|
|
523
|
+
* target_repo_worktree — cross-project + useWorktree: dispatcher pre-creates
|
|
524
|
+
* a worktree INSIDE the target repo (the Agent tool's
|
|
525
|
+
* own worktree derives from the conversation cwd repo
|
|
526
|
+
* and cannot isolate another repo — TASK_1672/1593).
|
|
527
|
+
* serial_lock — cross-project + !useWorktree (single-editor-bound
|
|
528
|
+
* projects like Unity): shared working tree, WRITES
|
|
529
|
+
* SERIALIZED via the per-project dispatch lock.
|
|
530
|
+
* direct_no_git — cross-project target WITHOUT a .git dir: the entire
|
|
531
|
+
* hazard class this decision guards (index.lock
|
|
532
|
+
* contention, commits silently vanishing, worktrees)
|
|
533
|
+
* is git-level and cannot occur — keep the plain
|
|
534
|
+
* direct-write behavior (no worktree, no lock).
|
|
535
|
+
* TASK_2176: also surfaces `verifyOffline` (the project's .kenaz/project.yaml
|
|
536
|
+
* `verify_offline: <command>` key, or null) regardless of isolation mode —
|
|
537
|
+
* same-project dispatches can declare it too, not only cross-project ones.
|
|
538
|
+
* The isolation decision itself (worktree vs serial_lock) is UNCHANGED by
|
|
539
|
+
* this key; verifyOffline only rides along so the caller can (a) hand the
|
|
540
|
+
* worktree agent a non-authoritative self-check instruction and (b) know,
|
|
541
|
+
* at landing time, that the authoritative run must happen serialized on the
|
|
542
|
+
* main tree (see verify-and-land.js stepVerifyOffline — a SEPARATE lock from
|
|
543
|
+
* the serial_lock dispatch lock above, scoped to just the verify command).
|
|
544
|
+
* @param {object} opts
|
|
545
|
+
* @param {string|null} opts.projectPath
|
|
546
|
+
* @param {boolean|null} [opts.useWorktreeOverride] - dispatch-time toggle (CLI --use-worktree)
|
|
547
|
+
* @returns {{ isCrossProject: boolean, mode: string, useWorktree: boolean, source: string, verifyOffline: string|null }}
|
|
548
|
+
*/
|
|
549
|
+
function resolveDispatchIsolation({ projectPath = null, useWorktreeOverride = null } = {}) {
|
|
550
|
+
// TASK_1710 semantics: samePath, not raw string compare (separator/case).
|
|
551
|
+
const isCrossProject = !!(projectPath && !samePath(projectPath, ROOT));
|
|
552
|
+
const verifyOffline = getVerifyOfflineCommand(projectPath);
|
|
553
|
+
if (!isCrossProject) {
|
|
554
|
+
return { isCrossProject, mode: 'agent_tool_worktree', useWorktree: true, source: 'same-project', verifyOffline };
|
|
555
|
+
}
|
|
556
|
+
if (!fs.existsSync(path.join(projectPath, '.git'))) {
|
|
557
|
+
return { isCrossProject, mode: 'direct_no_git', useWorktree: false, source: 'no-git-target', verifyOffline };
|
|
558
|
+
}
|
|
559
|
+
const d = resolveWorktreeDecision(projectPath, useWorktreeOverride);
|
|
560
|
+
return {
|
|
561
|
+
isCrossProject,
|
|
562
|
+
mode: d.useWorktree ? 'target_repo_worktree' : 'serial_lock',
|
|
563
|
+
useWorktree: d.useWorktree,
|
|
564
|
+
source: d.source,
|
|
565
|
+
verifyOffline,
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
function readActiveDispatches() {
|
|
570
|
+
try {
|
|
571
|
+
if (fs.existsSync(ACTIVE_DISPATCH_FILE)) {
|
|
572
|
+
return JSON.parse(fs.readFileSync(ACTIVE_DISPATCH_FILE, 'utf-8'));
|
|
573
|
+
}
|
|
574
|
+
} catch { /* corrupted file */ }
|
|
575
|
+
return [];
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
function writeActiveDispatches(list) {
|
|
579
|
+
try {
|
|
580
|
+
fs.writeFileSync(ACTIVE_DISPATCH_FILE, JSON.stringify(list, null, 2));
|
|
581
|
+
} catch { /* ignore */ }
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function registerDispatch({ sessionId, logPath, taskId, formation, projectPath: pp }) {
|
|
585
|
+
const list = readActiveDispatches();
|
|
586
|
+
const nextEntry = {
|
|
587
|
+
sessionId,
|
|
588
|
+
logPath,
|
|
589
|
+
taskId,
|
|
590
|
+
formation,
|
|
591
|
+
startedAt: new Date().toISOString(),
|
|
592
|
+
projectPath: pp || null,
|
|
593
|
+
};
|
|
594
|
+
const existingIndex = list.findIndex(d => d.sessionId === sessionId);
|
|
595
|
+
if (existingIndex >= 0) {
|
|
596
|
+
const mergedEntry = {
|
|
597
|
+
...list[existingIndex],
|
|
598
|
+
startedAt: list[existingIndex].startedAt || nextEntry.startedAt,
|
|
599
|
+
};
|
|
600
|
+
for (const [key, value] of Object.entries(nextEntry)) {
|
|
601
|
+
if (key === 'startedAt') continue;
|
|
602
|
+
if (value !== null && value !== undefined) {
|
|
603
|
+
mergedEntry[key] = value;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
list[existingIndex] = mergedEntry;
|
|
607
|
+
} else {
|
|
608
|
+
list.push(nextEntry);
|
|
609
|
+
}
|
|
610
|
+
writeActiveDispatches(list);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function unregisterDispatch(sessionId) {
|
|
614
|
+
const list = readActiveDispatches().filter(d => d.sessionId !== sessionId);
|
|
615
|
+
if (list.length === 0) {
|
|
616
|
+
try { fs.unlinkSync(ACTIVE_DISPATCH_FILE); } catch { /* ignore */ }
|
|
617
|
+
} else {
|
|
618
|
+
writeActiveDispatches(list);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// ─────────────────────────────────────────
|
|
623
|
+
// Cortex Context 注入(dispatch 前自動注入相關檔案摘要)
|
|
624
|
+
// ─────────────────────────────────────────
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* 從 scope_paths 提取相關檔案的簡要 context。
|
|
628
|
+
* Cortex 不可用時的 graceful fallback — 直接讀取檔案頭。
|
|
629
|
+
*
|
|
630
|
+
* 行為契約(TASK_1822 確認,回應外部 bug 回報的求證):
|
|
631
|
+
* - 目錄條目:**完全不展開**,直接跳過(不 inline 其下任何檔案)。
|
|
632
|
+
* scope_paths 全是目錄時,prompt 只會出現路徑清單、不會有本區段內容。
|
|
633
|
+
* - 檔案條目:inline 前 30 行,且整個 preview 另受位元組上限
|
|
634
|
+
* (CORTEX_PREVIEW_MAX_BYTES)保護 — 30 是「行數」上限不是「位元組」
|
|
635
|
+
* 上限,單行極長的檔案(.min.js、無換行大檔)曾借道灌入數百 KB;
|
|
636
|
+
* 超過位元組上限會截斷並明確標註。
|
|
637
|
+
* - 二進位檔(開頭 sniff 區含 NUL 位元組):跳過內容但保留區段標題
|
|
638
|
+
* 註明已跳過 — 靜默跳過會讓使用者誤以為內容已被看過。
|
|
639
|
+
* 偵測方式選 NUL-byte sniff 而非副檔名白名單:零依賴、不需維護
|
|
640
|
+
* 清單,且對無副檔名/罕見副檔名的二進位一樣有效(YAGNI)。
|
|
641
|
+
*
|
|
642
|
+
* @param {string[]} scopePaths - 任務的 scope_paths
|
|
643
|
+
* @param {string|null} projectPath - 子專案路徑
|
|
644
|
+
* @returns {string} 注入到 prompt 的 context 文字,空字串表示無可用 context
|
|
645
|
+
*/
|
|
646
|
+
const CORTEX_PREVIEW_MAX_LINES = 30;
|
|
647
|
+
// thrift: 8KB 對 30 行綽綽有餘(平均 273 bytes/行);若未來要 inline 更多行再調
|
|
648
|
+
const CORTEX_PREVIEW_MAX_BYTES = 8 * 1024;
|
|
649
|
+
const CORTEX_BINARY_SNIFF_BYTES = 8 * 1024;
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* 讀取檔案開頭 sniff 區,含 NUL 位元組即視為二進位。
|
|
653
|
+
* PNG/JPEG/EXE 等格式的頭部幾乎必含 0x00;UTF-8 文字合法內容不含 NUL。
|
|
654
|
+
*/
|
|
655
|
+
function isBinaryFile(fullPath) {
|
|
656
|
+
const fd = fs.openSync(fullPath, 'r');
|
|
657
|
+
try {
|
|
658
|
+
const buf = Buffer.alloc(CORTEX_BINARY_SNIFF_BYTES);
|
|
659
|
+
const bytesRead = fs.readSync(fd, buf, 0, buf.length, 0);
|
|
660
|
+
return buf.subarray(0, bytesRead).includes(0);
|
|
661
|
+
} finally {
|
|
662
|
+
fs.closeSync(fd);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
function buildCortexContext(scopePaths, projectPath) {
|
|
667
|
+
if (!scopePaths || scopePaths.length === 0) return '';
|
|
668
|
+
|
|
669
|
+
const projectRoot = projectPath || ROOT;
|
|
670
|
+
const sections = [];
|
|
671
|
+
|
|
672
|
+
for (const sp of scopePaths) {
|
|
673
|
+
const fullPath = path.resolve(projectRoot, sp);
|
|
674
|
+
if (!fs.existsSync(fullPath)) continue;
|
|
675
|
+
|
|
676
|
+
try {
|
|
677
|
+
const stat = fs.statSync(fullPath);
|
|
678
|
+
if (stat.isDirectory()) continue;
|
|
679
|
+
|
|
680
|
+
if (isBinaryFile(fullPath)) {
|
|
681
|
+
// 註明已跳過而非靜默略過 — 讓 agent 知道這個 scope 檔案沒被預覽
|
|
682
|
+
sections.push(`### ${sp} (binary file, ${stat.size} bytes — content preview skipped)`);
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// 只讀前 CORTEX_PREVIEW_MAX_BYTES(+1) 位元組(經 fd),不整檔載入記憶體
|
|
687
|
+
let head;
|
|
688
|
+
{
|
|
689
|
+
const fd = fs.openSync(fullPath, 'r');
|
|
690
|
+
try {
|
|
691
|
+
const buf = Buffer.alloc(CORTEX_PREVIEW_MAX_BYTES + 1);
|
|
692
|
+
head = buf.subarray(0, fs.readSync(fd, buf, 0, buf.length, 0));
|
|
693
|
+
} finally {
|
|
694
|
+
fs.closeSync(fd);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
const partial = head.length > CORTEX_PREVIEW_MAX_BYTES; // 檔案超過上限,總行數未知
|
|
698
|
+
const content = head.toString('utf-8');
|
|
699
|
+
const lines = content.split('\n');
|
|
700
|
+
if (partial && lines.length > 1) lines.pop(); // 丟掉被截斷的最後一行
|
|
701
|
+
let preview = lines.slice(0, CORTEX_PREVIEW_MAX_LINES).join('\n');
|
|
702
|
+
const totalLines = lines.length;
|
|
703
|
+
|
|
704
|
+
// 位元組上限:防單行極長檔案(.min.js、無換行大檔)繞過行數上限
|
|
705
|
+
let byteTruncated = false;
|
|
706
|
+
if (Buffer.byteLength(preview, 'utf-8') > CORTEX_PREVIEW_MAX_BYTES) {
|
|
707
|
+
preview = Buffer.from(preview, 'utf-8')
|
|
708
|
+
.subarray(0, CORTEX_PREVIEW_MAX_BYTES)
|
|
709
|
+
.toString('utf-8')
|
|
710
|
+
.replace(/�+$/, ''); // 去掉截斷產生的不完整 multibyte 殘片
|
|
711
|
+
byteTruncated = true;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const marker = (byteTruncated || (partial && totalLines <= CORTEX_PREVIEW_MAX_LINES))
|
|
715
|
+
? `\n... (truncated at ${CORTEX_PREVIEW_MAX_BYTES} bytes)`
|
|
716
|
+
: (totalLines > CORTEX_PREVIEW_MAX_LINES ? '\n... (truncated)' : '');
|
|
717
|
+
|
|
718
|
+
// partial 時只讀了開頭,行數僅為下限,故標 N+
|
|
719
|
+
sections.push(
|
|
720
|
+
`### ${sp} (${totalLines}${partial ? '+' : ''} lines)\n` +
|
|
721
|
+
'```\n' + preview + marker + '\n```'
|
|
722
|
+
);
|
|
723
|
+
} catch (err) {
|
|
724
|
+
// 註明已跳過而非靜默略過(與二進位分支一致)
|
|
725
|
+
sections.push(`### ${sp} (unreadable - preview skipped: ${(err && err.code) || 'error'})`);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
if (sections.length === 0) return '';
|
|
730
|
+
|
|
731
|
+
return (
|
|
732
|
+
'\n## Cortex Context (Related Files Preview)\n' +
|
|
733
|
+
'The following files are in your scope. Review them before making changes.\n\n' +
|
|
734
|
+
sections.join('\n\n')
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// ─────────────────────────────────────────
|
|
739
|
+
// TASK_1998 R1: dispatch-prompt telemetry
|
|
740
|
+
// ─────────────────────────────────────────
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Append one structured JSONL line to .kenaz/specialist/dispatch_prompt_stats.jsonl —
|
|
744
|
+
* one per sub-agent dispatch (getSubagentDispatchParams). Mirrors
|
|
745
|
+
* post-complete.js's appendPhase9OutcomeLog: same project-pinning
|
|
746
|
+
* (projectPath || ROOT), same best-effort append, never throws.
|
|
747
|
+
*
|
|
748
|
+
* Format: { ts, task_id, rigor, complexity, formation, prompt_bytes, sections: [{title, bytes}], model, model_source }
|
|
749
|
+
* dev/scripts/dispatch-stats.js reads this to print p50/p90 prompt_bytes per (rigor, complexity).
|
|
750
|
+
* model_source (TASK_1998 R3): 'dashboard'|'dashboard-by-rigor'|'cli' — which
|
|
751
|
+
* layer of resolveDispatchModelForRigor() picked `model`. Optional (older
|
|
752
|
+
* callers, and the non-subagent path, omit it — reader must tolerate absence).
|
|
753
|
+
* complexity (TASK_1998 two-axis policy): the normalized 'simple'|'medium'|'complex'
|
|
754
|
+
* CONTEXT-volume key (extractComplexity() default). Optional for older readers.
|
|
755
|
+
*/
|
|
756
|
+
function appendDispatchPromptStats({ taskId, rigor, complexity, formation, promptText, model, modelSource, projectPath }) {
|
|
757
|
+
const root = projectPath || ROOT;
|
|
758
|
+
const dir = path.join(root, '.kenaz', 'specialist');
|
|
759
|
+
try {
|
|
760
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
761
|
+
const line = JSON.stringify({
|
|
762
|
+
ts: new Date().toISOString(),
|
|
763
|
+
task_id: taskId || null,
|
|
764
|
+
rigor: rigor || 'medium',
|
|
765
|
+
complexity: complexity || 'medium',
|
|
766
|
+
formation,
|
|
767
|
+
prompt_bytes: Buffer.byteLength(promptText || '', 'utf-8'),
|
|
768
|
+
sections: splitPromptSections(promptText || ''),
|
|
769
|
+
model,
|
|
770
|
+
model_source: modelSource || null,
|
|
771
|
+
});
|
|
772
|
+
fs.appendFileSync(path.join(dir, 'dispatch_prompt_stats.jsonl'), line + '\n', 'utf8');
|
|
773
|
+
} catch { /* best-effort — telemetry must never block dispatch */ }
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// ─────────────────────────────────────────
|
|
777
|
+
// 依賴預檢
|
|
778
|
+
// ─────────────────────────────────────────
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* 檢查任務的依賴是否都已完成。
|
|
782
|
+
* 掃描 done/ + archived/ + completed/。
|
|
783
|
+
*
|
|
784
|
+
* @param {string} taskData - JSON or YAML 任務文本
|
|
785
|
+
* @param {string|null} projectPath - 子專案路徑(null = core)
|
|
786
|
+
* @returns {{ blocked: boolean, unmet: string[] }}
|
|
787
|
+
*/
|
|
788
|
+
function checkDependencies(taskData, projectPath) {
|
|
789
|
+
let deps = [];
|
|
790
|
+
try {
|
|
791
|
+
const parsed = JSON.parse(taskData);
|
|
792
|
+
deps = parsed.dependencies || [];
|
|
793
|
+
} catch {
|
|
794
|
+
// Try YAML key extraction as fallback
|
|
795
|
+
const match = taskData.match(/^dependencies:\s*\n((?:\s+-\s+\S+\n?)+)/m);
|
|
796
|
+
if (match) {
|
|
797
|
+
deps = match[1].split('\n')
|
|
798
|
+
.map(l => l.trim().replace(/^-\s*/, ''))
|
|
799
|
+
.filter(Boolean);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
if (deps.length === 0) return { blocked: false, unmet: [] };
|
|
804
|
+
|
|
805
|
+
// Collect completed task IDs from all relevant directories
|
|
806
|
+
const completedIds = new Set();
|
|
807
|
+
const blockedIds = new Set();
|
|
808
|
+
const scanDir = (dir, bucket) => {
|
|
809
|
+
if (!dir || !fs.existsSync(dir)) return;
|
|
810
|
+
try {
|
|
811
|
+
for (const f of fs.readdirSync(dir)) {
|
|
812
|
+
if (f.startsWith('TASK_')) {
|
|
813
|
+
const base = f.replace(/\.yaml$/, '');
|
|
814
|
+
bucket.add(base.split('_').slice(0, 2).join('_'));
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
} catch { /* ignore */ }
|
|
818
|
+
};
|
|
819
|
+
|
|
820
|
+
const projectRoot = projectPath || ROOT;
|
|
821
|
+
|
|
822
|
+
// New system: scan BOTH .kenaz/tasks/ and .collaboration/tasks/
|
|
823
|
+
// (Core project may have both directories)
|
|
824
|
+
const kenazTasks = path.join(projectRoot, '.kenaz', 'tasks');
|
|
825
|
+
const collabTasks = path.join(projectRoot, '.collaboration', 'tasks');
|
|
826
|
+
|
|
827
|
+
for (const base of [kenazTasks, collabTasks]) {
|
|
828
|
+
scanDir(path.join(base, 'done'), completedIds);
|
|
829
|
+
scanDir(path.join(base, 'archived'), completedIds);
|
|
830
|
+
scanDir(path.join(base, 'blocked'), blockedIds);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// Legacy system: completed/
|
|
834
|
+
scanDir(path.join(projectRoot, 'dev', 'pipeline', 'completed'), completedIds);
|
|
835
|
+
|
|
836
|
+
const blockedDeps = deps.filter(dep => blockedIds.has(dep));
|
|
837
|
+
const unmet = deps.filter(dep => !completedIds.has(dep));
|
|
838
|
+
return { blocked: unmet.length > 0, unmet, blockedDeps };
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// ─────────────────────────────────────────
|
|
842
|
+
// 調度主函數
|
|
843
|
+
// ─────────────────────────────────────────
|
|
844
|
+
|
|
845
|
+
async function dispatch(options) {
|
|
846
|
+
const {
|
|
847
|
+
formation = 'unit',
|
|
848
|
+
skill = 'do',
|
|
849
|
+
task,
|
|
850
|
+
output = null,
|
|
851
|
+
dryRun = false,
|
|
852
|
+
projectPath = null
|
|
853
|
+
} = options;
|
|
854
|
+
|
|
855
|
+
const sessionId = generateSessionId();
|
|
856
|
+
|
|
857
|
+
// 1. 載入技能定義
|
|
858
|
+
const skillDef = loadSkill(formation, skill);
|
|
859
|
+
|
|
860
|
+
// 2. 載入任務(如果是 TASK_ID,支援 projectPath)
|
|
861
|
+
const loadOpts = projectPath ? { projectPath } : undefined;
|
|
862
|
+
const taskData = task && task.startsWith('TASK_') ? loadTask(task, loadOpts) : null;
|
|
863
|
+
const taskInput = task || '';
|
|
864
|
+
|
|
865
|
+
// 2.5 依賴預檢:確認所有依賴都已完成
|
|
866
|
+
if (taskData) {
|
|
867
|
+
const depCheck = checkDependencies(taskData, projectPath);
|
|
868
|
+
if (depCheck.blocked) {
|
|
869
|
+
console.error(`❌ Dispatch blocked: ${taskInput} has unmet dependencies`);
|
|
870
|
+
for (const dep of depCheck.unmet) {
|
|
871
|
+
if (depCheck.blockedDeps && depCheck.blockedDeps.includes(dep)) {
|
|
872
|
+
console.error(` ??${dep} ??blocked`);
|
|
873
|
+
continue;
|
|
874
|
+
}
|
|
875
|
+
console.error(` ⛔ ${dep} — not in done/completed`);
|
|
876
|
+
}
|
|
877
|
+
console.error(` → Complete the dependencies first, or use --force to override`);
|
|
878
|
+
if (!options.force) {
|
|
879
|
+
process.exitCode = 1;
|
|
880
|
+
return null;
|
|
881
|
+
}
|
|
882
|
+
console.warn(` ⚠️ --force: dispatching despite unmet dependencies`);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// 3. 組裝 prompt(注入 projectPath context + Yggdrasil network context)
|
|
887
|
+
const promptOptions = {};
|
|
888
|
+
if (projectPath) {
|
|
889
|
+
promptOptions.projectPath = projectPath;
|
|
890
|
+
}
|
|
891
|
+
if (taskInput && taskInput.startsWith('TASK_')) {
|
|
892
|
+
promptOptions.taskId = taskInput;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// Yggdrasil: 查詢遠端節點狀態,注入 prompt 讓 Agent 知道其他人在做什麼
|
|
896
|
+
const taskScopePaths = (() => {
|
|
897
|
+
try {
|
|
898
|
+
if (!taskData) return [];
|
|
899
|
+
const parsed = JSON.parse(taskData);
|
|
900
|
+
return parsed.scope_paths || [];
|
|
901
|
+
} catch { return []; }
|
|
902
|
+
})();
|
|
903
|
+
try {
|
|
904
|
+
const ts = getTaskSync();
|
|
905
|
+
if (ts) {
|
|
906
|
+
const [onlineNodes, remoteTasks] = await Promise.all([
|
|
907
|
+
ts.getOnlineNodes(projectPath).catch(() => []),
|
|
908
|
+
ts.getRemoteActiveTasks(projectPath).catch(() => []),
|
|
909
|
+
]);
|
|
910
|
+
if (onlineNodes.length > 0 || remoteTasks.length > 0) {
|
|
911
|
+
const sb = getSupabaseClient(projectPath);
|
|
912
|
+
promptOptions.yggdrasilContext = {
|
|
913
|
+
onlineNodes,
|
|
914
|
+
remoteTasks,
|
|
915
|
+
myNodeName: sb?.config?.node_name || 'unknown',
|
|
916
|
+
myScopePaths: taskScopePaths,
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
} catch { /* Yggdrasil context is best-effort */ }
|
|
921
|
+
|
|
922
|
+
let prompt = buildPrompt(skillDef, taskInput, taskData, promptOptions);
|
|
923
|
+
|
|
924
|
+
// 3.5 Cortex Context 注入:將 scope_paths 相關檔案摘要注入 prompt
|
|
925
|
+
// TASK_1998: "Related Files Preview" is CONTEXT volume, driven by
|
|
926
|
+
// complexity — simple/medium drop it entirely (it was 3.9 KB of mostly
|
|
927
|
+
// low-relevance file-head previews on the measured TASK_1992 prompt),
|
|
928
|
+
// complex keeps it.
|
|
929
|
+
const _dietProfile = promptProfile({ rigor: extractRigor(taskData), complexity: extractComplexity(taskData) });
|
|
930
|
+
if (typeof prompt === 'string' && taskScopePaths.length > 0 && !_dietProfile.skipRelatedFilesPreview) {
|
|
931
|
+
const cortexCtx = buildCortexContext(taskScopePaths, projectPath);
|
|
932
|
+
if (cortexCtx) {
|
|
933
|
+
prompt = prompt + '\n' + cortexCtx;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
console.log(`⚔️ Formation Dispatch`);
|
|
938
|
+
console.log(` Formation: ${formation}`);
|
|
939
|
+
console.log(` Skill: ${skill}`);
|
|
940
|
+
console.log(` Task: ${taskInput.slice(0, 60)}${taskInput.length > 60 ? '...' : ''}`);
|
|
941
|
+
console.log(` Session: ${sessionId}`);
|
|
942
|
+
if (projectPath) console.log(` Project: ${projectPath}`);
|
|
943
|
+
|
|
944
|
+
// 4. 確保子專案 git 已就緒(TASK_2274: dry-run 不得 git init — 只回報)
|
|
945
|
+
if (dryRun) {
|
|
946
|
+
if (projectPath && !fs.existsSync(path.join(projectPath, '.git'))) console.log(' [dry-run] would git init: ' + projectPath);
|
|
947
|
+
} else {
|
|
948
|
+
ensureGitReady(projectPath);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// 4.5 遠端衝突預檢(警告但不阻擋)
|
|
952
|
+
const scopePaths = taskData?.scope_paths || [];
|
|
953
|
+
if (scopePaths.length > 0) {
|
|
954
|
+
try {
|
|
955
|
+
if (isCacheStale()) {
|
|
956
|
+
await refreshCache(projectPath);
|
|
957
|
+
}
|
|
958
|
+
const taskConflict = hasRemoteConflict(scopePaths);
|
|
959
|
+
if (taskConflict.conflict) {
|
|
960
|
+
console.log(`\n ⚠️ Remote conflict: ${taskConflict.conflictNode} is working on ${taskConflict.conflictTask}`);
|
|
961
|
+
}
|
|
962
|
+
const fileConflict = hasRemoteFileConflict(scopePaths);
|
|
963
|
+
if (fileConflict.conflict) {
|
|
964
|
+
console.log(` ⚠️ Remote file conflict: ${fileConflict.conflictNode} is touching ${fileConflict.conflictFile}`);
|
|
965
|
+
}
|
|
966
|
+
} catch {
|
|
967
|
+
// 衝突檢查失敗不阻擋 dispatch
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
|
|
972
|
+
// M1 (TASK_1758): Dispatch-time scope gate + resource lease
|
|
973
|
+
{
|
|
974
|
+
const _sgRoot = projectPath || ROOT;
|
|
975
|
+
const _sgSession = _getProvenSessionId(_sgRoot); // TASK_2265: proven identity only
|
|
976
|
+
const _sgPaths = (() => { try { return taskData ? JSON.parse(taskData).scope_paths || [] : []; } catch { return []; } })();
|
|
977
|
+
const _sgResult = checkDispatchScopeGate(_sgPaths, _sgRoot, _sgSession, !!options.force, taskInput);
|
|
978
|
+
if (_sgResult.collisions.length > 0) {
|
|
979
|
+
for (const col of _sgResult.collisions) {
|
|
980
|
+
const pl = col.paths.slice(0,3).join(', ') + (col.paths.length > 3 ? ' +' + (col.paths.length-3) + ' more' : '');
|
|
981
|
+
if (_sgResult.blocked) {
|
|
982
|
+
console.error(' Scope conflict with stream ' + col.stream_label + ' (task ' + col.task_id + '): ' + pl);
|
|
983
|
+
} else {
|
|
984
|
+
console.warn(' WARNING scope conflict with stream ' + col.stream_label + ' (task ' + col.task_id + '): ' + pl);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
if (_sgResult.blocked) {
|
|
988
|
+
console.error('Dispatch blocked: scope overlap with live stream(s). Use --force to override.');
|
|
989
|
+
process.exitCode = 1;
|
|
990
|
+
return null;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
// TASK_1863: adopt our own claim marker (written by the chain's pre-claim /
|
|
994
|
+
// move→active) so a post-gate rejection below releases it — TASK_1833
|
|
995
|
+
// late-failure semantics extended from resource leases to the claim marker.
|
|
996
|
+
const _sgResources = (() => { try { return taskData ? JSON.parse(taskData).resources || [] : []; } catch { return []; } })();
|
|
997
|
+
// TASK_2274: dry-run takes no claim adoption / resource locks (mirrors the subagent path)
|
|
998
|
+
const _sgClaim = dryRun ? null : adoptSelfClaimMarker(taskInput, _sgRoot, _sgSession);
|
|
999
|
+
if (_sgResources.length > 0 && dryRun) {
|
|
1000
|
+
console.log(' [dry-run] resource locks NOT acquired: ' + _sgResources.join(', '));
|
|
1001
|
+
} else if (_sgResources.length > 0) {
|
|
1002
|
+
const _sgLock = acquireResourceLocks(_sgResources, _sgRoot, _sgSession, taskInput);
|
|
1003
|
+
if (_sgLock.failed.length > 0) {
|
|
1004
|
+
for (const fail of _sgLock.failed) {
|
|
1005
|
+
const hi = fail.holder ? ' (session=' + fail.holder.owner_session + ', task=' + fail.holder.task_id + ')' : '';
|
|
1006
|
+
console.error((fail.orphan ? 'WARNING' : 'ERROR') + ': resource ' + fail.name + (fail.orphan ? ' ORPHAN lock' : ' busy') + hi);
|
|
1007
|
+
}
|
|
1008
|
+
releaseResourceLocks(_sgLock.acquired, _sgRoot);
|
|
1009
|
+
if (!options.force) { releaseAdoptedClaimMarker(_sgClaim); console.error('Dispatch blocked: resource lock conflict. Use --force to override.'); process.exitCode = 1; return null; }
|
|
1010
|
+
console.warn('WARNING: proceeding despite resource lock conflicts (--force).');
|
|
1011
|
+
} else if (_sgLock.acquired.length > 0) {
|
|
1012
|
+
console.log(' Resource locks acquired: ' + _sgLock.acquired.join(', '));
|
|
1013
|
+
console.log(' (Release after merge: node .specialist/tools/stream-lease.js resource-release --name=<resource>)');
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// 5. Dry run
|
|
1019
|
+
if (dryRun) {
|
|
1020
|
+
return handleDryRun(formation, prompt);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
// 5.5 Yggdrasil: 廣播上線狀態
|
|
1024
|
+
// Note: cleanup 由 child.on('close') 處理(await 確保完成)
|
|
1025
|
+
// process.on('exit') 不支援 async,不適合做 Supabase cleanup
|
|
1026
|
+
if (formation !== 'legion') {
|
|
1027
|
+
broadcastStatus(projectPath, {
|
|
1028
|
+
is_online: true,
|
|
1029
|
+
current_task: taskInput || null,
|
|
1030
|
+
touching_files: scopePaths || [],
|
|
1031
|
+
});
|
|
1032
|
+
|
|
1033
|
+
// Yggdrasil: 同步任務狀態為 active
|
|
1034
|
+
if (taskInput.startsWith('TASK_')) {
|
|
1035
|
+
const ts = getTaskSync();
|
|
1036
|
+
if (ts) {
|
|
1037
|
+
const sb = getSupabaseClient(projectPath);
|
|
1038
|
+
const myNode = sb?.config?.node_name || null;
|
|
1039
|
+
ts.syncTaskStatus({
|
|
1040
|
+
taskId: taskInput,
|
|
1041
|
+
status: 'active',
|
|
1042
|
+
claimedBy: myNode,
|
|
1043
|
+
scopePaths: taskScopePaths,
|
|
1044
|
+
projectPath,
|
|
1045
|
+
}).catch(() => {});
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// Signal handlers: 盡力 cleanup(best-effort,process 會等 promise)
|
|
1050
|
+
const handleSignal = (code) => {
|
|
1051
|
+
broadcastStatus(projectPath, { current_task: null, touching_files: [] })
|
|
1052
|
+
.finally(() => process.exit(code));
|
|
1053
|
+
};
|
|
1054
|
+
process.on('SIGINT', () => handleSignal(130));
|
|
1055
|
+
process.on('SIGTERM', () => handleSignal(143));
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
// 6. 根據陣型執行(傳入 projectPath + sessionId for registry)
|
|
1059
|
+
return execute(formation, { prompt, skill, sessionId, output, projectPath, taskId: taskInput });
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
// ─────────────────────────────────────────
|
|
1063
|
+
// Dry Run
|
|
1064
|
+
// ─────────────────────────────────────────
|
|
1065
|
+
|
|
1066
|
+
function handleDryRun(formation, prompt) {
|
|
1067
|
+
if (formation === 'squad' && Array.isArray(prompt)) {
|
|
1068
|
+
console.log(`\n--- SQUAD PROMPTS (${prompt.length} members) ---\n`);
|
|
1069
|
+
for (const m of prompt) {
|
|
1070
|
+
console.log(`=== Member: ${m.memberId} (skill: ${m.skill}) ===`);
|
|
1071
|
+
console.log(m.prompt);
|
|
1072
|
+
console.log('');
|
|
1073
|
+
}
|
|
1074
|
+
console.log(`--- END ---`);
|
|
1075
|
+
} else if (formation === 'legion' && prompt.members) {
|
|
1076
|
+
console.log(`\n--- LEGION CONFIG ---`);
|
|
1077
|
+
console.log(`Team: ${prompt.teamName}`);
|
|
1078
|
+
console.log(`Description: ${prompt.teamDesc}`);
|
|
1079
|
+
console.log(`Members: ${prompt.members.length}`);
|
|
1080
|
+
console.log(`\n--- LEAD PROMPT ---\n`);
|
|
1081
|
+
console.log(prompt.lead.prompt);
|
|
1082
|
+
console.log(`\n--- MEMBER PROMPTS ---\n`);
|
|
1083
|
+
for (const m of prompt.members) {
|
|
1084
|
+
console.log(`=== ${m.name} (${m.agentType}) ===`);
|
|
1085
|
+
console.log(m.prompt);
|
|
1086
|
+
console.log('');
|
|
1087
|
+
}
|
|
1088
|
+
console.log(`--- END ---`);
|
|
1089
|
+
} else {
|
|
1090
|
+
console.log(`\n--- PROMPT ---\n`);
|
|
1091
|
+
console.log(prompt);
|
|
1092
|
+
console.log(`\n--- END ---`);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
// ─────────────────────────────────────────
|
|
1097
|
+
// 執行分發
|
|
1098
|
+
// ─────────────────────────────────────────
|
|
1099
|
+
|
|
1100
|
+
function execute(formation, opts) {
|
|
1101
|
+
const { prompt, skill, sessionId, output, projectPath, taskId } = opts;
|
|
1102
|
+
|
|
1103
|
+
switch (formation) {
|
|
1104
|
+
case 'unit':
|
|
1105
|
+
case 'solo': {
|
|
1106
|
+
const child = runSingle({
|
|
1107
|
+
prompt,
|
|
1108
|
+
formation,
|
|
1109
|
+
skill,
|
|
1110
|
+
sessionId,
|
|
1111
|
+
outputPath: output,
|
|
1112
|
+
projectPath
|
|
1113
|
+
});
|
|
1114
|
+
|
|
1115
|
+
// 註冊 dispatch(Dashboard Agent Monitor 用)
|
|
1116
|
+
registerDispatch({ sessionId, logPath: child._formation?.logPath, taskId, formation, projectPath });
|
|
1117
|
+
|
|
1118
|
+
// Cleanup guard: 確保只執行一次,防止 close + formation:done 重複觸發
|
|
1119
|
+
let cleanedUp = false;
|
|
1120
|
+
const cleanup = (code) => {
|
|
1121
|
+
if (cleanedUp) return;
|
|
1122
|
+
cleanedUp = true;
|
|
1123
|
+
unregisterDispatch(sessionId);
|
|
1124
|
+
// Keep event loop alive with a timer so Supabase HTTP requests can complete
|
|
1125
|
+
// before Node.js exits (child close leaves no other handles active)
|
|
1126
|
+
const keepAlive = setTimeout(() => {}, 10000);
|
|
1127
|
+
|
|
1128
|
+
// Yggdrasil: 同步任務最終狀態到 kenaz_tasks
|
|
1129
|
+
const syncFinalStatus = (() => {
|
|
1130
|
+
if (!taskId || !taskId.startsWith('TASK_')) return Promise.resolve();
|
|
1131
|
+
try {
|
|
1132
|
+
const ts = getTaskSync();
|
|
1133
|
+
if (!ts) return Promise.resolve();
|
|
1134
|
+
return ts.syncTaskStatus({
|
|
1135
|
+
taskId,
|
|
1136
|
+
status: code === 0 ? 'done' : 'failed',
|
|
1137
|
+
projectPath,
|
|
1138
|
+
}).catch(() => {});
|
|
1139
|
+
} catch { return Promise.resolve(); }
|
|
1140
|
+
})();
|
|
1141
|
+
|
|
1142
|
+
Promise.allSettled([
|
|
1143
|
+
broadcastStatus(projectPath, { current_task: null, touching_files: [] }),
|
|
1144
|
+
code === 0 ? syncCommit(taskId, projectPath) : Promise.resolve(),
|
|
1145
|
+
syncFinalStatus,
|
|
1146
|
+
]).then(() => {
|
|
1147
|
+
clearTimeout(keepAlive);
|
|
1148
|
+
});
|
|
1149
|
+
};
|
|
1150
|
+
|
|
1151
|
+
child.on('close', cleanup);
|
|
1152
|
+
// Fallback: formation:done fires when result is received, even if process lingers
|
|
1153
|
+
child.on('formation:done', cleanup);
|
|
1154
|
+
|
|
1155
|
+
return child;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
case 'squad': {
|
|
1159
|
+
if (!Array.isArray(prompt)) {
|
|
1160
|
+
throw new Error('Squad prompt builder should return an array of member prompts');
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
// Squad: 註冊整個 session
|
|
1164
|
+
registerDispatch({ sessionId, logPath: null, taskId, formation: 'squad', projectPath });
|
|
1165
|
+
|
|
1166
|
+
const result = runParallel({
|
|
1167
|
+
members: prompt,
|
|
1168
|
+
formation,
|
|
1169
|
+
sessionId,
|
|
1170
|
+
projectPath
|
|
1171
|
+
});
|
|
1172
|
+
|
|
1173
|
+
// runParallel returns a promise; await cleanup 確保完成
|
|
1174
|
+
if (result && typeof result.then === 'function') {
|
|
1175
|
+
const cleanup = (results) => {
|
|
1176
|
+
unregisterDispatch(sessionId);
|
|
1177
|
+
|
|
1178
|
+
// Yggdrasil: 同步任務最終狀態(squad 以全員成功為準)
|
|
1179
|
+
const syncFinalStatus = (() => {
|
|
1180
|
+
if (!taskId || !taskId.startsWith('TASK_')) return Promise.resolve();
|
|
1181
|
+
try {
|
|
1182
|
+
const ts = getTaskSync();
|
|
1183
|
+
if (!ts) return Promise.resolve();
|
|
1184
|
+
const allSuccess = Array.isArray(results) && results.every(r => r.exitCode === 0);
|
|
1185
|
+
return ts.syncTaskStatus({
|
|
1186
|
+
taskId,
|
|
1187
|
+
status: allSuccess ? 'done' : 'failed',
|
|
1188
|
+
projectPath,
|
|
1189
|
+
}).catch(() => {});
|
|
1190
|
+
} catch { return Promise.resolve(); }
|
|
1191
|
+
})();
|
|
1192
|
+
|
|
1193
|
+
return Promise.allSettled([
|
|
1194
|
+
broadcastStatus(projectPath, { current_task: null, touching_files: [] }),
|
|
1195
|
+
syncFinalStatus,
|
|
1196
|
+
]);
|
|
1197
|
+
};
|
|
1198
|
+
result.then(cleanup, () => cleanup(null));
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
return result;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
case 'legion':
|
|
1205
|
+
// Legion 不 spawn 進程,輸出 TeamCreate 配置供 Formation Lead 使用
|
|
1206
|
+
console.log(`\n⚔️ Legion: TeamCreate configuration generated`);
|
|
1207
|
+
console.log(` Team: ${prompt.teamName}`);
|
|
1208
|
+
console.log(` Members: ${prompt.members.length}`);
|
|
1209
|
+
console.log(`\n Legion 不直接啟動進程。`);
|
|
1210
|
+
console.log(` 請使用 TeamCreate API 搭配以上配置啟動團隊。`);
|
|
1211
|
+
console.log(` 或使用 --dry-run 查看完整 prompt。`);
|
|
1212
|
+
return prompt;
|
|
1213
|
+
|
|
1214
|
+
default:
|
|
1215
|
+
throw new Error(`Unknown formation: ${formation}`);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
// ─────────────────────────────────────────
|
|
1220
|
+
// CLI
|
|
1221
|
+
// ─────────────────────────────────────────
|
|
1222
|
+
|
|
1223
|
+
if (require.main === module) {
|
|
1224
|
+
const args = process.argv.slice(2);
|
|
1225
|
+
|
|
1226
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
1227
|
+
console.log(`
|
|
1228
|
+
⚔️ Formation Dispatch
|
|
1229
|
+
|
|
1230
|
+
Usage:
|
|
1231
|
+
node .formation/tools/dispatch.js --skill=<name> --task=<TASK_ID|description>
|
|
1232
|
+
|
|
1233
|
+
Options:
|
|
1234
|
+
--formation <name> Formation type: unit (default), solo, squad, legion
|
|
1235
|
+
--skill <name> Skill to use (YAML filename without extension)
|
|
1236
|
+
--task <value> Task ID (TASK_XXX) or free-text description
|
|
1237
|
+
--concurrency <n> Parallel execution slots (default 3, max 5, legacy only)
|
|
1238
|
+
--output <path> Custom log output path
|
|
1239
|
+
--dry-run Only print the prompt, don't launch
|
|
1240
|
+
--prompt-only Print raw prompt text to stdout (machine-readable, no headers)
|
|
1241
|
+
--dispatch-mode <mode> Output mode: formation (default), subagent (JSON params for Agent tool)
|
|
1242
|
+
--dispatch-model <id> TASK_1998 R3: subagent-path model override (wins over
|
|
1243
|
+
dashboard-models.json dispatchModelByRigor and the
|
|
1244
|
+
default — the dashboard dispatchModel, used for
|
|
1245
|
+
every rigor unless dispatchModelByRigor sets that
|
|
1246
|
+
rigor's entry). Only used with --dispatch-mode=subagent.
|
|
1247
|
+
--use-worktree <bool> TASK_1833: dispatch-time worktree toggle (true|false).
|
|
1248
|
+
Overrides env FORMATION_USE_WORKTREE and the target
|
|
1249
|
+
project's .kenaz/project.yaml use_worktree. For
|
|
1250
|
+
cross-project subagent dispatch: true → pre-created
|
|
1251
|
+
worktree inside the target repo; false → shared tree
|
|
1252
|
+
with serialized writes (dispatch lock). Single-editor
|
|
1253
|
+
projects (Unity) should pass false.
|
|
1254
|
+
--release-lock TASK_1859: release the serial dispatch lock for
|
|
1255
|
+
--project-path (omit for the core lock). Prints the
|
|
1256
|
+
holder's taskId/sessionId/startedAt, then releases.
|
|
1257
|
+
Default releases only a lock held by THIS session;
|
|
1258
|
+
cross-session / unknown-holder release needs --force.
|
|
1259
|
+
Idempotent: exit 0 with a harmless message when no
|
|
1260
|
+
lock is held. Fallback remains deleting the lock file.
|
|
1261
|
+
--force Dispatch even if dependencies are not met
|
|
1262
|
+
(with --release-lock: release a lock this session
|
|
1263
|
+
cannot prove it owns)
|
|
1264
|
+
|
|
1265
|
+
Formation-Skill Quick Reference:
|
|
1266
|
+
unit: do, think, plan
|
|
1267
|
+
solo: strategy, diagnosis
|
|
1268
|
+
squad: blitz, sweep
|
|
1269
|
+
legion: forge, hive
|
|
1270
|
+
|
|
1271
|
+
Sub-agent dispatch (Ansuz billing-aware path):
|
|
1272
|
+
node .formation/tools/dispatch.js --skill=do --task=TASK_172 --dispatch-mode=subagent
|
|
1273
|
+
→ prints JSON: { promptText, taskId, agentParams: { model, isolation, description } }
|
|
1274
|
+
Ansuz passes promptText to Agent tool with agentParams for worktree-isolated execution.
|
|
1275
|
+
|
|
1276
|
+
Headless Mode (recommended for long tasks):
|
|
1277
|
+
node .formation/tools/headless.js --formation=legion --skill=forge --task=TASK_174
|
|
1278
|
+
|
|
1279
|
+
Examples:
|
|
1280
|
+
node .formation/tools/dispatch.js --skill=do --task=TASK_172
|
|
1281
|
+
node .formation/tools/dispatch.js --formation=solo --skill=strategy --task="評估新功能"
|
|
1282
|
+
node .formation/tools/dispatch.js --formation=squad --skill=blitz --task=TASK_173
|
|
1283
|
+
node .formation/tools/dispatch.js --formation=legion --skill=forge --task=TASK_174 --dry-run
|
|
1284
|
+
`);
|
|
1285
|
+
process.exit(0);
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
const getArg = (flag) => {
|
|
1289
|
+
for (let i = 0; i < args.length; i++) {
|
|
1290
|
+
if (args[i].startsWith(`${flag}=`)) {
|
|
1291
|
+
return args[i].split('=').slice(1).join('=');
|
|
1292
|
+
}
|
|
1293
|
+
if (args[i] === flag && args[i + 1]) {
|
|
1294
|
+
return args[i + 1];
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
return null;
|
|
1298
|
+
};
|
|
1299
|
+
|
|
1300
|
+
const formation = getArg('--formation') || 'unit';
|
|
1301
|
+
const skill = getArg('--skill');
|
|
1302
|
+
const task = getArg('--task');
|
|
1303
|
+
const output = getArg('--output');
|
|
1304
|
+
const projectPath = getArg('--project-path');
|
|
1305
|
+
const dryRun = args.includes('--dry-run');
|
|
1306
|
+
const promptOnly = args.includes('--prompt-only');
|
|
1307
|
+
const dispatchModeCli = getArg('--dispatch-mode');
|
|
1308
|
+
// TASK_1998 R3: subagent-path model override — wins over dashboard
|
|
1309
|
+
// dispatchModelByRigor and the dashboard dispatchModel default. Accepts
|
|
1310
|
+
// either a bare Agent tool family (sonnet|opus|haiku|fable) or a full
|
|
1311
|
+
// dashboard-style id (translated the same way as every other source).
|
|
1312
|
+
const dispatchModelCli = getArg('--dispatch-model');
|
|
1313
|
+
const force = args.includes('--force');
|
|
1314
|
+
// TASK_2315: harness selector; auto-detect Codex from its session env (same signal as the boot fix).
|
|
1315
|
+
const harnessCli = getArg('--harness') || ((process.env.CODEX_SESSION_ID || process.env.CODEX_THREAD_ID) ? 'codex' : 'claude');
|
|
1316
|
+
|
|
1317
|
+
// TASK_1833: dispatch-time worktree toggle. Parsed strictly — a typo must not
|
|
1318
|
+
// silently fall through to the project default. Also exported to
|
|
1319
|
+
// FORMATION_USE_WORKTREE so any in-process readWorktreeConfig consumer
|
|
1320
|
+
// (formation path included) sees the same decision.
|
|
1321
|
+
const useWorktreeRaw = getArg('--use-worktree');
|
|
1322
|
+
let useWorktreeCli = null;
|
|
1323
|
+
if (useWorktreeRaw != null) {
|
|
1324
|
+
const v = String(useWorktreeRaw).trim().toLowerCase();
|
|
1325
|
+
if (v === 'true' || v === '1') useWorktreeCli = true;
|
|
1326
|
+
else if (v === 'false' || v === '0') useWorktreeCli = false;
|
|
1327
|
+
else {
|
|
1328
|
+
console.error(`❌ --use-worktree expects true|false (got '${useWorktreeRaw}')`);
|
|
1329
|
+
process.exit(1);
|
|
1330
|
+
}
|
|
1331
|
+
process.env.FORMATION_USE_WORKTREE = String(useWorktreeCli);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// TASK_1859: standalone lock-release subcommand — needs neither --skill nor
|
|
1335
|
+
// --task. Exists because "delete the lock file" (the previous release
|
|
1336
|
+
// contract) is unexecutable where Bash(rm *) is denied.
|
|
1337
|
+
if (args.includes('--release-lock')) {
|
|
1338
|
+
const res = releaseDispatchLock({ projectPath, force });
|
|
1339
|
+
const h = res.holder || {};
|
|
1340
|
+
const holderLine = res.existed
|
|
1341
|
+
? ` Holder: task=${h.taskId || '?'}, session=${h.sessionId || '?'}, startedAt=${h.startedAt || '?'}` +
|
|
1342
|
+
(res.staleness ? ` (age=${Number.isFinite(res.staleness.ageMs) ? Math.round(res.staleness.ageMs / 60000) + 'min' : '?'}, stale=${res.staleness.stale})` : '')
|
|
1343
|
+
: null;
|
|
1344
|
+
if (!res.existed) {
|
|
1345
|
+
console.log(`✅ No dispatch lock held (${res.lockFile}) — nothing to release.`);
|
|
1346
|
+
process.exit(0);
|
|
1347
|
+
}
|
|
1348
|
+
if (res.released) {
|
|
1349
|
+
console.log(holderLine);
|
|
1350
|
+
console.log(`✅ Dispatch lock released (${res.reason}): ${res.lockFile}`);
|
|
1351
|
+
process.exit(0);
|
|
1352
|
+
}
|
|
1353
|
+
console.log(holderLine);
|
|
1354
|
+
console.error(`❌ Dispatch lock NOT released (${res.reason}): ${res.lockFile}`);
|
|
1355
|
+
if (res.reason === 'session-mismatch' || res.reason === 'holder-session-unknown' ||
|
|
1356
|
+
res.reason === 'own-session-unresolved' || res.reason === 'own-session-unproven' ||
|
|
1357
|
+
res.reason === 'holder-unreadable') {
|
|
1358
|
+
console.error(' This session cannot prove it owns the lock. Verify the previous agent is done, then re-run with --force. (Stale locks auto-break on the next dispatch after 60min.)');
|
|
1359
|
+
}
|
|
1360
|
+
process.exit(1);
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
if (!skill) {
|
|
1364
|
+
console.error('❌ --skill is required');
|
|
1365
|
+
process.exit(1);
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
if (!task) {
|
|
1369
|
+
console.error('❌ --task is required (TASK_ID or description)');
|
|
1370
|
+
process.exit(1);
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
// Sub-agent mode: output JSON params for Agent tool consumption
|
|
1374
|
+
if (dispatchModeCli === 'subagent') {
|
|
1375
|
+
getSubagentDispatchParams({ formation, skill, task, projectPath, force, useWorktree: useWorktreeCli, dispatchModelOverride: dispatchModelCli, dryRun, harness: harnessCli }).then(result => {
|
|
1376
|
+
if (!result) { process.exitCode = 1; return; }
|
|
1377
|
+
process.stdout.write(JSON.stringify(result, null, 2) + '\n');
|
|
1378
|
+
});
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
// Prompt-only mode: output raw prompt to stdout (machine-readable, no decorations)
|
|
1383
|
+
if (promptOnly) {
|
|
1384
|
+
const skillDef = loadSkill(formation, skill);
|
|
1385
|
+
const loadOpts = projectPath ? { projectPath } : undefined;
|
|
1386
|
+
const taskData = task && task.startsWith('TASK_') ? loadTask(task, loadOpts) : null;
|
|
1387
|
+
const promptOptions = {};
|
|
1388
|
+
if (projectPath) promptOptions.projectPath = projectPath;
|
|
1389
|
+
if (task && task.startsWith('TASK_')) promptOptions.taskId = task;
|
|
1390
|
+
const rawPrompt = buildPrompt(skillDef, task, taskData, promptOptions);
|
|
1391
|
+
const text = typeof rawPrompt === 'string' ? rawPrompt : JSON.stringify(rawPrompt);
|
|
1392
|
+
process.stdout.write(text + '\n');
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
dispatch({ formation, skill, task, output, dryRun, projectPath, force });
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
// ─────────────────────────────────────────
|
|
1400
|
+
// Sub-agent dispatch path
|
|
1401
|
+
// ─────────────────────────────────────────
|
|
1402
|
+
|
|
1403
|
+
/**
|
|
1404
|
+
* TASK_1813: read dispatch routing (dispatchFamily/dispatchAdapter) plus the raw
|
|
1405
|
+
* dashboard-models.json object, mirroring kenaz.rs load_dispatch_routing /
|
|
1406
|
+
* load_dashboard_model semantics:
|
|
1407
|
+
* - Candidate order: project first, then core (ROOT). Same order as the Rust
|
|
1408
|
+
* side's dashboard_models_candidates — both paths must read the SAME file or
|
|
1409
|
+
* they can reach different routing conclusions for one dispatch.
|
|
1410
|
+
* - ALL fields come from the FIRST parseable candidate file, so family and
|
|
1411
|
+
* adapter can never be mixed across two different dashboard-models.json files.
|
|
1412
|
+
* - Empty/whitespace strings coalesce to null (mirrors Rust `.filter(|s| !s.is_empty())`).
|
|
1413
|
+
* @param {string|null} projectPath
|
|
1414
|
+
* @returns {{ models: object|null, family: string|null, adapter: string|null }}
|
|
1415
|
+
*/
|
|
1416
|
+
function loadDispatchRouting(projectPath) {
|
|
1417
|
+
const parsed = loadDashboardModels(projectPath); // first parseable candidate wins (TASK_2249)
|
|
1418
|
+
if (!parsed) return { models: null, family: null, adapter: null };
|
|
1419
|
+
const get = (field) => {
|
|
1420
|
+
const v = parsed[field];
|
|
1421
|
+
if (typeof v !== 'string') return null;
|
|
1422
|
+
const trimmed = v.trim();
|
|
1423
|
+
return trimmed || null;
|
|
1424
|
+
};
|
|
1425
|
+
return { models: parsed, family: get('dispatchFamily'), adapter: get('dispatchAdapter') };
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
/**
|
|
1429
|
+
* Build the sub-agent dispatch payload without spawning a process.
|
|
1430
|
+
* Ansuz calls this to get the prompt + Agent tool parameters, then passes them
|
|
1431
|
+
* to the Agent tool (isolation='worktree') directly. (Originally motivated by
|
|
1432
|
+
* the June 15 claude -p credit pool, since rescinded; it remains the default
|
|
1433
|
+
* because results return in-session without log polling.)
|
|
1434
|
+
*
|
|
1435
|
+
* Routing: use for rigor:low/medium tasks estimated <30min.
|
|
1436
|
+
* Formation dispatch (claude -p) remains the default for rigor:high / multi-hour tasks.
|
|
1437
|
+
*
|
|
1438
|
+
* @param {object} options
|
|
1439
|
+
* @param {string} [options.formation='unit']
|
|
1440
|
+
* @param {string} [options.skill='do']
|
|
1441
|
+
* @param {string} options.task - Task ID (TASK_XXX) or description
|
|
1442
|
+
* @param {string|null} [options.projectPath]
|
|
1443
|
+
* @param {boolean} [options.force] - Skip dependency check
|
|
1444
|
+
* @param {boolean|null} [options.useWorktree] - TASK_1833 dispatch-time worktree toggle
|
|
1445
|
+
* (true/false overrides env/project.yaml; null = no override). Only affects
|
|
1446
|
+
* cross-project dispatch — same-project always uses Agent tool isolation:'worktree'.
|
|
1447
|
+
* @param {string|null} [options.dispatchModelOverride] - TASK_1998 R3: --dispatch-model
|
|
1448
|
+
* CLI value, if any. Wins over dashboard-models.json dispatchModelByRigor and
|
|
1449
|
+
* the dashboard dispatchModel default.
|
|
1450
|
+
* @returns {Promise<{ promptText: string, taskId: string, formation: string, skill: string, dispatchMode: string, effectiveMode: 'subagent', modelTranslation: { requested: string, agentToolModel: string, granularityLoss: boolean }, isolation: object, agentParams: object, rigor: 'low'|'medium'|'high', modelSource: 'dashboard'|'dashboard-by-rigor'|'cli' }|null>}
|
|
1451
|
+
* dispatchMode = TASK_1813 config echo (dashboard-models.json request);
|
|
1452
|
+
* effectiveMode = the path actually taken (always 'subagent' here — TASK_1859).
|
|
1453
|
+
*/
|
|
1454
|
+
async function getSubagentDispatchParams(options) {
|
|
1455
|
+
const {
|
|
1456
|
+
formation = 'unit', skill = 'do', task, projectPath = null, force = false, useWorktree = null,
|
|
1457
|
+
dispatchModelOverride = null, // TASK_1998 R3: --dispatch-model CLI flag, wins over dashboard dispatchModelByRigor/dispatchModel
|
|
1458
|
+
// --dry-run: build and print the payload with NO side effects — no resource
|
|
1459
|
+
// leases, no worktree, no serial lock, no prompt telemetry. Gates still run
|
|
1460
|
+
// so a dry run reports the same rejections a real dispatch would.
|
|
1461
|
+
dryRun = false,
|
|
1462
|
+
// TASK_2315: 'claude' (Agent tool) | 'codex' (Codex-native spawn_agent). Selects the payload shape.
|
|
1463
|
+
harness = 'claude',
|
|
1464
|
+
} = options;
|
|
1465
|
+
if (harness !== 'claude' && harness !== 'codex') {
|
|
1466
|
+
console.error(`❌ --harness expects claude|codex (got '${harness}')`);
|
|
1467
|
+
return null;
|
|
1468
|
+
}
|
|
1469
|
+
const isCodex = harness === 'codex';
|
|
1470
|
+
|
|
1471
|
+
// 1. Load skill + task
|
|
1472
|
+
const skillDef = loadSkill(formation, skill);
|
|
1473
|
+
const loadOpts = projectPath ? { projectPath } : undefined;
|
|
1474
|
+
const taskData = task && task.startsWith('TASK_') ? loadTask(task, loadOpts) : null;
|
|
1475
|
+
const taskInput = task || '';
|
|
1476
|
+
// TASK_1998 R3: extracted here (not at step 4, where it used to live) so the
|
|
1477
|
+
// model-resolution step (2c) below can read it before choosing a model.
|
|
1478
|
+
const rigor = extractRigor(taskData);
|
|
1479
|
+
// TASK_1998 two-axis policy: complexity drives CONTEXT volume (Cross-Project
|
|
1480
|
+
// Context caps, Related Files Preview, Known Failures, Project Memory).
|
|
1481
|
+
// Always normalized (extractComplexity defaults to 'medium').
|
|
1482
|
+
const complexity = extractComplexity(taskData);
|
|
1483
|
+
|
|
1484
|
+
// 2. Dependency check (same guard as Formation dispatch)
|
|
1485
|
+
if (taskData) {
|
|
1486
|
+
const depCheck = checkDependencies(taskData, projectPath);
|
|
1487
|
+
if (depCheck.blocked && !force) {
|
|
1488
|
+
console.error(`❌ Sub-agent dispatch blocked: ${taskInput} has unmet dependencies`);
|
|
1489
|
+
for (const dep of depCheck.unmet) {
|
|
1490
|
+
console.error(` ⛔ ${dep} — not in done/completed`);
|
|
1491
|
+
}
|
|
1492
|
+
return null;
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
// 2b. (TASK_1813) Dispatch routing guard — mirrors kenaz.rs tool_dispatch
|
|
1497
|
+
// (lines 624-654, TASK_1776) on the sub-agent path. The Agent tool's model
|
|
1498
|
+
// parameter only accepts Claude models, so a non-claude dispatchFamily has NO
|
|
1499
|
+
// viable execution here and MUST fail loudly (sigil_2a3f3b75 invariant:
|
|
1500
|
+
// "a non-claude model id MUST resolve to an adapter or fail loudly — never
|
|
1501
|
+
// silent Claude CLI fallback"). Runs BEFORE the scope gate / resource locks /
|
|
1502
|
+
// prompt build so a rejected dispatch never acquires locks it won't use.
|
|
1503
|
+
const routing = loadDispatchRouting(projectPath);
|
|
1504
|
+
const models = routing.models;
|
|
1505
|
+
// 2026-10-10: the harness decides the family. A Codex session can only spawn Codex
|
|
1506
|
+
// sub-agents (model inherited), so dashboard-models.json dispatchFamily (a Dashboard
|
|
1507
|
+
// preference for the retired Formation spawns) no longer blocks --harness=codex.
|
|
1508
|
+
if (isCodex && routing.family !== 'bifrost') {
|
|
1509
|
+
process.stderr.write(`[dispatch] --harness=codex: dispatchFamily '${routing.family || 'unset'}' ignored, Codex sub-agent inherits the session model
|
|
1510
|
+
`);
|
|
1511
|
+
}
|
|
1512
|
+
if (routing.family === 'bifrost' && !isCodex) {
|
|
1513
|
+
if (!routing.adapter) {
|
|
1514
|
+
console.error('❌ dashboard-models.json sets dispatchFamily=bifrost but dispatchAdapter is missing/empty — refusing to silently dispatch with the native Claude CLI. Fix the model selection (Quick Actions → Default Models) or dashboard-models.json, then use Formation dispatch (kenaz_dispatch).');
|
|
1515
|
+
} else {
|
|
1516
|
+
console.error(`❌ dashboard-models.json sets dispatchFamily=bifrost (dispatchAdapter '${routing.adapter}') — sub-agent dispatch cannot run non-Claude models (the Agent tool only accepts Claude models); refusing to silently dispatch with the native Claude CLI. Use Formation dispatch (kenaz_dispatch) instead — it routes through the Bifrost adapter.`);
|
|
1517
|
+
}
|
|
1518
|
+
return null;
|
|
1519
|
+
}
|
|
1520
|
+
if (!isCodex && routing.family && routing.family !== 'claude') {
|
|
1521
|
+
console.error(`❌ dashboard-models.json sets unsupported dispatchFamily '${routing.family}' (expected 'claude' or 'bifrost') — refusing to silently dispatch with the native Claude CLI. Fix the model selection (Quick Actions → Default Models) or use Formation dispatch (kenaz_dispatch).`);
|
|
1522
|
+
return null;
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
// 2c. (TASK_1815 + TASK_1998 R3) Resolve which raw model id to use — CLI
|
|
1526
|
+
// --dispatch-model > dashboard-models.json dispatchModelByRigor[rigor] >
|
|
1527
|
+
// dashboard-models.json dispatchModel (today's behaviour, used for every
|
|
1528
|
+
// rigor unless dispatchModelByRigor overrides it) — THEN translate it to the
|
|
1529
|
+
// Agent tool's family enum. The raw id (e.g. 'claude-fable-5[1m]') is rejected by the
|
|
1530
|
+
// Agent tool for ANY source (measured 2026-07-26: same InputValidationError
|
|
1531
|
+
// as 'gpt-5-codex'); only the family names in AGENT_TOOL_MODEL_ENUM pass
|
|
1532
|
+
// validation. Fail loudly on unmappable ids from ANY source (TASK_1815:
|
|
1533
|
+
// never silently substitute), and surface the version-granularity loss to
|
|
1534
|
+
// the caller. Runs BEFORE the scope gate / resource leases (same reason as
|
|
1535
|
+
// 2b: a rejected dispatch must never acquire locks it won't use).
|
|
1536
|
+
const resolution = resolveDispatchModelForRigor({ rigor, models, cliDispatchModel: dispatchModelOverride });
|
|
1537
|
+
const rawModel = resolution.rawModel;
|
|
1538
|
+
// TASK_2315: Codex inherits the session model — nothing to translate or pass.
|
|
1539
|
+
const translated = isCodex ? { model: null, lossless: true } : translateModelForAgentTool(rawModel);
|
|
1540
|
+
if (!isCodex && !translated.model) {
|
|
1541
|
+
console.error(`❌ ${resolution.label} '${rawModel}' cannot be mapped to an Agent tool model family (${AGENT_TOOL_MODEL_ENUM.join('|')}) — refusing to silently guess a substitute model. Fix the model selection (Quick Actions → Default Models) or use Formation dispatch (kenaz_dispatch), which accepts full model ids via --dispatch-model.`);
|
|
1542
|
+
return null;
|
|
1543
|
+
}
|
|
1544
|
+
const dispatchModel = translated.model;
|
|
1545
|
+
const modelTranslation = isCodex
|
|
1546
|
+
? { requested: rawModel, inherited: true }
|
|
1547
|
+
: { requested: rawModel, agentToolModel: dispatchModel, granularityLoss: !translated.lossless };
|
|
1548
|
+
if (!translated.lossless) {
|
|
1549
|
+
process.stderr.write(`[dispatch] model '${rawModel}' → Agent tool family '${dispatchModel}' — the Agent tool only expresses family names (${AGENT_TOOL_MODEL_ENUM.join('|')}); version/speed selections (e.g. 5 vs 4.x, [1m]) are NOT expressible on the subagent path. If the exact version matters, use Formation dispatch (kenaz_dispatch), which passes full model ids.\n`);
|
|
1550
|
+
}
|
|
1551
|
+
// TASK_1998 R3 (+ two-axis policy): the resolved choice, always printed
|
|
1552
|
+
// (unlike the granularity block above, which only fires on lossy translation).
|
|
1553
|
+
process.stderr.write(`[dispatch] rigor=${resolution.rigorKey} complexity=${complexity} model=${rawModel} → ${isCodex ? 'inherited by Codex session' : "family '" + dispatchModel + "'"} (source: ${resolution.source})\n`);
|
|
1554
|
+
|
|
1555
|
+
// TASK_2362: subagent is the only route. dispatchMode is a legacy config echo:
|
|
1556
|
+
// missing -> 'subagent'; 'subagent'|'auto' accepted; 'formation' (retired) or
|
|
1557
|
+
// any other value warns LOUDLY and uses 'subagent'.
|
|
1558
|
+
const rawDispatchMode = typeof models?.dispatchMode === 'string' ? models.dispatchMode.trim() : '';
|
|
1559
|
+
let dispatchMode = 'subagent';
|
|
1560
|
+
if (rawDispatchMode) {
|
|
1561
|
+
if (rawDispatchMode === 'subagent' || rawDispatchMode === 'auto') {
|
|
1562
|
+
dispatchMode = rawDispatchMode;
|
|
1563
|
+
} else {
|
|
1564
|
+
console.error(`⚠️ dashboard-models.json dispatchMode '${rawDispatchMode}' is invalid or retired (expected subagent|auto) — using 'subagent'`);
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
// M1 (TASK_1758): scope gate + resource lease (same as formation dispatch path)
|
|
1569
|
+
// TASK_1833: acquired resources tracked OUTSIDE the block so the isolation
|
|
1570
|
+
// step below can release them on late rejection (never leak leases).
|
|
1571
|
+
// TASK_1863: the self-owned claim marker gets the SAME late-rejection release
|
|
1572
|
+
// guarantee — tracked alongside the resources, released at every post-gate
|
|
1573
|
+
// failure exit (leaked markers blocked same-task retries for the 8h window).
|
|
1574
|
+
let _saAcquiredResources = [];
|
|
1575
|
+
let _saClaim = null;
|
|
1576
|
+
const _saRoot = projectPath || ROOT;
|
|
1577
|
+
{
|
|
1578
|
+
const _saSession = _getProvenSessionId(_saRoot); // TASK_2265: proven identity only
|
|
1579
|
+
const _saPaths = (() => { try { return taskData ? JSON.parse(taskData).scope_paths || [] : []; } catch { return []; } })();
|
|
1580
|
+
const _saResult = checkDispatchScopeGate(_saPaths, _saRoot, _saSession, !!force, taskInput);
|
|
1581
|
+
if (_saResult.collisions.length > 0) {
|
|
1582
|
+
for (const col of _saResult.collisions) {
|
|
1583
|
+
const pl = col.paths.slice(0,3).join(', ') + (col.paths.length > 3 ? ' +' + (col.paths.length-3) + ' more' : '');
|
|
1584
|
+
if (_saResult.blocked) { console.error('Sub-agent dispatch blocked: scope conflict with stream ' + col.stream_label + ' (task ' + col.task_id + '): ' + pl); }
|
|
1585
|
+
else { console.warn('WARNING scope conflict (--force): stream ' + col.stream_label + ' (task ' + col.task_id + '): ' + pl); }
|
|
1586
|
+
}
|
|
1587
|
+
if (_saResult.blocked) { return null; }
|
|
1588
|
+
}
|
|
1589
|
+
_saClaim = adoptSelfClaimMarker(taskInput, _saRoot, _saSession);
|
|
1590
|
+
const _saResources = (() => { try { return taskData ? JSON.parse(taskData).resources || [] : []; } catch { return []; } })();
|
|
1591
|
+
if (_saResources.length > 0 && dryRun) {
|
|
1592
|
+
console.error(' [dry-run] resource locks NOT acquired: ' + _saResources.join(', '));
|
|
1593
|
+
} else if (_saResources.length > 0) {
|
|
1594
|
+
const _saLock = acquireResourceLocks(_saResources, _saRoot, _saSession, taskInput);
|
|
1595
|
+
if (_saLock.failed.length > 0) {
|
|
1596
|
+
for (const fail of _saLock.failed) {
|
|
1597
|
+
const hi = fail.holder ? ' (session=' + fail.holder.owner_session + ', task=' + fail.holder.task_id + ')' : '';
|
|
1598
|
+
console.error((fail.orphan ? 'WARNING' : 'ERROR') + ': resource ' + fail.name + (fail.orphan ? ' ORPHAN' : ' busy') + hi);
|
|
1599
|
+
}
|
|
1600
|
+
releaseResourceLocks(_saLock.acquired, _saRoot);
|
|
1601
|
+
if (!force) { releaseAdoptedClaimMarker(_saClaim); return null; }
|
|
1602
|
+
console.warn('WARNING: proceeding despite resource lock conflicts (--force).');
|
|
1603
|
+
} else if (_saLock.acquired.length > 0) {
|
|
1604
|
+
console.error(' Resource locks acquired: ' + _saLock.acquired.join(', '));
|
|
1605
|
+
}
|
|
1606
|
+
_saAcquiredResources = _saLock.acquired;
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
// TASK_1833: cross-project dispatch now goes through the SAME isolation
|
|
1611
|
+
// decision as every other path (resolveDispatchIsolation — see its doc for
|
|
1612
|
+
// the mode taxonomy and the TASK_1672/1593 reason the Agent tool's own
|
|
1613
|
+
// isolation param cannot cover another repo). Before this, cross-project
|
|
1614
|
+
// sub-agent dispatch unconditionally got NEITHER isolation NOR
|
|
1615
|
+
// serialization, and the shared-tree `|| true` commit swallowed the
|
|
1616
|
+
// resulting index.lock data loss (measured 2026-07-31).
|
|
1617
|
+
// TASK_1824 ordering still holds: computed BEFORE buildPrompt so prompt
|
|
1618
|
+
// assembly (appendWorkflow staging gate, TASK_1819) knows the isolation mode.
|
|
1619
|
+
const iso = resolveDispatchIsolation({ projectPath, useWorktreeOverride: useWorktree });
|
|
1620
|
+
// TASK_2315: Codex has no harness-managed worktree isolation — always pre-create
|
|
1621
|
+
// one (same-project included) and hand its path to the agent as cwd.
|
|
1622
|
+
const wtRepo2315 = projectPath || ROOT;
|
|
1623
|
+
if (isCodex && iso.mode === 'agent_tool_worktree') { iso.mode = 'target_repo_worktree'; iso.source = 'codex-harness'; }
|
|
1624
|
+
const isCrossProject = iso.isCrossProject || (isCodex && iso.mode === 'target_repo_worktree');
|
|
1625
|
+
let crossWorktree = null; // { worktreePath, branchName } when mode=target_repo_worktree
|
|
1626
|
+
let serialLock = null; // { lockFile } when mode=serial_lock
|
|
1627
|
+
let worktreeFallbackReason = null; // TASK_2067: non-null only on a genuine target_repo_worktree creation failure that degraded to serial_lock -- rides in the isolation payload, not just stderr
|
|
1628
|
+
|
|
1629
|
+
// TASK_2297: free-space gate before any worktree is created. Reclaims finished-card
|
|
1630
|
+
// worktrees ONLY under pressure (merged+clean+no junctions+idle); refuses otherwise.
|
|
1631
|
+
if (iso.useWorktree && !dryRun) {
|
|
1632
|
+
const wtRepo = projectPath || ROOT;
|
|
1633
|
+
const space = require('./worktree-reclaim').ensureWorktreeSpace(wtRepo, path.join(wtRepo, '.formation', 'worktrees'));
|
|
1634
|
+
if (!space.ok) throw new Error(space.message);
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
if (iso.mode === 'target_repo_worktree' && dryRun) {
|
|
1638
|
+
const idBase = taskInput.startsWith('TASK_') ? taskInput.toLowerCase() : 'adhoc';
|
|
1639
|
+
crossWorktree = { worktreePath: path.join(wtRepo2315, '.formation', 'worktrees', `task_${idBase}`) + ' (dry-run: not created)', branchName: `task/${idBase}` };
|
|
1640
|
+
} else if (iso.mode === 'target_repo_worktree') {
|
|
1641
|
+
try {
|
|
1642
|
+
crossWorktree = setupSubagentCrossProjectWorktree(wtRepo2315, taskInput);
|
|
1643
|
+
// stderr, not stdout — subagent mode's stdout is machine-readable JSON
|
|
1644
|
+
process.stderr.write(` 🌿 Cross-project worktree (in target repo): ${crossWorktree.worktreePath}${crossWorktree.reusedBranch ? ' (reused existing branch)' : ''}\n`);
|
|
1645
|
+
} catch (e) {
|
|
1646
|
+
// Safe degradation: NEVER fall back to unserialized shared-tree writes —
|
|
1647
|
+
// that is exactly the defect this path exists to prevent. Serialize instead.
|
|
1648
|
+
// TASK_2067: this must now be a GENUINE creation failure (e.g. branch
|
|
1649
|
+
// checked out in another worktree already) -- the "branch exists but
|
|
1650
|
+
// its worktree doesn't" case is handled inside createWorktree itself
|
|
1651
|
+
// and no longer throws here. Surface the reason in the payload too,
|
|
1652
|
+
// not only stderr, so a consumer of the JSON payload can see WHY it
|
|
1653
|
+
// degraded instead of assuming this is the normal/expected path.
|
|
1654
|
+
console.error(`⚠️ Cross-project worktree creation failed (${e.message}) — falling back to SERIALIZED shared-tree dispatch`);
|
|
1655
|
+
worktreeFallbackReason = e.message;
|
|
1656
|
+
iso.mode = 'serial_lock';
|
|
1657
|
+
iso.useWorktree = false;
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
if (iso.mode === 'serial_lock' && dryRun) {
|
|
1662
|
+
console.error(' [dry-run] shared-tree dispatch lock NOT acquired: ' + dispatchLockPath(projectPath));
|
|
1663
|
+
} else if (iso.mode === 'serial_lock') {
|
|
1664
|
+
const lockFile = dispatchLockPath(projectPath);
|
|
1665
|
+
// pid:null on purpose — this CLI exits right after emitting params, so its
|
|
1666
|
+
// own pid says nothing about the agent's liveness. pid-less locks are
|
|
1667
|
+
// broken only by staleness (60min) or explicit release (delete the file
|
|
1668
|
+
// after merge — the lock file path is surfaced in the returned payload).
|
|
1669
|
+
const acq = tryAcquireDispatchLock(lockFile, {
|
|
1670
|
+
sessionId: _getProvenSessionId(ROOT) || 'unknown', // TASK_2265: unproven fallback never written as owner
|
|
1671
|
+
taskId: taskInput || null,
|
|
1672
|
+
pid: null,
|
|
1673
|
+
holder: 'subagent-shared-tree',
|
|
1674
|
+
});
|
|
1675
|
+
if (!acq.acquired) {
|
|
1676
|
+
const h = acq.holder || {};
|
|
1677
|
+
console.error(`❌ Sub-agent dispatch blocked: shared-tree dispatch lock for this project is held (task=${h.taskId || '?'}, session=${h.sessionId || '?'}, since=${h.startedAt || '?'}). Cross-project dispatch WITHOUT worktree isolation is serialized — multiple agents committing into one shared working tree destroy each other's work (index.lock). Wait for the current dispatch to finish (lock auto-breaks 60min after acquisition), or release it after verifying the previous agent is done: node .formation/tools/dispatch.js --release-lock${projectPath ? ` --project-path "${projectPath}"` : ''} (add --force if held by another session). Fallback: delete ${lockFile}`);
|
|
1678
|
+
releaseResourceLocks(_saAcquiredResources, _saRoot);
|
|
1679
|
+
releaseAdoptedClaimMarker(_saClaim); // TASK_1863: late rejection must not leak the claim
|
|
1680
|
+
return null;
|
|
1681
|
+
}
|
|
1682
|
+
if (acq.broke) console.warn(` ⚠️ Broke ${acq.brokeReason} dispatch lock from ${acq.broke.taskId || acq.broke.sessionId || '<corrupt>'}`);
|
|
1683
|
+
serialLock = { lockFile };
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
// 3. Build prompt (same buildPrompt() as Formation dispatch — same prompt quality)
|
|
1687
|
+
const promptOptions = { isSubagent: true, isCrossProject };
|
|
1688
|
+
if (crossWorktree) promptOptions.isWorktree = true; // isolated staging (TASK_1819 gate)
|
|
1689
|
+
if (projectPath) promptOptions.projectPath = projectPath;
|
|
1690
|
+
if (taskInput && taskInput.startsWith('TASK_')) promptOptions.taskId = taskInput;
|
|
1691
|
+
|
|
1692
|
+
const rawPrompt = buildPrompt(skillDef, taskInput, taskData, promptOptions);
|
|
1693
|
+
|
|
1694
|
+
// 4. Cortex context (same as Formation dispatch)
|
|
1695
|
+
const taskScopePaths = (() => {
|
|
1696
|
+
try {
|
|
1697
|
+
if (!taskData) return [];
|
|
1698
|
+
const parsed = JSON.parse(taskData);
|
|
1699
|
+
return parsed.scope_paths || [];
|
|
1700
|
+
} catch { return []; }
|
|
1701
|
+
})();
|
|
1702
|
+
|
|
1703
|
+
let promptText = typeof rawPrompt === 'string' ? rawPrompt : '';
|
|
1704
|
+
// TASK_1998: complexity (not rigor) gates the Related Files Preview section
|
|
1705
|
+
// (same two-axis gate as the Formation-dispatch path above). `rigor` and
|
|
1706
|
+
// `complexity` were both extracted in step 1 (rigor needed earlier, for
|
|
1707
|
+
// model resolution).
|
|
1708
|
+
const dietProfile = promptProfile({ rigor, complexity });
|
|
1709
|
+
if (taskScopePaths.length > 0 && !dietProfile.skipRelatedFilesPreview) {
|
|
1710
|
+
const cortexCtx = buildCortexContext(taskScopePaths, projectPath);
|
|
1711
|
+
if (cortexCtx) promptText = promptText + '\n' + cortexCtx;
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
// TASK_2176: project declares verify_offline (single heavyweight tool —
|
|
1715
|
+
// Unity/Unreal/mobile — the worktree agent cannot run authoritatively).
|
|
1716
|
+
// Surface it as a non-authoritative self-check only; the authoritative,
|
|
1717
|
+
// serialized run happens on the main tree at landing (verify-and-land.js
|
|
1718
|
+
// stepVerifyOffline), never inside this worktree.
|
|
1719
|
+
if (iso.verifyOffline) {
|
|
1720
|
+
promptText += `\n\n## Offline self-check (non-authoritative)\nThis project's .kenaz/project.yaml declares \`verify_offline: ${iso.verifyOffline}\`. Run it yourself before committing as a self-check and note the pass/fail in your final summary. It does NOT replace the authoritative verification — that runs serialized on the main tree at landing.\n`;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
// 5. Swap HEADLESS_PREFIX → sub-agent transport preamble (mode-specific)
|
|
1724
|
+
// TASK_1833: prefix follows the isolation mode —
|
|
1725
|
+
// agent_tool_worktree → SUBAGENT_PREFIX (harness worktree, pwd-derived)
|
|
1726
|
+
// target_repo_worktree → buildSubagentWorktreePrefix (pre-created worktree
|
|
1727
|
+
// inside the target repo; agent cd's there)
|
|
1728
|
+
// serial_lock → SUBAGENT_PREFIX_DIRECT (shared tree, explicit-paths
|
|
1729
|
+
// staging, writes serialized by the dispatch lock)
|
|
1730
|
+
let subagentPrefix = SUBAGENT_PREFIX;
|
|
1731
|
+
if (isCrossProject) {
|
|
1732
|
+
subagentPrefix = crossWorktree
|
|
1733
|
+
? buildSubagentWorktreePrefix(crossWorktree.worktreePath, crossWorktree.branchName, wtRepo2315)
|
|
1734
|
+
: SUBAGENT_PREFIX_DIRECT;
|
|
1735
|
+
process.stderr.write('[dispatch] cross-project detected (' + ROOT + ' vs ' + projectPath + ') — isolation mode: ' + iso.mode + '\n');
|
|
1736
|
+
}
|
|
1737
|
+
// TASK_2082 defect fix: when promptText's body carries the "## Rust check"
|
|
1738
|
+
// section (appendWorkflow -> appendRustCheckReminder), hard rule 4's
|
|
1739
|
+
// "Rust 交 Ansuz" wording inside the chosen prefix is contradictory — a
|
|
1740
|
+
// later "this overrides rule 4" note in the body was observed NOT
|
|
1741
|
+
// winning against the earlier hard rule. Rewrite the prefix itself at
|
|
1742
|
+
// this composition point instead; a body without the section marker
|
|
1743
|
+
// leaves the prefix byte-identical.
|
|
1744
|
+
subagentPrefix = applyRustCheckToPrefix(subagentPrefix, promptText);
|
|
1745
|
+
promptText = subagentPrefix + promptText;
|
|
1746
|
+
|
|
1747
|
+
// 6. Model (translated to the Agent tool enum, step 2c) + dispatchMode
|
|
1748
|
+
// (step 2b routing guard) were resolved above.
|
|
1749
|
+
|
|
1750
|
+
// TASK_1593: the Agent tool derives its worktree directory and branch from the
|
|
1751
|
+
// CONVERSATION id alone, so concurrent sub-agents of one session would collide on a
|
|
1752
|
+
// single worktree. That is HARNESS behaviour, upstream of us.
|
|
1753
|
+
//
|
|
1754
|
+
// TASK_1833 correction (2026-07-31): in THIS repo they no longer collide, and the
|
|
1755
|
+
// previous text here — "two parallel dispatches from the same Ansuz session share one
|
|
1756
|
+
// worktree directory" — is now FALSE. Registering .claude/hooks/worktree-create.js as
|
|
1757
|
+
// a WorktreeCreate hook makes the harness delegate creation entirely to that hook,
|
|
1758
|
+
// which DISCARDS the proposed path and synthesizes wt-<sid8>-<pid> (makeWtName), then
|
|
1759
|
+
// uniquifies the directory and the branch independently. Each hook invocation is its
|
|
1760
|
+
// own `node -e` process so the pid differs per sub-agent; the uniquify loops are what
|
|
1761
|
+
// actually guarantee correctness, since Windows recycles pids aggressively. Measured:
|
|
1762
|
+
// one session produced wt-8c83ecc1-12492 and wt-8c83ecc1-12624 for two concurrent
|
|
1763
|
+
// dispatches, and ten distinct wt-e989b14a-* trees exist from one earlier session.
|
|
1764
|
+
//
|
|
1765
|
+
// So parallel sub-agent dispatch from one Ansuz session IS safe here. Do not cite this
|
|
1766
|
+
// block as a reason to serialize — the stale version of this comment cost a round of
|
|
1767
|
+
// throughput on 2026-07-31 by talking a reader out of parallelizing. The historical
|
|
1768
|
+
// incident (TASK_1610/1611) was NOT collision-by-sharing: an older worktree-create.js
|
|
1769
|
+
// ran `worktree remove --force` for "idempotency" and destroyed a live sibling's
|
|
1770
|
+
// worktree mid-task. That path is gone (TASK_1639); the hook now never claims an
|
|
1771
|
+
// existing path.
|
|
1772
|
+
//
|
|
1773
|
+
// Still true: the description field does not affect the worktree name, and per-TASK
|
|
1774
|
+
// naming (task_<taskid>) requires the formation path via
|
|
1775
|
+
// formations.setupUnitWorktree({ taskId }).
|
|
1776
|
+
const agentParams = isCodex ? undefined : {
|
|
1777
|
+
// Include taskInput so the Agent tool description is unique per task (helps tracing)
|
|
1778
|
+
description: `[${taskInput}] Kenaz subagent (${skill})`,
|
|
1779
|
+
model: dispatchModel,
|
|
1780
|
+
// TASK_1672: omit Agent-tool isolation for cross-project dispatch — its worktree
|
|
1781
|
+
// would be rooted in the core/non-git cwd, not the sub-project repo. TASK_1833:
|
|
1782
|
+
// cross-project isolation is instead provided by the pre-created target-repo
|
|
1783
|
+
// worktree (target_repo_worktree) or by dispatch-lock serialization (serial_lock).
|
|
1784
|
+
...(isCrossProject ? {} : { isolation: 'worktree' }),
|
|
1785
|
+
// run_in_background: false → Ansuz awaits result directly (no log polling)
|
|
1786
|
+
};
|
|
1787
|
+
|
|
1788
|
+
// TASK_1833: isolation metadata rides NEXT TO agentParams (same reason as
|
|
1789
|
+
// modelTranslation — the Agent tool schema rejects unknown fields). Ansuz
|
|
1790
|
+
// needs it to: merge the target-repo worktree branch after the agent returns,
|
|
1791
|
+
// and to release the serial dispatch lock after merge.
|
|
1792
|
+
const isolation = {
|
|
1793
|
+
mode: iso.mode,
|
|
1794
|
+
source: iso.source,
|
|
1795
|
+
worktreePath: crossWorktree ? crossWorktree.worktreePath : null,
|
|
1796
|
+
branchName: crossWorktree ? crossWorktree.branchName : null,
|
|
1797
|
+
// TASK_2067: true when an existing task/<id> branch (worktree missing,
|
|
1798
|
+
// e.g. a cancelled task resumed) was reused rather than created fresh.
|
|
1799
|
+
reusedBranch: crossWorktree ? !!crossWorktree.reusedBranch : false,
|
|
1800
|
+
// TASK_2067: non-null only when target_repo_worktree creation genuinely
|
|
1801
|
+
// failed and dispatch degraded to serial_lock -- never set for the
|
|
1802
|
+
// reused-branch case above, which is not a degradation.
|
|
1803
|
+
worktreeFallbackReason,
|
|
1804
|
+
serialLock: serialLock
|
|
1805
|
+
? {
|
|
1806
|
+
lockFile: serialLock.lockFile,
|
|
1807
|
+
// TASK_1859: release contract is now the CLI (executable where
|
|
1808
|
+
// Bash(rm *) is denied); deleting the file stays as the fallback.
|
|
1809
|
+
releaseCommand: `node .formation/tools/dispatch.js --release-lock${projectPath ? ` --project-path "${projectPath}"` : ''}`,
|
|
1810
|
+
note: 'Release after the agent finishes and its work is merged: run releaseCommand (same session; add --force cross-session). Fallback: delete lockFile. Auto-breaks 60min after acquisition.',
|
|
1811
|
+
}
|
|
1812
|
+
: null,
|
|
1813
|
+
// TASK_2176: project's .kenaz/project.yaml verify_offline command, or
|
|
1814
|
+
// null (today's behaviour) when absent. The worktree agent already got
|
|
1815
|
+
// it as a non-authoritative self-check instruction above; this lets the
|
|
1816
|
+
// caller (Ansuz) pass it to verify-and-land.js at landing, where it runs
|
|
1817
|
+
// as the authoritative, serialized gate on the main tree.
|
|
1818
|
+
verifyOffline: iso.verifyOffline || null,
|
|
1819
|
+
};
|
|
1820
|
+
|
|
1821
|
+
// TASK_1815: modelTranslation rides NEXT TO agentParams (not inside it) so
|
|
1822
|
+
// the Agent tool payload stays pure while the caller (Ansuz) still SEES the
|
|
1823
|
+
// requested-vs-emitted model and the granularity loss. Do not fold it into
|
|
1824
|
+
// agentParams — the Agent tool schema would reject unknown fields.
|
|
1825
|
+
// TASK_1859: dispatchMode is the TASK_1813 CONFIG ECHO (what
|
|
1826
|
+
// dashboard-models.json requested: formation|subagent|auto) — do NOT change
|
|
1827
|
+
// its semantics, subagent-bifrost-guard.test.js pins them. effectiveMode is
|
|
1828
|
+
// the path this dispatch ACTUALLY took; this function IS the subagent path,
|
|
1829
|
+
// so consumers reading the payload of a --dispatch-mode=subagent run can see
|
|
1830
|
+
// 'subagent' even when the config echo says 'formation'.
|
|
1831
|
+
|
|
1832
|
+
// TASK_1998 R1a: telemetry — one JSONL line per sub-agent dispatch.
|
|
1833
|
+
// R3: modelSource rides along so dispatch-stats.js can break down turns/sec
|
|
1834
|
+
// by dashboard vs dashboard-by-rigor vs cli without re-deriving it.
|
|
1835
|
+
// Two-axis policy: complexity rides along too, so dispatch-stats.js can
|
|
1836
|
+
// group by (rigor, complexity) instead of rigor alone.
|
|
1837
|
+
if (!dryRun) appendDispatchPromptStats({ taskId: taskInput, rigor: resolution.rigorKey, complexity, formation, promptText, model: dispatchModel, modelSource: resolution.source, projectPath });
|
|
1838
|
+
|
|
1839
|
+
// TASK_2032: mirror headless.js's formation-path auto-activation (~L272-290)
|
|
1840
|
+
// on the subagent path — every gate/guard above has passed and this function
|
|
1841
|
+
// is about to return a real payload, so move the card backlog -> active NOW.
|
|
1842
|
+
// Root cause this fixes: the formation path activates the card before the
|
|
1843
|
+
// agent runs, but this function never did, so a --dispatch-mode=subagent
|
|
1844
|
+
// card sat in backlog/ the whole time the subagent worked — and afterwards
|
|
1845
|
+
// `task-api move <id> done` was rejected ("backlog -> done not allowed"),
|
|
1846
|
+
// forcing a backlog->active->done two-step every time.
|
|
1847
|
+
// Unlike headless.js, this does NOT git-commit the status change: the
|
|
1848
|
+
// subagent never reads the task dir (buildPrompt already inlined taskData
|
|
1849
|
+
// above) and post-complete's merge runs in the main tree, so there is no
|
|
1850
|
+
// worktree-forks-from-stale-HEAD problem to solve here.
|
|
1851
|
+
// Skipped for dryRun (same "no side effects" contract as the resource
|
|
1852
|
+
// leases / worktree / serial lock / telemetry above) and for non-TASK_
|
|
1853
|
+
// (ad-hoc) inputs, which have no card to move.
|
|
1854
|
+
// Non-fatal by design: already-active, an invalid transition, or task-api
|
|
1855
|
+
// being unavailable must never fail a dispatch that has otherwise succeeded
|
|
1856
|
+
// — log one stderr line and continue.
|
|
1857
|
+
if (!dryRun && taskInput && /^TASK_\d+$/i.test(taskInput)) {
|
|
1858
|
+
try {
|
|
1859
|
+
const projectArg = _saRoot !== ROOT ? ` --project-path "${_saRoot}"` : '';
|
|
1860
|
+
execSync(
|
|
1861
|
+
`node "${COLLABORATION_API}"${projectArg} move ${taskInput} active`,
|
|
1862
|
+
{ encoding: 'utf8', cwd: _saRoot, timeout: 10000, windowsHide: true, stdio: ['pipe', 'pipe', 'pipe'] }
|
|
1863
|
+
);
|
|
1864
|
+
process.stderr.write(`[dispatch] Auto-activated: ${taskInput} → active/\n`);
|
|
1865
|
+
} catch (e) {
|
|
1866
|
+
// Non-fatal: task may already be active, completed, or in an incompatible state.
|
|
1867
|
+
const msg = (e.stderr || e.message || '').toString().split('\n')[0];
|
|
1868
|
+
process.stderr.write(`[dispatch] Auto-activate skipped: ${msg}\n`);
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
// TASK_1998 R3: rigor + modelSource ride NEXT TO agentParams (same reason as
|
|
1873
|
+
// modelTranslation/isolation — the Agent tool schema rejects unknown fields
|
|
1874
|
+
// on agentParams itself). rigor is the NORMALIZED key (null/unrecognized →
|
|
1875
|
+
// 'medium') that actually drove model resolution, not the raw card field.
|
|
1876
|
+
// complexity is likewise the normalized CONTEXT-volume key.
|
|
1877
|
+
return {
|
|
1878
|
+
promptText, taskId: taskInput, formation, skill, dispatchMode, effectiveMode: 'subagent',
|
|
1879
|
+
...(isCodex ? { harness: 'codex', cwd: crossWorktree ? crossWorktree.worktreePath : null, worktreePath: crossWorktree ? crossWorktree.worktreePath : null } : {}),
|
|
1880
|
+
modelTranslation, isolation, ...(agentParams ? { agentParams } : {}), rigor: resolution.rigorKey, complexity, modelSource: resolution.source,
|
|
1881
|
+
...(dryRun ? { dryRun: true } : {}),
|
|
1882
|
+
};
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
/**
|
|
1886
|
+
* TASK_1833: pre-create an isolated worktree INSIDE the target sub-project repo
|
|
1887
|
+
* for a cross-project sub-agent dispatch. Naming matches the Formation path
|
|
1888
|
+
* (formations.setupUnitWorktree: .formation/worktrees/task_<id>, branch
|
|
1889
|
+
* task/<id>) so post-complete's worktree merge machinery finds it unchanged.
|
|
1890
|
+
* Reuses utils.createWorktree — index.lock wait, retry/backoff, stale-branch
|
|
1891
|
+
* and partial-dir cleanup all included. Throws on final failure (caller falls
|
|
1892
|
+
* back to serialized shared-tree mode — never to unserialized writes).
|
|
1893
|
+
* thrift: no MAX_PARALLEL semaphore / dirty-snapshot here (those live in the
|
|
1894
|
+
* long-lived Formation process; this CLI exits immediately). Sub-agent
|
|
1895
|
+
* cross-project dispatch is Ansuz-driven and low-fanout today — add the
|
|
1896
|
+
* semaphore if parallel cross-project sub-agent dispatch becomes routine.
|
|
1897
|
+
* @param {string} projectPath - target repo root
|
|
1898
|
+
* @param {string} taskInput - TASK_XXX id or free-text description
|
|
1899
|
+
* @returns {{ worktreePath: string, branchName: string }}
|
|
1900
|
+
*/
|
|
1901
|
+
function setupSubagentCrossProjectWorktree(projectPath, taskInput) {
|
|
1902
|
+
const idBase = (taskInput && taskInput.startsWith('TASK_'))
|
|
1903
|
+
? taskInput.toLowerCase()
|
|
1904
|
+
: `adhoc_${Date.now().toString(36)}`;
|
|
1905
|
+
const worktreePath = path.join(projectPath, '.formation', 'worktrees', `task_${idBase}`);
|
|
1906
|
+
const branchName = `task/${idBase}`;
|
|
1907
|
+
// createWorktree logs progress via console.log (fine on the Formation path),
|
|
1908
|
+
// but subagent mode's stdout is machine-readable JSON — redirect to stderr
|
|
1909
|
+
// for the duration of the call so the payload stays parseable.
|
|
1910
|
+
const origLog = console.log;
|
|
1911
|
+
console.log = (...a) => console.error(...a);
|
|
1912
|
+
let created;
|
|
1913
|
+
try {
|
|
1914
|
+
ensureWorktreeDirIgnored(projectPath);
|
|
1915
|
+
created = createWorktree(projectPath, worktreePath, branchName);
|
|
1916
|
+
} finally {
|
|
1917
|
+
console.log = origLog;
|
|
1918
|
+
}
|
|
1919
|
+
// TASK_2067: createWorktree returns { reusedBranch, divergence } when it
|
|
1920
|
+
// attached to a pre-existing task/<id> branch instead of creating a new
|
|
1921
|
+
// one (e.g. a cancelled task resumed) -- surface it so the caller can
|
|
1922
|
+
// report reuse in the dispatch payload instead of only in stderr logs.
|
|
1923
|
+
return {
|
|
1924
|
+
worktreePath,
|
|
1925
|
+
branchName,
|
|
1926
|
+
reusedBranch: !!(created && created.reusedBranch),
|
|
1927
|
+
divergence: (created && created.divergence) || null,
|
|
1928
|
+
};
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
module.exports = { dispatch, getSubagentDispatchParams, checkDispatchScopeGate, releaseDispatchLock, resolveDispatchIsolation, _getProvenSessionId, _getOwnConversationId, _isOwnClaimMarker, _buildCortexContext: buildCortexContext };
|