elanous 0.2.10 → 0.2.12
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/-6XrAoD3eU7NyMHAE4xPS/_buildManifest.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1147-466ec15afacc1a65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1394-ee3795b112907122.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/2426.8c6ee0c668d53def.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-3cd46526879f454c.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/5532.6899a12958a89b72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8067-87ce253ec2f23697.js → 5845-e6c003ce8d5fd36a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 5cd7e3a9-404fd6b8d0ecd44c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7277-0b2fc7c16ba2d64b.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/7758-0b018a9e4fc56200.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-0259994816604c49.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/9920-5cfdc5e8fd209825.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-cb169620945d1952.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-cefe8169e36cf62a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-d2e35228bc497119.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-54b32bd27726588d.js → page-5c05b0da4bc1392c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e0ccdb576812b523.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-813c4a52c9d05ca8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-4731f2c215358937.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-a022b257950f39e6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-a2ffc717e04b8b0a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-b59ee4e70fc18fcf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-a67e11ba962337b5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-c172dabd796eb7a3.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-1efd0cb9e0ed9d13.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-d5dc7ff69a37b4cf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-e71c84189e8c683e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-1d6a533ce5a6efcb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-dfca9b7d2de0b135.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-793fa536b3a6ef37.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-6dd3bfbbde2a5c2c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-490653e8d4cc8852.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-77447356baad75d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-29e961191f6057df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-c822f55b884d9104.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fa4ccfc432424e52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-6d604227e1664b71.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-9c7e8f744a765daf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-4048543b4b7ad5e0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-4c3a3126abed551a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-64b0aecb1ca75e75.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4292d0149020e8a7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-db14d0be7f1c460c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-e5d8072cd7cfef73.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-9547b5cec7cf76bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-e6dcb83265530636.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-45248f08d6aecae5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-2cddeb9e2aeedc55.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-e297866051595d81.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-baba2e047872fb0f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-e895da4ec9cac345.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-4344faf20216233b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-698bb29f11864b89.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-bd6a6dc1ddc273f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2e9e2fb01c9da1c9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d62ceb13411ebba4.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/128fb7fb670b2fbf.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -0
- package/apps/pwa/out/inside/index.txt +31 -0
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -0
- package/apps/pwa/out/outputs/index.txt +30 -0
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -24
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -24
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/graphs/context/nightly-condense.yaml +21 -0
- package/graphs/context/recipes.yaml +12 -0
- package/graphs/demo/inside-seed.yaml +20 -0
- package/graphs/demo/recipes.yaml +12 -0
- package/graphs/drafts/draft-cleanup.yaml +19 -0
- package/graphs/drafts/recipes.yaml +23 -0
- package/graphs/intake/intake-daily.yaml +2 -1
- package/graphs/ops/recipes.yaml +3 -0
- package/graphs/ops/secret-exposure.yaml +24 -0
- package/graphs/release/recipes.yaml +3 -0
- package/graphs/release/release-loop.yaml +4 -1
- package/graphs/video/explainer-line.yaml +2 -2
- package/package.json +2 -1
- package/plugins/card-followup/examples/sample-card.png +0 -0
- package/plugins/elanous-hwp/README.md +25 -0
- package/plugins/elanous-hwp/cli.ts +22 -0
- package/plugins/elanous-hwp/converter.ts +237 -0
- package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
- package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
- package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
- package/plugins/elanous-hwp/plugin.json +16 -0
- package/plugins/elanous-hwp/plugin.ts +40 -0
- package/scripts/ci-public-export-leak-gate.ts +75 -14
- package/scripts/ci-public-leak-gate.ts +44 -9
- package/scripts/context-hooks/claude-stop.sh +4 -0
- package/scripts/context-hooks/emit.ts +24 -0
- package/scripts/context-hooks/post-tool-use.sh +4 -0
- package/scripts/coord-channel-watch.sh +12 -0
- package/scripts/coord-requests-bridge.ts +143 -0
- package/scripts/field-feed/lib.ts +4 -0
- package/scripts/fleet/node-setup.sh +20 -3
- package/scripts/homebrew-formula-bump.ts +69 -0
- package/scripts/lib/telegram-inject-args.ts +31 -0
- package/scripts/marketing/measure-site-numbers.ts +169 -0
- package/scripts/measure-gate-shards.ts +309 -0
- package/scripts/measure-pod-memory-by-goal.ts +130 -0
- package/scripts/mission-request-judge.ts +31 -1
- package/scripts/morning-report.ts +2 -2
- package/scripts/opportunity-scan.ts +1 -1
- package/scripts/release-loop/auto-approve-node.ts +21 -4
- package/scripts/release-loop/checklist-gate-node.ts +2 -1
- package/scripts/release-loop/cut-branch.ts +84 -0
- package/scripts/release-loop/gate-node.ts +22 -15
- 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 +47 -6
- package/scripts/release-loop/publish-node.ts +4 -1
- 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 +74 -13
- package/scripts/signal-digest-cycle.ts +2 -7
- package/scripts/signal-digest-photo.ts +11 -0
- package/scripts/tech1-public-measure.ts +94 -0
- package/scripts/telegram-inject.ts +14 -6
- package/scripts/test-diet/node.ts +1 -1
- package/scripts/test-diet/remeasure-list.ts +112 -0
- package/scripts/tui-regress.ts +2 -2
- package/scripts/ux/demo-rehearsal.ts +247 -0
- package/scripts/ux/demo-seed.ts +108 -0
- package/scripts/ux/lib/rehearsal-verdict.ts +80 -0
- package/skills/diagram-master/SKILL.md +366 -0
- package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
- package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
- package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
- package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
- package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
- package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
- package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
- package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
- package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
- package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
- package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
- package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
- package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
- package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
- package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
- package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
- package/skills/diagram-master/references/examples/README.md +69 -0
- package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
- package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
- package/skills/diagram-master/references/pyproject.toml +16 -0
- package/skills/diagram-master/references/quality-checklist.md +33 -0
- package/skills/diagram-master/references/routing-guide.md +164 -0
- package/skills/diagram-master/references/uv.lock +1356 -0
- package/skills/google-workspace/SKILL.md +33 -0
- package/skills/google-workspace/scripts/gws-safe.sh +177 -0
- package/skills/grill-me/SKILL.md +1 -1
- package/skills/lecture-note-digitizer/SKILL.md +926 -0
- package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
- package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
- package/skills/lecture-note-digitizer/references/html-template.md +167 -0
- package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
- package/skills/omni-crawl/SKILL.md +21 -11
- package/skills/omni-crawl/scripts/main.ts +6 -6
- package/skills/omni-crawl/src/router.ts +3 -3
- package/skills/omni-digest/SKILL.md +17 -9
- package/skills/omni-digest/digest.md +2 -2
- package/skills/omni-digest/src/fetch.ts +30 -3
- package/skills/pitch-deck/SKILL.md +2 -2
- package/skills/pitch-deck/template.html +2 -2
- package/skills/youtube-master/SKILL.md +163 -0
- package/skills/youtube-master/package-lock.json +558 -0
- package/skills/youtube-master/package.json +13 -0
- package/skills/youtube-master/references/study-note-template.md +124 -0
- package/skills/youtube-master/scripts/main.ts +435 -0
- package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
- package/skills/youtube-master/src/audio.ts +63 -0
- package/skills/youtube-master/src/domain-staging.ts +50 -0
- package/skills/youtube-master/src/env.ts +36 -0
- package/skills/youtube-master/src/obsidian.ts +155 -0
- package/skills/youtube-master/src/router.ts +110 -0
- package/skills/youtube-master/src/stt.ts +199 -0
- package/skills/youtube-master/src/study-note.ts +175 -0
- package/skills/youtube-master/src/summarize.ts +358 -0
- package/skills/youtube-master/src/transcript.ts +76 -0
- package/skills/youtube-master/src/types.ts +91 -0
- package/skills/youtube-master/src/util.ts +93 -0
- package/skills/youtube-master/src/youtube.ts +70 -0
- package/skills/youtube-master/tsconfig.json +13 -0
- package/src/acp/server.ts +5 -2
- package/src/agent-mission/driver.ts +215 -23
- package/src/agent-mission/pty-decision.ts +71 -0
- package/src/agent-mission/review-loop.ts +30 -0
- package/src/autopilot/build/llm-conflict-merge.ts +16 -3
- package/src/autopilot/pty-control-loop.ts +4 -1
- package/src/autopilot/tool-registry.ts +2 -0
- package/src/boot/daemon-prompt-turn.ts +5 -0
- package/src/boot/daemon-runtime.ts +9 -3
- package/src/boot/daemon-tools/web-search.ts +3 -0
- package/src/card-followup/core.ts +109 -0
- package/src/chat/index.ts +2 -0
- package/src/cli/drive-input-jail.ts +101 -0
- package/src/cli/hooks-cli.ts +17 -3
- package/src/cli/make-cli.ts +43 -0
- package/src/cli/persona-cli.ts +98 -9
- package/src/cli/plugin-cli.ts +31 -22
- package/src/cli/pod-cli.ts +36 -9
- package/src/cli/pod-memory-advice.ts +35 -0
- package/src/cli/pr-cli.ts +51 -15
- package/src/cli/pty-drive-cli.ts +41 -7
- package/src/cli/pty-drive-verdict.ts +40 -0
- package/src/cli/release-cli.ts +63 -10
- package/src/cli/setup-cli.ts +43 -1
- package/src/cli/skills-cli.ts +17 -1
- package/src/context-bus/claude-hooks-install.ts +10 -0
- package/src/context-bus/context-now-surfaces.ts +65 -0
- package/src/context-bus/context-now.ts +104 -0
- package/src/context-bus/coord-events.ts +2 -2
- package/src/context-bus/external-events.ts +52 -0
- package/src/context-bus/long-term-memory.ts +108 -0
- package/src/context-bus/nightly-condense.ts +153 -0
- package/src/context-bus/session-events.ts +35 -0
- package/src/dashboard/dashboard-status-lines.ts +2 -0
- package/src/dashboard/index.ts +17 -4
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +31 -1
- package/src/decisions/decision-cards.ts +10 -3
- package/src/decisions/decision-ledger.ts +13 -5
- package/src/discord/sprint21-runtime.ts +5 -1
- package/src/discord-self-message.ts +32 -0
- package/src/discord-slash-wire.ts +5 -1
- package/src/discord.ts +17 -1
- package/src/domains/core-tools.ts +3 -2
- package/src/domains/outbound-alert.ts +105 -32
- package/src/domains/outbound-log-probe.ts +8 -0
- package/src/domains/telegram-kind-route.ts +51 -13
- package/src/exec-requests/default-outputs.ts +25 -0
- package/src/exec-requests/planner.ts +10 -2
- package/src/exec-requests/runner.ts +20 -6
- package/src/exec-requests/store.ts +3 -0
- package/src/execution-loop/launch-gate.ts +109 -0
- package/src/field/field-reel.ts +5 -1
- package/src/field-note/index.ts +201 -0
- package/src/field-note/telegram.ts +142 -0
- package/src/field-note/transcribe.ts +248 -0
- package/src/graph-kinds/registry.ts +3 -3
- package/src/graph-runner/graph-cli.ts +61 -1
- package/src/graph-runner/graph-grow-llm.ts +47 -0
- package/src/graph-runner/graph-grow.ts +50 -0
- package/src/graph-runner/runner.ts +329 -33
- package/src/grok/agent-search.ts +8 -2
- package/src/guardian/secret-exposure-scan.ts +101 -0
- package/src/harness/harness-cli-command.ts +375 -13
- package/src/harness/harness-pod-dispatch.ts +43 -23
- package/src/harness/harness-seams.ts +38 -4
- package/src/harness/harness-stop.ts +23 -4
- package/src/harness/launch-registry.ts +91 -0
- package/src/harness/process-garbage.ts +5 -3
- package/src/hooks/consult-intake.ts +153 -0
- 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 +94 -16
- package/src/index.ts +76 -14
- package/src/intake-plane/categorize.ts +18 -46
- package/src/intake-plane/discord-seat-work.ts +38 -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/telegram-seat-work.ts +36 -2
- package/src/intake-plane/wish-card.ts +33 -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/feature-maturity.ts +27 -4
- package/src/model-tier/index.ts +2 -2
- package/src/model-tier/tier-resolver.ts +20 -20
- package/src/model-tier/types.ts +6 -6
- package/src/mss/logging/log-store.ts +15 -0
- package/src/nexus/api/config-model-tier.ts +5 -4
- package/src/nexus/api/fabric-plans.ts +53 -0
- package/src/nexus/api/harness-api.ts +5 -1
- package/src/nexus/api/health.ts +2 -0
- package/src/nexus/api/http-server.ts +67 -8
- package/src/nexus/api/inside-events.ts +226 -0
- package/src/nexus/api/meta-api.ts +21 -8
- package/src/nexus/api/missions.ts +6 -1
- package/src/nexus/api/ops-seats.ts +33 -0
- package/src/nexus/api/outbound-report.ts +40 -7
- package/src/nexus/api/outputs-route.ts +44 -0
- package/src/nexus/api/personas.ts +95 -53
- package/src/nexus/api/seat-requests.ts +44 -2
- package/src/nexus/api/sessions-store.ts +17 -38
- package/src/nexus/api/sub-seat-charters.ts +34 -0
- package/src/nexus/api/tabs-mutations.ts +3 -1
- package/src/nexus/api/task-cards-api.ts +19 -0
- package/src/nexus/api/trace.ts +18 -6
- package/src/nexus/api/workflow-history.ts +88 -0
- package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
- package/src/nexus/api/workflows.ts +132 -6
- package/src/nexus/index.ts +2 -0
- package/src/nexus/kinds/webterm.ts +2 -1
- package/src/nexus/outbound/delivery-ledger.ts +17 -8
- package/src/nexus/outbound/router.ts +8 -3
- package/src/nexus/webterm/pty.ts +6 -2
- package/src/onboarding/cli-auth-status.ts +80 -0
- package/src/onboarding/voice-ai.ts +3 -3
- package/src/org/seat-budget.ts +48 -0
- package/src/org/stall-escalation.ts +63 -0
- package/src/outputs/ledger.ts +120 -0
- package/src/persona/persona-todo.ts +79 -0
- package/src/persona/presets.ts +123 -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 +110 -0
- package/src/plugins/maker/plugin-maker.ts +254 -11
- package/src/plugins/maker/wizard-generate.ts +103 -0
- package/src/pod-lease/admission.ts +150 -0
- package/src/pod-lease/dependency-state.ts +85 -0
- package/src/pod-lease/host-lease.ts +127 -0
- package/src/project/project-suggestion.ts +16 -0
- package/src/project/session-context.ts +24 -0
- package/src/release-loop/checklist.ts +17 -5
- package/src/release-loop/feature-store.ts +29 -13
- package/src/release-loop/landed-but-yellow.ts +48 -0
- package/src/release-loop/next-md-merge.ts +58 -0
- package/src/release-loop/release-note.ts +59 -4
- package/src/seat-dispatch/seat-ask.ts +130 -0
- package/src/seat-dispatch/seat-questions.ts +100 -0
- package/src/seat-loop/seat-loop.ts +709 -29
- package/src/seat-loop/seat-report.ts +37 -2
- package/src/self-dev/dev-cli.ts +4 -1
- package/src/self-dev/dev-pipeline.ts +37 -1
- package/src/self-dev/draft-sweep.ts +79 -40
- package/src/self-dev/draft-triage-rules.ts +62 -7
- package/src/self-dev/fabric-plan-core.ts +297 -0
- package/src/self-dev/orchestrate.ts +36 -4
- package/src/self-dev/release-path-guard.ts +62 -0
- package/src/self-dev/shard-aggregate.ts +230 -0
- package/src/self-dev/shard-placement.ts +60 -0
- package/src/self-dev/shard-plan.ts +48 -0
- package/src/self-dev/shard-pod-run.ts +77 -0
- package/src/self-dev/shard-run.ts +105 -0
- package/src/self-implement/budget-gate.ts +29 -12
- package/src/self-implement/gate-baseline.ts +1 -1
- package/src/self-implement/gate-candidate-ranking.ts +60 -0
- package/src/self-implement/gate-cli.ts +40 -1
- package/src/self-implement/gate-scope.ts +44 -13
- 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 +27 -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 +257 -9
- package/src/self-implement/route-consumer-test-index.ts +122 -0
- package/src/self-implement/seams.ts +72 -11
- package/src/self-implement/test-seams.ts +2 -0
- package/src/self-implement/uncommitted-work.ts +59 -0
- package/src/session/index.ts +36 -13
- package/src/skills/gift-install.ts +215 -0
- package/src/skills/tools/web-search.ts +4 -1
- package/src/steward/launch.ts +42 -26
- package/src/steward/steward-cards.ts +17 -9
- package/src/steward/triage.ts +46 -14
- package/src/task-cards/card-cli.ts +25 -1
- package/src/task-orchestrator/mission.ts +5 -0
- package/src/task-orchestrator/store.ts +12 -3
- package/src/task-orchestrator/surfaces/pod-command-job.ts +43 -17
- package/src/task-orchestrator/surfaces/pod-lease.ts +156 -19
- package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +222 -40
- package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
- package/src/task-orchestrator/types.ts +2 -0
- package/src/telegram-card-followup.ts +16 -96
- package/src/telegram-commands.ts +31 -1
- package/src/telegram-project-command.ts +145 -0
- package/src/telegram-report.ts +21 -17
- package/src/telegram.ts +61 -8
- package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
- package/src/user-config.ts +110 -24
- package/src/version/packed-revision.json +1 -1
- package/src/web-search/grok.ts +7 -1
- package/src/web-search/index.ts +28 -1
- package/src/web-search/provider.ts +4 -0
- package/src/web-search/x-intent.ts +5 -0
- package/src/workflow-runtime/executor.ts +277 -47
- package/src/workflow-runtime/index.ts +1 -0
- package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
- package/src/workflow-runtime/plugin-kind-node.ts +1 -1
- package/src/workflow-runtime/schema.ts +79 -4
- package/src/workflow-runtime/types.ts +35 -4
- package/apps/pwa/out/_next/static/2DsiDfDCks44g1cPUMhiW/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/24-e6d28380efab7faf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
- package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
- package/apps/pwa/out/_next/static/chunks/3615-740dd270764ffa24.js +0 -1
- package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3734-1015fe991eb9b7e7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5012-a7fe6f3c8b6fe45a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5783-ef40ebfc91d55230.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
- package/apps/pwa/out/_next/static/chunks/62-ff227c3edb8b248b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7633-1b3709b0854c9412.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7951-8b03dbb10b24cd06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8195-6fde3d7a39859206.js +0 -10
- package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8894-b5fb36bab837cd29.js +0 -1
- package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9454-84d0d5d77446bd92.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/988-5f92e7ab7ccea3dd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9989-5582582f06429840.js +0 -1
- package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d2253d7e58ef1890.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-5441d4a9ab35e518.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-d9b12d680922d980.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-e268d6d145827a22.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-f8116559c7424da7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-1085399fd0f32112.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-1df686a14f65895a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-54e1f966ab60a4dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-7ed95f296f5ee8e9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-11edac668d77e5c3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-59e2b9a22cd5a6d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-2976df21ad74ab48.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-34d211a67f16d510.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-8ff652d5d950639b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-b31610deda76337b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6cb0e1bbefe5fb3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-a286a152cf584576.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-d9237581e7003bcb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-83274e761643fdd2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-ceee6cfb1d4e6d68.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-9c9f8bb3e4a64091.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-c17217603ea3426a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-efb6177cbf1e8a51.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-d307523703bc4df3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-462f4e4bab45ce7d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-8990e96f33af3837.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-e168fa1030af0548.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-1233e05a4068bc9c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-13a1840b1fac337a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-64a29fc80b11ab55.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-68e787339a16b3dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-4fddc90b23feb215.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-886ba8260dc79c79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-0f26507a1722e40b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-109d4ccd42259c9d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-f5c2a4e510726774.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-b2e0039416f42522.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-26102fd7350f171e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-708948bc8a802794.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-5e5611620f78fb0b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-139ba5c367bbf60a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-202b4e81f33895ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
- package/apps/pwa/out/_next/static/css/43feca5fd387dcbd.css +0 -1
- /package/apps/pwa/out/_next/static/{2DsiDfDCks44g1cPUMhiW → -6XrAoD3eU7NyMHAE4xPS}/_ssgManifest.js +0 -0
|
@@ -22,7 +22,7 @@ export interface CoordEvent {
|
|
|
22
22
|
text: string;
|
|
23
23
|
summary: string;
|
|
24
24
|
kind: string;
|
|
25
|
-
refs: Pick<CoordEventInput, 'seat' | 'recipients' | 'all' | 'kind' | 'slot' | 'deadline' | 'url'
|
|
25
|
+
refs: Pick<CoordEventInput, 'seat' | 'recipients' | 'all' | 'kind' | 'slot' | 'deadline' | 'url'> & { origin?: string; source?: string; ref?: string | null };
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
function seatIds(): Set<string> {
|
|
@@ -104,7 +104,7 @@ export function listCoordEvents(opts: { since: string; seat?: string }, deps: {
|
|
|
104
104
|
const db = deps.db ?? openSurfaceEventsDb();
|
|
105
105
|
try {
|
|
106
106
|
const rows = db.prepare(`SELECT id, ts, text, summary, kind, refs FROM events
|
|
107
|
-
WHERE surface
|
|
107
|
+
WHERE surface IN ('coord:channel', 'context:external', 'context:session') AND direction='outbound' AND ts>=?
|
|
108
108
|
${opts.seat ? "AND json_extract(refs,'$.seat')=?" : ''} ORDER BY ts ASC, rowid ASC`)
|
|
109
109
|
.all(...(opts.seat ? [opts.since, opts.seat] : [opts.since])) as Array<{
|
|
110
110
|
id: string; ts: string; text: string; summary: string; kind: string; refs: string;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Database } from 'bun:sqlite';
|
|
2
|
+
import { debug, redactSecretText } from '../debug/log.js';
|
|
3
|
+
import { openSurfaceEventsDb, recordEvent } from '../domains/surface-events.js';
|
|
4
|
+
|
|
5
|
+
export type ExternalEventOrigin = 'claude-code' | 'codex-agent-mission' | 'harness-child';
|
|
6
|
+
export type ContextHookKind = 'claimed' | 'done' | 'asked' | 'guide-changed';
|
|
7
|
+
export type ExternalEventKind = ContextHookKind | 'started' | 'finished';
|
|
8
|
+
export const CONTEXT_SUMMARY_MAX = 120;
|
|
9
|
+
export const CONTEXT_SOURCE_MAX = 512;
|
|
10
|
+
|
|
11
|
+
export interface ExternalEventInput {
|
|
12
|
+
origin: ExternalEventOrigin;
|
|
13
|
+
kind: ExternalEventKind;
|
|
14
|
+
summary: string;
|
|
15
|
+
source: string;
|
|
16
|
+
at?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Only a single, bounded, redacted summary and a locator enter the journal; no prompt or transcript. */
|
|
20
|
+
export function recordExternalEvent(input: ExternalEventInput, deps: { db?: Database } = {}): string {
|
|
21
|
+
if (!['claude-code', 'codex-agent-mission', 'harness-child'].includes(input.origin)) throw new Error('invalid context origin');
|
|
22
|
+
if (input.origin === 'claude-code'
|
|
23
|
+
? !['claimed', 'done', 'asked', 'guide-changed'].includes(input.kind)
|
|
24
|
+
: !['started', 'finished'].includes(input.kind)) throw new Error('invalid context kind');
|
|
25
|
+
const summary = redactSecretText(input.summary.split(/\r?\n/, 1)[0] ?? '').trim().slice(0, CONTEXT_SUMMARY_MAX);
|
|
26
|
+
const source = redactSecretText(input.source.split(/\r?\n/, 1)[0] ?? '').trim();
|
|
27
|
+
if (!summary) throw new Error('context summary must be one nonempty line');
|
|
28
|
+
|
|
29
|
+
if (!/^(?:https?:\/\/|elanous:\/\/)[^\s]+$/.test(source) || source.length > CONTEXT_SOURCE_MAX) {
|
|
30
|
+
throw new Error('context source must be a link (http(s) or elanous://), at most 512 characters');
|
|
31
|
+
}
|
|
32
|
+
const db = deps.db ?? openSurfaceEventsDb();
|
|
33
|
+
try {
|
|
34
|
+
return recordEvent(db, {
|
|
35
|
+
surface: 'context:external', direction: 'outbound', domain: 'elanous', category: 'coordination',
|
|
36
|
+
kind: input.kind, text: summary, summary,
|
|
37
|
+
refs: JSON.stringify({ seat: input.origin, recipients: [], all: false, kind: input.kind,
|
|
38
|
+
slot: null, deadline: null, url: source, origin: input.origin, source }),
|
|
39
|
+
...(input.at ? { ts: input.at } : {}),
|
|
40
|
+
});
|
|
41
|
+
} finally { if (!deps.db) db.close(); }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Instrumentation never changes an agent's result. Failures remain visible without logging untrusted payloads. */
|
|
45
|
+
export function observeExternalEvent(input: ExternalEventInput, record: typeof recordExternalEvent = recordExternalEvent): void {
|
|
46
|
+
try { record(input); }
|
|
47
|
+
catch (error) {
|
|
48
|
+
try { debug.log('context.external', 'record-failed', {
|
|
49
|
+
origin: input.origin, kind: input.kind, reason: error instanceof Error ? error.message : String(error),
|
|
50
|
+
}, { level: 'warn' }); } catch { /* A broken logger cannot change an agent's result. */ }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { redactSecretText } from '../debug/log.js';
|
|
2
|
+
import { DecisionLedger, type DecisionEntry } from '../decisions/decision-ledger.js';
|
|
3
|
+
import { listCoordEvents, type CoordEvent } from './coord-events.js';
|
|
4
|
+
|
|
5
|
+
export interface MemoryItem {
|
|
6
|
+
project: string;
|
|
7
|
+
seat: string;
|
|
8
|
+
topic: string;
|
|
9
|
+
summary: string;
|
|
10
|
+
source: string;
|
|
11
|
+
updatedAt: string;
|
|
12
|
+
status: 'active' | 'retired';
|
|
13
|
+
/** A normalized, comparable assertion supplied by the summarizer; absent means no conflict judgment. */
|
|
14
|
+
claim?: { key: string; value: string };
|
|
15
|
+
conflict?: { owner: 'OP'; sources: [string, string] };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type MemorySource =
|
|
19
|
+
| { kind: 'event'; at: string; seat: string; text: string; source: string }
|
|
20
|
+
| { kind: 'decision'; at: string; seat: string; text: string; source: string };
|
|
21
|
+
|
|
22
|
+
export interface MemorySummary {
|
|
23
|
+
project: string;
|
|
24
|
+
topic: string;
|
|
25
|
+
summary: string;
|
|
26
|
+
/** Only supply this when the two strings identify the same fact and mutually exclusive values. */
|
|
27
|
+
claim?: { key: string; value: string };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface MemoryDeps {
|
|
31
|
+
summarize: (source: MemorySource) => Promise<MemorySummary>;
|
|
32
|
+
events?: (since: string) => CoordEvent[];
|
|
33
|
+
decisions?: () => DecisionEntry[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const DAY_MS = 86_400_000;
|
|
37
|
+
const oneLine = (text: string) => redactSecretText(text.split(/\r?\n/, 1)[0] ?? '').trim();
|
|
38
|
+
|
|
39
|
+
/** Condense one UTC day; callers persist the returned snapshot, not raw transcripts. Read-only ledger access. */
|
|
40
|
+
export async function condenseContextDay(
|
|
41
|
+
day: string, previous: readonly MemoryItem[], deps: MemoryDeps, now: Date = new Date(),
|
|
42
|
+
): Promise<MemoryItem[]> {
|
|
43
|
+
if (!/^\d{4}-\d\d-\d\d$/.test(day) || new Date(`${day}T00:00:00.000Z`).toISOString().slice(0, 10) !== day) {
|
|
44
|
+
throw new Error('day must be a valid UTC YYYY-MM-DD');
|
|
45
|
+
}
|
|
46
|
+
const since = `${day}T00:00:00.000Z`;
|
|
47
|
+
const start = Date.parse(since);
|
|
48
|
+
const until = start + DAY_MS;
|
|
49
|
+
// The store compares timestamp text, so fetch the previous local day too before UTC filtering.
|
|
50
|
+
const events = (deps.events ?? (from => listCoordEvents({ since: from })))(new Date(start - DAY_MS).toISOString());
|
|
51
|
+
const decisions = (deps.decisions ?? (() => new DecisionLedger().list({ status: 'all' })))();
|
|
52
|
+
const sources: MemorySource[] = [
|
|
53
|
+
...events.map(event => ({ kind: 'event' as const, at: event.at, seat: event.refs.seat,
|
|
54
|
+
text: event.summary, source: event.refs.source ?? event.refs.url ?? `elanous://context/event/${encodeURIComponent(event.id)}` })),
|
|
55
|
+
...decisions.map(decision => ({ kind: 'decision' as const,
|
|
56
|
+
at: decision.decidedAt ?? decision.raisedAt ?? decision.importedAt ?? '',
|
|
57
|
+
seat: decision.raisedBy.track ?? 'OP',
|
|
58
|
+
text: decision.status === 'decided' ? `${decision.title}: ${decision.options.find(o => o.key === decision.choice)?.label ?? decision.note ?? decision.scqa.a ?? '결정됨'}` : `${decision.title}: ${decision.status}`,
|
|
59
|
+
source: `elanous://decisions/${encodeURIComponent(decision.id)}` })),
|
|
60
|
+
].filter(source => {
|
|
61
|
+
const at = Date.parse(source.at);
|
|
62
|
+
return Number.isFinite(at) && at >= start && at < until;
|
|
63
|
+
}).sort((a, b) => Date.parse(a.at) - Date.parse(b.at) || a.source.localeCompare(b.source));
|
|
64
|
+
|
|
65
|
+
const items = new Map<string, MemoryItem>();
|
|
66
|
+
const keyFor = (item: Pick<MemoryItem, 'project' | 'seat' | 'topic'>) => JSON.stringify([item.project, item.seat, item.topic]);
|
|
67
|
+
for (const item of previous) items.set(keyFor(item), { ...item });
|
|
68
|
+
for (const source of sources) {
|
|
69
|
+
const summary = await deps.summarize(source);
|
|
70
|
+
const project = oneLine(summary.project);
|
|
71
|
+
const seat = oneLine(source.seat);
|
|
72
|
+
const topic = oneLine(summary.topic);
|
|
73
|
+
const text = oneLine(summary.summary);
|
|
74
|
+
const link = oneLine(source.source);
|
|
75
|
+
if (!project || !seat || !topic || !text || !/^(?:https?:\/\/|elanous:\/\/)[^\s]+$/.test(link)) {
|
|
76
|
+
throw new Error('memory summary needs a project, seat, topic, one-line summary and source link');
|
|
77
|
+
}
|
|
78
|
+
const claim = summary.claim && { key: oneLine(summary.claim.key), value: oneLine(summary.claim.value) };
|
|
79
|
+
if (claim && (!claim.key || !claim.value)) throw new Error('memory claim needs key and value');
|
|
80
|
+
const key = keyFor({ project, seat, topic });
|
|
81
|
+
const old = items.get(key);
|
|
82
|
+
// Equal timestamps are resolved by the source link, so shuffled input does not change the winner.
|
|
83
|
+
if (old && (Date.parse(old.updatedAt) > Date.parse(source.at)
|
|
84
|
+
|| (Date.parse(old.updatedAt) === Date.parse(source.at) && old.source >= link))) continue;
|
|
85
|
+
items.set(key, { project, seat, topic, summary: text, source: link, updatedAt: source.at,
|
|
86
|
+
status: 'active', ...(claim ? { claim } : {}) });
|
|
87
|
+
}
|
|
88
|
+
const cutoff = now.getTime() - 30 * DAY_MS;
|
|
89
|
+
// Compare only the winning, non-retired assertions; a superseded claim cannot keep a decision candidate alive.
|
|
90
|
+
const finalItems: MemoryItem[] = [...items.values()].map(({ conflict: _conflict, ...item }) => ({ ...item,
|
|
91
|
+
status: Date.parse(item.updatedAt) < cutoff ? 'retired' as const : 'active' as const,
|
|
92
|
+
}));
|
|
93
|
+
finalItems.sort((a, b) => Date.parse(a.updatedAt) - Date.parse(b.updatedAt) || a.source.localeCompare(b.source)
|
|
94
|
+
|| a.seat.localeCompare(b.seat));
|
|
95
|
+
for (let index = 0; index < finalItems.length; index++) {
|
|
96
|
+
const item = finalItems[index]!;
|
|
97
|
+
if (item.status !== 'active' || !item.claim) continue;
|
|
98
|
+
const { key, value } = item.claim;
|
|
99
|
+
const conflicting = finalItems.slice(0, index).find(other => other.status === 'active'
|
|
100
|
+
&& other.project === item.project
|
|
101
|
+
&& other.claim?.key === key && other.claim.value !== value);
|
|
102
|
+
if (conflicting) {
|
|
103
|
+
finalItems[index] = { ...item, conflict: { owner: 'OP', sources: [conflicting.source, item.source] } };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return finalItems.sort((a, b) => a.project.localeCompare(b.project) || a.seat.localeCompare(b.seat)
|
|
107
|
+
|| a.topic.localeCompare(b.topic));
|
|
108
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { readFileSync, readdirSync, mkdirSync, writeFileSync, renameSync, existsSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { streamLLM } from '../llm.js';
|
|
4
|
+
import { condenseContextDay, type MemoryItem, type MemorySource, type MemorySummary } from './long-term-memory.js';
|
|
5
|
+
import { listCoordEvents, type CoordEvent } from './coord-events.js';
|
|
6
|
+
import { DecisionLedger, type DecisionEntry } from '../decisions/decision-ledger.js';
|
|
7
|
+
import { acquireLockAsync } from '../storage/file-lock.js';
|
|
8
|
+
|
|
9
|
+
type Stage = 'collect' | 'condense' | 'record' | 'conflict-candidates';
|
|
10
|
+
type Input = { day?: string; events?: CoordEvent[]; decisions?: DecisionEntry[]; summaries?: Record<string, MemorySummary> };
|
|
11
|
+
type Context = { graphId?: string; nodeId?: string; input: Input | null; outputs: Record<string, { day?: string; events?: CoordEvent[]; decisions?: DecisionEntry[]; items?: MemoryItem[] } | null> };
|
|
12
|
+
|
|
13
|
+
const dayBefore = (date: Date) => new Date(date.getTime() - 86_400_000).toISOString().slice(0, 10);
|
|
14
|
+
const fileName = (value: string) => encodeURIComponent(value).replace(/\./g, '%2E');
|
|
15
|
+
|
|
16
|
+
function snapshotPath(root: string, project: string, seat: string): string {
|
|
17
|
+
if (project === '.' || project === '..' || seat === '.' || seat === '..') throw new Error('invalid memory path');
|
|
18
|
+
return join(root, 'context-memory', fileName(project), `${fileName(seat)}.json`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function save(file: string, value: unknown): void {
|
|
22
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
23
|
+
const temp = `${file}.${process.pid}.tmp`;
|
|
24
|
+
writeFileSync(temp, JSON.stringify(value, null, 2) + '\n');
|
|
25
|
+
renameSync(temp, file);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function withCurrentDay<T>(root: string, day: string, write: () => T): Promise<T> {
|
|
29
|
+
const dir = join(root, 'context-memory');
|
|
30
|
+
mkdirSync(dir, { recursive: true });
|
|
31
|
+
const lock = await acquireLockAsync(join(dir, '.nightly-write.lock'));
|
|
32
|
+
try {
|
|
33
|
+
const marker = join(dir, 'latest-day');
|
|
34
|
+
const latest = latestDay(root);
|
|
35
|
+
if ((latest && latest > day) || storedItems(root).some(item =>
|
|
36
|
+
Date.parse(item.updatedAt) >= Date.parse(`${day}T00:00:00Z`) + 86_400_000)) {
|
|
37
|
+
throw new Error(`cannot replay ${day}: later project/seat memory exists`);
|
|
38
|
+
}
|
|
39
|
+
if (!lock.stillHeld()) throw new Error('nightly memory write lock lost');
|
|
40
|
+
// Reserve the day before touching either output, so a failed writer cannot let an older run overwrite it.
|
|
41
|
+
if (!latest || latest < day) save(marker, day);
|
|
42
|
+
return write();
|
|
43
|
+
} finally { lock.release(); }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function latestDay(root: string): string | undefined {
|
|
47
|
+
const marker = join(root, 'context-memory', 'latest-day');
|
|
48
|
+
return existsSync(marker) ? JSON.parse(readFileSync(marker, 'utf8')) as string : undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function storedItems(root: string): MemoryItem[] {
|
|
52
|
+
const dir = join(root, 'context-memory');
|
|
53
|
+
if (!existsSync(dir)) return [];
|
|
54
|
+
const items: MemoryItem[] = [];
|
|
55
|
+
for (const project of readdirSync(dir, { withFileTypes: true })) {
|
|
56
|
+
if (!project.isDirectory()) continue;
|
|
57
|
+
for (const seat of readdirSync(join(dir, project.name))) {
|
|
58
|
+
if (!seat.endsWith('.json')) continue;
|
|
59
|
+
const content: unknown = JSON.parse(readFileSync(join(dir, project.name, seat), 'utf8'));
|
|
60
|
+
if (!Array.isArray(content)) throw new Error('invalid context memory file');
|
|
61
|
+
items.push(...content as MemoryItem[]);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return items;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function summarize(source: MemorySource, injected?: Record<string, MemorySummary>): Promise<MemorySummary> {
|
|
68
|
+
if (injected) {
|
|
69
|
+
const result = injected[source.source];
|
|
70
|
+
if (!result) throw new Error(`missing test summary: ${source.source}`);
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
const response = await streamLLM([
|
|
74
|
+
{ role: 'system', content: 'Summarize this one-line context event as a compact project/seat memory item. Return ONLY JSON: {"project":"...","topic":"...","summary":"...","claim":{"key":"...","value":"..."}}. Omit claim when the event makes no comparable factual assertion. Never invent a project, topic or claim.' },
|
|
75
|
+
{ role: 'user', content: JSON.stringify(source) },
|
|
76
|
+
], () => {}, { maxTokens: 350, usageRole: 'research' });
|
|
77
|
+
const parsed: unknown = JSON.parse(response.replace(/^```(?:json)?\s*|\s*```$/g, '').trim());
|
|
78
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('invalid memory summary');
|
|
79
|
+
const value = parsed as Record<string, unknown>;
|
|
80
|
+
if (typeof value.project !== 'string' || typeof value.topic !== 'string' || typeof value.summary !== 'string' ||
|
|
81
|
+
(value.claim !== undefined && (!value.claim || typeof value.claim !== 'object' || Array.isArray(value.claim) ||
|
|
82
|
+
typeof (value.claim as Record<string, unknown>).key !== 'string' || typeof (value.claim as Record<string, unknown>).value !== 'string'))) {
|
|
83
|
+
throw new Error('invalid memory summary');
|
|
84
|
+
}
|
|
85
|
+
return value as unknown as MemorySummary;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Stage outputs travel only through the graph runner's per-run contexts. No decision ledger write occurs here. */
|
|
89
|
+
export async function runNightlyStage(stage: Stage, context: Context, root: string, dryRun: boolean, now = new Date()): Promise<Record<string, unknown>> {
|
|
90
|
+
const input = context.input ?? {};
|
|
91
|
+
if (dryRun && stage !== 'collect' && (!input.events || !input.decisions || !input.summaries)) {
|
|
92
|
+
throw new Error('dry-run requires fake events, decisions and summaries');
|
|
93
|
+
}
|
|
94
|
+
const day = context.outputs.collect?.day ?? input.day ?? dayBefore(now);
|
|
95
|
+
if (!/^\d{4}-\d\d-\d\d$/.test(day) || new Date(`${day}T00:00:00Z`).toISOString().slice(0, 10) !== day) {
|
|
96
|
+
throw new Error('invalid UTC day');
|
|
97
|
+
}
|
|
98
|
+
if (stage === 'collect') {
|
|
99
|
+
if (!dryRun && ((latestDay(root) ?? '') > day || storedItems(root).some(item =>
|
|
100
|
+
Date.parse(item.updatedAt) >= Date.parse(`${day}T00:00:00Z`) + 86_400_000))) {
|
|
101
|
+
throw new Error(`cannot replay ${day}: later project/seat memory exists`);
|
|
102
|
+
}
|
|
103
|
+
if (dryRun && (!input.events || !input.decisions || !input.summaries)) {
|
|
104
|
+
throw new Error('dry-run requires fake events, decisions and summaries');
|
|
105
|
+
}
|
|
106
|
+
const events = input.events ?? listCoordEvents({ since: new Date(Date.parse(`${day}T00:00:00Z`) - 86_400_000).toISOString() });
|
|
107
|
+
const decisions = input.decisions ?? (dryRun ? [] : new DecisionLedger().list({ status: 'all' }));
|
|
108
|
+
return { outcome: 'ok', day, events, decisions };
|
|
109
|
+
}
|
|
110
|
+
const collected = context.outputs.collect;
|
|
111
|
+
if (!collected?.day || !collected.events || !collected.decisions) throw new Error('collect output missing');
|
|
112
|
+
if (stage === 'condense') {
|
|
113
|
+
const items = await condenseContextDay(collected.day, dryRun ? [] : storedItems(root).filter(item => Date.parse(item.updatedAt) < Date.parse(`${collected.day}T00:00:00Z`)), {
|
|
114
|
+
events: () => collected.events!, decisions: () => collected.decisions!,
|
|
115
|
+
summarize: source => summarize(source, input.summaries),
|
|
116
|
+
}, now);
|
|
117
|
+
return { outcome: 'ok', items };
|
|
118
|
+
}
|
|
119
|
+
const items = context.outputs.condense?.items;
|
|
120
|
+
if (!items) throw new Error('condense output missing');
|
|
121
|
+
if (stage === 'record') {
|
|
122
|
+
const grouped = new Map<string, MemoryItem[]>();
|
|
123
|
+
for (const item of items) {
|
|
124
|
+
const file = snapshotPath(root, item.project, item.seat);
|
|
125
|
+
grouped.set(file, [...grouped.get(file) ?? [], item]);
|
|
126
|
+
}
|
|
127
|
+
if (!dryRun) await withCurrentDay(root, day, () => {
|
|
128
|
+
for (const [file, group] of grouped) save(file, group);
|
|
129
|
+
});
|
|
130
|
+
return { outcome: 'ok', files: [...grouped.keys()], items: items.length, memoryItems: dryRun ? items : undefined, dryRun };
|
|
131
|
+
}
|
|
132
|
+
if (stage === 'conflict-candidates') {
|
|
133
|
+
if (!context.outputs.record) throw new Error('record output missing');
|
|
134
|
+
const candidates = items.filter(item => item.conflict && item.status === 'active').map(item => ({
|
|
135
|
+
project: item.project, topic: item.topic, owner: item.conflict!.owner,
|
|
136
|
+
sources: item.conflict!.sources, status: 'candidate' as const,
|
|
137
|
+
}));
|
|
138
|
+
if (!dryRun) await withCurrentDay(root, day, () => save(join(root, 'context-memory', 'conflict-candidates.json'), candidates));
|
|
139
|
+
return { outcome: 'ok', candidates, published: 0 };
|
|
140
|
+
}
|
|
141
|
+
throw new Error(`unknown stage: ${stage}`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (import.meta.main) {
|
|
145
|
+
const stage = process.argv[2] as Stage;
|
|
146
|
+
const path = process.env.ELANOUS_GRAPH_CONTEXT;
|
|
147
|
+
if (!path || !['collect', 'condense', 'record', 'conflict-candidates'].includes(stage)) throw new Error('invalid nightly graph stage');
|
|
148
|
+
const context = JSON.parse(readFileSync(path, 'utf8')) as Context;
|
|
149
|
+
if (context.graphId !== 'nightly-condense' || context.nodeId !== stage) throw new Error('nightly graph context mismatch');
|
|
150
|
+
const statePath = resolve(path, '..', '..', '..', '..');
|
|
151
|
+
const result = await runNightlyStage(stage, context, statePath, process.env.ELANOUS_GRAPH_DRY_RUN === '1');
|
|
152
|
+
console.log(JSON.stringify(result));
|
|
153
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Database } from 'bun:sqlite';
|
|
2
|
+
import { redactSecretText } from '../debug/log.js';
|
|
3
|
+
import { openSurfaceEventsDb, recordEvent } from '../domains/surface-events.js';
|
|
4
|
+
|
|
5
|
+
export const SESSION_EVENT_KINDS = ['task-claimed', 'task-done', 'asked', 'guidance-changed'] as const;
|
|
6
|
+
export type SessionEventKind = typeof SESSION_EVENT_KINDS[number];
|
|
7
|
+
|
|
8
|
+
export interface SessionEventInput {
|
|
9
|
+
kind: SessionEventKind;
|
|
10
|
+
seat: string;
|
|
11
|
+
text: string;
|
|
12
|
+
ref?: string;
|
|
13
|
+
at?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Publish a one-line external-agent session signal to the existing context journal. */
|
|
17
|
+
export function emitSessionEvent(input: SessionEventInput, deps: { db?: Database } = {}): string {
|
|
18
|
+
if (!SESSION_EVENT_KINDS.includes(input.kind)) throw new Error('unknown context session kind');
|
|
19
|
+
if (!['OP', 'TC', 'MK', 'UX'].includes(input.seat)) throw new Error('context session seat must be OP|TC|MK|UX');
|
|
20
|
+
if (/\r|\n/.test(input.text) || !input.text.trim()) throw new Error('context session text must be one nonempty line');
|
|
21
|
+
if (input.ref !== undefined && (/\r|\n/.test(input.ref) || !input.ref.trim())) throw new Error('context session ref must be one nonempty line');
|
|
22
|
+
const summary = redactSecretText(input.text).trim().slice(0, 120);
|
|
23
|
+
const ref = input.ref ?? null;
|
|
24
|
+
const db = deps.db ?? openSurfaceEventsDb();
|
|
25
|
+
try {
|
|
26
|
+
return recordEvent(db, {
|
|
27
|
+
surface: 'context:session', direction: 'outbound', domain: 'elanous', category: 'coordination',
|
|
28
|
+
kind: input.kind, text: input.text, summary,
|
|
29
|
+
refs: JSON.stringify({ seat: input.seat, recipients: [], all: false, kind: input.kind,
|
|
30
|
+
slot: null, deadline: null, url: null, ref,
|
|
31
|
+
...(ref ? { source: `elanous://context/ref/${encodeURIComponent(ref)}` } : {}) }),
|
|
32
|
+
...(input.at ? { ts: input.at } : {}),
|
|
33
|
+
});
|
|
34
|
+
} finally { if (!deps.db) db.close(); }
|
|
35
|
+
}
|
|
@@ -5,6 +5,7 @@ export interface DashboardStatusLinesInput {
|
|
|
5
5
|
readonly daemonAddress?: string | null;
|
|
6
6
|
readonly daemonConnected: boolean;
|
|
7
7
|
readonly accountName?: string | null;
|
|
8
|
+
readonly seatsNow?: string | null;
|
|
8
9
|
readonly sessionSurfaceLines: readonly string[];
|
|
9
10
|
readonly view: string;
|
|
10
11
|
readonly focus: string;
|
|
@@ -31,6 +32,7 @@ export function buildDashboardStatusLines(input: DashboardStatusLinesInput): str
|
|
|
31
32
|
`모델: ${known(input.provider)}/${known(input.model)} (${known(input.reasoning)})`,
|
|
32
33
|
`연결: 데몬 ${address} ${input.daemonConnected ? '붙음' : '안 붙음'}`,
|
|
33
34
|
`계정: ${input.accountName?.trim() === 'default' ? '기본' : known(input.accountName)}`,
|
|
35
|
+
...(input.seatsNow ? [input.seatsNow] : []),
|
|
34
36
|
'',
|
|
35
37
|
'자세히',
|
|
36
38
|
...input.sessionSurfaceLines.map(line => ` ${line}`),
|
package/src/dashboard/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ import type { ShootRunOptions } from '../ad-pipeline/shoot-run.js';
|
|
|
18
18
|
import type { QcThresholds } from '../ad-pipeline/qc.js';
|
|
19
19
|
import { elanousStateRoot } from '../autopilot/state-paths.js';
|
|
20
20
|
import { suggestProjectForFolder } from '../project/project-store.js';
|
|
21
|
+
import { createProjectSuggester } from '../project/project-suggestion.js';
|
|
21
22
|
|
|
22
23
|
const dashboardDefaultShootRunOptions: Required<Pick<ShootRunOptions, 'pollIntervalMs' | 'maxPollsPerJob' | 'submitStaggerMs'>> = {
|
|
23
24
|
pollIntervalMs: 3_000,
|
|
@@ -883,6 +884,7 @@ import { getInputHistoryStore, inputHistoryDbPath, inputHistoryJsonPath } from '
|
|
|
883
884
|
import { inspectActiveProvider } from '../provider-summary.js';
|
|
884
885
|
import { activeCodexAccountView } from '../oauth/codex-account-store.js';
|
|
885
886
|
import { buildDashboardStatusLines } from './dashboard-status-lines.js';
|
|
887
|
+
import { readSlashContextNow, seatsNowLine } from '../context-bus/context-now-surfaces.js';
|
|
886
888
|
import { buildFirstScreenBand } from './first-screen-band.js';
|
|
887
889
|
import { runNexusShow, type NexusShowResult } from '../cli/nexus-show.js';
|
|
888
890
|
import {
|
|
@@ -6404,7 +6406,14 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
6404
6406
|
const active = inspectActiveProvider(cfg);
|
|
6405
6407
|
const reasoningProvider = (['openai-codex', 'openai', 'anthropic', 'gemini', 'grok', 'local', 'openrouter'] as const)
|
|
6406
6408
|
.find(provider => active.provider === provider || active.provider === `auto:${provider}`);
|
|
6409
|
+
let seatsNow: string | null = null;
|
|
6410
|
+
try {
|
|
6411
|
+
seatsNow = seatsNowLine(readSlashContextNow([]), Date.now());
|
|
6412
|
+
} catch (error) {
|
|
6413
|
+
debug.log('dashboard.status', 'seats-unreadable', { error: String(error) });
|
|
6414
|
+
}
|
|
6407
6415
|
return buildDashboardStatusLines({
|
|
6416
|
+
seatsNow,
|
|
6408
6417
|
provider: active.provider,
|
|
6409
6418
|
model: active.model,
|
|
6410
6419
|
reasoning: reasoningProvider
|
|
@@ -15791,12 +15800,16 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15791
15800
|
chatLines.push(C.muted(` ${resume.turns} turns restored. Next turn continues this conversation.`));
|
|
15792
15801
|
}
|
|
15793
15802
|
}
|
|
15803
|
+
// 제안은 세션 작업 폴더 기준 — 시작 폴더 한 번이 아니라 폴더가 바뀔 때마다 다시 계산한다(IA1 리뷰 must-fix).
|
|
15804
|
+
const nextProjectSuggestion = createProjectSuggester(suggestProjectForFolder);
|
|
15805
|
+
const pushProjectSuggestion = (folder: string): void => {
|
|
15806
|
+
const project = nextProjectSuggestion(folder);
|
|
15807
|
+
if (project) chatLines.push(C.muted(` Project suggestion: ${project.name} (${project.id})`));
|
|
15808
|
+
};
|
|
15794
15809
|
if (dashboardAcpBootResult.mode !== 'resumed' && !chat.history.some((message) => message.role !== 'system')) {
|
|
15795
|
-
|
|
15796
|
-
const project = suggestProjectForFolder(process.cwd());
|
|
15797
|
-
if (project) chatLines.push(C.muted(` Project suggestion: ${project.name} (${project.id})`));
|
|
15798
|
-
} catch { /* suggestions must not interrupt the dashboard conversation */ }
|
|
15810
|
+
pushProjectSuggestion(getSessionCwd());
|
|
15799
15811
|
}
|
|
15812
|
+
subscribeSessionCwd((state) => { pushProjectSuggestion(state.cwd); });
|
|
15800
15813
|
chatScrollOffset = -1;
|
|
15801
15814
|
void renderDashboardFirstScreenBand({
|
|
15802
15815
|
history: chat.history,
|
|
@@ -272,6 +272,10 @@
|
|
|
272
272
|
// `../index.ts`) instead of importing the type — keeps this module free
|
|
273
273
|
// of circular dependency on dashboard/index.ts.
|
|
274
274
|
|
|
275
|
+
import { tuiNowSlash } from '../../context-bus/context-now-surfaces.js';
|
|
276
|
+
import { createWishCard } from '../../intake-plane/wish-card.js';
|
|
277
|
+
import { CardStore } from '../../task-cards/card-store.js';
|
|
278
|
+
import type { ContextNowDeps } from '../../context-bus/context-now.js';
|
|
275
279
|
import { runRebindCommand } from '../../input-core/index.js';
|
|
276
280
|
// B4 (TUI half) — /design reuses the CLI's own resolution so the three
|
|
277
281
|
// surfaces (CLI, PWA panel, this) cannot answer differently.
|
|
@@ -420,6 +424,8 @@ export interface DashboardSlashContext {
|
|
|
420
424
|
/** Existing TUI structured-question capability. Absent means /ask keeps
|
|
421
425
|
* the self-dev noninteractive deferred-clarification contract. */
|
|
422
426
|
surfaceUx?: Pick<SurfaceUx, 'question'>;
|
|
427
|
+
/** Optional wish-card store for isolated slash dispatch tests. */
|
|
428
|
+
wishCardStore?: CardStore;
|
|
423
429
|
attachmentRowMap: { clear(): void };
|
|
424
430
|
pushDebugLine(line: string): void;
|
|
425
431
|
pushChatLine(line: string): void;
|
|
@@ -1358,9 +1364,33 @@ function emitReplyToChat(ctx: Pick<DashboardSlashContext, 'pushChatLine'>, line:
|
|
|
1358
1364
|
ctx.pushChatLine(line);
|
|
1359
1365
|
}
|
|
1360
1366
|
|
|
1361
|
-
export function buildDashboardSlashRegistry(): SlashCommandRegistry<DashboardSlashContext, DashboardSlashReturn> {
|
|
1367
|
+
export function buildDashboardSlashRegistry(nowDeps?: ContextNowDeps): SlashCommandRegistry<DashboardSlashContext, DashboardSlashReturn> {
|
|
1362
1368
|
const registry = new SlashCommandRegistry<DashboardSlashContext, DashboardSlashReturn>();
|
|
1363
1369
|
|
|
1370
|
+
registry.register(['now'], (args, ctx) => {
|
|
1371
|
+
for (const line of tuiNowSlash(args, nowDeps)) ctx.pushChatLine(line);
|
|
1372
|
+
});
|
|
1373
|
+
|
|
1374
|
+
registry.register('wish', (args, ctx) => {
|
|
1375
|
+
const text = args.join(' ').trim();
|
|
1376
|
+
if (!text) {
|
|
1377
|
+
ctx.pushChatLine(ctx.warning(' usage: /wish <소원 한 줄>'));
|
|
1378
|
+
ctx.setChatScrollOffset(-1);
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
let store: CardStore | undefined;
|
|
1382
|
+
try {
|
|
1383
|
+
store = ctx.wishCardStore ?? new CardStore();
|
|
1384
|
+
const card = createWishCard({ text, source: 'tui', ref: crypto.randomUUID() }, store);
|
|
1385
|
+
ctx.pushChatLine(ctx.success(` 소원 카드로 남겼습니다 — ${card.title}`));
|
|
1386
|
+
} catch (err) {
|
|
1387
|
+
ctx.pushChatLine(ctx.error(` 소원 카드 등록 실패 — ${err instanceof Error ? err.message : String(err)}`));
|
|
1388
|
+
} finally {
|
|
1389
|
+
if (!ctx.wishCardStore) store?.close();
|
|
1390
|
+
}
|
|
1391
|
+
ctx.setChatScrollOffset(-1);
|
|
1392
|
+
});
|
|
1393
|
+
|
|
1364
1394
|
// ── B-1.a pilot ────────────────────────────────────────────────────
|
|
1365
1395
|
registry.register(['quit', 'q', 'exit'], (_args, ctx) => {
|
|
1366
1396
|
(ctx.exitTui ?? ctx.closeTui)();
|
|
@@ -43,6 +43,7 @@ export function renderCardText(e: DecisionEntry, extra: { note?: string; confirm
|
|
|
43
43
|
'',
|
|
44
44
|
`상황: ${e.scqa.s}`,
|
|
45
45
|
`문제: ${e.scqa.c}`,
|
|
46
|
+
...(e.pendingQuestion ? ['', `대기 질문 전문:\n${e.pendingQuestion}`] : []),
|
|
46
47
|
...(e.scqa.q ? [`질문: ${e.scqa.q}`] : []),
|
|
47
48
|
...(e.scqa.a ? [`제안: ${e.scqa.a}`] : []),
|
|
48
49
|
'',
|
|
@@ -180,7 +181,8 @@ export class DecisionCardService {
|
|
|
180
181
|
const entry = this.ledger.raise({
|
|
181
182
|
title: question.question.split(/\r?\n/, 1)[0]!.slice(0, 120),
|
|
182
183
|
category: question.impact === 'critical' ? 'irreversible' : 'scope',
|
|
183
|
-
scqa: { s: question.question, c:
|
|
184
|
+
scqa: { s: Array.from(question.question.split(/\r?\n/, 1)[0]!).slice(0, 200).join(''), c: 'The requesting run is waiting for this choice.' },
|
|
185
|
+
pendingQuestion: question.question,
|
|
184
186
|
options: question.options.map((option, index) => ({ key: keys[index]!, label: option.label, consequence: option.description })),
|
|
185
187
|
recommendation: recommended !== undefined && Number.isInteger(recommended) && recommended >= 0 && recommended < question.options.length
|
|
186
188
|
? { option: keys[recommended]!, why: '런이 추천' } : { skipped: true, reason: '추천 없음' },
|
|
@@ -251,9 +253,12 @@ export class DecisionCardService {
|
|
|
251
253
|
return { kind: 'confirm', view: renderCard(entry, { confirm: parsed.key, ...(card?.note ? { note: card.note } : {}) }), toast: '되돌릴 수 없는 결정 — 한 번 더 확인해 주세요' };
|
|
252
254
|
}
|
|
253
255
|
let decided: DecisionEntry;
|
|
256
|
+
let answerDelivery: ReturnType<DecisionLedger['decideWithDelivery']>['delivery'] = null;
|
|
254
257
|
try {
|
|
255
258
|
// Same ledger method the CLI `decide` uses — one record path.
|
|
256
|
-
|
|
259
|
+
const recorded = this.ledger.decideWithDelivery(entry.id, parsed.key, { kind: 'human' }, card?.note);
|
|
260
|
+
decided = recorded.entry;
|
|
261
|
+
answerDelivery = recorded.delivery;
|
|
257
262
|
} catch (error) {
|
|
258
263
|
debug.log('decisions.telegram', 'decide-failed', { platform, id: entry.id, reason: error instanceof Error ? error.message.slice(0, 80) : 'unknown' }, { level: 'warn' });
|
|
259
264
|
try { const now = this.ledger.show(entry.id); if (now.status !== 'open') return { kind: 'closed', view: renderCard(now), toast: '이미 정해진 결정입니다' }; } catch { /* fall through */ }
|
|
@@ -269,7 +274,9 @@ export class DecisionCardService {
|
|
|
269
274
|
await this.opts.replyToRaiser?.(decided, platform).catch((error: unknown) => {
|
|
270
275
|
debug.log('decisions.telegram', 'reply-failed', { platform, id: decided.id, reason: error instanceof Error ? error.message.slice(0, 80) : 'unknown' }, { level: 'warn' });
|
|
271
276
|
});
|
|
272
|
-
return { kind: 'decided', view, toast:
|
|
277
|
+
return { kind: 'decided', view, toast: answerDelivery && !answerDelivery.ok
|
|
278
|
+
? `결정은 기록됐지만 런 답 전달 실패 — decisions retry-answer ${decided.id}`
|
|
279
|
+
: `결정했습니다: ${decided.choice?.toUpperCase()}` };
|
|
273
280
|
}
|
|
274
281
|
|
|
275
282
|
/** Store a memo typed after «메모 달기»; the card shows it and the eventual decision carries it. */
|
|
@@ -7,7 +7,8 @@ import { createVersionResolver, type VersionOptions, type Versions } from '../di
|
|
|
7
7
|
import { getUserConfig } from '../user-config.js';
|
|
8
8
|
|
|
9
9
|
export type DecisionCategory = 'secret' | 'publish' | 'money' | 'security' | 'scope' | 'irreversible' | 'other';
|
|
10
|
-
|
|
10
|
+
/** Old track letters (S·T·F·O) stay readable; seat names (OP·MK·TC·UX) are the current identities. */
|
|
11
|
+
export type DecisionTrack = 'S' | 'T' | 'F' | 'O' | 'OP' | 'MK' | 'TC' | 'UX';
|
|
11
12
|
export interface DecisionOption { key: string; label: string; consequence: string }
|
|
12
13
|
export type Recommendation = { option: string; why: string } | { skipped: true; reason: string };
|
|
13
14
|
export type DecisionActor = { kind: 'human' } | { kind: 'auto'; agent: string; track?: DecisionTrack; delegation: string };
|
|
@@ -17,13 +18,15 @@ export interface DecisionEntry {
|
|
|
17
18
|
raisedBy: { agent: string; track?: DecisionTrack; session?: string }; version?: Versions;
|
|
18
19
|
status: 'open' | 'decided' | 'withdrawn'; refs?: string[];
|
|
19
20
|
resume?: { questionId: string; runId?: string };
|
|
21
|
+
/** Original pending question, including its newlines; SCQA fields are short summaries. */
|
|
22
|
+
pendingQuestion?: string;
|
|
20
23
|
/** DEC-TG — optional deadline (UTC). Cards remind the owner two hours before it. */
|
|
21
24
|
dueAt?: string;
|
|
22
25
|
decidedAt?: string; decidedBy?: DecisionActor; choice?: string; note?: string; versionAtDecision?: Versions;
|
|
23
26
|
withdrawnAt?: string; withdrawReason?: string;
|
|
24
27
|
history: Array<{ type: 'raised' | 'options-added' | 'decided' | 'withdrawn'; at?: string; by: string; version?: Versions; choice?: string; reason?: string }>;
|
|
25
28
|
}
|
|
26
|
-
export type RaiseInput = Pick<DecisionEntry, 'title' | 'category' | 'scqa' | 'options' | 'recommendation' | 'raisedBy' | 'refs' | 'dueAt' | 'resume'> & { raisedAt?: string };
|
|
29
|
+
export type RaiseInput = Pick<DecisionEntry, 'title' | 'category' | 'scqa' | 'options' | 'recommendation' | 'raisedBy' | 'refs' | 'dueAt' | 'resume' | 'pendingQuestion'> & { raisedAt?: string };
|
|
27
30
|
type Event = { type: 'raised'; entry: DecisionEntry } | { type: 'options-added'; id: string; at: string; options: DecisionOption[]; by: string } | { type: 'decided'; id: string; at?: string; by: DecisionActor; choice?: string; version?: Versions; note?: string } | { type: 'withdrawn'; id: string; at: string; reason: string; version: Versions };
|
|
28
31
|
export interface DecisionLedgerOptions extends VersionOptions { stateDir?: string; now?: () => Date; resolveVersion?: (at: string) => Versions; writeAnswer?: typeof writePendingQuestionAnswer }
|
|
29
32
|
|
|
@@ -38,7 +41,7 @@ export class DecisionAnswerDeliveryError extends Error {
|
|
|
38
41
|
}
|
|
39
42
|
}
|
|
40
43
|
const CATEGORIES: readonly string[] = ['secret', 'publish', 'money', 'security', 'scope', 'irreversible', 'other'];
|
|
41
|
-
const TRACKS: readonly string[] = ['S', 'T', 'F', 'O'];
|
|
44
|
+
const TRACKS: readonly string[] = ['S', 'T', 'F', 'O', 'OP', 'MK', 'TC', 'UX'];
|
|
42
45
|
|
|
43
46
|
function required(value: string, name: string): string {
|
|
44
47
|
if (typeof value !== 'string' || !value.trim()) throw new Error(`${name} is required`);
|
|
@@ -86,10 +89,12 @@ function validate(input: RaiseInput, historical = false): RaiseInput {
|
|
|
86
89
|
? { skipped: true as const, reason: safe(single(input.recommendation.reason, 'skip reason')) }
|
|
87
90
|
: { option: input.recommendation.option, why: safe(single(input.recommendation.why, 'recommendation why')) };
|
|
88
91
|
if ('option' in recommendation && !options.some(o => o.key === recommendation.option)) throw new Error('recommended option not found');
|
|
89
|
-
if (input.resume && !/^auq:[0-9a-z]+:[0-9a-z]{5}(?![\s\S])/.test(input.resume.questionId)) throw new Error('invalid resume questionId');
|
|
92
|
+
if (input.resume && !/^(?:auq:[0-9a-z]+:[0-9a-z]{5}|execution:[A-Za-z0-9_-]+:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?![\s\S])/.test(input.resume.questionId)) throw new Error('invalid resume questionId');
|
|
90
93
|
const resume = input.resume ? { questionId: input.resume.questionId,
|
|
91
94
|
...(input.resume.runId === undefined ? {} : { runId: single(input.resume.runId, 'resume runId') }) } : undefined;
|
|
95
|
+
if (input.pendingQuestion !== undefined) required(input.pendingQuestion, 'pending question');
|
|
92
96
|
return { ...input, title, scqa: { s, c, ...(q ? { q } : {}), ...(a ? { a } : {}) }, options, recommendation,
|
|
97
|
+
...(input.pendingQuestion === undefined ? {} : { pendingQuestion: safe(input.pendingQuestion) }),
|
|
93
98
|
...(resume ? { resume } : {}),
|
|
94
99
|
raisedBy: { agent: safe(single(input.raisedBy.agent, 'agent')), ...(input.raisedBy.track ? { track: input.raisedBy.track } : {}), ...(input.raisedBy.session ? { session: safe(single(input.raisedBy.session, 'session')) } : {}) },
|
|
95
100
|
...(input.refs ? { refs: input.refs.map(r => safe(single(r, 'ref'))) } : {}),
|
|
@@ -263,13 +268,16 @@ export class DecisionLedger {
|
|
|
263
268
|
if (!pending.ok) throw new Error(pending.error);
|
|
264
269
|
const target = pending.questions.find(item => item.id === questionId);
|
|
265
270
|
if (!target || target.questions.length !== 1 || !target.questions[0]?.id) throw new Error('pending question target not found or ambiguous');
|
|
271
|
+
if (questionId.startsWith('execution:') && (!runId || target.runId !== runId || !questionId.startsWith(`execution:${runId}:`))) throw new Error('pending question run differs from decision');
|
|
272
|
+
if (!questionId.startsWith('execution:') && runId !== undefined && target.runId !== undefined && target.runId !== runId) throw new Error('pending question run differs from decision');
|
|
273
|
+
if (target.expiresAt && Date.parse(target.expiresAt) <= this.now().getTime()) throw new Error('pending question expired');
|
|
266
274
|
const question = target.questions[0];
|
|
267
275
|
if (question.options.length !== entry.options.length || question.options.some((option, index) =>
|
|
268
276
|
entry.options[index]?.key !== String.fromCharCode(97 + index) || entry.options[index]?.label !== option.label)) {
|
|
269
277
|
throw new Error('pending question options differ from decision');
|
|
270
278
|
}
|
|
271
279
|
const answerKey = question.id;
|
|
272
|
-
const answer = { id: questionId, result: { answers: { [answerKey]: `${entry.choice}) ${label}` },
|
|
280
|
+
const answer = { id: questionId, result: { answers: { [answerKey]: questionId.startsWith('execution:') ? label : `${entry.choice}) ${label}` },
|
|
273
281
|
...(entry.note ? { otherText: { [answerKey]: entry.note } } : {}) } };
|
|
274
282
|
const existing = readPendingQuestionAnswer(questionId, deps);
|
|
275
283
|
if (!existing.ok) throw new Error('existing answer unreadable');
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
// ⏳ Mention parser → persona LLM dispatch wire
|
|
22
22
|
|
|
23
23
|
import { debug } from '../debug/log.js';
|
|
24
|
+
import { botAudienceFor, gateDiscordSchemas } from '../maturity/bot-command-maturity.js';
|
|
24
25
|
import type { DiscordBot } from '../discord.js';
|
|
25
26
|
import {
|
|
26
27
|
loadLayeredPersonaDirs,
|
|
@@ -204,7 +205,10 @@ export async function wireSprint21Runtime(opts: WireSprint21Opts): Promise<Sprin
|
|
|
204
205
|
// 6. Slash command registration
|
|
205
206
|
const cmdRest = makeCommandRest({ token: opts.token, fetchImpl: opts.fetchImpl });
|
|
206
207
|
async function registerSlashCommands(): Promise<number> {
|
|
207
|
-
const
|
|
208
|
+
const allSchemas = router.schemas();
|
|
209
|
+
const audience = botAudienceFor('discord');
|
|
210
|
+
const { schemas, hidden } = gateDiscordSchemas(allSchemas, audience);
|
|
211
|
+
debug.log('discord.command', 'menu-filtered', { total: allSchemas.length, shown: schemas.length - hidden, ...audience });
|
|
208
212
|
if (opts.devGuildId) {
|
|
209
213
|
const out = await cmdRest.bulkOverwriteGuild(opts.appId, opts.devGuildId, schemas);
|
|
210
214
|
log(`[sprint21-wire] registered ${out.length} slash commands to guild ${opts.devGuildId}`);
|