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/steward/launch.ts
CHANGED
|
@@ -2,11 +2,14 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { closeSync, mkdirSync, openSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { join, resolve } from 'node:path';
|
|
4
4
|
import { debug } from '../debug/log.js';
|
|
5
|
+
import { publishInsideEvent } from '../nexus/api/inside-events.js';
|
|
5
6
|
import { redactSecrets } from '../task-cards/card-store.js';
|
|
7
|
+
import { preLaunchGate, type PreLaunchGateDecision } from '../execution-loop/launch-gate.js';
|
|
8
|
+
import type { BudgetDecision } from '../self-implement/budget-gate.js';
|
|
6
9
|
import type { ScheduledDecision, StewardSettings, TriageIssue } from './triage.js';
|
|
7
10
|
|
|
8
11
|
/** `completed` = the run finished without a merge (a non-code artifact, or nothing to deliver) — never reported as a failure. */
|
|
9
|
-
export type LaunchStatus = 'shadow' | 'launched' | 'skipped-budget' | 'failed' | 'running' | 'merged' | 'completed';
|
|
12
|
+
export type LaunchStatus = 'shadow' | 'launched' | 'skipped-budget' | 'blocked-duplicate' | 'blocked-location' | 'failed' | 'running' | 'merged' | 'completed';
|
|
10
13
|
export interface LaunchEntry {
|
|
11
14
|
issue: string;
|
|
12
15
|
title: string;
|
|
@@ -40,12 +43,14 @@ export interface LaunchDeps {
|
|
|
40
43
|
/** Injected command boundary; the production adapter runs only argv, never a shell. */
|
|
41
44
|
command?: (args: string[]) => { exitCode: number; stdout: string; stderr?: string };
|
|
42
45
|
spawn?: (args: string[], log: string) => { pid: number };
|
|
46
|
+
gate?: (goalId: string, budget: BudgetDecision | 'unknown') => PreLaunchGateDecision;
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
const RUN_ID = /\brun-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i;
|
|
46
50
|
const DEFAULT_POOL = 'pool-node-b@node-b:8';
|
|
47
51
|
// `harness budget --json` outcomes: proceed | next-provider | wait-reset | stop. next-provider still runs (the harness switches provider itself).
|
|
48
52
|
const BUDGET_PROCEED: readonly string[] = ['proceed', 'next-provider'];
|
|
53
|
+
const launchMode = (settings: StewardSettings): 'off' | 'shadow' | 'live' => settings.mode ?? settings.launch ?? 'shadow';
|
|
49
54
|
const cli = (args: string[]) => ['bun', 'bin/elanous.mjs', ...(process.env.NODE_ENV === 'test' ? ['--test'] : []), ...args];
|
|
50
55
|
const sourceOf = (issue: TriageIssue): string => /^출처: (telegram|pwa|tui|cli)$/m.exec(issue.body)?.[1] ?? `linear:${issue.identifier}`;
|
|
51
56
|
const promptOf = (issue: TriageIssue): string => `${issue.title}\n${issue.body.slice(0, 1500)}`;
|
|
@@ -83,10 +88,10 @@ export function planLaunches(rows: ScheduledDecision[], issues: TriageIssue[], l
|
|
|
83
88
|
const issue = byId.get(row.issue);
|
|
84
89
|
if (!issue) continue;
|
|
85
90
|
if (row.rung === 'hitl' || row.hitlReason || row.disposition === 'hitl') {
|
|
86
|
-
if (settings
|
|
91
|
+
if (launchMode(settings) !== 'off' && (!ledger.hitl[row.issue] || launchMode(settings) === 'live' && !ledger.hitl[row.issue].attempted)) hitl.push({ issue, row });
|
|
87
92
|
continue;
|
|
88
93
|
}
|
|
89
|
-
if ((settings
|
|
94
|
+
if (launchMode(settings) === 'off' || row.disposition !== 'now' || row.rung !== 4 || (ledger.launches[row.issue] && !['skipped-budget', 'blocked-duplicate', 'blocked-location'].includes(ledger.launches[row.issue].status) && !(launchMode(settings) === 'live' && ledger.launches[row.issue].status === 'shadow')) || launches.length >= available) continue;
|
|
90
95
|
const args = argvFor(issue, settings);
|
|
91
96
|
launches.push({ issue, row, source: sourceOf(issue), command: args.map(arg => JSON.stringify(arg)).join(' ') });
|
|
92
97
|
}
|
|
@@ -118,37 +123,46 @@ function lastJson(stdout: string): Record<string, unknown> {
|
|
|
118
123
|
/** One issue is reserved before any side effect; budget skips are retriable, never counted as a launch. */
|
|
119
124
|
export function launch(item: LaunchItem, deps: LaunchDeps): LaunchEntry {
|
|
120
125
|
const { ledger, settings, root } = deps;
|
|
121
|
-
if (item.row.rung !== 4 || item.row.hitlReason || item.row.disposition !== 'now' || (ledger.launches[item.issue.identifier] && ledger.launches[item.issue.identifier].status
|
|
122
|
-
if (settings
|
|
126
|
+
if (item.row.rung !== 4 || item.row.hitlReason || item.row.disposition !== 'now' || (ledger.launches[item.issue.identifier] && !['skipped-budget', 'blocked-duplicate', 'blocked-location'].includes(ledger.launches[item.issue.identifier].status) && !(launchMode(settings) === 'live' && ledger.launches[item.issue.identifier].status === 'shadow'))) throw new Error('steward launch is not eligible');
|
|
127
|
+
if (launchMode(settings) === 'off') throw new Error('steward launch is off');
|
|
123
128
|
const key = item.issue.identifier;
|
|
124
129
|
const entry: LaunchEntry = { issue: key, title: redactSecrets(item.issue.title), source: item.source, command: redactSecrets(item.command), status: 'shadow' };
|
|
125
|
-
if (settings
|
|
130
|
+
if (launchMode(settings) !== 'live') {
|
|
126
131
|
ledger.launches[key] = entry;
|
|
127
132
|
saveLaunchLedger(root, ledger);
|
|
128
133
|
debug.log('steward.launch', 'shadow', { issue: key, command: entry.command });
|
|
134
|
+
publishInsideEvent({ kind: 'steward', issue: key, status: entry.status });
|
|
129
135
|
return entry;
|
|
130
136
|
}
|
|
131
137
|
const command = deps.command ?? runCommand;
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (!BUDGET_PROCEED.includes(String(decision.outcome))) {
|
|
136
|
-
entry.status = 'skipped-budget';
|
|
137
|
-
entry.reason = redactSecrets(budget.exitCode === 0 ? JSON.stringify(decision.reasons ?? ['budget unavailable']) : budget.stderr ?? 'budget unavailable');
|
|
138
|
-
// A budget skip may be reconsidered on the next cycle, but the reason remains observable now.
|
|
139
|
-
ledger.launches[key] = entry;
|
|
140
|
-
saveLaunchLedger(root, ledger);
|
|
141
|
-
debug.log('steward.launch', 'skipped-budget', { issue: key, reason: entry.reason });
|
|
142
|
-
return entry;
|
|
143
|
-
}
|
|
144
|
-
} catch (error) {
|
|
145
|
-
entry.status = 'skipped-budget';
|
|
146
|
-
entry.reason = redactSecrets(String(error));
|
|
138
|
+
const blocked = (status: LaunchStatus, reason: string): LaunchEntry => {
|
|
139
|
+
entry.status = status;
|
|
140
|
+
entry.reason = redactSecrets(reason);
|
|
147
141
|
ledger.launches[key] = entry;
|
|
148
142
|
saveLaunchLedger(root, ledger);
|
|
149
|
-
debug.log('steward.launch',
|
|
143
|
+
debug.log('steward.launch', status, { issue: key, reason: entry.reason });
|
|
144
|
+
publishInsideEvent({ kind: 'steward', issue: key, status: entry.status, reason: entry.reason });
|
|
150
145
|
return entry;
|
|
146
|
+
};
|
|
147
|
+
// L6: a launch must remain on the isolated Pod pool, never fall back to the host or another substrate.
|
|
148
|
+
if (!/^[a-zA-Z0-9_-]+(?:@[a-zA-Z0-9._-]+(?::[1-9][0-9]*)?)?$/.test(settings.podPool ?? DEFAULT_POOL))
|
|
149
|
+
return blocked('blocked-location', 'invalid steward pod pool');
|
|
150
|
+
let budget: BudgetDecision | 'unknown' = 'unknown';
|
|
151
|
+
try {
|
|
152
|
+
const result = command(cli(['harness', 'budget', '--json']));
|
|
153
|
+
const decision = result.exitCode === 0 ? lastJson(result.stdout) : {};
|
|
154
|
+
if (!BUDGET_PROCEED.includes(String(decision.outcome)))
|
|
155
|
+
return blocked('skipped-budget', result.exitCode === 0 ? JSON.stringify(decision.reasons ?? ['budget unavailable']) : result.stderr ?? 'budget unavailable');
|
|
156
|
+
budget = { action: decision.outcome as 'proceed' | 'next-provider', reasons: Array.isArray(decision.reasons) ? decision.reasons.map(String) : [] };
|
|
157
|
+
} catch (error) {
|
|
158
|
+
return blocked('skipped-budget', String(error));
|
|
151
159
|
}
|
|
160
|
+
// L6: the shared gate checks active same-goal runs and the budget decision immediately before spawn.
|
|
161
|
+
let gate: PreLaunchGateDecision;
|
|
162
|
+
try { gate = (deps.gate ?? ((goalId, decision) => preLaunchGate({ goalId, budget: decision })))(`linear:${key}`, budget); }
|
|
163
|
+
catch (error) { return blocked('blocked-duplicate', `launch gate unavailable: ${String(error)}`); }
|
|
164
|
+
if (gate.action !== 'proceed' || gate.sameGoalActiveRuns === 'unknown')
|
|
165
|
+
return blocked(gate.action === 'blocked-budget' || gate.action === 'wait-reset' ? 'skipped-budget' : 'blocked-duplicate', gate.sameGoalActiveRuns === 'unknown' ? 'active runs unknown' : gate.reason);
|
|
152
166
|
entry.status = 'launched';
|
|
153
167
|
entry.log = join(root, 'steward', 'launch', `${key.replace(/[^a-zA-Z0-9_-]/g, '_')}.log`);
|
|
154
168
|
mkdirSync(join(root, 'steward', 'launch'), { recursive: true });
|
|
@@ -166,15 +180,16 @@ export function launch(item: LaunchItem, deps: LaunchDeps): LaunchEntry {
|
|
|
166
180
|
}
|
|
167
181
|
saveLaunchLedger(root, ledger);
|
|
168
182
|
debug.log('steward.launch', 'launched', { issue: key, runId: entry.runId, pid: entry.pid, status: entry.status });
|
|
183
|
+
publishInsideEvent({ kind: 'steward', issue: key, status: entry.status, ...(entry.runId ? { runId: entry.runId } : {}) });
|
|
169
184
|
return entry;
|
|
170
185
|
}
|
|
171
186
|
|
|
172
187
|
export function raiseHitl(issue: TriageIssue, row: ScheduledDecision, deps: LaunchDeps): HitlEntry {
|
|
173
188
|
const old = deps.ledger.hitl[issue.identifier];
|
|
174
|
-
if (old && (old.attempted || deps.settings
|
|
189
|
+
if (old && (old.attempted || launchMode(deps.settings) !== 'live')) return old;
|
|
175
190
|
const entry: HitlEntry = old ?? { issue: issue.identifier, reason: redactSecrets(row.hitlReason ?? row.why), raised: false };
|
|
176
191
|
deps.ledger.hitl[issue.identifier] = entry;
|
|
177
|
-
if (deps.settings
|
|
192
|
+
if (launchMode(deps.settings) !== 'live') {
|
|
178
193
|
saveLaunchLedger(deps.root, deps.ledger);
|
|
179
194
|
return entry;
|
|
180
195
|
}
|
|
@@ -199,10 +214,10 @@ function alive(pid: number | undefined): boolean {
|
|
|
199
214
|
}
|
|
200
215
|
|
|
201
216
|
export function collectOutcomes(ledger: LaunchLedger, deps: LaunchDeps): LaunchEntry[] {
|
|
202
|
-
if (deps.settings
|
|
217
|
+
if (launchMode(deps.settings) !== 'live') return [];
|
|
203
218
|
const done: LaunchEntry[] = [];
|
|
204
219
|
for (const entry of Object.values(ledger.launches)) {
|
|
205
|
-
if (entry.reported || entry.status === 'shadow' || entry.status === 'skipped-budget') continue;
|
|
220
|
+
if (entry.reported || entry.status === 'shadow' || entry.status === 'skipped-budget' || entry.status === 'blocked-duplicate' || entry.status === 'blocked-location') continue;
|
|
206
221
|
if (!entry.runId && entry.log) {
|
|
207
222
|
try { entry.runId = readFileSync(entry.log, 'utf8').match(RUN_ID)?.[0]; } catch { /* Wait for log. */ }
|
|
208
223
|
}
|
|
@@ -244,6 +259,7 @@ export function collectOutcomes(ledger: LaunchLedger, deps: LaunchDeps): LaunchE
|
|
|
244
259
|
if (entry.status === 'running') continue;
|
|
245
260
|
done.push(entry);
|
|
246
261
|
debug.log('steward.launch', 'outcome', { issue: entry.issue, status: entry.status, runId: entry.runId, prNumber: entry.prNumber });
|
|
262
|
+
publishInsideEvent({ kind: 'steward', issue: entry.issue, status: entry.status, ...(entry.runId ? { runId: entry.runId } : {}) });
|
|
247
263
|
}
|
|
248
264
|
saveLaunchLedger(deps.root, ledger);
|
|
249
265
|
return done;
|
|
@@ -15,6 +15,22 @@ export interface StewardCardDeps {
|
|
|
15
15
|
now?: () => Date;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/** Record the first intake for each polled issue, independently of LLM triage. */
|
|
19
|
+
export function recordIntakeOnCards(store: StewardCardStore, issues: TriageIssue[], now: () => Date = () => new Date()): void {
|
|
20
|
+
for (const issue of issues) {
|
|
21
|
+
const card = store.createCard({ goalId: `linear:${issue.identifier}`, title: redactSecrets(issue.title) });
|
|
22
|
+
const intakeKey = `intake:${issue.identifier}`;
|
|
23
|
+
if (!card.sections.some(section => section.key === intakeKey)) {
|
|
24
|
+
const directiveSource = /^출처: (telegram|pwa|tui|cli)$/m.exec(issue.body)?.[1];
|
|
25
|
+
const directiveTime = /^시각: (\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z)$/m.exec(issue.body)?.[1];
|
|
26
|
+
store.appendSection(card.id, {
|
|
27
|
+
key: intakeKey, owner: 'steward',
|
|
28
|
+
content: JSON.stringify({ summary: redactSecrets(issue.title), source: directiveSource ?? `linear:${issue.identifier}`, at: directiveTime ?? now().toISOString() }),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
18
34
|
/** Record observe-only intake and the latest scheduled judgment without launching any work. */
|
|
19
35
|
export function recordTriageOnCards(decisions: ScheduledDecision[], issues: TriageIssue[], deps: StewardCardDeps = {}): void {
|
|
20
36
|
const store = deps.store ?? new CardStore(deps.root);
|
|
@@ -23,16 +39,8 @@ export function recordTriageOnCards(decisions: ScheduledDecision[], issues: Tria
|
|
|
23
39
|
for (const decision of decisions) {
|
|
24
40
|
const issue = byIssue.get(decision.issue);
|
|
25
41
|
if (!issue) throw new Error(`Missing issue ${decision.issue}`);
|
|
42
|
+
recordIntakeOnCards(store, [issue], deps.now);
|
|
26
43
|
const card = store.createCard({ goalId: `linear:${issue.identifier}`, title: redactSecrets(issue.title) });
|
|
27
|
-
const intakeKey = `intake:${issue.identifier}`;
|
|
28
|
-
if (!card.sections.some(section => section.key === intakeKey)) {
|
|
29
|
-
const directiveSource = /^출처: (telegram|pwa|tui|cli)$/m.exec(issue.body)?.[1];
|
|
30
|
-
const directiveTime = /^시각: (\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z)$/m.exec(issue.body)?.[1];
|
|
31
|
-
store.appendSection(card.id, {
|
|
32
|
-
key: intakeKey, owner: 'steward',
|
|
33
|
-
content: JSON.stringify({ summary: redactSecrets(issue.title), source: directiveSource ?? `linear:${issue.identifier}`, at: directiveTime ?? (deps.now ?? (() => new Date()))().toISOString() }),
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
44
|
const { rung, dependsOn, priority, disposition, hitlReason, why, owner } = decision;
|
|
37
45
|
const judgment = { rung, dependsOn, priority, disposition: rung === 'hitl' || hitlReason ? 'hitl' : disposition, hitlReason: hitlReason ?? null, why: redactSecrets(why), ...(owner ? { owner } : {}), ...(decision.capability ? { capability: decision.capability } : {}) };
|
|
38
46
|
const key = `triage:${createHash('sha256').update(JSON.stringify(judgment)).digest('hex')}`;
|
package/src/steward/triage.ts
CHANGED
|
@@ -9,8 +9,9 @@ import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
|
9
9
|
import { redactSecrets } from '../task-cards/card-store.js';
|
|
10
10
|
import { directiveHash } from './directive.js';
|
|
11
11
|
import { notifyOutcome, type OutcomeNotifyDeps } from './outcome-notify.js';
|
|
12
|
-
import { recordTriageOnCards, recordLaunchOnCard, recordOutcomeOnCard, recordHitlOnCard, type StewardCardDeps } from './steward-cards.js';
|
|
12
|
+
import { recordIntakeOnCards, recordTriageOnCards, recordLaunchOnCard, recordOutcomeOnCard, recordHitlOnCard, type StewardCardDeps } from './steward-cards.js';
|
|
13
13
|
import { planLaunches, launch, collectOutcomes, raiseHitl, readLaunchLedger, saveLaunchLedger, type LaunchDeps } from './launch.js';
|
|
14
|
+
import { listFabricExecutionCandidates } from '../self-dev/fabric-plan-core.js';
|
|
14
15
|
import { InvalidWorkingBackwardsDraft, recordWorkingBackwardsOnCards } from './working-backwards.js';
|
|
15
16
|
import { CardStore } from '../task-cards/card-store.js';
|
|
16
17
|
import { triageWithinBudget } from './triage-budget.js';
|
|
@@ -32,7 +33,7 @@ export interface TriageDecision {
|
|
|
32
33
|
}
|
|
33
34
|
export interface ScheduledDecision extends TriageDecision { disposition: 'now' | 'wait' | 'hitl' }
|
|
34
35
|
export interface StewardSettings {
|
|
35
|
-
mode?: '
|
|
36
|
+
mode?: 'off' | 'shadow' | 'live'; linearTeam?: string;
|
|
36
37
|
roles?: Record<string, { maxConcurrent?: number }>;
|
|
37
38
|
budget?: number;
|
|
38
39
|
tracks?: Record<string, string>;
|
|
@@ -52,18 +53,28 @@ export interface StewardDeps {
|
|
|
52
53
|
cardStore?: StewardCardDeps['store'];
|
|
53
54
|
warn?: (message: string) => void;
|
|
54
55
|
ask?: StewardAsk;
|
|
55
|
-
launchSettings?: Pick<StewardSettings, 'launch' | 'maxParallel' | 'podPool'>;
|
|
56
|
+
launchSettings?: Pick<StewardSettings, 'mode' | 'launch' | 'maxParallel' | 'podPool'>;
|
|
56
57
|
launchCommand?: LaunchDeps['command'];
|
|
57
58
|
spawnLaunch?: LaunchDeps['spawn'];
|
|
59
|
+
launchGate?: LaunchDeps['gate'];
|
|
58
60
|
outcomeNotify?: Pick<OutcomeNotifyDeps, 'document' | 'message' | 'worktreeCommand' | 'loadOrigin' | 'loadOrigins'>;
|
|
59
61
|
/** Internal command boundary: the current sync has already claimed this pid. */
|
|
60
62
|
stageOwnedByCommand?: boolean;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
export function stewardSettings(): StewardSettings {
|
|
64
|
-
return getUserConfig().loops?.steward ?? {};
|
|
66
|
+
return getUserConfig().loops?.steward ?? { mode: 'shadow' };
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
function effectiveStewardMode(settings: StewardSettings): 'off' | 'shadow' | 'live' {
|
|
70
|
+
return settings.mode ?? settings.launch ?? 'shadow';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function resolvedStewardSettings(override?: StewardDeps['launchSettings']): StewardSettings {
|
|
74
|
+
const settings = { ...stewardSettings(), ...override };
|
|
75
|
+
if (override?.launch !== undefined && override.mode === undefined) settings.mode = override.launch;
|
|
76
|
+
return { ...settings, mode: effectiveStewardMode(settings) };
|
|
77
|
+
}
|
|
67
78
|
|
|
68
79
|
function parseJudgment(issue: TriageIssue, raw: unknown, tracks?: Record<string, string>): TriageDecision {
|
|
69
80
|
const value = typeof raw === 'string' ? JSON.parse(raw) as unknown : raw;
|
|
@@ -247,10 +258,10 @@ function readState(path: string): { issues: Record<string, string>; digestDay?:
|
|
|
247
258
|
catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { issues: {} }; throw error; }
|
|
248
259
|
}
|
|
249
260
|
|
|
250
|
-
/** Each command node invokes one stage.
|
|
261
|
+
/** Each command node invokes one stage. Live launch still requires the launch gate; merge and approval remain with the harness and human. */
|
|
251
262
|
export async function runStewardStage(stage: 'sync' | 'triage' | 'schedule' | 'report', deps: StewardDeps = {}): Promise<void> {
|
|
252
|
-
const settings =
|
|
253
|
-
if (
|
|
263
|
+
const settings = resolvedStewardSettings(deps.launchSettings);
|
|
264
|
+
if (settings.mode === 'off') return;
|
|
254
265
|
const root = deps.root ?? effectiveInstanceRoot();
|
|
255
266
|
if (stage === 'sync' && !deps.stageOwnedByCommand) {
|
|
256
267
|
return withStageSlot(root, async () => {
|
|
@@ -272,7 +283,25 @@ export async function runStewardStage(stage: 'sync' | 'triage' | 'schedule' | 'r
|
|
|
272
283
|
if (!key) throw new Error('connector.linear.apiKey missing');
|
|
273
284
|
if (stage === 'sync') {
|
|
274
285
|
const events = await fetchLinearIssues({ apiKey: key, teamKey: settings.linearTeam ?? 'ELA', fetch: fetchFn });
|
|
275
|
-
|
|
286
|
+
const issues = events.map(e => ({ identifier: e.identifier, ref: e.ref, title: e.title, body: e.body }));
|
|
287
|
+
writeFileSync(snapshot, JSON.stringify(issues));
|
|
288
|
+
const cardIssues = issues.filter((issue): issue is TriageIssue => typeof issue.identifier === 'string');
|
|
289
|
+
if (cardIssues.length) {
|
|
290
|
+
const observeCardFailure = (error: unknown, issue?: string): void => {
|
|
291
|
+
const message = `steward sync: card write failed${issue ? ` (${issue})` : ''}: ${redactSecrets(error instanceof Error ? error.message : String(error))}`;
|
|
292
|
+
try { debug.log('steward.cards', 'write-failed', { error: message }); } catch { /* observation must not fail sync */ }
|
|
293
|
+
try { (deps.warn ?? console.warn)(message); } catch { /* observation must not fail sync */ }
|
|
294
|
+
};
|
|
295
|
+
try {
|
|
296
|
+
const store = deps.cardStore ?? new CardStore(root);
|
|
297
|
+
try {
|
|
298
|
+
for (const issue of cardIssues) {
|
|
299
|
+
try { recordIntakeOnCards(store, [issue], deps.now); }
|
|
300
|
+
catch (error) { observeCardFailure(error, issue.identifier); }
|
|
301
|
+
}
|
|
302
|
+
} finally { if (!deps.cardStore) store.close(); }
|
|
303
|
+
} catch (error) { observeCardFailure(error); }
|
|
304
|
+
}
|
|
276
305
|
} else if (stage === 'triage') {
|
|
277
306
|
const issues = JSON.parse(readFileSync(snapshot, 'utf8')) as TriageIssue[];
|
|
278
307
|
const judge = deps.judge;
|
|
@@ -341,10 +370,12 @@ export async function runStewardStage(stage: 'sync' | 'triage' | 'schedule' | 'r
|
|
|
341
370
|
}
|
|
342
371
|
writeFileSync(schedule, JSON.stringify(rows));
|
|
343
372
|
const ledger = readLaunchLedger(root);
|
|
344
|
-
const launchDeps: LaunchDeps = { root, settings, ledger, command: deps.launchCommand, spawn: deps.spawnLaunch };
|
|
373
|
+
const launchDeps: LaunchDeps = { root, settings, ledger, command: deps.launchCommand, spawn: deps.spawnLaunch, gate: deps.launchGate };
|
|
345
374
|
const cardDeps = { root, store: deps.cardStore, now: deps.now };
|
|
346
375
|
collectOutcomes(ledger, launchDeps);
|
|
347
376
|
const plan = planLaunches(rows, issues, ledger, settings);
|
|
377
|
+
// Keep fabric candidates distinct from Linear launches until a fabric executor is wired.
|
|
378
|
+
writeFileSync(join(dir, 'fabric-candidates.json'), JSON.stringify(listFabricExecutionCandidates(root)));
|
|
348
379
|
for (const { issue, row } of plan.hitl) {
|
|
349
380
|
const entry = raiseHitl(issue, row, launchDeps);
|
|
350
381
|
recordHitlOnCard(issue, entry, cardDeps);
|
|
@@ -391,7 +422,7 @@ export async function runStewardStage(stage: 'sync' | 'triage' | 'schedule' | 'r
|
|
|
391
422
|
const issue = issues.find(item => item.identifier === outcome.issue) ??
|
|
392
423
|
{ identifier: outcome.issue, title: outcome.title, ref: '', body: '' };
|
|
393
424
|
recordOutcomeOnCard(issue, outcome, { root, store: deps.cardStore, now: deps.now });
|
|
394
|
-
notifyOutcome(outcome, { root, ledger, shadow: settings.
|
|
425
|
+
notifyOutcome(outcome, { root, ledger, shadow: settings.mode !== 'live', ...deps.outcomeNotify });
|
|
395
426
|
const prefix = ['telegram', 'pwa', 'tui', 'cli'].includes(outcome.source) ? `${outcome.source} · ` : '';
|
|
396
427
|
await (deps.sendDigest ?? sendStewardDigest)(`${prefix}${issue.title} · PR ${outcome.prNumber ?? '없음'} · ${outcome.status}`);
|
|
397
428
|
outcome.reported = true;
|
|
@@ -399,11 +430,11 @@ export async function runStewardStage(stage: 'sync' | 'triage' | 'schedule' | 'r
|
|
|
399
430
|
}
|
|
400
431
|
const justCollected = new Set(outcomes.map(outcome => outcome.issue));
|
|
401
432
|
for (const outcome of Object.values(ledger.launches)) {
|
|
402
|
-
if ((settings.
|
|
403
|
-
(settings.
|
|
433
|
+
if ((settings.mode !== 'live' && outcome.status === 'shadow' && !outcome.notified) ||
|
|
434
|
+
(settings.mode === 'live' && !justCollected.has(outcome.issue) && outcome.reported && outcome.notified !== 'shadow') ||
|
|
404
435
|
// A finished run whose PR waits for merge still owes the wish's chat its PR link (once; failures retry).
|
|
405
|
-
(settings.
|
|
406
|
-
notifyOutcome(outcome, { root, ledger, shadow: settings.
|
|
436
|
+
(settings.mode === 'live' && outcome.awaitingMerge === true && !outcome.reported && outcome.notified !== 'sent')) {
|
|
437
|
+
notifyOutcome(outcome, { root, ledger, shadow: settings.mode !== 'live', ...deps.outcomeNotify });
|
|
407
438
|
}
|
|
408
439
|
}
|
|
409
440
|
const day = at.slice(0, 10);
|
|
@@ -455,6 +486,7 @@ async function withStageSlot<T>(root: string, run: () => Promise<T>, onBusy?: ()
|
|
|
455
486
|
|
|
456
487
|
/** The command-node boundary records both normal exits and an unclosed stage from a killed process. */
|
|
457
488
|
export async function runStewardStageCommand(stage: StewardStage, deps: StewardCommandDeps = {}): Promise<0 | 1> {
|
|
489
|
+
if (resolvedStewardSettings(deps.launchSettings).mode === 'off') return 0;
|
|
458
490
|
const root = deps.root ?? effectiveInstanceRoot();
|
|
459
491
|
if (stage !== 'sync' && existsSync(skippedPath(root))) return 0;
|
|
460
492
|
return withStageSlot(root, async () => {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
import { scanWishFolder } from '../intake-plane/wish-folder.js';
|
|
2
4
|
import { CardStore, type TaskCard } from './card-store.js';
|
|
3
5
|
|
|
4
6
|
export interface CardCliDeps {
|
|
@@ -20,7 +22,7 @@ function formatCard(card: TaskCard): string {
|
|
|
20
22
|
return lines.join('\n') + '\n';
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
/** Register
|
|
25
|
+
/** Register card inspection and Wish note import commands. */
|
|
24
26
|
export function registerCardCommand(program: Command, deps: CardCliDeps = {}): Command {
|
|
25
27
|
const createStore = deps.createStore ?? (() => new CardStore());
|
|
26
28
|
const write = deps.write ?? ((text: string) => { process.stdout.write(text); });
|
|
@@ -60,5 +62,27 @@ export function registerCardCommand(program: Command, deps: CardCliDeps = {}): C
|
|
|
60
62
|
}
|
|
61
63
|
});
|
|
62
64
|
|
|
65
|
+
card.command('wish-scan')
|
|
66
|
+
.description('Create task cards from Obsidian Wish notes')
|
|
67
|
+
.option('--dir <path>', 'Wish folder path')
|
|
68
|
+
.option('--json', 'Output JSON')
|
|
69
|
+
.action((options: { dir?: string; json?: boolean }) => {
|
|
70
|
+
const dir = resolve(options.dir ?? join(process.env.OBSIDIAN_VAULT_ROOT ?? '', '00. Inbox', '00. Wish'));
|
|
71
|
+
let store: CardStore | undefined;
|
|
72
|
+
try {
|
|
73
|
+
const result = scanWishFolder({ dir, store: (store = createStore()) });
|
|
74
|
+
write(options.json ? `${JSON.stringify(result)}\n` : `추가 ${result.added} · 갱신 ${result.updated} · 건너뜀 ${result.skipped}\n`);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
if (error instanceof Error && error.message.startsWith('Wish 폴더를 찾지 못했습니다: ')) {
|
|
77
|
+
process.stderr.write(`${error.message}\n`);
|
|
78
|
+
process.exitCode = 2;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
throw error;
|
|
82
|
+
} finally {
|
|
83
|
+
store?.close();
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
63
87
|
return card;
|
|
64
88
|
}
|
|
@@ -264,6 +264,8 @@ export interface Mission {
|
|
|
264
264
|
|
|
265
265
|
/** Optional bind to an existing goal (S2 auto-research / PFC). */
|
|
266
266
|
goalSlug?: string;
|
|
267
|
+
/** Project association; absent on legacy and unassigned missions. */
|
|
268
|
+
projectId?: string;
|
|
267
269
|
|
|
268
270
|
/** Free-form notes (append-only). */
|
|
269
271
|
notes: readonly string[];
|
|
@@ -296,6 +298,7 @@ export interface MissionInit {
|
|
|
296
298
|
priority?: MissionPriority;
|
|
297
299
|
taskIds?: readonly string[];
|
|
298
300
|
goalSlug?: string;
|
|
301
|
+
projectId?: string;
|
|
299
302
|
notes?: readonly string[];
|
|
300
303
|
/** Cascade-zyu Z0 — see {@link Mission.showroomSessionId}. */
|
|
301
304
|
showroomSessionId?: string;
|
|
@@ -370,6 +373,7 @@ export function createMission(
|
|
|
370
373
|
priority: init.priority,
|
|
371
374
|
taskIds: Object.freeze([...(init.taskIds ?? [])]),
|
|
372
375
|
goalSlug: init.goalSlug,
|
|
376
|
+
...(init.projectId !== undefined ? { projectId: init.projectId } : {}),
|
|
373
377
|
notes: Object.freeze([...(init.notes ?? [])]),
|
|
374
378
|
showroomSessionId: init.showroomSessionId,
|
|
375
379
|
autopilot: init.autopilot ? { ...init.autopilot } : undefined,
|
|
@@ -471,6 +475,7 @@ export function serializeMission(m: Mission): Record<string, unknown> {
|
|
|
471
475
|
priority: m.priority,
|
|
472
476
|
taskIds: [...m.taskIds],
|
|
473
477
|
goalSlug: m.goalSlug,
|
|
478
|
+
...(m.projectId !== undefined ? { projectId: m.projectId } : {}),
|
|
474
479
|
notes: [...m.notes],
|
|
475
480
|
showroomSessionId: m.showroomSessionId,
|
|
476
481
|
};
|
|
@@ -138,6 +138,7 @@ interface MissionRow {
|
|
|
138
138
|
priority: MissionPriority | null;
|
|
139
139
|
task_ids_json: string; // JSON array of taskId
|
|
140
140
|
goal_slug: string | null;
|
|
141
|
+
project_id: string | null;
|
|
141
142
|
notes_json: string; // JSON array of string
|
|
142
143
|
autopilot_json: string | null; // JSON MissionAutopilot | null (U1)
|
|
143
144
|
}
|
|
@@ -309,6 +310,8 @@ export class TaskStore {
|
|
|
309
310
|
// Mission Fabric 통합 U1 (v3) — tox_missions.autopilot_json:
|
|
310
311
|
// PFC Layer2 자율 메타(apm Mission 흡수). NULL = 일반 Mission.
|
|
311
312
|
this.addColumnIfMissing('tox_missions', 'autopilot_json', 'TEXT');
|
|
313
|
+
this.addColumnIfMissing('tox_missions', 'project_id', 'TEXT');
|
|
314
|
+
this.db.exec('CREATE INDEX IF NOT EXISTS idx_tox_missions_project ON tox_missions(project_id)');
|
|
312
315
|
this.addColumnIfMissing('tox_executions', 'host_id', 'TEXT');
|
|
313
316
|
this.addColumnIfMissing('tox_executions', 'hostname', 'TEXT');
|
|
314
317
|
this.db.exec('CREATE INDEX IF NOT EXISTS idx_tox_executions_host ON tox_executions(host_id, started_at)');
|
|
@@ -587,8 +590,8 @@ export class TaskStore {
|
|
|
587
590
|
`INSERT OR REPLACE INTO tox_missions (
|
|
588
591
|
id, created_at, updated_at, closed_at, title, description, intent,
|
|
589
592
|
source_json, status, priority, task_ids_json, goal_slug, notes_json,
|
|
590
|
-
autopilot_json
|
|
591
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
593
|
+
autopilot_json, project_id
|
|
594
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
592
595
|
)
|
|
593
596
|
.run(
|
|
594
597
|
mission.id,
|
|
@@ -605,6 +608,7 @@ export class TaskStore {
|
|
|
605
608
|
mission.goalSlug ?? null,
|
|
606
609
|
JSON.stringify([...mission.notes]),
|
|
607
610
|
mission.autopilot ? JSON.stringify(mission.autopilot) : null,
|
|
611
|
+
mission.projectId ?? null,
|
|
608
612
|
));
|
|
609
613
|
}
|
|
610
614
|
|
|
@@ -616,7 +620,7 @@ export class TaskStore {
|
|
|
616
620
|
return this.rowToMission(row);
|
|
617
621
|
}
|
|
618
622
|
|
|
619
|
-
listMissions(opts: { status?: MissionStatus; goalSlug?: string } = {}): Mission[] {
|
|
623
|
+
listMissions(opts: { status?: MissionStatus; goalSlug?: string; projectId?: string } = {}): Mission[] {
|
|
620
624
|
const where: string[] = [];
|
|
621
625
|
const params: Array<string | number | null> = [];
|
|
622
626
|
if (opts.status !== undefined) {
|
|
@@ -627,6 +631,10 @@ export class TaskStore {
|
|
|
627
631
|
where.push('goal_slug = ?');
|
|
628
632
|
params.push(opts.goalSlug);
|
|
629
633
|
}
|
|
634
|
+
if (opts.projectId !== undefined) {
|
|
635
|
+
where.push('project_id = ?');
|
|
636
|
+
params.push(opts.projectId);
|
|
637
|
+
}
|
|
630
638
|
const sql =
|
|
631
639
|
'SELECT * FROM tox_missions' +
|
|
632
640
|
(where.length > 0 ? ' WHERE ' + where.join(' AND ') : '') +
|
|
@@ -729,6 +737,7 @@ export class TaskStore {
|
|
|
729
737
|
priority: row.priority ?? undefined,
|
|
730
738
|
taskIds: Object.freeze(JSON.parse(row.task_ids_json) as string[]),
|
|
731
739
|
goalSlug: row.goal_slug ?? undefined,
|
|
740
|
+
...(row.project_id != null ? { projectId: row.project_id } : {}),
|
|
732
741
|
notes: Object.freeze(JSON.parse(row.notes_json) as string[]),
|
|
733
742
|
autopilot: row.autopilot_json
|
|
734
743
|
? (JSON.parse(row.autopilot_json) as Mission['autopilot'])
|
|
@@ -7,14 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
import { randomBytes } from 'node:crypto';
|
|
9
9
|
import { spawnSync } from 'node:child_process';
|
|
10
|
-
import { isAbsolute } from 'node:path';
|
|
10
|
+
import { isAbsolute, resolve } from 'node:path';
|
|
11
11
|
import { getUserConfig } from '../../user-config.js';
|
|
12
12
|
import { debug } from '../../debug/log.js';
|
|
13
13
|
import { effectiveInstanceRoot } from '../../instance/resolve.js';
|
|
14
14
|
import { collectPodArtifacts } from './pod-artifact-return.js';
|
|
15
15
|
import { podBunCacheVolume } from './pod-bun-cache.js';
|
|
16
16
|
import { type PodPoolMember, PodPoolScheduler, resolvePodPoolSpec, parsePodPool, checkPodPool, syncPoolImages, type PoolKubectl } from './pod-pool.js';
|
|
17
|
-
import { readSkillEnvFiles } from './pod-skills.js';
|
|
17
|
+
import { podSkillsDigest, readSkillEnvFiles, resolvePodSkills } from './pod-skills.js';
|
|
18
18
|
import { podSourceScript, type PodSource } from './pod-source-receive.js';
|
|
19
19
|
import {
|
|
20
20
|
POD_CHILD_REQUESTS,
|
|
@@ -30,6 +30,24 @@ import {
|
|
|
30
30
|
/** CLI `--deadline` 생략 시 — 기존 Pod Job 수명 상한과 같다. */
|
|
31
31
|
export const POD_COMMAND_DEADLINE_SECONDS = POD_JOB_DEADLINE_SECONDS;
|
|
32
32
|
|
|
33
|
+
export const POD_NETWORK_SKILLS = ['omni-crawl', 'omni-digest'] as const;
|
|
34
|
+
export const POD_LITE_IMAGE = 'elanous-harness-lite:local';
|
|
35
|
+
|
|
36
|
+
export const POD_LITE_MEMORY_LIMIT = '2Gi';
|
|
37
|
+
|
|
38
|
+
/** POD7 must-fix: the skill list alone can't tell a network-only job from one that needs ffmpeg/browser — so lite is
|
|
39
|
+
* only ever chosen when the caller says so (`lite`), and then only for network skills without a clone. Anything we
|
|
40
|
+
* can't judge keeps the full image. A lite request that doesn't fit is refused with the reason, not silently widened. */
|
|
41
|
+
export function podCommandImageFor(skills: readonly string[], clone: boolean, lite = false): string {
|
|
42
|
+
if (!lite) return 'elanous-harness:local';
|
|
43
|
+
if (clone) throw new Error('pod command: --lite 는 clone 없는 명령만 받는다(lite 이미지는 git·빌드 도구가 적다)');
|
|
44
|
+
const outside = skills.filter((skill) => !(POD_NETWORK_SKILLS as readonly string[]).includes(skill));
|
|
45
|
+
if (skills.length === 0 || outside.length > 0) {
|
|
46
|
+
throw new Error(`pod command: --lite 는 네트워크 스킬(${POD_NETWORK_SKILLS.join('·')})만 받는다${outside.length ? ` — 벗어난 스킬: ${outside.join(', ')}` : ' — --skill 이 없다'}`);
|
|
47
|
+
}
|
|
48
|
+
return POD_LITE_IMAGE;
|
|
49
|
+
}
|
|
50
|
+
|
|
33
51
|
const COMMAND_LOG_CHARS = 80;
|
|
34
52
|
|
|
35
53
|
const GATE = `ok=0
|
|
@@ -212,8 +230,10 @@ export interface RunPodCommandOptions {
|
|
|
212
230
|
clone?: boolean;
|
|
213
231
|
hostMirror?: string;
|
|
214
232
|
bunCache?: string;
|
|
215
|
-
/** 컨테이너 메모리 한도(기본 16Gi). */
|
|
233
|
+
/** 컨테이너 메모리 한도(기본 16Gi · lite 면 2Gi). */
|
|
216
234
|
memoryLimit?: string;
|
|
235
|
+
/** POD7: 호출부가 «네트워크 스킬만 쓰는 명령»이라고 말할 때만 lite 이미지 ⊕ 2Gi. */
|
|
236
|
+
lite?: boolean;
|
|
217
237
|
source?: PodSource;
|
|
218
238
|
ghToken?: () => string;
|
|
219
239
|
deadlineSeconds?: number;
|
|
@@ -266,7 +286,8 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
266
286
|
const baseKubectl = options.kubectl ?? defaultKubectl;
|
|
267
287
|
const sleep = options.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)));
|
|
268
288
|
const namespace = options.namespace ?? 'elanous-test';
|
|
269
|
-
const image = options.image ??
|
|
289
|
+
const image = options.image ?? podCommandImageFor(skills, options.clone === true, options.lite === true);
|
|
290
|
+
const memoryLimit = options.memoryLimit ?? (image === POD_LITE_IMAGE ? POD_LITE_MEMORY_LIMIT : undefined);
|
|
270
291
|
const repoUrl = options.repoUrl ?? 'https://github.com/ElanvitalAI/elanous';
|
|
271
292
|
const deadlineSeconds = options.deadlineSeconds ?? POD_COMMAND_DEADLINE_SECONDS;
|
|
272
293
|
// POD1 (10-01): two launches in the same moment got the same `si-cmd-<time>` and the failing one's cleanup
|
|
@@ -328,8 +349,9 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
328
349
|
localImageCommit: () => podImageFreshness({ image }).imageCommit,
|
|
329
350
|
});
|
|
330
351
|
if (pool && member) {
|
|
331
|
-
const
|
|
332
|
-
|
|
352
|
+
const localSkillsDigest = options.kubectl ? null : image === POD_LITE_IMAGE
|
|
353
|
+
? podSkillsDigest(POD_NETWORK_SKILLS, resolve(import.meta.dir, '../../../skills')).digest
|
|
354
|
+
: podSkillsDigest(resolvePodSkills(env).skills).digest;
|
|
333
355
|
const syncs = await (options.syncImages ?? syncPoolImages)([member], image, imageCommit, { localSkillsDigest });
|
|
334
356
|
const synced = syncs.get(member.context);
|
|
335
357
|
if (synced && !synced.ok) throw new Error(`pod command: 이미지 판을 못 맞췄다: ${synced.detail}`);
|
|
@@ -345,7 +367,7 @@ export async function runPodCommand(options: RunPodCommandOptions): Promise<PodC
|
|
|
345
367
|
name, namespace, launch, image: member?.imageRef ?? image,
|
|
346
368
|
...(member?.imageRef ? { imagePullPolicy: 'IfNotPresent' as const } : {}),
|
|
347
369
|
repoUrl, command, skills, ...(llm ? { llm } : {}), ...(options.clone ? { clone: true } : {}),
|
|
348
|
-
...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(
|
|
370
|
+
...(options.source ? { source: options.source } : {}), ...(hostMirror ? { hostMirror } : {}), ...(bunCache ? { bunCache } : {}), ...(memoryLimit ? { memoryLimit } : {}), deadlineSeconds,
|
|
349
371
|
...(options.runId ? { runId: options.runId } : {}),
|
|
350
372
|
});
|
|
351
373
|
kubectl(['-n', namespace, 'delete', 'job', '-l', own, '--ignore-not-found']);
|