@questionbase/deskfree 0.3.0-alpha.8 → 0.4.0-alpha.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 (78) hide show
  1. package/dist/bin.d.ts +1 -0
  2. package/dist/bin.js +14115 -0
  3. package/dist/bin.js.map +1 -0
  4. package/dist/cli/install.d.ts +3 -0
  5. package/dist/cli/install.js +53 -0
  6. package/dist/cli/install.js.map +1 -0
  7. package/dist/cli/uninstall.d.ts +3 -0
  8. package/dist/cli/uninstall.js +36 -0
  9. package/dist/cli/uninstall.js.map +1 -0
  10. package/dist/index.d.ts +419 -12
  11. package/dist/index.js +13801 -23
  12. package/dist/index.js.map +1 -1
  13. package/package.json +37 -46
  14. package/README.md +0 -137
  15. package/dist/channel.d.ts +0 -3
  16. package/dist/channel.d.ts.map +0 -1
  17. package/dist/channel.js +0 -529
  18. package/dist/channel.js.map +0 -1
  19. package/dist/client.d.ts +0 -184
  20. package/dist/client.d.ts.map +0 -1
  21. package/dist/client.js +0 -264
  22. package/dist/client.js.map +0 -1
  23. package/dist/context.d.ts +0 -15
  24. package/dist/context.d.ts.map +0 -1
  25. package/dist/context.js +0 -31
  26. package/dist/context.js.map +0 -1
  27. package/dist/deliver.d.ts +0 -22
  28. package/dist/deliver.d.ts.map +0 -1
  29. package/dist/deliver.js +0 -432
  30. package/dist/deliver.js.map +0 -1
  31. package/dist/error-reporter.d.ts +0 -39
  32. package/dist/error-reporter.d.ts.map +0 -1
  33. package/dist/error-reporter.js +0 -94
  34. package/dist/error-reporter.js.map +0 -1
  35. package/dist/gateway.d.ts +0 -13
  36. package/dist/gateway.d.ts.map +0 -1
  37. package/dist/gateway.js +0 -770
  38. package/dist/gateway.js.map +0 -1
  39. package/dist/index.d.ts.map +0 -1
  40. package/dist/llm-definitions.d.ts +0 -117
  41. package/dist/llm-definitions.d.ts.map +0 -1
  42. package/dist/llm-definitions.js +0 -121
  43. package/dist/llm-definitions.js.map +0 -1
  44. package/dist/offline-queue.d.ts +0 -45
  45. package/dist/offline-queue.d.ts.map +0 -1
  46. package/dist/offline-queue.js +0 -109
  47. package/dist/offline-queue.js.map +0 -1
  48. package/dist/paths.d.ts +0 -10
  49. package/dist/paths.d.ts.map +0 -1
  50. package/dist/paths.js +0 -29
  51. package/dist/paths.js.map +0 -1
  52. package/dist/runtime.d.ts +0 -17
  53. package/dist/runtime.d.ts.map +0 -1
  54. package/dist/runtime.js +0 -24
  55. package/dist/runtime.js.map +0 -1
  56. package/dist/streaming.d.ts +0 -44
  57. package/dist/streaming.d.ts.map +0 -1
  58. package/dist/streaming.js +0 -125
  59. package/dist/streaming.js.map +0 -1
  60. package/dist/tools.d.ts +0 -23
  61. package/dist/tools.d.ts.map +0 -1
  62. package/dist/tools.js +0 -437
  63. package/dist/tools.js.map +0 -1
  64. package/dist/types.d.ts +0 -484
  65. package/dist/types.d.ts.map +0 -1
  66. package/dist/types.js +0 -2
  67. package/dist/types.js.map +0 -1
  68. package/dist/version.d.ts +0 -2
  69. package/dist/version.d.ts.map +0 -1
  70. package/dist/version.js +0 -4
  71. package/dist/version.js.map +0 -1
  72. package/dist/workspace.d.ts +0 -18
  73. package/dist/workspace.d.ts.map +0 -1
  74. package/dist/workspace.js +0 -83
  75. package/dist/workspace.js.map +0 -1
  76. package/openclaw.plugin.json +0 -8
  77. package/skills/deskfree/SKILL.md +0 -243
  78. package/skills/deskfree/references/tools.md +0 -102
