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
|
@@ -1,27 +1,13 @@
|
|
|
1
|
-
// NEXUS · personas REST handlers
|
|
2
|
-
//
|
|
3
|
-
// Endpoints
|
|
4
|
-
// GET /v1/personas — list all loaded personas
|
|
5
|
-
// GET /v1/personas/:personaId — single persona profile
|
|
6
|
-
//
|
|
7
|
-
// Architecture: read-only thin wrapper over the global PersonaRegistry
|
|
8
|
-
// (`src/persona/global-registry.ts`). Disk yaml is the source of truth;
|
|
9
|
-
// editing requires text editor + `elanous persona reload` (or fs.watch
|
|
10
|
-
// auto-reload). PWA Showroom consumes this for the per-panel persona
|
|
11
|
-
// picker (§6.4 Q2 = REST read-only).
|
|
12
|
-
//
|
|
13
|
-
// PLAN: 내부 문서 `PLAN-cv-3-showroom-mvp-2026-05-07` §6.4
|
|
14
|
-
// Cross-ref: src/persona/global-registry.ts (singleton accessor)
|
|
15
|
-
// src/persona/types.ts (PersonaProfile shape)
|
|
16
|
-
|
|
17
|
-
import { homedir } from 'node:os';
|
|
18
|
-
import { join } from 'node:path';
|
|
1
|
+
// NEXUS · personas REST handlers. Presets clone into the state persona store;
|
|
2
|
+
// writes reload the global registry so subsequent reads see the saved profile.
|
|
19
3
|
|
|
20
4
|
import {
|
|
21
5
|
awaitGlobalPersonaLoad,
|
|
22
6
|
getGlobalPersonaRegistry,
|
|
23
7
|
reloadGlobalPersonaRegistry,
|
|
8
|
+
resolveStatePersonaDir,
|
|
24
9
|
} from '../../persona/global-registry.js';
|
|
10
|
+
import { clonePreset, editPersona, loadPresets } from '../../persona/presets.js';
|
|
25
11
|
import type { PersonaRegistryEvent } from '../../persona/registry.js';
|
|
26
12
|
import type { PersonaProfile } from '../../persona/types.js';
|
|
27
13
|
import {
|
|
@@ -193,22 +179,41 @@ export function handlePersonasEvents(
|
|
|
193
179
|
});
|
|
194
180
|
}
|
|
195
181
|
|
|
196
|
-
/**
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (env && env.length > 0) return env;
|
|
201
|
-
return join(homedir(), '.elanous', 'personas');
|
|
182
|
+
/** GET /v1/persona-presets — shipped preset catalog in index order. */
|
|
183
|
+
export function handlePersonaPresets(req: Request, opts: PersonaRouteOpts = {}): Response {
|
|
184
|
+
if (opts.checkAuth && !opts.checkAuth(req)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
185
|
+
return jsonResponse({ presets: loadPresets() }, 200);
|
|
202
186
|
}
|
|
203
187
|
|
|
204
|
-
/**
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
188
|
+
/** POST /v1/personas — clone a shipped preset into the user's persona store. */
|
|
189
|
+
export async function handlePersonaCreate(req: Request, opts: PersonaRouteOpts = {}): Promise<Response> {
|
|
190
|
+
if (opts.checkAuth && !opts.checkAuth(req)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
191
|
+
let body: unknown;
|
|
192
|
+
try { body = await req.json(); }
|
|
193
|
+
catch { return jsonResponse({ error: 'invalid-json' }, 400); }
|
|
194
|
+
if (!body || typeof body !== 'object' || Array.isArray(body)) return jsonResponse({ error: 'invalid-body' }, 400);
|
|
195
|
+
const { preset, name } = body as Record<string, unknown>;
|
|
196
|
+
if (typeof preset !== 'string' || !preset.trim() || typeof name !== 'string' || !name.trim()) {
|
|
197
|
+
return jsonResponse({ error: 'preset-and-name-required' }, 400);
|
|
198
|
+
}
|
|
199
|
+
await awaitGlobalPersonaLoad();
|
|
200
|
+
if (!loadPresets().some((p) => p.personaId === preset)) return notFound(`preset ${preset} not found`);
|
|
201
|
+
try {
|
|
202
|
+
const created = clonePreset(preset, name.trim(), { dir: resolveStatePersonaDir() });
|
|
203
|
+
await reloadGlobalPersonaRegistry();
|
|
204
|
+
const persona = getGlobalPersonaRegistry().get(created.personaId);
|
|
205
|
+
if (!persona) return notFound(`persona ${created.personaId} not found after reload`);
|
|
206
|
+
return jsonResponse({ persona: toWire(persona) }, 201);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
if (error instanceof Error && error.message.startsWith('persona name already exists:')) {
|
|
209
|
+
return jsonResponse({ error: 'persona-name-conflict' }, 409);
|
|
210
|
+
}
|
|
211
|
+
return jsonResponse({ error: 'create-failed' }, 500);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** PATCH /v1/personas/:personaId — description-only edits retain the
|
|
216
|
+
* existing surgical YAML behavior; multi-field edits use the persona store. */
|
|
212
217
|
export async function handlePersonaPatch(
|
|
213
218
|
req: Request,
|
|
214
219
|
personaId: string,
|
|
@@ -217,17 +222,23 @@ export async function handlePersonaPatch(
|
|
|
217
222
|
if (opts.checkAuth && !opts.checkAuth(req)) {
|
|
218
223
|
return jsonResponse({ error: 'unauthorized' }, 401);
|
|
219
224
|
}
|
|
220
|
-
let
|
|
221
|
-
try {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
return jsonResponse({ error: 'invalid-
|
|
225
|
+
let parsed: unknown;
|
|
226
|
+
try { parsed = await req.json(); }
|
|
227
|
+
catch { return jsonResponse({ error: 'invalid-json' }, 400); }
|
|
228
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
229
|
+
return jsonResponse({ error: 'invalid-body' }, 400);
|
|
225
230
|
}
|
|
226
|
-
|
|
227
|
-
|
|
231
|
+
const body = parsed as Record<string, unknown>;
|
|
232
|
+
const fields = Object.keys(body);
|
|
233
|
+
if (!fields.length) return jsonResponse({ error: 'description-required' }, 400);
|
|
234
|
+
if (fields.some((field) => !['displayName', 'description', 'systemPrompt'].includes(field))) {
|
|
235
|
+
return jsonResponse({ error: 'invalid-persona-field' }, 400);
|
|
228
236
|
}
|
|
229
|
-
if (
|
|
230
|
-
|
|
237
|
+
if (fields.some((field) => typeof body[field] !== 'string')
|
|
238
|
+
|| (body.displayName !== undefined && !(body.displayName as string).trim())) {
|
|
239
|
+
return jsonResponse({ error: 'invalid-persona-field' }, 400);
|
|
240
|
+
}
|
|
241
|
+
if (typeof body.description === 'string' && body.description.length > MAX_PERSONA_DESCRIPTION_LENGTH * 4) {
|
|
231
242
|
return jsonResponse({ error: 'description-too-long' }, 400);
|
|
232
243
|
}
|
|
233
244
|
|
|
@@ -237,14 +248,37 @@ export async function handlePersonaPatch(
|
|
|
237
248
|
return notFound(`persona ${personaId} not found`);
|
|
238
249
|
}
|
|
239
250
|
|
|
240
|
-
const dir =
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
251
|
+
const dir = resolveStatePersonaDir();
|
|
252
|
+
if (fields.length === 1 && typeof body.description === 'string') {
|
|
253
|
+
const result = updatePersonaDescription(dir, personaId, body.description);
|
|
254
|
+
if (!result.ok) {
|
|
255
|
+
const status = result.reason === 'file-not-found' ? 404 : 400;
|
|
256
|
+
return jsonResponse({ error: 'patch-failed', reason: result.reason }, status);
|
|
257
|
+
}
|
|
258
|
+
} else {
|
|
259
|
+
const edits: Record<string, unknown> = {};
|
|
260
|
+
for (const field of fields) edits[field] = body[field];
|
|
261
|
+
if (typeof edits.description === 'string') {
|
|
262
|
+
const description = edits.description.trim();
|
|
263
|
+
edits.description = description;
|
|
264
|
+
if (description.length > MAX_PERSONA_DESCRIPTION_LENGTH) {
|
|
265
|
+
return jsonResponse({ error: 'description-too-long' }, 400);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
try {
|
|
269
|
+
editPersona(personaId, edits, { dir });
|
|
270
|
+
} catch (error) {
|
|
271
|
+
if (error instanceof Error && error.message.startsWith('persona not found:')) {
|
|
272
|
+
return notFound(`persona ${personaId} not found in state store`);
|
|
273
|
+
}
|
|
274
|
+
if (error instanceof Error && error.message.startsWith('persona name already exists:')) {
|
|
275
|
+
return jsonResponse({ error: 'persona-name-conflict' }, 409);
|
|
276
|
+
}
|
|
277
|
+
return jsonResponse({ error: 'patch-failed', reason: error instanceof Error ? error.message : 'invalid-persona' }, 400);
|
|
278
|
+
}
|
|
245
279
|
}
|
|
246
280
|
|
|
247
|
-
// Reload so the in-memory registry reflects the
|
|
281
|
+
// Reload so the in-memory registry reflects the saved fields on the
|
|
248
282
|
// next GET. fs.watch would auto-reload but is async + race-y vs the
|
|
249
283
|
// immediate echo below.
|
|
250
284
|
await reloadGlobalPersonaRegistry();
|
|
@@ -255,7 +289,7 @@ export async function handlePersonaPatch(
|
|
|
255
289
|
return jsonResponse({ persona: toWire(reloaded) }, 200);
|
|
256
290
|
}
|
|
257
291
|
|
|
258
|
-
/** Combined dispatcher — `/v1/personas[/:id]` + `/v1/personas/events`.
|
|
292
|
+
/** Combined dispatcher — `/v1/persona-presets` + `/v1/personas[/:id]` + `/v1/personas/events`.
|
|
259
293
|
* Returns null when the pathname doesn't match so the caller chains. */
|
|
260
294
|
export async function dispatchPersonaRoute(
|
|
261
295
|
req: Request,
|
|
@@ -263,11 +297,14 @@ export async function dispatchPersonaRoute(
|
|
|
263
297
|
opts: PersonaRouteOpts = {},
|
|
264
298
|
): Promise<Response | null> {
|
|
265
299
|
const method = req.method.toUpperCase();
|
|
300
|
+
if (pathname === '/v1/persona-presets') {
|
|
301
|
+
if (method !== 'GET') return jsonResponse({ error: 'method not allowed' }, 405);
|
|
302
|
+
return handlePersonaPresets(req, opts);
|
|
303
|
+
}
|
|
266
304
|
if (pathname === '/v1/personas') {
|
|
267
|
-
if (method
|
|
268
|
-
|
|
269
|
-
}
|
|
270
|
-
return handlePersonasList(req, opts);
|
|
305
|
+
if (method === 'GET') return handlePersonasList(req, opts);
|
|
306
|
+
if (method === 'POST') return handlePersonaCreate(req, opts);
|
|
307
|
+
return jsonResponse({ error: 'method not allowed' }, 405);
|
|
271
308
|
}
|
|
272
309
|
// SSE — must come BEFORE the single-persona regex so that the
|
|
273
310
|
// literal "events" segment isn't misread as a personaId.
|
|
@@ -279,8 +316,13 @@ export async function dispatchPersonaRoute(
|
|
|
279
316
|
}
|
|
280
317
|
const match = pathname.match(/^\/v1\/personas\/([^/]+)$/);
|
|
281
318
|
if (!match) return null;
|
|
282
|
-
|
|
319
|
+
let personaId: string;
|
|
320
|
+
try { personaId = decodeURIComponent(match[1]!); }
|
|
321
|
+
catch { return jsonResponse({ error: 'invalid-persona-id' }, 400); }
|
|
283
322
|
if (method === 'PATCH') {
|
|
323
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(personaId)) {
|
|
324
|
+
return jsonResponse({ error: 'invalid-persona-id' }, 400);
|
|
325
|
+
}
|
|
284
326
|
return handlePersonaPatch(req, personaId, opts);
|
|
285
327
|
}
|
|
286
328
|
if (method !== 'GET') {
|
|
@@ -6,12 +6,14 @@ import { resolveAttachmentPath } from '../../boot/attachment-store.js';
|
|
|
6
6
|
import { runGh } from '../../decisions/decision-cards.js';
|
|
7
7
|
import { openMsgStore, canonicalSeatId } from '../../msg/msg-store.js';
|
|
8
8
|
import { dispatchCeoTask, type CeoCommandDeps } from '../../seat-dispatch/ceo-commands.js';
|
|
9
|
+
import { acknowledgeSeatAnswers, askSeat, deliverSeatAnswers, parseSeatAsk, type SeatAskDeps } from '../../seat-dispatch/seat-ask.js';
|
|
9
10
|
import { getUserConfig } from '../../user-config.js';
|
|
10
11
|
import { effectiveInstanceRoot } from '../../instance/resolve.js';
|
|
11
12
|
import { submitIntakeWork } from '../../intake-plane/submit-intake-work.js';
|
|
12
13
|
import { parseSeatAddress, resolveSeat } from '../../seat-address/seat-address.js';
|
|
13
14
|
import trackData from '../../../scripts/coord-tracks.json';
|
|
14
15
|
import { jsonResponse } from './json-response.js';
|
|
16
|
+
import { publishInsideEvent } from './inside-events.js';
|
|
15
17
|
|
|
16
18
|
export const SEAT_REQUESTS_PATH = '/v1/seat-requests';
|
|
17
19
|
|
|
@@ -50,6 +52,7 @@ export interface SeatRequestsDeps {
|
|
|
50
52
|
resolveAttachment?: typeof resolveAttachmentPath;
|
|
51
53
|
dispatch?: typeof dispatchCeoTask;
|
|
52
54
|
ceoDeps?: () => CeoCommandDeps;
|
|
55
|
+
askDeps?: SeatAskDeps;
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
const seats = trackData.tracks.filter((entry): entry is typeof entry & { title: string } => 'title' in entry)
|
|
@@ -189,6 +192,18 @@ export async function handleSeatRequests(req: Request, deps: SeatRequestsDeps =
|
|
|
189
192
|
const path = file((deps.root ?? effectiveInstanceRoot)());
|
|
190
193
|
if (req.method === 'GET') {
|
|
191
194
|
const params = new URL(req.url).searchParams;
|
|
195
|
+
if (params.get('answers') === '1') {
|
|
196
|
+
const clientId = req.headers.get('x-seat-ask-client');
|
|
197
|
+
if (!clientId || !/^[a-f0-9-]{36}$/i.test(clientId)) return jsonResponse({ error: 'bad_request' }, 400);
|
|
198
|
+
const base = deps.askDeps;
|
|
199
|
+
const messages: Array<{ id: string; text: string; status: 'answered' | 'expired' }> = [];
|
|
200
|
+
await deliverSeatAnswers({ ...base, channel: 'pwa', clientId, send: async (origin, text) => {
|
|
201
|
+
if (origin.channel !== 'pwa' || origin.clientId !== clientId) return;
|
|
202
|
+
const match = /\(([^)]+)\)/.exec(text);
|
|
203
|
+
if (match) messages.push({ id: match[1]!, text, status: text.startsWith('CTO 답변') ? 'answered' : 'expired' });
|
|
204
|
+
} });
|
|
205
|
+
return jsonResponse({ items: messages });
|
|
206
|
+
}
|
|
192
207
|
const requestedSeat = params.get('seat');
|
|
193
208
|
const seat = requestedSeat ? requestSeat(requestedSeat) : undefined;
|
|
194
209
|
if (requestedSeat && !seat) return unknownSeat();
|
|
@@ -204,6 +219,19 @@ export async function handleSeatRequests(req: Request, deps: SeatRequestsDeps =
|
|
|
204
219
|
}
|
|
205
220
|
if (req.method !== 'POST') return jsonResponse({ error: 'method-not-allowed' }, 405);
|
|
206
221
|
|
|
222
|
+
if (new URL(req.url).searchParams.get('answers') === 'ack') {
|
|
223
|
+
const clientId = req.headers.get('x-seat-ask-client');
|
|
224
|
+
if (!clientId || !/^[a-f0-9-]{36}$/i.test(clientId)) return jsonResponse({ error: 'bad_request' }, 400);
|
|
225
|
+
let body: unknown;
|
|
226
|
+
try { body = await req.json(); } catch { return jsonResponse({ error: 'bad_request' }, 400); }
|
|
227
|
+
const ids = (body as { ids?: unknown } | null)?.ids;
|
|
228
|
+
if (!Array.isArray(ids) || ids.length > 100 || ids.some((id) => typeof id !== 'string' || !/^[a-f0-9-]{36}$/i.test(id))) {
|
|
229
|
+
return jsonResponse({ error: 'bad_request' }, 400);
|
|
230
|
+
}
|
|
231
|
+
acknowledgeSeatAnswers(clientId, ids as string[], deps.askDeps?.open);
|
|
232
|
+
return jsonResponse({ ok: true });
|
|
233
|
+
}
|
|
234
|
+
|
|
207
235
|
let body: unknown;
|
|
208
236
|
try { body = await req.json(); }
|
|
209
237
|
catch { return jsonResponse({ error: 'bad_request' }, 400); }
|
|
@@ -219,10 +247,22 @@ export async function handleSeatRequests(req: Request, deps: SeatRequestsDeps =
|
|
|
219
247
|
const prefix = parsed ? `@${parsed.seats.join(',')}` : '';
|
|
220
248
|
const firstAddress = parsed && input.text.startsWith(prefix)
|
|
221
249
|
&& (input.text.length === prefix.length || /[ \t\r\n]/.test(input.text[prefix.length]!)) ? parsed : null;
|
|
222
|
-
const address = input.seat ?? (firstAddress?.seats.length === 1 ? firstAddress.seats[0] : undefined)
|
|
250
|
+
const address = input.seat ?? (firstAddress?.seats.length === 1 ? firstAddress.seats[0] : undefined)
|
|
251
|
+
?? (parseSeatAsk(input.text) ? 'TC' : undefined);
|
|
223
252
|
const seat = address ? requestSeat(address) : undefined;
|
|
224
253
|
if (!seat) return unknownSeat();
|
|
225
|
-
const text = input.seat === undefined ? firstAddress
|
|
254
|
+
const text = input.seat === undefined ? (firstAddress?.body ?? input.text).trim() : input.text.trim();
|
|
255
|
+
if (canonicalSeatIdSafe(seat.id) === 'TC' && parseSeatAsk(text)) {
|
|
256
|
+
if (input.attachments !== undefined) return jsonResponse({ error: 'attachments-unsupported' }, 400);
|
|
257
|
+
const clientId = req.headers.get('x-seat-ask-client');
|
|
258
|
+
if (!clientId || !/^[a-f0-9-]{36}$/i.test(clientId)) return jsonResponse({ error: 'bad_request' }, 400);
|
|
259
|
+
let ask: string;
|
|
260
|
+
try {
|
|
261
|
+
ask = await askSeat(text, { channel: 'pwa', clientId }, (deps.ceoDeps ?? defaultCeoDeps)(),
|
|
262
|
+
deps.askDeps ?? { channel: 'pwa', send: async () => { throw new Error('PWA seat ask requires polling'); } });
|
|
263
|
+
} catch { return unavailable(); }
|
|
264
|
+
return jsonResponse({ reply: ask }, 202);
|
|
265
|
+
}
|
|
226
266
|
if (!text) {
|
|
227
267
|
debug.log('seat-address.pwa', 'rejected', { reason: 'empty-text', seat: seat.id });
|
|
228
268
|
return jsonResponse({ error: 'bad_request' }, 400);
|
|
@@ -304,6 +344,7 @@ export async function handleSeatRequests(req: Request, deps: SeatRequestsDeps =
|
|
|
304
344
|
};
|
|
305
345
|
try { persistOutcome(path, item, deps.append ?? append); }
|
|
306
346
|
catch { return unavailable(); }
|
|
347
|
+
publishInsideEvent({ kind: 'seat', seat: item.seat, receiptId: item.receiptId, status: item.status, ts: item.queuedAt });
|
|
307
348
|
return receipt(item);
|
|
308
349
|
}
|
|
309
350
|
let result: Awaited<ReturnType<typeof submitIntakeWork>>;
|
|
@@ -325,6 +366,7 @@ export async function handleSeatRequests(req: Request, deps: SeatRequestsDeps =
|
|
|
325
366
|
try { persistOutcome(path, item, deps.append ?? append); }
|
|
326
367
|
catch { return unavailable(); }
|
|
327
368
|
debug.log('seat-address.pwa', 'enqueued', { seat: seat.id, receiptId: item.receiptId });
|
|
369
|
+
publishInsideEvent({ kind: 'seat', seat: item.seat, receiptId: item.receiptId, status: item.status, ts: item.queuedAt });
|
|
328
370
|
return receipt(item);
|
|
329
371
|
})();
|
|
330
372
|
inFlight.set(lock, { payload, task });
|
|
@@ -18,11 +18,9 @@ import {
|
|
|
18
18
|
isHarnessSessionOrigin,
|
|
19
19
|
type SessionMeta,
|
|
20
20
|
} from '../../session/index.js';
|
|
21
|
-
import { existsSync, mkdirSync, readFileSync, renameSync, rmdirSync, statSync, writeFileSync } from 'node:fs';
|
|
22
|
-
import { join } from 'node:path';
|
|
23
|
-
import { randomUUID } from 'node:crypto';
|
|
24
21
|
import { getProject } from '../../project/project-store.js';
|
|
25
|
-
import { sessionRoot } from '../../session/index.js';
|
|
22
|
+
import { sessionRoot, updateSessionMeta } from '../../session/index.js';
|
|
23
|
+
import { debug } from '../../debug/log.js';
|
|
26
24
|
import { checkAuth, type MetaApiOpts } from './meta-api.js';
|
|
27
25
|
import { jsonResponse } from './http-server.js';
|
|
28
26
|
|
|
@@ -181,43 +179,24 @@ export async function handleSessionsStorePatch(req: Request, id: string, opts: M
|
|
|
181
179
|
return jsonResponse({ ok: false, error: 'invalid_project_id' }, 400);
|
|
182
180
|
}
|
|
183
181
|
const projectId = (body as { projectId: unknown }).projectId;
|
|
184
|
-
if (projectId !== null &&
|
|
182
|
+
if (projectId !== null && typeof projectId !== 'string') {
|
|
185
183
|
return jsonResponse({ ok: false, error: 'invalid_project_id' }, 400);
|
|
186
184
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const deadline = Date.now() + 10_000;
|
|
191
|
-
for (;;) {
|
|
192
|
-
try { mkdirSync(lock); break; }
|
|
193
|
-
catch {
|
|
194
|
-
if (!existsSync(lock)) continue;
|
|
195
|
-
try {
|
|
196
|
-
if (Date.now() - statSync(lock).mtimeMs > 30_000) { rmdirSync(lock); continue; }
|
|
197
|
-
} catch { continue; }
|
|
198
|
-
if (Date.now() >= deadline) throw new Error(`timed out acquiring lock ${lock}`);
|
|
199
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
try {
|
|
203
|
-
const path = join(root, 'index.json');
|
|
204
|
-
const entries = JSON.parse(readFileSync(path, 'utf8')) as SessionMeta[];
|
|
205
|
-
const pos = entries.findIndex((meta) => meta.id === id);
|
|
206
|
-
if (pos < 0) return jsonResponse({ ok: false, error: 'not_found' }, 404);
|
|
207
|
-
const meta = { ...entries[pos] };
|
|
208
|
-
if (projectId === null) delete meta.projectId;
|
|
209
|
-
else meta.projectId = projectId;
|
|
210
|
-
entries[pos] = meta;
|
|
211
|
-
const temp = `${path}.${process.pid}.${randomUUID().slice(0, 8)}.tmp`;
|
|
212
|
-
writeFileSync(temp, JSON.stringify(entries, null, 2) + '\n', 'utf8');
|
|
213
|
-
renameSync(temp, path);
|
|
214
|
-
return jsonResponse({ ok: true, meta }, 200);
|
|
215
|
-
} catch (error) {
|
|
216
|
-
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return jsonResponse({ ok: false, error: 'not_found' }, 404);
|
|
217
|
-
throw error;
|
|
218
|
-
} finally {
|
|
219
|
-
rmdirSync(lock);
|
|
185
|
+
// 모양은 맞는데 없는 프로젝트 = 찾을 수 없음(404) — 요청 형식 오류(400)와 가른다(IA1b).
|
|
186
|
+
if (projectId !== null && !getProject(projectId)) {
|
|
187
|
+
return jsonResponse({ ok: false, error: 'project-not-found' }, 404);
|
|
220
188
|
}
|
|
189
|
+
|
|
190
|
+
let previous: string | null = null;
|
|
191
|
+
// 잠금 안에서 최신 목록 위에 고친다 — 동시 appendMessage 가 이 projectId 를 덮지 않는다.
|
|
192
|
+
const meta = updateSessionMeta(id, (m) => {
|
|
193
|
+
previous = m.projectId ?? null;
|
|
194
|
+
if (projectId === null) delete m.projectId;
|
|
195
|
+
else m.projectId = projectId;
|
|
196
|
+
}, sessionRoot());
|
|
197
|
+
if (!meta) return jsonResponse({ ok: false, error: 'not_found' }, 404);
|
|
198
|
+
debug.log('project', 'assign', { sessionId: id, projectId, previous });
|
|
199
|
+
return jsonResponse({ ok: true, meta }, 200);
|
|
221
200
|
}
|
|
222
201
|
|
|
223
202
|
/** DELETE /v1/sessions/store/:id — on-disk 세션 삭제(index.json + <id>.jsonl 제거).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { debug } from '../../debug/log.js';
|
|
4
|
+
|
|
5
|
+
export interface SubSeatCharter { id: string; seat: string; sub: string; title: string }
|
|
6
|
+
|
|
7
|
+
export function listSubSeatCharters(root = join(import.meta.dir, '..', '..', '..', 'docs', 'roles'), onUnreadable?: () => void): SubSeatCharter[] {
|
|
8
|
+
try {
|
|
9
|
+
readdirSync(root);
|
|
10
|
+
const charters: SubSeatCharter[] = [];
|
|
11
|
+
for (const seat of ['OP', 'MK', 'TC', 'UX']) {
|
|
12
|
+
let entries;
|
|
13
|
+
try { entries = readdirSync(join(root, seat), { withFileTypes: true }); }
|
|
14
|
+
catch (error) {
|
|
15
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') continue;
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
if (!entry.isFile() || !/^[a-z][a-z0-9-]{0,31}\.md$/.test(entry.name)) continue;
|
|
20
|
+
const sub = entry.name.slice(0, -3);
|
|
21
|
+
const id = `${seat}/${sub}`;
|
|
22
|
+
const content = readFileSync(join(root, seat, entry.name), 'utf8');
|
|
23
|
+
const heading = content.split(/\r?\n/).find((line) => line.startsWith('# '));
|
|
24
|
+
const title = heading?.slice(2).startsWith(`${id} — `) ? heading.slice(2 + id.length + 3).trim() || id : id;
|
|
25
|
+
charters.push({ id, seat, sub, title });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return charters.sort((a, b) => a.id.localeCompare(b.id));
|
|
29
|
+
} catch (error) {
|
|
30
|
+
debug.log('ops.seats', 'charters-unreadable', { root, error: error instanceof Error ? error.message : String(error) });
|
|
31
|
+
onUnreadable?.();
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -78,6 +78,8 @@ interface CreateTabBody {
|
|
|
78
78
|
kind?: string;
|
|
79
79
|
id?: string;
|
|
80
80
|
label?: string;
|
|
81
|
+
/** Conversation owning a newly created webterm. */
|
|
82
|
+
sessionId?: string;
|
|
81
83
|
/** Kind-specific factory opts (passed through to the factory). */
|
|
82
84
|
kindOpts?: Record<string, unknown>;
|
|
83
85
|
/** When true (default), supervisor.startTab is called immediately
|
|
@@ -95,7 +97,7 @@ function buildTabSpec(body: CreateTabBody, id: string): { spec: TabSpec; reason?
|
|
|
95
97
|
case 'chat':
|
|
96
98
|
return { spec: createChatTabSpec(opts as Parameters<typeof createChatTabSpec>[0]) };
|
|
97
99
|
case 'webterm':
|
|
98
|
-
return { spec: createWebtermTabSpec(opts as Parameters<typeof createWebtermTabSpec>[0]) };
|
|
100
|
+
return { spec: createWebtermTabSpec({ ...opts, sessionId: body.sessionId ?? opts.sessionId } as Parameters<typeof createWebtermTabSpec>[0]) };
|
|
99
101
|
case 'daemon':
|
|
100
102
|
return { spec: createDaemonTabSpec(opts as Parameters<typeof createDaemonTabSpec>[0]) };
|
|
101
103
|
case 'pwa-host':
|
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import { CardStore } from '../../task-cards/card-store.js';
|
|
2
|
+
import { createWishCard } from '../../intake-plane/wish-card.js';
|
|
2
3
|
import { jsonResponse } from './json-response.js';
|
|
3
4
|
|
|
5
|
+
export async function handleTaskCardsWishPost(req: Request, root?: string): Promise<Response> {
|
|
6
|
+
let body: unknown;
|
|
7
|
+
try { body = await req.json(); }
|
|
8
|
+
catch { return jsonResponse({ error: 'bad_request' }, 400); }
|
|
9
|
+
if (!body || typeof body !== 'object' || Array.isArray(body)) return jsonResponse({ error: 'bad_request' }, 400);
|
|
10
|
+
const { text, ref } = body as Record<string, unknown>;
|
|
11
|
+
if (typeof text !== 'string' || !text.trim() || typeof ref !== 'string' || !ref.trim()) {
|
|
12
|
+
return jsonResponse({ error: 'bad_request' }, 400);
|
|
13
|
+
}
|
|
14
|
+
const store = new CardStore(root);
|
|
15
|
+
try {
|
|
16
|
+
const card = createWishCard({ text, source: 'pwa', ref }, store);
|
|
17
|
+
return jsonResponse(card, card.created ? 201 : 200);
|
|
18
|
+
} finally {
|
|
19
|
+
store.close();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
4
23
|
/** Read-only card API; route registration and authorization belong to the HTTP server. */
|
|
5
24
|
export function handleTaskCardsGet(pathname: string, root?: string): Response {
|
|
6
25
|
if (pathname !== '/v1/task-cards' && !/^\/v1\/task-cards\/[^/]+$/.test(pathname)) {
|
package/src/nexus/api/trace.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { checkAuth, type MetaApiOpts } from './meta-api.js';
|
|
|
9
9
|
import { jsonResponse } from './json-response.js';
|
|
10
10
|
import { runLedgerDir, runLedgerPath } from '../../self-implement/run-ledger.js';
|
|
11
11
|
import { scanStoresForRun } from './trace-run-scan.js';
|
|
12
|
+
import { listSessions } from '../../session/index.js';
|
|
12
13
|
|
|
13
14
|
export type TraceLevel = 'L0' | 'L1' | 'L2' | 'L3';
|
|
14
15
|
export interface TraceEvent {
|
|
@@ -17,6 +18,7 @@ export interface TraceEvent {
|
|
|
17
18
|
universe: string;
|
|
18
19
|
machine?: string;
|
|
19
20
|
runId?: string;
|
|
21
|
+
projectId?: string;
|
|
20
22
|
parentRunId?: string;
|
|
21
23
|
phase?: string;
|
|
22
24
|
shard?: string;
|
|
@@ -83,6 +85,7 @@ function eventFor(row: LogStoreRow): TraceEvent {
|
|
|
83
85
|
id: evidenceRef(universe, row.id), ts: row.ts, universe,
|
|
84
86
|
...(machine ? { machine } : {}),
|
|
85
87
|
...(runId ? { runId } : {}),
|
|
88
|
+
...(text(data.projectId) ? { projectId: text(data.projectId) } : {}),
|
|
86
89
|
...(text(data.parentRunId) ? { parentRunId: text(data.parentRunId) } : {}),
|
|
87
90
|
...(text(data.phase) ? { phase: text(data.phase) } : {}),
|
|
88
91
|
...(text(data.shard) ? { shard: text(data.shard) } : {}),
|
|
@@ -259,11 +262,15 @@ function options(url: URL): { level: TraceLevel; limit: number; from?: number; t
|
|
|
259
262
|
if (from === null || to === null || (from !== undefined && to !== undefined && from > to)) return { level, limit: n, error: 'invalid time range' };
|
|
260
263
|
return { level, limit: Math.min(n, TRACE_LIMIT), ...(from !== undefined ? { from } : {}), ...(to !== undefined ? { to } : {}) };
|
|
261
264
|
}
|
|
262
|
-
function matches(row: LogStoreRow, url: URL): boolean {
|
|
265
|
+
function matches(row: LogStoreRow, url: URL, projectSessions?: ReadonlySet<string>): boolean {
|
|
263
266
|
const data = dataFor(row);
|
|
264
267
|
const runId = url.searchParams.get('runId');
|
|
265
268
|
const universe = url.searchParams.get('universe');
|
|
266
269
|
const kind = url.searchParams.get('kind');
|
|
270
|
+
const projectId = url.searchParams.get('projectId');
|
|
271
|
+
if (projectId !== null && (Object.hasOwn(data, 'projectId')
|
|
272
|
+
? data.projectId !== projectId
|
|
273
|
+
: !projectSessions?.has(row.session_id ?? '') && !projectSessions?.has(text(data.sessionId) ?? ''))) return false;
|
|
267
274
|
const q = url.searchParams.get('q')?.toLowerCase();
|
|
268
275
|
if (runId && data.runId !== runId && data.run_id !== runId) return false;
|
|
269
276
|
if (universe && row.instance !== universe) return false;
|
|
@@ -295,6 +302,8 @@ function findRunUniverse(runId: string, selected: readonly string[], deps: Trace
|
|
|
295
302
|
export function handleTrace(req: Request, opts: MetaApiOpts, deps: TraceDeps = {}): Response {
|
|
296
303
|
if (!checkAuth(req, opts)) return jsonResponse({ error: 'unauthorized' }, 401);
|
|
297
304
|
const url = new URL(req.url);
|
|
305
|
+
const projectId = url.searchParams.get('projectId');
|
|
306
|
+
const projectSessions = projectId === null ? undefined : new Set(listSessions({ projectId }).map(session => session.id));
|
|
298
307
|
const parsed = options(url);
|
|
299
308
|
if (parsed.error) return jsonResponse({ ok: false, error: 'bad_request', reason: parsed.error }, 400);
|
|
300
309
|
const names = storeNames(url, deps);
|
|
@@ -315,7 +324,8 @@ export function handleTrace(req: Request, opts: MetaApiOpts, deps: TraceDeps = {
|
|
|
315
324
|
for (const entry of stores) {
|
|
316
325
|
if (!entry.store) { failures.push({ name: entry.name, reason: entry.error ?? 'log-store-unavailable' }); continue; }
|
|
317
326
|
try {
|
|
318
|
-
const page = entry.store.aggregateRuns({ sinceMs: parsed.from, untilMs: parsed.to
|
|
327
|
+
const page = entry.store.aggregateRuns({ sinceMs: parsed.from, untilMs: parsed.to,
|
|
328
|
+
...(projectId !== null ? { projectId, projectSessionIds: [...projectSessions!] } : {}) }, RUN_LIMIT);
|
|
319
329
|
if (page.length >= RUN_LIMIT) runLimitReached = true;
|
|
320
330
|
runs.push(...page.map((run) => ({ ...run, universe: entry.name })));
|
|
321
331
|
opened++;
|
|
@@ -334,7 +344,8 @@ export function handleTrace(req: Request, opts: MetaApiOpts, deps: TraceDeps = {
|
|
|
334
344
|
for (const entry of stores) {
|
|
335
345
|
if (!entry.store) { failures.push({ name: entry.name, reason: entry.error ?? 'log-store-unavailable' }); continue; }
|
|
336
346
|
try {
|
|
337
|
-
const query: LogQuery = { sinceMs: parsed.from, untilMs: parsed.to, limit: TRACE_LIMIT + 1
|
|
347
|
+
const query: LogQuery = { sinceMs: parsed.from, untilMs: parsed.to, limit: TRACE_LIMIT + 1,
|
|
348
|
+
...(projectId !== null ? { projectId, projectSessionIds: [...projectSessions!] } : {}) };
|
|
338
349
|
const search = url.searchParams.get('q');
|
|
339
350
|
if (search) query.grep = search;
|
|
340
351
|
// Restrict a run before paging; other JSON-only filters still apply to the bounded window.
|
|
@@ -349,7 +360,7 @@ export function handleTrace(req: Request, opts: MetaApiOpts, deps: TraceDeps = {
|
|
|
349
360
|
const runId = url.searchParams.get('runId');
|
|
350
361
|
let resolution: { universe?: string; checked: number; truncated?: boolean; unresolved?: boolean } | undefined;
|
|
351
362
|
let resolvedFrom: 'ledger' | 'log-scan' | undefined;
|
|
352
|
-
if ((parsed.level === 'L2' || parsed.level === 'L3') && runId && !rows.some((row) => matches(row, url)) && !requestedUniverse) {
|
|
363
|
+
if ((parsed.level === 'L2' || parsed.level === 'L3') && runId && !rows.some((row) => matches(row, url, projectSessions)) && !requestedUniverse) {
|
|
353
364
|
// A store with no log db at all («has no log store yet» — e.g. the daemon's own tree-derived universe) cannot
|
|
354
365
|
// hold the run, so it must not block the ledger lookup. A store that exists but failed to open/read still does:
|
|
355
366
|
// «could not read» is never answered as «not there». The reply keeps `failedStores` either way.
|
|
@@ -379,7 +390,8 @@ export function handleTrace(req: Request, opts: MetaApiOpts, deps: TraceDeps = {
|
|
|
379
390
|
if (!entry?.store) return jsonResponse({ ok: false, error: 'log-store-unavailable', failedStores: [{ name, reason: entry?.error ?? 'log-store-unavailable' }] }, 503);
|
|
380
391
|
stores.push(entry);
|
|
381
392
|
try {
|
|
382
|
-
const query: LogQuery = { sinceMs: parsed.from, untilMs: parsed.to, limit: TRACE_LIMIT + 1
|
|
393
|
+
const query: LogQuery = { sinceMs: parsed.from, untilMs: parsed.to, limit: TRACE_LIMIT + 1,
|
|
394
|
+
...(projectId !== null ? { projectId, projectSessionIds: [...projectSessions!] } : {}) };
|
|
383
395
|
const search = url.searchParams.get('q');
|
|
384
396
|
if (search) query.grep = search;
|
|
385
397
|
const page = entry.store.queryTraceRun(runId, query);
|
|
@@ -388,7 +400,7 @@ export function handleTrace(req: Request, opts: MetaApiOpts, deps: TraceDeps = {
|
|
|
388
400
|
} catch (e) { return jsonResponse({ ok: false, error: 'log-store-unavailable', failedStores: [{ name, reason: e instanceof Error ? e.message : String(e) }] }, 503); }
|
|
389
401
|
}
|
|
390
402
|
}
|
|
391
|
-
const filtered = rows.filter((row) => matches(row, url)).sort(sortRows);
|
|
403
|
+
const filtered = rows.filter((row) => matches(row, url, projectSessions)).sort(sortRows);
|
|
392
404
|
const trace = buildTrace(filtered.slice(0, parsed.limit), parsed.level, filtered.length > parsed.limit || candidateLimitReached || failures.length > 0 || resolution?.truncated === true);
|
|
393
405
|
try { (deps.queryLog ?? ((details) => debug.log('logs.trace', 'query', details)))({ stores: names, level: parsed.level, count: trace.events.length, truncated: trace.truncated, mode: 'rows', runs: trace.nodes.filter((node) => node.level === 'L1' && node.count > 0).length }); } catch { /* query logging must not block reads */ }
|
|
394
406
|
return jsonResponse({ ok: true, ...trace, stores: names, registeredStores: registeredStoreCount(deps), ...(resolution ? resolution.universe ? { resolvedFrom, runUniverse: resolution.universe, ...(resolvedFrom === 'log-scan' ? { checked: resolution.checked } : {}) } : { runUniverse: resolution.truncated || resolution.unresolved ? 'unresolved' as const : 'not-found' as const, checked: resolution.checked } : {}), ...(failures.length ? { failedStores: failures } : {}) }, 200);
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { getGlobalWorkflowDir, getProjectWorkflowDir } from '../../workflow-runtime/discovery.js';
|
|
5
|
+
|
|
6
|
+
export interface WorkflowHistoryOpts {
|
|
7
|
+
scope?: 'project' | 'global';
|
|
8
|
+
cwd?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface WorkflowHistoryVersion {
|
|
12
|
+
id: string;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
size: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const MAX_VERSIONS = 20;
|
|
18
|
+
const VERSION_ID = /^(\d{13})-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
19
|
+
|
|
20
|
+
function safeName(name: string): void {
|
|
21
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name) || name.includes('..')) {
|
|
22
|
+
throw new Error('invalid workflow name');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function safeVersionId(id: string): void {
|
|
27
|
+
if (!/^[A-Za-z0-9_-]+$/.test(id)) throw new Error('invalid workflow history version id');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function workflowDir(opts: WorkflowHistoryOpts): string {
|
|
31
|
+
return opts.scope === 'global'
|
|
32
|
+
? getGlobalWorkflowDir()
|
|
33
|
+
: getProjectWorkflowDir(opts.cwd ?? process.cwd());
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function historyDir(name: string, opts: WorkflowHistoryOpts): string {
|
|
37
|
+
safeName(name);
|
|
38
|
+
return join(workflowDir(opts), '.history', name);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Capture the current YAML before its caller overwrites it; a missing file has no history. */
|
|
42
|
+
export function snapshotBeforeSave(name: string, opts: WorkflowHistoryOpts = {}): WorkflowHistoryVersion | null {
|
|
43
|
+
const dir = historyDir(name, opts);
|
|
44
|
+
const source = join(workflowDir(opts), `${name}.yaml`);
|
|
45
|
+
if (!existsSync(source)) return null;
|
|
46
|
+
const content = readFileSync(source);
|
|
47
|
+
const previous = listWorkflowHistory(name, opts)[0];
|
|
48
|
+
if (previous && readFileSync(join(dir, `${previous.id}.yaml`)).equals(content)) return null;
|
|
49
|
+
|
|
50
|
+
mkdirSync(dir, { recursive: true });
|
|
51
|
+
const timestamp = Math.max(Date.now(), previous ? Number(previous.id.slice(0, 13)) + 1 : 0);
|
|
52
|
+
const id = `${String(timestamp).padStart(13, '0')}-${randomUUID()}`;
|
|
53
|
+
const version: WorkflowHistoryVersion = {
|
|
54
|
+
id,
|
|
55
|
+
createdAt: new Date(Number(id.slice(0, 13))).toISOString(),
|
|
56
|
+
size: content.byteLength,
|
|
57
|
+
};
|
|
58
|
+
writeFileSync(join(dir, `${id}.yaml`), content, { flag: 'wx' });
|
|
59
|
+
for (const old of listWorkflowHistory(name, opts).slice(MAX_VERSIONS)) {
|
|
60
|
+
unlinkSync(join(dir, `${old.id}.yaml`));
|
|
61
|
+
}
|
|
62
|
+
return version;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Enumerate only this workflow's snapshots, newest first. */
|
|
66
|
+
export function listWorkflowHistory(name: string, opts: WorkflowHistoryOpts = {}): WorkflowHistoryVersion[] {
|
|
67
|
+
const dir = historyDir(name, opts);
|
|
68
|
+
if (!existsSync(dir)) return [];
|
|
69
|
+
return readdirSync(dir)
|
|
70
|
+
.filter(file => file.endsWith('.yaml') && VERSION_ID.test(file.slice(0, -5)))
|
|
71
|
+
.map(file => {
|
|
72
|
+
const id = file.slice(0, -5);
|
|
73
|
+
const filePath = join(dir, file);
|
|
74
|
+
const stat = statSync(filePath);
|
|
75
|
+
return stat.isFile() ? { id, createdAt: new Date(Number(id.slice(0, 13))).toISOString(), size: stat.size } : null;
|
|
76
|
+
})
|
|
77
|
+
.filter((version): version is WorkflowHistoryVersion => version !== null)
|
|
78
|
+
.sort((a, b) => b.id.localeCompare(a.id));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** A missing (well-formed) version returns null rather than an empty YAML draft. */
|
|
82
|
+
export function getWorkflowHistoryVersion(name: string, id: string, opts: WorkflowHistoryOpts = {}): string | null {
|
|
83
|
+
const dir = historyDir(name, opts);
|
|
84
|
+
safeVersionId(id);
|
|
85
|
+
const file = join(dir, `${id}.yaml`);
|
|
86
|
+
if (!VERSION_ID.test(id) || !existsSync(file)) return null;
|
|
87
|
+
return readFileSync(file, 'utf-8');
|
|
88
|
+
}
|