appduct 0.9.0
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/LICENSE +21 -0
- package/README.md +274 -0
- package/bin.js +2 -0
- package/dist/artifact-inspect.d.ts +110 -0
- package/dist/artifact-inspect.d.ts.map +1 -0
- package/dist/artifact-inspect.js +315 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +4 -0
- package/dist/cli/command-options.d.ts +44 -0
- package/dist/cli/command-options.d.ts.map +1 -0
- package/dist/cli/command-options.js +95 -0
- package/dist/cli/create-cli.d.ts +2 -0
- package/dist/cli/create-cli.d.ts.map +1 -0
- package/dist/cli/create-cli.js +56 -0
- package/dist/cli/dispatch.d.ts +3 -0
- package/dist/cli/dispatch.d.ts.map +1 -0
- package/dist/cli/dispatch.js +275 -0
- package/dist/cli/open-target.d.ts +112 -0
- package/dist/cli/open-target.d.ts.map +1 -0
- package/dist/cli/open-target.js +438 -0
- package/dist/cli/result-types.d.ts +194 -0
- package/dist/cli/result-types.d.ts.map +1 -0
- package/dist/cli/result-types.js +6 -0
- package/dist/cli/runner.d.ts +35 -0
- package/dist/cli/runner.d.ts.map +1 -0
- package/dist/cli/runner.js +111 -0
- package/dist/cli/types.d.ts +20 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +10 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +2 -0
- package/dist/client/app-client.d.ts +126 -0
- package/dist/client/app-client.d.ts.map +1 -0
- package/dist/client/app-client.js +223 -0
- package/dist/client/bootstrap.d.ts +48 -0
- package/dist/client/bootstrap.d.ts.map +1 -0
- package/dist/client/bootstrap.js +108 -0
- package/dist/client/connect.d.ts +17 -0
- package/dist/client/connect.d.ts.map +1 -0
- package/dist/client/connect.js +38 -0
- package/dist/client/errors.d.ts +26 -0
- package/dist/client/errors.d.ts.map +1 -0
- package/dist/client/errors.js +40 -0
- package/dist/client/index.d.ts +19 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +16 -0
- package/dist/commands/daemon.d.ts +22 -0
- package/dist/commands/daemon.d.ts.map +1 -0
- package/dist/commands/daemon.js +128 -0
- package/dist/commands/doctor.d.ts +23 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +42 -0
- package/dist/commands/events.d.ts +37 -0
- package/dist/commands/events.d.ts.map +1 -0
- package/dist/commands/events.js +76 -0
- package/dist/commands/init.d.ts +51 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +231 -0
- package/dist/commands/invoke.d.ts +22 -0
- package/dist/commands/invoke.d.ts.map +1 -0
- package/dist/commands/invoke.js +54 -0
- package/dist/commands/keygen.d.ts +23 -0
- package/dist/commands/keygen.d.ts.map +1 -0
- package/dist/commands/keygen.js +46 -0
- package/dist/commands/link.d.ts +30 -0
- package/dist/commands/link.d.ts.map +1 -0
- package/dist/commands/link.js +43 -0
- package/dist/commands/ls.d.ts +9 -0
- package/dist/commands/ls.d.ts.map +1 -0
- package/dist/commands/ls.js +7 -0
- package/dist/commands/mcp.d.ts +49 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +98 -0
- package/dist/commands/revoke.d.ts +12 -0
- package/dist/commands/revoke.d.ts.map +1 -0
- package/dist/commands/revoke.js +7 -0
- package/dist/commands/tools.d.ts +23 -0
- package/dist/commands/tools.d.ts.map +1 -0
- package/dist/commands/tools.js +52 -0
- package/dist/daemon/address.d.ts +30 -0
- package/dist/daemon/address.d.ts.map +1 -0
- package/dist/daemon/address.js +71 -0
- package/dist/daemon/audit.d.ts +107 -0
- package/dist/daemon/audit.d.ts.map +1 -0
- package/dist/daemon/audit.js +237 -0
- package/dist/daemon/calls.d.ts +84 -0
- package/dist/daemon/calls.d.ts.map +1 -0
- package/dist/daemon/calls.js +158 -0
- package/dist/daemon/config.d.ts +79 -0
- package/dist/daemon/config.d.ts.map +1 -0
- package/dist/daemon/config.js +170 -0
- package/dist/daemon/daemon.d.ts +43 -0
- package/dist/daemon/daemon.d.ts.map +1 -0
- package/dist/daemon/daemon.js +560 -0
- package/dist/daemon/event-bus.d.ts +49 -0
- package/dist/daemon/event-bus.d.ts.map +1 -0
- package/dist/daemon/event-bus.js +111 -0
- package/dist/daemon/links.d.ts +54 -0
- package/dist/daemon/links.d.ts.map +1 -0
- package/dist/daemon/links.js +118 -0
- package/dist/daemon/listener.d.ts +34 -0
- package/dist/daemon/listener.d.ts.map +1 -0
- package/dist/daemon/listener.js +132 -0
- package/dist/daemon/log-rotation.d.ts +82 -0
- package/dist/daemon/log-rotation.d.ts.map +1 -0
- package/dist/daemon/log-rotation.js +136 -0
- package/dist/daemon/pidfile.d.ts +38 -0
- package/dist/daemon/pidfile.d.ts.map +1 -0
- package/dist/daemon/pidfile.js +90 -0
- package/dist/daemon/policy.d.ts +22 -0
- package/dist/daemon/policy.d.ts.map +1 -0
- package/dist/daemon/policy.js +24 -0
- package/dist/daemon/registry.d.ts +19 -0
- package/dist/daemon/registry.d.ts.map +1 -0
- package/dist/daemon/registry.js +31 -0
- package/dist/daemon/rpc-server.d.ts +54 -0
- package/dist/daemon/rpc-server.d.ts.map +1 -0
- package/dist/daemon/rpc-server.js +203 -0
- package/dist/daemon/sessions.d.ts +86 -0
- package/dist/daemon/sessions.d.ts.map +1 -0
- package/dist/daemon/sessions.js +429 -0
- package/dist/daemon/socket-probe.d.ts +16 -0
- package/dist/daemon/socket-probe.d.ts.map +1 -0
- package/dist/daemon/socket-probe.js +28 -0
- package/dist/daemon/state-dir.d.ts +31 -0
- package/dist/daemon/state-dir.d.ts.map +1 -0
- package/dist/daemon/state-dir.js +43 -0
- package/dist/daemon/timers.d.ts +16 -0
- package/dist/daemon/timers.d.ts.map +1 -0
- package/dist/daemon/timers.js +12 -0
- package/dist/daemon/tls.d.ts +58 -0
- package/dist/daemon/tls.d.ts.map +1 -0
- package/dist/daemon/tls.js +79 -0
- package/dist/errors.d.ts +28 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +162 -0
- package/dist/host-certificate.d.ts +8 -0
- package/dist/host-certificate.d.ts.map +1 -0
- package/dist/host-certificate.js +111 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/key-material.d.ts +14 -0
- package/dist/key-material.d.ts.map +1 -0
- package/dist/key-material.js +42 -0
- package/dist/link.d.ts +76 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +117 -0
- package/dist/mcp/connect-tool.d.ts +115 -0
- package/dist/mcp/connect-tool.d.ts.map +1 -0
- package/dist/mcp/connect-tool.js +396 -0
- package/dist/mcp/daemon-tools.d.ts +13 -0
- package/dist/mcp/daemon-tools.d.ts.map +1 -0
- package/dist/mcp/daemon-tools.js +29 -0
- package/dist/mcp/events-tool.d.ts +111 -0
- package/dist/mcp/events-tool.d.ts.map +1 -0
- package/dist/mcp/events-tool.js +322 -0
- package/dist/mcp/server.d.ts +58 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +538 -0
- package/dist/mcp/tool-mapping.d.ts +58 -0
- package/dist/mcp/tool-mapping.d.ts.map +1 -0
- package/dist/mcp/tool-mapping.js +143 -0
- package/dist/mcp/tool-namespace.d.ts +40 -0
- package/dist/mcp/tool-namespace.d.ts.map +1 -0
- package/dist/mcp/tool-namespace.js +65 -0
- package/dist/native-scheme.d.ts +59 -0
- package/dist/native-scheme.d.ts.map +1 -0
- package/dist/native-scheme.js +465 -0
- package/dist/output.d.ts +28 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +342 -0
- package/dist/package-version.d.ts +30 -0
- package/dist/package-version.d.ts.map +1 -0
- package/dist/package-version.js +47 -0
- package/dist/qr-terminal.d.ts +13 -0
- package/dist/qr-terminal.d.ts.map +1 -0
- package/dist/qr-terminal.js +45 -0
- package/dist/rpc/client.d.ts +137 -0
- package/dist/rpc/client.d.ts.map +1 -0
- package/dist/rpc/client.js +819 -0
- package/dist/scheme.d.ts +181 -0
- package/dist/scheme.d.ts.map +1 -0
- package/dist/scheme.js +321 -0
- package/dist/spki-pin.d.ts +3 -0
- package/dist/spki-pin.d.ts.map +1 -0
- package/dist/spki-pin.js +14 -0
- package/package.json +65 -0
package/dist/output.js
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import pc from "picocolors";
|
|
2
|
+
import { formatAgentWebSocketUrl } from "@appduct/shared";
|
|
3
|
+
import { renderQrToTerminal } from "./qr-terminal.js";
|
|
4
|
+
const indentJson = (value) => {
|
|
5
|
+
return JSON.stringify(value, null, 2);
|
|
6
|
+
};
|
|
7
|
+
const renderMetaLines = (meta) => {
|
|
8
|
+
if (!meta) {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
return [
|
|
12
|
+
"Meta",
|
|
13
|
+
` Command: ${meta.command}`,
|
|
14
|
+
` Timestamp: ${meta.timestamp}`,
|
|
15
|
+
...(typeof meta.duration_ms === "number" ? [` Duration: ${meta.duration_ms} ms`] : []),
|
|
16
|
+
];
|
|
17
|
+
};
|
|
18
|
+
const formatScalar = (value) => {
|
|
19
|
+
if (typeof value === "string") {
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
23
|
+
return String(value);
|
|
24
|
+
}
|
|
25
|
+
if (value === null || value === undefined) {
|
|
26
|
+
return "null";
|
|
27
|
+
}
|
|
28
|
+
return indentJson(value);
|
|
29
|
+
};
|
|
30
|
+
const renderFields = (title, fields) => {
|
|
31
|
+
const visibleFields = fields.filter(([, value]) => value !== undefined);
|
|
32
|
+
if (visibleFields.length === 0) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
const width = Math.max(...visibleFields.map(([label]) => label.length));
|
|
36
|
+
return [
|
|
37
|
+
title,
|
|
38
|
+
...visibleFields.map(([label, value]) => ` ${label.padEnd(width)} ${formatScalar(value)}`),
|
|
39
|
+
];
|
|
40
|
+
};
|
|
41
|
+
/** Humanizes an elapsed duration for `ls`'s "age" column: seconds/minutes/hours/days, coarsest unit
|
|
42
|
+
* that keeps at least one digit of precision. */
|
|
43
|
+
const formatAge = (fromIso, toIso) => {
|
|
44
|
+
const elapsedMs = Math.max(0, new Date(toIso).getTime() - new Date(fromIso).getTime());
|
|
45
|
+
const elapsedSeconds = Math.floor(elapsedMs / 1000);
|
|
46
|
+
if (elapsedSeconds < 60) {
|
|
47
|
+
return `${elapsedSeconds}s`;
|
|
48
|
+
}
|
|
49
|
+
const elapsedMinutes = Math.floor(elapsedSeconds / 60);
|
|
50
|
+
if (elapsedMinutes < 60) {
|
|
51
|
+
return `${elapsedMinutes}m`;
|
|
52
|
+
}
|
|
53
|
+
const elapsedHours = Math.floor(elapsedMinutes / 60);
|
|
54
|
+
if (elapsedHours < 24) {
|
|
55
|
+
return `${elapsedHours}h`;
|
|
56
|
+
}
|
|
57
|
+
return `${Math.floor(elapsedHours / 24)}d`;
|
|
58
|
+
};
|
|
59
|
+
const formatDevice = (device) => {
|
|
60
|
+
const parts = [device.manufacturer, device.model].filter((part) => Boolean(part));
|
|
61
|
+
const label = parts.length > 0 ? parts.join(" ") : "unknown device";
|
|
62
|
+
return device.os ? `${label} (${device.os})` : label;
|
|
63
|
+
};
|
|
64
|
+
const renderLsData = (colors, data, meta) => {
|
|
65
|
+
if (data.length === 0) {
|
|
66
|
+
return [colors.dim("Sessions"), " No Appduct sessions are registered."];
|
|
67
|
+
}
|
|
68
|
+
const now = meta?.timestamp ?? new Date().toISOString();
|
|
69
|
+
const headers = ["Alias", "State", "Device", "Tools", "Age"];
|
|
70
|
+
const rows = data.map((session) => [
|
|
71
|
+
session.alias,
|
|
72
|
+
session.state,
|
|
73
|
+
formatDevice(session.device),
|
|
74
|
+
String(session.toolCount),
|
|
75
|
+
formatAge(session.claimedAt ?? session.createdAt, now),
|
|
76
|
+
]);
|
|
77
|
+
const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => row[index].length)));
|
|
78
|
+
return [
|
|
79
|
+
colors.green("Sessions"),
|
|
80
|
+
` ${headers.map((header, index) => header.padEnd(widths[index])).join(" ")}`,
|
|
81
|
+
...rows.map((row) => ` ${row.map((cell, index) => cell.padEnd(widths[index])).join(" ")}`),
|
|
82
|
+
];
|
|
83
|
+
};
|
|
84
|
+
const renderToolSummaryTable = (tools) => {
|
|
85
|
+
if (tools.length === 0) {
|
|
86
|
+
return ["Tools", " No tools registered."];
|
|
87
|
+
}
|
|
88
|
+
const nameWidth = Math.max(...tools.map((tool) => tool.name.length), "Name".length);
|
|
89
|
+
return [
|
|
90
|
+
"Tools",
|
|
91
|
+
` ${"Name".padEnd(nameWidth)} Description`,
|
|
92
|
+
...tools.map((tool) => ` ${tool.name.padEnd(nameWidth)} ${tool.description}`),
|
|
93
|
+
];
|
|
94
|
+
};
|
|
95
|
+
const renderToolDetail = (colors, tool) => {
|
|
96
|
+
return renderFields(colors.green(`Tool: ${tool.name}`), [
|
|
97
|
+
["Description", tool.description],
|
|
98
|
+
["Input schema", tool.input_schema],
|
|
99
|
+
["Output schema", tool.output_schema],
|
|
100
|
+
["Annotations", tool.annotations],
|
|
101
|
+
// Only rendered for a tool that declares one; `renderFields` drops undefined rows, so a tool
|
|
102
|
+
// on the daemon's default deadline shows no line at all rather than a misleading "10000".
|
|
103
|
+
["Timeout (ms)", tool.timeout_ms],
|
|
104
|
+
]);
|
|
105
|
+
};
|
|
106
|
+
const renderToolsData = (colors, data, full) => {
|
|
107
|
+
if (!Array.isArray(data)) {
|
|
108
|
+
return renderToolDetail(colors, data);
|
|
109
|
+
}
|
|
110
|
+
if (full) {
|
|
111
|
+
return data.length === 0
|
|
112
|
+
? ["Tools", " No tools registered."]
|
|
113
|
+
: data.flatMap((tool, index) => [...(index > 0 ? [""] : []), ...renderToolDetail(colors, tool)]);
|
|
114
|
+
}
|
|
115
|
+
return [colors.green("Tools"), ...renderToolSummaryTable(data).slice(1)];
|
|
116
|
+
};
|
|
117
|
+
const renderInvokeData = (colors, data) => {
|
|
118
|
+
return [colors.green("Result"), formatScalar(data)];
|
|
119
|
+
};
|
|
120
|
+
const renderLinkData = (colors, data, qr) => {
|
|
121
|
+
const lines = [
|
|
122
|
+
colors.green("Link Created"),
|
|
123
|
+
...renderFields("Link", [
|
|
124
|
+
["Session", data.sessionId],
|
|
125
|
+
["Deep link", data.deepLink],
|
|
126
|
+
["Endpoint", formatAgentWebSocketUrl(data.endpoint)],
|
|
127
|
+
["Pin", data.pin],
|
|
128
|
+
["Expires", new Date(data.expiresAt * 1000).toISOString()],
|
|
129
|
+
["Delivered", data.delivered ? `yes (${data.target})` : undefined],
|
|
130
|
+
]),
|
|
131
|
+
];
|
|
132
|
+
if (qr) {
|
|
133
|
+
lines.push("", "QR", renderQrToTerminal(data.deepLink));
|
|
134
|
+
}
|
|
135
|
+
return lines;
|
|
136
|
+
};
|
|
137
|
+
const renderRevokeData = (colors, _data) => {
|
|
138
|
+
return [colors.green("Session Revoked")];
|
|
139
|
+
};
|
|
140
|
+
const renderKeygenData = (colors, data) => {
|
|
141
|
+
return [
|
|
142
|
+
colors.green("Key Ready"),
|
|
143
|
+
...renderFields("Key", [
|
|
144
|
+
["Path", data.path],
|
|
145
|
+
["Fingerprint", data.pin],
|
|
146
|
+
]),
|
|
147
|
+
];
|
|
148
|
+
};
|
|
149
|
+
const renderInitData = (colors, data) => {
|
|
150
|
+
const snippet = JSON.stringify({ mcpServers: { appduct: data.mcpServerEntry } }, null, 2);
|
|
151
|
+
return [
|
|
152
|
+
colors.green(data.changed ? "Project Initialized" : "Project Already Initialized"),
|
|
153
|
+
...renderFields("Config", [
|
|
154
|
+
["Path", data.path],
|
|
155
|
+
["Scheme", data.scheme],
|
|
156
|
+
["Source", data.source],
|
|
157
|
+
// Only present for a scheme discovery read off a static project file (app.json, or one of
|
|
158
|
+
// the native Android/iOS probes) — names the exact file/key, not just which platform.
|
|
159
|
+
["Read from", data.origin],
|
|
160
|
+
["Written", data.changed ? (data.created ? "created" : "updated") : "unchanged"],
|
|
161
|
+
]),
|
|
162
|
+
...(data.note === undefined ? [] : ["", colors.yellow(`Note: ${data.note}`)]),
|
|
163
|
+
"",
|
|
164
|
+
"MCP server entry",
|
|
165
|
+
...snippet.split("\n").map((line) => ` ${line}`),
|
|
166
|
+
"",
|
|
167
|
+
"Next",
|
|
168
|
+
...data.nextSteps.map((step, index) => ` ${index + 1}. ${step}`),
|
|
169
|
+
];
|
|
170
|
+
};
|
|
171
|
+
const renderDaemonRunData = (colors, data) => {
|
|
172
|
+
return [
|
|
173
|
+
colors.green("Daemon Running"),
|
|
174
|
+
...renderFields("Daemon", [
|
|
175
|
+
["PID", data.daemon.pid],
|
|
176
|
+
["State dir", data.daemon.state_dir],
|
|
177
|
+
["Socket", data.daemon.socket_path],
|
|
178
|
+
]),
|
|
179
|
+
];
|
|
180
|
+
};
|
|
181
|
+
const renderDaemonStartData = (colors, data) => {
|
|
182
|
+
return [
|
|
183
|
+
colors.green("Daemon Started"),
|
|
184
|
+
...renderFields("Daemon", [
|
|
185
|
+
["PID", data.daemon.pid],
|
|
186
|
+
["WSS port", data.daemon.wss_port],
|
|
187
|
+
["Started at", data.daemon.started_at],
|
|
188
|
+
]),
|
|
189
|
+
];
|
|
190
|
+
};
|
|
191
|
+
const renderDaemonStopData = (colors, data) => {
|
|
192
|
+
return [
|
|
193
|
+
colors.green("Daemon Stopped"),
|
|
194
|
+
...renderFields("Daemon", [["Method", data.daemon.method]]),
|
|
195
|
+
];
|
|
196
|
+
};
|
|
197
|
+
/** Human column for a byte count (the machine-readable `bytes` stays exact in `--json`). Binary
|
|
198
|
+
* units, one decimal above KiB, so a growing `audit/` reads at a glance. */
|
|
199
|
+
const formatByteSize = (bytes) => {
|
|
200
|
+
const units = ["B", "KiB", "MiB", "GiB", "TiB"];
|
|
201
|
+
let value = bytes;
|
|
202
|
+
let unit = 0;
|
|
203
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
204
|
+
value /= 1024;
|
|
205
|
+
unit += 1;
|
|
206
|
+
}
|
|
207
|
+
return `${unit === 0 ? value : value.toFixed(1)} ${units[unit]}`;
|
|
208
|
+
};
|
|
209
|
+
const renderDaemonStatusData = (colors, data) => {
|
|
210
|
+
return [
|
|
211
|
+
colors.green("Daemon Status"),
|
|
212
|
+
...renderFields("Daemon", [
|
|
213
|
+
["Version", data.daemon.version],
|
|
214
|
+
["PID", data.daemon.pid],
|
|
215
|
+
["Started at", data.daemon.started_at],
|
|
216
|
+
["WSS port", data.daemon.wss_port],
|
|
217
|
+
["Pinned keys", data.daemon.pinned_keys.length],
|
|
218
|
+
["Sessions", data.daemon.session_count],
|
|
219
|
+
]),
|
|
220
|
+
"",
|
|
221
|
+
...renderFields("Policy", [
|
|
222
|
+
["Default", data.policy.default],
|
|
223
|
+
["Destructive", data.policy.destructive],
|
|
224
|
+
["Overrides", data.policy.tools ? Object.keys(data.policy.tools).length : 0],
|
|
225
|
+
]),
|
|
226
|
+
"",
|
|
227
|
+
// The retention rows drop out entirely against a daemon that predates them (`renderFields`
|
|
228
|
+
// skips `undefined`), rather than printing "undefined" or an invented zero.
|
|
229
|
+
...renderFields("Audit", [
|
|
230
|
+
["Path", data.audit.path],
|
|
231
|
+
["Retention", data.audit.retention_days === undefined ? undefined : `${data.audit.retention_days} days`],
|
|
232
|
+
["Files", data.audit.files],
|
|
233
|
+
["Size", data.audit.bytes === undefined ? undefined : formatByteSize(data.audit.bytes)],
|
|
234
|
+
["Failed writes", data.audit.failed_writes],
|
|
235
|
+
["Failed prunes", data.audit.failed_prunes],
|
|
236
|
+
]),
|
|
237
|
+
// Version drift (issue #30) is the one thing here an operator has to act on, so it goes last
|
|
238
|
+
// — the line still on screen after the block scrolls — and in yellow, not a quiet field row.
|
|
239
|
+
...(data.warning ? ["", colors.yellow(`Warning: ${data.warning}`)] : []),
|
|
240
|
+
];
|
|
241
|
+
};
|
|
242
|
+
const renderDoctorData = (colors, data) => {
|
|
243
|
+
return [
|
|
244
|
+
data.present ? colors.green("Appduct Present") : colors.yellow("Appduct Absent"),
|
|
245
|
+
...renderFields("Artifact", [
|
|
246
|
+
["Path", data.artifact],
|
|
247
|
+
["Platform", data.platform],
|
|
248
|
+
["Format", data.format],
|
|
249
|
+
["Present", data.present],
|
|
250
|
+
["Signals", data.signals.length > 0 ? data.signals.join(", ") : "none"],
|
|
251
|
+
["Assertion", data.assertion ? `${data.assertion.expected} (holds)` : undefined],
|
|
252
|
+
]),
|
|
253
|
+
];
|
|
254
|
+
};
|
|
255
|
+
const renderSuccessData = (colors, command, data, options, meta) => {
|
|
256
|
+
switch (command) {
|
|
257
|
+
case "init":
|
|
258
|
+
return renderInitData(colors, data);
|
|
259
|
+
case "keygen":
|
|
260
|
+
return renderKeygenData(colors, data);
|
|
261
|
+
case "link":
|
|
262
|
+
return renderLinkData(colors, data, options.qr);
|
|
263
|
+
case "ls":
|
|
264
|
+
return renderLsData(colors, data, meta);
|
|
265
|
+
case "tools":
|
|
266
|
+
return renderToolsData(colors, data, options.full);
|
|
267
|
+
case "invoke":
|
|
268
|
+
return renderInvokeData(colors, data);
|
|
269
|
+
case "revoke":
|
|
270
|
+
return renderRevokeData(colors, data);
|
|
271
|
+
case "daemon run":
|
|
272
|
+
return renderDaemonRunData(colors, data);
|
|
273
|
+
case "daemon start":
|
|
274
|
+
return renderDaemonStartData(colors, data);
|
|
275
|
+
case "daemon stop":
|
|
276
|
+
return renderDaemonStopData(colors, data);
|
|
277
|
+
case "daemon status":
|
|
278
|
+
return renderDaemonStatusData(colors, data);
|
|
279
|
+
case "doctor":
|
|
280
|
+
return renderDoctorData(colors, data);
|
|
281
|
+
default:
|
|
282
|
+
return [colors.green("Command Complete"), indentJson(data)];
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
const renderHumanError = (colors, error, meta) => {
|
|
286
|
+
return [
|
|
287
|
+
colors.red("Command Failed"),
|
|
288
|
+
...renderFields("Error", [
|
|
289
|
+
["Type", error.type],
|
|
290
|
+
["Message", error.message],
|
|
291
|
+
["Details", error.details],
|
|
292
|
+
]),
|
|
293
|
+
...(meta ? ["", ...renderMetaLines(meta)] : []),
|
|
294
|
+
].join("\n");
|
|
295
|
+
};
|
|
296
|
+
export const renderResult = (result, options) => {
|
|
297
|
+
if (options.json) {
|
|
298
|
+
return {
|
|
299
|
+
stdout: `${indentJson(result)}\n`,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
const colors = pc.createColors(options.color);
|
|
303
|
+
if (!result.ok) {
|
|
304
|
+
return {
|
|
305
|
+
stderr: `${renderHumanError(colors, result.error, result.meta)}\n`,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
const lines = [
|
|
309
|
+
...renderSuccessData(colors, options.command, result.data, options, result.meta),
|
|
310
|
+
"",
|
|
311
|
+
...renderMetaLines(result.meta),
|
|
312
|
+
].filter((line, index, collection) => {
|
|
313
|
+
if (line !== "") {
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
return index > 0 && collection[index - 1] !== "" && index < collection.length - 1;
|
|
317
|
+
});
|
|
318
|
+
return {
|
|
319
|
+
stdout: `${lines.join("\n")}\n`,
|
|
320
|
+
};
|
|
321
|
+
};
|
|
322
|
+
/** Renders one `appduct events` line: NDJSON under `--json`, a compact human line otherwise. */
|
|
323
|
+
export const renderEventLine = (event, options) => {
|
|
324
|
+
if (options.json) {
|
|
325
|
+
return JSON.stringify(event);
|
|
326
|
+
}
|
|
327
|
+
const colors = pc.createColors(options.color);
|
|
328
|
+
const timestamp = new Date(event.ts).toISOString();
|
|
329
|
+
const target = event.alias ?? event.sessionId;
|
|
330
|
+
const dataSuffix = event.data === undefined ? "" : ` ${indentJson(event.data)}`;
|
|
331
|
+
return `${colors.dim(timestamp)} ${colors.green(event.kind)}${target ? ` ${target}` : ""}${dataSuffix}`;
|
|
332
|
+
};
|
|
333
|
+
/** Renders the trailing cursor line for `appduct events --since` (issue #6): NDJSON under
|
|
334
|
+
* `--json` so a scripted caller can parse the resume point without maxing `seq` over the printed
|
|
335
|
+
* events (impossible when the response is empty), a human note otherwise. */
|
|
336
|
+
export const renderEventsCursorLine = (cursor, options) => {
|
|
337
|
+
if (options.json) {
|
|
338
|
+
return JSON.stringify({ cursor });
|
|
339
|
+
}
|
|
340
|
+
const colors = pc.createColors(options.color);
|
|
341
|
+
return colors.dim(`cursor: ${cursor} (pass --since ${cursor} to resume from here)`);
|
|
342
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single source of truth for "what version of Appduct is this process running".
|
|
3
|
+
*
|
|
4
|
+
* The daemon (`daemon/daemon.ts`), the MCP server (`mcp/server.ts`), the CLI's `--version`
|
|
5
|
+
* (`cli/create-cli.ts`) and the CLI's daemon version check (`cli/dispatch.ts`) all need the
|
|
6
|
+
* published package version, and every one of them used to re-read `package.json` itself. They
|
|
7
|
+
* read it through this module instead so a single mismatch in the relative path can't make one of
|
|
8
|
+
* them report a different version than the others (issue #30).
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Test seam (issue #30): when set, the daemon reports this instead of the real package version in
|
|
12
|
+
* `daemon.status` and the `daemon_started` event, so an integration test can produce a genuine
|
|
13
|
+
* client/daemon version mismatch without installing two builds. Read only by the daemon — a
|
|
14
|
+
* *client* must always report the version it truly is, or the check would compare a lie to a lie.
|
|
15
|
+
*
|
|
16
|
+
* Honored **only under a test runner** (see {@link isTestRuntime}). A daemon that lied about its
|
|
17
|
+
* version in production would make every command restart it, forever: the value is inherited by
|
|
18
|
+
* whatever the shell exported, and the replacement daemon would report the same lie. The RPC
|
|
19
|
+
* client additionally strips this key from the environment of any daemon it spawns.
|
|
20
|
+
*/
|
|
21
|
+
export declare const DAEMON_VERSION_OVERRIDE_ENV = "APPDUCT_DAEMON_VERSION_OVERRIDE";
|
|
22
|
+
/** The `version` field of this package's `package.json`, read once per process. */
|
|
23
|
+
export declare const getPackageVersion: () => string;
|
|
24
|
+
/**
|
|
25
|
+
* The version the *daemon* reports over RPC: {@link getPackageVersion}, unless
|
|
26
|
+
* {@link DAEMON_VERSION_OVERRIDE_ENV} overrides it. Evaluated per call (not cached) so a daemon
|
|
27
|
+
* started in-process by a test picks up the environment that test set.
|
|
28
|
+
*/
|
|
29
|
+
export declare const getDaemonReportedVersion: (env?: NodeJS.ProcessEnv) => string;
|
|
30
|
+
//# sourceMappingURL=package-version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-version.d.ts","sourceRoot":"","sources":["../src/package-version.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,2BAA2B,oCAAoC,CAAC;AAW7E,mFAAmF;AACnF,eAAO,MAAM,iBAAiB,QAAO,MAGpC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GAAI,MAAK,MAAM,CAAC,UAAwB,KAAG,MAO/E,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single source of truth for "what version of Appduct is this process running".
|
|
3
|
+
*
|
|
4
|
+
* The daemon (`daemon/daemon.ts`), the MCP server (`mcp/server.ts`), the CLI's `--version`
|
|
5
|
+
* (`cli/create-cli.ts`) and the CLI's daemon version check (`cli/dispatch.ts`) all need the
|
|
6
|
+
* published package version, and every one of them used to re-read `package.json` itself. They
|
|
7
|
+
* read it through this module instead so a single mismatch in the relative path can't make one of
|
|
8
|
+
* them report a different version than the others (issue #30).
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import { dirname, join } from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
/**
|
|
14
|
+
* Test seam (issue #30): when set, the daemon reports this instead of the real package version in
|
|
15
|
+
* `daemon.status` and the `daemon_started` event, so an integration test can produce a genuine
|
|
16
|
+
* client/daemon version mismatch without installing two builds. Read only by the daemon — a
|
|
17
|
+
* *client* must always report the version it truly is, or the check would compare a lie to a lie.
|
|
18
|
+
*
|
|
19
|
+
* Honored **only under a test runner** (see {@link isTestRuntime}). A daemon that lied about its
|
|
20
|
+
* version in production would make every command restart it, forever: the value is inherited by
|
|
21
|
+
* whatever the shell exported, and the replacement daemon would report the same lie. The RPC
|
|
22
|
+
* client additionally strips this key from the environment of any daemon it spawns.
|
|
23
|
+
*/
|
|
24
|
+
export const DAEMON_VERSION_OVERRIDE_ENV = "APPDUCT_DAEMON_VERSION_OVERRIDE";
|
|
25
|
+
/** True under Vitest, or with an explicit `NODE_ENV=test`. */
|
|
26
|
+
const isTestRuntime = (env) => {
|
|
27
|
+
return Boolean(env.VITEST) || env.NODE_ENV === "test";
|
|
28
|
+
};
|
|
29
|
+
const packageJsonPath = join(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
30
|
+
let cached;
|
|
31
|
+
/** The `version` field of this package's `package.json`, read once per process. */
|
|
32
|
+
export const getPackageVersion = () => {
|
|
33
|
+
cached ??= JSON.parse(readFileSync(packageJsonPath, "utf8")).version;
|
|
34
|
+
return cached;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* The version the *daemon* reports over RPC: {@link getPackageVersion}, unless
|
|
38
|
+
* {@link DAEMON_VERSION_OVERRIDE_ENV} overrides it. Evaluated per call (not cached) so a daemon
|
|
39
|
+
* started in-process by a test picks up the environment that test set.
|
|
40
|
+
*/
|
|
41
|
+
export const getDaemonReportedVersion = (env = process.env) => {
|
|
42
|
+
if (!isTestRuntime(env)) {
|
|
43
|
+
return getPackageVersion();
|
|
44
|
+
}
|
|
45
|
+
const override = env[DAEMON_VERSION_OVERRIDE_ENV];
|
|
46
|
+
return override !== undefined && override.length > 0 ? override : getPackageVersion();
|
|
47
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type QrTerminalRenderOptions = {
|
|
2
|
+
/** Quiet zone in modules (default 0). */
|
|
3
|
+
margin?: number;
|
|
4
|
+
/**
|
|
5
|
+
* `toqr` error-correction index: M=0, L=1, H=2, Q=3 (default 1 = L).
|
|
6
|
+
*/
|
|
7
|
+
ecLevel?: number;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Renders a QR payload as compact half-block terminal art (two modules per character row).
|
|
11
|
+
*/
|
|
12
|
+
export declare const renderQrToTerminal: (content: string, options?: QrTerminalRenderOptions) => string;
|
|
13
|
+
//# sourceMappingURL=qr-terminal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qr-terminal.d.ts","sourceRoot":"","sources":["../src/qr-terminal.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,uBAAuB,GAAG;IACpC,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAMF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,SAAS,MAAM,EACf,UAAU,uBAAuB,KAChC,MAyCF,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { toQR } from "toqr";
|
|
2
|
+
const HALF_UPPER = "\u2580"; // ▀
|
|
3
|
+
const HALF_LOWER = "\u2584"; // ▄
|
|
4
|
+
const FULL = "\u2588"; // █
|
|
5
|
+
/**
|
|
6
|
+
* Renders a QR payload as compact half-block terminal art (two modules per character row).
|
|
7
|
+
*/
|
|
8
|
+
export const renderQrToTerminal = (content, options) => {
|
|
9
|
+
const margin = options?.margin ?? 0;
|
|
10
|
+
const ecLevel = options?.ecLevel ?? 1;
|
|
11
|
+
const modules = toQR(content, ecLevel);
|
|
12
|
+
const side = Math.sqrt(modules.length);
|
|
13
|
+
if (!Number.isInteger(side)) {
|
|
14
|
+
throw new Error("Invalid QR matrix size");
|
|
15
|
+
}
|
|
16
|
+
const dim = side + 2 * margin;
|
|
17
|
+
const isDark = (row, col) => {
|
|
18
|
+
if (row < margin ||
|
|
19
|
+
col < margin ||
|
|
20
|
+
row >= margin + side ||
|
|
21
|
+
col >= margin + side) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const mr = row - margin;
|
|
25
|
+
const mc = col - margin;
|
|
26
|
+
return modules[mr * side + mc] === 1;
|
|
27
|
+
};
|
|
28
|
+
const lines = [];
|
|
29
|
+
for (let row = 0; row < dim; row += 2) {
|
|
30
|
+
let line = "";
|
|
31
|
+
for (let col = 0; col < dim; col++) {
|
|
32
|
+
const top = isDark(row, col);
|
|
33
|
+
const bottom = row + 1 < dim ? isDark(row + 1, col) : false;
|
|
34
|
+
line += top
|
|
35
|
+
? bottom
|
|
36
|
+
? FULL
|
|
37
|
+
: HALF_UPPER
|
|
38
|
+
: bottom
|
|
39
|
+
? HALF_LOWER
|
|
40
|
+
: " ";
|
|
41
|
+
}
|
|
42
|
+
lines.push(line);
|
|
43
|
+
}
|
|
44
|
+
return lines.join("\n");
|
|
45
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The auto-spawning RPC client library (ARCHITECTURE.md §4, §5) used by the CLI, MCP server, and
|
|
3
|
+
* tests to talk to `daemon.sock`. On `ENOENT`/`ECONNREFUSED` it takes an exclusive spawn-lock,
|
|
4
|
+
* spawns `daemon run` detached, polls the socket until ready, then retries the request once.
|
|
5
|
+
*/
|
|
6
|
+
import { type RpcErrorData } from "@appduct/shared";
|
|
7
|
+
export type SpawnContext = {
|
|
8
|
+
stateDir: string;
|
|
9
|
+
logFilePath: string;
|
|
10
|
+
};
|
|
11
|
+
/** Spawns `daemon run` detached with stdio redirected to `daemon.log`. Injectable for tests. */
|
|
12
|
+
export type SpawnFn = (args: string[], context: SpawnContext) => void | Promise<void>;
|
|
13
|
+
export declare class DaemonRpcError extends Error {
|
|
14
|
+
readonly code: number;
|
|
15
|
+
readonly data?: RpcErrorData | undefined;
|
|
16
|
+
constructor(code: number, message: string, data?: RpcErrorData | undefined);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* `reason` distinguishes outcomes that look identical to a caller but mean opposite things to the
|
|
20
|
+
* version-drift restart (issue #30): `"closed"` is the daemon dropping the connection — expected
|
|
21
|
+
* while it tears itself down — whereas `"timeout"` is a daemon that is very much alive and simply
|
|
22
|
+
* not answering, which must never be mistaken for "it is gone, spawn another one".
|
|
23
|
+
*/
|
|
24
|
+
export declare class DaemonUnavailableError extends Error {
|
|
25
|
+
readonly reason: "timeout" | "closed" | "unreachable";
|
|
26
|
+
constructor(message: string, reason?: "timeout" | "closed" | "unreachable");
|
|
27
|
+
}
|
|
28
|
+
/** What a restart would destroy, as read from one `daemon.status` reply. */
|
|
29
|
+
export type DaemonLiveState = {
|
|
30
|
+
sessions: number;
|
|
31
|
+
pendingLinks: number;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Raised when the daemon this client reached is running a different Appduct version and could
|
|
35
|
+
* not be replaced (issue #30). The common case is live state a restart would destroy: sessions
|
|
36
|
+
* (resume tokens are in-daemon memory, so a restart makes the app's resume fail closed with 1008)
|
|
37
|
+
* or pending links (a deep link or QR code someone is about to scan). The caller is told rather
|
|
38
|
+
* than silently paying that cost.
|
|
39
|
+
*/
|
|
40
|
+
export declare class DaemonVersionMismatchError extends Error {
|
|
41
|
+
readonly daemonVersion: string;
|
|
42
|
+
readonly clientVersion: string;
|
|
43
|
+
readonly sessionCount: number;
|
|
44
|
+
readonly pendingLinkCount: number;
|
|
45
|
+
constructor(daemonVersion: string, clientVersion: string, live: DaemonLiveState, message?: string);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Raised when the daemon *was* restarted and the daemon now answering still reports a different
|
|
49
|
+
* version. Retrying would just kill daemon after daemon, so the check stops after one restart and
|
|
50
|
+
* reports what it actually observed rather than guessing at a cause.
|
|
51
|
+
*/
|
|
52
|
+
export declare class DaemonVersionRestartIneffectiveError extends DaemonVersionMismatchError {
|
|
53
|
+
constructor(daemonVersion: string, clientVersion: string, live: DaemonLiveState);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Opt-in daemon/client version check (issue #30). Passed by the CLI dispatcher and the MCP
|
|
57
|
+
* server's startup stream; deliberately *not* passed by `appduct/client`, whose callers are
|
|
58
|
+
* test processes that must never have a daemon restarted out from under a live app session.
|
|
59
|
+
*/
|
|
60
|
+
export type VersionCheckOptions = {
|
|
61
|
+
/** The version this client actually is — always the real package version, never an override. */
|
|
62
|
+
clientVersion: string;
|
|
63
|
+
/** Restart even when the daemon has live sessions or pending links (`--daemon-restart`, the
|
|
64
|
+
* `APPDUCT_DAEMON_RESTART` env var, or `config.json`'s `restartDaemonOnVersionMismatch`). */
|
|
65
|
+
forceRestart?: boolean;
|
|
66
|
+
/** Where the "the daemon is newer than this client" notice goes. Defaults to `process.stderr` —
|
|
67
|
+
* never stdout, which belongs to `--json` output and to the MCP transport's frames. */
|
|
68
|
+
onWarning?: (message: string) => void;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* True when two version strings name the same version even though the strings differ — `1.2` and
|
|
72
|
+
* `1.2.0`, or two builds differing only in `+metadata`. Comparing the raw strings would report
|
|
73
|
+
* drift that does not exist and, worse, print a "the daemon is newer" notice about a daemon that
|
|
74
|
+
* is exactly this version.
|
|
75
|
+
*/
|
|
76
|
+
export declare const isSameVersion: (a: string, b: string) => boolean;
|
|
77
|
+
export type CallDaemonOptions = {
|
|
78
|
+
stateDir: string;
|
|
79
|
+
/** Auto-spawn a daemon on `ENOENT`/`ECONNREFUSED`. Defaults to `true`. */
|
|
80
|
+
autoSpawn?: boolean;
|
|
81
|
+
spawn?: SpawnFn;
|
|
82
|
+
/** Per-request timeout waiting for a response line. Defaults to 10s. */
|
|
83
|
+
requestTimeoutMs?: number;
|
|
84
|
+
/** How long to poll the socket for readiness after spawning. Defaults to 5000ms. */
|
|
85
|
+
spawnWaitTimeoutMs?: number;
|
|
86
|
+
/** Poll interval while waiting for the socket to become ready. Defaults to 100ms. */
|
|
87
|
+
spawnPollIntervalMs?: number;
|
|
88
|
+
/**
|
|
89
|
+
* When set, the first call from this process to a given daemon socket compares the daemon's
|
|
90
|
+
* version with {@link VersionCheckOptions.clientVersion} and restarts the daemon when they
|
|
91
|
+
* differ and doing so is safe. The result is cached per socket path, so this costs one extra
|
|
92
|
+
* `daemon.status` round-trip per process — not per request.
|
|
93
|
+
*/
|
|
94
|
+
checkVersion?: VersionCheckOptions;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* True when `error` indicates the daemon is not reachable at all — no listener at the socket
|
|
98
|
+
* path (`ENOENT`/`ECONNREFUSED`), or a `DaemonUnavailableError` from a request that timed out or
|
|
99
|
+
* had its connection drop mid-flight. Callers use this to decide whether a fallback (e.g. `daemon
|
|
100
|
+
* stop`'s SIGTERM-via-pidfile path) applies, as opposed to a `DaemonRpcError` from a daemon that
|
|
101
|
+
* is very much running but rejected the request.
|
|
102
|
+
*/
|
|
103
|
+
export declare const isDaemonUnreachableError: (error: unknown) => boolean;
|
|
104
|
+
/** Test seam: drops the per-process check cache so each test case starts from a clean slate. */
|
|
105
|
+
export declare const resetDaemonVersionChecks: () => void;
|
|
106
|
+
/**
|
|
107
|
+
* Runs the version check on its own, without issuing a command RPC — the CLI dispatcher's seam
|
|
108
|
+
* (issue #30). Pass `autoSpawn: false` (the default here) when the caller does not want a daemon
|
|
109
|
+
* started just to be checked: nothing listening means nothing to drift from.
|
|
110
|
+
*/
|
|
111
|
+
export declare const ensureDaemonVersionMatches: (options: Omit<CallDaemonOptions, "checkVersion"> & {
|
|
112
|
+
checkVersion: VersionCheckOptions;
|
|
113
|
+
}) => Promise<void>;
|
|
114
|
+
/** Calls a daemon RPC method, auto-spawning the daemon on a missing/refused connection. */
|
|
115
|
+
export declare const callDaemon: <TResult>(method: string, params: unknown, options: CallDaemonOptions) => Promise<TResult>;
|
|
116
|
+
export type DaemonStream = {
|
|
117
|
+
/** Sends a request over the persistent connection and awaits its response. `timeoutMs`
|
|
118
|
+
* overrides this stream's default transport timeout for this call only — needed when a
|
|
119
|
+
* request's own server-side deadline (e.g. `tools.call`'s `timeoutMs` param) can exceed the
|
|
120
|
+
* stream's default, so the transport timeout never fires before the server-side one does. */
|
|
121
|
+
call: <TResult>(method: string, params?: unknown, timeoutMs?: number) => Promise<TResult>;
|
|
122
|
+
/** Subscribes to server→client `"event"` notifications; returns an unsubscribe function. */
|
|
123
|
+
onNotification: (callback: (payload: unknown) => void) => () => void;
|
|
124
|
+
/** Fires once when the underlying socket closes (daemon gone, stop(), etc.); returns an
|
|
125
|
+
* unsubscribe function. Lets long-lived stream consumers (e.g. `appduct events`) end
|
|
126
|
+
* gracefully instead of hanging once the connection is no longer usable. */
|
|
127
|
+
onClose: (callback: () => void) => () => void;
|
|
128
|
+
close: () => void;
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Opens a persistent connection to the daemon (auto-spawning as needed) for use cases that need
|
|
132
|
+
* server→client notifications, e.g. `events.subscribe`.
|
|
133
|
+
*/
|
|
134
|
+
export declare const openDaemonStream: (options: Omit<CallDaemonOptions, "requestTimeoutMs"> & {
|
|
135
|
+
requestTimeoutMs?: number;
|
|
136
|
+
}) => Promise<DaemonStream>;
|
|
137
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/rpc/client.ts"],"names":[],"mappings":"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"}
|