elanous 0.2.9 → 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/5845-e6c003ce8d5fd36a.js +1 -0
- 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-f972fc1c00a62e88.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-adfbd2ba9598e59a.js → page-35414e0a007b4082.js} +1 -1
- 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 -0
- package/apps/pwa/out/ops/seats/index.txt +30 -0
- 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 -0
- package/apps/pwa/out/today/index.txt +33 -0
- 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/field/field-feed.yaml +2 -0
- package/graphs/implement-loop.yaml +1 -1
- 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/card-followup/graphs/run-step.ts +48 -13
- package/plugins/doc-draft/graphs/doc-draft.yaml +3 -3
- package/plugins/doc-draft/graphs/run-step.ts +13 -6
- 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/ci-pwa-build-gate.ts +160 -0
- 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 +54 -8
- package/scripts/coord-digest.ts +199 -0
- package/scripts/coord-post.sh +60 -3
- 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/install.ps1 +68 -9
- package/scripts/install.sh +39 -12
- package/scripts/lib/pwa-scenarios/scenarios.ts +20 -0
- package/scripts/lib/tui-regress-checks.ts +146 -0
- package/scripts/marketing/measure-site-numbers.ts +169 -0
- package/scripts/measure-gate-shards.ts +309 -0
- package/scripts/memory-lifecycle-cycle.ts +2 -2
- package/scripts/mission-request-judge.ts +31 -1
- package/scripts/morning-report.ts +2 -2
- package/scripts/opportunity-scan.ts +1 -1
- package/scripts/ops-now-probe.ts +327 -0
- package/scripts/publish-internal-dist.ts +11 -1
- package/scripts/release-loop/auto-approve-node.ts +21 -4
- package/scripts/release-loop/cut-branch.ts +84 -0
- package/scripts/release-loop/cutoff.ts +19 -8
- 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/ops-upgrade-node.ts +72 -16
- package/scripts/release-loop/release-readiness.ts +9 -0
- 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 +112 -13
- package/scripts/repo-watch-cycle.ts +1 -1
- package/scripts/retro-cycle.ts +2 -2
- package/scripts/schedule-health-report.ts +1 -1
- package/scripts/signal-digest-cycle.ts +2 -7
- package/scripts/signal-digest-photo.ts +11 -0
- package/scripts/storyboard/storyboard.ts +5 -161
- package/scripts/tech1-public-measure.ts +94 -0
- package/scripts/test-diet/lib.ts +30 -1
- package/scripts/test-diet/node.ts +83 -8
- package/scripts/test-timeout-audit.ts +114 -0
- package/scripts/tree-sync-alert.ts +1 -1
- package/scripts/tui-regress.ts +71 -0
- package/scripts/ux/demo-rehearsal.ts +243 -0
- package/scripts/ux/lib/rehearsal-verdict.ts +73 -0
- package/scripts/waitlist-daily-digest.ts +1 -1
- 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/explainer-video/SKILL.md +4 -0
- package/skills/explainer-video/engine/reel.mjs +18 -13
- package/skills/explainer-video/engine/reel.sh +24 -5
- package/skills/explainer-video/engine/stitch.mjs +145 -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 +36 -0
- package/skills/pitch-deck/template.html +80 -0
- 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/codex-approval-adapter.ts +9 -3
- package/src/acp/core-turn-bridge.ts +117 -18
- package/src/acp/fact-question.ts +11 -0
- package/src/acp/server.ts +53 -9
- package/src/acp/tool-approval.ts +126 -0
- package/src/acp/turn-runner.ts +36 -0
- package/src/agent/monad-agent-turn.ts +8 -0
- 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/ask-user-question/pending-questions.ts +25 -10
- package/src/ask-user-question/types.ts +9 -0
- package/src/auth/setup-link-tokens.ts +16 -5
- package/src/autopilot/build/integrity-gate.ts +12 -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 +8 -0
- package/src/boot/daemon-runtime.ts +9 -3
- package/src/boot/daemon-tools/index.ts +8 -0
- package/src/boot/daemon-tools/types.ts +2 -0
- package/src/boot/daemon-tools/web-search.ts +4 -0
- package/src/card-followup/core.ts +109 -0
- package/src/chat/ctrl-c-in-input.ts +14 -0
- package/src/chat/index.ts +53 -0
- package/src/chat/pickers/state.ts +6 -2
- package/src/cli/agent-cli.ts +7 -0
- package/src/cli/decisions-cli.ts +25 -3
- package/src/cli/doctor-bundle-upload.ts +68 -0
- package/src/cli/doctor-cli.ts +38 -4
- 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/ops-cli.ts +20 -0
- package/src/cli/persona-cli.ts +90 -4
- package/src/cli/plugin-cli.ts +31 -22
- package/src/cli/pod-cli.ts +61 -2
- package/src/cli/pr-cli.ts +82 -17
- package/src/cli/pty-drive-cli.ts +41 -7
- package/src/cli/pty-drive-verdict.ts +40 -0
- package/src/cli/pwa-stop.ts +163 -13
- package/src/cli/pwa-test.ts +3 -0
- package/src/cli/release-cli.ts +80 -24
- package/src/cli/self-update.ts +14 -0
- package/src/cli/setup-cli.ts +43 -1
- package/src/cli/skills-cli.ts +17 -1
- package/src/cli/storyboard-cli.ts +37 -0
- package/src/cli/test-state-dir-flag.ts +11 -4
- package/src/connectors/linear.ts +146 -0
- 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 +115 -0
- package/src/context-bus/external-events.ts +52 -0
- package/src/context-bus/long-term-memory.ts +108 -0
- package/src/dashboard/dashboard-boot-fixture.ts +23 -0
- package/src/dashboard/index.ts +63 -21
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +14 -1
- package/src/dashboard/slash-runtime/help-from-registry.ts +43 -28
- package/src/decisions/decision-cards.ts +58 -3
- package/src/decisions/decision-ledger.ts +85 -6
- package/src/decisions/decision-linear-projection.ts +157 -0
- package/src/decisions/web-push-decision-cards.ts +50 -0
- package/src/directive/interpretation-card.ts +36 -0
- 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 +19 -2
- package/src/domains/coo-admin-tool.ts +62 -0
- package/src/domains/core-tools.ts +13 -4
- package/src/domains/elanous-card.ts +29 -0
- package/src/domains/ops-facts-tool.ts +76 -0
- package/src/domains/outbound-alert.ts +46 -13
- package/src/domains/release-tool.ts +168 -0
- package/src/domains/telegram-kind-route.ts +65 -9
- package/src/exec-requests/default-outputs.ts +25 -0
- package/src/exec-requests/planner.ts +106 -28
- package/src/exec-requests/runner.ts +123 -12
- package/src/exec-requests/store.ts +11 -2
- package/src/execution-loop/launch-gate.ts +100 -0
- package/src/field/field-media.ts +10 -7
- package/src/field/field-reel.ts +19 -5
- package/src/field-note/index.ts +201 -0
- package/src/field-note/transcribe.ts +248 -0
- package/src/git-fs/worktree.ts +45 -6
- package/src/graph-kinds/registry.ts +3 -3
- package/src/graph-runner/graph-approval-card.ts +113 -0
- package/src/graph-runner/graph-cli.ts +189 -4
- package/src/graph-runner/graph-grow-llm.ts +37 -0
- package/src/graph-runner/graph-grow.ts +47 -0
- package/src/graph-runner/graph-notify.ts +25 -3
- package/src/graph-runner/runner.ts +453 -35
- package/src/grok/agent-search.ts +8 -2
- package/src/guardian/secret-exposure-scan.ts +101 -0
- package/src/harness/browser-verify.ts +25 -2
- package/src/harness/harness-cli-command.ts +478 -42
- package/src/harness/harness-incidents-writer.fixture.ts +24 -0
- package/src/harness/harness-incidents.ts +129 -0
- package/src/harness/harness-pod-dispatch.ts +43 -23
- package/src/harness/harness-seams.ts +38 -4
- package/src/harness/harness-stop.ts +75 -6
- package/src/harness/launch-registry.ts +91 -0
- package/src/harness/process-garbage.ts +5 -3
- package/src/hitl/clarification-policy.ts +3 -1
- 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 +206 -49
- package/src/intake-plane/author-goals.ts +37 -4
- package/src/intake-plane/categorize.ts +18 -46
- package/src/intake-plane/check.ts +3 -0
- package/src/intake-plane/discord-seat-work.ts +57 -2
- 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/seat-doc-route.ts +170 -6
- package/src/intake-plane/telegram-seat-work.ts +80 -4
- package/src/intake-plane/telegram-work.ts +1 -0
- 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/cli-maturity.ts +34 -0
- package/src/maturity/feature-maturity.ts +120 -1
- package/src/maturity/tui-slash-maturity.ts +31 -0
- package/src/memory.ts +32 -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/exec-requests.ts +33 -3
- 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 +89 -1
- package/src/nexus/api/inside-events.ts +226 -0
- package/src/nexus/api/meta-api.ts +32 -8
- package/src/nexus/api/missions.ts +6 -1
- package/src/nexus/api/ops-api.ts +10 -1
- package/src/nexus/api/ops-seats-sources.ts +37 -7
- package/src/nexus/api/ops-seats.ts +49 -6
- package/src/nexus/api/outputs-route.ts +44 -0
- package/src/nexus/api/seat-requests.ts +132 -10
- package/src/nexus/api/sessions-store.ts +42 -0
- package/src/nexus/api/setup-codex-login.ts +160 -0
- 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/usage-api.ts +102 -0
- package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
- package/src/nexus/api/workflows.ts +80 -6
- package/src/nexus/index.ts +47 -4
- 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/first-run.ts +89 -0
- package/src/onboarding/lan-address.ts +45 -0
- package/src/onboarding/voice-ai.ts +3 -3
- package/src/onboarding/web-first.ts +119 -24
- package/src/onboarding.ts +4 -0
- package/src/ops-now/ops-now-refresh.ts +100 -0
- 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-store.ts +115 -0
- package/src/project/project-suggestion.ts +16 -0
- package/src/project/session-context.ts +24 -0
- package/src/release-loop/checklist.ts +79 -5
- package/src/release-loop/feature-store.ts +159 -24
- package/src/release-loop/next-md-merge.ts +58 -0
- package/src/release-loop/release-note.ts +59 -4
- package/src/release-loop/release-schedule.ts +53 -0
- package/src/repl/index.ts +7 -0
- package/src/seat-dispatch/ceo-commands.ts +41 -8
- package/src/seat-dispatch/ceo-intent.ts +38 -0
- 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 +750 -0
- package/src/seat-loop/seat-report.ts +99 -0
- package/src/self-dev/decompose.ts +66 -11
- 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/run-store.ts +10 -1
- 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/execution-clarification.ts +115 -0
- package/src/self-implement/gate-baseline.ts +1 -1
- package/src/self-implement/gate-cli.ts +46 -4
- 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 +279 -12
- package/src/self-implement/pipeline-shape.ts +1 -1
- package/src/self-implement/route-consumer-test-index.ts +122 -0
- package/src/self-implement/run-status-mapping.ts +5 -3
- 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/chat.ts +2 -0
- package/src/session/index.ts +45 -13
- package/src/shell-env-bootstrap.ts +17 -0
- package/src/skills/gift-install.ts +215 -0
- package/src/skills/tools/web-search.ts +4 -1
- package/src/steward/directive.ts +51 -2
- package/src/steward/launch.ts +266 -0
- package/src/steward/outcome-notify.ts +115 -0
- package/src/steward/steward-cards.ts +25 -11
- package/src/steward/triage-plan.ts +32 -4
- package/src/steward/triage.ts +129 -13
- package/src/steward/working-backwards.ts +64 -0
- package/src/storyboard/storyboard.ts +141 -0
- package/src/task-cards/card-cli.ts +25 -1
- package/src/task-cards/card-store.ts +2 -2
- 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 +397 -0
- 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 +153 -0
- package/src/telegram-commands.ts +10 -1
- package/src/telegram-project-command.ts +71 -0
- package/src/telegram-report.ts +29 -19
- package/src/telegram-run.ts +7 -0
- package/src/telegram.ts +58 -11
- package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
- package/src/tool-runtime/types.ts +4 -0
- package/src/tui-client/dashboard-session.ts +2 -0
- package/src/user-config.ts +216 -27
- package/src/version/packed-revision.json +1 -1
- package/src/web-push/notify-exec-request.ts +32 -0
- 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/bFI5EEwg7T6aG88ibX4Zq/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1201-09613bce624467c0.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/2929-617f1e66a55be184.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/3441-a1dd4acfeda14488.js +0 -1
- package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5080-1613752891fcadb4.js +0 -10
- package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6090-85a3f05f954e5697.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6284-69db415193d5f8bd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6416-505ba707cacafbba.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/7032-f4ef698518fba61c.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/7990-e12efba616f46e03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8067-d976b441a104ab74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8519-5632377cce994f86.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8630-cdfc61e82c653ffc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8894-e263b332208e3957.js +0 -1
- package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9454-139040d37c79dbc9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9740-8f5ff96c522b5f55.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-fb7c2d458f32fcad.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-35e2713597dd24d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-918b656f064577ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-5f30e00693527ebd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-7fbae173b3c103a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-3b4edcce364062ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-c5794f484c251f44.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-1130d8eefcd87e76.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-973996d584f008c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-016e2bda04eecb1f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-b4d6d9a3b56f2940.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-ec49a466121233ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-f72db356744ceade.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-a6fd9b50d1b85378.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-8b0402a46a749a3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-037f83e2a1edc8e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-46fedff57d4bec67.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-0cf318e9dcee2bbf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-899b327cb8b6845c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6c1e6ba743a29dfe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-1a8e4807292f6b17.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-28deba6bcb834916.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-de68e2205794037d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-c71c33a573230672.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-0df30e0c7e50148a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-4fc56790fe0d2682.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-59df2aebb38a7c1e.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-4647be5dbcbd0795.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-e025892bda74b743.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-a0955de73b89f078.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-369846d2921af584.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-72cbc1c8cdd0f65d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-77b28bfb0996d5ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-3220c4934f49c6c2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-90670589b87abea8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-7df9243ed021a4cc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-4498c3853f4f688d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-35bedde6d885f08f.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-6870f30ea99f8346.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/f92f63a5df0ba229.css +0 -1
- package/src/dashboard/turn-typeahead-echo.ts +0 -23
- /package/apps/pwa/out/_next/static/{bFI5EEwg7T6aG88ibX4Zq → Y4zKzL62sakG5momz3SoQ}/_ssgManifest.js +0 -0
|
@@ -1,21 +1,77 @@
|
|
|
1
1
|
// 발송 목적(kind) → 텔레그램 채널 역할 · 대상. 가벼운 모듈(telegram.ts 를 import 하지 않는다 — outbound-alert 순환 방지).
|
|
2
|
-
//
|
|
2
|
+
// 명시적으로 매매 kind 인 경우만 trading; 나머지는 system. 역할 채널이 없으면 다른 역할로 폴백하지 않는다.
|
|
3
3
|
import type { UserConfig } from '../user-config.js';
|
|
4
|
-
import {
|
|
4
|
+
import { resolveChannelBotToken } from '../channel-bot-token.js';
|
|
5
|
+
import { debug } from '../debug/log.js';
|
|
6
|
+
import { resolveTelegramChannels } from './telegram-channels.js';
|
|
5
7
|
|
|
6
8
|
export const DEFAULT_KIND_ROLES: Readonly<Record<string, string>> = {
|
|
9
|
+
report: 'report', alert: 'report', digest: 'report',
|
|
7
10
|
intake: 'system', 'ops-report': 'system', 'ops-alert': 'system', 'ops-health': 'system',
|
|
11
|
+
regression: 'system', 'agent-mission': 'system', brief: 'system', 'op-report': 'system',
|
|
8
12
|
};
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return
|
|
14
|
+
/** Only named finance delivery kinds can use the trading/report bot. */
|
|
15
|
+
export function isTradingKind(kind?: string): boolean {
|
|
16
|
+
return kind === 'report' || kind === 'alert' || kind === 'digest';
|
|
13
17
|
}
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
export function isOperationalKind(kind?: string): boolean {
|
|
20
|
+
return !isTradingKind(kind);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function mainHomeTarget(cfg: UserConfig): { botToken: string; chatId: number } | null {
|
|
24
|
+
const botToken = operationsBotToken(cfg);
|
|
25
|
+
const chatId = cfg.telegram.homeChannel ?? cfg.telegram.allowedUsers[0];
|
|
26
|
+
return botToken && chatId != null && Number.isFinite(chatId) ? { botToken, chatId } : null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function logKindRouteFallback(kind: string | undefined, to: 'report-channel' | 'main-home' | 'conatus-env' | 'none', sameBot: boolean): void {
|
|
30
|
+
try { debug.log('telegram.kind-route', 'fallback', { kind, to, sameBot }); } catch { /* logging must not prevent delivery */ }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function operationsBotToken(cfg: UserConfig): string | undefined {
|
|
34
|
+
const main = resolveChannelBotToken('telegram', cfg);
|
|
35
|
+
const channels = cfg.telegram.channels?.length ? resolveTelegramChannels(cfg.telegram) : [];
|
|
36
|
+
const tradingTokens = new Set(channels.filter(c => c.roles.includes('report')).map(c => c.botToken));
|
|
37
|
+
// The report (trading) bot is never the operations bot — with or without a channels table (review must-fix · OUT1).
|
|
38
|
+
if (cfg.telegram.reportChannel?.botToken) tradingTokens.add(cfg.telegram.reportChannel.botToken);
|
|
39
|
+
if (main.source !== 'channels.main') return main.token && !tradingTokens.has(main.token) ? main.token : undefined;
|
|
40
|
+
// channels.main may mean "first channel", which can be the trading bot.
|
|
41
|
+
// Only a named operations channel (or the named main channel) with an
|
|
42
|
+
// operational role establishes identity; array order and role alone do not.
|
|
43
|
+
const tokens = new Set(channels
|
|
44
|
+
.filter(c => (c.name === 'ops' && c.roles.includes('system'))
|
|
45
|
+
|| (c.name === 'main' && c.roles.some(r => r === 'system' || r === 'qa' || r === 'default')))
|
|
46
|
+
.filter(c => !tradingTokens.has(c.botToken))
|
|
47
|
+
.map(c => c.botToken));
|
|
48
|
+
return tokens.size === 1 ? tokens.values().next().value : undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isAllowedBot(cfg: UserConfig, kind: string | undefined, token: string): boolean {
|
|
52
|
+
const mainToken = operationsBotToken(cfg);
|
|
53
|
+
if (!mainToken) return false;
|
|
54
|
+
if (!isTradingKind(kind)) return token === mainToken;
|
|
55
|
+
const reportToken = cfg.telegram.reportChannel?.botToken;
|
|
56
|
+
return token !== mainToken && (!reportToken || token === reportToken);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function roleForKind(cfg: UserConfig, kind?: string): string {
|
|
60
|
+
const fallback = isTradingKind(kind) ? 'report' : 'system';
|
|
61
|
+
if (!kind || !cfg.telegram.channels?.length) return fallback;
|
|
62
|
+
const override = cfg.telegram.kindRoles?.[kind];
|
|
63
|
+
if (!override) return fallback;
|
|
64
|
+
const channel = resolveTelegramChannels(cfg.telegram)
|
|
65
|
+
.find(c => c.roles.includes(override) && isAllowedBot(cfg, kind, c.botToken));
|
|
66
|
+
return channel ? override : fallback;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Exact role only: channelForRole's default/first fallback can cross bot boundaries. */
|
|
16
70
|
export function kindRouteTarget(cfg: UserConfig, kind?: string): { botToken: string; chatId: number } | null {
|
|
71
|
+
if (!cfg.telegram.channels?.length) return null;
|
|
17
72
|
const role = roleForKind(cfg, kind);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
73
|
+
const ch = resolveTelegramChannels(cfg.telegram)
|
|
74
|
+
.find(c => c.roles.includes(role) && isAllowedBot(cfg, kind, c.botToken));
|
|
75
|
+
if (!ch || !Number.isFinite(ch.chatId)) return null;
|
|
76
|
+
return { botToken: ch.botToken, chatId: ch.chatId };
|
|
21
77
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const OUTPUT_KINDS = {
|
|
2
|
+
report: { fileName: 'report.md', cardTitle: '한 장 보고서', guidance: '보고·정리·요약·회고 → 한 장 보고서', words: ['보고', '정리', '요약', '회고', 'report', 'summary', 'summarize', 'recap', 'brief'] },
|
|
3
|
+
slides: { fileName: 'slides.md', cardTitle: '슬라이드', guidance: '발표·자료·덱·피치 → 슬라이드(장마다 --- 구분)', words: ['발표', '자료', '덱', '피치', 'presentation', 'slides', 'slide', 'deck', 'pitch'] },
|
|
4
|
+
research: { fileName: 'research.md', cardTitle: '조사 문서', guidance: '조사·비교·경쟁사·시장 → 조사 문서(출처 링크 칸 필수)', words: ['조사', '비교', '경쟁사', '시장', 'research', 'compare', 'comparison', 'competitor', 'competitors', 'market'] },
|
|
5
|
+
post: { fileName: 'post.md', cardTitle: '게시글 초안', guidance: '게시글·캡션·공지·SNS → 게시글 초안(게시는 승인 노드 뒤)', words: ['게시글', '캡션', '공지', 'SNS', 'post', 'caption', 'announcement', 'social media'] },
|
|
6
|
+
video: { fileName: '', cardTitle: '영상', guidance: '영상·릴스·쇼츠 → 영상(그래프가 있을 때만)', words: ['영상', '릴스', '쇼츠', 'video', 'reels', 'shorts'] },
|
|
7
|
+
answer: { fileName: '', cardTitle: '답', guidance: '단순한 질문 → 답 그대로(산출물 없음)', words: [] },
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
export type OutputKind = keyof typeof OUTPUT_KINDS;
|
|
11
|
+
|
|
12
|
+
export function pickDefaultOutput(text: string): { kind: OutputKind; fileName: string; cardTitle: string } {
|
|
13
|
+
const normalized = text.toLowerCase();
|
|
14
|
+
// Explicit artifact formats outrank activity words such as 정리, 요약 and 비교.
|
|
15
|
+
for (const kind of ['slides', 'post', 'video', 'research', 'report'] as const) {
|
|
16
|
+
const entry = OUTPUT_KINDS[kind];
|
|
17
|
+
if (entry.words.some(word => /[a-z]/i.test(word)
|
|
18
|
+
? new RegExp(`(^|[^a-z])${word.toLowerCase()}(?=$|[^a-z])`).test(normalized)
|
|
19
|
+
: normalized.includes(word))) {
|
|
20
|
+
return { kind, fileName: entry.fileName, cardTitle: entry.cardTitle };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const kind = /(?:[??]|뭐|어떻게)\s*$/.test(text) ? 'answer' : 'report';
|
|
24
|
+
return { kind, fileName: OUTPUT_KINDS[kind].fileName, cardTitle: OUTPUT_KINDS[kind].cardTitle };
|
|
25
|
+
}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
2
|
-
import { dirname, join } from 'node:path';
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, statSync, type Dirent } from 'node:fs';
|
|
2
|
+
import { dirname, join, resolve, sep } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { parse as parseYaml } from 'yaml';
|
|
5
5
|
import { elanousStateRoot } from '../autopilot/state-paths.js';
|
|
6
6
|
import { defaultGraphsDir } from '../self-implement/graph-templates.js';
|
|
7
|
-
import {
|
|
7
|
+
import { getElanousConfigDir } from '../elanous-config-dir.js';
|
|
8
|
+
import type { ExecAttachment } from './store.js';
|
|
8
9
|
import { debug } from '../debug/log.js';
|
|
10
|
+
import { OUTPUT_KINDS, pickDefaultOutput, type OutputKind } from './default-outputs.js';
|
|
9
11
|
|
|
10
12
|
export interface InstalledGraph {
|
|
11
13
|
id: string;
|
|
12
14
|
title: string;
|
|
13
15
|
description: string;
|
|
14
16
|
path: string;
|
|
15
|
-
/**
|
|
17
|
+
/** 코어 loop.inputs 또는 플러그인 examples/*.json 표본의 입력 키. */
|
|
16
18
|
inputKeys?: string[];
|
|
17
19
|
}
|
|
18
20
|
export interface ExecPlanItem {
|
|
@@ -20,6 +22,8 @@ export interface ExecPlanItem {
|
|
|
20
22
|
title: string;
|
|
21
23
|
graphId: string;
|
|
22
24
|
inputs: Record<string, unknown>;
|
|
25
|
+
/** Planner fills this for every returned row; older injected plan fixtures may omit it. */
|
|
26
|
+
output?: OutputKind;
|
|
23
27
|
reason?: string;
|
|
24
28
|
/** A5b — indexes of earlier items whose results this item needs (it starts after they finish). */
|
|
25
29
|
after?: number[];
|
|
@@ -83,24 +87,41 @@ export async function installedGraphs(coreDir = defaultGraphsDir(), mineDir = jo
|
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
async function coreAndMineGraphs(coreDir: string, mineDir: string): Promise<InstalledGraph[]> {
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
90
|
+
const graphs: InstalledGraph[] = [];
|
|
91
|
+
const seen = new Set<string>();
|
|
92
|
+
const scan = (dir: string, core: boolean): void => {
|
|
93
|
+
let entries: Dirent[];
|
|
94
|
+
try { entries = readdirSync(dir, { withFileTypes: true }); }
|
|
95
|
+
catch { return; }
|
|
96
|
+
if (!core || dir === coreDir || entries.some(entry => entry.isFile() && entry.name === 'recipes.yaml')) {
|
|
97
|
+
for (const entry of entries) {
|
|
98
|
+
if (!entry.isFile() || !/\.ya?ml$/.test(entry.name) || entry.name === 'recipes.yaml') continue;
|
|
99
|
+
const path = join(dir, entry.name);
|
|
100
|
+
try {
|
|
101
|
+
const doc = parseYaml(readFileSync(path, 'utf8')) as {
|
|
102
|
+
graph_id?: unknown;
|
|
103
|
+
loop?: { title?: string; description?: string; exec_request?: unknown; inputs?: unknown };
|
|
104
|
+
} | null;
|
|
105
|
+
const id = doc?.graph_id;
|
|
106
|
+
if (typeof id !== 'string' || !/^[a-z0-9-]+$/.test(id) || seen.has(id)) continue;
|
|
107
|
+
if (core && doc?.loop?.exec_request !== true) continue;
|
|
108
|
+
const inputs = doc?.loop?.inputs;
|
|
109
|
+
const inputKeys = core && Array.isArray(inputs)
|
|
110
|
+
? inputs.filter((key): key is string => typeof key === 'string')
|
|
111
|
+
: core && inputs && typeof inputs === 'object' ? Object.keys(inputs) : undefined;
|
|
112
|
+
graphs.push({ id, title: doc?.loop?.title ?? id, description: doc?.loop?.description ?? '', path,
|
|
113
|
+
...(inputKeys ? { inputKeys } : {}) });
|
|
114
|
+
seen.add(id);
|
|
115
|
+
} catch { /* A malformed file is not an executable graph. */ }
|
|
116
|
+
}
|
|
101
117
|
}
|
|
102
|
-
|
|
103
|
-
|
|
118
|
+
if (core) for (const entry of entries) {
|
|
119
|
+
if (entry.isDirectory() && !entry.name.startsWith('.')) scan(join(dir, entry.name), true);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
scan(coreDir, true);
|
|
123
|
+
scan(mineDir, false);
|
|
124
|
+
return graphs;
|
|
104
125
|
}
|
|
105
126
|
|
|
106
127
|
export function seatTitles(path = fileURLToPath(new URL('../../scripts/coord-tracks.json', import.meta.url))): string[] {
|
|
@@ -108,8 +129,32 @@ export function seatTitles(path = fileURLToPath(new URL('../../scripts/coord-tra
|
|
|
108
129
|
return data.tracks.flatMap(track => track.title ? [track.title] : []);
|
|
109
130
|
}
|
|
110
131
|
|
|
111
|
-
export
|
|
112
|
-
const
|
|
132
|
+
export function latestFieldFolder(configRoot = getElanousConfigDir()): string | null {
|
|
133
|
+
const root = join(configRoot, 'field');
|
|
134
|
+
let latest: { path: string; time: number } | null = null;
|
|
135
|
+
try {
|
|
136
|
+
for (const event of readdirSync(root, { withFileTypes: true })) {
|
|
137
|
+
if (!event.isDirectory() || event.name.startsWith('.')) continue;
|
|
138
|
+
const path = join(root, event.name);
|
|
139
|
+
try {
|
|
140
|
+
const photos = readdirSync(path, { withFileTypes: true }).filter(file => file.isFile() && /\.(?:png|jpe?g|webp|heic)$/i.test(file.name));
|
|
141
|
+
for (const photo of photos) {
|
|
142
|
+
const time = statSync(join(path, photo.name)).mtimeMs;
|
|
143
|
+
if (!latest || time > latest.time || (time === latest.time && path.localeCompare(latest.path) > 0)) latest = { path, time };
|
|
144
|
+
}
|
|
145
|
+
} catch { /* Unreadable event does not supply photos. */ }
|
|
146
|
+
}
|
|
147
|
+
} catch { /* No field directory. */ }
|
|
148
|
+
return latest?.path ?? null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function execPlanPrompt(text: string, graphs: readonly InstalledGraph[], seats: readonly string[], attachments: readonly ExecAttachment[] = [], fieldFolder: string | null = latestFieldFolder()): string {
|
|
152
|
+
const supplied = attachments.map(({ name, path }) => `첨부: ${name} (${/\.(?:png|jpe?g|webp|gif|heic)$/i.test(name) ? '이미지' : '파일'}) — ${path}`).join('\n');
|
|
153
|
+
return `COO 역할. 요청을 실행 가능한 자리별 그래프로 나눠 맡겨라. JSON 배열만 출력: [{"seat":"자리","title":"할 일","graphId":"설치된 그래프 ID 또는 빈 문자열","inputs":{},"after":[]}]. 각 행에는 선택 칸 "output":"report|slides|research|post|video|answer"를 쓸 수 있다: ${Object.entries(OUTPUT_KINDS).map(([kind, entry]) => `${entry.guidance} = ${kind}${entry.fileName ? ` (${entry.fileName})` : ''}`).join(', ')}; 그 외 일은 report로 둔다. 앞 항목의 결과가 있어야 할 수 있는 일(예: 점검·조사 «결과로» 쓰는 한 장 · 보고)은 after 에 그 앞 항목 번호(0부터)를 적는다 — 그 항목은 앞 항목이 끝난 뒤 그 결과를 받아 시작한다. 서로 기다릴 필요가 없으면 after 는 빈 배열. 자리 이름은 주어진 목록에서만, 그래프 ID는 설치된 목록에서만 고른다. 맞는 그래프가 없으면 graphId=""로 표시한다. 그래프에 inputKeys 가 있으면 inputs 를 그 키로만 채우되 한 줄과 아래 알려진 값에서 얻을 수 있는 값만 넣는다(모르는 값은 넣지 않는다). image/photo/file 입력에는 알맞은 첨부 경로를 쓸 수 있다. folder 입력에는 첨부가 없거나 첨부 사진이 그 현장 폴더 안에 있을 때만 오늘 현장 폴더를 쓸 수 있다. 다른 현장 사진이나 출처를 모르는 업로드 사진이 있으면 폴더를 추측하지 마라. 그 그래프가 꼭 받아야 할 값(예: 브랜드 이름 · 사진 파일)을 알 수 없으면 graphId=""로 두고 title 끝에 « — <무엇> 필요»를 적는다. 단순히 묻는 말에는 없는 그래프를 지어내지 말고 graphId=""로 표시한다. 없는 그래프나 산출을 지어내지 마라. 바깥 게시·발행·광고·결제는 승인 노드를 거치기 전 실행하면 안 된다.\n자리: ${JSON.stringify(seats)}\n실행 가능한 그래프: ${JSON.stringify(graphs.map(({ id, title, description, inputKeys }) => ({ id, title, description, ...(inputKeys ? { inputKeys } : {}) })))}\n${fieldFolder ? `알려진 값: 오늘 현장 폴더 = ${fieldFolder}\n` : ''}${supplied ? `${supplied}\n` : ''}한 줄: ${JSON.stringify(text)}`;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export async function judgeExecPlan(text: string, graphs: readonly InstalledGraph[], seats: readonly string[], attachments: readonly ExecAttachment[] = [], fieldFolder: string | null = latestFieldFolder()): Promise<unknown> {
|
|
157
|
+
const prompt = execPlanPrompt(text, graphs, seats, attachments, fieldFolder);
|
|
113
158
|
const { streamLLM } = await import('../llm.js');
|
|
114
159
|
const { tierModel } = await import('../llm/model-defaults.js');
|
|
115
160
|
const raw = await streamLLM([{ role: 'user', content: prompt }], () => {}, { model: tierModel('best') });
|
|
@@ -120,13 +165,17 @@ export async function planExecRequest(text: string, deps: {
|
|
|
120
165
|
graphs?: () => Promise<InstalledGraph[]>;
|
|
121
166
|
seats?: () => string[];
|
|
122
167
|
judge?: typeof judgeExecPlan;
|
|
168
|
+
attachments?: readonly ExecAttachment[];
|
|
169
|
+
fieldFolder?: () => string | null;
|
|
123
170
|
} = {}): Promise<ExecPlanItem[]> {
|
|
124
171
|
const graphs = await (deps.graphs ?? installedGraphs)();
|
|
125
172
|
const seats = (deps.seats ?? seatTitles)();
|
|
126
|
-
const
|
|
173
|
+
const attachments = deps.attachments ?? [];
|
|
174
|
+
const fieldFolder = (deps.fieldFolder ?? latestFieldFolder)();
|
|
175
|
+
const raw = await (deps.judge ?? judgeExecPlan)(text, graphs, seats, attachments, fieldFolder);
|
|
127
176
|
if (!Array.isArray(raw) || raw.length === 0) throw new Error('COO 계획이 비었거나 배열이 아닙니다');
|
|
128
177
|
const known = new Map(graphs.map(graph => [graph.id, graph]));
|
|
129
|
-
|
|
178
|
+
const plans: ExecPlanItem[] = raw.map((item: unknown, index: number) => {
|
|
130
179
|
if (!item || typeof item !== 'object' || Array.isArray(item)) throw new Error('COO 계획 항목 형식 오류');
|
|
131
180
|
const row = item as Record<string, unknown>;
|
|
132
181
|
if (typeof row.seat !== 'string' || !seats.includes(row.seat) || typeof row.title !== 'string' || !row.title.trim()
|
|
@@ -136,11 +185,40 @@ export async function planExecRequest(text: string, deps: {
|
|
|
136
185
|
const after = Array.isArray(row.after)
|
|
137
186
|
? [...new Set(row.after.filter((n): n is number => Number.isInteger(n) && (n as number) >= 0 && (n as number) < index))]
|
|
138
187
|
: [];
|
|
188
|
+
const graph = known.get(row.graphId);
|
|
189
|
+
const modelOutput = typeof row.output === 'string' && Object.hasOwn(OUTPUT_KINDS, row.output)
|
|
190
|
+
? row.output as OutputKind : undefined;
|
|
191
|
+
const picked = modelOutput ?? pickDefaultOutput(row.title).kind;
|
|
192
|
+
const output = picked === 'video' && !graph ? 'report' : picked;
|
|
193
|
+
debug.log('exec.plan', 'default-output', { kind: output, source: modelOutput === output ? 'model' : 'rule' });
|
|
194
|
+
const inputs = { ...row.inputs as Record<string, unknown> };
|
|
195
|
+
let folderReason: string | undefined;
|
|
196
|
+
if (graph) {
|
|
197
|
+
for (const key of graph.inputKeys ?? []) {
|
|
198
|
+
if (key === 'folder') {
|
|
199
|
+
// A folder input must contain every attached photo — never guess it from «the latest event» (review r1).
|
|
200
|
+
const photos = attachments.filter(a => /\.(?:png|jpe?g|webp|gif|heic)$/i.test(a.name)).map(a => resolve(a.path));
|
|
201
|
+
const holds = (folder: string) => photos.every(photo => photo.startsWith(`${resolve(folder)}${sep}`));
|
|
202
|
+
const given = typeof inputs.folder === 'string' ? inputs.folder : undefined;
|
|
203
|
+
if (given !== undefined) {
|
|
204
|
+
if (!holds(given)) { delete inputs.folder; folderReason = `${row.seat}: folder 필요 — 첨부 사진이 그 현장 폴더 안에 없습니다`; }
|
|
205
|
+
} else if (fieldFolder && holds(fieldFolder)) inputs.folder = fieldFolder;
|
|
206
|
+
else if (photos.length) folderReason = `${row.seat}: folder 필요 — 첨부 사진의 현장 폴더를 알 수 없습니다`;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (inputs[key] !== undefined) continue;
|
|
210
|
+
if (['image', 'photo', 'file'].includes(key)) {
|
|
211
|
+
const attachment = attachments.find(a => key === 'file' || /\.(?:png|jpe?g|webp|gif|heic)$/i.test(a.name));
|
|
212
|
+
if (attachment) inputs[key] = attachment.path;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
139
216
|
return {
|
|
140
|
-
seat: row.seat, title: row.title.trim(), graphId: row.graphId,
|
|
141
|
-
inputs: row.inputs as Record<string, unknown>,
|
|
217
|
+
seat: row.seat, title: row.title.trim(), graphId: row.graphId, inputs, output,
|
|
142
218
|
...(after.length ? { after } : {}),
|
|
143
|
-
...(!
|
|
219
|
+
...(!graph ? { reason: `${row.seat}: 요청에 맞는 설치된 실행 그래프가 없습니다` } : folderReason ? { reason: folderReason } : {}),
|
|
144
220
|
};
|
|
145
221
|
});
|
|
222
|
+
for (const plan of plans) debug.log('exec.planner', 'select', { seat: plan.seat, chosen: plan.graphId, candidates: graphs.slice(0, 10).map(graph => graph.id) });
|
|
223
|
+
return plans;
|
|
146
224
|
}
|
|
@@ -1,16 +1,26 @@
|
|
|
1
|
-
import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs';
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, statSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { basename, dirname, isAbsolute, join, resolve, sep } from 'node:path';
|
|
3
3
|
import { createHash, randomUUID } from 'node:crypto';
|
|
4
4
|
import { debug } from '../debug/log.js';
|
|
5
|
+
import { notifyExecRequestTransition } from '../web-push/notify-exec-request.js';
|
|
5
6
|
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
6
7
|
import { lastJsonObject, runGraph, type GraphRunState } from '../graph-runner/runner.js';
|
|
7
8
|
import { installedGraphs, planExecRequest, type ExecPlanItem, type InstalledGraph } from './planner.js';
|
|
8
|
-
import { ExecRequestStore, type ExecRequest, type ExecResult, type ExecSeat } from './store.js';
|
|
9
|
+
import { ExecRequestStore, type ExecAttachment, type ExecRequest, type ExecResult, type ExecSeat } from './store.js';
|
|
10
|
+
import { answerAsSeat } from '../intake-plane/seat-answer.js';
|
|
11
|
+
import { redactSecrets } from '../task-cards/card-store.js';
|
|
12
|
+
import { recordOutput } from '../outputs/ledger.js';
|
|
13
|
+
import type { OutputKind } from './default-outputs.js';
|
|
14
|
+
|
|
15
|
+
function recordResult(result: ExecResult, id: string, root: string, kind: OutputKind | 'file'): void {
|
|
16
|
+
recordOutput({ source: 'exec', sourceId: id, seat: result.seat, title: result.title, url: result.url, kind }, root);
|
|
17
|
+
}
|
|
9
18
|
|
|
10
19
|
export interface ExecRunnerDeps {
|
|
11
20
|
store?: ExecRequestStore;
|
|
12
21
|
graphs?: () => Promise<InstalledGraph[]>;
|
|
13
|
-
plan?: (text: string) => Promise<ExecPlanItem[]>;
|
|
22
|
+
plan?: (text: string, attachments?: readonly ExecAttachment[]) => Promise<ExecPlanItem[]>;
|
|
23
|
+
answer?: typeof answerAsSeat;
|
|
14
24
|
run?: typeof runGraph;
|
|
15
25
|
root?: string;
|
|
16
26
|
}
|
|
@@ -38,7 +48,11 @@ function safeFile(path: string, root: string, graphId: string, runId: string): s
|
|
|
38
48
|
? realpathSync(artifactsDir) : null;
|
|
39
49
|
const inRunDirectory = realArtifactsDir === join(base, `${runId}.json.artifacts`)
|
|
40
50
|
&& real.startsWith(`${realArtifactsDir}${sep}`);
|
|
41
|
-
|
|
51
|
+
// EXEC2 — plugin graphs (doc-draft · geo-check) write into `<graphId>/<runId>/`; that directory is this run's own too.
|
|
52
|
+
const runDir = join(allowed, runId);
|
|
53
|
+
const realRunDir = existsSync(runDir) && statSync(runDir).isDirectory() ? realpathSync(runDir) : null;
|
|
54
|
+
const inOwnRunDir = realRunDir === join(base, runId) && real.startsWith(`${realRunDir}${sep}`);
|
|
55
|
+
if ((!local && !inRunDirectory && !inOwnRunDir) || !statSync(real).isFile()) return null;
|
|
42
56
|
return real;
|
|
43
57
|
} catch { return null; }
|
|
44
58
|
}
|
|
@@ -56,8 +70,32 @@ function fileName(path: string, runId: string): string {
|
|
|
56
70
|
return `${runId}--${digest}--${basename(path)}`;
|
|
57
71
|
}
|
|
58
72
|
|
|
73
|
+
/** EXEC2 — `report` is how geo-check names its file; treat it like `file`/`path`. */
|
|
74
|
+
function fileCandidate(output: Record<string, unknown>): string | null {
|
|
75
|
+
if (typeof output.file === 'string') return output.file;
|
|
76
|
+
if (typeof output.path === 'string') return output.path;
|
|
77
|
+
if (typeof output.report === 'string' && /\.(md|txt|pdf)$/i.test(output.report)) return output.report;
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const TEXT_RESULT_LIMIT = 200_000;
|
|
82
|
+
const TEXT_RESULT_NAME = 'result.md';
|
|
83
|
+
|
|
84
|
+
/** EXEC2 — a done seat whose graph only answered in text gets that text as a run artifact (redacted), so the result is viewable. */
|
|
85
|
+
function textResultFile(seat: ExecSeat, state: GraphRunState, root: string): string | null {
|
|
86
|
+
const outputs = [...(state.nodes ?? [])].reverse().map(node => lastJsonObject(node.output)).filter((o): o is Record<string, unknown> => !!o);
|
|
87
|
+
const text = outputs.map(o => o.markdown ?? o.text).find((v): v is string => typeof v === 'string' && v.trim().length > 0);
|
|
88
|
+
if (!text || !SEGMENT.test(seat.graphId) || !SEGMENT.test(seat.runId)) return null;
|
|
89
|
+
const dir = join(root, 'graph-runs', seat.graphId, `${seat.runId}.json.artifacts`);
|
|
90
|
+
const path = join(dir, TEXT_RESULT_NAME);
|
|
91
|
+
try {
|
|
92
|
+
if (!existsSync(path)) { mkdirSync(dir, { recursive: true }); writeFileSync(path, redactSecrets(text.slice(0, TEXT_RESULT_LIMIT)), { mode: 0o600 }); }
|
|
93
|
+
return path;
|
|
94
|
+
} catch { return null; }
|
|
95
|
+
}
|
|
96
|
+
|
|
59
97
|
function resultOf(output: Record<string, unknown>, seat: ExecSeat, id: string, root: string): ExecResult | null {
|
|
60
|
-
const candidate =
|
|
98
|
+
const candidate = fileCandidate(output);
|
|
61
99
|
let url: string;
|
|
62
100
|
let kind: ExecResult['kind'];
|
|
63
101
|
let name: string;
|
|
@@ -95,6 +133,7 @@ function syncRun(item: ExecRequest, seat: ExecSeat, state: GraphRunState, root:
|
|
|
95
133
|
if (state.status === 'awaiting-approval' && state.pending && !state.pending.decision && !existsSync(claim)) {
|
|
96
134
|
if (!item.approvals.some(a => a.graphId === seat.graphId && a.runId === seat.runId)) {
|
|
97
135
|
item.approvals.push({ graphId: seat.graphId, runId: seat.runId, message: state.pending.message });
|
|
136
|
+
notifyTransition(item, item.status, item.approvals.length);
|
|
98
137
|
}
|
|
99
138
|
} else item.approvals = item.approvals.filter(a => a.graphId !== seat.graphId || a.runId !== seat.runId);
|
|
100
139
|
for (const node of state.nodes ?? []) {
|
|
@@ -104,12 +143,36 @@ function syncRun(item: ExecRequest, seat: ExecSeat, state: GraphRunState, root:
|
|
|
104
143
|
for (const entry of entries) {
|
|
105
144
|
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) continue;
|
|
106
145
|
const result = resultOf(entry as Record<string, unknown>, seat, item.id, root);
|
|
107
|
-
if (result && !item.results.some(existing => existing.seat === result.seat && existing.url === result.url))
|
|
146
|
+
if (result && !item.results.some(existing => existing.seat === result.seat && existing.url === result.url)) {
|
|
147
|
+
item.results.push(result);
|
|
148
|
+
recordResult(result, item.id, root, seat.output ?? 'file');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (seat.status === 'done' && !item.results.some(existing => existing.seat === seat.seat)) {
|
|
153
|
+
const file = textResultFile(seat, state, root);
|
|
154
|
+
const result = file ? resultOf({ file, title: seat.title }, seat, item.id, root) : null;
|
|
155
|
+
if (result) {
|
|
156
|
+
item.results.push(result);
|
|
157
|
+
recordResult(result, item.id, root, seat.output ?? 'file');
|
|
158
|
+
} else {
|
|
159
|
+
const keys = [...new Set((state.nodes ?? []).flatMap(node => Object.keys(lastJsonObject(node.output) ?? {})))];
|
|
160
|
+
debug.log('exec.result', 'none', { seat: seat.seat, graphId: seat.graphId, keys });
|
|
108
161
|
}
|
|
109
162
|
}
|
|
110
163
|
const summary = [...(state.nodes ?? [])].reverse().map(node => lastJsonObject(node.output)?.summary).find(value => typeof value === 'string');
|
|
111
164
|
if (typeof summary === 'string') item.summary = summary;
|
|
112
|
-
if (seat.status === 'failed') seat.reason = state
|
|
165
|
+
if (seat.status === 'failed') seat.reason = failureReason(state);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** EXEC2 — the failing node's own error (e.g. doc-draft `check` {outcome:'fail', error}) beats the terminal gate's empty one. */
|
|
169
|
+
function failureReason(state: GraphRunState): string {
|
|
170
|
+
for (const node of [...(state.nodes ?? [])].reverse()) {
|
|
171
|
+
if (typeof node.error === 'string' && node.error) return node.error;
|
|
172
|
+
const output = lastJsonObject(node.output);
|
|
173
|
+
if (output && typeof output.error === 'string' && output.error) return redactSecrets(output.error);
|
|
174
|
+
}
|
|
175
|
+
return `그래프 런 ${state.status}`;
|
|
113
176
|
}
|
|
114
177
|
|
|
115
178
|
const PRIOR_TEXT_LIMIT = 4_000;
|
|
@@ -129,8 +192,14 @@ export function withPriorResults(inputs: Record<string, unknown> | undefined, pr
|
|
|
129
192
|
return { ...base, context: `${previous}앞 자리 결과:\n${parts.join('\n\n')}` };
|
|
130
193
|
}
|
|
131
194
|
|
|
195
|
+
function notifyTransition(item: ExecRequest, from: ExecRequest['status'], pendingApprovals: number): void {
|
|
196
|
+
void notifyExecRequestTransition({ id: item.id, text: item.text, from, to: item.status,
|
|
197
|
+
summary: item.summary, pendingApprovals }).catch(() => { /* Push never interrupts execution. */ });
|
|
198
|
+
}
|
|
199
|
+
|
|
132
200
|
function aggregate(item: ExecRequest): void {
|
|
133
201
|
if (item.status === 'planning' || item.seats.length === 0) return;
|
|
202
|
+
const previous = item.status;
|
|
134
203
|
if (item.seats.some(seat => seat.status === 'waiting' || seat.status === 'running')) item.status = 'running';
|
|
135
204
|
else item.status = item.seats.some(seat => seat.status === 'failed') ? 'failed' : 'done';
|
|
136
205
|
// 실패면 요약은 «실패 사유»가 이긴다 — 먼저 끝난 자리의 산출 설명이 남아 있어도 덮는다(혼합 결과에서 성공처럼 보이지 않게).
|
|
@@ -138,6 +207,7 @@ function aggregate(item: ExecRequest): void {
|
|
|
138
207
|
const reasons = item.seats.filter(seat => seat.status === 'failed').map(seat => seat.reason ?? `${seat.seat}: 그래프 실행 실패`);
|
|
139
208
|
if (reasons.length > 0) item.summary = reasons.join('; ');
|
|
140
209
|
}
|
|
210
|
+
if (previous !== item.status && (item.status === 'done' || item.status === 'failed')) notifyTransition(item, previous, item.approvals.length);
|
|
141
211
|
}
|
|
142
212
|
|
|
143
213
|
export class ExecRequestRunner {
|
|
@@ -156,10 +226,12 @@ export class ExecRequestRunner {
|
|
|
156
226
|
if (item.status === 'planning') {
|
|
157
227
|
item.status = 'failed';
|
|
158
228
|
item.summary = '데몬 재시작으로 COO 계획이 중단됐습니다';
|
|
229
|
+
notifyTransition(item, 'planning', item.approvals.length);
|
|
159
230
|
} else {
|
|
160
231
|
if (item.seats.length === 0) {
|
|
161
232
|
item.status = 'failed';
|
|
162
233
|
item.summary = '데몬 재시작으로 자리 배정이 중단됐습니다';
|
|
234
|
+
notifyTransition(item, 'running', item.approvals.length);
|
|
163
235
|
}
|
|
164
236
|
for (const seat of item.seats) {
|
|
165
237
|
if (seat.status === 'done' || seat.status === 'failed') continue;
|
|
@@ -192,14 +264,16 @@ export class ExecRequestRunner {
|
|
|
192
264
|
}
|
|
193
265
|
}
|
|
194
266
|
|
|
195
|
-
submit(text: string): ExecRequest {
|
|
196
|
-
const item = this.store.create(text);
|
|
267
|
+
submit(text: string, attachments?: ExecAttachment[]): ExecRequest {
|
|
268
|
+
const item = this.store.create(text, attachments);
|
|
197
269
|
void this.execute(item.id).catch(error => {
|
|
198
270
|
const current = this.store.get(item.id);
|
|
199
271
|
if (!current) return;
|
|
272
|
+
const previous = current.status;
|
|
200
273
|
current.status = 'failed';
|
|
201
274
|
current.summary = error instanceof Error ? error.message : String(error);
|
|
202
275
|
this.store.save(current);
|
|
276
|
+
if (previous !== current.status) notifyTransition(current, previous, current.approvals.length);
|
|
203
277
|
debug.log('exec-requests', 'failed', { id: item.id, reason: current.summary });
|
|
204
278
|
});
|
|
205
279
|
return item;
|
|
@@ -209,10 +283,45 @@ export class ExecRequestRunner {
|
|
|
209
283
|
const item = this.store.get(id);
|
|
210
284
|
if (!item) return;
|
|
211
285
|
const graphs = await (this.deps.graphs ?? installedGraphs)();
|
|
212
|
-
const plans = await (this.deps.plan ?? ((text: string) => planExecRequest(text, { graphs: async () => graphs })))(item.text);
|
|
286
|
+
const plans = await (this.deps.plan ?? ((text: string, attachments?: readonly ExecAttachment[]) => planExecRequest(text, { graphs: async () => graphs, attachments })))(item.text, item.attachments);
|
|
213
287
|
const byId = new Map(graphs.map(graph => [graph.id, graph]));
|
|
288
|
+
// Every clause must be a question — «상황 알려줘? 카드 만들어줘» carries a work item (review r1).
|
|
289
|
+
const clauses = [...item.text.trim().matchAll(/([^??.!。\n]+)([??]?)/g)].map(m => ({ body: m[1]!.trim(), asked: m[2] !== '' })).filter(c => c.body);
|
|
290
|
+
const isQuestion = clauses.length > 0 && clauses.every(c => c.asked
|
|
291
|
+
|| /(?:알려\s*줘|알려\s*주세요|보여\s*줘|보여\s*주세요|어떻게|무엇|뭐|어떤|언제|누구|질문|인가요|나요|습니까)$/.test(c.body));
|
|
292
|
+
if (isQuestion && plans.length > 0 && plans.every(plan => !plan.graphId
|
|
293
|
+
&& !/\s—\s.+\s필요\s*$/.test(plan.title) && !/\s—\s.+\s필요\s*$/.test(plan.reason ?? '')
|
|
294
|
+
&& !/(?:초안|작성|제작|생성|게시|분석|전략|메일|보고서)/.test(plan.title)) && !(item.attachments?.length)) {
|
|
295
|
+
for (const plan of plans) {
|
|
296
|
+
const answered = await (this.deps.answer ?? answerAsSeat)(plan.seat, item.text);
|
|
297
|
+
if (!answered) {
|
|
298
|
+
item.seats.push({ seat: plan.seat, title: plan.title, status: 'failed', graphId: '', runId: '',
|
|
299
|
+
reason: plan.reason ?? `${plan.seat}: 요청에 맞는 설치된 실행 그래프가 없습니다` });
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const seat: ExecSeat = { seat: plan.seat, title: plan.title, status: 'done', graphId: 'seat-answer', runId: randomUUID(), ...(plan.output ? { output: plan.output } : {}) };
|
|
303
|
+
const dir = join(this.root, 'graph-runs', seat.graphId);
|
|
304
|
+
const statePath = join(dir, `${seat.runId}.json`);
|
|
305
|
+
const artifactDir = join(dir, `${seat.runId}.json.artifacts`);
|
|
306
|
+
mkdirSync(artifactDir, { recursive: true });
|
|
307
|
+
const file = join(artifactDir, TEXT_RESULT_NAME);
|
|
308
|
+
writeFileSync(file, redactSecrets(answered.text.slice(0, TEXT_RESULT_LIMIT)), { mode: 0o600 });
|
|
309
|
+
const state: GraphRunState = { graphId: seat.graphId, runId: seat.runId, status: 'done', path: [], executed: 0, dryRun: false, statePath, nodes: [] };
|
|
310
|
+
writeFileSync(statePath, JSON.stringify(state), { mode: 0o600 });
|
|
311
|
+
item.seats.push(seat);
|
|
312
|
+
const result = resultOf({ file, title: answered.title }, seat, id, this.root);
|
|
313
|
+
if (result) {
|
|
314
|
+
item.results.push(result);
|
|
315
|
+
recordResult(result, item.id, this.root, seat.output ?? 'file');
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
item.status = 'running';
|
|
319
|
+
aggregate(item);
|
|
320
|
+
this.store.save(item);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
214
323
|
item.seats = plans.map(plan => ({ seat: plan.seat, title: plan.title, status: plan.reason || !byId.has(plan.graphId) ? 'failed' : 'waiting', graphId: plan.graphId,
|
|
215
|
-
runId: plan.reason || !byId.has(plan.graphId) ? '' : randomUUID(), inputs: plan.inputs, ...(plan.after?.length ? { after: plan.after } : {}),
|
|
324
|
+
runId: plan.reason || !byId.has(plan.graphId) ? '' : randomUUID(), inputs: plan.inputs, ...(plan.output ? { output: plan.output } : {}), ...(plan.after?.length ? { after: plan.after } : {}),
|
|
216
325
|
...(plan.reason || !byId.has(plan.graphId) ? { reason: plan.reason ?? `${plan.seat}: 요청에 맞는 설치된 실행 그래프가 없습니다` } : {}) }));
|
|
217
326
|
item.status = 'running';
|
|
218
327
|
debug.log('exec-requests', 'planned', { id, seats: item.seats.map(seat => ({ seat: seat.seat, graphId: seat.graphId, status: seat.status })) });
|
|
@@ -366,12 +475,14 @@ export class ExecRequestRunner {
|
|
|
366
475
|
for (const entry of Array.isArray(output.artifacts) ? output.artifacts : [output]) {
|
|
367
476
|
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) continue;
|
|
368
477
|
const artifact = entry as Record<string, unknown>;
|
|
369
|
-
const candidate =
|
|
478
|
+
const candidate = fileCandidate(artifact);
|
|
370
479
|
if (typeof candidate !== 'string') continue;
|
|
371
480
|
const path = safeFile(candidate, this.root, seat.graphId, seat.runId);
|
|
372
481
|
if (path && fileName(path, seat.runId) === name) return path;
|
|
373
482
|
}
|
|
374
483
|
}
|
|
484
|
+
const text = safeFile(join(this.root, 'graph-runs', seat.graphId, `${seat.runId}.json.artifacts`, TEXT_RESULT_NAME), this.root, seat.graphId, seat.runId);
|
|
485
|
+
if (text && fileName(text, seat.runId) === name) return text;
|
|
375
486
|
} catch { return null; }
|
|
376
487
|
return null;
|
|
377
488
|
}
|
|
@@ -2,6 +2,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { getElanousConfigDir } from '../elanous-config-dir.js';
|
|
5
|
+
import type { OutputKind } from './default-outputs.js';
|
|
5
6
|
|
|
6
7
|
export type SeatStatus = 'waiting' | 'running' | 'done' | 'failed';
|
|
7
8
|
export interface ExecSeat {
|
|
@@ -10,6 +11,8 @@ export interface ExecSeat {
|
|
|
10
11
|
status: SeatStatus;
|
|
11
12
|
graphId: string;
|
|
12
13
|
runId: string;
|
|
14
|
+
/** Requested output category, distinct from the result file MIME kind. */
|
|
15
|
+
output?: OutputKind;
|
|
13
16
|
inputs?: Record<string, unknown>;
|
|
14
17
|
reason?: string;
|
|
15
18
|
/** A5b — indexes of earlier seats this seat waits for. */
|
|
@@ -22,9 +25,15 @@ export interface ExecResult {
|
|
|
22
25
|
url: string;
|
|
23
26
|
sources?: Array<{ title: string; url: string }>;
|
|
24
27
|
}
|
|
28
|
+
export interface ExecAttachment {
|
|
29
|
+
name: string;
|
|
30
|
+
path: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
25
33
|
export interface ExecRequest {
|
|
26
34
|
id: string;
|
|
27
35
|
text: string;
|
|
36
|
+
attachments?: ExecAttachment[];
|
|
28
37
|
createdAt: string;
|
|
29
38
|
status: 'planning' | 'running' | 'done' | 'failed';
|
|
30
39
|
summary: string;
|
|
@@ -39,8 +48,8 @@ export class ExecRequestStore {
|
|
|
39
48
|
readonly dir: string;
|
|
40
49
|
constructor(configDir = getElanousConfigDir()) { this.dir = join(configDir, 'exec-requests'); }
|
|
41
50
|
|
|
42
|
-
create(text: string): ExecRequest {
|
|
43
|
-
const item: ExecRequest = { id: randomUUID(), text, createdAt: new Date().toISOString(), status: 'planning', summary: '', seats: [], results: [], approvals: [] };
|
|
51
|
+
create(text: string, attachments?: ExecAttachment[]): ExecRequest {
|
|
52
|
+
const item: ExecRequest = { id: randomUUID(), text, ...(attachments !== undefined ? { attachments } : {}), createdAt: new Date().toISOString(), status: 'planning', summary: '', seats: [], results: [], approvals: [] };
|
|
44
53
|
this.save(item);
|
|
45
54
|
return item;
|
|
46
55
|
}
|