elanous 0.2.9 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/Y4zKzL62sakG5momz3SoQ/_buildManifest.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1394-556de6d71bbdb0fb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1452.93700483b9d4fc61.js +9 -0
- package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 1829-b453a1b22d3999bb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2310-7a59f043f6db207e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2548-6e316138d347cefe.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3869-a39d1d9921e10d43.js +1 -0
- package/apps/pwa/out/_next/static/chunks/390.c373e31b3b9d0c41.js +5 -0
- package/apps/pwa/out/_next/static/chunks/3992-2e522a8ac5f2afde.js +25 -0
- package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4685-c3c1c625b71accd1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +2 -0
- package/apps/pwa/out/_next/static/chunks/507-5acd98bd6dab2d8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5445-745eb795c5963d79.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5845-e6c003ce8d5fd36a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 5cd7e3a9-404fd6b8d0ecd44c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 7334.a6679d9168f37aa8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +1 -0
- package/apps/pwa/out/_next/static/chunks/79f8be9e-957d68913b590b08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8039-df92e08fede5de8f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8421-1c4acfb1395a0edf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8605-ea5bee9dfae512c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2415.ed6428ff334c7ce2.js → 9269.d2a4795bc6812717.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9656-c1540088f5859c80.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9906-482c6619b3fdda20.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-1dcdc58fc2de2454.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-6a061bd97f0b9398.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-cb95a7432c9ee744.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-f972fc1c00a62e88.js → page-b12b6d2f8d2d1aea.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-b9efe868bfd36255.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-7c97dcdfe2e37a60.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-8fd36984f549270a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-5721537ca8a3598c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-b654240a572e4c48.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-b9750abc897508c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-4cd1de371f8ad048.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-d99f89657828421c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-50cb2a0eb15e6c83.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-c8b1ccda6ba7ae98.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-d6b1d156fb95e74b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-2a9932ddb62d76bd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-9688f5b4f1ff950f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6b15dd6456c5df09.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-adfbd2ba9598e59a.js → page-35414e0a007b4082.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-e7a529e0507ac86c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-e001823c35c9dd67.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-371423d1a573d64b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4b764b125339ac17.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cdf8e4b01067bcf1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-3a24072b35470157.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-94c82eb0ae5abb32.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-0be8d4b2ced75ba0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-d37cb0d52f9b6bd5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-686da0df9bf23e5c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4dc614f3ce043e63.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-53f80edc6b8dc07c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-d02c782fc792e2af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-239c17b911b84e72.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-dc6a79fb003f746c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-0fffb84cafdc9da6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-1218753c82d585f6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-4b5935e67531efb5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-3285bc87caf1eaa5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-ad553b0e06505ecd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-fca096e3e860306f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ebfa78f0d9885c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-3dc5f21f7e39622d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-c6da2b468454532d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-93bc70e36f595414.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2ea96958-e8c7e112de50b067.js → f48170cc-d05d28bf87a43bf4.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +1 -0
- package/apps/pwa/out/_next/static/css/543f56bcb1f79fca.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -0
- package/apps/pwa/out/inside/index.txt +31 -0
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -0
- package/apps/pwa/out/ops/seats/index.txt +30 -0
- package/apps/pwa/out/outputs/index.html +1 -0
- package/apps/pwa/out/outputs/index.txt +30 -0
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -24
- package/apps/pwa/out/today/index.html +1 -0
- package/apps/pwa/out/today/index.txt +33 -0
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -24
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/graphs/drafts/draft-cleanup.yaml +19 -0
- package/graphs/drafts/recipes.yaml +23 -0
- package/graphs/field/field-feed.yaml +2 -0
- package/graphs/implement-loop.yaml +1 -1
- package/graphs/intake/intake-daily.yaml +2 -1
- package/graphs/ops/recipes.yaml +3 -0
- package/graphs/ops/secret-exposure.yaml +24 -0
- package/graphs/release/recipes.yaml +3 -0
- package/graphs/release/release-loop.yaml +4 -1
- package/graphs/video/explainer-line.yaml +2 -2
- package/package.json +2 -1
- package/plugins/card-followup/graphs/run-step.ts +48 -13
- package/plugins/doc-draft/graphs/doc-draft.yaml +3 -3
- package/plugins/doc-draft/graphs/run-step.ts +13 -6
- package/plugins/elanous-hwp/README.md +25 -0
- package/plugins/elanous-hwp/cli.ts +22 -0
- package/plugins/elanous-hwp/converter.ts +237 -0
- package/plugins/elanous-hwp/fixtures/fixed-controls.hwpx +0 -0
- package/plugins/elanous-hwp/fixtures/fixed-table-controls.hwpx +0 -0
- package/plugins/elanous-hwp/fixtures/fixed.hwpx +0 -0
- package/plugins/elanous-hwp/plugin.json +16 -0
- package/plugins/elanous-hwp/plugin.ts +40 -0
- package/scripts/ci-public-export-leak-gate.ts +75 -14
- package/scripts/ci-public-leak-gate.ts +44 -9
- package/scripts/ci-pwa-build-gate.ts +160 -0
- package/scripts/context-hooks/claude-stop.sh +4 -0
- package/scripts/context-hooks/emit.ts +24 -0
- package/scripts/context-hooks/post-tool-use.sh +4 -0
- package/scripts/coord-channel-watch.sh +54 -8
- package/scripts/coord-digest.ts +199 -0
- package/scripts/coord-post.sh +60 -3
- package/scripts/coord-requests-bridge.ts +143 -0
- package/scripts/field-feed/lib.ts +4 -0
- package/scripts/fleet/node-setup.sh +20 -3
- package/scripts/homebrew-formula-bump.ts +69 -0
- package/scripts/install.ps1 +68 -9
- package/scripts/install.sh +39 -12
- package/scripts/lib/pwa-scenarios/scenarios.ts +20 -0
- package/scripts/lib/tui-regress-checks.ts +146 -0
- package/scripts/marketing/measure-site-numbers.ts +169 -0
- package/scripts/measure-gate-shards.ts +309 -0
- package/scripts/memory-lifecycle-cycle.ts +2 -2
- package/scripts/mission-request-judge.ts +31 -1
- package/scripts/morning-report.ts +2 -2
- package/scripts/opportunity-scan.ts +1 -1
- package/scripts/ops-now-probe.ts +327 -0
- package/scripts/publish-internal-dist.ts +11 -1
- package/scripts/release-loop/auto-approve-node.ts +21 -4
- package/scripts/release-loop/cut-branch.ts +84 -0
- package/scripts/release-loop/cutoff.ts +19 -8
- package/scripts/release-loop/gate-node.ts +14 -13
- package/scripts/release-loop/mac-smoke-node.ts +229 -0
- package/scripts/release-loop/node-verdict.ts +3 -3
- package/scripts/release-loop/ops-upgrade-node.ts +72 -16
- package/scripts/release-loop/release-readiness.ts +9 -0
- package/scripts/release-loop/tui-node-checks.ts +42 -0
- package/scripts/release-loop/tui-sim-node.ts +32 -8
- package/scripts/release-loop/unattended-release.ts +5 -3
- package/scripts/release-loop/version-node.ts +112 -13
- package/scripts/repo-watch-cycle.ts +1 -1
- package/scripts/retro-cycle.ts +2 -2
- package/scripts/schedule-health-report.ts +1 -1
- package/scripts/signal-digest-cycle.ts +2 -7
- package/scripts/signal-digest-photo.ts +11 -0
- package/scripts/storyboard/storyboard.ts +5 -161
- package/scripts/tech1-public-measure.ts +94 -0
- package/scripts/test-diet/lib.ts +30 -1
- package/scripts/test-diet/node.ts +83 -8
- package/scripts/test-timeout-audit.ts +114 -0
- package/scripts/tree-sync-alert.ts +1 -1
- package/scripts/tui-regress.ts +71 -0
- package/scripts/ux/demo-rehearsal.ts +243 -0
- package/scripts/ux/lib/rehearsal-verdict.ts +73 -0
- package/scripts/waitlist-daily-digest.ts +1 -1
- package/skills/diagram-master/SKILL.md +366 -0
- package/skills/diagram-master/references/engines/excalidraw/color-palette.md +67 -0
- package/skills/diagram-master/references/engines/excalidraw/element-templates.md +182 -0
- package/skills/diagram-master/references/engines/excalidraw/json-schema.md +71 -0
- package/skills/diagram-master/references/engines/excalidraw/render_excalidraw.py +189 -0
- package/skills/diagram-master/references/engines/excalidraw/render_template.html +57 -0
- package/skills/diagram-master/references/engines/matplotlib/matplotlib-patterns.md +235 -0
- package/skills/diagram-master/references/engines/matplotlib/render_matplotlib.py +184 -0
- package/skills/diagram-master/references/engines/mermaid/domain-templates.md +435 -0
- package/skills/diagram-master/references/engines/mermaid/render_mermaid.py +116 -0
- package/skills/diagram-master/references/engines/mermaid/syntax-reference.md +2247 -0
- package/skills/diagram-master/references/engines/nanobannana/render_nanobannana2.py +168 -0
- package/skills/diagram-master/references/engines/svg/color-palette.md +188 -0
- package/skills/diagram-master/references/engines/svg/html-base-template.html +332 -0
- package/skills/diagram-master/references/engines/svg/interactivity-patterns.md +435 -0
- package/skills/diagram-master/references/engines/svg/render_interactive_svg.py +212 -0
- package/skills/diagram-master/references/engines/svg/svg-element-templates.md +349 -0
- package/skills/diagram-master/references/examples/README.md +69 -0
- package/skills/diagram-master/references/examples/ref_grid_architecture.png +0 -0
- package/skills/diagram-master/references/examples/ref_layered_flow.png +0 -0
- package/skills/diagram-master/references/pyproject.toml +16 -0
- package/skills/diagram-master/references/quality-checklist.md +33 -0
- package/skills/diagram-master/references/routing-guide.md +164 -0
- package/skills/diagram-master/references/uv.lock +1356 -0
- package/skills/explainer-video/SKILL.md +4 -0
- package/skills/explainer-video/engine/reel.mjs +18 -13
- package/skills/explainer-video/engine/reel.sh +24 -5
- package/skills/explainer-video/engine/stitch.mjs +145 -0
- package/skills/google-workspace/SKILL.md +33 -0
- package/skills/google-workspace/scripts/gws-safe.sh +177 -0
- package/skills/grill-me/SKILL.md +1 -1
- package/skills/lecture-note-digitizer/SKILL.md +926 -0
- package/skills/lecture-note-digitizer/references/convert_to_pdf.py +30 -0
- package/skills/lecture-note-digitizer/references/extract_slide_diagram.py +73 -0
- package/skills/lecture-note-digitizer/references/html-template.md +167 -0
- package/skills/lecture-note-digitizer/references/katex-style-guide.md +165 -0
- package/skills/omni-crawl/SKILL.md +21 -11
- package/skills/omni-crawl/scripts/main.ts +6 -6
- package/skills/omni-crawl/src/router.ts +3 -3
- package/skills/omni-digest/SKILL.md +17 -9
- package/skills/omni-digest/digest.md +2 -2
- package/skills/omni-digest/src/fetch.ts +30 -3
- package/skills/pitch-deck/SKILL.md +36 -0
- package/skills/pitch-deck/template.html +80 -0
- package/skills/youtube-master/SKILL.md +163 -0
- package/skills/youtube-master/package-lock.json +558 -0
- package/skills/youtube-master/package.json +13 -0
- package/skills/youtube-master/references/study-note-template.md +124 -0
- package/skills/youtube-master/scripts/main.ts +435 -0
- package/skills/youtube-master/scripts/transcribe-local.ts +24 -0
- package/skills/youtube-master/src/audio.ts +63 -0
- package/skills/youtube-master/src/domain-staging.ts +50 -0
- package/skills/youtube-master/src/env.ts +36 -0
- package/skills/youtube-master/src/obsidian.ts +155 -0
- package/skills/youtube-master/src/router.ts +110 -0
- package/skills/youtube-master/src/stt.ts +199 -0
- package/skills/youtube-master/src/study-note.ts +175 -0
- package/skills/youtube-master/src/summarize.ts +358 -0
- package/skills/youtube-master/src/transcript.ts +76 -0
- package/skills/youtube-master/src/types.ts +91 -0
- package/skills/youtube-master/src/util.ts +93 -0
- package/skills/youtube-master/src/youtube.ts +70 -0
- package/skills/youtube-master/tsconfig.json +13 -0
- package/src/acp/codex-approval-adapter.ts +9 -3
- package/src/acp/core-turn-bridge.ts +117 -18
- package/src/acp/fact-question.ts +11 -0
- package/src/acp/server.ts +53 -9
- package/src/acp/tool-approval.ts +126 -0
- package/src/acp/turn-runner.ts +36 -0
- package/src/agent/monad-agent-turn.ts +8 -0
- package/src/agent-mission/driver.ts +80 -10
- package/src/agent-mission/pty-decision.ts +71 -0
- package/src/agent-mission/review-loop.ts +30 -0
- package/src/ask-user-question/pending-questions.ts +25 -10
- package/src/ask-user-question/types.ts +9 -0
- package/src/auth/setup-link-tokens.ts +16 -5
- package/src/autopilot/build/integrity-gate.ts +12 -0
- package/src/autopilot/build/llm-conflict-merge.ts +16 -3
- package/src/autopilot/tool-registry.ts +2 -0
- package/src/boot/daemon-prompt-turn.ts +8 -0
- package/src/boot/daemon-runtime.ts +9 -3
- package/src/boot/daemon-tools/index.ts +8 -0
- package/src/boot/daemon-tools/types.ts +2 -0
- package/src/boot/daemon-tools/web-search.ts +4 -0
- package/src/card-followup/core.ts +109 -0
- package/src/chat/ctrl-c-in-input.ts +14 -0
- package/src/chat/index.ts +53 -0
- package/src/chat/pickers/state.ts +6 -2
- package/src/cli/agent-cli.ts +7 -0
- package/src/cli/decisions-cli.ts +25 -3
- package/src/cli/doctor-bundle-upload.ts +68 -0
- package/src/cli/doctor-cli.ts +38 -4
- package/src/cli/drive-input-jail.ts +101 -0
- package/src/cli/hooks-cli.ts +17 -3
- package/src/cli/make-cli.ts +43 -0
- package/src/cli/ops-cli.ts +20 -0
- package/src/cli/persona-cli.ts +90 -4
- package/src/cli/plugin-cli.ts +31 -22
- package/src/cli/pod-cli.ts +61 -2
- package/src/cli/pr-cli.ts +82 -17
- package/src/cli/pty-drive-cli.ts +41 -7
- package/src/cli/pty-drive-verdict.ts +40 -0
- package/src/cli/pwa-stop.ts +163 -13
- package/src/cli/pwa-test.ts +3 -0
- package/src/cli/release-cli.ts +80 -24
- package/src/cli/self-update.ts +14 -0
- package/src/cli/setup-cli.ts +43 -1
- package/src/cli/skills-cli.ts +17 -1
- package/src/cli/storyboard-cli.ts +37 -0
- package/src/cli/test-state-dir-flag.ts +11 -4
- package/src/connectors/linear.ts +146 -0
- package/src/context-bus/claude-hooks-install.ts +10 -0
- package/src/context-bus/context-now-surfaces.ts +48 -0
- package/src/context-bus/context-now.ts +104 -0
- package/src/context-bus/coord-events.ts +115 -0
- package/src/context-bus/external-events.ts +52 -0
- package/src/context-bus/long-term-memory.ts +108 -0
- package/src/dashboard/dashboard-boot-fixture.ts +23 -0
- package/src/dashboard/index.ts +63 -21
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +14 -1
- package/src/dashboard/slash-runtime/help-from-registry.ts +43 -28
- package/src/decisions/decision-cards.ts +58 -3
- package/src/decisions/decision-ledger.ts +85 -6
- package/src/decisions/decision-linear-projection.ts +157 -0
- package/src/decisions/web-push-decision-cards.ts +50 -0
- package/src/directive/interpretation-card.ts +36 -0
- package/src/discord/sprint21-runtime.ts +5 -1
- package/src/discord-self-message.ts +32 -0
- package/src/discord-slash-wire.ts +5 -1
- package/src/discord.ts +19 -2
- package/src/domains/coo-admin-tool.ts +62 -0
- package/src/domains/core-tools.ts +13 -4
- package/src/domains/elanous-card.ts +29 -0
- package/src/domains/ops-facts-tool.ts +76 -0
- package/src/domains/outbound-alert.ts +46 -13
- package/src/domains/release-tool.ts +168 -0
- package/src/domains/telegram-kind-route.ts +65 -9
- package/src/exec-requests/default-outputs.ts +25 -0
- package/src/exec-requests/planner.ts +106 -28
- package/src/exec-requests/runner.ts +123 -12
- package/src/exec-requests/store.ts +11 -2
- package/src/execution-loop/launch-gate.ts +100 -0
- package/src/field/field-media.ts +10 -7
- package/src/field/field-reel.ts +19 -5
- package/src/field-note/index.ts +201 -0
- package/src/field-note/transcribe.ts +248 -0
- package/src/git-fs/worktree.ts +45 -6
- package/src/graph-kinds/registry.ts +3 -3
- package/src/graph-runner/graph-approval-card.ts +113 -0
- package/src/graph-runner/graph-cli.ts +189 -4
- package/src/graph-runner/graph-grow-llm.ts +37 -0
- package/src/graph-runner/graph-grow.ts +47 -0
- package/src/graph-runner/graph-notify.ts +25 -3
- package/src/graph-runner/runner.ts +453 -35
- package/src/grok/agent-search.ts +8 -2
- package/src/guardian/secret-exposure-scan.ts +101 -0
- package/src/harness/browser-verify.ts +25 -2
- package/src/harness/harness-cli-command.ts +478 -42
- package/src/harness/harness-incidents-writer.fixture.ts +24 -0
- package/src/harness/harness-incidents.ts +129 -0
- package/src/harness/harness-pod-dispatch.ts +43 -23
- package/src/harness/harness-seams.ts +38 -4
- package/src/harness/harness-stop.ts +75 -6
- package/src/harness/launch-registry.ts +91 -0
- package/src/harness/process-garbage.ts +5 -3
- package/src/hitl/clarification-policy.ts +3 -1
- package/src/hooks/dispatch.ts +82 -0
- package/src/hooks/expose.ts +254 -0
- package/src/hooks/github-shadow.ts +108 -0
- package/src/hooks/providers.ts +71 -5
- package/src/hooks/queue.ts +1 -1
- package/src/hooks/receiver.ts +21 -20
- package/src/index.ts +206 -49
- package/src/intake-plane/author-goals.ts +37 -4
- package/src/intake-plane/categorize.ts +18 -46
- package/src/intake-plane/check.ts +3 -0
- package/src/intake-plane/discord-seat-work.ts +57 -2
- package/src/intake-plane/front-route-classifier.ts +33 -39
- package/src/intake-plane/persona-answer.ts +30 -0
- package/src/intake-plane/runtime-callables.ts +8 -1
- package/src/intake-plane/seat-doc-route.ts +170 -6
- package/src/intake-plane/telegram-seat-work.ts +80 -4
- package/src/intake-plane/telegram-work.ts +1 -0
- package/src/intake-plane/wish-folder.ts +67 -0
- package/src/intent-gate/gate.ts +30 -10
- package/src/live/detail-switch.ts +5 -0
- package/src/llm/difficulty.ts +57 -0
- package/src/llm/judge-layer.ts +101 -0
- package/src/llm/mission-router.ts +33 -19
- package/src/loops/contract/examples/cmo-seat.loop.yaml +51 -0
- package/src/loops/contract/examples/orchestrator.loop.yaml +57 -0
- package/src/loops/contract/examples/steward.loop.yaml +50 -0
- package/src/loops/contract/loop-agent.schema.json +138 -0
- package/src/loops/contract/validate.ts +64 -0
- package/src/loops/registry.ts +20 -6
- package/src/market/signed-index.ts +4 -0
- package/src/maturity/bot-command-maturity.ts +45 -0
- package/src/maturity/cli-maturity.ts +34 -0
- package/src/maturity/feature-maturity.ts +120 -1
- package/src/maturity/tui-slash-maturity.ts +31 -0
- package/src/memory.ts +32 -4
- package/src/model-tier/index.ts +2 -2
- package/src/model-tier/tier-resolver.ts +20 -20
- package/src/model-tier/types.ts +6 -6
- package/src/mss/logging/log-store.ts +15 -0
- package/src/nexus/api/config-model-tier.ts +5 -4
- package/src/nexus/api/exec-requests.ts +33 -3
- package/src/nexus/api/fabric-plans.ts +53 -0
- package/src/nexus/api/harness-api.ts +5 -1
- package/src/nexus/api/health.ts +2 -0
- package/src/nexus/api/http-server.ts +89 -1
- package/src/nexus/api/inside-events.ts +226 -0
- package/src/nexus/api/meta-api.ts +32 -8
- package/src/nexus/api/missions.ts +6 -1
- package/src/nexus/api/ops-api.ts +10 -1
- package/src/nexus/api/ops-seats-sources.ts +37 -7
- package/src/nexus/api/ops-seats.ts +49 -6
- package/src/nexus/api/outputs-route.ts +44 -0
- package/src/nexus/api/seat-requests.ts +132 -10
- package/src/nexus/api/sessions-store.ts +42 -0
- package/src/nexus/api/setup-codex-login.ts +160 -0
- package/src/nexus/api/sub-seat-charters.ts +34 -0
- package/src/nexus/api/tabs-mutations.ts +3 -1
- package/src/nexus/api/trace.ts +18 -6
- package/src/nexus/api/usage-api.ts +102 -0
- package/src/nexus/api/workflow-run-event-bridge.ts +1 -0
- package/src/nexus/api/workflows.ts +80 -6
- package/src/nexus/index.ts +47 -4
- package/src/nexus/kinds/webterm.ts +2 -1
- package/src/nexus/webterm/pty.ts +6 -2
- package/src/onboarding/cli-auth-status.ts +80 -0
- package/src/onboarding/first-run.ts +89 -0
- package/src/onboarding/lan-address.ts +45 -0
- package/src/onboarding/voice-ai.ts +3 -3
- package/src/onboarding/web-first.ts +119 -24
- package/src/onboarding.ts +4 -0
- package/src/ops-now/ops-now-refresh.ts +100 -0
- package/src/org/seat-budget.ts +48 -0
- package/src/org/stall-escalation.ts +63 -0
- package/src/outputs/ledger.ts +120 -0
- package/src/persona/persona-todo.ts +79 -0
- package/src/persona/presets.ts +116 -2
- package/src/persona/team-set.ts +155 -0
- package/src/plugins/install/plugin-install.ts +14 -0
- package/src/plugins/maker/market-bundle.ts +109 -0
- package/src/plugins/maker/plugin-maker.ts +254 -11
- package/src/plugins/maker/wizard-generate.ts +103 -0
- package/src/pod-lease/admission.ts +150 -0
- package/src/pod-lease/dependency-state.ts +85 -0
- package/src/pod-lease/host-lease.ts +127 -0
- package/src/project/project-store.ts +115 -0
- package/src/project/project-suggestion.ts +16 -0
- package/src/project/session-context.ts +24 -0
- package/src/release-loop/checklist.ts +79 -5
- package/src/release-loop/feature-store.ts +159 -24
- package/src/release-loop/next-md-merge.ts +58 -0
- package/src/release-loop/release-note.ts +59 -4
- package/src/release-loop/release-schedule.ts +53 -0
- package/src/repl/index.ts +7 -0
- package/src/seat-dispatch/ceo-commands.ts +41 -8
- package/src/seat-dispatch/ceo-intent.ts +38 -0
- package/src/seat-dispatch/seat-ask.ts +130 -0
- package/src/seat-dispatch/seat-questions.ts +100 -0
- package/src/seat-loop/seat-loop.ts +750 -0
- package/src/seat-loop/seat-report.ts +99 -0
- package/src/self-dev/decompose.ts +66 -11
- package/src/self-dev/dev-cli.ts +4 -1
- package/src/self-dev/dev-pipeline.ts +37 -1
- package/src/self-dev/draft-sweep.ts +38 -33
- package/src/self-dev/draft-triage-rules.ts +8 -5
- package/src/self-dev/fabric-plan-core.ts +297 -0
- package/src/self-dev/orchestrate.ts +36 -4
- package/src/self-dev/release-path-guard.ts +62 -0
- package/src/self-dev/run-store.ts +10 -1
- package/src/self-dev/shard-aggregate.ts +230 -0
- package/src/self-dev/shard-placement.ts +60 -0
- package/src/self-dev/shard-plan.ts +48 -0
- package/src/self-dev/shard-pod-run.ts +77 -0
- package/src/self-dev/shard-run.ts +105 -0
- package/src/self-implement/execution-clarification.ts +115 -0
- package/src/self-implement/gate-baseline.ts +1 -1
- package/src/self-implement/gate-cli.ts +46 -4
- package/src/self-implement/gate-scope.ts +37 -7
- package/src/self-implement/graph-variant.ts +171 -0
- package/src/self-implement/harness-policy-gates.ts +1 -1
- package/src/self-implement/headless-elanous-driver.ts +22 -3
- package/src/self-implement/host-regate.ts +22 -1
- package/src/self-implement/importer-test-index.ts +2 -1
- package/src/self-implement/l8-merge-queue.ts +130 -0
- package/src/self-implement/orchestrator.ts +279 -12
- package/src/self-implement/pipeline-shape.ts +1 -1
- package/src/self-implement/route-consumer-test-index.ts +122 -0
- package/src/self-implement/run-status-mapping.ts +5 -3
- package/src/self-implement/seams.ts +72 -11
- package/src/self-implement/test-seams.ts +1 -0
- package/src/self-implement/uncommitted-work.ts +59 -0
- package/src/session/chat.ts +2 -0
- package/src/session/index.ts +45 -13
- package/src/shell-env-bootstrap.ts +17 -0
- package/src/skills/gift-install.ts +215 -0
- package/src/skills/tools/web-search.ts +4 -1
- package/src/steward/directive.ts +51 -2
- package/src/steward/launch.ts +266 -0
- package/src/steward/outcome-notify.ts +115 -0
- package/src/steward/steward-cards.ts +25 -11
- package/src/steward/triage-plan.ts +32 -4
- package/src/steward/triage.ts +129 -13
- package/src/steward/working-backwards.ts +64 -0
- package/src/storyboard/storyboard.ts +141 -0
- package/src/task-cards/card-cli.ts +25 -1
- package/src/task-cards/card-store.ts +2 -2
- package/src/task-orchestrator/mission.ts +5 -0
- package/src/task-orchestrator/store.ts +12 -3
- package/src/task-orchestrator/surfaces/pod-command-job.ts +29 -7
- package/src/task-orchestrator/surfaces/pod-lease.ts +397 -0
- package/src/task-orchestrator/surfaces/pod-pool.ts +127 -26
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +214 -40
- package/src/task-orchestrator/surfaces/self-implement.ts +15 -2
- package/src/task-orchestrator/types.ts +2 -0
- package/src/telegram-card-followup.ts +153 -0
- package/src/telegram-commands.ts +10 -1
- package/src/telegram-project-command.ts +71 -0
- package/src/telegram-report.ts +29 -19
- package/src/telegram-run.ts +7 -0
- package/src/telegram.ts +58 -11
- package/src/tool-runtime/self-cognition-runtimes.ts +13 -3
- package/src/tool-runtime/types.ts +4 -0
- package/src/tui-client/dashboard-session.ts +2 -0
- package/src/user-config.ts +216 -27
- package/src/version/packed-revision.json +1 -1
- package/src/web-push/notify-exec-request.ts +32 -0
- package/src/web-search/grok.ts +7 -1
- package/src/web-search/index.ts +28 -1
- package/src/web-search/provider.ts +4 -0
- package/src/web-search/x-intent.ts +5 -0
- package/src/workflow-runtime/executor.ts +277 -47
- package/src/workflow-runtime/index.ts +1 -0
- package/src/workflow-runtime/nodes/subworkflow.ts +60 -0
- package/src/workflow-runtime/plugin-kind-node.ts +1 -1
- package/src/workflow-runtime/schema.ts +79 -4
- package/src/workflow-runtime/types.ts +35 -4
- package/apps/pwa/out/_next/static/bFI5EEwg7T6aG88ibX4Zq/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1201-09613bce624467c0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1377-1efeffbbac0963ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1470.98a6ab61ccb4131c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/216-5acd01cbde4acda7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2330-c2f07246c8788af1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2375-cb6debea56cce4fb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2929-617f1e66a55be184.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2977-e38442e86289f1d3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2982-2a2df543be3d2e5a.js +0 -25
- package/apps/pwa/out/_next/static/chunks/3403.4bc97b4066945a94.js +0 -5
- package/apps/pwa/out/_next/static/chunks/3441-a1dd4acfeda14488.js +0 -1
- package/apps/pwa/out/_next/static/chunks/371-4ad6af55dad02ced.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4114-3e63117452378807.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5080-1613752891fcadb4.js +0 -10
- package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5791-bb82743fa6299562.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6090-85a3f05f954e5697.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6284-69db415193d5f8bd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6320-baac91d68843a9a6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6416-505ba707cacafbba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6725-68ab7cc0b1faf00d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6998-a654fe5c58271600.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7032-f4ef698518fba61c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7647.2fcd30d894d5ee30.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7673-2eda1507d38dadb8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7990-e12efba616f46e03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8067-d976b441a104ab74.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8142-744998d65d7bb17e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8519-5632377cce994f86.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8630-cdfc61e82c653ffc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8894-e263b332208e3957.js +0 -1
- package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9454-139040d37c79dbc9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9740-8f5ff96c522b5f55.js +0 -1
- package/apps/pwa/out/_next/static/chunks/ae787e4c-f2998de7f1ba72a4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-fb7c2d458f32fcad.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-35e2713597dd24d1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-918b656f064577ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-5f30e00693527ebd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-7fbae173b3c103a7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-3b4edcce364062ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-c5794f484c251f44.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-1130d8eefcd87e76.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-973996d584f008c1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-016e2bda04eecb1f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-b4d6d9a3b56f2940.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-ec49a466121233ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-f72db356744ceade.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-a6fd9b50d1b85378.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-8b0402a46a749a3d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-037f83e2a1edc8e2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-46fedff57d4bec67.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-0cf318e9dcee2bbf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-899b327cb8b6845c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-6c1e6ba743a29dfe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-1a8e4807292f6b17.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-28deba6bcb834916.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-de68e2205794037d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-c71c33a573230672.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-0df30e0c7e50148a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-4fc56790fe0d2682.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-59df2aebb38a7c1e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-859cea1570b6227a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-4647be5dbcbd0795.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-e025892bda74b743.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-a0955de73b89f078.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-369846d2921af584.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-72cbc1c8cdd0f65d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-77b28bfb0996d5ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-3220c4934f49c6c2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-90670589b87abea8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-7df9243ed021a4cc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-4498c3853f4f688d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-35bedde6d885f08f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-ea806bb57f2b8923.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-8d2302399c2c8f87.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-6870f30ea99f8346.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-b10928c60f0b8488.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-689039227d443fab.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-e5bea36f183b25e6.js +0 -1
- package/apps/pwa/out/_next/static/css/f92f63a5df0ba229.css +0 -1
- package/src/dashboard/turn-typeahead-echo.ts +0 -23
- /package/apps/pwa/out/_next/static/{bFI5EEwg7T6aG88ibX4Zq → Y4zKzL62sakG5momz3SoQ}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmdirSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { parse, stringify } from 'yaml';
|
|
4
|
+
import { resolveRepositoryPersonaDir, resolveStatePersonaDir } from './global-registry.js';
|
|
5
|
+
import { parsePersonaYaml } from './loader.js';
|
|
6
|
+
|
|
7
|
+
interface Member { persona: string; title: string; checklistTemplate: string; rules: string[] }
|
|
8
|
+
interface Handoff { from: string; to: string; when: string }
|
|
9
|
+
export interface TeamSet { 'team-set': string; members: Member[]; handoffs: Handoff[] }
|
|
10
|
+
const idPattern = /^[a-z0-9_][a-z0-9_-]*$/i;
|
|
11
|
+
const namePattern = /^[\p{L}\p{N}_][\p{L}\p{N} _-]*$/u;
|
|
12
|
+
const mapping = (value: unknown): value is Record<string, unknown> => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
13
|
+
const nonempty = (value: unknown): value is string => typeof value === 'string' && value.trim().length > 0;
|
|
14
|
+
|
|
15
|
+
function readDefinition(text: string): TeamSet {
|
|
16
|
+
const raw: unknown = parse(text);
|
|
17
|
+
if (!mapping(raw) || !nonempty(raw['team-set']) || !namePattern.test(raw['team-set'])) {
|
|
18
|
+
throw new Error('team-set must be a non-empty filesystem-safe name');
|
|
19
|
+
}
|
|
20
|
+
if (!Array.isArray(raw.members) || raw.members.length === 0) throw new Error('members must be a non-empty list');
|
|
21
|
+
const members: Member[] = raw.members.map((item: unknown) => {
|
|
22
|
+
if (!mapping(item) || !nonempty(item.persona) || !idPattern.test(item.persona)
|
|
23
|
+
|| !nonempty(item.title) || !nonempty(item.checklistTemplate)
|
|
24
|
+
|| !(nonempty(item.rules) || (Array.isArray(item.rules) && item.rules.length > 0 && item.rules.every(nonempty)))) {
|
|
25
|
+
throw new Error('each member requires persona (safe id), title, checklistTemplate and rules');
|
|
26
|
+
}
|
|
27
|
+
return { persona: item.persona, title: item.title, checklistTemplate: item.checklistTemplate,
|
|
28
|
+
rules: typeof item.rules === 'string' ? [item.rules] : item.rules as string[] };
|
|
29
|
+
});
|
|
30
|
+
const ids = new Set(members.map((member) => member.persona));
|
|
31
|
+
if (ids.size !== members.length) throw new Error('duplicate team-set member persona');
|
|
32
|
+
if (!Array.isArray(raw.handoffs)) throw new Error('handoffs must be a list');
|
|
33
|
+
const handoffs: Handoff[] = raw.handoffs.map((item: unknown) => {
|
|
34
|
+
if (!mapping(item) || !nonempty(item.from) || !nonempty(item.to) || !nonempty(item.when)) {
|
|
35
|
+
throw new Error('each handoff requires from, to and when');
|
|
36
|
+
}
|
|
37
|
+
if (!ids.has(item.from) || !ids.has(item.to)) throw new Error(`handoff references missing member: ${item.from} -> ${item.to}`);
|
|
38
|
+
return { from: item.from, to: item.to, when: item.when };
|
|
39
|
+
});
|
|
40
|
+
const edges = new Map(members.map((member) => [member.persona, [] as string[]]));
|
|
41
|
+
for (const edge of handoffs) edges.get(edge.from)!.push(edge.to);
|
|
42
|
+
const visiting = new Set<string>();
|
|
43
|
+
const visited = new Set<string>();
|
|
44
|
+
const visit = (id: string): void => {
|
|
45
|
+
if (visiting.has(id)) throw new Error(`handoff cycle at ${id}`);
|
|
46
|
+
if (visited.has(id)) return;
|
|
47
|
+
visiting.add(id);
|
|
48
|
+
for (const next of edges.get(id)!) visit(next);
|
|
49
|
+
visiting.delete(id);
|
|
50
|
+
visited.add(id);
|
|
51
|
+
};
|
|
52
|
+
for (const id of ids) visit(id);
|
|
53
|
+
return { 'team-set': raw['team-set'], members, handoffs };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function store(dir: string): string { return join(dir, '_team-sets'); }
|
|
57
|
+
function record(dir: string, name: string): string { return join(store(dir), `${name}.yaml`); }
|
|
58
|
+
function memberPath(dir: string, id: string): string { return join(dir, `${id}.yaml`); }
|
|
59
|
+
|
|
60
|
+
function recordedOwners(dir: string): Map<string, string> {
|
|
61
|
+
const owners = new Map<string, string>();
|
|
62
|
+
if (!existsSync(store(dir))) return owners;
|
|
63
|
+
for (const file of readdirSync(store(dir)).filter((name) => name.endsWith('.yaml'))) {
|
|
64
|
+
const data: unknown = parse(readFileSync(join(store(dir), file), 'utf8'));
|
|
65
|
+
if (!mapping(data) || !mapping(data.definition)) throw new Error(`invalid installed team-set: ${file}`);
|
|
66
|
+
const definition = readDefinition(stringify(data.definition));
|
|
67
|
+
const name = file.slice(0, -'.yaml'.length);
|
|
68
|
+
if (definition['team-set'] !== name) throw new Error(`invalid installed team-set: ${file}`);
|
|
69
|
+
for (const member of definition.members) {
|
|
70
|
+
const previous = owners.get(member.persona);
|
|
71
|
+
if (previous !== undefined) throw new Error(`persona has multiple team-set owners: ${member.persona} (${previous}, ${name})`);
|
|
72
|
+
owners.set(member.persona, name);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return owners;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function occupiedIds(dir: string): Set<string> {
|
|
79
|
+
const ids = new Set<string>();
|
|
80
|
+
if (!existsSync(dir)) return ids;
|
|
81
|
+
for (const file of readdirSync(dir).filter((name) => /\.ya?ml$/.test(name))) {
|
|
82
|
+
ids.add(file.replace(/\.ya?ml$/, ''));
|
|
83
|
+
const path = join(dir, file);
|
|
84
|
+
const parsed = parsePersonaYaml(readFileSync(path, 'utf8'), path);
|
|
85
|
+
if (parsed.ok) ids.add(parsed.profile.personaId);
|
|
86
|
+
}
|
|
87
|
+
return ids;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function addTeamSet(file: string, dir = resolveStatePersonaDir()): TeamSet {
|
|
91
|
+
const definition = readDefinition(readFileSync(file, 'utf8'));
|
|
92
|
+
if (existsSync(record(dir, definition['team-set']))) throw new Error(`team-set already exists: ${definition['team-set']}`);
|
|
93
|
+
const occupied = new Set([...occupiedIds(dir), ...occupiedIds(resolveRepositoryPersonaDir()), ...recordedOwners(dir).keys()]);
|
|
94
|
+
for (const member of definition.members) {
|
|
95
|
+
if (occupied.has(member.persona) || existsSync(memberPath(dir, member.persona))) throw new Error(`persona already exists: ${member.persona}`);
|
|
96
|
+
}
|
|
97
|
+
const files = definition.members.map((member) => {
|
|
98
|
+
const yaml = stringify({ personaId: member.persona, displayName: `${member.persona} · ${member.title}`,
|
|
99
|
+
systemPrompt: [`직함: ${member.title}`, `체크리스트 템플릿: ${member.checklistTemplate}`, '규칙:', ...member.rules.map((rule) => `- ${rule}`)].join('\n') }, { lineWidth: 0 });
|
|
100
|
+
const check = parsePersonaYaml(yaml, memberPath(dir, member.persona));
|
|
101
|
+
if (!check.ok) throw new Error(check.error.message);
|
|
102
|
+
return { persona: member.persona, yaml };
|
|
103
|
+
});
|
|
104
|
+
mkdirSync(dir, { recursive: true });
|
|
105
|
+
mkdirSync(store(dir), { recursive: true });
|
|
106
|
+
const created: string[] = [];
|
|
107
|
+
try {
|
|
108
|
+
for (const entry of files) {
|
|
109
|
+
const path = memberPath(dir, entry.persona);
|
|
110
|
+
writeFileSync(path, entry.yaml, { flag: 'wx' });
|
|
111
|
+
created.push(path);
|
|
112
|
+
}
|
|
113
|
+
writeFileSync(record(dir, definition['team-set']), stringify({ definition, files }, { lineWidth: 0 }), { flag: 'wx' });
|
|
114
|
+
} catch (error) {
|
|
115
|
+
for (const path of created) unlinkSync(path);
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
return definition;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function listTeamSets(dir = resolveStatePersonaDir()): TeamSet[] {
|
|
122
|
+
if (!existsSync(store(dir))) return [];
|
|
123
|
+
return readdirSync(store(dir)).filter((name) => name.endsWith('.yaml')).sort().map((name) => {
|
|
124
|
+
const data: unknown = parse(readFileSync(join(store(dir), name), 'utf8'));
|
|
125
|
+
if (!mapping(data) || !mapping(data.definition)) throw new Error(`invalid installed team-set: ${name}`);
|
|
126
|
+
return readDefinition(stringify(data.definition));
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function removeTeamSet(name: string, dir = resolveStatePersonaDir()): void {
|
|
131
|
+
if (!namePattern.test(name)) throw new Error('invalid team-set name');
|
|
132
|
+
const path = record(dir, name);
|
|
133
|
+
if (!existsSync(path)) throw new Error(`team-set not found: ${name}`);
|
|
134
|
+
const data: unknown = parse(readFileSync(path, 'utf8'));
|
|
135
|
+
if (!mapping(data) || !mapping(data.definition) || !Array.isArray(data.files)) throw new Error(`invalid installed team-set: ${name}`);
|
|
136
|
+
const definition = readDefinition(stringify(data.definition));
|
|
137
|
+
if (definition['team-set'] !== name || data.files.length !== definition.members.length) throw new Error(`invalid installed team-set: ${name}`);
|
|
138
|
+
const owners = recordedOwners(dir);
|
|
139
|
+
const filesToRemove: string[] = [];
|
|
140
|
+
for (let index = 0; index < definition.members.length; index++) {
|
|
141
|
+
const file: unknown = data.files[index];
|
|
142
|
+
const id = definition.members[index]!.persona;
|
|
143
|
+
if (!mapping(file) || file.persona !== id || typeof file.yaml !== 'string') {
|
|
144
|
+
throw new Error(`invalid installed team-set: ${name}`);
|
|
145
|
+
}
|
|
146
|
+
if (owners.get(id) !== name) throw new Error(`persona is not owned by team-set ${name}: ${id}`);
|
|
147
|
+
const personaPath = memberPath(dir, id);
|
|
148
|
+
if (existsSync(personaPath) && readFileSync(personaPath, 'utf8') === file.yaml) {
|
|
149
|
+
filesToRemove.push(personaPath);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
for (const personaPath of filesToRemove) unlinkSync(personaPath);
|
|
153
|
+
unlinkSync(path);
|
|
154
|
+
if (readdirSync(store(dir)).length === 0) rmdirSync(store(dir));
|
|
155
|
+
}
|
|
@@ -314,6 +314,20 @@ export async function installPlugin(spec: string, opts: InstallOptions = {}): Pr
|
|
|
314
314
|
const source = marketSpec(spec, opts)
|
|
315
315
|
? await fetchedMarketSource(spec, join(stage, 'package'), opts)
|
|
316
316
|
: resolvePluginSource(spec, join(stage, 'package'), opts);
|
|
317
|
+
const stagedManifest = join(stage, 'package', 'plugin.json');
|
|
318
|
+
if (existsSync(stagedManifest)) {
|
|
319
|
+
const rawManifest: unknown = JSON.parse(readFileSync(stagedManifest, 'utf8'));
|
|
320
|
+
if (rawManifest && typeof rawManifest === 'object' && !Array.isArray(rawManifest)) {
|
|
321
|
+
const rawExtensions = (rawManifest as Record<string, unknown>).extensions;
|
|
322
|
+
if (rawExtensions && typeof rawExtensions === 'object' && !Array.isArray(rawExtensions)) {
|
|
323
|
+
const elanous = (rawExtensions as Record<string, unknown>)['ai.elanous'];
|
|
324
|
+
if (elanous && typeof elanous === 'object' && !Array.isArray(elanous) &&
|
|
325
|
+
(elanous as Record<string, unknown>).researchDraft === true) {
|
|
326
|
+
fail('io', 'research draft only: implement and validate graph steps before installation');
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
317
331
|
const manifest: PluginManifest = loadPluginManifestFromDir(join(stage, 'package'), { id: source.expectedName ?? basename(spec) }).manifest;
|
|
318
332
|
if (!NAME.test(manifest.id) || !VERSION.test(manifest.version)) fail('io', 'invalid plugin name or version');
|
|
319
333
|
if (source.expectedName && (manifest.id !== source.expectedName || manifest.version !== source.expectedVersion)) fail('conflict', 'market name or version differs from manifest');
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { createHash, createPublicKey } from 'node:crypto';
|
|
2
|
+
import { signIndex, validateMarketplaceIndex, verifyIndex, type MarketplaceIndex } from '../../market/signed-index.js';
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { dirname, join, resolve, sep } from 'node:path';
|
|
6
|
+
import { userConfigPath } from '../../user-config.js';
|
|
7
|
+
import { loadPluginManifestFromDir } from '../core/manifest.js';
|
|
8
|
+
import { LEAK_MARKERS, loadPrivateRedactions, privateIdentifierMarkers, scanLeaks } from '../../../scripts/public-export.js';
|
|
9
|
+
|
|
10
|
+
export interface MarketBundleResult {
|
|
11
|
+
path: string;
|
|
12
|
+
artifact: string;
|
|
13
|
+
signature: 'signed' | 'signing-required';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function packageFiles(dir: string, prefix = ''): string[] {
|
|
17
|
+
const files: string[] = [];
|
|
18
|
+
for (const entry of readdirSync(join(dir, prefix), { withFileTypes: true })) {
|
|
19
|
+
const path = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
20
|
+
if (entry.name === '.git' || entry.name === '.elanous' || entry.name === 'node_modules') continue;
|
|
21
|
+
if (entry.isSymbolicLink() || (!entry.isFile() && !entry.isDirectory())) throw new Error(`unsafe market bundle entry: ${path}`);
|
|
22
|
+
if (entry.isDirectory()) files.push(...packageFiles(dir, path));
|
|
23
|
+
else files.push(path);
|
|
24
|
+
}
|
|
25
|
+
return files;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Prepare a local, reviewable official-market index and tar artifact; never publishes either file. */
|
|
29
|
+
export function bundleInstalledWizardPlugin(installedPath: string, outputDir: string, configPath = userConfigPath()): MarketBundleResult {
|
|
30
|
+
const source = resolve(installedPath);
|
|
31
|
+
const manifestFile = join(source, 'plugin.json');
|
|
32
|
+
if (!lstatSync(source).isDirectory() || !lstatSync(manifestFile).isFile() || lstatSync(manifestFile).isSymbolicLink()) {
|
|
33
|
+
throw new Error('market bundle requires an installed plugin.json');
|
|
34
|
+
}
|
|
35
|
+
const raw: unknown = JSON.parse(readFileSync(manifestFile, 'utf8'));
|
|
36
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw) || typeof (raw as { name?: unknown }).name !== 'string') {
|
|
37
|
+
throw new Error('invalid market plugin manifest name');
|
|
38
|
+
}
|
|
39
|
+
const { manifest, inferred } = loadPluginManifestFromDir(source, { id: (raw as { name: string }).name });
|
|
40
|
+
if (inferred || !/^[a-z0-9][a-z0-9-]{1,39}$/.test(manifest.id) ||
|
|
41
|
+
!/^[0-9]+\.[0-9]+\.[0-9]+(?:[-+][a-zA-Z0-9.-]+)?$/.test(manifest.version)) {
|
|
42
|
+
throw new Error('invalid market plugin manifest name or version');
|
|
43
|
+
}
|
|
44
|
+
if ((raw as { extensions?: { 'ai.elanous'?: { researchDraft?: boolean } } }).extensions?.['ai.elanous']?.researchDraft === true) {
|
|
45
|
+
throw new Error('research draft cannot be bundled for market');
|
|
46
|
+
}
|
|
47
|
+
const files = packageFiles(source);
|
|
48
|
+
if (!files.length) throw new Error('empty plugin bundle');
|
|
49
|
+
if (manifest.id !== (raw as { name: string }).name) throw new Error('market plugin manifest name mismatch');
|
|
50
|
+
for (const asset of [manifest.main, ...(manifest.contributes.graphs ?? []), ...(manifest.contributes.vocab ?? []), ...(manifest.contributes.nodes ?? [])]) {
|
|
51
|
+
if (asset === './plugin.ts' && !('main' in (raw as object))) continue;
|
|
52
|
+
if (!files.includes(asset.replace(/^\.\//, ''))) throw new Error(`market manifest asset missing: ${asset}`);
|
|
53
|
+
}
|
|
54
|
+
const redactions = loadPrivateRedactions();
|
|
55
|
+
if (!redactions) throw new Error('private export redaction list unavailable; market bundle refused');
|
|
56
|
+
const hits = scanLeaks(source, files, [...LEAK_MARKERS, ...privateIdentifierMarkers(redactions)]);
|
|
57
|
+
if (hits.length) throw new Error(`market bundle leak: ${hits.map(hit => `${hit.file}:${hit.line} ${hit.marker}`).join(', ')}`);
|
|
58
|
+
const config: unknown = existsSync(configPath) ? JSON.parse(readFileSync(configPath, 'utf8')) : {};
|
|
59
|
+
if (!config || typeof config !== 'object' || Array.isArray(config)) throw new Error('invalid market signing config');
|
|
60
|
+
const signing = (config as { market?: { signing?: { keyId?: unknown; privateKey?: unknown } } }).market?.signing;
|
|
61
|
+
const hasKey = signing?.privateKey !== undefined || signing?.keyId !== undefined;
|
|
62
|
+
if (hasKey && (typeof signing?.privateKey !== 'string' || !signing.privateKey.trim() || typeof signing.keyId !== 'string' || !signing.keyId.trim())) {
|
|
63
|
+
throw new Error('market signing requires configured keyId and privateKey');
|
|
64
|
+
}
|
|
65
|
+
const target = resolve(outputDir);
|
|
66
|
+
if (target === source || target.startsWith(`${source}${sep}`) || source.startsWith(`${target}${sep}`)) throw new Error('market bundle output must be outside plugin directory');
|
|
67
|
+
if (existsSync(target)) throw new Error(`market bundle already exists: ${target}`);
|
|
68
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
69
|
+
mkdirSync(target);
|
|
70
|
+
try {
|
|
71
|
+
const artifactKey = `${manifest.id}-${manifest.version}.tgz`;
|
|
72
|
+
const artifact = join(target, artifactKey);
|
|
73
|
+
const tar = spawnSync('tar', ['-czf', artifact, '-C', source, '--', ...files], { encoding: 'utf8' });
|
|
74
|
+
if (tar.status !== 0 || tar.error) throw new Error(`market archive failed: ${tar.error?.message ?? tar.stderr}`);
|
|
75
|
+
const bytes = readFileSync(artifact);
|
|
76
|
+
const index: MarketplaceIndex = { name: 'elanous', interface: { displayName: 'Elanous' }, sequence: 1, plugins: [{
|
|
77
|
+
name: manifest.id, version: manifest.version, description: manifest.description,
|
|
78
|
+
source: { source: 'local', path: '.' },
|
|
79
|
+
artifact: { key: artifactKey, sha256: createHash('sha256').update(bytes).digest('hex'), bytes: bytes.length },
|
|
80
|
+
'ai.elanous': {
|
|
81
|
+
capabilities: manifest.capabilities.map(capability => capability.kind),
|
|
82
|
+
connectors: (manifest.contributes.connectors ?? []).map(connector => ({
|
|
83
|
+
id: connector.id, kind: 'user-config', userConfig: (connector.userConfig ?? connector.fields?.map(field => ({
|
|
84
|
+
key: field.name, label: field.name, secret: field.secret === true,
|
|
85
|
+
})) ?? []).map(field => ({ key: field.key, label: field.label ?? field.key, secret: field.secret === true })),
|
|
86
|
+
})),
|
|
87
|
+
graphs: manifest.contributes.graphs ?? [], vocab: manifest.contributes.vocab ?? [],
|
|
88
|
+
pricing: { model: 'free' },
|
|
89
|
+
},
|
|
90
|
+
}] };
|
|
91
|
+
const invalid = validateMarketplaceIndex(index);
|
|
92
|
+
if (invalid) throw new Error(`invalid market index: ${invalid}`);
|
|
93
|
+
const indexBytes = Buffer.from(JSON.stringify(index, null, 2) + '\n');
|
|
94
|
+
writeFileSync(join(target, 'marketplace.json'), indexBytes);
|
|
95
|
+
if (hasKey) {
|
|
96
|
+
const signatureText = signIndex(indexBytes, signing!.privateKey as string, signing!.keyId as string);
|
|
97
|
+
const check = verifyIndex({ marketplaceBytes: indexBytes, signatureText, trustedKeys: [{
|
|
98
|
+
keyId: signing!.keyId as string,
|
|
99
|
+
publicKey: createPublicKey(signing!.privateKey as string).export({ format: 'der', type: 'spki' }).subarray(12).toString('base64'),
|
|
100
|
+
}] });
|
|
101
|
+
if (!check.ok) throw new Error(`market index signature invalid: ${check.detail}`);
|
|
102
|
+
writeFileSync(join(target, 'index.sig'), signatureText);
|
|
103
|
+
}
|
|
104
|
+
return { path: target, artifact, signature: hasKey ? 'signed' : 'signing-required' };
|
|
105
|
+
} catch (error) {
|
|
106
|
+
rmSync(target, { recursive: true, force: true });
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -1,36 +1,67 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
1
3
|
import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
4
|
import { tmpdir } from 'node:os';
|
|
3
5
|
import { dirname, join, relative, resolve, sep } from 'node:path';
|
|
4
6
|
import { parse as parseYaml } from 'yaml';
|
|
5
7
|
import { elanousStateRoot } from '../../autopilot/state-paths.js';
|
|
6
|
-
import { debug } from '../../debug/log.js';
|
|
8
|
+
import { debug, redactSecretText, redactSecrets } from '../../debug/log.js';
|
|
9
|
+
import { dispatchOmniSearch } from '../../skills/tools/omni-search.js';
|
|
7
10
|
import { runGraph } from '../../graph-runner/runner.js';
|
|
8
11
|
import { parseGraphTemplateYaml } from '../../self-implement/graph-yaml.js';
|
|
9
12
|
import { installPlugin } from '../install/plugin-install.js';
|
|
13
|
+
import { generateWizardFiles, type WizardResearchDraft } from './wizard-generate.js';
|
|
14
|
+
import { bundleInstalledWizardPlugin, type MarketBundleResult } from './market-bundle.js';
|
|
10
15
|
|
|
11
16
|
const CAPABILITIES = ['fs:workdir', 'proc:bun', 'proc:elanous'];
|
|
12
17
|
const isRecord = (value: unknown): value is Record<string, unknown> => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
13
18
|
|
|
19
|
+
export interface WizardStepEvent {
|
|
20
|
+
ts: string;
|
|
21
|
+
wizardId: string;
|
|
22
|
+
step: 'request' | 'research' | 'draft' | 'validate' | 'install' | 'done';
|
|
23
|
+
text: string;
|
|
24
|
+
detail?: unknown;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ResearchSource { title: string; url: string; snippet: string; source: 'omni-crawl' | 'aside' }
|
|
28
|
+
export interface PluginDraft {
|
|
29
|
+
connectors: Array<{ name: string; use: string; evidence: string[]; missingCredentials: string[] }>;
|
|
30
|
+
skills: Array<{ name: string; use: string; evidence: string[] }>;
|
|
31
|
+
graph: { use: string; nodes: string[]; evidence: string[] };
|
|
32
|
+
research: { sources: ResearchSource[]; unavailable: string[] };
|
|
33
|
+
}
|
|
34
|
+
|
|
14
35
|
export interface MakePluginDeps {
|
|
15
36
|
codex: (dir: string, prompt: string) => Promise<void>;
|
|
16
37
|
install?: typeof installPlugin;
|
|
38
|
+
bundle?: typeof bundleInstalledWizardPlugin;
|
|
17
39
|
runGraph?: typeof runGraph;
|
|
40
|
+
webSearch?: (query: string) => Promise<{ sources: ResearchSource[]; errors?: string[] }>;
|
|
41
|
+
memorySearch?: (query: string) => Promise<ResearchSource[]>;
|
|
42
|
+
asideBin?: string;
|
|
43
|
+
onEvent?: (event: WizardStepEvent) => void;
|
|
18
44
|
}
|
|
19
45
|
export interface MakePluginOptions {
|
|
20
46
|
request: string;
|
|
47
|
+
draftFile?: string;
|
|
21
48
|
name?: string;
|
|
22
49
|
parentDir?: string;
|
|
23
50
|
run?: boolean;
|
|
51
|
+
/** Optional local output directory for a reviewable, unpublished market bundle. */
|
|
52
|
+
marketBundleDir?: string;
|
|
24
53
|
input?: unknown;
|
|
25
54
|
deps?: MakePluginDeps;
|
|
26
55
|
}
|
|
27
56
|
export interface MakePluginResult {
|
|
28
|
-
status: 'installed' | 'ran' | 'failed';
|
|
57
|
+
status: 'draft' | 'installed' | 'ran' | 'failed';
|
|
29
58
|
dir: string;
|
|
30
59
|
plugin: string;
|
|
31
60
|
graph: string;
|
|
32
61
|
errors: string[];
|
|
33
62
|
runStatus?: Awaited<ReturnType<typeof runGraph>>['status'];
|
|
63
|
+
marketBundle?: MarketBundleResult;
|
|
64
|
+
draft: PluginDraft;
|
|
34
65
|
timings: { scaffold: number; write: number; validate: number; repair?: number; install: number; run?: number };
|
|
35
66
|
}
|
|
36
67
|
|
|
@@ -172,8 +203,136 @@ export async function validatePluginDir(dir: string): Promise<string[]> {
|
|
|
172
203
|
return errors;
|
|
173
204
|
}
|
|
174
205
|
|
|
175
|
-
|
|
176
|
-
const
|
|
206
|
+
async function searchWebForPlugin(query: string): Promise<{ sources: ResearchSource[]; errors?: string[] }> {
|
|
207
|
+
const sources: ResearchSource[] = [];
|
|
208
|
+
const errors: string[] = [];
|
|
209
|
+
try {
|
|
210
|
+
const found = await dispatchOmniSearch({ query, limit: 5 }, { onSource: hit => {
|
|
211
|
+
sources.push({ title: hit.title, url: hit.url, snippet: hit.snippet ?? '', source: 'omni-crawl' });
|
|
212
|
+
} });
|
|
213
|
+
errors.push(...Object.entries(found.metadata.perEngine).flatMap(([engine, status]) => status.error ? [`${engine}: ${status.error}`] : []));
|
|
214
|
+
if (!Object.keys(found.metadata.perEngine).length) errors.push('omni-crawl: 검색 제공자 없음');
|
|
215
|
+
} catch (error) { errors.push(`웹 검색: ${String(error)}`); }
|
|
216
|
+
try {
|
|
217
|
+
const script = resolve(dirname(import.meta.path), '../../../skills/omni-crawl/scripts/main.ts');
|
|
218
|
+
if (existsSync(script)) {
|
|
219
|
+
const stdout = await new Promise<string>((resolveOutput, rejectOutput) => {
|
|
220
|
+
const child = spawn(process.execPath, [script, query, '--engine', 'firecrawl', '--json', '--no-save'], { stdio: ['ignore', 'pipe', 'ignore'] });
|
|
221
|
+
let output = '';
|
|
222
|
+
const timer = setTimeout(() => { child.kill(); rejectOutput(new Error('크롤 시간 초과')); }, 20_000);
|
|
223
|
+
child.stdout.setEncoding('utf8');
|
|
224
|
+
child.stdout.on('data', (chunk: string) => { output += chunk; if (output.length > 1_000_000) child.kill(); });
|
|
225
|
+
child.on('error', error => { clearTimeout(timer); rejectOutput(error); });
|
|
226
|
+
child.on('close', code => {
|
|
227
|
+
clearTimeout(timer);
|
|
228
|
+
if (code !== 0) rejectOutput(new Error(`크롤 종료 코드 ${code}`));
|
|
229
|
+
else resolveOutput(output);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
const match = stdout.match(/---BEGIN_OMNI_CRAWL_JSON---\s*([\s\S]*?)\s*---END_OMNI_CRAWL_JSON---/);
|
|
233
|
+
if (!match) throw new Error('크롤 JSON 결과 없음');
|
|
234
|
+
const payload: unknown = JSON.parse(match[1]);
|
|
235
|
+
const results = isRecord(payload) && Array.isArray(payload.results) ? payload.results : [];
|
|
236
|
+
let count = 0;
|
|
237
|
+
for (const result of results) {
|
|
238
|
+
if (!isRecord(result) || !Array.isArray(result.items)) continue;
|
|
239
|
+
for (const item of result.items) {
|
|
240
|
+
if (!isRecord(item) || typeof item.url !== 'string' || !/^https?:\/\//.test(item.url)) continue;
|
|
241
|
+
count++;
|
|
242
|
+
const source = sources.find(source => source.url === item.url);
|
|
243
|
+
const text = typeof item.text === 'string' ? item.text.slice(0, 1800) : '';
|
|
244
|
+
if (source) source.snippet = text || source.snippet;
|
|
245
|
+
else sources.push({ title: typeof item.title === 'string' ? item.title : item.url, url: item.url, snippet: text, source: 'omni-crawl' });
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (!count) errors.push('omni-crawl: 크롤 결과 없음 또는 검색 실패');
|
|
249
|
+
} else errors.push('omni-crawl: 실행 스크립트 없음');
|
|
250
|
+
} catch (error) { errors.push(`omni-crawl: ${String(error)}`); }
|
|
251
|
+
return { sources, errors };
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async function searchLocalMemory(query: string, bin = 'aside'): Promise<ResearchSource[]> {
|
|
255
|
+
const prompt = `Search your local memory for the following plugin request (do not search the web): ${JSON.stringify(query)}. Return ONLY JSON: {"sources":[{"title":"note title","url":"local note URI or path","snippet":"relevant excerpt"}]}. Include at most 5 actual matching notes with their real reference URI or path; if none, return {"sources":[]}. Do not invent notes or references.`;
|
|
256
|
+
const stdout = await new Promise<string>((resolveOutput, rejectOutput) => {
|
|
257
|
+
const child = spawn(bin, ['exec', '--effort', 'low', prompt], { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
258
|
+
let output = '';
|
|
259
|
+
let errorOutput = '';
|
|
260
|
+
let finished = false;
|
|
261
|
+
const finish = (error?: Error): void => {
|
|
262
|
+
if (finished) return;
|
|
263
|
+
finished = true;
|
|
264
|
+
clearTimeout(timer);
|
|
265
|
+
if (error) rejectOutput(error);
|
|
266
|
+
else resolveOutput(output);
|
|
267
|
+
};
|
|
268
|
+
const timer = setTimeout(() => { child.kill(); finish(new Error('검색 시간 초과')); }, 20_000);
|
|
269
|
+
child.stdout.setEncoding('utf8');
|
|
270
|
+
child.stderr.setEncoding('utf8');
|
|
271
|
+
child.stdout.on('data', (chunk: string) => {
|
|
272
|
+
output += chunk;
|
|
273
|
+
if (output.length > 100_000) { child.kill(); finish(new Error('검색 결과 크기 초과')); }
|
|
274
|
+
});
|
|
275
|
+
child.stderr.on('data', (chunk: string) => { errorOutput = (errorOutput + chunk).slice(-500); });
|
|
276
|
+
child.on('error', error => finish(error));
|
|
277
|
+
child.on('close', code => finish(code === 0 ? undefined : new Error(`검색 종료 코드 ${code}: ${errorOutput.trim()}`)));
|
|
278
|
+
});
|
|
279
|
+
const parsed: unknown = JSON.parse(stdout.trim());
|
|
280
|
+
if (!isRecord(parsed) || !Array.isArray(parsed.sources)) throw new Error('검색 결과 JSON 에 sources 배열 없음');
|
|
281
|
+
return parsed.sources.slice(0, 5).filter((source): source is Record<string, string> =>
|
|
282
|
+
isRecord(source) && typeof source.title === 'string' && typeof source.url === 'string' && !!source.url.trim() && typeof source.snippet === 'string')
|
|
283
|
+
.map(source => ({ title: source.title.slice(0, 200), url: source.url.slice(0, 1000), snippet: source.snippet.slice(0, 800), source: 'aside' }));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function validResearchSource(source: ResearchSource): boolean {
|
|
287
|
+
if (!source.url.trim()) return false;
|
|
288
|
+
if (source.source === 'aside' && !/^https?:\/\//i.test(source.url)) return true;
|
|
289
|
+
try {
|
|
290
|
+
const url = new URL(source.url);
|
|
291
|
+
return (url.protocol === 'https:' || url.protocol === 'http:') && !!url.hostname;
|
|
292
|
+
} catch { return false; }
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function wizardDraftFromResearch(request: string, draft: PluginDraft): WizardResearchDraft {
|
|
296
|
+
const used = new Set<string>();
|
|
297
|
+
const connectors = draft.connectors.filter(connector => connector.name !== '미확인').map(connector => {
|
|
298
|
+
const base = connector.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 24).replace(/-$/, '') || 'connector';
|
|
299
|
+
let id = base;
|
|
300
|
+
for (let index = 2; used.has(id); index++) id = `${base}-${index}`;
|
|
301
|
+
used.add(id);
|
|
302
|
+
return { id, credentials: connector.missingCredentials
|
|
303
|
+
.filter(name => /^[A-Za-z_][A-Za-z0-9_-]*$/.test(name))
|
|
304
|
+
.map(name => ({ name })) };
|
|
305
|
+
});
|
|
306
|
+
const citedSkills = draft.skills.filter(skill => skill.name !== '미확인');
|
|
307
|
+
return { description: request, connectors,
|
|
308
|
+
skill: { description: request, instructions: request + (citedSkills.length
|
|
309
|
+
? `\n\nResearch sources:\n${citedSkills.map(skill => skill.evidence.join(', ')).join('\n')}` : ''), requires: [] } };
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function buildDraft(request: string, sources: ResearchSource[], unavailable: string[]): PluginDraft {
|
|
313
|
+
const evidence = [...new Set(sources.map(source => source.url).filter(Boolean))];
|
|
314
|
+
const connectors = sources.filter(source => /api|oauth|webhook|integration|connector|연동|인증/i.test(`${source.title} ${source.snippet}`))
|
|
315
|
+
.slice(0, 3).map(source => {
|
|
316
|
+
const name = /^https?:\/\//.test(source.url) ? new URL(source.url).hostname : source.title;
|
|
317
|
+
const fields = [...new Set((`${source.title} ${source.snippet}`.match(/\b[A-Z][A-Z0-9_]*(?:API_KEY|TOKEN|CLIENT_ID|CLIENT_SECRET)\b/g) ?? []))];
|
|
318
|
+
return { name, use: source.title, evidence: [source.url], missingCredentials: fields.length ? fields : ['자격 확인 필요'] };
|
|
319
|
+
});
|
|
320
|
+
const skills = sources.filter(source => /skill|스킬|workflow|작업/i.test(`${source.title} ${source.snippet}`))
|
|
321
|
+
.slice(0, 3).map(source => ({ name: source.title, use: source.snippet.slice(0, 200) || request, evidence: [source.url] }));
|
|
322
|
+
const graphSource = sources.find(source => /graph|workflow|pipeline|그래프|흐름/i.test(`${source.title} ${source.snippet}`));
|
|
323
|
+
const graphNodes = [...new Set((graphSource?.snippet.match(/\b(?:fetch|collect|extract|transform|process|analy[sz]e|report|publish)\b|수집|가공|분석|보고|발행/gi) ?? [])
|
|
324
|
+
.map(node => node.toLowerCase()))].slice(0, 3);
|
|
325
|
+
if (graphNodes.length < 2) graphNodes.push(...['fetch', 'process', 'report'].filter(node => !graphNodes.includes(node)).slice(0, 3 - graphNodes.length));
|
|
326
|
+
return {
|
|
327
|
+
connectors: connectors.length ? connectors : [{ name: '미확인', use: `요청에 필요한 커넥터 조사: ${request}`, evidence, missingCredentials: ['자격 확인 필요'] }],
|
|
328
|
+
skills: skills.length ? skills : [{ name: '미확인', use: `요청에 필요한 스킬 조사: ${request}`, evidence }],
|
|
329
|
+
graph: { use: request, nodes: graphNodes, evidence },
|
|
330
|
+
research: { sources, unavailable },
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export async function makePlugin({ request, draftFile, name, parentDir, run, marketBundleDir, input, deps }: MakePluginOptions): Promise<MakePluginResult> {
|
|
335
|
+
const slug = (name ?? request).toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 31).replace(/-$/, '') || `plugin-${Date.now()}`;
|
|
177
336
|
if (!request.trim() || !/^[a-z0-9][a-z0-9-]{1,39}$/.test(slug)) throw new Error(`invalid plugin request or name: ${slug}`);
|
|
178
337
|
if (name !== undefined && !/^[a-z0-9][a-z0-9-]{1,31}$/.test(name)) throw new Error(`invalid --name slug: ${name}`);
|
|
179
338
|
const root = elanousStateRoot();
|
|
@@ -182,26 +341,108 @@ export async function makePlugin({ request, name, parentDir, run, input, deps }:
|
|
|
182
341
|
const dir = join(parent, slug);
|
|
183
342
|
if (existsSync(dir)) throw new Error(`plugin directory already exists: ${dir}`);
|
|
184
343
|
const timings: MakePluginResult['timings'] = { scaffold: 0, write: 0, validate: 0, install: 0 };
|
|
185
|
-
const
|
|
344
|
+
const wizardId = randomUUID();
|
|
345
|
+
const result: MakePluginResult = { status: 'failed', dir, plugin: slug, graph: join(dir, 'graphs', `${slug}.yaml`), errors: [], timings,
|
|
346
|
+
draft: buildDraft(request, [], []) };
|
|
347
|
+
const emit = (stage: WizardStepEvent['step'], text: string, detail?: unknown): void => {
|
|
348
|
+
const event: WizardStepEvent = { ts: new Date().toISOString(), wizardId, step: stage, text: redactSecretText(text.slice(0, 500)),
|
|
349
|
+
...(detail === undefined ? {} : { detail: redactSecrets(detail) }) };
|
|
350
|
+
try { debug.log('wizard.step', 'wizard.step', event); } catch { /* Logging cannot stop make. */ }
|
|
351
|
+
try { deps?.onEvent?.(event); } catch { /* An observation sink must not stop installation. */ }
|
|
352
|
+
};
|
|
186
353
|
const step = async (stage: keyof MakePluginResult['timings'], action: () => void | Promise<void>): Promise<void> => {
|
|
187
354
|
const start = performance.now();
|
|
188
355
|
try { await action(); }
|
|
189
356
|
finally { const ms = Math.round(performance.now() - start); timings[stage] = ms; debug.log('plugin.maker', stage, { ms, errors: result.errors }); }
|
|
190
357
|
};
|
|
191
358
|
try {
|
|
192
|
-
|
|
359
|
+
emit('request', request);
|
|
360
|
+
const settled = await Promise.allSettled([
|
|
361
|
+
Promise.resolve().then(() => (deps?.webSearch ?? (process.env.NODE_ENV === 'test' ? async () => ({ sources: [], errors: ['omni-crawl: 시험 모드'] }) : searchWebForPlugin))(request)),
|
|
362
|
+
Promise.resolve().then(() => (deps?.memorySearch ?? (process.env.NODE_ENV === 'test' && !deps?.asideBin ? async () => [] : (query: string) => searchLocalMemory(query, deps?.asideBin)))(request)),
|
|
363
|
+
]);
|
|
364
|
+
const unavailable: string[] = [];
|
|
365
|
+
const sources: ResearchSource[] = [];
|
|
366
|
+
if (settled[0].status === 'fulfilled') {
|
|
367
|
+
sources.push(...settled[0].value.sources);
|
|
368
|
+
unavailable.push(...(settled[0].value.errors ?? []));
|
|
369
|
+
if (!settled[0].value.sources.length) unavailable.push('omni-crawl: 검색 결과 없음');
|
|
370
|
+
} else unavailable.push(`omni-crawl: ${String(settled[0].reason)}`);
|
|
371
|
+
if (settled[1].status === 'fulfilled') {
|
|
372
|
+
sources.push(...settled[1].value);
|
|
373
|
+
if (!settled[1].value.length) unavailable.push('aside: 검색 결과 없음');
|
|
374
|
+
} else unavailable.push(`aside: ${String(settled[1].reason)}`);
|
|
375
|
+
for (let i = sources.length - 1; i >= 0; i--) {
|
|
376
|
+
if (!validResearchSource(sources[i])) {
|
|
377
|
+
unavailable.push(`${sources[i].source}: 잘못된 출처 URL: ${sources[i].url}`);
|
|
378
|
+
sources.splice(i, 1);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
emit('research', sources.length ? `${sources.length}건 조사` : `조사 없음 · ${unavailable.join('; ')}`, { sources, unavailable });
|
|
382
|
+
result.draft = buildDraft(request, sources, unavailable);
|
|
383
|
+
emit('draft', '커넥터·스킬·그래프 초안', result.draft);
|
|
384
|
+
await step('scaffold', () => { mkdirSync(parent, { recursive: true }); mkdirSync(dir); if (draftFile === undefined) scaffold(dir, slug, request); });
|
|
193
385
|
const codex = deps?.codex ?? codexWrite;
|
|
194
386
|
const prompt = `요청 원문:\n${request}\n\n이 폴더의 뼈대를 수정해 작동하는 로컬 그래프 플러그인을 작성하라. plugin.json extensions["ai.elanous"].graphs 와 capabilities 는 유지하고, graphs/<id>.yaml 은 entry_node, terminal_nodes: [done, failed], nodes 의 recipe: 'cmd:<id>', edges 의 on: outcome, map: { ok, fail } 을 써라. graphs/recipes.yaml 에 모든 cmd:<id> 의 command: 'bun "$ELANOUS_GRAPH_DIR/run-step.ts" <id>' 와 timeout_ms 를 선언하라. graphs/run-step.ts 의 각 단계 stdout 마지막 줄은 JSON {outcome, ...} 이며 이전 출력은 ELANOUS_GRAPH_CONTEXT JSON 의 outputs 에 있다. src/ import 금지. 엘라누스 기능은 CLI elanous ask --json 또는 elanous research --json 로만 사용. 아무것도 보내지 말 것. 실행 노드는 2~6개. examples/input.json 에 실제로 돌릴 입력을 넣을 것. 폴더 밖에는 쓰지 말 것.`;
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
387
|
+
const researchedPrompt = `${prompt}\n\n조사 기반 초안 (확인되지 않은 자격을 지어내지 말 것):\n${JSON.stringify(result.draft, null, 2)}`;
|
|
388
|
+
if (draftFile !== undefined) {
|
|
389
|
+
await step('write', () => {
|
|
390
|
+
const draft = JSON.parse(readFileSync(resolve(draftFile), 'utf8')) as WizardResearchDraft;
|
|
391
|
+
generateWizardFiles(dir, slug, draft);
|
|
392
|
+
});
|
|
393
|
+
} else {
|
|
394
|
+
await step('write', async () => {
|
|
395
|
+
generateWizardFiles(dir, slug, wizardDraftFromResearch(request, result.draft));
|
|
396
|
+
await codex(dir, `${researchedPrompt}\n\n생성된 커넥터 선언과 skills/${slug}/SKILL.md 를 보존하고, researchDraft 그래프의 실패 단계는 실제 요청 처리로 구현하라. 설치 전에 실행 예제로 그래프를 검증하며, 실패하면 플러그인을 설치하지 않는다.`);
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
emit('validate', '플러그인 검사 시작');
|
|
400
|
+
const validate = async (): Promise<void> => {
|
|
401
|
+
if (draftFile === undefined) {
|
|
402
|
+
const manifestPath = join(dir, 'plugin.json');
|
|
403
|
+
const raw: unknown = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
404
|
+
const extension = isRecord(raw) && isRecord(raw.extensions) ? raw.extensions['ai.elanous'] : undefined;
|
|
405
|
+
if (isRecord(extension)) {
|
|
406
|
+
extension.researchDraft = true;
|
|
407
|
+
writeFileSync(manifestPath, JSON.stringify(raw, null, 2) + '\n');
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
result.errors = await validatePluginDir(dir);
|
|
411
|
+
if (draftFile === undefined && !result.errors.length) {
|
|
412
|
+
const probeRoot = mkdtempSync(join(tmpdir(), 'elanous-wizard-probe-'));
|
|
413
|
+
try {
|
|
414
|
+
const example = JSON.parse(readFileSync(join(dir, 'examples', 'input.json'), 'utf8')) as unknown;
|
|
415
|
+
const probe = await runGraph(result.graph, { input: example, deps: { root: probeRoot } });
|
|
416
|
+
if (probe.status !== 'done' || probe.nodes.some(node => !node.ok)) {
|
|
417
|
+
result.errors.push(`research graph validation failed: ${probe.status}`);
|
|
418
|
+
}
|
|
419
|
+
} finally { rmSync(probeRoot, { recursive: true, force: true }); }
|
|
420
|
+
if (!result.errors.length) {
|
|
421
|
+
const manifestPath = join(dir, 'plugin.json');
|
|
422
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as { extensions: { 'ai.elanous': { researchDraft?: boolean } } };
|
|
423
|
+
delete manifest.extensions['ai.elanous'].researchDraft;
|
|
424
|
+
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
await step('validate', validate);
|
|
429
|
+
if (result.errors.length && draftFile === undefined) {
|
|
430
|
+
await step('repair', () => codex(dir, `${researchedPrompt}\n\n아래 오류를 모두 수리하라:\n${result.errors.join('\n')}`));
|
|
431
|
+
await step('validate', validate);
|
|
200
432
|
}
|
|
201
433
|
if (result.errors.length) return result;
|
|
434
|
+
if (draftFile !== undefined) {
|
|
435
|
+
result.status = run ? 'failed' : 'draft';
|
|
436
|
+
if (run) result.errors.push('research draft only: implement graph steps before --run; no plugin was installed');
|
|
437
|
+
return result;
|
|
438
|
+
}
|
|
202
439
|
let installedPath = '';
|
|
440
|
+
emit('install', '플러그인 설치 시작');
|
|
203
441
|
await step('install', async () => { installedPath = (await (deps?.install ?? installPlugin)(dir, { yes: true, root })).path; });
|
|
204
442
|
result.status = 'installed';
|
|
443
|
+
if (marketBundleDir !== undefined) {
|
|
444
|
+
result.marketBundle = (deps?.bundle ?? bundleInstalledWizardPlugin)(installedPath, marketBundleDir);
|
|
445
|
+
}
|
|
205
446
|
const graph = JSON.parse(readFileSync(join(dir, 'plugin.json'), 'utf8')).extensions['ai.elanous'].graphs[0] as string;
|
|
206
447
|
result.graph = resolve(installedPath, graph);
|
|
207
448
|
if (run) {
|
|
@@ -215,6 +456,8 @@ export async function makePlugin({ request, name, parentDir, run, input, deps }:
|
|
|
215
456
|
} catch (error) {
|
|
216
457
|
result.status = 'failed';
|
|
217
458
|
result.errors.push(error instanceof Error ? error.message : String(error));
|
|
459
|
+
} finally {
|
|
460
|
+
emit('done', result.status, { errors: result.errors });
|
|
218
461
|
}
|
|
219
462
|
return result;
|
|
220
463
|
}
|