elanous 0.2.12 → 0.2.14
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/{7334.a6679d9168f37aa8.js → 1268.0840ff91e083fcbd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1307-6e7e0377c1db0bdc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9656-c1540088f5859c80.js → 1844-9ec4b1d12f6e80eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{390.c373e31b3b9d0c41.js → 1948.15f356b15a625597.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +1 -0
- package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4562-071d8bac44a01069.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4685-c3c1c625b71accd1.js → 4614-21403aac730d4586.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{8039-df92e08fede5de8f.js → 4795-f372490b178583fc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5135-44008fe8b1f2aa41.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5233-bf28bd6bd7a32099.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5977-2df489622a52a33a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1452.93700483b9d4fc61.js → 6110.1297d4093fdfbb0d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6158.9c0449a9a8d0064b.js +2 -0
- package/apps/pwa/out/_next/static/chunks/6877-7c6208705c284124.js +1 -0
- package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1829-b453a1b22d3999bb.js → 7327-2d69fb321ba73389.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7395-164e238f471b5d7b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7787-02a1c0b04e25e811.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9906-482c6619b3fdda20.js → 8060-cc008cc6fedfa818.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8827-e2f5b09a8d37e83b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +25 -0
- package/apps/pwa/out/_next/static/chunks/{8421-1c4acfb1395a0edf.js → 8949-ecb4128a0858b911.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9103-7a3ae7f60af3b99f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3869-3cd46526879f454c.js → 9247-29d889b809288e65.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{79f8be9e-957d68913b590b08.js → a9f2b54d-7865aba0f4d2ee49.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-74383f890f075511.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-7b2b4f378354869a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-c496bb16da85385f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-1abfe3aec3be6bdc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-1512d91c7491ed62.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-a627db94ec6904a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-fb260b9283dbf646.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-e6b84ab07d3567d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-61ec1d2e92bdd50a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-fed69f9759d248d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/{page-a67e11ba962337b5.js → page-15374909d8f1aebd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-012a742f81218b01.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-fd7e200d4d83fbd7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-99effd9d893a43dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-938de57ae0315e46.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-d47266766766d227.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-160089123a40dd91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-629e1ede482ec6eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-793fa536b3a6ef37.js → page-2ce5471926761fdd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-27e99b4e54a849d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-e995d30f6800b6bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-39f89c53038a51d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-32cde713be47cddb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-e7e10cd3386222e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-5a753bb4ec0cc511.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-04250f0e2c0d03df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-341480ed8e3c1ea8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-e64caff084f7ce21.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-db07eaffba0df7e3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-8ac8d71c2adf9c8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e1e47d8d940aba3d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-86f91034bd5cabe5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-94dc383d3d54db1a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-b3759cc14da80908.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-ce4d8a1215ce53a3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-58043db78ba519ae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-357750dfb91bf960.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-e297866051595d81.js → page-274703bc41b71333.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-194dce4a83143fce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-35bdeae2e2c17147.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-3b7e821dc492bdfd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-16bef3da05a900c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-f8da5dc6f3752276.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2f810b18d89ecba6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-134c1bc762aee62c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5cd7e3a9-404fd6b8d0ecd44c.js → f6231284-45726550aba08fca.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{f48170cc-d05d28bf87a43bf4.js → f6b7c9ba.64a895b8b2fedbdc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-539cde99554be20f.js +1 -0
- package/apps/pwa/out/_next/static/css/2e33713c444d5b39.css +1 -0
- package/apps/pwa/out/_next/static/x6mjI6vqOkVVu0jFuDkz1/_buildManifest.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/loops/index.html +1 -0
- package/apps/pwa/out/loops/index.txt +30 -0
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/examples/teams/personas/backend.yaml +4 -0
- package/examples/teams/personas/pm.yaml +4 -0
- package/examples/teams/personas/qa.yaml +4 -0
- package/examples/teams/small-product.yaml +20 -0
- package/graphs/lecture/lecture-note.yaml +28 -0
- package/graphs/lecture/recipes.yaml +17 -0
- package/graphs/orchestrator/orchestrator.yaml +59 -0
- package/graphs/orchestrator/recipes.yaml +18 -0
- package/graphs/release/recipes.yaml +3 -0
- package/graphs/release/release-loop.yaml +4 -1
- package/graphs/rhythm/daily.yaml +38 -0
- package/graphs/rhythm/recipes.yaml +18 -0
- package/graphs/rhythm/weekly.yaml +39 -0
- package/graphs/video/recipes.yaml +3 -0
- package/graphs/video/youtube-summary.yaml +17 -0
- package/package.json +2 -1
- package/scripts/audit-test-state-writes.ts +72 -17
- package/scripts/brand/check.ts +186 -0
- package/scripts/context-hooks/emit.ts +36 -14
- package/scripts/coord-channel-watch.sh +1 -0
- package/scripts/coord-post.sh +11 -1
- package/scripts/discord-seat-probe.ts +144 -0
- package/scripts/docs-cli-check.ts +23 -6
- package/scripts/expose-rubric-check.ts +118 -0
- package/scripts/expose-rubric-suggest.ts +163 -0
- package/scripts/heal/run-role.ts +14 -0
- package/scripts/hq/hq-standby.sh +65 -0
- package/scripts/hq/standby-promote.ts +173 -0
- package/scripts/hq/standby-role.ts +59 -0
- package/scripts/hq/standby-snapshot.ts +226 -0
- package/scripts/hq/standby-verify.ts +223 -0
- package/scripts/lecture-note/node.ts +256 -0
- package/scripts/lessons/handbook-page.ts +85 -0
- package/scripts/release-loop/gate-node.ts +62 -15
- package/scripts/release-loop/ops-upgrade-node.ts +17 -5
- package/scripts/release-loop/publish-node.ts +14 -1
- package/scripts/release-loop/unattended-release.ts +23 -1
- package/scripts/release-loop/vault-note-node.ts +196 -0
- package/scripts/release-story/draft.ts +172 -0
- package/scripts/rhythm/daily.ts +383 -0
- package/scripts/rhythm/weekly.ts +294 -0
- package/scripts/skills/public-check.ts +169 -0
- package/scripts/test-deterministic.ts +57 -11
- package/scripts/test-diet/effectiveness.ts +195 -0
- package/scripts/test-diet/lib.ts +16 -8
- package/scripts/test-diet/node.ts +77 -9
- package/scripts/ux/demo-rehearsal.ts +2 -2
- package/scripts/ux/lib/rehearsal-verdict.ts +1 -0
- package/scripts/video/youtube-summary.ts +133 -0
- package/skills/diagram-master/SKILL.md +42 -49
- package/skills/diagram-master/references/pyproject.toml +4 -1
- package/skills/diagram-master/references/routing-guide.md +4 -2
- package/skills/grill-me/SKILL.md +1 -0
- package/skills/omni-crawl/SKILL.md +16 -16
- package/skills/omni-crawl/package-lock.json +1 -544
- package/skills/omni-crawl/package.json +3 -4
- package/skills/omni-crawl/scripts/main.ts +13 -13
- package/skills/omni-crawl/scripts/monitor.ts +8 -8
- package/skills/omni-crawl/src/apify.ts +13 -2
- package/skills/omni-crawl/src/capture.ts +6 -0
- package/skills/omni-crawl/src/registry.ts +2 -2
- package/skills/omni-crawl/src/stdout-json.ts +4 -0
- package/skills/omni-digest/SKILL.md +10 -11
- package/skills/omni-digest/package-lock.json +0 -545
- package/skills/omni-digest/package.json +2 -5
- package/skills/omni-digest/scripts/main.ts +3 -3
- package/skills/omni-digest/src/delegate.ts +5 -5
- package/skills/omni-digest/src/fetch.ts +2 -2
- package/skills/omni-digest/src/media.ts +25 -11
- package/skills/omni-digest/src/visual.ts +3 -2
- package/skills/omni-market/scripts/main.ts +1 -1
- package/skills/omni-market/scripts/stdout-json.ts +4 -0
- package/skills/youtube-master/SKILL.md +13 -13
- package/skills/youtube-master/package-lock.json +0 -545
- package/skills/youtube-master/package.json +2 -5
- package/skills/youtube-master/scripts/main.ts +2 -2
- package/skills/youtube-master/scripts/transcribe-local.ts +1 -1
- package/skills/youtube-master/src/util.ts +30 -7
- package/src/agent/identity-env.ts +11 -0
- package/src/agent-mission/driver.ts +15 -10
- package/src/agent-mission/duo.ts +94 -0
- package/src/agent-mission/pty-decision.ts +1 -1
- package/src/autopilot/build/llm-conflict-merge.ts +45 -8
- package/src/autopilot/build/merge-intent.ts +53 -0
- package/src/autopilot/track-agent-shadow.ts +2 -1
- package/src/autopilot/track-agent.ts +4 -1
- package/src/boot/daemon-prompt-request.ts +3 -0
- package/src/boot/daemon-prompt-turn.ts +6 -2
- package/src/boot/daemon-runtime.ts +48 -16
- package/src/chat/index.ts +2 -0
- package/src/claims/claims-ledger.ts +232 -0
- package/src/claims/claims-render.ts +157 -0
- package/src/cli/claims-cli.ts +94 -0
- package/src/cli/decisions-cli.ts +84 -20
- package/src/cli/docs-cli.ts +2 -0
- package/src/cli/flow-cli.ts +11 -0
- package/src/cli/freeze-cli.ts +45 -0
- package/src/cli/lesson-cli.ts +108 -0
- package/src/cli/logs-cli.ts +104 -2
- package/src/cli/logs-model-input.ts +131 -0
- package/src/cli/outputs-cli.ts +92 -0
- package/src/cli/persona-cli.ts +29 -0
- package/src/cli/pod-cli.ts +10 -3
- package/src/cli/pr-cli.ts +44 -2
- package/src/cli/private-ledger-commands.ts +54 -4
- package/src/cli/pty-drive-verdict.ts +11 -2
- package/src/cli/release-cli.ts +248 -45
- package/src/cli/rfc-status.ts +91 -0
- package/src/connectors/linear.ts +5 -3
- package/src/context-bus/condense.ts +189 -0
- package/src/context-bus/context-day.ts +82 -0
- package/src/context-bus/context-now-public.ts +86 -0
- package/src/context-bus/context-now-surfaces.ts +70 -4
- package/src/context-bus/context-now.ts +4 -3
- package/src/context-bus/long-term-memory.ts +201 -24
- package/src/context-bus/nightly-condense.ts +1 -1
- package/src/dashboard/index.ts +75 -22
- package/src/dashboard/slash-runtime/chat-persona.ts +66 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +99 -0
- package/src/dashboard/slash-runtime/loops-table.ts +77 -0
- package/src/decisions/decision-cards.ts +13 -7
- package/src/decisions/decision-ledger.ts +83 -18
- package/src/discord/sprint21-runtime.ts +16 -0
- package/src/discord-self-message.ts +8 -0
- package/src/discord-slash-wire.ts +31 -2
- package/src/domains/outbound-alert.ts +1 -1
- package/src/elanous-config-dir.ts +29 -4
- package/src/execution-loop/launch-gate.ts +29 -14
- package/src/flow/cards.ts +239 -0
- package/src/graph-kinds/registry.ts +2 -2
- package/src/graph-runner/graph-approval-card.ts +2 -2
- package/src/graph-runner/graph-grow.ts +64 -11
- package/src/graph-runner/graph-tick.ts +13 -2
- package/src/graph-runner/runner.ts +111 -22
- package/src/harness/harness-cli-command.ts +178 -27
- package/src/harness/harness-incidents.ts +43 -12
- package/src/harness/harness-pod-dispatch.ts +2 -0
- package/src/harness/harness-queue-child.ts +37 -0
- package/src/harness/harness-queue.ts +494 -0
- package/src/harness/helper-scan.ts +139 -0
- package/src/harness/model-input-observation.ts +37 -0
- package/src/hooks/github-shadow.ts +72 -2
- package/src/hooks/receiver.ts +4 -2
- package/src/hq/hq.ts +318 -0
- package/src/hq/lease.ts +210 -0
- package/src/hq/ledger-write-target.ts +41 -0
- package/src/hq/promote.ts +301 -0
- package/src/index.ts +281 -27
- package/src/intake-plane/discord-seat-work.ts +13 -6
- package/src/intake-plane/linear-wish.ts +72 -0
- package/src/intake-plane/persona-answer.ts +5 -0
- package/src/intake-plane/telegram-seat-work.ts +13 -6
- package/src/intake-plane/wish-benchmark-ledger.ts +129 -0
- package/src/intake-plane/wish-card.ts +53 -2
- package/src/intake-plane/wish-folder.ts +5 -2
- package/src/intake-plane/wish-reply.ts +72 -0
- package/src/lessons/lesson-import.ts +106 -0
- package/src/lessons/lesson-ledger.ts +206 -0
- package/src/loops/activity.ts +203 -0
- package/src/loops/budget.ts +32 -0
- package/src/loops/checker.ts +180 -0
- package/src/loops/contract/examples/orchestrator.loop.yaml +1 -1
- package/src/loops/loop-cli.ts +72 -6
- package/src/loops/neighbors.ts +40 -0
- package/src/loops/observe.ts +59 -0
- package/src/loops/orchestrator/author-depth.ts +164 -0
- package/src/loops/orchestrator/author-input-check.ts +77 -0
- package/src/loops/orchestrator/author-ledger.ts +230 -0
- package/src/loops/orchestrator/finish-rate.ts +175 -0
- package/src/loops/orchestrator/overlap.ts +180 -0
- package/src/loops/orchestrator/resync-shadow.ts +227 -0
- package/src/loops/orchestrator/tick.ts +302 -0
- package/src/loops/orchestrator/traffic.ts +165 -0
- package/src/loops/package/verify.ts +125 -0
- package/src/loops/registry.ts +454 -9
- package/src/loops/status-rows.ts +118 -0
- package/src/loops/verdict.ts +34 -0
- package/src/maturity/bot-slash-catalog.ts +66 -0
- package/src/maturity/feature-maturity.ts +8 -5
- package/src/memory.ts +37 -4
- package/src/nexus/api/card-followup-route.ts +118 -0
- package/src/nexus/api/dashboard.ts +6 -1
- package/src/nexus/api/decisions-route.ts +68 -0
- package/src/nexus/api/http-server.ts +65 -2
- package/src/nexus/api/merge-approvals-gate.ts +1 -1
- package/src/nexus/api/personas.ts +2 -1
- package/src/nexus/api/schedules-read.ts +5 -1
- package/src/nexus/api/skill-exec-route.ts +97 -0
- package/src/nexus/api/task-cards-api.ts +44 -5
- package/src/nexus/api/workflows.ts +2 -1
- package/src/persona/loader.ts +18 -0
- package/src/persona/persona-todo.ts +14 -9
- package/src/persona/presets.ts +2 -1
- package/src/persona/team.ts +105 -0
- package/src/persona/types.ts +4 -0
- package/src/pod-lease/host-lease.ts +130 -20
- package/src/release-loop/auto-start.ts +48 -0
- package/src/release-loop/checklist.ts +13 -4
- package/src/release-loop/feature-store.ts +28 -16
- package/src/release-loop/landed-but-yellow.ts +12 -0
- package/src/release-loop/landing-freeze.ts +121 -0
- package/src/release-loop/placement.ts +242 -0
- package/src/release-loop/release-schedule.ts +3 -1
- package/src/seat-dispatch/ceo-commands.ts +2 -2
- package/src/seat-dispatch/seat-ask.ts +73 -15
- package/src/seat-dispatch/seat-questions.ts +58 -0
- package/src/seat-loop/seat-loop.ts +495 -46
- package/src/seat-loop/seat-pack.ts +127 -0
- package/src/self-dev/ask-launch-flow.ts +3 -0
- package/src/self-dev/dev-pipeline.ts +6 -2
- package/src/self-dev/draft-sweep.ts +76 -0
- package/src/self-dev/run-store.ts +73 -1
- package/src/self-dev/run-supervisor.ts +8 -0
- package/src/self-dev/self-orchestrate-runtime.ts +5 -1
- package/src/self-implement/budget-gate.ts +29 -0
- package/src/self-implement/expose-gate.ts +47 -0
- package/src/self-implement/frozen-merges.ts +294 -0
- package/src/self-implement/gate-cli.ts +10 -4
- package/src/self-implement/gate-scope.ts +46 -9
- package/src/self-implement/goal-archive.ts +222 -0
- package/src/self-implement/goal-lookup.ts +147 -0
- package/src/self-implement/heal-intake.ts +79 -0
- package/src/self-implement/host-regate.ts +25 -2
- package/src/self-implement/l8-merge-queue.ts +157 -1
- package/src/self-implement/orchestrator.ts +114 -10
- package/src/self-implement/revert-guard.ts +62 -0
- package/src/self-implement/run-ledger.ts +1 -1
- package/src/self-implement/seams.ts +28 -8
- package/src/session/index.ts +2 -0
- package/src/steward/launch.ts +5 -1
- package/src/steward/readiness.ts +125 -0
- package/src/steward/rescue.ts +75 -0
- package/src/steward/triage.ts +48 -9
- package/src/task-cards/card-cli.ts +86 -0
- package/src/task-cards/card-store.ts +10 -6
- package/src/task-orchestrator/surfaces/pod-lease.ts +23 -8
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +46 -6
- package/src/task-orchestrator/surfaces/pod-pool.ts +27 -10
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +112 -18
- package/src/telegram-commands.ts +27 -3
- package/src/telegram-dispatch-forward.ts +1 -1
- package/src/telegram-fabric-plan.ts +90 -0
- package/src/telegram-loops-command.ts +44 -0
- package/src/telegram-project-command.ts +10 -4
- package/src/telegram.ts +5 -0
- package/src/tool-runtime/elanous-control-runtimes.ts +2 -1
- package/src/user-config.ts +204 -16
- package/src/version/packed-revision.json +1 -1
- package/src/workflow-runtime/executor.ts +4 -0
- package/src/workflow-runtime/node-catalog.ts +13 -0
- package/src/workflow-runtime/nodes/knowledge.ts +38 -0
- package/src/workflow-runtime/schema.ts +17 -1
- package/src/workflow-runtime/storage.ts +31 -13
- package/src/workflow-runtime/types.ts +13 -1
- package/apps/pwa/out/_next/static/-6XrAoD3eU7NyMHAE4xPS/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1147-466ec15afacc1a65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1394-ee3795b112907122.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +0 -25
- package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +0 -2
- package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5845-e6c003ce8d5fd36a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7277-0b2fc7c16ba2d64b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7758-0b018a9e4fc56200.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8605-0259994816604c49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9269.d2a4795bc6812717.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9920-5cfdc5e8fd209825.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-cb169620945d1952.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cefe8169e36cf62a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-d2e35228bc497119.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-5c05b0da4bc1392c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e0ccdb576812b523.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-813c4a52c9d05ca8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-4731f2c215358937.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-a022b257950f39e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-a2ffc717e04b8b0a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-b59ee4e70fc18fcf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-c172dabd796eb7a3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-1efd0cb9e0ed9d13.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-d5dc7ff69a37b4cf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-e71c84189e8c683e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-1d6a533ce5a6efcb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-dfca9b7d2de0b135.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-6dd3bfbbde2a5c2c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-490653e8d4cc8852.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-77447356baad75d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-29e961191f6057df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-c822f55b884d9104.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fa4ccfc432424e52.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-6d604227e1664b71.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-9c7e8f744a765daf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-4048543b4b7ad5e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-4c3a3126abed551a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-64b0aecb1ca75e75.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4292d0149020e8a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-db14d0be7f1c460c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-e5d8072cd7cfef73.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-9547b5cec7cf76bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-e6dcb83265530636.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-45248f08d6aecae5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-2cddeb9e2aeedc55.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-baba2e047872fb0f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-e895da4ec9cac345.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-4344faf20216233b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-698bb29f11864b89.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-bd6a6dc1ddc273f2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2e9e2fb01c9da1c9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d62ceb13411ebba4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +0 -1
- package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.css +0 -1
- /package/apps/pwa/out/_next/static/{-6XrAoD3eU7NyMHAE4xPS → x6mjI6vqOkVVu0jFuDkz1}/_ssgManifest.js +0 -0
|
@@ -2,14 +2,16 @@ import { execFileSync } from 'node:child_process';
|
|
|
2
2
|
import { dlopen, FFIType } from 'bun:ffi';
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
4
|
import { existsSync, readFileSync } from 'node:fs';
|
|
5
|
-
import { constants as osConstants } from 'node:os';
|
|
6
|
-
import { resolve, sep } from 'node:path';
|
|
5
|
+
import { constants as osConstants, hostname } from 'node:os';
|
|
6
|
+
import { basename, dirname, resolve, sep } from 'node:path';
|
|
7
7
|
import { findGitDir } from '../git-fs/locate.js';
|
|
8
8
|
import { LogStore, logsDbPath } from '../mss/logging/log-store.js';
|
|
9
9
|
import { loadSelfDevRun } from '../self-dev/run-store.js';
|
|
10
10
|
import { normalizeRunId } from './harness-space.js';
|
|
11
|
-
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
12
|
-
import {
|
|
11
|
+
import { effectiveInstanceRoot, prodInstanceRoot } from '../instance/resolve.js';
|
|
12
|
+
import { lookupGoal, type GoalLookupOptions, type GoalLookupResult } from '../self-implement/goal-lookup.js';
|
|
13
|
+
import { archiveGoals, type GoalArchiveOptions } from '../self-implement/goal-archive.js';
|
|
14
|
+
import { detectBursts, formatIncidentBurstWarning, incidentLastLines, readRunExits, recentBurst, recordRunExit } from './harness-incidents.js';
|
|
13
15
|
import { Command, Option } from 'commander';
|
|
14
16
|
import { runGitCommand } from '../git-fs/runner.js';
|
|
15
17
|
import { GOAL_TYPES, lintGoalFile, parseGoalId, parseGoalType, tracedPathReferences, type GoalType } from '../self-implement/goal-author.js';
|
|
@@ -29,6 +31,7 @@ import { DEFAULT_FALLBACK_CHAIN } from '../oauth/fallback-chain.js';
|
|
|
29
31
|
import { installDeliverableVerifyCliCommand, type InstallDeliverableVerifyCliDeps } from './deliverable-verify-cli.js';
|
|
30
32
|
import { getUserConfig } from '../user-config.js';
|
|
31
33
|
import { installHarnessCliSinkHook } from './harness-cli-sink.js';
|
|
34
|
+
import { addHarnessQueue, listHarnessQueue, queueSeatForCwd, reconcileHarnessQueue, removeHarnessQueue, tickHarnessQueue, type HarnessQueueDeps, type QueueSeat } from './harness-queue.js';
|
|
32
35
|
import { resolveHarnessSubstrate, type ResolvedHarnessSubstrate } from './harness-substrate-default.js';
|
|
33
36
|
import { runHarnessPlanRfc } from './harness-plan-rfc.js';
|
|
34
37
|
import { classifyGarbage, isGarbageProcessTarget, type GarbageProcess } from './process-garbage.js';
|
|
@@ -91,6 +94,7 @@ export class HarnessCliInputError extends Error {
|
|
|
91
94
|
}
|
|
92
95
|
|
|
93
96
|
export interface HarnessAskSayOptions {
|
|
97
|
+
seat?: QueueSeat;
|
|
94
98
|
json?: boolean;
|
|
95
99
|
base?: string;
|
|
96
100
|
target?: string;
|
|
@@ -252,6 +256,7 @@ function registerHarnessAskSayOptions(command: Command): Command {
|
|
|
252
256
|
.option('--target <path>', 'self: harness가 작업할 레포 또는 디렉터리(self-mission 전용)')
|
|
253
257
|
.option('--yes', 'git 아닌 프로젝트에 git init 및 첫 커밋을 만들도록 동의')
|
|
254
258
|
.option('--correlation <id>', '요청과 런을 잇는 불투명 correlation 값')
|
|
259
|
+
.addOption(new Option('--seat <seat>', '런 귀속 자리 (OP|TC|MK|UX)').choices(['OP', 'TC', 'MK', 'UX']))
|
|
255
260
|
.addOption(new Option('--goal-type <type>', `골 종류 (${GOAL_TYPES.join('|')})`).choices([...GOAL_TYPES]))
|
|
256
261
|
.option('--force-preflight', '전제 검사 막힘을 명시 요청으로 우회(관측에 남음)')
|
|
257
262
|
.option('--force-gate', '같은 골 실행 중 막힘을 명시 요청으로 우회(관측에 남음; 예산 막힘은 우회 불가)')
|
|
@@ -283,6 +288,7 @@ function registerHarnessMissionOptions(command: Command): Command {
|
|
|
283
288
|
function normalizeHarnessCommonOptions(opts: HarnessAskSayOptions): HarnessAskSayOptions {
|
|
284
289
|
return {
|
|
285
290
|
...(opts.json ? { json: true } : {}),
|
|
291
|
+
...(opts.seat !== undefined ? { seat: opts.seat } : {}),
|
|
286
292
|
...(opts.base !== undefined ? { base: opts.base } : {}),
|
|
287
293
|
...(opts.target !== undefined ? { target: opts.target } : {}),
|
|
288
294
|
...(opts.yes === true ? { yes: true } : {}),
|
|
@@ -327,7 +333,7 @@ function assertHarnessChildLlmModel(opts: HarnessAskSayChildLlmOptions): void {
|
|
|
327
333
|
}
|
|
328
334
|
|
|
329
335
|
/** Shared post-parse gate: validate child model before any ask/say early return (including `--dry-run`). */
|
|
330
|
-
type HarnessSubstrateOpts = { substrate?: 'local' | 'pod'; podPool?: string; podMemory?: string; after?: string; autoMerge?: boolean; base?: string; json?: boolean; target?: string; source?: string };
|
|
336
|
+
type HarnessSubstrateOpts = { substrate?: 'local' | 'pod'; podPool?: string; podMemory?: string; after?: string; autoMerge?: boolean; base?: string; json?: boolean; target?: string; source?: string; seat?: QueueSeat };
|
|
331
337
|
function resolveLaunchSubstrate(opts: HarnessSubstrateOpts): ResolvedHarnessSubstrate {
|
|
332
338
|
const resolved = resolveHarnessSubstrate({ flag: opts, config: getUserConfig(), env: process.env });
|
|
333
339
|
debug.log('harness.substrate', 'resolved', resolved);
|
|
@@ -337,7 +343,17 @@ function resolveLaunchSubstrate(opts: HarnessSubstrateOpts): ResolvedHarnessSubs
|
|
|
337
343
|
return resolved;
|
|
338
344
|
}
|
|
339
345
|
type PodExit = { status: number | null; signal?: string | null };
|
|
340
|
-
type PodExitReason = 'signal' | 'human-stop' | 'supervisor' | 'no-launch' | 'unknown'
|
|
346
|
+
type PodExitReason = 'signal' | 'human-stop' | 'supervisor' | 'no-launch' | 'unknown'
|
|
347
|
+
| 'pod-error' | 'launch-gate-blocked' | 'ENOBUFS' | 'OOMKilled';
|
|
348
|
+
|
|
349
|
+
function unknownPodExitTailReason(output: string): PodExitReason | undefined {
|
|
350
|
+
const tail = output.slice(-16_000);
|
|
351
|
+
if (/\bOOMKilled\b/i.test(tail)) return 'OOMKilled';
|
|
352
|
+
if (/\bENOBUFS\b/i.test(tail)) return 'ENOBUFS';
|
|
353
|
+
if (/launch gate[^\r\n]*blocked|blocked[^\r\n]*launch gate/i.test(tail)) return 'launch-gate-blocked';
|
|
354
|
+
if (/\bpod-error\b/i.test(tail)) return 'pod-error';
|
|
355
|
+
return undefined;
|
|
356
|
+
}
|
|
341
357
|
/** GitHub lists at most this many files for one pull request; a list that reaches it is not provably complete. */
|
|
342
358
|
export const GITHUB_PR_FILES_LIST_CAP = 3000;
|
|
343
359
|
const STOPPING_SUPERVISOR_VERDICTS = new Set(['UNCONVERGEABLE', 'CONTRACT-CONFLICT']);
|
|
@@ -440,34 +456,47 @@ export function classifyHarnessPodExit(
|
|
|
440
456
|
try { applied = (deps.hasJobApplied ?? hasHarnessPodJobApplied)(runId, output); } catch { /* unknown */ }
|
|
441
457
|
const noLaunch = ledgerReadable && !ledger?.some((entry) => LAUNCH_EVIDENCE_EVENTS.has(entry.event))
|
|
442
458
|
&& applied === false && !pr;
|
|
443
|
-
reason = noLaunch ? 'no-launch' : 'unknown';
|
|
459
|
+
reason = noLaunch ? 'no-launch' : unknownPodExitTailReason(output) ?? 'unknown';
|
|
444
460
|
line = noLaunch
|
|
445
461
|
? 'Pod 실행에 닿지 못했다 — 풀·컨텍스트·SSH 연결을 확인하거나 `--substrate local` 로 명시하라'
|
|
446
|
-
: 'Pod 실행 여부 또는 종료 이유를 확인하지 못했다'
|
|
462
|
+
: reason === 'unknown' ? 'Pod 실행 여부 또는 종료 이유를 확인하지 못했다'
|
|
463
|
+
: `Pod 종료 출력에서 확인한 원인: ${reason}`;
|
|
447
464
|
}
|
|
448
465
|
try { debug.log('harness.pod', 'exit-classified', { runId, reason, status: exit.status, signal: signal ?? null }); } catch { /* observation is fail-soft */ }
|
|
449
466
|
return { reason, lines: [line, ...(pr ? [`PR 이 남아 있다: ${pr}`] : [])] };
|
|
450
467
|
}
|
|
451
468
|
|
|
452
469
|
/** The classified status is the same exit handed to the launcher; ledger failure is never an exit failure. */
|
|
453
|
-
export function recordClassifiedHarnessPodExit(runId: string | undefined, reason: string, status: number
|
|
470
|
+
export function recordClassifiedHarnessPodExit(runId: string | undefined, reason: string, status: number,
|
|
471
|
+
context: { entrance?: string; seat?: string; output?: string } = {}): void {
|
|
454
472
|
if (!runId) return;
|
|
455
473
|
try {
|
|
456
474
|
const signal = status > 128
|
|
457
475
|
? Object.entries(osConstants.signals).find(([, number]) => number === status - 128)?.[0] ?? null : null;
|
|
458
|
-
|
|
476
|
+
const cwd = process.cwd();
|
|
477
|
+
const seat = context.seat ?? process.env.ELANOUS_HARNESS_SEAT;
|
|
478
|
+
recordRunExit({ runId, reason, status, signal, at: new Date().toISOString(),
|
|
479
|
+
...(context.entrance ? { entrance: context.entrance } : {}),
|
|
480
|
+
...(['OP', 'TC', 'MK', 'UX'].includes(seat ?? '') ? { seat } : {}),
|
|
481
|
+
cwd: `${basename(dirname(cwd))}/${basename(cwd)}`, hostname: hostname().split('.')[0]!, pid: process.pid,
|
|
482
|
+
...(context.output ? { lastLines: incidentLastLines(context.output) } : {}),
|
|
483
|
+
}, effectiveInstanceRoot());
|
|
459
484
|
} catch { /* incident writes cannot change Pod output or exit */ }
|
|
460
485
|
}
|
|
461
486
|
|
|
462
487
|
/** Every Pod launch entrance (harness ask/say · dev ask --substrate pod) warns once after a recent burst; it never blocks the launch. */
|
|
463
488
|
export function warnRecentIncidentBurst(
|
|
464
489
|
root: string = effectiveInstanceRoot(), now: Date = new Date(), write: (line: string) => void = (line) => console.error(line),
|
|
490
|
+
context: { seat?: string; entrance?: string } = {},
|
|
465
491
|
): boolean {
|
|
466
492
|
try {
|
|
467
|
-
const
|
|
493
|
+
const seat = context.seat ?? process.env.ELANOUS_HARNESS_SEAT;
|
|
494
|
+
const burst = recentBurst(root, now, { entrance: context.entrance,
|
|
495
|
+
...(['OP', 'TC', 'MK', 'UX'].includes(seat ?? '') ? { seat } : {}) });
|
|
468
496
|
if (!burst) return false;
|
|
469
497
|
write(formatIncidentBurstWarning(burst));
|
|
470
|
-
try { debug.log('harness.incident', 'burst', { reason: burst.reason, count: burst.count
|
|
498
|
+
try { debug.log('harness.incident', 'burst', { reason: burst.reason, count: burst.count,
|
|
499
|
+
...(burst.seat ? { seat: burst.seat } : {}), ...(burst.entrance ? { entrance: burst.entrance } : {}) }); } catch { /* observation is fail-soft */ }
|
|
471
500
|
return true;
|
|
472
501
|
} catch { return false; /* incident reads cannot block a launch */ }
|
|
473
502
|
}
|
|
@@ -539,7 +568,8 @@ async function onPod(opts: unknown, entrance: 'cli-harness-ask' | 'cli-harness-s
|
|
|
539
568
|
process.exitCode = 2;
|
|
540
569
|
return;
|
|
541
570
|
}
|
|
542
|
-
warnRecentIncidentBurst()
|
|
571
|
+
warnRecentIncidentBurst(effectiveInstanceRoot(), new Date(), (line) => console.error(line),
|
|
572
|
+
{ entrance, seat: o.seat });
|
|
543
573
|
let dispatchRecorded = false;
|
|
544
574
|
try {
|
|
545
575
|
const goalText = entrance === 'cli-harness-ask' ? readFileSync(input, 'utf8') : input;
|
|
@@ -558,14 +588,15 @@ async function onPod(opts: unknown, entrance: 'cli-harness-ask' | 'cli-harness-s
|
|
|
558
588
|
const { dispatchHarnessOnPod } = await import('./harness-pod-dispatch.js');
|
|
559
589
|
let output = '';
|
|
560
590
|
let runId: string | undefined;
|
|
561
|
-
const status = await dispatchHarnessOnPod({ entrance, input, podPool: pool, ...(dispatchRecorded ? { dispatchRecorded: true } : {}), ...(o.podMemory ? { podMemory: o.podMemory } : {}), ...(o.after ? { after: o.after } : {}), ...(o.autoMerge === false ? { autoMerge: false } : {}), ...(o.base ? { base: o.base } : {}), ...(o.json ? { json: true } : {}), ...(o.source ? { source: o.source } : {}) },
|
|
591
|
+
const status = await dispatchHarnessOnPod({ entrance, input, podPool: pool, ...(dispatchRecorded ? { dispatchRecorded: true } : {}), ...(o.podMemory ? { podMemory: o.podMemory } : {}), ...(o.after ? { after: o.after } : {}), ...(o.autoMerge === false ? { autoMerge: false } : {}), ...(o.base ? { base: o.base } : {}), ...(o.json ? { json: true } : {}), ...(o.source ? { source: o.source } : {}), ...(o.seat ? { seat: o.seat } : {}) },
|
|
562
592
|
{ onOutput: (text) => {
|
|
563
593
|
runId ??= harnessPodRunId(output + text);
|
|
564
594
|
output = (output + text).slice(-16_000);
|
|
565
595
|
} });
|
|
566
596
|
if (status !== 0) {
|
|
567
597
|
const classified = classifyHarnessPodExit({ status }, output, { ...(runId ? { runId } : {}) });
|
|
568
|
-
recordClassifiedHarnessPodExit(runId ?? harnessPodRunId(output), classified.reason, status
|
|
598
|
+
recordClassifiedHarnessPodExit(runId ?? harnessPodRunId(output), classified.reason, status,
|
|
599
|
+
{ entrance, seat: o.seat, output });
|
|
569
600
|
for (const line of classified.lines) console.error(line);
|
|
570
601
|
process.exitCode = status;
|
|
571
602
|
}
|
|
@@ -633,7 +664,7 @@ async function dispatchHarnessAskSay(
|
|
|
633
664
|
readonly wouldStart: string;
|
|
634
665
|
readonly goalPath?: string;
|
|
635
666
|
},
|
|
636
|
-
dispatch: (resolved: ResolvedHarnessSubstrate) => Promise<void>,
|
|
667
|
+
dispatch: (resolved: ResolvedHarnessSubstrate, stampedOpts: HarnessAskSayChildLlmOptions & HarnessDryRunOpts) => Promise<void>,
|
|
637
668
|
gate: PreLaunchGateDeps & { readBudget?: () => Promise<BudgetDecision | 'unknown'> } = {},
|
|
638
669
|
): Promise<void> {
|
|
639
670
|
await runInjectedHarnessHandler(async () => {
|
|
@@ -643,6 +674,25 @@ async function dispatchHarnessAskSay(
|
|
|
643
674
|
printHarnessLaunchDryRun(dryRunPreview);
|
|
644
675
|
return;
|
|
645
676
|
}
|
|
677
|
+
// Resolve the launch directory once; descendants and the checkpoint retain the same identity.
|
|
678
|
+
const queued = process.env.ELANOUS_HARNESS_QUEUE_LAUNCH && process.env.ELANOUS_HARNESS_SEAT;
|
|
679
|
+
const queueSeat = queued === 'OP' || queued === 'TC' || queued === 'MK' || queued === 'UX' ? queued : undefined;
|
|
680
|
+
const assigned = opts.seat ?? queueSeat ?? queueSeatForCwd(process.cwd(), getUserConfig().loops?.orchestrator?.seatTrees);
|
|
681
|
+
const inheritedSeat = process.env.ELANOUS_HARNESS_SEAT;
|
|
682
|
+
const podSeat = resolved.substrate === 'pod' && ['OP', 'TC', 'MK', 'UX'].includes(inheritedSeat ?? '')
|
|
683
|
+
? inheritedSeat as QueueSeat : undefined;
|
|
684
|
+
const stampedSeat = resolved.substrate === 'pod' ? opts.seat ?? queueSeat ?? podSeat ?? assigned : assigned;
|
|
685
|
+
const stampedOpts = stampedSeat ? { ...opts, seat: stampedSeat } : opts;
|
|
686
|
+
const launch = async () => {
|
|
687
|
+
const previous = process.env.ELANOUS_HARNESS_SEAT;
|
|
688
|
+
if (stampedSeat) process.env.ELANOUS_HARNESS_SEAT = stampedSeat;
|
|
689
|
+
else delete process.env.ELANOUS_HARNESS_SEAT;
|
|
690
|
+
try { await dispatch(resolved, stampedOpts); }
|
|
691
|
+
finally {
|
|
692
|
+
if (previous === undefined) delete process.env.ELANOUS_HARNESS_SEAT;
|
|
693
|
+
else process.env.ELANOUS_HARNESS_SEAT = previous;
|
|
694
|
+
}
|
|
695
|
+
};
|
|
646
696
|
// Without a GoalId, match the request to a live run's exact verbatim original ask; still check budget.
|
|
647
697
|
let identity = dryRunPreview.input;
|
|
648
698
|
let goalId: string | null = null;
|
|
@@ -657,7 +707,7 @@ async function dispatchHarnessAskSay(
|
|
|
657
707
|
// CLI wiring tests time out on them. Gate tests inject deps or opt in with ELANOUS_LAUNCH_GATE_LIVE=1.
|
|
658
708
|
if (process.env.NODE_ENV === 'test' && Object.keys(gate).length === 0 && process.env.ELANOUS_LAUNCH_GATE_LIVE !== '1') {
|
|
659
709
|
try { debug.log('execution-loop.launch-gate', 'skipped-test-env', { goalId }); } catch { /* observation is fail-soft */ }
|
|
660
|
-
await
|
|
710
|
+
await launch();
|
|
661
711
|
return;
|
|
662
712
|
}
|
|
663
713
|
const budget = await (gate.readBudget ?? (() => readHarnessLaunchBudget(opts)))();
|
|
@@ -672,7 +722,7 @@ async function dispatchHarnessAskSay(
|
|
|
672
722
|
...(decision.budget === 'unknown' ? ['budget unknown'] : decision.budget.action === 'next-provider' ? [decision.budget.reasons.join(' · ') || 'next-provider'] : []),
|
|
673
723
|
];
|
|
674
724
|
if (warnings.length > 0) console.error(`⚠️ launch gate: ${warnings.join(' · ').split(/\r?\n/, 1)[0]}`);
|
|
675
|
-
await
|
|
725
|
+
await launch();
|
|
676
726
|
});
|
|
677
727
|
}
|
|
678
728
|
|
|
@@ -1471,7 +1521,7 @@ export function readProcessOwnership(
|
|
|
1471
1521
|
}
|
|
1472
1522
|
}
|
|
1473
1523
|
|
|
1474
|
-
function defaultListHarnessProcesses(): HarnessProcessListObservation {
|
|
1524
|
+
export function defaultListHarnessProcesses(): HarnessProcessListObservation {
|
|
1475
1525
|
let out: string;
|
|
1476
1526
|
try {
|
|
1477
1527
|
out = execFileSync('ps', ['-axo', 'pid=,ppid=,pcpu=,etime=,command='], {
|
|
@@ -1605,6 +1655,30 @@ const executeGh: GhExecute = (args) => execFileSync('gh', args, {
|
|
|
1605
1655
|
stdio: ['ignore', 'pipe', 'pipe'], env: process.env,
|
|
1606
1656
|
});
|
|
1607
1657
|
|
|
1658
|
+
/** Merge-time adapter: reuse the sweep's GitHub inventory and worktree liveness without a second triage implementation. */
|
|
1659
|
+
export async function supersedeMergedGoalDrafts(
|
|
1660
|
+
number: number, cwd: string,
|
|
1661
|
+
execute: GhExecute = executeGh, git: DraftSweepGitExecute = runGitCommand,
|
|
1662
|
+
): Promise<void> {
|
|
1663
|
+
const remote = git(cwd, ['config', '--get', 'remote.origin.url']);
|
|
1664
|
+
const repository = remote.status === 0 ? githubRemoteRepository(remote.stdout) : undefined;
|
|
1665
|
+
if (!repository) throw new Error('Merge repository unavailable');
|
|
1666
|
+
// The PR can change between open and merge; never authorize a close using locally reconstructed metadata.
|
|
1667
|
+
const pr = ghJson<GithubPull>(['api', `repos/${repository}/pulls/${number}`], execute);
|
|
1668
|
+
if (!pr || pr.number !== number || pr.state !== 'closed' || !pr.merged_at || !pr.title?.trim()
|
|
1669
|
+
|| !pr.head?.ref?.trim() || !pr.created_at || !Array.isArray(pr.labels)
|
|
1670
|
+
|| !Number.isFinite(Date.parse(pr.created_at)) || !Number.isFinite(Date.parse(pr.merged_at))
|
|
1671
|
+
|| Date.parse(pr.merged_at) < Date.parse(pr.created_at)) {
|
|
1672
|
+
throw new Error('Merged PR metadata unavailable');
|
|
1673
|
+
}
|
|
1674
|
+
const merged: SweepMergedPr & { createdAt: string; mergedAt: string } = {
|
|
1675
|
+
number: pr.number, title: pr.title, body: pr.body ?? undefined, branch: pr.head.ref,
|
|
1676
|
+
createdAt: pr.created_at, mergedAt: pr.merged_at,
|
|
1677
|
+
};
|
|
1678
|
+
const { supersedeDraftsOnMerge } = await import('../self-dev/draft-sweep.js');
|
|
1679
|
+
await supersedeDraftsOnMerge({ repository, merged, adapters: githubDraftSweepAdapters(execute, git, cwd) });
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1608
1682
|
function ghJson<T>(args: string[], execute: GhExecute): T {
|
|
1609
1683
|
return JSON.parse(execute(args)) as T;
|
|
1610
1684
|
}
|
|
@@ -1669,7 +1743,7 @@ function githubRemoteRepository(url: string): string | undefined {
|
|
|
1669
1743
|
return match?.[1];
|
|
1670
1744
|
}
|
|
1671
1745
|
|
|
1672
|
-
export function githubDraftSweepAdapters(execute: GhExecute = executeGh, git: DraftSweepGitExecute = runGitCommand): DraftSweepAdapters {
|
|
1746
|
+
export function githubDraftSweepAdapters(execute: GhExecute = executeGh, git: DraftSweepGitExecute = runGitCommand, cwd = process.cwd()): DraftSweepAdapters {
|
|
1673
1747
|
const inventory = async (repository: string, state: 'open' | 'closed'): Promise<GithubPull[]> => {
|
|
1674
1748
|
// ⛔ A large repository has tens of thousands of closed PRs (2026-09-28: 21k → «exceeded pagination limit», no sweep at all).
|
|
1675
1749
|
// Merged twins only matter after the oldest open draft was opened, so the closed listing stops at that time.
|
|
@@ -1762,6 +1836,7 @@ export function githubDraftSweepAdapters(execute: GhExecute = executeGh, git: Dr
|
|
|
1762
1836
|
return draftSweepRunStatus(ledgerMatches, running, repository, draft.number);
|
|
1763
1837
|
};
|
|
1764
1838
|
return {
|
|
1839
|
+
getPrFiles: async (repository, number) => filesFor(repository, number),
|
|
1765
1840
|
listDrafts: async (page, perPage, repository): Promise<SweepDraft[]> =>
|
|
1766
1841
|
(await listed(open, repository, 'open')).filter((pr) => pr.draft)
|
|
1767
1842
|
.slice((page - 1) * perPage, page * perPage)
|
|
@@ -1810,7 +1885,6 @@ export function githubDraftSweepAdapters(execute: GhExecute = executeGh, git: Dr
|
|
|
1810
1885
|
} finally { store.close(); }
|
|
1811
1886
|
},
|
|
1812
1887
|
listLiveBranches: async (repository) => {
|
|
1813
|
-
const cwd = process.cwd();
|
|
1814
1888
|
const remote = git(cwd, ['config', '--get', 'remote.origin.url']);
|
|
1815
1889
|
if (remote.status !== 0 || githubRemoteRepository(remote.stdout)?.toLowerCase() !== repository.toLowerCase()) {
|
|
1816
1890
|
return undefined;
|
|
@@ -1919,6 +1993,55 @@ function installHarnessDraftSweepCommand(harnessCmd: Command, deps: HarnessDraft
|
|
|
1919
1993
|
});
|
|
1920
1994
|
}
|
|
1921
1995
|
|
|
1996
|
+
function renderHarnessGoal(result: GoalLookupResult, universe: '운영' | '시험'): string {
|
|
1997
|
+
const matchedRun = result.runState?.results.find((entry) => entry.runId === result.runId);
|
|
1998
|
+
return [
|
|
1999
|
+
`골: ${result.goalBody?.split(/\r?\n/, 1)[0] || '골 문서에 없음'}`,
|
|
2000
|
+
`runId: ${result.runId ?? '원장에 없음'}`,
|
|
2001
|
+
`칸 id: ${result.kanId ?? '기록 없음'}`,
|
|
2002
|
+
`PR: ${result.record?.prNumber != null ? `#${result.record.prNumber}` : '기록 없음'}`,
|
|
2003
|
+
`stage/결과: ${result.record?.stage ?? '기록 없음'} / ${result.record?.outcome ?? '기록 없음'}`,
|
|
2004
|
+
`종결 사유: ${result.runState?.supervisorStopReason ?? matchedRun?.error?.message ?? '기록 없음'}`,
|
|
2005
|
+
`찾은 우주: ${universe}`,
|
|
2006
|
+
`원장: ${result.runState ? '찾음' : '원장에 없음'}`,
|
|
2007
|
+
`골 문서: ${result.goalFile ? '찾음' : '골 문서에 없음'}`,
|
|
2008
|
+
].join('\n');
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
function installHarnessGoalCommand(harnessCmd: Command, options?: GoalLookupOptions, archiveOptions?: GoalArchiveOptions): Command {
|
|
2012
|
+
const goal = harnessCmd.command('goal').usage('<reference> | archive [--before <date>] [--apply]')
|
|
2013
|
+
.description('골 문서와 실행 결과를 조회하거나 보관한다');
|
|
2014
|
+
goal.command('archive')
|
|
2015
|
+
.description('종료된 골 문서를 미리 보거나 상태 루트에 보관한다 — 저장소는 건드리지 않고 지울 목록(filesForPr)만 낸다')
|
|
2016
|
+
.option('--before <date>', '완료 시각이 이 YYYY-MM-DD 이전인 골만')
|
|
2017
|
+
.option('--apply', '상태 루트에 보관 복사·색인 (저장소 삭제·스테이지·커밋 없음 · 지우기는 filesForPr 로 사람이 PR)')
|
|
2018
|
+
.option('--trust-doc-record', '런 원장이 없을 때 문서에 적힌 종료 실행 기록을 신뢰')
|
|
2019
|
+
.action((opts: { before?: string; apply?: boolean; trustDocRecord?: boolean }) => {
|
|
2020
|
+
try {
|
|
2021
|
+
const result = archiveGoals({ ...archiveOptions, before: opts.before, apply: opts.apply, trustDocRecord: opts.trustDocRecord });
|
|
2022
|
+
console.log(JSON.stringify(result));
|
|
2023
|
+
} catch (error) {
|
|
2024
|
+
console.error(humanErrorLine(error));
|
|
2025
|
+
process.exitCode = 1;
|
|
2026
|
+
}
|
|
2027
|
+
});
|
|
2028
|
+
goal.command('show <reference>', { isDefault: true })
|
|
2029
|
+
.description('PR 번호 또는 runId 로 골 문서와 실행 결과를 조회한다 (읽기 전용)')
|
|
2030
|
+
.option('--json', 'GoalLookupResult 그대로 출력')
|
|
2031
|
+
.action((reference: string, opts: { json?: boolean }) => {
|
|
2032
|
+
try {
|
|
2033
|
+
const result = lookupGoal(reference, options);
|
|
2034
|
+
const universe = effectiveInstanceRoot() === prodInstanceRoot() ? '운영' : '시험';
|
|
2035
|
+
console.log(opts.json ? JSON.stringify(result) : renderHarnessGoal(result, universe));
|
|
2036
|
+
if (!result.goalFile || !result.runState) process.exitCode = 1;
|
|
2037
|
+
} catch (error) {
|
|
2038
|
+
console.error(humanErrorLine(error));
|
|
2039
|
+
process.exitCode = 1;
|
|
2040
|
+
}
|
|
2041
|
+
});
|
|
2042
|
+
return goal;
|
|
2043
|
+
}
|
|
2044
|
+
|
|
1922
2045
|
function installHarnessBudgetCommand(harnessCmd: Command): Command {
|
|
1923
2046
|
return harnessCmd
|
|
1924
2047
|
.command('budget')
|
|
@@ -2104,6 +2227,9 @@ export interface HarnessCliCommandDeps {
|
|
|
2104
2227
|
deliverableVerify?: InstallDeliverableVerifyCliDeps;
|
|
2105
2228
|
processObservation?: HarnessProcessObservationDeps;
|
|
2106
2229
|
draftSweep?: HarnessDraftSweepDeps;
|
|
2230
|
+
queue?: HarnessQueueDeps;
|
|
2231
|
+
goalLookup?: GoalLookupOptions;
|
|
2232
|
+
goalArchive?: GoalArchiveOptions;
|
|
2107
2233
|
ask?: HarnessAskHandler;
|
|
2108
2234
|
say?: HarnessSayHandler;
|
|
2109
2235
|
/** Observe-only Pod host dispatch seam. */
|
|
@@ -2144,8 +2270,8 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
|
|
|
2144
2270
|
const bursts = detectBursts(rows).filter((burst) => Date.parse(burst.lastAt) >= now - since * 60_000 && Date.parse(burst.lastAt) <= now);
|
|
2145
2271
|
if (opts.json) console.log(JSON.stringify({ rows: selected, bursts }));
|
|
2146
2272
|
else {
|
|
2147
|
-
for (const row of selected) console.log(`${row.at} run ${row.runId} ·
|
|
2148
|
-
for (const burst of bursts) console.log(`${burst.firstAt}–${burst.lastAt} 묶음 ${burst.reason} ×${burst.count} · ${burst.runIds.join(', ')}`);
|
|
2273
|
+
for (const row of selected) console.log(`${row.at} run ${row.runId} · seat=${row.seat ?? '-'} entrance=${row.entrance ?? '-'} reason=${row.reason} · status=${row.status} signal=${row.signal ?? '-'}`);
|
|
2274
|
+
for (const burst of bursts) console.log(`${burst.firstAt}–${burst.lastAt} 묶음 ${burst.reason} ×${burst.count} · seat=${burst.seat ?? '-'} entrance=${burst.entrance ?? '-'} · ${burst.runIds.join(', ')}`);
|
|
2149
2275
|
}
|
|
2150
2276
|
} catch (error) {
|
|
2151
2277
|
console.error(humanErrorLine(error));
|
|
@@ -2155,7 +2281,32 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
|
|
|
2155
2281
|
installDeliverableVerifyCliCommand(harnessCmd, deps.deliverableVerify);
|
|
2156
2282
|
installHarnessProcessObservationCommand(harnessCmd, deps.processObservation);
|
|
2157
2283
|
installHarnessBudgetCommand(harnessCmd);
|
|
2284
|
+
installHarnessGoalCommand(harnessCmd, deps.goalLookup, deps.goalArchive);
|
|
2158
2285
|
installHarnessDraftSweepCommand(harnessCmd, deps.draftSweep);
|
|
2286
|
+
const queue = harnessCmd.command('queue').description('자리별 영속 발사 대기열');
|
|
2287
|
+
const queueDeps = deps.queue ?? {};
|
|
2288
|
+
const queueAction = (action: () => Promise<void>): Promise<void> => runInjectedHarnessHandler(action);
|
|
2289
|
+
queue.command('add').requiredOption('--seat <seat>', 'OP|TC|MK|UX')
|
|
2290
|
+
.option('--say <sentence>', '원문 문장').option('--ask <goal-path>', '골 문서 경로')
|
|
2291
|
+
.option('--hold', '자동 병합 금지').option('--heavy', 'Pod high 메모리')
|
|
2292
|
+
.action((opts: { seat: string; say?: string; ask?: string; hold?: boolean; heavy?: boolean }) => queueAction(async () => {
|
|
2293
|
+
const row = await addHarnessQueue(opts, queueDeps);
|
|
2294
|
+
console.log(`${row.id} ${row.seat} ${row.kind} queued`);
|
|
2295
|
+
}));
|
|
2296
|
+
queue.command('list').description('대기·발사 원장 조회').action(() => queueAction(async () => {
|
|
2297
|
+
for (const row of listHarnessQueue(queueDeps)) console.log(`${row.id} ${row.seat} ${row.status} ${row.kind} ${row.input}`);
|
|
2298
|
+
}));
|
|
2299
|
+
queue.command('remove <id>').description('대기 중 또는 종료 확인된 항목 제거').action((id: string) => queueAction(async () => {
|
|
2300
|
+
if (!await removeHarnessQueue(id, queueDeps)) throw new Error(`queue item active or not found: ${id}`);
|
|
2301
|
+
console.log(`${id} removed`);
|
|
2302
|
+
}));
|
|
2303
|
+
queue.command('reconcile <id>').description('불확정 발사를 확인하고 종료 또는 미발사 증거가 있으면 예약 해소').action((id: string) => queueAction(async () => {
|
|
2304
|
+
console.log(`${id} ${await reconcileHarnessQueue(id, queueDeps)}`);
|
|
2305
|
+
}));
|
|
2306
|
+
queue.command('tick').description('맨 앞 한 건의 자리 몫과 Pod 풀 여유를 확인하고 발사').action(() => queueAction(async () => {
|
|
2307
|
+
const result = await tickHarnessQueue(queueDeps);
|
|
2308
|
+
console.log(`${result.outcome}${result.item ? ` ${result.item.id}` : ''}: ${result.reason}`);
|
|
2309
|
+
}));
|
|
2159
2310
|
|
|
2160
2311
|
const ask = deps.ask;
|
|
2161
2312
|
if (ask) {
|
|
@@ -2171,13 +2322,13 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
|
|
|
2171
2322
|
...(opts.goalType !== undefined ? { goalType: opts.goalType } : {}),
|
|
2172
2323
|
...(opts.target !== undefined ? { target: opts.target } : {}),
|
|
2173
2324
|
},
|
|
2174
|
-
(resolved) => {
|
|
2325
|
+
(resolved, stampedOpts) => {
|
|
2175
2326
|
if (resolved.substrate !== 'pod' && (opts as { source?: string }).source !== undefined) {
|
|
2176
2327
|
console.error('`--source` 는 `--substrate pod` 와 함께');
|
|
2177
2328
|
process.exitCode = 2;
|
|
2178
2329
|
return Promise.resolve();
|
|
2179
2330
|
}
|
|
2180
|
-
return resolved.substrate === 'pod' ? onPod(
|
|
2331
|
+
return resolved.substrate === 'pod' ? onPod(stampedOpts, 'cli-harness-ask', goalPath, resolved.pool!, deps.podDispatchTask) : ask(goalPath, normalizeHarnessAskSayOptions(stampedOpts));
|
|
2181
2332
|
},
|
|
2182
2333
|
deps.launchGate,
|
|
2183
2334
|
);
|
|
@@ -2196,13 +2347,13 @@ export function installHarnessCliCommand(program: Command, deps: HarnessCliComma
|
|
|
2196
2347
|
wouldStart: '골 문서 · 워크트리 · 브랜치 · 자식 · 파이프라인',
|
|
2197
2348
|
...(opts.target !== undefined ? { target: opts.target } : {}),
|
|
2198
2349
|
},
|
|
2199
|
-
(resolved) => {
|
|
2350
|
+
(resolved, stampedOpts) => {
|
|
2200
2351
|
if (resolved.substrate !== 'pod' && (opts as { source?: string }).source !== undefined) {
|
|
2201
2352
|
console.error('`--source` 는 `--substrate pod` 와 함께');
|
|
2202
2353
|
process.exitCode = 2;
|
|
2203
2354
|
return Promise.resolve();
|
|
2204
2355
|
}
|
|
2205
|
-
return resolved.substrate === 'pod' ? onPod(
|
|
2356
|
+
return resolved.substrate === 'pod' ? onPod(stampedOpts, 'cli-harness-say', sentence.join(' '), resolved.pool!, deps.podDispatchTask) : say(sentence, normalizeHarnessAskSayOptions(stampedOpts));
|
|
2206
2357
|
},
|
|
2207
2358
|
deps.launchGate,
|
|
2208
2359
|
);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Database } from 'bun:sqlite';
|
|
2
2
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
+
import { redactSecretText } from '../debug/log.js';
|
|
4
5
|
|
|
5
6
|
export interface RunExit {
|
|
6
7
|
runId: string;
|
|
@@ -8,6 +9,12 @@ export interface RunExit {
|
|
|
8
9
|
status: number | null;
|
|
9
10
|
signal: string | null;
|
|
10
11
|
at: string;
|
|
12
|
+
entrance?: string;
|
|
13
|
+
seat?: string;
|
|
14
|
+
cwd?: string;
|
|
15
|
+
hostname?: string;
|
|
16
|
+
pid?: number;
|
|
17
|
+
lastLines?: string[];
|
|
11
18
|
}
|
|
12
19
|
|
|
13
20
|
export interface IncidentBurst {
|
|
@@ -16,6 +23,14 @@ export interface IncidentBurst {
|
|
|
16
23
|
firstAt: string;
|
|
17
24
|
lastAt: string;
|
|
18
25
|
runIds: string[];
|
|
26
|
+
entrance?: string;
|
|
27
|
+
seat?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Scrub before bounding: a token crossing the 200-character boundary must not leak. */
|
|
31
|
+
export function incidentLastLines(output: string): string[] {
|
|
32
|
+
return output.split(/\r?\n/).filter((line) => line.trim().length > 0).slice(-3)
|
|
33
|
+
.map((line) => redactSecretText(line).slice(0, 200));
|
|
19
34
|
}
|
|
20
35
|
|
|
21
36
|
const KST_OFFSET_MS = 9 * 60 * 60_000;
|
|
@@ -52,7 +67,15 @@ export function readRunExits(root: string): RunExit[] {
|
|
|
52
67
|
|| !(row.status === null || typeof row.status === 'number')
|
|
53
68
|
|| !(row.signal === null || typeof row.signal === 'string')) continue;
|
|
54
69
|
seen.add(row.runId);
|
|
55
|
-
rows.push(row
|
|
70
|
+
rows.push({ runId: row.runId, reason: row.reason, status: row.status, signal: row.signal, at: row.at,
|
|
71
|
+
...(typeof row.entrance === 'string' ? { entrance: row.entrance } : {}),
|
|
72
|
+
...(typeof row.seat === 'string' ? { seat: row.seat } : {}),
|
|
73
|
+
...(typeof row.cwd === 'string' ? { cwd: row.cwd } : {}),
|
|
74
|
+
...(typeof row.hostname === 'string' ? { hostname: row.hostname } : {}),
|
|
75
|
+
...(typeof row.pid === 'number' && Number.isSafeInteger(row.pid) ? { pid: row.pid } : {}),
|
|
76
|
+
...(Array.isArray(row.lastLines) && row.lastLines.every((line) => typeof line === 'string')
|
|
77
|
+
? { lastLines: row.lastLines } : {}),
|
|
78
|
+
});
|
|
56
79
|
}
|
|
57
80
|
}
|
|
58
81
|
return rows.sort((a, b) => Date.parse(a.at) - Date.parse(b.at) || a.runId.localeCompare(b.runId));
|
|
@@ -71,7 +94,10 @@ export function recordRunExit(row: RunExit, root: string): void {
|
|
|
71
94
|
lock.exec('BEGIN IMMEDIATE');
|
|
72
95
|
try {
|
|
73
96
|
if (!readRunExits(root).some((record) => record.runId === row.runId)) {
|
|
74
|
-
|
|
97
|
+
const safeRow = row.lastLines === undefined ? row : {
|
|
98
|
+
...row, lastLines: row.lastLines.slice(-3).map((line) => redactSecretText(line).slice(0, 200)),
|
|
99
|
+
};
|
|
100
|
+
appendFileSync(join(dir, `${kstDate(at)}.jsonl`), `${JSON.stringify(safeRow)}\n`);
|
|
75
101
|
}
|
|
76
102
|
lock.exec('COMMIT');
|
|
77
103
|
} catch (error) {
|
|
@@ -83,21 +109,23 @@ export function recordRunExit(row: RunExit, root: string): void {
|
|
|
83
109
|
}
|
|
84
110
|
}
|
|
85
111
|
|
|
86
|
-
/** Non-overlapping, maximal same-reason windows; no run contributes to two bursts. */
|
|
112
|
+
/** Non-overlapping, maximal same-reason/seat/entrance windows; no run contributes to two bursts. */
|
|
87
113
|
export function detectBursts(rows: readonly RunExit[], { windowMs = 60_000, threshold = 3 }: {
|
|
88
114
|
windowMs?: number; threshold?: number;
|
|
89
115
|
} = {}): IncidentBurst[] {
|
|
90
116
|
const bursts: IncidentBurst[] = [];
|
|
91
|
-
const
|
|
117
|
+
const byIdentity = new Map<string, RunExit[]>();
|
|
92
118
|
const seen = new Set<string>();
|
|
93
119
|
for (const row of rows) {
|
|
94
120
|
if (!row.runId || seen.has(row.runId) || !Number.isFinite(Date.parse(row.at))) continue;
|
|
95
121
|
seen.add(row.runId);
|
|
96
|
-
const
|
|
122
|
+
const key = JSON.stringify([row.reason, row.seat ?? null, row.entrance ?? null]);
|
|
123
|
+
const group = byIdentity.get(key) ?? [];
|
|
97
124
|
group.push(row);
|
|
98
|
-
|
|
125
|
+
byIdentity.set(key, group);
|
|
99
126
|
}
|
|
100
|
-
for (const
|
|
127
|
+
for (const group of byIdentity.values()) {
|
|
128
|
+
const { reason, seat, entrance } = group[0]!;
|
|
101
129
|
group.sort((a, b) => Date.parse(a.at) - Date.parse(b.at) || a.runId.localeCompare(b.runId));
|
|
102
130
|
for (let start = 0; start < group.length;) {
|
|
103
131
|
let end = start + 1;
|
|
@@ -105,25 +133,28 @@ export function detectBursts(rows: readonly RunExit[], { windowMs = 60_000, thre
|
|
|
105
133
|
if (end - start < threshold) { start++; continue; }
|
|
106
134
|
const members = group.slice(start, end);
|
|
107
135
|
bursts.push({ reason, count: members.length, firstAt: members[0]!.at,
|
|
108
|
-
lastAt: members[members.length - 1]!.at, runIds: members.map((row) => row.runId)
|
|
136
|
+
lastAt: members[members.length - 1]!.at, runIds: members.map((row) => row.runId),
|
|
137
|
+
...(seat ? { seat } : {}), ...(entrance ? { entrance } : {}) });
|
|
109
138
|
start = end;
|
|
110
139
|
}
|
|
111
140
|
}
|
|
112
141
|
return bursts.sort((a, b) => Date.parse(a.firstAt) - Date.parse(b.firstAt) || a.reason.localeCompare(b.reason));
|
|
113
142
|
}
|
|
114
143
|
|
|
115
|
-
export function recentBurst(root: string, now: Date | number, { lookbackMs = 15 * 60_000 }: {
|
|
116
|
-
lookbackMs?: number;
|
|
144
|
+
export function recentBurst(root: string, now: Date | number, { lookbackMs = 15 * 60_000, seat, entrance }: {
|
|
145
|
+
lookbackMs?: number; seat?: string; entrance?: string;
|
|
117
146
|
} = {}): IncidentBurst | null {
|
|
118
147
|
const time = typeof now === 'number' ? now : now.getTime();
|
|
119
148
|
const recent = detectBursts(readRunExits(root)).filter((burst) => {
|
|
120
149
|
const last = Date.parse(burst.lastAt);
|
|
121
|
-
return last <= time && last >= time - lookbackMs
|
|
150
|
+
return last <= time && last >= time - lookbackMs
|
|
151
|
+
&& burst.seat === seat && burst.entrance === entrance;
|
|
122
152
|
});
|
|
123
153
|
return recent.sort((a, b) => Date.parse(a.lastAt) - Date.parse(b.lastAt)).at(-1) ?? null;
|
|
124
154
|
}
|
|
125
155
|
|
|
126
156
|
export function formatIncidentBurstWarning(burst: IncidentBurst): string {
|
|
127
157
|
const time = new Date(Date.parse(burst.lastAt) + KST_OFFSET_MS).toISOString().slice(11, 16);
|
|
128
|
-
|
|
158
|
+
const owner = burst.seat || burst.entrance ? ` [seat=${burst.seat ?? '-'} entrance=${burst.entrance ?? '-'}]` : '';
|
|
159
|
+
return `⚠ 최근 묶음 사고${owner}: ${burst.reason} ×${burst.count} (${time} KST) — 원인 확인 전 재발사는 중복·재사고 위험 · elanous harness incidents`;
|
|
129
160
|
}
|
|
@@ -20,6 +20,7 @@ export interface HarnessPodDispatchInput {
|
|
|
20
20
|
/** say 의 문장, 또는 ask 의 골 문서 경로. */
|
|
21
21
|
readonly input: string;
|
|
22
22
|
readonly podPool?: string;
|
|
23
|
+
readonly seat?: 'OP' | 'TC' | 'MK' | 'UX';
|
|
23
24
|
/** Host already recorded the observe-only dispatch; suppress a second decision in the Pod. */
|
|
24
25
|
readonly dispatchRecorded?: boolean;
|
|
25
26
|
/** Pod 메모리 등급(standard|high) — 오케스트레이터 환경 `ELANOUS_POD_MEMORY_TIER` 로 Job 까지 간다. */
|
|
@@ -80,6 +81,7 @@ export function dispatchHarnessOnPod(input: HarnessPodDispatchInput, deps: PodDi
|
|
|
80
81
|
const args = podOrchestrateArgs(input, goalFile);
|
|
81
82
|
debug.log('harness.substrate', 'goal-file', { entrance: input.entrance, mode: tempDir ? 'temp' : 'path' });
|
|
82
83
|
const env = { ...process.env };
|
|
84
|
+
if (input.seat) env.ELANOUS_HARNESS_SEAT = input.seat;
|
|
83
85
|
delete env.ELANOUS_POD_GOAL_DOC;
|
|
84
86
|
delete env.ELANOUS_DISPATCH_RECORDED;
|
|
85
87
|
if (input.dispatchRecorded) env.ELANOUS_DISPATCH_RECORDED = '1';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { renameSync, writeFileSync } from 'node:fs';
|
|
4
|
+
|
|
5
|
+
/** Only a confirmed terminal observation allows reconciliation to release an uncertain launch. */
|
|
6
|
+
export function writeHarnessQueueReceipt(receiptPath: string, state: 'started' | 'finished' | 'not-started', exitCode?: number): void {
|
|
7
|
+
const temp = `${receiptPath}.${randomUUID()}.tmp`;
|
|
8
|
+
writeFileSync(temp, JSON.stringify({ state, at: new Date().toISOString(), ...(exitCode === undefined ? {} : { exitCode }) }), { flag: 'wx', mode: 0o600 });
|
|
9
|
+
renameSync(temp, receiptPath);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function runHarnessQueueChild(
|
|
13
|
+
receiptPath: string, command: string, args: string[],
|
|
14
|
+
start: typeof spawn = spawn,
|
|
15
|
+
): Promise<number> {
|
|
16
|
+
const record = (state: 'started' | 'finished' | 'not-started') => writeHarnessQueueReceipt(receiptPath, state);
|
|
17
|
+
let child: ReturnType<typeof spawn>;
|
|
18
|
+
try { child = start(process.execPath, [command, ...args], { stdio: 'inherit', env: process.env }); }
|
|
19
|
+
catch { record('not-started'); return 1; }
|
|
20
|
+
return await new Promise<number>((done) => {
|
|
21
|
+
let started = false;
|
|
22
|
+
child.once('spawn', () => {
|
|
23
|
+
started = true;
|
|
24
|
+
record('started');
|
|
25
|
+
child.once('exit', (code) => { writeHarnessQueueReceipt(receiptPath, 'finished', code ?? 1); done(code ?? 1); });
|
|
26
|
+
});
|
|
27
|
+
child.once('error', () => {
|
|
28
|
+
if (!started) { record('not-started'); done(1); }
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (import.meta.main) {
|
|
34
|
+
const [receiptPath, command, ...args] = process.argv.slice(2);
|
|
35
|
+
if (!receiptPath || !command) throw new Error('queue child requires receipt path and command');
|
|
36
|
+
process.exitCode = await runHarnessQueueChild(receiptPath, command, args);
|
|
37
|
+
}
|