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
package/src/cli/pty-drive-cli.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { StreamLLMFn } from '../autopilot/llm-control-brain.js';
|
|
|
8
8
|
import { establishElanousTuiIsolation, elanousTuiSpawnOptions, type ElanousTuiIsolation } from '../self-implement/elanous-tui-spawn.js';
|
|
9
9
|
import { resolveObserveOnlyDecision } from '../self-implement/observe-only.js';
|
|
10
10
|
import { getUserConfig } from '../user-config.js';
|
|
11
|
+
import { verdictForFinalPtyScreen } from './pty-drive-verdict.js';
|
|
11
12
|
import { debug } from '../debug/log.js';
|
|
12
13
|
import { writeHarnessScreen } from '../harness/harness-screen.js';
|
|
13
14
|
import { resolveControlInboxDir } from '../harness/control-inbox.js';
|
|
@@ -19,6 +20,7 @@ import { resolvePtyRef } from '../pty-shell/pty-ref.js';
|
|
|
19
20
|
import { parsePtyWriteActor } from '../pty-shell/pty-write-arbiter.js';
|
|
20
21
|
import { controlDepsForHandle, controlDepsForRemoteRef, runPtyControlLoop } from '../autopilot/pty-control-loop.js';
|
|
21
22
|
import { createLlmControlBrain } from '../autopilot/llm-control-brain.js';
|
|
23
|
+
import { withDriveJail } from './drive-input-jail.js';
|
|
22
24
|
|
|
23
25
|
/** `pty list` 한 줄의 상태 컬럼 위치 — `<id>\t<kind>\t<nickname>\t<scope>\t<state>\t<extra…>`.
|
|
24
26
|
* ⚠️⛔ **회귀 테스트의 fixture 는 실측 형식의 *스냅샷*이지 형식 변경 감지기가 아니다**(리뷰 지적 · 과장 정정) —
|
|
@@ -166,6 +168,8 @@ export interface PtyDriveOpts {
|
|
|
166
168
|
readonly maxSteps?: number;
|
|
167
169
|
readonly pollMs?: number;
|
|
168
170
|
readonly model?: string;
|
|
171
|
+
/** DRIVE-JAIL: brain inputs naming paths outside this directory are not sent to the PTY. */
|
|
172
|
+
readonly jailHome?: string;
|
|
169
173
|
/** Enable the child SelfImplement observation-only override at boot. */
|
|
170
174
|
readonly observeOnly?: boolean;
|
|
171
175
|
readonly cwd?: string;
|
|
@@ -213,6 +217,8 @@ const liveAttachDriveDeps: PtyAttachDriveDeps = {
|
|
|
213
217
|
|
|
214
218
|
export interface PtyAttachDriveOpts {
|
|
215
219
|
readonly goal: string;
|
|
220
|
+
/** DRIVE-JAIL: brain inputs naming paths outside this directory are not sent to the PTY. */
|
|
221
|
+
readonly jailHome?: string;
|
|
216
222
|
readonly maxSteps?: number;
|
|
217
223
|
readonly pollMs?: number;
|
|
218
224
|
readonly model?: string;
|
|
@@ -250,8 +256,11 @@ export async function runPtyAttachDrive(ref: string, opts: PtyAttachDriveOpts, d
|
|
|
250
256
|
...(opts.stream ? { stream: opts.stream } : {}),
|
|
251
257
|
onDecision: (decision) => out(decision.action === 'input' ? ` → input (${decision.text.length} chars)\n` : decision.action === 'done' ? ` → done (${decision.reason})\n` : ' · wait\n'),
|
|
252
258
|
});
|
|
259
|
+
const controlDeps = withDriveJail(handle ? deps.controlDepsForHandle(handle) : deps.controlDepsForRemoteRef?.(id, { actor }) ?? (() => { throw new Error('pty auto: remote control dependencies unavailable'); })(), opts.jailHome, (event, data) => deps.log(event, data));
|
|
260
|
+
const inputHistory: string[] = [];
|
|
253
261
|
const result = await deps.runControlLoop(brain, {
|
|
254
|
-
...
|
|
262
|
+
...controlDeps,
|
|
263
|
+
inject: (text: string) => { inputHistory.push(text); return controlDeps.inject(text); },
|
|
255
264
|
subjectPtyId: id,
|
|
256
265
|
canReceiveInput: true,
|
|
257
266
|
}, {
|
|
@@ -260,7 +269,14 @@ export async function runPtyAttachDrive(ref: string, opts: PtyAttachDriveOpts, d
|
|
|
260
269
|
});
|
|
261
270
|
deps.log('attach-finish', { id, termination: result.termination.kind, steps: result.steps });
|
|
262
271
|
out(`\n▸ ${result.termination.kind} (${result.steps} steps)\n`);
|
|
263
|
-
|
|
272
|
+
if (result.termination.kind !== 'success') return { exitCode: 1, message: `pty auto: ${id} ${result.termination.kind}` };
|
|
273
|
+
// DRIVE-OK: «done» from the brain still has to show on the final screen.
|
|
274
|
+
let screen = '';
|
|
275
|
+
try { screen = String(await controlDeps.observe()); } catch { /* unreadable → unverified */ }
|
|
276
|
+
const verdict = verdictForFinalPtyScreen({ screen, inputHistory, exitCode: null });
|
|
277
|
+
out(`▸ verdict: ${verdict.kind} — ${verdict.reason}\n`);
|
|
278
|
+
deps.log('attach-verdict', { id, kind: verdict.kind, reason: verdict.reason.slice(0, 200) });
|
|
279
|
+
return { exitCode: verdict.kind === 'success' ? 0 : 1, message: `pty auto: ${id} ${verdict.kind}` };
|
|
264
280
|
}
|
|
265
281
|
|
|
266
282
|
export type PtyAttachDriveRunner = (start: () => Promise<{ readonly exitCode: number; readonly message: string }>) => Promise<void>;
|
|
@@ -273,14 +289,15 @@ export function registerPtyAttachDriveCommand(pty: Command, run: PtyAttachDriveR
|
|
|
273
289
|
.option('--poll-ms <ms>', 'screen polling interval in milliseconds', '800')
|
|
274
290
|
.option('--model <model>', 'LLM model override')
|
|
275
291
|
.option('--actor <who>', 'remote input actor (human or agent)', 'human')
|
|
292
|
+
.option('--jail-home <dir>', 'DRIVE-JAIL: do not send inputs naming paths outside this directory')
|
|
276
293
|
.description('Drive an existing agent-owned PTY without spawning a terminal')
|
|
277
|
-
.action((ref: string, opts: { goal: string; maxSteps: string; pollMs: string; model?: string; actor?: string }) => run(async () => {
|
|
294
|
+
.action((ref: string, opts: { goal: string; maxSteps: string; pollMs: string; model?: string; actor?: string; jailHome?: string }) => run(async () => {
|
|
278
295
|
const maxSteps = Number(opts.maxSteps);
|
|
279
296
|
const pollMs = Number(opts.pollMs);
|
|
280
297
|
const actor = parsePtyWriteActor(opts.actor);
|
|
281
298
|
if (!actor) return { exitCode: 2, message: 'pty auto: --actor must be human or agent' };
|
|
282
299
|
return Number.isInteger(maxSteps) && maxSteps >= 1 && Number.isInteger(pollMs) && pollMs >= 0
|
|
283
|
-
? runPtyAttachDrive(ref, { goal: opts.goal, maxSteps, pollMs, actor, ...(opts.model ? { model: opts.model } : {}) }, deps)
|
|
300
|
+
? runPtyAttachDrive(ref, { goal: opts.goal, maxSteps, pollMs, actor, ...(opts.model ? { model: opts.model } : {}), ...(opts.jailHome ? { jailHome: opts.jailHome } : {}) }, deps)
|
|
284
301
|
: { exitCode: 2, message: 'pty auto: --max-steps must be an integer >= 1 and --poll-ms must be an integer >= 0' };
|
|
285
302
|
}));
|
|
286
303
|
}
|
|
@@ -299,6 +316,8 @@ export interface DriveCliOpts {
|
|
|
299
316
|
json?: boolean;
|
|
300
317
|
/** Existing PTY ref. Absent = spawn a new shell PTY (the default). */
|
|
301
318
|
attach?: string;
|
|
319
|
+
/** DRIVE-JAIL boundary directory. */
|
|
320
|
+
jailHome?: string;
|
|
302
321
|
}
|
|
303
322
|
|
|
304
323
|
export interface DriveCliDeps {
|
|
@@ -357,6 +376,7 @@ export async function runDriveCliCommand(command: string | undefined, opts: Driv
|
|
|
357
376
|
attached = await runAttach(attach, {
|
|
358
377
|
goal: opts.goal, maxSteps, pollMs,
|
|
359
378
|
...(opts.model ? { model: opts.model } : {}),
|
|
379
|
+
...(opts.jailHome ? { jailHome: opts.jailHome } : {}),
|
|
360
380
|
});
|
|
361
381
|
} catch (err) {
|
|
362
382
|
writeError(`drive: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
@@ -379,6 +399,7 @@ export async function runDriveCliCommand(command: string | undefined, opts: Driv
|
|
|
379
399
|
command, goal: opts.goal, maxSteps, pollMs,
|
|
380
400
|
...(opts.model ? { model: opts.model } : {}),
|
|
381
401
|
...(opts.cwd ? { cwd: opts.cwd } : {}),
|
|
402
|
+
...(opts.jailHome ? { jailHome: opts.jailHome } : {}),
|
|
382
403
|
}));
|
|
383
404
|
} catch (err) {
|
|
384
405
|
writeError(`drive: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
@@ -827,7 +848,10 @@ async function runPtyDriveInner(opts: PtyDriveOpts): Promise<{ exitCode: number
|
|
|
827
848
|
writeScreen(screenKey, await h!.renderScreen(), process.env);
|
|
828
849
|
delivered = true;
|
|
829
850
|
} : undefined;
|
|
830
|
-
const
|
|
851
|
+
const rawDeps = withDriveJail(controlDepsForHandle(h), opts.jailHome, (event, data) => debug.log('pty.drive', event, data));
|
|
852
|
+
// DRIVE-OK: keep what we typed so the final verdict can tell child output from echoed input.
|
|
853
|
+
const inputHistory: string[] = [];
|
|
854
|
+
const deps = { ...rawDeps, inject: (text: string) => { inputHistory.push(text); return rawDeps.inject(text); } };
|
|
831
855
|
const autoAssist = opts.elanous ? getUserConfig().tools.selfImplement.autoAssist : undefined;
|
|
832
856
|
const observe = opts.elanous ? async () => {
|
|
833
857
|
const frame = await deps.observe();
|
|
@@ -851,12 +875,22 @@ async function runPtyDriveInner(opts: PtyDriveOpts): Promise<{ exitCode: number
|
|
|
851
875
|
if (screen.trim()) out(`▸ 최종 화면:\n${screen}\n`);
|
|
852
876
|
const childExit = h.exitCode;
|
|
853
877
|
const alive = h.isAlive();
|
|
854
|
-
|
|
878
|
+
// DRIVE-OK (10-03 X1: every step failed yet drive said ok): the brain's «done» is not proof —
|
|
879
|
+
// judge the final screen. Plain drives take the verdict as the exit; elanous-TUI drives only observe it.
|
|
880
|
+
const verdict = result.termination.kind === 'success' ? verdictForFinalPtyScreen({ screen, inputHistory, exitCode: childExit }) : null;
|
|
881
|
+
if (verdict) {
|
|
882
|
+
out(`▸ verdict: ${verdict.kind} — ${verdict.reason}\n`);
|
|
883
|
+
debug.log('pty.drive', 'verdict', { kind: verdict.kind, reason: verdict.reason.slice(0, 200), enforced: !opts.elanous });
|
|
884
|
+
}
|
|
885
|
+
const verdictFails = !!verdict && !opts.elanous && verdict.kind !== 'success';
|
|
886
|
+
const baseExit = childExit !== null
|
|
855
887
|
? childExit
|
|
856
888
|
: alive
|
|
857
889
|
? result.termination.kind === 'success' ? 0 : 1
|
|
858
890
|
: null;
|
|
859
|
-
|
|
891
|
+
// The verdict only withholds a success: nonzero and unknown (null) exits keep their meaning.
|
|
892
|
+
const exitCode = baseExit === 0 && verdictFails ? 1 : baseExit;
|
|
893
|
+
debug.log('pty.drive', 'exit-resolve', { alive, childExit, exitCode, termination: result.termination.kind, ...(verdict ? { verdict: verdict.kind } : {}) });
|
|
860
894
|
if (exitCode === null) out('▸ child exited without an exit code; reporting failure at the process boundary (exit 1)\n');
|
|
861
895
|
return { exitCode };
|
|
862
896
|
} finally {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Final-screen evidence is independent of the controller's "done" declaration.
|
|
2
|
+
export type PtyDriveVerdict =
|
|
3
|
+
| { readonly kind: 'done-but-failed'; readonly reason: string; readonly evidence: null }
|
|
4
|
+
| { readonly kind: 'success'; readonly reason: string; readonly evidence: string }
|
|
5
|
+
| { readonly kind: 'success-unverified'; readonly reason: string; readonly evidence: null };
|
|
6
|
+
|
|
7
|
+
export interface FinalPtyEvidence {
|
|
8
|
+
readonly screen: string;
|
|
9
|
+
readonly inputHistory: readonly string[];
|
|
10
|
+
readonly exitCode: number | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line no-control-regex
|
|
14
|
+
const ANSI = /\x1b(?:\][^\x07\x1b]*(?:\x07|\x1b\\)|\[[0-?]*[ -/]*[@-~]|[@-Z\\-_])/g;
|
|
15
|
+
const FAILURE = /(?:\bcommand not found\b|\bnot recognized as (?:an internal or external )?command\b|\bno such file or directory\b|\b(?:error|fatal|exception)\s*:|\berror TS\d+\b|\b(?:build failed|tests? failed|test suite failed|failed to|compilation failed|permission denied)\b|(?:^|\s)[1-9]\d*\s+fail(?:ed|ing|ures?)?\b|\b(?:exit(?:ed)? (?:with )?(?:code |status )?)[1-9]\d*\b|\bnpm ERR!\b|^\s*(?:FAIL\b|✗|❌))/i;
|
|
16
|
+
const SUCCESS = /(?:\b[1-9]\d*\s+(?:pass|passed)\b|\btests?:\s*[1-9]\d*\s+passed\b|\bbuild successful\b|\b(?:successfully|succeeded)\b|\bGOAL-COMPLETE\b)/i;
|
|
17
|
+
|
|
18
|
+
/** Failure wins over success; an exit code of zero is not itself proof of the goal. */
|
|
19
|
+
export function verdictForFinalPtyScreen({ screen, inputHistory, exitCode }: FinalPtyEvidence): PtyDriveVerdict {
|
|
20
|
+
if (exitCode !== null && exitCode !== 0) {
|
|
21
|
+
return { kind: 'done-but-failed', reason: `child exit code ${exitCode}`, evidence: null };
|
|
22
|
+
}
|
|
23
|
+
// The PTY may echo commands (including fabricated success markers). Only child output is evidence.
|
|
24
|
+
const inputs = new Set(inputHistory.flatMap((input) => input.replace(/\r/g, '\n').split('\n').map((line) => line.trim()).filter(Boolean)));
|
|
25
|
+
// An echo/printf command prints its operand; that output is not independent proof of anything
|
|
26
|
+
// (`echo "7 pass"` must not count as passing tests — review round 2).
|
|
27
|
+
const echoedLiterals = new Set([...inputs].flatMap((input) => {
|
|
28
|
+
const match = /^(?:echo(?:\s+-[neE]+)?|printf)\s+(.+)$/i.exec(input);
|
|
29
|
+
if (!match) return [];
|
|
30
|
+
const operand = match[1]!.trim().replace(/^(['"])(.*)\1$/s, '$2').replace(/\\n$/, '').trim();
|
|
31
|
+
return operand ? [operand] : [];
|
|
32
|
+
}));
|
|
33
|
+
const lines = screen.replace(ANSI, '').replace(/\r/g, '\n').split('\n')
|
|
34
|
+
.map((line) => line.trim()).filter((line) => line && !inputs.has(line) && !echoedLiterals.has(line) && ![...inputs].some((input) => line.endsWith(`$ ${input}`) || line.endsWith(`> ${input}`)));
|
|
35
|
+
const failure = lines.find((line) => FAILURE.test(line));
|
|
36
|
+
if (failure) return { kind: 'done-but-failed', reason: failure, evidence: null };
|
|
37
|
+
const evidence = lines.find((line) => SUCCESS.test(line) && !/\b0\s+(?:pass|passed)\b/i.test(line));
|
|
38
|
+
if (evidence) return { kind: 'success', reason: 'final PTY screen has success evidence', evidence };
|
|
39
|
+
return { kind: 'success-unverified', reason: 'final PTY screen has no success evidence', evidence: null };
|
|
40
|
+
}
|
package/src/cli/release-cli.ts
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
// elanous release tag --version <x.y.z> --source <commit> [--yes]
|
|
6
6
|
// elanous release verify [--version <x.y.z>]
|
|
7
7
|
// elanous release notes --from <ref> [--to <ref>]
|
|
8
|
-
// elanous release run --version <x.y.z> [--dry-run] [--json] [--if-ready]
|
|
8
|
+
// elanous release run --version <x.y.z> [--cut-commit <sha>] [--dry-run] [--json] [--if-ready]
|
|
9
|
+
// elanous release cut-branch --version <x.y.z> --base <sha> --pick <sha>... [--dry-run]
|
|
9
10
|
//
|
|
10
11
|
// 🩸 계기(2026-09-25 v0.1.0 첫 공개): 손으로 밟은 절차에서 둘을 빠뜨릴 뻔했다 — 공개본 git 커밋(판 커밋이 공개본 커밋이 된다) ·
|
|
11
12
|
// PWA 빌드(빌드 산출은 공개본에 안 실린다 → 빠뜨리면 «웹 화면 없는 판»). 절차를 명령으로 굳힌다.
|
|
@@ -25,10 +26,12 @@ import { envLiteral } from '../platform/env-literal.js';
|
|
|
25
26
|
import { userConfigPath } from '../user-config.js';
|
|
26
27
|
import { addItem, claimItem, decodeClaimHistoryEntry, devVersion, listChecklist, ownerMatches, parseOwner, parityGap, removeItem, seedFromRoadmap, setItem, summarizeChecklist, type ChecklistStatus, type ChecklistDisposition, type ChecklistKind } from '../release-loop/checklist.js';
|
|
27
28
|
import * as features from '../release-loop/feature-store.js';
|
|
29
|
+
import { landedButYellow, type MergedChecklistPr } from '../release-loop/landed-but-yellow.js';
|
|
28
30
|
import { formatSchedule, getSchedule, listSchedules, setSchedule } from '../release-loop/release-schedule.js';
|
|
29
31
|
import { writeStdoutJson } from './stdout-json.js';
|
|
30
32
|
import { CliUserError } from './cli-user-error.js';
|
|
31
33
|
import { runUnattendedRelease, type UnattendedReleaseDeps } from '../../scripts/release-loop/unattended-release.js';
|
|
34
|
+
import { cutReleaseBranch } from '../../scripts/release-loop/cut-branch.js';
|
|
32
35
|
import { releaseReadiness } from '../../scripts/release-loop/release-readiness.js';
|
|
33
36
|
import { runReleaseIfReady } from './release-run-if-ready.js';
|
|
34
37
|
|
|
@@ -497,7 +500,13 @@ async function checklistOutput(v: string, codenames: Record<string, string>, mod
|
|
|
497
500
|
}
|
|
498
501
|
}
|
|
499
502
|
|
|
500
|
-
export
|
|
503
|
+
export interface LandedButYellowDeps {
|
|
504
|
+
run?: Runner;
|
|
505
|
+
checklist?: typeof listChecklist;
|
|
506
|
+
now?: () => Date;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
export function registerReleaseCommands(program: Command, releaseRunDeps: UnattendedReleaseDeps = {}, landedDeps: LandedButYellowDeps = {}): void {
|
|
501
510
|
const release = program.command('release').description('공개 배포 한 판 — prepare(로컬) → publish(--yes) → verify (docs/manual/MANUAL-versioning-and-release-2026-09-25.md)');
|
|
502
511
|
const schedule = release.command('schedule').description('판별 컷·착지 마감 조회·갱신');
|
|
503
512
|
const scheduleLedgerRoot = () => releaseRunDeps.ledgerRoot ?? releaseLedgerRoot();
|
|
@@ -536,10 +545,43 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
536
545
|
const { version, codenames, json } = context(cmd);
|
|
537
546
|
await checklistOutput(version, codenames, 'status', json, opts.owner);
|
|
538
547
|
});
|
|
548
|
+
withContext(checklist.command('landed-but-yellow').description('병합 PR 이 있지만 노랑·빨강인 칸(읽기 전용)'))
|
|
549
|
+
.option('--owner <owner>', '자리 또는 하위 자리로 거르기')
|
|
550
|
+
.action(async (opts: { owner?: string }, cmd: Command) => {
|
|
551
|
+
const { version, json } = context(cmd);
|
|
552
|
+
try {
|
|
553
|
+
if (opts.owner !== undefined) parseOwner(opts.owner);
|
|
554
|
+
const since = new Date((landedDeps.now ?? (() => new Date()))().getTime() - 7 * 86_400_000).toISOString().slice(0, 10);
|
|
555
|
+
const raw = must((landedDeps.run ?? defaultRunner)('gh', ['pr', 'list', '--state', 'merged', '--search', `merged:>=${since}`, '--limit', '400', '--json', 'number,title,body,mergedAt'], process.cwd()), '병합 PR 조회(gh)');
|
|
556
|
+
const prs = JSON.parse(raw) as MergedChecklistPr[];
|
|
557
|
+
if (!Array.isArray(prs)) throw new Error('병합 PR 조회(gh): 배열이 아니다');
|
|
558
|
+
const items = (landedDeps.checklist ?? listChecklist)(version).items;
|
|
559
|
+
const rows = landedButYellow(items, prs, { owner: opts.owner });
|
|
560
|
+
if (json) await writeStdoutJson(`${JSON.stringify(rows)}\n`);
|
|
561
|
+
else {
|
|
562
|
+
const updatedAtById = new Map(items.map((item) => [item.id, item.updatedAt]));
|
|
563
|
+
const date = (iso: string) => {
|
|
564
|
+
const parts = new Intl.DateTimeFormat('en-US', { timeZone: 'Asia/Seoul', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hourCycle: 'h23' }).formatToParts(new Date(iso));
|
|
565
|
+
const part = (name: string) => parts.find((entry) => entry.type === name)?.value;
|
|
566
|
+
return `${part('month')}-${part('day')} ${part('hour')}:${part('minute')}`;
|
|
567
|
+
};
|
|
568
|
+
for (const row of rows) {
|
|
569
|
+
const icon = row.status === 'yellow' ? '🟡' : '🔴';
|
|
570
|
+
console.log(`${row.id} ${row.owner ?? '-'} ${icon} ← ${row.prs.map((pr, i) => `#${pr.number} «${pr.title}» (${date(pr.mergedAt)} · 근거에 ${row.alreadyInEvidence[i] ? '있음' : '없음'}${pr.mergedAt > (updatedAtById.get(row.id) ?? '') ? ' · 칸보다 새것' : ''})`).join(' · ')}`);
|
|
571
|
+
}
|
|
572
|
+
console.log(`${rows.length}칸 · 그중 근거에 없는 PR 이 있는 칸 ${rows.filter((row) => row.alreadyInEvidence.includes(false)).length}`);
|
|
573
|
+
}
|
|
574
|
+
if (prs.length >= 400) console.error('⚠ 병합 PR 400개 상한: 목록이 잘렸을 수 있다');
|
|
575
|
+
} catch (error) {
|
|
576
|
+
console.error(`⛔ ${error instanceof Error ? error.message : String(error)}`);
|
|
577
|
+
process.exitCode = 1;
|
|
578
|
+
}
|
|
579
|
+
});
|
|
539
580
|
withContext(checklist.command('add <id> <title>').description('칸 추가')).option('--owner <owner>', '담당').option('--kind <kind>', 'screen = 다섯 화면 짝 칸 · 근거에 짝: PWA … · 데스크톱 … · 폴드 … · 아이폰 … · 아이패드 … 한 줄')
|
|
540
|
-
.
|
|
581
|
+
.option('--allow-duplicate-id', '다른 판에 같은 id 가 있어도 경고 후 추가')
|
|
582
|
+
.action((id: string, title: string, opts: { owner?: string; kind?: string; allowDuplicateId?: boolean }, cmd: Command) => {
|
|
541
583
|
const { version, json } = context(cmd);
|
|
542
|
-
const data = addItem(version, { id, title, ...(opts.owner !== undefined ? { owner: opts.owner } : {}), ...(opts.kind !== undefined ? { kind: opts.kind as ChecklistKind } : {}) });
|
|
584
|
+
const data = addItem(version, { id, title, ...(opts.owner !== undefined ? { owner: opts.owner } : {}), ...(opts.kind !== undefined ? { kind: opts.kind as ChecklistKind } : {}) }, { allowDuplicateId: opts.allowDuplicateId });
|
|
543
585
|
if (json) console.log(JSON.stringify(data)); else console.log(`✅ ${id} 추가`);
|
|
544
586
|
});
|
|
545
587
|
withContext(checklist.command('set <id>').description('칸 상태·근거·담당·처분 갱신'))
|
|
@@ -579,11 +621,11 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
579
621
|
});
|
|
580
622
|
const actor = () => process.env.ELANOUS_TRACK || 'cli';
|
|
581
623
|
withContext(checklist.command('move <id>').description('칸을 한 트랜잭션으로 다른 판에 옮긴다'))
|
|
582
|
-
.requiredOption('--from <v>', '현재 판').requiredOption('--to <v>', '새 판')
|
|
583
|
-
.action((id: string, opts: { from: string; to: string }, cmd: Command) => {
|
|
624
|
+
.requiredOption('--from <v>', '현재 판').requiredOption('--to <v>', '새 판').option('--reason <reason>', '이동 사유')
|
|
625
|
+
.action((id: string, opts: { from: string; to: string; reason?: string }, cmd: Command) => {
|
|
584
626
|
const { codenames, json } = context(cmd);
|
|
585
627
|
const from = checklistVersion(opts.from, codenames), to = checklistVersion(opts.to, codenames);
|
|
586
|
-
features.move(id, from, to, actor());
|
|
628
|
+
features.move(id, from, to, actor(), undefined, undefined, opts.reason);
|
|
587
629
|
if (json) console.log(JSON.stringify(listChecklist(to))); else console.log(`✅ ${id} ${from} → ${to}`);
|
|
588
630
|
});
|
|
589
631
|
withContext(checklist.command('retitle <id> <title>').description('칸 제목 수정')).action((id: string, title: string, _opts: unknown, cmd: Command) => {
|
|
@@ -675,19 +717,30 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
675
717
|
const { draftReleaseNotes, readLandedCommits, renderReleaseNotes } = await import('../../scripts/release-notes.js');
|
|
676
718
|
console.log(renderReleaseNotes(draftReleaseNotes(readLandedCommits(o.from, o.to), o.from, o.to)));
|
|
677
719
|
});
|
|
720
|
+
release.command('cut-branch')
|
|
721
|
+
.description('원래 컷에 main 의 수리 커밋만 얹은 release/<v> 가지를 만들고 push')
|
|
722
|
+
.requiredOption('--version <v>', '릴리스 판(x.y.z)')
|
|
723
|
+
.requiredOption('--base <sha>', '원래 컷 SHA')
|
|
724
|
+
.requiredOption('--pick <sha...>', '차례로 얹을 main 커밋 SHA')
|
|
725
|
+
.option('--dry-run', '가지·worktree·push 없이 계획만 출력')
|
|
726
|
+
.option('--json', '결과 한 줄 JSON(stdout)')
|
|
727
|
+
.action(async (o: { version: string; base: string; pick: string[]; dryRun?: boolean; json?: boolean }) => {
|
|
728
|
+
await jsonAction(o.json, async (log) => cutReleaseBranch({ ...o, log }), () => true);
|
|
729
|
+
});
|
|
678
730
|
release.command('run')
|
|
679
731
|
.description('릴리스 루프 실행 — 원장 직전 판과 release.loop 설정으로 그래프 입력 구성 · --dry-run 은 입력만 출력')
|
|
680
732
|
.requiredOption('--version <v>', '공개할 판(x.y.z)')
|
|
733
|
+
.option('--cut-commit <sha>', 'origin/main HEAD 대신 컷으로 쓸 커밋')
|
|
681
734
|
.option('--dry-run', '체크리스트·그래프 실행 없이 전체 입력 보기')
|
|
682
735
|
.option('--if-ready', '준비되지 않았으면 사유를 출력하고 성공으로 건너뛴다')
|
|
683
736
|
.option('--json', '결과 한 줄 JSON(stdout) · 사람 줄은 stderr')
|
|
684
|
-
.action(async (o: { version: string; dryRun?: boolean; ifReady?: boolean; json?: boolean }) => {
|
|
737
|
+
.action(async (o: { version: string; cutCommit?: string; dryRun?: boolean; ifReady?: boolean; json?: boolean }) => {
|
|
685
738
|
if (o.ifReady && !o.dryRun) {
|
|
686
739
|
try {
|
|
687
740
|
const outcome = await runReleaseIfReady(o.version, {
|
|
688
741
|
ledgerRoot: releaseRunDeps.ledgerRoot,
|
|
689
742
|
readiness: (version, options) => releaseReadiness(version, { ledgerRoot: releaseRunDeps.ledgerRoot, checklist: releaseRunDeps.checklist, ...options }),
|
|
690
|
-
run: () => runUnattendedRelease({ version: o.version }, releaseRunDeps),
|
|
743
|
+
run: () => runUnattendedRelease({ version: o.version, cutCommit: o.cutCommit }, releaseRunDeps),
|
|
691
744
|
});
|
|
692
745
|
if (outcome.skipped) {
|
|
693
746
|
if (o.json) await writeStdoutJson(`${JSON.stringify(outcome)}\n`);
|
|
@@ -707,7 +760,7 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
707
760
|
return;
|
|
708
761
|
}
|
|
709
762
|
await jsonAction(o.json, async (log) => {
|
|
710
|
-
const result = await runUnattendedRelease({ version: o.version, dryRun: o.dryRun }, releaseRunDeps);
|
|
763
|
+
const result = await runUnattendedRelease({ version: o.version, dryRun: o.dryRun, cutCommit: o.cutCommit }, releaseRunDeps);
|
|
711
764
|
log(`${result.dryRun ? '· 드라이런' : '▶ 릴리스 루프'} ${result.input.version} · 입력 ${JSON.stringify(result.input)}`);
|
|
712
765
|
return result;
|
|
713
766
|
}, (r) => r.dryRun || r.state?.status === 'done' || r.state?.status === 'awaiting-approval');
|
package/src/cli/setup-cli.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { Command } from 'commander';
|
|
|
5
5
|
import { formatDoctorReport, registerDoctorCommand, runDoctor, type DoctorOptions, type DoctorReport } from './doctor-cli.js';
|
|
6
6
|
import { applyClaudePluginSetup, planClaudePluginSetup } from './claude-plugin-setup.js';
|
|
7
7
|
import { recommendedSetup } from './setup-recommend.js';
|
|
8
|
+
import { detectSkillCliAuth, type CliAuthStatus } from '../onboarding/cli-auth-status.js';
|
|
8
9
|
import { debug } from '../debug/log.js';
|
|
9
10
|
import { getUserConfig, saveUserConfig, type UserConfig } from '../user-config.js';
|
|
10
11
|
|
|
@@ -22,6 +23,7 @@ type SetupStep = {
|
|
|
22
23
|
export interface SetupCliDeps extends DoctorOptions {
|
|
23
24
|
runDoctor?: (options: DoctorOptions) => DoctorReport;
|
|
24
25
|
runDoctorFix?: (args: readonly string[]) => Promise<number>;
|
|
26
|
+
detectSkillCliAuth?: typeof detectSkillCliAuth;
|
|
25
27
|
readFile?: (path: string) => string;
|
|
26
28
|
exists?: (path: string) => boolean;
|
|
27
29
|
homeDir?: () => string;
|
|
@@ -142,10 +144,46 @@ export function formatSetupReport(doctor: DoctorReport, steps: SetupStep[], nonI
|
|
|
142
144
|
].join('\n');
|
|
143
145
|
}
|
|
144
146
|
|
|
147
|
+
const CLI_SKILLS = {
|
|
148
|
+
gh: 'github', gws: 'google-workspace', op: '1password', himalaya: 'himalaya',
|
|
149
|
+
} as const;
|
|
150
|
+
|
|
151
|
+
function formatCliSkillStatus(status: CliAuthStatus, enabled: boolean, reason?: string): string {
|
|
152
|
+
return `${status.cli}: found=${status.found ? 'yes' : 'no'} / enabled=${enabled ? 'yes' : 'no'} / ${enabled ? 'enabled' : `skipped (${reason ?? status.skippedReason ?? 'not authenticated'})`}`;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function reportCliSkills(deps: SetupCliDeps, apply: boolean): string[] {
|
|
156
|
+
const statuses = (deps.detectSkillCliAuth ?? detectSkillCliAuth)();
|
|
157
|
+
const config = (deps.getUserConfig ?? getUserConfig)();
|
|
158
|
+
const deny = new Set(config.skills.deny ?? []);
|
|
159
|
+
const allow = config.skills.allow ?? [];
|
|
160
|
+
let changed = false;
|
|
161
|
+
const lines = statuses.map((status) => {
|
|
162
|
+
const skill = CLI_SKILLS[status.cli];
|
|
163
|
+
const allowed = allow.length === 0 || allow.some((name) => name.toLowerCase() === skill);
|
|
164
|
+
if (apply) {
|
|
165
|
+
if (status.authenticated && allowed && deny.has(skill)) { deny.delete(skill); changed = true; }
|
|
166
|
+
if (!status.authenticated && !deny.has(skill)) { deny.add(skill); changed = true; }
|
|
167
|
+
}
|
|
168
|
+
const enabled = status.authenticated && allowed && !deny.has(skill);
|
|
169
|
+
return formatCliSkillStatus(status, enabled,
|
|
170
|
+
status.authenticated && !allowed ? 'excluded by skills.allow' :
|
|
171
|
+
status.authenticated && !apply && deny.has(skill) ? 'not enabled; run setup to apply' : undefined);
|
|
172
|
+
});
|
|
173
|
+
if (apply && changed) (deps.saveUserConfig ?? saveUserConfig)({
|
|
174
|
+
...config, skills: { ...config.skills, deny: [...deny] },
|
|
175
|
+
});
|
|
176
|
+
return lines;
|
|
177
|
+
}
|
|
178
|
+
|
|
145
179
|
export function registerSetupCommand(program: Command, deps: SetupCliDeps = {}): void {
|
|
146
180
|
const out = deps.out ?? { log: (value: string) => console.log(value), error: (value: string) => console.error(value) };
|
|
147
181
|
const setExitCode = deps.setExitCode ?? ((code: number) => { process.exitCode = code; });
|
|
148
182
|
const doctorRunner = deps.runDoctor ?? runDoctor;
|
|
183
|
+
const showCliSkills = (apply: boolean) => {
|
|
184
|
+
out.log('Setup: CLI skills (public GitHub repository reads remain available without login)');
|
|
185
|
+
for (const line of reportCliSkills(deps, apply)) out.log(line);
|
|
186
|
+
};
|
|
149
187
|
const isStdinTty = deps.isStdinTty ?? (() => process.stdin.isTTY === true);
|
|
150
188
|
const prompt = deps.prompt ?? (async (message: string) => {
|
|
151
189
|
const { createInterface } = await import('node:readline/promises');
|
|
@@ -161,6 +199,7 @@ export function registerSetupCommand(program: Command, deps: SetupCliDeps = {}):
|
|
|
161
199
|
const doctor = doctorRunner(deps);
|
|
162
200
|
if (opts.nonInteractive) {
|
|
163
201
|
out.log(formatSetupReport(doctor, setupSteps(deps), true));
|
|
202
|
+
showCliSkills(false);
|
|
164
203
|
for (const line of recommendedSetup((deps.getUserConfig ?? getUserConfig)())) out.log(line);
|
|
165
204
|
setExitCode(0);
|
|
166
205
|
return;
|
|
@@ -183,6 +222,7 @@ export function registerSetupCommand(program: Command, deps: SetupCliDeps = {}):
|
|
|
183
222
|
}
|
|
184
223
|
}
|
|
185
224
|
out.log(formatSetupReport(doctor, steps, false));
|
|
225
|
+
showCliSkills(false);
|
|
186
226
|
for (const line of recommendedSetup((deps.getUserConfig ?? getUserConfig)())) out.log(line);
|
|
187
227
|
const accepted = opts.yes || (isStdinTty() && /^(?:y|yes)?$/i.test((await prompt('추천대로 켤까요? [Y/n] '))?.trim() ?? 'n'));
|
|
188
228
|
if (accepted) {
|
|
@@ -197,7 +237,9 @@ export function registerSetupCommand(program: Command, deps: SetupCliDeps = {}):
|
|
|
197
237
|
await doctorProgram.parseAsync([...args], { from: 'user' });
|
|
198
238
|
return exitCode;
|
|
199
239
|
});
|
|
200
|
-
|
|
240
|
+
const fixCode = await runDoctorFix(['doctor', '--fix', '--yes']);
|
|
241
|
+
showCliSkills(true);
|
|
242
|
+
setExitCode(fixCode);
|
|
201
243
|
return;
|
|
202
244
|
}
|
|
203
245
|
setExitCode(0);
|
package/src/cli/skills-cli.ts
CHANGED
|
@@ -73,7 +73,23 @@ export function registerConnectCommand(program: Command): void {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
export function registerSkillsCommands(program: Command): void {
|
|
76
|
-
const skills = program.command('skills').description('Check and repair
|
|
76
|
+
const skills = program.command('skills').description('Check, install and repair skills');
|
|
77
|
+
skills.command('install <pack>')
|
|
78
|
+
.description('Install a gift skill pack from a code')
|
|
79
|
+
.option('--code <code>', 'Gift code')
|
|
80
|
+
.option('--email <address>', 'Email for gift delivery')
|
|
81
|
+
.option('--agree', 'Agree to email collection and retention')
|
|
82
|
+
.option('--endpoint <url>', 'Gift API origin (overrides skills.giftEndpoint)')
|
|
83
|
+
.option('--json', 'Print the install result as JSON')
|
|
84
|
+
.action(async (pack: string, opts: { code?: string; email?: string; agree?: boolean; endpoint?: string; json?: boolean }) => {
|
|
85
|
+
const { getUserConfig } = await import('../user-config.js');
|
|
86
|
+
const { installGiftPack } = await import('../skills/gift-install.js');
|
|
87
|
+
const result = await installGiftPack({ pack, code: opts.code, email: opts.email, agree: opts.agree,
|
|
88
|
+
endpoint: opts.endpoint ?? getUserConfig().skills.giftEndpoint });
|
|
89
|
+
if (opts.json) console.log(JSON.stringify(result));
|
|
90
|
+
else console.log(result.message);
|
|
91
|
+
if (!result.ok) process.exitCode = 1;
|
|
92
|
+
});
|
|
77
93
|
skills.command('sources')
|
|
78
94
|
.description('List every skill folder elanous reads, in order (preset · shared · connected · package)')
|
|
79
95
|
.option('--json', 'JSON output')
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
|
|
3
|
+
/** Render a Claude Code settings fragment; never touch the user's settings file. */
|
|
4
|
+
export function claudeHooksSettings(repoRoot: string): string {
|
|
5
|
+
const command = (file: string) => `bash '${resolve(repoRoot, 'scripts/context-hooks', file).replaceAll("'", "'\\''")}'`;
|
|
6
|
+
return JSON.stringify({ hooks: {
|
|
7
|
+
Stop: [{ hooks: [{ type: 'command', command: command('claude-stop.sh') }] }],
|
|
8
|
+
PostToolUse: [{ hooks: [{ type: 'command', command: command('post-tool-use.sh') }] }],
|
|
9
|
+
} }, null, 2);
|
|
10
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { contextNow, type ContextFact, type ContextNowAnswer, type ContextNowDeps } from './context-now.js';
|
|
2
|
+
|
|
3
|
+
export function readSlashContextNow(args: string[], deps?: ContextNowDeps): ContextNowAnswer {
|
|
4
|
+
return contextNow({ topic: args.join(' ').trim() }, deps);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function seatsNowLine(answer: ContextNowAnswer, now: number): string | null {
|
|
8
|
+
const seats = [ ['OP', 'COO'], ['MK', 'CMO'], ['TC', 'CTO'], ['UX', 'CXO'] ] as const;
|
|
9
|
+
const facts = answer.facts.filter(fact => fact.kind === 'seat');
|
|
10
|
+
const lines = seats.flatMap(([seat, label]) => {
|
|
11
|
+
const latest = facts.filter(fact => fact.seat === seat)
|
|
12
|
+
.sort((a, b) => b.at.localeCompare(a.at))[0];
|
|
13
|
+
if (!latest) return [];
|
|
14
|
+
const minutes = Math.max(0, Math.floor((now - Date.parse(latest.at)) / 60_000));
|
|
15
|
+
const age = minutes >= 24 * 60 ? '하루 넘음'
|
|
16
|
+
: minutes >= 60 ? `${Math.floor(minutes / 60)}시간 전`
|
|
17
|
+
: minutes > 0 ? `${minutes}분 전` : '방금';
|
|
18
|
+
const title = latest.title?.split(/\r?\n/, 1)[0]?.trim();
|
|
19
|
+
return [`${label} ${title ? title.slice(0, 20) : latest.status} · ${age}`];
|
|
20
|
+
});
|
|
21
|
+
return lines.length ? `지금 자리들: ${lines.join(' | ')}` : null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function factText(fact: ContextFact): string {
|
|
25
|
+
switch (fact.kind) {
|
|
26
|
+
case 'version': return fact.version;
|
|
27
|
+
case 'cell': return `${fact.id} ${fact.title} (${fact.status})`;
|
|
28
|
+
case 'decision': return `${fact.id} ${fact.title} (${fact.status})`;
|
|
29
|
+
case 'seat': return `${fact.seat} ${fact.id ?? ''} ${fact.title ?? ''} (${fact.status})`.trim();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function renderTelegramNow(answer: ContextNowAnswer): string {
|
|
34
|
+
const rows = [
|
|
35
|
+
['판', answer.facts.filter(f => f.kind === 'version')],
|
|
36
|
+
['칸', answer.facts.filter(f => f.kind === 'cell')],
|
|
37
|
+
['결정', answer.facts.filter(f => f.kind === 'decision')],
|
|
38
|
+
['자리', answer.facts.filter(f => f.kind === 'seat')],
|
|
39
|
+
] as const;
|
|
40
|
+
const lines = rows.map(([label, facts]) => `${label}: ${facts.length ? facts.map(f => `${factText(f)} — ${f.source}`).join(' · ') : '없음'}`);
|
|
41
|
+
lines.push(`최근: ${answer.events.length ? answer.events.map(e => `${e.summary} — ${e.source}`).join(' · ') : '없음'}${answer.guide.length ? ` · 안내 ${answer.guide.join(' · ')}` : ''}`);
|
|
42
|
+
return lines.map(line => line.replace(/\s+/g, ' ').trim()).join('\n');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function renderTuiNow(answer: ContextNowAnswer): string[] {
|
|
46
|
+
const rows = [
|
|
47
|
+
...answer.facts.map(f => [f.kind, factText(f), f.source]),
|
|
48
|
+
...answer.events.map(e => [e.kind, e.summary, e.source]),
|
|
49
|
+
...answer.guide.map(guide => ['안내', guide, '']),
|
|
50
|
+
];
|
|
51
|
+
return [
|
|
52
|
+
`지금${answer.topic ? ` · ${answer.topic}` : ''} (${answer.at})`,
|
|
53
|
+
'| 종류 | 사실 | 출처 |',
|
|
54
|
+
'| --- | --- | --- |',
|
|
55
|
+
...rows.map(row => `| ${row.map(cell => cell.replaceAll('|', '\\|').replaceAll(/\r?\n/g, ' ')).join(' | ')} |`),
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function telegramNowSlash(args: string[], deps?: ContextNowDeps): string {
|
|
60
|
+
return renderTelegramNow(readSlashContextNow(args, deps));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function tuiNowSlash(args: string[], deps?: ContextNowDeps): string[] {
|
|
64
|
+
return renderTuiNow(readSlashContextNow(args, deps));
|
|
65
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { debug, redactSecretText } from '../debug/log.js';
|
|
3
|
+
import { DecisionLedger, type DecisionEntry } from '../decisions/decision-ledger.js';
|
|
4
|
+
import { listChecklist, devVersion, type Checklist } from '../release-loop/checklist.js';
|
|
5
|
+
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
6
|
+
import { seatDay, seatLedgerPath, type SeatEntry } from '../seat-loop/seat-loop.js';
|
|
7
|
+
import { listCoordEvents, type CoordEvent } from './coord-events.js';
|
|
8
|
+
|
|
9
|
+
export type ContextFact =
|
|
10
|
+
| { kind: 'version'; version: string; source: string }
|
|
11
|
+
| { kind: 'cell'; version: string; id: string; title: string; status: string; owner: string | null; source: string }
|
|
12
|
+
| { kind: 'decision'; id: string; title: string; status: string; dueAt: string | null; source: string }
|
|
13
|
+
| { kind: 'seat'; seat: string; at: string; status: string; id: string | null; title: string | null; source: string };
|
|
14
|
+
export type ContextEvent = { at: string; kind: string; summary: string; source: string };
|
|
15
|
+
export type ContextNowAnswer = { at: string; topic: string | null; facts: ContextFact[]; events: ContextEvent[]; guide: string[] };
|
|
16
|
+
|
|
17
|
+
export interface ContextNowDeps {
|
|
18
|
+
now?: () => Date;
|
|
19
|
+
version?: () => string;
|
|
20
|
+
checklist?: (version: string) => Checklist;
|
|
21
|
+
decisions?: () => DecisionEntry[];
|
|
22
|
+
seatEntries?: (now: Date) => Array<{ entry: SeatEntry; source: string }>;
|
|
23
|
+
events?: (since: string) => CoordEvent[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function todaySeatEntries(now: Date): Array<{ entry: SeatEntry; source: string }> {
|
|
27
|
+
const root = effectiveInstanceRoot();
|
|
28
|
+
const day = seatDay(now);
|
|
29
|
+
return ['OP', 'TC', 'MK', 'UX'].flatMap(seat => {
|
|
30
|
+
const path = seatLedgerPath(seat, root, now);
|
|
31
|
+
if (!existsSync(path)) return [];
|
|
32
|
+
return readFileSync(path, 'utf8').split('\n').flatMap((line, index) => line.trim() ? [{
|
|
33
|
+
entry: JSON.parse(line) as SeatEntry,
|
|
34
|
+
source: `elanous://seat-loop/${seat}/${day}#${index + 1}`,
|
|
35
|
+
}] : []);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Read a bounded, source-labelled view of current ledgers, never a transcript or decision body. */
|
|
40
|
+
export function contextNow(options: { topic?: string; limit?: number } = {}, deps: ContextNowDeps = {}): ContextNowAnswer {
|
|
41
|
+
const now = (deps.now ?? (() => new Date()))();
|
|
42
|
+
const at = `${now.toISOString().slice(0, 16)}:00.000Z`;
|
|
43
|
+
const topic = options.topic?.trim() || null;
|
|
44
|
+
const limit = typeof options.limit === 'number' && Number.isFinite(options.limit)
|
|
45
|
+
? Math.max(1, Math.min(100, Math.floor(options.limit))) : 20;
|
|
46
|
+
const version = (deps.version ?? devVersion)().replace(/-.*$/, '');
|
|
47
|
+
const next = version.replace(/^(\d+)\.(\d+)\.(\d+)$/, (_, major: string, minor: string, patch: string) => `${major}.${minor}.${Number(patch) + 1}`);
|
|
48
|
+
const facts: ContextFact[] = [];
|
|
49
|
+
for (const v of [...new Set([version, next])]) {
|
|
50
|
+
const checklist = (deps.checklist ?? listChecklist)(v);
|
|
51
|
+
if (v === version) facts.push({ kind: 'version', version: v, source: `elanous://release/${v}/checklist` });
|
|
52
|
+
for (const item of checklist.items) {
|
|
53
|
+
if (item.status === 'done') continue;
|
|
54
|
+
facts.push({ kind: 'cell', version: v, id: item.id, title: redactSecretText(item.title.split(/\r?\n/, 1)[0] ?? '').slice(0, 120),
|
|
55
|
+
status: item.status, owner: item.owner ?? null, source: `elanous://release/${v}/checklist#${encodeURIComponent(item.id)}` });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
for (const item of (deps.decisions ?? (() => new DecisionLedger().list({ status: 'open' })))()) {
|
|
59
|
+
if (item.status !== 'open') continue;
|
|
60
|
+
facts.push({ kind: 'decision', id: item.id, title: redactSecretText(item.title.split(/\r?\n/, 1)[0] ?? '').slice(0, 120),
|
|
61
|
+
status: item.status, dueAt: item.dueAt ?? null, source: `elanous://decisions/${encodeURIComponent(item.id)}` });
|
|
62
|
+
}
|
|
63
|
+
for (const { entry, source } of (deps.seatEntries ?? todaySeatEntries)(now)) {
|
|
64
|
+
facts.push({ kind: 'seat', seat: entry.seat, at: entry.at, status: entry.status,
|
|
65
|
+
id: entry.item?.id ?? null, title: entry.item?.source === 'checklist'
|
|
66
|
+
? redactSecretText(entry.item.title.split(/\r?\n/, 1)[0] ?? '').slice(0, 120) : null, source });
|
|
67
|
+
}
|
|
68
|
+
const rawEvents = (deps.events ?? (since => listCoordEvents({ since })))(new Date(now.getTime() - 7 * 86_400_000).toISOString());
|
|
69
|
+
const chronologicalEvents = rawEvents.slice().sort((a, b) => a.at.localeCompare(b.at));
|
|
70
|
+
const matches = (text: string) => !topic || text.toLocaleLowerCase().includes(topic.toLocaleLowerCase());
|
|
71
|
+
const selectedFacts = facts.filter(f => !topic || (f.kind === 'cell' && matches(`${f.id} ${f.title}`))
|
|
72
|
+
|| (f.kind === 'seat' && matches(`${f.id ?? ''} ${f.title ?? ''}`)));
|
|
73
|
+
const groups = (['version', 'cell', 'decision', 'seat'] as const).map(kind => selectedFacts.filter(f => f.kind === kind));
|
|
74
|
+
groups[3]!.sort((a, b) => (a.kind === 'seat' && b.kind === 'seat' ? b.at.localeCompare(a.at) : 0));
|
|
75
|
+
const nonEmpty = groups.filter(group => group.length > 0);
|
|
76
|
+
const perKind = Math.floor(limit / nonEmpty.length);
|
|
77
|
+
const chosen = groups.map(group => group.splice(0, perKind));
|
|
78
|
+
let remaining = limit - chosen.reduce((total, group) => total + group.length, 0);
|
|
79
|
+
for (const index of [2, 3, 0, 1]) {
|
|
80
|
+
if (remaining <= 0) break;
|
|
81
|
+
if (chosen[index]!.length === 0 && groups[index]!.length > 0) {
|
|
82
|
+
chosen[index]!.push(...groups[index]!.splice(0, 1));
|
|
83
|
+
remaining--;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
for (const index of [1, 2, 3, 0]) {
|
|
87
|
+
if (remaining <= 0) break;
|
|
88
|
+
const extra = groups[index]!.splice(0, remaining);
|
|
89
|
+
chosen[index]!.push(...extra);
|
|
90
|
+
remaining -= extra.length;
|
|
91
|
+
}
|
|
92
|
+
const boundedFacts = chosen.flat();
|
|
93
|
+
const summaries = chronologicalEvents.map(event => ({
|
|
94
|
+
at: event.at, kind: event.kind, summary: redactSecretText(event.summary.split(/\r?\n/, 1)[0] ?? '').slice(0, 120),
|
|
95
|
+
source: event.refs.source ?? event.refs.url ?? `elanous://context/event/${encodeURIComponent(event.id)}`,
|
|
96
|
+
}));
|
|
97
|
+
const selectedEvents = summaries.filter(event => matches(event.summary)).reverse().slice(0, limit);
|
|
98
|
+
const guide = summaries.filter(event => event.kind === 'guide-changed' || event.kind === 'guidance-changed' || event.summary.startsWith('📌안내'))
|
|
99
|
+
.filter(event => matches(event.summary)).reverse().slice(0, limit)
|
|
100
|
+
.map(event => `📌 ${event.summary} — ${event.source}`);
|
|
101
|
+
const answer = { at, topic, facts: boundedFacts, events: selectedEvents, guide };
|
|
102
|
+
debug.log('context.now', 'answer', { topic, facts: answer.facts, events: answer.events });
|
|
103
|
+
return answer;
|
|
104
|
+
}
|