mindwire 0.1.52 → 0.1.54

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.
package/README.md CHANGED
@@ -16,6 +16,11 @@ protocol; this package is a thin, dependency-free client over its REST + SSE sur
16
16
 
17
17
  ## Install
18
18
 
19
+ Connect saved bots to Slack, Microsoft Teams, Discord, or Telegram through
20
+ `mw.integrations`: chat with streamed replies, run commands, trigger tasks, or send notifications.
21
+ Connections are shared with the app and Go SDK. See the
22
+ [messaging integrations guide](https://mindwire.sh/docs/guides/integrations) for setup and examples.
23
+
19
24
  ```bash
20
25
  npm i mindwire
21
26
  # or: bun add mindwire / pnpm add mindwire
@@ -38,7 +43,7 @@ If macOS rejects the login, the CLI lets you retry the password or check Screen
38
43
  Sharing permissions. Canceling or entering a wrong password keeps the existing
39
44
  desktop setup and active connections unchanged.
40
45
  Opening a workspace or checking status does not enable screen access. See the
41
- [desktop contract](../../daemon/DESKTOP.md#personal-mac-desktop) for platform support,
46
+ [desktop contract](../../packages/daemon/DESKTOP.md#personal-mac-desktop) for platform support,
42
47
  permissions and the shared input protocol. Existing installations need a release
43
48
  advertising `health().localDesktopVersion >= 1`.
44
49
 
@@ -112,7 +117,7 @@ and native transcripts. Use `deleteChat()` for an explicit transcript purge.
112
117
 
113
118
  Check `health().workspaceMetadataVersion` before enabling registry features on an
114
119
  older daemon. `workspace.import()` imports legacy IDs once; existing records and
115
- deletion markers win. See the [registry contract](../../daemon/WORKSPACES.md) for
120
+ deletion markers win. See the [registry contract](../../packages/daemon/WORKSPACES.md) for
116
121
  migration and recovery. The embedded Go SDK exposes the same operations through
117
122
  `client.Workspace`, using the same SQLite implementation.
118
123
 
@@ -153,6 +158,93 @@ blocks running chats/overlapping projects and recovers removal across restarts.
153
158
  Cancellation returns 409 after the `deleting` phase; cleanup then affects only the
154
159
  owned quarantine, even if someone recreates the original directory.
155
160
 
161
+ Create a plain harness profile with `mw.bots.create({ agentId, projectId, name, raw: true })`
162
+ (Go: `Bot.Raw`). Requires `health().botsVersion >= 7`. It keeps a named conversation
163
+ group and the existing harness authentication, settings and native tools, without
164
+ Mindwire bot instructions, memory, knowledge, skills or bot MCP tools. `raw` is
165
+ creation-only; create a separate profile to change modes without carrying an old
166
+ persona into a resumed conversation.
167
+
168
+ With `botsVersion >= 8`, bots belong to a workspace and can work in any of its
169
+ projects. `projectId` is only their optional default working folder. Start a chat
170
+ in another project with `mw.bots.createChat(bot.id, { projectId })` (Go:
171
+ `Bots.CreateChat(bot.ID, chatID, title, projectID)`). The profile, memory and skills
172
+ stay shared; each chat retains its own project, native session and permissions.
173
+ Deleting a project clears a matching default folder while preserving the bot and
174
+ its conversations in other projects.
175
+
176
+ ### Bot skills
177
+
178
+ Bots keep standing identity in `instructions`, durable facts in `memory`, and
179
+ reference material in `knowledge`. Assign reusable workflows separately with
180
+ `skills`, an array containing complete portable `SKILL.md` documents:
181
+
182
+ ```ts
183
+ import { readFile } from "node:fs/promises";
184
+
185
+ await mw.bots.update(bot.id, {
186
+ expectedRevision: bot.revision,
187
+ skills: [await readFile("./skills/reports/SKILL.md", "utf8")],
188
+ });
189
+ ```
190
+
191
+ Requires `health().botsVersion >= 6`. The Go equivalent is `BotEdit.Skills`.
192
+ Each document needs YAML `name` and `description` frontmatter and a Markdown body.
193
+ Limits are 16 skills, 32 KiB each, 128 KiB total, with unique names. The portable
194
+ frontmatter supports `license`, `compatibility` and string-valued `metadata`;
195
+ native permission overrides, hooks and dynamic shell substitutions are rejected. Omit `skills` when updating
196
+ unrelated fields; an explicit empty array removes assignments.
197
+
198
+ The daemon supplies a private bundle for the current turn. Codex discovers it
199
+ through process-scoped extra roots; Claude loads it through `--plugin-dir`.
200
+ Other harnesses load the same content through `skills_list` / `skills_read` on
201
+ the existing scoped tool bridge. Older Codex versions without extra-root support
202
+ also use that fallback. Only skill metadata enters standing context; bodies are
203
+ read on demand. Assignments retain the turn's starting revision. Skills grant no
204
+ additional permissions and never alter global harness configuration. Product
205
+ presets and skill content belong to the client; the Go core supplies the generic
206
+ validation, storage, delivery and permission checks.
207
+
208
+ ### Applications and scheduled work
209
+
210
+ `mw.apps` saves application resources on their owning host. Clients can present
211
+ these as shortcuts, launchers or other application catalogs. Consumer bot presets
212
+ and General-mode UI are outside the Go registry; no new AI runtime is created.
213
+
214
+ ```ts
215
+ const { app } = await mw.apps.register({
216
+ projectId, name: "Reports", icon: "chart.bar", url: "http://127.0.0.1:3000",
217
+ startupCommand: "./scripts/ensure-reports.sh", healthPath: "/health",
218
+ });
219
+ await mw.apps.open(app.id); // bounded readiness check/startup; returns the saved URL
220
+ await mw.apps.channels(); // labels/IDs only, no provider credentials
221
+ await mw.apps.notifications(app.id); // protected credentialFile path on the computer
222
+ await mw.apps.saveSchedule(app.id, {
223
+ name: "Morning report", localTime: "09:00", timeZone: "Europe/London",
224
+ weekdays: [1, 2, 3, 4, 5], command: "./scripts/build-report.sh",
225
+ title: "Reports", body: "Your morning report is ready.",
226
+ });
227
+ const schedules = await mw.apps.schedules(app.id);
228
+ ```
229
+
230
+ Check `health().appsVersion >= 1`. Phone delivery must already be configured.
231
+ Schedules persist across restarts and run while the owning computer is awake;
232
+ notifications retry without rerunning a completed command. Backend credentials
233
+ can only send as one app through its saved destinations. See the
234
+ [Apps contract](../../docs/apple/Apps.md) for native tools, private forwarding,
235
+ calendar rules, removal and recovery. The Go SDK shares `client.Apps` for saved
236
+ records, readiness, notification delivery and schedules; backend credential files
237
+ are provisioned through the running daemon's HTTP/native tool service.
238
+
239
+ The standalone daemon explicitly owns scheduling. The embedded Go SDK does not
240
+ run scheduled commands merely because a client is constructed; opt in with
241
+ `mindwire.Options{RunScheduledJobs: true}` when hosting a long-lived runtime.
242
+ Native agent tools request owner approval before enabling background commands,
243
+ using the existing interaction stream. Direct owner API/SDK requests explicitly
244
+ authorize their work. Pausing remains available when notifications are muted or
245
+ unconfigured. Commands use the host OS permissions; the working directory does
246
+ not provide a sandbox.
247
+
156
248
  ## Targets — where the daemon runs
157
249
 
158
250
  **One `new Mindwire` = one instance = one daemon = one environment.** Every agent that instance runs
@@ -289,3 +381,6 @@ bun test # client + SSE parser tests (mocked fetch)
289
381
  ```
290
382
 
291
383
  License: Apache-2.0.
384
+
385
+
386
+ Public hosting adapters can check `health().appsVersion >= 2`, then call `mw.apps.preparePublication(appId)` (Go: `client.Apps.PreparePublication(ctx, appID)`). This validates a port or static build plan without deploying it. After the adapter confirms hosting, save its HTTPS link using `apps.update(..., { expectedRevision, publicUrl })`. The original private URL stays intact. Provider credentials and billing belong in the host application, outside the generic runtime.
package/dist/apps.d.ts ADDED
@@ -0,0 +1,94 @@
1
+ import type { Mindwire } from "./client.js";
2
+ import type { WorkspaceSnapshot } from "./workspace.js";
3
+ /** An application resource saved on its owning host. */
4
+ export interface AppShortcut {
5
+ id: string;
6
+ workspaceId: string;
7
+ projectId: string;
8
+ botId?: string;
9
+ name: string;
10
+ icon?: string;
11
+ url: string;
12
+ startupCommand?: string;
13
+ healthPath?: string;
14
+ archived: boolean;
15
+ createdAt: string;
16
+ revision: number;
17
+ channelIds?: string[];
18
+ notificationsMuted: boolean;
19
+ automation?: boolean;
20
+ staticDirectory?: string;
21
+ publicUrl?: string;
22
+ }
23
+ export type AppShortcutCreate = Pick<AppShortcut, "projectId" | "name" | "url"> & Partial<Pick<AppShortcut, "id" | "botId" | "icon" | "startupCommand" | "healthPath" | "automation" | "channelIds" | "notificationsMuted" | "staticDirectory" | "publicUrl">>;
24
+ export type AppShortcutEdit = {
25
+ expectedRevision: number;
26
+ } & Partial<Pick<AppShortcut, "name" | "icon" | "url" | "startupCommand" | "healthPath" | "archived" | "channelIds" | "notificationsMuted" | "staticDirectory" | "publicUrl">>;
27
+ export interface AppShortcutMutation {
28
+ app: AppShortcut;
29
+ snapshot: WorkspaceSnapshot;
30
+ }
31
+ export interface AppPublication {
32
+ app: AppShortcut;
33
+ kind: "port" | "static";
34
+ port?: number;
35
+ directory?: string;
36
+ }
37
+ export interface AppNotificationChannel {
38
+ id: string;
39
+ name: string;
40
+ type: string;
41
+ }
42
+ export interface AppScheduleSpec {
43
+ id?: string;
44
+ expectedRevision?: number;
45
+ name: string;
46
+ runAt?: string;
47
+ intervalSeconds?: number;
48
+ localTime?: string;
49
+ timeZone?: string;
50
+ weekdays?: number[];
51
+ command?: string;
52
+ title?: string;
53
+ body?: string;
54
+ enabled?: boolean;
55
+ }
56
+ export interface AppSchedule extends Omit<AppScheduleSpec, "id"> {
57
+ id: string;
58
+ appId: string;
59
+ revision: number;
60
+ active: boolean;
61
+ state: string;
62
+ nextRunAt?: string;
63
+ retryAt?: string;
64
+ lastRunAt?: string;
65
+ lastError?: string;
66
+ attempts: number;
67
+ }
68
+ export declare class AppsApi {
69
+ private readonly mw;
70
+ constructor(mw: Mindwire);
71
+ list(): Promise<AppShortcut[]>;
72
+ get(id: string): Promise<AppShortcut>;
73
+ register(input: AppShortcutCreate): Promise<AppShortcutMutation>;
74
+ update(id: string, input: AppShortcutEdit): Promise<AppShortcutMutation>;
75
+ /** Ensures readiness on the owning computer; the client opens the returned URL. */
76
+ open(id: string): Promise<AppShortcut>;
77
+ /** Validates a plan for the owner's hosting adapter; does not deploy or charge. */
78
+ preparePublication(id: string): Promise<AppPublication>;
79
+ channels(): Promise<AppNotificationChannel[]>;
80
+ notifications(id: string, options?: {
81
+ channelIds?: string[];
82
+ rotate?: boolean;
83
+ }): Promise<AppShortcutMutation & {
84
+ credentialFile: string;
85
+ }>;
86
+ revokeNotificationAccess(id: string): Promise<{
87
+ revoked: boolean;
88
+ }>;
89
+ schedules(id: string): Promise<AppSchedule[]>;
90
+ saveSchedule(id: string, schedule: AppScheduleSpec): Promise<AppSchedule>;
91
+ deleteSchedule(id: string, scheduleId: string): Promise<{
92
+ removed: boolean;
93
+ }>;
94
+ }
package/dist/bots.d.ts ADDED
@@ -0,0 +1,168 @@
1
+ import type { Mindwire } from "./client.js";
2
+ import type { WorkspaceRecord, WorkspaceSnapshot, WorkspaceChat, WorkspaceAgent, WorkspaceProject } from "./workspace.js";
3
+ import type { Run } from "./types.js";
4
+ export interface BotKnowledge {
5
+ id: string;
6
+ title: string;
7
+ content: string;
8
+ }
9
+ export interface Bot extends WorkspaceRecord {
10
+ agentId: string;
11
+ /** Default folder for new chats. The bot belongs to workspaceId and can work in its other projects. */
12
+ projectId: string;
13
+ name: string;
14
+ /** Saved palette-character ID; omitted/empty keeps the automatic avatar. */
15
+ icon?: string;
16
+ purpose: string;
17
+ instructions: string;
18
+ memory: string;
19
+ knowledge: BotKnowledge[];
20
+ /** Portable SKILL.md documents, loaded on demand. Requires botsVersion >= 6. */
21
+ skills?: string[] | null;
22
+ /** Creation-only plain harness: no Mindwire bot context, tools or skills. Requires botsVersion >= 7. */
23
+ raw?: boolean;
24
+ isMaster: boolean;
25
+ archived: boolean;
26
+ /** Applies to this bot's current and future chats, independent of its base engine. */
27
+ notificationsMuted?: boolean;
28
+ }
29
+ export interface BotInput {
30
+ icon?: string;
31
+ id?: string;
32
+ agentId: string;
33
+ projectId?: string;
34
+ name: string;
35
+ purpose?: string;
36
+ instructions?: string;
37
+ memory?: string;
38
+ knowledge?: BotKnowledge[];
39
+ skills?: string[];
40
+ /** Keep native harness behavior. Cannot be changed after creation or combined with bot context. */
41
+ raw?: boolean;
42
+ }
43
+ export interface BotEdit {
44
+ /** Base agent for future chats; existing chats retain their original engine. Requires botsVersion >= 5. */
45
+ agentId?: string;
46
+ icon?: string;
47
+ expectedRevision: number;
48
+ name?: string;
49
+ purpose?: string;
50
+ instructions?: string;
51
+ memory?: string;
52
+ knowledge?: BotKnowledge[];
53
+ archived?: boolean;
54
+ /** Replaces assigned SKILL.md documents; omit to preserve existing skills. */
55
+ skills?: string[];
56
+ notificationsMuted?: boolean;
57
+ }
58
+ export interface BotMutation {
59
+ bot: Bot;
60
+ snapshot: WorkspaceSnapshot;
61
+ }
62
+ export interface BotTaskInput {
63
+ requestId: string;
64
+ message: string;
65
+ }
66
+ export interface BotTaskRequest extends BotTaskInput {
67
+ chatId?: string;
68
+ title?: string;
69
+ projectId?: string;
70
+ }
71
+ export interface BotTask {
72
+ botId: string;
73
+ chatId: string;
74
+ run: Run;
75
+ messages?: {
76
+ role: string;
77
+ text: string;
78
+ createdAt: string;
79
+ }[];
80
+ output?: string;
81
+ historyError?: string;
82
+ interactions?: {
83
+ id: string;
84
+ kind: string;
85
+ title?: string;
86
+ detail?: string;
87
+ needsResponse: boolean;
88
+ }[];
89
+ tools?: {
90
+ name: string;
91
+ status?: string;
92
+ }[];
93
+ cancelRequested?: boolean;
94
+ }
95
+ export type BotPeerRoute = {
96
+ kind: "ssh";
97
+ host: string;
98
+ port: number;
99
+ } | {
100
+ kind: "websocket";
101
+ url: string;
102
+ };
103
+ export interface BotPeerIdentity {
104
+ workspaceId: string;
105
+ publicKey: string;
106
+ hostKeyFingerprint: string;
107
+ port?: number;
108
+ sshPort?: number;
109
+ routes?: BotPeerRoute[];
110
+ }
111
+ export interface BotPeerInput {
112
+ name: string;
113
+ publicKey: string;
114
+ hostKeyFingerprint: string;
115
+ routes: BotPeerRoute[];
116
+ enabled?: boolean;
117
+ }
118
+ export interface BotPeer extends BotPeerInput {
119
+ workspaceId: string;
120
+ }
121
+ export interface BotPeerCheck {
122
+ workspaceId: string;
123
+ reachable: boolean;
124
+ error?: string;
125
+ addressRecovery?: boolean;
126
+ }
127
+ /** Saved bot identities, native tasks, and explicitly paired bot-control peers. */
128
+ export declare class BotsApi {
129
+ private readonly mw;
130
+ constructor(mw: Mindwire);
131
+ list(options?: {
132
+ projectId?: string;
133
+ archived?: boolean;
134
+ }): Promise<Bot[]>;
135
+ get(id: string): Promise<Bot>;
136
+ ensure(agentId: string, projectId: string): Promise<BotMutation>;
137
+ create(input: BotInput): Promise<BotMutation>;
138
+ update(id: string, edit: BotEdit): Promise<BotMutation>;
139
+ chats(id: string): Promise<WorkspaceChat[]>;
140
+ createChat(id: string, input?: {
141
+ chatId?: string;
142
+ title?: string;
143
+ projectId?: string;
144
+ }): Promise<{
145
+ chatId: string;
146
+ snapshot: WorkspaceSnapshot;
147
+ }>;
148
+ agents(): Promise<{
149
+ agents: WorkspaceAgent[];
150
+ projects: WorkspaceProject[];
151
+ }>;
152
+ tasks(id: string): Promise<BotTask[]>;
153
+ /** Keep requestId stable when retrying a task after a lost acknowledgement. */
154
+ delegate(id: string, input: BotTaskRequest): Promise<BotTask>;
155
+ task(id: string, runId: string): Promise<BotTask>;
156
+ input(id: string, runId: string, input: BotTaskInput): Promise<BotTask>;
157
+ cancel(id: string, runId: string): Promise<BotTask>;
158
+ peerIdentity(): Promise<BotPeerIdentity>;
159
+ startPeerListener(port?: number): Promise<BotPeerIdentity>;
160
+ peers(): Promise<BotPeer[]>;
161
+ pair(workspaceId: string, input: BotPeerInput): Promise<BotPeer>;
162
+ revokePeer(workspaceId: string): Promise<{
163
+ ok: boolean;
164
+ }>;
165
+ /** Bounded peer handshake/discovery; does not start a bot task. */
166
+ checkPeer(workspaceId: string): Promise<BotPeerCheck>;
167
+ private taskPath;
168
+ }
@@ -88,7 +88,7 @@ function computerPairingURI(invitation) {
88
88
  }
89
89
 
90
90
  // src/version.ts
91
- var SDK_VERSION = "0.1.52" ;
91
+ var SDK_VERSION = "0.1.54" ;
92
92
  function versionAtLeast(actual, desired) {
93
93
  if (actual === desired) return true;
94
94
  if (!actual || !/^\d+\.\d+\.\d+$/.test(actual) || !/^\d+\.\d+\.\d+$/.test(desired)) return false;
@@ -1390,6 +1390,12 @@ var WorkspaceApi = class {
1390
1390
  projectIcon(projectId, path5) {
1391
1391
  return this.mw.http.request("GET", `/workspace/projects/${encodeURIComponent(projectId)}/icon`, { query: { path: path5 } });
1392
1392
  }
1393
+ /** Upload a validated image (base64 content, at most 1 MB). Requires projectIconsVersion >= 2.
1394
+ * Stores the image inside the project; set projects.put(..., { iconPath: result.path }) to select it.
1395
+ */
1396
+ uploadProjectIcon(projectId, image) {
1397
+ return this.mw.http.request("POST", `/workspace/projects/${encodeURIComponent(projectId)}/icon`, { body: image });
1398
+ }
1393
1399
  /** Start an operation owned by the daemon. The same ID/payload returns the existing operation. */
1394
1400
  createProject(request) {
1395
1401
  return this.mw.http.request("POST", "/workspace/projects", { body: request });
@@ -1490,6 +1496,160 @@ var GitAccessApi = class {
1490
1496
  }
1491
1497
  };
1492
1498
 
1499
+ // src/bots.ts
1500
+ var BotsApi = class {
1501
+ constructor(mw) {
1502
+ this.mw = mw;
1503
+ }
1504
+ mw;
1505
+ list(options = {}) {
1506
+ return this.mw.http.request("GET", "/bots", { query: { projectId: options.projectId, archived: options.archived ? "true" : void 0 } });
1507
+ }
1508
+ get(id) {
1509
+ return this.mw.http.request("GET", `/bots/${encodeURIComponent(id)}`);
1510
+ }
1511
+ ensure(agentId, projectId) {
1512
+ return this.mw.http.request("POST", "/bots/ensure", { body: { agentId, projectId } });
1513
+ }
1514
+ create(input) {
1515
+ return this.mw.http.request("POST", "/bots", { body: input });
1516
+ }
1517
+ update(id, edit) {
1518
+ return this.mw.http.request("PATCH", `/bots/${encodeURIComponent(id)}`, { body: edit });
1519
+ }
1520
+ chats(id) {
1521
+ return this.mw.http.request("GET", `/bots/${encodeURIComponent(id)}/chats`);
1522
+ }
1523
+ createChat(id, input = {}) {
1524
+ return this.mw.http.request("POST", `/bots/${encodeURIComponent(id)}/chats`, { body: input });
1525
+ }
1526
+ agents() {
1527
+ return this.mw.http.request("GET", "/bots/agents");
1528
+ }
1529
+ tasks(id) {
1530
+ return this.mw.http.request("GET", `/bots/${encodeURIComponent(id)}/tasks`);
1531
+ }
1532
+ /** Keep requestId stable when retrying a task after a lost acknowledgement. */
1533
+ delegate(id, input) {
1534
+ return this.mw.http.request("POST", `/bots/${encodeURIComponent(id)}/tasks`, { body: input });
1535
+ }
1536
+ task(id, runId) {
1537
+ return this.mw.http.request("GET", this.taskPath(id, runId));
1538
+ }
1539
+ input(id, runId, input) {
1540
+ return this.mw.http.request("POST", `${this.taskPath(id, runId)}/input`, { body: input });
1541
+ }
1542
+ cancel(id, runId) {
1543
+ return this.mw.http.request("POST", `${this.taskPath(id, runId)}/cancel`);
1544
+ }
1545
+ peerIdentity() {
1546
+ return this.mw.http.request("GET", "/bots/peers/identity");
1547
+ }
1548
+ startPeerListener(port) {
1549
+ return this.mw.http.request("POST", "/bots/peers/listener", { body: { port } });
1550
+ }
1551
+ peers() {
1552
+ return this.mw.http.request("GET", "/bots/peers");
1553
+ }
1554
+ pair(workspaceId, input) {
1555
+ return this.mw.http.request("PUT", `/bots/peers/${encodeURIComponent(workspaceId)}`, { body: input });
1556
+ }
1557
+ revokePeer(workspaceId) {
1558
+ return this.mw.http.request("DELETE", `/bots/peers/${encodeURIComponent(workspaceId)}`);
1559
+ }
1560
+ /** Bounded peer handshake/discovery; does not start a bot task. */
1561
+ checkPeer(workspaceId) {
1562
+ return this.mw.http.request("POST", `/bots/peers/${encodeURIComponent(workspaceId)}/check`, { body: {} });
1563
+ }
1564
+ taskPath(id, runId) {
1565
+ return `/bots/${encodeURIComponent(id)}/tasks/${encodeURIComponent(runId)}`;
1566
+ }
1567
+ };
1568
+
1569
+ // src/apps.ts
1570
+ var AppsApi = class {
1571
+ constructor(mw) {
1572
+ this.mw = mw;
1573
+ }
1574
+ mw;
1575
+ list() {
1576
+ return this.mw.http.request("GET", "/apps");
1577
+ }
1578
+ get(id) {
1579
+ return this.mw.http.request("GET", `/apps/${encodeURIComponent(id)}`);
1580
+ }
1581
+ register(input) {
1582
+ return this.mw.http.request("POST", "/apps", { body: input });
1583
+ }
1584
+ update(id, input) {
1585
+ return this.mw.http.request("PATCH", `/apps/${encodeURIComponent(id)}`, { body: input });
1586
+ }
1587
+ /** Ensures readiness on the owning computer; the client opens the returned URL. */
1588
+ open(id) {
1589
+ return this.mw.http.request("POST", `/apps/${encodeURIComponent(id)}/open`, { body: {} });
1590
+ }
1591
+ /** Validates a plan for the owner's hosting adapter; does not deploy or charge. */
1592
+ preparePublication(id) {
1593
+ return this.mw.http.request("POST", `/apps/${encodeURIComponent(id)}/publication/prepare`, { body: {} });
1594
+ }
1595
+ channels() {
1596
+ return this.mw.http.request("GET", "/apps/channels");
1597
+ }
1598
+ notifications(id, options = {}) {
1599
+ return this.mw.http.request("POST", `/apps/${encodeURIComponent(id)}/notifications`, { body: options });
1600
+ }
1601
+ revokeNotificationAccess(id) {
1602
+ return this.mw.http.request("DELETE", `/apps/${encodeURIComponent(id)}/notifications/token`);
1603
+ }
1604
+ schedules(id) {
1605
+ return this.mw.http.request("GET", `/apps/${encodeURIComponent(id)}/schedules`);
1606
+ }
1607
+ saveSchedule(id, schedule) {
1608
+ return this.mw.http.request("POST", `/apps/${encodeURIComponent(id)}/schedules`, { body: schedule });
1609
+ }
1610
+ deleteSchedule(id, scheduleId) {
1611
+ return this.mw.http.request("DELETE", `/apps/${encodeURIComponent(id)}/schedules/${encodeURIComponent(scheduleId)}`);
1612
+ }
1613
+ };
1614
+
1615
+ // src/integrations.ts
1616
+ var IntegrationsApi = class {
1617
+ constructor(mw) {
1618
+ this.mw = mw;
1619
+ }
1620
+ mw;
1621
+ list() {
1622
+ return this.mw.http.request("GET", "/integrations");
1623
+ }
1624
+ get(id) {
1625
+ return this.mw.http.request("GET", this.path(id));
1626
+ }
1627
+ create(spec) {
1628
+ return this.mw.http.request("POST", "/integrations", { body: spec });
1629
+ }
1630
+ /** Complete replacement with optimistic concurrency; omit credentials to preserve them. */
1631
+ update(id, spec) {
1632
+ return this.mw.http.request("PUT", this.path(id), { body: spec });
1633
+ }
1634
+ async delete(id) {
1635
+ await this.mw.http.request("DELETE", this.path(id));
1636
+ }
1637
+ /** Sends to the configured destination, also useful as a connection test. */
1638
+ send(id, text) {
1639
+ return this.mw.http.request("POST", `${this.path(id)}/send`, { body: { text } });
1640
+ }
1641
+ /** Latest 100 redacted delivery receipts. */
1642
+ events(id) {
1643
+ return this.mw.http.request("GET", `${this.path(id)}/events`);
1644
+ }
1645
+ retry(id, eventId) {
1646
+ return this.mw.http.request("POST", `${this.path(id)}/events/${encodeURIComponent(eventId)}/retry`);
1647
+ }
1648
+ path(id) {
1649
+ return `/integrations/${encodeURIComponent(id)}`;
1650
+ }
1651
+ };
1652
+
1493
1653
  // src/surfaces.ts
1494
1654
  function savedDesktopID(id) {
1495
1655
  if (!/^(console|ds_[a-f0-9]{16})$/.test(id)) throw new Error("Invalid saved desktop ID.");
@@ -1988,7 +2148,7 @@ function daemonStartError(resolved, cause) {
1988
2148
  " \u2022 check GitHub Release access so the SDK can download its matching daemon binary; or",
1989
2149
  " \u2022 set MINDWIRE_DAEMON to a `mindwired` binary; or",
1990
2150
  " \u2022 pass { baseUrl } to connect to a daemon you run yourself.",
1991
- " \u2022 Working inside the mindwire monorepo? Run `go build -o /tmp/mindwired ./daemon/cmd/daemon` and set MINDWIRE_DAEMON.",
2151
+ " \u2022 Working inside the mindwire monorepo? Run `go -C packages/daemon build -o /tmp/mindwired ./cmd/daemon` and set MINDWIRE_DAEMON.",
1992
2152
  `(underlying error: ${cause.message})`
1993
2153
  ].join("\n");
1994
2154
  }
@@ -2085,6 +2245,9 @@ var handleByTransport = /* @__PURE__ */ new WeakMap();
2085
2245
  var Mindwire = class _Mindwire {
2086
2246
  /** Workspace registry: saved agent profiles, projects and chat relationships. */
2087
2247
  workspace;
2248
+ bots;
2249
+ apps;
2250
+ integrations;
2088
2251
  surfaces;
2089
2252
  service;
2090
2253
  execution;
@@ -2125,6 +2288,9 @@ var Mindwire = class _Mindwire {
2125
2288
  });
2126
2289
  this.defaultAgent = opts.agent;
2127
2290
  this.workspace = new WorkspaceApi(this);
2291
+ this.bots = new BotsApi(this);
2292
+ this.apps = new AppsApi(this);
2293
+ this.integrations = new IntegrationsApi(this);
2128
2294
  this.surfaces = new SurfacesApi(this);
2129
2295
  this.service = new ServiceApi(this);
2130
2296
  this.execution = new ExecutionApi(this);
@@ -2152,6 +2318,9 @@ var Mindwire = class _Mindwire {
2152
2318
  clone.http = this.http;
2153
2319
  clone.defaultAgent = agent;
2154
2320
  clone.workspace = new WorkspaceApi(clone);
2321
+ clone.bots = new BotsApi(clone);
2322
+ clone.apps = new AppsApi(clone);
2323
+ clone.integrations = new IntegrationsApi(clone);
2155
2324
  clone.surfaces = new SurfacesApi(clone);
2156
2325
  clone.service = new ServiceApi(clone);
2157
2326
  clone.execution = new ExecutionApi(clone);
@@ -2323,6 +2492,20 @@ var Mindwire = class _Mindwire {
2323
2492
  deleteChat(chatId) {
2324
2493
  return this.http.request("DELETE", `/chats/${encodeURIComponent(chatId)}`);
2325
2494
  }
2495
+ /** Read-only portable handoff context; requires crossAgentHandoffVersion >= 2. */
2496
+ previewHandoff(chatId) {
2497
+ return this.http.request("GET", `/chats/${encodeURIComponent(chatId)}/handoff`);
2498
+ }
2499
+ /** Start another agent in a linked conversation in the source project.
2500
+ * Reuse the identical payload after a lost response to recover the same run. */
2501
+ async handoff(chatId, request) {
2502
+ const result = await this.http.request(
2503
+ "POST",
2504
+ `/chats/${encodeURIComponent(chatId)}/handoff`,
2505
+ { body: request }
2506
+ );
2507
+ return { ...result, run: new Run(this.http, result.run) };
2508
+ }
2326
2509
  /**
2327
2510
  * `POST /chats/{id}/fork` — clone a chat into a new id (generated when `newChatId` is omitted).
2328
2511
  * Codex and Claude preserve native context. `beforeMessageId` excludes that prompt and every
@@ -2869,7 +3052,7 @@ async function ensureComputer(directory, cliPath, patch = {}, onProgress, option
2869
3052
  if (!compatible(controller2) || !await processStateAlive(controller2)) {
2870
3053
  await ensureComputer(directory, cliPath, {}, onProgress, { ...options, waitForRoutes: false });
2871
3054
  }
2872
- const { changeComputerConnection } = await import('./connection-change-6E7QLJFC.js');
3055
+ const { changeComputerConnection } = await import('./connection-change-RVS6XWTC.js');
2873
3056
  await changeComputerConnection(directory, Object.fromEntries(changed.map((key) => [key, patch[key]])), { signal: options.signal, onProgress });
2874
3057
  return computerClient(directory);
2875
3058
  }
@@ -2910,7 +3093,7 @@ async function ensureComputer(directory, cliPath, patch = {}, onProgress, option
2910
3093
  let controller = await readJSON(path4.join(directory, "computer-controller.json"));
2911
3094
  if (existing && controller && !compatible(controller) && await processStateAlive(controller)) {
2912
3095
  onProgress?.("Refreshing the background connection service\u2026");
2913
- const { handoffController } = await import('./controller-handoff-KNEQ5W6J.js');
3096
+ const { handoffController } = await import('./controller-handoff-7EOSPHSD.js');
2914
3097
  await handoffController(directory, controller, config, await existing.computer.info());
2915
3098
  controller = void 0;
2916
3099
  }
@@ -2944,7 +3127,7 @@ async function ensureComputer(directory, cliPath, patch = {}, onProgress, option
2944
3127
  }
2945
3128
  }
2946
3129
  async function superviseComputer(directory) {
2947
- const controller = await import('./controller-566LDBZD.js');
3130
+ const controller = await import('./controller-2WCEJ3F2.js');
2948
3131
  await controller.superviseComputer(directory);
2949
3132
  }
2950
3133
  async function stopComputer(directory, force = false) {
@@ -2969,5 +3152,5 @@ async function stopComputer(directory, force = false) {
2969
3152
  }
2970
3153
 
2971
3154
  export { CONTROLLER_PROTOCOL, ProviderConnectionError, RelayOutput, SDK_VERSION, acquireProcessLock, adoptProcess, adoptRelay, cloudflareCommand, computerClient, computerPairingQRData, computerPairingURI, currentProcessIdentity, defaultComputerConfig, defaultStateDirectory, directRoutes, ensureComputer, ensureDaemonBinary, hasCertificateError, ownChild, processIdentity, processStateAlive, providerFailure, providerNeedsAction, readJSON, startRelay, stopComputer, superviseComputer, versionAtLeast, websocketURL, writeJSON };
2972
- //# sourceMappingURL=chunk-4XL565EU.js.map
2973
- //# sourceMappingURL=chunk-4XL565EU.js.map
3155
+ //# sourceMappingURL=chunk-P3JTWITC.js.map
3156
+ //# sourceMappingURL=chunk-P3JTWITC.js.map