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
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { debug, redactSecretText } from '../../debug/log.js';
|
|
4
4
|
import { parseOwner, type ChecklistItem } from '../../release-loop/checklist.js';
|
|
5
5
|
import { canonicalSeatId } from '../../msg/msg-store.js';
|
|
6
|
+
import { listSubSeatCharters, type SubSeatCharter } from './sub-seat-charters.js';
|
|
6
7
|
|
|
7
8
|
export const SEATS = [
|
|
8
9
|
{ seat: 'OP', role: 'COO' }, { seat: 'TC', role: 'CTO' }, { seat: 'MK', role: 'CMO' }, { seat: 'UX', role: 'CXO' },
|
|
@@ -26,6 +27,7 @@ export interface SeatsSources {
|
|
|
26
27
|
checklist(): { current: ChecklistItem[]; all: ChecklistItem[] } | null;
|
|
27
28
|
/** `raisedBy.agent` of every open decision. */
|
|
28
29
|
openDecisionRaisers(): string[] | null;
|
|
30
|
+
charters?(): SubSeatCharter[] | null;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
export interface SeatRow {
|
|
@@ -36,6 +38,7 @@ export interface SeatRow {
|
|
|
36
38
|
blocked: Array<{ id: string; title: string; status: 'red' }> | null;
|
|
37
39
|
pendingDecisions: number | null;
|
|
38
40
|
checklist: { green: number; yellow: number; red: number; done: number } | null;
|
|
41
|
+
subSeats: Array<{ id: string; title: string; open: number | null; landed: number | null; blocked: Array<{ id: string; title: string }> | null }> | null;
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
function seatOf(value: string | undefined): string | null {
|
|
@@ -65,16 +68,37 @@ export async function buildSeatsBoard(date: string, sources: SeatsSources): Prom
|
|
|
65
68
|
try { checklist = sources.checklist(); } catch { checklist = null; }
|
|
66
69
|
let raisers: string[] | null = null;
|
|
67
70
|
try { raisers = sources.openDecisionRaisers(); } catch { raisers = null; }
|
|
71
|
+
let charters: SubSeatCharter[] | null = null;
|
|
72
|
+
try {
|
|
73
|
+
if (sources.charters) charters = sources.charters();
|
|
74
|
+
else {
|
|
75
|
+
let unreadable = false;
|
|
76
|
+
const listed = listSubSeatCharters(undefined, () => { unreadable = true; });
|
|
77
|
+
charters = unreadable ? null : listed;
|
|
78
|
+
}
|
|
79
|
+
} catch { charters = null; }
|
|
68
80
|
|
|
69
81
|
const owners = new Map<string, string>();
|
|
70
82
|
for (const item of checklist?.all ?? []) { const seat = seatOf(item.owner); if (seat) owners.set(item.id, seat); }
|
|
71
83
|
const ids = [...owners.keys()];
|
|
72
84
|
const landedBySeat = new Map<string, NonNullable<SeatRow['landed']>>();
|
|
85
|
+
const landedBySub = new Map<string, number>();
|
|
86
|
+
const subOwner = (owner: string | undefined, charter: SubSeatCharter): boolean => {
|
|
87
|
+
if (!owner) return false;
|
|
88
|
+
try { const parsed = parseOwner(owner); return owner === charter.id && parsed.seat === charter.seat && parsed.sub === charter.sub; }
|
|
89
|
+
catch { return false; }
|
|
90
|
+
};
|
|
91
|
+
const subOwners = new Map(checklist?.all.flatMap((item) => {
|
|
92
|
+
const charter = charters?.find((candidate) => subOwner(item.owner, candidate));
|
|
93
|
+
return charter ? [[item.id, charter.id] as const] : [];
|
|
94
|
+
}) ?? []);
|
|
73
95
|
for (const pr of merged ?? []) {
|
|
74
96
|
const id = checklistIdOf(pr, ids);
|
|
75
97
|
const seat = id ? owners.get(id) : undefined;
|
|
76
98
|
if (!seat) continue; // ⛔ not by commit author — every seat lands through the same account.
|
|
77
99
|
landedBySeat.set(seat, [...(landedBySeat.get(seat) ?? []), { pr: pr.number, title: clip(pr.title, 80), at: pr.mergedAt, checklistId: id }]);
|
|
100
|
+
const sub = id ? subOwners.get(id) : undefined;
|
|
101
|
+
if (sub) landedBySub.set(sub, (landedBySub.get(sub) ?? 0) + 1);
|
|
78
102
|
}
|
|
79
103
|
|
|
80
104
|
const seats = SEATS.map(({ seat, role }): SeatRow => {
|
|
@@ -91,6 +115,15 @@ export async function buildSeatsBoard(date: string, sources: SeatsSources): Prom
|
|
|
91
115
|
green: mine.filter((i) => i.status === 'green').length, yellow: mine.filter((i) => i.status === 'yellow').length,
|
|
92
116
|
red: mine.filter((i) => i.status === 'red').length, done: mine.filter((i) => i.status === 'done').length,
|
|
93
117
|
} : null,
|
|
118
|
+
subSeats: charters?.filter((charter) => charter.seat === seat).map((charter) => {
|
|
119
|
+
const items = checklist?.current.filter((item) => subOwner(item.owner, charter));
|
|
120
|
+
return {
|
|
121
|
+
id: charter.id, title: clip(charter.title, 80),
|
|
122
|
+
open: items ? items.filter((item) => item.status !== 'done').length : null,
|
|
123
|
+
landed: merged !== null && checklist !== null ? landedBySub.get(charter.id) ?? 0 : null,
|
|
124
|
+
blocked: items ? items.filter((item) => item.status === 'red').map((item) => ({ id: item.id, title: clip(item.title, 80) })) : null,
|
|
125
|
+
};
|
|
126
|
+
}) ?? null,
|
|
94
127
|
};
|
|
95
128
|
});
|
|
96
129
|
debug.log('ops.seats', 'built', {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { basename } from 'node:path';
|
|
2
|
+
import { debug } from '../../debug/log.js';
|
|
3
|
+
import { OUTPUT_KINDS } from '../../exec-requests/default-outputs.js';
|
|
4
|
+
import { listOutputs } from '../../outputs/ledger.js';
|
|
5
|
+
import { jsonResponse } from './json-response.js';
|
|
6
|
+
|
|
7
|
+
export interface OutputsDeps {
|
|
8
|
+
list?: typeof listOutputs;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function handleOutputsGet(req: Request, deps: OutputsDeps = {}): Response {
|
|
12
|
+
const params = new URL(req.url).searchParams;
|
|
13
|
+
const rawLimit = params.get('limit');
|
|
14
|
+
if (rawLimit !== null && (!/^[1-9]\d*$/.test(rawLimit) || Number(rawLimit) > 200)) {
|
|
15
|
+
return jsonResponse({ error: 'invalid_limit' }, 400);
|
|
16
|
+
}
|
|
17
|
+
const limit = rawLimit === null ? 50 : Number(rawLimit);
|
|
18
|
+
const rawSource = params.get('source');
|
|
19
|
+
if (rawSource !== null && rawSource !== 'exec' && rawSource !== 'field-reel' && rawSource !== 'field-feed') {
|
|
20
|
+
return jsonResponse({ error: 'invalid_source' }, 400);
|
|
21
|
+
}
|
|
22
|
+
const source = rawSource ?? undefined;
|
|
23
|
+
const rawSince = params.get('since');
|
|
24
|
+
if (rawSince !== null && (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/.test(rawSince)
|
|
25
|
+
|| !Number.isFinite(Date.parse(rawSince))
|
|
26
|
+
|| !Number.isFinite(Date.parse(`${rawSince.slice(0, 10)}T00:00:00Z`))
|
|
27
|
+
|| new Date(`${rawSince.slice(0, 10)}T00:00:00Z`).toISOString().slice(0, 10) !== rawSince.slice(0, 10))) {
|
|
28
|
+
return jsonResponse({ error: 'invalid_since' }, 400);
|
|
29
|
+
}
|
|
30
|
+
const since = rawSince ? new Date(rawSince).toISOString() : undefined;
|
|
31
|
+
const rows = (deps.list ?? listOutputs)({ limit, ...(source ? { source } : {}), ...(since ? { since } : {}) });
|
|
32
|
+
const outputs = rows.map(({ kind, title, path, url, source: entrySource, seat, at }) => ({
|
|
33
|
+
kind,
|
|
34
|
+
kindLabel: kind === 'file' ? '파일' : OUTPUT_KINDS[kind]?.cardTitle ?? '파일',
|
|
35
|
+
title,
|
|
36
|
+
...(path ? { fileName: basename(path) } : {}),
|
|
37
|
+
...(url ? { url } : {}),
|
|
38
|
+
source: entrySource,
|
|
39
|
+
...(seat ? { seat } : {}),
|
|
40
|
+
at,
|
|
41
|
+
}));
|
|
42
|
+
debug.log('outputs.route', 'listed', { count: outputs.length, source, limit });
|
|
43
|
+
return jsonResponse({ outputs });
|
|
44
|
+
}
|
|
@@ -6,12 +6,14 @@ import { resolveAttachmentPath } from '../../boot/attachment-store.js';
|
|
|
6
6
|
import { runGh } from '../../decisions/decision-cards.js';
|
|
7
7
|
import { openMsgStore, canonicalSeatId } from '../../msg/msg-store.js';
|
|
8
8
|
import { dispatchCeoTask, type CeoCommandDeps } from '../../seat-dispatch/ceo-commands.js';
|
|
9
|
+
import { acknowledgeSeatAnswers, askSeat, deliverSeatAnswers, parseSeatAsk, type SeatAskDeps } from '../../seat-dispatch/seat-ask.js';
|
|
9
10
|
import { getUserConfig } from '../../user-config.js';
|
|
10
11
|
import { effectiveInstanceRoot } from '../../instance/resolve.js';
|
|
11
12
|
import { submitIntakeWork } from '../../intake-plane/submit-intake-work.js';
|
|
12
13
|
import { parseSeatAddress, resolveSeat } from '../../seat-address/seat-address.js';
|
|
13
14
|
import trackData from '../../../scripts/coord-tracks.json';
|
|
14
15
|
import { jsonResponse } from './json-response.js';
|
|
16
|
+
import { publishInsideEvent } from './inside-events.js';
|
|
15
17
|
|
|
16
18
|
export const SEAT_REQUESTS_PATH = '/v1/seat-requests';
|
|
17
19
|
|
|
@@ -50,6 +52,7 @@ export interface SeatRequestsDeps {
|
|
|
50
52
|
resolveAttachment?: typeof resolveAttachmentPath;
|
|
51
53
|
dispatch?: typeof dispatchCeoTask;
|
|
52
54
|
ceoDeps?: () => CeoCommandDeps;
|
|
55
|
+
askDeps?: SeatAskDeps;
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
const seats = trackData.tracks.filter((entry): entry is typeof entry & { title: string } => 'title' in entry)
|
|
@@ -189,6 +192,18 @@ export async function handleSeatRequests(req: Request, deps: SeatRequestsDeps =
|
|
|
189
192
|
const path = file((deps.root ?? effectiveInstanceRoot)());
|
|
190
193
|
if (req.method === 'GET') {
|
|
191
194
|
const params = new URL(req.url).searchParams;
|
|
195
|
+
if (params.get('answers') === '1') {
|
|
196
|
+
const clientId = req.headers.get('x-seat-ask-client');
|
|
197
|
+
if (!clientId || !/^[a-f0-9-]{36}$/i.test(clientId)) return jsonResponse({ error: 'bad_request' }, 400);
|
|
198
|
+
const base = deps.askDeps;
|
|
199
|
+
const messages: Array<{ id: string; text: string; status: 'answered' | 'expired' }> = [];
|
|
200
|
+
await deliverSeatAnswers({ ...base, channel: 'pwa', clientId, send: async (origin, text) => {
|
|
201
|
+
if (origin.channel !== 'pwa' || origin.clientId !== clientId) return;
|
|
202
|
+
const match = /\(([^)]+)\)/.exec(text);
|
|
203
|
+
if (match) messages.push({ id: match[1]!, text, status: text.startsWith('CTO 답변') ? 'answered' : 'expired' });
|
|
204
|
+
} });
|
|
205
|
+
return jsonResponse({ items: messages });
|
|
206
|
+
}
|
|
192
207
|
const requestedSeat = params.get('seat');
|
|
193
208
|
const seat = requestedSeat ? requestSeat(requestedSeat) : undefined;
|
|
194
209
|
if (requestedSeat && !seat) return unknownSeat();
|
|
@@ -204,6 +219,19 @@ export async function handleSeatRequests(req: Request, deps: SeatRequestsDeps =
|
|
|
204
219
|
}
|
|
205
220
|
if (req.method !== 'POST') return jsonResponse({ error: 'method-not-allowed' }, 405);
|
|
206
221
|
|
|
222
|
+
if (new URL(req.url).searchParams.get('answers') === 'ack') {
|
|
223
|
+
const clientId = req.headers.get('x-seat-ask-client');
|
|
224
|
+
if (!clientId || !/^[a-f0-9-]{36}$/i.test(clientId)) return jsonResponse({ error: 'bad_request' }, 400);
|
|
225
|
+
let body: unknown;
|
|
226
|
+
try { body = await req.json(); } catch { return jsonResponse({ error: 'bad_request' }, 400); }
|
|
227
|
+
const ids = (body as { ids?: unknown } | null)?.ids;
|
|
228
|
+
if (!Array.isArray(ids) || ids.length > 100 || ids.some((id) => typeof id !== 'string' || !/^[a-f0-9-]{36}$/i.test(id))) {
|
|
229
|
+
return jsonResponse({ error: 'bad_request' }, 400);
|
|
230
|
+
}
|
|
231
|
+
acknowledgeSeatAnswers(clientId, ids as string[], deps.askDeps?.open);
|
|
232
|
+
return jsonResponse({ ok: true });
|
|
233
|
+
}
|
|
234
|
+
|
|
207
235
|
let body: unknown;
|
|
208
236
|
try { body = await req.json(); }
|
|
209
237
|
catch { return jsonResponse({ error: 'bad_request' }, 400); }
|
|
@@ -219,10 +247,22 @@ export async function handleSeatRequests(req: Request, deps: SeatRequestsDeps =
|
|
|
219
247
|
const prefix = parsed ? `@${parsed.seats.join(',')}` : '';
|
|
220
248
|
const firstAddress = parsed && input.text.startsWith(prefix)
|
|
221
249
|
&& (input.text.length === prefix.length || /[ \t\r\n]/.test(input.text[prefix.length]!)) ? parsed : null;
|
|
222
|
-
const address = input.seat ?? (firstAddress?.seats.length === 1 ? firstAddress.seats[0] : undefined)
|
|
250
|
+
const address = input.seat ?? (firstAddress?.seats.length === 1 ? firstAddress.seats[0] : undefined)
|
|
251
|
+
?? (parseSeatAsk(input.text) ? 'TC' : undefined);
|
|
223
252
|
const seat = address ? requestSeat(address) : undefined;
|
|
224
253
|
if (!seat) return unknownSeat();
|
|
225
|
-
const text = input.seat === undefined ? firstAddress
|
|
254
|
+
const text = input.seat === undefined ? (firstAddress?.body ?? input.text).trim() : input.text.trim();
|
|
255
|
+
if (canonicalSeatIdSafe(seat.id) === 'TC' && parseSeatAsk(text)) {
|
|
256
|
+
if (input.attachments !== undefined) return jsonResponse({ error: 'attachments-unsupported' }, 400);
|
|
257
|
+
const clientId = req.headers.get('x-seat-ask-client');
|
|
258
|
+
if (!clientId || !/^[a-f0-9-]{36}$/i.test(clientId)) return jsonResponse({ error: 'bad_request' }, 400);
|
|
259
|
+
let ask: string;
|
|
260
|
+
try {
|
|
261
|
+
ask = await askSeat(text, { channel: 'pwa', clientId }, (deps.ceoDeps ?? defaultCeoDeps)(),
|
|
262
|
+
deps.askDeps ?? { channel: 'pwa', send: async () => { throw new Error('PWA seat ask requires polling'); } });
|
|
263
|
+
} catch { return unavailable(); }
|
|
264
|
+
return jsonResponse({ reply: ask }, 202);
|
|
265
|
+
}
|
|
226
266
|
if (!text) {
|
|
227
267
|
debug.log('seat-address.pwa', 'rejected', { reason: 'empty-text', seat: seat.id });
|
|
228
268
|
return jsonResponse({ error: 'bad_request' }, 400);
|
|
@@ -304,6 +344,7 @@ export async function handleSeatRequests(req: Request, deps: SeatRequestsDeps =
|
|
|
304
344
|
};
|
|
305
345
|
try { persistOutcome(path, item, deps.append ?? append); }
|
|
306
346
|
catch { return unavailable(); }
|
|
347
|
+
publishInsideEvent({ kind: 'seat', seat: item.seat, receiptId: item.receiptId, status: item.status, ts: item.queuedAt });
|
|
307
348
|
return receipt(item);
|
|
308
349
|
}
|
|
309
350
|
let result: Awaited<ReturnType<typeof submitIntakeWork>>;
|
|
@@ -325,6 +366,7 @@ export async function handleSeatRequests(req: Request, deps: SeatRequestsDeps =
|
|
|
325
366
|
try { persistOutcome(path, item, deps.append ?? append); }
|
|
326
367
|
catch { return unavailable(); }
|
|
327
368
|
debug.log('seat-address.pwa', 'enqueued', { seat: seat.id, receiptId: item.receiptId });
|
|
369
|
+
publishInsideEvent({ kind: 'seat', seat: item.seat, receiptId: item.receiptId, status: item.status, ts: item.queuedAt });
|
|
328
370
|
return receipt(item);
|
|
329
371
|
})();
|
|
330
372
|
inFlight.set(lock, { payload, task });
|
|
@@ -18,11 +18,9 @@ import {
|
|
|
18
18
|
isHarnessSessionOrigin,
|
|
19
19
|
type SessionMeta,
|
|
20
20
|
} from '../../session/index.js';
|
|
21
|
-
import { existsSync, mkdirSync, readFileSync, renameSync, rmdirSync, statSync, writeFileSync } from 'node:fs';
|
|
22
|
-
import { join } from 'node:path';
|
|
23
|
-
import { randomUUID } from 'node:crypto';
|
|
24
21
|
import { getProject } from '../../project/project-store.js';
|
|
25
|
-
import { sessionRoot } from '../../session/index.js';
|
|
22
|
+
import { sessionRoot, updateSessionMeta } from '../../session/index.js';
|
|
23
|
+
import { debug } from '../../debug/log.js';
|
|
26
24
|
import { checkAuth, type MetaApiOpts } from './meta-api.js';
|
|
27
25
|
import { jsonResponse } from './http-server.js';
|
|
28
26
|
|
|
@@ -181,43 +179,24 @@ export async function handleSessionsStorePatch(req: Request, id: string, opts: M
|
|
|
181
179
|
return jsonResponse({ ok: false, error: 'invalid_project_id' }, 400);
|
|
182
180
|
}
|
|
183
181
|
const projectId = (body as { projectId: unknown }).projectId;
|
|
184
|
-
if (projectId !== null &&
|
|
182
|
+
if (projectId !== null && typeof projectId !== 'string') {
|
|
185
183
|
return jsonResponse({ ok: false, error: 'invalid_project_id' }, 400);
|
|
186
184
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const deadline = Date.now() + 10_000;
|
|
191
|
-
for (;;) {
|
|
192
|
-
try { mkdirSync(lock); break; }
|
|
193
|
-
catch {
|
|
194
|
-
if (!existsSync(lock)) continue;
|
|
195
|
-
try {
|
|
196
|
-
if (Date.now() - statSync(lock).mtimeMs > 30_000) { rmdirSync(lock); continue; }
|
|
197
|
-
} catch { continue; }
|
|
198
|
-
if (Date.now() >= deadline) throw new Error(`timed out acquiring lock ${lock}`);
|
|
199
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
try {
|
|
203
|
-
const path = join(root, 'index.json');
|
|
204
|
-
const entries = JSON.parse(readFileSync(path, 'utf8')) as SessionMeta[];
|
|
205
|
-
const pos = entries.findIndex((meta) => meta.id === id);
|
|
206
|
-
if (pos < 0) return jsonResponse({ ok: false, error: 'not_found' }, 404);
|
|
207
|
-
const meta = { ...entries[pos] };
|
|
208
|
-
if (projectId === null) delete meta.projectId;
|
|
209
|
-
else meta.projectId = projectId;
|
|
210
|
-
entries[pos] = meta;
|
|
211
|
-
const temp = `${path}.${process.pid}.${randomUUID().slice(0, 8)}.tmp`;
|
|
212
|
-
writeFileSync(temp, JSON.stringify(entries, null, 2) + '\n', 'utf8');
|
|
213
|
-
renameSync(temp, path);
|
|
214
|
-
return jsonResponse({ ok: true, meta }, 200);
|
|
215
|
-
} catch (error) {
|
|
216
|
-
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return jsonResponse({ ok: false, error: 'not_found' }, 404);
|
|
217
|
-
throw error;
|
|
218
|
-
} finally {
|
|
219
|
-
rmdirSync(lock);
|
|
185
|
+
// 모양은 맞는데 없는 프로젝트 = 찾을 수 없음(404) — 요청 형식 오류(400)와 가른다(IA1b).
|
|
186
|
+
if (projectId !== null && !getProject(projectId)) {
|
|
187
|
+
return jsonResponse({ ok: false, error: 'project-not-found' }, 404);
|
|
220
188
|
}
|
|
189
|
+
|
|
190
|
+
let previous: string | null = null;
|
|
191
|
+
// 잠금 안에서 최신 목록 위에 고친다 — 동시 appendMessage 가 이 projectId 를 덮지 않는다.
|
|
192
|
+
const meta = updateSessionMeta(id, (m) => {
|
|
193
|
+
previous = m.projectId ?? null;
|
|
194
|
+
if (projectId === null) delete m.projectId;
|
|
195
|
+
else m.projectId = projectId;
|
|
196
|
+
}, sessionRoot());
|
|
197
|
+
if (!meta) return jsonResponse({ ok: false, error: 'not_found' }, 404);
|
|
198
|
+
debug.log('project', 'assign', { sessionId: id, projectId, previous });
|
|
199
|
+
return jsonResponse({ ok: true, meta }, 200);
|
|
221
200
|
}
|
|
222
201
|
|
|
223
202
|
/** DELETE /v1/sessions/store/:id — on-disk 세션 삭제(index.json + <id>.jsonl 제거).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { debug } from '../../debug/log.js';
|
|
4
|
+
|
|
5
|
+
export interface SubSeatCharter { id: string; seat: string; sub: string; title: string }
|
|
6
|
+
|
|
7
|
+
export function listSubSeatCharters(root = join(import.meta.dir, '..', '..', '..', 'docs', 'roles'), onUnreadable?: () => void): SubSeatCharter[] {
|
|
8
|
+
try {
|
|
9
|
+
readdirSync(root);
|
|
10
|
+
const charters: SubSeatCharter[] = [];
|
|
11
|
+
for (const seat of ['OP', 'MK', 'TC', 'UX']) {
|
|
12
|
+
let entries;
|
|
13
|
+
try { entries = readdirSync(join(root, seat), { withFileTypes: true }); }
|
|
14
|
+
catch (error) {
|
|
15
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') continue;
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
if (!entry.isFile() || !/^[a-z][a-z0-9-]{0,31}\.md$/.test(entry.name)) continue;
|
|
20
|
+
const sub = entry.name.slice(0, -3);
|
|
21
|
+
const id = `${seat}/${sub}`;
|
|
22
|
+
const content = readFileSync(join(root, seat, entry.name), 'utf8');
|
|
23
|
+
const heading = content.split(/\r?\n/).find((line) => line.startsWith('# '));
|
|
24
|
+
const title = heading?.slice(2).startsWith(`${id} — `) ? heading.slice(2 + id.length + 3).trim() || id : id;
|
|
25
|
+
charters.push({ id, seat, sub, title });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return charters.sort((a, b) => a.id.localeCompare(b.id));
|
|
29
|
+
} catch (error) {
|
|
30
|
+
debug.log('ops.seats', 'charters-unreadable', { root, error: error instanceof Error ? error.message : String(error) });
|
|
31
|
+
onUnreadable?.();
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -78,6 +78,8 @@ interface CreateTabBody {
|
|
|
78
78
|
kind?: string;
|
|
79
79
|
id?: string;
|
|
80
80
|
label?: string;
|
|
81
|
+
/** Conversation owning a newly created webterm. */
|
|
82
|
+
sessionId?: string;
|
|
81
83
|
/** Kind-specific factory opts (passed through to the factory). */
|
|
82
84
|
kindOpts?: Record<string, unknown>;
|
|
83
85
|
/** When true (default), supervisor.startTab is called immediately
|
|
@@ -95,7 +97,7 @@ function buildTabSpec(body: CreateTabBody, id: string): { spec: TabSpec; reason?
|
|
|
95
97
|
case 'chat':
|
|
96
98
|
return { spec: createChatTabSpec(opts as Parameters<typeof createChatTabSpec>[0]) };
|
|
97
99
|
case 'webterm':
|
|
98
|
-
return { spec: createWebtermTabSpec(opts as Parameters<typeof createWebtermTabSpec>[0]) };
|
|
100
|
+
return { spec: createWebtermTabSpec({ ...opts, sessionId: body.sessionId ?? opts.sessionId } as Parameters<typeof createWebtermTabSpec>[0]) };
|
|
99
101
|
case 'daemon':
|
|
100
102
|
return { spec: createDaemonTabSpec(opts as Parameters<typeof createDaemonTabSpec>[0]) };
|
|
101
103
|
case 'pwa-host':
|
package/src/nexus/api/trace.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { checkAuth, type MetaApiOpts } from './meta-api.js';
|
|
|
9
9
|
import { jsonResponse } from './json-response.js';
|
|
10
10
|
import { runLedgerDir, runLedgerPath } from '../../self-implement/run-ledger.js';
|
|
11
11
|
import { scanStoresForRun } from './trace-run-scan.js';
|
|
12
|
+
import { listSessions } from '../../session/index.js';
|
|
12
13
|
|
|
13
14
|
export type TraceLevel = 'L0' | 'L1' | 'L2' | 'L3';
|
|
14
15
|
export interface TraceEvent {
|
|
@@ -17,6 +18,7 @@ export interface TraceEvent {
|
|
|
17
18
|
universe: string;
|
|
18
19
|
machine?: string;
|
|
19
20
|
runId?: string;
|
|
21
|
+
projectId?: string;
|
|
20
22
|
parentRunId?: string;
|
|
21
23
|
phase?: string;
|
|
22
24
|
shard?: string;
|
|
@@ -83,6 +85,7 @@ function eventFor(row: LogStoreRow): TraceEvent {
|
|
|
83
85
|
id: evidenceRef(universe, row.id), ts: row.ts, universe,
|
|
84
86
|
...(machine ? { machine } : {}),
|
|
85
87
|
...(runId ? { runId } : {}),
|
|
88
|
+
...(text(data.projectId) ? { projectId: text(data.projectId) } : {}),
|
|
86
89
|
...(text(data.parentRunId) ? { parentRunId: text(data.parentRunId) } : {}),
|
|
87
90
|
...(text(data.phase) ? { phase: text(data.phase) } : {}),
|
|
88
91
|
...(text(data.shard) ? { shard: text(data.shard) } : {}),
|
|
@@ -259,11 +262,15 @@ function options(url: URL): { level: TraceLevel; limit: number; from?: number; t
|
|
|
259
262
|
if (from === null || to === null || (from !== undefined && to !== undefined && from > to)) return { level, limit: n, error: 'invalid time range' };
|
|
260
263
|
return { level, limit: Math.min(n, TRACE_LIMIT), ...(from !== undefined ? { from } : {}), ...(to !== undefined ? { to } : {}) };
|
|
261
264
|
}
|
|
262
|
-
function matches(row: LogStoreRow, url: URL): boolean {
|
|
265
|
+
function matches(row: LogStoreRow, url: URL, projectSessions?: ReadonlySet<string>): boolean {
|
|
263
266
|
const data = dataFor(row);
|
|
264
267
|
const runId = url.searchParams.get('runId');
|
|
265
268
|
const universe = url.searchParams.get('universe');
|
|
266
269
|
const kind = url.searchParams.get('kind');
|
|
270
|
+
const projectId = url.searchParams.get('projectId');
|
|
271
|
+
if (projectId !== null && (Object.hasOwn(data, 'projectId')
|
|
272
|
+
? data.projectId !== projectId
|
|
273
|
+
: !projectSessions?.has(row.session_id ?? '') && !projectSessions?.has(text(data.sessionId) ?? ''))) return false;
|
|
267
274
|
const q = url.searchParams.get('q')?.toLowerCase();
|
|
268
275
|
if (runId && data.runId !== runId && data.run_id !== runId) return false;
|
|
269
276
|
if (universe && row.instance !== universe) return false;
|
|
@@ -295,6 +302,8 @@ function findRunUniverse(runId: string, selected: readonly string[], deps: Trace
|
|
|
295
302
|
export function handleTrace(req: Request, opts: MetaApiOpts, deps: TraceDeps = {}): Response {
|
|
296
303
|
if (!checkAuth(req, opts)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
297
304
|
const url = new URL(req.url);
|
|
305
|
+
const projectId = url.searchParams.get('projectId');
|
|
306
|
+
const projectSessions = projectId === null ? undefined : new Set(listSessions({ projectId }).map(session => session.id));
|
|
298
307
|
const parsed = options(url);
|
|
299
308
|
if (parsed.error) return jsonResponse({ ok: false, error: 'bad_request', reason: parsed.error }, 400);
|
|
300
309
|
const names = storeNames(url, deps);
|
|
@@ -315,7 +324,8 @@ export function handleTrace(req: Request, opts: MetaApiOpts, deps: TraceDeps = {
|
|
|
315
324
|
for (const entry of stores) {
|
|
316
325
|
if (!entry.store) { failures.push({ name: entry.name, reason: entry.error ?? 'log-store-unavailable' }); continue; }
|
|
317
326
|
try {
|
|
318
|
-
const page = entry.store.aggregateRuns({ sinceMs: parsed.from, untilMs: parsed.to
|
|
327
|
+
const page = entry.store.aggregateRuns({ sinceMs: parsed.from, untilMs: parsed.to,
|
|
328
|
+
...(projectId !== null ? { projectId, projectSessionIds: [...projectSessions!] } : {}) }, RUN_LIMIT);
|
|
319
329
|
if (page.length >= RUN_LIMIT) runLimitReached = true;
|
|
320
330
|
runs.push(...page.map((run) => ({ ...run, universe: entry.name })));
|
|
321
331
|
opened++;
|
|
@@ -334,7 +344,8 @@ export function handleTrace(req: Request, opts: MetaApiOpts, deps: TraceDeps = {
|
|
|
334
344
|
for (const entry of stores) {
|
|
335
345
|
if (!entry.store) { failures.push({ name: entry.name, reason: entry.error ?? 'log-store-unavailable' }); continue; }
|
|
336
346
|
try {
|
|
337
|
-
const query: LogQuery = { sinceMs: parsed.from, untilMs: parsed.to, limit: TRACE_LIMIT + 1
|
|
347
|
+
const query: LogQuery = { sinceMs: parsed.from, untilMs: parsed.to, limit: TRACE_LIMIT + 1,
|
|
348
|
+
...(projectId !== null ? { projectId, projectSessionIds: [...projectSessions!] } : {}) };
|
|
338
349
|
const search = url.searchParams.get('q');
|
|
339
350
|
if (search) query.grep = search;
|
|
340
351
|
// Restrict a run before paging; other JSON-only filters still apply to the bounded window.
|
|
@@ -349,7 +360,7 @@ export function handleTrace(req: Request, opts: MetaApiOpts, deps: TraceDeps = {
|
|
|
349
360
|
const runId = url.searchParams.get('runId');
|
|
350
361
|
let resolution: { universe?: string; checked: number; truncated?: boolean; unresolved?: boolean } | undefined;
|
|
351
362
|
let resolvedFrom: 'ledger' | 'log-scan' | undefined;
|
|
352
|
-
if ((parsed.level === 'L2' || parsed.level === 'L3') && runId && !rows.some((row) => matches(row, url)) && !requestedUniverse) {
|
|
363
|
+
if ((parsed.level === 'L2' || parsed.level === 'L3') && runId && !rows.some((row) => matches(row, url, projectSessions)) && !requestedUniverse) {
|
|
353
364
|
// A store with no log db at all («has no log store yet» — e.g. the daemon's own tree-derived universe) cannot
|
|
354
365
|
// hold the run, so it must not block the ledger lookup. A store that exists but failed to open/read still does:
|
|
355
366
|
// «could not read» is never answered as «not there». The reply keeps `failedStores` either way.
|
|
@@ -379,7 +390,8 @@ export function handleTrace(req: Request, opts: MetaApiOpts, deps: TraceDeps = {
|
|
|
379
390
|
if (!entry?.store) return jsonResponse({ ok: false, error: 'log-store-unavailable', failedStores: [{ name, reason: entry?.error ?? 'log-store-unavailable' }] }, 503);
|
|
380
391
|
stores.push(entry);
|
|
381
392
|
try {
|
|
382
|
-
const query: LogQuery = { sinceMs: parsed.from, untilMs: parsed.to, limit: TRACE_LIMIT + 1
|
|
393
|
+
const query: LogQuery = { sinceMs: parsed.from, untilMs: parsed.to, limit: TRACE_LIMIT + 1,
|
|
394
|
+
...(projectId !== null ? { projectId, projectSessionIds: [...projectSessions!] } : {}) };
|
|
383
395
|
const search = url.searchParams.get('q');
|
|
384
396
|
if (search) query.grep = search;
|
|
385
397
|
const page = entry.store.queryTraceRun(runId, query);
|
|
@@ -388,7 +400,7 @@ export function handleTrace(req: Request, opts: MetaApiOpts, deps: TraceDeps = {
|
|
|
388
400
|
} catch (e) { return jsonResponse({ ok: false, error: 'log-store-unavailable', failedStores: [{ name, reason: e instanceof Error ? e.message : String(e) }] }, 503); }
|
|
389
401
|
}
|
|
390
402
|
}
|
|
391
|
-
const filtered = rows.filter((row) => matches(row, url)).sort(sortRows);
|
|
403
|
+
const filtered = rows.filter((row) => matches(row, url, projectSessions)).sort(sortRows);
|
|
392
404
|
const trace = buildTrace(filtered.slice(0, parsed.limit), parsed.level, filtered.length > parsed.limit || candidateLimitReached || failures.length > 0 || resolution?.truncated === true);
|
|
393
405
|
try { (deps.queryLog ?? ((details) => debug.log('logs.trace', 'query', details)))({ stores: names, level: parsed.level, count: trace.events.length, truncated: trace.truncated, mode: 'rows', runs: trace.nodes.filter((node) => node.level === 'L1' && node.count > 0).length }); } catch { /* query logging must not block reads */ }
|
|
394
406
|
return jsonResponse({ ok: true, ...trace, stores: names, registeredStores: registeredStoreCount(deps), ...(resolution ? resolution.universe ? { resolvedFrom, runUniverse: resolution.universe, ...(resolvedFrom === 'log-scan' ? { checked: resolution.checked } : {}) } : { runUniverse: resolution.truncated || resolution.unresolved ? 'unresolved' as const : 'not-found' as const, checked: resolution.checked } : {}), ...(failures.length ? { failedStores: failures } : {}) }, 200);
|
|
@@ -73,6 +73,7 @@ export function publishWorkflowRunEvent(
|
|
|
73
73
|
const detail: Record<string, unknown> = {
|
|
74
74
|
runId: ctx.runId,
|
|
75
75
|
workflowName: ctx.workflowName,
|
|
76
|
+
...(evt.mode !== undefined ? { mode: evt.mode } : {}),
|
|
76
77
|
};
|
|
77
78
|
if (evt.type === 'node_start' || evt.type === 'node_skipped' || evt.type === 'node_done') {
|
|
78
79
|
detail.nodeId = evt.nodeId;
|
|
@@ -40,8 +40,12 @@ import {
|
|
|
40
40
|
parseWorkflowYaml,
|
|
41
41
|
runWorkflow,
|
|
42
42
|
saveWorkflow,
|
|
43
|
+
topoSort,
|
|
43
44
|
type WorkflowDeps,
|
|
44
45
|
type WorkflowEvent,
|
|
46
|
+
type WorkflowRunMode,
|
|
47
|
+
type NodeOutput,
|
|
48
|
+
type RunWorkflowOpts,
|
|
45
49
|
} from '../../workflow-runtime/index.js';
|
|
46
50
|
import { buildRunCft, buildRunSkill } from '../../workflow-runtime/deps-bridge.js';
|
|
47
51
|
import {
|
|
@@ -59,6 +63,7 @@ import { runApprovalAcrossChannels } from './workflow-approval-multi-channel.js'
|
|
|
59
63
|
interface RunRecord {
|
|
60
64
|
runId: string;
|
|
61
65
|
workflowName: string;
|
|
66
|
+
mode: WorkflowRunMode;
|
|
62
67
|
startedAt: number;
|
|
63
68
|
events: WorkflowEvent[];
|
|
64
69
|
/** Settled state: undefined while running, true on workflow_done,
|
|
@@ -384,10 +389,51 @@ export async function handleWorkflowRunStart(
|
|
|
384
389
|
// so the PWA "▶ Run now" button runs the dependent chain straight
|
|
385
390
|
// through. Default false preserves the production wire.
|
|
386
391
|
const dryRun: boolean = Boolean(body && typeof body === 'object' && (body as { dryRun?: unknown }).dryRun === true);
|
|
392
|
+
const input = body && typeof body === 'object' ? body as Record<string, unknown> : {};
|
|
393
|
+
const { onlyNode, fromNode, fromRunId } = input;
|
|
394
|
+
if ('usePins' in input || (onlyNode !== undefined && (fromNode !== undefined || fromRunId !== undefined))
|
|
395
|
+
|| (onlyNode !== undefined && (typeof onlyNode !== 'string' || !onlyNode.trim()))
|
|
396
|
+
|| (fromNode !== undefined && (typeof fromNode !== 'string' || !fromNode.trim()))
|
|
397
|
+
|| (fromRunId !== undefined && (typeof fromRunId !== 'string' || !fromRunId.trim()))
|
|
398
|
+
|| (fromNode === undefined) !== (fromRunId === undefined)
|
|
399
|
+
|| (input.mode !== undefined && input.mode !== 'test')) {
|
|
400
|
+
return jsonResponse({ error: 'bad_request', reason: 'invalid run selection' }, 400);
|
|
401
|
+
}
|
|
402
|
+
if ((onlyNode && !entry.definition.nodes.some(n => n.id === onlyNode))
|
|
403
|
+
|| (fromNode && !entry.definition.nodes.some(n => n.id === fromNode))) {
|
|
404
|
+
return jsonResponse({ error: 'bad_request', reason: 'unknown selected node' }, 400);
|
|
405
|
+
}
|
|
406
|
+
let previousOutputs: Record<string, NodeOutput> | undefined;
|
|
407
|
+
if (typeof fromRunId === 'string') {
|
|
408
|
+
const previous = RUN_REGISTRY.get(fromRunId);
|
|
409
|
+
if (previous) {
|
|
410
|
+
if (previous.workflowName !== name || previous.ok === undefined) {
|
|
411
|
+
return jsonResponse({ error: 'bad_request', reason: 'source run must be settled for this workflow' }, 400);
|
|
412
|
+
}
|
|
413
|
+
const terminal = previous.events.find(e => e.type === 'workflow_done' || e.type === 'workflow_failed');
|
|
414
|
+
previousOutputs = terminal?.type === 'workflow_done' ? terminal.outputs
|
|
415
|
+
: terminal?.type === 'workflow_failed' ? terminal.partial : {};
|
|
416
|
+
} else {
|
|
417
|
+
const disk = readRunOutputSnapshot(fromRunId);
|
|
418
|
+
if (!disk || disk.workflowName !== name || (disk.status !== 'done' && disk.status !== 'failed')) {
|
|
419
|
+
return jsonResponse({ error: 'bad_request', reason: 'source run must be settled for this workflow' }, 400);
|
|
420
|
+
}
|
|
421
|
+
previousOutputs = disk.outputs;
|
|
422
|
+
}
|
|
423
|
+
let order: string[];
|
|
424
|
+
try { order = topoSort(entry.definition.nodes); }
|
|
425
|
+
catch { return jsonResponse({ error: 'bad_request', reason: 'invalid workflow topology' }, 400); }
|
|
426
|
+
const upstream = order.slice(0, order.indexOf(fromNode as string));
|
|
427
|
+
if (upstream.some(id => previousOutputs?.[id] === undefined)) {
|
|
428
|
+
return jsonResponse({ error: 'bad_request', reason: 'source run missing upstream outputs' }, 400);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
const mode: WorkflowRunMode = input.mode === 'test' ? 'test' : onlyNode ? 'only' : fromNode ? 'from' : 'full';
|
|
387
432
|
const runId = `wf-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
388
433
|
const record: RunRecord = {
|
|
389
434
|
runId,
|
|
390
435
|
workflowName: name,
|
|
436
|
+
mode,
|
|
391
437
|
startedAt: Date.now(),
|
|
392
438
|
events: [],
|
|
393
439
|
ok: undefined,
|
|
@@ -400,10 +446,14 @@ export async function handleWorkflowRunStart(
|
|
|
400
446
|
void (async () => {
|
|
401
447
|
const deps = buildDefaultWorkflowDeps({ runId });
|
|
402
448
|
try {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
449
|
+
const runOpts: RunWorkflowOpts = {
|
|
450
|
+
workflow: entry.definition, arguments: args, runId, dryRun, mode,
|
|
451
|
+
...(typeof onlyNode === 'string' ? { onlyNode } : {}),
|
|
452
|
+
...(typeof fromNode === 'string' ? { fromNode } : {}),
|
|
453
|
+
...(previousOutputs ? { previousOutputs } : {}),
|
|
454
|
+
};
|
|
455
|
+
for await (const runtimeEvent of runWorkflow(runOpts, deps)) {
|
|
456
|
+
const evt = { ...runtimeEvent, mode };
|
|
407
457
|
record.events.push(evt);
|
|
408
458
|
// §15.8(b) — fan into NexusEventBus → PWA invalidates queries
|
|
409
459
|
// on push instead of polling. No-op when bus is unwired
|
|
@@ -423,13 +473,14 @@ export async function handleWorkflowRunStart(
|
|
|
423
473
|
type: 'workflow_failed' as const,
|
|
424
474
|
error: err instanceof Error ? err.message : String(err),
|
|
425
475
|
partial: {},
|
|
476
|
+
mode,
|
|
426
477
|
};
|
|
427
478
|
record.events.push(failEvt);
|
|
428
479
|
publishWorkflowRunEvent({ runId, workflowName: name }, failEvt);
|
|
429
480
|
}
|
|
430
481
|
})();
|
|
431
482
|
|
|
432
|
-
return jsonResponse({ ok: true, runId }, 202);
|
|
483
|
+
return jsonResponse({ ok: true, runId, mode }, 202);
|
|
433
484
|
}
|
|
434
485
|
|
|
435
486
|
export function handleWorkflowRunGet(
|
|
@@ -444,6 +495,7 @@ export function handleWorkflowRunGet(
|
|
|
444
495
|
{
|
|
445
496
|
runId: rec.runId,
|
|
446
497
|
workflowName: rec.workflowName,
|
|
498
|
+
mode: rec.mode,
|
|
447
499
|
startedAt: rec.startedAt,
|
|
448
500
|
ok: rec.ok,
|
|
449
501
|
events: rec.events,
|
|
@@ -597,6 +649,21 @@ interface DiskRunSummary {
|
|
|
597
649
|
* enough that abandoned runs don't pollute the list across sessions. */
|
|
598
650
|
const STALE_RUNNING_AFTER_MS = 30 * 60 * 1000;
|
|
599
651
|
|
|
652
|
+
function readRunOutputSnapshot(runId: string): {
|
|
653
|
+
workflowName: string;
|
|
654
|
+
status: string;
|
|
655
|
+
outputs: Record<string, NodeOutput>;
|
|
656
|
+
} | null {
|
|
657
|
+
if (!/^wf-[A-Za-z0-9-]+$/.test(runId) || runId.includes('..')) return null;
|
|
658
|
+
try {
|
|
659
|
+
const parsed = JSON.parse(readFileSync(join(workflowsRunsRoot(), runId, 'run.json'), 'utf-8')) as {
|
|
660
|
+
workflowName?: string; status?: string; outputs?: Record<string, NodeOutput>;
|
|
661
|
+
};
|
|
662
|
+
if (!parsed.workflowName || !parsed.status || !parsed.outputs || typeof parsed.outputs !== 'object') return null;
|
|
663
|
+
return { workflowName: parsed.workflowName, status: parsed.status, outputs: parsed.outputs };
|
|
664
|
+
} catch { return null; }
|
|
665
|
+
}
|
|
666
|
+
|
|
600
667
|
/** Read `<root>/<runId>/run.json` and translate into the same shape as
|
|
601
668
|
* GET /runs/<id> serves from memory. Returns null when the file is
|
|
602
669
|
* missing or unreadable. Events are reconstructed minimally from the
|
|
@@ -608,6 +675,7 @@ function loadRunFromDisk(runId: string): {
|
|
|
608
675
|
ok: boolean | undefined;
|
|
609
676
|
events: WorkflowEvent[];
|
|
610
677
|
outputs: Record<string, unknown>;
|
|
678
|
+
mode?: WorkflowRunMode;
|
|
611
679
|
} | null {
|
|
612
680
|
if (!runId || runId.includes('/') || runId.includes('..')) return null;
|
|
613
681
|
const root = workflowsRunsRoot();
|
|
@@ -623,6 +691,7 @@ function loadRunFromDisk(runId: string): {
|
|
|
623
691
|
completedAt?: number;
|
|
624
692
|
ok?: boolean;
|
|
625
693
|
status?: string;
|
|
694
|
+
mode?: WorkflowRunMode;
|
|
626
695
|
outputs?: Record<string, { output?: unknown }>;
|
|
627
696
|
};
|
|
628
697
|
if (!parsed.runId || !parsed.workflowName) return null;
|
|
@@ -634,7 +703,8 @@ function loadRunFromDisk(runId: string): {
|
|
|
634
703
|
// so a polling client still sees the node_done sequence even
|
|
635
704
|
// though the live run.json doesn't store events.
|
|
636
705
|
const events: WorkflowEvent[] = [];
|
|
637
|
-
events.push({ type: 'workflow_start', workflow: parsed.workflowName, runId: parsed.runId
|
|
706
|
+
events.push({ type: 'workflow_start', workflow: parsed.workflowName, runId: parsed.runId,
|
|
707
|
+
...(parsed.mode !== undefined ? { mode: parsed.mode } : {}) });
|
|
638
708
|
const nodesDir = join(runDir, 'nodes');
|
|
639
709
|
// Iterate `parsed.outputs` keys instead of `readdirSync(nodesDir)`
|
|
640
710
|
// so the reconstructed node_done sequence is in execution order
|
|
@@ -673,6 +743,7 @@ function loadRunFromDisk(runId: string): {
|
|
|
673
743
|
events.push({
|
|
674
744
|
type: 'node_done',
|
|
675
745
|
nodeId,
|
|
746
|
+
...(parsed.mode !== undefined ? { mode: parsed.mode } : {}),
|
|
676
747
|
result: {
|
|
677
748
|
ok: nodeData.ok,
|
|
678
749
|
output: nodeData.output ?? '',
|
|
@@ -684,6 +755,7 @@ function loadRunFromDisk(runId: string): {
|
|
|
684
755
|
if (parsed.status === 'done') {
|
|
685
756
|
events.push({
|
|
686
757
|
type: 'workflow_done',
|
|
758
|
+
...(parsed.mode !== undefined ? { mode: parsed.mode } : {}),
|
|
687
759
|
outputs: Object.fromEntries(
|
|
688
760
|
Object.entries(parsed.outputs ?? {}).map(([k, v]) => [
|
|
689
761
|
k,
|
|
@@ -694,6 +766,7 @@ function loadRunFromDisk(runId: string): {
|
|
|
694
766
|
} else if (parsed.status === 'failed') {
|
|
695
767
|
events.push({
|
|
696
768
|
type: 'workflow_failed',
|
|
769
|
+
...(parsed.mode !== undefined ? { mode: parsed.mode } : {}),
|
|
697
770
|
error: 'failed (see node events)',
|
|
698
771
|
partial: Object.fromEntries(
|
|
699
772
|
Object.entries(parsed.outputs ?? {}).map(([k, v]) => [
|
|
@@ -706,6 +779,7 @@ function loadRunFromDisk(runId: string): {
|
|
|
706
779
|
return {
|
|
707
780
|
runId: parsed.runId,
|
|
708
781
|
workflowName: parsed.workflowName,
|
|
782
|
+
...(parsed.mode !== undefined ? { mode: parsed.mode } : {}),
|
|
709
783
|
startedAt: parsed.startedAt ?? 0,
|
|
710
784
|
ok: parsed.status === 'done' ? true : parsed.status === 'failed' ? false : undefined,
|
|
711
785
|
events,
|