@gajae-code/coding-agent 0.6.4 → 0.7.0
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/CHANGELOG.md +51 -0
- package/dist/types/async/job-manager.d.ts +3 -1
- package/dist/types/cli/daemon-cli.d.ts +25 -0
- package/dist/types/cli/migrate-cli.d.ts +20 -0
- package/dist/types/cli/notify-cli.d.ts +23 -0
- package/dist/types/cli/setup-cli.d.ts +20 -1
- package/dist/types/commands/daemon.d.ts +41 -0
- package/dist/types/commands/migrate.d.ts +33 -0
- package/dist/types/commands/notify.d.ts +41 -0
- package/dist/types/config/keybindings.d.ts +4 -0
- package/dist/types/config/model-profile-activation.d.ts +12 -0
- package/dist/types/config/model-profiles.d.ts +2 -1
- package/dist/types/config/model-registry.d.ts +3 -3
- package/dist/types/config/models-config-schema.d.ts +5 -0
- package/dist/types/config/settings-schema.d.ts +38 -0
- package/dist/types/coordinator/contract.d.ts +1 -1
- package/dist/types/daemon/builtin.d.ts +20 -0
- package/dist/types/daemon/control-types.d.ts +57 -0
- package/dist/types/daemon/runtime.d.ts +25 -0
- package/dist/types/extensibility/extensions/types.d.ts +8 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +2 -2
- package/dist/types/gjc-runtime/goal-mode-request.d.ts +1 -1
- package/dist/types/gjc-runtime/session-layout.d.ts +59 -0
- package/dist/types/gjc-runtime/session-resolution.d.ts +47 -0
- package/dist/types/gjc-runtime/state-graph.d.ts +1 -1
- package/dist/types/gjc-runtime/state-runtime.d.ts +5 -4
- package/dist/types/gjc-runtime/state-schema.d.ts +2 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +38 -7
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +15 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +21 -4
- package/dist/types/gjc-runtime/workflow-command-ref.d.ts +1 -1
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +1 -1
- package/dist/types/harness-control-plane/storage.d.ts +2 -1
- package/dist/types/hooks/skill-state.d.ts +12 -4
- package/dist/types/migrate/action-planner.d.ts +11 -0
- package/dist/types/migrate/adapters/claude-code.d.ts +2 -0
- package/dist/types/migrate/adapters/codex.d.ts +5 -0
- package/dist/types/migrate/adapters/index.d.ts +45 -0
- package/dist/types/migrate/adapters/opencode.d.ts +2 -0
- package/dist/types/migrate/executor.d.ts +2 -0
- package/dist/types/migrate/mcp-mapper.d.ts +20 -0
- package/dist/types/migrate/report.d.ts +18 -0
- package/dist/types/migrate/skill-normalizer.d.ts +27 -0
- package/dist/types/migrate/types.d.ts +126 -0
- package/dist/types/modes/components/custom-editor.d.ts +1 -1
- package/dist/types/modes/components/oauth-selector.d.ts +2 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +2 -2
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/unattended-audit.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +10 -0
- package/dist/types/modes/types.d.ts +7 -1
- package/dist/types/notifications/config-commands.d.ts +26 -0
- package/dist/types/notifications/config.d.ts +61 -0
- package/dist/types/notifications/helpers.d.ts +55 -0
- package/dist/types/notifications/html-format.d.ts +62 -0
- package/dist/types/notifications/index.d.ts +28 -0
- package/dist/types/notifications/rate-limit-pool.d.ts +93 -0
- package/dist/types/notifications/telegram-cli.d.ts +19 -0
- package/dist/types/notifications/telegram-daemon-cli.d.ts +11 -0
- package/dist/types/notifications/telegram-daemon-control.d.ts +56 -0
- package/dist/types/notifications/telegram-daemon.d.ts +276 -0
- package/dist/types/notifications/telegram-reference.d.ts +111 -0
- package/dist/types/notifications/threaded-inbound.d.ts +58 -0
- package/dist/types/notifications/threaded-render.d.ts +66 -0
- package/dist/types/notifications/topic-registry.d.ts +67 -0
- package/dist/types/research-plan/index.d.ts +1 -0
- package/dist/types/research-plan/ledger.d.ts +33 -0
- package/dist/types/rlm/artifacts.d.ts +1 -1
- package/dist/types/rlm/index.d.ts +12 -0
- package/dist/types/runtime-mcp/config-writer.d.ts +26 -0
- package/dist/types/session/agent-session.d.ts +39 -2
- package/dist/types/session/auth-storage.d.ts +1 -1
- package/dist/types/setup/credential-auto-import.d.ts +63 -0
- package/dist/types/setup/credential-import.d.ts +3 -0
- package/dist/types/setup/host-plugin-setup.d.ts +39 -0
- package/dist/types/skill-state/active-state.d.ts +6 -11
- package/dist/types/skill-state/canonical-skills.d.ts +3 -0
- package/dist/types/skill-state/workflow-hud.d.ts +2 -0
- package/dist/types/task/spawn-gate.d.ts +1 -10
- package/dist/types/tools/ask-answer-registry.d.ts +13 -0
- package/dist/types/tools/index.d.ts +18 -0
- package/dist/types/tools/subagent.d.ts +3 -0
- package/package.json +7 -7
- package/scripts/build-binary.ts +3 -0
- package/src/async/job-manager.ts +5 -1
- package/src/cli/daemon-cli.ts +122 -0
- package/src/cli/migrate-cli.ts +106 -0
- package/src/cli/notify-cli.ts +274 -0
- package/src/cli/setup-cli.ts +173 -84
- package/src/cli.ts +3 -0
- package/src/commands/daemon.ts +47 -0
- package/src/commands/deep-interview.ts +2 -2
- package/src/commands/migrate.ts +46 -0
- package/src/commands/notify.ts +61 -0
- package/src/commands/setup.ts +11 -1
- package/src/commands/state.ts +2 -1
- package/src/commands/team.ts +7 -3
- package/src/config/model-profile-activation.ts +74 -5
- package/src/config/model-profiles.ts +7 -4
- package/src/config/model-registry.ts +6 -3
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/settings-schema.ts +29 -0
- package/src/coordinator/contract.ts +3 -0
- package/src/coordinator-mcp/policy.ts +10 -2
- package/src/coordinator-mcp/server.ts +270 -1
- package/src/daemon/builtin.ts +46 -0
- package/src/daemon/control-types.ts +65 -0
- package/src/daemon/runtime.ts +51 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/biome.json +0 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +28 -24
- package/src/defaults/gjc/skills/ralplan/SKILL.md +8 -4
- package/src/defaults/gjc/skills/team/SKILL.md +51 -47
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +33 -13
- package/src/extensibility/custom-commands/loader.ts +0 -7
- package/src/extensibility/extensions/runner.ts +4 -0
- package/src/extensibility/extensions/types.ts +8 -0
- package/src/extensibility/gjc-plugins/injection.ts +23 -4
- package/src/extensibility/gjc-plugins/state.ts +16 -1
- package/src/gjc-runtime/deep-interview-recorder.ts +51 -18
- package/src/gjc-runtime/deep-interview-runtime.ts +49 -23
- package/src/gjc-runtime/goal-mode-request.ts +26 -11
- package/src/gjc-runtime/launch-tmux.ts +6 -1
- package/src/gjc-runtime/ralplan-runtime.ts +79 -50
- package/src/gjc-runtime/session-layout.ts +180 -0
- package/src/gjc-runtime/session-resolution.ts +217 -0
- package/src/gjc-runtime/state-graph.ts +1 -2
- package/src/gjc-runtime/state-migrations.ts +1 -0
- package/src/gjc-runtime/state-runtime.ts +247 -124
- package/src/gjc-runtime/state-schema.ts +2 -0
- package/src/gjc-runtime/state-writer.ts +289 -41
- package/src/gjc-runtime/team-runtime.ts +43 -19
- package/src/gjc-runtime/tmux-sessions.ts +7 -1
- package/src/gjc-runtime/ultragoal-guard.ts +102 -4
- package/src/gjc-runtime/ultragoal-runtime.ts +226 -60
- package/src/gjc-runtime/workflow-command-ref.ts +1 -2
- package/src/gjc-runtime/workflow-manifest.generated.json +27 -2
- package/src/gjc-runtime/workflow-manifest.ts +12 -3
- package/src/goals/tools/goal-tool.ts +11 -2
- package/src/harness-control-plane/storage.ts +14 -4
- package/src/hooks/native-skill-hook.ts +38 -12
- package/src/hooks/skill-state.ts +178 -83
- package/src/internal-urls/docs-index.generated.ts +9 -6
- package/src/main.ts +30 -0
- package/src/migrate/action-planner.ts +318 -0
- package/src/migrate/adapters/claude-code.ts +39 -0
- package/src/migrate/adapters/codex.ts +70 -0
- package/src/migrate/adapters/index.ts +277 -0
- package/src/migrate/adapters/opencode.ts +52 -0
- package/src/migrate/executor.ts +81 -0
- package/src/migrate/mcp-mapper.ts +152 -0
- package/src/migrate/report.ts +104 -0
- package/src/migrate/skill-normalizer.ts +80 -0
- package/src/migrate/types.ts +163 -0
- package/src/modes/acp/acp-event-mapper.ts +1 -0
- package/src/modes/bridge/bridge-mode.ts +2 -2
- package/src/modes/components/custom-editor.ts +30 -20
- package/src/modes/components/hook-editor.ts +7 -2
- package/src/modes/components/oauth-selector.ts +19 -0
- package/src/modes/controllers/event-controller.ts +20 -0
- package/src/modes/controllers/selector-controller.ts +80 -17
- package/src/modes/interactive-mode.ts +6 -2
- package/src/modes/rpc/rpc-mode.ts +2 -2
- package/src/modes/runtime-init.ts +1 -0
- package/src/modes/shared/agent-wire/event-contract.ts +1 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +1 -0
- package/src/modes/shared/agent-wire/event-observation.ts +16 -0
- package/src/modes/shared/agent-wire/unattended-audit.ts +3 -2
- package/src/modes/shared/agent-wire/unattended-session.ts +22 -0
- package/src/modes/types.ts +7 -1
- package/src/modes/utils/ui-helpers.ts +23 -0
- package/src/notifications/config-commands.ts +50 -0
- package/src/notifications/config.ts +107 -0
- package/src/notifications/helpers.ts +135 -0
- package/src/notifications/html-format.ts +389 -0
- package/src/notifications/index.ts +663 -0
- package/src/notifications/rate-limit-pool.ts +179 -0
- package/src/notifications/telegram-cli.ts +194 -0
- package/src/notifications/telegram-daemon-cli.ts +74 -0
- package/src/notifications/telegram-daemon-control.ts +370 -0
- package/src/notifications/telegram-daemon.ts +1370 -0
- package/src/notifications/telegram-reference.ts +335 -0
- package/src/notifications/threaded-inbound.ts +80 -0
- package/src/notifications/threaded-render.ts +155 -0
- package/src/notifications/topic-registry.ts +133 -0
- package/src/prompts/agents/init.md +1 -1
- package/src/prompts/system/plan-mode-active.md +1 -1
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/search.md +1 -1
- package/src/prompts/tools/task.md +1 -2
- package/src/research-plan/index.ts +1 -0
- package/src/research-plan/ledger.ts +177 -0
- package/src/rlm/artifacts.ts +12 -3
- package/src/rlm/index.ts +26 -0
- package/src/runtime-mcp/config-writer.ts +46 -0
- package/src/sdk.ts +16 -0
- package/src/session/agent-session.ts +128 -24
- package/src/session/auth-storage.ts +3 -0
- package/src/session/session-dump-format.ts +43 -2
- package/src/session/session-manager.ts +39 -5
- package/src/setup/credential-auto-import.ts +258 -0
- package/src/setup/credential-import.ts +17 -0
- package/src/setup/hermes/templates/operator-instructions.v1.md +10 -0
- package/src/setup/hermes-setup.ts +1 -1
- package/src/setup/host-plugin-setup.ts +142 -0
- package/src/skill-state/active-state.ts +72 -108
- package/src/skill-state/canonical-skills.ts +4 -0
- package/src/skill-state/deep-interview-mutation-guard.ts +28 -109
- package/src/skill-state/workflow-hud.ts +4 -2
- package/src/skill-state/workflow-state-contract.ts +3 -3
- package/src/slash-commands/builtin-registry.ts +4 -1
- package/src/task/agents.ts +1 -22
- package/src/task/executor.ts +5 -1
- package/src/task/index.ts +1 -41
- package/src/task/spawn-gate.ts +1 -38
- package/src/task/types.ts +1 -1
- package/src/tools/ask-answer-registry.ts +25 -0
- package/src/tools/ask.ts +108 -16
- package/src/tools/computer.ts +58 -4
- package/src/tools/image-gen.ts +5 -8
- package/src/tools/index.ts +19 -0
- package/src/tools/inspect-image.ts +16 -11
- package/src/tools/subagent-render.ts +7 -0
- package/src/tools/subagent.ts +38 -7
- package/dist/types/extensibility/custom-commands/bundled/review/index.d.ts +0 -10
- package/src/extensibility/custom-commands/bundled/review/index.ts +0 -456
- package/src/prompts/agents/explore.md +0 -58
- package/src/prompts/agents/plan.md +0 -49
- package/src/prompts/agents/reviewer.md +0 -141
- package/src/prompts/agents/task.md +0 -16
- package/src/prompts/review-request.md +0 -70
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import type { Settings } from "../config/settings";
|
|
3
|
+
import type { DaemonRuntimeInfo } from "../daemon/control-types";
|
|
4
|
+
import { type AliasTable, type CallbackRoute, type PendingAsk } from "./telegram-reference";
|
|
5
|
+
export type EnsureDaemonResult = "owner_spawned" | "attached" | "disabled";
|
|
6
|
+
export interface DaemonState {
|
|
7
|
+
pid: number;
|
|
8
|
+
ownerId: string;
|
|
9
|
+
tokenFingerprint: string;
|
|
10
|
+
chatId: string;
|
|
11
|
+
startedAt: number;
|
|
12
|
+
heartbeatAt: number;
|
|
13
|
+
roots: string[];
|
|
14
|
+
version: 1;
|
|
15
|
+
stoppedAt?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface DaemonPaths {
|
|
18
|
+
dir: string;
|
|
19
|
+
lock: string;
|
|
20
|
+
state: string;
|
|
21
|
+
roots: string;
|
|
22
|
+
steal: string;
|
|
23
|
+
aliases: string;
|
|
24
|
+
}
|
|
25
|
+
export interface TelegramDaemonFs {
|
|
26
|
+
mkdir(path: string, opts?: fs.MakeDirectoryOptions): Promise<void>;
|
|
27
|
+
readFile(path: string, encoding: BufferEncoding): Promise<string>;
|
|
28
|
+
writeFile(path: string, data: string, opts?: fs.WriteFileOptions): Promise<void>;
|
|
29
|
+
rename(oldPath: string, newPath: string): Promise<void>;
|
|
30
|
+
unlink(path: string): Promise<void>;
|
|
31
|
+
open(path: string, flags: string, mode?: number): Promise<{
|
|
32
|
+
close(): Promise<void>;
|
|
33
|
+
}>;
|
|
34
|
+
readdir(path: string): Promise<string[]>;
|
|
35
|
+
chmod(path: string, mode: number): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export interface SpawnResult {
|
|
38
|
+
unref?: () => void;
|
|
39
|
+
}
|
|
40
|
+
export interface TelegramDaemonDeps {
|
|
41
|
+
fs?: TelegramDaemonFs;
|
|
42
|
+
now?: () => number;
|
|
43
|
+
pid?: number;
|
|
44
|
+
pidAlive?: (pid: number) => boolean;
|
|
45
|
+
spawn?: (command: string, args: string[], opts: {
|
|
46
|
+
detached: boolean;
|
|
47
|
+
stdio: "ignore";
|
|
48
|
+
logPath?: string;
|
|
49
|
+
}) => SpawnResult;
|
|
50
|
+
execPath?: string;
|
|
51
|
+
randomId?: () => string;
|
|
52
|
+
}
|
|
53
|
+
export declare const HEARTBEAT_INTERVAL_MS = 5000;
|
|
54
|
+
export declare const HEARTBEAT_TTL_MS = 20000;
|
|
55
|
+
export declare const DAEMON_VERSION = 1;
|
|
56
|
+
/** Capability token advertised when the server supports app-level ping/pong. */
|
|
57
|
+
export declare const CLIENT_PING_PONG_CAPABILITY = "client_ping_pong";
|
|
58
|
+
/** Protocol version the daemon advertises in its ClientHello. */
|
|
59
|
+
export declare const NOTIFICATION_PROTOCOL_VERSION = 2;
|
|
60
|
+
export declare function daemonPaths(agentDir: string): DaemonPaths;
|
|
61
|
+
export declare function registerNotificationRoot(input: {
|
|
62
|
+
settings: Settings;
|
|
63
|
+
cwd: string;
|
|
64
|
+
sessionId: string;
|
|
65
|
+
fs?: TelegramDaemonFs;
|
|
66
|
+
}): Promise<string>;
|
|
67
|
+
export declare function isFreshLiveOwner(input: {
|
|
68
|
+
state: DaemonState | undefined;
|
|
69
|
+
now: number;
|
|
70
|
+
tokenFingerprint: string;
|
|
71
|
+
chatId: string;
|
|
72
|
+
pidAlive: (pid: number) => boolean;
|
|
73
|
+
}): boolean;
|
|
74
|
+
export declare function acquireDaemonOwnership(input: {
|
|
75
|
+
settings: Settings;
|
|
76
|
+
roots?: string[];
|
|
77
|
+
tokenFingerprint: string;
|
|
78
|
+
chatId: string;
|
|
79
|
+
fs?: TelegramDaemonFs;
|
|
80
|
+
now?: () => number;
|
|
81
|
+
pid?: number;
|
|
82
|
+
pidAlive?: (pid: number) => boolean;
|
|
83
|
+
randomId?: () => string;
|
|
84
|
+
}): Promise<{
|
|
85
|
+
acquired: boolean;
|
|
86
|
+
ownerId?: string;
|
|
87
|
+
attached?: boolean;
|
|
88
|
+
}>;
|
|
89
|
+
export declare function renewDaemonHeartbeat(input: {
|
|
90
|
+
settings: Settings;
|
|
91
|
+
ownerId: string;
|
|
92
|
+
fs?: TelegramDaemonFs;
|
|
93
|
+
now?: () => number;
|
|
94
|
+
pid?: number;
|
|
95
|
+
}): Promise<boolean>;
|
|
96
|
+
export declare function releaseDaemonOwnership(input: {
|
|
97
|
+
settings: Settings;
|
|
98
|
+
ownerId: string;
|
|
99
|
+
fs?: TelegramDaemonFs;
|
|
100
|
+
now?: () => number;
|
|
101
|
+
}): Promise<void>;
|
|
102
|
+
/** Read the persisted daemon ownership state (or undefined when absent). */
|
|
103
|
+
export declare function readDaemonState(settings: Settings, fs?: TelegramDaemonFs): Promise<DaemonState | undefined>;
|
|
104
|
+
/** Read the persisted notification roots list. */
|
|
105
|
+
export declare function readDaemonRoots(settings: Settings, fs?: TelegramDaemonFs): Promise<string[]>;
|
|
106
|
+
export interface TelegramSpawnOwnerInput {
|
|
107
|
+
settings: Settings;
|
|
108
|
+
roots?: string[];
|
|
109
|
+
tokenFingerprint: string;
|
|
110
|
+
chatId: string;
|
|
111
|
+
}
|
|
112
|
+
export interface TelegramSpawnOwnerResult {
|
|
113
|
+
result: EnsureDaemonResult;
|
|
114
|
+
ownerId?: string;
|
|
115
|
+
runtime: DaemonRuntimeInfo;
|
|
116
|
+
warnings: string[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Build the detached spawn command/args for the daemon-internal entrypoint.
|
|
120
|
+
* Source mode prepends the entry script so the respawn loads edited source;
|
|
121
|
+
* a compiled binary self-spawns its own subcommand directly.
|
|
122
|
+
*/
|
|
123
|
+
export declare function buildTelegramDaemonSpawnArgs(input: {
|
|
124
|
+
execPath?: string;
|
|
125
|
+
ownerId: string;
|
|
126
|
+
agentDir: string;
|
|
127
|
+
}): {
|
|
128
|
+
command: string;
|
|
129
|
+
args: string[];
|
|
130
|
+
runtime: DaemonRuntimeInfo;
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Acquire ownership for the given Telegram identity and, if acquired, spawn a
|
|
134
|
+
* fresh detached daemon process. Does NOT register notification roots; callers
|
|
135
|
+
* that own a session (autostart) register roots separately, while reload reuses
|
|
136
|
+
* already-persisted roots.
|
|
137
|
+
*/
|
|
138
|
+
export declare function spawnTelegramDaemonOwner(input: TelegramSpawnOwnerInput, deps?: TelegramDaemonDeps): Promise<TelegramSpawnOwnerResult>;
|
|
139
|
+
export declare function ensureTelegramDaemonRunning(input: {
|
|
140
|
+
settings: Settings;
|
|
141
|
+
cwd: string;
|
|
142
|
+
sessionId: string;
|
|
143
|
+
}, deps?: TelegramDaemonDeps): Promise<EnsureDaemonResult>;
|
|
144
|
+
export interface BotApi {
|
|
145
|
+
call(method: string, body: unknown, opts?: {
|
|
146
|
+
signal?: AbortSignal;
|
|
147
|
+
}): Promise<unknown>;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Cooperative control seam for the daemon run loop. Implemented by the
|
|
151
|
+
* daemon-internal CLI / controller against the owner-scoped control-request
|
|
152
|
+
* file so the daemon does not import the control module directly.
|
|
153
|
+
*/
|
|
154
|
+
export interface DaemonControlHooks {
|
|
155
|
+
/** Returns true when a stop/reload has been requested for this owner. */
|
|
156
|
+
shouldStop(ownerId: string): Promise<boolean>;
|
|
157
|
+
/** Clear a consumed control request (best-effort). */
|
|
158
|
+
clear?(ownerId: string): Promise<void>;
|
|
159
|
+
}
|
|
160
|
+
export interface TelegramDaemonOptions {
|
|
161
|
+
settings: Settings;
|
|
162
|
+
ownerId: string;
|
|
163
|
+
botToken: string;
|
|
164
|
+
chatId: string;
|
|
165
|
+
apiBase?: string;
|
|
166
|
+
fetchImpl?: typeof fetch;
|
|
167
|
+
fs?: TelegramDaemonFs;
|
|
168
|
+
WebSocketImpl?: typeof WebSocket;
|
|
169
|
+
now?: () => number;
|
|
170
|
+
setTimeoutImpl?: typeof setTimeout;
|
|
171
|
+
clearTimeoutImpl?: typeof clearTimeout;
|
|
172
|
+
setIntervalImpl?: typeof setInterval;
|
|
173
|
+
clearIntervalImpl?: typeof clearInterval;
|
|
174
|
+
idleTimeoutMs?: number;
|
|
175
|
+
scanIntervalMs?: number;
|
|
176
|
+
pid?: number;
|
|
177
|
+
botApi?: BotApi;
|
|
178
|
+
control?: DaemonControlHooks;
|
|
179
|
+
}
|
|
180
|
+
interface SessionSocket {
|
|
181
|
+
sessionId: string;
|
|
182
|
+
token: string;
|
|
183
|
+
ws: WebSocket;
|
|
184
|
+
pending: Map<string, {
|
|
185
|
+
sessionId: string;
|
|
186
|
+
actionId: string;
|
|
187
|
+
}>;
|
|
188
|
+
/** True once the server advertised the `client_ping_pong` capability. */
|
|
189
|
+
capable: boolean;
|
|
190
|
+
/** Timestamp (via opts.now) of the last received pong; seeds the TTL window. */
|
|
191
|
+
lastPongAt: number;
|
|
192
|
+
/** Nonce of the most recent in-flight ping, if any. */
|
|
193
|
+
awaitingNonce: string | undefined;
|
|
194
|
+
/** Per-session liveness interval handle (only set for capable sessions). */
|
|
195
|
+
pingTimer: ReturnType<typeof setInterval> | undefined;
|
|
196
|
+
}
|
|
197
|
+
export declare class TelegramNotificationDaemon {
|
|
198
|
+
private readonly opts;
|
|
199
|
+
readonly aliasTable: AliasTable;
|
|
200
|
+
readonly messageRoutes: Map<string | number, CallbackRoute | Omit<CallbackRoute, "answer">>;
|
|
201
|
+
readonly sessions: Map<string, SessionSocket>;
|
|
202
|
+
private running;
|
|
203
|
+
private offset;
|
|
204
|
+
private readonly fsImpl;
|
|
205
|
+
private readonly botApi;
|
|
206
|
+
private readonly topics;
|
|
207
|
+
private readonly pool;
|
|
208
|
+
private readonly seenUpdateIds;
|
|
209
|
+
private flushTimer;
|
|
210
|
+
private scanTimer;
|
|
211
|
+
private scanning;
|
|
212
|
+
private typingTimer;
|
|
213
|
+
/** Sessions whose agent loop is currently busy (drives the typing indicator). */
|
|
214
|
+
private readonly busy;
|
|
215
|
+
/** Inbound update id → originating Telegram message, for delivery reactions. */
|
|
216
|
+
private readonly inboundReactions;
|
|
217
|
+
/** AbortController for the in-flight long poll; aborted by requestStop() to wake the loop. */
|
|
218
|
+
private activePoll;
|
|
219
|
+
/** Set when a cooperative stop has been requested (signal or control request). */
|
|
220
|
+
private stopRequested;
|
|
221
|
+
/** Current bounded backoff after a Telegram getUpdates 409 conflict (0 when healthy). */
|
|
222
|
+
private pollConflictBackoffMs;
|
|
223
|
+
/**
|
|
224
|
+
* Cooperatively stop the daemon: set the stop flag and abort the in-flight
|
|
225
|
+
* long poll so the run loop wakes immediately instead of waiting out the
|
|
226
|
+
* ~25s getUpdates timeout. Safe to call from a signal handler.
|
|
227
|
+
*/
|
|
228
|
+
requestStop(_reason?: "reload" | "stop" | "signal"): void;
|
|
229
|
+
constructor(opts: TelegramDaemonOptions);
|
|
230
|
+
loadAliases(): Promise<void>;
|
|
231
|
+
persistAliases(): Promise<void>;
|
|
232
|
+
scanRoots(): Promise<void>;
|
|
233
|
+
connectSession(sessionId: string, url: string, token: string): void;
|
|
234
|
+
/**
|
|
235
|
+
* Start ack-based liveness for a session whose server advertised the
|
|
236
|
+
* `client_ping_pong` capability. Each interval drops the session when no pong
|
|
237
|
+
* has arrived within the TTL (the half-open case the socket never signals via
|
|
238
|
+
* `close`), otherwise sends a fresh application-level ping. The timer is bound
|
|
239
|
+
* to this exact session object.
|
|
240
|
+
*/
|
|
241
|
+
private startLiveness;
|
|
242
|
+
/**
|
|
243
|
+
* Idempotent, identity-guarded session teardown. Clears the liveness timer,
|
|
244
|
+
* removes the map entry only when it still points at this exact session object
|
|
245
|
+
* (so a delayed old close cannot delete a replacement), and best-effort closes
|
|
246
|
+
* the socket. `scanRoots()` then reconnects the session.
|
|
247
|
+
*/
|
|
248
|
+
private dropSession;
|
|
249
|
+
private static readonly THREADED_FRAMES;
|
|
250
|
+
private topicNameFor;
|
|
251
|
+
private ensureTopic;
|
|
252
|
+
private persistTopics;
|
|
253
|
+
loadTopics(): Promise<void>;
|
|
254
|
+
private flushPool;
|
|
255
|
+
private startFlushTimer;
|
|
256
|
+
private stopFlushTimer;
|
|
257
|
+
private runScan;
|
|
258
|
+
private startScanTimer;
|
|
259
|
+
private stopScanTimer;
|
|
260
|
+
private sendTyping;
|
|
261
|
+
private setReaction;
|
|
262
|
+
private startTypingTimer;
|
|
263
|
+
private stopTypingTimer;
|
|
264
|
+
handleSessionMessage(session: SessionSocket, msg: any): Promise<void>;
|
|
265
|
+
pendingBySession: (sessionId?: string) => PendingAsk[];
|
|
266
|
+
private sendStaleGuidance;
|
|
267
|
+
handleTelegramUpdate(update: unknown): Promise<void>;
|
|
268
|
+
pollOnce(signal?: AbortSignal): Promise<number>;
|
|
269
|
+
/** Abortable sleep honoring the injected timer; resolves early on abort. */
|
|
270
|
+
private sleep;
|
|
271
|
+
/** Sync the bot's Telegram command menu to what the daemon actually handles. */
|
|
272
|
+
registerBotCommands(): Promise<void>;
|
|
273
|
+
run(): Promise<void>;
|
|
274
|
+
private controlStopRequested;
|
|
275
|
+
}
|
|
276
|
+
export {};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram **reference** client for the notifications SDK.
|
|
3
|
+
*
|
|
4
|
+
* This is an example/template, NOT an upstream-owned integration: it implements
|
|
5
|
+
* the documented WS protocol (see `docs/notifications-sdk.md`) so you can copy it
|
|
6
|
+
* to build Discord/Slack/etc. clients with zero upstream changes. The Bot API
|
|
7
|
+
* transport shape is salvaged from the removed `telegram-remote` package.
|
|
8
|
+
*
|
|
9
|
+
* Flow: read the endpoint discovery file -> connect to the session WS -> render
|
|
10
|
+
* `action_needed` to a Telegram chat (inline keyboard for options) -> map button
|
|
11
|
+
* taps / text replies to `reply` frames -> reflect `action_resolved` /
|
|
12
|
+
* `reply_rejected`.
|
|
13
|
+
*
|
|
14
|
+
* Dependency-free: uses global `fetch` and `WebSocket` (Bun/Node 22+).
|
|
15
|
+
*/
|
|
16
|
+
/** One inline-keyboard button. */
|
|
17
|
+
export interface InlineButton {
|
|
18
|
+
text: string;
|
|
19
|
+
callback_data: string;
|
|
20
|
+
}
|
|
21
|
+
/** A rendered Telegram message for an `action_needed`. */
|
|
22
|
+
export interface RenderedMessage {
|
|
23
|
+
text: string;
|
|
24
|
+
inline_keyboard?: InlineButton[][];
|
|
25
|
+
}
|
|
26
|
+
/** Encode `actionId` + option `index` into Telegram callback_data (<=64 bytes). */
|
|
27
|
+
export declare function encodeCallbackData(actionId: string, index: number): string;
|
|
28
|
+
/** Decode callback_data produced by {@link encodeCallbackData}. */
|
|
29
|
+
export declare function decodeCallbackData(data: string): {
|
|
30
|
+
id: string;
|
|
31
|
+
index: number;
|
|
32
|
+
} | null;
|
|
33
|
+
export interface CallbackRoute {
|
|
34
|
+
sessionId: string;
|
|
35
|
+
actionId: string;
|
|
36
|
+
answer: number | string;
|
|
37
|
+
}
|
|
38
|
+
export interface SerializedAliasTable {
|
|
39
|
+
version: 1;
|
|
40
|
+
next: number;
|
|
41
|
+
routes: Record<string, CallbackRoute>;
|
|
42
|
+
}
|
|
43
|
+
export interface AliasTable {
|
|
44
|
+
put(route: CallbackRoute): string;
|
|
45
|
+
get(alias: string): CallbackRoute | undefined;
|
|
46
|
+
delete(alias: string): boolean;
|
|
47
|
+
serialize(): SerializedAliasTable;
|
|
48
|
+
load(json: unknown): void;
|
|
49
|
+
entries(): Array<[string, CallbackRoute]>;
|
|
50
|
+
}
|
|
51
|
+
/** Create a compact, durable callback alias table. Serialized data contains routing ids only. */
|
|
52
|
+
export declare function createAliasTable(): AliasTable;
|
|
53
|
+
/** Render an `action_needed` payload into a Telegram message. */
|
|
54
|
+
export declare function buildActionMessage(action: {
|
|
55
|
+
kind: "ask" | "idle";
|
|
56
|
+
id: string;
|
|
57
|
+
question?: string;
|
|
58
|
+
options?: string[];
|
|
59
|
+
summary?: string;
|
|
60
|
+
}): RenderedMessage;
|
|
61
|
+
/** A protocol `reply` frame the client should send to the server. */
|
|
62
|
+
export interface ReplyFrame {
|
|
63
|
+
type: "reply";
|
|
64
|
+
id: string;
|
|
65
|
+
answer: number | string;
|
|
66
|
+
token: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Map a Telegram update into a reply frame, given the most recent pending ask id
|
|
70
|
+
* (for free-text replies). Returns `null` when the update is not actionable.
|
|
71
|
+
*/
|
|
72
|
+
export declare function telegramUpdateToReply(update: unknown, token: string, latestPendingAskId: string | undefined): ReplyFrame | null;
|
|
73
|
+
export type RouteDecision = ({
|
|
74
|
+
kind: "reply";
|
|
75
|
+
} & CallbackRoute) | {
|
|
76
|
+
kind: "stale";
|
|
77
|
+
reason: string;
|
|
78
|
+
} | {
|
|
79
|
+
kind: "ignore";
|
|
80
|
+
};
|
|
81
|
+
export interface PendingAsk {
|
|
82
|
+
sessionId: string;
|
|
83
|
+
actionId: string;
|
|
84
|
+
}
|
|
85
|
+
export interface RouteInboundContext {
|
|
86
|
+
aliasTable: Pick<AliasTable, "get">;
|
|
87
|
+
messageRoutes: Map<string | number, CallbackRoute | Omit<CallbackRoute, "answer">>;
|
|
88
|
+
pendingBySession: (sessionId?: string) => PendingAsk[];
|
|
89
|
+
pairedChatId: string;
|
|
90
|
+
}
|
|
91
|
+
/** Route a Telegram update to a session/action without I/O. Fail closed under ambiguity. */
|
|
92
|
+
export declare function routeInboundUpdate(update: unknown, ctx: RouteInboundContext): RouteDecision;
|
|
93
|
+
/** Read `{url, token}` from an endpoint discovery file. */
|
|
94
|
+
export declare function readEndpoint(path: string): {
|
|
95
|
+
url: string;
|
|
96
|
+
token: string;
|
|
97
|
+
};
|
|
98
|
+
/** Options for {@link runTelegramReferenceClient}. */
|
|
99
|
+
export interface TelegramReferenceOptions {
|
|
100
|
+
botToken: string;
|
|
101
|
+
chatId: string;
|
|
102
|
+
endpointFile: string;
|
|
103
|
+
apiBase?: string;
|
|
104
|
+
fetchImpl?: typeof fetch;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Run the reference bridge until the WebSocket closes. Sends `action_needed` to
|
|
108
|
+
* the chat and forwards taps/text as replies. This is a minimal example loop;
|
|
109
|
+
* production clients add reconnection, multi-chat routing, and persistence.
|
|
110
|
+
*/
|
|
111
|
+
export declare function runTelegramReferenceClient(opts: TelegramReferenceOptions): Promise<void>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fail-closed routing for inbound Telegram updates in threaded session mode.
|
|
3
|
+
*
|
|
4
|
+
* In the threaded surface, a free-text reply inside a session's forum topic
|
|
5
|
+
* injects a new user turn into that session (steering it at any time). That is
|
|
6
|
+
* remote control of the agent, so every inbound path must fail closed:
|
|
7
|
+
*
|
|
8
|
+
* - the update must come from the single paired chat id;
|
|
9
|
+
* - it must carry a `message_thread_id` (topic) that maps to a KNOWN session;
|
|
10
|
+
* - its `update_id` must not have been seen before (idempotency / replay guard);
|
|
11
|
+
* - the text must be non-empty.
|
|
12
|
+
*
|
|
13
|
+
* Anything ambiguous or unmapped is ignored with a reason rather than guessed.
|
|
14
|
+
* This module is pure (the dedupe set and topic map are injected) so the
|
|
15
|
+
* security rules are exhaustively unit-testable without a live Bot API.
|
|
16
|
+
*/
|
|
17
|
+
/** Minimal shape of the inbound Telegram message we route on. */
|
|
18
|
+
export interface InboundUpdate {
|
|
19
|
+
update_id?: unknown;
|
|
20
|
+
message?: {
|
|
21
|
+
message_id?: unknown;
|
|
22
|
+
text?: unknown;
|
|
23
|
+
chat?: {
|
|
24
|
+
id?: unknown;
|
|
25
|
+
};
|
|
26
|
+
message_thread_id?: unknown;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Context for {@link decideThreadedInbound}. All lookups are injected. */
|
|
30
|
+
export interface ThreadedInboundCtx {
|
|
31
|
+
/** The single paired chat id (string-compared). */
|
|
32
|
+
pairedChatId: string;
|
|
33
|
+
/** Resolve a topic/thread id to its owning session id, or undefined. */
|
|
34
|
+
topicToSession: (threadId: string) => string | undefined;
|
|
35
|
+
/** Whether this `update_id` has already been processed. */
|
|
36
|
+
isDuplicate: (updateId: number) => boolean;
|
|
37
|
+
}
|
|
38
|
+
/** Outcome of routing an inbound update. */
|
|
39
|
+
export type ThreadedInboundDecision = {
|
|
40
|
+
kind: "inject";
|
|
41
|
+
sessionId: string;
|
|
42
|
+
text: string;
|
|
43
|
+
updateId: number;
|
|
44
|
+
threadId: string;
|
|
45
|
+
messageId?: number;
|
|
46
|
+
} | {
|
|
47
|
+
kind: "duplicate";
|
|
48
|
+
updateId: number;
|
|
49
|
+
} | {
|
|
50
|
+
kind: "ignore";
|
|
51
|
+
reason: string;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Decide whether an inbound update should inject a user turn. Fail-closed:
|
|
55
|
+
* returns `ignore` (with a reason) or `duplicate` for anything that is not an
|
|
56
|
+
* unambiguous, first-seen, paired-chat, known-topic text message.
|
|
57
|
+
*/
|
|
58
|
+
export declare function decideThreadedInbound(update: InboundUpdate, ctx: ThreadedInboundCtx): ThreadedInboundDecision;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure rendering of threaded-session frames into Telegram send specs.
|
|
3
|
+
*
|
|
4
|
+
* The daemon receives the additive `ServerMessage` frames (identity_header,
|
|
5
|
+
* context_update, turn_stream, image_attachment, config_update) over the session
|
|
6
|
+
* WS and must turn each into a Bot API call scoped to the session's forum topic
|
|
7
|
+
* (`message_thread_id`), throttled through the shared rate-limit pool. This
|
|
8
|
+
* module is the pure frame→send mapping (including the priority lane and live-
|
|
9
|
+
* edit coalesce key), so rendering is unit-testable without a live Bot API.
|
|
10
|
+
*/
|
|
11
|
+
import type { RateLimitLane } from "./rate-limit-pool";
|
|
12
|
+
/** A Telegram send derived from a threaded frame (topic id is applied by the daemon). */
|
|
13
|
+
export interface ThreadedSend {
|
|
14
|
+
method: "sendMessage" | "sendPhoto";
|
|
15
|
+
/** Rate-limit lane for prioritisation/fairness. */
|
|
16
|
+
lane: RateLimitLane;
|
|
17
|
+
/** Message text (sendMessage) or photo caption (sendPhoto). */
|
|
18
|
+
text?: string;
|
|
19
|
+
/** Base64 image bytes for sendPhoto. */
|
|
20
|
+
photoBase64?: string;
|
|
21
|
+
/** Image MIME type for sendPhoto. */
|
|
22
|
+
mime?: string;
|
|
23
|
+
/** Coalesce key for live edits (same key collapses to the latest). */
|
|
24
|
+
coalesceKey?: string;
|
|
25
|
+
/** True for the one-time identity header (the daemon pins it once). */
|
|
26
|
+
identity?: boolean;
|
|
27
|
+
}
|
|
28
|
+
interface ThreadedFrame {
|
|
29
|
+
type?: unknown;
|
|
30
|
+
sessionId?: unknown;
|
|
31
|
+
repo?: unknown;
|
|
32
|
+
branch?: unknown;
|
|
33
|
+
machine?: unknown;
|
|
34
|
+
title?: unknown;
|
|
35
|
+
lastMessage?: unknown;
|
|
36
|
+
task?: unknown;
|
|
37
|
+
goal?: unknown;
|
|
38
|
+
tokenUsage?: unknown;
|
|
39
|
+
model?: unknown;
|
|
40
|
+
diff?: unknown;
|
|
41
|
+
phase?: unknown;
|
|
42
|
+
text?: unknown;
|
|
43
|
+
messageRef?: unknown;
|
|
44
|
+
source?: unknown;
|
|
45
|
+
data?: unknown;
|
|
46
|
+
mime?: unknown;
|
|
47
|
+
caption?: unknown;
|
|
48
|
+
verbosity?: unknown;
|
|
49
|
+
redact?: unknown;
|
|
50
|
+
}
|
|
51
|
+
/** Format the one-time identity header as pinned bullets. */
|
|
52
|
+
export declare function formatIdentityHeader(frame: {
|
|
53
|
+
repo?: unknown;
|
|
54
|
+
branch?: unknown;
|
|
55
|
+
machine?: unknown;
|
|
56
|
+
sessionId?: unknown;
|
|
57
|
+
title?: unknown;
|
|
58
|
+
}): string;
|
|
59
|
+
/** Format a streamed context update into a compact block (omitting empty fields). */
|
|
60
|
+
export declare function formatContextUpdate(frame: ThreadedFrame): string | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Map a threaded frame to a Telegram send spec, or `undefined` when there is
|
|
63
|
+
* nothing to send (e.g. an empty context update or an unknown frame type).
|
|
64
|
+
*/
|
|
65
|
+
export declare function renderThreadedFrame(frame: ThreadedFrame): ThreadedSend | undefined;
|
|
66
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-session forum-topic registry for the threaded session surface.
|
|
3
|
+
*
|
|
4
|
+
* Each GJC session owns exactly one Telegram forum topic in the paired private
|
|
5
|
+
* DM. The topic is created once (via `createForumTopic`) and REUSED on resume,
|
|
6
|
+
* keyed by session id, so a resumed session streams back into its existing
|
|
7
|
+
* thread/history. The registry also tracks whether the one-time identity header
|
|
8
|
+
* has already been pinned, so it is sent exactly once per topic even across
|
|
9
|
+
* reconnects.
|
|
10
|
+
*
|
|
11
|
+
* State is a plain serialisable map persisted beside the daemon state files;
|
|
12
|
+
* topic creation is injected so this module is pure and unit-testable without a
|
|
13
|
+
* live Bot API.
|
|
14
|
+
*/
|
|
15
|
+
/** Persisted record for one session's topic. */
|
|
16
|
+
export interface TopicRecord {
|
|
17
|
+
/** Telegram forum topic id (message_thread_id). */
|
|
18
|
+
topicId: string;
|
|
19
|
+
/** Whether the one-time identity header has been sent/pinned. */
|
|
20
|
+
identitySent: boolean;
|
|
21
|
+
/** Creation timestamp (ms epoch). */
|
|
22
|
+
createdAt: number;
|
|
23
|
+
/** Last applied topic title (for rename detection). */
|
|
24
|
+
name?: string;
|
|
25
|
+
}
|
|
26
|
+
/** Serialisable shape persisted to disk. */
|
|
27
|
+
export interface TopicRegistryState {
|
|
28
|
+
/** sessionId -> record. */
|
|
29
|
+
topics: Record<string, TopicRecord>;
|
|
30
|
+
}
|
|
31
|
+
export declare function emptyTopicRegistryState(): TopicRegistryState;
|
|
32
|
+
/**
|
|
33
|
+
* In-memory registry over a serialisable state. Topic creation is injected via
|
|
34
|
+
* `getOrCreateTopic`'s `create` callback (the daemon supplies a real
|
|
35
|
+
* `createForumTopic` call); reuse-on-resume is automatic when a record exists.
|
|
36
|
+
*/
|
|
37
|
+
export declare class TopicRegistry {
|
|
38
|
+
private readonly topics;
|
|
39
|
+
/** Maps topicId -> sessionId for fast inbound routing. */
|
|
40
|
+
private readonly byTopic;
|
|
41
|
+
/** In-flight create promises, keyed by session, to dedupe concurrent creates. */
|
|
42
|
+
private readonly inflight;
|
|
43
|
+
constructor(state?: TopicRegistryState);
|
|
44
|
+
/** Merge a serialized state into this registry, preserving all persisted fields. */
|
|
45
|
+
load(state: TopicRegistryState): void;
|
|
46
|
+
/** Resolve the owning session for a topic id (for fail-closed inbound routing). */
|
|
47
|
+
sessionForTopic(topicId: string): string | undefined;
|
|
48
|
+
/** The existing topic record for a session, if any. */
|
|
49
|
+
get(sessionId: string): TopicRecord | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Return the existing topic for `sessionId`, or create one via `create`
|
|
52
|
+
* (called only on first use). Reuse-on-resume: an existing record is
|
|
53
|
+
* returned without invoking `create`.
|
|
54
|
+
*/
|
|
55
|
+
getOrCreateTopic(sessionId: string, create: () => Promise<string>, now?: () => number): Promise<TopicRecord>;
|
|
56
|
+
/** Mark the identity header as sent for a session. Idempotent. */
|
|
57
|
+
markIdentitySent(sessionId: string): void;
|
|
58
|
+
/** Whether the identity header still needs sending for this session. */
|
|
59
|
+
needsIdentity(sessionId: string): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Record the topic's applied title. Returns `true` when it changed (so the
|
|
62
|
+
* caller should `editForumTopic`), `false` when already current or unknown.
|
|
63
|
+
*/
|
|
64
|
+
applyName(sessionId: string, name: string): boolean;
|
|
65
|
+
/** Serialise for atomic persistence beside the daemon state. */
|
|
66
|
+
serialize(): TopicRegistryState;
|
|
67
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./ledger";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type ResearchPlanConfidence = "low" | "medium" | "high";
|
|
2
|
+
export type ResearchEvidenceVerdict = "support" | "contradict" | "uncertain";
|
|
3
|
+
export interface ResearchPlanItem {
|
|
4
|
+
claim: string;
|
|
5
|
+
confidence: ResearchPlanConfidence;
|
|
6
|
+
unknowns: string[];
|
|
7
|
+
evidenceNeeded: string[];
|
|
8
|
+
counterexampleQueries: string[];
|
|
9
|
+
sourceConflictPolicy: string;
|
|
10
|
+
dropCondition: string;
|
|
11
|
+
verifierChecks: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface ResearchEvidenceEntry {
|
|
14
|
+
claim: string;
|
|
15
|
+
source: string;
|
|
16
|
+
confidence: ResearchPlanConfidence;
|
|
17
|
+
verdict: ResearchEvidenceVerdict;
|
|
18
|
+
notes?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ResearchLedgerVerdict {
|
|
21
|
+
claim: string;
|
|
22
|
+
finalVerdict: "accepted" | "rejected" | "uncertain";
|
|
23
|
+
survivingSources: ResearchEvidenceEntry[];
|
|
24
|
+
rejectReason?: string;
|
|
25
|
+
unresolvedUnknowns: string[];
|
|
26
|
+
}
|
|
27
|
+
export interface ResearchPlanValidationResult {
|
|
28
|
+
valid: boolean;
|
|
29
|
+
errors: string[];
|
|
30
|
+
}
|
|
31
|
+
export declare function validateResearchPlanItem(item: Partial<ResearchPlanItem>): ResearchPlanValidationResult;
|
|
32
|
+
export declare function validateResearchEvidenceEntry(entry: Partial<ResearchEvidenceEntry>): ResearchPlanValidationResult;
|
|
33
|
+
export declare function evaluateResearchLedger(item: ResearchPlanItem, evidence: readonly ResearchEvidenceEntry[]): ResearchLedgerVerdict;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RlmArtifactPaths } from "./types";
|
|
2
|
-
export declare const RLM_DIR_SEGMENT
|
|
2
|
+
export declare const RLM_DIR_SEGMENT = "rlm";
|
|
3
3
|
export declare function isValidRlmSessionId(sessionId: string): boolean;
|
|
4
4
|
/** Generate a filesystem-safe, sortable session id (timestamp + random suffix). */
|
|
5
5
|
export declare function generateRlmSessionId(now?: Date): string;
|
|
@@ -31,5 +31,17 @@ export declare function buildRlmGoalObjective(input: {
|
|
|
31
31
|
}): string;
|
|
32
32
|
export declare function isRlmAutonomousRun(parsed: Pick<Args, "print" | "mode" | "messages">, pipedStdin: boolean): boolean;
|
|
33
33
|
export declare function prepareRlmLaunchMode(parsed: Args, pipedStdin: boolean): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* RLM artifacts are scoped under a GJC session directory and resolving their
|
|
36
|
+
* paths is a *write* (it must pick a concrete session). When `gjc rlm` runs
|
|
37
|
+
* standalone — no parent agent, no `GJC_SESSION_ID` in the environment — there is
|
|
38
|
+
* no session to resolve and `resolveGjcSessionForWrite` throws
|
|
39
|
+
* `missing_for_write`. Establish a dedicated GJC session id in that case and pin
|
|
40
|
+
* it into the environment so artifact-path resolution, the per-session activity
|
|
41
|
+
* marker, and the child agent's workflow state all share one writable session.
|
|
42
|
+
*
|
|
43
|
+
* Returns the resolved (existing or freshly generated) GJC session id.
|
|
44
|
+
*/
|
|
45
|
+
export declare function ensureRlmGjcSessionId(): string;
|
|
34
46
|
export declare function runRlmCommand(argv: string[]): Promise<void>;
|
|
35
47
|
export {};
|
|
@@ -28,6 +28,32 @@ export declare function addMCPServer(filePath: string, name: string, config: MCP
|
|
|
28
28
|
* @throws Error if validation fails
|
|
29
29
|
*/
|
|
30
30
|
export declare function updateMCPServer(filePath: string, name: string, config: MCPServerConfig): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Result of an {@link upsertMCPServer} call.
|
|
33
|
+
* - `added`: server did not exist and was written.
|
|
34
|
+
* - `updated`: server existed and was overwritten because `force` was set.
|
|
35
|
+
* - `skipped`: server existed and `force` was not set, so nothing was written.
|
|
36
|
+
*/
|
|
37
|
+
export type UpsertMCPServerResult = {
|
|
38
|
+
status: "added";
|
|
39
|
+
} | {
|
|
40
|
+
status: "updated";
|
|
41
|
+
} | {
|
|
42
|
+
status: "skipped";
|
|
43
|
+
reason: "exists";
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Add an MCP server, or overwrite an existing one only when `force` is set.
|
|
47
|
+
*
|
|
48
|
+
* Collision-aware wrapper over {@link addMCPServer} / {@link updateMCPServer} used by
|
|
49
|
+
* `gjc migrate`. Never connects to the server. Reuses the underlying writers so the
|
|
50
|
+
* rest of the config file (including `disabledServers`) is preserved on update.
|
|
51
|
+
*
|
|
52
|
+
* @throws Error if the server name or config is invalid (validated before any write).
|
|
53
|
+
*/
|
|
54
|
+
export declare function upsertMCPServer(filePath: string, name: string, config: MCPServerConfig, options?: {
|
|
55
|
+
force?: boolean;
|
|
56
|
+
}): Promise<UpsertMCPServerResult>;
|
|
31
57
|
/**
|
|
32
58
|
* Remove an MCP server from a config file.
|
|
33
59
|
*
|