@nettee/beacon 0.3.6 → 0.4.1

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.
Files changed (115) hide show
  1. package/README.md +16 -1
  2. package/dist/cli-app.d.ts +31 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +11 -8
  5. package/dist/daemon/config/channels.d.ts +11 -0
  6. package/dist/daemon/config/event-credentials.d.ts +6 -0
  7. package/dist/daemon/config/global.d.ts +40 -0
  8. package/dist/daemon/config/profile.d.ts +38 -0
  9. package/dist/daemon/config/registry.d.ts +3 -0
  10. package/dist/daemon/config/runtime-environment.d.ts +2 -0
  11. package/dist/daemon/config/secrets.d.ts +5 -0
  12. package/dist/daemon/config/yaml.d.ts +1 -0
  13. package/dist/daemon/dashboard/export.d.ts +11 -0
  14. package/dist/daemon/dashboard/profiles.d.ts +5 -0
  15. package/dist/daemon/dashboard/records.d.ts +25 -0
  16. package/dist/daemon/dashboard/server.d.ts +15 -0
  17. package/dist/daemon/dashboard/session-prompt.d.ts +4 -0
  18. package/dist/daemon/dashboard/static.d.ts +2 -0
  19. package/dist/daemon/doctor.d.ts +1 -0
  20. package/dist/daemon/domain/types.d.ts +137 -0
  21. package/dist/daemon/events/cloudevent.d.ts +25 -0
  22. package/dist/daemon/events/pipeline.d.ts +35 -0
  23. package/dist/daemon/events/server.d.ts +15 -0
  24. package/dist/daemon/events/store.d.ts +58 -0
  25. package/dist/daemon/feishu/doctor.d.ts +2 -0
  26. package/dist/daemon/feishu/final-outcome-card.d.ts +20 -0
  27. package/dist/daemon/feishu/gateway.d.ts +46 -0
  28. package/dist/daemon/feishu/intake.d.ts +37 -0
  29. package/dist/daemon/feishu/mentions.d.ts +37 -0
  30. package/dist/daemon/feishu/message-gateway.d.ts +4 -0
  31. package/dist/daemon/feishu/message-pipeline.d.ts +13 -0
  32. package/dist/daemon/feishu/reply-experiment.d.ts +3 -0
  33. package/dist/daemon/feishu/trigger-input.d.ts +36 -0
  34. package/dist/daemon/index.d.ts +6 -0
  35. package/dist/daemon/index.js +5 -0
  36. package/dist/daemon/manual-trigger.d.ts +2 -0
  37. package/dist/{manual-trigger.js → daemon/manual-trigger.js} +2 -1
  38. package/dist/daemon/message/gateway.d.ts +9 -0
  39. package/dist/daemon/outcome/content.d.ts +68 -0
  40. package/dist/daemon/outcome/doctor.d.ts +2 -0
  41. package/dist/{outcome → daemon/outcome}/doctor.js +2 -3
  42. package/dist/daemon/outcome/instructions.d.ts +3 -0
  43. package/dist/daemon/outcome/server.d.ts +20 -0
  44. package/dist/daemon/outcome/submit.d.ts +5 -0
  45. package/dist/daemon/run/create-pi-orchestrator.d.ts +17 -0
  46. package/dist/{run → daemon/run}/create-pi-orchestrator.js +1 -2
  47. package/dist/daemon/run/orchestrator.d.ts +61 -0
  48. package/dist/daemon/run/profile-runner.d.ts +9 -0
  49. package/dist/daemon/run/queue.d.ts +20 -0
  50. package/dist/daemon/runtime/pi-doctor.d.ts +1 -0
  51. package/dist/daemon/runtime/pi-outcome-extension.d.ts +43 -0
  52. package/dist/daemon/runtime/pi-rpc.d.ts +56 -0
  53. package/dist/{runtime → daemon/runtime}/pi-rpc.js +92 -25
  54. package/dist/daemon/runtime/system-prompt.d.ts +10 -0
  55. package/dist/daemon/runtime-options.d.ts +4 -0
  56. package/dist/daemon/runtime-options.js +1 -0
  57. package/dist/daemon/schedule/cron.d.ts +2 -0
  58. package/dist/daemon/schedule/cursor-store.d.ts +18 -0
  59. package/dist/daemon/schedule/loop.d.ts +17 -0
  60. package/dist/daemon/schedule/reconciler.d.ts +16 -0
  61. package/dist/daemon/schedule-trigger.d.ts +18 -0
  62. package/dist/{schedule-trigger.js → daemon/schedule-trigger.js} +2 -1
  63. package/dist/daemon/service.d.ts +4 -0
  64. package/dist/{service.js → daemon/service.js} +3 -1
  65. package/dist/daemon/state/trigger-store.d.ts +30 -0
  66. package/dist/version.d.ts +1 -0
  67. package/package.json +13 -25
  68. /package/dist/{config → daemon/config}/channels.js +0 -0
  69. /package/dist/{config → daemon/config}/event-credentials.js +0 -0
  70. /package/dist/{config → daemon/config}/global.js +0 -0
  71. /package/dist/{config → daemon/config}/profile.js +0 -0
  72. /package/dist/{config → daemon/config}/registry.js +0 -0
  73. /package/dist/{config → daemon/config}/runtime-environment.js +0 -0
  74. /package/dist/{config → daemon/config}/secrets.js +0 -0
  75. /package/dist/{config → daemon/config}/yaml.js +0 -0
  76. /package/dist/{dashboard → daemon/dashboard}/export.js +0 -0
  77. /package/dist/{dashboard → daemon/dashboard}/profiles.js +0 -0
  78. /package/dist/{dashboard → daemon/dashboard}/records.js +0 -0
  79. /package/dist/{dashboard → daemon/dashboard}/server.js +0 -0
  80. /package/dist/{dashboard → daemon/dashboard}/session-prompt.js +0 -0
  81. /package/dist/{dashboard → daemon/dashboard}/static.js +0 -0
  82. /package/dist/{doctor.js → daemon/doctor.js} +0 -0
  83. /package/dist/{domain → daemon/domain}/types.js +0 -0
  84. /package/dist/{events → daemon/events}/cloudevent.js +0 -0
  85. /package/dist/{events → daemon/events}/pipeline.js +0 -0
  86. /package/dist/{events → daemon/events}/server.js +0 -0
  87. /package/dist/{events → daemon/events}/store.js +0 -0
  88. /package/dist/{feishu → daemon/feishu}/doctor.js +0 -0
  89. /package/dist/{feishu → daemon/feishu}/final-outcome-card.js +0 -0
  90. /package/dist/{feishu → daemon/feishu}/gateway.js +0 -0
  91. /package/dist/{feishu → daemon/feishu}/intake.js +0 -0
  92. /package/dist/{feishu → daemon/feishu}/mentions.js +0 -0
  93. /package/dist/{feishu → daemon/feishu}/message-gateway.js +0 -0
  94. /package/dist/{feishu → daemon/feishu}/message-pipeline.js +0 -0
  95. /package/dist/{feishu → daemon/feishu}/reply-experiment.js +0 -0
  96. /package/dist/{feishu → daemon/feishu}/trigger-input.js +0 -0
  97. /package/dist/{message → daemon/message}/gateway.js +0 -0
  98. /package/dist/{outcome → daemon/outcome}/content.js +0 -0
  99. /package/dist/{outcome → daemon/outcome}/instructions.js +0 -0
  100. /package/dist/{outcome → daemon/outcome}/server.js +0 -0
  101. /package/dist/{outcome → daemon/outcome}/submit.js +0 -0
  102. /package/dist/{run → daemon/run}/orchestrator.js +0 -0
  103. /package/dist/{run → daemon/run}/profile-runner.js +0 -0
  104. /package/dist/{run → daemon/run}/queue.js +0 -0
  105. /package/dist/{runtime → daemon/runtime}/pi-doctor.js +0 -0
  106. /package/dist/{runtime → daemon/runtime}/pi-outcome-extension.js +0 -0
  107. /package/dist/{runtime → daemon/runtime}/system-prompt.js +0 -0
  108. /package/dist/{schedule → daemon/schedule}/cron.js +0 -0
  109. /package/dist/{schedule → daemon/schedule}/cursor-store.js +0 -0
  110. /package/dist/{schedule → daemon/schedule}/loop.js +0 -0
  111. /package/dist/{schedule → daemon/schedule}/reconciler.js +0 -0
  112. /package/dist/{state → daemon/state}/trigger-store.js +0 -0
  113. /package/dist/{dashboard/ui → web}/assets/index-BP5xd2Iv.js +0 -0
  114. /package/dist/{dashboard/ui → web}/assets/index-D3C6sw_J.css +0 -0
  115. /package/dist/{dashboard/ui → web}/index.html +0 -0
