elanous 0.2.11 → 0.2.12
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/1147-466ec15afacc1a65.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{1394-556de6d71bbdb0fb.js → 1394-ee3795b112907122.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/3869-3cd46526879f454c.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7277-0b2fc7c16ba2d64b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7758-0b018a9e4fc56200.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{8605-ea5bee9dfae512c7.js → 8605-0259994816604c49.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/9920-5cfdc5e8fd209825.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-cb169620945d1952.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-6a061bd97f0b9398.js → page-cefe8169e36cf62a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/board/{page-cb95a7432c9ee744.js → page-d2e35228bc497119.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-b12b6d2f8d2d1aea.js → page-5c05b0da4bc1392c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/{page-b9efe868bfd36255.js → page-e0ccdb576812b523.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/chat/{page-7c97dcdfe2e37a60.js → page-813c4a52c9d05ca8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-4731f2c215358937.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/{page-5721537ca8a3598c.js → page-a022b257950f39e6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/design-check/{page-b654240a572e4c48.js → page-a2ffc717e04b8b0a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/{page-b9750abc897508c3.js → page-b59ee4e70fc18fcf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-a67e11ba962337b5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/field/page-c172dabd796eb7a3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/inside/page-1efd0cb9e0ed9d13.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/{page-c8b1ccda6ba7ae98.js → page-d5dc7ff69a37b4cf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-e71c84189e8c683e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/{page-2a9932ddb62d76bd.js → page-1d6a533ce5a6efcb.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/market/{page-9688f5b4f1ff950f.js → page-dfca9b7d2de0b135.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-793fa536b3a6ef37.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-35414e0a007b4082.js → page-6dd3bfbbde2a5c2c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/{not-found-e7a529e0507ac86c.js → not-found-490653e8d4cc8852.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/{page-e001823c35c9dd67.js → page-77447356baad75d2.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-29e961191f6057df.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-c822f55b884d9104.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fa4ccfc432424e52.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/{page-3a24072b35470157.js → page-6d604227e1664b71.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/page-9c7e8f744a765daf.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/{page-0be8d4b2ced75ba0.js → page-4048543b4b7ad5e0.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/{page-d37cb0d52f9b6bd5.js → page-4c3a3126abed551a.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/sessions/{page-686da0df9bf23e5c.js → page-64b0aecb1ca75e75.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4292d0149020e8a7.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/{page-53f80edc6b8dc07c.js → page-db14d0be7f1c460c.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-e5d8072cd7cfef73.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/{page-239c17b911b84e72.js → page-9547b5cec7cf76bf.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-e6dcb83265530636.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-45248f08d6aecae5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/tasks/{page-1218753c82d585f6.js → page-2cddeb9e2aeedc55.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/term/{page-4b5935e67531efb5.js → page-e297866051595d81.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/today/{page-3285bc87caf1eaa5.js → page-baba2e047872fb0f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/trace/{page-ad553b0e06505ecd.js → page-e895da4ec9cac345.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-4344faf20216233b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-698bb29f11864b89.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-bd6a6dc1ddc273f2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-2e9e2fb01c9da1c9.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-d62ceb13411ebba4.js +1 -0
- package/apps/pwa/out/_next/static/css/128fb7fb670b2fbf.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/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/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/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/context/nightly-condense.yaml +21 -0
- package/graphs/context/recipes.yaml +12 -0
- package/graphs/demo/inside-seed.yaml +20 -0
- package/graphs/demo/recipes.yaml +12 -0
- package/package.json +1 -1
- package/plugins/card-followup/examples/sample-card.png +0 -0
- package/scripts/lib/telegram-inject-args.ts +31 -0
- package/scripts/measure-pod-memory-by-goal.ts +130 -0
- package/scripts/release-loop/auto-approve-node.ts +1 -1
- package/scripts/release-loop/checklist-gate-node.ts +2 -1
- package/scripts/release-loop/gate-node.ts +8 -2
- package/scripts/release-loop/ops-upgrade-node.ts +47 -6
- package/scripts/release-loop/publish-node.ts +4 -1
- package/scripts/release-loop/version-node.ts +13 -3
- package/scripts/telegram-inject.ts +14 -6
- package/scripts/test-diet/remeasure-list.ts +112 -0
- package/scripts/ux/demo-rehearsal.ts +17 -13
- package/scripts/ux/demo-seed.ts +108 -0
- package/scripts/ux/lib/rehearsal-verdict.ts +12 -5
- package/src/agent-mission/driver.ts +138 -16
- package/src/agent-mission/pty-decision.ts +1 -1
- package/src/autopilot/pty-control-loop.ts +4 -1
- package/src/chat/index.ts +1 -0
- package/src/cli/persona-cli.ts +17 -14
- package/src/cli/pod-cli.ts +17 -0
- package/src/cli/pod-memory-advice.ts +35 -0
- package/src/cli/release-cli.ts +46 -6
- package/src/context-bus/context-now-surfaces.ts +17 -0
- package/src/context-bus/context-now.ts +2 -2
- package/src/context-bus/coord-events.ts +2 -2
- package/src/context-bus/nightly-condense.ts +153 -0
- package/src/context-bus/session-events.ts +35 -0
- package/src/dashboard/dashboard-status-lines.ts +2 -0
- package/src/dashboard/index.ts +8 -0
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +24 -0
- package/src/domains/outbound-alert.ts +99 -31
- package/src/domains/outbound-log-probe.ts +8 -0
- package/src/execution-loop/launch-gate.ts +17 -8
- package/src/field-note/telegram.ts +142 -0
- package/src/graph-runner/graph-grow-llm.ts +23 -13
- package/src/graph-runner/graph-grow.ts +5 -2
- package/src/graph-runner/runner.ts +12 -8
- package/src/harness/harness-cli-command.ts +138 -16
- package/src/hooks/consult-intake.ts +153 -0
- package/src/hooks/receiver.ts +78 -1
- package/src/index.ts +33 -9
- package/src/intake-plane/discord-seat-work.ts +28 -2
- package/src/intake-plane/wish-card.ts +33 -0
- package/src/llm/difficulty.ts +1 -1
- package/src/maturity/feature-maturity.ts +2 -1
- package/src/nexus/api/http-server.ts +31 -8
- package/src/nexus/api/outbound-report.ts +40 -7
- package/src/nexus/api/personas.ts +95 -53
- package/src/nexus/api/task-cards-api.ts +19 -0
- package/src/nexus/api/workflow-history.ts +88 -0
- package/src/nexus/api/workflows.ts +52 -0
- package/src/nexus/outbound/delivery-ledger.ts +17 -8
- package/src/nexus/outbound/router.ts +8 -3
- package/src/persona/presets.ts +8 -1
- package/src/plugins/maker/market-bundle.ts +2 -1
- package/src/release-loop/checklist.ts +15 -3
- package/src/release-loop/feature-store.ts +24 -10
- package/src/release-loop/landed-but-yellow.ts +48 -0
- package/src/seat-loop/seat-loop.ts +168 -7
- package/src/self-dev/draft-sweep.ts +44 -10
- package/src/self-dev/draft-triage-rules.ts +54 -2
- package/src/self-implement/budget-gate.ts +29 -12
- package/src/self-implement/gate-candidate-ranking.ts +60 -0
- package/src/self-implement/gate-scope.ts +9 -8
- package/src/self-implement/headless-elanous-driver.ts +7 -2
- package/src/self-implement/orchestrator.ts +15 -0
- package/src/self-implement/test-seams.ts +1 -0
- package/src/task-orchestrator/surfaces/pod-command-job.ts +14 -10
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +8 -0
- package/src/telegram-commands.ts +21 -0
- package/src/telegram-project-command.ts +78 -4
- package/src/telegram.ts +32 -5
- package/src/user-config.ts +8 -4
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/2310-7a59f043f6db207e.js +0 -1
- package/apps/pwa/out/_next/static/chunks/2548-6e316138d347cefe.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3869-a39d1d9921e10d43.js +0 -1
- package/apps/pwa/out/_next/static/chunks/507-5acd98bd6dab2d8a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5445-745eb795c5963d79.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/approvals/page-1dcdc58fc2de2454.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-8fd36984f549270a.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/exec/page-4cd1de371f8ad048.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/field/page-d99f89657828421c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-50cb2a0eb15e6c83.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-d6b1d156fb95e74b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-6b15dd6456c5df09.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-371423d1a573d64b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4b764b125339ac17.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-cdf8e4b01067bcf1.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-94c82eb0ae5abb32.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-4dc614f3ce043e63.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-d02c782fc792e2af.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/share/page-dc6a79fb003f746c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/page-0fffb84cafdc9da6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-fca096e3e860306f.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-9ebfa78f0d9885c3.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-3dc5f21f7e39622d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workspace/page-c6da2b468454532d.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-93bc70e36f595414.js +0 -1
- package/apps/pwa/out/_next/static/css/543f56bcb1f79fca.css +0 -1
- /package/apps/pwa/out/_next/static/{Y4zKzL62sakG5momz3SoQ → -6XrAoD3eU7NyMHAE4xPS}/_buildManifest.js +0 -0
- /package/apps/pwa/out/_next/static/{Y4zKzL62sakG5momz3SoQ → -6XrAoD3eU7NyMHAE4xPS}/_ssgManifest.js +0 -0
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { debug } from './debug/log.js';
|
|
2
2
|
import { getProject, listProjects, type Project } from './project/project-store.js';
|
|
3
3
|
import { findSessionByTelegramChat, updateSessionMeta } from './session/index.js';
|
|
4
|
+
import { telegramDecisionOwner } from './decisions/telegram-decision-cards.js';
|
|
5
|
+
import type { TelegramBot } from './telegram.js';
|
|
4
6
|
import type { TgSlashCommand } from './telegram-commands.js';
|
|
7
|
+
import type { UserConfig } from './user-config.js';
|
|
5
8
|
|
|
6
9
|
export interface TelegramProjectCommandDeps {
|
|
7
10
|
list: () => Project[];
|
|
@@ -19,7 +22,7 @@ export function projectCommand(deps: TelegramProjectCommandDeps = {
|
|
|
19
22
|
return {
|
|
20
23
|
name: 'project',
|
|
21
24
|
description: '이 대화의 프로젝트 보기·옮기기',
|
|
22
|
-
handler: async (args, ctx) => {
|
|
25
|
+
handler: async (args, ctx, ctxOptions) => {
|
|
23
26
|
const session = deps.findSession(ctx.chatId, ctx.threadId, ctx.botId);
|
|
24
27
|
if (!session) {
|
|
25
28
|
debug.log('telegram.project', 'rejected', { projects: [], reason: 'no-session' });
|
|
@@ -28,13 +31,32 @@ export function projectCommand(deps: TelegramProjectCommandDeps = {
|
|
|
28
31
|
|
|
29
32
|
if (args.length === 0) {
|
|
30
33
|
const current = session.projectId ? deps.find(session.projectId) : null;
|
|
31
|
-
const projects = deps.list().sort((a, b) => a.name.localeCompare(b.name))
|
|
32
|
-
debug.log('telegram.project', 'listed', { projects: projects.map(p => ({ id: p.id, name: p.name })) });
|
|
34
|
+
const projects = deps.list().sort((a, b) => a.name.localeCompare(b.name));
|
|
35
|
+
debug.log('telegram.project', 'listed', { projects: projects.slice(0, 20).map(p => ({ id: p.id, name: p.name })) });
|
|
36
|
+
if (ctx.isDm && ctx.chatId === ctx.userId
|
|
37
|
+
&& String(ctx.userId) === telegramDecisionOwner(ctxOptions.userConfig) && ctxOptions.sendButtons) {
|
|
38
|
+
const buttons = projects.filter(p => {
|
|
39
|
+
const bytes = Buffer.byteLength(`prj:${p.id}`, 'utf8');
|
|
40
|
+
if (bytes <= 64) return true;
|
|
41
|
+
debug.log('telegram.project', 'button-rejected', { reason: 'callback-data-too-long', projectId: p.id, bytes });
|
|
42
|
+
return false;
|
|
43
|
+
}).slice(0, 8).map(p => ({ text: p.name, data: `prj:${p.id}` }));
|
|
44
|
+
buttons.push({ text: '받은 대화로', data: 'prj:-' });
|
|
45
|
+
const rows: Array<Array<{ text: string; data: string }>> = [];
|
|
46
|
+
for (let i = 0; i < buttons.length; i += 2) rows.push(buttons.slice(i, i + 2));
|
|
47
|
+
try {
|
|
48
|
+
await ctxOptions.sendButtons('프로젝트를 선택하세요', rows);
|
|
49
|
+
} catch (err) {
|
|
50
|
+
debug.log('telegram.project', 'button-rejected', {
|
|
51
|
+
reason: 'send-failed', error: err instanceof Error ? err.message : String(err),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
33
55
|
return [
|
|
34
56
|
`지금 대화의 프로젝트: ${current?.name ?? '받은 대화(프로젝트 없음)'}`,
|
|
35
57
|
'',
|
|
36
58
|
'프로젝트 목록:',
|
|
37
|
-
...projects.map(p => `• ${p.name}`),
|
|
59
|
+
...projects.slice(0, 20).map(p => `• ${p.name}`),
|
|
38
60
|
'',
|
|
39
61
|
'옮기려면 /project <이름>',
|
|
40
62
|
].join('\n');
|
|
@@ -69,3 +91,55 @@ export function projectCommand(deps: TelegramProjectCommandDeps = {
|
|
|
69
91
|
},
|
|
70
92
|
};
|
|
71
93
|
}
|
|
94
|
+
|
|
95
|
+
export function attachTelegramProjectButtons(
|
|
96
|
+
bot: Pick<TelegramBot, 'botId' | 'onCallbackQuery' | 'sendMessage' | 'answerCallbackQuery'>,
|
|
97
|
+
cfg: UserConfig,
|
|
98
|
+
deps: TelegramProjectCommandDeps = {
|
|
99
|
+
list: listProjects,
|
|
100
|
+
find: getProject,
|
|
101
|
+
update: updateSessionMeta,
|
|
102
|
+
findSession: findSessionByTelegramChat,
|
|
103
|
+
},
|
|
104
|
+
): () => void {
|
|
105
|
+
const owner = telegramDecisionOwner(cfg);
|
|
106
|
+
return bot.onCallbackQuery(async q => {
|
|
107
|
+
if (!q.data.startsWith('prj:')) return;
|
|
108
|
+
if (!owner || String(q.userId) !== owner) {
|
|
109
|
+
debug.log('telegram.project', 'button-rejected', { reason: 'not-owner', userId: q.userId, chatId: q.chatId });
|
|
110
|
+
await bot.answerCallbackQuery(q.id, { text: '권한이 없습니다' });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (q.chatId === undefined || q.chatId !== q.userId || q.threadId !== undefined) {
|
|
114
|
+
debug.log('telegram.project', 'button-rejected', { reason: 'not-private-chat', userId: q.userId, chatId: q.chatId });
|
|
115
|
+
await bot.answerCallbackQuery(q.id, { text: '개인 대화에서만 고를 수 있습니다' });
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const chatId = q.chatId;
|
|
119
|
+
const session = deps.findSession(chatId, q.threadId, bot.botId);
|
|
120
|
+
if (!session) {
|
|
121
|
+
debug.log('telegram.project', 'button-rejected', { reason: 'no-session', chatId });
|
|
122
|
+
await bot.answerCallbackQuery(q.id);
|
|
123
|
+
await bot.sendMessage(chatId, '아직 이 채팅에 대화가 없습니다 — 한 마디 보낸 뒤 다시');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (q.data === 'prj:-') {
|
|
127
|
+
deps.update(session.id, m => { delete m.projectId; });
|
|
128
|
+
debug.log('telegram.project', 'button-cleared', { chatId, sessionId: session.id });
|
|
129
|
+
await bot.answerCallbackQuery(q.id);
|
|
130
|
+
await bot.sendMessage(chatId, '받은 대화로 옮겼습니다');
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const project = deps.find(q.data.slice(4));
|
|
134
|
+
if (!project) {
|
|
135
|
+
debug.log('telegram.project', 'button-rejected', { reason: 'not-found', chatId, projectId: q.data.slice(4) });
|
|
136
|
+
await bot.answerCallbackQuery(q.id);
|
|
137
|
+
await bot.sendMessage(chatId, '그 이름의 프로젝트가 없습니다 — /project 로 목록 보기');
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
deps.update(session.id, m => { m.projectId = project.id; });
|
|
141
|
+
debug.log('telegram.project', 'button-moved', { chatId, sessionId: session.id, projectId: project.id });
|
|
142
|
+
await bot.answerCallbackQuery(q.id);
|
|
143
|
+
await bot.sendMessage(chatId, `이 대화를 ${project.name} 프로젝트로 옮겼습니다`);
|
|
144
|
+
});
|
|
145
|
+
}
|
package/src/telegram.ts
CHANGED
|
@@ -73,7 +73,10 @@ import { effectiveInstanceRoot } from './instance/resolve.js';
|
|
|
73
73
|
import { getElanousConfigDir } from './elanous-config-dir.js';
|
|
74
74
|
import { defaultFieldEvent, FieldUploadError, parseFieldCaption, resolveFieldMime, saveFieldMedia } from './field/field-media.js';
|
|
75
75
|
import { scheduleFieldReel, type FieldReelOptions } from './field/field-reel.js';
|
|
76
|
+
import { handleTelegramFieldNote } from './field-note/telegram.js';
|
|
77
|
+
import type { TranscriptionEngine, FieldAudio } from './field-note/transcribe.js';
|
|
76
78
|
import { maybeHandleCardPhoto, type CardPhotoDeps } from './telegram-card-followup.js';
|
|
79
|
+
import { attachTelegramProjectButtons } from './telegram-project-command.js';
|
|
77
80
|
|
|
78
81
|
export type TgAttachmentKind = 'photo' | 'voice' | 'audio' | 'document';
|
|
79
82
|
|
|
@@ -101,6 +104,8 @@ export interface TgIncoming {
|
|
|
101
104
|
text: string;
|
|
102
105
|
messageId: number;
|
|
103
106
|
threadId?: number;
|
|
107
|
+
/** Telegram message timestamp, not poll time. */
|
|
108
|
+
receivedAt?: string;
|
|
104
109
|
isDm: boolean;
|
|
105
110
|
isGroup: boolean;
|
|
106
111
|
/** Zero or more attached media — populated by parseUpdate from
|
|
@@ -219,6 +224,9 @@ export interface TelegramBotOpts {
|
|
|
219
224
|
fieldRootDir?: () => string;
|
|
220
225
|
/** 시험에서는 실제 렌더 대신 가짜 실행기를 주입한다. */
|
|
221
226
|
fieldReel?: FieldReelOptions;
|
|
227
|
+
/** NOTE3a engine and audio decoder are injected; no transcription provider is assumed. */
|
|
228
|
+
fieldNoteEngine?: TranscriptionEngine;
|
|
229
|
+
fieldNoteDecodeAudio?: (file: string, recordedAt: string) => FieldAudio;
|
|
222
230
|
/** Test seam for the business-card graph and its private run root. */
|
|
223
231
|
cardFollowupDeps?: Pick<CardPhotoDeps, 'runGraph' | 'rootDir' | 'ocrText'>;
|
|
224
232
|
}
|
|
@@ -278,7 +286,7 @@ export function classifyTelegramText(
|
|
|
278
286
|
|
|
279
287
|
export class TelegramBot {
|
|
280
288
|
private readonly token: string;
|
|
281
|
-
|
|
289
|
+
readonly botId: string;
|
|
282
290
|
private readonly allowedUsers: Set<number>;
|
|
283
291
|
private readonly onMessage: TelegramBotOpts['onMessage'];
|
|
284
292
|
private readonly fetchImpl: typeof fetch;
|
|
@@ -338,6 +346,8 @@ export class TelegramBot {
|
|
|
338
346
|
private readonly fieldDefaultEventOpt?: string;
|
|
339
347
|
private readonly fieldRootDir: () => string;
|
|
340
348
|
private readonly fieldReel?: FieldReelOptions;
|
|
349
|
+
private readonly fieldNoteEngine?: TranscriptionEngine;
|
|
350
|
+
private readonly fieldNoteDecodeAudio?: (file: string, recordedAt: string) => FieldAudio;
|
|
341
351
|
private readonly cardFollowupDeps: Pick<CardPhotoDeps, 'runGraph' | 'rootDir' | 'ocrText'>;
|
|
342
352
|
private readonly seatWorkDeps: TelegramSeatWorkDeps;
|
|
343
353
|
private seatAskTimer: ReturnType<typeof setInterval> | null = null;
|
|
@@ -375,6 +385,8 @@ export class TelegramBot {
|
|
|
375
385
|
this.fieldDefaultEventOpt = opts.fieldDefaultEvent;
|
|
376
386
|
this.fieldRootDir = opts.fieldRootDir ?? getElanousConfigDir;
|
|
377
387
|
this.fieldReel = opts.fieldReel;
|
|
388
|
+
this.fieldNoteEngine = opts.fieldNoteEngine;
|
|
389
|
+
this.fieldNoteDecodeAudio = opts.fieldNoteDecodeAudio;
|
|
378
390
|
this.cardFollowupDeps = opts.cardFollowupDeps ?? {};
|
|
379
391
|
this.seatWorkDeps = { ...opts.seatWorkDeps, askDeps: { ...opts.seatWorkDeps?.askDeps,
|
|
380
392
|
channel: 'telegram', botId: this.botId,
|
|
@@ -1214,6 +1226,7 @@ export class TelegramBot {
|
|
|
1214
1226
|
userId: cq.from.id,
|
|
1215
1227
|
userName: cq.from.username ?? cq.from.first_name,
|
|
1216
1228
|
chatId: cq.message?.chat.id,
|
|
1229
|
+
threadId: cq.message?.message_thread_id,
|
|
1217
1230
|
messageId: cq.message?.message_id,
|
|
1218
1231
|
data: cq.data ?? '',
|
|
1219
1232
|
};
|
|
@@ -1528,6 +1541,13 @@ export class TelegramBot {
|
|
|
1528
1541
|
}
|
|
1529
1542
|
// 현장 업로드 — `#현장` 캡션(또는 태그된 앨범의 나머지)의 사진·영상은 LLM 대신 현장 폴더로.
|
|
1530
1543
|
if (await this.tryHandleFieldUpload(ctx)) return;
|
|
1544
|
+
if (await handleTelegramFieldNote(ctx, {
|
|
1545
|
+
rootDir: this.fieldRootDir(),
|
|
1546
|
+
download: (fileId) => this.downloadFile(fileId),
|
|
1547
|
+
reply: async (incoming, text) => { await this.sendMessage(incoming.chatId, text, { replyTo: incoming.messageId, threadId: incoming.threadId }); },
|
|
1548
|
+
engine: this.fieldNoteEngine, decodeAudio: this.fieldNoteDecodeAudio,
|
|
1549
|
+
now: () => new Date(this.nowImpl()),
|
|
1550
|
+
})) return;
|
|
1531
1551
|
if (await maybeHandleCardPhoto(ctx, {
|
|
1532
1552
|
isOwner: (userId) => this.isOwnerAllowed(userId),
|
|
1533
1553
|
isFieldAlbum: (id) => this.fieldGroups.has(id),
|
|
@@ -1827,6 +1847,7 @@ export class TelegramBot {
|
|
|
1827
1847
|
const reply = await slashParse.cmd.handler(slashParse.args, ctx, {
|
|
1828
1848
|
userConfig: this.slashContext.userConfig,
|
|
1829
1849
|
allCommands: this.slashCommands,
|
|
1850
|
+
sendButtons: async (text, buttons) => { await this.sendInlineKeyboard(ctx.chatId, text, buttons, { replyTo: ctx.messageId, threadId: ctx.threadId }); },
|
|
1830
1851
|
downloadAttachments: () => this.downloadCtxAttachments(ctx),
|
|
1831
1852
|
daemonBridge: this.slashContext.daemonBridge,
|
|
1832
1853
|
hitlConfirmChannel: this.hitlConfirmChannelForChat(ctx.chatId, ctx.threadId),
|
|
@@ -2011,6 +2032,7 @@ export class TelegramBot {
|
|
|
2011
2032
|
return await slashParse.cmd.handler(slashParse.args, ctx, {
|
|
2012
2033
|
userConfig: this.slashContext!.userConfig,
|
|
2013
2034
|
allCommands: this.slashCommands,
|
|
2035
|
+
sendButtons: async (text, buttons) => { await this.sendInlineKeyboard(ctx.chatId, text, buttons, { replyTo: ctx.messageId, threadId: ctx.threadId }); },
|
|
2014
2036
|
streamer,
|
|
2015
2037
|
downloadAttachments: () => this.downloadCtxAttachments(ctx),
|
|
2016
2038
|
daemonBridge: this.slashContext!.daemonBridge,
|
|
@@ -2030,6 +2052,7 @@ export class TelegramBot {
|
|
|
2030
2052
|
return await runAcpViaSlash(activeBackend, [ctx.text], ctx, {
|
|
2031
2053
|
userConfig: this.slashContext!.userConfig,
|
|
2032
2054
|
allCommands: this.slashCommands,
|
|
2055
|
+
sendButtons: async (text, buttons) => { await this.sendInlineKeyboard(ctx.chatId, text, buttons, { replyTo: ctx.messageId, threadId: ctx.threadId }); },
|
|
2033
2056
|
streamer,
|
|
2034
2057
|
downloadAttachments: () => this.downloadCtxAttachments(ctx),
|
|
2035
2058
|
daemonBridge: this.slashContext!.daemonBridge,
|
|
@@ -2270,6 +2293,7 @@ interface RawUpdate {
|
|
|
2270
2293
|
update_id: number;
|
|
2271
2294
|
message?: {
|
|
2272
2295
|
message_id: number;
|
|
2296
|
+
date?: number;
|
|
2273
2297
|
from?: { id: number; first_name?: string; username?: string };
|
|
2274
2298
|
chat: { id: number; type: 'private' | 'group' | 'supergroup' | 'channel' };
|
|
2275
2299
|
text?: string;
|
|
@@ -2286,7 +2310,7 @@ interface RawUpdate {
|
|
|
2286
2310
|
callback_query?: {
|
|
2287
2311
|
id: string;
|
|
2288
2312
|
from: { id: number; first_name?: string; username?: string };
|
|
2289
|
-
message?: { message_id: number; chat: { id: number } };
|
|
2313
|
+
message?: { message_id: number; message_thread_id?: number; chat: { id: number } };
|
|
2290
2314
|
data?: string;
|
|
2291
2315
|
chat_instance?: string;
|
|
2292
2316
|
};
|
|
@@ -2305,6 +2329,7 @@ export interface TgCallbackQuery {
|
|
|
2305
2329
|
userId: number;
|
|
2306
2330
|
userName?: string;
|
|
2307
2331
|
chatId?: number;
|
|
2332
|
+
threadId?: number;
|
|
2308
2333
|
messageId?: number;
|
|
2309
2334
|
data: string;
|
|
2310
2335
|
}
|
|
@@ -2397,6 +2422,7 @@ export function parseUpdate(u: RawUpdate): TgIncoming | null {
|
|
|
2397
2422
|
text: (typeof m.text === 'string' ? m.text : (m.caption ?? '')),
|
|
2398
2423
|
messageId: m.message_id,
|
|
2399
2424
|
threadId: m.message_thread_id,
|
|
2425
|
+
...(typeof m.date === 'number' ? { receivedAt: new Date(m.date * 1000).toISOString() } : {}),
|
|
2400
2426
|
isDm,
|
|
2401
2427
|
isGroup: !isDm,
|
|
2402
2428
|
attachments,
|
|
@@ -2912,9 +2938,10 @@ export function botFromConfig(opts: BotFromConfigOpts): TelegramBot {
|
|
|
2912
2938
|
botRef.ensureSurfaceHitl();
|
|
2913
2939
|
// DEC-TG(대표 10-02) — decision cards on the MAIN bot only (other channel pollers carry other tokens). The ticker
|
|
2914
2940
|
// itself sends only while this bot polls, so a send-only nexus bot never duplicates the standalone poller's cards.
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2941
|
+
const mainToken = resolveChannelBotToken('telegram', opts.userConfig)?.token;
|
|
2942
|
+
if (mainToken && botToken === mainToken) {
|
|
2943
|
+
attachTelegramProjectButtons(botRef, opts.userConfig);
|
|
2944
|
+
if (opts.userConfig.raw?.decisions === undefined || (opts.userConfig.raw.decisions as { cards?: unknown }).cards !== false) {
|
|
2918
2945
|
const bot = botRef;
|
|
2919
2946
|
void import('./decisions/telegram-decision-cards.js')
|
|
2920
2947
|
.then(({ attachTelegramDecisionCards }) => { attachTelegramDecisionCards(bot, opts.userConfig); })
|
package/src/user-config.ts
CHANGED
|
@@ -3240,7 +3240,7 @@ export interface AutoReviewConfig {
|
|
|
3240
3240
|
};
|
|
3241
3241
|
}
|
|
3242
3242
|
|
|
3243
|
-
export type ModelRole = 'implement' | 'review' | 'research' | 'planning' | 'audit' | 'classify';
|
|
3243
|
+
export type ModelRole = 'implement' | 'review' | 'research' | 'planning' | 'audit' | 'classify' | 'graph-grow';
|
|
3244
3244
|
|
|
3245
3245
|
export interface RoleModelConfig {
|
|
3246
3246
|
implement?: string;
|
|
@@ -3249,6 +3249,7 @@ export interface RoleModelConfig {
|
|
|
3249
3249
|
planning?: string;
|
|
3250
3250
|
audit?: string;
|
|
3251
3251
|
classify?: string;
|
|
3252
|
+
'graph-grow'?: string;
|
|
3252
3253
|
}
|
|
3253
3254
|
|
|
3254
3255
|
/** Sparse provider-agnostic model tier preferences by execution role. */
|
|
@@ -3315,6 +3316,7 @@ export const ROLE_MODEL_DEFAULTS: Record<ModelRole, { environment: string; tier:
|
|
|
3315
3316
|
planning: { environment: 'ELANOUS_SKILL_PLAN_MODEL', tier: 'best' },
|
|
3316
3317
|
audit: { environment: 'ELANOUS_MEMORY_JUDGE_MODEL', tier: 'better' },
|
|
3317
3318
|
classify: { environment: 'ELANOUS_ACTION_CLASSIFIER_MODEL', tier: 'budget' },
|
|
3319
|
+
'graph-grow': { environment: 'ELANOUS_GRAPH_GROW_MODEL', tier: 'better' },
|
|
3318
3320
|
};
|
|
3319
3321
|
|
|
3320
3322
|
/** Resolve `auto` through the same runtime provider selector that dispatches LLM calls.
|
|
@@ -3530,7 +3532,7 @@ export interface UserConfig {
|
|
|
3530
3532
|
loops?: { steward?: { mode?: StewardLoopMode; linearTeam?: string; roles?: Record<string, { maxConcurrent?: number }>; budget?: number; tracks?: Record<string, string>; alertAfterFailures?: number; launch?: 'off' | 'shadow' | 'live'; maxParallel?: number; podPool?: string }; seat?: SeatLoopConfig; persona?: PersonaLoopConfig };
|
|
3531
3533
|
/** 🔐 Pod 의 Grok API 키 과금은 명시 opt-in 만. 생략·잘못된 값은 false.
|
|
3532
3534
|
* budgetGate 와 같은 `harness` 객체다 — 중복 선언이면 뒤 타입이 앞을 지운다. */
|
|
3533
|
-
harness?: { pod?: { grokApiKeyOptIn: boolean }; budgetGate?: HarnessBudgetGateConfig; defaultRepo?: string; substrate?: 'local' | 'pod'; podPool?: string; worktreeAddTimeoutSec?: number };
|
|
3535
|
+
harness?: { pod?: { grokApiKeyOptIn: boolean }; budgetGate?: HarnessBudgetGateConfig; difficultyPlacement?: boolean; defaultRepo?: string; substrate?: 'local' | 'pod'; podPool?: string; worktreeAddTimeoutSec?: number };
|
|
3534
3536
|
/** ☸️ Pod 실행 칸 — `pool` = 기존 기본 풀(`컨텍스트[@ssh호스트][:상한][#k3d-레지스트리:포트]` 쉼표 · 앞이 우선). harness 실행은 인자·ELANOUS_POD_POOL·harness.podPool 다음으로 읽는다. */
|
|
3535
3537
|
pod?: { pool?: string; /** 호스트 Git 미러 디렉터리 — Pod Job 에 읽기 전용으로 마운트한다. */ hostMirror?: string; /** 원격 그라운딩 엔드포인트(호스트 nexus · tailnet 주소) — Pod 가 토큰으로 «질의→인용»만 묻는다(P13). */ groundingUrl?: string; /** 읽기 전용 Pod lease 권장에 쓰는 계정별 동시 수. */ lease?: { perAccount?: number } };
|
|
3536
3538
|
skillRouter: SkillRouterConfig;
|
|
@@ -3700,7 +3702,7 @@ export function parseRoleLlmEntry(raw: unknown): { ok: true; spec: RoleLlmSpec }
|
|
|
3700
3702
|
return { ok: true, spec };
|
|
3701
3703
|
}
|
|
3702
3704
|
|
|
3703
|
-
export const MODEL_ROLES: readonly ModelRole[] = ['implement', 'review', 'research', 'planning', 'audit', 'classify'];
|
|
3705
|
+
export const MODEL_ROLES: readonly ModelRole[] = ['implement', 'review', 'research', 'planning', 'audit', 'classify', 'graph-grow'];
|
|
3704
3706
|
|
|
3705
3707
|
export function isModelRole(v: unknown): v is ModelRole {
|
|
3706
3708
|
return typeof v === 'string' && (MODEL_ROLES as readonly string[]).includes(v);
|
|
@@ -3928,7 +3930,7 @@ function defaultConfig(): UserConfig {
|
|
|
3928
3930
|
nativeStructure: { ...TOOLS_DEFAULTS.nativeStructure },
|
|
3929
3931
|
selfImplement: { ...TOOLS_DEFAULTS.selfImplement },
|
|
3930
3932
|
},
|
|
3931
|
-
harness: { budgetGate: { ...DEFAULT_BUDGET_GATE } },
|
|
3933
|
+
harness: { budgetGate: { ...DEFAULT_BUDGET_GATE }, difficultyPlacement: false },
|
|
3932
3934
|
grounding: { sources: [] },
|
|
3933
3935
|
raw: {},
|
|
3934
3936
|
};
|
|
@@ -4539,6 +4541,7 @@ export function buildUserConfig(path: string = defaultPath()): UserConfig {
|
|
|
4539
4541
|
},
|
|
4540
4542
|
harness: {
|
|
4541
4543
|
pod: { grokApiKeyOptIn: harnessPod.grokApiKeyOptIn === true },
|
|
4544
|
+
difficultyPlacement: harness.difficultyPlacement === true,
|
|
4542
4545
|
...(harness.substrate === 'local' || harness.substrate === 'pod' ? { substrate: harness.substrate } : {}),
|
|
4543
4546
|
...(typeof harness.podPool === 'string' && harness.podPool.trim() ? { podPool: harness.podPool.trim() } : {}),
|
|
4544
4547
|
...(typeof harness.worktreeAddTimeoutSec === 'number' && Number.isSafeInteger(harness.worktreeAddTimeoutSec)
|
|
@@ -5783,6 +5786,7 @@ export function saveUserConfig(
|
|
|
5783
5786
|
...rawHarness,
|
|
5784
5787
|
pod: cfg.harness?.pod ?? rawHarness.pod,
|
|
5785
5788
|
budgetGate: cfg.harness?.budgetGate ?? rawHarness.budgetGate,
|
|
5789
|
+
difficultyPlacement: cfg.harness?.difficultyPlacement ?? rawHarness.difficultyPlacement,
|
|
5786
5790
|
defaultRepo: cfg.harness?.defaultRepo ?? rawHarness.defaultRepo,
|
|
5787
5791
|
substrate: cfg.harness?.substrate,
|
|
5788
5792
|
podPool: cfg.harness?.podPool,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"commit":"
|
|
1
|
+
{"commit":"27045f4612b148543fb0f91b82d37592d1d6c9f2"}
|