elanous 0.2.18 → 0.2.20
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/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/{1307-30dff22c9e1f3073.js → 1307-77fad80cf54477c6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1612-f60c0c93ec773f81.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2116-6429c188eb846ab8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/224-e7be8f762fe74986.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2489-ff55a35b202c0f94.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2549-89c518a4c8ed4d00.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3857-995ea9f5ef33d71e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5755-ea7ed88eb956f47b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5977-94ed6f78e9814b2b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7748-6e51bfe927019f5c.js +25 -0
- package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9247-c1753a059e7bac08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/a9f2b54d-33c0689b70ed8cf3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/{page-d92f7ee3994e84c7.js → page-c855c24de7db74fe.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-4733c967b56a4277.js → page-85b316bb4235980b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/board/{page-d22fd849cc22f104.js → page-9b2b26a33cb2cd42.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-bb742f995c6769e7.js → page-c9955fde67b1bcb5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/{page-02b073a2ac793b83.js → page-7a852956c74015a3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c5a5c621be0e04ae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/{page-8a9b3594bc23289b.js → page-4ba4abe096b6c2a8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-575d4a8b4f7becb2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/{page-308111abadf35670.js → page-f5d56ff5f45ad164.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-2260e9eef0357421.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/{page-5d97b2901e0d1ea6.js → page-7c058069c5e7fa63.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-dc5da0b8a2edb8a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/{page-8c3d8e63ae2e1c98.js → page-466bf0ee16ad1432.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/field/{page-9b72a07d424701c6.js → page-a23bc71713bcc08f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ed4a6f799f005d09.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/{page-a572f58cd3ca5864.js → page-9cd565005b93aca6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-55f0f40c6db95f15.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/{page-be5ea965a07fbc41.js → page-474cb5888ea0e8f3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-35bfec2e631d3eae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/{page-fa244bd146a00ae8.js → page-9ca21f9ad3208a61.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-44d56d6391965a6a.js → page-f9ccb1b1adbea14d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-83a700d4c754d802.js → page-ec102c9b8b691e37.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/{not-found-7b3170f374f77b9d.js → not-found-a9c2cfa8dda922a5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-6da35144878feb6d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-f6055495e9ed7ea8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-25204694fa9984a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-a60e035f151d84d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-189c587f36874538.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-c56634bde705a65d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/{page-1467047104141297.js → page-db03ae3589a81c9e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-4a6463b97f0ad94f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/{page-102310930791197a.js → page-75bffecc9aa1004e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a8d2fe0c669e0de4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/{page-6ed0b73bae8351d8.js → page-31d5b875760bb62d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c26fa10aac6c21c4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/{page-43336055451f6e37.js → page-68793c6e10331d66.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/share/{page-3cc47dca0922ab9a.js → page-46d5201d2207a511.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/{page-a77ee355a2304ff0.js → page-d81c07a7b4f618ae.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/{page-b17cd46cf0e9b8cf.js → page-be1c4e8697f22360.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-cf0a4b4abead71ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-a4717e2c4bf7a28f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/{page-7bf54c9bb9274af8.js → page-0fd895fab9b62c1b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-8b6c1454a8e8f306.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-c6e4364d9de8f717.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-0acc8e198f7b0dfb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/{page-134da468538baf48.js → page-34882c84f84021c5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-0506a1e0e4bdb2f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{webpack-c2782b330447ffb6.js → webpack-c260571513bf43c2.js} +1 -1
- package/apps/pwa/out/_next/static/css/{e99e3cff94ced78a.css → 599369d853c61df7.css} +1 -1
- package/apps/pwa/out/_next/static/css/c23d959d3ee15e57.css +1 -0
- package/apps/pwa/out/_next/static/css/d3427996da11e480.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +14 -14
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +14 -14
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +14 -14
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +14 -14
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +14 -14
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +14 -14
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +14 -14
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +14 -14
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +14 -14
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +14 -14
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +14 -14
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +16 -15
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +14 -14
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +14 -14
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +14 -14
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +16 -15
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +14 -14
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +14 -14
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +24 -23
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +14 -14
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +14 -14
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +14 -14
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +14 -14
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +14 -14
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +14 -14
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +14 -14
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +14 -14
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +15 -15
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +14 -14
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +14 -14
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +14 -14
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +14 -14
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +14 -14
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +14 -14
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +14 -14
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +14 -14
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +14 -14
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +14 -14
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +14 -14
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +14 -14
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +14 -14
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +14 -14
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +14 -14
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +14 -14
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +14 -14
- package/graphs/demo/editor-recipes.yaml +22 -0
- package/graphs/ops/guardian.yaml +26 -0
- package/graphs/ops/recipes.yaml +3 -0
- package/graphs/retro/daily.yaml +25 -0
- package/graphs/retro/recipes.yaml +24 -0
- package/package.json +1 -1
- package/scripts/ask-marker-check.ts +3 -1
- package/scripts/coord-channel-watch.sh +2 -2
- package/scripts/discord-seat-probe.ts +3 -1
- package/scripts/land-global-checks.ts +89 -0
- package/scripts/lib/pch-regress-map.ts +24 -0
- package/scripts/morning-report.ts +18 -4
- package/scripts/pch-regress.ts +88 -0
- package/scripts/release-loop/gate-diff.ts +18 -0
- package/scripts/release-loop/gate-node.ts +628 -65
- package/scripts/release-loop/gate-partial.ts +106 -0
- package/scripts/release-loop/gate-timing.ts +229 -0
- package/scripts/release-loop/preflight.ts +6 -4
- package/scripts/release-loop/publish-window.ts +141 -0
- package/scripts/release-loop/release-docs.ts +1 -4
- package/scripts/release-loop/release-universe.ts +38 -0
- package/scripts/release-loop/resume-release.ts +67 -5
- package/scripts/release-loop/shard-plan.ts +65 -0
- package/scripts/release-loop/unattended-release.ts +12 -2
- package/scripts/release-story/draft.ts +5 -1
- package/scripts/retro/shadow-compare.ts +71 -0
- package/scripts/rhythm/daily.ts +6 -1
- package/scripts/video/scene-table.ts +159 -0
- package/src/acp/core-turn-bridge.ts +39 -2
- package/src/agent-mission/driver.ts +34 -6
- package/src/autopilot/build/llm-conflict-merge.ts +132 -7
- package/src/autopilot/build/merge-intent.ts +135 -7
- package/src/away/presence.ts +40 -0
- package/src/away/release-watch.ts +272 -0
- package/src/chat/index.ts +2 -1
- package/src/chat/short-question.ts +3 -40
- package/src/cli/away-cli.ts +68 -0
- package/src/cli/config-drift.ts +513 -0
- package/src/cli/guardian-cli.ts +49 -0
- package/src/cli/intake-cli.ts +13 -7
- package/src/cli/log-event-names.ts +5 -0
- package/src/cli/pod-cli.ts +5 -1
- package/src/cli/pr-cli.ts +20 -0
- package/src/cli/pty-drive-cli.ts +14 -3
- package/src/cli/release-cli.ts +52 -12
- package/src/cli/retro-cli.ts +78 -0
- package/src/cli/setup-cli.ts +31 -1
- package/src/cli/tasks-cli.ts +193 -14
- package/src/context-bus/context-now-public.ts +1 -1
- package/src/context-bus/context-now-surfaces.ts +16 -6
- package/src/context-bus/context-now.ts +97 -3
- package/src/core-turn/short-question.ts +100 -0
- package/src/dashboard/dashboard-status-lines.ts +24 -4
- package/src/dashboard/index.ts +50 -5
- package/src/dashboard/input/slash-executor.ts +6 -2
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +68 -40
- package/src/dashboard/slash-runtime/decide-slash.ts +60 -0
- package/src/dashboard/slash-runtime/help-from-registry.ts +62 -23
- package/src/dashboard/slash-runtime/help-groups.ts +44 -0
- package/src/dashboard/slash-runtime/model-choices.ts +125 -0
- package/src/domains/guardian-tick.ts +138 -0
- package/src/domains/outbound-alert.ts +44 -13
- package/src/domains/outbound-log-probe.ts +6 -1
- package/src/domains/schedule-registry.ts +23 -0
- package/src/domains/telegram-kind-route.ts +39 -0
- package/src/domains/watch-default-scheduler.ts +95 -0
- package/src/esc-abort-gate.ts +44 -0
- package/src/graph-runner/graph-run-api.ts +205 -0
- package/src/graph-runner/runner.ts +36 -6
- package/src/harness/harness-cli-command.ts +420 -51
- package/src/harness/harness-queue.ts +315 -25
- package/src/harness/harness-salvage-cli.ts +140 -0
- package/src/harness/harness-worktree-add.ts +68 -0
- package/src/harness/ledger-write-guard.ts +6 -16
- package/src/hq/fence-outcomes.ts +63 -0
- package/src/hq/fence-wrapper.ts +33 -0
- package/src/hq/hq.ts +17 -2
- package/src/index.ts +118 -6
- package/src/instance/test-write-guard-spy-first.fixture.ts +13 -0
- package/src/instance/test-write-guard.ts +200 -0
- package/src/intake-plane/digest.ts +39 -15
- package/src/intake-plane/harness-target.ts +4 -3
- package/src/intake-plane/intake-sources.ts +1 -0
- package/src/intake-plane/items.ts +1 -0
- package/src/loops/orchestrator/degradation.ts +57 -0
- package/src/loops/orchestrator/finish-rate.ts +33 -3
- package/src/loops/orchestrator/tick.ts +166 -45
- package/src/maturity/feature-maturity.ts +6 -4
- package/src/maturity/tui-slash-maturity.ts +1 -0
- package/src/mss/logging/log-store.ts +3 -0
- package/src/nexus/api/graph-kinds.ts +10 -4
- package/src/nexus/api/graphs-api.ts +178 -6
- package/src/nexus/api/http-server.ts +54 -8
- package/src/nexus/api/loop-edges.ts +292 -17
- package/src/nexus/api/ops-api.ts +112 -29
- package/src/nexus/api/ops-board-route.ts +48 -0
- package/src/nexus/index.ts +7 -0
- package/src/onboarding/entry-hints.ts +5 -0
- package/src/onboarding.ts +24 -6
- package/src/release-loop/checklist.ts +2 -0
- package/src/release-loop/feature-store.ts +68 -18
- package/src/release-loop/gate-shards.ts +158 -0
- package/src/release-loop/light-rc.ts +173 -0
- package/src/release-loop/placement.ts +51 -17
- package/src/release-loop/release-schedule.ts +6 -2
- package/src/release-loop/rubric.ts +57 -1
- package/src/retro/daily.ts +372 -0
- package/src/seat-loop/op-decide.ts +173 -0
- package/src/seat-loop/seat-loop.ts +60 -3
- package/src/seat-loop/seat-report.ts +58 -3
- package/src/self-dev/ask-launch-flow.ts +5 -4
- package/src/self-dev/ask-launch-io.ts +49 -1
- package/src/self-dev/ask-path-candidates.ts +40 -2
- package/src/self-dev/dev-cli.ts +36 -0
- package/src/self-dev/draft-sweep.ts +371 -16
- package/src/self-dev/draft-triage-rules.ts +19 -4
- package/src/self-dev/orchestrate.ts +1 -0
- package/src/self-dev/pr-preview.ts +247 -0
- package/src/self-dev/shard-run.ts +23 -7
- package/src/self-implement/blocked-draft-policy.ts +101 -0
- package/src/self-implement/execution-clarification.ts +11 -0
- package/src/self-implement/gate-cli.ts +29 -8
- package/src/self-implement/gate-env-retry.ts +83 -0
- package/src/self-implement/goal-author-clarification.ts +88 -13
- package/src/self-implement/goal-clarification-escalation.ts +2 -0
- package/src/self-implement/orchestrator.ts +220 -6
- package/src/self-implement/run-stop.ts +123 -0
- package/src/self-implement/run-ttl.ts +258 -0
- package/src/self-implement/salvage-branches.ts +254 -0
- package/src/self-implement/salvage-retention.ts +123 -0
- package/src/self-implement/seams.ts +4 -0
- package/src/self-implement/self-implement-cli.ts +2 -0
- package/src/self-implement/sibling-resync.ts +223 -0
- package/src/self-implement/stop-autoheal.ts +204 -0
- package/src/task-agent/actions.ts +63 -2
- package/src/task-agent/board.ts +132 -0
- package/src/task-agent/card-evidence.ts +292 -0
- package/src/task-agent/completion-evidence.ts +126 -0
- package/src/task-agent/judge.ts +25 -0
- package/src/task-agent/live-moves.ts +276 -0
- package/src/task-agent/mission.ts +33 -7
- package/src/task-agent/shadow.ts +192 -15
- package/src/task-agent/task-hand.ts +124 -17
- package/src/task-orchestrator/surfaces/pod-command-job.ts +82 -8
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +4 -0
- package/src/task-orchestrator/surfaces/pod-install-slots.ts +89 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +233 -21
- package/src/task-orchestrator/surfaces/pod-pool.ts +155 -34
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +21 -5
- package/src/telegram-away-command.ts +38 -0
- package/src/telegram-commands.ts +52 -0
- package/src/telegram-report-log-probe.ts +21 -0
- package/src/telegram-report.ts +27 -3
- package/src/testing/real-cli-spawn.ts +106 -0
- package/src/tui-client/dashboard-session.ts +1 -0
- package/src/user-config.ts +190 -5
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3857-4f936cdb30322aa6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4554-5761612531d0146b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-a11f37254196b659.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8401-8615a660c84cdb03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +0 -25
- package/apps/pwa/out/_next/static/chunks/9247-269e4464cc4b491c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/a9f2b54d-7865aba0f4d2ee49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-60c3da708f9a0ccc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-a0eb02638b1e6f31.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-6eaf7bac37830c21.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-c39554c321576982.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-bd5d586429167fea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-59b7834d497c2255.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-c130b63862437814.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-5f23d0c66a3b4793.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-a3c58f5c72a5f3f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a2c4625596f8d69c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-0e9099531d239f11.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-e8e1ecaea7cd71d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-a1b7ffed710a93e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-2da6f9b8a38c6978.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-f331e38fefc00393.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-44d5f767491692bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-61553851aa606146.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-a1f585e154e61c59.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-5150ef17b5383a57.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b9d8ce70792c1672.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-a5a3de231f2cc7d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31ac4afa2dcd915c.js +0 -1
- package/apps/pwa/out/_next/static/css/7fa358fec7da7c47.css +0 -1
- /package/apps/pwa/out/_next/static/{P6YTVgzuZz5oTZhY4Din_ → Bam1YziK2iH9bN4K0utGk}/_buildManifest.js +0 -0
- /package/apps/pwa/out/_next/static/{P6YTVgzuZz5oTZhY4Din_ → Bam1YziK2iH9bN4K0utGk}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ⏱️ GATE-SPEED ③ — 실물 엔트리 spawn 을 «비동기 ⊕ 상한 있는 동시성»으로 돌리는 테스트 전용 도구.
|
|
3
|
+
*
|
|
4
|
+
* Situation: 배선 시험(`bin/elanous.mjs` 실물 spawn)은 1회 ~3–4초(전 모듈 그래프 콜드 스타트)이고,
|
|
5
|
+
* `spawnSync` 로 줄 세우면 파일 하나가 게이트 임계 경로(수백 초)를 잡는다.
|
|
6
|
+
* Answer: 시험이 문는 값(실물 프로세스의 stdout·stderr·종료 코드·시그널)은 그대로 두고,
|
|
7
|
+
* «기다리는 방식»만 바꾼다 — `describe.concurrent` 안에서 이 함수를 `await` 하면 서로 독립인
|
|
8
|
+
* spawn 들이 `REAL_CLI_SPAWN_CONCURRENCY` 개까지 겹쳐 돈다.
|
|
9
|
+
*
|
|
10
|
+
* ⛔ 반환 모양은 `spawnSync(..., { encoding: 'utf8' })` 와 같다 — 시그널로 죽으면 `status` 는 null 이고
|
|
11
|
+
* `signal` 이 찬다. spawn 자체가 실패하면 `error` 가 찬다(타임아웃 = 0바이트 산출과 구분하려고).
|
|
12
|
+
* ⛔ spawn 의 `timeoutMs` 는 «슬롯을 얻은 뒤»부터 잰다 — 대기열에서 기다린 시간은 실패로 세지 않는다.
|
|
13
|
+
* 그래서 이 도구를 쓰는 시험의 «테스트» 타임아웃은 대기열 몫까지 넉넉히 둔다.
|
|
14
|
+
*/
|
|
15
|
+
import { availableParallelism } from 'node:os';
|
|
16
|
+
|
|
17
|
+
export interface RealCliSpawnResult {
|
|
18
|
+
stdout: string;
|
|
19
|
+
stderr: string;
|
|
20
|
+
status: number | null;
|
|
21
|
+
signal: string | null;
|
|
22
|
+
error?: Error;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface RealCliSpawnOptions {
|
|
26
|
+
cwd?: string;
|
|
27
|
+
env?: Record<string, string | undefined>;
|
|
28
|
+
timeoutMs: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function resolveConcurrency(): number {
|
|
32
|
+
const fromEnv = Number(process.env.ELANOUS_TEST_REAL_CLI_CONCURRENCY);
|
|
33
|
+
if (Number.isInteger(fromEnv) && fromEnv > 0) return fromEnv;
|
|
34
|
+
return Math.max(2, Math.min(6, Math.floor(availableParallelism() / 3)));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const REAL_CLI_SPAWN_CONCURRENCY = resolveConcurrency();
|
|
38
|
+
|
|
39
|
+
let active = 0;
|
|
40
|
+
const waiters: Array<() => void> = [];
|
|
41
|
+
|
|
42
|
+
async function withSlot<T>(run: () => Promise<T>): Promise<T> {
|
|
43
|
+
while (active >= REAL_CLI_SPAWN_CONCURRENCY) await new Promise<void>((resolve) => waiters.push(resolve));
|
|
44
|
+
active += 1;
|
|
45
|
+
try {
|
|
46
|
+
return await run();
|
|
47
|
+
} finally {
|
|
48
|
+
active -= 1;
|
|
49
|
+
waiters.shift()?.();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function definedEnv(env: Record<string, string | undefined>): Record<string, string> {
|
|
54
|
+
const out: Record<string, string> = {};
|
|
55
|
+
for (const [key, value] of Object.entries(env)) if (value !== undefined) out[key] = value;
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** `spawnSync(cmd[0], cmd.slice(1), { encoding: 'utf8' })` 의 비동기 대응 — 동시성 상한 안에서 돈다. */
|
|
60
|
+
export async function spawnRealCli(cmd: string[], options: RealCliSpawnOptions): Promise<RealCliSpawnResult> {
|
|
61
|
+
const r = await spawnRealCliBytes(cmd, options);
|
|
62
|
+
const decoder = new TextDecoder();
|
|
63
|
+
return {
|
|
64
|
+
stdout: decoder.decode(r.stdout),
|
|
65
|
+
stderr: decoder.decode(r.stderr),
|
|
66
|
+
status: r.exitCode,
|
|
67
|
+
signal: r.signal,
|
|
68
|
+
...(r.error ? { error: r.error } : {}),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface RealCliSpawnBytesResult {
|
|
73
|
+
/** `Bun.spawnSync` 와 같은 이름 — 시그널로 죽으면 null. */
|
|
74
|
+
exitCode: number | null;
|
|
75
|
+
stdout: Uint8Array;
|
|
76
|
+
stderr: Uint8Array;
|
|
77
|
+
signal: string | null;
|
|
78
|
+
error?: Error;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** `Bun.spawnSync({ cmd, stdout: 'pipe', stderr: 'pipe' })` 의 비동기 대응 — 바이트 그대로 돌려준다. */
|
|
82
|
+
export function spawnRealCliBytes(cmd: string[], options: RealCliSpawnOptions): Promise<RealCliSpawnBytesResult> {
|
|
83
|
+
return withSlot(async () => {
|
|
84
|
+
let proc: ReturnType<typeof Bun.spawn>;
|
|
85
|
+
try {
|
|
86
|
+
proc = Bun.spawn(cmd, {
|
|
87
|
+
cwd: options.cwd,
|
|
88
|
+
env: definedEnv(options.env ?? { ...process.env }),
|
|
89
|
+
stdin: 'ignore',
|
|
90
|
+
stdout: 'pipe',
|
|
91
|
+
stderr: 'pipe',
|
|
92
|
+
timeout: options.timeoutMs,
|
|
93
|
+
killSignal: 'SIGKILL',
|
|
94
|
+
});
|
|
95
|
+
} catch (error) {
|
|
96
|
+
return { stdout: new Uint8Array(), stderr: new Uint8Array(), exitCode: null, signal: null, error: error instanceof Error ? error : new Error(String(error)) };
|
|
97
|
+
}
|
|
98
|
+
const [stdout, stderr] = await Promise.all([
|
|
99
|
+
new Response(proc.stdout as ReadableStream).arrayBuffer(),
|
|
100
|
+
new Response(proc.stderr as ReadableStream).arrayBuffer(),
|
|
101
|
+
]);
|
|
102
|
+
await proc.exited;
|
|
103
|
+
const signal = proc.signalCode ?? null;
|
|
104
|
+
return { stdout: new Uint8Array(stdout), stderr: new Uint8Array(stderr), exitCode: signal ? null : proc.exitCode, signal };
|
|
105
|
+
});
|
|
106
|
+
}
|
|
@@ -195,6 +195,7 @@ export class DashboardSession {
|
|
|
195
195
|
const pair = createInProcessTransportPair();
|
|
196
196
|
const shutdownCtrl = new AbortController();
|
|
197
197
|
const runTurn = bridgeCoreTurnToAcp({
|
|
198
|
+
tuiRouting: true,
|
|
198
199
|
getMessages: opts.getMessages,
|
|
199
200
|
getTools: opts.getTools,
|
|
200
201
|
dispatchTool: opts.dispatchTool,
|
package/src/user-config.ts
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
// crashed wizard cannot corrupt an existing file. Mode 0600 when the
|
|
28
28
|
// telegram bot token is present.
|
|
29
29
|
|
|
30
|
+
import { DRAFT_ON_STOP_MODES, parseDraftOnStopMode, type DraftOnStopMode } from './self-implement/blocked-draft-policy.js';
|
|
30
31
|
import { isCodexQuotaPolicy } from './oauth/codex-quota-policy.js';
|
|
31
32
|
import { defaultObsidianVault } from './obsidian/default-vault.js';
|
|
32
33
|
import {
|
|
@@ -1146,6 +1147,12 @@ export interface SelfImplementToolConfig {
|
|
|
1146
1147
|
decompositionShadow: SelfImplementDecompositionShadowConfig;
|
|
1147
1148
|
/** Opt-in delivery of authored goal clarifications from unattended dev runs. */
|
|
1148
1149
|
clarificationEscalation: SelfImplementClarificationEscalationConfig;
|
|
1150
|
+
/** RUN-TTL: hours an open self-impl PR may go without a commit before the draft sweep asks for a rebase. Absent or invalid = 24. */
|
|
1151
|
+
runTtlHours?: number;
|
|
1152
|
+
/** RUN-TTL sweep step: `shadow` (default) only logs; `live` sends the resync memo / adds `elanous:needs-rebase`. Cap absent or invalid = 30. */
|
|
1153
|
+
runTtl?: { mode: 'shadow' | 'live'; cap?: number };
|
|
1154
|
+
/** STOP-AUTOHEAL: `shadow` (default) only records what the stop dispatcher would do (`event='autoheal'`); `live` runs the injected heal seams once per run per stop class. */
|
|
1155
|
+
autoheal?: { mode: 'shadow' | 'live' };
|
|
1149
1156
|
/** 사용자 자식 모델 선호. 없으면 해석기가 auto + fallbackChain 으로 만든다.
|
|
1150
1157
|
* Overload failover (OVERLOAD-FAILOVER) may move an unpinned codex child to
|
|
1151
1158
|
* grok. A pinned codex provider is never moved. */
|
|
@@ -1165,6 +1172,11 @@ export interface SelfImplementToolConfig {
|
|
|
1165
1172
|
* clean)로 남는다 — draft PR 은 닫고 브랜치를 지우면 되돌릴 수 있지만 병합은 아니다.
|
|
1166
1173
|
* `false` 로 두면 종전대로 `ux.confirm`(채널 없으면 fail-closed). */
|
|
1167
1174
|
autoOpenPr: boolean;
|
|
1175
|
+
/** DRAFT-NOT-ARCHIVE — 멈춘 런의 산출을 어디에 남기나. `'always'`(기본 · 종전) = draft PR ·
|
|
1176
|
+
* `'needs-owner-only'` = 사람 판단이 필요한 멈춤만 draft PR(⊕ 주인 자리 라벨), 나머지는 수확 가지 `salvage/run-<6hex>/…` ⊕ 런 원장. */
|
|
1177
|
+
draftOnStop?: DraftOnStopMode;
|
|
1178
|
+
/** SALVAGE-RETENTION — 원격 `salvage/*` 보존 규칙(14일 초과 ⊕ 열린 PR·카드 참조 0). `'shadow'`(기본) = 수만 보고 · `'live'` = 다음 조각에서 삭제. */
|
|
1179
|
+
salvageRetention?: { mode: 'shadow' | 'live' };
|
|
1168
1180
|
}
|
|
1169
1181
|
|
|
1170
1182
|
export interface RunDevHarnessToolConfig {
|
|
@@ -2670,6 +2682,18 @@ function parseToolsConfig(raw: unknown): ToolsConfig {
|
|
|
2670
2682
|
...(clarificationTimeoutMs === undefined ? {} : { timeoutMs: clarificationTimeoutMs }),
|
|
2671
2683
|
};
|
|
2672
2684
|
const childLlm = parseChildLlmPreference(selfImplRaw.childLlm);
|
|
2685
|
+
const runTtlHoursRaw = selfImplRaw.runTtlHours;
|
|
2686
|
+
const runTtlHours = typeof runTtlHoursRaw === 'number' && Number.isFinite(runTtlHoursRaw) && runTtlHoursRaw > 0 ? runTtlHoursRaw : undefined;
|
|
2687
|
+
const runTtlRaw = selfImplRaw.runTtl && typeof selfImplRaw.runTtl === 'object' && !Array.isArray(selfImplRaw.runTtl)
|
|
2688
|
+
? selfImplRaw.runTtl as Record<string, unknown> : undefined;
|
|
2689
|
+
const runTtl = runTtlRaw ? {
|
|
2690
|
+
mode: runTtlRaw.mode === 'live' ? 'live' as const : 'shadow' as const,
|
|
2691
|
+
...(typeof runTtlRaw.cap === 'number' && Number.isSafeInteger(runTtlRaw.cap) && runTtlRaw.cap >= 0 ? { cap: runTtlRaw.cap } : {}),
|
|
2692
|
+
} : undefined;
|
|
2693
|
+
const autohealRaw = selfImplRaw.autoheal && typeof selfImplRaw.autoheal === 'object' && !Array.isArray(selfImplRaw.autoheal)
|
|
2694
|
+
? selfImplRaw.autoheal as Record<string, unknown> : undefined;
|
|
2695
|
+
// ⛔ 모르는 값은 좁은 쪽(shadow) — 오타가 live 를 켜면 안 된다.
|
|
2696
|
+
const autoheal = autohealRaw ? { mode: autohealRaw.mode === 'live' ? 'live' as const : 'shadow' as const } : undefined;
|
|
2673
2697
|
// ⭐ 관측(리뷰 should-fix) — 오타/비-boolean 은 기본값(ON)으로 수렴하는데, 그게 조용하면
|
|
2674
2698
|
// "껐다고 믿었는데 자동 개설되는" 운영 사고가 된다. 값이 **있는데 boolean 이 아닐 때만**
|
|
2675
2699
|
// 경고한다(부재는 정상). 로거 대신 stderr — 이 파일의 기존 경고와 동형(부트 시점·의존 0).
|
|
@@ -2686,13 +2710,26 @@ function parseToolsConfig(raw: unknown): ToolsConfig {
|
|
|
2686
2710
|
const autoOpenPr = autoOpenPrRaw === false
|
|
2687
2711
|
? false
|
|
2688
2712
|
: TOOLS_DEFAULTS.selfImplement.autoOpenPr;
|
|
2713
|
+
const draftOnStopParsed = parseDraftOnStopMode((selfImplRaw as { draftOnStop?: unknown }).draftOnStop);
|
|
2714
|
+
if (draftOnStopParsed.invalid) {
|
|
2715
|
+
try {
|
|
2716
|
+
process.stderr.write(`[user-config] tools.selfImplement.draftOnStop 값이 알 수 없습니다(${JSON.stringify((selfImplRaw as { draftOnStop?: unknown }).draftOnStop)}) — 'always' 로 진행합니다. 허용값: ${DRAFT_ON_STOP_MODES.join(' | ')}\n`);
|
|
2717
|
+
} catch { /* swallow */ }
|
|
2718
|
+
}
|
|
2719
|
+
const draftOnStop = draftOnStopParsed.mode;
|
|
2720
|
+
const salvageRetentionRaw = (selfImplRaw as { salvageRetention?: unknown }).salvageRetention;
|
|
2721
|
+
const salvageRetentionModeRaw = salvageRetentionRaw && typeof salvageRetentionRaw === 'object' ? (salvageRetentionRaw as { mode?: unknown }).mode : undefined;
|
|
2722
|
+
if (salvageRetentionModeRaw !== undefined && salvageRetentionModeRaw !== 'shadow' && salvageRetentionModeRaw !== 'live') {
|
|
2723
|
+
try { process.stderr.write(`[user-config] tools.selfImplement.salvageRetention.mode 값이 알 수 없습니다(${JSON.stringify(salvageRetentionModeRaw)}) — 'shadow' 로 진행합니다. 허용값: shadow | live\n`); } catch { /* swallow */ }
|
|
2724
|
+
}
|
|
2725
|
+
const salvageRetention = { mode: salvageRetentionModeRaw === 'live' ? 'live' as const : 'shadow' as const };
|
|
2689
2726
|
return {
|
|
2690
2727
|
deferred: { mode },
|
|
2691
2728
|
agentSpawn: { hopCap },
|
|
2692
2729
|
runDevHarness,
|
|
2693
2730
|
selfOrchestrate,
|
|
2694
2731
|
nativeStructure,
|
|
2695
|
-
selfImplement: { worktreeRoot, childInstanceMode, prApprovalDelivery, observeOnly, goalRecordInDoc, goalAuthorPersistentGrounding, fabricDecompose, fabricDecomposeAutoPathThreshold, autoOpenPr, autoStop, autoAssist, screenStallTermination, reworkBudget, decompositionShadow, clarificationEscalation, ...(childLlm ? { childLlm } : {}) },
|
|
2732
|
+
selfImplement: { worktreeRoot, childInstanceMode, prApprovalDelivery, observeOnly, goalRecordInDoc, goalAuthorPersistentGrounding, fabricDecompose, fabricDecomposeAutoPathThreshold, autoOpenPr, draftOnStop, salvageRetention, autoStop, autoAssist, screenStallTermination, reworkBudget, decompositionShadow, clarificationEscalation, ...(childLlm ? { childLlm } : {}), ...(runTtlHours !== undefined ? { runTtlHours } : {}), ...(runTtl ? { runTtl } : {}), ...(autoheal ? { autoheal } : {}) },
|
|
2696
2733
|
};
|
|
2697
2734
|
}
|
|
2698
2735
|
|
|
@@ -3491,6 +3528,8 @@ export interface OrchestratorLoopConfig {
|
|
|
3491
3528
|
mode: 'off' | 'shadow' | 'live';
|
|
3492
3529
|
seatTrees: Partial<Record<OrchestratorSeat, string[]>>;
|
|
3493
3530
|
seatCaps: Record<OrchestratorSeat, number>;
|
|
3531
|
+
/** Max new delegations per tick; absent means no limit. */
|
|
3532
|
+
maxDelegatePerTick?: number;
|
|
3494
3533
|
/** Per-seat release gate; absent seats retain the spawn-budget default. */
|
|
3495
3534
|
releaseGate?: Partial<Record<OrchestratorSeat, number>>;
|
|
3496
3535
|
trafficMode: 'shadow' | 'live';
|
|
@@ -3502,6 +3541,9 @@ export interface OrchestratorLoopConfig {
|
|
|
3502
3541
|
handToTaskAgent?: 'off' | 'shadow' | 'live';
|
|
3503
3542
|
/** Demo: hand only this cell id (others keep the seat path). Absent = every delegatable cell. */
|
|
3504
3543
|
handToTaskAgentCell?: string;
|
|
3544
|
+
/** COORD-HA — the tick CLI probes LLM ⊕ task board for the degradation ladder. Absent = shadow (probe and log only) ·
|
|
3545
|
+
* live = the tick acts on it (L1 rules only · L2 no new assignment) · off = no probe. */
|
|
3546
|
+
degradationSignal?: 'off' | 'shadow' | 'live';
|
|
3505
3547
|
}
|
|
3506
3548
|
|
|
3507
3549
|
export const ORCHESTRATOR_DEFAULTS: OrchestratorLoopConfig = {
|
|
@@ -3527,12 +3569,16 @@ export function parseOrchestratorLoopConfig(raw: unknown): OrchestratorLoopConfi
|
|
|
3527
3569
|
if (typeof gate === 'number' && Number.isSafeInteger(gate) && gate >= 0) releaseGate[seat] = gate;
|
|
3528
3570
|
}
|
|
3529
3571
|
const mode = value.mode === 'off' || value.mode === 'live' ? value.mode : 'shadow';
|
|
3530
|
-
|
|
3572
|
+
const maxDelegatePerTick = value.maxDelegatePerTick;
|
|
3573
|
+
return { mode, seatTrees, seatCaps,
|
|
3574
|
+
...(typeof maxDelegatePerTick === 'number' && Number.isSafeInteger(maxDelegatePerTick) && maxDelegatePerTick >= 0 ? { maxDelegatePerTick } : {}),
|
|
3575
|
+
...(Object.keys(releaseGate).length ? { releaseGate } : {}),
|
|
3531
3576
|
trafficMode: value.trafficMode === 'live' ? 'live' : 'shadow',
|
|
3532
3577
|
idleRequest: value.idleRequest === 'off' || value.idleRequest === 'live' ? value.idleRequest : 'shadow',
|
|
3533
3578
|
finishGate: value.finishGate === 'off' || value.finishGate === 'on' ? value.finishGate : 'shadow',
|
|
3534
3579
|
...(value.handToTaskAgent === 'shadow' || value.handToTaskAgent === 'live' ? { handToTaskAgent: value.handToTaskAgent } : {}),
|
|
3535
|
-
...(typeof value.handToTaskAgentCell === 'string' && value.handToTaskAgentCell.trim() ? { handToTaskAgentCell: value.handToTaskAgentCell.trim() } : {})
|
|
3580
|
+
...(typeof value.handToTaskAgentCell === 'string' && value.handToTaskAgentCell.trim() ? { handToTaskAgentCell: value.handToTaskAgentCell.trim() } : {}),
|
|
3581
|
+
...(value.degradationSignal === 'off' || value.degradationSignal === 'shadow' || value.degradationSignal === 'live' ? { degradationSignal: value.degradationSignal } : {}) };
|
|
3536
3582
|
}
|
|
3537
3583
|
|
|
3538
3584
|
export type StewardLoopMode = 'off' | 'shadow' | 'live' | 'rescue';
|
|
@@ -3555,6 +3601,8 @@ export interface SeatLoopConfig {
|
|
|
3555
3601
|
stall?: { parents?: Record<string, string>; redMinutes?: number; blockedMinutes?: number };
|
|
3556
3602
|
/** Unlanded attempts of the same seat cell before the loop stops relaunching and asks a person. Absent or invalid means 3. */
|
|
3557
3603
|
repeatStop?: number;
|
|
3604
|
+
/** OP-LOOP-DECIDE: OP seat filters open decision cards (repeat-stop → b · harness scope → b unless money/security/secret/public paths). shadow records only; live decides/routes. Absent = shadow. */
|
|
3605
|
+
opDecide?: { mode: 'shadow' | 'live' };
|
|
3558
3606
|
}
|
|
3559
3607
|
|
|
3560
3608
|
export type EventSeat = 'OP' | 'TC' | 'MK' | 'UX';
|
|
@@ -3602,6 +3650,8 @@ export interface HqConfig {
|
|
|
3602
3650
|
tailscaleBin?: string;
|
|
3603
3651
|
/** Highest lease generation this host ever saw (default ~/.elanous-hq/seen-generation · 600). */
|
|
3604
3652
|
seenGenerationFile?: string;
|
|
3653
|
+
/** Board writes only reject stale generations when explicitly enforced (default shadow). */
|
|
3654
|
+
boardFencing?: 'shadow' | 'enforce';
|
|
3605
3655
|
/** Per-probe timeout in seconds (default 5). */
|
|
3606
3656
|
probeTimeoutSeconds?: number;
|
|
3607
3657
|
}
|
|
@@ -3636,7 +3686,64 @@ export function parseGateRemoteConfig(raw: unknown): GateRemoteConfig | undefine
|
|
|
3636
3686
|
return Object.keys(out).length ? out : undefined;
|
|
3637
3687
|
}
|
|
3638
3688
|
|
|
3689
|
+
export interface ProjectConfig {
|
|
3690
|
+
/** `axes` is absent when the configured axes are invalid; `error` then carries the config error text. */
|
|
3691
|
+
rubric?: { axes?: import('./release-loop/rubric.js').RubricAxis[]; error?: string };
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
/** Validate one project's `rubric.axes` — throws the config error text (key duplicate · non-numeric weight). */
|
|
3695
|
+
export function parseProjectRubricAxes(id: string, axes: unknown): Array<{ key: string; weight: number }> {
|
|
3696
|
+
if (!Array.isArray(axes)) throw new Error(`[user-config] projects.${id}.rubric.axes 는 배열이어야 합니다`);
|
|
3697
|
+
const seen = new Set<string>();
|
|
3698
|
+
const parsed: Array<{ key: string; weight: number }> = [];
|
|
3699
|
+
for (const [index, axis] of axes.entries()) {
|
|
3700
|
+
const field = `projects.${id}.rubric.axes[${index}]`;
|
|
3701
|
+
if (!axis || typeof axis !== 'object' || Array.isArray(axis)) throw new Error(`[user-config] ${field} 는 {key,weight} 객체여야 합니다`);
|
|
3702
|
+
const { key, weight } = axis as Record<string, unknown>;
|
|
3703
|
+
if (typeof key !== 'string' || !key.trim()) throw new Error(`[user-config] ${field}.key 는 빈 문자열일 수 없습니다`);
|
|
3704
|
+
if (seen.has(key)) throw new Error(`[user-config] projects.${id}.rubric.axes 키 중복: ${key}`);
|
|
3705
|
+
if (typeof weight !== 'number' || !Number.isFinite(weight)) throw new Error(`[user-config] ${field}.weight 는 유한한 숫자여야 합니다: ${String(weight)}`);
|
|
3706
|
+
seen.add(key);
|
|
3707
|
+
parsed.push({ key, weight });
|
|
3708
|
+
}
|
|
3709
|
+
return parsed;
|
|
3710
|
+
}
|
|
3711
|
+
|
|
3712
|
+
/**
|
|
3713
|
+
* Project rubric axes (P3b CORE-GENERIC). Loading never throws — one bad project entry must not
|
|
3714
|
+
* stop every command — so an invalid entry keeps its error text and `resolveRubricAxes` raises it.
|
|
3715
|
+
*/
|
|
3716
|
+
function parseProjectsConfig(raw: unknown): Record<string, ProjectConfig> | undefined {
|
|
3717
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return undefined;
|
|
3718
|
+
const projects: Record<string, ProjectConfig> = {};
|
|
3719
|
+
for (const [id, entry] of Object.entries(raw)) {
|
|
3720
|
+
if (id === '__proto__' || !entry || typeof entry !== 'object' || Array.isArray(entry)) continue;
|
|
3721
|
+
const rubric = (entry as Record<string, unknown>).rubric;
|
|
3722
|
+
if (!rubric || typeof rubric !== 'object' || Array.isArray(rubric)) continue;
|
|
3723
|
+
const axes = (rubric as Record<string, unknown>).axes;
|
|
3724
|
+
if (axes === undefined) continue;
|
|
3725
|
+
try {
|
|
3726
|
+
projects[id] = { rubric: { axes: parseProjectRubricAxes(id, axes) } };
|
|
3727
|
+
} catch (err) {
|
|
3728
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
3729
|
+
console.warn(`${error} — 이 프로젝트의 루브릭 축 해석은 오류로 멈춘다`);
|
|
3730
|
+
projects[id] = { rubric: { error } };
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
return Object.keys(projects).length ? projects : undefined;
|
|
3734
|
+
}
|
|
3735
|
+
|
|
3639
3736
|
export interface UserConfig {
|
|
3737
|
+
projects?: Record<string, ProjectConfig>;
|
|
3738
|
+
/** Default personal topic watch; absent = enabled when user sources exist. */
|
|
3739
|
+
watch?: { enabled?: boolean };
|
|
3740
|
+
starter?: { topics?: string[] };
|
|
3741
|
+
/** GUARD-ONE-a: omitted means shadow. `live` is parsed for the later cutover, but `elanous guardian tick`
|
|
3742
|
+
* refuses it until a human-confirmed operational change (GUARD-ONE-a ships shadow only). */
|
|
3743
|
+
guardian?: { mode?: 'shadow' | 'live' };
|
|
3744
|
+
/** TA-JUDGE-LIVE-SAFE: task-agent judge moves executed for real. Only `review` · `propose-green` are honoured
|
|
3745
|
+
* (`src/task-agent/live-moves.ts` drops anything else with a warning). Absent = env ELANOUS_TASK_AGENT_LIVE_MOVES, else none (pure shadow). */
|
|
3746
|
+
taskAgent?: { liveMoves?: string[] };
|
|
3640
3747
|
events?: EventsConfig;
|
|
3641
3748
|
/** GATE-REMOTE — see GateRemoteConfig. Absent = defaults (auto on · node-b · load 20 · cap 2). */
|
|
3642
3749
|
gateRemote?: GateRemoteConfig;
|
|
@@ -3661,7 +3768,7 @@ export interface UserConfig {
|
|
|
3661
3768
|
loops?: { owners?: Record<string, EventSeat>; defaultOwner?: EventSeat; orchestrator?: OrchestratorLoopConfig; steward?: { mode?: StewardLoopMode; linearTeam?: string; roles?: Record<string, { maxConcurrent?: number }>; budget?: number; tracks?: Record<string, string>; alertAfterFailures?: number; launch?: 'off' | 'shadow' | 'live'; maxParallel?: number; podPool?: string }; seat?: SeatLoopConfig; persona?: PersonaLoopConfig };
|
|
3662
3769
|
/** 🔐 Pod 의 Grok API 키 과금은 명시 opt-in 만. 생략·잘못된 값은 false.
|
|
3663
3770
|
* budgetGate 와 같은 `harness` 객체다 — 중복 선언이면 뒤 타입이 앞을 지운다. */
|
|
3664
|
-
harness?: { edgeRail?: { canaryOkRuns?: number; failureMultiplier?: number; minSamples?: number }; /** Goal authoring grade; absent or invalid config resolves to full. */ authorGrade?: 'full' | 'lite'; revertGuard?: { depth: number }; pod?: { grokApiKeyOptIn: boolean }; budgetGate?: HarnessBudgetGateConfig; exposeGate?: 'warn' | 'strict'; difficultyPlacement?: boolean; defaultRepo?: string; /** Optional GitHub repository name (owner/repo), distinct from the local defaultRepo path. */ repo?: string; substrate?: 'local' | 'pod'; podPool?: string; worktreeAddTimeoutSec?: number; queue?: { seatCap?: Partial<Record<'OP' | 'TC' | 'MK' | 'UX', number>>; /** Direct `harness say|ask` goes through the seat queue first (ONEDOOR-2). Absent = env ELANOUS_HARNESS_QUEUE_DIRECT_SAY, else off. */ directSay?: boolean; /** SEAT-CAP-STALE: a run whose last ledger progress is older than this stops holding its seat. Absent = env ELANOUS_HARNESS_QUEUE_STALE_RUN_MINUTES, else 30. */ staleRunMinutes?: number; /** Seat-less runs count in one bucket with this cap instead of every seat. Absent = env ELANOUS_HARNESS_QUEUE_UNKNOWN_SEAT_CAP, else 2. */ unknownSeatCap?: number }; /** `harness say` 문장을 Pod 안에서 저작부터 돌릴지. 생략·false = 끔(호스트가 저작). */ authorOnPod?: boolean; /** Stopped-PR repair goals: shadow records only (default); live enqueues them. */ helper?: { repair?: 'shadow' | 'live'; /** Live launches allowed per UTC day. Absent or invalid means 3. */ repairPerDay?: number };
|
|
3771
|
+
harness?: { edgeRail?: { canaryOkRuns?: number; failureMultiplier?: number; minSamples?: number }; /** Goal authoring grade; absent or invalid config resolves to full. */ authorGrade?: 'full' | 'lite'; revertGuard?: { depth: number }; pod?: { grokApiKeyOptIn: boolean }; budgetGate?: HarnessBudgetGateConfig; exposeGate?: 'warn' | 'strict'; difficultyPlacement?: boolean; defaultRepo?: string; /** Optional GitHub repository name (owner/repo), distinct from the local defaultRepo path. */ repo?: string; substrate?: 'local' | 'pod'; podPool?: string; worktreeAddTimeoutSec?: number; queue?: { seatCap?: Partial<Record<'OP' | 'TC' | 'MK' | 'UX', number>>; /** Direct `harness say|ask` goes through the seat queue first (ONEDOOR-2). Absent = env ELANOUS_HARNESS_QUEUE_DIRECT_SAY, else off. */ directSay?: boolean; /** SEAT-CAP-STALE: a run whose last ledger progress is older than this stops holding its seat. Absent = env ELANOUS_HARNESS_QUEUE_STALE_RUN_MINUTES, else 30. */ staleRunMinutes?: number; /** Seat-less runs count in one bucket with this cap instead of every seat. Absent = env ELANOUS_HARNESS_QUEUE_UNKNOWN_SEAT_CAP, else 2. */ unknownSeatCap?: number; /** QUEUE-BURST: most launches one scheduled tick may make (30 s apart, each within seat cap and Pod pool headroom). Absent or invalid = 5; 1 = one launch per tick. */ burstMax?: number }; /** `harness say` 문장을 Pod 안에서 저작부터 돌릴지. 생략·false = 끔(호스트가 저작). */ authorOnPod?: boolean; /** SIBLING-RESYNC-ON-MERGE: most open sibling PR file inventories fetched per merge. Absent or invalid = 40. */ siblingResync?: { maxFetch?: number }; /** Stopped-PR repair goals: shadow records only (default); live enqueues them. */ helper?: { repair?: 'shadow' | 'live'; /** Live launches allowed per UTC day. Absent or invalid means 3. */ repairPerDay?: number };
|
|
3665
3772
|
/** Nested elanous launches. Only depth 0 may set `allow`. Absent or any other value refuses. A depth >= 1 `--nested-elanous allow` is ignored. */
|
|
3666
3773
|
nestedElanous?: 'allow' | 'refuse';
|
|
3667
3774
|
/** Maximum nested elanous depth; safe positive integer, default 2. */
|
|
@@ -3914,6 +4021,36 @@ function parseAutoReviewConfig(raw: unknown): AutoReviewConfig | undefined {
|
|
|
3914
4021
|
return Object.keys(out).length > 0 ? out : undefined;
|
|
3915
4022
|
}
|
|
3916
4023
|
|
|
4024
|
+
/** Keeps `taskAgent.liveMoves` as raw strings — the allow-list (and the unknown-entry warning) lives in the task agent. */
|
|
4025
|
+
function parseTaskAgentConfig(raw: unknown): UserConfig['taskAgent'] {
|
|
4026
|
+
if (raw === undefined) return undefined;
|
|
4027
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
4028
|
+
warnUserConfigDrop('taskAgent', '섹션이 객체가 아니다 — 버림');
|
|
4029
|
+
return undefined;
|
|
4030
|
+
}
|
|
4031
|
+
const liveMoves = (raw as Record<string, unknown>).liveMoves;
|
|
4032
|
+
if (liveMoves === undefined) return undefined;
|
|
4033
|
+
// 설정이 «있으면» 환경 변수로 내려가지 않는다 — 배열이 아니면 빈 목록(fail-closed), 문자열 밖 항목은 글자로 바꿔 넘겨
|
|
4034
|
+
// 실행부가 «모르는 항목»으로 경고하고 버리게 한다(유효한 항목은 산다).
|
|
4035
|
+
if (!Array.isArray(liveMoves)) {
|
|
4036
|
+
warnUserConfigDrop('taskAgent.liveMoves', '배열이 아니다 — 빈 목록(실행 0)');
|
|
4037
|
+
return { liveMoves: [] };
|
|
4038
|
+
}
|
|
4039
|
+
return { liveMoves: liveMoves.map((entry) => typeof entry === 'string' ? entry : JSON.stringify(entry) ?? String(entry)) };
|
|
4040
|
+
}
|
|
4041
|
+
|
|
4042
|
+
function parseGuardianConfig(raw: unknown): UserConfig['guardian'] {
|
|
4043
|
+
if (raw === undefined) return undefined;
|
|
4044
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
4045
|
+
warnUserConfigDrop('guardian', '섹션이 객체가 아니다 — 버림');
|
|
4046
|
+
return undefined;
|
|
4047
|
+
}
|
|
4048
|
+
const mode = (raw as Record<string, unknown>).mode;
|
|
4049
|
+
if (mode === 'shadow' || mode === 'live') return { mode };
|
|
4050
|
+
if (mode !== undefined) warnUserConfigDrop('guardian.mode', 'shadow 또는 live 가 아니다 — 버림');
|
|
4051
|
+
return undefined;
|
|
4052
|
+
}
|
|
4053
|
+
|
|
3917
4054
|
/** Parse optional ops fields independently; invalid settings cannot silently select a cron cwd. */
|
|
3918
4055
|
function parseOpsConfig(raw: unknown): UserConfig['ops'] | undefined {
|
|
3919
4056
|
if (raw === undefined) return undefined;
|
|
@@ -4588,6 +4725,12 @@ function parseSeatLoopsConfig(input: unknown): SeatLoopConfig {
|
|
|
4588
4725
|
})(),
|
|
4589
4726
|
...(typeof values.repeatStop === 'number' && Number.isSafeInteger(values.repeatStop) && values.repeatStop > 0
|
|
4590
4727
|
? { repeatStop: values.repeatStop } : {}),
|
|
4728
|
+
...(() => {
|
|
4729
|
+
const raw = values.opDecide;
|
|
4730
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return {};
|
|
4731
|
+
const mode = (raw as Record<string, unknown>).mode;
|
|
4732
|
+
return mode === 'shadow' || mode === 'live' ? { opDecide: { mode } } : {};
|
|
4733
|
+
})(),
|
|
4591
4734
|
};
|
|
4592
4735
|
}
|
|
4593
4736
|
|
|
@@ -4635,6 +4778,7 @@ export function parseHqConfig(raw: unknown): HqConfig | undefined {
|
|
|
4635
4778
|
}
|
|
4636
4779
|
if (typeof r.ttlSeconds === 'number' && Number.isFinite(r.ttlSeconds) && r.ttlSeconds > 0) out.ttlSeconds = r.ttlSeconds;
|
|
4637
4780
|
if (typeof r.probeTimeoutSeconds === 'number' && Number.isFinite(r.probeTimeoutSeconds) && r.probeTimeoutSeconds > 0) out.probeTimeoutSeconds = r.probeTimeoutSeconds;
|
|
4781
|
+
if (r.boardFencing === 'shadow' || r.boardFencing === 'enforce') out.boardFencing = r.boardFencing;
|
|
4638
4782
|
if (r.autoPromote && typeof r.autoPromote === 'object' && !Array.isArray(r.autoPromote)) {
|
|
4639
4783
|
const auto = r.autoPromote as Record<string, unknown>;
|
|
4640
4784
|
const setting: NonNullable<HqConfig['autoPromote']> = {};
|
|
@@ -4771,7 +4915,15 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
4771
4915
|
const nexus = rawObj.nexus && typeof rawObj.nexus === 'object' && !Array.isArray(rawObj.nexus)
|
|
4772
4916
|
? rawObj.nexus as Record<string, unknown> : {};
|
|
4773
4917
|
const gateRemoteConfig = parseGateRemoteConfig(rawObj.gateRemote);
|
|
4918
|
+
const projects = parseProjectsConfig(rawObj.projects);
|
|
4774
4919
|
return {
|
|
4920
|
+
...(projects ? { projects } : {}),
|
|
4921
|
+
...(rawObj.starter && typeof rawObj.starter === 'object' && !Array.isArray(rawObj.starter)
|
|
4922
|
+
&& Array.isArray((rawObj.starter as Record<string, unknown>).topics)
|
|
4923
|
+
? { starter: { topics: ((rawObj.starter as { topics: unknown[] }).topics).filter((topic): topic is string => typeof topic === 'string' && !!topic.trim()) } } : {}),
|
|
4924
|
+
...(rawObj.watch && typeof rawObj.watch === 'object' && !Array.isArray(rawObj.watch)
|
|
4925
|
+
&& typeof (rawObj.watch as Record<string, unknown>).enabled === 'boolean'
|
|
4926
|
+
? { watch: { enabled: (rawObj.watch as { enabled: boolean }).enabled } } : {}),
|
|
4775
4927
|
nexus: { demoMode: nexus.demoMode === true },
|
|
4776
4928
|
...(Object.keys(seatBudgets).length ? { org: { budget: seatBudgets } } : {}),
|
|
4777
4929
|
pod: {
|
|
@@ -4818,8 +4970,9 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
4818
4970
|
...(() => {
|
|
4819
4971
|
const queue = harness.queue && typeof harness.queue === 'object' && !Array.isArray(harness.queue)
|
|
4820
4972
|
? harness.queue as Record<string, unknown> : {};
|
|
4821
|
-
const stale = queue.staleRunMinutes, unknownCap = queue.unknownSeatCap;
|
|
4973
|
+
const stale = queue.staleRunMinutes, unknownCap = queue.unknownSeatCap, burstMax = queue.burstMax;
|
|
4822
4974
|
return {
|
|
4975
|
+
...(typeof burstMax === 'number' && Number.isSafeInteger(burstMax) && burstMax > 0 ? { burstMax } : {}),
|
|
4823
4976
|
...(typeof stale === 'number' && Number.isSafeInteger(stale) && stale > 0 ? { staleRunMinutes: stale } : {}),
|
|
4824
4977
|
...(typeof unknownCap === 'number' && Number.isSafeInteger(unknownCap) && unknownCap >= 0 ? { unknownSeatCap: unknownCap } : {}),
|
|
4825
4978
|
};
|
|
@@ -4845,6 +4998,12 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
4845
4998
|
})(),
|
|
4846
4999
|
...(harness.authorGrade === 'lite' || harness.authorGrade === 'full' ? { authorGrade: harness.authorGrade } : {}),
|
|
4847
5000
|
...(harness.authorOnPod === true ? { authorOnPod: true } : {}),
|
|
5001
|
+
...(() => {
|
|
5002
|
+
const sibling = harness.siblingResync && typeof harness.siblingResync === 'object' && !Array.isArray(harness.siblingResync)
|
|
5003
|
+
? harness.siblingResync as Record<string, unknown> : undefined;
|
|
5004
|
+
const maxFetch = sibling?.maxFetch;
|
|
5005
|
+
return typeof maxFetch === 'number' && Number.isSafeInteger(maxFetch) && maxFetch >= 0 ? { siblingResync: { maxFetch } } : {};
|
|
5006
|
+
})(),
|
|
4848
5007
|
...(harness.nestedElanous === 'allow' || harness.nestedElanous === 'refuse'
|
|
4849
5008
|
? { nestedElanous: harness.nestedElanous } : {}),
|
|
4850
5009
|
nestedElanousMaxDepth: typeof harness.nestedElanousMaxDepth === 'number'
|
|
@@ -5507,6 +5666,8 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
5507
5666
|
loops: { ...(stewardLoops ?? {}), ...parseLoopOwners(rawObj.loops), orchestrator: parseOrchestratorLoopConfig((rawObj.loops as { orchestrator?: unknown } | undefined)?.orchestrator), seat: parseSeatLoopsConfig(rawObj.loops),
|
|
5508
5667
|
persona: { enabled: (rawObj.loops as { persona?: { enabled?: unknown } } | undefined)?.persona?.enabled === true } },
|
|
5509
5668
|
events: parseEventsConfig(rawObj.events),
|
|
5669
|
+
guardian: parseGuardianConfig(rawObj.guardian),
|
|
5670
|
+
taskAgent: parseTaskAgentConfig(rawObj.taskAgent),
|
|
5510
5671
|
// M1-1: sparse — undefined when the user hasn't set anything, so
|
|
5511
5672
|
// resolvers fall through to zero-config defaults.
|
|
5512
5673
|
...spreadIfDefined('modelTier', parseModelTierConfig(rawObj.modelTier)),
|
|
@@ -6045,6 +6206,21 @@ export function saveUserConfig(
|
|
|
6045
6206
|
},
|
|
6046
6207
|
};
|
|
6047
6208
|
const rawRest = { ...(cfg.raw ?? {}) };
|
|
6209
|
+
// projects: raw entries are kept verbatim — an invalid entry loaded from disk is preserved, not blocked (its error
|
|
6210
|
+
// surfaces in resolveRubricAxes) — and typed axes handed to save are validated (invalid ones refuse the save).
|
|
6211
|
+
const rawProjectsValue = rawRest.projects;
|
|
6212
|
+
const rawProjects = rawRest.projects && typeof rawRest.projects === 'object' && !Array.isArray(rawRest.projects)
|
|
6213
|
+
? rawRest.projects as Record<string, unknown> : undefined;
|
|
6214
|
+
const savedProjects: Record<string, unknown> | undefined = rawProjects || cfg.projects ? { ...(rawProjects ?? {}) } : undefined;
|
|
6215
|
+
for (const [id, project] of Object.entries(cfg.projects ?? {})) {
|
|
6216
|
+
if (project?.rubric?.axes === undefined) continue;
|
|
6217
|
+
const axes = parseProjectRubricAxes(id, project.rubric.axes);
|
|
6218
|
+
const rawProject = rawProjects?.[id] && typeof rawProjects[id] === 'object' && !Array.isArray(rawProjects[id])
|
|
6219
|
+
? rawProjects[id] as Record<string, unknown> : {};
|
|
6220
|
+
const rawRubric = rawProject.rubric && typeof rawProject.rubric === 'object' && !Array.isArray(rawProject.rubric)
|
|
6221
|
+
? rawProject.rubric as Record<string, unknown> : {};
|
|
6222
|
+
savedProjects![id] = { ...rawProject, rubric: { ...rawRubric, axes } };
|
|
6223
|
+
}
|
|
6048
6224
|
// Strip typed sections from raw so we don't double-write stale copies.
|
|
6049
6225
|
delete rawRest.skillRouter;
|
|
6050
6226
|
delete rawRest.llm;
|
|
@@ -6079,6 +6255,10 @@ export function saveUserConfig(
|
|
|
6079
6255
|
delete rawRest.smartDefaults;
|
|
6080
6256
|
delete rawRest.grounding;
|
|
6081
6257
|
delete rawRest.diagnostics;
|
|
6258
|
+
delete rawRest.projects;
|
|
6259
|
+
delete rawRest.starter;
|
|
6260
|
+
delete rawRest.watch;
|
|
6261
|
+
delete rawRest.guardian;
|
|
6082
6262
|
const rawHarness = rawRest.harness && typeof rawRest.harness === 'object' && !Array.isArray(rawRest.harness)
|
|
6083
6263
|
? rawRest.harness as Record<string, unknown> : {};
|
|
6084
6264
|
delete rawRest.harness;
|
|
@@ -6113,6 +6293,10 @@ export function saveUserConfig(
|
|
|
6113
6293
|
helper: cfg.harness?.helper ?? rawHarness.helper,
|
|
6114
6294
|
}),
|
|
6115
6295
|
...rawRest,
|
|
6296
|
+
...(savedProjects ? { projects: savedProjects } : rawProjectsValue !== undefined ? { projects: rawProjectsValue } : {}),
|
|
6297
|
+
...(cfg.starter ? { starter: cfg.starter } : {}),
|
|
6298
|
+
...(cfg.watch ? { watch: cfg.watch } : {}),
|
|
6299
|
+
...(cfg.guardian ? { guardian: cfg.guardian } : {}),
|
|
6116
6300
|
...(cfg.loops ? { loops: {
|
|
6117
6301
|
...rawLoops,
|
|
6118
6302
|
owners: cfg.loops.owners ?? {}, defaultOwner: cfg.loops.defaultOwner ?? 'OP',
|
|
@@ -6127,6 +6311,7 @@ export function saveUserConfig(
|
|
|
6127
6311
|
...(cfg.loops.seat.reportPr === undefined ? {} : { reportPr: cfg.loops.seat.reportPr }),
|
|
6128
6312
|
...(cfg.loops.seat.stall ? { stall: cfg.loops.seat.stall } : {}),
|
|
6129
6313
|
...(cfg.loops.seat.repeatStop === undefined ? {} : { repeatStop: cfg.loops.seat.repeatStop }),
|
|
6314
|
+
...(cfg.loops.seat.opDecide ? { opDecide: cfg.loops.seat.opDecide } : {}),
|
|
6130
6315
|
} } : {}),
|
|
6131
6316
|
} } : {}),
|
|
6132
6317
|
...(cfg.autopilot ? { autopilot: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"commit":"
|
|
1
|
+
{"commit":"047da54ef704187c124a2969c6222d61fe01beb0"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[224],{1369:(e,r,t)=>{t.d(r,{QL:()=>p,WelcomeHome:()=>w});var n=t(55539),l=t(46124),a=t(3558),s=t.n(a),i=t(58603),o=t(6535),u=t(44373),c=t(97479),d=t(92161);let f=["/term","/chat","/intake","/live","/editor","/market","/setup"];var m=t(65650),h=t(57147),g=t(48087);let x=[...g.Ue.map(e=>({href:function(e){if(!(g.Ue.some(r=>r.href===e)||g.OE.some(r=>r.href===e)))throw Error("Unknown sidebar route: ".concat(e));return e}(e.href),label:e.label,navigable:!0})),...g.OE.map(e=>({href:e.href,label:e.href,navigable:!1,reason:e.reason}))],b=[...x.filter(e=>e.navigable),{href:"/setup",label:"Setup",navigable:!0}],v=[{href:"/morning",label:"아침 브리핑",navigable:!0},{href:"/settings/devices",label:"기기 목록",navigable:!0},{href:"/workflows/chat-ui",label:"워크플로 채팅",navigable:!0}];function p(e){let{ariaLabel:r,items:t=x}=e;return(0,n.jsx)("section",{"aria-label":r,className:"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3",children:t.map(e=>{var r;return(0,n.jsx)("article",{"data-testid":(r=e.href,"route-guidance-".concat("/"===r?"root":r.slice(1).replaceAll("/","-"))),"data-route-kind":e.navigable?"destination":"reference",className:(0,u.cn)("rounded-2xl border border-border/60 bg-card/60 p-5 shadow-sm",!e.navigable&&"bg-muted/40"),children:e.navigable?(0,n.jsxs)(s(),{href:e.href,className:"font-semibold underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",children:[e.label," ",(0,n.jsx)("code",{className:"text-xs text-muted-foreground",children:e.href})]}):(0,n.jsxs)("div",{className:"flex flex-col gap-2",children:[(0,n.jsxs)("span",{className:"font-semibold",children:["참고 주소 ",(0,n.jsx)("code",{className:"text-xs text-muted-foreground",children:e.href})]}),(0,n.jsx)("p",{className:"text-sm leading-relaxed text-muted-foreground",children:e.reason})]})},e.href)})})}function w(){let{role:e}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return null==(0,l.useContext)(o.AppRouterContext)?(0,n.jsx)(N,{role:e}):(0,n.jsx)(j,{role:e})}function j(e){let{role:r}=e,t=(0,i.useRouter)(),a=(0,i.usePathname)(),s=(0,m._r)(),o=null==a||s.isError||s.isPending||s.isLoading?null:(0,h.P)(s.data,a);return(0,l.useEffect)(()=>{"/setup"===o&&t.replace("/setup")},[o,t]),(0,n.jsx)(N,{role:r})}function N(e){var r;let{role:t}=e,l=(0,c.In)(),a=null!=t?t:l,{core:s,more:i}=(r=b.filter(e=>(0,d.EX)(a,e.href)),{core:f.flatMap(e=>r.filter(r=>r.href===e)),more:r.filter(e=>!f.some(r=>r===e.href))});return(0,n.jsx)("main",{"data-testid":"welcome-home",className:"min-h-screen bg-gradient-to-b from-background via-background to-muted/40 px-6 py-12 sm:px-10",children:(0,n.jsxs)("div",{className:"mx-auto flex w-full max-w-5xl flex-col gap-10",children:[(0,n.jsxs)("header",{className:"flex flex-col gap-3",children:[(0,n.jsx)("p",{className:"text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground",children:"elanous PWA"}),(0,n.jsx)("h1",{className:"text-3xl font-bold leading-tight sm:text-4xl",children:"웰컴 — 어디부터 시작할까요?"}),(0,n.jsx)("p",{className:"max-w-2xl text-sm text-muted-foreground sm:text-base",children:"처음이라면 아래 핵심 화면에서 시작하세요. 다른 화면은 필요할 때 펼쳐 볼 수 있습니다."})]}),(0,n.jsx)(p,{ariaLabel:"핵심 화면",items:s}),i.length>0&&(0,n.jsxs)("details",{className:"rounded-2xl border border-border/60 bg-card/60 p-5",children:[(0,n.jsxs)("summary",{className:"cursor-pointer font-semibold focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",children:["모든 화면 (",i.length,")"]}),(0,n.jsx)("div",{className:"mt-4",children:(0,n.jsx)(p,{ariaLabel:"나머지 화면",items:i})})]}),v.some(e=>(0,d.EX)(a,e.href))&&(0,n.jsxs)("details",{className:"rounded-2xl border border-border/60 bg-card/60 p-5",children:[(0,n.jsx)("summary",{className:"cursor-pointer font-semibold focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",children:"고치는 중인 화면"}),(0,n.jsx)("div",{className:"mt-4",children:(0,n.jsx)(p,{ariaLabel:"고치는 중인 화면",items:v.filter(e=>(0,d.EX)(a,e.href))})})]})]})})}},3704:(e,r,t)=>{t.d(r,{A:()=>u});var n=t(46124);let l=function(){for(var e=arguments.length,r=Array(e),t=0;t<e;t++)r[t]=arguments[t];return r.filter((e,r,t)=>!!e&&""!==e.trim()&&t.indexOf(e)===r).join(" ").trim()},a=e=>{let r=e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,r,t)=>t?t.toUpperCase():r.toLowerCase());return r.charAt(0).toUpperCase()+r.slice(1)};var s={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};let i=(0,n.createContext)({}),o=(0,n.forwardRef)((e,r)=>{var t,a,o;let{color:u,size:c,strokeWidth:d,absoluteStrokeWidth:f,className:m="",children:h,iconNode:g,...x}=e,{size:b=24,strokeWidth:v=2,absoluteStrokeWidth:p=!1,color:w="currentColor",className:j=""}=null!=(t=(0,n.useContext)(i))?t:{},N=(null!=f?f:p)?24*Number(null!=d?d:v)/Number(null!=c?c:b):null!=d?d:v;return(0,n.createElement)("svg",{ref:r,...s,width:null!=(a=null!=c?c:b)?a:s.width,height:null!=(o=null!=c?c:b)?o:s.height,stroke:null!=u?u:w,strokeWidth:N,className:l("lucide",j,m),...!h&&!(e=>{for(let r in e)if(r.startsWith("aria-")||"role"===r||"title"===r)return!0;return!1})(x)&&{"aria-hidden":"true"},...x},[...g.map(e=>{let[r,t]=e;return(0,n.createElement)(r,t)}),...Array.isArray(h)?h:[h]])}),u=(e,r)=>{let t=(0,n.forwardRef)((t,s)=>{let{className:i,...u}=t;return(0,n.createElement)(o,{ref:s,iconNode:r,className:l("lucide-".concat(a(e).replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()),"lucide-".concat(e),i),...u})});return t.displayName=a(e),t}},44373:(e,r,t)=>{t.d(r,{cn:()=>a});var n=t(20852),l=t(30984);function a(){for(var e=arguments.length,r=Array(e),t=0;t<e;t++)r[t]=arguments[t];return(0,l.QP)((0,n.$)(r))}},57147:(e,r,t)=>{t.d(r,{C:()=>a,P:()=>l});let n="셋업 모드 — 먼저 LLM 을 정하세요";function l(e,r){return(null==e?void 0:e.setupMode)!==!0||"/"!==r?null:"/setup"}function a(e,r){if((null==e?void 0:e.setupMode)!==!0||"/setup"===r||r.startsWith("/setup/"))return null;let t=e.setupMissing;return t&&t.length>0?"".concat(n," (").concat(t.join(", "),")"):n}},58603:(e,r,t)=>{var n=t(99027);t.o(n,"useParams")&&t.d(r,{useParams:function(){return n.useParams}}),t.o(n,"usePathname")&&t.d(r,{usePathname:function(){return n.usePathname}}),t.o(n,"useRouter")&&t.d(r,{useRouter:function(){return n.useRouter}}),t.o(n,"useSearchParams")&&t.d(r,{useSearchParams:function(){return n.useSearchParams}})},65650:(e,r,t)=>{t.d(r,{_r:()=>a});var n=t(46124),l=t(94306);function a(){let e=(0,l.Qj)(),[r,t]=(0,n.useState)({data:void 0,isError:!1,isPending:!0});return(0,n.useEffect)(()=>{if(!e)return void t({data:void 0,isError:!1,isPending:!0});let r=!0,n=()=>{e.getHealth().then(e=>{r&&t({data:e,isError:!1,isPending:!1})}).catch(()=>{r&&t(e=>({...e,isError:!0,isPending:!1}))})};n();let l=setInterval(n,6e4);return()=>{r=!1,clearInterval(l)}},[e]),{...r,isLoading:r.isPending&&null!==e}}t(65354)},97479:(e,r,t)=>{t.d(r,{GC:()=>l,In:()=>u,OG:()=>i});var n=t(46124);let l="elanous.pwa.role",a="elanous:pwa-role";function s(){try{let e=window.localStorage.getItem(l);if("owner"===e||"contributor"===e||"general"===e)return e}catch(e){}return"general"}function i(e){try{window.localStorage.setItem(l,e)}catch(e){}"function"==typeof window.dispatchEvent&&window.dispatchEvent(new Event(a))}function o(e){if("function"!=typeof window.addEventListener)return()=>{};window.addEventListener(a,e);let r=r=>{(r.key===l||null===r.key)&&e()};return window.addEventListener("storage",r),()=>{window.removeEventListener(a,e),window.removeEventListener("storage",r)}}function u(){return(0,n.useSyncExternalStore)(o,s,()=>"general")}}}]);
|