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
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { chmodSync, mkdirSync, readFileSync, rmSync } from 'node:fs';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { join, resolve } from 'node:path';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { debug } from './debug/log.js';
|
|
6
|
+
import { effectiveInstanceRoot } from './instance/resolve.js';
|
|
7
|
+
import { runGraph } from './graph-runner/runner.js';
|
|
8
|
+
import { cardShape, detectCard, runCardFollowup, NotACardError, type CardDetectDecision } from './card-followup/core.js';
|
|
9
|
+
import type { TgIncoming } from './telegram.js';
|
|
10
|
+
|
|
11
|
+
// Latin keywords are whole words only — «postcard» or «cardinal» is not a card request (review round 3).
|
|
12
|
+
const KEYWORD = /명함|전략|메일\s*초안|초안|팔로업|\bcard\b|\bCRM\b/i;
|
|
13
|
+
/** Untagged albums start one graph run, not one per photo (chatId:mediaGroupId → first seen at). */
|
|
14
|
+
const startedAlbums = new Map<string, number>();
|
|
15
|
+
const ALBUM_TTL_MS = 10 * 60_000;
|
|
16
|
+
function firstOfAlbum(chatId: number, mediaGroupId: string | undefined, now: number): boolean {
|
|
17
|
+
if (!mediaGroupId) return true;
|
|
18
|
+
for (const [key, at] of startedAlbums) if (now - at > ALBUM_TTL_MS) startedAlbums.delete(key);
|
|
19
|
+
const key = `${chatId}:${mediaGroupId}`;
|
|
20
|
+
if (startedAlbums.has(key)) return false;
|
|
21
|
+
startedAlbums.set(key, now);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { cardShape, cardText } from './card-followup/core.js';
|
|
26
|
+
const OCR_SCRIPT = resolve(import.meta.dir, '../scripts/ocr-text-regions.swift');
|
|
27
|
+
/** Local macOS Vision OCR (no network · no new dependency); null where it cannot run. */
|
|
28
|
+
export function localOcrText(path: string, timeoutMs = 30_000): Promise<string | null> {
|
|
29
|
+
if (process.platform !== 'darwin') return Promise.resolve(null);
|
|
30
|
+
return new Promise((done) => {
|
|
31
|
+
let out = '';
|
|
32
|
+
let child: ReturnType<typeof spawn>;
|
|
33
|
+
try { child = spawn('swift', [OCR_SCRIPT, path], { stdio: ['ignore', 'pipe', 'ignore'] }); } catch { done(null); return; }
|
|
34
|
+
const timer = setTimeout(() => { child.kill('SIGKILL'); done(null); }, timeoutMs);
|
|
35
|
+
child.stdout?.on('data', (chunk) => { out += String(chunk); });
|
|
36
|
+
child.once('error', () => { clearTimeout(timer); done(null); });
|
|
37
|
+
child.once('close', (code) => {
|
|
38
|
+
clearTimeout(timer);
|
|
39
|
+
if (code !== 0) { done(null); return; }
|
|
40
|
+
done(out.split('\n').map((l) => /^\s+[\d.]+\s+(.*?)\s+box=/.exec(l)?.[1]).filter(Boolean).join('\n'));
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type Picked = 'all' | 'strategy' | 'draft' | 'crm';
|
|
46
|
+
export interface CardPhotoDeps {
|
|
47
|
+
isOwner: (userId: number) => boolean;
|
|
48
|
+
isFieldAlbum?: (id: string) => boolean;
|
|
49
|
+
downloadFile: (fileId: string, destDir: string) => Promise<{ localPath: string }>;
|
|
50
|
+
sendMessage: (chatId: number, text: string, opts: { replyTo: number; threadId?: number }) => Promise<unknown>;
|
|
51
|
+
sendDocument: (chatId: number, body: string | Buffer, filename: string, opts: { replyTo: number; threadId?: number; mimeType?: string }) => Promise<unknown>;
|
|
52
|
+
runGraph?: typeof runGraph;
|
|
53
|
+
rootDir?: () => string;
|
|
54
|
+
/** OCR text of a downloaded photo, or null when unavailable (default: local macOS Vision). */
|
|
55
|
+
ocrText?: (path: string) => Promise<string | null>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function pick(caption: string): Picked {
|
|
59
|
+
if (/\bCRM\b/i.test(caption)) return 'crm';
|
|
60
|
+
if (/메일\s*초안|초안/i.test(caption)) return 'draft';
|
|
61
|
+
if (/전략/.test(caption)) return 'strategy';
|
|
62
|
+
return 'all';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Starts a private graph run without blocking the Telegram message turn. */
|
|
66
|
+
export async function maybeHandleCardPhoto(ctx: TgIncoming, deps: CardPhotoDeps): Promise<boolean> {
|
|
67
|
+
const photo = ctx.attachments.find((att) => att.kind === 'photo');
|
|
68
|
+
const caption = ctx.text.trim();
|
|
69
|
+
if (!ctx.isDm || ctx.isGroup || !deps.isOwner(ctx.userId) || !photo
|
|
70
|
+
|| (ctx.mediaGroupId && deps.isFieldAlbum?.(ctx.mediaGroupId))
|
|
71
|
+
|| /#현장/.test(caption) || (caption && !KEYWORD.test(caption))) return false;
|
|
72
|
+
const detect = (decision: CardDetectDecision, signal: string) =>
|
|
73
|
+
debug.log('telegram.card-followup', 'detect', { chatId: ctx.chatId, decision, signal });
|
|
74
|
+
if (!caption) {
|
|
75
|
+
const shape = cardShape(photo.width, photo.height);
|
|
76
|
+
if (shape.decision === 'skip') { detect('skip', shape.signal); return false; }
|
|
77
|
+
}
|
|
78
|
+
// Album items after the first: a keyword caption sits on one item only, so later items follow the normal flow.
|
|
79
|
+
if (!firstOfAlbum(ctx.chatId, ctx.mediaGroupId, Date.now())) return false;
|
|
80
|
+
|
|
81
|
+
const picked = pick(caption);
|
|
82
|
+
const started = Date.now();
|
|
83
|
+
const reply = { replyTo: ctx.messageId, ...(ctx.threadId === undefined ? {} : { threadId: ctx.threadId }) };
|
|
84
|
+
const log = (event: 'started' | 'not-a-card' | 'replied' | 'failed') =>
|
|
85
|
+
debug.log('card.followup', event, { chatId: ctx.chatId, picked, ms: Date.now() - started });
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const root = (deps.rootDir ?? effectiveInstanceRoot)();
|
|
89
|
+
const base = join(root, 'graph-runs', 'card-followup');
|
|
90
|
+
const runId = randomUUID();
|
|
91
|
+
const dir = join(base, runId);
|
|
92
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
93
|
+
chmodSync(base, 0o700);
|
|
94
|
+
chmodSync(dir, 0o700);
|
|
95
|
+
const prepare = async (): Promise<string | null> => {
|
|
96
|
+
const { localPath } = await deps.downloadFile(photo.fileId, dir);
|
|
97
|
+
chmodSync(localPath, 0o600);
|
|
98
|
+
if (!caption) {
|
|
99
|
+
const verdict = detectCard({ width: photo.width, height: photo.height, ocrText: await (deps.ocrText ?? localOcrText)(localPath) });
|
|
100
|
+
detect(verdict.decision, verdict.signal);
|
|
101
|
+
if (verdict.decision !== 'card') { rmSync(dir, { recursive: true, force: true }); return null; }
|
|
102
|
+
}
|
|
103
|
+
log('started');
|
|
104
|
+
await deps.sendMessage(ctx.chatId, '명함으로 보고 정리하는 중입니다(1~3분)', reply);
|
|
105
|
+
return localPath;
|
|
106
|
+
};
|
|
107
|
+
// A keyword caption is an explicit request: download before returning. A bare photo is judged in the background.
|
|
108
|
+
const prepared = caption ? await prepare() : null;
|
|
109
|
+
void (async () => {
|
|
110
|
+
let localPath = prepared;
|
|
111
|
+
try {
|
|
112
|
+
if (!caption) {
|
|
113
|
+
try { localPath = await prepare(); } catch { log('failed'); return; }
|
|
114
|
+
if (!localPath) return;
|
|
115
|
+
}
|
|
116
|
+
let result;
|
|
117
|
+
try {
|
|
118
|
+
result = await runCardFollowup({ imagePath: localPath!, ocrText: null,
|
|
119
|
+
runGraph: deps.runGraph ?? runGraph, rootDir: root, outDir: dir, runId,
|
|
120
|
+
...(caption ? { context: caption } : {}),
|
|
121
|
+
});
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (error instanceof NotACardError) { log('not-a-card'); return; }
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
const markdown = readFileSync(result.followupPath!);
|
|
127
|
+
const crmLine = picked === 'crm'
|
|
128
|
+
? /^## ② CRM 한 줄\r?\n파일: [^\r\n]*\r?\n([^\r\n]+)/m.exec(markdown.toString('utf8'))?.[1]
|
|
129
|
+
: undefined;
|
|
130
|
+
if (picked === 'crm' && !crmLine) throw new Error('CRM row missing from report');
|
|
131
|
+
const messages = picked === 'strategy' ? [result.replies[1]] : picked === 'draft' ? [result.replies[2]] : picked === 'crm' ? [`CRM 한 줄\n${crmLine}`] : result.replies;
|
|
132
|
+
for (const message of messages) await deps.sendMessage(ctx.chatId, message, reply);
|
|
133
|
+
const sent = await deps.sendDocument(ctx.chatId, markdown, 'followup.md', { ...reply, mimeType: 'text/markdown' });
|
|
134
|
+
if (sent === undefined) throw new Error('document delivery failed');
|
|
135
|
+
log('replied');
|
|
136
|
+
} catch {
|
|
137
|
+
log('failed');
|
|
138
|
+
try {
|
|
139
|
+
await deps.sendMessage(ctx.chatId, '명함 정리에 실패했습니다. 다시 시도해 주세요.', reply);
|
|
140
|
+
} catch { /* Telegram delivery itself failed; the failure is already observed. */ }
|
|
141
|
+
}
|
|
142
|
+
})();
|
|
143
|
+
} catch {
|
|
144
|
+
log('failed');
|
|
145
|
+
// A bare photo was never claimed as a card — failing to prepare it stays silent.
|
|
146
|
+
if (caption) {
|
|
147
|
+
try {
|
|
148
|
+
await deps.sendMessage(ctx.chatId, '명함 정리에 실패했습니다. 다시 시도해 주세요.', reply);
|
|
149
|
+
} catch { /* Telegram delivery itself failed; the failure is already observed. */ }
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return !!caption;
|
|
153
|
+
}
|
package/src/telegram-commands.ts
CHANGED
|
@@ -44,6 +44,9 @@ import { readDaemonSessionHistory } from './telegram/daemon-history-reader.js';
|
|
|
44
44
|
import { renderTelegramReplayPreviewHtml } from './telegram/replay-preview.js';
|
|
45
45
|
import { classifyIntake } from './ad-pipeline/intake.js';
|
|
46
46
|
import { createAdPipelineDeps, runAdPipeline } from './ad-pipeline/run.js';
|
|
47
|
+
import { projectCommand } from './telegram-project-command.js';
|
|
48
|
+
import { telegramNowSlash } from './context-bus/context-now-surfaces.js';
|
|
49
|
+
import type { ContextNowDeps } from './context-bus/context-now.js';
|
|
47
50
|
|
|
48
51
|
/** How many prior user/assistant turns to pass into `executeSkill` as
|
|
49
52
|
* the `## Recent conversation` block. Mirrors the dashboard default
|
|
@@ -291,7 +294,7 @@ function dropChatSessionReply(ctx: TgIncoming): string {
|
|
|
291
294
|
/** Build the default command set for a Telegram bot wired via
|
|
292
295
|
* botFromConfig. Returns the array rather than mutating globals so
|
|
293
296
|
* tests can construct a variant set with stubbed handlers. */
|
|
294
|
-
export function defaultTelegramCommands(): TgSlashCommand[] {
|
|
297
|
+
export function defaultTelegramCommands(nowDeps?: ContextNowDeps): TgSlashCommand[] {
|
|
295
298
|
return [
|
|
296
299
|
{
|
|
297
300
|
name: 'help',
|
|
@@ -304,6 +307,11 @@ export function defaultTelegramCommands(): TgSlashCommand[] {
|
|
|
304
307
|
return lines.join('\n');
|
|
305
308
|
},
|
|
306
309
|
},
|
|
310
|
+
{
|
|
311
|
+
name: 'now',
|
|
312
|
+
description: 'Show current release, decisions, seats and context: /now [topic]',
|
|
313
|
+
handler: async (args) => telegramNowSlash(args, nowDeps),
|
|
314
|
+
},
|
|
307
315
|
{
|
|
308
316
|
name: 'status',
|
|
309
317
|
description: 'Show bot identity, current session, provider + model',
|
|
@@ -581,6 +589,7 @@ export function defaultTelegramCommands(): TgSlashCommand[] {
|
|
|
581
589
|
return lines.join('\n');
|
|
582
590
|
},
|
|
583
591
|
},
|
|
592
|
+
projectCommand(),
|
|
584
593
|
{
|
|
585
594
|
name: 'fork',
|
|
586
595
|
description: 'Fork the current chat session (or /fork <prefix>) and continue HERE on the fork · time-travel: /fork before:N',
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { debug } from './debug/log.js';
|
|
2
|
+
import { getProject, listProjects, type Project } from './project/project-store.js';
|
|
3
|
+
import { findSessionByTelegramChat, updateSessionMeta } from './session/index.js';
|
|
4
|
+
import type { TgSlashCommand } from './telegram-commands.js';
|
|
5
|
+
|
|
6
|
+
export interface TelegramProjectCommandDeps {
|
|
7
|
+
list: () => Project[];
|
|
8
|
+
find: (id: string) => Project | null;
|
|
9
|
+
update: typeof updateSessionMeta;
|
|
10
|
+
findSession: typeof findSessionByTelegramChat;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function projectCommand(deps: TelegramProjectCommandDeps = {
|
|
14
|
+
list: listProjects,
|
|
15
|
+
find: getProject,
|
|
16
|
+
update: updateSessionMeta,
|
|
17
|
+
findSession: findSessionByTelegramChat,
|
|
18
|
+
}): TgSlashCommand {
|
|
19
|
+
return {
|
|
20
|
+
name: 'project',
|
|
21
|
+
description: '이 대화의 프로젝트 보기·옮기기',
|
|
22
|
+
handler: async (args, ctx) => {
|
|
23
|
+
const session = deps.findSession(ctx.chatId, ctx.threadId, ctx.botId);
|
|
24
|
+
if (!session) {
|
|
25
|
+
debug.log('telegram.project', 'rejected', { projects: [], reason: 'no-session' });
|
|
26
|
+
return '아직 이 채팅에 대화가 없습니다 — 한 마디 보낸 뒤 다시';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (args.length === 0) {
|
|
30
|
+
const current = session.projectId ? deps.find(session.projectId) : null;
|
|
31
|
+
const projects = deps.list().sort((a, b) => a.name.localeCompare(b.name)).slice(0, 20);
|
|
32
|
+
debug.log('telegram.project', 'listed', { projects: projects.map(p => ({ id: p.id, name: p.name })) });
|
|
33
|
+
return [
|
|
34
|
+
`지금 대화의 프로젝트: ${current?.name ?? '받은 대화(프로젝트 없음)'}`,
|
|
35
|
+
'',
|
|
36
|
+
'프로젝트 목록:',
|
|
37
|
+
...projects.map(p => `• ${p.name}`),
|
|
38
|
+
'',
|
|
39
|
+
'옮기려면 /project <이름>',
|
|
40
|
+
].join('\n');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const name = args.join(' ').trim();
|
|
44
|
+
if (name === '-') {
|
|
45
|
+
deps.update(session.id, m => { delete m.projectId; });
|
|
46
|
+
debug.log('telegram.project', 'cleared', { projects: [] });
|
|
47
|
+
return '받은 대화로 옮겼습니다';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const projects = deps.list();
|
|
51
|
+
const normalized = name.toLocaleLowerCase();
|
|
52
|
+
const exact = projects.filter(p => p.name.toLocaleLowerCase() === normalized);
|
|
53
|
+
const matches = exact.length ? exact : projects.filter(p => p.name.toLocaleLowerCase().startsWith(normalized));
|
|
54
|
+
if (matches.length === 0) {
|
|
55
|
+
debug.log('telegram.project', 'rejected', { projects: [], reason: 'not-found' });
|
|
56
|
+
return '그 이름의 프로젝트가 없습니다 — /project 로 목록 보기';
|
|
57
|
+
}
|
|
58
|
+
if (matches.length > 1) {
|
|
59
|
+
debug.log('telegram.project', 'rejected', {
|
|
60
|
+
projects: matches.map(p => ({ id: p.id, name: p.name })), reason: 'ambiguous',
|
|
61
|
+
});
|
|
62
|
+
return `여러 프로젝트가 맞습니다 — 이름을 골라 주세요:\n${matches.map(p => `• ${p.name}`).join('\n')}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const project = matches[0]!;
|
|
66
|
+
deps.update(session.id, m => { m.projectId = project.id; });
|
|
67
|
+
debug.log('telegram.project', 'moved', { projects: [{ id: project.id, name: project.name }] });
|
|
68
|
+
return `이 대화를 ${project.name} 프로젝트로 옮겼습니다`;
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
package/src/telegram-report.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// the report channel while interactive Q&A stays on the main bot.
|
|
12
12
|
|
|
13
13
|
import { TelegramBot } from './telegram.js';
|
|
14
|
-
import { kindRouteTarget } from './domains/telegram-kind-route.js';
|
|
14
|
+
import { isTradingKind, kindRouteTarget, logKindRouteFallback, mainHomeTarget } from './domains/telegram-kind-route.js';
|
|
15
15
|
export { DEFAULT_KIND_ROLES, roleForKind } from './domains/telegram-kind-route.js';
|
|
16
16
|
import { resolveChannelBotToken } from './channel-bot-token.js';
|
|
17
17
|
import type { UserConfig } from './user-config.js';
|
|
@@ -51,18 +51,29 @@ export interface ReportTarget {
|
|
|
51
51
|
chatId: number;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
/**
|
|
55
|
-
* the
|
|
56
|
-
*
|
|
57
|
-
* same bot. Returns null when nothing is configured. */
|
|
54
|
+
/** An exact role channel wins. A configured channels table cannot silently fall through
|
|
55
|
+
* to the legacy report bot or a channel with a different role. Without that table, only
|
|
56
|
+
* named finance kinds can use the legacy trading report channel. */
|
|
58
57
|
export function resolveReportTarget(cfg: UserConfig, kind?: string): ReportTarget | null {
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
if (cfg.telegram.channels?.length) {
|
|
59
|
+
const routed = kindRouteTarget(cfg, kind);
|
|
60
|
+
if (routed) return routed;
|
|
61
|
+
logKindRouteFallback(kind, 'none', false);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
61
64
|
const rc = cfg.telegram.reportChannel;
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
if (!
|
|
65
|
-
|
|
65
|
+
const mainToken = resolveChannelBotToken('telegram', cfg).token;
|
|
66
|
+
const sameBot = !!mainToken && !!rc && (rc.botToken ?? mainToken) === mainToken;
|
|
67
|
+
if (!isTradingKind(kind)) {
|
|
68
|
+
const home = mainHomeTarget(cfg);
|
|
69
|
+
logKindRouteFallback(kind, home ? 'main-home' : 'none', sameBot);
|
|
70
|
+
return home;
|
|
71
|
+
}
|
|
72
|
+
const botToken = rc?.botToken;
|
|
73
|
+
const target = rc && Number.isFinite(rc.chatId) && botToken && botToken !== mainToken
|
|
74
|
+
? { botToken, chatId: rc.chatId } : null;
|
|
75
|
+
logKindRouteFallback(kind, target ? 'report-channel' : 'none', sameBot);
|
|
76
|
+
return target;
|
|
66
77
|
}
|
|
67
78
|
|
|
68
79
|
export interface SendReportOpts {
|
|
@@ -75,10 +86,9 @@ export interface SendReportOpts {
|
|
|
75
86
|
kind?: string;
|
|
76
87
|
}
|
|
77
88
|
|
|
78
|
-
/** Send a report to
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* Telegram API failure once a target exists. */
|
|
89
|
+
/** Send a report to its kind's exact-role channel (or the safe legacy target).
|
|
90
|
+
* Returns false when no safe target exists; throws only on an actual
|
|
91
|
+
* Telegram API failure after a target has been selected. */
|
|
82
92
|
export async function sendTelegramReport(
|
|
83
93
|
cfg: UserConfig,
|
|
84
94
|
text: string,
|
|
@@ -104,9 +114,9 @@ export async function sendTelegramReport(
|
|
|
104
114
|
export async function sendReportPhoto(
|
|
105
115
|
cfg: UserConfig,
|
|
106
116
|
photoUrl: string,
|
|
107
|
-
opts: { caption?: string; fetchImpl?: typeof fetch } = {},
|
|
117
|
+
opts: { caption?: string; fetchImpl?: typeof fetch; kind?: string } = {},
|
|
108
118
|
): Promise<boolean> {
|
|
109
|
-
const target = resolveReportTarget(cfg);
|
|
119
|
+
const target = resolveReportTarget(cfg, opts.kind);
|
|
110
120
|
if (!target || !photoUrl) return false;
|
|
111
121
|
const bot = new TelegramBot({
|
|
112
122
|
token: target.botToken,
|
|
@@ -125,9 +135,9 @@ export async function sendReportPhoto(
|
|
|
125
135
|
export async function sendReportPhotoBuffer(
|
|
126
136
|
cfg: UserConfig,
|
|
127
137
|
png: Buffer,
|
|
128
|
-
opts: { caption?: string; fetchImpl?: typeof fetch } = {},
|
|
138
|
+
opts: { caption?: string; fetchImpl?: typeof fetch; kind?: string } = {},
|
|
129
139
|
): Promise<boolean> {
|
|
130
|
-
const target = resolveReportTarget(cfg);
|
|
140
|
+
const target = resolveReportTarget(cfg, opts.kind);
|
|
131
141
|
if (!target || !png) return false;
|
|
132
142
|
const bot = new TelegramBot({
|
|
133
143
|
token: target.botToken,
|
package/src/telegram-run.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { effectiveInstanceRoot } from './instance/resolve.js';
|
|
|
18
18
|
import { getUserConfig } from './user-config.js';
|
|
19
19
|
import { resolveChannelBotToken } from './channel-bot-token.js';
|
|
20
20
|
import { forwardTelegramDispatch } from './telegram-dispatch-forward.js';
|
|
21
|
+
import { mergeCapturedPath, warmCapturedEnv } from './shell-env-bootstrap.js';
|
|
21
22
|
import type { NexusTelegramQaPollerWireHandle } from './nexus/index.js';
|
|
22
23
|
|
|
23
24
|
export interface TelegramRunResult {
|
|
@@ -138,7 +139,13 @@ export async function runTelegramPoller(deps: {
|
|
|
138
139
|
alert?: (text: string, kind: string) => boolean;
|
|
139
140
|
wait?: () => Promise<void>;
|
|
140
141
|
registerLogSink?: () => Promise<void>;
|
|
142
|
+
warm?: () => Promise<boolean>;
|
|
141
143
|
} = {}): Promise<void> {
|
|
144
|
+
void (deps.warm ?? warmCapturedEnv)().then((ok) => {
|
|
145
|
+
if (ok) mergeCapturedPath();
|
|
146
|
+
}).catch((error) => {
|
|
147
|
+
debug.log('shell.envbootstrap.capture', 'warm-failed', { error: String(error) });
|
|
148
|
+
});
|
|
142
149
|
try {
|
|
143
150
|
if (deps.registerLogSink) await deps.registerLogSink();
|
|
144
151
|
else {
|
package/src/telegram.ts
CHANGED
|
@@ -25,6 +25,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
25
25
|
import { buildTurnOutputTextBlocks } from './input/turn-output-block.js';
|
|
26
26
|
import { selectTurnOutputTextForSink } from './input/turn-output-sink-registry.js';
|
|
27
27
|
import { debug } from './debug/log.js';
|
|
28
|
+
import { botAudienceFor, filterBotCommands, readBotAudience } from './maturity/bot-command-maturity.js';
|
|
28
29
|
import { resolveChannelBotToken } from './channel-bot-token.js';
|
|
29
30
|
import type { TelegramVoiceAdapter } from './voice/channel-adapters/telegram-voice-adapter.js';
|
|
30
31
|
import { createTelegramSurfaceHitl, type TelegramSurfaceHitl } from './hitl/telegram-surface-hitl.js';
|
|
@@ -67,10 +68,12 @@ import { runUrlRoute } from './skills/url-route-exec.js';
|
|
|
67
68
|
import { recordRoutedLinkAbsorbed } from './intake-plane/link-ledger.js';
|
|
68
69
|
import { classifyFrontInput } from './intake-plane/front-classifier.js';
|
|
69
70
|
import { handleTelegramSeatWork, type TelegramSeatWorkDeps } from './intake-plane/telegram-seat-work.js';
|
|
71
|
+
import { deliverSeatAnswers } from './seat-dispatch/seat-ask.js';
|
|
70
72
|
import { effectiveInstanceRoot } from './instance/resolve.js';
|
|
71
73
|
import { getElanousConfigDir } from './elanous-config-dir.js';
|
|
72
74
|
import { defaultFieldEvent, FieldUploadError, parseFieldCaption, resolveFieldMime, saveFieldMedia } from './field/field-media.js';
|
|
73
75
|
import { scheduleFieldReel, type FieldReelOptions } from './field/field-reel.js';
|
|
76
|
+
import { maybeHandleCardPhoto, type CardPhotoDeps } from './telegram-card-followup.js';
|
|
74
77
|
|
|
75
78
|
export type TgAttachmentKind = 'photo' | 'voice' | 'audio' | 'document';
|
|
76
79
|
|
|
@@ -216,6 +219,8 @@ export interface TelegramBotOpts {
|
|
|
216
219
|
fieldRootDir?: () => string;
|
|
217
220
|
/** 시험에서는 실제 렌더 대신 가짜 실행기를 주입한다. */
|
|
218
221
|
fieldReel?: FieldReelOptions;
|
|
222
|
+
/** Test seam for the business-card graph and its private run root. */
|
|
223
|
+
cardFollowupDeps?: Pick<CardPhotoDeps, 'runGraph' | 'rootDir' | 'ocrText'>;
|
|
219
224
|
}
|
|
220
225
|
|
|
221
226
|
/** Surface-unification v2 (FU-2) — Telegram trigger event passed to
|
|
@@ -333,10 +338,12 @@ export class TelegramBot {
|
|
|
333
338
|
private readonly fieldDefaultEventOpt?: string;
|
|
334
339
|
private readonly fieldRootDir: () => string;
|
|
335
340
|
private readonly fieldReel?: FieldReelOptions;
|
|
341
|
+
private readonly cardFollowupDeps: Pick<CardPhotoDeps, 'runGraph' | 'rootDir' | 'ocrText'>;
|
|
336
342
|
private readonly seatWorkDeps: TelegramSeatWorkDeps;
|
|
343
|
+
private seatAskTimer: ReturnType<typeof setInterval> | null = null;
|
|
337
344
|
/** 앨범 id → `#현장` 행사 · 답장 디바운스. 태그된 앨범만 들어온다. */
|
|
338
345
|
private readonly fieldGroups = new Map<string, {
|
|
339
|
-
event: string; at: number; chatId: number; threadId?: number; replyTo: number; count: number;
|
|
346
|
+
event: string; mode?: 'instant'; at: number; chatId: number; threadId?: number; replyTo: number; count: number;
|
|
340
347
|
timer?: ReturnType<typeof setTimeout>;
|
|
341
348
|
}>();
|
|
342
349
|
|
|
@@ -368,7 +375,16 @@ export class TelegramBot {
|
|
|
368
375
|
this.fieldDefaultEventOpt = opts.fieldDefaultEvent;
|
|
369
376
|
this.fieldRootDir = opts.fieldRootDir ?? getElanousConfigDir;
|
|
370
377
|
this.fieldReel = opts.fieldReel;
|
|
371
|
-
this.
|
|
378
|
+
this.cardFollowupDeps = opts.cardFollowupDeps ?? {};
|
|
379
|
+
this.seatWorkDeps = { ...opts.seatWorkDeps, askDeps: { ...opts.seatWorkDeps?.askDeps,
|
|
380
|
+
channel: 'telegram', botId: this.botId,
|
|
381
|
+
send: opts.seatWorkDeps?.askDeps?.send ?? (async (origin, text) => {
|
|
382
|
+
if (origin.channel !== 'telegram') throw new Error('seat ask belongs to another surface');
|
|
383
|
+
const posted = await this.sendMessage(Number(origin.chatId), text, { replyTo: origin.messageId, threadId: origin.threadId });
|
|
384
|
+
if (!posted) throw new Error('Telegram seat ask reply was not posted');
|
|
385
|
+
}),
|
|
386
|
+
} };
|
|
387
|
+
|
|
372
388
|
if (opts.onTriggerTap) {
|
|
373
389
|
// Assign through `as unknown` to bypass `readonly` + private —
|
|
374
390
|
// the tap is set once at construction and never reassigned.
|
|
@@ -376,7 +392,7 @@ export class TelegramBot {
|
|
|
376
392
|
}
|
|
377
393
|
}
|
|
378
394
|
|
|
379
|
-
|
|
395
|
+
isOwnerAllowed(userId: number): boolean {
|
|
380
396
|
return this.allowedUsers.size > 0 && this.allowedUsers.has(userId);
|
|
381
397
|
}
|
|
382
398
|
|
|
@@ -1115,6 +1131,9 @@ export class TelegramBot {
|
|
|
1115
1131
|
async start(): Promise<void> {
|
|
1116
1132
|
this.running = true;
|
|
1117
1133
|
this.log(`telegram bot starting (allowlist size ${this.allowedUsers.size})`);
|
|
1134
|
+
this.seatAskTimer = setInterval(() => {
|
|
1135
|
+
void deliverSeatAnswers(this.seatWorkDeps.askDeps!).catch((error) => this.log(`seat ask delivery failed: ${String(error)}`));
|
|
1136
|
+
}, 10_000);
|
|
1118
1137
|
if (this.allowedUsers.size === 0) this.log('telegram.owner-gate empty-allowlist');
|
|
1119
1138
|
|
|
1120
1139
|
// Publish the slash-command menu to Telegram. Clients pick up the
|
|
@@ -1123,9 +1142,16 @@ export class TelegramBot {
|
|
|
1123
1142
|
// still processes `/commands` via the incoming-message dispatch
|
|
1124
1143
|
// path, users just don't get the autocomplete.
|
|
1125
1144
|
if (this.slashCommands.length > 0) {
|
|
1145
|
+
const audience = this.slashContext
|
|
1146
|
+
? readBotAudience((this.slashContext.userConfig.raw?.telegram as { commandAudience?: unknown } | undefined)?.commandAudience)
|
|
1147
|
+
: botAudienceFor('telegram');
|
|
1148
|
+
const commands = filterBotCommands('telegram', this.slashCommands, audience);
|
|
1149
|
+
debug.log('telegram.command', 'menu-filtered', {
|
|
1150
|
+
total: this.slashCommands.length, shown: commands.length, ...audience,
|
|
1151
|
+
});
|
|
1126
1152
|
try {
|
|
1127
1153
|
const result = await this.apiCall<unknown>('setMyCommands', {
|
|
1128
|
-
commands: toTelegramBotCommands(
|
|
1154
|
+
commands: toTelegramBotCommands(commands),
|
|
1129
1155
|
});
|
|
1130
1156
|
debug.log('telegram.command', 'published', { success: true, result });
|
|
1131
1157
|
this.log(`telegram: setMyCommands published (${String(result)})`);
|
|
@@ -1146,6 +1172,7 @@ export class TelegramBot {
|
|
|
1146
1172
|
const CONFLICT_BACKOFF_CAP = 60_000;
|
|
1147
1173
|
while (this.running) {
|
|
1148
1174
|
try {
|
|
1175
|
+
await deliverSeatAnswers(this.seatWorkDeps.askDeps!);
|
|
1149
1176
|
const wantCallbackQuery = this.callbackHandlers.size > 0;
|
|
1150
1177
|
const wantReaction = this.reactionHandlers.size > 0;
|
|
1151
1178
|
// allowed_updates 는 명시한 것만 받으므로 등록된 핸들러 종류만 추가(비파괴 — 핸들러
|
|
@@ -1287,7 +1314,11 @@ export class TelegramBot {
|
|
|
1287
1314
|
this.log('telegram bot stopped');
|
|
1288
1315
|
}
|
|
1289
1316
|
|
|
1290
|
-
stop(): void {
|
|
1317
|
+
stop(): void {
|
|
1318
|
+
this.running = false;
|
|
1319
|
+
if (this.seatAskTimer) clearInterval(this.seatAskTimer);
|
|
1320
|
+
this.seatAskTimer = null;
|
|
1321
|
+
}
|
|
1291
1322
|
|
|
1292
1323
|
/** Download + normalize this message's attachments into the shape
|
|
1293
1324
|
* the ACP content-blocks module consumes. Called lazily by slash
|
|
@@ -1415,6 +1446,10 @@ export class TelegramBot {
|
|
|
1415
1446
|
? tag.event ?? defaultFieldEvent(
|
|
1416
1447
|
this.fieldDefaultEventOpt ?? this.slashContext?.userConfig?.telegram?.fieldDefaultEvent, new Date(now))
|
|
1417
1448
|
: group!.event;
|
|
1449
|
+
const captionMode = tag?.mode ?? group?.mode;
|
|
1450
|
+
const configMode = this.slashContext?.userConfig?.telegram?.fieldReelMode;
|
|
1451
|
+
const mode = captionMode ?? configMode ?? 'standard';
|
|
1452
|
+
const source = captionMode ? 'caption' : configMode ? 'config' : 'default';
|
|
1418
1453
|
|
|
1419
1454
|
let count: number | null = null;
|
|
1420
1455
|
let failure: string | null = null;
|
|
@@ -1435,14 +1470,16 @@ export class TelegramBot {
|
|
|
1435
1470
|
// 글(자막)은 캡션이 달린 항목에만 있다 — 앨범이면 첫 장에만 붙는다(MK 2026-09-30).
|
|
1436
1471
|
const saved = saveFieldMedia(inputs, { rootDir: this.fieldRootDir(), event, device: 'telegram', ...(tag?.text ? { caption: tag.text } : {}) });
|
|
1437
1472
|
count = saved.count;
|
|
1473
|
+
debug.log('telegram.field', 'reel-mode', { event, mode, source });
|
|
1438
1474
|
scheduleFieldReel(saved.dir, {
|
|
1439
1475
|
...this.fieldReel,
|
|
1476
|
+
mode,
|
|
1440
1477
|
notificationKey: `telegram:${this.botId}:${ctx.chatId}:${ctx.threadId ?? ''}:${ctx.mediaGroupId ?? ctx.messageId}`,
|
|
1441
1478
|
onDone: async (result) => {
|
|
1442
1479
|
const reply = { replyTo: ctx.messageId, threadId: ctx.threadId };
|
|
1443
1480
|
if (result.ok && result.file) {
|
|
1444
1481
|
const sent = await this.sendDocument(ctx.chatId, readFileSync(result.file), 'reel-9x16.mp4', {
|
|
1445
|
-
...reply, mimeType: 'video/mp4', caption: `현장 영상 · ${event} · ${result.seconds}
|
|
1482
|
+
...reply, mimeType: 'video/mp4', caption: `현장 영상 · ${event} · ${result.seconds}초${mode === 'instant' ? ' (즉석판)' : ''}`,
|
|
1446
1483
|
});
|
|
1447
1484
|
if (!sent) throw new Error('sendDocument failed');
|
|
1448
1485
|
if (result.feed?.started) {
|
|
@@ -1469,7 +1506,8 @@ export class TelegramBot {
|
|
|
1469
1506
|
return true;
|
|
1470
1507
|
}
|
|
1471
1508
|
// 앨범은 항목마다 답하지 않는다 — 마지막 항목 뒤 한 번(디바운스)만 최신 수로 답한다.
|
|
1472
|
-
const entry = group ?? { event, at: now, chatId: ctx.chatId, threadId: ctx.threadId, replyTo: ctx.messageId, count: 0 };
|
|
1509
|
+
const entry = group ?? { event, mode: tag?.mode, at: now, chatId: ctx.chatId, threadId: ctx.threadId, replyTo: ctx.messageId, count: 0 };
|
|
1510
|
+
if (group && tag?.mode) group.mode = tag.mode;
|
|
1473
1511
|
entry.at = now;
|
|
1474
1512
|
entry.count = count!;
|
|
1475
1513
|
if (entry.timer) clearTimeout(entry.timer);
|
|
@@ -1490,10 +1528,18 @@ export class TelegramBot {
|
|
|
1490
1528
|
}
|
|
1491
1529
|
// 현장 업로드 — `#현장` 캡션(또는 태그된 앨범의 나머지)의 사진·영상은 LLM 대신 현장 폴더로.
|
|
1492
1530
|
if (await this.tryHandleFieldUpload(ctx)) return;
|
|
1493
|
-
if (ctx
|
|
1531
|
+
if (await maybeHandleCardPhoto(ctx, {
|
|
1532
|
+
isOwner: (userId) => this.isOwnerAllowed(userId),
|
|
1533
|
+
isFieldAlbum: (id) => this.fieldGroups.has(id),
|
|
1534
|
+
downloadFile: (fileId, dir) => this.downloadFile(fileId, dir),
|
|
1535
|
+
sendMessage: (chatId, text, opts) => this.sendMessage(chatId, text, opts),
|
|
1536
|
+
sendDocument: (chatId, body, filename, opts) => this.sendDocument(chatId, body, filename, opts),
|
|
1537
|
+
...this.cardFollowupDeps,
|
|
1538
|
+
})) return;
|
|
1539
|
+
if (ctx.text.startsWith('@') || (ctx.isDm && ctx.text && !ctx.text.startsWith('/'))) {
|
|
1494
1540
|
const reply = await handleTelegramSeatWork(ctx.text, {
|
|
1495
|
-
chatId: ctx.chatId, messageId: ctx.messageId, threadId: ctx.threadId, botId: ctx.botId,
|
|
1496
|
-
}, this.seatWorkDeps);
|
|
1541
|
+
chatId: ctx.chatId, userId: ctx.userId, messageId: ctx.messageId, threadId: ctx.threadId, botId: ctx.botId,
|
|
1542
|
+
}, { ...this.seatWorkDeps, config: this.seatWorkDeps.config ?? this.slashContext?.userConfig });
|
|
1497
1543
|
if (reply !== null) {
|
|
1498
1544
|
await this.sendMessage(ctx.chatId, reply, { replyTo: ctx.messageId, threadId: ctx.threadId });
|
|
1499
1545
|
return;
|
|
@@ -1529,7 +1575,7 @@ export class TelegramBot {
|
|
|
1529
1575
|
try {
|
|
1530
1576
|
const { addDirective } = await import('./steward/directive.js');
|
|
1531
1577
|
const text = ctx.text.startsWith('지시:') ? ctx.text.slice('지시:'.length) : ctx.text.slice('/directive '.length);
|
|
1532
|
-
const result = await addDirective(text, { source: 'telegram' });
|
|
1578
|
+
const result = await addDirective(text, { source: 'telegram', origin: { chatId: ctx.chatId, botId: ctx.botId, threadId: ctx.threadId } });
|
|
1533
1579
|
await this.sendMessage(ctx.chatId, `${result.issue}: ${result.status}`, { replyTo: ctx.messageId, threadId: ctx.threadId });
|
|
1534
1580
|
} catch {
|
|
1535
1581
|
await this.sendMessage(ctx.chatId, '지시 등록 실패 — Linear 연결과 자격을 확인하세요.', { replyTo: ctx.messageId, threadId: ctx.threadId });
|
|
@@ -2746,6 +2792,7 @@ export function botFromConfig(opts: BotFromConfigOpts): TelegramBot {
|
|
|
2746
2792
|
// (makeTelegramAgentRunTurn) threads it into `delegate_code_agent`
|
|
2747
2793
|
// so a delegated sub-agent's approval prompt lands back here.
|
|
2748
2794
|
hitlConfirmChannel: botRef.hitlConfirmChannelForChat(ctx.chatId, ctx.threadId),
|
|
2795
|
+
...(botRef.isOwnerAllowed(ctx.userId) ? { verifiedOwner: { id: `telegram:${ctx.userId}` } } : {}),
|
|
2749
2796
|
hitlQuestionChannel: botRef.hitlQuestionChannelForChat(ctx.chatId, ctx.threadId),
|
|
2750
2797
|
// P1.4 — surface file spill bound to THIS chat so the NL
|
|
2751
2798
|
// `delegate_code_agent` path spills big diffs/stdout back here.
|
|
@@ -11,6 +11,7 @@ export const SELF_COGNITION_TOOL_NAMES = [
|
|
|
11
11
|
'logs_query',
|
|
12
12
|
'ops_status',
|
|
13
13
|
'memory_recall',
|
|
14
|
+
'context_now',
|
|
14
15
|
] as const;
|
|
15
16
|
|
|
16
17
|
type SelfCognitionToolName = (typeof SELF_COGNITION_TOOL_NAMES)[number];
|
|
@@ -23,7 +24,14 @@ function coreTools(): CoreToolsModule {
|
|
|
23
24
|
return require('../domains/core-tools.js') as CoreToolsModule;
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
export const CONTEXT_NOW_SPEC: LLMToolSpec = {
|
|
28
|
+
name: 'context_now',
|
|
29
|
+
description: '지금 무엇이 돌고 있는지 릴리스 칸·열린 결정·자리 원장·최근 맥락 이벤트의 출처 있는 요약을 읽는다. 원문 대화는 반환하지 않는다.',
|
|
30
|
+
parameters: { type: 'object', properties: { topic: { type: 'string', description: '칸 id·제목 또는 이벤트 요약에 들어 있는 낱말(선택).' } }, required: [] },
|
|
31
|
+
};
|
|
32
|
+
|
|
26
33
|
function coreSpec(name: SelfCognitionToolName): LLMToolSpec {
|
|
34
|
+
if (name === 'context_now') return CONTEXT_NOW_SPEC;
|
|
27
35
|
const spec = coreTools().CORE_TOOL_SPECS.find(candidate => candidate.name === name);
|
|
28
36
|
if (!spec) throw new Error(`Missing core tool spec for self-cognition runtime '${name}'`);
|
|
29
37
|
return spec;
|
|
@@ -193,9 +201,11 @@ export const SELF_COGNITION_RUNTIMES: readonly ToolRuntime[] = SELF_COGNITION_TO
|
|
|
193
201
|
get spec() {
|
|
194
202
|
return coreSpec(name);
|
|
195
203
|
},
|
|
196
|
-
run: async (args, ctx) => name === '
|
|
197
|
-
?
|
|
198
|
-
:
|
|
204
|
+
run: async (args, ctx) => name === 'context_now'
|
|
205
|
+
? (await import('../context-bus/context-now.js')).contextNow({ ...(typeof args.topic === 'string' ? { topic: args.topic } : {}) })
|
|
206
|
+
: name === 'memory_recall' || name === 'self_recall'
|
|
207
|
+
? runRecall(name, args, ctx)
|
|
208
|
+
: toToolRunResult(await coreTools().buildCoreTools().dispatch(name, args)),
|
|
199
209
|
}));
|
|
200
210
|
|
|
201
211
|
/** MCP catalog metadata derived from the same name ledger as the runtimes. */
|
|
@@ -91,8 +91,12 @@ export interface ToolRuntimeContext {
|
|
|
91
91
|
sessionId?: string;
|
|
92
92
|
/** Session that originated this execution when it was delegated through another runtime session. */
|
|
93
93
|
originSessionId?: string;
|
|
94
|
+
/** Server-verified owner principal. Never derive this from session source, tool args, or a client-declared origin. */
|
|
95
|
+
verifiedOwner?: { id: string };
|
|
94
96
|
/** Server-assigned provenance; omitted on existing owner tool paths. */
|
|
95
97
|
requestOrigin?: RequestOrigin;
|
|
98
|
+
/** Confirm through the originating chat's channels, not another user's global channel. */
|
|
99
|
+
confirmChannels?: import('../hitl/confirm.js').ConfirmChannel[];
|
|
96
100
|
}
|
|
97
101
|
|
|
98
102
|
/** Output shape the LLM layer expects back. Most tools produce
|
|
@@ -210,6 +210,8 @@ export class DashboardSession {
|
|
|
210
210
|
transportFactory: pair.transportFactory,
|
|
211
211
|
shutdownSignal: shutdownCtrl.signal,
|
|
212
212
|
runTurn,
|
|
213
|
+
// PCH-2b — the in-process TUI dispatcher carries its own approval modals.
|
|
214
|
+
toolApproval: 'off',
|
|
213
215
|
...(opts.agentName ? { agentName: opts.agentName } : {}),
|
|
214
216
|
...(opts.agentVersion ? { agentVersion: opts.agentVersion } : {}),
|
|
215
217
|
...(opts.serverOptions ?? {}),
|