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
package/src/hooks/providers.ts
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
2
2
|
|
|
3
|
-
export type HookProvider = 'linear' | 'asana';
|
|
3
|
+
export type HookProvider = 'linear' | 'asana' | 'github';
|
|
4
|
+
export const PUBLIC_GITHUB_REPO = 'ElanvitalAI/elanous';
|
|
5
|
+
/** Links to documentation and reproductions are not spam signals. */
|
|
6
|
+
export function isGithubSpamText(value: string): boolean {
|
|
7
|
+
return /\b(?:casino|crypto giveaway|free money|seo backlinks|airdrop)\b/i.test(value);
|
|
8
|
+
}
|
|
4
9
|
export interface ExternalTask {
|
|
5
10
|
eventId: string;
|
|
6
11
|
title: string;
|
|
7
12
|
description?: string;
|
|
8
13
|
external: { provider: HookProvider; ref: string; url?: string };
|
|
14
|
+
/** Linear issue assignee ID, resolved by the configured seat mapping; events.routes takes precedence. */
|
|
15
|
+
assigneeId?: string;
|
|
16
|
+
/** L14: an opened PR/issue on the public repository — shadow intake only, never dispatched to seats. */
|
|
17
|
+
github?: { repository: string; number: number; type: 'pull_request' | 'issue'; spamSignal?: boolean };
|
|
9
18
|
}
|
|
10
19
|
export type Verification = { ok: true; body: unknown; eventIds: string[]; ignored?: string } | { ok: false; reason: 'bad-signature' | 'stale' | 'invalid-body' };
|
|
11
20
|
|
|
@@ -29,7 +38,9 @@ export function asanaEventId(event: unknown): string | undefined {
|
|
|
29
38
|
}
|
|
30
39
|
|
|
31
40
|
export function verifyWebhook(provider: HookProvider, raw: Buffer, headers: Headers, secret: string, now = Date.now()): Verification {
|
|
32
|
-
|
|
41
|
+
const signature = headers.get(provider === 'linear' ? 'linear-signature' : provider === 'github' ? 'x-hub-signature-256' : 'x-hook-signature');
|
|
42
|
+
const digest = provider === 'github' ? (signature?.startsWith('sha256=') ? signature.slice(7) : null) : signature;
|
|
43
|
+
if (!equalSignature(raw, secret, digest))
|
|
33
44
|
return { ok: false, reason: 'bad-signature' };
|
|
34
45
|
let parsed: unknown;
|
|
35
46
|
try { parsed = JSON.parse(raw.toString('utf8')); } catch { return { ok: false, reason: 'invalid-body' }; }
|
|
@@ -39,15 +50,45 @@ export function verifyWebhook(provider: HookProvider, raw: Buffer, headers: Head
|
|
|
39
50
|
const timestamp = body.webhookTimestamp;
|
|
40
51
|
if (typeof timestamp !== 'number' || !Number.isFinite(timestamp) || Math.abs(now - timestamp) > 60_000)
|
|
41
52
|
return { ok: false, reason: 'stale' };
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
53
|
+
// Acknowledge signed, out-of-scope events so Linear does not disable the webhook.
|
|
54
|
+
const previous = object(body.updatedFrom);
|
|
55
|
+
const relevantUpdate = body.action === 'update' && previous &&
|
|
56
|
+
('assigneeId' in previous || 'stateId' in previous);
|
|
57
|
+
if (body.type !== 'Issue' || (body.action !== 'create' && !relevantUpdate))
|
|
45
58
|
return { ok: true, body, eventIds: [], ignored: `${String(body.type)}:${String(body.action)}` };
|
|
46
59
|
const eventId = text(headers.get('linear-delivery')) ?? (text(body.webhookId) && text(body.createdAt) ? `${body.webhookId}:${body.createdAt}` : undefined);
|
|
47
60
|
if (!eventId || !object(body.data) || !text(object(body.data)?.id) || !text(object(body.data)?.title))
|
|
48
61
|
return { ok: false, reason: 'invalid-body' };
|
|
49
62
|
return { ok: true, body, eventIds: [eventId] };
|
|
50
63
|
}
|
|
64
|
+
if (provider === 'github' && object(body.repository)?.full_name === PUBLIC_GITHUB_REPO) {
|
|
65
|
+
// L14: the public repository's newly opened PRs/issues go to the shadow intake (no seat dispatch, no outside writes).
|
|
66
|
+
const kind = headers.get('x-github-event');
|
|
67
|
+
if (!['pull_request', 'issues'].includes(kind ?? '') || body.action !== 'opened')
|
|
68
|
+
return { ok: true, body, eventIds: [], ignored: `${kind ?? 'unknown'}:${String(body.action)}` };
|
|
69
|
+
const item = object(body[kind === 'pull_request' ? 'pull_request' : 'issue']);
|
|
70
|
+
const delivery = headers.get('x-github-delivery');
|
|
71
|
+
if (!delivery || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(delivery) || !Number.isSafeInteger(body.number) ||
|
|
72
|
+
(body.number as number) < 1 || !item || item.number !== body.number || !text(item.title) ||
|
|
73
|
+
!text(item.html_url) || !text(object(item.user)?.login) ||
|
|
74
|
+
item.html_url !== `https://github.com/${PUBLIC_GITHUB_REPO}/${kind === 'pull_request' ? 'pull' : 'issues'}/${body.number}`)
|
|
75
|
+
return { ok: false, reason: 'invalid-body' };
|
|
76
|
+
return { ok: true, body: { ...body, githubEvent: kind, publicIntake: true }, eventIds: [delivery] };
|
|
77
|
+
}
|
|
78
|
+
if (provider === 'github') {
|
|
79
|
+
const event = headers.get('x-github-event');
|
|
80
|
+
const action = text(body.action);
|
|
81
|
+
if (!((event === 'pull_request' && action === 'review_requested') ||
|
|
82
|
+
(event === 'check_run' && action === 'completed' && object(body.check_run)?.conclusion === 'failure') ||
|
|
83
|
+
(event === 'check_suite' && action === 'completed' && object(body.check_suite)?.conclusion === 'failure')))
|
|
84
|
+
return { ok: true, body, eventIds: [], ignored: `${String(event)}:${String(action)}` };
|
|
85
|
+
const delivery = text(headers.get('x-github-delivery'));
|
|
86
|
+
const resource = object(event === 'pull_request' ? body.pull_request : event === 'check_run' ? body.check_run : body.check_suite);
|
|
87
|
+
if (!delivery || !resource || typeof resource.id !== 'number' ||
|
|
88
|
+
!(text(resource.html_url) ?? text(resource.details_url) ?? text(object(body.repository)?.html_url)))
|
|
89
|
+
return { ok: false, reason: 'invalid-body' };
|
|
90
|
+
return { ok: true, body: { ...body, githubEvent: event }, eventIds: [delivery] };
|
|
91
|
+
}
|
|
51
92
|
if (!Array.isArray(body.events)) return { ok: false, reason: 'invalid-body' };
|
|
52
93
|
const ids = body.events.map(asanaEventId);
|
|
53
94
|
if (ids.some(id => !id)) return { ok: false, reason: 'invalid-body' };
|
|
@@ -63,9 +104,34 @@ export function toExternalTask(provider: HookProvider, body: unknown): ExternalT
|
|
|
63
104
|
const title = text(issue?.title);
|
|
64
105
|
const eventId = text(row.eventId) ?? (text(row.webhookId) && text(row.createdAt) ? `${row.webhookId}:${row.createdAt}` : undefined);
|
|
65
106
|
if (!ref || !title || !eventId) throw new Error('invalid linear issue');
|
|
107
|
+
const assigneeId = text(issue?.assigneeId) ?? text(object(issue?.assignee)?.id);
|
|
66
108
|
return { eventId, title, ...(text(issue?.description) ? { description: text(issue?.description) } : {}),
|
|
109
|
+
...(assigneeId ? { assigneeId } : {}),
|
|
67
110
|
external: { provider, ref, ...(text(issue?.url) ? { url: text(issue?.url) } : {}) } };
|
|
68
111
|
}
|
|
112
|
+
if (provider === 'github' && row.publicIntake === true) {
|
|
113
|
+
const type = row.githubEvent === 'pull_request' ? 'pull_request' : 'issue';
|
|
114
|
+
const item = object(type === 'pull_request' ? row.pull_request : row.issue);
|
|
115
|
+
const number = row.number;
|
|
116
|
+
const eventId = text(row.eventId);
|
|
117
|
+
if (!Number.isSafeInteger(number) || !item || !eventId || !text(item.title) || !text(item.html_url))
|
|
118
|
+
throw new Error('invalid github event');
|
|
119
|
+
return { eventId, title: item.title as string,
|
|
120
|
+
external: { provider, ref: `${PUBLIC_GITHUB_REPO}#${number}`, url: item.html_url as string },
|
|
121
|
+
github: { repository: PUBLIC_GITHUB_REPO, number: number as number, type,
|
|
122
|
+
spamSignal: typeof item.body === 'string' && isGithubSpamText(item.body) } };
|
|
123
|
+
}
|
|
124
|
+
if (provider === 'github') {
|
|
125
|
+
const event = text(row.githubEvent);
|
|
126
|
+
const resource = object(event === 'pull_request' ? row.pull_request : event === 'check_run' ? row.check_run : row.check_suite);
|
|
127
|
+
const ref = resource?.id;
|
|
128
|
+
const eventId = text(row.eventId);
|
|
129
|
+
const url = text(resource?.html_url) ?? text(resource?.details_url) ?? text(object(row.repository)?.html_url);
|
|
130
|
+
if (typeof ref !== 'number' || !eventId || !url) throw new Error('invalid github event');
|
|
131
|
+
const title = event === 'pull_request' ? `PR review requested: ${text(resource?.title) ?? url}`
|
|
132
|
+
: `Check failed: ${text(resource?.name) ?? text(resource?.head_branch) ?? url}`;
|
|
133
|
+
return { eventId, title, external: { provider, ref: String(ref), url } };
|
|
134
|
+
}
|
|
69
135
|
const event = object(row.event);
|
|
70
136
|
const task = object(row.task);
|
|
71
137
|
const ref = text(object(event?.resource)?.gid);
|
package/src/hooks/queue.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { dirname, join } from 'node:path';
|
|
|
4
4
|
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
5
5
|
import type { ExternalTask } from './providers.js';
|
|
6
6
|
|
|
7
|
-
export interface QueuedHook { provider: ExternalTask['external']['provider']; eventId: string; task: ExternalTask }
|
|
7
|
+
export interface QueuedHook { provider: ExternalTask['external']['provider']; eventId: string; kind?: string; task: ExternalTask }
|
|
8
8
|
|
|
9
9
|
export class HookQueue {
|
|
10
10
|
readonly directory: string;
|
package/src/hooks/receiver.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { debug } from '../debug/log.js';
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
|
-
import { userConfigPath } from '../user-config.js';
|
|
3
|
+
import { getUserConfig, parseEventsConfig, userConfigPath, type EventsConfig } from '../user-config.js';
|
|
4
|
+
import { dispatchHook, type HookWake } from './dispatch.js';
|
|
4
5
|
import { getSecretAsync } from '../nexus/config/secrets/index.js';
|
|
5
6
|
import { HookQueue, type QueuedHook } from './queue.js';
|
|
7
|
+
import { recordGithubShadow } from './github-shadow.js';
|
|
6
8
|
import { toExternalTask, verifyWebhook, type HookProvider } from './providers.js';
|
|
7
9
|
import { drainReports, handleReportPost, ReportLimiter, ReportQueue, type ReceivedReport } from './error-report.js';
|
|
8
10
|
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
@@ -10,6 +12,7 @@ import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
|
10
12
|
export interface HookSecrets {
|
|
11
13
|
linear?: string;
|
|
12
14
|
asana?: string;
|
|
15
|
+
github?: string;
|
|
13
16
|
saveAsana?: (secret: string) => Promise<void>;
|
|
14
17
|
}
|
|
15
18
|
export interface HookReceiverOptions {
|
|
@@ -20,8 +23,12 @@ export interface HookReceiverOptions {
|
|
|
20
23
|
now?: () => number;
|
|
21
24
|
root?: string;
|
|
22
25
|
retryBaseMs?: number;
|
|
26
|
+
events?: EventsConfig;
|
|
27
|
+
wakeSeat?: HookWake;
|
|
23
28
|
/** ER2 — forward one queued error report to the Primary; default = POST /v1/reports/ingest over the tailnet. */
|
|
24
29
|
forwardReport?: (item: ReceivedReport) => Promise<boolean>;
|
|
30
|
+
/** GET-only public metadata lookup; failure forces human review. */
|
|
31
|
+
githubFetch?: typeof fetch;
|
|
25
32
|
}
|
|
26
33
|
|
|
27
34
|
/** `/v1/tasks` lives on the Primary's nexus API, not on the control plane — so the address is its own setting. */
|
|
@@ -33,19 +40,6 @@ export function hooksPrimaryUrl(config: { hooks?: { primaryUrl?: unknown } }): U
|
|
|
33
40
|
return url;
|
|
34
41
|
}
|
|
35
42
|
|
|
36
|
-
async function forwardToPrimary(event: QueuedHook): Promise<Response> {
|
|
37
|
-
const config = JSON.parse(readFileSync(userConfigPath(), 'utf8')) as { hooks?: { primaryTokenRef?: string; primaryUrl?: unknown } };
|
|
38
|
-
const ref = config.hooks?.primaryTokenRef;
|
|
39
|
-
if (!ref) throw new Error('primary token reference missing');
|
|
40
|
-
const token = await getSecretAsync(ref);
|
|
41
|
-
if (!token) throw new Error('primary token missing');
|
|
42
|
-
return fetch(new URL('/v1/tasks', hooksPrimaryUrl(config)), {
|
|
43
|
-
method: 'POST', headers: { 'content-type': 'application/json', authorization: `Bearer ${token}`,
|
|
44
|
-
'x-elanous-trace-id': `${event.provider}:${event.eventId}` },
|
|
45
|
-
body: JSON.stringify({ ...event.task, eventId: `${event.provider}:${event.eventId}` }), signal: AbortSignal.timeout(10_000),
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
43
|
async function forwardReportToPrimary(item: ReceivedReport): Promise<boolean> {
|
|
50
44
|
const config = JSON.parse(readFileSync(userConfigPath(), 'utf8')) as { hooks?: { primaryTokenRef?: string; primaryUrl?: unknown } };
|
|
51
45
|
const ref = config.hooks?.primaryTokenRef;
|
|
@@ -81,7 +75,12 @@ export function startHookReceiver(options: HookReceiverOptions): { url: string;
|
|
|
81
75
|
} finally { reportsDraining = false; }
|
|
82
76
|
}
|
|
83
77
|
const now = options.now ?? Date.now;
|
|
84
|
-
const
|
|
78
|
+
const events = options.events ?? getUserConfig().events ?? parseEventsConfig(undefined);
|
|
79
|
+
// L14: public-repository intake events take the shadow ledger path; every other event keeps the seat dispatch path.
|
|
80
|
+
const dispatch = options.forward ?? ((event: QueuedHook) => dispatchHook(event, options.root ?? effectiveInstanceRoot(), events, options.wakeSeat).then(() => 204));
|
|
81
|
+
const forward = (event: QueuedHook) => event.provider === 'github' && event.task.github
|
|
82
|
+
? recordGithubShadow(event, options.root ?? effectiveInstanceRoot(), options.githubFetch).then(() => 204)
|
|
83
|
+
: dispatch(event);
|
|
85
84
|
const attempts = new Map<string, { next: number; failures: number }>();
|
|
86
85
|
const pending = new Set<string>();
|
|
87
86
|
let stopped = false;
|
|
@@ -124,7 +123,7 @@ export function startHookReceiver(options: HookReceiverOptions): { url: string;
|
|
|
124
123
|
if (request.method === 'POST' && url.pathname === '/v1/reports')
|
|
125
124
|
return handleReportPost(request, { limiter: reportLimiter, queue: reportQueue, ...(options.now ? { now: options.now } : {}),
|
|
126
125
|
log: (event, data) => debug.log('hooks.reports', event, data), wake: () => { reportNextAt = 0; void drainReportQueue(); } });
|
|
127
|
-
if (request.method !== 'POST' || !/^\/hooks\/(linear|asana)$/.test(url.pathname)) return new Response('Not Found', { status: 404 });
|
|
126
|
+
if (request.method !== 'POST' || !/^\/hooks\/(linear|asana|github)$/.test(url.pathname)) return new Response('Not Found', { status: 404 });
|
|
128
127
|
const provider = url.pathname.slice('/hooks/'.length) as HookProvider;
|
|
129
128
|
const reject = (reason: string) => {
|
|
130
129
|
debug.log('hooks.receiver', 'rejected', { provider, reason });
|
|
@@ -150,13 +149,15 @@ export function startHookReceiver(options: HookReceiverOptions): { url: string;
|
|
|
150
149
|
debug.log('hooks.receiver', 'ignored', { provider, kind: verified.ignored });
|
|
151
150
|
return new Response(null, { status: 200 });
|
|
152
151
|
}
|
|
153
|
-
if (provider === 'linear') {
|
|
152
|
+
if (provider === 'linear' || provider === 'github') {
|
|
154
153
|
const eventId = verified.eventIds[0]!;
|
|
155
|
-
|
|
154
|
+
const body = verified.body as { type?: string; action: string; githubEvent?: string };
|
|
155
|
+
const kind = provider === 'linear' ? `${body.type}:${body.action}` : `${body.githubEvent}:${body.action}`;
|
|
156
|
+
queue.enqueue({ provider, eventId, kind, task: toExternalTask(provider, { ...body, eventId }) });
|
|
156
157
|
} else {
|
|
157
158
|
const body = verified.body as { events: unknown[] };
|
|
158
|
-
const tasks = body.events.map(event => toExternalTask(provider, { event, task: (event as { task?: unknown }).task }));
|
|
159
|
-
for (const task of tasks) queue.enqueue({ provider, eventId: task.eventId, task });
|
|
159
|
+
const tasks = body.events.map(event => ({ event: event as { action?: string }, task: toExternalTask(provider, { event, task: (event as { task?: unknown }).task }) }));
|
|
160
|
+
for (const { event, task } of tasks) queue.enqueue({ provider, eventId: task.eventId, kind: `task:${event.action ?? 'unknown'}`, task });
|
|
160
161
|
}
|
|
161
162
|
if (!draining) {
|
|
162
163
|
if (timer) clearTimeout(timer);
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { LOGS_SINCE_OPTION, registerLogsCommands } from './cli/logs-cli.js';
|
|
|
9
9
|
import { registerDocsCommands } from './cli/docs-cli.js';
|
|
10
10
|
import { registerA2ACommands } from './cli/a2a-cli.js';
|
|
11
11
|
import { registerPluginCommands } from './cli/plugin-cli.js';
|
|
12
|
+
import { registerMakeCommand } from './cli/make-cli.js';
|
|
12
13
|
import { registerConnectCommand, registerSkillsCommands } from './cli/skills-cli.js';
|
|
13
14
|
import { registerImportCommand } from './cli/import-cli.js';
|
|
14
15
|
import { registerPersonaCommands } from './cli/persona-cli.js';
|
|
@@ -873,8 +874,10 @@ seatCmd.command('loop').requiredOption('--seat <SEAT>', 'MK|OP|TC|UX')
|
|
|
873
874
|
.option('--json', 'JSON 출력')
|
|
874
875
|
.action(async (opts: { seat: string; once: boolean; json?: boolean }) => {
|
|
875
876
|
try {
|
|
876
|
-
|
|
877
|
-
|
|
877
|
+
// V3 F5: without the sink, the seat loop's judgment lines (seat.loop) never reach the log store when cron runs it.
|
|
878
|
+
await (await import('./domains/standalone-log-sink.js')).registerStandaloneLogSink('seat-loop');
|
|
879
|
+
const { runSeatLoopTurn } = await import('./seat-loop/seat-loop.js');
|
|
880
|
+
const result = await runSeatLoopTurn(opts.seat);
|
|
878
881
|
if (opts.json) await writeStdoutJson(`${JSON.stringify(result)}\n`);
|
|
879
882
|
else console.log(`seat loop ${opts.seat}: ${result.status}${'runId' in result && result.runId ? ` ${result.runId}` : ''}`);
|
|
880
883
|
} catch (error) { console.error(`seat loop: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
|
|
@@ -913,6 +916,7 @@ registerCardCommand(program);
|
|
|
913
916
|
registerLaunchHeadCommands(program);
|
|
914
917
|
registerA2ACommands(program);
|
|
915
918
|
registerPluginCommands(program);
|
|
919
|
+
registerMakeCommand(program);
|
|
916
920
|
registerSkillsCommands(program);
|
|
917
921
|
registerConnectCommand(program);
|
|
918
922
|
registerImportCommand(program);
|
|
@@ -3024,6 +3028,24 @@ const harnessOrchestrateCmd = registerHarnessOrchestrateCapabilityOptions(
|
|
|
3024
3028
|
await runHarnessOrchestrateExecution(plan, parts);
|
|
3025
3029
|
});
|
|
3026
3030
|
|
|
3031
|
+
const contextCmd = program.command('context').description('외부 에이전트 맥락 이벤트');
|
|
3032
|
+
contextCmd.command('hooks').description('Claude Code 맥락 훅 설정').command('install')
|
|
3033
|
+
.requiredOption('--print', '설정 조각만 출력하고 설정 파일은 수정하지 않음')
|
|
3034
|
+
.action(async () => {
|
|
3035
|
+
const { claudeHooksSettings } = await import('./context-bus/claude-hooks-install.js');
|
|
3036
|
+
console.log(claudeHooksSettings(REPOSITORY_ROOT));
|
|
3037
|
+
});
|
|
3038
|
+
contextCmd.command('emit')
|
|
3039
|
+
.requiredOption('--kind <kind>', 'claimed|done|asked|guide-changed')
|
|
3040
|
+
.requiredOption('--summary <line>', '한 줄 요약')
|
|
3041
|
+
.requiredOption('--source <link>', '출처 링크')
|
|
3042
|
+
.action(async (opts: { kind: string; summary: string; source: string }) => {
|
|
3043
|
+
if (!['claimed', 'done', 'asked', 'guide-changed'].includes(opts.kind)) throw new Error('context emit --kind must be claimed|done|asked|guide-changed');
|
|
3044
|
+
const { recordExternalEvent } = await import('./context-bus/external-events.js');
|
|
3045
|
+
recordExternalEvent({ origin: 'claude-code', kind: opts.kind as import('./context-bus/external-events.js').ContextHookKind,
|
|
3046
|
+
summary: opts.summary, source: opts.source });
|
|
3047
|
+
});
|
|
3048
|
+
|
|
3027
3049
|
const coordCmd = program.command('coord').description('조율 채널 맥락 원장');
|
|
3028
3050
|
coordCmd.command('event').command('record')
|
|
3029
3051
|
.requiredOption('--seat <ID>', '발신 자리')
|
|
@@ -3975,11 +3997,12 @@ selfCmd
|
|
|
3975
3997
|
.option('--changed', '변경 파일 범위 게이트임을 명시한다')
|
|
3976
3998
|
.option('--base <ref>', '커밋됐지만 PR 없는 변경의 비교 기준(ref...HEAD)')
|
|
3977
3999
|
.option('--pr <number>', '열린 PR 번호에서 gh pr view files로 변경 파일을 읽는다')
|
|
3978
|
-
.
|
|
3979
|
-
|
|
4000
|
+
.option('--shards [number]', '메모리 예산에 맞춰 시험을 별도 프로세스로 분할한다 (기본 2)')
|
|
4001
|
+
.action((opts: { changed?: boolean; base?: string; pr?: string; shards?: string | boolean }) => {
|
|
4002
|
+
if (!opts.changed && opts.shards === undefined) { ui.error('self gate requires --changed or --shards'); process.exitCode = 2; return; }
|
|
3980
4003
|
try {
|
|
3981
4004
|
const { runSelfGateCli } = require('./self-implement/gate-cli.js') as typeof import('./self-implement/gate-cli.js');
|
|
3982
|
-
const result = runSelfGateCli(process.cwd(), { base: opts.base, pr: opts.pr });
|
|
4005
|
+
const result = runSelfGateCli(process.cwd(), { base: opts.base, pr: opts.pr, shards: opts.shards === undefined ? undefined : opts.shards === true ? 2 : Number(opts.shards) });
|
|
3983
4006
|
console.log(result.lines.join('\n'));
|
|
3984
4007
|
process.exitCode = result.exitCode;
|
|
3985
4008
|
} catch (error) {
|
|
@@ -4011,7 +4034,8 @@ selfCmd
|
|
|
4011
4034
|
// runSelfImplement(내부 SelfImplement 툴과 동일 코어)를 감싼다: fork→worktree→헤드리스 goal-loop
|
|
4012
4035
|
// (+클린빌드 앵커)→gate(bun test)→PR(HITL). PR-open 은 --open-pr(명시 승인)일 때만·기본 fail-closed.
|
|
4013
4036
|
selfCmd
|
|
4014
|
-
.command('implement
|
|
4037
|
+
.command('implement [feature...]')
|
|
4038
|
+
.option('--feature-file <path>', 'feature 문면을 파일에서 읽는다 (문면을 argv 에 싣지 않음)')
|
|
4015
4039
|
.description('자율 구현(self-build) — feature 를 격리 worktree 에서 goal-loop + 클린빌드 앵커로 끝까지 구현하고 gate(bun test) 통과까지. --config-dir 의 provider 로 모델 선택(gemma 등). PR-open 은 --open-pr(HITL 명시승인)일 때만. 수분 소요.')
|
|
4016
4040
|
.option('--base <branch>', 'PR base 브랜치(생략 시 provider 기본)')
|
|
4017
4041
|
.option('--no-draft', 'non-draft PR (기본 draft)')
|
|
@@ -4029,8 +4053,11 @@ selfCmd
|
|
|
4029
4053
|
.option('--no-supervise', '⛔ 런 슈퍼바이저를 «끈다»(대표 2026-08-22: ***기본 ON***) — 켜져 있으면 실행이 끝나면 실패를 «트리아지»해서 다시 걸 수 있으면 스스로 재개한다(끝까지). 정지 사유는 converged|needs-human|max-rounds|no-progress 로 각각 «다른 값». 관측=elanous logs --category self-dev.supervisor')
|
|
4030
4054
|
.option('--supervise-rounds <n>', '슈퍼바이저 재개 라운드 상한 (기본 3 · 끄려면 --no-supervise)')
|
|
4031
4055
|
.option('--json', '구조화 출력 {stage, ok, branch, worktree, prUrl?, merged?}')
|
|
4032
|
-
.action(async (parts: string[], opts: { base?: string; draft?: boolean; openPr?: boolean; autoMerge?: boolean; autoReview?: boolean; maxWait?: string; json?: boolean; plan?: boolean; enhance?: boolean; ground?: boolean; observeOnly?: boolean }) => {
|
|
4033
|
-
|
|
4056
|
+
.action(async (parts: string[], opts: { featureFile?: string; base?: string; draft?: boolean; openPr?: boolean; autoMerge?: boolean; autoReview?: boolean; maxWait?: string; json?: boolean; plan?: boolean; enhance?: boolean; ground?: boolean; observeOnly?: boolean }) => {
|
|
4057
|
+
if (opts.featureFile && parts.length > 0) { ui.error('--feature-file 과 위치 인자 feature 는 함께 줄 수 없다'); process.exit(2); }
|
|
4058
|
+
let feature: string;
|
|
4059
|
+
try { feature = (opts.featureFile ? readFileSync(opts.featureFile, 'utf8') : parts.join(' ')).trim(); }
|
|
4060
|
+
catch (error) { ui.error(`--feature-file 읽기 실패: ${String(error)}`); process.exit(2); return; }
|
|
4034
4061
|
if (!feature) { ui.error('feature 필요: elanous self implement "<무엇을 구현할지>"'); process.exit(2); }
|
|
4035
4062
|
// Retired entry points must fail before run identity or log-sink setup creates observable execution state.
|
|
4036
4063
|
if (opts.plan) { ui.error('self implement --plan is retired and rejected'); process.exit(1); return; }
|
|
@@ -4128,8 +4155,14 @@ export function setSelfOrchestrateSpawnForTesting(spawn: typeof selfOrchestrateS
|
|
|
4128
4155
|
selfOrchestrateSpawnForTesting = spawn;
|
|
4129
4156
|
}
|
|
4130
4157
|
|
|
4158
|
+
export function readSelfOrchestrateGoals(parts: string[], goalFiles: readonly string[] = []): { request: string; goals: string[] } {
|
|
4159
|
+
const fileGoals = goalFiles.map((path) => readFileSync(path, 'utf8'));
|
|
4160
|
+
return { request: [...parts, ...fileGoals].join(' '), goals: [...splitOrchestrateGoalTexts(parts), ...fileGoals] };
|
|
4161
|
+
}
|
|
4162
|
+
|
|
4131
4163
|
const selfOrchestrateCmd = selfCmd
|
|
4132
4164
|
.command('orchestrate [goals...]')
|
|
4165
|
+
.option('--goal-file <path>', '골 문면을 파일에서 읽는다 (반복 가능)', (value: string, acc: string[]) => [...acc, value], [] as string[])
|
|
4133
4166
|
.description('병렬 self-dev — 여러 goal 을 각자 격리 worktree self-implement 서브프로세스로 동시성캡 병렬 실행. goal 은 `;;` 로 구분(또는 각 인자 1 goal). --concurrency 로 동시 잡 수(기본 2).')
|
|
4134
4167
|
.option('--concurrency <n>', '동시 실행 잡 수 (기본 2)')
|
|
4135
4168
|
.option('--auto-merge', '각 잡: 리뷰 clean 시 자동 병합(각 self-implement 에 --auto-merge 전달·리뷰노드 경유)')
|
|
@@ -4138,7 +4171,7 @@ const selfOrchestrateCmd = selfCmd
|
|
|
4138
4171
|
.option('--base <branch>', '각 잡 PR base 브랜치')
|
|
4139
4172
|
.option('--decompose', 'S2 — goal 1개를 LLM 으로 의존성 서브-DAG(위상 병렬 + hot-file 직렬)로 분해 후 실행')
|
|
4140
4173
|
.addOption(new Option('--pod-skill-env', 'pod: 필수 스킬(설정 pod-skills.txt)의 키(.env)를 이 런의 Secret 으로 넘긴다 — 명시 opt-in(유료 크레딧) · 이미지엔 안 들어간다').hideHelp())
|
|
4141
|
-
.addOption(new Option('--pod-pool <spec>', 'pod 풀 — 컨텍스트[@ssh호스트][:상한]
|
|
4174
|
+
.addOption(new Option('--pod-pool <spec>', 'pod 풀 — 컨텍스트[@ssh호스트][:상한][#k3d-레지스트리:포트] 쉼표, 앞이 우선(예 pool-node-b@node-b:12#k3d-elanous-registry:5051,pool-node-c@node-c:3#k3d-elanous-registry:5052) · 없으면 ELANOUS_POD_POOL · 그것도 없으면 현재 컨텍스트 하나').hideHelp())
|
|
4142
4175
|
.addOption(new Option('--reduce', '끝에 PR 을 연 조각들을 통합 브랜치 하나로 모아(게이트 한 번) PR 하나 — `--open-pr` 과 짝 · `--auto-merge` 와는 함께 못 쓴다(elanous self reduce)').hideHelp())
|
|
4143
4176
|
.option('--substrate <kind>', '실행 칸: local(기본 · 격리 워크트리) | pod(k8s Job · docker/harness 이미지 · MANUAL-pods-for-elanous-ops-and-dev)')
|
|
4144
4177
|
.option('--pod-account <name>', 'pod: codex 계정(~/.elanous/auth.json openai-codex:<name> · refresh 제외 사본) · 없으면 브로커가 Job 마다 잔량 많은 계정을 돌려 준다')
|
|
@@ -4146,11 +4179,14 @@ const selfOrchestrateCmd = selfCmd
|
|
|
4146
4179
|
.option('--pod-pass-env <keys>', 'pod: 호스트 env 에서 Pod 로 넘길 키(쉼표) — 예 OPENROUTER_API_KEY,ANTHROPIC_API_KEY(벤치마크 과금 경로)')
|
|
4147
4180
|
.option('--bench-arms <spec>', 'pod 벤치마크: 골 1개를 팔마다 «라벨 한 줄만 다르게» 복제해 동시에 — "id=provider[:model][@KEY+KEY];…" (예 codex=openai-codex;or-kimi=openrouter:openrouter/moonshotai/kimi-k3@OPENROUTER_API_KEY) · --auto-merge 거부 · RFC fleet 슈퍼바이저 §A3')
|
|
4148
4181
|
.option('--help-all', '모든 orchestrate 옵션 표시')
|
|
4149
|
-
.action(function (this: Command, parts: string[], opts: { concurrency?: string; autoMerge?: boolean; autoReview?: boolean; openPr?: boolean; base?: string; teardown?: boolean; resume?: string; board?: boolean; decompose?: boolean; fabricDecompose?: boolean; maxTasks?: string; supervise?: boolean; superviseRounds?: string; json?: boolean }) {
|
|
4182
|
+
.action(function (this: Command, parts: string[], opts: { goalFile?: string[]; concurrency?: string; autoMerge?: boolean; autoReview?: boolean; openPr?: boolean; base?: string; teardown?: boolean; resume?: string; board?: boolean; decompose?: boolean; fabricDecompose?: boolean; maxTasks?: string; supervise?: boolean; superviseRounds?: string; json?: boolean }) {
|
|
4150
4183
|
return (async () => {
|
|
4151
|
-
//
|
|
4152
|
-
|
|
4153
|
-
|
|
4184
|
+
// 위치 인자는 종전처럼 분리하고 파일 입력은 파일당 한 골이다.
|
|
4185
|
+
let inputGoals: ReturnType<typeof readSelfOrchestrateGoals>;
|
|
4186
|
+
try { inputGoals = readSelfOrchestrateGoals(parts, opts.goalFile); }
|
|
4187
|
+
catch (error) { ui.error(`--goal-file 읽기 실패: ${String(error)}`); process.exit(2); return; }
|
|
4188
|
+
const joined = inputGoals.request;
|
|
4189
|
+
let goalTexts = inputGoals.goals;
|
|
4154
4190
|
if ((opts as { reduce?: boolean }).reduce && opts.autoMerge) { ui.error('--reduce 는 --auto-merge 와 함께 못 쓴다 — 조각을 하나씩 main 에 병합하는 것과 하나로 모으는 것은 반대다(--open-pr 과 짝)'); process.exit(2); }
|
|
4155
4191
|
// ☸️ 벤치 팔 — 골 1개를 팔마다 라벨 한 줄만 다르게(A/B 매뉴얼 ②) · pod 전용 · 자동 머지 금지(한 팔이 머지되면 다른 팔의 밑 땅이 바뀐다).
|
|
4156
4192
|
const benchSpec = (opts as { benchArms?: string }).benchArms;
|
|
@@ -6298,7 +6334,7 @@ const selfDevCmd = program
|
|
|
6298
6334
|
// `drive --help` 에도 그대로 보이고 자식이 그것을 계약으로 읽는다.
|
|
6299
6335
|
// ⇒ 별칭을 없애지 않는다([[RFC-two-command-convergence-dev-and-pty-2026-07-28]] §6-2 = 층이 다르니
|
|
6300
6336
|
// `drive` 는 프리미티브로 **유지**한다) — 대신 **도움말이 그 갈림을 먼저 말하게** 한다.
|
|
6301
|
-
.description('⛔ `drive` 별칭으로 부르면 옵션은
|
|
6337
|
+
.description('⛔ `drive` 별칭으로 부르면 옵션은 아홉뿐 (--goal · --attach · --max-steps · --poll-ms · --model · --cwd · --worktree · --json · --jail-home) — `--attach <ref>` 는 이미 있는 PTY 를 몬다(생략하면 셸 명령을 새로 띄운다). 나머지는 전부 `dev` 전용이고 `drive` 에서는 거부된다. dev 와 drive 는 한 명령이라 이 도움말을 공유하므로, 아래 목록은 `dev` 기준이다. ⚠️ 실험 — 통합 self-dev 파이프라인 runDevPipeline. --backend self(디폴트·elanous-chat 자체구현)|codex/claude/gemini/grok(외부). --transport pty(디폴트·worktree·--branch 필수)|acp(cwd 세션·U6·capability 미검증). 미배선 조합은 NotYetUnified 명시 거부. ★self 는 무인 완결이 기본(PR 개설→auto-review 라벨→리뷰 clean 시 병합) — 끄려면 --no-open-pr/--no-auto-review/--no-auto-merge. 관측=elanous logs --category dev-pipeline · 상세=docs/manual/MANUAL-frontdoor-selfdev-dogfood-mechanism-2026-07-25.md')
|
|
6302
6338
|
.option('--file <path>', 'input 파일(verbatim 바이트·<text...> 대신)')
|
|
6303
6339
|
// ⭐ 대표 2026-08-11 — 발사 절차 «넷»을 한 명령으로. ask 파일을 주면 ⑴저작 → ⑵열린 PR ⊕ ⑶도는 런 검사 → ⑷발사.
|
|
6304
6340
|
// ⛔ 걸리면 «이름을 대며» 멈춘다(조용히 진행하지 않는다). 우회는 --force-preflight 이고 그 사실이 관측에 남는다.
|
|
@@ -6324,6 +6360,7 @@ const selfDevCmd = program
|
|
|
6324
6360
|
.option('-n, --max-steps <n>', 'elanous 또는 셸 drive: 최대 제어 스텝(기본 30)')
|
|
6325
6361
|
.option('-p, --poll-ms <ms>', 'elanous 또는 셸 drive: 제어 스텝 간 폴 간격(ms·0 허용·기본 800)')
|
|
6326
6362
|
.option('--attach <ref>', 'drive: 이미 있는 PTY 를 몬다(생략하면 셸 명령을 새로 띄운다·pty auto 와 같은 루프)')
|
|
6363
|
+
.option('--jail-home <dir>', 'drive: DRIVE-JAIL — 두뇌 입력에 이 디렉터리 밖 경로가 있으면 PTY 로 보내지 않는다')
|
|
6327
6364
|
.option('-m, --model <id>', 'elanous 또는 셸 drive: 제어 brain LLM 모델(기본 config)')
|
|
6328
6365
|
.option('--observe-only', 'elanous: child boot부터 SelfImplement 호출을 기록만 한다')
|
|
6329
6366
|
.option('--isolated-root <path>', 'elanous: child config/state 격리 루트(설정 실패 시 fail-closed)')
|
|
@@ -6620,6 +6657,7 @@ const selfDevCmd = program
|
|
|
6620
6657
|
...(devOpts.worktree === true ? { worktree: true } : {}),
|
|
6621
6658
|
...(opts.json === true ? { json: true } : {}),
|
|
6622
6659
|
attach: devOpts.attach,
|
|
6660
|
+
...(devOpts.jailHome ? { jailHome: devOpts.jailHome } : {}),
|
|
6623
6661
|
}, {
|
|
6624
6662
|
exit: ((code: number): never => {
|
|
6625
6663
|
completionGuard.conclude();
|
|
@@ -25,6 +25,7 @@ import type {
|
|
|
25
25
|
} from './enrich.js';
|
|
26
26
|
import { summariseContext } from './enrich.js';
|
|
27
27
|
import { buildResponseFormatHeader } from './prompt-format.js';
|
|
28
|
+
import { judge } from '../llm/judge-layer.js';
|
|
28
29
|
|
|
29
30
|
// ──────────────────── Closed sets ──────────────────────────────────────
|
|
30
31
|
|
|
@@ -69,7 +70,7 @@ export interface CategorizeResult {
|
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
export interface CategorizeCallable {
|
|
72
|
-
(args: { prompt: string; signal?: AbortSignal }): Promise<{
|
|
73
|
+
(args: { prompt: string; signal?: AbortSignal; provider?: string; model?: string }): Promise<{
|
|
73
74
|
text: string;
|
|
74
75
|
promptTokens?: number;
|
|
75
76
|
completionTokens?: number;
|
|
@@ -219,26 +220,6 @@ export function buildCategorizePrompt(decomposition: EnrichedDecomposition): str
|
|
|
219
220
|
|
|
220
221
|
// ──────────────────── Parse + coerce ──────────────────────────────────
|
|
221
222
|
|
|
222
|
-
function extractJsonBlock(text: string): unknown | null {
|
|
223
|
-
const trimmed = text.trim();
|
|
224
|
-
const fence = trimmed.match(/```(?:json)?\n([\s\S]*?)```/);
|
|
225
|
-
const candidate = fence ? fence[1]! : trimmed;
|
|
226
|
-
try {
|
|
227
|
-
return JSON.parse(candidate);
|
|
228
|
-
} catch {
|
|
229
|
-
const open = candidate.indexOf('{');
|
|
230
|
-
const close = candidate.lastIndexOf('}');
|
|
231
|
-
if (open >= 0 && close > open) {
|
|
232
|
-
try {
|
|
233
|
-
return JSON.parse(candidate.slice(open, close + 1));
|
|
234
|
-
} catch {
|
|
235
|
-
return null;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
return null;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
223
|
function coerceConfidence(v: unknown): 'high' | 'medium' | 'low' {
|
|
243
224
|
if (v === 'high' || v === 'medium' || v === 'low') return v;
|
|
244
225
|
return 'medium';
|
|
@@ -306,27 +287,18 @@ export async function categorizeDecomposition(
|
|
|
306
287
|
|
|
307
288
|
const prompt = buildCategorizePrompt(decomposition);
|
|
308
289
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
'LLM_CALL_FAILED',
|
|
316
|
-
err instanceof Error ? err.message : String(err),
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
return {
|
|
320
|
-
categorizations: Object.fromEntries(tasks.map((t) => [t.key, fallbackRow(t.key)])),
|
|
321
|
-
fallback: true,
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
const parsed = extractJsonBlock(raw.text);
|
|
326
|
-
const coerced = parsed ? coerceCategorizations(parsed, validKeys) : null;
|
|
327
|
-
if (coerced === null) {
|
|
290
|
+
const decision = await judge({
|
|
291
|
+
site: 'intake.categorize', prompt, signal: opts.signal,
|
|
292
|
+
call: ({ prompt, signal, provider, model }) => opts.callable({ prompt, signal, provider, model }),
|
|
293
|
+
schema: (parsed) => coerceCategorizations(parsed, validKeys),
|
|
294
|
+
});
|
|
295
|
+
if (!decision.ok) {
|
|
328
296
|
if (opts.strict) {
|
|
329
|
-
|
|
297
|
+
if (decision.reason === 'call') {
|
|
298
|
+
throw new CategorizeError('LLM_CALL_FAILED',
|
|
299
|
+
decision.error instanceof Error ? decision.error.message : String(decision.error));
|
|
300
|
+
}
|
|
301
|
+
throw new CategorizeError('PARSE_FAILED', 'no usable categorizations', decision.rawText);
|
|
330
302
|
}
|
|
331
303
|
return {
|
|
332
304
|
categorizations: Object.fromEntries(tasks.map((t) => [t.key, fallbackRow(t.key)])),
|
|
@@ -336,7 +308,7 @@ export async function categorizeDecomposition(
|
|
|
336
308
|
|
|
337
309
|
// Backfill any missing tasks with the fallback shape so callers can
|
|
338
310
|
// index by key without null checks.
|
|
339
|
-
const filled: Record<string, TaskCategorization> = { ...
|
|
311
|
+
const filled: Record<string, TaskCategorization> = { ...decision.value };
|
|
340
312
|
for (const t of tasks) {
|
|
341
313
|
if (!filled[t.key]) filled[t.key] = fallbackRow(t.key);
|
|
342
314
|
}
|
|
@@ -344,10 +316,10 @@ export async function categorizeDecomposition(
|
|
|
344
316
|
categorizations: filled,
|
|
345
317
|
fallback: false,
|
|
346
318
|
usage: {
|
|
347
|
-
promptTokens:
|
|
348
|
-
completionTokens:
|
|
349
|
-
costUsd:
|
|
350
|
-
modelId:
|
|
319
|
+
promptTokens: decision.reply.promptTokens,
|
|
320
|
+
completionTokens: decision.reply.completionTokens,
|
|
321
|
+
costUsd: decision.reply.costUsd,
|
|
322
|
+
modelId: decision.reply.modelId,
|
|
351
323
|
},
|
|
352
324
|
};
|
|
353
325
|
}
|
|
@@ -3,6 +3,7 @@ import { discordDecisionOwner } from '../decisions/discord-decision-cards.js';
|
|
|
3
3
|
import { canonicalSeatId } from '../msg/msg-store.js';
|
|
4
4
|
import { dispatchCeoTask, type CeoCommandDeps } from '../seat-dispatch/ceo-commands.js';
|
|
5
5
|
import { ceoTaskDeps, classifyCeoIntent } from '../seat-dispatch/ceo-intent.js';
|
|
6
|
+
import { askSeat, parseSeatAsk, type SeatAskDeps } from '../seat-dispatch/seat-ask.js';
|
|
6
7
|
import { parseSeatAddress, resolveSeat } from '../seat-address/seat-address.js';
|
|
7
8
|
import { getUserConfig, type UserConfig } from '../user-config.js';
|
|
8
9
|
import { answerAsSeat } from './seat-answer.js';
|
|
@@ -25,6 +26,7 @@ export interface DiscordSeatWorkDeps extends SubmitIntakeWorkDeps {
|
|
|
25
26
|
answer?: typeof answerAsSeat;
|
|
26
27
|
dispatch?: typeof dispatchCeoTask;
|
|
27
28
|
commandDeps?: CeoCommandDeps;
|
|
29
|
+
askDeps?: SeatAskDeps;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
/** Addressed work preserves graph intake except for one owner's private seat request. */
|
|
@@ -44,6 +46,14 @@ export async function handleDiscordSeatWork(
|
|
|
44
46
|
debug.log('seat.dispatch', 'intent', { seat, intent: 'task', via: 'discord', outcome: result.channel });
|
|
45
47
|
return result.reply;
|
|
46
48
|
};
|
|
49
|
+
if (parseSeatAsk(text)) {
|
|
50
|
+
const auth = owner();
|
|
51
|
+
if (!auth) return null;
|
|
52
|
+
if (!deps.askDeps) throw new Error('seat ask delivery unavailable');
|
|
53
|
+
return askSeat(text, { channel: 'discord', channelId: msg.channelId, messageId: msg.messageId,
|
|
54
|
+
...(msg.threadId ? { threadId: msg.threadId } : {}) },
|
|
55
|
+
deps.commandDeps ?? ceoTaskDeps(auth.cfg, auth.id), deps.askDeps);
|
|
56
|
+
}
|
|
47
57
|
const address = parseSeatAddress(text);
|
|
48
58
|
if (!address) {
|
|
49
59
|
if (!text.trim() || /^\s*[/@@]/.test(text)) return null;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { debug } from '../debug/log.js';
|
|
2
|
-
import type {
|
|
3
|
-
import
|
|
4
|
-
import { extractJsonBlock } from './decompose.js';
|
|
2
|
+
import type { ResolveRoleProviderFn, StreamLlmFn } from './runtime-callables.js';
|
|
3
|
+
import { judge } from '../llm/judge-layer.js';
|
|
5
4
|
import {
|
|
6
5
|
INTAKE_FRONT_ROUTE_TRACKS,
|
|
7
6
|
type IntakeFrontRouteDecision,
|
|
@@ -14,17 +13,6 @@ interface ClassifierDeps {
|
|
|
14
13
|
minConfidence?: number;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
function loadRoleProvider(): ResolveRoleProviderFn {
|
|
18
|
-
const { resolveRoleLlm } = require('../user-config.js') as {
|
|
19
|
-
resolveRoleLlm: (role: ModelRole) => { provider: string; model: string };
|
|
20
|
-
};
|
|
21
|
-
const { PROVIDERS } = require('../llm.js') as { PROVIDERS: ProviderRegistry };
|
|
22
|
-
return (role) => {
|
|
23
|
-
const resolved = resolveRoleLlm(role);
|
|
24
|
-
return { provider: PROVIDERS[resolved.provider] ?? { name: resolved.provider }, model: resolved.model };
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
16
|
/** Classify only after the deterministic front-route rules return rule-unknown. */
|
|
29
17
|
export async function classifyIntakeFrontRoute(
|
|
30
18
|
text: string,
|
|
@@ -43,32 +31,38 @@ export async function classifyIntakeFrontRoute(
|
|
|
43
31
|
const failed = (cause: string) => finish('ask-human', 0, `classifier-failed:${cause}`, 'failed');
|
|
44
32
|
|
|
45
33
|
try {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
34
|
+
const decision = await judge({
|
|
35
|
+
site: 'intake.front-route',
|
|
36
|
+
prompt: text,
|
|
37
|
+
messages: [
|
|
38
|
+
{ role: 'system', content: [
|
|
39
|
+
'Classify the intake text into exactly one track:',
|
|
40
|
+
'absorb: read, save, or summarize external material.',
|
|
41
|
+
'tasks: a list of independent to-dos.',
|
|
42
|
+
'graph: an implementation or multi-step workflow request.',
|
|
43
|
+
'ask-human: ambiguous intent requiring human choice.',
|
|
44
|
+
'Return only one JSON object: {"track":"...","confidence":0.0,"reason":"..."}. Confidence must be between 0 and 1.',
|
|
45
|
+
].join('\n') },
|
|
46
|
+
{ role: 'user', content: text },
|
|
47
|
+
],
|
|
48
|
+
streamLLM: deps.streamLLM,
|
|
49
|
+
resolveRoleProvider: deps.resolveRoleProvider,
|
|
50
|
+
schema: (parsed) => {
|
|
51
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return null;
|
|
52
|
+
const candidate = parsed as Record<string, unknown>;
|
|
53
|
+
if (typeof candidate.track !== 'string' ||
|
|
54
|
+
!(INTAKE_FRONT_ROUTE_TRACKS as readonly string[]).includes(candidate.track)) return null;
|
|
55
|
+
if (typeof candidate.confidence !== 'number' || !Number.isFinite(candidate.confidence) ||
|
|
56
|
+
candidate.confidence < 0 || candidate.confidence > 1) return null;
|
|
57
|
+
if (typeof candidate.reason !== 'string') return null;
|
|
58
|
+
return { track: candidate.track as IntakeFrontRouteTrack, confidence: candidate.confidence, reason: candidate.reason };
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
provider = decision.ok ? decision.provider : provider;
|
|
62
|
+
if (!decision.ok) return failed(decision.reason === 'schema' ? 'invalid-json' : 'llm-error');
|
|
63
|
+
const candidate = decision.value;
|
|
70
64
|
|
|
71
|
-
const track = candidate.track
|
|
65
|
+
const track = candidate.track;
|
|
72
66
|
const confidence = candidate.confidence;
|
|
73
67
|
if (confidence < (deps.minConfidence ?? 0.6)) {
|
|
74
68
|
return finish('ask-human', confidence, `classifier-low-confidence:${track}`, 'low-confidence');
|