elanous 0.2.16 → 0.2.18
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/P6YTVgzuZz5oTZhY4Din_/_buildManifest.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1307-b46d45b705e8c9ae.js → 1307-30dff22c9e1f3073.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/195-fb1d7690bf30bab4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1986-33e13d648a9df765.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2537-6c289376caa88ca1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2699-325cc923ba7b8631.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3857-4f936cdb30322aa6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4554-5761612531d0146b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4565-3d7e3fdeb43686a8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5977-a11f37254196b659.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{6158.9c0449a9a8d0064b.js → 6158.af2e93b7adff709b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6877-74399f69c7da1433.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7797-df5aa0381fdc078f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8401-8615a660c84cdb03.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8695-846034ce44852c70.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9247-269e4464cc4b491c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-d92f7ee3994e84c7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-3cb52e5ea8fc2fa5.js → page-4733c967b56a4277.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-d22fd849cc22f104.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-c1e20d7d338713f1.js → page-bb742f995c6769e7.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/{page-482c5dbde699947c.js → page-02b073a2ac793b83.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-60c3da708f9a0ccc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-8a9b3594bc23289b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-a0eb02638b1e6f31.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/{page-a0e2a6d1bfb52fc5.js → page-308111abadf35670.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-6eaf7bac37830c21.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/{page-c53598cfce6156f2.js → page-5d97b2901e0d1ea6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/{page-13a63953f53c6a23.js → page-c39554c321576982.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/{page-5d3c8429d04f3831.js → page-8c3d8e63ae2e1c98.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/field/{page-3193bdc0bbab047a.js → page-9b72a07d424701c6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-bd5d586429167fea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/{page-6107ca8ddd5e3bdd.js → page-a572f58cd3ca5864.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-59b7834d497c2255.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-be5ea965a07fbc41.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-c130b63862437814.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-fa244bd146a00ae8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-44d56d6391965a6a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-4167348049166852.js → page-83a700d4c754d802.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/{not-found-de52e8fdf9095f7a.js → not-found-7b3170f374f77b9d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-5f23d0c66a3b4793.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-ca3952cd78a83ca2.js → page-a3c58f5c72a5f3f9.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a2c4625596f8d69c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-0e9099531d239f11.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-e8e1ecaea7cd71d2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-a1b7ffed710a93e0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/{page-1ebfe049c640e171.js → page-1467047104141297.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-2da6f9b8a38c6978.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-102310930791197a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-f331e38fefc00393.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/page-6ed0b73bae8351d8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/{page-abe8e3b74bea1ffc.js → page-44d5f767491692bf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-43336055451f6e37.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/{page-d28573d6792b4275.js → page-3cc47dca0922ab9a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-a77ee355a2304ff0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/{page-d751de5f8062ff5e.js → page-b17cd46cf0e9b8cf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/term/{page-fe1759f94003b32b.js → page-61553851aa606146.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/{page-d64c984e855c8c68.js → page-a1f585e154e61c59.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-7bf54c9bb9274af8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/{page-9afdee66b820c76e.js → page-5150ef17b5383a57.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b9d8ce70792c1672.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-a5a3de231f2cc7d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/{page-3544f154c87b43ee.js → page-134da468538baf48.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31ac4afa2dcd915c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{webpack-539cde99554be20f.js → webpack-c2782b330447ffb6.js} +1 -1
- package/apps/pwa/out/_next/static/css/7fa358fec7da7c47.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +14 -14
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +14 -14
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +14 -14
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +14 -14
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +14 -14
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +14 -14
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +14 -14
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +14 -14
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +14 -14
- package/apps/pwa/out/decisions/index.html +1 -0
- package/apps/pwa/out/decisions/index.txt +30 -0
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +14 -14
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +14 -14
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +14 -14
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +14 -14
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +14 -14
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +14 -14
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +14 -14
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +14 -14
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +14 -14
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +14 -14
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +14 -14
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +14 -14
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +14 -14
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +14 -14
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +14 -14
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +14 -14
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +14 -14
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +15 -15
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +14 -14
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +14 -14
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +14 -14
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +14 -14
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +14 -14
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +14 -14
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +14 -14
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +14 -14
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +14 -14
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +14 -14
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +14 -14
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +14 -14
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +14 -14
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +14 -14
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +14 -14
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +14 -14
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +14 -14
- package/graphs/intake/intake-daily.yaml +9 -2
- package/graphs/intake/news-sources.yaml +4 -0
- package/graphs/intake/recipes.yaml +6 -1
- package/package.json +2 -1
- package/samples/workflows/templates/approval-gated-deploy.yaml +30 -0
- package/samples/workflows/templates/chat-driven-research.yaml +35 -0
- package/samples/workflows/templates/discord-listen-and-respond.yaml +29 -0
- package/samples/workflows/templates/http-poll-then-alert.yaml +30 -0
- package/samples/workflows/templates/manual-quickstart.yaml +21 -0
- package/samples/workflows/templates/scheduled-daily-digest.yaml +30 -0
- package/samples/workflows/templates/webhook-deploy-hook.yaml +27 -0
- package/scripts/__fixtures__/intake-news.xml +7 -0
- package/scripts/ci-public-export-import-gate.ts +7 -2
- package/scripts/ci-typecheck-changed.ts +21 -6
- package/scripts/discord-seat-probe.ts +3 -2
- package/scripts/docs/generate-cli-anatomy.ts +162 -0
- package/scripts/goals/authoring-metrics.ts +73 -0
- package/scripts/intake-news.ts +169 -0
- package/scripts/landing-heal/must-fix-match.ts +7 -7
- package/scripts/landing-heal/run-mission.ts +3 -2
- package/scripts/public-export-test-run.ts +37 -2
- package/scripts/release-loop/checklist-gate-node.ts +13 -11
- package/scripts/release-loop/cut-branch.ts +2 -1
- package/scripts/release-loop/cutoff.ts +4 -2
- package/scripts/release-loop/docs-land-node.ts +77 -11
- package/scripts/release-loop/docs-node.ts +1 -1
- package/scripts/release-loop/gate-node.ts +99 -14
- package/scripts/release-loop/node-verdict.ts +2 -1
- package/scripts/release-loop/npm-publish-node.ts +11 -7
- package/scripts/release-loop/ops-upgrade-node.ts +8 -1
- package/scripts/release-loop/preflight.ts +246 -0
- package/scripts/release-loop/publish-node.ts +10 -3
- package/scripts/release-loop/release-docs.ts +134 -0
- package/scripts/release-loop/release-readiness.ts +11 -6
- package/scripts/release-loop/release-version.ts +48 -0
- package/scripts/release-loop/resume-release.ts +115 -0
- package/scripts/release-loop/unattended-release.ts +43 -7
- package/scripts/release-loop/version-node.ts +149 -41
- package/scripts/release-story/draft.ts +42 -14
- package/scripts/rhythm/daily.ts +25 -4
- package/scripts/skills/public-check.ts +62 -12
- package/scripts/test-deterministic.ts +51 -33
- package/scripts/test-diet/effectiveness.ts +62 -1
- package/scripts/test-diet/lib.ts +1 -1
- package/scripts/test-diet/node.ts +8 -1
- package/src/agent-mission/driver.ts +53 -10
- package/src/agent-mission/review-loop.ts +4 -3
- package/src/agent-substrate/pr-comment-meta.ts +20 -0
- package/src/autopilot/build/llm-conflict-merge.ts +28 -8
- package/src/autopilot/track-agent.ts +5 -3
- package/src/briefing/brief-items.ts +86 -17
- package/src/cli/autopilot-cli.ts +86 -1
- package/src/cli/brief-cli.ts +36 -2
- package/src/cli/decisions-cli.ts +4 -1
- package/src/cli/freeze-cli.ts +3 -2
- package/src/cli/intake-cli.ts +74 -2
- package/src/cli/log-event-names.ts +1 -0
- package/src/cli/notify-cli.ts +75 -0
- package/src/cli/pr-cli.ts +12 -1
- package/src/cli/provider-cli.ts +24 -0
- package/src/cli/release-cli.ts +101 -17
- package/src/cli/self-update-canary.ts +46 -0
- package/src/cli/self-update.ts +200 -1
- package/src/cli/tasks-cli.ts +309 -3
- package/src/context-bus/condense.ts +19 -3
- package/src/context-bus/context-day.ts +77 -24
- package/src/context-bus/context-first.ts +33 -0
- package/src/context-card/index.ts +45 -0
- package/src/context-card/task.ts +76 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +2 -0
- package/src/decisions/decision-ledger.ts +10 -1
- package/src/discord-self-message.ts +20 -2
- package/src/discord-slash-wire.ts +1 -0
- package/src/domains/outbound-alert.ts +200 -27
- package/src/domains/outbound-log-probe.ts +16 -1
- package/src/domains/release-tool.ts +2 -2
- package/src/execution-loop/gates.ts +11 -2
- package/src/flow-loop/split.ts +8 -4
- package/src/git-fs/worktree.ts +23 -3
- package/src/harness/harness-cli-command.ts +151 -11
- package/src/harness/harness-pod-dispatch.ts +11 -0
- package/src/harness/harness-queue.ts +466 -32
- package/src/harness/helper-scan.ts +10 -3
- package/src/harness/nested-elanous-policy.ts +23 -4
- package/src/hq/fence-wrapper.ts +123 -0
- package/src/hq/hq.ts +8 -0
- package/src/hq/seats.ts +369 -0
- package/src/index.ts +190 -23
- package/src/intake-plane/adopt-gate.ts +49 -0
- package/src/intake-plane/check.ts +3 -0
- package/src/intake-plane/collect-github.ts +57 -25
- package/src/intake-plane/digest.ts +39 -4
- package/src/intake-plane/discord-seat-work.ts +8 -2
- package/src/intake-plane/requirement-funnel.ts +316 -0
- package/src/knowledge/know-find.ts +10 -1
- package/src/loops/budget.ts +36 -0
- package/src/loops/orchestrator/finish-rate.ts +73 -1
- package/src/loops/orchestrator/grid-place.ts +11 -0
- package/src/loops/orchestrator/tick.ts +295 -20
- package/src/maturity/feature-maturity.ts +3 -2
- package/src/nexus/api/decisions-route.ts +11 -1
- package/src/nexus/api/grid.ts +61 -0
- package/src/nexus/api/http-server.ts +19 -1
- package/src/nexus/api/loop-edges.ts +69 -13
- package/src/nexus/api/ops-seats-sources.ts +2 -2
- package/src/nexus/api/task-cards-api.ts +19 -0
- package/src/nexus/api/workflow-templates.ts +3 -0
- package/src/oauth/codex.ts +120 -2
- package/src/onboarding/first-chat-gate.ts +29 -0
- package/src/release-loop/checklist.ts +104 -6
- package/src/release-loop/feature-store.ts +10 -9
- package/src/release-loop/landing-freeze.ts +24 -14
- package/src/release-loop/placement.ts +13 -3
- package/src/release-loop/rubric.ts +80 -0
- package/src/seat-dispatch/seat-ask.ts +79 -16
- package/src/seat-loop/seat-loop.ts +107 -37
- package/src/self-dev/ask-launch-flow.ts +50 -10
- package/src/self-dev/ask-path-candidates.ts +68 -0
- package/src/self-dev/dev-pipeline.ts +4 -0
- package/src/self-dev/draft-triage-rules.ts +1 -1
- package/src/self-dev/orchestrate-cli.ts +22 -0
- package/src/self-dev/round-pr-supersede.ts +244 -0
- package/src/self-dev/run-store.ts +5 -1
- package/src/self-dev/run-supervisor.ts +21 -1
- package/src/self-dev/supervisor-verdict-edges.ts +46 -0
- package/src/self-implement/follow-up-goals.ts +2 -2
- package/src/self-implement/frozen-merges.ts +25 -20
- package/src/self-implement/gate-remote.ts +427 -0
- package/src/self-implement/goal-author-clarification.ts +81 -0
- package/src/self-implement/goal-author-cli.ts +33 -5
- package/src/self-implement/goal-author.ts +93 -12
- package/src/self-implement/goal-clarification-escalation.ts +37 -1
- package/src/self-implement/goal-document-write.ts +28 -0
- package/src/self-implement/heal-intake.ts +4 -0
- package/src/self-implement/host-regate.ts +3 -1
- package/src/self-implement/l8-merge-queue.ts +29 -5
- package/src/self-implement/orchestrator.ts +78 -13
- package/src/self-implement/prior-draft-findings.ts +4 -3
- package/src/skills/skill-feedback.ts +76 -0
- package/src/task-agent/actions.ts +151 -0
- package/src/task-agent/judge.ts +122 -0
- package/src/task-agent/mission.ts +423 -0
- package/src/task-agent/shadow.ts +90 -0
- package/src/task-agent/task-hand.ts +235 -0
- package/src/task-cards/card-store.ts +4 -1
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +43 -4
- package/src/task-orchestrator/surfaces/pod-lease.ts +5 -2
- package/src/task-orchestrator/surfaces/pod-pool.ts +81 -13
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +225 -35
- package/src/telegram-commands.ts +1 -1
- package/src/telegram-loops-command.ts +22 -15
- package/src/telegram.ts +5 -20
- package/src/user-config.ts +86 -4
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4614-21403aac730d4586.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5135-44008fe8b1f2aa41.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5233-bf28bd6bd7a32099.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-c952712c87a1f757.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6877-7c6208705c284124.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7395-164e238f471b5d7b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7787-02a1c0b04e25e811.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8827-e2f5b09a8d37e83b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8949-ecb4128a0858b911.js +0 -1
- package/apps/pwa/out/_next/static/chunks/899-46946fe8363e1262.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9247-29d889b809288e65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-79c3ed84baaedd03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-a424ef80885d1743.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-1e962b31d1f11081.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-8c2d9526164f5d09.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-ffff6d819fbc6e0f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-76270efaee638f17.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-dce686e582c23937.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-d3d53b146416e422.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-1a61c7ca1ceb3ae7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-51f811fa119308b6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-dacff46049e1557e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-36a7d994f4ca0299.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-5b042736aa113756.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-acb749f1e432bcf3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-cd78862707999911.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-54b9ef8afe6278fd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-57924393e3e4e539.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-9e0ce6c8129fa641.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-31fa1ce4c4aff9ae.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-0f5cd57ca928f42b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-4364ef9f4e7c7f0f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-59f03fda76c03d22.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-86914b0dee8ab7f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-d4aef67abf264874.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-1ea64acadd704ace.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-30c2073bfc21c004.js +0 -1
- package/apps/pwa/out/_next/static/css/001d5fbaee388a25.css +0 -1
- package/apps/pwa/out/_next/static/rv9cierV0jSOvDBm1g0XB/_buildManifest.js +0 -1
- /package/apps/pwa/out/_next/static/{rv9cierV0jSOvDBm1g0XB → P6YTVgzuZz5oTZhY4Din_}/_ssgManifest.js +0 -0
package/src/index.ts
CHANGED
|
@@ -74,6 +74,7 @@ import { registerModelWatchCommand } from './cli/model-watch-cli.js';
|
|
|
74
74
|
import { registerIntakeCommands } from './cli/intake-cli.js';
|
|
75
75
|
import { registerTasksCommands } from './cli/tasks-cli.js';
|
|
76
76
|
import { registerBriefCommands } from './cli/brief-cli.js';
|
|
77
|
+
import { registerNotifyCommand } from './cli/notify-cli.js';
|
|
77
78
|
import { registerLabelsCommands } from './cli/labels-cli.js';
|
|
78
79
|
import { registerMsgCommands } from './cli/msg-cli.js';
|
|
79
80
|
import { registerDoctorCommand } from './cli/doctor-cli.js';
|
|
@@ -135,6 +136,7 @@ import type { ReviewResult } from './agent-substrate/pr-reviewer.js';
|
|
|
135
136
|
import type { ReviewVerdict } from './agent-mission/review-loop.js';
|
|
136
137
|
import type { SyncMode } from './types.js';
|
|
137
138
|
import { runOnboarding, runOnboardingStep, runOnboardingNonInteractive, needsOnboarding, needsFirstRun, handleOnboardingRefusal, type OnboardingStepId } from './onboarding.js';
|
|
139
|
+
import { firstChatGate } from './onboarding/first-chat-gate.js';
|
|
138
140
|
import {
|
|
139
141
|
getUserConfig, reloadUserConfig, userConfigPath, saveUserConfig,
|
|
140
142
|
backupUserConfig, backupConfigPath, addRotationEntry, type RotationEntry,
|
|
@@ -259,7 +261,7 @@ interface RunDevAskFromGoalFileDeps {
|
|
|
259
261
|
runSayLaunchFlow: (
|
|
260
262
|
sayText: string,
|
|
261
263
|
entrance?: import('./self-dev/entrance-registry.js').EntranceDeclaration,
|
|
262
|
-
selection?: { readonly forcePreflight?: boolean; readonly goalType?: import('./self-implement/goal-author.js').GoalType; readonly groundingCwd?: string },
|
|
264
|
+
selection?: { readonly forcePreflight?: boolean; readonly goalType?: import('./self-implement/goal-author.js').GoalType; readonly groundingCwd?: string; readonly authorGrade?: import('./self-implement/goal-author.js').GoalAuthorGradeSelection },
|
|
263
265
|
) => Promise<RunDevAskFlowResult>;
|
|
264
266
|
runAskFileLaunchFlow: (
|
|
265
267
|
askPath: string,
|
|
@@ -294,7 +296,7 @@ export function assembleAskLaunchPolicy(selection: {
|
|
|
294
296
|
async function runDefaultSayLaunchFlow(
|
|
295
297
|
sayText: string,
|
|
296
298
|
entrance?: import('./self-dev/entrance-registry.js').EntranceDeclaration,
|
|
297
|
-
selection: { readonly forcePreflight?: boolean; readonly goalType?: import('./self-implement/goal-author.js').GoalType; readonly groundingCwd?: string } = {},
|
|
299
|
+
selection: { readonly forcePreflight?: boolean; readonly goalType?: import('./self-implement/goal-author.js').GoalType; readonly groundingCwd?: string; readonly authorGrade?: import('./self-implement/goal-author.js').GoalAuthorGradeSelection } = {},
|
|
298
300
|
): Promise<RunDevAskFlowResult> {
|
|
299
301
|
const { readFileSync, writeFileSync } = await import('node:fs');
|
|
300
302
|
const [flowMod, { runGoalAuthorCli }, { relative: relativeToCwdPath }, { CLI_HARNESS_SAY_ENTRANCE }] = await Promise.all([
|
|
@@ -319,6 +321,7 @@ async function runDefaultSayLaunchFlow(
|
|
|
319
321
|
...assembleAskLaunchPolicy(selection),
|
|
320
322
|
...(selection.goalType === undefined ? {} : { goalType: selection.goalType }),
|
|
321
323
|
...(selection.groundingCwd === undefined ? {} : { groundingCwd: selection.groundingCwd }),
|
|
324
|
+
...(selection.authorGrade === undefined ? {} : { authorGrade: selection.authorGrade }),
|
|
322
325
|
}, {
|
|
323
326
|
print: (line) => console.error(line),
|
|
324
327
|
log: (event, data, level) => debug.log('dev-pipeline', event, data, { level }),
|
|
@@ -328,6 +331,9 @@ async function runDefaultSayLaunchFlow(
|
|
|
328
331
|
cwd: () => process.cwd(),
|
|
329
332
|
now: () => Date.now(),
|
|
330
333
|
isInteractive: () => process.stdin.isTTY === true && process.stdout.isTTY === true,
|
|
334
|
+
// POD-SELF-ANSWER: non-TTY (Pod) authoring self-answers clarifications with the author resolver.
|
|
335
|
+
selfResolveClarification: (await import('./self-implement/goal-author-clarification.js')).defaultGoalAuthorSelfResolve,
|
|
336
|
+
writeGoalDocument: (await import('./self-implement/goal-document-write.js')).writeGoalDocumentAtomic,
|
|
331
337
|
buildPreflightDeps: askIo.buildAskPreflightDeps,
|
|
332
338
|
priorBlockSamples: () => askIo.priorBlockSamplesFrom(askLogRows),
|
|
333
339
|
recentAuthoringSamples: () => askIo.recentAuthoringSamplesFrom(askLogRows),
|
|
@@ -376,6 +382,9 @@ async function runDefaultAskFileLaunchFlow(
|
|
|
376
382
|
cwd: () => process.cwd(),
|
|
377
383
|
now: () => Date.now(),
|
|
378
384
|
isInteractive: () => process.stdin.isTTY === true && process.stdout.isTTY === true,
|
|
385
|
+
// POD-SELF-ANSWER: non-TTY (Pod) authoring self-answers clarifications with the author resolver.
|
|
386
|
+
selfResolveClarification: (await import('./self-implement/goal-author-clarification.js')).defaultGoalAuthorSelfResolve,
|
|
387
|
+
writeGoalDocument: (await import('./self-implement/goal-document-write.js')).writeGoalDocumentAtomic,
|
|
379
388
|
buildPreflightDeps: askIo.buildAskPreflightDeps,
|
|
380
389
|
priorBlockSamples: () => askIo.priorBlockSamplesFrom(askLogRows),
|
|
381
390
|
recentAuthoringSamples: () => askIo.recentAuthoringSamplesFrom(askLogRows),
|
|
@@ -818,6 +827,7 @@ async function runDevSayFromWords(
|
|
|
818
827
|
authoringEntrance,
|
|
819
828
|
{
|
|
820
829
|
...(opts.forcePreflight === undefined ? {} : { forcePreflight: opts.forcePreflight }),
|
|
830
|
+
...(opts.authorGrade === undefined ? {} : { authorGrade: { grade: opts.authorGrade, source: opts.authorGradeSource ?? 'flag' } }),
|
|
821
831
|
...(grounding.groundingCwd === undefined ? {} : { groundingCwd: grounding.groundingCwd }),
|
|
822
832
|
},
|
|
823
833
|
);
|
|
@@ -880,6 +890,7 @@ registerLiveCommands(program);
|
|
|
880
890
|
registerResearchCommand(program);
|
|
881
891
|
registerReleaseCommands(program);
|
|
882
892
|
registerKnowCommand(program);
|
|
893
|
+
registerNotifyCommand(program);
|
|
883
894
|
registerFreezeCommands(program);
|
|
884
895
|
registerFlowCommands(program);
|
|
885
896
|
// HQ-HB · HQ-FENCE (10-04): one writer across mbp · node-b · cloud-vm — lease on the arbiter, 2-of-3 quorum, generation fencing.
|
|
@@ -977,12 +988,78 @@ hqCmd.command('seen').description('이 호스트가 본 가장 높은 임대 세
|
|
|
977
988
|
process.exitCode = result.seen ? 0 : 3;
|
|
978
989
|
});
|
|
979
990
|
registerHqMovePlanCommand(hqCmd);
|
|
991
|
+
hqCmd.command('init').description('한 저장소의 bare 미러와 집 원장을 만들고 5분 fetch 크론 줄만 출력')
|
|
992
|
+
.option('--root <dir>', 'HQ 폴더 (기본 ~/elanous-hq)')
|
|
993
|
+
.action(async (opts: { root?: string }) => {
|
|
994
|
+
try {
|
|
995
|
+
const { hqInit } = await import('./hq/seats.js');
|
|
996
|
+
const { getElanousConfigDir } = await import('./elanous-config-dir.js');
|
|
997
|
+
const result = hqInit({ ...opts, home: getElanousConfigDir() });
|
|
998
|
+
console.log(`hq init: ${result.created ? 'created' : 'already exists'} ${result.root}\n# OP installs this line; nothing was installed:\n${result.cron}`);
|
|
999
|
+
} catch (error) { console.error(`hq init: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
|
|
1000
|
+
});
|
|
1001
|
+
hqCmd.command('seat <role>').description('OP|MK|TC|UX 자리 워크트리 (깨끗할 때만 갱신)')
|
|
1002
|
+
.option('--refresh', 'origin/main으로 깨끗한 자리만 최신화')
|
|
1003
|
+
.option('--root <dir>', 'HQ 폴더')
|
|
1004
|
+
.action(async (role: string, opts: { refresh?: boolean; root?: string }) => {
|
|
1005
|
+
try {
|
|
1006
|
+
const { hqSeat } = await import('./hq/seats.js');
|
|
1007
|
+
const result = hqSeat(role, opts);
|
|
1008
|
+
if (result.outcome === 'dirty') console.warn(`hq seat ${role}: dirty — refresh skipped; move edits to hq work new`);
|
|
1009
|
+
else console.log(`hq seat ${role}: ${result.outcome} ${result.path}`);
|
|
1010
|
+
} catch (error) { console.error(`hq seat: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
|
|
1011
|
+
});
|
|
1012
|
+
const hqWorkCmd = hqCmd.command('work').description('고칠 때만 작업 워크트리를 만들고 병합 후 회수');
|
|
1013
|
+
for (const action of ['new', 'done'] as const) hqWorkCmd.command(`${action} <role> <name>`)
|
|
1014
|
+
.option('--root <dir>', 'HQ 폴더')
|
|
1015
|
+
.action(async (role: string, name: string, opts: { root?: string }) => {
|
|
1016
|
+
try {
|
|
1017
|
+
const { hqWork } = await import('./hq/seats.js');
|
|
1018
|
+
const result = hqWork(action, role, name, opts);
|
|
1019
|
+
console.log(`hq work ${action}: ${result.outcome} ${result.path}`);
|
|
1020
|
+
} catch (error) { console.error(`hq work ${action}: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
|
|
1021
|
+
});
|
|
1022
|
+
const fenceWrapperCmd = hqCmd.command('fence-wrapper').description('설치본 HQ 울타리 크론 래퍼');
|
|
1023
|
+
fenceWrapperCmd.command('install').description('래퍼 제안 또는 백업 후 원자적 설치')
|
|
1024
|
+
.option('--dry-run', '변경 내용만 출력 (기본)')
|
|
1025
|
+
.option('--yes', '기존 파일 백업 후 설치')
|
|
1026
|
+
.action(async (opts: { dryRun?: boolean; yes?: boolean }) => {
|
|
1027
|
+
try {
|
|
1028
|
+
if (opts.dryRun && opts.yes) throw new Error('--dry-run and --yes cannot be used together');
|
|
1029
|
+
const { getElanousConfigDir } = await import('./elanous-config-dir.js');
|
|
1030
|
+
const { installedHqFenceEntry, installHqFenceWrapper, renderHqFenceWrapper, resolveHqFenceBun } = await import('./hq/fence-wrapper.js');
|
|
1031
|
+
const configDir = getElanousConfigDir();
|
|
1032
|
+
const bun = resolveHqFenceBun();
|
|
1033
|
+
const body = renderHqFenceWrapper({ entry: installedHqFenceEntry(), configDir, bun });
|
|
1034
|
+
const result = installHqFenceWrapper(configDir, body, opts.yes === true);
|
|
1035
|
+
if (opts.yes) console.log(`hq-fence installed: ${result.path} · bun: ${bun}${result.backup ? ` · backup: ${result.backup}` : ''}`);
|
|
1036
|
+
else console.log(`hq-fence bun (absolute · cron has no PATH): ${bun}\n${result.preview}`);
|
|
1037
|
+
} catch (error) { console.error(`hq fence-wrapper install: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
|
|
1038
|
+
});
|
|
1039
|
+
fenceWrapperCmd.command('alert <reason>').description('HQ 울타리 실패를 기존 루프 소유자 요청 원장에 적재')
|
|
1040
|
+
.action(async (reason: string) => {
|
|
1041
|
+
try {
|
|
1042
|
+
const { notifyOwners } = await import('./loops/checker.js');
|
|
1043
|
+
const { getElanousConfigDir } = await import('./elanous-config-dir.js');
|
|
1044
|
+
notifyOwners([{ id: `hq-fence:${Date.now()}:${process.pid}`, owner: 'TC', enabled: true, registered: true,
|
|
1045
|
+
state: 'failing', reason }], { root: getElanousConfigDir() });
|
|
1046
|
+
} catch (error) { console.error(`hq fence-wrapper alert: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
|
|
1047
|
+
});
|
|
980
1048
|
hqCmd.command('fence-audit').description('운영 crontab 의 HQ 울타리 밖 쓰기 잡 목록과 감싼 줄 제안(읽기 전용)')
|
|
981
1049
|
.option('--json', 'JSON 출력')
|
|
982
1050
|
.action(async (opts: { json?: boolean }) => {
|
|
983
1051
|
try {
|
|
984
1052
|
await hqSink();
|
|
985
1053
|
const rows = (await import('./hq/fence-audit.js')).hqFenceAudit();
|
|
1054
|
+
const { getElanousConfigDir } = await import('./elanous-config-dir.js');
|
|
1055
|
+
const { repositoryWorktreeCdWarning } = await import('./hq/fence-wrapper.js');
|
|
1056
|
+
const wrapper = _joinPath(getElanousConfigDir(), 'bin', 'hq-fence');
|
|
1057
|
+
if (existsSync(wrapper)) {
|
|
1058
|
+
try {
|
|
1059
|
+
const warning = repositoryWorktreeCdWarning(readFileSync(wrapper, 'utf8'));
|
|
1060
|
+
if (warning) console.error(warning);
|
|
1061
|
+
} catch (error) { console.error(`hq fence-audit: wrapper inspection unavailable: ${error instanceof Error ? error.message : String(error)}`); }
|
|
1062
|
+
}
|
|
986
1063
|
if (opts.json) await writeStdoutJson(`${JSON.stringify(rows)}\n`);
|
|
987
1064
|
else if (!rows.length) console.log('hq fence-audit: unfenced 0');
|
|
988
1065
|
else for (const row of rows) console.log(`${row.raw}\n role: ${row.recommendedRole}\n suggested: ${row.suggestedLine}`);
|
|
@@ -999,6 +1076,40 @@ hqCmd.command('fence').description('이 호스트가 임대를 쥐었을 때만
|
|
|
999
1076
|
});
|
|
1000
1077
|
const seatCmd = program.command('seat').description('분배된 자리의 하루 루프와 보고');
|
|
1001
1078
|
registerSeatRequestsCommands(seatCmd);
|
|
1079
|
+
seatCmd.command('asks').description('최근 CTO 되묻기 왕복과 10분 판정')
|
|
1080
|
+
.option('--since <duration>', '조회 창 (예: 24h)', '24h')
|
|
1081
|
+
.option('--json', 'JSON 출력')
|
|
1082
|
+
.action(async (opts: { since: string; json?: boolean }) => {
|
|
1083
|
+
try {
|
|
1084
|
+
const duration = /^(\d+)([mhd])$/.exec(opts.since);
|
|
1085
|
+
if (!duration || !Number.isSafeInteger(Number(duration[1]))) throw new Error('--since: 24h, 30m, 7d 형식 필요');
|
|
1086
|
+
const ms = Number(duration[1]) * ({ m: 60_000, h: 3_600_000, d: 86_400_000 }[duration[2]!] ?? 0);
|
|
1087
|
+
if (!Number.isSafeInteger(ms) || ms <= 0) throw new Error('--since: 양의 시간 필요');
|
|
1088
|
+
const { defaultMsgStorePath } = await import('./msg/msg-store.js');
|
|
1089
|
+
const path = defaultMsgStorePath();
|
|
1090
|
+
if (!(await import('node:fs')).existsSync(path)) {
|
|
1091
|
+
if (opts.json) await writeStdoutJson('[]\n');
|
|
1092
|
+
else console.log(`원장 없음 — ${path}`);
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
const { listSeatAskRoundTrips } = await import('./seat-dispatch/seat-ask.js');
|
|
1096
|
+
const now = Date.now();
|
|
1097
|
+
const rows = listSeatAskRoundTrips({ since: now - ms, now });
|
|
1098
|
+
if (!rows.length) {
|
|
1099
|
+
if (opts.json) await writeStdoutJson('[]\n');
|
|
1100
|
+
else console.log('이 창에 되묻기 0건');
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
if (opts.json) { await writeStdoutJson(`${JSON.stringify(rows)}\n`); return; }
|
|
1104
|
+
const clock = (value: number | null) => value === null ? '-' : new Intl.DateTimeFormat('ko-KR', {
|
|
1105
|
+
timeZone: 'Asia/Seoul', hour: '2-digit', minute: '2-digit', hourCycle: 'h23',
|
|
1106
|
+
}).format(value);
|
|
1107
|
+
console.log('id · 표면 · 물음 HH:MM KST · 답 · 도착 · 왕복 분 · 판정');
|
|
1108
|
+
for (const row of rows) console.log(`${row.id} · ${row.surface} · ${clock(row.askedAt)} KST · ${clock(row.answeredAt)} · ${clock(row.deliveredAt)} · ${row.roundTripMs === null ? '-' : (row.roundTripMs / 60_000).toFixed(1)}분 · ${row.verdict}`);
|
|
1109
|
+
const count = (verdict: string) => rows.filter(row => row.verdict === verdict).length;
|
|
1110
|
+
console.log(`10분 안 ${count('10분 안')} / 넘음 ${count('10분 넘음')} / 미답 ${count('미답')} / 대기 ${count('답 대기') + count('전달 대기')} / 미상 ${count('시각 미상')}`);
|
|
1111
|
+
} catch (error) { console.error(`seat asks: ${error instanceof Error ? error.message : String(error)}`); process.exitCode = 1; }
|
|
1112
|
+
});
|
|
1002
1113
|
seatCmd.command('answer <askId> <answer>').description('자리 질문에 답을 남기고 원래 표면으로 회신 예약')
|
|
1003
1114
|
.action(async (askId: string, answer: string) => {
|
|
1004
1115
|
try {
|
|
@@ -1255,7 +1366,7 @@ pythonCmd.command('setup').description('elanous venv(~/.local/share/elanous/pyth
|
|
|
1255
1366
|
|
|
1256
1367
|
program.command('self-update')
|
|
1257
1368
|
.alias('update')
|
|
1258
|
-
.description('설치본은 릴리스로, 체크아웃은 깨끗한 체크아웃으로
|
|
1369
|
+
.description('설치본은 릴리스로, 체크아웃은 깨끗한 체크아웃으로 갱신 · --auto 는 캐너리 자동 판단, --auto on|off|status 는 기존 자동 갱신 서비스 관리')
|
|
1259
1370
|
.option('--from <checkout>', '설치할 체크아웃 (기본: 설치본은 릴리스, 체크아웃은 현재 체크아웃)')
|
|
1260
1371
|
.option('--version <version>', '설치본에서 지정한 릴리스 버전 설치 (기본: latest)')
|
|
1261
1372
|
.option('--restart', '넥서스 재시작 승인')
|
|
@@ -1265,9 +1376,13 @@ program.command('self-update')
|
|
|
1265
1376
|
.option('--skip-pwa-build', '체크아웃 설치 전 PWA 빌드를 명시적으로 건너뜀')
|
|
1266
1377
|
.option('--dev', '판 사이 dev 빌드 설치 — versions/<판>-dev.<sha12> · install.json channel=dev · 이전 versionDir 보존 (사람 승인 · 자동 아님)')
|
|
1267
1378
|
.option('--rollback', 'install.json 의 이전 versionDir 로 current 를 되돌린다 (이전이 없으면 거부)')
|
|
1268
|
-
.option('--auto
|
|
1269
|
-
.
|
|
1270
|
-
|
|
1379
|
+
.option('--auto [on|off|status]', '인자 없이: 에지 레일 계획/실행 · on|off|status: 기존 자동 갱신 서비스 관리')
|
|
1380
|
+
.option('--dry-run', '에지 레일 계획만 출력; 설치·되돌림·상태 쓰기 없음')
|
|
1381
|
+
.option('--seat <seat>', '에지 레일 자리 (OP|TC|MK|UX)')
|
|
1382
|
+
.option('--quiet-window', '상주 프로세스 재시작이 가능한 조용한 창이라고 명시')
|
|
1383
|
+
.option('--canary-run-id <id>', '캐너리 성공 런의 고유 ID (독립 검증된 성공 런에서만 입력; 같은 ID 는 중복 적중하지 않음)')
|
|
1384
|
+
.action(async (opts: { from?: string; version?: string; restart?: boolean; json?: boolean; keep?: string; alert?: boolean; skipPwaBuild?: boolean; dev?: boolean; rollback?: boolean; auto?: string | boolean; dryRun?: boolean; seat?: string; quietWindow?: boolean; canaryRunId?: string }) => {
|
|
1385
|
+
if (typeof opts.auto === 'string') {
|
|
1271
1386
|
if (!['on', 'off', 'status'].includes(opts.auto)) { console.error(`--auto 는 on · off · status 중 하나: ${opts.auto}`); process.exitCode = 2; return; }
|
|
1272
1387
|
const { runAutoUpdate } = await import('./cli/update-auto.js');
|
|
1273
1388
|
process.exitCode = (await runAutoUpdate(opts.auto as 'on' | 'off' | 'status')).exitCode;
|
|
@@ -1275,9 +1390,9 @@ program.command('self-update')
|
|
|
1275
1390
|
}
|
|
1276
1391
|
const { runUpdateForInstallation } = await import('./cli/self-update.js');
|
|
1277
1392
|
// ⭐ 한 번 도는 CLI 는 logs.db 싱크를 스스로 붙여야 `debug.log('self-update', …)` 가 저장된다(없으면 조용히 사라진다 · 09-24 실측).
|
|
1278
|
-
try { const { registerStandaloneLogSink } = await import('./domains/standalone-log-sink.js'); await registerStandaloneLogSink('self-update'); } catch { /* 관측 실패가 갱신을 막지 않는다 */ }
|
|
1393
|
+
if (!opts.dryRun) try { const { registerStandaloneLogSink } = await import('./domains/standalone-log-sink.js'); await registerStandaloneLogSink('self-update'); } catch { /* 관측 실패가 갱신을 막지 않는다 */ }
|
|
1279
1394
|
const keep = Number.parseInt(opts.keep ?? '3', 10);
|
|
1280
|
-
const result = await runUpdateForInstallation({ ...opts, skipPwaBuild: opts.skipPwaBuild, keep: Number.isFinite(keep) ? keep : 3 }, { cliRoot: REPOSITORY_ROOT });
|
|
1395
|
+
const result = await runUpdateForInstallation({ ...opts, auto: opts.auto === true, quietWindow: opts.quietWindow === true, skipPwaBuild: opts.skipPwaBuild, keep: Number.isFinite(keep) ? keep : 3 }, { cliRoot: REPOSITORY_ROOT });
|
|
1281
1396
|
process.exitCode = result.exitCode;
|
|
1282
1397
|
});
|
|
1283
1398
|
|
|
@@ -3252,11 +3367,20 @@ contextCmd.command('day')
|
|
|
3252
3367
|
.description('자리 넷과 외부 세션의 최근 맥락 이벤트 수·마지막 시각 (읽기 전용)')
|
|
3253
3368
|
.option('--since <hours>', '최근 시간 창 (예: 24h)', '24h')
|
|
3254
3369
|
.option('--json', '구조화된 JSON 출력')
|
|
3255
|
-
.
|
|
3370
|
+
.option('--timeline', '시간순 사건 한 줄씩 (KST)')
|
|
3371
|
+
.option('--seat <source>', '한 출처만 (OP|TC|MK|UX|claude-code|codex-agent-mission|harness-child)')
|
|
3372
|
+
.action(async (opts: { since: string; json?: boolean; timeline?: boolean; seat?: string }) => {
|
|
3256
3373
|
try {
|
|
3257
|
-
const { contextDay, renderContextDay } = await import('./context-bus/context-day.js');
|
|
3258
|
-
|
|
3259
|
-
|
|
3374
|
+
const { contextDay, contextDayTimeline, renderContextDay, renderContextDayTimeline, CONTEXT_DAY_SOURCES } = await import('./context-bus/context-day.js');
|
|
3375
|
+
if (opts.seat && !CONTEXT_DAY_SOURCES.some(source => source === opts.seat)) throw new Error(`unknown --seat: ${opts.seat}`);
|
|
3376
|
+
if (opts.seat && !opts.timeline) throw new Error('--seat requires --timeline');
|
|
3377
|
+
if (opts.timeline) {
|
|
3378
|
+
const report = contextDayTimeline(opts.since, { seat: opts.seat as typeof CONTEXT_DAY_SOURCES[number] | undefined });
|
|
3379
|
+
await writeStdoutJson(`${opts.json ? JSON.stringify(report) : renderContextDayTimeline(report)}\n`);
|
|
3380
|
+
} else {
|
|
3381
|
+
const report = contextDay(opts.since);
|
|
3382
|
+
await writeStdoutJson(`${opts.json ? JSON.stringify(report) : renderContextDay(report)}\n`);
|
|
3383
|
+
}
|
|
3260
3384
|
} catch (error) {
|
|
3261
3385
|
console.error(`context day: ${error instanceof Error ? error.message : String(error)}`);
|
|
3262
3386
|
process.exitCode = 2;
|
|
@@ -4290,16 +4414,52 @@ selfCmd
|
|
|
4290
4414
|
.option('--base <ref>', '커밋됐지만 PR 없는 변경의 비교 기준(ref...HEAD)')
|
|
4291
4415
|
.option('--pr <number>', '열린 PR 번호에서 gh pr view files로 변경 파일을 읽는다')
|
|
4292
4416
|
.option('--shards [number]', '메모리 예산에 맞춰 시험을 별도 프로세스로 분할한다 (기본 2)')
|
|
4293
|
-
.
|
|
4417
|
+
.option('--remote [host]', 'GATE-REMOTE — 같은 커밋을 원격 호스트(기본 config gateRemote.host=node-b)에서 돌리고 결과만 가져온다(깨끗한 트리 · --pr 은 로컬)')
|
|
4418
|
+
.option('--local', '원격 자동 분배(로컬 1분 부하 > gateRemote.loadThreshold=20)를 끄고 로컬에서 돌린다')
|
|
4419
|
+
.action(async (opts: { changed?: boolean; base?: string; pr?: string; shards?: string | boolean; remote?: string | boolean; local?: boolean }) => {
|
|
4294
4420
|
if (!opts.changed && opts.shards === undefined) { ui.error('self gate requires --changed or --shards'); process.exitCode = 2; return; }
|
|
4421
|
+
// The root strips `--local` from argv anywhere (remote-bookmark attach · src/cli/remote-resolve.ts) before Commander
|
|
4422
|
+
// sees it, so this subcommand reads it from the untouched process.argv.
|
|
4423
|
+
opts.local = !!opts.local || process.argv.slice(2).includes('--local');
|
|
4424
|
+
if (opts.remote !== undefined && opts.local) { ui.error('self gate: --remote and --local cannot be combined'); process.exitCode = 2; return; }
|
|
4425
|
+
if (typeof opts.remote === 'string') {
|
|
4426
|
+
const { isValidGateHost } = await import('./self-implement/gate-remote.js');
|
|
4427
|
+
if (!isValidGateHost(opts.remote)) { ui.error(`self gate: invalid --remote host: ${opts.remote}`); process.exitCode = 2; return; }
|
|
4428
|
+
}
|
|
4429
|
+
const shards = opts.shards === undefined ? undefined : opts.shards === true ? 2 : Number(opts.shards);
|
|
4430
|
+
const runLocal = () => {
|
|
4431
|
+
try {
|
|
4432
|
+
const { runSelfGateCli } = require('./self-implement/gate-cli.js') as typeof import('./self-implement/gate-cli.js');
|
|
4433
|
+
const result = runSelfGateCli(process.cwd(), { base: opts.base, pr: opts.pr, shards });
|
|
4434
|
+
console.log(result.lines.join('\n'));
|
|
4435
|
+
return result.exitCode;
|
|
4436
|
+
} catch (error) {
|
|
4437
|
+
ui.error(`self gate failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
4438
|
+
return 1;
|
|
4439
|
+
}
|
|
4440
|
+
};
|
|
4295
4441
|
try {
|
|
4296
|
-
const {
|
|
4297
|
-
const
|
|
4298
|
-
|
|
4299
|
-
|
|
4442
|
+
const { dispatchHeavyCheck } = await import('./self-implement/gate-remote.js');
|
|
4443
|
+
const { execFileSync } = await import('node:child_process');
|
|
4444
|
+
const repo = execFileSync('git', ['rev-parse', '--show-toplevel'], { encoding: 'utf8' }).trim();
|
|
4445
|
+
// Only a committed --base range is reproducible on another host: the default mode measures uncommitted files, --pr
|
|
4446
|
+
// reads files through gh on this host, and the remote checkout runs from the repository root — those stay local.
|
|
4447
|
+
const { realpathSync } = await import('node:fs');
|
|
4448
|
+
const localOnlyReason = opts.pr ? 'self gate --pr reads PR files through gh on this host'
|
|
4449
|
+
: !opts.base ? 'self gate without --base measures uncommitted files on this host'
|
|
4450
|
+
: realpathSync(repo) !== realpathSync(process.cwd()) ? 'self gate run from a sub-directory' : undefined;
|
|
4451
|
+
// origin/main is pinned to this machine's origin/main on the host; any other base is passed as its resolved sha.
|
|
4452
|
+
const remoteArgv = (sha: (ref: string) => string) => ['bun', 'bin/elanous.mjs', 'self', 'gate', '--local', ...(opts.changed ? ['--changed'] : []),
|
|
4453
|
+
...(opts.base ? ['--base', opts.base === 'origin/main' ? opts.base : sha(opts.base)] : []), ...(shards !== undefined ? ['--shards', String(shards)] : [])];
|
|
4454
|
+
process.exitCode = await dispatchHeavyCheck({
|
|
4455
|
+
tool: 'self-gate', repo, installPwa: true, remoteArgv, refs: opts.base ? [opts.base] : [],
|
|
4456
|
+
localOnlyReason,
|
|
4457
|
+
flags: { remote: typeof opts.remote === 'string' ? opts.remote : opts.remote ? true : undefined, local: !!opts.local },
|
|
4458
|
+
runLocal,
|
|
4459
|
+
});
|
|
4300
4460
|
} catch (error) {
|
|
4301
|
-
ui.error(`self gate failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
4302
|
-
process.exitCode =
|
|
4461
|
+
ui.error(`self gate dispatch failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
4462
|
+
process.exitCode = runLocal();
|
|
4303
4463
|
}
|
|
4304
4464
|
});
|
|
4305
4465
|
|
|
@@ -7001,6 +7161,8 @@ const selfDevCmd = program
|
|
|
7001
7161
|
now: () => Date.now(),
|
|
7002
7162
|
// ⛔ 「대화형인가」는 «두 쪽»을 본다 — 파이프로 몰면 물어도 답이 안 온다.
|
|
7003
7163
|
isInteractive: () => process.stdin.isTTY === true && process.stdout.isTTY === true,
|
|
7164
|
+
selfResolveClarification: (await import('./self-implement/goal-author-clarification.js')).defaultGoalAuthorSelfResolve,
|
|
7165
|
+
writeGoalDocument: (await import('./self-implement/goal-document-write.js')).writeGoalDocumentAtomic,
|
|
7004
7166
|
buildPreflightDeps: buildAskPreflightDeps,
|
|
7005
7167
|
priorBlockSamples: () => askIo.priorBlockSamplesFrom(askLogRows),
|
|
7006
7168
|
recentAuthoringSamples: () => askIo.recentAuthoringSamplesFrom(askLogRows),
|
|
@@ -8550,10 +8712,15 @@ program
|
|
|
8550
8712
|
}
|
|
8551
8713
|
if (opts.tools) announceChatToolsCompatibility();
|
|
8552
8714
|
const cfg = getUserConfig();
|
|
8553
|
-
if (
|
|
8554
|
-
|
|
8555
|
-
|
|
8556
|
-
|
|
8715
|
+
if (await firstChatGate(cfg, {
|
|
8716
|
+
isTTY: process.stdin.isTTY === true,
|
|
8717
|
+
runFirstRun: async (deps) => (await import('./onboarding/first-run.js')).runFirstRun(deps),
|
|
8718
|
+
runInteractive: () => {
|
|
8719
|
+
if (cfg.onboarding.webFirst === false) ui.info('No config yet — launching setup wizard first.');
|
|
8720
|
+
return runFirstSetupForCli(cfg, true);
|
|
8721
|
+
},
|
|
8722
|
+
print: (line) => console.log(line),
|
|
8723
|
+
}) === 'stop') return;
|
|
8557
8724
|
const refreshed = reloadUserConfig();
|
|
8558
8725
|
// ★ 관측갭 수리(2026-07-21·제1원칙·트랙A) — self-implement 자식 goal-loop(`chat --goal-loop`)은 데몬과
|
|
8559
8726
|
// 별개 독립 프로세스라 nexus StoreSink 를 상속 안 한다. 부모 `self implement`(위 self 커맨드)는 sink 를
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { debug } from '../debug/log.js';
|
|
2
|
+
|
|
3
|
+
export interface AdoptionCandidate {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly grade: 'P1' | 'P2' | 'P3' | 'P4';
|
|
6
|
+
readonly risk: number;
|
|
7
|
+
readonly money: number;
|
|
8
|
+
readonly security: number;
|
|
9
|
+
readonly license: string | null;
|
|
10
|
+
readonly touchesPatentCandidate: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type AdoptShadowReason = 'grade' | 'risk' | 'money' | 'security' | 'license' | 'patent' | 'daily-cap';
|
|
14
|
+
|
|
15
|
+
export interface AdoptShadowVerdict {
|
|
16
|
+
readonly id: string;
|
|
17
|
+
readonly adopt: boolean;
|
|
18
|
+
readonly reasons: readonly AdoptShadowReason[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const ALLOWED_LICENSES: ReadonlySet<string> = new Set([
|
|
22
|
+
'MIT', 'Apache-2.0', 'BSD-2-Clause', 'BSD-3-Clause', 'ISC', 'MPL-2.0',
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
export function judgeAdoption(candidate: AdoptionCandidate, adoptedToday: number): AdoptShadowVerdict {
|
|
26
|
+
const reasons: AdoptShadowReason[] = [];
|
|
27
|
+
if (candidate.grade !== 'P1' && candidate.grade !== 'P2') reasons.push('grade');
|
|
28
|
+
if (!(candidate.risk <= 1)) reasons.push('risk');
|
|
29
|
+
if (candidate.money !== 0) reasons.push('money');
|
|
30
|
+
if (candidate.security !== 0) reasons.push('security');
|
|
31
|
+
if (candidate.license === null || !ALLOWED_LICENSES.has(candidate.license)) reasons.push('license');
|
|
32
|
+
if (candidate.touchesPatentCandidate !== false) reasons.push('patent');
|
|
33
|
+
if (!(adoptedToday < 5)) reasons.push('daily-cap');
|
|
34
|
+
return { id: candidate.id, adopt: reasons.length === 0, reasons };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function shadowAdopt(candidates: readonly AdoptionCandidate[]): AdoptShadowVerdict[] {
|
|
38
|
+
const verdicts: AdoptShadowVerdict[] = [];
|
|
39
|
+
let adoptedToday = 0;
|
|
40
|
+
for (const candidate of candidates) {
|
|
41
|
+
const verdict = judgeAdoption(candidate, adoptedToday);
|
|
42
|
+
if (verdict.adopt) adoptedToday++;
|
|
43
|
+
verdicts.push(verdict);
|
|
44
|
+
debug.log('intake.adopt', 'shadow-verdict', {
|
|
45
|
+
id: verdict.id, adopt: verdict.adopt, reasons: verdict.reasons,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return verdicts;
|
|
49
|
+
}
|
|
@@ -21,6 +21,7 @@ import { parse as parseYaml } from 'yaml';
|
|
|
21
21
|
import { debug } from '../debug/log.js';
|
|
22
22
|
import { openSurfaceEventsDb, recallEvents } from '../domains/surface-events.js';
|
|
23
23
|
import { extractJsonBlock, skeletonFallback } from './decompose.js';
|
|
24
|
+
import type { AdoptShadowVerdict } from './adopt-gate.js';
|
|
24
25
|
|
|
25
26
|
export const INTAKE_CHECK_MODE = 'check' as const;
|
|
26
27
|
|
|
@@ -110,6 +111,7 @@ export interface IntakeCheckReport {
|
|
|
110
111
|
/** 비교·시너지 제안 수(근거 없음 포함). */
|
|
111
112
|
readonly proposalCount?: number;
|
|
112
113
|
readonly proposals?: readonly IntakeCompareProposal[];
|
|
114
|
+
readonly adoptShadow?: readonly AdoptShadowVerdict[];
|
|
113
115
|
}
|
|
114
116
|
|
|
115
117
|
/** 선가공 렌즈 여섯. 🅞 원장 · PR #20009. */
|
|
@@ -1826,6 +1828,7 @@ export function intakeCheckReportJson(report: IntakeCheckReport): Record<string,
|
|
|
1826
1828
|
proposalCount: report.proposalCount,
|
|
1827
1829
|
proposals: report.proposals,
|
|
1828
1830
|
} : {}),
|
|
1831
|
+
...(report.adoptShadow !== undefined ? { adoptShadow: report.adoptShadow } : {}),
|
|
1829
1832
|
};
|
|
1830
1833
|
}
|
|
1831
1834
|
|
|
@@ -6,14 +6,18 @@ import { execFileSync } from 'node:child_process';
|
|
|
6
6
|
import { debug } from '../debug/log.js';
|
|
7
7
|
import { ingestIntakeItems, intakeLedgerDir, type IngestResult, type RawIntakeItem } from './items.js';
|
|
8
8
|
|
|
9
|
-
/** 한 판에 열 번
|
|
9
|
+
/** 한 판에 열 번 이하 — 검색 API 비율 제한(인증 시 분당 30회)을 시험 밖에서 상수로 묶는다. */
|
|
10
10
|
export const GITHUB_STAR_QUERIES = [
|
|
11
11
|
'topic:ai-agents',
|
|
12
|
-
'topic:llm-agent',
|
|
13
12
|
'topic:coding-agent',
|
|
14
13
|
'topic:mcp',
|
|
15
14
|
'topic:video-generation',
|
|
16
|
-
'
|
|
15
|
+
'topic:agent-framework',
|
|
16
|
+
'topic:computer-use',
|
|
17
|
+
'topic:local-llm',
|
|
18
|
+
'topic:claude-code',
|
|
19
|
+
'topic:codex',
|
|
20
|
+
'topic:agent-memory',
|
|
17
21
|
] as const;
|
|
18
22
|
|
|
19
23
|
/** `--days` 기본. 최근 이 일수 안에 만들어졌거나 푸시된 저장소만 받는다. */
|
|
@@ -32,6 +36,7 @@ export interface GithubStarRepo {
|
|
|
32
36
|
stars: number;
|
|
33
37
|
createdAt: string;
|
|
34
38
|
pushedAt: string;
|
|
39
|
+
license?: string;
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
/** 질의 하나 → 저장소 목록. 실제 구현은 `gh api` · 시험은 가짜. */
|
|
@@ -43,6 +48,7 @@ export interface GithubStarSignals {
|
|
|
43
48
|
stars: number;
|
|
44
49
|
starsDelta?: number;
|
|
45
50
|
starsPerDay?: number;
|
|
51
|
+
baselineDays?: number;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
export interface CollectGithubQueryCount { query: string; received: number }
|
|
@@ -55,6 +61,8 @@ export interface CollectGithubRepoRow {
|
|
|
55
61
|
stars: number;
|
|
56
62
|
starsDelta?: number;
|
|
57
63
|
starsPerDay?: number;
|
|
64
|
+
baselineDays?: number;
|
|
65
|
+
license?: string;
|
|
58
66
|
}
|
|
59
67
|
|
|
60
68
|
export interface CollectGithubResult {
|
|
@@ -99,6 +107,17 @@ export function precedingSnapshot(snaps: readonly StarSnapshot[], repo: string,
|
|
|
99
107
|
return best;
|
|
100
108
|
}
|
|
101
109
|
|
|
110
|
+
/** 7일 전 또는 그 이전 중 가장 가까운 스냅숏; 없으면 직전 스냅숏. */
|
|
111
|
+
export function surgeBaseline(snaps: readonly StarSnapshot[], repo: string, day: string): StarSnapshot | undefined {
|
|
112
|
+
const cutoff = new Date(Date.parse(`${day}T00:00:00.000Z`) - 7 * 86_400_000).toISOString().slice(0, 10);
|
|
113
|
+
let best: StarSnapshot | undefined;
|
|
114
|
+
for (const s of snaps) {
|
|
115
|
+
if (s.repo !== repo || s.day > cutoff) continue;
|
|
116
|
+
if (!best || s.day > best.day) best = s;
|
|
117
|
+
}
|
|
118
|
+
return best ?? precedingSnapshot(snaps, repo, day);
|
|
119
|
+
}
|
|
120
|
+
|
|
102
121
|
function utcDay(iso: string): string {
|
|
103
122
|
const t = Date.parse(iso);
|
|
104
123
|
if (!Number.isFinite(t)) return '';
|
|
@@ -128,7 +147,7 @@ export function signalsFromSnapshot(stars: number, prev: StarSnapshot | undefine
|
|
|
128
147
|
if (!prev) return { stars };
|
|
129
148
|
const span = Math.max(1, daysBetween(prev.day, day));
|
|
130
149
|
const starsDelta = stars - prev.stars;
|
|
131
|
-
return { stars, starsDelta, starsPerDay: starsDelta / span };
|
|
150
|
+
return { stars, starsDelta, starsPerDay: starsDelta / span, baselineDays: span };
|
|
132
151
|
}
|
|
133
152
|
|
|
134
153
|
export function appendGithubStarSnapshots(root: string, rows: StarSnapshot[]): void {
|
|
@@ -154,13 +173,13 @@ export interface CollectGithubOpts {
|
|
|
154
173
|
/** 스냅숏·비교의 «오늘». 생략하면 UTC 날짜. */
|
|
155
174
|
day?: string;
|
|
156
175
|
now?: () => Date;
|
|
157
|
-
/** 등록 원천이 질의 하나만 수집할 때; 생략 시
|
|
176
|
+
/** 등록 원천이 질의 하나만 수집할 때; 생략 시 관심 질의 전부 (최대 10개). */
|
|
158
177
|
queries?: readonly string[];
|
|
159
178
|
}
|
|
160
179
|
|
|
161
180
|
/**
|
|
162
181
|
* 관심 주제 질의마다 별 순 검색을 부르고, 최근 창 안의 저장소만 남긴 뒤 질의 사이에서 중복을 없앤다.
|
|
163
|
-
* 저장소마다 오늘 별 수 스냅숏을 덧붙이고, 직전 스냅숏과 비교한 신호를 원장에 넣는다.
|
|
182
|
+
* 저장소마다 오늘 별 수 스냅숏을 덧붙이고, 7일 기준(없으면 직전) 스냅숏과 비교한 신호를 원장에 넣는다.
|
|
164
183
|
* dryRun 이면 스냅숏·원장을 바꾸지 않는다.
|
|
165
184
|
*/
|
|
166
185
|
export async function collectGithubStars(
|
|
@@ -175,7 +194,7 @@ export async function collectGithubStars(
|
|
|
175
194
|
const found: GithubStarRepo[] = [];
|
|
176
195
|
// «급상승»은 최근에 생긴 저장소 중 별 순이다 — 전체 기간 별 순이면 활발한 거대 저장소가 매일 같은 목록으로 나온다(2026-09-26 검토).
|
|
177
196
|
const windowStart = new Date(Date.parse(`${day}T00:00:00.000Z`) - days * 86_400_000).toISOString().slice(0, 10);
|
|
178
|
-
for (const query of opts.queries ?? GITHUB_STAR_QUERIES) {
|
|
197
|
+
for (const query of (opts.queries ?? GITHUB_STAR_QUERIES).slice(0, 10)) {
|
|
179
198
|
const rows = await search(`${query} created:>=${windowStart}`, perQuery);
|
|
180
199
|
const recent = rows.filter((r) => isRecentRepo(r, day, days));
|
|
181
200
|
queries.push({ query, received: recent.length });
|
|
@@ -186,20 +205,24 @@ export async function collectGithubStars(
|
|
|
186
205
|
const repos: CollectGithubRepoRow[] = unique.map((repo) => {
|
|
187
206
|
const prev = precedingSnapshot(prior, repo.fullName, day);
|
|
188
207
|
const signals = signalsFromSnapshot(repo.stars, prev, day);
|
|
208
|
+
const surge = signalsFromSnapshot(repo.stars, surgeBaseline(prior, repo.fullName, day), day);
|
|
189
209
|
return {
|
|
190
210
|
repo: repo.fullName,
|
|
191
211
|
url: repo.url,
|
|
192
212
|
title: repo.fullName,
|
|
193
213
|
text: repo.description,
|
|
194
214
|
stars: signals.stars,
|
|
215
|
+
...(repo.license !== undefined ? { license: repo.license } : {}),
|
|
195
216
|
...(signals.starsDelta !== undefined ? { starsDelta: signals.starsDelta } : {}),
|
|
196
|
-
...(
|
|
217
|
+
...(surge.starsPerDay !== undefined ? { starsPerDay: surge.starsPerDay } : {}),
|
|
218
|
+
...(surge.baselineDays !== undefined ? { baselineDays: surge.baselineDays } : {}),
|
|
197
219
|
};
|
|
198
|
-
});
|
|
220
|
+
}).sort((a, b) => (b.starsPerDay ?? -Infinity) - (a.starsPerDay ?? -Infinity) || b.stars - a.stars);
|
|
199
221
|
const raws: RawIntakeItem[] = repos.map((row) => ({
|
|
200
222
|
url: row.url,
|
|
201
223
|
title: row.title,
|
|
202
|
-
|
|
224
|
+
// 모든 행 첫 줄에 라이선스: SPDX · 확인된 부재는 «없음» · 응답이 알려 주지 않으면 «미상»(없음으로 읽지 않는다).
|
|
225
|
+
text: `라이선스: ${row.license ?? '미상'}\n${row.text}`,
|
|
203
226
|
signals: {
|
|
204
227
|
stars: row.stars,
|
|
205
228
|
...(row.starsDelta !== undefined ? { starsDelta: row.starsDelta } : {}),
|
|
@@ -226,23 +249,10 @@ interface GhSearchItem {
|
|
|
226
249
|
stargazers_count?: number;
|
|
227
250
|
created_at?: string;
|
|
228
251
|
pushed_at?: string;
|
|
252
|
+
license?: { spdx_id?: string | null } | null;
|
|
229
253
|
}
|
|
230
254
|
|
|
231
|
-
|
|
232
|
-
export const ghApiSearchRepos: SearchGithubRepos = async (query, perQuery) => {
|
|
233
|
-
const perPage = Math.min(100, Math.max(1, perQuery));
|
|
234
|
-
const q = `${query} sort:stars`;
|
|
235
|
-
const out = execFileSync('gh', [
|
|
236
|
-
'api',
|
|
237
|
-
'-X', 'GET',
|
|
238
|
-
'search/repositories',
|
|
239
|
-
'-f', `q=${q}`,
|
|
240
|
-
'-f', 'sort=stars',
|
|
241
|
-
'-f', 'order=desc',
|
|
242
|
-
'-f', `per_page=${perPage}`,
|
|
243
|
-
'--jq', '.items',
|
|
244
|
-
], { encoding: 'utf8', timeout: 30_000 });
|
|
245
|
-
const items = JSON.parse(out) as GhSearchItem[];
|
|
255
|
+
export function reposFromGhSearchItems(items: GhSearchItem[], perQuery: number): GithubStarRepo[] {
|
|
246
256
|
if (!Array.isArray(items)) return [];
|
|
247
257
|
const repos: GithubStarRepo[] = [];
|
|
248
258
|
for (const item of items) {
|
|
@@ -254,7 +264,29 @@ export const ghApiSearchRepos: SearchGithubRepos = async (query, perQuery) => {
|
|
|
254
264
|
stars: Number(item.stargazers_count ?? 0),
|
|
255
265
|
createdAt: item.created_at ?? '',
|
|
256
266
|
pushedAt: item.pushed_at ?? '',
|
|
267
|
+
...(item.license === null
|
|
268
|
+
? { license: '없음' }
|
|
269
|
+
: typeof item.license?.spdx_id === 'string' && item.license.spdx_id
|
|
270
|
+
? { license: item.license.spdx_id }
|
|
271
|
+
: {}),
|
|
257
272
|
});
|
|
258
273
|
}
|
|
259
274
|
return repos.slice(0, perQuery);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** `gh api search/repositories` 를 `sort=stars` 로 한 번 부른다. */
|
|
278
|
+
export const ghApiSearchRepos: SearchGithubRepos = async (query, perQuery) => {
|
|
279
|
+
const perPage = Math.min(100, Math.max(1, perQuery));
|
|
280
|
+
const q = `${query} sort:stars`;
|
|
281
|
+
const out = execFileSync('gh', [
|
|
282
|
+
'api',
|
|
283
|
+
'-X', 'GET',
|
|
284
|
+
'search/repositories',
|
|
285
|
+
'-f', `q=${q}`,
|
|
286
|
+
'-f', 'sort=stars',
|
|
287
|
+
'-f', 'order=desc',
|
|
288
|
+
'-f', `per_page=${perPage}`,
|
|
289
|
+
'--jq', '.items',
|
|
290
|
+
], { encoding: 'utf8', timeout: 30_000 });
|
|
291
|
+
return reposFromGhSearchItems(JSON.parse(out) as GhSearchItem[], perQuery);
|
|
260
292
|
};
|