elanous 0.2.4 → 0.2.6
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/README.md +7 -6
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/1169-696263ac7af8c4d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1883.c91a2648af4842fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1947-9d64872eeb9cfdec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2808-dc06482994b40f70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5080-1613752891fcadb4.js → 2984-977cfa339fcd65a5.js} +3 -3
- package/apps/pwa/out/_next/static/chunks/3165-95515ca5f299a120.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8142-011e1f474efb8b33.js → 3190-e9282753e7ebde85.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3995-bee512a7063036ce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6062-73e68343a9814f6a.js → 4240-7153881b0b377306.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/4259-99614149577e77cb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4283-329eabeaf233e6cd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4328-cb5058b1acc2de5e.js +25 -0
- package/apps/pwa/out/_next/static/chunks/4801-ecee6ef62b349b18.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5110-8058791dd25a2e14.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3403.4bc97b4066945a94.js → 5329.8b7e4bca684b6eec.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/5330-c41e9670f594c38f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5423-e95fd125d1794349.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5478-b5eae07dc79ea619.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5787-96ee6642b9a661e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6448-79d72368589f98bc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6522-9866c002b5531836.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6729-b4a558b7aa891e0c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/6969-cb03f9410b7d2e03.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7007-3b9861091bb8dd21.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5791-bb82743fa6299562.js → 763-7d0e1913b5074e98.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{4323.c5dfb6f503304775.js → 7633.0654fe6ea259c1ee.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7930-8dc7e20fc6fc19ca.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8071-187edbc22a86741f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8198-d4101ad70cb9a579.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8250.4a2c5553a07cdf47.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8293-123b91e7b0330dc0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8296-d6d5d87dfa911d41.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8305-603963c33ee8eec3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8612-4a0066f20951b8fd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{2ea96958-e8c7e112de50b067.js → 8d0d9faf-97887ff99713b84e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9181-cf4e1b61c4783f92.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8046cadf-211ca3c0e00f2b72.js → 91ff6dda-3b33d42d20657429.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9262-26c2ecbd5a67e4a2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9328-45abdebce4fbecb7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9355-dbc67205adf8745f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9763.255b90dd69875689.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9933-66d31ec25c0231af.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-bd06fb55f4da0381.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-4e586142da455a25.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-889ad5cddcf45b0d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-47ba401d56572c27.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-0b54f9c83458e038.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/bots/page-4fcc296ef6c8ed90.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-fe9fda494a87f4e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-f9642e25ce129590.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-e1063e8ba5f3e2e7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-9d0df30027d8aa9d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-bd06fb55f4da0381.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-d97adf2c9455b8d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-236b80d202110362.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-21a30f35f1a276ad.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-b1a5be357c4fa25d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-1705a60303f7f573.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/page-76b337c11ad0e237.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-7c0f85fbb56f64c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-65ca16b20617b44d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-e7f9b8fc29411c1d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-92ea6213d1aeec04.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-a913a005aacb5476.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-2d78804a40dfdef6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-08a99148e780ac00.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-deb674e7ed36f815.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-49f8de0534d192d7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-bd06fb55f4da0381.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-ba162a28d2176e18.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-1ff1a37b550ab41a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-ccaa698f56c0fbdb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-53b944082de1d7db.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/page-9b70adf1552789bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-30d482aa63241fe8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-aecf786f54651d8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-6ab9b62c7b6e08f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-08949735455e0c9a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-a1479005234a46c2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-c3890e90bd232732.js +1 -0
- package/apps/pwa/out/_next/static/chunks/beb5cf10-9adcc10b83930090.js +1 -0
- package/apps/pwa/out/_next/static/chunks/framework-d68d41c88e05c801.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-11c63971b7a9593b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-d09452353bd0d9cc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-184d727cebeca767.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-21bbbbac99b720b1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{webpack-e5bea36f183b25e6.js → webpack-37b8bf78a3c6eec5.js} +1 -1
- package/apps/pwa/out/_next/static/css/eaa74e8bb2f62269.css +1 -0
- package/apps/pwa/out/_next/static/{zoQX5iTvXOsIvCjxCe1Ji → qMI0jnlZaBjjm4aIDYNGM}/_buildManifest.js +1 -1
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +29 -27
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +29 -27
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +29 -27
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +26 -24
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +26 -24
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +26 -24
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +29 -27
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +29 -27
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +29 -27
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/icons/elanous-16.png +0 -0
- package/apps/pwa/out/icons/elanous-180.png +0 -0
- package/apps/pwa/out/icons/elanous-192.png +0 -0
- package/apps/pwa/out/icons/elanous-32.png +0 -0
- package/apps/pwa/out/icons/elanous-512.png +0 -0
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +26 -24
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +29 -27
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +29 -27
- package/apps/pwa/out/manifest.webmanifest +5 -2
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +26 -24
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +26 -24
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +29 -27
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +29 -27
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +27 -25
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +29 -27
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +26 -24
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +29 -27
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +29 -27
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +29 -27
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +29 -27
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +29 -27
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +26 -24
- package/apps/pwa/out/sw-strategies.js +44 -0
- package/apps/pwa/out/sw.js +6 -44
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +29 -27
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +29 -27
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +29 -27
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +29 -27
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +29 -27
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +29 -27
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +29 -27
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +29 -27
- package/catalog/resources.yaml +6 -6
- package/docs/goal-context/steward-directives-2026-09-28.md +35 -37
- package/graphs/landing/landing-heal.yaml +1 -1
- package/graphs/release/recipes.yaml +11 -1
- package/graphs/release/release-loop.yaml +9 -2
- package/graphs/video/README.md +1 -0
- package/graphs/video/explainer-line.yaml +58 -0
- package/package.json +3 -1
- package/plugins/card-followup/README.md +33 -0
- package/plugins/card-followup/examples/card-sample.json +7 -0
- package/plugins/card-followup/graphs/card-followup.yaml +16 -0
- package/plugins/card-followup/graphs/recipes.yaml +12 -0
- package/plugins/card-followup/graphs/run-step.ts +172 -0
- package/plugins/card-followup/plugin.json +25 -0
- package/plugins/geo-check/README.md +13 -0
- package/plugins/geo-check/examples/brand-sample.json +8 -0
- package/plugins/geo-check/graphs/geo-check.yaml +20 -0
- package/plugins/geo-check/graphs/recipes.yaml +18 -0
- package/plugins/geo-check/graphs/run-step.ts +177 -0
- package/plugins/geo-check/plugin.json +24 -0
- package/plugins/job-coach/.codex-plugin/plugin.json +18 -1
- package/plugins/job-coach/README.md +42 -0
- package/plugins/job-coach/connectors/ncs/server.ts +4 -3
- package/plugins/job-coach/graphs/gap-judge.ts +44 -0
- package/plugins/job-coach/graphs/recipes.yaml +27 -0
- package/plugins/job-coach/graphs/report-enterprise.yaml +28 -0
- package/plugins/job-coach/graphs/run-step.ts +211 -17
- package/plugins/job-coach/plugin.json +16 -3
- package/plugins/job-coach/skills/enterprise-ai-fit/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-competency/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-needs/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-roadmap/SKILL.md +8 -0
- package/plugins/job-coach/skills/enterprise-task-analysis/SKILL.md +8 -0
- package/plugins/job-coach/skills/interview-to-profile/SKILL.md +18 -1
- package/scripts/backup/elanous-backup.sh +4 -1
- package/scripts/build-docs-site.ts +4 -3
- package/scripts/coord-channel-watch.sh +23 -4
- package/scripts/coord-post.sh +49 -12
- package/scripts/coord-tracks.json +5 -5
- package/scripts/daemon-port-baseline.txt +1 -2
- package/scripts/eval-bot-vs-grok.ts +79 -0
- package/scripts/eval-grok-live-baseline.ts +36 -0
- package/scripts/fixtures/front-route-corpus.sample.json +17 -0
- package/scripts/fleet/node-setup.sh +46 -7
- package/scripts/landing-heal/must-fix-match.ts +26 -0
- package/scripts/landing-heal/run-mission.ts +114 -20
- package/scripts/lib/android-test-device.ts +32 -0
- package/scripts/lib/front-route-measurement.ts +131 -0
- package/scripts/lib/tui-sim-keys.ts +42 -0
- package/scripts/measure-front-route-classifier.ts +56 -0
- package/scripts/media/ocr-leak-scan.sh +21 -0
- package/scripts/public-export.ts +2 -3
- package/scripts/public-import-pr.ts +80 -6
- package/scripts/publish-internal-dist.ts +2 -3
- package/scripts/red-sweep-diff.ts +1 -1
- package/scripts/release-loop/auto-approve-node.ts +72 -0
- package/scripts/release-loop/checklist-gate-node.ts +35 -0
- package/scripts/release-loop/gate-diff.ts +29 -0
- package/scripts/release-loop/gate-node.ts +366 -45
- package/scripts/release-loop/publish-node.ts +7 -3
- package/scripts/release-loop/release-docs.ts +20 -13
- package/scripts/release-loop/shard-plan.ts +47 -0
- package/scripts/release-loop/test-durations.ts +63 -0
- package/scripts/release-loop/upgrade-node.ts +3 -2
- package/scripts/test-audit-coverage-per-file.sh +16 -0
- package/scripts/test-audit-meaningless.ts +88 -0
- package/scripts/test-audit-overlap-and-weak.ts +73 -0
- package/scripts/test-deterministic.ts +27 -5
- package/scripts/tui-sim.ts +59 -14
- package/scripts/ux/bump-installed.sh +20 -0
- package/scripts/ux/lib/cdp.ts +72 -0
- package/scripts/ux/record-page.ts +53 -0
- package/skills/explainer-video/SKILL.md +117 -0
- package/skills/explainer-video/engine/brand/elanous-mark-on-dark.svg +1 -0
- package/skills/explainer-video/engine/build.mjs +431 -0
- package/skills/explainer-video/engine/reel.mjs +128 -0
- package/skills/explainer-video/engine/reel.sh +8 -0
- package/skills/explainer-video/engine/vo.ts +79 -0
- package/skills/explainer-video/examples/elanous-0.2.5/script.json +155 -0
- package/src/agent/nested-agent-env.ts +1 -0
- package/src/agent-mission/driver.ts +95 -16
- package/src/agent-mission/mission-cli.ts +6 -0
- package/src/agent-mission/resource-ladder.ts +73 -25
- package/src/auth/acp-token.ts +16 -0
- package/src/auth/github-app-token.ts +112 -0
- package/src/autopilot/gh-rest-fallback.ts +177 -0
- package/src/autopilot/mission-origin.ts +20 -4
- package/src/autopilot/mission-phase-track.ts +11 -1
- package/src/autopilot/pr-manager.ts +51 -4
- package/src/autopilot/track-agent.ts +3 -3
- package/src/autopilot/track-courier.ts +2 -2
- package/src/boot/acp-server.ts +2 -16
- package/src/boot/daemon-tools/web-search.ts +2 -1
- package/src/boot/ws-bridge.ts +11 -0
- package/src/chat/index.ts +37 -8
- package/src/chat/log-scroll-key.ts +12 -0
- package/src/chat/submit-trace.ts +30 -0
- package/src/cli/agent-cli.ts +7 -2
- package/src/cli/decisions-cli.ts +94 -0
- package/src/cli/doctor-cli.ts +40 -54
- package/src/cli/doctor-readiness.ts +16 -24
- package/src/cli/intake-cli.ts +1 -1
- package/src/cli/mcp-call.ts +9 -0
- package/src/cli/mcp-gateway-cli.ts +7 -3
- package/src/cli/nexus-ios-bind.ts +25 -8
- package/src/cli/phone-link.ts +117 -0
- package/src/cli/plugin-cli.ts +136 -11
- package/src/cli/pr-lineage.ts +2 -1
- package/src/cli/private-ledger-commands.ts +31 -0
- package/src/cli/pwa-start.ts +3 -0
- package/src/cli/release-cli.ts +97 -7
- package/src/cli/self-update.ts +7 -4
- package/src/cli/start-cli.ts +33 -14
- package/src/dashboard/acp-boot.ts +3 -0
- package/src/dashboard/index.ts +62 -13
- package/src/dashboard/input/no-provider-reply.ts +13 -0
- package/src/dashboard/slash-runtime/unknown-slash-reply.ts +78 -0
- package/src/dashboard/stale-install-check.ts +77 -0
- package/src/decisions/decision-ledger.ts +404 -0
- package/src/domains/outbound-alert.ts +13 -7
- package/src/domains/telegram-kind-route.ts +21 -0
- package/src/execution-loop/dispatch-task.ts +139 -0
- package/src/execution-loop/gate-decision-summary.ts +29 -0
- package/src/execution-loop/gates.ts +197 -0
- package/src/field/field-media.ts +245 -0
- package/src/graph-kinds/installed-plugin-nodes.ts +95 -0
- package/src/graph-kinds/plugin-nodes.ts +10 -2
- package/src/graph-runner/runner.ts +35 -5
- package/src/grounding/token.ts +12 -6
- package/src/harness/harness-cli-command.ts +68 -9
- package/src/harness/harness-pod-dispatch.ts +8 -2
- package/src/harness/harness-stop.ts +147 -18
- package/src/harness/self-send-decide.ts +26 -17
- package/src/harness/self-send-target.ts +22 -1
- package/src/harness/worktree-branch-prefix.ts +4 -3
- package/src/index.ts +50 -13
- package/src/instance/resolve.ts +6 -0
- package/src/intake-plane/collect-telegram-saved.ts +5 -0
- package/src/intake-plane/digest.ts +11 -2
- package/src/live/detail-switch.ts +8 -3
- package/src/llm/usable-llm.ts +32 -0
- package/src/loops/registry.ts +27 -5
- package/src/market/publish.ts +59 -3
- package/src/native-tool-catalog.ts +2 -2
- package/src/nexus/api/field-uploads.ts +143 -0
- package/src/nexus/api/graph-approvals.ts +174 -0
- package/src/nexus/api/harness-api.ts +219 -5
- package/src/nexus/api/http-server.ts +69 -6
- package/src/nexus/api/log-fabric.ts +10 -1
- package/src/nexus/api/mcp-oauth-hint.ts +10 -9
- package/src/nexus/api/merge-approvals.ts +2 -1
- package/src/nexus/api/meta-api.ts +14 -0
- package/src/nexus/api/plugins-credentials-api.ts +47 -0
- package/src/nexus/api/plugins-market.ts +87 -3
- package/src/nexus/api/pod-credential-api.ts +68 -14
- package/src/nexus/api/public-routes.ts +7 -0
- package/src/nexus/api/trace.ts +57 -6
- package/src/nexus/boot/register-mcp-clients.ts +99 -14
- package/src/nexus/index.ts +33 -32
- package/src/nexus/outbound/router.ts +1 -1
- package/src/notify/llm-budget-alert.ts +119 -0
- package/src/onboarding.ts +25 -2
- package/src/plugins/core/host.ts +14 -0
- package/src/plugins/install/market-fetch.ts +4 -3
- package/src/plugins/install/plugin-credentials.ts +106 -0
- package/src/plugins/install/plugin-install.ts +163 -32
- package/src/plugins/maker/plugin-maker.ts +208 -0
- package/src/prompt-library/universal-preamble.ts +8 -2
- package/src/relay/channel.ts +184 -0
- package/src/relay/mux.ts +182 -0
- package/src/relay/test-vectors.json +29 -0
- package/src/release-loop/checklist.ts +217 -0
- package/src/release-loop/release-note.ts +6 -3
- package/src/seat-address/seat-address.ts +34 -0
- package/src/self-dev/dev-cli.ts +40 -20
- package/src/self-dev/dev-pipeline.ts +77 -1
- package/src/self-implement/gate-baseline.ts +3 -1
- package/src/self-implement/goal-author.ts +18 -1
- package/src/self-implement/host-regate.ts +6 -2
- package/src/self-implement/orchestrator.ts +7 -2
- package/src/self-implement/run-ledger-compact.ts +1 -1
- package/src/self-implement/seams.ts +4 -2
- package/src/session/index.ts +23 -10
- package/src/skills/tools/dev-harness.ts +42 -0
- package/src/steward/steward-cards.ts +45 -0
- package/src/steward/triage.ts +50 -14
- package/src/task-orchestrator/surfaces/pod-artifact-return.ts +61 -3
- package/src/task-orchestrator/surfaces/pod-bun-cache.ts +18 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +36 -6
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +39 -9
- package/src/task-orchestrator/surfaces/pod-source-bundle.ts +16 -1
- package/src/task-orchestrator/surfaces/pod-source-receive.ts +51 -13
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +172 -28
- package/src/telegram-report.ts +12 -6
- package/src/telegram.ts +108 -1
- package/src/tui-client/acp-transport-ws-client.ts +72 -5
- package/src/tui.ts +3 -2
- package/src/user-config.ts +32 -2
- package/src/util/spawn-sync-output.ts +15 -0
- package/src/version/code-revision.ts +1 -1
- package/src/version/packed-revision.json +1 -1
- package/src/video-pipeline/recipes/explainer.ts +213 -0
- package/src/video-pipeline/walk-line.ts +3 -2
- package/src/web-search/free.ts +77 -0
- package/src/web-search/index.ts +2 -0
- package/src/workflow-runtime/deps-bridge.ts +4 -3
- package/src/workflow-runtime/plugin-kind-node.ts +32 -4
- package/src/workflow-runtime/types.ts +2 -1
- package/apps/pwa/out/_next/static/chunks/1105-c473ed46272fba79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1191-7b13a24117a689fa.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-3fcae5186c64fe6b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2415.ed6428ff334c7ce2.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/319-d37df1b6e0cbeff4.js +0 -1
- 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/4836-3c93795ab834381e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5609-012bb3557211f07e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6090-1bd6077591603947.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/7457-f5cb1cc8db9f7453.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-f74bf14d67ad98f1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8519-0059d82bdb4812bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8619-4365e03a2862830f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/920-f7dceb78f1c585ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9651-3cd291a6fa1370d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9740-52467f244755917f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9804-64c02c3c127d5014.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-21c3261af6ab377c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-1991445b8ea86274.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-4ebfaee2369fe248.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/page-9fa879ebf5959096.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-ca7c3cc305c3285a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-9951930add3d2051.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-4472ddf1e2458e69.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-4de08d4b766f134b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-7a975e2b9db1dfb7.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-49270714ef35bb96.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-33fbdf353e2a5982.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-259f122e2dd64317.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-65b82726753658e1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-4b8df3748dc06285.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-112f7e477bda77fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-542a5c0006da637c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-63ffb347831262ea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-98e4e359d97263b4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-97e24ac675ce576e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-ac6391f26391d89d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-9f45c9d45ffc43bd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-36995b9cb5d98218.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-0c795b577988d63f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-b4311e2f71c6735a.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-eb2381074df20dba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-b01336e64eba01ae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-7af7f21c1f2858ef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-a98ecd364586c89b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-57f0502dfbfa089b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-3467d2e1abd8a14a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-7842ca23d53ba682.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-ae9ac882912b0198.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-3a0d72e3f783bcef.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-f3b39fe8358c2a97.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-5a22af3181ac2afb.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-1457627bb302a22c.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/css/e66b7f5efc8df3f3.css +0 -1
- /package/apps/pwa/out/_next/static/{zoQX5iTvXOsIvCjxCe1Ji → qMI0jnlZaBjjm4aIDYNGM}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Named tui-sim keys and raw PTY input bytes.
|
|
2
|
+
const KEYS: Record<string, string> = {
|
|
3
|
+
enter: '\r', return: '\r', tab: '\t', 'shift-tab': '\x1b[Z', esc: '\x1b', escape: '\x1b',
|
|
4
|
+
space: ' ', backspace: '\x7f', delete: '\x1b[3~',
|
|
5
|
+
up: '\x1b[A', down: '\x1b[B', right: '\x1b[C', left: '\x1b[D',
|
|
6
|
+
pageup: '\x1b[5~', pagedown: '\x1b[6~', home: '\x1b[H', end: '\x1b[F',
|
|
7
|
+
'shift-enter': '\x1b[13;2u',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function resolveKeyBytes(name: string): string | null {
|
|
11
|
+
const key = name.toLowerCase();
|
|
12
|
+
if (Object.hasOwn(KEYS, key)) return KEYS[key]!;
|
|
13
|
+
if (/^ctrl-[a-z]$/.test(key)) return String.fromCharCode(key.charCodeAt(5) - 96);
|
|
14
|
+
if (key === 'ctrl-\\') return '\x1c';
|
|
15
|
+
if (key === 'ctrl-]') return '\x1d';
|
|
16
|
+
if (key.startsWith('hex:')) {
|
|
17
|
+
const hex = key.slice(4);
|
|
18
|
+
return hex.length > 0 && hex.length % 2 === 0 && /^[0-9a-f]+$/.test(hex)
|
|
19
|
+
? Buffer.from(hex, 'hex').toString('latin1')
|
|
20
|
+
: null;
|
|
21
|
+
}
|
|
22
|
+
if (key.startsWith('alt-')) {
|
|
23
|
+
const suffix = name.slice(4);
|
|
24
|
+
const bytes = Object.hasOwn(KEYS, suffix.toLowerCase()) ? KEYS[suffix.toLowerCase()]!
|
|
25
|
+
: suffix.toLowerCase().startsWith('ctrl-') ? resolveKeyBytes(suffix)
|
|
26
|
+
: [...suffix].length === 1 ? suffix : null;
|
|
27
|
+
return bytes === null ? null : `\x1b${bytes}`;
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Keep raw hex as a Buffer: passing a latin1 string to the PTY would UTF-8 encode bytes >= 0x80. */
|
|
33
|
+
export function resolveKeyInput(name: string): string | Buffer | null {
|
|
34
|
+
const bytes = resolveKeyBytes(name);
|
|
35
|
+
if (bytes === null) return null;
|
|
36
|
+
return name.toLowerCase().startsWith('hex:') ? Buffer.from(name.slice(4), 'hex') : bytes;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Bun's native PTY passes Buffer bytes through unchanged; its typed registry API only declares strings. */
|
|
40
|
+
export function writeKeyInput(handle: { write(chars: string): void }, input: string | Buffer): void {
|
|
41
|
+
handle.write(input as string);
|
|
42
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import type { ResolveRoleProviderFn } from '../src/intake-plane/runtime-callables.js';
|
|
4
|
+
import type { LLMProvider } from '../src/llm.js';
|
|
5
|
+
import { formatFrontRouteReport, loadFrontRouteCorpus, measureFrontRoute } from './lib/front-route-measurement.js';
|
|
6
|
+
|
|
7
|
+
interface RunnerOptions { providers: string[]; runs: number; json: boolean }
|
|
8
|
+
|
|
9
|
+
export function parseFrontRouteArgs(args: readonly string[]): RunnerOptions {
|
|
10
|
+
const options: RunnerOptions = { providers: [], runs: 1, json: false };
|
|
11
|
+
for (let i = 0; i < args.length; i++) {
|
|
12
|
+
const arg = args[i];
|
|
13
|
+
if (arg === '--json') options.json = true;
|
|
14
|
+
else if (arg === '--provider') {
|
|
15
|
+
const value = args[++i];
|
|
16
|
+
if (!value || value.startsWith('--') || !/^[\w-]+(?:\/\S+)?$/.test(value)) throw new Error('--provider requires <name>[/<model>]');
|
|
17
|
+
options.providers.push(value);
|
|
18
|
+
} else if (arg === '--runs') {
|
|
19
|
+
const value = args[++i];
|
|
20
|
+
if (!value || !/^[1-9]\d*$/.test(value) || !Number.isSafeInteger(Number(value))) throw new Error('--runs requires a positive integer');
|
|
21
|
+
options.runs = Number(value);
|
|
22
|
+
} else throw new Error(`Unknown option: ${arg}`);
|
|
23
|
+
}
|
|
24
|
+
return options;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function frontRouteProviders(specs: readonly string[], registry: Record<string, LLMProvider>): { label: string; resolve: ResolveRoleProviderFn }[] {
|
|
28
|
+
return specs.map((label) => {
|
|
29
|
+
const slash = label.indexOf('/');
|
|
30
|
+
const name = slash < 0 ? label : label.slice(0, slash);
|
|
31
|
+
const model = slash < 0 ? undefined : label.slice(slash + 1);
|
|
32
|
+
const provider = registry[name];
|
|
33
|
+
if (!provider) throw new Error(`Unknown provider: ${name}`);
|
|
34
|
+
const selectedModel = model ?? provider.defaultModel;
|
|
35
|
+
const resolveRole: ResolveRoleProviderFn = (_role) => ({ provider: provider as unknown as ReturnType<ResolveRoleProviderFn>['provider'], ...(typeof selectedModel === 'string' ? { model: selectedModel } : {}) });
|
|
36
|
+
return { label, resolve: resolveRole };
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function main(args: readonly string[] = process.argv.slice(2), env: NodeJS.ProcessEnv = process.env): Promise<void> {
|
|
41
|
+
const options = parseFrontRouteArgs(args);
|
|
42
|
+
if (!env.CORPUS_PATH?.trim()) throw new Error('CORPUS_PATH is required (path to front-route corpus JSON)');
|
|
43
|
+
const corpus = loadFrontRouteCorpus(readFileSync(resolve(process.cwd(), env.CORPUS_PATH), 'utf8'));
|
|
44
|
+
const { PROVIDERS } = await import('../src/llm.js');
|
|
45
|
+
let selected = options.providers;
|
|
46
|
+
if (!selected.length) {
|
|
47
|
+
const { resolveRoleLlm } = await import('../src/user-config.js');
|
|
48
|
+
const { provider, model } = resolveRoleLlm('classify');
|
|
49
|
+
selected = [model ? `${provider}/${model}` : provider];
|
|
50
|
+
}
|
|
51
|
+
const providers = frontRouteProviders(selected, PROVIDERS);
|
|
52
|
+
const result = await measureFrontRoute(corpus.items, { providers, runs: options.runs });
|
|
53
|
+
console.log(options.json ? JSON.stringify(result, null, 2) : formatFrontRouteReport(result));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (import.meta.main) await main();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/bin/zsh
|
|
2
|
+
# 공개 영상 누출 관문 — 1초 한 장(또는 --fps N) 전수 OCR → 금지 목록 → 초 단위 표(hits.tsv).
|
|
3
|
+
# 사용: scripts/media/ocr-leak-scan.sh <영상> <산출 폴더> [--fps N]
|
|
4
|
+
# 한계: tesseract eng — 한글 칸·이모지는 사람 눈으로 따로 본다(내부 문서 `TC` §2). 걸림은 오독이 많다 → 그 초 프레임을 눈으로 대조한다.
|
|
5
|
+
V=$1; O=$2; FPS=1
|
|
6
|
+
[ "${3:-}" = "--fps" ] && FPS=${4:-1}
|
|
7
|
+
[ -f "$V" ] && [ -n "$O" ] || { echo "사용: $0 <영상> <산출 폴더> [--fps N]" >&2; exit 2; }
|
|
8
|
+
command -v tesseract >/dev/null && command -v ffmpeg >/dev/null || { echo "tesseract·ffmpeg 가 필요하다" >&2; exit 2; }
|
|
9
|
+
mkdir -p "$O/f" && ffmpeg -loglevel error -i "$V" -vf "fps=$FPS" "$O/f/%05d.png" || exit 2
|
|
10
|
+
# 금지: 홈 경로 · 실명 계정 표지 · 사설 호스트 · tailnet · 금액 · 크레딧 수 · 메일 · 키·토큰 모양(elanous 단기 토큰 elt_ · bearer · GitHub 토큰 · 40자+ 연속)
|
|
11
|
+
PAT='/Users/|msb[0-9]|\bmbp\b|tail[0-9a-f]{4,}|ts\.net|\$[0-9]|USD|credit[s]? *[0-9]|@gmail|api[_-]?key|sk-[A-Za-z0-9]{8}|elt_[A-Za-z0-9_-]{6}|bearer|ghs_|gh[po]_|[A-Za-z0-9_-]{40,}'
|
|
12
|
+
[ -n "${OCR_EXTRA_PATTERN:-}" ] && PAT="$PAT|$OCR_EXTRA_PATTERN" # 계정 실명 등은 저장소에 적지 않고 환경변수로 준다
|
|
13
|
+
: > "$O/hits.tsv"
|
|
14
|
+
for f in "$O"/f/*.png; do
|
|
15
|
+
n=${${f:t:r}#0*}; s=$(( (n - 1) / FPS ))
|
|
16
|
+
t=$(tesseract "$f" - -l eng --psm 11 2>/dev/null)
|
|
17
|
+
print -r -- "$t" > "$O/f/${f:t:r}.txt"
|
|
18
|
+
print -r -- "$t" | grep -inE "$PAT" | grep -vE '^[0-9]+:[^ ]*run-[0-9a-f]{8}-[0-9a-f-]{27}$' \
|
|
19
|
+
| while read -r line; do print -r -- "$s\t$line" >> "$O/hits.tsv"; done
|
|
20
|
+
done
|
|
21
|
+
print "frames=$(ls "$O"/f/*.png | wc -l | tr -d ' ') hits=$(wc -l < "$O/hits.tsv" | tr -d ' ')"
|
package/scripts/public-export.ts
CHANGED
|
@@ -23,6 +23,7 @@ import { userInfo } from 'node:os';
|
|
|
23
23
|
import { dirname, join, posix, resolve } from 'node:path';
|
|
24
24
|
import ts from 'typescript';
|
|
25
25
|
import { parse } from 'yaml';
|
|
26
|
+
import { spawnSyncText } from '../src/util/spawn-sync-output.js';
|
|
26
27
|
|
|
27
28
|
export interface ExportTransform {
|
|
28
29
|
readonly id: string;
|
|
@@ -369,9 +370,7 @@ export function summarizeLeaks(hits: readonly LeakHit[]): Record<string, { hits:
|
|
|
369
370
|
}
|
|
370
371
|
|
|
371
372
|
function trackedFiles(root: string): string[] {
|
|
372
|
-
|
|
373
|
-
if (listed.status !== 0) throw new Error(`git ls-files failed: ${listed.stderr.trim()}`);
|
|
374
|
-
return listed.stdout.split('\0').filter(Boolean);
|
|
373
|
+
return spawnSyncText('git', ['-C', root, 'ls-files', '-z']).split('\0').filter(Boolean);
|
|
375
374
|
}
|
|
376
375
|
|
|
377
376
|
export function run(argv: readonly string[], root = resolve(import.meta.dir, '..')): number {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
/** Import a public PR patch without
|
|
2
|
+
/** Import a public PR patch without committing or publishing it. */
|
|
3
3
|
import { spawnSync } from 'node:child_process';
|
|
4
4
|
import { existsSync, lstatSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
5
5
|
import { tmpdir } from 'node:os';
|
|
6
6
|
import { dirname, isAbsolute, join } from 'node:path';
|
|
7
7
|
import { loadExportConfig, selectExportFiles, transformExportFiles } from './public-export.js';
|
|
8
|
+
import { debug } from '../src/debug/log.js';
|
|
9
|
+
import { spawnSyncText } from '../src/util/spawn-sync-output.js';
|
|
8
10
|
|
|
9
11
|
export type ImportKind = 'clean' | 'renamed' | 'transformed' | 'outside-export';
|
|
10
12
|
export interface ImportFile { publicPath: string; sourcePath?: string; kind: ImportKind; reason?: string }
|
|
@@ -83,9 +85,7 @@ function gitApply(root: string, patch: string, check = false): string | undefine
|
|
|
83
85
|
}
|
|
84
86
|
|
|
85
87
|
function trackedFiles(root: string): string[] {
|
|
86
|
-
|
|
87
|
-
if (result.status !== 0) throw new Error(`git ls-files failed: ${result.stderr}`);
|
|
88
|
-
return result.stdout.split('\0').filter(Boolean);
|
|
88
|
+
return spawnSyncText('git', ['ls-files', '-z'], { cwd: root, encoding: 'utf8' }).split('\0').filter(Boolean);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
/** Classify against the real export, stage eligible edits, then write only on --apply. */
|
|
@@ -177,8 +177,82 @@ export function importPublicPatch(patch: string, root: string, apply = false, au
|
|
|
177
177
|
} finally { rmSync(staging, { recursive: true, force: true }); }
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
interface GhResult { status: number | null; stdout: string; stderr?: string }
|
|
181
|
+
interface RunDeps { gh?: (argv: readonly string[], root: string) => GhResult }
|
|
182
|
+
|
|
183
|
+
function prAuthors(raw: string, databaseIdForLogin: (login: string) => number): string[] {
|
|
184
|
+
const parsed: unknown = JSON.parse(raw);
|
|
185
|
+
if (!parsed || typeof parsed !== 'object' || !('commits' in parsed) || !Array.isArray(parsed.commits) || !parsed.commits.length) {
|
|
186
|
+
throw new Error('PR has no commits');
|
|
187
|
+
}
|
|
188
|
+
const unique = new Map<string, string>();
|
|
189
|
+
const seenEmails = new Set<string>();
|
|
190
|
+
for (const commit of parsed.commits) {
|
|
191
|
+
const identities = commit?.authors ?? (commit?.author ? [commit.author] : []);
|
|
192
|
+
if (!Array.isArray(identities) || !identities.length) throw new Error('PR commit has no author');
|
|
193
|
+
for (const identity of identities) {
|
|
194
|
+
const name = identity?.name?.trim();
|
|
195
|
+
const email = identity?.email?.trim();
|
|
196
|
+
const login = identity?.login?.trim() ?? identity?.user?.login?.trim();
|
|
197
|
+
const key = login ? `login:${login.toLowerCase()}` : `email:${email?.toLowerCase()}`;
|
|
198
|
+
if (unique.has(key) || (email && seenEmails.has(email.toLowerCase()))) continue;
|
|
199
|
+
const id = identity?.user?.databaseId ?? identity?.id;
|
|
200
|
+
const numericId = /^[1-9]\d*$/.test(String(id)) ? Number(id) : undefined;
|
|
201
|
+
const address = email || (login && /^[A-Za-z0-9-]+$/.test(login)
|
|
202
|
+
? `${numericId && Number.isSafeInteger(numericId) ? numericId : databaseIdForLogin(login)}+${login}@users.noreply.github.com`
|
|
203
|
+
: undefined);
|
|
204
|
+
if (typeof name !== 'string' || !/^[^<>\r\n]+$/.test(name) || !address || !/^[^<>\s@]+@[^<>\s@]+$/.test(address)) {
|
|
205
|
+
throw new Error('PR commit author lacks a valid name or email/identity');
|
|
206
|
+
}
|
|
207
|
+
unique.set(key, `${name} <${address}>`);
|
|
208
|
+
seenEmails.add(address.toLowerCase());
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return [...unique.values()];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** CLI entrypoint: patch + --author, or --pr <number> --repo <owner/name>. */
|
|
215
|
+
export function run(argv: readonly string[], root = process.cwd(), stdin?: string, deps: RunDeps = {}): number {
|
|
216
|
+
const prMode = argv.includes('--pr') || argv.includes('--repo');
|
|
217
|
+
if (prMode) {
|
|
218
|
+
const prIndex = argv.indexOf('--pr');
|
|
219
|
+
const repoIndex = argv.indexOf('--repo');
|
|
220
|
+
const pr = argv[prIndex + 1];
|
|
221
|
+
const repo = argv[repoIndex + 1];
|
|
222
|
+
const flags = argv.filter((arg) => arg === '--apply' || arg === '--dry-run');
|
|
223
|
+
if (prIndex < 0 || repoIndex < 0 || !pr || !/^[1-9]\d*$/.test(pr) || !repo ||
|
|
224
|
+
!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repo) ||
|
|
225
|
+
argv.length !== 4 + flags.length || flags.length > 1 ||
|
|
226
|
+
argv.some((arg, i) => (arg === '--pr' && i !== prIndex) || (arg === '--repo' && i !== repoIndex))) {
|
|
227
|
+
console.error('usage: bun scripts/public-import-pr.ts --pr <number> --repo <owner/name> [--dry-run|--apply]');
|
|
228
|
+
return 2;
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
const gh = deps.gh ?? ((args: readonly string[], cwd: string) => spawnSync('gh', [...args], { cwd, encoding: 'utf8' }));
|
|
232
|
+
const fetch = (args: string[]): string => {
|
|
233
|
+
const result = gh(args, root);
|
|
234
|
+
if (result.status !== 0) throw new Error(result.stderr || `gh ${args[1]} failed`);
|
|
235
|
+
return result.stdout;
|
|
236
|
+
};
|
|
237
|
+
const patch = fetch(['pr', 'diff', pr, '--repo', repo]);
|
|
238
|
+
const authors = prAuthors(fetch(['pr', 'view', pr, '--repo', repo, '--json', 'commits']), (login) => {
|
|
239
|
+
const user: unknown = JSON.parse(fetch(['api', `users/${login}`]));
|
|
240
|
+
const id = user && typeof user === 'object' && 'id' in user ? user.id : undefined;
|
|
241
|
+
const resolvedLogin = user && typeof user === 'object' && 'login' in user ? user.login : undefined;
|
|
242
|
+
if (typeof id !== 'number' || !Number.isSafeInteger(id) || id <= 0 ||
|
|
243
|
+
typeof resolvedLogin !== 'string' || resolvedLogin.toLowerCase() !== login.toLowerCase()) {
|
|
244
|
+
throw new Error('GitHub user lacks a matching login or numeric database ID');
|
|
245
|
+
}
|
|
246
|
+
return id;
|
|
247
|
+
});
|
|
248
|
+
const result = importPublicPatch(patch, root, flags.includes('--apply'));
|
|
249
|
+
debug.log('public-import.pr', 'fetched', { repo, pr: Number(pr), files: result.files.length, authors: authors.length });
|
|
250
|
+
for (const file of result.files) console.log(`${file.kind}\t${file.publicPath}\t${file.sourcePath ?? '-'}${file.reason ? `\t${file.reason}` : ''}`);
|
|
251
|
+
console.log(`\nCommit message draft (not committed):\nImport public PR ${repo}#${pr}\n\nhttps://github.com/${repo}/pull/${pr}\n\n${authors.map((author) => `Co-Authored-By: ${author}`).join('\n')}`);
|
|
252
|
+
if (result.rc) console.error('import incomplete: one or more files were not applied');
|
|
253
|
+
return result.rc;
|
|
254
|
+
} catch (error) { console.error(`import failed: ${String(error)}`); return 1; }
|
|
255
|
+
}
|
|
182
256
|
const apply = argv.includes('--apply');
|
|
183
257
|
const authorIndex = argv.indexOf('--author');
|
|
184
258
|
const author = authorIndex >= 0 ? argv[authorIndex + 1] : undefined;
|
|
@@ -3,6 +3,7 @@ import { createHash } from 'node:crypto';
|
|
|
3
3
|
import { spawnSync } from 'node:child_process';
|
|
4
4
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, statSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
5
5
|
import { join, resolve } from 'node:path';
|
|
6
|
+
import { spawnSyncText } from '../src/util/spawn-sync-output.js';
|
|
6
7
|
|
|
7
8
|
export function publishInternalDist(checkout: string, out: string, keep = 3): { ok: true; version: string; commit: string; sha256: string; out: string; pwaBuild: 'present' | 'missing' } {
|
|
8
9
|
checkout = resolve(checkout);
|
|
@@ -42,9 +43,7 @@ export function publishInternalDist(checkout: string, out: string, keep = 3): {
|
|
|
42
43
|
const isBuildOutput = (path: string): boolean => path.startsWith('apps/pwa/out/') || path === 'src/version/packed-revision.json';
|
|
43
44
|
const publishedPaths = [...new Set([...packedPaths, 'scripts/install.sh'])].filter((path) => !isBuildOutput(path));
|
|
44
45
|
const pwaBuild: 'present' | 'missing' = packedPaths.includes('apps/pwa/out/index.html') ? 'present' : 'missing';
|
|
45
|
-
const
|
|
46
|
-
if (tracked.status !== 0) throw new Error(`cannot list committed files: ${tracked.stderr}`);
|
|
47
|
-
const committed = new Set(tracked.stdout.split('\0').filter(Boolean));
|
|
46
|
+
const committed = new Set(spawnSyncText('git', ['ls-files', '--cached', '-z'], { cwd: checkout, encoding: 'utf8' }).split('\0').filter(Boolean));
|
|
48
47
|
const uncommitted = publishedPaths.filter((path) => !committed.has(path));
|
|
49
48
|
if (uncommitted.length) throw new Error(`packed files not committed at HEAD: ${uncommitted.join(', ')}`);
|
|
50
49
|
const changed = spawnSync('git', ['diff', '--quiet', 'HEAD', '--', ...publishedPaths], { cwd: checkout, encoding: 'utf8' });
|
|
@@ -71,7 +71,7 @@ export async function main(argv: readonly string[]): Promise<number> {
|
|
|
71
71
|
const grown = diffs.filter((d) => d.newRed.length > 0);
|
|
72
72
|
if (argv.includes('--notify') && grown.length > 0) {
|
|
73
73
|
const { sendOutbound } = await import('../src/domains/outbound-alert.js');
|
|
74
|
-
sendOutbound(`⚠️ **파일별 빨강 스윕 — 새 빨강**\n\n${grown.map(renderDiff).join('\n\n')}`, 'alert');
|
|
74
|
+
sendOutbound(`⚠️ **파일별 빨강 스윕 — 새 빨강**\n\n${grown.map(renderDiff).join('\n\n')}`, 'ops-alert');
|
|
75
75
|
}
|
|
76
76
|
return diffs.length === 0 ? 2 : 0;
|
|
77
77
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
4
|
+
import { debug } from '../../src/debug/log.js';
|
|
5
|
+
import { effectiveInstanceRoot } from '../../src/instance/resolve.js';
|
|
6
|
+
import { emitNodeResult, readGraphContext, type GraphContext } from './node-verdict.js';
|
|
7
|
+
|
|
8
|
+
export type MetricVerdict = 'pass' | 'fail' | 'unmeasured';
|
|
9
|
+
export interface ApprovalMetric { name: string; value: string; verdict: MetricVerdict }
|
|
10
|
+
|
|
11
|
+
const outcomeMetric = (name: string, node: Record<string, unknown> | undefined): ApprovalMetric => ({
|
|
12
|
+
name, value: node?.outcome === undefined ? 'missing' : String(node.outcome),
|
|
13
|
+
verdict: node?.outcome === undefined ? 'unmeasured' : node.outcome === 'ok' ? 'pass' : 'fail',
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export function runAutoApprove(context: GraphContext = readGraphContext(), deps: { instanceRoot?: string; repo?: string; bunVersion?: string } = {}) {
|
|
17
|
+
const { version } = context.input;
|
|
18
|
+
const root = deps.instanceRoot ?? effectiveInstanceRoot();
|
|
19
|
+
const repo = deps.repo ?? resolve(import.meta.dir, '../..');
|
|
20
|
+
const gate = context.outputs.gate;
|
|
21
|
+
const prepare = context.outputs.prepare;
|
|
22
|
+
let pinned: string | undefined;
|
|
23
|
+
try { pinned = readFileSync(join(repo, '.bun-version'), 'utf8').trim(); } catch { pinned = undefined; }
|
|
24
|
+
const bunVersion = deps.bunVersion ?? Bun.version;
|
|
25
|
+
const out = prepare?.out;
|
|
26
|
+
let distCount: number | undefined;
|
|
27
|
+
if (prepare?.outcome === 'ok' && typeof out === 'string' && isAbsolute(out)
|
|
28
|
+
&& resolve(out) === join(root, 'release', version, 'prepared')) {
|
|
29
|
+
try { distCount = readdirSync(join(out, 'dist'), { withFileTypes: true }).filter((entry) => entry.isFile()).length; }
|
|
30
|
+
catch { distCount = undefined; }
|
|
31
|
+
}
|
|
32
|
+
const gateErrorAbsent = gate && !Object.hasOwn(gate, 'error');
|
|
33
|
+
const metrics: ApprovalMetric[] = [
|
|
34
|
+
{ name: 'gate regressions and measurement', value: JSON.stringify({ outcome: gate?.outcome ?? null, introduced: gate?.introduced ?? null, error: gate?.error ?? null }),
|
|
35
|
+
verdict: !gate || gate.outcome === undefined || !Array.isArray(gate.introduced) ? 'unmeasured'
|
|
36
|
+
: gate.outcome === 'ok' && gate.introduced.length === 0 && gateErrorAbsent ? 'pass' : 'fail' },
|
|
37
|
+
{ name: 'bun version', value: `running=${bunVersion}; pinned=${pinned ?? 'missing'}`,
|
|
38
|
+
verdict: !pinned ? 'unmeasured' : bunVersion === pinned ? 'pass' : 'fail' },
|
|
39
|
+
outcomeMetric('upgrade', context.outputs.upgrade),
|
|
40
|
+
outcomeMetric('tui', context.outputs.tui),
|
|
41
|
+
outcomeMetric('notes-check', context.outputs['notes-check']),
|
|
42
|
+
{ name: 'public leak and prepare completeness', value: `prepare=${prepare?.outcome ?? 'missing'}`,
|
|
43
|
+
verdict: prepare?.outcome === undefined ? 'unmeasured' : prepare.outcome === 'ok' ? 'pass' : 'fail' },
|
|
44
|
+
{ name: 'docs notes page', value: `docs=${context.outputs.docs?.outcome ?? 'missing'}; notes=${String(context.outputs.docs?.notes ?? 'missing')}`,
|
|
45
|
+
verdict: context.outputs.docs?.outcome === undefined || context.outputs.docs.notes === undefined ? 'unmeasured'
|
|
46
|
+
: context.outputs.docs.outcome === 'ok' && typeof context.outputs.docs.notes === 'string' && context.outputs.docs.notes.trim() ? 'pass' : 'fail' },
|
|
47
|
+
{ name: 'installation files', value: `dist files=${distCount ?? 'missing'}; prepare.out=${String(out ?? 'missing')}`,
|
|
48
|
+
verdict: prepare?.outcome !== 'ok' ? prepare?.outcome === undefined ? 'unmeasured' : 'fail'
|
|
49
|
+
: distCount === undefined ? 'unmeasured' : distCount === 5 ? 'pass' : 'fail' },
|
|
50
|
+
];
|
|
51
|
+
const outcome = metrics.every((metric) => metric.verdict === 'pass') ? 'ok' as const : 'fail' as const;
|
|
52
|
+
const report = join(root, 'release', version, 'auto-approval.md');
|
|
53
|
+
const lines = [`# v${version} auto-approval`, '', `Outcome: ${outcome}`, '', '| # | Metric | Value | Verdict |', '|---|---|---|---|',
|
|
54
|
+
...metrics.map((metric, i) => `| ${i + 1} | ${metric.name} | ${metric.value.replaceAll('|', '\\|').replace(/[\r\n]/g, ' ')} | ${metric.verdict} |`),
|
|
55
|
+
'', '## 되돌리는 법', `gh release edit v${version} --draft`, `git tag -d v${version} && git push origin :refs/tags/v${version}`, '해당 docs PR revert', ''];
|
|
56
|
+
mkdirSync(dirname(report), { recursive: true });
|
|
57
|
+
writeFileSync(report, lines.join('\n'));
|
|
58
|
+
debug.log('release-loop.approve', 'auto-decision', { version, outcome, metrics });
|
|
59
|
+
return { outcome, verdict: outcome === 'ok' ? 'pass' as const : 'fail' as const, summary: `auto approval ${outcome}: ${metrics.filter((metric) => metric.verdict === 'pass').length}/8`,
|
|
60
|
+
...(outcome === 'ok' ? { decidedBy: 'release-loop metrics' as const } : {}), metrics, report };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (import.meta.main) {
|
|
64
|
+
try {
|
|
65
|
+
const result = runAutoApprove();
|
|
66
|
+
emitNodeResult(result);
|
|
67
|
+
process.exitCode = result.outcome === 'ok' ? 0 : 1;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
emitNodeResult({ outcome: 'fail', verdict: 'fail', summary: `auto approval unmeasured: ${error instanceof Error ? error.message : String(error)}` });
|
|
70
|
+
process.exitCode = 1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { addItem, checklistGate, listChecklist, summarizeChecklist } from '../../src/release-loop/checklist.js';
|
|
3
|
+
import { emitNodeResult, errorResult, readGraphContext, type GraphContext } from './node-verdict.js';
|
|
4
|
+
|
|
5
|
+
export function runChecklistGate(context: GraphContext = readGraphContext()) {
|
|
6
|
+
const version = context.input.version;
|
|
7
|
+
const data = listChecklist(version);
|
|
8
|
+
const gate = checklistGate(version);
|
|
9
|
+
const counts = summarizeChecklist(data);
|
|
10
|
+
const summary = `확인표 🟢${counts.green} 🟡${counts.yellow}(이동 ${gate.moved.length} · 알려진 문제 ${gate.knownIssues.length} · 막음 ${gate.blocked.length} · 판정 없음 ${gate.undecided.length}) 🔴${counts.red}${gate.red.length ? ` (${gate.red.join(', ')})` : ''}`;
|
|
11
|
+
if (gate.ok && gate.moved.length) {
|
|
12
|
+
const [major, minor, patch] = version.split('.').map(Number);
|
|
13
|
+
const next = `${major}.${minor}.${patch! + 1}`;
|
|
14
|
+
for (const id of gate.moved) {
|
|
15
|
+
const item = data.items.find((candidate) => candidate.id === id)!;
|
|
16
|
+
if (listChecklist(next).items.some((candidate) => candidate.id === id)) continue;
|
|
17
|
+
try { addItem(next, { id, title: item.title, ...(item.owner !== undefined ? { owner: item.owner } : {}) }); }
|
|
18
|
+
catch (error) {
|
|
19
|
+
if (!listChecklist(next).items.some((candidate) => candidate.id === id)) throw error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return { outcome: gate.ok ? 'ok' as const : 'fail' as const, verdict: gate.ok ? 'pass' as const : 'fail' as const, summary, ...gate };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (import.meta.main) {
|
|
27
|
+
try {
|
|
28
|
+
const result = runChecklistGate();
|
|
29
|
+
emitNodeResult(result);
|
|
30
|
+
process.exitCode = result.outcome === 'ok' ? 0 : 1;
|
|
31
|
+
} catch (error) {
|
|
32
|
+
emitNodeResult(errorResult(error));
|
|
33
|
+
process.exitCode = 2;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -18,6 +18,35 @@ export function parseFailures(output: string): string[] {
|
|
|
18
18
|
return [...failures].sort();
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
const xmlText = (value: string): string => value
|
|
22
|
+
.replace(/"/g, '"').replace(/'/g, "'").replace(/</g, '<').replace(/>/g, '>')
|
|
23
|
+
.replace(/&#(\d+);/g, (_, code: string) => String.fromCodePoint(Number(code))).replace(/&/g, '&');
|
|
24
|
+
|
|
25
|
+
/** Failed test names from a bun junit report, in the same `<file> > <describe> > <name>` shape as {@link parseFailures}.
|
|
26
|
+
* Used when the console summary counts a failure but prints no `(fail)` line for it (09-30 0.2.6 gate: `--dots`). */
|
|
27
|
+
export function junitFailures(xml: string): string[] {
|
|
28
|
+
const failures = new Set<string>();
|
|
29
|
+
const suites: string[] = [];
|
|
30
|
+
let file: string | undefined;
|
|
31
|
+
let open: string | undefined;
|
|
32
|
+
for (const match of xml.matchAll(/<(\/?)(testsuite|testcase|failure)\b([^>]*?)(\/?)>/g)) {
|
|
33
|
+
const [, closing, tag, attrs, selfClosing] = match;
|
|
34
|
+
const attr = (name: string) => { const m = new RegExp(`\\b${name}="([^"]*)"`).exec(attrs!); return m ? xmlText(m[1]!) : undefined; };
|
|
35
|
+
if (tag === 'testsuite') {
|
|
36
|
+
if (closing) { suites.pop(); continue; }
|
|
37
|
+
suites.push(attr('name') ?? '');
|
|
38
|
+
if (suites.length === 1) file = attr('file') ?? attr('name');
|
|
39
|
+
} else if (tag === 'testcase') {
|
|
40
|
+
if (closing) { open = undefined; continue; }
|
|
41
|
+
const name = [...suites.slice(1), attr('name') ?? ''].join(' > ');
|
|
42
|
+
open = selfClosing ? undefined : `${attr('file') ?? file} > ${name}`;
|
|
43
|
+
} else if (tag === 'failure' && !closing && open) {
|
|
44
|
+
failures.add(open);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return [...failures].sort();
|
|
48
|
+
}
|
|
49
|
+
|
|
21
50
|
export function diffFailures(cut: Iterable<string>, baseline: Iterable<string>): FailureDiff {
|
|
22
51
|
const c = new Set(cut);
|
|
23
52
|
const b = new Set(baseline);
|