elanous 0.2.10 → 0.2.11
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/Y4zKzL62sakG5momz3SoQ/_buildManifest.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1394-556de6d71bbdb0fb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1452.93700483b9d4fc61.js +9 -0
- package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 1829-b453a1b22d3999bb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2310-7a59f043f6db207e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2548-6e316138d347cefe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3869-a39d1d9921e10d43.js +1 -0
- package/apps/pwa/out/_next/static/chunks/390.c373e31b3b9d0c41.js +5 -0
- package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +25 -0
- package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4685-c3c1c625b71accd1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +2 -0
- package/apps/pwa/out/_next/static/chunks/507-5acd98bd6dab2d8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5445-745eb795c5963d79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8067-87ce253ec2f23697.js → 5845-e6c003ce8d5fd36a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 5cd7e3a9-404fd6b8d0ecd44c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 7334.a6679d9168f37aa8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +1 -0
- package/apps/pwa/out/_next/static/chunks/79f8be9e-957d68913b590b08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8039-df92e08fede5de8f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8421-1c4acfb1395a0edf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8605-ea5bee9dfae512c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 9269.d2a4795bc6812717.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9656-c1540088f5859c80.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9906-482c6619b3fdda20.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-1dcdc58fc2de2454.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-6a061bd97f0b9398.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-cb95a7432c9ee744.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-54b32bd27726588d.js → page-b12b6d2f8d2d1aea.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-b9efe868bfd36255.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-7c97dcdfe2e37a60.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-8fd36984f549270a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-5721537ca8a3598c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-b654240a572e4c48.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-b9750abc897508c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-4cd1de371f8ad048.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-d99f89657828421c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-50cb2a0eb15e6c83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c8b1ccda6ba7ae98.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-d6b1d156fb95e74b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-2a9932ddb62d76bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-9688f5b4f1ff950f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6b15dd6456c5df09.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-35414e0a007b4082.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-e7a529e0507ac86c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-e001823c35c9dd67.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-371423d1a573d64b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4b764b125339ac17.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cdf8e4b01067bcf1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a24072b35470157.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-94c82eb0ae5abb32.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-0be8d4b2ced75ba0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d37cb0d52f9b6bd5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-686da0df9bf23e5c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4dc614f3ce043e63.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-53f80edc6b8dc07c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-d02c782fc792e2af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-239c17b911b84e72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-dc6a79fb003f746c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-0fffb84cafdc9da6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-1218753c82d585f6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-4b5935e67531efb5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-3285bc87caf1eaa5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-ad553b0e06505ecd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-fca096e3e860306f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ebfa78f0d9885c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-3dc5f21f7e39622d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-c6da2b468454532d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-93bc70e36f595414.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2ea96958-e8c7e112de50b067.js → f48170cc-d05d28bf87a43bf4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +1 -0
- package/apps/pwa/out/_next/static/css/543f56bcb1f79fca.css +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 -0
- package/apps/pwa/out/inside/index.txt +31 -0
- 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/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 -0
- package/apps/pwa/out/outputs/index.txt +30 -0
- 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 -24
- 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 -24
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/graphs/drafts/draft-cleanup.yaml +19 -0
- package/graphs/drafts/recipes.yaml +23 -0
- package/graphs/intake/intake-daily.yaml +2 -1
- package/graphs/ops/recipes.yaml +3 -0
- package/graphs/ops/secret-exposure.yaml +24 -0
- package/graphs/release/recipes.yaml +3 -0
- package/graphs/release/release-loop.yaml +4 -1
- package/graphs/video/explainer-line.yaml +2 -2
- package/package.json +2 -1
- package/plugins/elanous-hwp/README.md +25 -0
- package/plugins/elanous-hwp/cli.ts +22 -0
- package/plugins/elanous-hwp/converter.ts +237 -0
- package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
- package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
- package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
- package/plugins/elanous-hwp/plugin.json +16 -0
- package/plugins/elanous-hwp/plugin.ts +40 -0
- package/scripts/ci-public-export-leak-gate.ts +75 -14
- package/scripts/ci-public-leak-gate.ts +44 -9
- package/scripts/context-hooks/claude-stop.sh +4 -0
- package/scripts/context-hooks/emit.ts +24 -0
- package/scripts/context-hooks/post-tool-use.sh +4 -0
- package/scripts/coord-channel-watch.sh +12 -0
- package/scripts/coord-requests-bridge.ts +143 -0
- package/scripts/field-feed/lib.ts +4 -0
- package/scripts/fleet/node-setup.sh +20 -3
- package/scripts/homebrew-formula-bump.ts +69 -0
- package/scripts/marketing/measure-site-numbers.ts +169 -0
- package/scripts/measure-gate-shards.ts +309 -0
- package/scripts/mission-request-judge.ts +31 -1
- package/scripts/morning-report.ts +2 -2
- package/scripts/opportunity-scan.ts +1 -1
- package/scripts/release-loop/auto-approve-node.ts +21 -4
- package/scripts/release-loop/cut-branch.ts +84 -0
- package/scripts/release-loop/gate-node.ts +14 -13
- package/scripts/release-loop/mac-smoke-node.ts +229 -0
- package/scripts/release-loop/node-verdict.ts +3 -3
- package/scripts/release-loop/tui-node-checks.ts +42 -0
- package/scripts/release-loop/tui-sim-node.ts +32 -8
- package/scripts/release-loop/unattended-release.ts +5 -3
- package/scripts/release-loop/version-node.ts +61 -10
- package/scripts/signal-digest-cycle.ts +2 -7
- package/scripts/signal-digest-photo.ts +11 -0
- package/scripts/tech1-public-measure.ts +94 -0
- package/scripts/test-diet/node.ts +1 -1
- package/scripts/tui-regress.ts +2 -2
- package/scripts/ux/demo-rehearsal.ts +243 -0
- package/scripts/ux/lib/rehearsal-verdict.ts +73 -0
- package/skills/diagram-master/SKILL.md +366 -0
- package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
- package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
- package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
- package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
- package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
- package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
- package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
- package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
- package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
- package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
- package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
- package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
- package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
- package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
- package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
- package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
- package/skills/diagram-master/references/examples/README.md +69 -0
- package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
- package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
- package/skills/diagram-master/references/pyproject.toml +16 -0
- package/skills/diagram-master/references/quality-checklist.md +33 -0
- package/skills/diagram-master/references/routing-guide.md +164 -0
- package/skills/diagram-master/references/uv.lock +1356 -0
- package/skills/google-workspace/SKILL.md +33 -0
- package/skills/google-workspace/scripts/gws-safe.sh +177 -0
- package/skills/grill-me/SKILL.md +1 -1
- package/skills/lecture-note-digitizer/SKILL.md +926 -0
- package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
- package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
- package/skills/lecture-note-digitizer/references/html-template.md +167 -0
- package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
- package/skills/omni-crawl/SKILL.md +21 -11
- package/skills/omni-crawl/scripts/main.ts +6 -6
- package/skills/omni-crawl/src/router.ts +3 -3
- package/skills/omni-digest/SKILL.md +17 -9
- package/skills/omni-digest/digest.md +2 -2
- package/skills/omni-digest/src/fetch.ts +30 -3
- package/skills/pitch-deck/SKILL.md +2 -2
- package/skills/pitch-deck/template.html +2 -2
- package/skills/youtube-master/SKILL.md +163 -0
- package/skills/youtube-master/package-lock.json +558 -0
- package/skills/youtube-master/package.json +13 -0
- package/skills/youtube-master/references/study-note-template.md +124 -0
- package/skills/youtube-master/scripts/main.ts +435 -0
- package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
- package/skills/youtube-master/src/audio.ts +63 -0
- package/skills/youtube-master/src/domain-staging.ts +50 -0
- package/skills/youtube-master/src/env.ts +36 -0
- package/skills/youtube-master/src/obsidian.ts +155 -0
- package/skills/youtube-master/src/router.ts +110 -0
- package/skills/youtube-master/src/stt.ts +199 -0
- package/skills/youtube-master/src/study-note.ts +175 -0
- package/skills/youtube-master/src/summarize.ts +358 -0
- package/skills/youtube-master/src/transcript.ts +76 -0
- package/skills/youtube-master/src/types.ts +91 -0
- package/skills/youtube-master/src/util.ts +93 -0
- package/skills/youtube-master/src/youtube.ts +70 -0
- package/skills/youtube-master/tsconfig.json +13 -0
- package/src/acp/server.ts +5 -2
- package/src/agent-mission/driver.ts +80 -10
- package/src/agent-mission/pty-decision.ts +71 -0
- package/src/agent-mission/review-loop.ts +30 -0
- package/src/autopilot/build/llm-conflict-merge.ts +16 -3
- package/src/autopilot/tool-registry.ts +2 -0
- package/src/boot/daemon-prompt-turn.ts +5 -0
- package/src/boot/daemon-runtime.ts +9 -3
- package/src/boot/daemon-tools/web-search.ts +3 -0
- package/src/card-followup/core.ts +109 -0
- package/src/chat/index.ts +1 -0
- package/src/cli/drive-input-jail.ts +101 -0
- package/src/cli/hooks-cli.ts +17 -3
- package/src/cli/make-cli.ts +43 -0
- package/src/cli/persona-cli.ts +90 -4
- package/src/cli/plugin-cli.ts +31 -22
- package/src/cli/pod-cli.ts +19 -9
- package/src/cli/pr-cli.ts +51 -15
- package/src/cli/pty-drive-cli.ts +41 -7
- package/src/cli/pty-drive-verdict.ts +40 -0
- package/src/cli/release-cli.ts +17 -4
- package/src/cli/setup-cli.ts +43 -1
- package/src/cli/skills-cli.ts +17 -1
- package/src/context-bus/claude-hooks-install.ts +10 -0
- package/src/context-bus/context-now-surfaces.ts +48 -0
- package/src/context-bus/context-now.ts +104 -0
- package/src/context-bus/coord-events.ts +2 -2
- package/src/context-bus/external-events.ts +52 -0
- package/src/context-bus/long-term-memory.ts +108 -0
- package/src/dashboard/index.ts +9 -4
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +7 -1
- package/src/decisions/decision-cards.ts +10 -3
- package/src/decisions/decision-ledger.ts +13 -5
- package/src/discord/sprint21-runtime.ts +5 -1
- package/src/discord-self-message.ts +32 -0
- package/src/discord-slash-wire.ts +5 -1
- package/src/discord.ts +17 -1
- package/src/domains/core-tools.ts +3 -2
- package/src/domains/outbound-alert.ts +6 -1
- package/src/domains/telegram-kind-route.ts +51 -13
- package/src/exec-requests/default-outputs.ts +25 -0
- package/src/exec-requests/planner.ts +10 -2
- package/src/exec-requests/runner.ts +20 -6
- package/src/exec-requests/store.ts +3 -0
- package/src/execution-loop/launch-gate.ts +100 -0
- package/src/field/field-reel.ts +5 -1
- package/src/field-note/index.ts +201 -0
- package/src/field-note/transcribe.ts +248 -0
- package/src/graph-kinds/registry.ts +3 -3
- package/src/graph-runner/graph-cli.ts +61 -1
- package/src/graph-runner/graph-grow-llm.ts +37 -0
- package/src/graph-runner/graph-grow.ts +47 -0
- package/src/graph-runner/runner.ts +317 -25
- package/src/grok/agent-search.ts +8 -2
- package/src/guardian/secret-exposure-scan.ts +101 -0
- package/src/harness/harness-cli-command.ts +247 -7
- package/src/harness/harness-pod-dispatch.ts +43 -23
- package/src/harness/harness-seams.ts +38 -4
- package/src/harness/harness-stop.ts +23 -4
- package/src/harness/launch-registry.ts +91 -0
- package/src/harness/process-garbage.ts +5 -3
- package/src/hooks/dispatch.ts +82 -0
- package/src/hooks/expose.ts +254 -0
- package/src/hooks/github-shadow.ts +108 -0
- package/src/hooks/providers.ts +71 -5
- package/src/hooks/queue.ts +1 -1
- package/src/hooks/receiver.ts +21 -20
- package/src/index.ts +52 -14
- package/src/intake-plane/categorize.ts +18 -46
- package/src/intake-plane/discord-seat-work.ts +10 -0
- package/src/intake-plane/front-route-classifier.ts +33 -39
- package/src/intake-plane/persona-answer.ts +30 -0
- package/src/intake-plane/runtime-callables.ts +8 -1
- package/src/intake-plane/telegram-seat-work.ts +36 -2
- package/src/intake-plane/wish-folder.ts +67 -0
- package/src/intent-gate/gate.ts +30 -10
- package/src/live/detail-switch.ts +5 -0
- package/src/llm/difficulty.ts +57 -0
- package/src/llm/judge-layer.ts +101 -0
- package/src/llm/mission-router.ts +33 -19
- package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
- package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
- package/src/loops/contract/examples/steward.loop.yaml +50 -0
- package/src/loops/contract/loop-agent.schema.json +138 -0
- package/src/loops/contract/validate.ts +64 -0
- package/src/loops/registry.ts +20 -6
- package/src/market/signed-index.ts +4 -0
- package/src/maturity/bot-command-maturity.ts +45 -0
- package/src/maturity/feature-maturity.ts +26 -4
- package/src/model-tier/index.ts +2 -2
- package/src/model-tier/tier-resolver.ts +20 -20
- package/src/model-tier/types.ts +6 -6
- package/src/mss/logging/log-store.ts +15 -0
- package/src/nexus/api/config-model-tier.ts +5 -4
- package/src/nexus/api/fabric-plans.ts +53 -0
- package/src/nexus/api/harness-api.ts +5 -1
- package/src/nexus/api/health.ts +2 -0
- package/src/nexus/api/http-server.ts +36 -0
- package/src/nexus/api/inside-events.ts +226 -0
- package/src/nexus/api/meta-api.ts +21 -8
- package/src/nexus/api/missions.ts +6 -1
- package/src/nexus/api/ops-seats.ts +33 -0
- package/src/nexus/api/outputs-route.ts +44 -0
- package/src/nexus/api/seat-requests.ts +44 -2
- package/src/nexus/api/sessions-store.ts +17 -38
- package/src/nexus/api/sub-seat-charters.ts +34 -0
- package/src/nexus/api/tabs-mutations.ts +3 -1
- package/src/nexus/api/trace.ts +18 -6
- package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
- package/src/nexus/api/workflows.ts +80 -6
- package/src/nexus/index.ts +2 -0
- package/src/nexus/kinds/webterm.ts +2 -1
- package/src/nexus/webterm/pty.ts +6 -2
- package/src/onboarding/cli-auth-status.ts +80 -0
- package/src/onboarding/voice-ai.ts +3 -3
- package/src/org/seat-budget.ts +48 -0
- package/src/org/stall-escalation.ts +63 -0
- package/src/outputs/ledger.ts +120 -0
- package/src/persona/persona-todo.ts +79 -0
- package/src/persona/presets.ts +116 -2
- package/src/persona/team-set.ts +155 -0
- package/src/plugins/install/plugin-install.ts +14 -0
- package/src/plugins/maker/market-bundle.ts +109 -0
- package/src/plugins/maker/plugin-maker.ts +254 -11
- package/src/plugins/maker/wizard-generate.ts +103 -0
- package/src/pod-lease/admission.ts +150 -0
- package/src/pod-lease/dependency-state.ts +85 -0
- package/src/pod-lease/host-lease.ts +127 -0
- package/src/project/project-suggestion.ts +16 -0
- package/src/project/session-context.ts +24 -0
- package/src/release-loop/checklist.ts +2 -2
- package/src/release-loop/feature-store.ts +5 -3
- package/src/release-loop/next-md-merge.ts +58 -0
- package/src/release-loop/release-note.ts +59 -4
- package/src/seat-dispatch/seat-ask.ts +130 -0
- package/src/seat-dispatch/seat-questions.ts +100 -0
- package/src/seat-loop/seat-loop.ts +548 -29
- package/src/seat-loop/seat-report.ts +37 -2
- package/src/self-dev/dev-cli.ts +4 -1
- package/src/self-dev/dev-pipeline.ts +37 -1
- package/src/self-dev/draft-sweep.ts +38 -33
- package/src/self-dev/draft-triage-rules.ts +8 -5
- package/src/self-dev/fabric-plan-core.ts +297 -0
- package/src/self-dev/orchestrate.ts +36 -4
- package/src/self-dev/release-path-guard.ts +62 -0
- package/src/self-dev/shard-aggregate.ts +230 -0
- package/src/self-dev/shard-placement.ts +60 -0
- package/src/self-dev/shard-plan.ts +48 -0
- package/src/self-dev/shard-pod-run.ts +77 -0
- package/src/self-dev/shard-run.ts +105 -0
- package/src/self-implement/gate-baseline.ts +1 -1
- package/src/self-implement/gate-cli.ts +40 -1
- package/src/self-implement/gate-scope.ts +37 -7
- package/src/self-implement/graph-variant.ts +171 -0
- package/src/self-implement/harness-policy-gates.ts +1 -1
- package/src/self-implement/headless-elanous-driver.ts +22 -3
- package/src/self-implement/host-regate.ts +22 -1
- package/src/self-implement/importer-test-index.ts +2 -1
- package/src/self-implement/l8-merge-queue.ts +130 -0
- package/src/self-implement/orchestrator.ts +242 -9
- package/src/self-implement/route-consumer-test-index.ts +122 -0
- package/src/self-implement/seams.ts +72 -11
- package/src/self-implement/test-seams.ts +1 -0
- package/src/self-implement/uncommitted-work.ts +59 -0
- package/src/session/index.ts +36 -13
- package/src/skills/gift-install.ts +215 -0
- package/src/skills/tools/web-search.ts +4 -1
- package/src/steward/launch.ts +42 -26
- package/src/steward/steward-cards.ts +17 -9
- package/src/steward/triage.ts +46 -14
- package/src/task-cards/card-cli.ts +25 -1
- package/src/task-orchestrator/mission.ts +5 -0
- package/src/task-orchestrator/store.ts +12 -3
- package/src/task-orchestrator/surfaces/pod-command-job.ts +29 -7
- package/src/task-orchestrator/surfaces/pod-lease.ts +156 -19
- package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +214 -40
- package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
- package/src/task-orchestrator/types.ts +2 -0
- package/src/telegram-card-followup.ts +16 -96
- package/src/telegram-commands.ts +10 -1
- package/src/telegram-project-command.ts +71 -0
- package/src/telegram-report.ts +21 -17
- package/src/telegram.ts +29 -3
- package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
- package/src/user-config.ts +102 -20
- package/src/version/packed-revision.json +1 -1
- package/src/web-search/grok.ts +7 -1
- package/src/web-search/index.ts +28 -1
- package/src/web-search/provider.ts +4 -0
- package/src/web-search/x-intent.ts +5 -0
- package/src/workflow-runtime/executor.ts +277 -47
- package/src/workflow-runtime/index.ts +1 -0
- package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
- package/src/workflow-runtime/plugin-kind-node.ts +1 -1
- package/src/workflow-runtime/schema.ts +79 -4
- package/src/workflow-runtime/types.ts +35 -4
- package/apps/pwa/out/_next/static/2DsiDfDCks44g1cPUMhiW/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/24-e6d28380efab7faf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
- package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
- package/apps/pwa/out/_next/static/chunks/3615-740dd270764ffa24.js +0 -1
- package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3734-1015fe991eb9b7e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5012-a7fe6f3c8b6fe45a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5783-ef40ebfc91d55230.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
- package/apps/pwa/out/_next/static/chunks/62-ff227c3edb8b248b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7633-1b3709b0854c9412.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7951-8b03dbb10b24cd06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8195-6fde3d7a39859206.js +0 -10
- package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8894-b5fb36bab837cd29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9454-84d0d5d77446bd92.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/988-5f92e7ab7ccea3dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9989-5582582f06429840.js +0 -1
- package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d2253d7e58ef1890.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5441d4a9ab35e518.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-d9b12d680922d980.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e268d6d145827a22.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-f8116559c7424da7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-1085399fd0f32112.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-1df686a14f65895a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-54e1f966ab60a4dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-7ed95f296f5ee8e9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-11edac668d77e5c3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-59e2b9a22cd5a6d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-2976df21ad74ab48.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-34d211a67f16d510.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-8ff652d5d950639b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-b31610deda76337b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6cb0e1bbefe5fb3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-a286a152cf584576.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-d9237581e7003bcb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-83274e761643fdd2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ceee6cfb1d4e6d68.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-9c9f8bb3e4a64091.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c17217603ea3426a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-efb6177cbf1e8a51.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-d307523703bc4df3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-462f4e4bab45ce7d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-8990e96f33af3837.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e168fa1030af0548.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-1233e05a4068bc9c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-13a1840b1fac337a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-64a29fc80b11ab55.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-68e787339a16b3dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-4fddc90b23feb215.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-886ba8260dc79c79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-0f26507a1722e40b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-109d4ccd42259c9d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-f5c2a4e510726774.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-b2e0039416f42522.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-26102fd7350f171e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-708948bc8a802794.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-5e5611620f78fb0b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-139ba5c367bbf60a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-202b4e81f33895ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
- package/apps/pwa/out/_next/static/css/43feca5fd387dcbd.css +0 -1
- /package/apps/pwa/out/_next/static/{2DsiDfDCks44g1cPUMhiW → Y4zKzL62sakG5momz3SoQ}/_ssgManifest.js +0 -0
|
@@ -24,7 +24,7 @@ import { effectiveInstanceRoot } from '../../instance/resolve.js';
|
|
|
24
24
|
import { controlInboxEnv } from '../../harness/control-inbox.js';
|
|
25
25
|
import { finishPodFragment, writePodFragment } from '../../harness/self-send-target.js';
|
|
26
26
|
import { mintRunId, normalizeRunId } from '../../harness/harness-space.js';
|
|
27
|
-
import { appendRunLedgerEntry, runLedgerDir, runLedgerPath } from '../../self-implement/run-ledger.js';
|
|
27
|
+
import { appendRunLedgerEntry, loadRunLedger, runLedgerDir, runLedgerPath } from '../../self-implement/run-ledger.js';
|
|
28
28
|
import type { GoalExecutionRecord } from '../../self-implement/orchestrator.js';
|
|
29
29
|
import { runHostRegate, type HostRegateResult } from '../../self-implement/host-regate.js';
|
|
30
30
|
|
|
@@ -40,6 +40,7 @@ export const POD_JOB_DEADLINE_SECONDS = 10_800;
|
|
|
40
40
|
* 예약만 실사용에 맞춘다. */
|
|
41
41
|
export const POD_CHILD_REQUESTS = { cpu: '1', memory: '4Gi' } as const;
|
|
42
42
|
import type { PodPoolMember, PodPoolScheduler } from './pod-pool.js';
|
|
43
|
+
import { measurePoolLease, recommendConcurrency, POD_HOST_LEASE_ANNOTATION } from './pod-lease.js';
|
|
43
44
|
import { ACTUAL_SUBSTRATE_ENV, RUN_CONTRACT_ENV, carryRunContract, completionFloorFor } from '../../self-implement/graph-run-contract.js';
|
|
44
45
|
import { spawnSync } from 'node:child_process';
|
|
45
46
|
import { createHash } from 'node:crypto';
|
|
@@ -388,6 +389,10 @@ export function k8sLabelValue(value: string | undefined): string | undefined {
|
|
|
388
389
|
return cleaned || undefined;
|
|
389
390
|
}
|
|
390
391
|
|
|
392
|
+
/** POD9 — Job identity for OOM-retry recovery: which goal execution (hash of the request) and which attempt (1 = first · 2 = high retry). */
|
|
393
|
+
export const POD_EXECUTION_KEY_ANNOTATION = 'elanous.dev/execution-key';
|
|
394
|
+
export const POD_ATTEMPT_ANNOTATION = 'elanous.dev/attempt';
|
|
395
|
+
|
|
391
396
|
/** `elanous.run` = 사람이 보는 하니스 런(오케스트레이터 · `ELANOUS_RUN_ID`) — `harness stop <runId>` 와 오케스트레이터의 신호 정리(#21171)가
|
|
392
397
|
* 이 라벨로 Job 을 고른다. 자식 런 id 는 `elanous.child-run`. */
|
|
393
398
|
export function podRunLabels(o: { runId?: string; parentRunId?: string }): Record<string, string> {
|
|
@@ -402,11 +407,30 @@ export function podRunLabels(o: { runId?: string; parentRunId?: string }): Recor
|
|
|
402
407
|
* node-b 노드 할당 가능 약 251Gi. */
|
|
403
408
|
export const POD_MEMORY_DEFAULT = '16Gi';
|
|
404
409
|
export const POD_MEMORY_HIGH_DEFAULT = '32Gi';
|
|
405
|
-
|
|
410
|
+
/** POD7 — `lite`(`ELANOUS_POD_MEMORY_LITE` 또는 2Gi): 명시할 때만(인자·문면 줄) · 자동 판정은 없다(성공 런 피크 기록 0 — 설계 §②). OOM 이면 POD9 가 high 로 한 번 다시 띄운다. */
|
|
411
|
+
export const POD_MEMORY_LITE_DEFAULT = '2Gi';
|
|
412
|
+
export const POD_MEMORY_TIERS = ['lite', 'standard', 'high'] as const;
|
|
406
413
|
export type PodMemoryTier = (typeof POD_MEMORY_TIERS)[number];
|
|
407
414
|
export type PodMemorySource = 'option' | 'goal-line' | 'pwa-auto' | 'default' | 'parent-goal-line' | 'parent-pwa-auto';
|
|
408
415
|
const PWA_PATH = /(?:^|[\s`'"(,·])apps\/pwa\//m;
|
|
409
|
-
const GOAL_LINE =
|
|
416
|
+
const GOAL_LINE = /^[ \t]*(?:Pod 메모리|pod-memory)[ \t]*:[ \t]*(lite|standard|high)[ \t]*\r?$/im;
|
|
417
|
+
|
|
418
|
+
/** L7c — Pod queue predecessor («선행 = 결과 위에 짓는 경우만»; sharing target files is not a predecessor).
|
|
419
|
+
* Order (first wins): spawn input `after` · launch option `--after` (→ `ELANOUS_POD_AFTER`) · piece line `선행: #N|<goal id>` · parent goal line. */
|
|
420
|
+
const AFTER_LINE = /^[ \t]*(?:선행|after)[ \t]*:[ \t]*(#?[1-9]\d*|[a-f0-9]{16})[ \t]*\r?$/im;
|
|
421
|
+
|
|
422
|
+
export function parsePodPredecessor(v: string | undefined): string | number | null {
|
|
423
|
+
const t = v?.trim();
|
|
424
|
+
if (!t) return null;
|
|
425
|
+
if (/^[a-f0-9]{16}$/.test(t)) return t;
|
|
426
|
+
if (/^#?[1-9]\d*$/.test(t)) { const n = Number(t.replace(/^#/, '')); return Number.isSafeInteger(n) ? n : null; }
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
export function podPredecessorFor(feature: string, env: NodeJS.ProcessEnv | Readonly<Record<string, string | undefined>>, parentGoal?: string): string | number | undefined {
|
|
431
|
+
return parsePodPredecessor(env.ELANOUS_POD_AFTER) ?? parsePodPredecessor(AFTER_LINE.exec(feature)?.[1])
|
|
432
|
+
?? parsePodPredecessor(AFTER_LINE.exec(parentGoal ?? '')?.[1]) ?? undefined;
|
|
433
|
+
}
|
|
410
434
|
|
|
411
435
|
export function goalTouchesPwa(feature: string): boolean {
|
|
412
436
|
return PWA_PATH.test(feature);
|
|
@@ -433,6 +457,7 @@ export function podMemoryLimitFor(feature: string, env: NodeJS.ProcessEnv | Read
|
|
|
433
457
|
: parentLine ? [parentLine, 'parent-goal-line']
|
|
434
458
|
: parentGoal && goalTouchesPwa(parentGoal) ? ['high', 'parent-pwa-auto']
|
|
435
459
|
: ['standard', 'default'];
|
|
460
|
+
if (tier === 'lite') return { limit: env.ELANOUS_POD_MEMORY_LITE?.trim() || POD_MEMORY_LITE_DEFAULT, tier, source };
|
|
436
461
|
const base = env.ELANOUS_POD_MEMORY?.trim() || POD_MEMORY_DEFAULT;
|
|
437
462
|
if (tier === 'standard') return { limit: base, tier, source };
|
|
438
463
|
const high = env.ELANOUS_POD_MEMORY_HIGH?.trim() || POD_MEMORY_HIGH_DEFAULT;
|
|
@@ -440,7 +465,7 @@ export function podMemoryLimitFor(feature: string, env: NodeJS.ProcessEnv | Read
|
|
|
440
465
|
return { limit: a !== null && b !== null && a > b ? base : high, tier, source };
|
|
441
466
|
}
|
|
442
467
|
|
|
443
|
-
export function podJobManifest(o: { name: string; namespace: string; image: string; /** 레지스트리 이미지면 IfNotPresent(노드가 pull) · 반입 이미지면 Never. */ imagePullPolicy?: 'Never' | 'IfNotPresent'; repoUrl: string; source?: PodSource; hostMirror?: string; args: readonly string[]; passEnv: readonly string[]; deadlineSeconds: number; runId?: string; parentRunId?: string; armEnv?: Readonly<Record<string, string>>; hostId?: string; imageCommit?: string | null; skillEnvs?: readonly string[]; memoryLimit?: string; goalDoc?: string; grokCredential?: 'subscription' | 'api_key'; codexAccounts?: readonly string[]; appCredential?: boolean; /** Test seam — default POD_GH_STALE_SECONDS. */ githubStaleSeconds?: number }): Record<string, unknown> {
|
|
468
|
+
export function podJobManifest(o: { name: string; namespace: string; image: string; /** 레지스트리 이미지면 IfNotPresent(노드가 pull) · 반입 이미지면 Never. */ imagePullPolicy?: 'Never' | 'IfNotPresent'; repoUrl: string; source?: PodSource; hostMirror?: string; args: readonly string[]; passEnv: readonly string[]; deadlineSeconds: number; runId?: string; parentRunId?: string; armEnv?: Readonly<Record<string, string>>; hostId?: string; imageCommit?: string | null; skillEnvs?: readonly string[]; memoryLimit?: string; goalDoc?: string; grokCredential?: 'subscription' | 'api_key'; codexAccounts?: readonly string[]; appCredential?: boolean; /** Test seam — default POD_GH_STALE_SECONDS. */ githubStaleSeconds?: number; /** Which goal execution and attempt this Job is — a resumed host verifies it before following the Job (POD9). */ execution?: { key: string; attempt: number }; hostLeaseAdmitted?: boolean }): Record<string, unknown> {
|
|
444
469
|
const quoted = o.args.map((a) => `'${a.replace(/'/g, `'\\''`)}'`).join(' ');
|
|
445
470
|
const goalPath = o.goalDoc ? `'${(o.goalDoc.startsWith('-') ? `./${o.goalDoc}` : o.goalDoc).replace(/'/g, `'\\''`)}'` : undefined;
|
|
446
471
|
const askBaseIndex = o.goalDoc ? o.args.indexOf('--base') : -1;
|
|
@@ -536,7 +561,8 @@ if [ "$found" -eq 0 ]; then echo ELANOUS_RUN_LEDGER_NONE; fi`,
|
|
|
536
561
|
return {
|
|
537
562
|
apiVersion: 'batch/v1',
|
|
538
563
|
kind: 'Job',
|
|
539
|
-
metadata: { name: o.name, namespace: o.namespace, labels: { 'elanous.substrate': 'pod', 'elanous.job': o.name, ...podRunLabels(o) }
|
|
564
|
+
metadata: { name: o.name, namespace: o.namespace, labels: { 'elanous.substrate': 'pod', 'elanous.job': o.name, ...podRunLabels(o) },
|
|
565
|
+
...((o.execution || o.hostLeaseAdmitted) ? { annotations: { ...(o.execution ? { [POD_EXECUTION_KEY_ANNOTATION]: o.execution.key, [POD_ATTEMPT_ANNOTATION]: String(o.execution.attempt) } : {}), ...(o.hostLeaseAdmitted ? { [POD_HOST_LEASE_ANNOTATION]: 'true' } : {}) } } : {}) },
|
|
540
566
|
spec: {
|
|
541
567
|
backoffLimit: 0,
|
|
542
568
|
ttlSecondsAfterFinished: 7200,
|
|
@@ -612,7 +638,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
|
|
|
612
638
|
let parentGoal: string | undefined;
|
|
613
639
|
let parentGoalUnreadable = false;
|
|
614
640
|
let inheritedFrom: string | undefined;
|
|
615
|
-
if (
|
|
641
|
+
if (env.ELANOUS_POD_GOAL_DOC) {
|
|
616
642
|
try {
|
|
617
643
|
const requestedPath = normalize(env.ELANOUS_POD_GOAL_DOC);
|
|
618
644
|
if (isAbsolute(requestedPath) || requestedPath === '..' || requestedPath.startsWith(`..${sep}`) || requestedPath === '.') throw new Error('invalid goal path');
|
|
@@ -626,13 +652,42 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
|
|
|
626
652
|
inheritedFrom = withinRoot;
|
|
627
653
|
} catch { parentGoalUnreadable = true; }
|
|
628
654
|
}
|
|
629
|
-
const { limit:
|
|
655
|
+
const { limit: selectedMemoryLimit, tier: memoryTier, source: memorySource } = parentGoal === undefined ? featureMemory : podMemoryLimitFor(input.feature, env, parentGoal);
|
|
656
|
+
for (const [where, text] of [['feature', input.feature], ['parent-goal', parentGoal]] as const) {
|
|
657
|
+
if (text && text.split(/\r?\n/u).some((line) => /Pod 메모리/u.test(line) && !GOAL_LINE.test(line))) {
|
|
658
|
+
const reason = '한 줄 단독 `Pod 메모리: high|standard` 형식이 아님';
|
|
659
|
+
console.warn(`[pod] Pod 메모리 지시 무시됨 · 이유: ${reason} (${where})`);
|
|
660
|
+
debug.log('self-implement.pod', 'memory-directive-ignored', { spaceId: input.spaceId, where, reason }, { level: 'warn' });
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
let memoryLimit = selectedMemoryLimit;
|
|
664
|
+
const after = input.after ?? podPredecessorFor(input.feature, env, parentGoal);
|
|
665
|
+
if (after !== undefined) debug.log('self-implement.pod', 'predecessor', { spaceId: input.spaceId, after, source: input.after !== undefined ? 'input' : 'goal-or-option' });
|
|
666
|
+
let oomRetried = false;
|
|
667
|
+
let retryFromChildRunId: string | undefined;
|
|
668
|
+
let retryFromMemoryLimit: string | undefined;
|
|
630
669
|
debug.log('self-implement.pod', 'memory-limit', { spaceId: input.spaceId, memoryLimit, tier: memoryTier, source: memorySource,
|
|
631
670
|
...(memorySource.startsWith('parent-') ? { inheritedFrom } : {}), ...(parentGoalUnreadable ? { parentGoal: 'unreadable' } : {}) });
|
|
632
671
|
const childRunId = mintRunId();
|
|
672
|
+
const executionKey = createHash('sha256').update(JSON.stringify({ spaceId: input.spaceId, feature: input.feature, base: input.base, autoMerge: input.autoMerge, autoReview: input.autoReview, openPr: input.openPr, draft: input.draft })).digest('hex');
|
|
633
673
|
const parentRunId = env.ELANOUS_RUN_ID?.trim();
|
|
674
|
+
// Standalone callers journal retries without altering the existing Pod manifest.
|
|
675
|
+
const ledgerRunId = parentRunId || `run-${executionKey.slice(0, 8)}-${executionKey.slice(8, 12)}-${executionKey.slice(12, 16)}-${executionKey.slice(16, 20)}-${executionKey.slice(20, 32)}`;
|
|
634
676
|
const address = `self-impl:${input.spaceId}`;
|
|
635
677
|
const ledgerDir = runLedgerDir(env.ELANOUS_STATE_DIR);
|
|
678
|
+
let recoveryError: string | undefined;
|
|
679
|
+
try {
|
|
680
|
+
const entries = loadRunLedger(ledgerRunId, ledgerDir) ?? [];
|
|
681
|
+
const intents = entries.filter((entry) => entry.event === 'pod-oom-retry-intent' && entry.data.job === name && entry.data.executionKey === executionKey && entry.data.attempt === 2);
|
|
682
|
+
const intent = intents.at(-1);
|
|
683
|
+
if (intent && !entries.slice(entries.indexOf(intent) + 1).some((entry) => entry.event === 'pod-oom-retry-finished' && entry.data.job === name && entry.data.executionKey === executionKey && entry.data.fromChildRunId === intent.data.fromChildRunId)) {
|
|
684
|
+
if (typeof intent.data.to !== 'string' || memoryGi(intent.data.to) === null) throw new Error('invalid OOM retry memory limit');
|
|
685
|
+
oomRetried = true;
|
|
686
|
+
memoryLimit = intent.data.to;
|
|
687
|
+
retryFromChildRunId = typeof intent.data.fromChildRunId === 'string' ? intent.data.fromChildRunId : undefined;
|
|
688
|
+
retryFromMemoryLimit = typeof intent.data.from === 'string' ? intent.data.from : undefined;
|
|
689
|
+
}
|
|
690
|
+
} catch (error) { recoveryError = `OOM 재시도 원장 판독 실패: ${error instanceof Error ? error.message : String(error)}`; }
|
|
636
691
|
const args = [
|
|
637
692
|
...(input.base ? ['--base', input.base] : []),
|
|
638
693
|
...(input.autoMerge ? ['--merge-by-host'] : []),
|
|
@@ -647,19 +702,45 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
|
|
|
647
702
|
];
|
|
648
703
|
debug.log('pod.self-implement', 'child-supervise', { hostSupervised, childSupervise: !hostSupervised });
|
|
649
704
|
const done = (async (): Promise<SelfImplementJobDone> => {
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
705
|
+
if (after !== undefined && (!options.pool || typeof options.pool.acquireAdmission !== 'function')) {
|
|
706
|
+
return { exitCode: 1, output: '', error: { code: 'pod-lease', message: 'Pod predecessor requires pool dependency admission' } };
|
|
707
|
+
}
|
|
708
|
+
if (recoveryError) return { exitCode: 1, output: '', error: { code: 'pod-oom-recovery', message: recoveryError } };
|
|
709
|
+
// Each Job attempt has its own host lease; releasing the first after OOM lets the retry
|
|
710
|
+
// compete with other processes for the newly measured capacity before applying another Job.
|
|
711
|
+
let releaseAdmission: ((() => void) & { applied?: () => void }) | undefined;
|
|
712
|
+
try {
|
|
713
|
+
// Every attempt, including an OOM retry, must acquire a pool slot before applying a Job.
|
|
714
|
+
const acquireSlot = async (): Promise<PodPoolMember | null> => {
|
|
715
|
+
if (!options.pool) return null;
|
|
653
716
|
for (;;) {
|
|
654
|
-
if (input.signal?.aborted) return
|
|
655
|
-
|
|
656
|
-
if (
|
|
717
|
+
if (input.signal?.aborted) return null;
|
|
718
|
+
const acquired = options.pool.tryAcquire();
|
|
719
|
+
if (acquired) {
|
|
720
|
+
debug.log('self-implement.pod', 'pool-slot', { spaceId: input.spaceId, context: acquired.context, inflight: options.pool.snapshot() });
|
|
721
|
+
return acquired;
|
|
722
|
+
}
|
|
657
723
|
await sleep(options.pollMs ?? 15_000);
|
|
658
724
|
}
|
|
659
|
-
|
|
660
|
-
|
|
725
|
+
};
|
|
726
|
+
const acquireAdmission = async (): Promise<boolean> => {
|
|
727
|
+
if (!options.pool || typeof options.pool.acquireAdmission !== 'function') return true;
|
|
728
|
+
try { releaseAdmission = await options.pool.acquireAdmission(input.signal, after); return true; }
|
|
729
|
+
catch (error) {
|
|
730
|
+
// A predecessor closed without merging is not a cancellation: surface it so the queue owner is notified.
|
|
731
|
+
if (error instanceof Error && error.message.startsWith('pod lease predecessor blocked')) admissionBlocked = error.message;
|
|
732
|
+
return false;
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
let admissionBlocked: string | undefined;
|
|
736
|
+
const admissionFailure = (): SelfImplementJobDone => admissionBlocked
|
|
737
|
+
? { exitCode: 1, output: '', error: { code: 'pod-predecessor-blocked', message: admissionBlocked } }
|
|
738
|
+
: { exitCode: null, output: '', error: { code: 'aborted', message: 'aborted before a pool slot opened' } };
|
|
739
|
+
if (!await acquireAdmission()) return admissionFailure();
|
|
740
|
+
let member: PodPoolMember | null = await acquireSlot();
|
|
741
|
+
if (options.pool && !member) return { exitCode: null, output: '', error: { code: 'aborted', message: 'aborted before a pool slot opened' } };
|
|
661
742
|
const currentContext = member ? null : baseKubectl(['config', 'current-context']);
|
|
662
|
-
|
|
743
|
+
let context = member?.context ?? (currentContext?.status === 0 ? currentContext.stdout.trim() : '');
|
|
663
744
|
const kubectl: Kubectl = (args, stdin) => baseKubectl(['--context', context, ...args], stdin);
|
|
664
745
|
let recorded = false;
|
|
665
746
|
let groundingMinted: string | null = null;
|
|
@@ -699,6 +780,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
|
|
|
699
780
|
return { status: ledgerIncomplete || artifactIncomplete ? 'incomplete' : 'ok', childLedgerIncomplete, samples: parseMemSamples(full.stdout) };
|
|
700
781
|
};
|
|
701
782
|
let retryAccount: string | undefined;
|
|
783
|
+
let retrySamples: ReturnType<typeof parseMemSamples> = [];
|
|
702
784
|
let failedAccount: string | undefined;
|
|
703
785
|
let usageLimitRetried = false;
|
|
704
786
|
for (;;) {
|
|
@@ -875,38 +957,85 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
|
|
|
875
957
|
// 🩸 종전엔 여기서 delete 부터 해서, 재개가 원격에서 멀쩡히 돌던 Job 을 죽였다. 실패로 끝난 Job 만 지우고 다시 만든다.
|
|
876
958
|
// ☸️ 노드 레지스트리에 이 판이 있으면 그것을 pull 한다(델타 · 대표 2026-09-26) — 라벨 판정은 로컬 이미지 이름으로 한다.
|
|
877
959
|
const jobImage = member?.imageRef ?? image;
|
|
878
|
-
const launchRunId = retryAccount ? mintRunId() : childRunId;
|
|
960
|
+
const launchRunId = retryAccount || oomRetried ? mintRunId() : childRunId;
|
|
879
961
|
let liveChildRunId = launchRunId;
|
|
962
|
+
let reattachedMemoryLimit: string | undefined;
|
|
963
|
+
let existingExecutionKey: string | undefined;
|
|
964
|
+
let existingAttempt = NaN;
|
|
880
965
|
const existing = kubectl(['-n', namespace, 'get', 'job', name, '-o', 'jsonpath={.metadata.uid} {.status.conditions[*].type}']);
|
|
881
966
|
const [existingUid = '', ...existingConditions] = existing.status === 0 ? existing.stdout.trim().split(/\s+/u) : [];
|
|
882
|
-
const
|
|
883
|
-
|
|
884
|
-
|
|
967
|
+
const hasExistingJob = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu.test(existingUid);
|
|
968
|
+
let reattach = hasExistingJob && !/Failed|FailureTarget/.test(existingConditions.join(' '));
|
|
969
|
+
const failedExisting = hasExistingJob && /Failed|FailureTarget/.test(existingConditions.join(' '));
|
|
970
|
+
if (hasExistingJob) {
|
|
885
971
|
const existingJob = kubectl(['-n', namespace, 'get', 'job', name, '-o', 'json']);
|
|
886
972
|
if (existingJob.status === 0) {
|
|
887
973
|
try {
|
|
888
|
-
const job = JSON.parse(existingJob.stdout) as { spec?: { template?: { spec?: { containers?: Array<{ name?: string; args?: string[]; env?: Array<{ name: string; value?: string }
|
|
974
|
+
const job = JSON.parse(existingJob.stdout) as { metadata?: { annotations?: Record<string, string> }; spec?: { template?: { spec?: { containers?: Array<{ name?: string; args?: string[]; env?: Array<{ name: string; value?: string }>; resources?: { limits?: { memory?: string } } }> } } } };
|
|
975
|
+
existingExecutionKey = job.metadata?.annotations?.[POD_EXECUTION_KEY_ANNOTATION];
|
|
976
|
+
existingAttempt = Number(job.metadata?.annotations?.[POD_ATTEMPT_ANNOTATION] ?? NaN);
|
|
889
977
|
const child = job.spec?.template?.spec?.containers?.find((c) => c.name === 'child');
|
|
978
|
+
reattachedMemoryLimit = child?.resources?.limits?.memory;
|
|
890
979
|
const inherited = child?.env?.find((e) => e.name === 'ELANOUS_RUN_ID')?.value;
|
|
891
980
|
if (inherited && inherited !== parentRunId && inherited === normalizeRunId(inherited)) liveChildRunId = inherited;
|
|
981
|
+
if (oomRetried && reattach && reattachedMemoryLimit && (memoryGi(reattachedMemoryLimit) ?? 0) < (memoryGi(memoryLimit) ?? Infinity)) reattach = false;
|
|
892
982
|
// A resumed App Job has an unknown remaining lifetime; refresh its gh config on the first live poll.
|
|
893
983
|
ghTokenExpiresAt = child?.args?.[0]?.includes('gh auth login --with-token < /creds/gh-token') ? now() : null;
|
|
894
984
|
} catch { /* The existing Job's identity must be verified before following it. */ }
|
|
895
985
|
}
|
|
896
|
-
|
|
986
|
+
// POD9 must-fix: an OOM-retry resume follows only this execution's attempt-2 Job — a high Job another goal made
|
|
987
|
+
// under the same space name must not be read as this goal's retry result.
|
|
988
|
+
// Same execution's attempt 1 (the lower-memory OOM Job) still goes through the existing replace path below.
|
|
989
|
+
if (oomRetried && (existingExecutionKey !== executionKey || (existingAttempt !== 1 && existingAttempt !== 2))) {
|
|
990
|
+
debug.log('self-implement.pod', 'oom-retry-job-mismatch', { job: name, expectedAttempt: 2, attempt: Number.isNaN(existingAttempt) ? null : existingAttempt, sameExecution: existingExecutionKey === executionKey });
|
|
991
|
+
return { exitCode: 1, output: '', error: { code: 'pod-oom-retry-mismatch', message: `Job ${name} 은 이 골의 OOM 재시도(attempt 2)가 아니다 — 따라가지 않는다` } };
|
|
992
|
+
}
|
|
993
|
+
if (!reattach && !failedExisting) liveChildRunId = launchRunId;
|
|
994
|
+
if (reattach && liveChildRunId === launchRunId && !failedExisting) {
|
|
897
995
|
debug.log('self-implement.pod', 'job-reattach-id-unavailable', { job: name });
|
|
898
996
|
return { exitCode: 1, output: '', error: { code: 'pod-child-run-id', message: `Job ${name} child runId를 확인할 수 없다` } };
|
|
899
997
|
}
|
|
900
998
|
}
|
|
901
|
-
if (
|
|
999
|
+
if (failedExisting) {
|
|
1000
|
+
const pods = kubectl(['-n', namespace, 'get', 'pods', '-l', `job-name=${name}`, '-o', 'jsonpath={range .items[*]}{.metadata.creationTimestamp}{"\\t"}{range .status.containerStatuses[?(@.name=="child")]}{.state.terminated.reason}{"\\t"}{.state.terminated.exitCode}{end}{"\\n"}{end}']);
|
|
1001
|
+
const failedOom = pods.status === 0 && pods.stdout.split('\n').some((line) => { const fields = line.split('\t'); return fields[1] === 'OOMKilled' && fields[2]?.trim() === '137'; });
|
|
1002
|
+
// Once attempt 2 exists, consume its terminal result even if it failed for a non-OOM reason.
|
|
1003
|
+
// Only the old, lower-memory attempt may be removed to make room for high.
|
|
1004
|
+
if (failedOom || oomRetried) reattach = !oomRetried || (memoryGi(reattachedMemoryLimit ?? '') ?? 0) >= (memoryGi(memoryLimit) ?? Infinity);
|
|
1005
|
+
if ((failedOom || reattach) && (memoryGi(reattachedMemoryLimit ?? '') === null || liveChildRunId === launchRunId)) {
|
|
1006
|
+
return { exitCode: 1, output: '', error: { code: 'pod-memory-unavailable', message: `Job ${name} 실제 메모리 한도 또는 child runId를 확인할 수 없다` } };
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
if (reattach) {
|
|
1010
|
+
if (reattachedMemoryLimit) memoryLimit = reattachedMemoryLimit;
|
|
1011
|
+
debug.log('self-implement.pod', 'job-reattach', { job: name, conditions: existingConditions.join(' ') || 'running', spaceId: input.spaceId });
|
|
1012
|
+
}
|
|
902
1013
|
if (!hostRefresh && ghTokenExpiresAt === null && !githubRelay) debug.log('self-implement.pod', 'gh-token-app-skipped', { job: name, reason: 'no-verified-app-or-refresh-path' });
|
|
903
1014
|
if (!reattach) {
|
|
904
|
-
if (
|
|
1015
|
+
if (oomRetried && hasExistingJob && !failedExisting && memoryGi(reattachedMemoryLimit ?? '') === null) {
|
|
1016
|
+
return { exitCode: 1, output: '', error: { code: 'pod-memory-unavailable', message: `Job ${name} 실제 메모리 한도를 확인할 수 없다` } };
|
|
1017
|
+
}
|
|
1018
|
+
if (oomRetried && !retryAccount) {
|
|
1019
|
+
const high = podMemoryLimitFor(input.feature, { ...env, ELANOUS_POD_MEMORY_TIER: 'high' }).limit;
|
|
1020
|
+
if ((memoryGi(memoryLimit) ?? 0) < (memoryGi(high) ?? Infinity)) throw new Error(`pod: OOM 재시도 한도가 high 와 다름: ${memoryLimit}`);
|
|
1021
|
+
const leaseMembers = member ? [member] : [{ context, capacity: 1, k3dCluster: '' }];
|
|
1022
|
+
const lease = recommendConcurrency(measurePoolLease(leaseMembers, { kubectl: (args) => baseKubectl(args) }), {
|
|
1023
|
+
capacity: leaseMembers.reduce((sum, item) => sum + item.capacity, 0), perGoalMemory: high, accounts: 0, perAccount: 0,
|
|
1024
|
+
});
|
|
1025
|
+
if (lease.recommended === null || lease.placeableSlots === null || lease.placeableSlots < 1 || lease.memorySlots === null || lease.memorySlots < 1) {
|
|
1026
|
+
return { exitCode: 1, output: '', error: { code: 'pod-lease', message: `OOM 재시도 high 자리 판정 실패: ${lease.reason ?? lease.limitedBy ?? 'no capacity'}\n${formatLastMemSample(retrySamples.at(-1))}` } };
|
|
1027
|
+
}
|
|
1028
|
+
debug.log('self-implement.pod', 'oom-retry-lease', { job: name, context, memoryLimit: high, recommended: lease.recommended });
|
|
1029
|
+
}
|
|
1030
|
+
if (failedExisting && !reattach && !oomRetried && collectFullLogs('failed-job-logs-unavailable').status === 'incomplete') {
|
|
905
1031
|
return { exitCode: 1, output: '', error: { code: 'pod-collection-incomplete', message: `Job ${name} recovery incomplete — old Job retained` } };
|
|
906
1032
|
}
|
|
1033
|
+
if (hasExistingJob) {
|
|
1034
|
+
const removed = kubectl(['-n', namespace, 'delete', 'job', name, '--ignore-not-found', '--wait=true']);
|
|
1035
|
+
if (removed.status !== 0) return { exitCode: 1, output: removed.stderr, error: { code: 'pod-delete', message: removed.stderr.trim() } };
|
|
1036
|
+
}
|
|
907
1037
|
const s = kubectl(['apply', '-f', '-'], JSON.stringify(secret));
|
|
908
1038
|
if (s.status !== 0) return { exitCode: 1, output: s.stderr, error: { code: 'pod-secret', message: s.stderr.trim() } };
|
|
909
|
-
kubectl(['-n', namespace, 'delete', 'job', name, '--ignore-not-found']);
|
|
910
1039
|
const jobPassEnv = [
|
|
911
1040
|
...passEnv,
|
|
912
1041
|
...(grounding ? [GROUNDING_TOKEN_ENV] : []),
|
|
@@ -927,7 +1056,7 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
|
|
|
927
1056
|
...(githubRelay ? { [POD_GITHUB_CREDENTIAL_URL_ENV]: `${new URL(groundingUrl!).origin}${POD_CREDENTIAL_GITHUB_PATH}` } : {}),
|
|
928
1057
|
}
|
|
929
1058
|
: undefined;
|
|
930
|
-
const job = podJobManifest({ name, namespace, image: jobImage, ...(member?.imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}), repoUrl, ...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), args, passEnv: jobPassEnv, deadlineSeconds: options.deadlineSeconds ?? POD_JOB_DEADLINE_SECONDS, ...(goalDoc ? { goalDoc } : {}), runId: launchRunId, ...(parentRunId ? { parentRunId } : {}), ...(jobArmEnv ? { armEnv: jobArmEnv } : {}), hostId: resolveHostId(env), skillEnvs: Object.keys(skillEnvs), memoryLimit, imageCommit: options.imageCommit !== undefined ? options.imageCommit : options.kubectl ? null : podImageFreshness({ image }).imageCommit, ...(grok ? { grokCredential: 'grokAuth' in creds && creds.grokAuth ? 'subscription' as const : 'api_key' as const } : {}), ...(codexAccounts ? { codexAccounts } : {}), ...(hostRefresh ? { appCredential: true } : {}) }); // kubectl 주입(=시험)이면 docker 를 부르지 않는다
|
|
1059
|
+
const job = podJobManifest({ name, namespace, image: jobImage, ...(member?.imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}), repoUrl, ...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), args, passEnv: jobPassEnv, deadlineSeconds: options.deadlineSeconds ?? POD_JOB_DEADLINE_SECONDS, ...(goalDoc ? { goalDoc } : {}), runId: launchRunId, ...(parentRunId ? { parentRunId } : {}), ...(jobArmEnv ? { armEnv: jobArmEnv } : {}), hostId: resolveHostId(env), skillEnvs: Object.keys(skillEnvs), memoryLimit, imageCommit: options.imageCommit !== undefined ? options.imageCommit : options.kubectl ? null : podImageFreshness({ image }).imageCommit, ...(grok ? { grokCredential: 'grokAuth' in creds && creds.grokAuth ? 'subscription' as const : 'api_key' as const } : {}), ...(codexAccounts ? { codexAccounts } : {}), ...(hostRefresh ? { appCredential: true } : {}), execution: { key: executionKey, attempt: oomRetried ? 2 : 1 }, hostLeaseAdmitted: !!releaseAdmission }); // kubectl 주입(=시험)이면 docker 를 부르지 않는다
|
|
931
1060
|
const a = kubectl(['apply', '-f', '-'], JSON.stringify(job));
|
|
932
1061
|
if (a.status !== 0) { cleanupSecret(); return { exitCode: 1, output: a.stderr, error: { code: 'pod-apply', message: a.stderr.trim() } }; }
|
|
933
1062
|
if (options.source?.kind === 'bundle') {
|
|
@@ -958,12 +1087,18 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
|
|
|
958
1087
|
if (owned.status !== 0) debug.log('self-implement.pod', 'secret-owner-failed', { job: name, stderr: owned.stderr.trim() }, { level: 'warn' });
|
|
959
1088
|
}
|
|
960
1089
|
}
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1090
|
+
try {
|
|
1091
|
+
appendRunLedgerEntry({ runId: ledgerRunId, event: 'pod-child-run', data: { childRunId: liveChildRunId, job: name, attempt: oomRetried ? 2 : 1, ...(goalFile ? { goalFile } : {}) } }, ledgerDir);
|
|
1092
|
+
if (oomRetried && retryFromChildRunId) appendRunLedgerEntry({ runId: ledgerRunId, event: 'pod-oom-retry', data: { attempt: 2, from: retryFromMemoryLimit ?? selectedMemoryLimit, to: memoryLimit, job: name, childRunId: liveChildRunId, fromChildRunId: retryFromChildRunId } }, ledgerDir);
|
|
1093
|
+
} catch (error) {
|
|
1094
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
1095
|
+
debug.log('self-implement.pod', 'parent-ledger-unavailable', { job: name, reason, attempt: oomRetried ? 2 : 1 });
|
|
1096
|
+
// POD9 must-fix: attempt 2 without its ledger record must not end as a success — the ledger would show a retry-less pass.
|
|
1097
|
+
if (oomRetried) return { exitCode: 1, output: '', error: { code: 'pod-oom-retry-ledger', message: `OOM 재시도 원장 기록 실패: ${reason}` } };
|
|
964
1098
|
}
|
|
965
1099
|
writePodFragment({ spaceId: input.spaceId, context, namespace, job: name, inboxDir: POD_CONTROL_INBOX_DIR, ...(liveChildRunId === normalizeRunId(liveChildRunId) ? { runId: liveChildRunId } : {}), ...(parentRunId && normalizeRunId(parentRunId) === parentRunId ? { parentRunId } : {}) }, env);
|
|
966
1100
|
recorded = true;
|
|
1101
|
+
releaseAdmission?.applied?.();
|
|
967
1102
|
debug.log('self-implement.pod', 'job-applied', { job: name, namespace, ...(member ? { context: member.context } : {}), image: jobImage, spaceId: input.spaceId, passEnv, extraArgs: options.extraArgs ?? [], ...(options.armEnv?.ELANOUS_ARM_ID ? { armId: options.armEnv.ELANOUS_ARM_ID } : {}) });
|
|
968
1103
|
let state: 'complete' | 'failed' | 'aborted' = 'failed';
|
|
969
1104
|
let failedReason = '';
|
|
@@ -1034,7 +1169,8 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
|
|
|
1034
1169
|
if ((event === 'ledger-collected' || event === 'ledger-collect-already-complete') && data.runId === liveChildRunId) ledgerCollected = true;
|
|
1035
1170
|
}, liveChildRunId);
|
|
1036
1171
|
const samples = collection.status === 'unavailable' ? parseMemSamples(logs) : collection.samples;
|
|
1037
|
-
|
|
1172
|
+
const oomKilled = state === 'failed' && containerReason === 'OOMKilled' && containerExitCode === 137;
|
|
1173
|
+
if (oomKilled) {
|
|
1038
1174
|
// 자식 stdout 원문은 싣지 않는다 — 임의 출력에 든 비밀이 진단 경로로 새지 않도록 «모양»(줄·바이트)만 남긴다.
|
|
1039
1175
|
const childLines = logs ? logs.replace(/\n$/, '').split('\n').filter((line) => !line.startsWith('ELANOUS_MEM ')) : [];
|
|
1040
1176
|
const logShape = logs ? { lines: childLines.length, bytes: Buffer.byteLength(childLines.join('\n')) } : null;
|
|
@@ -1092,7 +1228,49 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
|
|
|
1092
1228
|
try { (options.ghComment ?? defaultGhComment)(prNumber, `호스트 재게이트 실패(${process.platform}): ${failedStep} — ${detail}`); }
|
|
1093
1229
|
catch (error) { debug.log('harness.host-regate', 'unmeasured', { pr: prNumber, files: [], os: process.platform, failedStep: 'comment', detail: error instanceof Error ? error.message : String(error) }); }
|
|
1094
1230
|
}
|
|
1095
|
-
|
|
1231
|
+
const releaseHold = regate.failures[0]?.step === 'release-path-hold';
|
|
1232
|
+
disposition = { ...disposition, stage: regate.passed ? 'merged' : releaseHold ? 'pr-opened' : 'host-regate-failed', merged: regate.passed, hostRegate: regate, ok: regate.passed || releaseHold };
|
|
1233
|
+
}
|
|
1234
|
+
const childFailure = state === 'failed' && !oomKilled && failedReason !== 'DeadlineExceeded'
|
|
1235
|
+
? lastPodChildFailure(logs) : null;
|
|
1236
|
+
if (childFailure) debug.log('self-implement.pod', 'child-error', { job: name, stage: childFailure.stage, error: childFailure.error }, { compact: { stringMax: 500 } });
|
|
1237
|
+
debug.log('self-implement.pod', 'job-finished', { job: name, ...(member ? { context: member.context } : {}), state, containerReason, stage: disposition?.stage ?? null, prUrl: disposition?.prUrl ?? null, childRunId: liveChildRunId, ledgerCompleteness,
|
|
1238
|
+
...(state === 'failed' && !oomKilled && failedReason !== 'DeadlineExceeded'
|
|
1239
|
+
? { ...(childFailure ? { childStage: childFailure.stage } : {}), childError: childFailure?.error ?? 'no-result-line' } : {}) },
|
|
1240
|
+
state === 'failed' && !oomKilled && failedReason !== 'DeadlineExceeded' ? { compact: { stringMax: 500 } } : undefined);
|
|
1241
|
+
if (oomKilled && reattach && !oomRetried && (!reattachedMemoryLimit || memoryGi(reattachedMemoryLimit) === null)) {
|
|
1242
|
+
return { exitCode: 1, output: '', error: { code: 'pod-memory-unavailable', message: `Job ${name} 실제 메모리 한도를 확인할 수 없다` } };
|
|
1243
|
+
}
|
|
1244
|
+
if (oomKilled && failedReason !== 'DeadlineExceeded' && !input.signal?.aborted && !oomRetried) {
|
|
1245
|
+
const high = podMemoryLimitFor(input.feature, { ...env, ELANOUS_POD_MEMORY_TIER: 'high' }).limit;
|
|
1246
|
+
const actual = memoryGi(reattachedMemoryLimit ?? memoryLimit);
|
|
1247
|
+
if (actual === null) {
|
|
1248
|
+
return { exitCode: 1, output: '', error: { code: 'pod-memory-unavailable', message: `Job ${name} 실제 메모리 한도를 판정할 수 없다: ${memoryLimit}` } };
|
|
1249
|
+
}
|
|
1250
|
+
if (actual < (memoryGi(high) ?? actual)) {
|
|
1251
|
+
const from = reattachedMemoryLimit ?? memoryLimit;
|
|
1252
|
+
appendRunLedgerEntry({ runId: ledgerRunId, event: 'pod-oom-retry-intent', data: { attempt: 2, from, to: high, job: name, executionKey, fromChildRunId: liveChildRunId } }, ledgerDir);
|
|
1253
|
+
debug.log('self-implement.pod', 'oom-retry', { from, to: high, job: name });
|
|
1254
|
+
const deleted = kubectl(['-n', namespace, 'delete', 'job', name, '--ignore-not-found', '--wait=true']);
|
|
1255
|
+
if (deleted.status !== 0) throw new Error(`pod: OOM Job 삭제 실패: ${deleted.stderr.trim()}`);
|
|
1256
|
+
oomRetried = true;
|
|
1257
|
+
retryFromChildRunId = liveChildRunId;
|
|
1258
|
+
retryFromMemoryLimit = from;
|
|
1259
|
+
retrySamples = samples;
|
|
1260
|
+
memoryLimit = high;
|
|
1261
|
+
if (member) { options.pool!.release(member); member = null; }
|
|
1262
|
+
releaseAdmission?.();
|
|
1263
|
+
releaseAdmission = undefined;
|
|
1264
|
+
if (!await acquireAdmission()) return admissionFailure();
|
|
1265
|
+
member = await acquireSlot();
|
|
1266
|
+
if (options.pool && !member) return { exitCode: null, output: '', error: { code: 'aborted', message: 'aborted before a pool slot opened' } };
|
|
1267
|
+
if (member) context = member.context;
|
|
1268
|
+
if (input.signal?.aborted) return { exitCode: null, output: '', error: { code: 'aborted', message: 'aborted before OOM retry' } };
|
|
1269
|
+
continue;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
if (oomRetried && retryFromChildRunId) {
|
|
1273
|
+
appendRunLedgerEntry({ runId: ledgerRunId, event: 'pod-oom-retry-finished', data: { job: name, executionKey, fromChildRunId: retryFromChildRunId, childRunId: liveChildRunId, state } }, ledgerDir);
|
|
1096
1274
|
}
|
|
1097
1275
|
if (goalFile) {
|
|
1098
1276
|
const record: GoalExecutionRecord = {
|
|
@@ -1106,13 +1284,6 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
|
|
|
1106
1284
|
try { const { appendGoalExecutionRecord } = await import('../../self-implement/orchestrator.js'); appendGoalExecutionRecord(goalFile, record); }
|
|
1107
1285
|
catch (error) { debug.log('self-implement.pod', 'goal-record-unavailable', { job: name, childRunId: liveChildRunId, reason: error instanceof Error ? error.message : String(error) }); }
|
|
1108
1286
|
}
|
|
1109
|
-
const childFailure = state === 'failed' && containerReason !== 'OOMKilled' && failedReason !== 'DeadlineExceeded'
|
|
1110
|
-
? lastPodChildFailure(logs) : null;
|
|
1111
|
-
if (childFailure) debug.log('self-implement.pod', 'child-error', { job: name, stage: childFailure.stage, error: childFailure.error }, { compact: { stringMax: 500 } });
|
|
1112
|
-
debug.log('self-implement.pod', 'job-finished', { job: name, ...(member ? { context: member.context } : {}), state, containerReason, stage: disposition?.stage ?? null, prUrl: disposition?.prUrl ?? null, childRunId: liveChildRunId, ledgerCompleteness,
|
|
1113
|
-
...(state === 'failed' && containerReason !== 'OOMKilled' && failedReason !== 'DeadlineExceeded'
|
|
1114
|
-
? { ...(childFailure ? { childStage: childFailure.stage } : {}), childError: childFailure?.error ?? 'no-result-line' } : {}) },
|
|
1115
|
-
state === 'failed' && containerReason !== 'OOMKilled' && failedReason !== 'DeadlineExceeded' ? { compact: { stringMax: 500 } } : undefined);
|
|
1116
1287
|
const tail = podRunResultLine(logs, salvage);
|
|
1117
1288
|
if (state === 'aborted') return { exitCode: null, output: tail, error: { code: 'aborted', message: 'aborted — Job deleted' }, ...(disposition ? { disposition } : {}) };
|
|
1118
1289
|
const deadlineExceeded = state === 'failed' && failedReason === 'DeadlineExceeded';
|
|
@@ -1135,8 +1306,8 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
|
|
|
1135
1306
|
...(deadlineExceeded
|
|
1136
1307
|
? { error: { code: 'pod-deadline-exceeded', message: `Job ${name} 이 수명 상한 ${deadlineSeconds}초에 닿았다` } }
|
|
1137
1308
|
: state === 'failed'
|
|
1138
|
-
?
|
|
1139
|
-
? { error: { code: 'pod-oom-killed', message: `Job ${name} failed (OOMKilled/${containerExitCode ?? 'unknown'}, memoryLimit=${memoryLimit})\n${formatLastMemSample(samples.at(-1))}` } }
|
|
1309
|
+
? oomKilled
|
|
1310
|
+
? { error: { code: 'pod-oom-killed', message: `Job ${name} failed (OOMKilled/${containerExitCode ?? 'unknown'}, memoryLimit=${memoryLimit})${oomRetried || (memoryGi(reattachedMemoryLimit ?? memoryLimit) ?? 0) >= (memoryGi(podMemoryLimitFor(input.feature, { ...env, ELANOUS_POD_MEMORY_TIER: 'high' }).limit) ?? Infinity) ? ' — OOM · high 에서도' : ''}\n${formatLastMemSample(samples.at(-1))}` } }
|
|
1140
1311
|
: { error: { code: 'pod-job-failed', message: `Job ${name} failed${failedReason || containerReason ? ` (${[failedReason, containerReason ? `container=${containerReason}/${containerExitCode ?? 'unknown'}` : ''].filter(Boolean).join(', ')})` : ''}${childFailure ? ` — childStage=${childFailure.stage} · childError=${childFailure.error}` : ' — childError=no-result-line'}` } }
|
|
1141
1312
|
: {}),
|
|
1142
1313
|
...(finishedDisposition ? { disposition: finishedDisposition } : {}),
|
|
@@ -1153,6 +1324,9 @@ export function podSelfImplementSpawn(options: PodSpawnOptions = {}): SelfImplem
|
|
|
1153
1324
|
if (groundingMinted) { try { (options.revokeGrounding ?? revokeGroundingRun)(groundingMinted); } catch (e) { debug.log('self-implement.pod', 'grounding-revoke-failed', { job: name, reason: e instanceof Error ? e.message : String(e) }, { level: 'warn' }); } }
|
|
1154
1325
|
if (member) options.pool!.release(member);
|
|
1155
1326
|
}
|
|
1327
|
+
} finally {
|
|
1328
|
+
releaseAdmission?.();
|
|
1329
|
+
}
|
|
1156
1330
|
})();
|
|
1157
1331
|
return { address, done };
|
|
1158
1332
|
};
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
*
|
|
19
19
|
* Cf. PLAN-parallel-self-dev-orchestrator-2026-07-21.
|
|
20
20
|
*/
|
|
21
|
-
import { lstatSync } from 'node:fs';
|
|
21
|
+
import { lstatSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
22
|
+
import { selfDevRunsDir } from '../../self-dev/run-store.js';
|
|
22
23
|
import { debug } from '../../debug/log.js';
|
|
23
24
|
import { join, resolve } from 'node:path';
|
|
24
25
|
import { findGitDir } from '../../git-fs/locate.js';
|
|
@@ -94,6 +95,8 @@ export interface SelfImplementDisposition {
|
|
|
94
95
|
export interface SelfImplementJobSpawn {
|
|
95
96
|
(input: {
|
|
96
97
|
feature: string;
|
|
98
|
+
/** Predecessor goal ID or PR number; Pod admission waits until it is merged. */
|
|
99
|
+
after?: string | number;
|
|
97
100
|
base?: string;
|
|
98
101
|
autoMerge?: boolean;
|
|
99
102
|
/** G8 — attach `auto-review` opt-in label → `--auto-review`. */
|
|
@@ -196,6 +199,7 @@ export function createSelfImplementAdapter(opts: SelfImplementAdapterOptions) {
|
|
|
196
199
|
try {
|
|
197
200
|
const res = opts.spawn({
|
|
198
201
|
feature: surface.feature,
|
|
202
|
+
...(surface.after !== undefined ? { after: surface.after } : {}),
|
|
199
203
|
...(surface.base !== undefined ? { base: surface.base } : {}),
|
|
200
204
|
...(surface.autoMerge !== undefined ? { autoMerge: surface.autoMerge } : {}),
|
|
201
205
|
...(surface.autoReview !== undefined ? { autoReview: surface.autoReview } : {}),
|
|
@@ -316,7 +320,13 @@ export function defaultSelfImplementSpawn(): SelfImplementJobSpawn {
|
|
|
316
320
|
const { bin, source: binSource } = resolveSpawnElanousBin();
|
|
317
321
|
// `--json` so the child prints its SelfImplementResult on the last
|
|
318
322
|
// line → we parse the real disposition (stage / prUrl / merged).
|
|
319
|
-
const
|
|
323
|
+
const runsDir = selfDevRunsDir();
|
|
324
|
+
mkdirSync(runsDir, { recursive: true });
|
|
325
|
+
const featureDir = mkdtempSync(join(runsDir, 'feature-'));
|
|
326
|
+
const featureFile = join(featureDir, 'feature.txt');
|
|
327
|
+
try { writeFileSync(featureFile, input.feature, { mode: 0o600 }); }
|
|
328
|
+
catch (error) { rmSync(featureDir, { recursive: true, force: true }); throw error; }
|
|
329
|
+
const args = [bin, 'self', 'implement', '--feature-file', featureFile, '--json'];
|
|
320
330
|
if (input.base) args.push('--base', input.base);
|
|
321
331
|
if (input.autoMerge) args.push('--auto-merge');
|
|
322
332
|
if (input.autoReview) args.push('--auto-review');
|
|
@@ -348,6 +358,7 @@ export function defaultSelfImplementSpawn(): SelfImplementJobSpawn {
|
|
|
348
358
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
349
359
|
});
|
|
350
360
|
} catch (err) {
|
|
361
|
+
rmSync(featureDir, { recursive: true, force: true });
|
|
351
362
|
resolve({
|
|
352
363
|
exitCode: null,
|
|
353
364
|
output: '',
|
|
@@ -364,10 +375,12 @@ export function defaultSelfImplementSpawn(): SelfImplementJobSpawn {
|
|
|
364
375
|
child.stdout?.on('data', (d: Buffer) => { out += d.toString(); });
|
|
365
376
|
child.stderr?.on('data', (d: Buffer) => { out += d.toString(); });
|
|
366
377
|
child.on('error', (e: Error) => {
|
|
378
|
+
rmSync(featureDir, { recursive: true, force: true });
|
|
367
379
|
input.signal?.removeEventListener('abort', onAbort);
|
|
368
380
|
resolve({ exitCode: null, output: out, error: { code: 'SELF_IMPL_SPAWN_FAILED', message: String(e?.message ?? e) } });
|
|
369
381
|
});
|
|
370
382
|
child.on('exit', (code: number | null) => {
|
|
383
|
+
rmSync(featureDir, { recursive: true, force: true });
|
|
371
384
|
input.signal?.removeEventListener('abort', onAbort);
|
|
372
385
|
const disposition = parseSelfImplementJson(out);
|
|
373
386
|
resolve({ exitCode: code, output: out, ...(disposition ? { disposition } : {}) });
|
|
@@ -268,6 +268,8 @@ export type TaskSurface =
|
|
|
268
268
|
kind: 'self-implement';
|
|
269
269
|
/** Feature/goal text passed to `elanous self implement <feature>`. */
|
|
270
270
|
feature: string;
|
|
271
|
+
/** Pod queue predecessor goal ID or PR number. */
|
|
272
|
+
after?: string | number;
|
|
271
273
|
/** Optional base ref (branch/tag) — maps to `--base`. */
|
|
272
274
|
base?: string;
|
|
273
275
|
/** Auto-merge on review-clean — maps to `--auto-merge`. */
|