@rozek/nanoclaw 0.0.5 → 0.0.6

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 (132) hide show
  1. package/container/agent-runner/package-lock.json +1524 -0
  2. package/dist/cli.js +39 -4
  3. package/dist/cli.js.map +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +34 -0
  6. package/dist/index.js.map +1 -1
  7. package/package.json +7 -1
  8. package/.claude/settings.json +0 -1
  9. package/.claude/skills/add-compact/SKILL.md +0 -135
  10. package/.claude/skills/add-discord/SKILL.md +0 -203
  11. package/.claude/skills/add-gmail/SKILL.md +0 -220
  12. package/.claude/skills/add-image-vision/SKILL.md +0 -94
  13. package/.claude/skills/add-ollama-tool/SKILL.md +0 -153
  14. package/.claude/skills/add-parallel/SKILL.md +0 -290
  15. package/.claude/skills/add-pdf-reader/SKILL.md +0 -104
  16. package/.claude/skills/add-reactions/SKILL.md +0 -117
  17. package/.claude/skills/add-slack/SKILL.md +0 -207
  18. package/.claude/skills/add-telegram/SKILL.md +0 -222
  19. package/.claude/skills/add-telegram-swarm/SKILL.md +0 -384
  20. package/.claude/skills/add-voice-transcription/SKILL.md +0 -148
  21. package/.claude/skills/add-whatsapp/SKILL.md +0 -372
  22. package/.claude/skills/convert-to-apple-container/SKILL.md +0 -175
  23. package/.claude/skills/customize/SKILL.md +0 -110
  24. package/.claude/skills/debug/SKILL.md +0 -349
  25. package/.claude/skills/get-qodo-rules/SKILL.md +0 -122
  26. package/.claude/skills/get-qodo-rules/references/output-format.md +0 -41
  27. package/.claude/skills/get-qodo-rules/references/pagination.md +0 -33
  28. package/.claude/skills/get-qodo-rules/references/repository-scope.md +0 -26
  29. package/.claude/skills/qodo-pr-resolver/SKILL.md +0 -326
  30. package/.claude/skills/qodo-pr-resolver/resources/providers.md +0 -329
  31. package/.claude/skills/setup/SKILL.md +0 -218
  32. package/.claude/skills/update-nanoclaw/SKILL.md +0 -235
  33. package/.claude/skills/update-skills/SKILL.md +0 -130
  34. package/.claude/skills/use-local-whisper/SKILL.md +0 -152
  35. package/.claude/skills/x-integration/SKILL.md +0 -417
  36. package/.claude/skills/x-integration/agent.ts +0 -243
  37. package/.claude/skills/x-integration/host.ts +0 -159
  38. package/.claude/skills/x-integration/lib/browser.ts +0 -148
  39. package/.claude/skills/x-integration/lib/config.ts +0 -62
  40. package/.claude/skills/x-integration/scripts/like.ts +0 -56
  41. package/.claude/skills/x-integration/scripts/post.ts +0 -66
  42. package/.claude/skills/x-integration/scripts/quote.ts +0 -80
  43. package/.claude/skills/x-integration/scripts/reply.ts +0 -74
  44. package/.claude/skills/x-integration/scripts/retweet.ts +0 -62
  45. package/.claude/skills/x-integration/scripts/setup.ts +0 -87
  46. package/.env.example +0 -1
  47. package/.github/CODEOWNERS +0 -10
  48. package/.github/PULL_REQUEST_TEMPLATE.md +0 -14
  49. package/.github/workflows/bump-version.yml +0 -32
  50. package/.github/workflows/ci.yml +0 -25
  51. package/.github/workflows/merge-forward-skills.yml +0 -160
  52. package/.github/workflows/update-tokens.yml +0 -42
  53. package/.husky/pre-commit +0 -1
  54. package/.mcp.json +0 -3
  55. package/.nvmrc +0 -1
  56. package/.prettierrc +0 -3
  57. package/CHANGELOG.md +0 -8
  58. package/CONTRIBUTING.md +0 -23
  59. package/CONTRIBUTORS.md +0 -15
  60. package/NanoClaw_with_Web-Support.md +0 -326
  61. package/README_zh.md +0 -200
  62. package/assets/nanoclaw-favicon.png +0 -0
  63. package/assets/nanoclaw-icon.png +0 -0
  64. package/assets/nanoclaw-logo-dark.png +0 -0
  65. package/assets/nanoclaw-logo.png +0 -0
  66. package/assets/nanoclaw-profile.jpeg +0 -0
  67. package/assets/nanoclaw-sales.png +0 -0
  68. package/assets/social-preview.jpg +0 -0
  69. package/config-examples/mount-allowlist.json +0 -25
  70. package/docs/APPLE-CONTAINER-NETWORKING.md +0 -90
  71. package/docs/DEBUG_CHECKLIST.md +0 -143
  72. package/docs/REQUIREMENTS.md +0 -196
  73. package/docs/SDK_DEEP_DIVE.md +0 -643
  74. package/docs/SECURITY.md +0 -122
  75. package/docs/SPEC.md +0 -785
  76. package/docs/docker-sandboxes.md +0 -359
  77. package/docs/nanoclaw-architecture-final.md +0 -1063
  78. package/docs/nanorepo-architecture.md +0 -168
  79. package/docs/skills-as-branches.md +0 -662
  80. package/groups/global/CLAUDE.md +0 -58
  81. package/groups/main/CLAUDE.md +0 -246
  82. package/launchd/com.nanoclaw.plist +0 -32
  83. package/repo-tokens/README.md +0 -113
  84. package/repo-tokens/action.yml +0 -186
  85. package/repo-tokens/badge.svg +0 -23
  86. package/repo-tokens/examples/green.svg +0 -14
  87. package/repo-tokens/examples/red.svg +0 -14
  88. package/repo-tokens/examples/yellow-green.svg +0 -14
  89. package/repo-tokens/examples/yellow.svg +0 -14
  90. package/scripts/run-migrations.ts +0 -105
  91. package/setup.sh +0 -161
  92. package/src/channels/index.ts +0 -15
  93. package/src/channels/registry.test.ts +0 -42
  94. package/src/channels/registry.ts +0 -32
  95. package/src/channels/web.ts +0 -1931
  96. package/src/cli.ts +0 -254
  97. package/src/config.ts +0 -73
  98. package/src/container-runner.test.ts +0 -210
  99. package/src/container-runner.ts +0 -768
  100. package/src/container-runtime.test.ts +0 -149
  101. package/src/container-runtime.ts +0 -127
  102. package/src/credential-proxy.test.ts +0 -192
  103. package/src/credential-proxy.ts +0 -125
  104. package/src/db.test.ts +0 -484
  105. package/src/db.ts +0 -803
  106. package/src/env.ts +0 -42
  107. package/src/formatting.test.ts +0 -256
  108. package/src/group-folder.test.ts +0 -43
  109. package/src/group-folder.ts +0 -44
  110. package/src/group-queue.test.ts +0 -484
  111. package/src/group-queue.ts +0 -379
  112. package/src/index.ts +0 -854
  113. package/src/ipc-auth.test.ts +0 -679
  114. package/src/ipc.ts +0 -461
  115. package/src/logger.ts +0 -16
  116. package/src/mount-security.ts +0 -419
  117. package/src/remote-control.test.ts +0 -397
  118. package/src/remote-control.ts +0 -224
  119. package/src/router.ts +0 -52
  120. package/src/routing.test.ts +0 -170
  121. package/src/sender-allowlist.test.ts +0 -216
  122. package/src/sender-allowlist.ts +0 -128
  123. package/src/session-commands.test.ts +0 -247
  124. package/src/session-commands.ts +0 -163
  125. package/src/task-scheduler.test.ts +0 -129
  126. package/src/task-scheduler.ts +0 -328
  127. package/src/timezone.test.ts +0 -29
  128. package/src/timezone.ts +0 -16
  129. package/src/types.ts +0 -109
  130. package/tsconfig.json +0 -20
  131. package/vitest.config.ts +0 -7
  132. package/vitest.skills.config.ts +0 -7
