elanous 0.2.13 → 0.2.14
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/chunks/{7334.a6679d9168f37aa8.js → 1268.0840ff91e083fcbd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1307-6e7e0377c1db0bdc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/1826-5d279da64bbbc2de.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{9656-c1540088f5859c80.js → 1844-9ec4b1d12f6e80eb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1866-e7a6999f25548b30.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{390.c373e31b3b9d0c41.js → 1948.15f356b15a625597.js} +2 -2
- package/apps/pwa/out/_next/static/chunks/211-9c9090c59e2c5907.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2196-4700653d12a44b40.js +1 -0
- package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2699-63b73fa4d3bcf6ff.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2957-96ffab3d521fb08f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/311.e685738f92e6e2ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3194-807b212fb8eae065.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3324-d1d2979821dfa845.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3558-bbb5ab553a0471d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3916-3d02dd1fc257dd3c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4554-3565eea1f1495ba7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4562-071d8bac44a01069.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{4685-c3c1c625b71accd1.js → 4614-21403aac730d4586.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{8039-df92e08fede5de8f.js → 4795-f372490b178583fc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/5135-44008fe8b1f2aa41.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5233-bf28bd6bd7a32099.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5360-be1f1d8f9fcc9755.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5977-2df489622a52a33a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1452.93700483b9d4fc61.js → 6110.1297d4093fdfbb0d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/6158.9c0449a9a8d0064b.js +2 -0
- package/apps/pwa/out/_next/static/chunks/6877-7c6208705c284124.js +1 -0
- package/apps/pwa/out/_next/static/chunks/726.83532d69452ee24b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7290-f09c928a06c52e2d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1829-b453a1b22d3999bb.js → 7327-2d69fb321ba73389.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/7395-164e238f471b5d7b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7787-02a1c0b04e25e811.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8060-cc008cc6fedfa818.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8085-d065d0393c1760f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8682-7061dd4fa7bd62ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8827-e2f5b09a8d37e83b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +25 -0
- package/apps/pwa/out/_next/static/chunks/{8421-1c4acfb1395a0edf.js → 8949-ecb4128a0858b911.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9070.067c106528ec1ae6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9103-7a3ae7f60af3b99f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{3869-3cd46526879f454c.js → 9247-29d889b809288e65.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/935.4ddaa99fc1d1126c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{79f8be9e-957d68913b590b08.js → a9f2b54d-7865aba0f4d2ee49.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-74383f890f075511.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-7b2b4f378354869a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/board/page-c496bb16da85385f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-f14987d5850a31e0.js → page-1abfe3aec3be6bdc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-1512d91c7491ed62.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/page-a627db94ec6904a0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/consult/page-fb260b9283dbf646.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/page-e6b84ab07d3567d5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-61ec1d2e92bdd50a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/editor/page-fed69f9759d248d0.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/page-15374909d8f1aebd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-012a742f81218b01.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-fd7e200d4d83fbd7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/page-99effd9d893a43dc.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/layout-938de57ae0315e46.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/page-d47266766766d227.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/loops/page-160089123a40dd91.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/page-629e1ede482ec6eb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-66c27608f651b866.js → page-2ce5471926761fdd.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-27e99b4e54a849d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/not-found-e995d30f6800b6bf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-39f89c53038a51d4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-32cde713be47cddb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-e7e10cd3386222e5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-5a753bb4ec0cc511.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-04250f0e2c0d03df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-341480ed8e3c1ea8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-e64caff084f7ce21.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-db07eaffba0df7e3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-8ac8d71c2adf9c8a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-78b40a344ed22f24.js → page-e1e47d8d940aba3d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-86f91034bd5cabe5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-94dc383d3d54db1a.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-c1a96669158471ec.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/page-b3759cc14da80908.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/share/page-ce4d8a1215ce53a3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-58043db78ba519ae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-357750dfb91bf960.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/term/{page-63d14a4d8fe1e1c1.js → page-274703bc41b71333.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-194dce4a83143fce.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/page-35bdeae2e2c17147.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/vault/page-3b7e821dc492bdfd.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-16bef3da05a900c3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-f8da5dc6f3752276.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2f810b18d89ecba6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-134c1bc762aee62c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{5cd7e3a9-404fd6b8d0ecd44c.js → f6231284-45726550aba08fca.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/{f48170cc-d05d28bf87a43bf4.js → f6b7c9ba.64a895b8b2fedbdc.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/framework-5c169757551134ed.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-59fe95fed40c7a01.js +1 -0
- package/apps/pwa/out/_next/static/chunks/main-app-4ca74dbbee7057c6.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_app-13a0a886df4d97a1.js +1 -0
- package/apps/pwa/out/_next/static/chunks/pages/_error-6af8591cd3a3f038.js +1 -0
- package/apps/pwa/out/_next/static/chunks/webpack-539cde99554be20f.js +1 -0
- package/apps/pwa/out/_next/static/css/2e33713c444d5b39.css +1 -0
- package/apps/pwa/out/_next/static/x6mjI6vqOkVVu0jFuDkz1/_buildManifest.js +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +23 -23
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +23 -23
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +23 -23
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +22 -22
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +22 -22
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +22 -22
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +23 -23
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +23 -23
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +23 -23
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +23 -23
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +23 -23
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +23 -23
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +22 -22
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +22 -22
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +23 -23
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +23 -23
- package/apps/pwa/out/loops/index.html +1 -0
- package/apps/pwa/out/loops/index.txt +30 -0
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +22 -22
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +22 -22
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +23 -23
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +23 -23
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +22 -22
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +22 -22
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +22 -22
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +22 -22
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +23 -23
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +23 -23
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +22 -22
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +23 -23
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +23 -23
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +23 -23
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +23 -23
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +23 -23
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +22 -22
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +23 -23
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +23 -23
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +23 -23
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +23 -23
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +23 -23
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +23 -23
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +23 -23
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +23 -23
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +23 -23
- package/graphs/orchestrator/orchestrator.yaml +59 -0
- package/graphs/orchestrator/recipes.yaml +18 -0
- package/graphs/release/recipes.yaml +3 -0
- package/graphs/release/release-loop.yaml +4 -1
- package/graphs/rhythm/daily.yaml +38 -0
- package/graphs/rhythm/recipes.yaml +18 -0
- package/graphs/rhythm/weekly.yaml +39 -0
- package/graphs/video/recipes.yaml +3 -0
- package/graphs/video/youtube-summary.yaml +17 -0
- package/package.json +1 -1
- package/scripts/audit-test-state-writes.ts +72 -17
- package/scripts/brand/check.ts +186 -0
- package/scripts/coord-post.sh +11 -1
- package/scripts/docs-cli-check.ts +23 -6
- package/scripts/expose-rubric-check.ts +118 -0
- package/scripts/expose-rubric-suggest.ts +163 -0
- package/scripts/heal/run-role.ts +14 -0
- package/scripts/hq/standby-verify.ts +11 -7
- package/scripts/lessons/handbook-page.ts +85 -0
- package/scripts/release-loop/gate-node.ts +9 -0
- package/scripts/release-loop/publish-node.ts +14 -1
- package/scripts/release-loop/unattended-release.ts +23 -1
- package/scripts/release-loop/vault-note-node.ts +196 -0
- package/scripts/release-story/draft.ts +172 -0
- package/scripts/rhythm/daily.ts +383 -0
- package/scripts/rhythm/weekly.ts +294 -0
- package/scripts/skills/public-check.ts +169 -0
- package/scripts/test-deterministic.ts +4 -8
- package/scripts/test-diet/effectiveness.ts +195 -0
- package/scripts/test-diet/lib.ts +16 -8
- package/scripts/test-diet/node.ts +77 -9
- package/scripts/ux/demo-rehearsal.ts +2 -2
- package/scripts/ux/lib/rehearsal-verdict.ts +1 -0
- package/scripts/video/youtube-summary.ts +133 -0
- package/skills/diagram-master/SKILL.md +42 -49
- package/skills/diagram-master/references/pyproject.toml +4 -1
- package/skills/diagram-master/references/routing-guide.md +4 -2
- package/skills/grill-me/SKILL.md +1 -0
- package/skills/youtube-master/SKILL.md +13 -13
- package/skills/youtube-master/package-lock.json +0 -545
- package/skills/youtube-master/package.json +2 -5
- package/skills/youtube-master/scripts/main.ts +2 -2
- package/skills/youtube-master/scripts/transcribe-local.ts +1 -1
- package/skills/youtube-master/src/util.ts +30 -7
- package/src/agent-mission/driver.ts +3 -3
- package/src/autopilot/build/llm-conflict-merge.ts +45 -8
- package/src/autopilot/build/merge-intent.ts +53 -0
- package/src/chat/index.ts +2 -0
- package/src/claims/claims-ledger.ts +232 -0
- package/src/claims/claims-render.ts +157 -0
- package/src/cli/claims-cli.ts +94 -0
- package/src/cli/decisions-cli.ts +35 -3
- package/src/cli/docs-cli.ts +2 -0
- package/src/cli/flow-cli.ts +11 -0
- package/src/cli/freeze-cli.ts +45 -0
- package/src/cli/lesson-cli.ts +108 -0
- package/src/cli/logs-cli.ts +104 -2
- package/src/cli/logs-model-input.ts +131 -0
- package/src/cli/pr-cli.ts +29 -1
- package/src/cli/private-ledger-commands.ts +54 -4
- package/src/cli/pty-drive-verdict.ts +11 -2
- package/src/cli/release-cli.ts +144 -21
- package/src/cli/rfc-status.ts +91 -0
- package/src/connectors/linear.ts +5 -3
- package/src/context-bus/condense.ts +15 -20
- package/src/context-bus/context-now-public.ts +86 -0
- package/src/context-bus/context-now-surfaces.ts +55 -2
- package/src/context-bus/context-now.ts +4 -3
- package/src/context-bus/long-term-memory.ts +92 -11
- package/src/dashboard/index.ts +75 -22
- package/src/dashboard/slash-runtime/chat-persona.ts +66 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +99 -0
- package/src/dashboard/slash-runtime/loops-table.ts +77 -0
- package/src/decisions/decision-ledger.ts +40 -1
- package/src/discord/sprint21-runtime.ts +16 -0
- package/src/discord-self-message.ts +8 -0
- package/src/discord-slash-wire.ts +31 -2
- package/src/domains/outbound-alert.ts +1 -1
- package/src/elanous-config-dir.ts +29 -4
- package/src/execution-loop/launch-gate.ts +29 -14
- package/src/flow/cards.ts +239 -0
- package/src/graph-runner/graph-tick.ts +4 -0
- package/src/graph-runner/runner.ts +30 -5
- package/src/harness/harness-cli-command.ts +152 -27
- package/src/harness/harness-incidents.ts +43 -12
- package/src/harness/harness-pod-dispatch.ts +2 -0
- package/src/harness/harness-queue-child.ts +3 -3
- package/src/harness/harness-queue.ts +216 -28
- package/src/harness/helper-scan.ts +139 -0
- package/src/harness/model-input-observation.ts +37 -0
- package/src/hq/hq.ts +1 -1
- package/src/hq/promote.ts +301 -0
- package/src/index.ts +83 -21
- package/src/intake-plane/linear-wish.ts +39 -11
- package/src/intake-plane/wish-benchmark-ledger.ts +129 -0
- package/src/intake-plane/wish-card.ts +53 -2
- package/src/intake-plane/wish-folder.ts +5 -2
- package/src/intake-plane/wish-reply.ts +72 -0
- package/src/lessons/lesson-import.ts +106 -0
- package/src/lessons/lesson-ledger.ts +206 -0
- package/src/loops/activity.ts +203 -0
- package/src/loops/budget.ts +32 -0
- package/src/loops/checker.ts +5 -3
- package/src/loops/contract/examples/orchestrator.loop.yaml +1 -1
- package/src/loops/loop-cli.ts +36 -4
- package/src/loops/neighbors.ts +40 -0
- package/src/loops/observe.ts +10 -0
- package/src/loops/orchestrator/author-depth.ts +164 -0
- package/src/loops/orchestrator/author-input-check.ts +77 -0
- package/src/loops/orchestrator/author-ledger.ts +230 -0
- package/src/loops/orchestrator/finish-rate.ts +175 -0
- package/src/loops/orchestrator/overlap.ts +51 -12
- package/src/loops/orchestrator/resync-shadow.ts +227 -0
- package/src/loops/orchestrator/tick.ts +302 -0
- package/src/loops/orchestrator/traffic.ts +18 -3
- package/src/loops/registry.ts +454 -9
- package/src/loops/status-rows.ts +118 -0
- package/src/loops/verdict.ts +17 -5
- package/src/maturity/bot-slash-catalog.ts +66 -0
- package/src/maturity/feature-maturity.ts +7 -4
- package/src/nexus/api/dashboard.ts +6 -1
- package/src/nexus/api/http-server.ts +18 -2
- package/src/nexus/api/merge-approvals-gate.ts +1 -1
- package/src/nexus/api/schedules-read.ts +5 -1
- package/src/nexus/api/task-cards-api.ts +44 -5
- package/src/nexus/api/workflows.ts +2 -1
- package/src/release-loop/auto-start.ts +48 -0
- package/src/release-loop/checklist.ts +13 -4
- package/src/release-loop/feature-store.ts +28 -16
- package/src/release-loop/landing-freeze.ts +121 -0
- package/src/release-loop/placement.ts +242 -0
- package/src/release-loop/release-schedule.ts +3 -1
- package/src/seat-dispatch/ceo-commands.ts +2 -2
- package/src/seat-dispatch/seat-ask.ts +16 -3
- package/src/seat-dispatch/seat-questions.ts +58 -0
- package/src/seat-loop/seat-loop.ts +406 -31
- package/src/self-dev/dev-pipeline.ts +6 -2
- package/src/self-dev/draft-sweep.ts +76 -0
- package/src/self-dev/run-store.ts +73 -1
- package/src/self-dev/run-supervisor.ts +8 -0
- package/src/self-dev/self-orchestrate-runtime.ts +5 -1
- package/src/self-implement/budget-gate.ts +29 -0
- package/src/self-implement/expose-gate.ts +47 -0
- package/src/self-implement/frozen-merges.ts +294 -0
- package/src/self-implement/gate-cli.ts +10 -4
- package/src/self-implement/gate-scope.ts +46 -9
- package/src/self-implement/goal-archive.ts +222 -0
- package/src/self-implement/goal-lookup.ts +147 -0
- package/src/self-implement/heal-intake.ts +79 -0
- package/src/self-implement/host-regate.ts +25 -2
- package/src/self-implement/orchestrator.ts +114 -10
- package/src/self-implement/revert-guard.ts +62 -0
- package/src/self-implement/run-ledger.ts +1 -1
- package/src/self-implement/seams.ts +28 -8
- package/src/session/index.ts +2 -0
- package/src/task-cards/card-cli.ts +10 -2
- package/src/task-cards/card-store.ts +10 -6
- package/src/task-orchestrator/surfaces/pod-lease.ts +5 -2
- package/src/task-orchestrator/surfaces/pod-ledger-collect.ts +46 -6
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +80 -16
- package/src/telegram-commands.ts +27 -3
- package/src/telegram-loops-command.ts +44 -0
- package/src/user-config.ts +120 -16
- package/src/version/packed-revision.json +1 -1
- package/src/workflow-runtime/storage.ts +31 -13
- package/apps/pwa/out/_next/static/D51l8jUBplJrIpWvENsDK/_buildManifest.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1159-0c5ef8bc21cb6afb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/1394-931c9827067b2276.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2176-c379e3ebce874151.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2426.8c6ee0c668d53def.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3170-7ec60a56fa0e4728.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3278-ae6ef084769f6195.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3454-988a53dac60a1763.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3638-aa80b4641ea439db.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3735-fe3402553ac1c9c6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3992-fe5c06d6b31f8b25.js +0 -25
- package/apps/pwa/out/_next/static/chunks/4215-c9d91dd644ec1719.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4508-5d0161d1e724d735.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4733-623a79345b171e1c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4883.3bd969ea1d3aaaff.js +0 -2
- package/apps/pwa/out/_next/static/chunks/5250-c78ca295585bbf95.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5532.6899a12958a89b72.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5845-e6c003ce8d5fd36a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5978-b27004c677119115.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6048-4c5c33579bc4ef78.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6303-422dbf0f67c72aac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6511-ff8360be3d65aaa4.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6588-ba380869b67c4fa7.js +0 -1
- package/apps/pwa/out/_next/static/chunks/6751-bb3595948b2e311b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7274-19b7279f18b47ab3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7551-a0e0707b79164ddd.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7758-85c2b53f731da024.js +0 -1
- package/apps/pwa/out/_next/static/chunks/7777-79f845045aa1ed86.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8025-cc24ee5d8f2fb6f8.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8206-c6684dcde12be721.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8605-9da4678f8a310d18.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8725.bf46bb1395dd0fa2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8734-252d511cd276c0dc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8834-ca1cb09c1cb1a6bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9269.d2a4795bc6812717.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9538-2816b90923606459.js +0 -1
- package/apps/pwa/out/_next/static/chunks/9906-e7b8b5310a169dfe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/_not-found/page-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-e5b4e1b256f41076.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/page-e49b9b76c565a0b1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/board/page-b4f032c893b21cc9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/page-b433308aad13ceb6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/page-4c1dbb21861beab2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-c85b816e3b269dbb.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/control/page-f6bc66b919b2ea7d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/page-60603c1e056c9b25.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-a0ea8f5a2341ee6b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-45c5bf04b4a605e6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-36c6c4183353ac9e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/healthz/route-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-cb2eb0fd809980da.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/intake/page-31012264da8a341f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-50309aeb0bdd554a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/live/page-bc00e964e855f4df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/market/page-0696ee3fac9fe56c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/page-6ddd2109b7fc3a80.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/not-found-4e50b7298c1f69a5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-7a2bf830038a2264.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-1f327f18694fabca.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-e5cef2fe6e4028df.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cf596128d2b420ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-f672536f14f0969f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-b52365662232db89.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/reflection/page-e7a6c80f288b1948.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-29a709616df9b050.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/page-fee842d7c2151129.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/page-75d199f448171014.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-a011dd5b0bff29c5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/layout-d16993889b125c42.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/page-d92e32d51ab5157e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-5f21aed6932ef375.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-1e1a53946804debf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/page-a1833cd43d832601.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-2a511d320f762e06.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/page-1c3e03f88dac1e21.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-c4d5289c2ea97a89.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b91f8952deaeaf27.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-71b43a2588489987.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2b256feed331546f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-505bb96d69a8622c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/framework-172630e6aa5e2d7f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-app-f0fe2d7477845181.js +0 -1
- package/apps/pwa/out/_next/static/chunks/main-fc98ac70b44eccb0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_app-5bd7f10271f72413.js +0 -1
- package/apps/pwa/out/_next/static/chunks/pages/_error-97d0d85ea05fef9b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/webpack-9e4d02d567b98240.js +0 -1
- package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.css +0 -1
- /package/apps/pwa/out/_next/static/{D51l8jUBplJrIpWvENsDK → x6mjI6vqOkVVu0jFuDkz1}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { checkBrand } from '../../scripts/brand/check.js';
|
|
5
|
+
import type { ContextFact, ContextNowAnswer } from './context-now.js';
|
|
6
|
+
|
|
7
|
+
const internalItem = (count: number) => `내부 항목 ${count}개`;
|
|
8
|
+
const seatNames: Record<string, string> = { OP: '운영', TC: '기술', MK: '마케팅', UX: '사용자 경험' };
|
|
9
|
+
|
|
10
|
+
/** Public copy only: no raw ledger identifiers or private sources in the rendered answer. */
|
|
11
|
+
export function filterPublicDemoContext(answer: ContextNowAnswer): ContextNowAnswer {
|
|
12
|
+
const dir = mkdtempSync(join(tmpdir(), 'context-now-public-'));
|
|
13
|
+
const file = join(dir, 'text.txt');
|
|
14
|
+
try {
|
|
15
|
+
const flagged = (texts: string[]): Set<number> => {
|
|
16
|
+
if (!texts.length) return new Set();
|
|
17
|
+
writeFileSync(file, texts.map(text => text.replace(/[\r\n]+/g, ' ')).join('\n') + '\n');
|
|
18
|
+
const result = checkBrand('public-docs', [file]);
|
|
19
|
+
if (result.missing) throw new Error('brand rules missing');
|
|
20
|
+
return new Set(result.findings.map(finding => finding.line - 1));
|
|
21
|
+
};
|
|
22
|
+
const publicText = (value: string): string => value
|
|
23
|
+
.replace(/\bhttps?:\/\/[^\s)\]}>]+/gi, '공개 주소')
|
|
24
|
+
.replace(/\b(?:[\w-]+\.)+[a-z]{2,}(?::\d+)?(?:\/[^\s)\]}>]*)?/gi, '공개 주소')
|
|
25
|
+
.replace(/(?:\/Users\/|\/home\/|\/root(?=[\/\s)\]}>]|$)|~(?=\/)|\$HOME(?=\/)|\$\{HOME\}(?=\/))[^\s)\]}>]*/g, '공개 경로')
|
|
26
|
+
.replace(/\b[\w.-]+@(?!공개)[a-z][\w-]*(?=\b|:\d)/gi, '공개 호스트')
|
|
27
|
+
.replace(/\b(?:run[-_][a-z0-9-]{8,}|[a-f0-9]{8}-[a-f0-9-]{16,})\b/gi, '공개 실행')
|
|
28
|
+
.replace(/\bPR[\s-]*#?\d+\b|#\d+\b/gi, '공개 변경')
|
|
29
|
+
.replace(/\b(?:OP|TC|MK|UX)\b/g, seat => seatNames[seat]!)
|
|
30
|
+
.replace(/\b(host(?:name)?|machine|server)\s*([:=])\s*([a-z][\w-]*)\b/gi, '$1$2 공개 호스트')
|
|
31
|
+
.replace(/\b(host(?:name)?|machine|server|ssh|scp|rsync|ping|mosh)\s+((?:to|from|into|on|at)\s+)?(?!공개)([a-z][\w-]*)(?=\b|:\d)/gi, '$1 $2공개 호스트')
|
|
32
|
+
.replace(/\b((?:deploy(?:ed|ing)?|connect(?:ed|ing)?)\s+(?:at|on|to|from))\s+[a-z][\w-]*(?=\b|:\d)/gi, '$1 공개 호스트')
|
|
33
|
+
.replace(/\b(at|on|to|from)\s+(?:msb\d+|localhost|[a-z][\w-]*\d+)(?=\b|:\d)/gi, '$1 공개 호스트')
|
|
34
|
+
.replace(/\b(?:msb\d+|node-c|cloud-vm|localhost)\b/gi, '공개 호스트');
|
|
35
|
+
const safe = (value: string, fallback: string): string => {
|
|
36
|
+
const text = publicText(value);
|
|
37
|
+
return flagged([text]).size ? fallback : text;
|
|
38
|
+
};
|
|
39
|
+
const source = (value: string) => value.startsWith('elanous://') ? '내부 원장' : safe(value, '공개 출처');
|
|
40
|
+
const titleFacts = answer.facts.filter((fact): fact is Extract<ContextFact, { kind: 'cell' | 'decision' }> =>
|
|
41
|
+
fact.kind === 'cell' || fact.kind === 'decision');
|
|
42
|
+
const privateTitles = flagged(titleFacts.map(fact => fact.title));
|
|
43
|
+
const privateFacts = new Set(titleFacts.filter((_, index) => privateTitles.has(index)));
|
|
44
|
+
const privateIds = new Set(titleFacts.filter(fact => privateFacts.has(fact)).map(fact => fact.id));
|
|
45
|
+
const hasOpenPrivateDecision = titleFacts.some(fact => fact.kind === 'decision' && privateFacts.has(fact) && fact.status === 'open');
|
|
46
|
+
const publicField = (value: string, fallback: string) => safe(value.replace(/\b(?:K|D)\d+\b/g, id =>
|
|
47
|
+
privateIds.has(id) ? '내부 항목' : id), fallback);
|
|
48
|
+
const collapsed = { cell: 0, decision: 0 };
|
|
49
|
+
const facts: ContextFact[] = [];
|
|
50
|
+
for (const fact of answer.facts) {
|
|
51
|
+
if (fact.kind === 'cell' || fact.kind === 'decision') {
|
|
52
|
+
if (privateFacts.has(fact)) {
|
|
53
|
+
collapsed[fact.kind]++;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
facts.push(fact.kind === 'cell'
|
|
57
|
+
? { ...fact, version: safe(fact.version, '공개 판'), id: safe(fact.id, '공개 항목'), title: safe(fact.title, '공개 항목'),
|
|
58
|
+
status: safe(fact.status, '진행 중'), owner: fact.owner ? safe(fact.owner, '공개 담당') : null, source: source(fact.source) }
|
|
59
|
+
: { ...fact, id: safe(fact.id, '공개 항목'), title: safe(fact.title, '공개 항목'),
|
|
60
|
+
status: safe(fact.status, '진행 중'), source: source(fact.source) });
|
|
61
|
+
} else if (fact.kind === 'seat') {
|
|
62
|
+
facts.push({ ...fact, seat: safe(fact.seat, '공개 담당'), status: safe(fact.status, '진행 중'),
|
|
63
|
+
id: fact.id ? (privateIds.has(fact.id) ? '내부 항목' : safe(fact.id, '공개 항목')) : null,
|
|
64
|
+
title: fact.title ? (privateIds.has(fact.id ?? '') ? '내부 항목' : safe(fact.title, '공개 항목')) : null, source: source(fact.source) });
|
|
65
|
+
} else facts.push({ ...fact, version: safe(fact.version, '공개 판'), source: source(fact.source) });
|
|
66
|
+
}
|
|
67
|
+
for (const kind of ['cell', 'decision'] as const) {
|
|
68
|
+
if (!collapsed[kind]) continue;
|
|
69
|
+
const title = internalItem(collapsed[kind]);
|
|
70
|
+
facts.push(kind === 'cell'
|
|
71
|
+
? { kind, version: '공개 판', id: '내부 항목', title, status: '진행 중', owner: null, source: '내부 원장' }
|
|
72
|
+
: { kind, id: '내부 항목', title, status: hasOpenPrivateDecision ? 'open' : '진행 중', dueAt: null, source: '내부 원장' });
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
at: answer.at,
|
|
76
|
+
topic: answer.topic === null ? null : publicField(answer.topic, '공개 주제'),
|
|
77
|
+
facts,
|
|
78
|
+
events: answer.events.map(event => ({ ...event, kind: safe(event.kind, '소식'),
|
|
79
|
+
summary: publicField(event.summary, '공개 소식'), source: source(event.source) })),
|
|
80
|
+
guide: answer.guide.map(text => publicField(text, '공개 안내')),
|
|
81
|
+
hiddenCount: collapsed.cell + collapsed.decision,
|
|
82
|
+
};
|
|
83
|
+
} finally {
|
|
84
|
+
rmSync(dir, { recursive: true, force: true });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { contextNow, type ContextFact, type ContextNowAnswer, type ContextNowDeps } from './context-now.js';
|
|
2
|
+
import { filterPublicDemoContext } from './context-now-public.js';
|
|
3
|
+
|
|
4
|
+
export type ContextNowAudience = 'operator' | 'user' | 'public-demo';
|
|
5
|
+
const publicSeatNames: Record<string, string> = { OP: '운영', MK: '마케팅', TC: '기술', UX: '사용자 경험' };
|
|
6
|
+
const seatOrder = ['OP', 'MK', 'TC', 'UX'] as const;
|
|
7
|
+
const forAudience = (answer: ContextNowAnswer, audience: ContextNowAudience): ContextNowAnswer =>
|
|
8
|
+
audience === 'public-demo' ? filterPublicDemoContext(answer) : answer;
|
|
2
9
|
|
|
3
10
|
export function readSlashContextNow(args: string[], deps?: ContextNowDeps): ContextNowAnswer {
|
|
4
11
|
return contextNow({ topic: args.join(' ').trim() }, deps);
|
|
@@ -30,7 +37,8 @@ function factText(fact: ContextFact): string {
|
|
|
30
37
|
}
|
|
31
38
|
}
|
|
32
39
|
|
|
33
|
-
export function renderTelegramNow(
|
|
40
|
+
export function renderTelegramNow(input: ContextNowAnswer, audience: ContextNowAudience = 'operator'): string {
|
|
41
|
+
const answer = forAudience(input, audience);
|
|
34
42
|
const rows = [
|
|
35
43
|
['판', answer.facts.filter(f => f.kind === 'version')],
|
|
36
44
|
['칸', answer.facts.filter(f => f.kind === 'cell')],
|
|
@@ -42,7 +50,8 @@ export function renderTelegramNow(answer: ContextNowAnswer): string {
|
|
|
42
50
|
return lines.map(line => line.replace(/\s+/g, ' ').trim()).join('\n');
|
|
43
51
|
}
|
|
44
52
|
|
|
45
|
-
export function renderTuiNow(
|
|
53
|
+
export function renderTuiNow(input: ContextNowAnswer, audience: ContextNowAudience = 'operator'): string[] {
|
|
54
|
+
const answer = forAudience(input, audience);
|
|
46
55
|
const shortText = (text: string) => {
|
|
47
56
|
const characters = Array.from(text);
|
|
48
57
|
return characters.length > 100 ? `${characters.slice(0, 100).join('')}…` : text;
|
|
@@ -69,6 +78,50 @@ export function renderTuiNow(answer: ContextNowAnswer): string[] {
|
|
|
69
78
|
];
|
|
70
79
|
}
|
|
71
80
|
|
|
81
|
+
/** Voice keeps the source-labelled ledger view out of the spoken transcript. */
|
|
82
|
+
export function renderVoiceNow(input: ContextNowAnswer, audience: ContextNowAudience = 'operator'): string {
|
|
83
|
+
const answer = forAudience(input, audience);
|
|
84
|
+
const spoken = (text: string) => text.replace(/\s+/g, ' ').replace(/[.!?。!?]+/g, ' ').trim();
|
|
85
|
+
const sentence = (text: string) => `${Array.from(spoken(text)).slice(0, 119).join('').trimEnd()}。`;
|
|
86
|
+
const seats = seatOrder.flatMap(seat => {
|
|
87
|
+
const label = audience === 'public-demo' ? publicSeatNames[seat]! : seat;
|
|
88
|
+
const latest = answer.facts.filter((fact): fact is Extract<ContextFact, { kind: 'seat' }> => fact.kind === 'seat' && (fact.seat === label || (audience === 'public-demo' && fact.seat === seat)))
|
|
89
|
+
.sort((a, b) => Date.parse(b.at) - Date.parse(a.at))[0];
|
|
90
|
+
if (!latest) return [];
|
|
91
|
+
return [`${label} ${Array.from(spoken(latest.title ?? latest.status)).slice(0, 18).join('')}`];
|
|
92
|
+
});
|
|
93
|
+
const first = sentence(seats.length ? `지금 ${seats.join(', ')} 중입니다` : '지금 자리 현황은 확인되지 않았습니다');
|
|
94
|
+
const decision = answer.facts.find(fact => fact.kind === 'decision' && fact.status === 'open');
|
|
95
|
+
const cell = answer.facts.find(fact => fact.kind === 'cell' && fact.status !== 'done');
|
|
96
|
+
const shortTitle = (text: string) => Array.from(spoken(text)).slice(0, 75).join('').trimEnd();
|
|
97
|
+
const next = decision?.kind === 'decision' ? `다음은 ${shortTitle(decision.title)} 결정이 필요합니다`
|
|
98
|
+
: cell?.kind === 'cell' ? `다음은 ${shortTitle(cell.title)} 칸을 확인해야 합니다`
|
|
99
|
+
: '다음에 필요한 결정이나 미완료 칸은 확인되지 않았습니다';
|
|
100
|
+
return `${first} ${sentence(next)}`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** A compact card retains the same source-labelled public facts as the other /now surfaces. */
|
|
104
|
+
export function renderCardNow(input: ContextNowAnswer, audience: ContextNowAudience = 'operator'): {
|
|
105
|
+
title: string;
|
|
106
|
+
sections: Array<{ label: string; items: Array<{ text: string; source: string }> }>;
|
|
107
|
+
} {
|
|
108
|
+
const answer = forAudience(input, audience);
|
|
109
|
+
const kinds = [
|
|
110
|
+
['판', 'version'], ['칸', 'cell'], ['결정', 'decision'], ['자리', 'seat'],
|
|
111
|
+
] as const;
|
|
112
|
+
return {
|
|
113
|
+
title: `지금${answer.topic ? ` · ${answer.topic}` : ''} (${answer.at})`,
|
|
114
|
+
sections: [
|
|
115
|
+
...kinds.map(([label, kind]) => ({
|
|
116
|
+
label,
|
|
117
|
+
items: answer.facts.filter(fact => fact.kind === kind).map(fact => ({ text: factText(fact), source: fact.source })),
|
|
118
|
+
})),
|
|
119
|
+
{ label: '최근', items: answer.events.map(event => ({ text: event.summary, source: event.source })) },
|
|
120
|
+
{ label: '안내', items: answer.guide.map(text => ({ text, source: '' })) },
|
|
121
|
+
],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
72
125
|
export function telegramNowSlash(args: string[], deps?: ContextNowDeps): string {
|
|
73
126
|
return renderTelegramNow(readSlashContextNow(args, deps));
|
|
74
127
|
}
|
|
@@ -5,6 +5,7 @@ import { listChecklist, devVersion, type Checklist } from '../release-loop/check
|
|
|
5
5
|
import { effectiveInstanceRoot } from '../instance/resolve.js';
|
|
6
6
|
import { seatDay, seatLedgerPath, type SeatEntry } from '../seat-loop/seat-loop.js';
|
|
7
7
|
import { listCoordEvents, type CoordEvent } from './coord-events.js';
|
|
8
|
+
import { filterPublicDemoContext } from './context-now-public.js';
|
|
8
9
|
|
|
9
10
|
export type ContextFact =
|
|
10
11
|
| { kind: 'version'; version: string; source: string }
|
|
@@ -12,7 +13,7 @@ export type ContextFact =
|
|
|
12
13
|
| { kind: 'decision'; id: string; title: string; status: string; dueAt: string | null; source: string }
|
|
13
14
|
| { kind: 'seat'; seat: string; at: string; status: string; id: string | null; title: string | null; source: string };
|
|
14
15
|
export type ContextEvent = { at: string; kind: string; summary: string; source: string };
|
|
15
|
-
export type ContextNowAnswer = { at: string; topic: string | null; facts: ContextFact[]; events: ContextEvent[]; guide: string[] };
|
|
16
|
+
export type ContextNowAnswer = { at: string; topic: string | null; facts: ContextFact[]; events: ContextEvent[]; guide: string[]; hiddenCount?: number };
|
|
16
17
|
|
|
17
18
|
export interface ContextNowDeps {
|
|
18
19
|
now?: () => Date;
|
|
@@ -37,7 +38,7 @@ function todaySeatEntries(now: Date): Array<{ entry: SeatEntry; source: string }
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
/** Read a bounded, source-labelled view of current ledgers, never a transcript or decision body. */
|
|
40
|
-
export function contextNow(options: { topic?: string; limit?: number } = {}, deps: ContextNowDeps = {}): ContextNowAnswer {
|
|
41
|
+
export function contextNow(options: { topic?: string; limit?: number; audience?: 'operator' | 'user' | 'public-demo' } = {}, deps: ContextNowDeps = {}): ContextNowAnswer {
|
|
41
42
|
const now = (deps.now ?? (() => new Date()))();
|
|
42
43
|
const at = `${now.toISOString().slice(0, 16)}:00.000Z`;
|
|
43
44
|
const topic = options.topic?.trim() || null;
|
|
@@ -100,5 +101,5 @@ export function contextNow(options: { topic?: string; limit?: number } = {}, dep
|
|
|
100
101
|
.map(event => `📌 ${event.summary} — ${event.source}`);
|
|
101
102
|
const answer = { at, topic, facts: boundedFacts, events: selectedEvents, guide };
|
|
102
103
|
debug.log('context.now', 'answer', { topic, facts: answer.facts, events: answer.events });
|
|
103
|
-
return answer;
|
|
104
|
+
return options.audience === 'public-demo' ? filterPublicDemoContext(answer) : answer;
|
|
104
105
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { Database } from 'bun:sqlite';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
1
3
|
import { debug, redactSecretText } from '../debug/log.js';
|
|
2
4
|
import { DecisionLedger, type DecisionEntry } from '../decisions/decision-ledger.js';
|
|
5
|
+
import { surfaceEventsDbPath } from '../domains/surface-events.js';
|
|
3
6
|
import { listCoordEvents, type CoordEvent } from './coord-events.js';
|
|
4
7
|
|
|
5
8
|
export interface MemoryItem {
|
|
@@ -27,23 +30,50 @@ export interface MemorySummary {
|
|
|
27
30
|
claim?: { key: string; value: string };
|
|
28
31
|
}
|
|
29
32
|
|
|
33
|
+
type CondenseEvent = CoordEvent & { surface?: string };
|
|
34
|
+
|
|
30
35
|
export interface MemoryDeps {
|
|
31
36
|
summarize: (source: MemorySource) => Promise<MemorySummary>;
|
|
32
|
-
events?: (since: string) =>
|
|
37
|
+
events?: (since: string) => CondenseEvent[];
|
|
33
38
|
decisions?: () => DecisionEntry[];
|
|
34
39
|
}
|
|
35
40
|
|
|
36
|
-
export type CondenseSkipReason = 'no-seat' | 'no-project' | 'no-topic' | 'no-summary' | 'bad-link' | 'bad-claim' | 'summarize-failed';
|
|
41
|
+
export type CondenseSkipReason = 'no-seat' | 'no-project' | 'no-topic' | 'no-summary' | 'bad-link' | 'bad-claim' | 'no-claim' | 'summarize-failed';
|
|
37
42
|
export type CondenseSkipped = Partial<Record<CondenseSkipReason, number>>;
|
|
43
|
+
export interface FunnelCount { total: number; bySeat: Record<string, number> }
|
|
44
|
+
export interface CondenseFunnel {
|
|
45
|
+
read: FunnelCount & { bySurface: Record<string, number> };
|
|
46
|
+
sources: FunnelCount & { folded: FunnelCount; droppedHarnessChild: FunnelCount; noSeat: FunnelCount };
|
|
47
|
+
summarized: FunnelCount & { accepted: FunnelCount; summarizeFailed: FunnelCount;
|
|
48
|
+
skipped: Partial<Record<CondenseSkipReason, FunnelCount>> };
|
|
49
|
+
collapsed: FunnelCount;
|
|
50
|
+
cards: FunnelCount & { carried: FunnelCount; supersededByPrevious: FunnelCount };
|
|
51
|
+
}
|
|
38
52
|
export interface CondenseWindowReport {
|
|
39
53
|
cards: MemoryItem[];
|
|
54
|
+
funnel: CondenseFunnel;
|
|
40
55
|
skipped: CondenseSkipped;
|
|
41
56
|
folded: number;
|
|
57
|
+
droppedHarnessChild: number;
|
|
42
58
|
}
|
|
43
59
|
|
|
44
60
|
const DAY_MS = 86_400_000;
|
|
45
61
|
const oneLine = (text: string) => redactSecretText(text.split(/\r?\n/, 1)[0] ?? '').trim();
|
|
46
62
|
|
|
63
|
+
/** Keep the reader's event selection unchanged; attach surfaces from the same read-only snapshot. */
|
|
64
|
+
export function readCondenseEvents(since: string): CondenseEvent[] {
|
|
65
|
+
const path = surfaceEventsDbPath();
|
|
66
|
+
if (!existsSync(path)) return [];
|
|
67
|
+
const db = new Database(path, { readonly: true, strict: true });
|
|
68
|
+
try {
|
|
69
|
+
const surfaces = db.prepare(`SELECT id, surface FROM events
|
|
70
|
+
WHERE surface IN ('coord:channel', 'context:external', 'context:session') AND direction='outbound' AND ts>=?`)
|
|
71
|
+
.all(since) as Array<{ id: string; surface: string }>;
|
|
72
|
+
const byEvent = new Map(surfaces.map(row => [row.id, row.surface]));
|
|
73
|
+
return listCoordEvents({ since }, { db }).map(event => ({ ...event, surface: byEvent.get(event.id) }));
|
|
74
|
+
} finally { db.close(); }
|
|
75
|
+
}
|
|
76
|
+
|
|
47
77
|
/** Condense one UTC day; callers persist the returned snapshot, not raw transcripts. Read-only ledger access. */
|
|
48
78
|
export async function condenseContextDay(
|
|
49
79
|
day: string, previous: readonly MemoryItem[], deps: MemoryDeps, now: Date = new Date(),
|
|
@@ -68,27 +98,47 @@ export async function condenseContextWindowWithReport(
|
|
|
68
98
|
const end = Date.parse(until);
|
|
69
99
|
if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) throw new Error('invalid context window');
|
|
70
100
|
// Fetch the previous local day as well: the store compares timestamp text rather than instants.
|
|
71
|
-
const events = (deps.events ??
|
|
101
|
+
const events = (deps.events ?? readCondenseEvents)(new Date(start - DAY_MS).toISOString());
|
|
72
102
|
const decisions = (deps.decisions ?? (() => new DecisionLedger().list({ status: 'all' })))();
|
|
73
103
|
const inWindow = (at: string) => {
|
|
74
104
|
const time = Date.parse(at);
|
|
75
105
|
return Number.isFinite(time) && time >= start && time < end;
|
|
76
106
|
};
|
|
107
|
+
const count = (): FunnelCount => ({ total: 0, bySeat: {} });
|
|
108
|
+
const bump = (bucket: FunnelCount, seat: string | undefined) => {
|
|
109
|
+
const key = seat || '(unknown)';
|
|
110
|
+
bucket.total++;
|
|
111
|
+
bucket.bySeat[key] = (bucket.bySeat[key] ?? 0) + 1;
|
|
112
|
+
};
|
|
113
|
+
const funnel: CondenseFunnel = {
|
|
114
|
+
read: { ...count(), bySurface: {} },
|
|
115
|
+
sources: { ...count(), folded: count(), droppedHarnessChild: count(), noSeat: count() },
|
|
116
|
+
summarized: { ...count(), accepted: count(), summarizeFailed: count(), skipped: {} },
|
|
117
|
+
collapsed: count(), cards: { ...count(), carried: count(), supersededByPrevious: count() },
|
|
118
|
+
};
|
|
77
119
|
const harnessRuns: Array<{ events: CoordEvent[]; locators: Set<string> }> = [];
|
|
78
120
|
const earlierStarts: CoordEvent[] = [];
|
|
79
121
|
const otherEvents: CoordEvent[] = [];
|
|
80
122
|
let harnessEvents = 0;
|
|
123
|
+
let droppedHarnessChild = 0;
|
|
81
124
|
for (const event of events) {
|
|
82
125
|
if (!inWindow(event.at)) {
|
|
83
126
|
const time = Date.parse(event.at);
|
|
84
|
-
if (event.kind === 'started' &&
|
|
127
|
+
if (event.kind === 'started' && event.refs.seat !== 'harness-child'
|
|
128
|
+
&& Number.isFinite(time) && time >= start - DAY_MS && time < start) {
|
|
85
129
|
earlierStarts.push(event);
|
|
86
130
|
}
|
|
87
131
|
continue;
|
|
88
132
|
}
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
133
|
+
bump(funnel.read, event.refs.seat);
|
|
134
|
+
const surface = event.surface ?? '(unknown)';
|
|
135
|
+
funnel.read.bySurface[surface] = (funnel.read.bySurface[surface] ?? 0) + 1;
|
|
136
|
+
if (event.refs.seat === 'harness-child' && event.kind !== '보고') {
|
|
137
|
+
droppedHarnessChild++;
|
|
138
|
+
bump(funnel.sources.droppedHarnessChild, event.refs.seat);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const isLifecycle = event.kind === 'started' || event.kind === 'finished';
|
|
92
142
|
if (!isLifecycle) {
|
|
93
143
|
otherEvents.push(event);
|
|
94
144
|
continue;
|
|
@@ -119,6 +169,7 @@ export async function condenseContextWindowWithReport(
|
|
|
119
169
|
(group.locators.has(event.refs.source ?? '') || group.locators.has(event.refs.url ?? '')))
|
|
120
170
|
.sort((a, b) => Date.parse(b.at) - Date.parse(a.at)).at(0) : undefined);
|
|
121
171
|
const winner = finish ?? inWindowStart ?? group.events.at(-1)!;
|
|
172
|
+
for (const event of group.events) if (event !== winner) bump(funnel.sources.folded, event.refs.seat);
|
|
122
173
|
const frequency = (ref: string) => group.events.filter(event => event.refs.source === ref || event.refs.url === ref).length;
|
|
123
174
|
const run = [...group.locators].sort((a, b) => frequency(b) - frequency(a))[0] ?? eventSource(winner).source;
|
|
124
175
|
const duration = finish && begin && Date.parse(finish.at) >= Date.parse(begin.at)
|
|
@@ -130,7 +181,7 @@ export async function condenseContextWindowWithReport(
|
|
|
130
181
|
source: run, text: `${run} ${result} · ${duration}` });
|
|
131
182
|
}
|
|
132
183
|
const folded = harnessEvents - foldedSources.length;
|
|
133
|
-
try { debug.log('context.condense', 'folded', { harnessEvents, kept: foldedSources.length }); }
|
|
184
|
+
try { debug.log('context.condense', 'folded', { harnessEvents, kept: foldedSources.length, droppedHarnessChild }); }
|
|
134
185
|
catch { /* Observation must not stop condensation. */ }
|
|
135
186
|
const sources: MemorySource[] = [
|
|
136
187
|
...otherEvents.map(eventSource), ...foldedSources,
|
|
@@ -142,23 +193,41 @@ export async function condenseContextWindowWithReport(
|
|
|
142
193
|
].filter(source => inWindow(source.at))
|
|
143
194
|
.sort((a, b) => Date.parse(a.at) - Date.parse(b.at) || a.source.localeCompare(b.source));
|
|
144
195
|
|
|
196
|
+
for (const source of sources) {
|
|
197
|
+
if (typeof source.seat !== 'string' || !oneLine(source.seat)) bump(funnel.sources.noSeat, source.seat);
|
|
198
|
+
else bump(funnel.sources, source.seat);
|
|
199
|
+
}
|
|
200
|
+
for (const decision of decisions) {
|
|
201
|
+
const at = decision.decidedAt ?? decision.raisedAt ?? decision.importedAt ?? '';
|
|
202
|
+
if (!inWindow(at)) continue;
|
|
203
|
+
bump(funnel.read, decision.raisedBy.track ?? 'OP');
|
|
204
|
+
funnel.read.bySurface['decision:ledger'] = (funnel.read.bySurface['decision:ledger'] ?? 0) + 1;
|
|
205
|
+
}
|
|
206
|
+
|
|
145
207
|
const items = new Map<string, MemoryItem>();
|
|
146
208
|
const skipped: CondenseSkipped = {};
|
|
147
209
|
let kept = 0;
|
|
148
210
|
const skip = (reason: CondenseSkipReason, source: MemorySource) => {
|
|
149
211
|
skipped[reason] = (skipped[reason] ?? 0) + 1;
|
|
150
|
-
|
|
151
|
-
|
|
212
|
+
bump(funnel.summarized.skipped[reason] ??= count(), source.seat);
|
|
213
|
+
if (reason === 'summarize-failed') bump(funnel.summarized.summarizeFailed, source.seat);
|
|
214
|
+
try {
|
|
215
|
+
debug.log('context.condense', 'source-skipped', { reason, kind: source.kind, at: source.at });
|
|
216
|
+
if (reason === 'no-claim') debug.log('context.condense', 'skipped', { reason, source: source.source });
|
|
217
|
+
} catch { /* Observation must not stop condensation. */ }
|
|
152
218
|
};
|
|
153
219
|
const safeLine = (value: unknown) => typeof value === 'string' ? oneLine(value) : '';
|
|
154
220
|
const keyFor = (item: Pick<MemoryItem, 'project' | 'seat' | 'topic'>) => JSON.stringify([item.project, item.seat, item.topic]);
|
|
155
221
|
for (const item of previous) items.set(keyFor(item), { ...item });
|
|
222
|
+
const candidateKeys = new Set<string>();
|
|
223
|
+
const updatedKeys = new Set<string>();
|
|
156
224
|
for (const source of sources) {
|
|
157
225
|
const seat = safeLine(source.seat);
|
|
158
226
|
if (!seat) { skip('no-seat', source); continue; }
|
|
159
227
|
let summary: MemorySummary;
|
|
160
228
|
try { summary = await deps.summarize(source); }
|
|
161
229
|
catch { skip('summarize-failed', source); continue; }
|
|
230
|
+
bump(funnel.summarized, source.seat);
|
|
162
231
|
const project = safeLine(summary?.project);
|
|
163
232
|
const topic = safeLine(summary?.topic);
|
|
164
233
|
const text = safeLine(summary?.summary);
|
|
@@ -169,14 +238,19 @@ export async function condenseContextWindowWithReport(
|
|
|
169
238
|
if (!/^(?:https?:\/\/|elanous:\/\/)[^\s]+$/.test(link)) { skip('bad-link', source); continue; }
|
|
170
239
|
const claim = summary.claim && { key: safeLine(summary.claim.key), value: safeLine(summary.claim.value) };
|
|
171
240
|
if (claim && (!claim.key || !claim.value)) { skip('bad-claim', source); continue; }
|
|
241
|
+
if (source.kind === 'event' && !claim) { skip('no-claim', source); continue; }
|
|
172
242
|
kept++;
|
|
243
|
+
bump(funnel.summarized.accepted, source.seat);
|
|
173
244
|
const key = keyFor({ project, seat, topic });
|
|
245
|
+
if (candidateKeys.has(key)) bump(funnel.collapsed, source.seat);
|
|
246
|
+
else candidateKeys.add(key);
|
|
174
247
|
const old = items.get(key);
|
|
175
248
|
// Equal timestamps are resolved by the source link, so shuffled input does not change the winner.
|
|
176
249
|
if (old && (Date.parse(old.updatedAt) > Date.parse(source.at)
|
|
177
250
|
|| (Date.parse(old.updatedAt) === Date.parse(source.at) && old.source >= link))) continue;
|
|
178
251
|
items.set(key, { project, seat, topic, summary: text, source: link, updatedAt: source.at,
|
|
179
252
|
status: 'active', ...(claim ? { claim } : {}) });
|
|
253
|
+
updatedKeys.add(key);
|
|
180
254
|
}
|
|
181
255
|
const cutoff = now.getTime() - 30 * DAY_MS;
|
|
182
256
|
// Compare only the winning, non-retired assertions; a superseded claim cannot keep a decision candidate alive.
|
|
@@ -198,7 +272,14 @@ export async function condenseContextWindowWithReport(
|
|
|
198
272
|
}
|
|
199
273
|
const cards = finalItems.sort((a, b) => a.project.localeCompare(b.project) || a.seat.localeCompare(b.seat)
|
|
200
274
|
|| a.topic.localeCompare(b.topic));
|
|
275
|
+
for (const card of cards) {
|
|
276
|
+
bump(funnel.cards, card.seat);
|
|
277
|
+
if (!candidateKeys.has(keyFor(card))) bump(funnel.cards.carried, card.seat);
|
|
278
|
+
else if (!updatedKeys.has(keyFor(card))) bump(funnel.cards.supersededByPrevious, card.seat);
|
|
279
|
+
}
|
|
201
280
|
try { debug.log('context.condense', 'window', { sources: sources.length, kept, skipped }); }
|
|
202
281
|
catch { /* Observation must not stop condensation. */ }
|
|
203
|
-
|
|
282
|
+
try { debug.log('context.condense', 'funnel', funnel); }
|
|
283
|
+
catch { /* Observation must not stop condensation. */ }
|
|
284
|
+
return { cards, skipped, folded, droppedHarnessChild, funnel };
|
|
204
285
|
}
|
package/src/dashboard/index.ts
CHANGED
|
@@ -593,6 +593,8 @@ import { resolveDashboardChatMainSubmitIntent } from './input/chat-main-submit-r
|
|
|
593
593
|
import { maybeEmitDashboardSubmitQuickPass } from './input/chat-main-submit-control.js';
|
|
594
594
|
import { attachDashboardQuickPassConsumers } from './input/control-signal-consumers.js';
|
|
595
595
|
import { resolveDashboardChatMainSlashCommand } from './input/chat-main-slash-command.js';
|
|
596
|
+
import { TuiChatPersonaSelection, tuiChatPersonaMessages } from './slash-runtime/chat-persona.js';
|
|
597
|
+
import { awaitGlobalPersonaLoad } from '../persona/global-registry.js';
|
|
596
598
|
import { resolveDashboardChatMainCacheCommand } from './input/chat-main-cache-command.js';
|
|
597
599
|
import {
|
|
598
600
|
dashboardDeltaHelpLines,
|
|
@@ -956,6 +958,8 @@ import {
|
|
|
956
958
|
resetDashboardAcpTurnRef,
|
|
957
959
|
} from './turn-lifecycle-runtime.js';
|
|
958
960
|
import { runDashboardTurnPrelude } from './turn-prelude-runtime.js';
|
|
961
|
+
import { askSeat, deliverSeatAnswers, getTuiSeatAskClientId, parseSeatAsk } from '../seat-dispatch/seat-ask.js';
|
|
962
|
+
import { ceoTaskDeps } from '../seat-dispatch/ceo-intent.js';
|
|
959
963
|
import {
|
|
960
964
|
commitDashboardAssistantRenderState,
|
|
961
965
|
runDashboardTurnTailAutoCopy,
|
|
@@ -2136,6 +2140,7 @@ export function renderDashboardFirstScreenBand(input: {
|
|
|
2136
2140
|
}
|
|
2137
2141
|
|
|
2138
2142
|
export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<DashboardAction> {
|
|
2143
|
+
await awaitGlobalPersonaLoad().catch(() => {});
|
|
2139
2144
|
const dashboardQuitConfirmationState = createQuitConfirmationState();
|
|
2140
2145
|
const signalQuitConfirmationState = createQuitConfirmationState();
|
|
2141
2146
|
let disposeDashboardEventLoopMonitor = (): void => {};
|
|
@@ -2639,6 +2644,19 @@ When a user's request matches an installed skill (they will see a "hint: /run-sk
|
|
|
2639
2644
|
Mode- and sync-specific instructions are injected per-turn when relevant — do not assume sync/diff context unless the current turn's Context: block explicitly mentions them.`,
|
|
2640
2645
|
);
|
|
2641
2646
|
let chatLines: string[] = []; // chat log — increasingly reserved for transcript / LLM speech
|
|
2647
|
+
const tuiSeatAskClientId = getTuiSeatAskClientId();
|
|
2648
|
+
const tuiSeatAskDeps = {
|
|
2649
|
+
channel: 'tui' as const, clientId: tuiSeatAskClientId,
|
|
2650
|
+
send: async (_origin: import('../seat-dispatch/seat-ask.js').AskOrigin, answer: string) => {
|
|
2651
|
+
chatLines.push(C.info(answer));
|
|
2652
|
+
chatScrollOffset = -1;
|
|
2653
|
+
draw();
|
|
2654
|
+
},
|
|
2655
|
+
};
|
|
2656
|
+
const pollTuiSeatAnswers = (): void => {
|
|
2657
|
+
void deliverSeatAnswers(tuiSeatAskDeps).catch((error) => debug.log('seat.ask', 'delivery-failed', { via: 'tui', error: String(error) }, { level: 'warn' }));
|
|
2658
|
+
};
|
|
2659
|
+
let tuiSeatAskTimer: ReturnType<typeof setInterval> | undefined;
|
|
2642
2660
|
let debugLines: string[] = [
|
|
2643
2661
|
C.muted('Dashboard ready. Press / for slash, Ctrl+L for plain input.'),
|
|
2644
2662
|
C.muted('Debug window ready. Use /debug window open.'),
|
|
@@ -3121,6 +3139,9 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3121
3139
|
// the laptop left off. `/telegram attach` creates this, `/telegram
|
|
3122
3140
|
// detach` clears it. Lives for the dashboard lifetime.
|
|
3123
3141
|
let attachedSessionId: string | null = null;
|
|
3142
|
+
const chatPersonaSelection = new TuiChatPersonaSelection();
|
|
3143
|
+
let chatPersonaConversationId = crypto.randomUUID();
|
|
3144
|
+
const currentChatPersonaSessionId = () => attachedSessionId ?? chatPersonaConversationId;
|
|
3124
3145
|
let attachedChatId: number | null = null;
|
|
3125
3146
|
const forkableSessionHistory = (source: ChatMessage[] = chat.history): ForkableSessionTurn[] =>
|
|
3126
3147
|
flattenForkableSessionHistory(source);
|
|
@@ -3134,7 +3155,9 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3134
3155
|
messages: forkableSessionHistory(),
|
|
3135
3156
|
});
|
|
3136
3157
|
const prev = attachedSessionId;
|
|
3158
|
+
const selectedPersona = chatPersonaSelection.get(currentChatPersonaSessionId());
|
|
3137
3159
|
attachedSessionId = forked.meta.id;
|
|
3160
|
+
if (selectedPersona) chatPersonaSelection.set(forked.meta.id, selectedPersona);
|
|
3138
3161
|
try { _setActive(forked.meta.id); } catch { /* best-effort */ }
|
|
3139
3162
|
chatLines.push('');
|
|
3140
3163
|
chatLines.push(prev
|
|
@@ -3174,7 +3197,9 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
3174
3197
|
messages: forkableSessionHistory(truncatedChat),
|
|
3175
3198
|
});
|
|
3176
3199
|
const prev = attachedSessionId;
|
|
3200
|
+
const selectedPersona = chatPersonaSelection.get(currentChatPersonaSessionId());
|
|
3177
3201
|
attachedSessionId = forked.meta.id;
|
|
3202
|
+
if (selectedPersona) chatPersonaSelection.set(forked.meta.id, selectedPersona);
|
|
3178
3203
|
try { setActiveForTimetravel(forked.meta.id); } catch { /* best-effort */ }
|
|
3179
3204
|
// in-memory 히스토리도 동일 경계로 절단 — 스토어와 문맥 일치 보장.
|
|
3180
3205
|
chat.history.length = 0;
|
|
@@ -15522,20 +15547,23 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15522
15547
|
rich: false,
|
|
15523
15548
|
})
|
|
15524
15549
|
: [];
|
|
15525
|
-
return
|
|
15526
|
-
|
|
15527
|
-
|
|
15528
|
-
|
|
15529
|
-
|
|
15530
|
-
|
|
15531
|
-
|
|
15532
|
-
|
|
15533
|
-
|
|
15534
|
-
|
|
15535
|
-
|
|
15536
|
-
|
|
15537
|
-
|
|
15538
|
-
|
|
15550
|
+
return [
|
|
15551
|
+
...tuiChatPersonaMessages(currentChatPersonaSessionId(), chatPersonaSelection),
|
|
15552
|
+
...buildDashboardTurnPreamble({
|
|
15553
|
+
userText,
|
|
15554
|
+
sessionId,
|
|
15555
|
+
cwd: getSessionCwd(),
|
|
15556
|
+
turnProfile: acpTurnRef.turnProfile,
|
|
15557
|
+
userConfig: getUserConfig(),
|
|
15558
|
+
// Resolved per-turn so a mid-session model switch (codex →
|
|
15559
|
+
// claude or vice-versa) takes effect immediately. Drives the
|
|
15560
|
+
// codex-only behavioral addendum (fix L-1) inside the
|
|
15561
|
+
// universal preamble.
|
|
15562
|
+
modelFamily: getModelFamily(inspectActiveProvider().model),
|
|
15563
|
+
rich: false,
|
|
15564
|
+
enabledTools: tools.map(t => t.name),
|
|
15565
|
+
}),
|
|
15566
|
+
];
|
|
15539
15567
|
},
|
|
15540
15568
|
getTools: ({ userText }) => {
|
|
15541
15569
|
const runtime = acpToolRuntime;
|
|
@@ -15819,6 +15847,9 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
15819
15847
|
observe: (data) => { try { debug.log('dashboard.first-screen-band', 'resolved', data); } catch { /* observation is best-effort */ } },
|
|
15820
15848
|
});
|
|
15821
15849
|
|
|
15850
|
+
tuiSeatAskTimer = setInterval(pollTuiSeatAnswers, 10_000);
|
|
15851
|
+
tuiSeatAskTimer.unref();
|
|
15852
|
+
pollTuiSeatAnswers();
|
|
15822
15853
|
while (true) {
|
|
15823
15854
|
draw();
|
|
15824
15855
|
let wdInputExited = false; // set true when the input-mode loop exits this iter
|
|
@@ -17571,6 +17602,18 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
17571
17602
|
const cmdText = submitIntent.kind === 'control-turn'
|
|
17572
17603
|
? (submitIntent.commandText ?? '')
|
|
17573
17604
|
: submitIntent.text;
|
|
17605
|
+
if (submitIntent.kind === 'submit-turn' && parseSeatAsk(submitIntent.text)) {
|
|
17606
|
+
try {
|
|
17607
|
+
const receipt = await askSeat(submitIntent.text, { channel: 'tui', clientId: tuiSeatAskClientId },
|
|
17608
|
+
ceoTaskDeps(getUserConfig(), null), tuiSeatAskDeps);
|
|
17609
|
+
chatLines.push(C.info(receipt));
|
|
17610
|
+
} catch (error) {
|
|
17611
|
+
chatLines.push(C.error(`CTO 질문 전송 실패: ${String(error)}`));
|
|
17612
|
+
}
|
|
17613
|
+
chatScrollOffset = -1;
|
|
17614
|
+
draw();
|
|
17615
|
+
continue;
|
|
17616
|
+
}
|
|
17574
17617
|
if (submitIntent.kind === 'submit-turn' && submitIntent.route === 'sticky-acp') {
|
|
17575
17618
|
await runDashboardChatMainSubmitIntent({
|
|
17576
17619
|
submit: createDashboardChatMainTurnSubmit(submitIntent),
|
|
@@ -18198,6 +18241,11 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
18198
18241
|
},
|
|
18199
18242
|
getAttachedSessionId: () => attachedSessionId,
|
|
18200
18243
|
setAttachedSessionId: (id) => { attachedSessionId = id; },
|
|
18244
|
+
chatPersona: {
|
|
18245
|
+
sessionId: currentChatPersonaSessionId,
|
|
18246
|
+
selection: chatPersonaSelection,
|
|
18247
|
+
newConversation: () => { chatPersonaConversationId = crypto.randomUUID(); },
|
|
18248
|
+
},
|
|
18201
18249
|
getAttachedChatId: () => attachedChatId,
|
|
18202
18250
|
setAttachedChatId: (id) => { attachedChatId = id; },
|
|
18203
18251
|
sessionSlash: {
|
|
@@ -19010,14 +19058,17 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19010
19058
|
rich: false,
|
|
19011
19059
|
})
|
|
19012
19060
|
: [];
|
|
19013
|
-
return
|
|
19014
|
-
|
|
19015
|
-
|
|
19016
|
-
|
|
19017
|
-
|
|
19018
|
-
|
|
19019
|
-
|
|
19020
|
-
|
|
19061
|
+
return [
|
|
19062
|
+
...tuiChatPersonaMessages(currentChatPersonaSessionId(), chatPersonaSelection),
|
|
19063
|
+
...buildDashboardTurnPreamble({
|
|
19064
|
+
userText: args.userText,
|
|
19065
|
+
cwd: args.cwd,
|
|
19066
|
+
turnProfile: args.turnProfile as SessionTurnProfile,
|
|
19067
|
+
userConfig: args.userConfig,
|
|
19068
|
+
rich: false,
|
|
19069
|
+
enabledTools: tools.map(t => t.name),
|
|
19070
|
+
}),
|
|
19071
|
+
];
|
|
19021
19072
|
},
|
|
19022
19073
|
runAutoCompact: async ({ preamble, chatHistory, userMsg }) => {
|
|
19023
19074
|
const compactMod = await import('../compact/index.js');
|
|
@@ -19427,5 +19478,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
|
|
|
19427
19478
|
} catch (err) {
|
|
19428
19479
|
closeDashboardTui();
|
|
19429
19480
|
throw err;
|
|
19481
|
+
} finally {
|
|
19482
|
+
if (tuiSeatAskTimer) clearInterval(tuiSeatAskTimer);
|
|
19430
19483
|
}
|
|
19431
19484
|
}
|