@@ -0,0 +1,3 @@
1
+ declare function install(token: string): void;
2
+
3
+ export { install };
@@ -0,0 +1,53 @@
1
+ import { createRequire } from 'node:module';
2
+ import { execSync } from 'child_process';
3
+ import { writeFileSync, chmodSync } from 'fs';
4
+
5
+ createRequire(import.meta.url);
6
+ var SERVICE_NAME = "deskfree-agent";
7
+ var SERVICE_FILE = `/etc/systemd/system/${SERVICE_NAME}.service`;
8
+ var ENV_FILE = `/etc/${SERVICE_NAME}.env`;
9
+ var PACKAGE = "@questionbase/deskfree-agents-sdk@latest";
10
+ function install(token) {
11
+ if (process.getuid?.() !== 0) {
12
+ console.error("Error: install must be run as root (use sudo)");
13
+ process.exit(1);
14
+ }
15
+ let npxPath;
16
+ try {
17
+ npxPath = execSync("which npx", { encoding: "utf8" }).trim();
18
+ } catch {
19
+ console.error("Error: npx not found in PATH");
20
+ process.exit(1);
21
+ }
22
+ writeFileSync(ENV_FILE, `DESKFREE_LAUNCH=${token}
23
+ `, { mode: 384 });
24
+ chmodSync(ENV_FILE, 384);
25
+ console.log(`Wrote ${ENV_FILE}`);
26
+ const unit = `[Unit]
27
+ Description=DeskFree Agent
28
+ After=network-online.target
29
+ Wants=network-online.target
30
+
31
+ [Service]
32
+ Type=simple
33
+ ExecStart=${npxPath} ${PACKAGE} start
34
+ EnvironmentFile=${ENV_FILE}
35
+ Environment=NODE_ENV=production
36
+ Restart=always
37
+ RestartSec=10
38
+
39
+ [Install]
40
+ WantedBy=multi-user.target
41
+ `;
42
+ writeFileSync(SERVICE_FILE, unit);
43
+ console.log(`Wrote ${SERVICE_FILE}`);
44
+ execSync("systemctl daemon-reload");
45
+ execSync(`systemctl enable ${SERVICE_NAME}`);
46
+ execSync(`systemctl start ${SERVICE_NAME}`);
47
+ console.log(`Service ${SERVICE_NAME} installed and started.`);
48
+ console.log(`Check status: systemctl status ${SERVICE_NAME}`);
49
+ }
50
+
51
+ export { install };
52
+ //# sourceMappingURL=install.js.map
53
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/install.ts"],"names":[],"mappings":";;;;;AAGA,IAAM,YAAA,GAAe,gBAAA;AACrB,IAAM,YAAA,GAAe,uBAAuB,YAAY,CAAA,QAAA,CAAA;AACxD,IAAM,QAAA,GAAW,QAAQ,YAAY,CAAA,IAAA,CAAA;AACrC,IAAM,OAAA,GAAU,0CAAA;AAET,SAAS,QAAQ,KAAA,EAAqB;AAC3C,EAAA,IAAI,OAAA,CAAQ,MAAA,IAAS,KAAM,CAAA,EAAG;AAC5B,IAAA,OAAA,CAAQ,MAAM,+CAA+C,CAAA;AAC7D,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AAGA,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI;AACF,IAAA,OAAA,GAAU,SAAS,WAAA,EAAa,EAAE,UAAU,MAAA,EAAQ,EAAE,IAAA,EAAK;AAAA,EAC7D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAA,CAAQ,MAAM,8BAA8B,CAAA;AAC5C,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AAGA,EAAA,aAAA,CAAc,QAAA,EAAU,mBAAmB,KAAK;AAAA,CAAA,EAAM,EAAE,IAAA,EAAM,GAAA,EAAO,CAAA;AACrE,EAAA,SAAA,CAAU,UAAU,GAAK,CAAA;AACzB,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,MAAA,EAAS,QAAQ,CAAA,CAAE,CAAA;AAG/B,EAAA,MAAM,IAAA,GAAO,CAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,UAAA,EAOH,OAAO,IAAI,OAAO,CAAA;AAAA,gBAAA,EACZ,QAAQ;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,CAAA;AASxB,EAAA,aAAA,CAAc,cAAc,IAAI,CAAA;AAChC,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,MAAA,EAAS,YAAY,CAAA,CAAE,CAAA;AAGnC,EAAA,QAAA,CAAS,yBAAyB,CAAA;AAClC,EAAA,QAAA,CAAS,CAAA,iBAAA,EAAoB,YAAY,CAAA,CAAE,CAAA;AAC3C,EAAA,QAAA,CAAS,CAAA,gBAAA,EAAmB,YAAY,CAAA,CAAE,CAAA;AAE1C,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,QAAA,EAAW,YAAY,CAAA,uBAAA,CAAyB,CAAA;AAC5D,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,+BAAA,EAAkC,YAAY,CAAA,CAAE,CAAA;AAC9D","file":"install.js","sourcesContent":["import { execSync } from 'node:child_process';\nimport { chmodSync, writeFileSync } from 'node:fs';\n\nconst SERVICE_NAME = 'deskfree-agent';\nconst SERVICE_FILE = `/etc/systemd/system/${SERVICE_NAME}.service`;\nconst ENV_FILE = `/etc/${SERVICE_NAME}.env`;\nconst PACKAGE = '@questionbase/deskfree-agents-sdk@latest';\n\nexport function install(token: string): void {\n if (process.getuid?.() !== 0) {\n console.error('Error: install must be run as root (use sudo)');\n process.exit(1);\n }\n\n // Resolve full npx path so systemd doesn't depend on PATH\n let npxPath: string;\n try {\n npxPath = execSync('which npx', { encoding: 'utf8' }).trim();\n } catch {\n console.error('Error: npx not found in PATH');\n process.exit(1);\n }\n\n // Write env file with token (chmod 600 — only root can read)\n writeFileSync(ENV_FILE, `DESKFREE_LAUNCH=${token}\\n`, { mode: 0o600 });\n chmodSync(ENV_FILE, 0o600);\n console.log(`Wrote ${ENV_FILE}`);\n\n // Write systemd unit file\n const unit = `[Unit]\nDescription=DeskFree Agent\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nExecStart=${npxPath} ${PACKAGE} start\nEnvironmentFile=${ENV_FILE}\nEnvironment=NODE_ENV=production\nRestart=always\nRestartSec=10\n\n[Install]\nWantedBy=multi-user.target\n`;\n\n writeFileSync(SERVICE_FILE, unit);\n console.log(`Wrote ${SERVICE_FILE}`);\n\n // Enable and start\n execSync('systemctl daemon-reload');\n execSync(`systemctl enable ${SERVICE_NAME}`);\n execSync(`systemctl start ${SERVICE_NAME}`);\n\n console.log(`Service ${SERVICE_NAME} installed and started.`);\n console.log(`Check status: systemctl status ${SERVICE_NAME}`);\n}\n"]}
@@ -0,0 +1,3 @@
1
+ declare function uninstall(): void;
2
+
3
+ export { uninstall };
@@ -0,0 +1,36 @@
1
+ import { createRequire } from 'node:module';
2
+ import { execSync } from 'child_process';
3
+ import { existsSync, unlinkSync } from 'fs';
4
+
5
+ createRequire(import.meta.url);
6
+ var SERVICE_NAME = "deskfree-agent";
7
+ var SERVICE_FILE = `/etc/systemd/system/${SERVICE_NAME}.service`;
8
+ var ENV_FILE = `/etc/${SERVICE_NAME}.env`;
9
+ function uninstall() {
10
+ if (process.getuid?.() !== 0) {
11
+ console.error("Error: uninstall must be run as root (use sudo)");
12
+ process.exit(1);
13
+ }
14
+ try {
15
+ execSync(`systemctl stop ${SERVICE_NAME}`, { stdio: "ignore" });
16
+ } catch {
17
+ }
18
+ try {
19
+ execSync(`systemctl disable ${SERVICE_NAME}`, { stdio: "ignore" });
20
+ } catch {
21
+ }
22
+ if (existsSync(SERVICE_FILE)) {
23
+ unlinkSync(SERVICE_FILE);
24
+ console.log(`Removed ${SERVICE_FILE}`);
25
+ }
26
+ if (existsSync(ENV_FILE)) {
27
+ unlinkSync(ENV_FILE);
28
+ console.log(`Removed ${ENV_FILE}`);
29
+ }
30
+ execSync("systemctl daemon-reload");
31
+ console.log(`Service ${SERVICE_NAME} uninstalled.`);
32
+ }
33
+
34
+ export { uninstall };
35
+ //# sourceMappingURL=uninstall.js.map
36
+ //# sourceMappingURL=uninstall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/uninstall.ts"],"names":[],"mappings":";;;;;AAGA,IAAM,YAAA,GAAe,gBAAA;AACrB,IAAM,YAAA,GAAe,uBAAuB,YAAY,CAAA,QAAA,CAAA;AACxD,IAAM,QAAA,GAAW,QAAQ,YAAY,CAAA,IAAA,CAAA;AAE9B,SAAS,SAAA,GAAkB;AAChC,EAAA,IAAI,OAAA,CAAQ,MAAA,IAAS,KAAM,CAAA,EAAG;AAC5B,IAAA,OAAA,CAAQ,MAAM,iDAAiD,CAAA;AAC/D,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AAGA,EAAA,IAAI;AACF,IAAA,QAAA,CAAS,kBAAkB,YAAY,CAAA,CAAA,EAAI,EAAE,KAAA,EAAO,UAAU,CAAA;AAAA,EAChE,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,IAAI;AACF,IAAA,QAAA,CAAS,qBAAqB,YAAY,CAAA,CAAA,EAAI,EAAE,KAAA,EAAO,UAAU,CAAA;AAAA,EACnE,CAAA,CAAA,MAAQ;AAAA,EAER;AAGA,EAAA,IAAI,UAAA,CAAW,YAAY,CAAA,EAAG;AAC5B,IAAA,UAAA,CAAW,YAAY,CAAA;AACvB,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,QAAA,EAAW,YAAY,CAAA,CAAE,CAAA;AAAA,EACvC;AACA,EAAA,IAAI,UAAA,CAAW,QAAQ,CAAA,EAAG;AACxB,IAAA,UAAA,CAAW,QAAQ,CAAA;AACnB,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,QAAA,EAAW,QAAQ,CAAA,CAAE,CAAA;AAAA,EACnC;AAEA,EAAA,QAAA,CAAS,yBAAyB,CAAA;AAClC,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,QAAA,EAAW,YAAY,CAAA,aAAA,CAAe,CAAA;AACpD","file":"uninstall.js","sourcesContent":["import { execSync } from 'node:child_process';\nimport { existsSync, unlinkSync } from 'node:fs';\n\nconst SERVICE_NAME = 'deskfree-agent';\nconst SERVICE_FILE = `/etc/systemd/system/${SERVICE_NAME}.service`;\nconst ENV_FILE = `/etc/${SERVICE_NAME}.env`;\n\nexport function uninstall(): void {\n if (process.getuid?.() !== 0) {\n console.error('Error: uninstall must be run as root (use sudo)');\n process.exit(1);\n }\n\n // Stop and disable (ignore errors if not running/enabled)\n try {\n execSync(`systemctl stop ${SERVICE_NAME}`, { stdio: 'ignore' });\n } catch {\n // not running — fine\n }\n try {\n execSync(`systemctl disable ${SERVICE_NAME}`, { stdio: 'ignore' });\n } catch {\n // not enabled — fine\n }\n\n // Remove files\n if (existsSync(SERVICE_FILE)) {\n unlinkSync(SERVICE_FILE);\n console.log(`Removed ${SERVICE_FILE}`);\n }\n if (existsSync(ENV_FILE)) {\n unlinkSync(ENV_FILE);\n console.log(`Removed ${ENV_FILE}`);\n }\n\n execSync('systemctl daemon-reload');\n console.log(`Service ${SERVICE_NAME} uninstalled.`);\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,12 +1,419 @@
1
- import type { OpenClawPluginApi } from './types';
2
- export { DeskFreeClient, DeskFreeError } from './client';
3
- export { reportError } from './error-reporter';
4
- export { OfflineQueue } from './offline-queue';
5
- export type * from './types';
6
- declare const plugin: {
7
- id: string;
8
- name: string;
9
- register(api: OpenClawPluginApi): void;
10
- };
11
- export default plugin;
12
- //# sourceMappingURL=index.d.ts.map
1
+ import { PluginLogger, DeskFreeClient, DeskFreeTool, ChatMessage, RuntimeBootstrapConfig } from '@deskfree/core';
2
+ import * as _anthropic_ai_claude_agent_sdk from '@anthropic-ai/claude-agent-sdk';
3
+ import { McpSdkServerConfigWithInstance, SDKMessage, SDKUserMessage, Query, tool } from '@anthropic-ai/claude-agent-sdk';
4
+
5
+ interface StartAgentOptions {
6
+ log?: PluginLogger;
7
+ }
8
+ /** Dispose function returned by startAgent — call to shut down cleanly. */
9
+ type DisposeAgent = () => void;
10
+ /**
11
+ * Full agent startup sequence:
12
+ *
13
+ * 1. Load local config (token + apiUrl from env)
14
+ * 2. Create DeskFree client
15
+ * 3. Bootstrap: fetch config from API (wsUrl, model, region, tools)
16
+ * 4. Install enabled tool packages
17
+ * 5. Configure Agent SDK env vars (Bedrock, region, model)
18
+ * 6. Create MCP servers
19
+ * 7. Start health server + WS gateway + heartbeat
20
+ */
21
+ declare function startAgent(opts?: StartAgentOptions): Promise<DisposeAgent>;
22
+
23
+ interface OrchestratorQueryOptions {
24
+ prompt: string;
25
+ orchestratorServer: McpSdkServerConfigWithInstance;
26
+ model: string;
27
+ /** Agent SDK session ID to resume (for multi-turn conversations). */
28
+ sessionId?: string;
29
+ }
30
+ /**
31
+ * Run the orchestrator agent. Returns an async iterable of SDKMessage events.
32
+ *
33
+ * The orchestrator:
34
+ * - Uses DeskFree orchestrator tools via MCP
35
+ * - Dispatches workers via the deskfree_dispatch_worker MCP tool
36
+ * - Persists sessions for multi-turn conversations
37
+ */
38
+ declare function runOrchestrator(opts: OrchestratorQueryOptions): AsyncGenerator<SDKMessage, void>;
39
+ interface HeartbeatOptions {
40
+ prompt: string;
41
+ orchestratorServer: McpSdkServerConfigWithInstance;
42
+ model: string;
43
+ }
44
+ /**
45
+ * Run a one-shot heartbeat query (no session persistence).
46
+ */
47
+ declare function runHeartbeat(opts: HeartbeatOptions): AsyncGenerator<SDKMessage, void>;
48
+
49
+ interface WorkerQueryOptions {
50
+ prompt: string | AsyncIterable<SDKUserMessage>;
51
+ workerServer: McpSdkServerConfigWithInstance;
52
+ model: string;
53
+ /** Agent SDK session ID to resume (for multi-turn task conversations). */
54
+ sessionId?: string;
55
+ }
56
+ /**
57
+ * Run the worker agent directly. Returns a Query (async iterable of
58
+ * SDKMessage events with a .close() method for teardown).
59
+ *
60
+ * Used for task thread messages where the router routes to 'runner'.
61
+ * The worker:
62
+ * - Claims a task and loads its context
63
+ * - Executes work (update files, steps, send messages)
64
+ * - Completes the task
65
+ */
66
+ declare function runWorker(opts: WorkerQueryOptions): Query;
67
+
68
+ /**
69
+ * Manages daily log files for memory observations.
70
+ *
71
+ * Logs are stored at `{stateDir}/memory/{botId}/daily/YYYY-MM-DD.md`.
72
+ * Each entry is a single line: `- [ISO timestamp] (task: {taskId}) {content}`
73
+ *
74
+ * Appends are atomic via O_APPEND flag (safe for writes <4KB on Linux).
75
+ */
76
+ declare class DailyLogManager {
77
+ private readonly dailyDir;
78
+ constructor(stateDir: string, botId: string);
79
+ /** Ensure the daily log directory exists. */
80
+ init(): void;
81
+ /** Append a learning entry to today's log file. */
82
+ appendLearning(content: string, taskId?: string): Promise<void>;
83
+ /** Read today's daily log, or null if it doesn't exist. */
84
+ readToday(): Promise<string | null>;
85
+ /** Read all daily logs, concatenated with date headers. */
86
+ readAllLogs(): Promise<string | null>;
87
+ /**
88
+ * Read recent daily logs up to a character budget (newest first).
89
+ * Returns as many days as fit. Quiet week → 14 days. Busy day → just today.
90
+ */
91
+ readRecentWithBudget(maxChars: number): Promise<string | null>;
92
+ /** Delete daily log files older than the given number of days. */
93
+ pruneOlderThan(days: number): void;
94
+ private todayPath;
95
+ }
96
+
97
+ interface WorkerManagerDeps {
98
+ client: DeskFreeClient;
99
+ createWorkerServer: () => McpSdkServerConfigWithInstance;
100
+ model: string;
101
+ log: PluginLogger;
102
+ /** Max concurrent workers. Defaults to 5. */
103
+ maxConcurrentWorkers?: number;
104
+ /** DailyLogManager for injecting recent observations into worker context. */
105
+ dailyLog?: DailyLogManager;
106
+ /** Character budget for daily log injection (~4 chars/token). Defaults to 16000. */
107
+ dailyLogCharBudget?: number;
108
+ /** Path to persist session history JSON (taskId → sessionId). */
109
+ sessionHistoryPath?: string;
110
+ }
111
+ declare class WorkerManager {
112
+ private workers;
113
+ /** Persists taskId → sessionId across worker restarts for session resume. */
114
+ private sessionHistory;
115
+ private pendingQueue;
116
+ private deps;
117
+ private maxConcurrent;
118
+ constructor(deps: WorkerManagerDeps);
119
+ /** Check if a worker is currently active for a task. */
120
+ has(taskId: string): boolean;
121
+ /**
122
+ * Dispatch a new long-lived worker for a task.
123
+ * Claims the task and loads workspace state server-side, then builds
124
+ * an enriched first message so the worker can start immediately.
125
+ *
126
+ * If at capacity, queues the dispatch and notifies the user.
127
+ * If a worker already exists for this taskId, returns 'already_running'.
128
+ */
129
+ dispatch(taskId: string, userMessage?: string): Promise<'started' | 'already_running' | 'queued'>;
130
+ /** Number of active workers. */
131
+ get activeCount(): number;
132
+ /** Number of queued dispatches waiting for a slot. */
133
+ get queuedCount(): number;
134
+ /** Maximum number of concurrent workers allowed. */
135
+ get maxConcurrentWorkers(): number;
136
+ /**
137
+ * Push a message into an active worker's channel.
138
+ * Resets the idle timer.
139
+ */
140
+ pushMessage(taskId: string, content: string): void;
141
+ /** Tear down a specific worker. */
142
+ teardown(taskId: string): void;
143
+ /** Tear down all active workers and clear the queue (shutdown hook). */
144
+ teardownAll(): void;
145
+ /** Core worker startup logic (no capacity check — callers must check first). */
146
+ private startWorker;
147
+ /** Drain the pending queue — called when a worker finishes. */
148
+ private drainQueue;
149
+ private startIdleTimer;
150
+ /**
151
+ * Background drain loop — processes query output and streams it back
152
+ * to DeskFree via DeskFreeStreamingSession.
153
+ */
154
+ private drainLoop;
155
+ /** Load session history from disk (best-effort). */
156
+ private loadSessionHistory;
157
+ /** Persist session history to disk (best-effort). */
158
+ private saveSessionHistory;
159
+ /** Build an SDKUserMessage from plain text content. */
160
+ private buildUserMessage;
161
+ }
162
+
163
+ /**
164
+ * Create an in-process MCP server with orchestrator tools.
165
+ *
166
+ * When a WorkerManager is provided, adds the deskfree_dispatch_worker
167
+ * tool that lets the orchestrator dispatch long-lived workers for tasks.
168
+ */
169
+ declare function createOrchestratorMcpServer(client: DeskFreeClient, customTools?: DeskFreeTool[], workerManager?: WorkerManager): _anthropic_ai_claude_agent_sdk.McpSdkServerConfigWithInstance;
170
+
171
+ interface ContentScanner {
172
+ scan(content: string): Promise<ScanResult>;
173
+ }
174
+ interface ScanResult {
175
+ safe: boolean;
176
+ reason?: string;
177
+ }
178
+ /**
179
+ * Default content scanner — applies heuristic injection pattern detection.
180
+ * In production the backend may provide a more sophisticated scanner.
181
+ */
182
+ declare class DefaultContentScanner implements ContentScanner {
183
+ private readonly log?;
184
+ constructor(log?: PluginLogger | undefined);
185
+ scan(content: string): Promise<ScanResult>;
186
+ }
187
+ /**
188
+ * Wrap a tool's execute function with content scan verification.
189
+ * Used to gate file write operations.
190
+ *
191
+ * @param execute - The original tool execute function
192
+ * @param extractContent - Function to extract the text content to scan from args
193
+ * @param scanner - ContentScanner implementation
194
+ */
195
+ declare function withContentScan<TArgs extends Record<string, unknown>>(execute: (args: TArgs) => Promise<unknown>, extractContent: (args: TArgs) => string | null | undefined, scanner: ContentScanner): (args: TArgs) => Promise<unknown>;
196
+ /**
197
+ * Validate a URL is safe to fetch (HTTPS only, no private IPs).
198
+ * Throws an error with a descriptive message if validation fails.
199
+ */
200
+ declare function validateDownloadUrl(url: string): void;
201
+ /**
202
+ * Check whether a content type is allowed for attachment downloads.
203
+ */
204
+ declare function isContentTypeAllowed(contentType: string): boolean;
205
+ /**
206
+ * Sanitize a filename to prevent directory traversal and injection.
207
+ */
208
+ declare function sanitizeFileName(fileName: string): string;
209
+
210
+ /**
211
+ * Create an in-process MCP server with worker tools.
212
+ *
213
+ * If a ContentScanner is provided, the deskfree_update_file tool's execute
214
+ * function is wrapped to scan file content for prompt injection before
215
+ * allowing the write.
216
+ */
217
+ declare function createWorkerMcpServer(client: DeskFreeClient, customTools?: DeskFreeTool[], contentScanner?: ContentScanner, dailyLog?: DailyLogManager): _anthropic_ai_claude_agent_sdk.McpSdkServerConfigWithInstance;
218
+
219
+ /**
220
+ * MCP Tool Adapter
221
+ *
222
+ * Converts DeskFreeTool[] into Agent SDK tool() definitions.
223
+ * JSON Schema parameters are converted to Zod schemas for the SDK's
224
+ * type-safe tool() function.
225
+ */
226
+
227
+ type AgentSdkTool = ReturnType<typeof tool>;
228
+ /**
229
+ * Adapt a single DeskFreeTool into an Agent SDK tool() definition.
230
+ *
231
+ * The handler delegates to `tool.execute()` which returns a `ToolResult`
232
+ * — this is already compatible with the MCP `CallToolResult` shape:
233
+ * `{ content: Array<{ type: 'text', text: string }>, isError?: boolean }`
234
+ */
235
+ declare function adaptTool(deskfreeTool: DeskFreeTool): AgentSdkTool;
236
+ /**
237
+ * Adapt an array of DeskFree tools into Agent SDK tool() definitions.
238
+ */
239
+ declare function adaptTools(tools: DeskFreeTool[]): AgentSdkTool[];
240
+
241
+ /**
242
+ * Session Store — maps DeskFree session keys to Agent SDK session IDs.
243
+ *
244
+ * Session keys:
245
+ * dm:<peerId> — DM messages routed to orchestrator
246
+ * task:<taskId> — Task thread messages routed to worker
247
+ *
248
+ * The Agent SDK handles conversation history internally via session
249
+ * persistence. We only need to track the mapping from our session keys
250
+ * to the Agent SDK session IDs.
251
+ *
252
+ * Why in-memory is fine:
253
+ * - Container restarts are clean — agents re-claim context from backend
254
+ * - Session ID mapping is a performance optimization, not state of record
255
+ * - Backend stores all messages persistently
256
+ */
257
+ interface SessionEntry {
258
+ /** Agent SDK session ID for resuming conversations. */
259
+ agentSessionId: string;
260
+ /** Timestamp of last activity (for TTL eviction). */
261
+ lastActivityAt: number;
262
+ }
263
+ declare class SessionStore {
264
+ private readonly staleTtlMs;
265
+ private readonly maxSessions;
266
+ private readonly sessions;
267
+ private cleanupTimer;
268
+ constructor(staleTtlMs?: number, // 30 min TTL
269
+ maxSessions?: number);
270
+ /**
271
+ * Get the Agent SDK session ID for a given key.
272
+ * Returns undefined if no session exists or it has expired.
273
+ */
274
+ getSessionId(key: string): string | undefined;
275
+ /**
276
+ * Store an Agent SDK session ID for a given key.
277
+ */
278
+ setSessionId(key: string, agentSessionId: string): void;
279
+ /** Delete a specific session. */
280
+ delete(key: string): void;
281
+ /** Number of active sessions. */
282
+ get size(): number;
283
+ /** Remove sessions that haven't been active within the TTL. */
284
+ private cleanup;
285
+ /** Evict the session with the oldest lastActivityAt. */
286
+ private evictOldest;
287
+ /** Dispose — clear the cleanup timer. */
288
+ dispose(): void;
289
+ }
290
+
291
+ interface WorkerStatus {
292
+ activeWorkers: number;
293
+ queuedTasks: number;
294
+ maxConcurrency: number;
295
+ }
296
+ interface GatewayConfig {
297
+ client: DeskFreeClient;
298
+ wsUrl: string;
299
+ accountId: string;
300
+ stateDir: string;
301
+ log: PluginLogger;
302
+ abortSignal: AbortSignal;
303
+ onMessage: (message: ChatMessage) => Promise<void>;
304
+ getWorkerStatus?: () => WorkerStatus;
305
+ }
306
+ /**
307
+ * Start the WS gateway — reconnection loop with backoff.
308
+ *
309
+ * Loop: getWsTicket() → connect → listen for notify → poll messages → deliver
310
+ * On disconnect: backoff → reconnect
311
+ * Fallback: interval-based polling when WS is unavailable
312
+ */
313
+ declare function startGateway(config: GatewayConfig): Promise<void>;
314
+
315
+ interface ToolPackageConfig {
316
+ package: string;
317
+ version: string;
318
+ }
319
+ /**
320
+ * Install tool packages into an isolated directory.
321
+ * Creates a minimal package.json and runs `bun install`.
322
+ *
323
+ * Tool packages are pre-bundled single files with zero deps —
324
+ * install is fast (~2-5s for a handful of tools).
325
+ *
326
+ * Security: only @deskfree/tool-* packages are allowed.
327
+ */
328
+ declare function installTools(tools: ToolPackageConfig[], toolsDir: string, log?: PluginLogger): Promise<void>;
329
+ /**
330
+ * Load installed tool packages and extract DeskFreeTool definitions.
331
+ *
332
+ * Each @deskfree/tool-* package must export one of:
333
+ * export const tools: DeskFreeTool[]
334
+ * export function createTools(): DeskFreeTool[]
335
+ */
336
+ declare function loadToolModules(tools: ToolPackageConfig[], toolsDir: string, log?: PluginLogger): Promise<DeskFreeTool[]>;
337
+
338
+ /**
339
+ * Local config: values known before connecting to the API.
340
+ * Only botToken + apiUrl are required. Everything else has sensible defaults.
341
+ */
342
+ interface LocalConfig {
343
+ /** Bot authentication token (required) */
344
+ botToken: string;
345
+ /** DeskFree backend API URL (required) */
346
+ apiUrl: string;
347
+ /** Directory for cursor + media storage */
348
+ stateDir: string;
349
+ /** Directory for dynamic tool installs */
350
+ toolsDir: string;
351
+ /** Log level */
352
+ logLevel: 'debug' | 'info' | 'warn' | 'error';
353
+ /** HTTP port for health check endpoint */
354
+ healthPort: number;
355
+ }
356
+ /**
357
+ * Full runtime config: local config + API-bootstrapped values.
358
+ * Built by merging LocalConfig with the config.get response.
359
+ * Env var overrides take precedence over API values.
360
+ */
361
+ interface RuntimeConfig extends LocalConfig {
362
+ /** DeskFree WebSocket URL */
363
+ wsUrl: string;
364
+ /** Model ID (Bedrock or Anthropic format) */
365
+ model: string;
366
+ /** AWS region for Bedrock */
367
+ awsRegion: string;
368
+ /** Heartbeat interval in ms (0 = disabled) */
369
+ heartbeatIntervalMs: number;
370
+ /** Tool packages to install */
371
+ tools: Array<{
372
+ package: string;
373
+ version: string;
374
+ }>;
375
+ /** Account ID (set after first API call) */
376
+ accountId: string;
377
+ /** LLM provider: bedrock (default), anthropic, or ollama */
378
+ provider: 'bedrock' | 'anthropic' | 'ollama';
379
+ /** Anthropic API key (only set when provider is 'anthropic') */
380
+ anthropicApiKey?: string;
381
+ /** Base URL for Ollama-compatible API (only set when provider is 'ollama') */
382
+ baseUrl?: string;
383
+ /** Bot ID for this runtime instance */
384
+ botId: string;
385
+ /** File ID for the bot's Memory file (null if not created yet) */
386
+ memoryFileId: string | null;
387
+ /** Hour of day (0-23) in local time for the nightly sleep cycle (null = disabled) */
388
+ sleepHour: number | null;
389
+ /** Hour of day (0-23) in local time for the evening dusk planning cycle (null = disabled) */
390
+ duskHour: number | null;
391
+ /** IANA timezone string (e.g. 'America/New_York') for sleep scheduling */
392
+ timezone: string | null;
393
+ }
394
+ /**
395
+ * Load local config from environment variables.
396
+ *
397
+ * Checks DESKFREE_LAUNCH first — a base64-encoded JSON with { botToken, apiUrl }.
398
+ * Falls back to individual env vars DESKFREE_BOT_TOKEN and DESKFREE_API_URL.
399
+ */
400
+ declare function loadConfig(): LocalConfig;
401
+ /**
402
+ * Merge local config with API-bootstrapped config.
403
+ * Env var overrides take precedence over API values for debugging/testing.
404
+ */
405
+ declare function mergeWithRemoteConfig(local: LocalConfig, remote: RuntimeBootstrapConfig): RuntimeConfig;
406
+
407
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
408
+ /**
409
+ * Structured JSON logger that satisfies the PluginLogger interface.
410
+ * Writes newline-delimited JSON to stdout/stderr.
411
+ *
412
+ * Supports optional structured fields that are merged into the JSON entry:
413
+ * log.info('message routed', { sessionKey: 'dm:abc', target: 'orchestrator' })
414
+ */
415
+ declare function createLogger(component: string, minLevel?: LogLevel): PluginLogger;
416
+ /** Default logger for the root process. */
417
+ declare const logger: PluginLogger;
418
+
419
+ export { type ContentScanner, DefaultContentScanner, type DisposeAgent, type GatewayConfig, type HeartbeatOptions, type LocalConfig, type LogLevel, type OrchestratorQueryOptions, type RuntimeConfig, type ScanResult, type SessionEntry, SessionStore, type StartAgentOptions, type ToolPackageConfig, type WorkerQueryOptions, adaptTool, adaptTools, createLogger, createOrchestratorMcpServer, createWorkerMcpServer, installTools, isContentTypeAllowed, loadConfig, loadToolModules, logger, mergeWithRemoteConfig, runHeartbeat, runOrchestrator, runWorker, sanitizeFileName, startAgent, startGateway, validateDownloadUrl, withContentScan };