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
package/src/cli/release-cli.ts
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
// elanous release tag --version <x.y.z> --source <commit> [--yes]
|
|
6
6
|
// elanous release verify [--version <x.y.z>]
|
|
7
7
|
// elanous release notes --from <ref> [--to <ref>]
|
|
8
|
-
// elanous release run --version <x.y.z> [--dry-run] [--json] [--if-ready]
|
|
8
|
+
// elanous release run --version <x.y.z> [--cut-commit <sha>] [--dry-run] [--json] [--if-ready]
|
|
9
|
+
// elanous release cut-branch --version <x.y.z> --base <sha> --pick <sha>... [--dry-run]
|
|
9
10
|
//
|
|
10
11
|
// 🩸 계기(2026-09-25 v0.1.0 첫 공개): 손으로 밟은 절차에서 둘을 빠뜨릴 뻔했다 — 공개본 git 커밋(판 커밋이 공개본 커밋이 된다) ·
|
|
11
12
|
// PWA 빌드(빌드 산출은 공개본에 안 실린다 → 빠뜨리면 «웹 화면 없는 판»). 절차를 명령으로 굳힌다.
|
|
@@ -23,10 +24,13 @@ import { effectiveInstanceRoot, releaseLedgerRoot } from '../instance/resolve.js
|
|
|
23
24
|
import { getElanousConfigDirOverride } from '../elanous-config-dir.js';
|
|
24
25
|
import { envLiteral } from '../platform/env-literal.js';
|
|
25
26
|
import { userConfigPath } from '../user-config.js';
|
|
26
|
-
import { addItem, devVersion, listChecklist, removeItem, seedFromRoadmap, setItem, summarizeChecklist, type ChecklistStatus, type ChecklistDisposition, type ChecklistKind } from '../release-loop/checklist.js';
|
|
27
|
+
import { addItem, claimItem, decodeClaimHistoryEntry, devVersion, listChecklist, ownerMatches, parseOwner, parityGap, removeItem, seedFromRoadmap, setItem, summarizeChecklist, type ChecklistStatus, type ChecklistDisposition, type ChecklistKind } from '../release-loop/checklist.js';
|
|
27
28
|
import * as features from '../release-loop/feature-store.js';
|
|
29
|
+
import { formatSchedule, getSchedule, listSchedules, setSchedule } from '../release-loop/release-schedule.js';
|
|
28
30
|
import { writeStdoutJson } from './stdout-json.js';
|
|
31
|
+
import { CliUserError } from './cli-user-error.js';
|
|
29
32
|
import { runUnattendedRelease, type UnattendedReleaseDeps } from '../../scripts/release-loop/unattended-release.js';
|
|
33
|
+
import { cutReleaseBranch } from '../../scripts/release-loop/cut-branch.js';
|
|
30
34
|
import { releaseReadiness } from '../../scripts/release-loop/release-readiness.js';
|
|
31
35
|
import { runReleaseIfReady } from './release-run-if-ready.js';
|
|
32
36
|
|
|
@@ -468,15 +472,23 @@ function checklistCodenames(): Record<string, string> {
|
|
|
468
472
|
function checklistVersion(input: string | undefined, codenames: Record<string, string>): string {
|
|
469
473
|
const v = input ?? devVersion().replace(/-dev\.\d+$/, '');
|
|
470
474
|
const resolved = isReleaseVersion(v) ? v : Object.entries(codenames).find(([, name]) => name === v)?.[0] ?? v;
|
|
471
|
-
if (!isReleaseVersion(resolved)) throw new
|
|
475
|
+
if (!isReleaseVersion(resolved)) throw new CliUserError(`체크리스트 판 또는 별칭이 아니다: ${v}`);
|
|
472
476
|
return resolved;
|
|
473
477
|
}
|
|
474
478
|
|
|
475
|
-
async function checklistOutput(v: string, codenames: Record<string, string>, mode: 'list' | 'status', json?: boolean): Promise<void> {
|
|
476
|
-
|
|
479
|
+
async function checklistOutput(v: string, codenames: Record<string, string>, mode: 'list' | 'status', json?: boolean, owner?: string): Promise<void> {
|
|
480
|
+
if (owner !== undefined) parseOwner(owner);
|
|
481
|
+
const snapshot = listChecklist(v);
|
|
482
|
+
const data = owner === undefined ? snapshot : { ...snapshot, items: snapshot.items.filter((item) => ownerMatches(item.owner, owner)) };
|
|
477
483
|
const summary = summarizeChecklist(data);
|
|
478
|
-
const
|
|
484
|
+
const parity = data.items.flatMap((item) => {
|
|
485
|
+
const why = item.kind === 'screen' ? parityGap(item.evidence) : null;
|
|
486
|
+
return why ? [{ id: item.id, why }] : [];
|
|
487
|
+
});
|
|
488
|
+
const result = { ...data, codename: codenames[v] ?? '', ...summary, parity };
|
|
489
|
+
for (const { id, why } of parity) debug.log('release.checklist', 'parity-warning', { version: v, id, why });
|
|
479
490
|
if (json) { await writeStdoutJson(`${JSON.stringify(result)}\n`); return; }
|
|
491
|
+
console.log(`⚠ 짝 경고 ${parity.length}: ${parity.map(({ id }) => id).join(', ') || '없음'}`);
|
|
480
492
|
console.log(`${v}${result.codename ? ` (${result.codename})` : ''} · 공개 ${data.released || '없음'} · 개발 ${data.dev}`);
|
|
481
493
|
if (mode === 'list') {
|
|
482
494
|
for (const item of data.items) console.log(`${({ green: '🟢', yellow: '🟡', red: '🔴', done: '✅' } as const)[item.status]} ${item.id} ${item.title}${item.owner ? ` · ${item.owner}` : ''}`);
|
|
@@ -489,6 +501,26 @@ async function checklistOutput(v: string, codenames: Record<string, string>, mod
|
|
|
489
501
|
|
|
490
502
|
export function registerReleaseCommands(program: Command, releaseRunDeps: UnattendedReleaseDeps = {}): void {
|
|
491
503
|
const release = program.command('release').description('공개 배포 한 판 — prepare(로컬) → publish(--yes) → verify (docs/manual/MANUAL-versioning-and-release-2026-09-25.md)');
|
|
504
|
+
const schedule = release.command('schedule').description('판별 컷·착지 마감 조회·갱신');
|
|
505
|
+
const scheduleLedgerRoot = () => releaseRunDeps.ledgerRoot ?? releaseLedgerRoot();
|
|
506
|
+
schedule.command('list').option('--json', '결과 JSON').action((o: { json?: boolean }) => {
|
|
507
|
+
const rows = listSchedules(scheduleLedgerRoot());
|
|
508
|
+
if (o.json) console.log(JSON.stringify(rows));
|
|
509
|
+
else for (const row of rows) console.log(formatSchedule(row));
|
|
510
|
+
});
|
|
511
|
+
schedule.command('show').requiredOption('--version <v>', '조회할 판').option('--json', '결과 JSON')
|
|
512
|
+
.action((o: { version: string; json?: boolean }) => {
|
|
513
|
+
const row = getSchedule(o.version, scheduleLedgerRoot());
|
|
514
|
+
if (!row) throw new CliUserError(`없는 판 일정: ${o.version}`, '판 일정 등록: elanous release schedule set --version <v> --cut-at <iso> --land-by <iso>');
|
|
515
|
+
if (o.json) console.log(JSON.stringify(row)); else console.log(formatSchedule(row));
|
|
516
|
+
});
|
|
517
|
+
schedule.command('set').requiredOption('--version <v>', '갱신할 판')
|
|
518
|
+
.option('--cut-at <iso>', '오프셋 포함 컷 시각').option('--land-by <iso>', '오프셋 포함 착지 마감').option('--json', '결과 JSON')
|
|
519
|
+
.action((o: { version: string; cutAt?: string; landBy?: string; json?: boolean }) => {
|
|
520
|
+
if (o.cutAt === undefined && o.landBy === undefined) throw new CliUserError('갱신할 시각을 지정하라', '--cut-at <iso> 또는 --land-by <iso>');
|
|
521
|
+
const row = setSchedule(o.version, { cutAt: o.cutAt, landBy: o.landBy }, process.env.ELANOUS_TRACK || 'cli', scheduleLedgerRoot());
|
|
522
|
+
if (o.json) console.log(JSON.stringify(row)); else console.log(formatSchedule(row));
|
|
523
|
+
});
|
|
492
524
|
const checklist = release.command('checklist').description('판별 확인표 조회·갱신')
|
|
493
525
|
.option('--version <v>', '판 또는 별칭(기본: package.json 의 개발판에서 -dev.N 제거)')
|
|
494
526
|
.option('--json', '결과 JSON');
|
|
@@ -498,15 +530,15 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
498
530
|
return { version: checklistVersion(opts.version, codenames), codenames, json: opts.json };
|
|
499
531
|
};
|
|
500
532
|
const withContext = (cmd: Command) => cmd.option('--version <v>', '판 또는 별칭').option('--json', '결과 JSON');
|
|
501
|
-
withContext(checklist.command('list').description('모든 칸')).action(async (
|
|
533
|
+
withContext(checklist.command('list').description('모든 칸')).option('--owner <owner>', '자리 또는 하위 자리로 거르기').action(async (opts: { owner?: string }, cmd: Command) => {
|
|
502
534
|
const { version, codenames, json } = context(cmd);
|
|
503
|
-
await checklistOutput(version, codenames, 'list', json);
|
|
535
|
+
await checklistOutput(version, codenames, 'list', json, opts.owner);
|
|
504
536
|
});
|
|
505
|
-
withContext(checklist.command('status').description('상태 요약')).action(async (
|
|
537
|
+
withContext(checklist.command('status').description('상태 요약')).option('--owner <owner>', '자리 또는 하위 자리로 거르기').action(async (opts: { owner?: string }, cmd: Command) => {
|
|
506
538
|
const { version, codenames, json } = context(cmd);
|
|
507
|
-
await checklistOutput(version, codenames, 'status', json);
|
|
539
|
+
await checklistOutput(version, codenames, 'status', json, opts.owner);
|
|
508
540
|
});
|
|
509
|
-
withContext(checklist.command('add <id> <title>').description('칸 추가')).option('--owner <owner>', '담당').option('--kind <kind>', 'screen = 다섯 화면 짝 칸')
|
|
541
|
+
withContext(checklist.command('add <id> <title>').description('칸 추가')).option('--owner <owner>', '담당').option('--kind <kind>', 'screen = 다섯 화면 짝 칸 · 근거에 짝: PWA … · 데스크톱 … · 폴드 … · 아이폰 … · 아이패드 … 한 줄')
|
|
510
542
|
.action((id: string, title: string, opts: { owner?: string; kind?: string }, cmd: Command) => {
|
|
511
543
|
const { version, json } = context(cmd);
|
|
512
544
|
const data = addItem(version, { id, title, ...(opts.owner !== undefined ? { owner: opts.owner } : {}), ...(opts.kind !== undefined ? { kind: opts.kind as ChecklistKind } : {}) });
|
|
@@ -514,15 +546,28 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
514
546
|
});
|
|
515
547
|
withContext(checklist.command('set <id>').description('칸 상태·근거·담당·처분 갱신'))
|
|
516
548
|
.option('--status <status>', 'green|yellow|red|done').option('--evidence <evidence>', '근거').option('--owner <owner>', '담당')
|
|
517
|
-
.option('--disposition <disposition>', 'move|known-issue|block').option('--kind <kind>', 'screen = 다섯 화면 짝 칸')
|
|
549
|
+
.option('--disposition <disposition>', 'move|known-issue|block').option('--kind <kind>', 'screen = 다섯 화면 짝 칸 · 근거에 짝: PWA … · 데스크톱 … · 폴드 … · 아이폰 … · 아이패드 … 한 줄')
|
|
518
550
|
.action((id: string, opts: { status?: string; evidence?: string; owner?: string; disposition?: string; kind?: string }, cmd: Command) => {
|
|
519
551
|
const { version, json } = context(cmd);
|
|
520
|
-
if (opts.status !== undefined && !['green', 'yellow', 'red', 'done'].includes(opts.status)) throw new
|
|
521
|
-
if (opts.disposition !== undefined && !['move', 'known-issue', 'block'].includes(opts.disposition)) throw new
|
|
522
|
-
if (opts.status === undefined && opts.evidence === undefined && opts.owner === undefined && opts.disposition === undefined && opts.kind === undefined) throw new
|
|
552
|
+
if (opts.status !== undefined && !['green', 'yellow', 'red', 'done'].includes(opts.status)) throw new CliUserError(`잘못된 상태: ${opts.status}`, 'green|yellow|red|done');
|
|
553
|
+
if (opts.disposition !== undefined && !['move', 'known-issue', 'block'].includes(opts.disposition)) throw new CliUserError(`잘못된 처분: ${opts.disposition}`, 'move|known-issue|block');
|
|
554
|
+
if (opts.status === undefined && opts.evidence === undefined && opts.owner === undefined && opts.disposition === undefined && opts.kind === undefined) throw new CliUserError('갱신할 칸을 지정하라', '--status · --evidence · --owner · --disposition · --kind 중 하나');
|
|
523
555
|
const data = setItem(version, id, { ...(opts.status !== undefined ? { status: opts.status as ChecklistStatus } : {}), ...(opts.evidence !== undefined ? { evidence: opts.evidence } : {}), ...(opts.owner !== undefined ? { owner: opts.owner } : {}), ...(opts.disposition !== undefined ? { disposition: opts.disposition as ChecklistDisposition } : {}), ...(opts.kind !== undefined ? { kind: opts.kind as ChecklistKind } : {}) }, process.env.ELANOUS_TRACK || 'cli');
|
|
556
|
+
const item = data.items.find((entry) => entry.id === id);
|
|
557
|
+
const why = item?.kind === 'screen' && item.status === 'green' ? parityGap(item.evidence) : null;
|
|
558
|
+
if (why) {
|
|
559
|
+
console.error(`⚠ 짝: ${why} — 근거에 «짝: PWA … · 데스크톱 … · 폴드 … · 아이폰 … · 아이패드 …» 한 줄`);
|
|
560
|
+
debug.log('release.checklist', 'parity-warning', { version, id, why });
|
|
561
|
+
}
|
|
524
562
|
if (json) console.log(JSON.stringify(data)); else console.log(`✅ ${id} 갱신`);
|
|
525
563
|
});
|
|
564
|
+
withContext(checklist.command('claim <id>').description('칸의 단일 주인을 잡는다'))
|
|
565
|
+
.requiredOption('--by <owner>', '잡을 자리 또는 하위 자리').option('--force', '기존 주인에서 강제로 바꾼다')
|
|
566
|
+
.action((id: string, opts: { by: string; force?: boolean }, cmd: Command) => {
|
|
567
|
+
const { version, json } = context(cmd);
|
|
568
|
+
const data = claimItem(version, id, opts.by, { force: opts.force });
|
|
569
|
+
if (json) console.log(JSON.stringify(data)); else console.log(`✅ ${id} 주인 ${opts.by}`);
|
|
570
|
+
});
|
|
526
571
|
withContext(checklist.command('rm <id>').description('칸 삭제')).action((id: string, _opts: unknown, cmd: Command) => {
|
|
527
572
|
const { version, json } = context(cmd);
|
|
528
573
|
const data = removeItem(version, id, process.env.ELANOUS_TRACK || 'cli');
|
|
@@ -540,8 +585,8 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
540
585
|
.action((id: string, opts: { from: string; to: string }, cmd: Command) => {
|
|
541
586
|
const { codenames, json } = context(cmd);
|
|
542
587
|
const from = checklistVersion(opts.from, codenames), to = checklistVersion(opts.to, codenames);
|
|
543
|
-
|
|
544
|
-
if (json) console.log(JSON.stringify(
|
|
588
|
+
features.move(id, from, to, actor());
|
|
589
|
+
if (json) console.log(JSON.stringify(listChecklist(to))); else console.log(`✅ ${id} ${from} → ${to}`);
|
|
545
590
|
});
|
|
546
591
|
withContext(checklist.command('retitle <id> <title>').description('칸 제목 수정')).action((id: string, title: string, _opts: unknown, cmd: Command) => {
|
|
547
592
|
const { version, json } = context(cmd);
|
|
@@ -554,11 +599,11 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
554
599
|
const { version, json } = context(cmd);
|
|
555
600
|
const snapshot = listChecklist(version);
|
|
556
601
|
features.evidenceAdd(id, version, ref, actor(), snapshot.released, snapshot.dev);
|
|
557
|
-
if (json) console.log(JSON.stringify(features.history(id))); else console.log(`✅ ${id} 근거 ${ref}`);
|
|
602
|
+
if (json) console.log(JSON.stringify(features.history(id).map(decodeClaimHistoryEntry))); else console.log(`✅ ${id} 근거 ${ref}`);
|
|
558
603
|
});
|
|
559
604
|
withContext(checklist.command('history <id>').description('칸의 판 이동·변경 이력')).action((id: string, _opts: unknown, cmd: Command) => {
|
|
560
605
|
const { json } = context(cmd);
|
|
561
|
-
const rows = features.history(id);
|
|
606
|
+
const rows = features.history(id).map(decodeClaimHistoryEntry);
|
|
562
607
|
if (json) { console.log(JSON.stringify(rows)); return; }
|
|
563
608
|
const info = features.details(id);
|
|
564
609
|
if (info) {
|
|
@@ -570,8 +615,8 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
570
615
|
withContext(checklist.command('export').description('SQLite 에서 checklist.json 스냅샷 생성')).action((_opts: unknown, cmd: Command) => {
|
|
571
616
|
const { version, json } = context(cmd);
|
|
572
617
|
const snapshot = listChecklist(version);
|
|
573
|
-
|
|
574
|
-
if (json) console.log(JSON.stringify(
|
|
618
|
+
features.exportJson(version, snapshot.released, snapshot.dev);
|
|
619
|
+
if (json) console.log(JSON.stringify(listChecklist(version))); else console.log(`✅ ${version} checklist.json 내보냄`);
|
|
575
620
|
});
|
|
576
621
|
release.command('prepare')
|
|
577
622
|
.description('깨끗한 원본 → 공개본 → 공개 저장소 이력 위 커밋 → PWA → 묶음·체크섬 → 로컬 끝까지 (네트워크 쓰기 없음)')
|
|
@@ -632,19 +677,30 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
632
677
|
const { draftReleaseNotes, readLandedCommits, renderReleaseNotes } = await import('../../scripts/release-notes.js');
|
|
633
678
|
console.log(renderReleaseNotes(draftReleaseNotes(readLandedCommits(o.from, o.to), o.from, o.to)));
|
|
634
679
|
});
|
|
680
|
+
release.command('cut-branch')
|
|
681
|
+
.description('원래 컷에 main 의 수리 커밋만 얹은 release/<v> 가지를 만들고 push')
|
|
682
|
+
.requiredOption('--version <v>', '릴리스 판(x.y.z)')
|
|
683
|
+
.requiredOption('--base <sha>', '원래 컷 SHA')
|
|
684
|
+
.requiredOption('--pick <sha...>', '차례로 얹을 main 커밋 SHA')
|
|
685
|
+
.option('--dry-run', '가지·worktree·push 없이 계획만 출력')
|
|
686
|
+
.option('--json', '결과 한 줄 JSON(stdout)')
|
|
687
|
+
.action(async (o: { version: string; base: string; pick: string[]; dryRun?: boolean; json?: boolean }) => {
|
|
688
|
+
await jsonAction(o.json, async (log) => cutReleaseBranch({ ...o, log }), () => true);
|
|
689
|
+
});
|
|
635
690
|
release.command('run')
|
|
636
691
|
.description('릴리스 루프 실행 — 원장 직전 판과 release.loop 설정으로 그래프 입력 구성 · --dry-run 은 입력만 출력')
|
|
637
692
|
.requiredOption('--version <v>', '공개할 판(x.y.z)')
|
|
693
|
+
.option('--cut-commit <sha>', 'origin/main HEAD 대신 컷으로 쓸 커밋')
|
|
638
694
|
.option('--dry-run', '체크리스트·그래프 실행 없이 전체 입력 보기')
|
|
639
695
|
.option('--if-ready', '준비되지 않았으면 사유를 출력하고 성공으로 건너뛴다')
|
|
640
696
|
.option('--json', '결과 한 줄 JSON(stdout) · 사람 줄은 stderr')
|
|
641
|
-
.action(async (o: { version: string; dryRun?: boolean; ifReady?: boolean; json?: boolean }) => {
|
|
697
|
+
.action(async (o: { version: string; cutCommit?: string; dryRun?: boolean; ifReady?: boolean; json?: boolean }) => {
|
|
642
698
|
if (o.ifReady && !o.dryRun) {
|
|
643
699
|
try {
|
|
644
700
|
const outcome = await runReleaseIfReady(o.version, {
|
|
645
701
|
ledgerRoot: releaseRunDeps.ledgerRoot,
|
|
646
702
|
readiness: (version, options) => releaseReadiness(version, { ledgerRoot: releaseRunDeps.ledgerRoot, checklist: releaseRunDeps.checklist, ...options }),
|
|
647
|
-
run: () => runUnattendedRelease({ version: o.version }, releaseRunDeps),
|
|
703
|
+
run: () => runUnattendedRelease({ version: o.version, cutCommit: o.cutCommit }, releaseRunDeps),
|
|
648
704
|
});
|
|
649
705
|
if (outcome.skipped) {
|
|
650
706
|
if (o.json) await writeStdoutJson(`${JSON.stringify(outcome)}\n`);
|
|
@@ -664,7 +720,7 @@ export function registerReleaseCommands(program: Command, releaseRunDeps: Unatte
|
|
|
664
720
|
return;
|
|
665
721
|
}
|
|
666
722
|
await jsonAction(o.json, async (log) => {
|
|
667
|
-
const result = await runUnattendedRelease({ version: o.version, dryRun: o.dryRun }, releaseRunDeps);
|
|
723
|
+
const result = await runUnattendedRelease({ version: o.version, dryRun: o.dryRun, cutCommit: o.cutCommit }, releaseRunDeps);
|
|
668
724
|
log(`${result.dryRun ? '· 드라이런' : '▶ 릴리스 루프'} ${result.input.version} · 입력 ${JSON.stringify(result.input)}`);
|
|
669
725
|
return result;
|
|
670
726
|
}, (r) => r.dryRun || r.state?.status === 'done' || r.state?.status === 'awaiting-approval');
|
package/src/cli/self-update.ts
CHANGED
|
@@ -343,6 +343,14 @@ function pruneReleaseVersions(plan: { current: string; previous: string; keep: n
|
|
|
343
343
|
return { removed, kept };
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
+
/** The build identity of an install.json — version, version folder and commit; empty when it cannot be read. */
|
|
347
|
+
function installedBuild(metadata: unknown): string {
|
|
348
|
+
if (typeof metadata !== 'object' || metadata === null) return '';
|
|
349
|
+
const { version, versionDir, commit } = metadata as { version?: unknown; versionDir?: unknown; commit?: unknown };
|
|
350
|
+
if (typeof version !== 'string' || !version || typeof versionDir !== 'string' || !versionDir) return '';
|
|
351
|
+
return JSON.stringify([version, versionDir, typeof commit === 'string' ? commit : '']);
|
|
352
|
+
}
|
|
353
|
+
|
|
346
354
|
/** A release update never packs the checkout: the downloaded installer verifies its own release tarball. */
|
|
347
355
|
export async function runReleaseUpdate(options: ReleaseUpdateOptions = {}, deps: ReleaseUpdateDeps = {}): Promise<SelfUpdateResult> {
|
|
348
356
|
const out = deps.out ?? console;
|
|
@@ -390,8 +398,10 @@ export async function runReleaseUpdate(options: ReleaseUpdateOptions = {}, deps:
|
|
|
390
398
|
return fail(1, `설치기 다운로드 실패 (${url}): ${String(error)}`);
|
|
391
399
|
}
|
|
392
400
|
let previous = '';
|
|
401
|
+
let previousBuild = '';
|
|
393
402
|
try {
|
|
394
403
|
const metadata: unknown = JSON.parse(readFileSync(join(prefix, 'install.json'), 'utf8'));
|
|
404
|
+
previousBuild = installedBuild(metadata);
|
|
395
405
|
if (typeof metadata === 'object' && metadata !== null && 'versionDir' in metadata && typeof metadata.versionDir === 'string') {
|
|
396
406
|
const dir = metadata.versionDir;
|
|
397
407
|
if (/^versions\/[a-zA-Z0-9._-]+$/.test(dir) && !dir.includes('..')) previous = basename(dir);
|
|
@@ -421,6 +431,10 @@ export async function runReleaseUpdate(options: ReleaseUpdateOptions = {}, deps:
|
|
|
421
431
|
prune = { removed: [], kept: [], skipped: `정리 실패: ${String(error)}` };
|
|
422
432
|
}
|
|
423
433
|
if (!options.restart) return finish({ exitCode: 0, installedVersion, decision: null, restarted: false, prune, reason: '--restart 없음: 재시작하지 않음' });
|
|
434
|
+
// REL6: the same build again (version · folder · commit unchanged) leaves the running daemon as it is.
|
|
435
|
+
if (previousBuild && previousBuild === installedBuild(metadata)) {
|
|
436
|
+
return finish({ exitCode: 0, installedVersion, decision: null, restarted: false, prune, reason: `already at ${installedVersion} · restart skipped` });
|
|
437
|
+
}
|
|
424
438
|
const os = deps.os ?? platform();
|
|
425
439
|
const command = os === 'darwin' ? 'launchctl' : os === 'linux' ? 'systemctl' : null;
|
|
426
440
|
if (!command) return finish({ exitCode: 1, installedVersion, decision: null, restarted: false, prune, reason: `지원하지 않는 플랫폼: ${os}` });
|
package/src/cli/setup-cli.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { Command } from 'commander';
|
|
|
5
5
|
import { formatDoctorReport, registerDoctorCommand, runDoctor, type DoctorOptions, type DoctorReport } from './doctor-cli.js';
|
|
6
6
|
import { applyClaudePluginSetup, planClaudePluginSetup } from './claude-plugin-setup.js';
|
|
7
7
|
import { recommendedSetup } from './setup-recommend.js';
|
|
8
|
+
import { detectSkillCliAuth, type CliAuthStatus } from '../onboarding/cli-auth-status.js';
|
|
8
9
|
import { debug } from '../debug/log.js';
|
|
9
10
|
import { getUserConfig, saveUserConfig, type UserConfig } from '../user-config.js';
|
|
10
11
|
|
|
@@ -22,6 +23,7 @@ type SetupStep = {
|
|
|
22
23
|
export interface SetupCliDeps extends DoctorOptions {
|
|
23
24
|
runDoctor?: (options: DoctorOptions) => DoctorReport;
|
|
24
25
|
runDoctorFix?: (args: readonly string[]) => Promise<number>;
|
|
26
|
+
detectSkillCliAuth?: typeof detectSkillCliAuth;
|
|
25
27
|
readFile?: (path: string) => string;
|
|
26
28
|
exists?: (path: string) => boolean;
|
|
27
29
|
homeDir?: () => string;
|
|
@@ -142,10 +144,46 @@ export function formatSetupReport(doctor: DoctorReport, steps: SetupStep[], nonI
|
|
|
142
144
|
].join('\n');
|
|
143
145
|
}
|
|
144
146
|
|
|
147
|
+
const CLI_SKILLS = {
|
|
148
|
+
gh: 'github', gws: 'google-workspace', op: '1password', himalaya: 'himalaya',
|
|
149
|
+
} as const;
|
|
150
|
+
|
|
151
|
+
function formatCliSkillStatus(status: CliAuthStatus, enabled: boolean, reason?: string): string {
|
|
152
|
+
return `${status.cli}: found=${status.found ? 'yes' : 'no'} / enabled=${enabled ? 'yes' : 'no'} / ${enabled ? 'enabled' : `skipped (${reason ?? status.skippedReason ?? 'not authenticated'})`}`;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function reportCliSkills(deps: SetupCliDeps, apply: boolean): string[] {
|
|
156
|
+
const statuses = (deps.detectSkillCliAuth ?? detectSkillCliAuth)();
|
|
157
|
+
const config = (deps.getUserConfig ?? getUserConfig)();
|
|
158
|
+
const deny = new Set(config.skills.deny ?? []);
|
|
159
|
+
const allow = config.skills.allow ?? [];
|
|
160
|
+
let changed = false;
|
|
161
|
+
const lines = statuses.map((status) => {
|
|
162
|
+
const skill = CLI_SKILLS[status.cli];
|
|
163
|
+
const allowed = allow.length === 0 || allow.some((name) => name.toLowerCase() === skill);
|
|
164
|
+
if (apply) {
|
|
165
|
+
if (status.authenticated && allowed && deny.has(skill)) { deny.delete(skill); changed = true; }
|
|
166
|
+
if (!status.authenticated && !deny.has(skill)) { deny.add(skill); changed = true; }
|
|
167
|
+
}
|
|
168
|
+
const enabled = status.authenticated && allowed && !deny.has(skill);
|
|
169
|
+
return formatCliSkillStatus(status, enabled,
|
|
170
|
+
status.authenticated && !allowed ? 'excluded by skills.allow' :
|
|
171
|
+
status.authenticated && !apply && deny.has(skill) ? 'not enabled; run setup to apply' : undefined);
|
|
172
|
+
});
|
|
173
|
+
if (apply && changed) (deps.saveUserConfig ?? saveUserConfig)({
|
|
174
|
+
...config, skills: { ...config.skills, deny: [...deny] },
|
|
175
|
+
});
|
|
176
|
+
return lines;
|
|
177
|
+
}
|
|
178
|
+
|
|
145
179
|
export function registerSetupCommand(program: Command, deps: SetupCliDeps = {}): void {
|
|
146
180
|
const out = deps.out ?? { log: (value: string) => console.log(value), error: (value: string) => console.error(value) };
|
|
147
181
|
const setExitCode = deps.setExitCode ?? ((code: number) => { process.exitCode = code; });
|
|
148
182
|
const doctorRunner = deps.runDoctor ?? runDoctor;
|
|
183
|
+
const showCliSkills = (apply: boolean) => {
|
|
184
|
+
out.log('Setup: CLI skills (public GitHub repository reads remain available without login)');
|
|
185
|
+
for (const line of reportCliSkills(deps, apply)) out.log(line);
|
|
186
|
+
};
|
|
149
187
|
const isStdinTty = deps.isStdinTty ?? (() => process.stdin.isTTY === true);
|
|
150
188
|
const prompt = deps.prompt ?? (async (message: string) => {
|
|
151
189
|
const { createInterface } = await import('node:readline/promises');
|
|
@@ -161,6 +199,7 @@ export function registerSetupCommand(program: Command, deps: SetupCliDeps = {}):
|
|
|
161
199
|
const doctor = doctorRunner(deps);
|
|
162
200
|
if (opts.nonInteractive) {
|
|
163
201
|
out.log(formatSetupReport(doctor, setupSteps(deps), true));
|
|
202
|
+
showCliSkills(false);
|
|
164
203
|
for (const line of recommendedSetup((deps.getUserConfig ?? getUserConfig)())) out.log(line);
|
|
165
204
|
setExitCode(0);
|
|
166
205
|
return;
|
|
@@ -183,6 +222,7 @@ export function registerSetupCommand(program: Command, deps: SetupCliDeps = {}):
|
|
|
183
222
|
}
|
|
184
223
|
}
|
|
185
224
|
out.log(formatSetupReport(doctor, steps, false));
|
|
225
|
+
showCliSkills(false);
|
|
186
226
|
for (const line of recommendedSetup((deps.getUserConfig ?? getUserConfig)())) out.log(line);
|
|
187
227
|
const accepted = opts.yes || (isStdinTty() && /^(?:y|yes)?$/i.test((await prompt('추천대로 켤까요? [Y/n] '))?.trim() ?? 'n'));
|
|
188
228
|
if (accepted) {
|
|
@@ -197,7 +237,9 @@ export function registerSetupCommand(program: Command, deps: SetupCliDeps = {}):
|
|
|
197
237
|
await doctorProgram.parseAsync([...args], { from: 'user' });
|
|
198
238
|
return exitCode;
|
|
199
239
|
});
|
|
200
|
-
|
|
240
|
+
const fixCode = await runDoctorFix(['doctor', '--fix', '--yes']);
|
|
241
|
+
showCliSkills(true);
|
|
242
|
+
setExitCode(fixCode);
|
|
201
243
|
return;
|
|
202
244
|
}
|
|
203
245
|
setExitCode(0);
|
package/src/cli/skills-cli.ts
CHANGED
|
@@ -73,7 +73,23 @@ export function registerConnectCommand(program: Command): void {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
export function registerSkillsCommands(program: Command): void {
|
|
76
|
-
const skills = program.command('skills').description('Check and repair
|
|
76
|
+
const skills = program.command('skills').description('Check, install and repair skills');
|
|
77
|
+
skills.command('install <pack>')
|
|
78
|
+
.description('Install a gift skill pack from a code')
|
|
79
|
+
.option('--code <code>', 'Gift code')
|
|
80
|
+
.option('--email <address>', 'Email for gift delivery')
|
|
81
|
+
.option('--agree', 'Agree to email collection and retention')
|
|
82
|
+
.option('--endpoint <url>', 'Gift API origin (overrides skills.giftEndpoint)')
|
|
83
|
+
.option('--json', 'Print the install result as JSON')
|
|
84
|
+
.action(async (pack: string, opts: { code?: string; email?: string; agree?: boolean; endpoint?: string; json?: boolean }) => {
|
|
85
|
+
const { getUserConfig } = await import('../user-config.js');
|
|
86
|
+
const { installGiftPack } = await import('../skills/gift-install.js');
|
|
87
|
+
const result = await installGiftPack({ pack, code: opts.code, email: opts.email, agree: opts.agree,
|
|
88
|
+
endpoint: opts.endpoint ?? getUserConfig().skills.giftEndpoint });
|
|
89
|
+
if (opts.json) console.log(JSON.stringify(result));
|
|
90
|
+
else console.log(result.message);
|
|
91
|
+
if (!result.ok) process.exitCode = 1;
|
|
92
|
+
});
|
|
77
93
|
skills.command('sources')
|
|
78
94
|
.description('List every skill folder elanous reads, in order (preset · shared · connected · package)')
|
|
79
95
|
.option('--json', 'JSON output')
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join, relative } from 'node:path';
|
|
3
|
+
import { parse } from 'yaml';
|
|
4
|
+
import { debug } from '../debug/log.js';
|
|
5
|
+
import { files, lint, render, STORYBOARD_ROOT, type Storyboard } from '../storyboard/storyboard.js';
|
|
6
|
+
|
|
7
|
+
export function runStoryboard(cmd: 'lint' | 'render', args: string[], json = false): number {
|
|
8
|
+
const reports: Array<{ file: string; errors: string[]; warnings: string[] }> = [];
|
|
9
|
+
let errorCount = 0, warningCount = 0;
|
|
10
|
+
for (const f of files(args)) {
|
|
11
|
+
const file = relative(STORYBOARD_ROOT, f);
|
|
12
|
+
let sb: Storyboard | undefined;
|
|
13
|
+
let errors: string[], warnings: string[];
|
|
14
|
+
try {
|
|
15
|
+
sb = parse(readFileSync(f, 'utf8')) as Storyboard;
|
|
16
|
+
({ errors, warnings } = lint(sb, file));
|
|
17
|
+
} catch (cause) {
|
|
18
|
+
errors = [cause instanceof Error ? cause.message : String(cause)];
|
|
19
|
+
warnings = [];
|
|
20
|
+
}
|
|
21
|
+
reports.push({ file, errors, warnings });
|
|
22
|
+
errorCount += errors.length;
|
|
23
|
+
warningCount += warnings.length;
|
|
24
|
+
if (json) continue;
|
|
25
|
+
for (const e of errors) console.log(`✗ ${file}: ${e}`);
|
|
26
|
+
for (const w of warnings) console.log(`⚠ ${file}: ${w}`);
|
|
27
|
+
if (errors.length || !sb) continue;
|
|
28
|
+
if (cmd === 'render') {
|
|
29
|
+
const out = join(STORYBOARD_ROOT, 'docs', 'marketing', `STORYBOARD-${sb.id}-v${sb.version}.md`);
|
|
30
|
+
writeFileSync(out, render(sb, file) + '\n');
|
|
31
|
+
console.log(`✓ ${file} → ${relative(STORYBOARD_ROOT, out)}`);
|
|
32
|
+
} else console.log(`✓ ${file} · v${sb.version} · ${sb.status} · ${sb.kind === 'site' ? `사이트 ${sb.sites?.length ?? 0}` : `샷 ${sb.shots.length}`}`);
|
|
33
|
+
}
|
|
34
|
+
if (cmd === 'lint') debug.log('storyboard.lint', 'checked', { files: reports.length, errorCount, warningCount });
|
|
35
|
+
if (json) console.log(JSON.stringify({ files: reports, errorCount, warningCount }));
|
|
36
|
+
return errorCount ? 1 : 0;
|
|
37
|
+
}
|
|
@@ -71,7 +71,8 @@ export function applyTestStateDirFlagFromArgv(): string | undefined {
|
|
|
71
71
|
* 뒤에만 있어 사람이 부를 입구가 없었고, 그래서 문서 174곳에 수동 주문이 화석으로 남았다.
|
|
72
72
|
*
|
|
73
73
|
* 하는 일: nexus state root ⊕ ELANOUS_STATE_DIR ⊕ config-dir 을 **한 뿌리로** 세우고,
|
|
74
|
-
* config
|
|
74
|
+
* 운영 config 가 있으면 test-safe 사본을 물질화하고, 없으면 격리 기본값을 사용하며,
|
|
75
|
+
* config 경로가 test 루트 밖이면 **기동을 거부**한다. */
|
|
75
76
|
export function applyIsolatedRoot(dir: string): void {
|
|
76
77
|
const { setTestStateRoot } = require('../nexus/paths.js') as typeof import('../nexus/paths.js');
|
|
77
78
|
setTestStateRoot(dir);
|
|
@@ -98,7 +99,7 @@ export function applyIsolatedRoot(dir: string): void {
|
|
|
98
99
|
}
|
|
99
100
|
cfgDir.setElanousConfigDir(dir);
|
|
100
101
|
}
|
|
101
|
-
// config
|
|
102
|
+
// config 사본이 없고 운영 원본이 있으면 물질화하고, 있으면 drift 경고만
|
|
102
103
|
// (자동 덮어쓰기 금지 — 명시적 sync 원칙). 유닛 테스트(NODE_ENV=test)는
|
|
103
104
|
// 실 운영 config/secrets 를 temp 로 복사하지 않도록 sync 스킵.
|
|
104
105
|
if (process.env.NODE_ENV !== 'test') {
|
|
@@ -106,8 +107,14 @@ export function applyIsolatedRoot(dir: string): void {
|
|
|
106
107
|
const { existsSync } = require('node:fs') as typeof import('node:fs');
|
|
107
108
|
const { join } = require('node:path') as typeof import('node:path');
|
|
108
109
|
if (!existsSync(join(dir, 'config.json'))) {
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
// A fresh build/test environment may have no operating config to copy.
|
|
111
|
+
// Keep the isolated config root and use the ordinary safe defaults there.
|
|
112
|
+
if (existsSync(join(sync.prodConfigDir(), 'config.json'))) {
|
|
113
|
+
const r = sync.syncTestConfig(dir);
|
|
114
|
+
console.error(`[test-isolation] 운영 config 물질화 → ${r.testConfigPath} (telegram=${r.telegramMode})`);
|
|
115
|
+
} else {
|
|
116
|
+
console.error(`[test-isolation] 운영 config 없음 — ${dir} 의 기본 설정 사용`);
|
|
117
|
+
}
|
|
111
118
|
} else if (sync.isTestConfigStale(dir)) {
|
|
112
119
|
console.error(`[test-isolation] ⚠️ 운영 config 가 테스트 사본보다 최신 — 'elanous config sync-test' 로 갱신 권장`);
|
|
113
120
|
}
|
package/src/connectors/linear.ts
CHANGED
|
@@ -122,6 +122,152 @@ export async function fetchLinearIssues({ apiKey, teamKey, labelOrPrefix, since,
|
|
|
122
122
|
return events.sort((a, b) => PRIORITY_RANK[a.priority ?? 'none'] - PRIORITY_RANK[b.priority ?? 'none']);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
export interface LinearProjectIssue {
|
|
126
|
+
identifier: string;
|
|
127
|
+
title: string;
|
|
128
|
+
url: string;
|
|
129
|
+
state: { name: string; type: string };
|
|
130
|
+
dueDate: string | null;
|
|
131
|
+
priority: number;
|
|
132
|
+
assignee: { name: string } | null;
|
|
133
|
+
updatedAt: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
type LinearRequestOptions = { apiKey: string; fetch?: typeof fetch };
|
|
137
|
+
|
|
138
|
+
async function linearRequest<T>({ apiKey, fetch: fetchFn = fetch }: LinearRequestOptions, query: string, variables: Record<string, unknown>): Promise<T> {
|
|
139
|
+
let response: Response;
|
|
140
|
+
try {
|
|
141
|
+
response = await fetchFn('https://api.linear.app/graphql', {
|
|
142
|
+
method: 'POST', headers: { Authorization: apiKey, 'Content-Type': 'application/json' },
|
|
143
|
+
body: JSON.stringify({ query, variables }),
|
|
144
|
+
});
|
|
145
|
+
} catch (error) {
|
|
146
|
+
throw new Error(`Linear GraphQL request failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
147
|
+
}
|
|
148
|
+
if (!response.ok) throw new Error(`Linear GraphQL HTTP ${response.status}`);
|
|
149
|
+
let body: { data?: T; errors?: Array<{ message?: string }> };
|
|
150
|
+
try { body = await response.json() as typeof body; }
|
|
151
|
+
catch { throw new Error('Linear GraphQL invalid JSON response'); }
|
|
152
|
+
if (body.errors?.length) throw new Error(`Linear GraphQL: ${body.errors.map(e => e.message ?? 'unknown error').join('; ')}`);
|
|
153
|
+
if (!body.data) throw new Error('Linear GraphQL missing data');
|
|
154
|
+
return body.data;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Shared unique name → project id lookup for COO reads and decision writes. */
|
|
158
|
+
export async function resolveLinearProjectId({ apiKey, project, fetch: fetchFn = fetch }: LinearRequestOptions & { project: string }): Promise<string> {
|
|
159
|
+
const cursors = new Set<string>();
|
|
160
|
+
let projectId = project;
|
|
161
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(project)) {
|
|
162
|
+
const matches: string[] = [];
|
|
163
|
+
let after: string | null = null;
|
|
164
|
+
do {
|
|
165
|
+
const data: { projects?: { nodes?: Array<{ id: string; name: string }>; pageInfo?: { hasNextPage: boolean; endCursor: string | null } } } = await linearRequest({ apiKey, fetch: fetchFn },
|
|
166
|
+
`query CooProjects($after: String) { projects(first: 100, after: $after) { nodes { id name } pageInfo { hasNextPage endCursor } } }`, { after });
|
|
167
|
+
if (!Array.isArray(data.projects?.nodes)) throw new Error('Linear GraphQL missing projects');
|
|
168
|
+
for (const candidate of data.projects.nodes) if (candidate.name === project) matches.push(candidate.id);
|
|
169
|
+
const page = data.projects.pageInfo;
|
|
170
|
+
if (page?.hasNextPage && (!page.endCursor || cursors.has(page.endCursor))) throw new Error('Linear GraphQL pagination cursor missing or repeated');
|
|
171
|
+
after = page?.hasNextPage ? page.endCursor : null;
|
|
172
|
+
if (after) cursors.add(after);
|
|
173
|
+
} while (after);
|
|
174
|
+
if (matches.length > 1) throw new Error('프로젝트 이름이 여럿과 맞습니다');
|
|
175
|
+
if (!matches.length) throw new Error('프로젝트 이름과 맞는 항목이 없습니다');
|
|
176
|
+
projectId = matches[0]!;
|
|
177
|
+
}
|
|
178
|
+
return projectId;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Read-only project lookup. A name is resolved uniquely before querying its issues. */
|
|
182
|
+
export async function fetchLinearProjectIssues({ apiKey, project, includeDone = false, fetch: fetchFn = fetch }: {
|
|
183
|
+
apiKey: string; project: string; includeDone?: boolean; fetch?: typeof fetch;
|
|
184
|
+
}): Promise<LinearProjectIssue[] & { truncated: boolean }> {
|
|
185
|
+
const projectId = await resolveLinearProjectId({ apiKey, project, fetch: fetchFn });
|
|
186
|
+
const issues: LinearProjectIssue[] = [];
|
|
187
|
+
const cursors = new Set<string>();
|
|
188
|
+
let after: string | null = null;
|
|
189
|
+
do {
|
|
190
|
+
const stateFilter = includeDone ? '' : ', state: { type: { nin: ["completed", "canceled"] } }';
|
|
191
|
+
const data: { issues?: { nodes?: LinearProjectIssue[]; pageInfo?: { hasNextPage: boolean; endCursor: string | null } } } = await linearRequest({ apiKey, fetch: fetchFn },
|
|
192
|
+
`query CooProjectIssues($projectId: ID!, $after: String, $first: Int!) {
|
|
193
|
+
issues(filter: { project: { id: { eq: $projectId } }${stateFilter} }, first: $first, after: $after) {
|
|
194
|
+
nodes { identifier title url state { name type } dueDate priority assignee { name } updatedAt }
|
|
195
|
+
pageInfo { hasNextPage endCursor }
|
|
196
|
+
}
|
|
197
|
+
}`, { projectId, after, first: Math.min(100, 250 - issues.length) });
|
|
198
|
+
if (!Array.isArray(data.issues?.nodes)) throw new Error('Linear GraphQL missing issues');
|
|
199
|
+
for (const node of data.issues.nodes) {
|
|
200
|
+
if (!includeDone && (node.state?.type === 'completed' || node.state?.type === 'canceled')) continue;
|
|
201
|
+
if (issues.length < 250) issues.push(node);
|
|
202
|
+
}
|
|
203
|
+
const page = data.issues.pageInfo;
|
|
204
|
+
if (page?.hasNextPage && (!page.endCursor || cursors.has(page.endCursor))) throw new Error('Linear GraphQL pagination cursor missing or repeated');
|
|
205
|
+
after = page?.hasNextPage ? page.endCursor : null;
|
|
206
|
+
if (after) cursors.add(after);
|
|
207
|
+
} while (after && issues.length < 250);
|
|
208
|
+
Object.defineProperty(issues, 'truncated', { value: after !== null, enumerable: false });
|
|
209
|
+
return issues as LinearProjectIssue[] & { truncated: boolean };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** Find a previously created decision issue after a crash between Linear creation and the local rename. */
|
|
213
|
+
export async function findLinearDecisionIssue({ apiKey, projectId, decisionId, fetch: fetchFn = fetch }: LinearRequestOptions & { projectId: string; decisionId: string }): Promise<string | null> {
|
|
214
|
+
const cursors = new Set<string>();
|
|
215
|
+
let after: string | null = null;
|
|
216
|
+
let match: string | null = null;
|
|
217
|
+
do {
|
|
218
|
+
const data: { issues?: { nodes?: Array<{ id: string; description: string | null }>; pageInfo?: { hasNextPage: boolean; endCursor: string | null } } } = await linearRequest({ apiKey, fetch: fetchFn },
|
|
219
|
+
'query DecisionIssue($projectId: ID!, $decisionId: String!, $after: String) { issues(filter: { project: { id: { eq: $projectId } }, description: { contains: $decisionId } }, first: 100, after: $after) { nodes { id description } pageInfo { hasNextPage endCursor } } }',
|
|
220
|
+
{ projectId, decisionId, after });
|
|
221
|
+
if (!Array.isArray(data.issues?.nodes)) throw new Error('Linear GraphQL missing issues');
|
|
222
|
+
for (const node of data.issues.nodes) {
|
|
223
|
+
if (!node.description?.split('\n').includes(`결정 id: ${decisionId}`)) continue;
|
|
224
|
+
if (match) throw new Error('Linear decision issue duplicated');
|
|
225
|
+
match = node.id;
|
|
226
|
+
}
|
|
227
|
+
const page = data.issues.pageInfo;
|
|
228
|
+
if (page?.hasNextPage && (!page.endCursor || cursors.has(page.endCursor))) throw new Error('Linear GraphQL pagination cursor missing or repeated');
|
|
229
|
+
after = page?.hasNextPage ? page.endCursor : null;
|
|
230
|
+
if (after) cursors.add(after);
|
|
231
|
+
} while (after);
|
|
232
|
+
return match;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** Create in the COO project; Linear requires a team from that project for issueCreate. */
|
|
236
|
+
export async function createLinearIssue({ apiKey, projectId, title, description, dueDate, fetch: fetchFn = fetch }: LinearRequestOptions & {
|
|
237
|
+
projectId: string; title: string; description: string; dueDate?: string;
|
|
238
|
+
}): Promise<string> {
|
|
239
|
+
const data = await linearRequest<{ project?: { teams?: { nodes?: Array<{ id: string }> } } }>({ apiKey, fetch: fetchFn },
|
|
240
|
+
'query DecisionProjectTeam($id: String!) { project(id: $id) { teams { nodes { id } } } }', { id: projectId });
|
|
241
|
+
const teams = data.project?.teams?.nodes;
|
|
242
|
+
if (!teams?.[0]?.id) throw new Error('Linear project has no team');
|
|
243
|
+
const created = await linearRequest<{ issueCreate?: { success?: boolean; issue?: { id?: string } } }>({ apiKey, fetch: fetchFn },
|
|
244
|
+
'mutation DecisionIssueCreate($input: IssueCreateInput!) { issueCreate(input: $input) { success issue { id } } }',
|
|
245
|
+
{ input: { teamId: teams[0].id, projectId, title, description, ...(dueDate ? { dueDate } : {}) } });
|
|
246
|
+
const id = created.issueCreate?.issue?.id;
|
|
247
|
+
if (!created.issueCreate?.success || !id) throw new Error('Linear issueCreate did not return an issue id');
|
|
248
|
+
return id;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export async function commentLinearIssue({ apiKey, issueId, body, fetch: fetchFn = fetch }: LinearRequestOptions & { issueId: string; body: string }): Promise<void> {
|
|
252
|
+
const data = await linearRequest<{ commentCreate?: { success?: boolean; comment?: { id?: string } } }>({ apiKey, fetch: fetchFn },
|
|
253
|
+
'mutation DecisionComment($input: CommentCreateInput!) { commentCreate(input: $input) { success comment { id } } }',
|
|
254
|
+
{ input: { issueId, body } });
|
|
255
|
+
if (!data.commentCreate?.success || !data.commentCreate.comment?.id) throw new Error('Linear commentCreate failed');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export async function moveLinearIssueToStateType({ apiKey, issueId, type, fetch: fetchFn = fetch }: LinearRequestOptions & {
|
|
259
|
+
issueId: string; type: 'completed' | 'canceled';
|
|
260
|
+
}): Promise<void> {
|
|
261
|
+
const data = await linearRequest<{ issue?: { team?: { states?: { nodes?: Array<{ id: string; type: string }> } } } }>({ apiKey, fetch: fetchFn },
|
|
262
|
+
'query DecisionIssueStates($id: String!) { issue(id: $id) { team { states { nodes { id type } } } } }', { id: issueId });
|
|
263
|
+
const state = data.issue?.team?.states?.nodes?.find(node => node.type === type);
|
|
264
|
+
if (!state?.id) throw new Error(`Linear team workflow state not found: ${type}`);
|
|
265
|
+
const updated = await linearRequest<{ issueUpdate?: { success?: boolean } }>({ apiKey, fetch: fetchFn },
|
|
266
|
+
'mutation DecisionIssueClose($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }',
|
|
267
|
+
{ id: issueId, input: { stateId: state.id } });
|
|
268
|
+
if (!updated.issueUpdate?.success) throw new Error('Linear issueUpdate failed');
|
|
269
|
+
}
|
|
270
|
+
|
|
125
271
|
export function toTaskRequest(event: ExternalTaskEvent): {
|
|
126
272
|
title: string; description: string; priority: 'high' | 'medium' | 'low';
|
|
127
273
|
external: { provider: 'linear'; ref: string; url?: string; team?: string };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
|
|
3
|
+
/** Render a Claude Code settings fragment; never touch the user's settings file. */
|
|
4
|
+
export function claudeHooksSettings(repoRoot: string): string {
|
|
5
|
+
const command = (file: string) => `bash '${resolve(repoRoot, 'scripts/context-hooks', file).replaceAll("'", "'\\''")}'`;
|
|
6
|
+
return JSON.stringify({ hooks: {
|
|
7
|
+
Stop: [{ hooks: [{ type: 'command', command: command('claude-stop.sh') }] }],
|
|
8
|
+
PostToolUse: [{ hooks: [{ type: 'command', command: command('post-tool-use.sh') }] }],
|
|
9
|
+
} }, null, 2);
|
|
10
|
+
}
|