twinny 0.0.0-dev.260525150705

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 (191) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +264 -0
  3. package/README.zh-CN.md +252 -0
  4. package/configs/banner.png +0 -0
  5. package/configs/logo.png +0 -0
  6. package/dist/app/caffeinate.d.ts +28 -0
  7. package/dist/app/caffeinate.js +96 -0
  8. package/dist/app/caffeinate.js.map +1 -0
  9. package/dist/app/daemon.d.ts +1 -0
  10. package/dist/app/daemon.js +44 -0
  11. package/dist/app/daemon.js.map +1 -0
  12. package/dist/app/lark-assets.d.ts +25 -0
  13. package/dist/app/lark-assets.js +108 -0
  14. package/dist/app/lark-assets.js.map +1 -0
  15. package/dist/app/startup-probe.d.ts +17 -0
  16. package/dist/app/startup-probe.js +90 -0
  17. package/dist/app/startup-probe.js.map +1 -0
  18. package/dist/app/wiring.d.ts +122 -0
  19. package/dist/app/wiring.js +694 -0
  20. package/dist/app/wiring.js.map +1 -0
  21. package/dist/cli/commands.d.ts +1 -0
  22. package/dist/cli/commands.js +47 -0
  23. package/dist/cli/commands.js.map +1 -0
  24. package/dist/cli/install-wizard.d.ts +41 -0
  25. package/dist/cli/install-wizard.js +629 -0
  26. package/dist/cli/install-wizard.js.map +1 -0
  27. package/dist/codex/appserver.d.ts +109 -0
  28. package/dist/codex/appserver.js +308 -0
  29. package/dist/codex/appserver.js.map +1 -0
  30. package/dist/codex/goal.d.ts +64 -0
  31. package/dist/codex/goal.js +433 -0
  32. package/dist/codex/goal.js.map +1 -0
  33. package/dist/codex/index.d.ts +6 -0
  34. package/dist/codex/index.js +7 -0
  35. package/dist/codex/index.js.map +1 -0
  36. package/dist/codex/protocol.d.ts +95 -0
  37. package/dist/codex/protocol.js +205 -0
  38. package/dist/codex/protocol.js.map +1 -0
  39. package/dist/codex/thread-name.d.ts +3 -0
  40. package/dist/codex/thread-name.js +27 -0
  41. package/dist/codex/thread-name.js.map +1 -0
  42. package/dist/codex/thread.d.ts +76 -0
  43. package/dist/codex/thread.js +80 -0
  44. package/dist/codex/thread.js.map +1 -0
  45. package/dist/codex/turn.d.ts +166 -0
  46. package/dist/codex/turn.js +746 -0
  47. package/dist/codex/turn.js.map +1 -0
  48. package/dist/config/bootstrap.d.ts +14 -0
  49. package/dist/config/bootstrap.js +56 -0
  50. package/dist/config/bootstrap.js.map +1 -0
  51. package/dist/config/index.d.ts +4 -0
  52. package/dist/config/index.js +5 -0
  53. package/dist/config/index.js.map +1 -0
  54. package/dist/config/loader.d.ts +49 -0
  55. package/dist/config/loader.js +467 -0
  56. package/dist/config/loader.js.map +1 -0
  57. package/dist/config/paths.d.ts +11 -0
  58. package/dist/config/paths.js +43 -0
  59. package/dist/config/paths.js.map +1 -0
  60. package/dist/config/secrets.d.ts +33 -0
  61. package/dist/config/secrets.js +85 -0
  62. package/dist/config/secrets.js.map +1 -0
  63. package/dist/conversation/manager.d.ts +701 -0
  64. package/dist/conversation/manager.js +7673 -0
  65. package/dist/conversation/manager.js.map +1 -0
  66. package/dist/conversation/queue.d.ts +8 -0
  67. package/dist/conversation/queue.js +28 -0
  68. package/dist/conversation/queue.js.map +1 -0
  69. package/dist/conversation/routing.d.ts +11 -0
  70. package/dist/conversation/routing.js +55 -0
  71. package/dist/conversation/routing.js.map +1 -0
  72. package/dist/errors.d.ts +6 -0
  73. package/dist/errors.js +17 -0
  74. package/dist/errors.js.map +1 -0
  75. package/dist/index.d.ts +3 -0
  76. package/dist/index.js +4 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/lark/auth.d.ts +41 -0
  79. package/dist/lark/auth.js +132 -0
  80. package/dist/lark/auth.js.map +1 -0
  81. package/dist/lark/browser-auth.d.ts +68 -0
  82. package/dist/lark/browser-auth.js +258 -0
  83. package/dist/lark/browser-auth.js.map +1 -0
  84. package/dist/lark/cards.d.ts +140 -0
  85. package/dist/lark/cards.js +1150 -0
  86. package/dist/lark/cards.js.map +1 -0
  87. package/dist/lark/contact.d.ts +41 -0
  88. package/dist/lark/contact.js +122 -0
  89. package/dist/lark/contact.js.map +1 -0
  90. package/dist/lark/events.d.ts +65 -0
  91. package/dist/lark/events.js +218 -0
  92. package/dist/lark/events.js.map +1 -0
  93. package/dist/lark/files.d.ts +36 -0
  94. package/dist/lark/files.js +191 -0
  95. package/dist/lark/files.js.map +1 -0
  96. package/dist/lark/filters.d.ts +73 -0
  97. package/dist/lark/filters.js +678 -0
  98. package/dist/lark/filters.js.map +1 -0
  99. package/dist/lark/index.d.ts +10 -0
  100. package/dist/lark/index.js +11 -0
  101. package/dist/lark/index.js.map +1 -0
  102. package/dist/lark/messages.d.ts +87 -0
  103. package/dist/lark/messages.js +428 -0
  104. package/dist/lark/messages.js.map +1 -0
  105. package/dist/lark/openapi.d.ts +58 -0
  106. package/dist/lark/openapi.js +206 -0
  107. package/dist/lark/openapi.js.map +1 -0
  108. package/dist/lark/redactor.d.ts +5 -0
  109. package/dist/lark/redactor.js +68 -0
  110. package/dist/lark/redactor.js.map +1 -0
  111. package/dist/lark/types.d.ts +49 -0
  112. package/dist/lark/types.js +18 -0
  113. package/dist/lark/types.js.map +1 -0
  114. package/dist/launchd/install.d.ts +22 -0
  115. package/dist/launchd/install.js +114 -0
  116. package/dist/launchd/install.js.map +1 -0
  117. package/dist/launchd/plist.d.ts +10 -0
  118. package/dist/launchd/plist.js +61 -0
  119. package/dist/launchd/plist.js.map +1 -0
  120. package/dist/lock/index.d.ts +20 -0
  121. package/dist/lock/index.js +74 -0
  122. package/dist/lock/index.js.map +1 -0
  123. package/dist/main.d.ts +2 -0
  124. package/dist/main.js +11 -0
  125. package/dist/main.js.map +1 -0
  126. package/dist/markdown.d.ts +12 -0
  127. package/dist/markdown.js +149 -0
  128. package/dist/markdown.js.map +1 -0
  129. package/dist/observability/health.d.ts +25 -0
  130. package/dist/observability/health.js +187 -0
  131. package/dist/observability/health.js.map +1 -0
  132. package/dist/observability/logs.d.ts +10 -0
  133. package/dist/observability/logs.js +34 -0
  134. package/dist/observability/logs.js.map +1 -0
  135. package/dist/observability/system-notifications.d.ts +25 -0
  136. package/dist/observability/system-notifications.js +33 -0
  137. package/dist/observability/system-notifications.js.map +1 -0
  138. package/dist/profiles/guest.d.ts +19 -0
  139. package/dist/profiles/guest.js +241 -0
  140. package/dist/profiles/guest.js.map +1 -0
  141. package/dist/profiles/index.d.ts +5 -0
  142. package/dist/profiles/index.js +14 -0
  143. package/dist/profiles/index.js.map +1 -0
  144. package/dist/profiles/owner.d.ts +1 -0
  145. package/dist/profiles/owner.js +6 -0
  146. package/dist/profiles/owner.js.map +1 -0
  147. package/dist/store/db.d.ts +10 -0
  148. package/dist/store/db.js +29 -0
  149. package/dist/store/db.js.map +1 -0
  150. package/dist/store/index.d.ts +3 -0
  151. package/dist/store/index.js +4 -0
  152. package/dist/store/index.js.map +1 -0
  153. package/dist/store/migrations.d.ts +13 -0
  154. package/dist/store/migrations.js +79 -0
  155. package/dist/store/migrations.js.map +1 -0
  156. package/dist/store/repositories.d.ts +227 -0
  157. package/dist/store/repositories.js +1384 -0
  158. package/dist/store/repositories.js.map +1 -0
  159. package/dist/telemetry/client.d.ts +60 -0
  160. package/dist/telemetry/client.js +204 -0
  161. package/dist/telemetry/client.js.map +1 -0
  162. package/dist/telemetry/hash.d.ts +1 -0
  163. package/dist/telemetry/hash.js +8 -0
  164. package/dist/telemetry/hash.js.map +1 -0
  165. package/dist/telemetry/index.d.ts +4 -0
  166. package/dist/telemetry/index.js +5 -0
  167. package/dist/telemetry/index.js.map +1 -0
  168. package/dist/telemetry/posthog.d.ts +27 -0
  169. package/dist/telemetry/posthog.js +45 -0
  170. package/dist/telemetry/posthog.js.map +1 -0
  171. package/dist/telemetry/reporter.d.ts +13 -0
  172. package/dist/telemetry/reporter.js +29 -0
  173. package/dist/telemetry/reporter.js.map +1 -0
  174. package/dist/types.d.ts +330 -0
  175. package/dist/types.js +9 -0
  176. package/dist/types.js.map +1 -0
  177. package/dist/version.d.ts +1 -0
  178. package/dist/version.js +1 -0
  179. package/dist/version.js.map +1 -0
  180. package/dist/version.json +3 -0
  181. package/dist/workspace/index.d.ts +2 -0
  182. package/dist/workspace/index.js +3 -0
  183. package/dist/workspace/index.js.map +1 -0
  184. package/dist/workspace/manager.d.ts +14 -0
  185. package/dist/workspace/manager.js +69 -0
  186. package/dist/workspace/manager.js.map +1 -0
  187. package/dist/workspace/slug.d.ts +8 -0
  188. package/dist/workspace/slug.js +59 -0
  189. package/dist/workspace/slug.js.map +1 -0
  190. package/migrations/0001_initial.sql +102 -0
  191. package/package.json +85 -0
