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/pr-cli.ts
CHANGED
|
@@ -13,11 +13,12 @@ import { runGate as runChangedTypecheckGate } from '../../scripts/ci-typecheck-c
|
|
|
13
13
|
import { runIsolationHardcodeGate } from '../../scripts/ci-isolation-hardcode-gate.js';
|
|
14
14
|
import { androidFilesIn, runAndroidUnitTestGate } from '../../scripts/ci-android-unit-tests.js';
|
|
15
15
|
import { iosFilesIn, runIosUnitTestGate } from '../../scripts/ci-ios-unit-tests.js';
|
|
16
|
+
import { runPwaBuildGate } from '../../scripts/ci-pwa-build-gate.js';
|
|
16
17
|
import { runMockModuleRestoreGate } from '../../scripts/ci-mock-module-restore-gate.js';
|
|
17
18
|
import { runModelHardcodeGate } from '../../scripts/ci-model-hardcode-gate.js';
|
|
18
19
|
import { runDaemonPortGate } from '../../scripts/ci-daemon-port-gate.js';
|
|
19
20
|
import { runPublicLeakGate } from '../../scripts/ci-public-leak-gate.js';
|
|
20
|
-
import { exportLeakCheck, type ExportLeakCheck } from '../../scripts/ci-public-export-leak-gate.js';
|
|
21
|
+
import { exportLeakCheck, publicExportChangedFiles, type ExportLeakCheck } from '../../scripts/ci-public-export-leak-gate.js';
|
|
21
22
|
import { checkCommands, extractElanousCommands, type Finding as DocsCliFinding } from '../../scripts/docs-cli-check.js';
|
|
22
23
|
import { runTestInterferenceGate } from '../../scripts/ci-test-interference-gate.js';
|
|
23
24
|
import { isGoalDocumentFileName } from '../self-implement/goal-document.js';
|
|
@@ -51,6 +52,7 @@ import {
|
|
|
51
52
|
unionPaths,
|
|
52
53
|
} from './pr-granularity.js';
|
|
53
54
|
import { branchLineageSlug, findSiblingPrs } from './pr-lineage.js';
|
|
55
|
+
import { parseReleaseNoteSection } from '../release-loop/release-note.js';
|
|
54
56
|
|
|
55
57
|
export { branchLineageSlug, findSiblingPrs };
|
|
56
58
|
|
|
@@ -102,7 +104,7 @@ export interface PrLandDeps {
|
|
|
102
104
|
runMockModuleRestoreGate?: (out: { log: (message: string) => void; error: (message: string) => void }) => boolean;
|
|
103
105
|
runModelHardcodeGate?: (out: { log: (message: string) => void; error: (message: string) => void }) => boolean;
|
|
104
106
|
runDaemonPortGate?: (out: { log: (message: string) => void; error: (message: string) => void }) => boolean;
|
|
105
|
-
/** 공개 유출 래칫(경고 전용) — 반환 0
|
|
107
|
+
/** 공개 유출 래칫(경고 전용) — 반환 0 동일 · 1 늘었다 · 2 못 쟀다 · 3 줄었다. */
|
|
106
108
|
runPublicLeakGate?: (changedFiles: readonly string[], out: { log: (message: string) => void; error: (message: string) => void }) => number;
|
|
107
109
|
/** Test seam — the post-transform export leak check on changed files. */
|
|
108
110
|
runExportLeakCheck?: (changedFiles: readonly string[], cwd: string) => ExportLeakCheck;
|
|
@@ -114,6 +116,7 @@ export interface PrLandDeps {
|
|
|
114
116
|
runAndroidGate?: (out: { log: (message: string) => void; error: (message: string) => void }, changedFiles: readonly string[]) => boolean;
|
|
115
117
|
/** iOS 시험 게이트 심(시험 주입용). */
|
|
116
118
|
runIosGate?: (out: { log: (message: string) => void; error: (message: string) => void }, changedFiles: readonly string[]) => boolean;
|
|
119
|
+
runPwaGate?: (out: { log: (message: string) => void; error: (message: string) => void }, changedFiles: readonly string[]) => boolean;
|
|
117
120
|
isInteractive?: () => boolean;
|
|
118
121
|
/** Clock for the recent-landings window (test seam · default Date.now). */
|
|
119
122
|
now?: () => number;
|
|
@@ -272,8 +275,10 @@ export function runPrLandIsolationGate(
|
|
|
272
275
|
|
|
273
276
|
/** ⭐ 2026-09-24 — 공개 유출 래칫은 «경고만» 낸다(착지를 막지 않는다 · 막는 것은 공개 결정 뒤 · 채널 합의).
|
|
274
277
|
* 계기: 기준선 뒤 3시간 만에 🅢 착지분에서 유출 증가 다섯을 이 게이트가 잡았다 — 착지 순간에 보여야 그 자리에서 고친다. */
|
|
275
|
-
function runPrLandPublicLeakGate(changedFiles: readonly string[], out: { log: (message: string) => void; error: (message: string) => void }): number {
|
|
276
|
-
|
|
278
|
+
function runPrLandPublicLeakGate(changedFiles: readonly string[], out: { log: (message: string) => void; error: (message: string) => void }, cwd: string, baselineRef: string): number {
|
|
279
|
+
const top = runGitCommand(cwd, ['rev-parse', '--show-toplevel'], { encoding: 'utf-8' });
|
|
280
|
+
if (top.status !== 0 || !String(top.stdout ?? '').trim()) return 2;
|
|
281
|
+
return runPublicLeakGate({ args: ['--changed-files', ...changedFiles], root: String(top.stdout).trim(), baselineRef, log: out.log, error: out.log });
|
|
277
282
|
}
|
|
278
283
|
|
|
279
284
|
/** The prepare check on this landing's changed files — scripts/ci-public-export-leak-gate.ts. */
|
|
@@ -282,23 +287,49 @@ export function runPrLandExportLeakCheck(changedFiles: readonly string[], cwd: s
|
|
|
282
287
|
return exportLeakCheck(changedFiles, top.status === 0 && String(top.stdout ?? '').trim() ? String(top.stdout).trim() : cwd);
|
|
283
288
|
}
|
|
284
289
|
|
|
285
|
-
/** Blocks
|
|
290
|
+
/** Blocks changed public files that leak or cannot be measured. */
|
|
286
291
|
export function exportLeakBlock(
|
|
287
292
|
changedFiles: readonly string[] | undefined,
|
|
288
293
|
check: () => ExportLeakCheck,
|
|
289
294
|
allow: boolean,
|
|
290
295
|
out: { log: (message: string) => void; error: (message: string) => void },
|
|
296
|
+
cwd: string = process.cwd(),
|
|
291
297
|
): boolean {
|
|
292
298
|
if (!changedFiles || changedFiles.length === 0) return true;
|
|
293
299
|
let result: ExportLeakCheck;
|
|
294
|
-
try { result = check(); } catch
|
|
295
|
-
|
|
296
|
-
if (!result.measured) {
|
|
297
|
-
|
|
300
|
+
try { result = check(); } catch { result = { measured: false, hits: [], detail: '검사 실행 실패' }; }
|
|
301
|
+
let publicFiles: string[] = [];
|
|
302
|
+
if (!result.measured) {
|
|
303
|
+
try { publicFiles = publicExportChangedFiles(changedFiles, cwd); }
|
|
304
|
+
catch { publicFiles = [...changedFiles]; } // A missing/invalid manifest cannot prove these files are private.
|
|
305
|
+
}
|
|
306
|
+
const applicable = result.hits.filter((hit) => hit.marker !== 'skill-boundary' || changedFiles.includes(hit.file));
|
|
307
|
+
const missingReason: ExportLeakCheck['hits'][number][] = [];
|
|
308
|
+
const blockedHits: ExportLeakCheck['hits'][number][] = [];
|
|
309
|
+
let allowed = 0;
|
|
310
|
+
for (const hit of applicable) {
|
|
311
|
+
let lines: string[];
|
|
312
|
+
try { lines = readFileSync(join(cwd, hit.file), 'utf8').split(/\r?\n/); }
|
|
313
|
+
catch { blockedHits.push(hit); continue; }
|
|
314
|
+
const notes = [lines[hit.line - 1], lines[hit.line - 2]].filter((line): line is string => line !== undefined)
|
|
315
|
+
.map((line) => /(?:\/\/|\/\*|\*|#|<!--)\s*public-export-allow:\s*(.*)/u.exec(line));
|
|
316
|
+
if (notes.some((note) => note?.[1]?.replace(/(?:\*\/|-->)\s*$/u, '').trim())) { allowed++; continue; }
|
|
317
|
+
blockedHits.push(hit);
|
|
318
|
+
if (notes.some(Boolean)) missingReason.push(hit);
|
|
319
|
+
}
|
|
320
|
+
const blocked = (!result.measured && publicFiles.length > 0) || (blockedHits.length > 0 && !allow);
|
|
321
|
+
record('public-export-leak', !blocked, { measured: result.measured, hits: applicable.length, allowed });
|
|
322
|
+
debug.log('pr.land', 'leak-gate', { blocked, hits: applicable.map(({ file, marker }) => ({ file, marker })), measured: result.measured, allowed });
|
|
323
|
+
if (!result.measured) {
|
|
324
|
+
const write = blocked ? out.error : out.log;
|
|
325
|
+
write(`${blocked ? '✗' : '⚠'} public-export-leak: 못 쟀다${blocked ? ' — 막는다' : ' — 공개 대상 변경 없음'}(${result.detail ?? '?'}) · 확인: bun scripts/public-export.ts --leak-check --json --all --files <파일…>`);
|
|
326
|
+
return !blocked;
|
|
327
|
+
}
|
|
328
|
+
if (blockedHits.length === 0) { out.log('✓ public-export-leak: 바뀐 파일이 공개본에 사적 흔적을 싣지 않는다(prepare 와 같은 변환 뒤).'); return true; }
|
|
298
329
|
const write = allow ? out.log : out.error;
|
|
299
|
-
write(`${allow ? '⚠' : '✗'} public-export-leak: 바뀐 파일 ${
|
|
300
|
-
for (const
|
|
301
|
-
if (
|
|
330
|
+
write(`${allow ? '⚠' : '✗'} public-export-leak: 바뀐 파일 ${blockedHits.length}곳이 공개본에 사적 흔적을 싣는다 — 다음 release prepare 가 여기서 실패한다:`);
|
|
331
|
+
for (const hit of blockedHits.slice(0, 20)) write(` ${hit.file}:${hit.line} · ${hit.marker}${missingReason.includes(hit) ? ' · 사유 없음' : ''}`);
|
|
332
|
+
if (blockedHits.length > 20) write(` … 외 ${blockedHits.length - 20}곳`);
|
|
302
333
|
write(' 확인: bun scripts/public-export.ts --leak-check --all --files <파일…>');
|
|
303
334
|
if (allow) { out.log(' --allow-public-leak 로 넘긴다(이유는 --land-reason).'); return true; }
|
|
304
335
|
out.error(' 고치거나, 공개본과 무관한 것이 확실하면 --allow-public-leak --land-reason "<이유>" 로 넘긴다.');
|
|
@@ -319,8 +350,12 @@ export function publicLeakWarning(
|
|
|
319
350
|
record('public-leak-gate', true, { warnOnly: true, measured: false });
|
|
320
351
|
return;
|
|
321
352
|
}
|
|
322
|
-
record('public-leak-gate', true, { warnOnly: true, measured: rc !== 2, grew: rc === 1 });
|
|
353
|
+
record('public-leak-gate', true, { warnOnly: true, measured: rc !== 2, grew: rc === 1, shrank: rc === 3 });
|
|
323
354
|
if (rc === 0) { out.log('✓ public-leak-gate(경고 전용): 공개 유출이 늘지 않았다.'); return; }
|
|
355
|
+
if (rc === 3) {
|
|
356
|
+
for (const line of captured.filter((l) => /→/.test(l))) out.log(`✓ public-leak-gate(경고 전용): 공개 유출이 줄었다 · 기준선 --update 권장 — ${line.trim()}`);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
324
359
|
if (rc === 1) {
|
|
325
360
|
out.log('⚠ public-leak-gate(경고 전용 · 착지는 막지 않는다): 공개 유출이 늘었다 —');
|
|
326
361
|
for (const line of captured.filter((l) => /→/.test(l))) out.log(` ${line.trim()}`);
|
|
@@ -406,13 +441,14 @@ function gateVerdict(
|
|
|
406
441
|
label: string,
|
|
407
442
|
gate: (out: { log: (message: string) => void; error: (message: string) => void }) => boolean,
|
|
408
443
|
out: { log: (message: string) => void; error: (message: string) => void },
|
|
444
|
+
failClosed = false,
|
|
409
445
|
): { ok: boolean; measured: boolean } {
|
|
410
446
|
try {
|
|
411
447
|
return { ok: gate(out), measured: true };
|
|
412
448
|
} catch (error) {
|
|
413
449
|
out.error(`⚠ ${label}: 게이트가 «못 쟀다» — ${error instanceof Error ? error.message : String(error)}`);
|
|
414
|
-
out.error(`⚠ ${label}: 「위반 없음」이 아니라 「검사 못 함」이다. 이 착지는 통과시키되 게이트를
|
|
415
|
-
return { ok:
|
|
450
|
+
out.error(`⚠ ${label}: 「위반 없음」이 아니라 「검사 못 함」이다. ${failClosed ? '착지를 막는다.' : '이 착지는 통과시키되 게이트를 고쳐라.'}`);
|
|
451
|
+
return { ok: !failClosed, measured: false };
|
|
416
452
|
}
|
|
417
453
|
}
|
|
418
454
|
|
|
@@ -426,6 +462,21 @@ function record(step: string, ok: boolean, extra: Record<string, unknown> = {}):
|
|
|
426
462
|
debug.log('pr.land', 'step', { step, ok, ...extra });
|
|
427
463
|
}
|
|
428
464
|
|
|
465
|
+
export function nextMdWarning(body: string, changedFiles: readonly string[], out: { log: (message: string) => void }): void {
|
|
466
|
+
const section = body.split(/^## 릴리스 노트[ \t]*\r?$/m).at(-1)!;
|
|
467
|
+
const parsed = parseReleaseNoteSection(body);
|
|
468
|
+
const hasNote = parsed.fragment !== undefined || parsed.problems.length > 0;
|
|
469
|
+
const kind = parsed.fragment?.kind ?? (hasNote
|
|
470
|
+
? /^[ \t]*- 종류:[ \t]*(feat|fix|security|internal)[ \t]*\r?$/m.exec(section.split(/^#{1,6}[ \t]+/m)[0]!)?.[1]
|
|
471
|
+
: undefined);
|
|
472
|
+
const reason = hasNote
|
|
473
|
+
? (kind === 'feat' || kind === 'fix' || kind === 'security' ? `release-note:${kind}` : undefined)
|
|
474
|
+
: (changedFiles.some((file) => /^(?:apps\/pwa\/src\/|src\/cli\/|src\/dashboard\/)/.test(file)) ? 'user-facing-path' : undefined);
|
|
475
|
+
const warn = !!reason && !changedFiles.includes('release/next.md');
|
|
476
|
+
record('next-md', true, { warnOnly: true, reason: reason ?? (hasNote ? 'non-user-facing-note' : 'no-user-facing-path') });
|
|
477
|
+
if (warn) out.log('⚠ next-md: 사용자에게 보이는 변경인데 release/next.md 에 줄이 없습니다 — 공개 노트에서 빠집니다. 「- <kind> — <영어 한 문장>. Documentation: … Target: next.」 한 줄을 더하십시오.');
|
|
478
|
+
}
|
|
479
|
+
|
|
429
480
|
type PrRemoteCapability = 'github' | 'local-path' | 'no-remote' | 'other';
|
|
430
481
|
|
|
431
482
|
function isLocalRemote(raw: string): boolean {
|
|
@@ -1012,6 +1063,10 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1012
1063
|
out.error('✗ body: --body와 --body-file은 함께 사용할 수 없습니다.');
|
|
1013
1064
|
return 1;
|
|
1014
1065
|
}
|
|
1066
|
+
if (opts.allowPublicLeak && !opts.landReason?.trim()) {
|
|
1067
|
+
out.error('✗ public-export-leak: --allow-public-leak 에는 --land-reason "<이유>" 가 필요합니다.');
|
|
1068
|
+
return 1;
|
|
1069
|
+
}
|
|
1015
1070
|
if (opts.includeActiveRunFiles && opts.excludeActiveRunFiles) {
|
|
1016
1071
|
out.error('✗ active-run-files: --include-active-run-files와 --exclude-active-run-files는 함께 사용할 수 없습니다.');
|
|
1017
1072
|
return 1;
|
|
@@ -1323,8 +1378,9 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1323
1378
|
}
|
|
1324
1379
|
|
|
1325
1380
|
const changedPaths = currentChangePaths(run, cwd, staged, base, out);
|
|
1326
|
-
|
|
1327
|
-
|
|
1381
|
+
nextMdWarning(body ?? '', changedPaths, out);
|
|
1382
|
+
publicLeakWarning(changedPaths, deps.runPublicLeakGate ?? ((files, sink) => runPrLandPublicLeakGate(files, sink, cwd, base)), out);
|
|
1383
|
+
if (!exportLeakBlock(changedPaths, () => (deps.runExportLeakCheck ?? runPrLandExportLeakCheck)(changedPaths ?? [], cwd), opts.allowPublicLeak === true, out, cwd)) return 1;
|
|
1328
1384
|
if (publicDocPaths(changedPaths, () => true).length > 0) {
|
|
1329
1385
|
const top = run('git', ['rev-parse', '--show-toplevel'], { cwd });
|
|
1330
1386
|
const docsRoot = top.ok && top.out.trim() ? top.out.trim() : cwd;
|
|
@@ -1371,6 +1427,15 @@ export async function runPrLand(opts: PrLandOpts = {}, deps: PrLandDeps = {}): P
|
|
|
1371
1427
|
out.log('✓ ios-gate: scripts/ci-ios-unit-tests.ts PASS — iOS 순수-로직 시험이 «실제로 돌았고» 실패 0.');
|
|
1372
1428
|
}
|
|
1373
1429
|
|
|
1430
|
+
// PWA 는 bun test/tsc 밖의 정적 번들이다. 측정 불가도 착지 불가로 판정한다.
|
|
1431
|
+
const pwaGate = gateVerdict('pwa-gate', deps.runPwaGate
|
|
1432
|
+
? (o) => deps.runPwaGate!(o, changedPaths)
|
|
1433
|
+
: (o) => runPwaBuildGate({ args: ['--changed-files', ...changedPaths], cwd, log: o.log, error: o.error }) === 0, out, true);
|
|
1434
|
+
record('pwa-gate', pwaGate.ok && pwaGate.measured, { measured: pwaGate.measured });
|
|
1435
|
+
if (!pwaGate.ok || !pwaGate.measured) {
|
|
1436
|
+
out.error('✗ pwa-gate: scripts/ci-pwa-build-gate.ts blocked pr land — PWA 빌드 실패 또는 측정 불가.');
|
|
1437
|
+
return 1;
|
|
1438
|
+
}
|
|
1374
1439
|
|
|
1375
1440
|
const overlapFound = emitLandingOverlapAdvisory(run, cwd, base, changedPaths, out);
|
|
1376
1441
|
const siblingFound = emitSiblingPrAdvisory(
|
package/src/cli/pty-drive-cli.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { StreamLLMFn } from '../autopilot/llm-control-brain.js';
|
|
|
8
8
|
import { establishElanousTuiIsolation, elanousTuiSpawnOptions, type ElanousTuiIsolation } from '../self-implement/elanous-tui-spawn.js';
|
|
9
9
|
import { resolveObserveOnlyDecision } from '../self-implement/observe-only.js';
|
|
10
10
|
import { getUserConfig } from '../user-config.js';
|
|
11
|
+
import { verdictForFinalPtyScreen } from './pty-drive-verdict.js';
|
|
11
12
|
import { debug } from '../debug/log.js';
|
|
12
13
|
import { writeHarnessScreen } from '../harness/harness-screen.js';
|
|
13
14
|
import { resolveControlInboxDir } from '../harness/control-inbox.js';
|
|
@@ -19,6 +20,7 @@ import { resolvePtyRef } from '../pty-shell/pty-ref.js';
|
|
|
19
20
|
import { parsePtyWriteActor } from '../pty-shell/pty-write-arbiter.js';
|
|
20
21
|
import { controlDepsForHandle, controlDepsForRemoteRef, runPtyControlLoop } from '../autopilot/pty-control-loop.js';
|
|
21
22
|
import { createLlmControlBrain } from '../autopilot/llm-control-brain.js';
|
|
23
|
+
import { withDriveJail } from './drive-input-jail.js';
|
|
22
24
|
|
|
23
25
|
/** `pty list` 한 줄의 상태 컬럼 위치 — `<id>\t<kind>\t<nickname>\t<scope>\t<state>\t<extra…>`.
|
|
24
26
|
* ⚠️⛔ **회귀 테스트의 fixture 는 실측 형식의 *스냅샷*이지 형식 변경 감지기가 아니다**(리뷰 지적 · 과장 정정) —
|
|
@@ -166,6 +168,8 @@ export interface PtyDriveOpts {
|
|
|
166
168
|
readonly maxSteps?: number;
|
|
167
169
|
readonly pollMs?: number;
|
|
168
170
|
readonly model?: string;
|
|
171
|
+
/** DRIVE-JAIL: brain inputs naming paths outside this directory are not sent to the PTY. */
|
|
172
|
+
readonly jailHome?: string;
|
|
169
173
|
/** Enable the child SelfImplement observation-only override at boot. */
|
|
170
174
|
readonly observeOnly?: boolean;
|
|
171
175
|
readonly cwd?: string;
|
|
@@ -213,6 +217,8 @@ const liveAttachDriveDeps: PtyAttachDriveDeps = {
|
|
|
213
217
|
|
|
214
218
|
export interface PtyAttachDriveOpts {
|
|
215
219
|
readonly goal: string;
|
|
220
|
+
/** DRIVE-JAIL: brain inputs naming paths outside this directory are not sent to the PTY. */
|
|
221
|
+
readonly jailHome?: string;
|
|
216
222
|
readonly maxSteps?: number;
|
|
217
223
|
readonly pollMs?: number;
|
|
218
224
|
readonly model?: string;
|
|
@@ -250,8 +256,11 @@ export async function runPtyAttachDrive(ref: string, opts: PtyAttachDriveOpts, d
|
|
|
250
256
|
...(opts.stream ? { stream: opts.stream } : {}),
|
|
251
257
|
onDecision: (decision) => out(decision.action === 'input' ? ` → input (${decision.text.length} chars)\n` : decision.action === 'done' ? ` → done (${decision.reason})\n` : ' · wait\n'),
|
|
252
258
|
});
|
|
259
|
+
const controlDeps = withDriveJail(handle ? deps.controlDepsForHandle(handle) : deps.controlDepsForRemoteRef?.(id, { actor }) ?? (() => { throw new Error('pty auto: remote control dependencies unavailable'); })(), opts.jailHome, (event, data) => deps.log(event, data));
|
|
260
|
+
const inputHistory: string[] = [];
|
|
253
261
|
const result = await deps.runControlLoop(brain, {
|
|
254
|
-
...
|
|
262
|
+
...controlDeps,
|
|
263
|
+
inject: (text: string) => { inputHistory.push(text); return controlDeps.inject(text); },
|
|
255
264
|
subjectPtyId: id,
|
|
256
265
|
canReceiveInput: true,
|
|
257
266
|
}, {
|
|
@@ -260,7 +269,14 @@ export async function runPtyAttachDrive(ref: string, opts: PtyAttachDriveOpts, d
|
|
|
260
269
|
});
|
|
261
270
|
deps.log('attach-finish', { id, termination: result.termination.kind, steps: result.steps });
|
|
262
271
|
out(`\n▸ ${result.termination.kind} (${result.steps} steps)\n`);
|
|
263
|
-
|
|
272
|
+
if (result.termination.kind !== 'success') return { exitCode: 1, message: `pty auto: ${id} ${result.termination.kind}` };
|
|
273
|
+
// DRIVE-OK: «done» from the brain still has to show on the final screen.
|
|
274
|
+
let screen = '';
|
|
275
|
+
try { screen = String(await controlDeps.observe()); } catch { /* unreadable → unverified */ }
|
|
276
|
+
const verdict = verdictForFinalPtyScreen({ screen, inputHistory, exitCode: null });
|
|
277
|
+
out(`▸ verdict: ${verdict.kind} — ${verdict.reason}\n`);
|
|
278
|
+
deps.log('attach-verdict', { id, kind: verdict.kind, reason: verdict.reason.slice(0, 200) });
|
|
279
|
+
return { exitCode: verdict.kind === 'success' ? 0 : 1, message: `pty auto: ${id} ${verdict.kind}` };
|
|
264
280
|
}
|
|
265
281
|
|
|
266
282
|
export type PtyAttachDriveRunner = (start: () => Promise<{ readonly exitCode: number; readonly message: string }>) => Promise<void>;
|
|
@@ -273,14 +289,15 @@ export function registerPtyAttachDriveCommand(pty: Command, run: PtyAttachDriveR
|
|
|
273
289
|
.option('--poll-ms <ms>', 'screen polling interval in milliseconds', '800')
|
|
274
290
|
.option('--model <model>', 'LLM model override')
|
|
275
291
|
.option('--actor <who>', 'remote input actor (human or agent)', 'human')
|
|
292
|
+
.option('--jail-home <dir>', 'DRIVE-JAIL: do not send inputs naming paths outside this directory')
|
|
276
293
|
.description('Drive an existing agent-owned PTY without spawning a terminal')
|
|
277
|
-
.action((ref: string, opts: { goal: string; maxSteps: string; pollMs: string; model?: string; actor?: string }) => run(async () => {
|
|
294
|
+
.action((ref: string, opts: { goal: string; maxSteps: string; pollMs: string; model?: string; actor?: string; jailHome?: string }) => run(async () => {
|
|
278
295
|
const maxSteps = Number(opts.maxSteps);
|
|
279
296
|
const pollMs = Number(opts.pollMs);
|
|
280
297
|
const actor = parsePtyWriteActor(opts.actor);
|
|
281
298
|
if (!actor) return { exitCode: 2, message: 'pty auto: --actor must be human or agent' };
|
|
282
299
|
return Number.isInteger(maxSteps) && maxSteps >= 1 && Number.isInteger(pollMs) && pollMs >= 0
|
|
283
|
-
? runPtyAttachDrive(ref, { goal: opts.goal, maxSteps, pollMs, actor, ...(opts.model ? { model: opts.model } : {}) }, deps)
|
|
300
|
+
? runPtyAttachDrive(ref, { goal: opts.goal, maxSteps, pollMs, actor, ...(opts.model ? { model: opts.model } : {}), ...(opts.jailHome ? { jailHome: opts.jailHome } : {}) }, deps)
|
|
284
301
|
: { exitCode: 2, message: 'pty auto: --max-steps must be an integer >= 1 and --poll-ms must be an integer >= 0' };
|
|
285
302
|
}));
|
|
286
303
|
}
|
|
@@ -299,6 +316,8 @@ export interface DriveCliOpts {
|
|
|
299
316
|
json?: boolean;
|
|
300
317
|
/** Existing PTY ref. Absent = spawn a new shell PTY (the default). */
|
|
301
318
|
attach?: string;
|
|
319
|
+
/** DRIVE-JAIL boundary directory. */
|
|
320
|
+
jailHome?: string;
|
|
302
321
|
}
|
|
303
322
|
|
|
304
323
|
export interface DriveCliDeps {
|
|
@@ -357,6 +376,7 @@ export async function runDriveCliCommand(command: string | undefined, opts: Driv
|
|
|
357
376
|
attached = await runAttach(attach, {
|
|
358
377
|
goal: opts.goal, maxSteps, pollMs,
|
|
359
378
|
...(opts.model ? { model: opts.model } : {}),
|
|
379
|
+
...(opts.jailHome ? { jailHome: opts.jailHome } : {}),
|
|
360
380
|
});
|
|
361
381
|
} catch (err) {
|
|
362
382
|
writeError(`drive: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
@@ -379,6 +399,7 @@ export async function runDriveCliCommand(command: string | undefined, opts: Driv
|
|
|
379
399
|
command, goal: opts.goal, maxSteps, pollMs,
|
|
380
400
|
...(opts.model ? { model: opts.model } : {}),
|
|
381
401
|
...(opts.cwd ? { cwd: opts.cwd } : {}),
|
|
402
|
+
...(opts.jailHome ? { jailHome: opts.jailHome } : {}),
|
|
382
403
|
}));
|
|
383
404
|
} catch (err) {
|
|
384
405
|
writeError(`drive: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
@@ -827,7 +848,10 @@ async function runPtyDriveInner(opts: PtyDriveOpts): Promise<{ exitCode: number
|
|
|
827
848
|
writeScreen(screenKey, await h!.renderScreen(), process.env);
|
|
828
849
|
delivered = true;
|
|
829
850
|
} : undefined;
|
|
830
|
-
const
|
|
851
|
+
const rawDeps = withDriveJail(controlDepsForHandle(h), opts.jailHome, (event, data) => debug.log('pty.drive', event, data));
|
|
852
|
+
// DRIVE-OK: keep what we typed so the final verdict can tell child output from echoed input.
|
|
853
|
+
const inputHistory: string[] = [];
|
|
854
|
+
const deps = { ...rawDeps, inject: (text: string) => { inputHistory.push(text); return rawDeps.inject(text); } };
|
|
831
855
|
const autoAssist = opts.elanous ? getUserConfig().tools.selfImplement.autoAssist : undefined;
|
|
832
856
|
const observe = opts.elanous ? async () => {
|
|
833
857
|
const frame = await deps.observe();
|
|
@@ -851,12 +875,22 @@ async function runPtyDriveInner(opts: PtyDriveOpts): Promise<{ exitCode: number
|
|
|
851
875
|
if (screen.trim()) out(`▸ 최종 화면:\n${screen}\n`);
|
|
852
876
|
const childExit = h.exitCode;
|
|
853
877
|
const alive = h.isAlive();
|
|
854
|
-
|
|
878
|
+
// DRIVE-OK (10-03 X1: every step failed yet drive said ok): the brain's «done» is not proof —
|
|
879
|
+
// judge the final screen. Plain drives take the verdict as the exit; elanous-TUI drives only observe it.
|
|
880
|
+
const verdict = result.termination.kind === 'success' ? verdictForFinalPtyScreen({ screen, inputHistory, exitCode: childExit }) : null;
|
|
881
|
+
if (verdict) {
|
|
882
|
+
out(`▸ verdict: ${verdict.kind} — ${verdict.reason}\n`);
|
|
883
|
+
debug.log('pty.drive', 'verdict', { kind: verdict.kind, reason: verdict.reason.slice(0, 200), enforced: !opts.elanous });
|
|
884
|
+
}
|
|
885
|
+
const verdictFails = !!verdict && !opts.elanous && verdict.kind !== 'success';
|
|
886
|
+
const baseExit = childExit !== null
|
|
855
887
|
? childExit
|
|
856
888
|
: alive
|
|
857
889
|
? result.termination.kind === 'success' ? 0 : 1
|
|
858
890
|
: null;
|
|
859
|
-
|
|
891
|
+
// The verdict only withholds a success: nonzero and unknown (null) exits keep their meaning.
|
|
892
|
+
const exitCode = baseExit === 0 && verdictFails ? 1 : baseExit;
|
|
893
|
+
debug.log('pty.drive', 'exit-resolve', { alive, childExit, exitCode, termination: result.termination.kind, ...(verdict ? { verdict: verdict.kind } : {}) });
|
|
860
894
|
if (exitCode === null) out('▸ child exited without an exit code; reporting failure at the process boundary (exit 1)\n');
|
|
861
895
|
return { exitCode };
|
|
862
896
|
} finally {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Final-screen evidence is independent of the controller's "done" declaration.
|
|
2
|
+
export type PtyDriveVerdict =
|
|
3
|
+
| { readonly kind: 'done-but-failed'; readonly reason: string; readonly evidence: null }
|
|
4
|
+
| { readonly kind: 'success'; readonly reason: string; readonly evidence: string }
|
|
5
|
+
| { readonly kind: 'success-unverified'; readonly reason: string; readonly evidence: null };
|
|
6
|
+
|
|
7
|
+
export interface FinalPtyEvidence {
|
|
8
|
+
readonly screen: string;
|
|
9
|
+
readonly inputHistory: readonly string[];
|
|
10
|
+
readonly exitCode: number | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line no-control-regex
|
|
14
|
+
const ANSI = /\x1b(?:\][^\x07\x1b]*(?:\x07|\x1b\\)|\[[0-?]*[ -/]*[@-~]|[@-Z\\-_])/g;
|
|
15
|
+
const FAILURE = /(?:\bcommand not found\b|\bnot recognized as (?:an internal or external )?command\b|\bno such file or directory\b|\b(?:error|fatal|exception)\s*:|\berror TS\d+\b|\b(?:build failed|tests? failed|test suite failed|failed to|compilation failed|permission denied)\b|(?:^|\s)[1-9]\d*\s+fail(?:ed|ing|ures?)?\b|\b(?:exit(?:ed)? (?:with )?(?:code |status )?)[1-9]\d*\b|\bnpm ERR!\b|^\s*(?:FAIL\b|✗|❌))/i;
|
|
16
|
+
const SUCCESS = /(?:\b[1-9]\d*\s+(?:pass|passed)\b|\btests?:\s*[1-9]\d*\s+passed\b|\bbuild successful\b|\b(?:successfully|succeeded)\b|\bGOAL-COMPLETE\b)/i;
|
|
17
|
+
|
|
18
|
+
/** Failure wins over success; an exit code of zero is not itself proof of the goal. */
|
|
19
|
+
export function verdictForFinalPtyScreen({ screen, inputHistory, exitCode }: FinalPtyEvidence): PtyDriveVerdict {
|
|
20
|
+
if (exitCode !== null && exitCode !== 0) {
|
|
21
|
+
return { kind: 'done-but-failed', reason: `child exit code ${exitCode}`, evidence: null };
|
|
22
|
+
}
|
|
23
|
+
// The PTY may echo commands (including fabricated success markers). Only child output is evidence.
|
|
24
|
+
const inputs = new Set(inputHistory.flatMap((input) => input.replace(/\r/g, '\n').split('\n').map((line) => line.trim()).filter(Boolean)));
|
|
25
|
+
// An echo/printf command prints its operand; that output is not independent proof of anything
|
|
26
|
+
// (`echo "7 pass"` must not count as passing tests — review round 2).
|
|
27
|
+
const echoedLiterals = new Set([...inputs].flatMap((input) => {
|
|
28
|
+
const match = /^(?:echo(?:\s+-[neE]+)?|printf)\s+(.+)$/i.exec(input);
|
|
29
|
+
if (!match) return [];
|
|
30
|
+
const operand = match[1]!.trim().replace(/^(['"])(.*)\1$/s, '$2').replace(/\\n$/, '').trim();
|
|
31
|
+
return operand ? [operand] : [];
|
|
32
|
+
}));
|
|
33
|
+
const lines = screen.replace(ANSI, '').replace(/\r/g, '\n').split('\n')
|
|
34
|
+
.map((line) => line.trim()).filter((line) => line && !inputs.has(line) && !echoedLiterals.has(line) && ![...inputs].some((input) => line.endsWith(`$ ${input}`) || line.endsWith(`> ${input}`)));
|
|
35
|
+
const failure = lines.find((line) => FAILURE.test(line));
|
|
36
|
+
if (failure) return { kind: 'done-but-failed', reason: failure, evidence: null };
|
|
37
|
+
const evidence = lines.find((line) => SUCCESS.test(line) && !/\b0\s+(?:pass|passed)\b/i.test(line));
|
|
38
|
+
if (evidence) return { kind: 'success', reason: 'final PTY screen has success evidence', evidence };
|
|
39
|
+
return { kind: 'success-unverified', reason: 'final PTY screen has no success evidence', evidence: null };
|
|
40
|
+
}
|
package/src/cli/pwa-stop.ts
CHANGED
|
@@ -23,6 +23,12 @@ import { probeTailscale, type TailscaleProbe } from '../nexus/onboarding/tailsca
|
|
|
23
23
|
import { unregisterPwaInstance } from './pwa-registry.js';
|
|
24
24
|
import { readNexusLock } from '../nexus/supervisor/lock.js';
|
|
25
25
|
import { resolveNexusPwa, type NexusPwaResolution } from './nexus-show.js';
|
|
26
|
+
import { debug } from '../debug/log.js';
|
|
27
|
+
import { isPidAlive } from '../process/pid-liveness.js';
|
|
28
|
+
import { execFileSync } from 'node:child_process';
|
|
29
|
+
import { join as joinPath, resolve as resolvePath } from 'node:path';
|
|
30
|
+
import { hostname } from 'node:os';
|
|
31
|
+
import { safeReadLock } from '../telegram-lock.js';
|
|
26
32
|
|
|
27
33
|
export interface PwaStopOpts {
|
|
28
34
|
out?: { log: (s: string) => void; error: (s: string) => void };
|
|
@@ -45,7 +51,19 @@ export interface PwaStopOpts {
|
|
|
45
51
|
* from `~/.elanous/pwa-registry.json`. */
|
|
46
52
|
unregisterFn?: (pid: number) => void;
|
|
47
53
|
/** P4 — read the nexus lock to recover daemon pid. Test seam. */
|
|
48
|
-
readLockFn?: () => { pid: number } | null;
|
|
54
|
+
readLockFn?: () => { pid: number; host?: string; startedAt?: string } | null;
|
|
55
|
+
/** Isolated test daemon stop only: the project-local root to inspect for orphans. */
|
|
56
|
+
isolatedRoot?: string;
|
|
57
|
+
/** Test seams for signals, liveness and bounded polling. */
|
|
58
|
+
signalFn?: (pid: number, signal: 'SIGINT' | 'SIGTERM') => void;
|
|
59
|
+
pidAliveFn?: (pid: number) => boolean;
|
|
60
|
+
sleepFn?: (ms: number) => Promise<void>;
|
|
61
|
+
stopTimeoutMs?: number;
|
|
62
|
+
nowFn?: () => number;
|
|
63
|
+
/** Process table for isolated daemon identity checks and orphan discovery (pid, start time, argv). */
|
|
64
|
+
processTableFn?: () => Array<{ pid: number; startedAt: string; args: string }>;
|
|
65
|
+
/** Test seam for the raw `ps -eo pid=,lstart=,args=` response. */
|
|
66
|
+
psOutputFn?: () => string;
|
|
49
67
|
}
|
|
50
68
|
|
|
51
69
|
export type PwaStopShareUnmount =
|
|
@@ -57,7 +75,7 @@ export interface PwaStopResult {
|
|
|
57
75
|
exitCode: number;
|
|
58
76
|
/** True when the dev BG was actually killed (vs no-lock no-op). */
|
|
59
77
|
devKilled: boolean;
|
|
60
|
-
/** True when the
|
|
78
|
+
/** True when the daemon stop completed (or the ordinary stop trigger succeeded). */
|
|
61
79
|
nexusStopped: boolean;
|
|
62
80
|
/** True when `tailscale serve reset` was issued (not skipped). */
|
|
63
81
|
shareReset: boolean;
|
|
@@ -73,6 +91,126 @@ async function defaultNexusStop(): Promise<{ exitCode: number }> {
|
|
|
73
91
|
return { exitCode: 0 };
|
|
74
92
|
}
|
|
75
93
|
|
|
94
|
+
function runningProcesses(output: string): Array<{ pid: number; startedAt: string; args: string }> {
|
|
95
|
+
const lines = output.split('\n');
|
|
96
|
+
return lines.flatMap(line => {
|
|
97
|
+
const match = line.match(/^\s*(\d+)\s+((?:\S+\s+){4}\d{4})\s+(.+)$/);
|
|
98
|
+
return match ? [{ pid: Number(match[1]), startedAt: match[2]!, args: match[3]! }] : [];
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
type ProcessRow = ReturnType<typeof runningProcesses>[number];
|
|
103
|
+
|
|
104
|
+
function isolatedDaemons(root: string, table: ProcessRow[]): ProcessRow[] {
|
|
105
|
+
return table.filter(row => {
|
|
106
|
+
if (!/^(?:(?:\S*\/)?(?:bun|node)\s+)?(?:\S*\/)?elanous(?:\.(?:mjs|cjs))?\s/.test(row.args)
|
|
107
|
+
|| !/(?:^|\s)nexus\s+run(?:\s|$)/.test(row.args)) return false;
|
|
108
|
+
const roots = ['--config-dir', '--test-state-dir'].flatMap(flag => {
|
|
109
|
+
const value = row.args.match(new RegExp(`(?:^|\\s)${flag}(?:=|\\s+)(?:"([^"]+)"|'([^']+)'|(\\S+))`));
|
|
110
|
+
const arg = value?.[1] ?? value?.[2] ?? value?.[3];
|
|
111
|
+
return arg === undefined ? [] : [resolvePath(arg)];
|
|
112
|
+
});
|
|
113
|
+
return roots.length > 0 && roots.every(value => value === resolvePath(root));
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function stopIsolatedNexus(
|
|
118
|
+
opts: PwaStopOpts,
|
|
119
|
+
out: NonNullable<PwaStopOpts['out']>,
|
|
120
|
+
lock: ReturnType<NonNullable<PwaStopOpts['readLockFn']>>,
|
|
121
|
+
): Promise<{ exitCode: number }> {
|
|
122
|
+
const root = opts.isolatedRoot!;
|
|
123
|
+
const inspect = (): ProcessRow[] => isolatedDaemons(root, opts.processTableFn
|
|
124
|
+
? opts.processTableFn()
|
|
125
|
+
: runningProcesses((opts.psOutputFn ?? (() => execFileSync('ps', ['-eo', 'pid=,lstart=,args='], { encoding: 'utf8' })))()));
|
|
126
|
+
const reportOrphans = (): { exitCode: number } => {
|
|
127
|
+
const orphans = inspect();
|
|
128
|
+
debug.log('nexus.stop', 'orphans', { pid: 0, waitedMs: 0, count: orphans.length });
|
|
129
|
+
if (orphans.length === 0) {
|
|
130
|
+
out.log(' nothing to stop (no lock)');
|
|
131
|
+
return { exitCode: 0 };
|
|
132
|
+
}
|
|
133
|
+
for (const row of orphans) out.error(` orphan pid ${row.pid} · started ${row.startedAt} · root ${root}`);
|
|
134
|
+
out.error(` cleanup: ${orphans.map(row => `kill ${row.pid}`).join(' ; ')}`);
|
|
135
|
+
return { exitCode: 1 };
|
|
136
|
+
};
|
|
137
|
+
if (!lock) {
|
|
138
|
+
try { return reportOrphans(); }
|
|
139
|
+
catch (error) {
|
|
140
|
+
out.error(` cannot inspect nexus processes: ${error instanceof Error ? error.message : String(error)}`);
|
|
141
|
+
return { exitCode: 1 };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const pid = lock.pid;
|
|
145
|
+
if (lock.host && lock.host !== hostname()) {
|
|
146
|
+
out.error(` nexus lock held by remote host ${lock.host}; cannot stop from here`);
|
|
147
|
+
return { exitCode: 1 };
|
|
148
|
+
}
|
|
149
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) {
|
|
150
|
+
out.error(` invalid nexus lock pid ${pid}`);
|
|
151
|
+
return { exitCode: 1 };
|
|
152
|
+
}
|
|
153
|
+
const signal = opts.signalFn ?? ((target: number, name: 'SIGINT' | 'SIGTERM') => process.kill(target, name));
|
|
154
|
+
const alive = opts.pidAliveFn ?? isPidAlive;
|
|
155
|
+
const sleep = opts.sleepFn ?? ((ms: number) => new Promise<void>(resolve => setTimeout(resolve, ms)));
|
|
156
|
+
const timeout = opts.stopTimeoutMs ?? 10_000;
|
|
157
|
+
const now = opts.nowFn ?? Date.now;
|
|
158
|
+
let waitedMs = 0;
|
|
159
|
+
const wait = async (): Promise<boolean> => {
|
|
160
|
+
const start = now();
|
|
161
|
+
let elapsed = 0;
|
|
162
|
+
while (alive(pid) && elapsed < timeout) {
|
|
163
|
+
const interval = Math.min(100, timeout - elapsed);
|
|
164
|
+
await sleep(interval);
|
|
165
|
+
elapsed = Math.max(elapsed + interval, now() - start);
|
|
166
|
+
}
|
|
167
|
+
waitedMs += elapsed;
|
|
168
|
+
debug.log('nexus.stop', 'wait', { pid, waitedMs, count: 1 });
|
|
169
|
+
return !alive(pid);
|
|
170
|
+
};
|
|
171
|
+
try {
|
|
172
|
+
if (!alive(pid)) return reportOrphans();
|
|
173
|
+
const identity = inspect().find(row => row.pid === pid);
|
|
174
|
+
if (!identity) {
|
|
175
|
+
out.error(` pid ${pid} does not match this tree's isolated nexus daemon; no signal sent`);
|
|
176
|
+
return { exitCode: 1 };
|
|
177
|
+
}
|
|
178
|
+
if (lock.startedAt) {
|
|
179
|
+
const processStart = Date.parse(identity.startedAt);
|
|
180
|
+
const lockStart = Date.parse(lock.startedAt);
|
|
181
|
+
if (!Number.isFinite(processStart) || !Number.isFinite(lockStart) || processStart > lockStart + 1_000) {
|
|
182
|
+
out.error(` pid ${pid} start time cannot match the nexus lock; no signal sent`);
|
|
183
|
+
return { exitCode: 1 };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// Recheck the argv and start time immediately before each signal: a stale
|
|
187
|
+
// lock or a PID recycled during the wait must never target another process.
|
|
188
|
+
const stillOwned = (): boolean => inspect().some(row => row.pid === pid && row.startedAt === identity.startedAt && row.args === identity.args);
|
|
189
|
+
if (!stillOwned()) {
|
|
190
|
+
out.error(` pid ${pid} no longer matches the locked daemon; no signal sent`);
|
|
191
|
+
return { exitCode: 1 };
|
|
192
|
+
}
|
|
193
|
+
signal(pid, 'SIGINT');
|
|
194
|
+
out.log(` SIGINT sent to pid ${pid}`);
|
|
195
|
+
if (await wait()) return { exitCode: 0 };
|
|
196
|
+
if (!alive(pid)) return { exitCode: 0 };
|
|
197
|
+
if (!stillOwned()) {
|
|
198
|
+
out.error(` pid ${pid} no longer matches the locked daemon; SIGTERM not sent`);
|
|
199
|
+
return { exitCode: 1 };
|
|
200
|
+
}
|
|
201
|
+
signal(pid, 'SIGTERM');
|
|
202
|
+
debug.log('nexus.stop', 'escalated', { pid, waitedMs, count: 1 });
|
|
203
|
+
if (await wait()) return { exitCode: 0 };
|
|
204
|
+
} catch (error) {
|
|
205
|
+
out.error(` pid ${pid} 이 멈추지 않았다: ${error instanceof Error ? error.message : String(error)}`);
|
|
206
|
+
debug.log('nexus.stop', 'stuck', { pid, waitedMs, count: 1 });
|
|
207
|
+
return { exitCode: 1 };
|
|
208
|
+
}
|
|
209
|
+
out.error(` pid ${pid} 이 멈추지 않았다`);
|
|
210
|
+
debug.log('nexus.stop', 'stuck', { pid, waitedMs, count: 1 });
|
|
211
|
+
return { exitCode: 1 };
|
|
212
|
+
}
|
|
213
|
+
|
|
76
214
|
async function defaultShareReset(binary: string, port: number): Promise<{ exitCode: number }> {
|
|
77
215
|
const r = await unmountTailscaleServe({
|
|
78
216
|
mode: { kind: 'tls-tcp', port },
|
|
@@ -111,11 +249,12 @@ export async function runPwaStop(opts: PwaStopOpts = {}): Promise<PwaStopResult>
|
|
|
111
249
|
const out = opts.out ?? console;
|
|
112
250
|
const portResolution = resolveShareUnmountPort(opts);
|
|
113
251
|
const devStopFn = opts.devStopFn ?? (() => runPwaDevStop({ out }));
|
|
114
|
-
const nexusStopFn = opts.nexusStopFn ?? defaultNexusStop;
|
|
115
252
|
const shareProbeFn = opts.shareProbeFn ?? (() => probeTailscale());
|
|
116
253
|
const shareResetFn = opts.shareResetFn ?? defaultShareReset;
|
|
117
|
-
const unregisterFn = opts.unregisterFn ?? unregisterPwaInstance;
|
|
118
|
-
const readLockFn = opts.readLockFn ?? (
|
|
254
|
+
const unregisterFn = opts.unregisterFn ?? (opts.isolatedRoot ? undefined : unregisterPwaInstance);
|
|
255
|
+
const readLockFn = opts.readLockFn ?? (opts.isolatedRoot
|
|
256
|
+
? () => safeReadLock(joinPath(opts.isolatedRoot!, 'nexus', '.lock'))
|
|
257
|
+
: () => readNexusLock());
|
|
119
258
|
|
|
120
259
|
out.log('elanous nexus pwa stop: cascade');
|
|
121
260
|
|
|
@@ -157,19 +296,30 @@ export async function runPwaStop(opts: PwaStopOpts = {}): Promise<PwaStopResult>
|
|
|
157
296
|
}
|
|
158
297
|
|
|
159
298
|
// P4 registry unregister — read the lock for the daemon pid before
|
|
160
|
-
// we send SIGINT (the lock is removed during stop).
|
|
161
|
-
//
|
|
299
|
+
// we send SIGINT (the lock is removed during stop). The isolated stop
|
|
300
|
+
// never writes to the production registry. Missing lock/pid is best-effort.
|
|
162
301
|
let unregisteredPid: number | undefined;
|
|
302
|
+
let lock: ReturnType<typeof readLockFn> = null;
|
|
303
|
+
try { lock = readLockFn(); }
|
|
304
|
+
catch (error) {
|
|
305
|
+
if (opts.isolatedRoot) {
|
|
306
|
+
out.error(` cannot read nexus lock: ${error instanceof Error ? error.message : String(error)}`);
|
|
307
|
+
return { exitCode: 1, devKilled: false, nexusStopped: false, shareReset, shareUnmount };
|
|
308
|
+
}
|
|
309
|
+
}
|
|
163
310
|
try {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
311
|
+
if (lock && typeof lock.pid === 'number' && (!opts.isolatedRoot || !lock.host || lock.host === hostname())) {
|
|
312
|
+
if (unregisterFn) {
|
|
313
|
+
unregisterFn(lock.pid);
|
|
314
|
+
unregisteredPid = lock.pid;
|
|
315
|
+
}
|
|
168
316
|
}
|
|
169
|
-
} catch { /*
|
|
317
|
+
} catch { /* registry unregister failure — non-fatal */ }
|
|
170
318
|
|
|
171
319
|
const devR = await devStopFn();
|
|
172
|
-
const nexusR = await nexusStopFn(
|
|
320
|
+
const nexusR = await (opts.nexusStopFn ?? (opts.isolatedRoot
|
|
321
|
+
? () => stopIsolatedNexus(opts, out, lock)
|
|
322
|
+
: defaultNexusStop))();
|
|
173
323
|
const exitCode = devR.exitCode === 0 && nexusR.exitCode === 0 ? 0 : 1;
|
|
174
324
|
return {
|
|
175
325
|
exitCode,
|
package/src/cli/pwa-test.ts
CHANGED
|
@@ -720,8 +720,11 @@ async function runStop(
|
|
|
720
720
|
out,
|
|
721
721
|
shareProbeFn: async () => ({ installed: false, alive: false }),
|
|
722
722
|
shareResetFn: async () => ({ exitCode: 0 }),
|
|
723
|
+
isolatedRoot: layout.stateDir,
|
|
723
724
|
});
|
|
724
725
|
|
|
726
|
+
// Keep the record when the daemon did not stop; status must not imply a clean shutdown.
|
|
727
|
+
if (stopRes.exitCode !== 0) return { exitCode: stopRes.exitCode };
|
|
725
728
|
// Cleanup state files — leave logs/ for post-mortem.
|
|
726
729
|
const stateFile = joinPath(layout.stateDir, 'test-state.json');
|
|
727
730
|
if (existsSync(stateFile)) {
|