package/README.md CHANGED
@@ -514,7 +514,7 @@ pnpm bump-version patch
514
514
  ```
515
515
 
516
516
  For an in-repository pull request that changes production CLI inputs under
517
- `src/`, `package.json`, `pnpm-lock.yaml`, or `tsconfig.json` without changing
517
+ `apps/`, `services/`, `packages/`, or workspace build configuration without changing
518
518
  the package version, CI automatically commits a patch bump to the PR branch.
519
519
  Test-only and documentation changes do not trigger a release. An explicit
520
520
  version change takes precedence over the automatic patch bump, and CI rejects
@@ -551,3 +551,18 @@ a package to exist before Trusted Publishing can be configured. After the
551
551
  The repository variable deliberately keeps publishing disabled during the
552
552
  bootstrap merge. Subsequent versions publish from GitHub Actions with OIDC and
553
553
  do not use a long-lived npm write token.
554
+
555
+ ## Workspace layout
556
+
557
+ Beacon is a pnpm monorepo:
558
+
559
+ - `apps/cli`: the published `@nettee/beacon` command-line package and its version.
560
+ - `apps/web`: the React/Vite web application.
561
+ - `services/daemon`: scheduling, triggers, Agent execution, storage, and HTTP endpoints.
562
+ - `packages/shared`: browser-safe HTTP response contracts shared by daemon and web.
563
+
564
+ Run `pnpm install`, `pnpm build`, `pnpm typecheck`, and `pnpm test` from the repository root. The workspace builds dependencies before consumers. Run the built CLI with `node apps/cli/dist/cli.js serve`; it defaults to `~/.beacon/config.yaml`. For web development, run `pnpm --filter @nettee/beacon-web dev` alongside the daemon; Vite proxies API and run-export requests to port 46183.
565
+
566
+ The daemon and web are separate workspace packages, but the published CLI remains a single installable product. Its build assembles the daemon modules and web assets inside `apps/cli/dist`; external daemon runtime dependencies remain regular CLI dependencies and are checked for consistency during assembly. Internal packages are private and do not require separate registry releases. Run `pnpm build` before `npm pack ./apps/cli` or publishing from `apps/cli`. `pnpm test:package` checks an isolated installation.
567
+
568
+ `pnpm bump-version minor` updates `apps/cli/package.json`. Package separation preserves existing runtime behavior: `serve` starts the daemon and serves web assets in one process, and manual triggers still execute locally.
@@ -0,0 +1,31 @@
1
+ export declare const defaultConfigPath: string;
2
+ export type CliCommand = {
3
+ command: "serve";
4
+ config: string;
5
+ } | {
6
+ command: "doctor";
7
+ config: string;
8
+ } | {
9
+ command: "trigger";
10
+ config: string;
11
+ profile: string;
12
+ } | {
13
+ command: "schedule-trigger";
14
+ config: string;
15
+ profile: string;
16
+ schedule: string;
17
+ } | {
18
+ command: "version";
19
+ } | {
20
+ command: "outcome-submit";
21
+ };
22
+ export declare function parseCli(args: string[]): CliCommand;
23
+ export type CliDependencies = {
24
+ serve(config: string): Promise<void>;
25
+ doctor(config: string): Promise<void>;
26
+ trigger(config: string, profile: string, input: string): Promise<void>;
27
+ triggerSchedule(config: string, profile: string, schedule: string): Promise<void>;
28
+ submitOutcome(): Promise<void>;
29
+ version: string;
30
+ };
31
+ export declare function runCli(command: CliCommand, dependencies: CliDependencies): Promise<void>;
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js CHANGED
@@ -1,17 +1,20 @@
1
1
  #!/usr/bin/env node
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { runBeacon, runDoctor, runManualTrigger, runScheduleTrigger, submitOutcomeFromCli, } from "./daemon/index.js";
2
5
  import { parseCli, runCli } from "./cli-app.js";
3
- import { runDoctor } from "./doctor.js";
4
- import { runManualTrigger } from "./manual-trigger.js";
5
- import { submitOutcomeFromCli } from "./outcome/submit.js";
6
- import { runScheduleTrigger } from "./schedule-trigger.js";
7
- import { runBeacon } from "./service.js";
8
6
  import { packageVersion } from "./version.js";
7
+ const beaconCliPath = fileURLToPath(import.meta.url);
8
+ const runtime = { beaconCliPath };
9
9
  async function main() {
10
10
  await runCli(parseCli(process.argv.slice(2)), {
11
- serve: runBeacon,
11
+ serve: (config) => runBeacon(config, {
12
+ ...runtime,
13
+ uiDirectory: join(dirname(beaconCliPath), "web"),
14
+ }),
12
15
  doctor: runDoctor,
13
- trigger: runManualTrigger,
14
- triggerSchedule: runScheduleTrigger,
16
+ trigger: (config, profile, input) => runManualTrigger(config, profile, input, runtime),
17
+ triggerSchedule: (config, profile, schedule) => runScheduleTrigger(config, profile, schedule, runtime),
15
18
  submitOutcome: submitOutcomeFromCli,
16
19
  version: packageVersion,
17
20
  });
@@ -0,0 +1,11 @@
1
+ export declare const channelNamePattern: RegExp;
2
+ export type Channel = {
3
+ name: string;
4
+ description: string;
5
+ chatId: string;
6
+ };
7
+ export type ChannelRegistry = ReadonlyMap<string, Channel>;
8
+ export declare function defaultChannelsPath(homeDirectory?: string): string;
9
+ export declare function emptyChannelRegistry(): ChannelRegistry;
10
+ export declare function loadChannelRegistry(path: string): Promise<ChannelRegistry>;
11
+ export declare function resolveChannelName(name: string, channels: ChannelRegistry, channelsPath: string): Channel;
@@ -0,0 +1,6 @@
1
+ export type EventProducer = {
2
+ id: string;
3
+ token: string;
4
+ sources: string[];
5
+ };
6
+ export declare function loadEventCredentials(path: string): Promise<EventProducer[]>;
@@ -0,0 +1,40 @@
1
+ export type GlobalConfig = {
2
+ path: string;
3
+ homeDirectory: string;
4
+ profilesDirectory: string;
5
+ secretsPath: string;
6
+ channelsPath: string;
7
+ runtimeEnvironmentPath: string;
8
+ pi: {
9
+ executable: string;
10
+ codingAgentDirectory: string;
11
+ sessionDirectory: string;
12
+ };
13
+ runs: {
14
+ maxConcurrent: number;
15
+ maxQueued: number;
16
+ timeoutSeconds: number;
17
+ terminateGraceSeconds: number;
18
+ };
19
+ scheduler: {
20
+ maxOccurrencesPerReconciliation: number;
21
+ };
22
+ events?: {
23
+ listen: string;
24
+ port: number;
25
+ maxBodyBytes: number;
26
+ maxPending: number;
27
+ credentialsPath: string;
28
+ };
29
+ dashboard: {
30
+ enabled: boolean;
31
+ listen: string;
32
+ port: number;
33
+ };
34
+ };
35
+ export declare const defaultDashboard: {
36
+ readonly enabled: true;
37
+ readonly listen: "0.0.0.0";
38
+ readonly port: 46183;
39
+ };
40
+ export declare function loadGlobalConfig(path: string): Promise<GlobalConfig>;
@@ -0,0 +1,38 @@
1
+ import { type EventListener } from "../events/cloudevent.js";
2
+ import { type ChannelRegistry } from "./channels.js";
3
+ export declare const profilePersonaFile = "persona.md";
4
+ export declare const profileTaskFile = "task.md";
5
+ export declare const workspaceProfileDirectoryName = ".beacon-profile";
6
+ export type DeliveryDestination = {
7
+ chatId: string;
8
+ name?: string | undefined;
9
+ description?: string | undefined;
10
+ };
11
+ export type Profile = {
12
+ id: string;
13
+ directory: string;
14
+ persona: string;
15
+ task: string;
16
+ workspace: string;
17
+ runtime: "pi";
18
+ model: {
19
+ provider: string;
20
+ id: string;
21
+ };
22
+ admin?: DeliveryDestination | undefined;
23
+ listener?: EventListener | undefined;
24
+ schedules: Array<{
25
+ id: string;
26
+ cron: string;
27
+ timezone: string;
28
+ input: string;
29
+ notify?: DeliveryDestination | undefined;
30
+ }>;
31
+ };
32
+ export type LoadProfileOptions = {
33
+ channels?: ChannelRegistry;
34
+ channelsPath?: string;
35
+ };
36
+ export declare function workspaceProfileDirectory(workspace: string): string;
37
+ export declare function loadProfile(profileId: string, profilesDirectory?: string, options?: LoadProfileOptions): Promise<Profile>;
38
+ export declare function profileAdminChatId(profile: Profile): string;
@@ -0,0 +1,3 @@
1
+ import type { ChannelRegistry } from "./channels.js";
2
+ import { type Profile } from "./profile.js";
3
+ export declare function loadProfileRegistry(profilesDirectory: string, channels?: ChannelRegistry, channelsPath?: string): Promise<Profile[]>;
@@ -0,0 +1,2 @@
1
+ export declare function assertRuntimeEnvironmentKey(key: string): void;
2
+ export declare function loadRuntimeEnvironment(path: string): Promise<NodeJS.ProcessEnv>;
@@ -0,0 +1,5 @@
1
+ export type FeishuCredentials = {
2
+ appId: string;
3
+ appSecret: string;
4
+ };
5
+ export declare function loadFeishuCredentials(profileId: string, path?: string): Promise<FeishuCredentials>;
@@ -0,0 +1 @@
1
+ export declare function parseStrictYaml(path: string): Promise<unknown>;
@@ -0,0 +1,11 @@
1
+ export type SessionExportRequest = {
2
+ executable: string;
3
+ sessionDirectory: string;
4
+ runId: string;
5
+ sessionPath: string;
6
+ /** Beacon `--system-prompt` text for this Run, used when JSONL has no system line. */
7
+ systemPrompt?: string | undefined;
8
+ timeoutMs?: number | undefined;
9
+ };
10
+ export declare function resolveSessionJsonl(sessionDirectory: string, runId: string, sessionPath: string): Promise<string>;
11
+ export declare function exportSessionHtml(request: SessionExportRequest): Promise<string>;
@@ -0,0 +1,5 @@
1
+ import type { ProfileDetailView, ProfileListItem } from "@nettee/beacon-shared";
2
+ export type { ProfileDetailView, ProfileListenerView, ProfileListItem, ProfileNotifyView, ProfileScheduleView, } from "@nettee/beacon-shared";
3
+ export declare function isProfileId(value: string): boolean;
4
+ export declare function listProfileViews(profilesDirectory: string): Promise<ProfileListItem[]>;
5
+ export declare function getProfileDetailView(profilesDirectory: string, profileId: string): Promise<ProfileDetailView | null>;
@@ -0,0 +1,25 @@
1
+ import type { RunRow } from "@nettee/beacon-shared";
2
+ import type { FeedbackRecord } from "../domain/types.js";
3
+ export declare const runIdPattern: RegExp;
4
+ export type RunSummary = {
5
+ profileId: string;
6
+ triggerKey: string;
7
+ acceptedAt: string;
8
+ kind: string;
9
+ scheduleId: string | undefined;
10
+ eventSource?: string | undefined;
11
+ eventType?: string | undefined;
12
+ hasNotifyTarget: boolean;
13
+ runId: string | undefined;
14
+ state: string | undefined;
15
+ failureCode: string | undefined;
16
+ deliveryState: string | undefined;
17
+ sessionPath: string | undefined;
18
+ hasSessionFile: boolean;
19
+ systemPrompt: string | undefined;
20
+ feedback: FeedbackRecord | undefined;
21
+ };
22
+ export declare function listRunSummaries(profilesDirectory: string): Promise<RunSummary[]>;
23
+ export declare function kindLabel(row: Pick<RunSummary, "kind" | "scheduleId" | "eventSource" | "eventType">): string;
24
+ export declare function toRunListItem(row: RunSummary): RunRow;
25
+ export declare function findRunSummary(profilesDirectory: string, runId: string): Promise<RunSummary | undefined>;
@@ -0,0 +1,15 @@
1
+ export type DashboardOptions = {
2
+ listen: string;
3
+ port: number;
4
+ profilesDirectory: string;
5
+ sessionDirectory: string;
6
+ piExecutable: string;
7
+ exportTimeoutMs?: number | undefined;
8
+ uiDirectory?: string | undefined;
9
+ };
10
+ export type DashboardServer = {
11
+ port: number;
12
+ close(): Promise<void>;
13
+ };
14
+ export declare function defaultUiDirectory(): string;
15
+ export declare function startDashboard(options: DashboardOptions): Promise<DashboardServer>;
@@ -0,0 +1,4 @@
1
+ /** Prefer a JSONL system message; otherwise the Beacon-owned `--system-prompt` text. */
2
+ export declare function pickExportedSystemPrompt(jsonl: string, beaconOwned?: string | undefined): string | undefined;
3
+ export declare function systemPromptFromJsonl(jsonl: string): string | undefined;
4
+ export declare function fillExportedHtmlSystemPrompt(html: string, systemPrompt: string): string;
@@ -0,0 +1,2 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ export declare function sendStaticFile(_request: IncomingMessage, response: ServerResponse, root: string, urlPath: string): Promise<boolean>;
@@ -0,0 +1 @@
1
+ export declare function runDoctor(configPath: string): Promise<void>;
@@ -0,0 +1,137 @@
1
+ import type { CloudEvent } from "../events/cloudevent.js";
2
+ export type ReplyDeliveryTarget = {
3
+ kind: "reply";
4
+ messageId: string;
5
+ };
6
+ export type ChatDeliveryTarget = {
7
+ kind: "chat";
8
+ chatId: string;
9
+ };
10
+ export type LocalStdoutDeliveryTarget = {
11
+ kind: "local_stdout";
12
+ };
13
+ export type DeliveryTarget = ReplyDeliveryTarget | ChatDeliveryTarget | LocalStdoutDeliveryTarget;
14
+ export type MessageSnapshot = {
15
+ messageId: string;
16
+ messageType: string;
17
+ senderType: string;
18
+ senderId?: string | undefined;
19
+ content: unknown;
20
+ };
21
+ export type FeishuMessageInput = {
22
+ kind: "feishu_message";
23
+ eventId: string;
24
+ chatType: "p2p" | "group";
25
+ quotedMessages: MessageSnapshot[];
26
+ currentMessage: MessageSnapshot;
27
+ };
28
+ export type ScheduleInput = {
29
+ kind: "schedule";
30
+ scheduleId: string;
31
+ scheduledFor: string;
32
+ text: string;
33
+ };
34
+ export type ManualInput = {
35
+ kind: "manual";
36
+ text: string;
37
+ };
38
+ export type EventInput = {
39
+ kind: "event";
40
+ event: CloudEvent;
41
+ };
42
+ export type TriggerInput = FeishuMessageInput | ScheduleInput | ManualInput | EventInput;
43
+ export declare const failureCodes: readonly ["config_invalid", "secret_invalid", "gateway_terminal", "trigger_persist_failed", "trigger_normalization_failed", "schedule_state_invalid", "capacity_exceeded", "runtime_spawn_failed", "runtime_protocol_error", "runtime_timeout", "runtime_exit_failed", "outcome_missing", "outcome_invalid", "service_interrupted", "delivery_api_failed", "delivery_interrupted"];
44
+ export type FailureCode = (typeof failureCodes)[number];
45
+ export type RunState = "queued" | "starting" | "running" | "succeeded" | "failed";
46
+ export type DeliveryState = "pending" | "delivering" | "delivered" | "failed";
47
+ export type Failure = {
48
+ code: FailureCode;
49
+ summary: string;
50
+ };
51
+ export type TextReplyContent = {
52
+ kind: "text";
53
+ text: string;
54
+ };
55
+ export type NoReplyContent = {
56
+ kind: "no_reply";
57
+ reason: string;
58
+ };
59
+ export type CardContent = {
60
+ kind: "card";
61
+ title: string;
62
+ content: string;
63
+ buttons: Array<{
64
+ label: string;
65
+ url: string;
66
+ }>;
67
+ };
68
+ /** Text, silent, or a `reply_card` interactive message on the conversational channel. */
69
+ export type ReplyContent = TextReplyContent | NoReplyContent | CardContent;
70
+ export type FinalOutcomeContent = {
71
+ reply: ReplyContent;
72
+ notify?: CardContent | undefined;
73
+ };
74
+ export declare const feedbackPriorities: readonly ["high", "medium"];
75
+ export type FeedbackPriority = (typeof feedbackPriorities)[number];
76
+ export type FeedbackItem = {
77
+ priority: FeedbackPriority;
78
+ summary: string;
79
+ };
80
+ export type FeedbackContent = {
81
+ items: FeedbackItem[];
82
+ };
83
+ export type FeedbackRecord = {
84
+ items: FeedbackItem[];
85
+ submittedAt: string;
86
+ };
87
+ export type DeliveryContent = TextReplyContent | CardContent;
88
+ export type RunRecord = {
89
+ runId: string;
90
+ /** Pi session ID. Absent only on records written before session persistence. */
91
+ sessionId?: string | undefined;
92
+ /** Dedicated directory containing this Run's Pi session JSONL file. */
93
+ sessionPath?: string | undefined;
94
+ state: RunState;
95
+ queuedAt: string;
96
+ startedAt?: string | undefined;
97
+ finishedAt?: string | undefined;
98
+ provider: string;
99
+ model: string;
100
+ workspace: string;
101
+ promptDigest: string;
102
+ /** Full `--system-prompt` text sent to Pi. Absent on records written before this field. */
103
+ systemPrompt?: string | undefined;
104
+ failure?: Failure | undefined;
105
+ };
106
+ export type FinalOutcomeRecord = {
107
+ origin: "agent" | "beacon_failure";
108
+ content: FinalOutcomeContent;
109
+ submittedAt: string;
110
+ };
111
+ export type DeliveryRecord = {
112
+ deliveryId: string;
113
+ target: DeliveryTarget;
114
+ state: DeliveryState;
115
+ startedAt?: string | undefined;
116
+ finishedAt?: string | undefined;
117
+ providerRequestId?: string | undefined;
118
+ failure?: Failure | undefined;
119
+ };
120
+ export type TriggerRecord = {
121
+ version: 1;
122
+ triggerKey: string;
123
+ triggerId: string;
124
+ profileId: string;
125
+ sourceKey: string[];
126
+ acceptedAt: string;
127
+ target: DeliveryTarget;
128
+ notifyTarget?: DeliveryTarget | undefined;
129
+ input?: TriggerInput | undefined;
130
+ ingress?: Record<string, unknown> | undefined;
131
+ run?: RunRecord | undefined;
132
+ finalOutcome?: FinalOutcomeRecord | undefined;
133
+ /** Present only when the Agent called `submit_feedback`. */
134
+ feedback?: FeedbackRecord | undefined;
135
+ delivery?: DeliveryRecord | undefined;
136
+ notifyDelivery?: DeliveryRecord | undefined;
137
+ };
@@ -0,0 +1,25 @@
1
+ import { z } from "zod";
2
+ export declare const eventSourceSchema: z.ZodString;
3
+ export type EventListener = {
4
+ sources: string[];
5
+ types: string[];
6
+ notify?: {
7
+ chatId: string;
8
+ name?: string | undefined;
9
+ description?: string | undefined;
10
+ } | undefined;
11
+ };
12
+ export declare const cloudEventSchema: z.ZodObject<{
13
+ specversion: z.ZodLiteral<"1.0">;
14
+ id: z.ZodString;
15
+ source: z.ZodString;
16
+ type: z.ZodString;
17
+ subject: z.ZodOptional<z.ZodString>;
18
+ time: z.ZodOptional<z.ZodISODateTime>;
19
+ dataschema: z.ZodOptional<z.ZodString>;
20
+ datacontenttype: z.ZodOptional<z.ZodString>;
21
+ data: z.ZodOptional<z.ZodJSONSchema>;
22
+ }, z.core.$catchall<z.ZodUnion<readonly [z.ZodString, z.ZodBoolean, z.ZodNumber]>>>;
23
+ export type CloudEvent = z.infer<typeof cloudEventSchema>;
24
+ export declare function parseCloudEvent(input: unknown): CloudEvent;
25
+ export declare function matchesListener(event: CloudEvent, listener: EventListener): boolean;
@@ -0,0 +1,35 @@
1
+ import type { EventProducer } from "../config/event-credentials.js";
2
+ import type { Profile } from "../config/profile.js";
3
+ import type { TriggerInput } from "../domain/types.js";
4
+ import type { TriggerStore } from "../state/trigger-store.js";
5
+ import { type CloudEvent } from "./cloudevent.js";
6
+ import { type EventRecord, type EventStore } from "./store.js";
7
+ export type EventContext = {
8
+ profile: Profile;
9
+ store: TriggerStore;
10
+ orchestrator: {
11
+ process(key: string, normalize: () => Promise<TriggerInput>): Promise<void>;
12
+ };
13
+ };
14
+ export declare class EventPipeline {
15
+ private readonly options;
16
+ private work;
17
+ private requested;
18
+ private stopped;
19
+ private failure;
20
+ constructor(options: {
21
+ store: EventStore;
22
+ contexts: EventContext[];
23
+ maxPending: number;
24
+ onFatal(error: Error): void;
25
+ });
26
+ accept(event: CloudEvent, producer: EventProducer): Promise<{
27
+ created: boolean;
28
+ record: EventRecord;
29
+ }>;
30
+ /** Call after Profile orchestrator recovery and after the HTTP listener binds. */
31
+ wake(): void;
32
+ private pump;
33
+ close(): Promise<void>;
34
+ drain(): Promise<void>;
35
+ }
@@ -0,0 +1,15 @@
1
+ import type { EventProducer } from "../config/event-credentials.js";
2
+ import type { EventPipeline } from "./pipeline.js";
3
+ import { type EventStore } from "./store.js";
4
+ export declare function startEventServer(options: {
5
+ listen: string;
6
+ port: number;
7
+ maxBodyBytes: number;
8
+ producers: EventProducer[];
9
+ pipeline: EventPipeline;
10
+ store: EventStore;
11
+ onFatal(error: Error): void;
12
+ }): Promise<{
13
+ port: number;
14
+ close(): Promise<void>;
15
+ }>;
@@ -0,0 +1,58 @@
1
+ import { z } from "zod";
2
+ import { type CloudEvent } from "./cloudevent.js";
3
+ declare const recipientSchema: z.ZodObject<{
4
+ profileId: z.ZodString;
5
+ chatId: z.ZodString;
6
+ notifyChatId: z.ZodOptional<z.ZodString>;
7
+ triggerId: z.ZodOptional<z.ZodString>;
8
+ }, z.core.$strict>;
9
+ declare const recordSchema: z.ZodObject<{
10
+ version: z.ZodLiteral<1>;
11
+ receiptId: z.ZodString;
12
+ producerId: z.ZodString;
13
+ acceptedAt: z.ZodString;
14
+ event: z.ZodObject<{
15
+ specversion: z.ZodLiteral<"1.0">;
16
+ id: z.ZodString;
17
+ source: z.ZodString;
18
+ type: z.ZodString;
19
+ subject: z.ZodOptional<z.ZodString>;
20
+ time: z.ZodOptional<z.ZodISODateTime>;
21
+ dataschema: z.ZodOptional<z.ZodString>;
22
+ datacontenttype: z.ZodOptional<z.ZodString>;
23
+ data: z.ZodOptional<z.ZodJSONSchema>;
24
+ }, z.core.$catchall<z.ZodUnion<readonly [z.ZodString, z.ZodBoolean, z.ZodNumber]>>>;
25
+ recipients: z.ZodArray<z.ZodObject<{
26
+ profileId: z.ZodString;
27
+ chatId: z.ZodString;
28
+ notifyChatId: z.ZodOptional<z.ZodString>;
29
+ triggerId: z.ZodOptional<z.ZodString>;
30
+ }, z.core.$strict>>;
31
+ }, z.core.$strict>;
32
+ export type EventRecipient = z.infer<typeof recipientSchema>;
33
+ export type EventRecord = z.infer<typeof recordSchema>;
34
+ export declare class EventIntakeError extends Error {
35
+ readonly status: number;
36
+ constructor(status: number, message: string);
37
+ }
38
+ export declare function eventStatus(record: EventRecord): "unmatched" | "pending" | "dispatched";
39
+ /** Single service owner; serialized read/modify/write, atomic durable snapshots. */
40
+ export declare class EventStore {
41
+ readonly directory: string;
42
+ private tail;
43
+ constructor(directory: string);
44
+ private exclusive;
45
+ private prepare;
46
+ private path;
47
+ private read;
48
+ private records;
49
+ private write;
50
+ accept(event: CloudEvent, producerId: string, recipients: EventRecipient[], maxPending: number): Promise<{
51
+ created: boolean;
52
+ record: EventRecord;
53
+ }>;
54
+ get(id: string): Promise<EventRecord | undefined>;
55
+ pending(): Promise<EventRecord[]>;
56
+ markDispatched(id: string, profileId: string, triggerId: string): Promise<void>;
57
+ }
58
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { FeishuCredentials } from "../config/secrets.js";
2
+ export declare function runFeishuDoctor(credentials: FeishuCredentials): Promise<void>;
@@ -0,0 +1,20 @@
1
+ import type { CardContent } from "../domain/types.js";
2
+ type CardOutcome = CardContent;
3
+ export type FeishuFinalOutcomeCard = {
4
+ config: {
5
+ wide_screen_mode: true;
6
+ };
7
+ header: {
8
+ template: "blue";
9
+ title: {
10
+ tag: "plain_text";
11
+ content: string;
12
+ };
13
+ };
14
+ elements: object[];
15
+ };
16
+ export declare function buildFeishuFinalOutcomeCard(outcome: CardOutcome, options?: {
17
+ generatedAt?: Date;
18
+ timeZone?: string;
19
+ }): FeishuFinalOutcomeCard;
20
+ export {};
@@ -0,0 +1,46 @@
1
+ import type { FeishuCredentials } from "../config/secrets.js";
2
+ import type { DeliveryContent } from "../domain/types.js";
3
+ import type { DeliveryAdapter } from "../run/orchestrator.js";
4
+ import type { FeishuMessageEvent } from "./intake.js";
5
+ import type { FeishuMessageGateway } from "./message-gateway.js";
6
+ import type { FetchedMessage } from "./trigger-input.js";
7
+ type ApiResult = {
8
+ code?: number | undefined;
9
+ msg?: string | undefined;
10
+ request_id?: string | undefined;
11
+ };
12
+ type MessageSendResult = ApiResult & {
13
+ data?: {
14
+ message_id?: string | undefined;
15
+ } | undefined;
16
+ };
17
+ /** Prefer Feishu's outbound `message_id` so quote-replies can resume that Run's Pi session. */
18
+ export declare function providerRequestIdFromMessageSend(result: MessageSendResult): {
19
+ providerRequestId?: string | undefined;
20
+ };
21
+ type ShutdownSignalSource = {
22
+ once(event: "SIGINT" | "SIGTERM", listener: () => void): unknown;
23
+ off(event: "SIGINT" | "SIGTERM", listener: () => void): unknown;
24
+ };
25
+ export declare function waitForShutdown(signals?: ShutdownSignalSource): Promise<void>;
26
+ export declare function shouldAcceptFeishuMessage(chatType: string, senderType: string, messageId: string, processedMessageIds: ReadonlySet<string>): boolean;
27
+ export declare function encodeFeishuFinalOutcome(outcome: DeliveryContent): {
28
+ msgType: "text" | "interactive";
29
+ content: string;
30
+ };
31
+ export declare class FeishuGateway implements FeishuMessageGateway {
32
+ private readonly credentials;
33
+ private readonly client;
34
+ constructor(credentials: FeishuCredentials);
35
+ checkReady(): Promise<void>;
36
+ run(handleEvent: (event: FeishuMessageEvent) => Promise<unknown>, shutdown?: Promise<void>): Promise<void>;
37
+ acknowledge(messageId: string): Promise<{
38
+ clear: () => Promise<void>;
39
+ }>;
40
+ fetchMessage(messageId: string): Promise<FetchedMessage>;
41
+ deliver(target: Parameters<DeliveryAdapter["deliver"]>[0], outcome: Parameters<DeliveryAdapter["deliver"]>[1]): Promise<{
42
+ providerRequestId?: string | undefined;
43
+ }>;
44
+ }
45
+ export declare function createFeishuGateway(credentials: FeishuCredentials): FeishuGateway;
46
+ export {};