@@ -0,0 +1,58 @@
1
+ import { TwinnyError } from "../errors.js";
2
+ import { TenantAccessTokenManager } from "./auth.js";
3
+ import type { FetchLike } from "./types.js";
4
+ export interface LarkOpenApiClientOptions {
5
+ tokenManager: TenantAccessTokenManager;
6
+ baseUrl?: string;
7
+ fetch?: FetchLike;
8
+ maxRetries?: number;
9
+ retryBaseDelayMs?: number;
10
+ now?: () => number;
11
+ }
12
+ export interface LarkOpenApiRequestOptions {
13
+ method?: "GET" | "POST" | "DELETE" | "PATCH" | "PUT";
14
+ query?: Record<string, string | number | boolean | undefined>;
15
+ body?: unknown;
16
+ signal?: AbortSignal;
17
+ retry?: boolean;
18
+ }
19
+ export interface LarkOpenApiBinaryResponse {
20
+ body: Buffer;
21
+ contentType?: string;
22
+ contentDisposition?: string;
23
+ }
24
+ export interface LarkOpenApiMultipartFile {
25
+ fieldName: string;
26
+ fileName: string;
27
+ body: Buffer;
28
+ contentType?: string;
29
+ }
30
+ export declare class LarkOpenApiError extends TwinnyError {
31
+ readonly detail: {
32
+ status?: number;
33
+ code?: number;
34
+ responseBody?: unknown;
35
+ retryable?: boolean;
36
+ };
37
+ constructor(message: string, detail: {
38
+ status?: number;
39
+ code?: number;
40
+ responseBody?: unknown;
41
+ retryable?: boolean;
42
+ }, cause?: unknown);
43
+ }
44
+ export declare class LarkOpenApiClient {
45
+ private readonly tokenManager;
46
+ private readonly baseUrl;
47
+ private readonly fetch;
48
+ private readonly maxRetries;
49
+ private readonly retryBaseDelayMs;
50
+ constructor(options: LarkOpenApiClientOptions);
51
+ request(pathname: string, options?: LarkOpenApiRequestOptions): Promise<unknown>;
52
+ download(pathname: string, options?: LarkOpenApiRequestOptions): Promise<LarkOpenApiBinaryResponse>;
53
+ uploadMultipart(pathname: string, fields: Record<string, string | number | boolean | undefined>, files: LarkOpenApiMultipartFile[], options?: Pick<LarkOpenApiRequestOptions, "query" | "signal" | "retry">): Promise<unknown>;
54
+ private requestOnce;
55
+ private downloadOnce;
56
+ private uploadMultipartOnce;
57
+ private buildUrl;
58
+ }
@@ -0,0 +1,206 @@
1
+ import { TwinnyError, toErrorMessage } from "../errors.js";
2
+ import { DEFAULT_LARK_OPENAPI_BASE_URL, normalizeBaseUrl } from "./auth.js";
3
+ export class LarkOpenApiError extends TwinnyError {
4
+ detail;
5
+ constructor(message, detail, cause) {
6
+ super(message, "LARK_OPENAPI_ERROR", cause);
7
+ this.detail = detail;
8
+ this.name = "LarkOpenApiError";
9
+ }
10
+ }
11
+ export class LarkOpenApiClient {
12
+ tokenManager;
13
+ baseUrl;
14
+ fetch;
15
+ maxRetries;
16
+ retryBaseDelayMs;
17
+ constructor(options) {
18
+ this.tokenManager = options.tokenManager;
19
+ this.baseUrl = normalizeBaseUrl(options.baseUrl ?? DEFAULT_LARK_OPENAPI_BASE_URL);
20
+ this.fetch = options.fetch ?? globalFetch;
21
+ this.maxRetries = options.maxRetries ?? 2;
22
+ this.retryBaseDelayMs = options.retryBaseDelayMs ?? 100;
23
+ }
24
+ async request(pathname, options = {}) {
25
+ const retry = options.retry ?? true;
26
+ const attempts = retry ? this.maxRetries + 1 : 1;
27
+ let lastError;
28
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
29
+ try {
30
+ return await this.requestOnce(pathname, options);
31
+ }
32
+ catch (error) {
33
+ lastError = error;
34
+ if (attempt >= attempts - 1 || !isRetryableError(error)) {
35
+ break;
36
+ }
37
+ await sleep(this.retryBaseDelayMs * 2 ** attempt);
38
+ }
39
+ }
40
+ throw lastError;
41
+ }
42
+ async download(pathname, options = {}) {
43
+ const retry = options.retry ?? true;
44
+ const attempts = retry ? this.maxRetries + 1 : 1;
45
+ let lastError;
46
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
47
+ try {
48
+ return await this.downloadOnce(pathname, options);
49
+ }
50
+ catch (error) {
51
+ lastError = error;
52
+ if (attempt >= attempts - 1 || !isRetryableError(error)) {
53
+ break;
54
+ }
55
+ await sleep(this.retryBaseDelayMs * 2 ** attempt);
56
+ }
57
+ }
58
+ throw lastError;
59
+ }
60
+ async uploadMultipart(pathname, fields, files, options = {}) {
61
+ const retry = options.retry ?? true;
62
+ const attempts = retry ? this.maxRetries + 1 : 1;
63
+ let lastError;
64
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
65
+ try {
66
+ return await this.uploadMultipartOnce(pathname, fields, files, options);
67
+ }
68
+ catch (error) {
69
+ lastError = error;
70
+ if (attempt >= attempts - 1 || !isRetryableError(error)) {
71
+ break;
72
+ }
73
+ await sleep(this.retryBaseDelayMs * 2 ** attempt);
74
+ }
75
+ }
76
+ throw lastError;
77
+ }
78
+ async requestOnce(pathname, options) {
79
+ const token = await this.tokenManager.getTenantAccessToken();
80
+ const response = await this.fetch(this.buildUrl(pathname, options.query), {
81
+ method: options.method ?? "GET",
82
+ headers: {
83
+ authorization: `Bearer ${token}`,
84
+ "content-type": "application/json"
85
+ },
86
+ body: options.body === undefined ? undefined : JSON.stringify(options.body),
87
+ signal: options.signal
88
+ });
89
+ const body = await readJsonBody(response);
90
+ const record = toRecord(body);
91
+ const code = typeof record.code === "number" ? record.code : undefined;
92
+ if (!response.ok || (code !== undefined && code !== 0)) {
93
+ const retryable = response.status === 429 || response.status >= 500;
94
+ throw new LarkOpenApiError(`Lark OpenAPI request failed: ${formatOpenApiFailure(response, record)}`, { status: response.status, code, responseBody: body, retryable });
95
+ }
96
+ return body;
97
+ }
98
+ async downloadOnce(pathname, options) {
99
+ const token = await this.tokenManager.getTenantAccessToken();
100
+ const response = await this.fetch(this.buildUrl(pathname, options.query), {
101
+ method: options.method ?? "GET",
102
+ headers: {
103
+ authorization: `Bearer ${token}`,
104
+ "content-type": "application/json"
105
+ },
106
+ body: options.body === undefined ? undefined : JSON.stringify(options.body),
107
+ signal: options.signal
108
+ });
109
+ if (!response.ok) {
110
+ throw new LarkOpenApiError(`Lark OpenAPI download failed: ${await formatDownloadFailure(response)}`, { status: response.status, retryable: response.status === 429 || response.status >= 500 });
111
+ }
112
+ if (!response.arrayBuffer) {
113
+ throw new LarkOpenApiError("Lark OpenAPI binary response cannot be read in this runtime", {
114
+ status: response.status
115
+ });
116
+ }
117
+ return {
118
+ body: Buffer.from(await response.arrayBuffer()),
119
+ contentType: response.headers?.get("content-type") ?? undefined,
120
+ contentDisposition: response.headers?.get("content-disposition") ?? undefined
121
+ };
122
+ }
123
+ async uploadMultipartOnce(pathname, fields, files, options) {
124
+ const token = await this.tokenManager.getTenantAccessToken();
125
+ const form = new FormData();
126
+ for (const [key, value] of Object.entries(fields)) {
127
+ if (value !== undefined) {
128
+ form.append(key, String(value));
129
+ }
130
+ }
131
+ for (const file of files) {
132
+ form.append(file.fieldName, new Blob([file.body], { type: file.contentType ?? "application/octet-stream" }), file.fileName);
133
+ }
134
+ const response = await this.fetch(this.buildUrl(pathname, options.query), {
135
+ method: "POST",
136
+ headers: {
137
+ authorization: `Bearer ${token}`
138
+ },
139
+ body: form,
140
+ signal: options.signal
141
+ });
142
+ const body = await readJsonBody(response);
143
+ const record = toRecord(body);
144
+ const code = typeof record.code === "number" ? record.code : undefined;
145
+ if (!response.ok || (code !== undefined && code !== 0)) {
146
+ const retryable = response.status === 429 || response.status >= 500;
147
+ throw new LarkOpenApiError(`Lark OpenAPI request failed: ${formatOpenApiFailure(response, record)}`, { status: response.status, code, responseBody: body, retryable });
148
+ }
149
+ return body;
150
+ }
151
+ buildUrl(pathname, query) {
152
+ const path = pathname.startsWith("/") ? pathname : `/${pathname}`;
153
+ const url = new URL(`${this.baseUrl}${path}`);
154
+ for (const [key, value] of Object.entries(query ?? {})) {
155
+ if (value !== undefined) {
156
+ url.searchParams.set(key, String(value));
157
+ }
158
+ }
159
+ return url.toString();
160
+ }
161
+ }
162
+ function isRetryableError(error) {
163
+ if (error instanceof LarkOpenApiError) {
164
+ return error.detail.retryable === true;
165
+ }
166
+ return true;
167
+ }
168
+ function formatOpenApiFailure(response, body) {
169
+ const msg = typeof body.msg === "string" && body.msg.length > 0 ? body.msg : response.statusText;
170
+ return `status=${response.status} code=${String(body.code ?? "unknown")} msg=${msg}`;
171
+ }
172
+ async function formatDownloadFailure(response) {
173
+ const text = response.text ? await response.text().catch(() => "") : "";
174
+ return `status=${response.status} msg=${text || response.statusText}`;
175
+ }
176
+ async function readJsonBody(response) {
177
+ try {
178
+ return await response.json();
179
+ }
180
+ catch (error) {
181
+ if (response.text) {
182
+ try {
183
+ return { raw: await response.text() };
184
+ }
185
+ catch {
186
+ throw error;
187
+ }
188
+ }
189
+ throw new LarkOpenApiError(`Lark OpenAPI returned invalid JSON: ${toErrorMessage(error)}`, {}, error);
190
+ }
191
+ }
192
+ function toRecord(value) {
193
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
194
+ }
195
+ function sleep(ms) {
196
+ return new Promise((resolve) => {
197
+ setTimeout(resolve, ms);
198
+ });
199
+ }
200
+ const globalFetch = async (input, init) => {
201
+ if (typeof fetch !== "function") {
202
+ throw new TwinnyError("global fetch is not available in this Node.js runtime", "LARK_FETCH_UNAVAILABLE");
203
+ }
204
+ return fetch(input, init);
205
+ };
206
+ //# sourceMappingURL=openapi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi.js","sourceRoot":"","sources":["../../src/lark/openapi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { type LarkMessageRedactionConfig } from "../types.js";
2
+ export declare const DEFAULT_LARK_MESSAGE_REDACTION: LarkMessageRedactionConfig;
3
+ export declare function normalizeLarkMessageRedactionConfig(config: Partial<LarkMessageRedactionConfig> | undefined): LarkMessageRedactionConfig;
4
+ export declare function redactSensitiveText(text: string, config?: Partial<LarkMessageRedactionConfig> | undefined): string;
5
+ export declare function redactLarkMessageContent<T>(content: T, config?: Partial<LarkMessageRedactionConfig>): T;
@@ -0,0 +1,68 @@
1
+ import { DEFAULT_LARK_MESSAGE_REDACTION_STRATEGY } from "../types.js";
2
+ export const DEFAULT_LARK_MESSAGE_REDACTION = {
3
+ email: DEFAULT_LARK_MESSAGE_REDACTION_STRATEGY,
4
+ chinesePhoneNumber: DEFAULT_LARK_MESSAGE_REDACTION_STRATEGY
5
+ };
6
+ const EMAIL_PATTERN = /(^|[^\w.!#$%&'*+/=?^`{|}~-])([A-Za-z0-9.!#$%&'*+/=?^_`{|}~-]+)@([A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?)+)(?![\w-])/g;
7
+ const CHINESE_PHONE_PATTERN = /(^|[^\dA-Za-z])(1[3-9]\d)(\d{4})(\d{4})(?=$|[^\dA-Za-z])/g;
8
+ export function normalizeLarkMessageRedactionConfig(config) {
9
+ return {
10
+ email: normalizeStrategy(config?.email),
11
+ chinesePhoneNumber: normalizeStrategy(config?.chinesePhoneNumber)
12
+ };
13
+ }
14
+ export function redactSensitiveText(text, config = DEFAULT_LARK_MESSAGE_REDACTION) {
15
+ const normalized = normalizeLarkMessageRedactionConfig(config);
16
+ return redactChinesePhoneNumbers(redactEmails(text, normalized.email), normalized.chinesePhoneNumber);
17
+ }
18
+ export function redactLarkMessageContent(content, config) {
19
+ return redactStringValues(content, normalizeLarkMessageRedactionConfig(config));
20
+ }
21
+ function normalizeStrategy(strategy) {
22
+ return strategy ?? DEFAULT_LARK_MESSAGE_REDACTION_STRATEGY;
23
+ }
24
+ function redactEmails(text, strategy) {
25
+ if (strategy === "none") {
26
+ return text;
27
+ }
28
+ return text.replace(EMAIL_PATTERN, (_match, prefix, local, domain) => {
29
+ if (strategy === "whitespace") {
30
+ return `${prefix}${local} @ ${domain}`;
31
+ }
32
+ return `${prefix}${maskEmailLocalPart(local)}@${domain}`;
33
+ });
34
+ }
35
+ function redactChinesePhoneNumbers(text, strategy) {
36
+ if (strategy === "none") {
37
+ return text;
38
+ }
39
+ return text.replace(CHINESE_PHONE_PATTERN, (_match, prefix, first, middle, last) => {
40
+ if (strategy === "whitespace") {
41
+ return `${prefix}${first} ${middle} ${last}`;
42
+ }
43
+ return `${prefix}${first}****${last}`;
44
+ });
45
+ }
46
+ function maskEmailLocalPart(local) {
47
+ if (local.length <= 2) {
48
+ return local;
49
+ }
50
+ return `${local[0]}${"*".repeat(local.length - 2)}${local[local.length - 1]}`;
51
+ }
52
+ function redactStringValues(value, config) {
53
+ if (typeof value === "string") {
54
+ return redactSensitiveText(value, config);
55
+ }
56
+ if (Array.isArray(value)) {
57
+ return value.map((item) => redactStringValues(item, config));
58
+ }
59
+ if (!value || typeof value !== "object") {
60
+ return value;
61
+ }
62
+ const result = {};
63
+ for (const [childKey, childValue] of Object.entries(value)) {
64
+ result[childKey] = redactStringValues(childValue, config);
65
+ }
66
+ return result;
67
+ }
68
+ //# sourceMappingURL=redactor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redactor.js","sourceRoot":"","sources":["../../src/lark/redactor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import type { IncomingLarkBotMenuAction, IncomingLarkCardAction, IncomingLarkMessage, IncomingLarkMessageRecall, LarkReactionHandle } from "../types.js";
2
+ export declare const LARK_BOT_MENU_EVENT: "application.bot.menu_v6";
3
+ export declare const LARK_MESSAGE_RECEIVE_EVENT: "im.message.receive_v1";
4
+ export declare const LARK_MESSAGE_RECALLED_EVENT: "im.message.recalled_v1";
5
+ export declare const LARK_CARD_ACTION_TRIGGER_EVENT: "card.action.trigger";
6
+ export declare const LARK_REQUIRED_SCOPES: readonly ["im:message.p2p_msg:readonly", "im:message.group_msg", "im:message:readonly", "im:message:send_as_bot", "im:message:update", "im:message:recall", "im:message.reactions:write_only", "im:chat:read", "im:chat:create", "im:chat:update", "im:resource"];
7
+ export interface FetchResponseLike {
8
+ readonly ok: boolean;
9
+ readonly status: number;
10
+ readonly statusText: string;
11
+ readonly headers?: {
12
+ get(name: string): string | null;
13
+ };
14
+ json(): Promise<unknown>;
15
+ text?(): Promise<string>;
16
+ arrayBuffer?(): Promise<ArrayBuffer>;
17
+ }
18
+ export interface FetchRequestInitLike {
19
+ method?: string;
20
+ headers?: Record<string, string>;
21
+ body?: string | FormData;
22
+ signal?: AbortSignal;
23
+ }
24
+ export type FetchLike = (input: string, init?: FetchRequestInitLike) => Promise<FetchResponseLike>;
25
+ export interface LarkCredentialOptions {
26
+ appId: string;
27
+ appSecret: string;
28
+ baseUrl?: string;
29
+ fetch?: FetchLike;
30
+ now?: () => number;
31
+ }
32
+ export interface LarkLogger {
33
+ debug?: (metadata: Record<string, unknown>, message?: string) => void;
34
+ info?: (metadata: Record<string, unknown>, message?: string) => void;
35
+ warn?: (metadata: Record<string, unknown>, message?: string) => void;
36
+ error?: (metadata: Record<string, unknown>, message?: string) => void;
37
+ }
38
+ export interface LarkSdkLogger {
39
+ trace: (...args: unknown[]) => void;
40
+ debug: (...args: unknown[]) => void;
41
+ info: (...args: unknown[]) => void;
42
+ warn: (...args: unknown[]) => void;
43
+ error: (...args: unknown[]) => void;
44
+ }
45
+ export interface LarkSendMessageResult {
46
+ messageId?: string;
47
+ raw: unknown;
48
+ }
49
+ export type { IncomingLarkBotMenuAction, IncomingLarkCardAction, IncomingLarkMessage, IncomingLarkMessageRecall, LarkReactionHandle };
@@ -0,0 +1,18 @@
1
+ export const LARK_BOT_MENU_EVENT = "application.bot.menu_v6";
2
+ export const LARK_MESSAGE_RECEIVE_EVENT = "im.message.receive_v1";
3
+ export const LARK_MESSAGE_RECALLED_EVENT = "im.message.recalled_v1";
4
+ export const LARK_CARD_ACTION_TRIGGER_EVENT = "card.action.trigger";
5
+ export const LARK_REQUIRED_SCOPES = [
6
+ "im:message.p2p_msg:readonly",
7
+ "im:message.group_msg",
8
+ "im:message:readonly",
9
+ "im:message:send_as_bot",
10
+ "im:message:update",
11
+ "im:message:recall",
12
+ "im:message.reactions:write_only",
13
+ "im:chat:read",
14
+ "im:chat:create",
15
+ "im:chat:update",
16
+ "im:resource"
17
+ ];
18
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/lark/types.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,mBAAmB,GAAG,yBAAkC,CAAC;AACtE,MAAM,CAAC,MAAM,0BAA0B,GAAG,uBAAgC,CAAC;AAC3E,MAAM,CAAC,MAAM,2BAA2B,GAAG,wBAAiC,CAAC;AAC7E,MAAM,CAAC,MAAM,8BAA8B,GAAG,qBAA8B,CAAC;AAE7E,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,6BAA6B;IAC7B,sBAAsB;IACtB,qBAAqB;IACrB,wBAAwB;IACxB,mBAAmB;IACnB,mBAAmB;IACnB,iCAAiC;IACjC,cAAc;IACd,gBAAgB;IAChB,gBAAgB;IAChB,aAAa;CACL,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { TwinnyConfig } from "../types.js";
2
+ export interface WaitForRuntimeLockReleaseOptions {
3
+ home?: string;
4
+ timeoutMs?: number;
5
+ pollMs?: number;
6
+ }
7
+ export interface LaunchAgentCommandOptions {
8
+ home?: string;
9
+ }
10
+ export interface InstallLaunchAgentOptions extends LaunchAgentCommandOptions {
11
+ config?: TwinnyConfig;
12
+ entrypoint?: string;
13
+ environment?: Record<string, string | undefined>;
14
+ }
15
+ export declare function installLaunchAgent(options?: InstallLaunchAgentOptions): Promise<void>;
16
+ export declare function uninstallLaunchAgent(options?: LaunchAgentCommandOptions): Promise<void>;
17
+ export declare function startLaunchAgent(options?: LaunchAgentCommandOptions): Promise<void>;
18
+ export declare function stopLaunchAgent(options?: LaunchAgentCommandOptions): Promise<void>;
19
+ export declare function restartLaunchAgent(options?: LaunchAgentCommandOptions): Promise<void>;
20
+ export declare function waitForRuntimeLockRelease(options?: WaitForRuntimeLockReleaseOptions): Promise<void>;
21
+ export declare function statusLaunchAgent(options?: LaunchAgentCommandOptions): Promise<void>;
22
+ export declare function tailLogs(options?: LaunchAgentCommandOptions): Promise<void>;
@@ -0,0 +1,114 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { execa } from "execa";
5
+ import { createRuntimePaths, readConfigStatus, resolveTwinnyHome } from "../config/index.js";
6
+ import { isTwinnyLockHeld, readTwinnyLockPid } from "../lock/index.js";
7
+ import { createLaunchAgentPlist, launchAgentLabelForHomeRandom } from "./plist.js";
8
+ const defaultStopWaitTimeoutMs = 35_000;
9
+ const defaultStopWaitPollMs = 250;
10
+ const runtimeLockStaleMs = 30_000;
11
+ export async function installLaunchAgent(options = {}) {
12
+ const runtime = await resolveLaunchAgentRuntime(options);
13
+ const plistPath = runtime.plistPath;
14
+ fs.mkdirSync(path.dirname(plistPath), { recursive: true });
15
+ fs.writeFileSync(plistPath, createLaunchAgentPlist({
16
+ label: runtime.label,
17
+ twinnyHome: runtime.home,
18
+ entrypoint: options.entrypoint,
19
+ environment: options.environment
20
+ }), "utf8");
21
+ console.log(`Installed ${runtime.label} at ${plistPath}`);
22
+ }
23
+ export async function uninstallLaunchAgent(options = {}) {
24
+ const runtime = await resolveLaunchAgentRuntime(options);
25
+ const plistPath = runtime.plistPath;
26
+ await execa("launchctl", ["bootout", `gui/${process.getuid?.() ?? os.userInfo().uid}`, plistPath], {
27
+ reject: false
28
+ });
29
+ if (fs.existsSync(plistPath)) {
30
+ fs.rmSync(plistPath);
31
+ }
32
+ console.log(`Uninstalled ${runtime.label}`);
33
+ }
34
+ export async function startLaunchAgent(options = {}) {
35
+ const runtime = await resolveLaunchAgentRuntime(options);
36
+ const plistPath = runtime.plistPath;
37
+ if (!fs.existsSync(plistPath)) {
38
+ await installLaunchAgent(options);
39
+ return;
40
+ }
41
+ await execa("launchctl", ["bootstrap", `gui/${process.getuid?.() ?? os.userInfo().uid}`, plistPath], {
42
+ reject: false
43
+ });
44
+ await execa("launchctl", ["kickstart", "-k", `gui/${process.getuid?.() ?? os.userInfo().uid}/${runtime.label}`]);
45
+ console.log(`Started ${runtime.label}`);
46
+ }
47
+ export async function stopLaunchAgent(options = {}) {
48
+ const runtime = await resolveLaunchAgentRuntime(options);
49
+ await execa("launchctl", ["bootout", `gui/${process.getuid?.() ?? os.userInfo().uid}`, runtime.plistPath], {
50
+ reject: false
51
+ });
52
+ await waitForRuntimeLockRelease({ home: runtime.home });
53
+ console.log(`Stopped ${runtime.label}`);
54
+ }
55
+ export async function restartLaunchAgent(options = {}) {
56
+ await stopLaunchAgent(options);
57
+ await startLaunchAgent(options);
58
+ }
59
+ export async function waitForRuntimeLockRelease(options = {}) {
60
+ const paths = createRuntimePaths(options.home ?? resolveTwinnyHome());
61
+ const timeoutMs = options.timeoutMs ?? defaultStopWaitTimeoutMs;
62
+ const pollMs = options.pollMs ?? defaultStopWaitPollMs;
63
+ const deadline = Date.now() + timeoutMs;
64
+ while (await isTwinnyLockHeld(paths, { stale: runtimeLockStaleMs })) {
65
+ if (Date.now() >= deadline) {
66
+ const pid = await readTwinnyLockPid(paths, { stale: runtimeLockStaleMs });
67
+ const detail = pid ? `pid ${pid}` : "unknown pid";
68
+ throw new Error(`Timed out waiting for Twinny runtime lock to release (${detail})`);
69
+ }
70
+ await sleep(pollMs);
71
+ }
72
+ }
73
+ export async function statusLaunchAgent(options = {}) {
74
+ const runtime = await resolveLaunchAgentRuntime(options);
75
+ const result = await execa("launchctl", ["print", `gui/${process.getuid?.() ?? os.userInfo().uid}/${runtime.label}`], {
76
+ reject: false
77
+ });
78
+ if (result.exitCode === 0) {
79
+ console.log(result.stdout);
80
+ return;
81
+ }
82
+ console.log(`${runtime.label} is not loaded`);
83
+ }
84
+ export async function tailLogs(options = {}) {
85
+ const runtime = await resolveLaunchAgentRuntime(options);
86
+ const logPath = path.join(os.homedir(), "Library", "Logs", "twinny", `${runtime.label}.log`);
87
+ fs.mkdirSync(path.dirname(logPath), { recursive: true });
88
+ if (!fs.existsSync(logPath)) {
89
+ fs.writeFileSync(logPath, "", "utf8");
90
+ }
91
+ await execa("tail", ["-f", logPath], { stdio: "inherit" });
92
+ }
93
+ function getLaunchAgentPath(label) {
94
+ return path.join(os.homedir(), "Library", "LaunchAgents", `${label}.plist`);
95
+ }
96
+ async function resolveLaunchAgentRuntime(options = {}) {
97
+ const status = options.config
98
+ ? { complete: true, issues: [], config: options.config, paths: createRuntimePaths(options.config.home) }
99
+ : await readConfigStatus({ home: options.home });
100
+ if (!status.complete || !status.config) {
101
+ throw new Error(`Twinny home is not configured. Issues: ${status.issues.join("; ")}`);
102
+ }
103
+ const label = launchAgentLabelForHomeRandom(status.config.homeIdentity.random);
104
+ return {
105
+ home: status.paths.home,
106
+ label,
107
+ plistPath: getLaunchAgentPath(label),
108
+ config: status.config
109
+ };
110
+ }
111
+ function sleep(ms) {
112
+ return new Promise((resolve) => setTimeout(resolve, ms));
113
+ }
114
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/launchd/install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export declare const legacyLaunchAgentLabel = "com.twinny.daemon";
2
+ export declare const launchAgentLabelPrefix = "com.twinny.daemon";
3
+ export interface CreateLaunchAgentPlistOptions {
4
+ label?: string;
5
+ entrypoint?: string;
6
+ twinnyHome?: string;
7
+ environment?: Record<string, string | undefined>;
8
+ }
9
+ export declare function createLaunchAgentPlist(options?: CreateLaunchAgentPlistOptions): string;
10
+ export declare function launchAgentLabelForHomeRandom(homeRandom: string): string;
@@ -0,0 +1,61 @@
1
+ import { createHash } from "node:crypto";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ export const legacyLaunchAgentLabel = "com.twinny.daemon";
5
+ export const launchAgentLabelPrefix = "com.twinny.daemon";
6
+ export function createLaunchAgentPlist(options = {}) {
7
+ const label = options.label ?? legacyLaunchAgentLabel;
8
+ const entrypoint = options.entrypoint ? path.resolve(options.entrypoint) : process.argv[1] ? path.resolve(process.argv[1]) : process.execPath;
9
+ const logsDir = path.join(os.homedir(), "Library", "Logs", "twinny");
10
+ const stdout = path.join(logsDir, `${label}.log`);
11
+ const twinnyHome = options.twinnyHome ?? process.env.TWINNY_HOME ?? path.join(os.homedir(), ".twinny");
12
+ const args = entrypoint === process.execPath ? [process.execPath, "run"] : [process.execPath, entrypoint, "run"];
13
+ const environment = normalizeEnvironment({
14
+ ...(options.environment ?? {}),
15
+ TWINNY_HOME: twinnyHome
16
+ });
17
+ return `<?xml version="1.0" encoding="UTF-8"?>
18
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
19
+ <plist version="1.0">
20
+ <dict>
21
+ <key>Label</key>
22
+ <string>${escapeXml(label)}</string>
23
+ <key>ProgramArguments</key>
24
+ <array>
25
+ ${args.map((arg) => ` <string>${escapeXml(arg)}</string>`).join("\n")}
26
+ </array>
27
+ <key>EnvironmentVariables</key>
28
+ <dict>
29
+ ${Object.entries(environment).map(([key, value]) => ` <key>${escapeXml(key)}</key>\n <string>${escapeXml(value)}</string>`).join("\n")}
30
+ </dict>
31
+ <key>RunAtLoad</key>
32
+ <true/>
33
+ <key>KeepAlive</key>
34
+ <true/>
35
+ <key>StandardOutPath</key>
36
+ <string>${escapeXml(stdout)}</string>
37
+ <key>StandardErrorPath</key>
38
+ <string>${escapeXml(stdout)}</string>
39
+ </dict>
40
+ </plist>
41
+ `;
42
+ }
43
+ export function launchAgentLabelForHomeRandom(homeRandom) {
44
+ const homeId = createHash("sha256").update(homeRandom.trim().toLowerCase()).digest("hex").slice(0, 16);
45
+ return `${launchAgentLabelPrefix}.${homeId}`;
46
+ }
47
+ function escapeXml(value) {
48
+ return value
49
+ .replaceAll("&", "&amp;")
50
+ .replaceAll("<", "&lt;")
51
+ .replaceAll(">", "&gt;")
52
+ .replaceAll('"', "&quot;")
53
+ .replaceAll("'", "&apos;");
54
+ }
55
+ function normalizeEnvironment(environment) {
56
+ return Object.fromEntries(Object.entries(environment)
57
+ .filter(([key, value]) => key.trim() && value !== undefined)
58
+ .sort(([left], [right]) => left.localeCompare(right))
59
+ .map(([key, value]) => [key, String(value)]));
60
+ }
61
+ //# sourceMappingURL=plist.js.map