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
|
@@ -125,6 +125,9 @@ export interface LogQuery {
|
|
|
125
125
|
/** event/data/category LIKE 부분 일치. */
|
|
126
126
|
grep?: string;
|
|
127
127
|
sessionId?: string;
|
|
128
|
+
/** Trace ownership: explicit row projectId takes precedence over session ownership. */
|
|
129
|
+
projectId?: string;
|
|
130
|
+
projectSessionIds?: readonly string[];
|
|
128
131
|
sinceMs?: number;
|
|
129
132
|
untilMs?: number;
|
|
130
133
|
/** 증분 커서 — id > afterId 를 오름차순으로(SSE 드레인). */
|
|
@@ -397,6 +400,18 @@ export class LogStore {
|
|
|
397
400
|
params.push(needle, needle, needle);
|
|
398
401
|
}
|
|
399
402
|
if (q.sessionId) { where.push('session_id = ?'); params.push(q.sessionId); }
|
|
403
|
+
if (q.projectId !== undefined) {
|
|
404
|
+
const sessionIds = [...new Set(q.projectSessionIds ?? [])];
|
|
405
|
+
// An explicit project tag wins, even if the row's session belongs to another project.
|
|
406
|
+
// Guard JSON extraction so malformed and absent payloads cannot match by accident.
|
|
407
|
+
const tagged = "CASE WHEN json_valid(data) THEN json_extract(data, '$.projectId') ELSE NULL END";
|
|
408
|
+
const session = "CASE WHEN json_valid(data) THEN json_extract(data, '$.sessionId') ELSE NULL END";
|
|
409
|
+
const untagged = "CASE WHEN json_valid(data) THEN json_type(data, '$.projectId') IS NULL ELSE 1 END";
|
|
410
|
+
where.push(`(${tagged} = ? OR (${untagged} AND (${sessionIds.length
|
|
411
|
+
? `session_id IN (${sessionIds.map(() => '?').join(',')}) OR ${session} IN (${sessionIds.map(() => '?').join(',')})`
|
|
412
|
+
: '0'})))`);
|
|
413
|
+
params.push(q.projectId, ...sessionIds, ...sessionIds);
|
|
414
|
+
}
|
|
400
415
|
if (q.sinceMs !== undefined) { where.push('ts_ms >= ?'); params.push(q.sinceMs); }
|
|
401
416
|
if (q.untilMs !== undefined) { where.push('ts_ms <= ?'); params.push(q.untilMs); }
|
|
402
417
|
if (q.afterId !== undefined) { where.push('id > ?'); params.push(q.afterId); }
|
|
@@ -39,7 +39,7 @@ function jsonResponse(body: unknown, status = 200): Response {
|
|
|
39
39
|
|
|
40
40
|
import {
|
|
41
41
|
isModelTier,
|
|
42
|
-
|
|
42
|
+
isModelTierProfile,
|
|
43
43
|
type BudgetUserConfig,
|
|
44
44
|
type ModelTier,
|
|
45
45
|
type ModelTierUserConfig,
|
|
@@ -74,9 +74,10 @@ function normalizeModelTier(v: unknown): ModelTierUserConfig | undefined | 'inva
|
|
|
74
74
|
if (!v || typeof v !== 'object' || Array.isArray(v)) return 'invalid';
|
|
75
75
|
const r = v as Record<string, unknown>;
|
|
76
76
|
const out: ModelTierUserConfig = {};
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
const profile = r.profile === undefined ? r.persona : r.profile;
|
|
78
|
+
if (profile !== undefined) {
|
|
79
|
+
if (!isModelTierProfile(profile)) return 'invalid';
|
|
80
|
+
out.profile = profile;
|
|
80
81
|
}
|
|
81
82
|
if (r.preset !== undefined) {
|
|
82
83
|
if (typeof r.preset !== 'string' || r.preset.trim().length === 0) return 'invalid';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { effectiveInstanceRoot } from '../../instance/resolve.js';
|
|
2
|
+
import {
|
|
3
|
+
approveFabricPlan,
|
|
4
|
+
createFabricPlan,
|
|
5
|
+
loadFabricPlan,
|
|
6
|
+
type FabricPlan,
|
|
7
|
+
} from '../../self-dev/fabric-plan-core.js';
|
|
8
|
+
import { jsonResponse } from './json-response.js';
|
|
9
|
+
|
|
10
|
+
export interface FabricPlansRouteOpts {
|
|
11
|
+
create?: (root: string, request: string) => Promise<FabricPlan>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** This route never launches a plan. Only approval writes the fabric execution-candidate ledger. */
|
|
15
|
+
export async function handleFabricPlans(req: Request, opts: FabricPlansRouteOpts = {}): Promise<Response> {
|
|
16
|
+
const pathname = new URL(req.url).pathname;
|
|
17
|
+
const root = effectiveInstanceRoot();
|
|
18
|
+
if (pathname === '/v1/fabric/decompose') {
|
|
19
|
+
if (req.method !== 'POST') return jsonResponse({ error: 'method-not-allowed' }, 405);
|
|
20
|
+
let body: unknown;
|
|
21
|
+
try { body = await req.json(); }
|
|
22
|
+
catch { return jsonResponse({ error: 'invalid_json' }, 400); }
|
|
23
|
+
const request = body && typeof body === 'object' && !Array.isArray(body)
|
|
24
|
+
? (body as Record<string, unknown>).request : undefined;
|
|
25
|
+
if (typeof request !== 'string' || !request.trim()) return jsonResponse({ error: 'invalid_request' }, 400);
|
|
26
|
+
try {
|
|
27
|
+
const plan = await (opts.create ?? createFabricPlan)(root, request);
|
|
28
|
+
return jsonResponse({ plan }, 201);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
return jsonResponse({ error: 'decomposition_failed', reason: error instanceof Error ? error.message : String(error) }, 422);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const match = /^\/v1\/fabric\/plans\/([^/]+)(\/approve)?$/.exec(pathname);
|
|
34
|
+
if (!match) return jsonResponse({ error: 'not-found' }, 404);
|
|
35
|
+
let id: string;
|
|
36
|
+
try { id = decodeURIComponent(match[1]!); }
|
|
37
|
+
catch { return jsonResponse({ error: 'invalid_plan_id' }, 400); }
|
|
38
|
+
if (!/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(id)) return jsonResponse({ error: 'invalid_plan_id' }, 400);
|
|
39
|
+
if (!match[2]) {
|
|
40
|
+
if (req.method !== 'GET') return jsonResponse({ error: 'method-not-allowed' }, 405);
|
|
41
|
+
const plan = loadFabricPlan(root, id);
|
|
42
|
+
return plan ? jsonResponse({ plan }) : jsonResponse({ error: 'not-found' }, 404);
|
|
43
|
+
}
|
|
44
|
+
if (req.method !== 'POST') return jsonResponse({ error: 'method-not-allowed' }, 405);
|
|
45
|
+
// The ledger transition is atomic and rejects a second approval; no draft is executable.
|
|
46
|
+
try {
|
|
47
|
+
return jsonResponse({ candidate: approveFabricPlan(root, id) });
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (error instanceof Error && error.message.startsWith('fabric plan not found:')) return jsonResponse({ error: 'not-found' }, 404);
|
|
50
|
+
if (error instanceof Error && error.message === 'fabric plan already approved') return jsonResponse({ error: 'already-approved' }, 409);
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -19,6 +19,7 @@ import { resolveHarnessTarget } from '../../self-implement/harness-target-option
|
|
|
19
19
|
import { queryRunningRuns, type RunningRunsResult } from '../../self-implement/running-runs.js';
|
|
20
20
|
import { getDefaultLogStore, type LogStore } from '../../mss/logging/log-store.js';
|
|
21
21
|
import { createSeqTracker, makeEnvelope, type FeedbackEnvelope } from '../../feedback/envelope.js';
|
|
22
|
+
import { publishInsideEvent } from './inside-events.js';
|
|
22
23
|
|
|
23
24
|
const JSON_HEADERS = { 'content-type': 'application/json; charset=utf-8' };
|
|
24
25
|
const ASK_USAGE = 'usage: POST /v1/harness/ask with JSON body {"text":"<ask>"} — optional "target":"<path>" (홈 안의 git repo·디렉터리·파일)';
|
|
@@ -248,7 +249,10 @@ export async function handleHarnessAskPost(req: Request, _metaApi: HarnessMetaAp
|
|
|
248
249
|
}
|
|
249
250
|
|
|
250
251
|
const acceptanceId = deps.createAcceptanceId?.() ?? crypto.randomUUID();
|
|
251
|
-
const log =
|
|
252
|
+
const log = (event: string, data: Record<string, unknown>) => {
|
|
253
|
+
(deps.log ?? ((name: string, payload: Record<string, unknown>) => debug.log('harness-http', name, payload)))(event, data);
|
|
254
|
+
publishInsideEvent({ ...data, kind: 'harness-run', event });
|
|
255
|
+
};
|
|
252
256
|
const suppliedOrigin = (body as { origin?: unknown }).origin;
|
|
253
257
|
const origin = suppliedOrigin === undefined ? null
|
|
254
258
|
: readReportOrigin({ [REPORT_ORIGIN_ENV]: JSON.stringify(suppliedOrigin) });
|
package/src/nexus/api/health.ts
CHANGED
|
@@ -128,6 +128,8 @@ export function handleHealth(
|
|
|
128
128
|
universeRoot: safeUniverseRoot(),
|
|
129
129
|
testUniverse: safeTestUniverse(),
|
|
130
130
|
bindHost: safeBindHost(bind),
|
|
131
|
+
// W4 — POST /v1/workflows/:name/run understands onlyNode · fromNode+fromRunId · mode (PWA enables its run-mode buttons on this).
|
|
132
|
+
workflowRunModes: true as const,
|
|
131
133
|
...(setup?.mode === true
|
|
132
134
|
? { setupMode: true as const, setupMissing: setup.missing }
|
|
133
135
|
: {}),
|
|
@@ -21,6 +21,7 @@ import type { TelegramEvent } from '../../workflow-runtime/triggers/telegram-sou
|
|
|
21
21
|
import { spawnSync } from 'node:child_process';
|
|
22
22
|
import { isAbsolute } from 'node:path';
|
|
23
23
|
import { createProject, listProjects } from '../../project/project-store.js';
|
|
24
|
+
import { handleOutputsGet, type OutputsDeps } from './outputs-route.js';
|
|
24
25
|
import { compareTokenConstTime } from '../../acp/transport/auth.js';
|
|
25
26
|
import { ensureAuthToken } from '../../auth/acp-token.js';
|
|
26
27
|
import type { NexusState } from '../state/state.js';
|
|
@@ -42,6 +43,7 @@ import { OPENAI_RELAY_PATH, tryHandleOpenAiRelay } from './openai-relay.js';
|
|
|
42
43
|
import { handleHealth, type HealthSetupContext } from './health.js';
|
|
43
44
|
import { handleTabsList, handleTabDetail, handleNexusSnapshot } from './tabs.js';
|
|
44
45
|
import { handleSseEvents } from './events.js';
|
|
46
|
+
import { handleInsideEvents, INSIDE_EVENTS_PATH, startInsideEventRelay } from './inside-events.js';
|
|
45
47
|
import { dispatchIntentPredictionRoute } from './intent-prediction.js';
|
|
46
48
|
import { handleNotificationAction } from './notification-action.js';
|
|
47
49
|
import { handleUserIntentEmit, handleUserIntentBatch } from './user-intents.js';
|
|
@@ -157,6 +159,7 @@ import {
|
|
|
157
159
|
} from './vault-api.js';
|
|
158
160
|
import { handleBuildsGet, parseBuildsPath } from './builds-api.js';
|
|
159
161
|
import { handleHarnessAskPost, handleHarnessAskStatusGet, handleHarnessRunEventsGet, handleHarnessRunScreenGet, handleHarnessRunsGet, handleHarnessStopPost } from './harness-api.js';
|
|
162
|
+
import { handleFabricPlans, type FabricPlansRouteOpts } from './fabric-plans.js';
|
|
160
163
|
import { dispatchPersonaRoute } from './personas.js';
|
|
161
164
|
import { handleMe } from './operator.js';
|
|
162
165
|
import { handleOpsApi } from './ops-api.js';
|
|
@@ -178,6 +181,7 @@ import { handleChannelBotsGet, handleChannelBotSet } from './setup-channel-bot.j
|
|
|
178
181
|
import { handleLlmRoutePredict } from './llm-route-predict.js';
|
|
179
182
|
import type { MissionRouter } from '../../llm/mission-router.js';
|
|
180
183
|
import { handleContextFetchUrl } from './context-url.js';
|
|
184
|
+
import { contextNow } from '../../context-bus/context-now.js';
|
|
181
185
|
import type { IntentPredictionService } from '../../intent-prediction/index.js';
|
|
182
186
|
import type { NotificationActionLoopback } from '../../web-push/notification-action-loopback.js';
|
|
183
187
|
import { handlePlatforms } from './platforms.js';
|
|
@@ -461,8 +465,11 @@ export function probeNexusHttpPort(
|
|
|
461
465
|
export type NexusWsBridgeInit = Omit<WsBridgeOpts, 'hostname' | 'port'>;
|
|
462
466
|
|
|
463
467
|
export interface NexusHttpServerOpts {
|
|
468
|
+
/** Optional fabric-plan ledger and decomposition seam; production uses the instance root and existing fabric decomposer. */
|
|
469
|
+
fabricPlans?: FabricPlansRouteOpts;
|
|
464
470
|
/** Optional installer state root for isolated API consumers and tests. */
|
|
465
471
|
pluginStateRoot?: string;
|
|
472
|
+
outputs?: OutputsDeps;
|
|
466
473
|
execRequests?: ExecRequestRunner;
|
|
467
474
|
seatRequests?: SeatRequestsDeps;
|
|
468
475
|
consultRequests?: ConsultRequestsDeps;
|
|
@@ -790,11 +797,13 @@ export function startNexusHttpServer(opts: NexusHttpServerOpts): NexusHttpServer
|
|
|
790
797
|
}
|
|
791
798
|
|
|
792
799
|
const url = `http://${hostname}:${resolvedPort}`;
|
|
800
|
+
const stopInsideRelay = startInsideEventRelay();
|
|
793
801
|
return {
|
|
794
802
|
port: resolvedPort,
|
|
795
803
|
hostname,
|
|
796
804
|
url,
|
|
797
805
|
stop() {
|
|
806
|
+
stopInsideRelay();
|
|
798
807
|
try { server!.stop(true); } catch { /* idempotent */ }
|
|
799
808
|
setInProcessOutbound(null);
|
|
800
809
|
},
|
|
@@ -984,6 +993,11 @@ export async function routeRequest(
|
|
|
984
993
|
}
|
|
985
994
|
}
|
|
986
995
|
|
|
996
|
+
if (pathname === INSIDE_EVENTS_PATH) {
|
|
997
|
+
if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
998
|
+
return handleInsideEvents(req);
|
|
999
|
+
}
|
|
1000
|
+
|
|
987
1001
|
if (pathname === LIVE_SHIPPED_PATH) {
|
|
988
1002
|
return handleLiveShipped(req, { authorize: (request) => !!opts.metaApi && checkAuth(request, opts.metaApi) });
|
|
989
1003
|
}
|
|
@@ -1312,11 +1326,21 @@ export async function routeRequest(
|
|
|
1312
1326
|
return handleGraphsValidatePost(req, opts.metaApi);
|
|
1313
1327
|
}
|
|
1314
1328
|
|
|
1329
|
+
if (pathname === '/v1/fabric/decompose' || pathname.startsWith('/v1/fabric/plans/')) {
|
|
1330
|
+
if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1331
|
+
return handleFabricPlans(req, opts.fabricPlans);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1315
1334
|
if (pathname === '/v1/projects' && (method === 'GET' || method === 'POST')) {
|
|
1316
1335
|
if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1317
1336
|
return method === 'GET' ? handleProjectsGet() : handleProjectsPost(req);
|
|
1318
1337
|
}
|
|
1319
1338
|
|
|
1339
|
+
if (method === 'GET' && pathname === '/v1/outputs') {
|
|
1340
|
+
if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1341
|
+
return handleOutputsGet(req, opts.outputs);
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1320
1344
|
if (pathname === '/v1/config/chat-fast-path' && (method === 'GET' || method === 'PUT')) {
|
|
1321
1345
|
if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
1322
1346
|
return handleChatFastPathConfig(req);
|
|
@@ -1328,6 +1352,14 @@ export async function routeRequest(
|
|
|
1328
1352
|
return (opts.usageHandler ?? handleUsageGet)();
|
|
1329
1353
|
}
|
|
1330
1354
|
|
|
1355
|
+
// SK2 (PWA) list — GET must be routed before the non-GET block below; the original route sat inside it,
|
|
1356
|
+
// so the PWA banner's GET always fell through to «not-found» (found by the DEMO-RUNa rehearsal · 10-03).
|
|
1357
|
+
if (method === 'GET' && pathname === '/v1/skills/problems') {
|
|
1358
|
+
if (!opts.metaApi) return jsonResponse({ error: 'meta-api-not-wired' }, 503);
|
|
1359
|
+
const { handleSkillProblems } = await import('./skill-problems.js');
|
|
1360
|
+
return handleSkillProblems(req, opts.metaApi);
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1331
1363
|
// Mutation routes (PR ι) — POST/PATCH/DELETE on /v1/nexus/tabs[/:id[/action]].
|
|
1332
1364
|
// Templates POST handled here too (PR κ).
|
|
1333
1365
|
// Config / secrets PUT/POST/DELETE here too (PR μ).
|
|
@@ -2775,6 +2807,10 @@ export async function routeRequest(
|
|
|
2775
2807
|
const result = await dispatchPersonaRoute(req, pathname);
|
|
2776
2808
|
if (result) return result;
|
|
2777
2809
|
}
|
|
2810
|
+
if (pathname === '/v1/context/now') {
|
|
2811
|
+
if (!opts.metaApi || !checkAuth(req, opts.metaApi)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
2812
|
+
return jsonResponse(contextNow({ ...(url.searchParams.has('topic') ? { topic: url.searchParams.get('topic') ?? '' } : {}) }));
|
|
2813
|
+
}
|
|
2778
2814
|
// §6.3 (2026-05-09) — context URL fetch (showroom).
|
|
2779
2815
|
// POST /v1/context/fetch-url
|
|
2780
2816
|
if (pathname === '/v1/context/fetch-url') {
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { appendFileSync, existsSync, mkdirSync, openSync, closeSync, readSync, readFileSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { StringDecoder } from 'node:string_decoder';
|
|
5
|
+
import { debug } from '../../debug/log.js';
|
|
6
|
+
import { nexusRootDir } from '../paths.js';
|
|
7
|
+
import { SSE_HEARTBEAT_MS } from './sse-heartbeat.js';
|
|
8
|
+
|
|
9
|
+
/** The node envelope matches apps/pwa/src/lib/inside-events.ts without importing browser code. */
|
|
10
|
+
export interface InsideNodeEvent {
|
|
11
|
+
kind: 'node';
|
|
12
|
+
graphId: string;
|
|
13
|
+
runId: string;
|
|
14
|
+
nodeId: string;
|
|
15
|
+
phase: 'start' | 'ok' | 'fail';
|
|
16
|
+
ts: string;
|
|
17
|
+
seconds?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Other producers can add their own domain fields without changing the transport. */
|
|
21
|
+
export type InsideLiveEvent = InsideNodeEvent | ({ kind: string; ts: string } & Record<string, unknown>);
|
|
22
|
+
export type InsideEventInput = { kind: string; ts?: string } & Record<string, unknown>;
|
|
23
|
+
|
|
24
|
+
export const INSIDE_EVENTS_PATH = '/v1/inside/events';
|
|
25
|
+
const MAX_PENDING_FRAMES = 16;
|
|
26
|
+
const MAX_FRAME_BYTES = 64 * 1024;
|
|
27
|
+
const MASK = '[REDACTED]';
|
|
28
|
+
const SECRET_KEY = /(?:secret|password|passwd|token|api[_-]?key|authorization|credential|private[_-]?key|cookie|session[_-]?key)/i;
|
|
29
|
+
const INLINE_SECRET = /\b((?:Bearer|Basic)\s+|(?:sk|ghp|gho|ghu|ghs|ghr|github_pat|glpat|xox[baprs])[-_])[^\s"'`,;]+/gi;
|
|
30
|
+
const ASSIGNMENT_SECRET = /\b((?:api[_-]?key|(?:access[_-]?)?token|secret|password|authorization)\s*[:=]\s*)(?:(["'])[^\r\n]*?\2|[^\s"'`,;]+)/gi;
|
|
31
|
+
|
|
32
|
+
function maskString(value: string): string {
|
|
33
|
+
return value.replace(INLINE_SECRET, `$1${MASK}`)
|
|
34
|
+
.replace(ASSIGNMENT_SECRET, (_match, prefix: string, quote?: string) => `${prefix}${quote ?? ''}${MASK}${quote ?? ''}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Sanitize before fan-out; never put an unmasked payload in the subscriber queue. */
|
|
38
|
+
export function maskInsideEventValue(value: unknown, seen = new WeakSet<object>()): unknown {
|
|
39
|
+
if (typeof value === 'string') return maskString(value);
|
|
40
|
+
if (!value || typeof value !== 'object') return value;
|
|
41
|
+
if (seen.has(value)) return MASK;
|
|
42
|
+
seen.add(value);
|
|
43
|
+
if (Array.isArray(value)) {
|
|
44
|
+
const result = value.map((item) => maskInsideEventValue(item, seen));
|
|
45
|
+
seen.delete(value);
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
const result: Record<string, unknown> = {};
|
|
49
|
+
for (const [key, item] of Object.entries(value)) {
|
|
50
|
+
result[key] = SECRET_KEY.test(key) ? MASK : maskInsideEventValue(item, seen);
|
|
51
|
+
}
|
|
52
|
+
seen.delete(value);
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
type Listener = (event: InsideLiveEvent) => void;
|
|
57
|
+
const listeners = new Set<Listener>();
|
|
58
|
+
const RELAY_INTERVAL_MS = 20;
|
|
59
|
+
const RELAY_MAX_RECORD_BYTES = 64 * 1024;
|
|
60
|
+
const RELAY_ROTATE_BYTES = 4 * 1024 * 1024;
|
|
61
|
+
const RELAY_RETIRE_GRACE_MS = 2000;
|
|
62
|
+
const relayIdentity = randomUUID();
|
|
63
|
+
|
|
64
|
+
function relayPaths() {
|
|
65
|
+
const root = nexusRootDir();
|
|
66
|
+
return { root, pointer: join(root, 'inside-events-relay.json') };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function dispatch(event: InsideLiveEvent): void {
|
|
70
|
+
for (const listener of listeners) {
|
|
71
|
+
try { listener(event); } catch { /* a disconnected observer must not stop a run */ }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Each daemon owns its journal; child processes append masked records to that journal.
|
|
76
|
+
* The journal rotates once fully consumed past RELAY_ROTATE_BYTES: the pointer moves to a fresh file and the old one is
|
|
77
|
+
* drained for a grace period (producers that read the old pointer may still append) before it is removed. */
|
|
78
|
+
export function startInsideEventRelay(opts: { rotateBytes?: number; retireGraceMs?: number } = {}): () => void {
|
|
79
|
+
const { root, pointer } = relayPaths();
|
|
80
|
+
mkdirSync(root, { recursive: true });
|
|
81
|
+
const rotateBytes = opts.rotateBytes ?? RELAY_ROTATE_BYTES;
|
|
82
|
+
const retireGraceMs = opts.retireGraceMs ?? RELAY_RETIRE_GRACE_MS;
|
|
83
|
+
type Journal = { file: string; offset: number; pending: string; decoder: StringDecoder; retireAt?: number };
|
|
84
|
+
const journals: Journal[] = [];
|
|
85
|
+
let descriptor = '';
|
|
86
|
+
const open = (): Journal => {
|
|
87
|
+
const id = randomUUID();
|
|
88
|
+
const file = join(root, `inside-events-${id}.jsonl`);
|
|
89
|
+
writeFileSync(file, '', { mode: 0o600, flag: 'wx' });
|
|
90
|
+
descriptor = JSON.stringify({ pid: process.pid, id });
|
|
91
|
+
writeFileSync(pointer, descriptor, { mode: 0o600 });
|
|
92
|
+
const journal: Journal = { file, offset: 0, pending: '', decoder: new StringDecoder('utf8') };
|
|
93
|
+
journals.push(journal);
|
|
94
|
+
return journal;
|
|
95
|
+
};
|
|
96
|
+
let current = open();
|
|
97
|
+
const drain = (journal: Journal): void => {
|
|
98
|
+
const size = statSync(journal.file).size;
|
|
99
|
+
if (size < journal.offset) { journal.offset = 0; journal.pending = ''; journal.decoder = new StringDecoder('utf8'); }
|
|
100
|
+
while (size > journal.offset) {
|
|
101
|
+
const count = Math.min(size - journal.offset, 1024 * 1024);
|
|
102
|
+
const chunk = Buffer.alloc(count);
|
|
103
|
+
const fd = openSync(journal.file, 'r');
|
|
104
|
+
let length: number;
|
|
105
|
+
try { length = readSync(fd, chunk, 0, count, journal.offset); }
|
|
106
|
+
finally { closeSync(fd); }
|
|
107
|
+
if (length <= 0) break;
|
|
108
|
+
journal.offset += length;
|
|
109
|
+
// A chunk boundary may split a multi-byte character; the decoder carries the partial bytes into the next read.
|
|
110
|
+
journal.pending += journal.decoder.write(chunk.subarray(0, length));
|
|
111
|
+
const lines = journal.pending.split('\n');
|
|
112
|
+
journal.pending = lines.pop() ?? '';
|
|
113
|
+
if (journal.pending.length > RELAY_MAX_RECORD_BYTES) journal.pending = '';
|
|
114
|
+
for (const line of lines) {
|
|
115
|
+
if (line.length > RELAY_MAX_RECORD_BYTES) continue;
|
|
116
|
+
try {
|
|
117
|
+
const record = JSON.parse(line) as { origin?: string; event?: InsideEventInput };
|
|
118
|
+
if (record.origin === relayIdentity || !record.event || typeof record.event.kind !== 'string'
|
|
119
|
+
|| !/^[a-z][a-z0-9._-]*$/i.test(record.event.kind)) continue;
|
|
120
|
+
dispatch(maskInsideEventValue(record.event) as InsideLiveEvent);
|
|
121
|
+
} catch { /* malformed producer record */ }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
const remove = (journal: Journal): void => {
|
|
126
|
+
try { unlinkSync(journal.file); } catch { /* already removed */ }
|
|
127
|
+
journals.splice(journals.indexOf(journal), 1);
|
|
128
|
+
};
|
|
129
|
+
const timer = setInterval(() => {
|
|
130
|
+
for (const journal of [...journals]) {
|
|
131
|
+
try { drain(journal); } catch { /* journal disappeared during shutdown */ }
|
|
132
|
+
if (journal.retireAt !== undefined && Date.now() >= journal.retireAt && journal.pending === '') remove(journal);
|
|
133
|
+
}
|
|
134
|
+
if (current.offset >= rotateBytes && current.pending === '') {
|
|
135
|
+
try {
|
|
136
|
+
current.retireAt = Date.now() + retireGraceMs;
|
|
137
|
+
current = open();
|
|
138
|
+
debug.log('inside.events', 'relay-rotated', { journals: journals.length });
|
|
139
|
+
} catch { /* keep appending to the current journal */ }
|
|
140
|
+
}
|
|
141
|
+
}, RELAY_INTERVAL_MS);
|
|
142
|
+
timer.unref();
|
|
143
|
+
return () => {
|
|
144
|
+
clearInterval(timer);
|
|
145
|
+
try { if (readFileSync(pointer, 'utf8') === descriptor) unlinkSync(pointer); } catch { /* another daemon owns it */ }
|
|
146
|
+
for (const journal of [...journals]) remove(journal);
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Ordered local delivery plus best-effort cross-process delivery to the current daemon. */
|
|
151
|
+
export function publishInsideEvent(event: InsideEventInput): void {
|
|
152
|
+
if (!event || typeof event.kind !== 'string' || !/^[a-z][a-z0-9._-]*$/i.test(event.kind)) return;
|
|
153
|
+
const safe = maskInsideEventValue({ ...event, ts: event.ts ?? new Date().toISOString() }) as InsideLiveEvent;
|
|
154
|
+
dispatch(safe);
|
|
155
|
+
try {
|
|
156
|
+
const { root, pointer } = relayPaths();
|
|
157
|
+
if (!existsSync(pointer)) return;
|
|
158
|
+
const descriptor = JSON.parse(readFileSync(pointer, 'utf8')) as { pid?: number; id?: string };
|
|
159
|
+
if (!Number.isSafeInteger(descriptor.pid) || typeof descriptor.id !== 'string' || !/^[a-f0-9-]{36}$/.test(descriptor.id)) return;
|
|
160
|
+
process.kill(descriptor.pid!, 0);
|
|
161
|
+
const file = join(root, `inside-events-${descriptor.id}.jsonl`);
|
|
162
|
+
const line = JSON.stringify({ origin: relayIdentity, event: safe }) + '\n';
|
|
163
|
+
if (Buffer.byteLength(line) > RELAY_MAX_RECORD_BYTES) return;
|
|
164
|
+
appendFileSync(file, line, { mode: 0o600, flag: 'a' });
|
|
165
|
+
} catch { /* a missing daemon must not interrupt the producer */ }
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function subscribeInsideEvent(listener: Listener): () => void {
|
|
169
|
+
listeners.add(listener);
|
|
170
|
+
return () => { listeners.delete(listener); };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** No history/replay: the stream starts at the moment a client subscribes. */
|
|
174
|
+
export function handleInsideEvents(req: Request): Response {
|
|
175
|
+
if (req.method !== 'GET') return new Response(null, { status: 405, headers: { allow: 'GET' } });
|
|
176
|
+
const encoder = new TextEncoder();
|
|
177
|
+
let cleanup: (() => void) | undefined;
|
|
178
|
+
const stream = new ReadableStream<Uint8Array>({
|
|
179
|
+
start(controller) {
|
|
180
|
+
let closed = false;
|
|
181
|
+
let unsubscribe = () => {};
|
|
182
|
+
let heartbeat: ReturnType<typeof setInterval> | undefined;
|
|
183
|
+
const onAbort = () => close();
|
|
184
|
+
cleanup = () => {
|
|
185
|
+
if (closed) return;
|
|
186
|
+
closed = true;
|
|
187
|
+
if (heartbeat !== undefined) clearInterval(heartbeat);
|
|
188
|
+
unsubscribe();
|
|
189
|
+
req.signal.removeEventListener('abort', onAbort);
|
|
190
|
+
};
|
|
191
|
+
const close = () => {
|
|
192
|
+
cleanup?.();
|
|
193
|
+
try { controller.close(); } catch { /* cancelled already */ }
|
|
194
|
+
};
|
|
195
|
+
const send = (text: string): void => {
|
|
196
|
+
if (closed) return;
|
|
197
|
+
const bytes = encoder.encode(text);
|
|
198
|
+
if (bytes.byteLength > MAX_FRAME_BYTES || (controller.desiredSize ?? 0) <= 0) {
|
|
199
|
+
close();
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
try { controller.enqueue(bytes); } catch { close(); }
|
|
203
|
+
};
|
|
204
|
+
if (req.signal.aborted) {
|
|
205
|
+
close();
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
unsubscribe = subscribeInsideEvent((event) => {
|
|
209
|
+
send(`event: ${event.kind}\ndata: ${JSON.stringify(event)}\n\n`);
|
|
210
|
+
});
|
|
211
|
+
heartbeat = setInterval(() => send(': ping\n\n'), SSE_HEARTBEAT_MS);
|
|
212
|
+
req.signal.addEventListener('abort', onAbort, { once: true });
|
|
213
|
+
if (req.signal.aborted) close();
|
|
214
|
+
else send(': inside events stream\n\n');
|
|
215
|
+
},
|
|
216
|
+
cancel() { cleanup?.(); },
|
|
217
|
+
}, { highWaterMark: MAX_PENDING_FRAMES, size: () => 1 });
|
|
218
|
+
return new Response(stream, {
|
|
219
|
+
headers: {
|
|
220
|
+
'content-type': 'text/event-stream; charset=utf-8',
|
|
221
|
+
'cache-control': 'no-cache, no-transform',
|
|
222
|
+
'x-accel-buffering': 'no',
|
|
223
|
+
connection: 'keep-alive',
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
}
|
|
@@ -81,6 +81,7 @@ import { createPwaConfirmChannel, createPwaQuestionChannel } from './hitl-pwa-ch
|
|
|
81
81
|
import type { NexusEventBus } from './event-bus.js';
|
|
82
82
|
import { jsonResponse } from './http-server.js';
|
|
83
83
|
import { defaultChatEventBus } from './chat-event-bus.js';
|
|
84
|
+
import { resolveSessionProjectContext } from '../../project/session-context.js';
|
|
84
85
|
|
|
85
86
|
const MIME_BY_EXT: Record<string, string> = {
|
|
86
87
|
'.png': 'image/png',
|
|
@@ -803,13 +804,18 @@ export async function handlePromptPost(
|
|
|
803
804
|
): Promise<Response> {
|
|
804
805
|
if (!checkAuth(req, opts)) return authFailureResponse(req, opts);
|
|
805
806
|
if (!opts.history) return jsonResponse({ error: RUNTIME_NOT_WIRED }, 503);
|
|
806
|
-
let
|
|
807
|
+
let rawBody: unknown;
|
|
807
808
|
try {
|
|
808
|
-
|
|
809
|
+
rawBody = await req.json();
|
|
809
810
|
} catch {
|
|
810
811
|
return badRequest('invalid JSON body');
|
|
811
812
|
}
|
|
812
|
-
|
|
813
|
+
if (!rawBody || typeof rawBody !== 'object' || Array.isArray(rawBody)) {
|
|
814
|
+
return badRequest('userText or userContent required');
|
|
815
|
+
}
|
|
816
|
+
const body = rawBody as DaemonPromptBody;
|
|
817
|
+
const projectContext = resolveSessionProjectContext(typeof body.sessionId === 'string' ? body.sessionId : undefined);
|
|
818
|
+
const parsed = parseDaemonPromptBody(body, projectContext?.instructions ? [opts.systemPrompt, projectContext.instructions].filter(Boolean).join('\n\n') : opts.systemPrompt);
|
|
813
819
|
if (!parsed.ok) return badRequest(parsed.reason);
|
|
814
820
|
const submit = createDaemonPromptTurnSubmit({
|
|
815
821
|
kind: 'submit-turn',
|
|
@@ -843,7 +849,8 @@ export async function handlePromptPost(
|
|
|
843
849
|
...((owner) => owner ? { verifiedOwner: owner } : {})(promptVerifiedOwner(req, opts)),
|
|
844
850
|
...(resolvePromptHitlChannels(typeof body.sessionId === 'string' ? body.sessionId : '', opts) ?? {}),
|
|
845
851
|
...(effectiveSurface ? { toolSurface: effectiveSurface } : {}),
|
|
846
|
-
...(opts.toolCwd ? { toolCwd: opts.toolCwd } : {}),
|
|
852
|
+
...(projectContext?.cwd || opts.toolCwd ? { toolCwd: projectContext?.cwd ?? opts.toolCwd } : {}),
|
|
853
|
+
...(projectContext?.instructions ? { projectInstructions: projectContext.instructions } : {}),
|
|
847
854
|
dispatchToolErrorMessage: 'NEXUS prompt runtime has no tool surface (start nexus with `--tools readonly|webterm`)',
|
|
848
855
|
});
|
|
849
856
|
},
|
|
@@ -930,13 +937,18 @@ export async function handlePromptStreamPost(
|
|
|
930
937
|
): Promise<Response> {
|
|
931
938
|
if (!checkAuth(req, opts)) return authFailureResponse(req, opts);
|
|
932
939
|
if (!opts.history) return jsonResponse({ error: RUNTIME_NOT_WIRED }, 503);
|
|
933
|
-
let
|
|
940
|
+
let rawBody: unknown;
|
|
934
941
|
try {
|
|
935
|
-
|
|
942
|
+
rawBody = await req.json();
|
|
936
943
|
} catch {
|
|
937
944
|
return badRequest('invalid JSON body');
|
|
938
945
|
}
|
|
939
|
-
|
|
946
|
+
if (!rawBody || typeof rawBody !== 'object' || Array.isArray(rawBody)) {
|
|
947
|
+
return badRequest('userText or userContent required');
|
|
948
|
+
}
|
|
949
|
+
const body = rawBody as DaemonPromptBody;
|
|
950
|
+
const projectContext = resolveSessionProjectContext(typeof body.sessionId === 'string' ? body.sessionId : undefined);
|
|
951
|
+
const parsed = parseDaemonPromptBody(body, projectContext?.instructions ? [opts.systemPrompt, projectContext.instructions].filter(Boolean).join('\n\n') : opts.systemPrompt);
|
|
940
952
|
if (!parsed.ok) return badRequest(parsed.reason);
|
|
941
953
|
// M6 PR 1 (PLAN-rich-dev-feedback-multi-surface · 2026-05-13) — opt-in
|
|
942
954
|
// debug-tap. PWA `/chat?debug-tap=on` propagates the query down to
|
|
@@ -1201,7 +1213,8 @@ export async function handlePromptStreamPost(
|
|
|
1201
1213
|
...((owner) => owner ? { verifiedOwner: owner } : {})(promptVerifiedOwner(req, opts)),
|
|
1202
1214
|
...(resolvePromptHitlChannels(typeof body.sessionId === 'string' ? body.sessionId : '', opts) ?? {}),
|
|
1203
1215
|
...(effectiveSurface ? { toolSurface: effectiveSurface } : {}),
|
|
1204
|
-
...(opts.toolCwd ? { toolCwd: opts.toolCwd } : {}),
|
|
1216
|
+
...(projectContext?.cwd || opts.toolCwd ? { toolCwd: projectContext?.cwd ?? opts.toolCwd } : {}),
|
|
1217
|
+
...(projectContext?.instructions ? { projectInstructions: projectContext.instructions } : {}),
|
|
1205
1218
|
signal: turnAbortController.signal,
|
|
1206
1219
|
onTextDelta: dualEmitTextDelta,
|
|
1207
1220
|
onImageBlock: dualEmitImageBlock,
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* Query params (list):
|
|
21
21
|
* status=<MissionStatus> filter by status (active / planning / ...)
|
|
22
22
|
* goalSlug=<slug> filter by goal binding
|
|
23
|
+
* projectId=<id> filter by project association
|
|
23
24
|
*
|
|
24
25
|
* Cross-ref:
|
|
25
26
|
* src/task-orchestrator/store.ts (listMissions · getMission ·
|
|
@@ -53,6 +54,7 @@ export interface MissionCardWire {
|
|
|
53
54
|
status: MissionStatus;
|
|
54
55
|
priority: Mission['priority'];
|
|
55
56
|
goalSlug: string | null;
|
|
57
|
+
projectId?: string;
|
|
56
58
|
taskCount: number;
|
|
57
59
|
/** Counts so the PWA mission lane shows progress at a glance. */
|
|
58
60
|
taskStatusCounts: Record<string, number>;
|
|
@@ -85,6 +87,7 @@ export function summarise(mission: Mission, tasks: readonly Task[]): MissionCard
|
|
|
85
87
|
status: mission.status,
|
|
86
88
|
priority: mission.priority,
|
|
87
89
|
goalSlug: mission.goalSlug ?? null,
|
|
90
|
+
...(mission.projectId !== undefined ? { projectId: mission.projectId } : {}),
|
|
88
91
|
taskCount: tasks.length,
|
|
89
92
|
taskStatusCounts,
|
|
90
93
|
surfaceKindCounts,
|
|
@@ -103,9 +106,11 @@ export function handleMissionsList(
|
|
|
103
106
|
const url = new URL(req.url);
|
|
104
107
|
const statusParam = url.searchParams.get('status');
|
|
105
108
|
const goalSlug = url.searchParams.get('goalSlug') ?? undefined;
|
|
106
|
-
const
|
|
109
|
+
const projectId = url.searchParams.get('projectId') ?? undefined;
|
|
110
|
+
const filter: { status?: MissionStatus; goalSlug?: string; projectId?: string } = {};
|
|
107
111
|
if (statusParam && isMissionStatus(statusParam)) filter.status = statusParam;
|
|
108
112
|
if (goalSlug) filter.goalSlug = goalSlug;
|
|
113
|
+
if (projectId !== undefined) filter.projectId = projectId;
|
|
109
114
|
|
|
110
115
|
const store = new TaskStore();
|
|
111
116
|
try {
|