@krischoichoi/channel-core 0.0.0-stage → 0.6.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 (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +103 -2
  3. package/lib/access.d.ts +194 -0
  4. package/lib/access.d.ts.map +1 -0
  5. package/lib/access.js +122 -0
  6. package/lib/access.js.map +1 -0
  7. package/lib/account.d.ts +47 -0
  8. package/lib/account.d.ts.map +1 -0
  9. package/lib/account.js +20 -0
  10. package/lib/account.js.map +1 -0
  11. package/lib/adapter.d.ts +119 -0
  12. package/lib/adapter.d.ts.map +1 -0
  13. package/lib/adapter.js +6 -0
  14. package/lib/adapter.js.map +1 -0
  15. package/lib/capabilities.d.ts +124 -0
  16. package/lib/capabilities.d.ts.map +1 -0
  17. package/lib/capabilities.js +34 -0
  18. package/lib/capabilities.js.map +1 -0
  19. package/lib/context.d.ts +26 -0
  20. package/lib/context.d.ts.map +1 -0
  21. package/lib/context.js +2 -0
  22. package/lib/context.js.map +1 -0
  23. package/lib/define.d.ts +67 -0
  24. package/lib/define.d.ts.map +1 -0
  25. package/lib/define.js +36 -0
  26. package/lib/define.js.map +1 -0
  27. package/lib/errors.d.ts +43 -0
  28. package/lib/errors.d.ts.map +1 -0
  29. package/lib/errors.js +86 -0
  30. package/lib/errors.js.map +1 -0
  31. package/lib/events.d.ts +131 -0
  32. package/lib/events.d.ts.map +1 -0
  33. package/lib/events.js +2 -0
  34. package/lib/events.js.map +1 -0
  35. package/lib/file-secret-store.d.ts +14 -0
  36. package/lib/file-secret-store.d.ts.map +1 -0
  37. package/lib/file-secret-store.js +82 -0
  38. package/lib/file-secret-store.js.map +1 -0
  39. package/lib/file-storage.d.ts +14 -0
  40. package/lib/file-storage.d.ts.map +1 -0
  41. package/lib/file-storage.js +76 -0
  42. package/lib/file-storage.js.map +1 -0
  43. package/lib/health.d.ts +21 -0
  44. package/lib/health.d.ts.map +1 -0
  45. package/lib/health.js +6 -0
  46. package/lib/health.js.map +1 -0
  47. package/lib/index.d.ts +35 -0
  48. package/lib/index.d.ts.map +1 -0
  49. package/lib/index.js +35 -0
  50. package/lib/index.js.map +1 -0
  51. package/lib/media/bounded-response.d.ts +85 -0
  52. package/lib/media/bounded-response.d.ts.map +1 -0
  53. package/lib/media/bounded-response.js +192 -0
  54. package/lib/media/bounded-response.js.map +1 -0
  55. package/lib/media/hydration.d.ts +82 -0
  56. package/lib/media/hydration.d.ts.map +1 -0
  57. package/lib/media/hydration.js +94 -0
  58. package/lib/media/hydration.js.map +1 -0
  59. package/lib/media/index.d.ts +17 -0
  60. package/lib/media/index.d.ts.map +1 -0
  61. package/lib/media/index.js +17 -0
  62. package/lib/media/index.js.map +1 -0
  63. package/lib/media/mime-hint.d.ts +5 -0
  64. package/lib/media/mime-hint.d.ts.map +1 -0
  65. package/lib/media/mime-hint.js +29 -0
  66. package/lib/media/mime-hint.js.map +1 -0
  67. package/lib/media/remote-policy.d.ts +79 -0
  68. package/lib/media/remote-policy.d.ts.map +1 -0
  69. package/lib/media/remote-policy.js +230 -0
  70. package/lib/media/remote-policy.js.map +1 -0
  71. package/lib/media/secure-fetcher.d.ts +85 -0
  72. package/lib/media/secure-fetcher.d.ts.map +1 -0
  73. package/lib/media/secure-fetcher.js +143 -0
  74. package/lib/media/secure-fetcher.js.map +1 -0
  75. package/lib/messages.d.ts +187 -0
  76. package/lib/messages.d.ts.map +1 -0
  77. package/lib/messages.js +20 -0
  78. package/lib/messages.js.map +1 -0
  79. package/lib/mount.d.ts +51 -0
  80. package/lib/mount.d.ts.map +1 -0
  81. package/lib/mount.js +44 -0
  82. package/lib/mount.js.map +1 -0
  83. package/lib/paths.d.ts +4 -0
  84. package/lib/paths.d.ts.map +1 -0
  85. package/lib/paths.js +12 -0
  86. package/lib/paths.js.map +1 -0
  87. package/lib/plugin.d.ts +18 -0
  88. package/lib/plugin.d.ts.map +1 -0
  89. package/lib/plugin.js +36 -0
  90. package/lib/plugin.js.map +1 -0
  91. package/lib/registry.d.ts +11 -0
  92. package/lib/registry.d.ts.map +1 -0
  93. package/lib/registry.js +36 -0
  94. package/lib/registry.js.map +1 -0
  95. package/lib/reply.d.ts +37 -0
  96. package/lib/reply.d.ts.map +1 -0
  97. package/lib/reply.js +46 -0
  98. package/lib/reply.js.map +1 -0
  99. package/lib/runtime-resources.d.ts +19 -0
  100. package/lib/runtime-resources.d.ts.map +1 -0
  101. package/lib/runtime-resources.js +2 -0
  102. package/lib/runtime-resources.js.map +1 -0
  103. package/lib/schema.d.ts +124 -0
  104. package/lib/schema.d.ts.map +1 -0
  105. package/lib/schema.js +143 -0
  106. package/lib/schema.js.map +1 -0
  107. package/lib/secrets.d.ts +28 -0
  108. package/lib/secrets.d.ts.map +1 -0
  109. package/lib/secrets.js +28 -0
  110. package/lib/secrets.js.map +1 -0
  111. package/lib/service.d.ts +71 -0
  112. package/lib/service.d.ts.map +1 -0
  113. package/lib/service.js +97 -0
  114. package/lib/service.js.map +1 -0
  115. package/lib/storage.d.ts +18 -0
  116. package/lib/storage.d.ts.map +1 -0
  117. package/lib/storage.js +19 -0
  118. package/lib/storage.js.map +1 -0
  119. package/lib/volatile.d.ts +32 -0
  120. package/lib/volatile.d.ts.map +1 -0
  121. package/lib/volatile.js +46 -0
  122. package/lib/volatile.js.map +1 -0
  123. package/package.json +44 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wsz987
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,104 @@
1
- # Temporary Holding Version
1
+ # @krischoichoi/channel-core
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Stable cross-channel contract and Cordis `ChannelService` for DeepSeek Harness Channels.
4
+
5
+ `channel-core` is the foundation of the `dsh-channels` monorepo. It defines the
6
+ **Channel Contract** that every adapter implements, and the shared runtime
7
+ service mounted at `ctx.channels`. It never imports Harness Agent APIs and never
8
+ depends on a concrete messaging platform.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ pnpm add @krischoichoi/channel-core
14
+ ```
15
+
16
+ As a Cordis plugin:
17
+
18
+ ```yaml
19
+ - id: channels-service
20
+ name: '@krischoichoi/channel-core/plugin'
21
+ ```
22
+
23
+ ## What's inside
24
+
25
+ | Export | Purpose |
26
+ | --- | --- |
27
+ | `ChannelAdapter` / `defineChannelAdapter` | The adapter contract and the third-party authoring helper |
28
+ | `ChannelService` (`ctx.channels`) | Adapter registry, typed event bus, shared secrets/storage resources |
29
+ | `ChannelCapabilities` | Capability negotiation (`text`, `image`, `file`, `streaming`, …) |
30
+ | `ChannelTarget` / `OutboundMessage` / `SendResult` / `ReplyHandle` | Structured messaging types |
31
+ | `ChannelEvent` / `AuthChallenge` / `ChannelHealth` | Event, auth and health surfaces |
32
+ | `ChannelError` / `isChannelError` | Stable machine-readable error hierarchy |
33
+ | `mountChannelAdapter` | Transactional mount lifecycle (register → start → stop → unregister) |
34
+ | `ChannelRuntimeResources` | Durable secrets and storage shared by all mounted adapters |
35
+ | media helpers | `SecureRemoteMediaFetcher`, `RemotePolicy`, bounded response readers |
36
+
37
+ ## Quick start
38
+
39
+ ```ts
40
+ import { defineChannelAdapter } from '@krischoichoi/channel-core';
41
+
42
+ export default defineChannelAdapter({
43
+ id: 'my-channel',
44
+ capabilities: {
45
+ text: true,
46
+ image: false,
47
+ file: false,
48
+ audio: false,
49
+ video: false,
50
+ markdown: false,
51
+ cards: false,
52
+ reactions: false,
53
+ threads: false,
54
+ streaming: 'buffered', // 'native' | 'edit' | 'buffered'
55
+ },
56
+ async start(ctx) {
57
+ // connect the platform, then emit messages with ctx.emit('message', ...)
58
+ },
59
+ async stop() {
60
+ // idempotent cleanup
61
+ },
62
+ async send(target, message) {
63
+ // send one OutboundMessage
64
+ },
65
+ });
66
+ ```
67
+
68
+ In production the plugin wires file-backed resources automatically; in tests the
69
+ service falls back to in-memory stores:
70
+
71
+ ```ts
72
+ import { Context } from '@deepseek-ai/cordis';
73
+ import { ChannelService } from '@krischoichoi/channel-core';
74
+
75
+ const ctx = new Context();
76
+ const channels = new ChannelService(ctx);
77
+
78
+ channels.register(adapter);
79
+ channels.on((event) => console.log(event.type));
80
+ ```
81
+
82
+ ## Data directory
83
+
84
+ The plugin resolves the durable data directory in this order:
85
+
86
+ 1. `DSH_CHANNELS_DATA_DIR` (explicit override)
87
+ 2. `<Harness home>/dsh-channels` (`$DSH_HOME`, else `~/.dsh`)
88
+
89
+ ## Development
90
+
91
+ ```bash
92
+ pnpm --filter @krischoichoi/channel-core build
93
+ pnpm --filter @krischoichoi/channel-core typecheck
94
+ pnpm --filter @krischoichoi/channel-core test
95
+ ```
96
+
97
+ ## Related
98
+
99
+ - [Repository root](../../README.md)
100
+ - [Adapter authoring guide](../../docs/adapter-authoring.md)
101
+
102
+ ## License
103
+
104
+ [MIT](../../LICENSE)
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Channel Access Policy — the shared, versioned, cross-package contract for
3
+ * inbound access control.
4
+ *
5
+ * This module defines ONLY stable cross-package semantics:
6
+ *
7
+ * - the `ChannelAccessPolicy` type + zod schema
8
+ * - the versioned storage-key codec (`accessPolicyStorageKey`)
9
+ * - `MessageActivation` (the `activation` fact on a received message)
10
+ * - the reserved owner-claim command constant + parser (`/dsh-claim`)
11
+ *
12
+ * It does NOT implement policy persistence orchestration, the authorization
13
+ * decision, Owner Claim session lifecycle, platform identity parsing, or any
14
+ * Web concerns. Those live in channel-control / channel-harness / channel-web,
15
+ * all of which share ONLY this contract.
16
+ *
17
+ * Policy model:
18
+ * - Groups support disabled, named allowlist, or global access through an
19
+ * explicit `defaultGroupRule`.
20
+ * - `allowFrom: []` means DENY ALL, never "open".
21
+ * - `requireMention` is an ACTIVATION fact, not authorization, and only
22
+ * applies in group conversations.
23
+ */
24
+ import { z } from 'zod';
25
+ import type { MessageId } from './account.js';
26
+ import type { MessagePart } from './messages.js';
27
+ /** User-facing preset label. Runtime enforcement never branches on it. */
28
+ export type AccessPreset = 'owner-only' | 'allowlist' | 'custom';
29
+ export type DirectMessagePolicy = 'disabled' | 'allowlist' | 'open';
30
+ export type GroupPolicy = 'disabled' | 'allowlist' | 'open';
31
+ /**
32
+ * Within an already explicitly-allowed group:
33
+ * - `allowlist`: `sender.id` must be present in `rule.allowFrom`
34
+ * - `open`: any sender in this NAMED group is authorized
35
+ */
36
+ export type GroupSenderPolicy = 'allowlist' | 'open';
37
+ export interface GroupAccessRule {
38
+ enabled: boolean;
39
+ senderPolicy: GroupSenderPolicy;
40
+ /** canonical sender.id exact-match allowlist. */
41
+ allowFrom: string[];
42
+ /**
43
+ * Only configurable to `true` when `descriptor.mentions === true`.
44
+ * `undefined !== true`, so a channel without reliable activation facts
45
+ * can never be required to mention (no fail-open).
46
+ */
47
+ requireMention: boolean;
48
+ }
49
+ export interface ChannelAccessPolicy {
50
+ /**
51
+ * Persistent schema version. Future semantic changes bump this version
52
+ * instead of silently re-interpreting old JSON. Unknown versions are
53
+ * treated as invalid (fail closed).
54
+ */
55
+ version: 1;
56
+ /**
57
+ * Web UX / materialization source only. Runtime enforcement must NOT branch
58
+ * on preset.
59
+ */
60
+ preset: AccessPreset;
61
+ /** The local operator's canonical sender.id (optional until claimed). */
62
+ ownerId?: string;
63
+ /** Private-chat rule. */
64
+ dmPolicy: DirectMessagePolicy;
65
+ /** DM canonical sender.id allowlist (V1 only exists for dmPolicy=allowlist). */
66
+ allowFrom: string[];
67
+ /** Whether groups are disabled, explicitly named, or governed by a default rule. */
68
+ groupPolicy: GroupPolicy;
69
+ /** canonical conversation.id -> rule. */
70
+ groups: Record<string, GroupAccessRule>;
71
+ /** Required only when groupPolicy=open; applies to every inbound group. */
72
+ defaultGroupRule?: GroupAccessRule;
73
+ }
74
+ export declare const accessPresetSchema: z.ZodEnum<{
75
+ "owner-only": "owner-only";
76
+ allowlist: "allowlist";
77
+ custom: "custom";
78
+ }>;
79
+ export declare const directMessagePolicySchema: z.ZodEnum<{
80
+ allowlist: "allowlist";
81
+ disabled: "disabled";
82
+ open: "open";
83
+ }>;
84
+ export declare const groupPolicySchema: z.ZodEnum<{
85
+ allowlist: "allowlist";
86
+ disabled: "disabled";
87
+ open: "open";
88
+ }>;
89
+ export declare const groupSenderPolicySchema: z.ZodEnum<{
90
+ allowlist: "allowlist";
91
+ open: "open";
92
+ }>;
93
+ export declare const groupAccessRuleSchema: z.ZodObject<{
94
+ enabled: z.ZodBoolean;
95
+ senderPolicy: z.ZodEnum<{
96
+ allowlist: "allowlist";
97
+ open: "open";
98
+ }>;
99
+ allowFrom: z.ZodArray<z.ZodString>;
100
+ requireMention: z.ZodBoolean;
101
+ }, z.core.$strip>;
102
+ /**
103
+ * Strict access-policy schema. Matches the persisted `access:policy:v1:*` JSON.
104
+ * Every field is enforced; unknown keys are rejected (a policy JSON must be
105
+ * exactly what we understand). `ownerId` is optional (pre-claim).
106
+ */
107
+ export declare const channelAccessPolicySchema: z.ZodObject<{
108
+ version: z.ZodLiteral<1>;
109
+ preset: z.ZodEnum<{
110
+ "owner-only": "owner-only";
111
+ allowlist: "allowlist";
112
+ custom: "custom";
113
+ }>;
114
+ ownerId: z.ZodOptional<z.ZodString>;
115
+ dmPolicy: z.ZodEnum<{
116
+ allowlist: "allowlist";
117
+ disabled: "disabled";
118
+ open: "open";
119
+ }>;
120
+ allowFrom: z.ZodArray<z.ZodString>;
121
+ groupPolicy: z.ZodEnum<{
122
+ allowlist: "allowlist";
123
+ disabled: "disabled";
124
+ open: "open";
125
+ }>;
126
+ groups: z.ZodRecord<z.ZodString, z.ZodObject<{
127
+ enabled: z.ZodBoolean;
128
+ senderPolicy: z.ZodEnum<{
129
+ allowlist: "allowlist";
130
+ open: "open";
131
+ }>;
132
+ allowFrom: z.ZodArray<z.ZodString>;
133
+ requireMention: z.ZodBoolean;
134
+ }, z.core.$strip>>;
135
+ defaultGroupRule: z.ZodOptional<z.ZodObject<{
136
+ enabled: z.ZodBoolean;
137
+ senderPolicy: z.ZodEnum<{
138
+ allowlist: "allowlist";
139
+ open: "open";
140
+ }>;
141
+ allowFrom: z.ZodArray<z.ZodString>;
142
+ requireMention: z.ZodBoolean;
143
+ }, z.core.$strip>>;
144
+ }, z.core.$strict>;
145
+ /**
146
+ * Shared channel-domain KV namespace for an access policy. Reused by both the
147
+ * channel-control writer and the channel-harness reader so neither hard-codes
148
+ * the other's key format. E.g. `access:policy:v1:telegram:main`.
149
+ */
150
+ export declare function accessPolicyStorageKey(channelId: string, accountId: string): string;
151
+ /**
152
+ * The single reserved control-plane command. It is the ONLY inbound message
153
+ * that may be observed by the Control Plane before any access policy exists,
154
+ * and it MUST never reach the model / command dispatcher / Session / Binding.
155
+ *
156
+ * Format: `/dsh-claim <challengeCode>`
157
+ */
158
+ export declare const OWNER_CLAIM_COMMAND = "/dsh-claim";
159
+ export interface ParsedOwnerClaimCommand {
160
+ command: '/dsh-claim';
161
+ /** 8+ character one-time challenge code sent to the bot in a DM. */
162
+ code?: string;
163
+ }
164
+ /**
165
+ * True when `text` looks like the reserved claim command (exact slash at byte
166
+ * zero — shared with the official parseCommand convention). Both the Harness
167
+ * reserved-claim gate and the Control owner-claim observer use this same rule.
168
+ */
169
+ export declare function isReservedClaimCommand(text: string): boolean;
170
+ /**
171
+ * Parse a `/dsh-claim ...` line into its challenge code, or `undefined` when
172
+ * the text is not a claim command. Only the first whitespace-delimited token
173
+ * after the command is treated as the code; the rest is ignored.
174
+ */
175
+ export declare function parseOwnerClaimCommand(text: string): ParsedOwnerClaimCommand | undefined;
176
+ export interface MessageActivation {
177
+ /**
178
+ * Whether this message reliably, explicitly mentions the current Bot.
179
+ * `undefined`/`false` means we have no reliable fact — a rule requiring
180
+ * mention must NOT be treated as activated.
181
+ */
182
+ mentionedBot?: boolean;
183
+ /** Reserved for a future activation policy; V1 does not use it. */
184
+ repliedToBot?: boolean;
185
+ }
186
+ export interface AccessMessageRef {
187
+ id: MessageId;
188
+ content: MessagePart[];
189
+ replyTo?: MessageId;
190
+ createdAt?: number;
191
+ activation?: MessageActivation;
192
+ }
193
+ export type { MessageId };
194
+ //# sourceMappingURL=access.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAMjD,0EAA0E;AAC1E,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;AAEjE,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,WAAW,GAAG,MAAM,CAAC;AAEpE,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,MAAM,CAAC;AAE5D;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,MAAM,CAAC;AAErD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,iBAAiB,CAAC;IAChC,iDAAiD;IACjD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB;;;;OAIG;IACH,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,OAAO,EAAE,CAAC,CAAC;IACX;;;OAGG;IACH,MAAM,EAAE,YAAY,CAAC;IACrB,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,gFAAgF;IAChF,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,oFAAoF;IACpF,WAAW,EAAE,WAAW,CAAC;IACzB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACxC,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,eAAe,CAAC;CACpC;AAaD,eAAO,MAAM,kBAAkB;;;;EAAgD,CAAC;AAChF,eAAO,MAAM,yBAAyB;;;;EAA4C,CAAC;AACnF,eAAO,MAAM,iBAAiB;;;;EAA4C,CAAC;AAC3E,eAAO,MAAM,uBAAuB;;;EAAgC,CAAC;AAErE,eAAO,MAAM,qBAAqB;;;;;;;;iBAKhC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA0BlC,CAAC;AAML;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEnF;AAMD;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,eAAe,CAAC;AAEhD,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,YAAY,CAAC;IACtB,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAI5D;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS,CAKxF;AAMD,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mEAAmE;IACnE,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,SAAS,CAAC;IACd,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC;AAED,YAAY,EAAE,SAAS,EAAE,CAAC"}
package/lib/access.js ADDED
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Channel Access Policy — the shared, versioned, cross-package contract for
3
+ * inbound access control.
4
+ *
5
+ * This module defines ONLY stable cross-package semantics:
6
+ *
7
+ * - the `ChannelAccessPolicy` type + zod schema
8
+ * - the versioned storage-key codec (`accessPolicyStorageKey`)
9
+ * - `MessageActivation` (the `activation` fact on a received message)
10
+ * - the reserved owner-claim command constant + parser (`/dsh-claim`)
11
+ *
12
+ * It does NOT implement policy persistence orchestration, the authorization
13
+ * decision, Owner Claim session lifecycle, platform identity parsing, or any
14
+ * Web concerns. Those live in channel-control / channel-harness / channel-web,
15
+ * all of which share ONLY this contract.
16
+ *
17
+ * Policy model:
18
+ * - Groups support disabled, named allowlist, or global access through an
19
+ * explicit `defaultGroupRule`.
20
+ * - `allowFrom: []` means DENY ALL, never "open".
21
+ * - `requireMention` is an ACTIVATION fact, not authorization, and only
22
+ * applies in group conversations.
23
+ */
24
+ import { z } from 'zod';
25
+ // ---------------------------------------------------------------------------
26
+ // Zod schema (shared trust boundary — validation.ts / harness resolver reuse it)
27
+ // ---------------------------------------------------------------------------
28
+ const idSchema = z
29
+ .string()
30
+ .min(1)
31
+ // Trim leading/trailing whitespace is the ONLY allowed normalization. No
32
+ // lowercase, no fuzzy matching, no username resolution. IDs are opaque.
33
+ .trim();
34
+ export const accessPresetSchema = z.enum(['owner-only', 'allowlist', 'custom']);
35
+ export const directMessagePolicySchema = z.enum(['disabled', 'allowlist', 'open']);
36
+ export const groupPolicySchema = z.enum(['disabled', 'allowlist', 'open']);
37
+ export const groupSenderPolicySchema = z.enum(['allowlist', 'open']);
38
+ export const groupAccessRuleSchema = z.object({
39
+ enabled: z.boolean(),
40
+ senderPolicy: groupSenderPolicySchema,
41
+ allowFrom: z.array(idSchema),
42
+ requireMention: z.boolean(),
43
+ });
44
+ /**
45
+ * Strict access-policy schema. Matches the persisted `access:policy:v1:*` JSON.
46
+ * Every field is enforced; unknown keys are rejected (a policy JSON must be
47
+ * exactly what we understand). `ownerId` is optional (pre-claim).
48
+ */
49
+ export const channelAccessPolicySchema = z
50
+ .object({
51
+ version: z.literal(1),
52
+ preset: accessPresetSchema,
53
+ ownerId: idSchema.optional(),
54
+ dmPolicy: directMessagePolicySchema,
55
+ allowFrom: z.array(idSchema),
56
+ groupPolicy: groupPolicySchema,
57
+ groups: z.record(z.string().trim(), groupAccessRuleSchema),
58
+ defaultGroupRule: groupAccessRuleSchema.optional(),
59
+ })
60
+ .strict()
61
+ .superRefine((policy, ctx) => {
62
+ if (policy.groupPolicy === 'open') {
63
+ if (!policy.defaultGroupRule) {
64
+ ctx.addIssue({ code: 'custom', path: ['defaultGroupRule'], message: 'required when groupPolicy is open' });
65
+ }
66
+ if (Object.keys(policy.groups).length > 0) {
67
+ ctx.addIssue({ code: 'custom', path: ['groups'], message: 'must be empty when groupPolicy is open' });
68
+ }
69
+ if (policy.defaultGroupRule?.enabled !== true) {
70
+ ctx.addIssue({ code: 'custom', path: ['defaultGroupRule', 'enabled'], message: 'must be enabled when groupPolicy is open' });
71
+ }
72
+ }
73
+ else if (policy.defaultGroupRule) {
74
+ ctx.addIssue({ code: 'custom', path: ['defaultGroupRule'], message: 'only allowed when groupPolicy is open' });
75
+ }
76
+ });
77
+ // ---------------------------------------------------------------------------
78
+ // Storage key codec
79
+ // ---------------------------------------------------------------------------
80
+ /**
81
+ * Shared channel-domain KV namespace for an access policy. Reused by both the
82
+ * channel-control writer and the channel-harness reader so neither hard-codes
83
+ * the other's key format. E.g. `access:policy:v1:telegram:main`.
84
+ */
85
+ export function accessPolicyStorageKey(channelId, accountId) {
86
+ return `access:policy:v1:${encodeURIComponent(channelId)}:${encodeURIComponent(accountId)}`;
87
+ }
88
+ // ---------------------------------------------------------------------------
89
+ // Reserved owner-claim command
90
+ // ---------------------------------------------------------------------------
91
+ /**
92
+ * The single reserved control-plane command. It is the ONLY inbound message
93
+ * that may be observed by the Control Plane before any access policy exists,
94
+ * and it MUST never reach the model / command dispatcher / Session / Binding.
95
+ *
96
+ * Format: `/dsh-claim <challengeCode>`
97
+ */
98
+ export const OWNER_CLAIM_COMMAND = '/dsh-claim';
99
+ /**
100
+ * True when `text` looks like the reserved claim command (exact slash at byte
101
+ * zero — shared with the official parseCommand convention). Both the Harness
102
+ * reserved-claim gate and the Control owner-claim observer use this same rule.
103
+ */
104
+ export function isReservedClaimCommand(text) {
105
+ if (!text.startsWith(OWNER_CLAIM_COMMAND))
106
+ return false;
107
+ const rest = text.slice(OWNER_CLAIM_COMMAND.length);
108
+ return rest.length === 0 || /^\s/.test(rest);
109
+ }
110
+ /**
111
+ * Parse a `/dsh-claim ...` line into its challenge code, or `undefined` when
112
+ * the text is not a claim command. Only the first whitespace-delimited token
113
+ * after the command is treated as the code; the rest is ignored.
114
+ */
115
+ export function parseOwnerClaimCommand(text) {
116
+ if (!isReservedClaimCommand(text))
117
+ return undefined;
118
+ const rest = text.slice(OWNER_CLAIM_COMMAND.length).trim();
119
+ const code = rest.split(/\s+/)[0];
120
+ return { command: '/dsh-claim', code: code || undefined };
121
+ }
122
+ //# sourceMappingURL=access.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access.js","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Identity types shared by every channel.
3
+ *
4
+ * All identities are branded strings so that a `ConversationId` cannot be
5
+ * silently passed where a `MessageId` is expected. Adapters are responsible
6
+ * for mapping platform-native ids into these types.
7
+ */
8
+ /** Channel id, e.g. `'weixin'`, `'qq'`, `'dingtalk'`, `'lark'`. */
9
+ export type ChannelId = string & {
10
+ readonly __brand: 'ChannelId';
11
+ };
12
+ /** Account id within a channel, e.g. `'main'`, `'bot01'`, `'corpA'`. */
13
+ export type AccountId = string & {
14
+ readonly __brand: 'AccountId';
15
+ };
16
+ /** Conversation id within a channel account. */
17
+ export type ConversationId = string & {
18
+ readonly __brand: 'ConversationId';
19
+ };
20
+ /** Optional thread id within a conversation. */
21
+ export type ThreadId = string & {
22
+ readonly __brand: 'ThreadId';
23
+ };
24
+ /** Platform message id, used for dedup and reply correlation. */
25
+ export type MessageId = string & {
26
+ readonly __brand: 'MessageId';
27
+ };
28
+ /** Platform sender id. */
29
+ export type SenderId = string & {
30
+ readonly __brand: 'SenderId';
31
+ };
32
+ /** Key identifying one conversation binding target. */
33
+ export interface ChannelConversationKey {
34
+ channelId: ChannelId;
35
+ accountId: AccountId;
36
+ conversationId: ConversationId;
37
+ threadId?: ThreadId;
38
+ }
39
+ /**
40
+ * Canonical string form of a conversation key:
41
+ * `channel:account:conversation[:thread]`.
42
+ *
43
+ * Never allowed to collapse a whole account into one session — each
44
+ * conversation (and optionally thread) is a distinct key.
45
+ */
46
+ export declare function conversationKey(key: ChannelConversationKey): string;
47
+ //# sourceMappingURL=account.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../src/account.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,mEAAmE;AACnE,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AAEnE,wEAAwE;AACxE,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AAEnE,gDAAgD;AAChD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAE7E,gDAAgD;AAChD,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;CAAE,CAAC;AAEjE,iEAAiE;AACjE,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AAEnE,0BAA0B;AAC1B,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;CAAE,CAAC;AAEjE,uDAAuD;AACvD,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,SAAS,CAAC;IACrB,SAAS,EAAE,SAAS,CAAC;IACrB,cAAc,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,sBAAsB,GAAG,MAAM,CAInE"}
package/lib/account.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Identity types shared by every channel.
3
+ *
4
+ * All identities are branded strings so that a `ConversationId` cannot be
5
+ * silently passed where a `MessageId` is expected. Adapters are responsible
6
+ * for mapping platform-native ids into these types.
7
+ */
8
+ /**
9
+ * Canonical string form of a conversation key:
10
+ * `channel:account:conversation[:thread]`.
11
+ *
12
+ * Never allowed to collapse a whole account into one session — each
13
+ * conversation (and optionally thread) is a distinct key.
14
+ */
15
+ export function conversationKey(key) {
16
+ return key.threadId
17
+ ? `${key.channelId}:${key.accountId}:${key.conversationId}:${key.threadId}`
18
+ : `${key.channelId}:${key.accountId}:${key.conversationId}`;
19
+ }
20
+ //# sourceMappingURL=account.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account.js","sourceRoot":"","sources":["../src/account.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4BH;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,GAA2B;IACzD,OAAO,GAAG,CAAC,QAAQ;QACjB,CAAC,CAAC,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,QAAQ,EAAE;QAC3E,CAAC,CAAC,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;AAChE,CAAC"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * `ChannelAdapter` contract: the stable boundary between a messaging
3
+ * platform and the Channel Core.
4
+ *
5
+ * An adapter maps platform semantics to the Channel Contract and delegates
6
+ * all SDK/package/protocol interaction to an upstream driver. Adapters never
7
+ * call Harness Agent APIs.
8
+ *
9
+ * Streaming may be target-aware: an adapter's *streaming capability* can be
10
+ * static (`capabilities.streaming`) or depend on the concrete reply target via
11
+ * the optional `resolveStreamingMode(target)` hook (e.g. QQ streams natively
12
+ * for C2C with a triggering message id, buffering for groups — but the fields
13
+ * are generic and reused by Telegram reply, Slack thread reply, Lark reply and
14
+ * DingTalk reference).
15
+ */
16
+ import type { ChannelAdapterContext } from './context.js';
17
+ import type { ChannelCapabilities, StreamingMode } from './capabilities.js';
18
+ import type { AuthState } from './events.js';
19
+ import type { ChannelConversationKey, MessageId } from './account.js';
20
+ import type { OutboundMessage, SendResult } from './messages.js';
21
+ import type { ChannelHealth } from './health.js';
22
+ export interface ChannelTarget extends ChannelConversationKey {
23
+ /**
24
+ * Conversation kind of the reply target. Generic capability field — reused
25
+ * by replies whose semantics differ between DMs and groups (e.g. QQ: C2C
26
+ * native streaming vs. group buffered). Not QQ-specific.
27
+ */
28
+ conversationType?: 'dm' | 'group';
29
+ /**
30
+ * Id of the inbound message this reply answers. Lets adapters correlate a
31
+ * reply to the triggering message (Telegram reply, Slack thread reply, Lark
32
+ * reply, DingTalk reference, QQ C2C native streaming all reuse it). Not
33
+ * QQ-specific.
34
+ */
35
+ replyToMessageId?: MessageId;
36
+ /** Raw target data the adapter needs but core does not model. */
37
+ raw?: unknown;
38
+ /**
39
+ * Turn-scoped correlation id shared by every send within one Harness turn.
40
+ * Generic: adapters that correlate outbound sends to a single turn (e.g.
41
+ * Weixin run_id) read it; others ignore it.
42
+ */
43
+ runId?: string;
44
+ }
45
+ export interface CreateReplyOptions {
46
+ /** Send an initial "working on it" message immediately. */
47
+ placeholder?: string;
48
+ /** Whether reply content may contain markdown. */
49
+ markdown?: boolean;
50
+ }
51
+ export interface ReplyHandle {
52
+ /** Append a delta to the streaming reply. */
53
+ append(delta: string): Promise<void>;
54
+ /** Replace the whole reply content. */
55
+ replace(message: OutboundMessage): Promise<void>;
56
+ /** Finalize the reply, optionally with a final message. */
57
+ finish(message?: OutboundMessage): Promise<void>;
58
+ /** Mark the reply as failed. */
59
+ fail(error: unknown): Promise<void>;
60
+ }
61
+ export interface AuthChallenge {
62
+ /** Stable id of this challenge. */
63
+ id: string;
64
+ /** Human-readable instruction for the operator. */
65
+ instruction: string;
66
+ /** Optional QR/login URL for terminal or card rendering. */
67
+ qrUrl?: string;
68
+ /** Optional expiry timestamp. */
69
+ expiresAt?: number;
70
+ /** Adapter-specific payload; never a credential. */
71
+ payload?: unknown;
72
+ }
73
+ export interface AuthStatePoll {
74
+ state: Exclude<AuthState, 'unknown'>;
75
+ detail?: string;
76
+ }
77
+ export interface AuthInput {
78
+ kind: 'verification-code';
79
+ value: string;
80
+ }
81
+ export interface ChannelAdapter {
82
+ readonly id: string;
83
+ readonly capabilities: ChannelCapabilities;
84
+ /**
85
+ * Resolve the streaming mode for one reply target. Adapters whose
86
+ * streaming capability depends on the target (e.g. QQ: C2C + msgId →
87
+ * native, group → buffered) override the static `capabilities.streaming`.
88
+ * Defaults to `capabilities.streaming` when absent.
89
+ */
90
+ resolveStreamingMode?(target: ChannelTarget): StreamingMode;
91
+ start(ctx: ChannelAdapterContext): Promise<void>;
92
+ stop(): Promise<void>;
93
+ send(target: ChannelTarget, message: OutboundMessage): Promise<SendResult>;
94
+ /**
95
+ * Optional in-place edit of an already-sent message (e.g. Telegram
96
+ * `editMessageText` / `editMessageReplyMarkup`, Lark/DingTalk card update).
97
+ * Enables interactive flows that rewrite a single sent message (multi-select
98
+ * toggling, removing stale buttons). Adapters without an edit primitive leave
99
+ * it undefined; the harness must degrade those flows to a non-edit strategy.
100
+ */
101
+ edit?(target: ChannelTarget, messageId: string, message: OutboundMessage): Promise<SendResult>;
102
+ /**
103
+ * Best-effort typing indicator. Optional: adapters with a typing API (e.g.
104
+ * Weixin sendtyping) implement these; the harness fires them around turn
105
+ * start/end and NEVER lets a failure break reply delivery.
106
+ */
107
+ startTyping?(conversationId: string): Promise<void>;
108
+ stopTyping?(conversationId: string): Promise<void>;
109
+ startTypingForTarget?(target: ChannelTarget): Promise<void>;
110
+ stopTypingForTarget?(target: ChannelTarget): Promise<void>;
111
+ createReply?(target: ChannelTarget, options?: CreateReplyOptions): Promise<ReplyHandle>;
112
+ beginAuth?(): Promise<AuthChallenge>;
113
+ pollAuth?(challenge: AuthChallenge): Promise<AuthStatePoll>;
114
+ submitAuthInput?(challenge: AuthChallenge, input: AuthInput): Promise<void> | void;
115
+ getHealth?(): Promise<ChannelHealth>;
116
+ }
117
+ /** Emit a message event through the adapter context helper. */
118
+ export declare function isChannelAdapter(value: unknown): value is ChannelAdapter;
119
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
package/lib/adapter.js ADDED
@@ -0,0 +1,6 @@
1
+ import { channelAdapterShapeSchema } from './schema.js';
2
+ /** Emit a message event through the adapter context helper. */
3
+ export function isChannelAdapter(value) {
4
+ return channelAdapterShapeSchema.safeParse(value).success;
5
+ }
6
+ //# sourceMappingURL=adapter.js.map