@@ -1,328 +0,0 @@
1
- import { ChildProcess } from 'child_process';
2
- import { CronExpressionParser } from 'cron-parser';
3
- import fs from 'fs';
4
-
5
- import { ASSISTANT_NAME, SCHEDULER_POLL_INTERVAL, TIMEZONE } from './config.js';
6
- import {
7
- ContainerOutput,
8
- runContainerAgent,
9
- writeTasksSnapshot,
10
- } from './container-runner.js';
11
- import {
12
- getAllTasks,
13
- getDueTasks,
14
- getTaskById,
15
- logTaskRun,
16
- updateTask,
17
- updateTaskAfterRun,
18
- } from './db.js';
19
- import { GroupQueue } from './group-queue.js';
20
- import { resolveGroupFolderPath } from './group-folder.js';
21
- import { logger } from './logger.js';
22
- import { RegisteredGroup, ScheduledTask } from './types.js';
23
-
24
- // Web-channel JID prefix and dedicated cron session JID.
25
- // Scheduled task output for web sessions is always routed to the cron session
26
- // so users see it in one dedicated place instead of the originating session.
27
- const WEB_JID_PREFIX = 'local@web-';
28
- const WEB_JID_LEGACY = 'local@web'; // Legacy JID used before per-session JIDs were introduced
29
- const CRON_SESSION_JID = 'local@web-cron';
30
-
31
- /**
32
- * Compute the next run time for a recurring task, anchored to the
33
- * task's scheduled time rather than Date.now() to prevent cumulative
34
- * drift on interval-based tasks.
35
- *
36
- * Co-authored-by: @community-pr-601
37
- */
38
- export function computeNextRun(task: ScheduledTask): string | null {
39
- if (task.schedule_type === 'once') return null;
40
-
41
- const now = Date.now();
42
-
43
- if (task.schedule_type === 'cron') {
44
- const interval = CronExpressionParser.parse(task.schedule_value, {
45
- tz: TIMEZONE,
46
- });
47
- return interval.next().toISOString();
48
- }
49
-
50
- if (task.schedule_type === 'interval') {
51
- const ms = parseInt(task.schedule_value, 10);
52
- if (!ms || ms <= 0) {
53
- // Guard against malformed interval that would cause an infinite loop
54
- logger.warn(
55
- { taskId: task.id, value: task.schedule_value },
56
- 'Invalid interval value',
57
- );
58
- return new Date(now + 60_000).toISOString();
59
- }
60
- // Anchor to the scheduled time, not now, to prevent drift.
61
- // Skip past any missed intervals so we always land in the future.
62
- let next = new Date(task.next_run!).getTime() + ms;
63
- while (next <= now) {
64
- next += ms;
65
- }
66
- return new Date(next).toISOString();
67
- }
68
-
69
- return null;
70
- }
71
-
72
- export interface SchedulerDependencies {
73
- registeredGroups: () => Record<string, RegisteredGroup>;
74
- getSessions: () => Record<string, string>;
75
- queue: GroupQueue;
76
- onProcess: (
77
- groupJid: string,
78
- proc: ChildProcess,
79
- containerName: string,
80
- groupFolder: string,
81
- ) => void;
82
- sendMessage: (jid: string, text: string) => Promise<void>;
83
- }
84
-
85
- async function runTask(
86
- task: ScheduledTask,
87
- deps: SchedulerDependencies,
88
- ): Promise<void> {
89
- const startTime = Date.now();
90
- let groupDir: string;
91
- try {
92
- groupDir = resolveGroupFolderPath(task.group_folder);
93
- } catch (err) {
94
- const error = err instanceof Error ? err.message : String(err);
95
- // Stop retry churn for malformed legacy rows.
96
- updateTask(task.id, { status: 'paused' });
97
- logger.error(
98
- { taskId: task.id, groupFolder: task.group_folder, error },
99
- 'Task has invalid group folder',
100
- );
101
- logTaskRun({
102
- task_id: task.id,
103
- run_at: new Date().toISOString(),
104
- duration_ms: Date.now() - startTime,
105
- status: 'error',
106
- result: null,
107
- error,
108
- });
109
- return;
110
- }
111
- fs.mkdirSync(groupDir, { recursive: true });
112
-
113
- logger.info(
114
- { taskId: task.id, group: task.group_folder },
115
- 'Running scheduled task',
116
- );
117
-
118
- const groups = deps.registeredGroups();
119
- let group = Object.values(groups).find((g) => g.folder === task.group_folder);
120
-
121
- if (!group) {
122
- // Fall back to the first isMain group so that legacy tasks created with
123
- // group_folder='main' still run after a web-channel migration.
124
- const fallback = Object.values(groups).find((g) => g.isMain === true);
125
- if (fallback) {
126
- logger.warn(
127
- {
128
- taskId: task.id,
129
- groupFolder: task.group_folder,
130
- fallback: fallback.folder,
131
- },
132
- 'Group not found for task, falling back to main group',
133
- );
134
- group = fallback;
135
- } else {
136
- logger.error(
137
- { taskId: task.id, groupFolder: task.group_folder },
138
- 'Group not found for task',
139
- );
140
- logTaskRun({
141
- task_id: task.id,
142
- run_at: new Date().toISOString(),
143
- duration_ms: Date.now() - startTime,
144
- status: 'error',
145
- result: null,
146
- error: `Group not found: ${task.group_folder}`,
147
- });
148
- return;
149
- }
150
- }
151
-
152
- // Update tasks snapshot for container to read (filtered by group)
153
- const isMain = group.isMain === true;
154
- const tasks = getAllTasks();
155
- writeTasksSnapshot(
156
- group.folder,
157
- isMain,
158
- tasks.map((t) => ({
159
- id: t.id,
160
- groupFolder: t.group_folder,
161
- prompt: t.prompt,
162
- schedule_type: t.schedule_type,
163
- schedule_value: t.schedule_value,
164
- status: t.status,
165
- next_run: t.next_run,
166
- })),
167
- );
168
-
169
- let result: string | null = null;
170
- let error: string | null = null;
171
-
172
- // For web sessions, display output in the dedicated cron session instead of
173
- // the originating session, so all scheduled-task output is in one place.
174
- // Also handle legacy JID 'local@web' (without suffix) used before per-session JIDs.
175
- const displayJid =
176
- task.chat_jid === WEB_JID_LEGACY || task.chat_jid.startsWith(WEB_JID_PREFIX)
177
- ? CRON_SESSION_JID
178
- : task.chat_jid;
179
-
180
- // For group context mode, look up the session by chatJid first (per-session key),
181
- // then fall back to group_folder (backward compatibility).
182
- const sessions = deps.getSessions();
183
- const sessionId =
184
- task.context_mode === 'group'
185
- ? (sessions[task.chat_jid] ?? sessions[task.group_folder])
186
- : undefined;
187
-
188
- // Each task gets its own queue JID so it runs in parallel with user messages
189
- // and with other tasks, without blocking the user's message queue slot.
190
- const taskQueueJid = `task:${task.id}`;
191
-
192
- // Send a header to the cron session so the user knows which task is running.
193
- const promptPreview = task.prompt.split('\n')[0].slice(0, 80);
194
- const scheduleLabel =
195
- task.schedule_type === 'interval'
196
- ? `every ${Math.round(parseInt(task.schedule_value, 10) / 60000)} min`
197
- : task.schedule_value;
198
- const taskHeader = `---\n**Task #${task.id}** | ${scheduleLabel}\n> ${promptPreview}`;
199
- await deps.sendMessage(displayJid, taskHeader);
200
-
201
- // After the task produces a result, close the container promptly.
202
- // Tasks are single-turn — no need to wait IDLE_TIMEOUT (30 min) for the
203
- // query loop to time out. A short delay handles any final MCP calls.
204
- const TASK_CLOSE_DELAY_MS = 10000;
205
- let closeTimer: ReturnType<typeof setTimeout> | null = null;
206
-
207
- const scheduleClose = () => {
208
- if (closeTimer) return; // already scheduled
209
- closeTimer = setTimeout(() => {
210
- logger.debug({ taskId: task.id }, 'Closing task container after result');
211
- deps.queue.closeStdin(taskQueueJid);
212
- }, TASK_CLOSE_DELAY_MS);
213
- };
214
-
215
- try {
216
- const output = await runContainerAgent(
217
- group,
218
- {
219
- prompt: task.prompt,
220
- sessionId,
221
- groupFolder: group.folder,
222
- chatJid: task.chat_jid,
223
- isMain,
224
- isScheduledTask: true,
225
- assistantName: ASSISTANT_NAME,
226
- },
227
- (proc, containerName) =>
228
- deps.onProcess(taskQueueJid, proc, containerName, group.folder),
229
- async (streamedOutput: ContainerOutput) => {
230
- if (streamedOutput.result) {
231
- result = streamedOutput.result;
232
- // Forward result to the display JID (cron session for web tasks)
233
- await deps.sendMessage(displayJid, streamedOutput.result);
234
- scheduleClose();
235
- }
236
- if (streamedOutput.status === 'success') {
237
- deps.queue.notifyIdle(taskQueueJid);
238
- scheduleClose(); // Close promptly even when result is null (e.g. IPC-only tasks)
239
- }
240
- if (streamedOutput.status === 'error') {
241
- error = streamedOutput.error || 'Unknown error';
242
- }
243
- },
244
- );
245
-
246
- if (closeTimer) clearTimeout(closeTimer);
247
-
248
- if (output.status === 'error') {
249
- error = output.error || 'Unknown error';
250
- } else if (output.result) {
251
- // Result was already forwarded to the user via the streaming callback above
252
- result = output.result;
253
- }
254
-
255
- logger.info(
256
- { taskId: task.id, durationMs: Date.now() - startTime },
257
- 'Task completed',
258
- );
259
- } catch (err) {
260
- if (closeTimer) clearTimeout(closeTimer);
261
- error = err instanceof Error ? err.message : String(err);
262
- logger.error({ taskId: task.id, error }, 'Task failed');
263
- }
264
-
265
- const durationMs = Date.now() - startTime;
266
-
267
- logTaskRun({
268
- task_id: task.id,
269
- run_at: new Date().toISOString(),
270
- duration_ms: durationMs,
271
- status: error ? 'error' : 'success',
272
- result,
273
- error,
274
- });
275
-
276
- const nextRun = computeNextRun(task);
277
- const resultSummary = error
278
- ? `Error: ${error}`
279
- : result
280
- ? result.slice(0, 200)
281
- : 'Completed';
282
- updateTaskAfterRun(task.id, nextRun, resultSummary);
283
- }
284
-
285
- let schedulerRunning = false;
286
-
287
- export function startSchedulerLoop(deps: SchedulerDependencies): void {
288
- if (schedulerRunning) {
289
- logger.debug('Scheduler loop already running, skipping duplicate start');
290
- return;
291
- }
292
- schedulerRunning = true;
293
- logger.info('Scheduler loop started');
294
-
295
- const loop = async () => {
296
- try {
297
- const dueTasks = getDueTasks();
298
- if (dueTasks.length > 0) {
299
- logger.info({ count: dueTasks.length }, 'Found due tasks');
300
- }
301
-
302
- for (const task of dueTasks) {
303
- // Re-check task status in case it was paused/cancelled
304
- const currentTask = getTaskById(task.id);
305
- if (!currentTask || currentTask.status !== 'active') {
306
- continue;
307
- }
308
-
309
- // Use a task-specific queue JID so the task runs in parallel with
310
- // user messages and other tasks (not serialized on the group's slot).
311
- deps.queue.enqueueTask(`task:${currentTask.id}`, currentTask.id, () =>
312
- runTask(currentTask, deps),
313
- );
314
- }
315
- } catch (err) {
316
- logger.error({ err }, 'Error in scheduler loop');
317
- }
318
-
319
- setTimeout(loop, SCHEDULER_POLL_INTERVAL);
320
- };
321
-
322
- loop();
323
- }
324
-
325
- /** @internal - for tests only. */
326
- export function _resetSchedulerLoopForTests(): void {
327
- schedulerRunning = false;
328
- }
@@ -1,29 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
-
3
- import { formatLocalTime } from './timezone.js';
4
-
5
- // --- formatLocalTime ---
6
-
7
- describe('formatLocalTime', () => {
8
- it('converts UTC to local time display', () => {
9
- // 2026-02-04T18:30:00Z in America/New_York (EST, UTC-5) = 1:30 PM
10
- const result = formatLocalTime(
11
- '2026-02-04T18:30:00.000Z',
12
- 'America/New_York',
13
- );
14
- expect(result).toContain('1:30');
15
- expect(result).toContain('PM');
16
- expect(result).toContain('Feb');
17
- expect(result).toContain('2026');
18
- });
19
-
20
- it('handles different timezones', () => {
21
- // Same UTC time should produce different local times
22
- const utc = '2026-06-15T12:00:00.000Z';
23
- const ny = formatLocalTime(utc, 'America/New_York');
24
- const tokyo = formatLocalTime(utc, 'Asia/Tokyo');
25
- // NY is UTC-4 in summer (EDT), Tokyo is UTC+9
26
- expect(ny).toContain('8:00');
27
- expect(tokyo).toContain('9:00');
28
- });
29
- });
package/src/timezone.ts DELETED
@@ -1,16 +0,0 @@
1
- /**
2
- * Convert a UTC ISO timestamp to a localized display string.
3
- * Uses the Intl API (no external dependencies).
4
- */
5
- export function formatLocalTime(utcIso: string, timezone: string): string {
6
- const date = new Date(utcIso);
7
- return date.toLocaleString('en-US', {
8
- timeZone: timezone,
9
- year: 'numeric',
10
- month: 'short',
11
- day: 'numeric',
12
- hour: 'numeric',
13
- minute: '2-digit',
14
- hour12: true,
15
- });
16
- }
package/src/types.ts DELETED
@@ -1,109 +0,0 @@
1
- export interface AdditionalMount {
2
- hostPath: string; // Absolute path on host (supports ~ for home)
3
- containerPath?: string; // Optional — defaults to basename of hostPath. Mounted at /workspace/extra/{value}
4
- readonly?: boolean; // Default: true for safety
5
- }
6
-
7
- /**
8
- * Mount Allowlist - Security configuration for additional mounts
9
- * This file should be stored at ~/.config/nanoclaw/mount-allowlist.json
10
- * and is NOT mounted into any container, making it tamper-proof from agents.
11
- */
12
- export interface MountAllowlist {
13
- // Directories that can be mounted into containers
14
- allowedRoots: AllowedRoot[];
15
- // Glob patterns for paths that should never be mounted (e.g., ".ssh", ".gnupg")
16
- blockedPatterns: string[];
17
- // If true, non-main groups can only mount read-only regardless of config
18
- nonMainReadOnly: boolean;
19
- }
20
-
21
- export interface AllowedRoot {
22
- // Absolute path or ~ for home (e.g., "~/projects", "/var/repos")
23
- path: string;
24
- // Whether read-write mounts are allowed under this root
25
- allowReadWrite: boolean;
26
- // Optional description for documentation
27
- description?: string;
28
- }
29
-
30
- export interface ContainerConfig {
31
- additionalMounts?: AdditionalMount[];
32
- timeout?: number; // Default: 300000 (5 minutes)
33
- }
34
-
35
- export interface RegisteredGroup {
36
- name: string;
37
- folder: string;
38
- trigger: string;
39
- added_at: string;
40
- containerConfig?: ContainerConfig;
41
- requiresTrigger?: boolean; // Default: true for groups, false for solo chats
42
- isMain?: boolean; // True for the main control group (no trigger, elevated privileges)
43
- }
44
-
45
- export interface NewMessage {
46
- id: string;
47
- chat_jid: string;
48
- sender: string;
49
- sender_name: string;
50
- content: string;
51
- timestamp: string;
52
- is_from_me?: boolean;
53
- is_bot_message?: boolean;
54
- }
55
-
56
- export interface ScheduledTask {
57
- id: string;
58
- group_folder: string;
59
- chat_jid: string;
60
- prompt: string;
61
- schedule_type: 'cron' | 'interval' | 'once';
62
- schedule_value: string;
63
- context_mode: 'group' | 'isolated';
64
- next_run: string | null;
65
- last_run: string | null;
66
- last_result: string | null;
67
- status: 'active' | 'paused' | 'completed';
68
- created_at: string;
69
- }
70
-
71
- export interface TaskRunLog {
72
- task_id: string;
73
- run_at: string;
74
- duration_ms: number;
75
- status: 'success' | 'error';
76
- result: string | null;
77
- error: string | null;
78
- }
79
-
80
- // --- Channel abstraction ---
81
-
82
- export interface Channel {
83
- name: string;
84
- connect(): Promise<void>;
85
- sendMessage(jid: string, text: string): Promise<void>;
86
- isConnected(): boolean;
87
- ownsJid(jid: string): boolean;
88
- disconnect(): Promise<void>;
89
- // Optional: typing indicator. Channels that support it implement it.
90
- setTyping?(jid: string, isTyping: boolean): Promise<void>;
91
- // Optional: sync group/chat names from the platform.
92
- syncGroups?(force: boolean): Promise<void>;
93
- // Optional: live tool-use status. Call with null to clear the status display.
94
- setStatus?(jid: string, tool: string | null, inputSnippet?: string): void;
95
- }
96
-
97
- // Callback type that channels use to deliver inbound messages
98
- export type OnInboundMessage = (chatJid: string, message: NewMessage) => void;
99
-
100
- // Callback for chat metadata discovery.
101
- // name is optional — channels that deliver names inline (Telegram) pass it here;
102
- // channels that sync names separately (via syncGroups) omit it.
103
- export type OnChatMetadata = (
104
- chatJid: string,
105
- timestamp: string,
106
- name?: string,
107
- channel?: string,
108
- isGroup?: boolean,
109
- ) => void;
package/tsconfig.json DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "lib": ["ES2022"],
7
- "outDir": "./dist",
8
- "rootDir": "./src",
9
- "strict": true,
10
- "esModuleInterop": true,
11
- "skipLibCheck": true,
12
- "forceConsistentCasingInFileNames": true,
13
- "resolveJsonModule": true,
14
- "declaration": true,
15
- "declarationMap": true,
16
- "sourceMap": true
17
- },
18
- "exclude": ["node_modules", "dist", "setup/**/*.test.ts"],
19
- "include": ["src/**/*"]
20
- }
package/vitest.config.ts DELETED
@@ -1,7 +0,0 @@
1
- import { defineConfig } from 'vitest/config';
2
-
3
- export default defineConfig({
4
- test: {
5
- include: ['src/**/*.test.ts', 'setup/**/*.test.ts'],
6
- },
7
- });
@@ -1,7 +0,0 @@
1
- import { defineConfig } from 'vitest/config';
2
-
3
- export default defineConfig({
4
- test: {
5
- include: ['.claude/skills/**/tests/*.test.ts'],
6
- },
7
- });