appduct 0.13.0 → 0.15.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/README.md +55 -24
- package/dist/artifact-inspect.d.ts +38 -39
- package/dist/bin.js +106 -7
- package/dist/cli/result-types.d.ts +35 -2
- package/dist/cli/routes/daemon/index.js +90 -2
- package/dist/cli/routes/daemon/run.js +1088 -517
- package/dist/cli/routes/daemon/start.js +98 -2
- package/dist/cli/routes/daemon/status.js +99 -2
- package/dist/cli/routes/daemon/stop.js +98 -2
- package/dist/cli/routes/doctor.js +98 -3
- package/dist/cli/routes/events/index.d.ts +0 -3
- package/dist/cli/routes/events/index.js +92 -3
- package/dist/cli/routes/events/ls.d.ts +5 -0
- package/dist/cli/routes/events/ls.js +1837 -0
- package/dist/cli/routes/events/since.js +98 -2
- package/dist/cli/routes/events/tail.js +98 -2
- package/dist/cli/routes/init.js +265 -108
- package/dist/cli/routes/keygen.js +90 -2
- package/dist/cli/routes/mcp.js +243 -25
- package/dist/cli/routes/sessions/index.js +90 -2
- package/dist/cli/routes/sessions/link.js +199 -22
- package/dist/cli/routes/sessions/ls.js +98 -2
- package/dist/cli/routes/sessions/revoke.js +98 -2
- package/dist/cli/routes/tools/call.js +98 -2
- package/dist/cli/routes/tools/describe.js +98 -2
- package/dist/cli/routes/tools/index.js +90 -2
- package/dist/cli/routes/tools/ls.js +98 -2
- package/dist/client/attach-page.d.ts +39 -0
- package/dist/client/bootstrap.d.ts +17 -3
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.js +286 -112
- package/dist/commands/doctor.d.ts +3 -4
- package/dist/commands/events-ls.d.ts +21 -0
- package/dist/commands/init.d.ts +8 -2
- package/dist/commands/link.d.ts +10 -1
- package/dist/daemon/calls.d.ts +3 -1
- package/dist/daemon/config.d.ts +6 -0
- package/dist/daemon/daemon.d.ts +6 -1
- package/dist/daemon/event-bus.d.ts +10 -0
- package/dist/daemon/links.d.ts +9 -5
- package/dist/daemon/listener.d.ts +28 -1
- package/dist/daemon/registry.d.ts +20 -12
- package/dist/daemon/rpc-errors.d.ts +6 -0
- package/dist/daemon/sessions.d.ts +14 -8
- package/dist/daemon/tls.d.ts +0 -3
- package/dist/devtools-relay/attach-tab.d.ts +33 -0
- package/dist/devtools-relay/index.d.ts +8 -0
- package/dist/devtools-relay/memory-daemon-sockets.d.ts +20 -0
- package/dist/devtools-relay/memory-devtools-browser.d.ts +10 -0
- package/dist/devtools-relay/memory-page-channel.d.ts +16 -0
- package/dist/devtools-relay/node-daemon-socket.d.ts +3 -0
- package/dist/devtools-relay/node-devtools-browser.d.ts +3 -0
- package/dist/devtools-relay/ports.d.ts +48 -0
- package/dist/devtools-relay/relay.d.ts +16 -0
- package/dist/index.js +106 -7
- package/dist/link.d.ts +35 -1
- package/dist/mcp/app-tools.d.ts +19 -0
- package/dist/mcp/connect-tool.d.ts +15 -2
- package/dist/mcp/events-tool.d.ts +39 -0
- package/dist/native-scheme.d.ts +11 -7
- package/dist/scheme.d.ts +5 -1
- package/package.json +15 -5
|
@@ -24,6 +24,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
24
24
|
"daemonLogMaxBytes",
|
|
25
25
|
"eventsLogMaxBytes",
|
|
26
26
|
"policy",
|
|
27
|
+
"webOrigins",
|
|
27
28
|
"advertisedIp",
|
|
28
29
|
"scheme",
|
|
29
30
|
"restartDaemonOnVersionMismatch"
|
|
@@ -84,6 +85,7 @@ var defaultConfig = (paths) => {
|
|
|
84
85
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
85
86
|
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
86
87
|
restartDaemonOnVersionMismatch: false,
|
|
88
|
+
webOrigins: [],
|
|
87
89
|
policy: {
|
|
88
90
|
default: "allow",
|
|
89
91
|
destructive: "allow"
|
|
@@ -154,6 +156,12 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
154
156
|
"restartDaemonOnVersionMismatch"
|
|
155
157
|
);
|
|
156
158
|
}
|
|
159
|
+
if (parsed.webOrigins !== void 0) {
|
|
160
|
+
if (!Array.isArray(parsed.webOrigins)) {
|
|
161
|
+
throw configError("webOrigins", "must be an array of origin strings.");
|
|
162
|
+
}
|
|
163
|
+
config.webOrigins = parsed.webOrigins.map((origin) => requireNonEmptyString(origin, "webOrigins"));
|
|
164
|
+
}
|
|
157
165
|
if (parsed.policy !== void 0) {
|
|
158
166
|
if (typeof parsed.policy !== "object" || parsed.policy === null || Array.isArray(parsed.policy)) {
|
|
159
167
|
throw configError("policy", "must be an object.");
|
|
@@ -932,7 +940,7 @@ var EXIT_CODE_BY_ERROR_TYPE = {
|
|
|
932
940
|
// EX_NOINPUT (66): "an input file did not exist or was not readable" — `doctor` throws this for a
|
|
933
941
|
// missing external tool or an unreadable/corrupt artifact, deliberately distinct from every other
|
|
934
942
|
// code here so a release pipeline can't mistake "we couldn't tell" for either a clean pass or an
|
|
935
|
-
// assertion failure
|
|
943
|
+
// assertion failure.
|
|
936
944
|
inspection_error: 66,
|
|
937
945
|
connection_error: 70,
|
|
938
946
|
session_error: 71,
|
|
@@ -1049,6 +1057,7 @@ var formatJson = (value, flags) => {
|
|
|
1049
1057
|
import pc from "picocolors";
|
|
1050
1058
|
import {
|
|
1051
1059
|
formatAgentWebSocketUrl,
|
|
1060
|
+
renderEventSignature,
|
|
1052
1061
|
renderToolSignature,
|
|
1053
1062
|
summarizeToolDescription
|
|
1054
1063
|
} from "@appduct/shared";
|
|
@@ -1144,6 +1153,13 @@ var formatDevice = (device) => {
|
|
|
1144
1153
|
const label = parts.length > 0 ? parts.join(" ") : "unknown device";
|
|
1145
1154
|
return device.os ? `${label} (${device.os})` : label;
|
|
1146
1155
|
};
|
|
1156
|
+
var SUSPEND_REASON_LABELS = {
|
|
1157
|
+
app_backgrounded: "app in background",
|
|
1158
|
+
connection_lost: "connection lost"
|
|
1159
|
+
};
|
|
1160
|
+
var formatSessionState = (session) => {
|
|
1161
|
+
return session.suspendReason ? `${session.state} (${SUSPEND_REASON_LABELS[session.suspendReason]})` : session.state;
|
|
1162
|
+
};
|
|
1147
1163
|
var renderLsData = (colors, data, now) => {
|
|
1148
1164
|
if (data.length === 0) {
|
|
1149
1165
|
return [colors.dim("Sessions"), " No Appduct sessions are registered."];
|
|
@@ -1152,7 +1168,7 @@ var renderLsData = (colors, data, now) => {
|
|
|
1152
1168
|
const headers = ["Alias", "State", "Device", "Tools", "Age"];
|
|
1153
1169
|
const rows = data.map((session) => [
|
|
1154
1170
|
session.alias,
|
|
1155
|
-
session
|
|
1171
|
+
formatSessionState(session),
|
|
1156
1172
|
formatDevice(session.device),
|
|
1157
1173
|
String(session.toolCount),
|
|
1158
1174
|
formatAge(session.claimedAt ?? session.createdAt, nowIso)
|
|
@@ -1326,10 +1342,87 @@ var renderToolsListData = (colors, data, flags, full) => {
|
|
|
1326
1342
|
}
|
|
1327
1343
|
return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
|
|
1328
1344
|
};
|
|
1345
|
+
var renderEventsTruncationLine = (data) => {
|
|
1346
|
+
const offset = data.offset ?? 0;
|
|
1347
|
+
if (data.events.length >= data.total) {
|
|
1348
|
+
return [];
|
|
1349
|
+
}
|
|
1350
|
+
return [
|
|
1351
|
+
"",
|
|
1352
|
+
`Showing ${data.events.length} of ${data.total} events (offset ${offset}). Narrow with --name <glob> or page with --offset <n>.`
|
|
1353
|
+
];
|
|
1354
|
+
};
|
|
1355
|
+
var renderEventsListData = (colors, data, flags) => {
|
|
1356
|
+
const [only] = data.events;
|
|
1357
|
+
if (data.name !== void 0 && !data.name.includes("*") && only !== void 0) {
|
|
1358
|
+
return renderFields(
|
|
1359
|
+
colors.green(`Event: ${only.name}`),
|
|
1360
|
+
[
|
|
1361
|
+
["Signature", renderEventSignature(only)],
|
|
1362
|
+
["Description", only.description],
|
|
1363
|
+
["Payload schema", only.payload_schema]
|
|
1364
|
+
],
|
|
1365
|
+
flags
|
|
1366
|
+
);
|
|
1367
|
+
}
|
|
1368
|
+
if (data.events.length === 0 && data.total > 0) {
|
|
1369
|
+
return [
|
|
1370
|
+
colors.green("Events"),
|
|
1371
|
+
` No events at offset ${data.offset ?? 0}; ${data.total} matching event${data.total === 1 ? "" : "s"} in total.`
|
|
1372
|
+
];
|
|
1373
|
+
}
|
|
1374
|
+
if (data.events.length === 0) {
|
|
1375
|
+
return [
|
|
1376
|
+
colors.green("Events"),
|
|
1377
|
+
data.name === void 0 ? " No events declared." : ` No events match ${JSON.stringify(data.name)}.`
|
|
1378
|
+
];
|
|
1379
|
+
}
|
|
1380
|
+
const lines = data.events.flatMap((event) => [
|
|
1381
|
+
` ${renderEventSignature(event)}`,
|
|
1382
|
+
` ${summarizeToolDescription(event.description)}`
|
|
1383
|
+
]);
|
|
1384
|
+
return [
|
|
1385
|
+
colors.green("Events"),
|
|
1386
|
+
...lines,
|
|
1387
|
+
...renderEventsTruncationLine(data),
|
|
1388
|
+
"",
|
|
1389
|
+
"Run `appduct events ls --name <name>` for an event's full payload schema."
|
|
1390
|
+
];
|
|
1391
|
+
};
|
|
1329
1392
|
var renderInvokeData = (colors, data, flags) => {
|
|
1330
1393
|
return [colors.green("Result"), formatScalar(data, flags)];
|
|
1331
1394
|
};
|
|
1332
1395
|
var renderLinkData = (colors, data, flags, qr) => {
|
|
1396
|
+
if ("attached" in data) {
|
|
1397
|
+
return [
|
|
1398
|
+
colors.green("Page Attached"),
|
|
1399
|
+
...renderFields(
|
|
1400
|
+
"Page",
|
|
1401
|
+
[
|
|
1402
|
+
["Session", data.sessionId],
|
|
1403
|
+
["Tab", data.targetId],
|
|
1404
|
+
["URL", data.url],
|
|
1405
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
1406
|
+
],
|
|
1407
|
+
flags
|
|
1408
|
+
)
|
|
1409
|
+
];
|
|
1410
|
+
}
|
|
1411
|
+
if ("script" in data) {
|
|
1412
|
+
return [
|
|
1413
|
+
colors.green("Link Created"),
|
|
1414
|
+
...renderFields(
|
|
1415
|
+
"Link",
|
|
1416
|
+
[
|
|
1417
|
+
["Session", data.sessionId],
|
|
1418
|
+
["URL", data.url],
|
|
1419
|
+
["Script", data.script],
|
|
1420
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
1421
|
+
],
|
|
1422
|
+
flags
|
|
1423
|
+
)
|
|
1424
|
+
];
|
|
1425
|
+
}
|
|
1333
1426
|
const lines = [
|
|
1334
1427
|
colors.green("Link Created"),
|
|
1335
1428
|
...renderFields(
|
|
@@ -1450,6 +1543,7 @@ var renderDaemonStatusData = (colors, data, flags) => {
|
|
|
1450
1543
|
["PID", data.daemon.pid],
|
|
1451
1544
|
["Started at", data.daemon.started_at],
|
|
1452
1545
|
["WSS port", data.daemon.wss_port],
|
|
1546
|
+
["Web port", data.daemon.web_port],
|
|
1453
1547
|
["Pinned keys", data.daemon.pinned_keys.length],
|
|
1454
1548
|
["Sessions", data.daemon.session_count]
|
|
1455
1549
|
],
|
|
@@ -1517,6 +1611,8 @@ var renderSuccessData = (colors, command, data, options) => {
|
|
|
1517
1611
|
return renderToolsListData(colors, data, flags, options.full);
|
|
1518
1612
|
case "tools describe":
|
|
1519
1613
|
return renderToolDetail(colors, data, flags);
|
|
1614
|
+
case "events ls":
|
|
1615
|
+
return renderEventsListData(colors, data, flags);
|
|
1520
1616
|
case "tools call":
|
|
1521
1617
|
return renderInvokeData(colors, data, flags);
|
|
1522
1618
|
case "sessions revoke":
|
|
@@ -68,6 +68,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
68
68
|
"daemonLogMaxBytes",
|
|
69
69
|
"eventsLogMaxBytes",
|
|
70
70
|
"policy",
|
|
71
|
+
"webOrigins",
|
|
71
72
|
"advertisedIp",
|
|
72
73
|
"scheme",
|
|
73
74
|
"restartDaemonOnVersionMismatch"
|
|
@@ -128,6 +129,7 @@ var defaultConfig = (paths) => {
|
|
|
128
129
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
129
130
|
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
130
131
|
restartDaemonOnVersionMismatch: false,
|
|
132
|
+
webOrigins: [],
|
|
131
133
|
policy: {
|
|
132
134
|
default: "allow",
|
|
133
135
|
destructive: "allow"
|
|
@@ -198,6 +200,12 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
198
200
|
"restartDaemonOnVersionMismatch"
|
|
199
201
|
);
|
|
200
202
|
}
|
|
203
|
+
if (parsed.webOrigins !== void 0) {
|
|
204
|
+
if (!Array.isArray(parsed.webOrigins)) {
|
|
205
|
+
throw configError("webOrigins", "must be an array of origin strings.");
|
|
206
|
+
}
|
|
207
|
+
config.webOrigins = parsed.webOrigins.map((origin) => requireNonEmptyString(origin, "webOrigins"));
|
|
208
|
+
}
|
|
201
209
|
if (parsed.policy !== void 0) {
|
|
202
210
|
if (typeof parsed.policy !== "object" || parsed.policy === null || Array.isArray(parsed.policy)) {
|
|
203
211
|
throw configError("policy", "must be an object.");
|
|
@@ -932,6 +940,7 @@ var handleDaemonStatusCommand = async (context) => {
|
|
|
932
940
|
pid: status.pid,
|
|
933
941
|
started_at: status.startedAt,
|
|
934
942
|
wss_port: status.wssPort,
|
|
943
|
+
web_port: status.webPort,
|
|
935
944
|
pinned_keys: status.pinnedKeys,
|
|
936
945
|
session_count: sessionCount
|
|
937
946
|
},
|
|
@@ -961,7 +970,7 @@ var EXIT_CODE_BY_ERROR_TYPE = {
|
|
|
961
970
|
// EX_NOINPUT (66): "an input file did not exist or was not readable" — `doctor` throws this for a
|
|
962
971
|
// missing external tool or an unreadable/corrupt artifact, deliberately distinct from every other
|
|
963
972
|
// code here so a release pipeline can't mistake "we couldn't tell" for either a clean pass or an
|
|
964
|
-
// assertion failure
|
|
973
|
+
// assertion failure.
|
|
965
974
|
inspection_error: 66,
|
|
966
975
|
connection_error: 70,
|
|
967
976
|
session_error: 71,
|
|
@@ -1078,6 +1087,7 @@ var formatJson = (value, flags) => {
|
|
|
1078
1087
|
import pc from "picocolors";
|
|
1079
1088
|
import {
|
|
1080
1089
|
formatAgentWebSocketUrl,
|
|
1090
|
+
renderEventSignature,
|
|
1081
1091
|
renderToolSignature,
|
|
1082
1092
|
summarizeToolDescription
|
|
1083
1093
|
} from "@appduct/shared";
|
|
@@ -1173,6 +1183,13 @@ var formatDevice = (device) => {
|
|
|
1173
1183
|
const label = parts.length > 0 ? parts.join(" ") : "unknown device";
|
|
1174
1184
|
return device.os ? `${label} (${device.os})` : label;
|
|
1175
1185
|
};
|
|
1186
|
+
var SUSPEND_REASON_LABELS = {
|
|
1187
|
+
app_backgrounded: "app in background",
|
|
1188
|
+
connection_lost: "connection lost"
|
|
1189
|
+
};
|
|
1190
|
+
var formatSessionState = (session) => {
|
|
1191
|
+
return session.suspendReason ? `${session.state} (${SUSPEND_REASON_LABELS[session.suspendReason]})` : session.state;
|
|
1192
|
+
};
|
|
1176
1193
|
var renderLsData = (colors, data, now) => {
|
|
1177
1194
|
if (data.length === 0) {
|
|
1178
1195
|
return [colors.dim("Sessions"), " No Appduct sessions are registered."];
|
|
@@ -1181,7 +1198,7 @@ var renderLsData = (colors, data, now) => {
|
|
|
1181
1198
|
const headers = ["Alias", "State", "Device", "Tools", "Age"];
|
|
1182
1199
|
const rows = data.map((session) => [
|
|
1183
1200
|
session.alias,
|
|
1184
|
-
session
|
|
1201
|
+
formatSessionState(session),
|
|
1185
1202
|
formatDevice(session.device),
|
|
1186
1203
|
String(session.toolCount),
|
|
1187
1204
|
formatAge(session.claimedAt ?? session.createdAt, nowIso)
|
|
@@ -1355,10 +1372,87 @@ var renderToolsListData = (colors, data, flags, full) => {
|
|
|
1355
1372
|
}
|
|
1356
1373
|
return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
|
|
1357
1374
|
};
|
|
1375
|
+
var renderEventsTruncationLine = (data) => {
|
|
1376
|
+
const offset = data.offset ?? 0;
|
|
1377
|
+
if (data.events.length >= data.total) {
|
|
1378
|
+
return [];
|
|
1379
|
+
}
|
|
1380
|
+
return [
|
|
1381
|
+
"",
|
|
1382
|
+
`Showing ${data.events.length} of ${data.total} events (offset ${offset}). Narrow with --name <glob> or page with --offset <n>.`
|
|
1383
|
+
];
|
|
1384
|
+
};
|
|
1385
|
+
var renderEventsListData = (colors, data, flags) => {
|
|
1386
|
+
const [only] = data.events;
|
|
1387
|
+
if (data.name !== void 0 && !data.name.includes("*") && only !== void 0) {
|
|
1388
|
+
return renderFields(
|
|
1389
|
+
colors.green(`Event: ${only.name}`),
|
|
1390
|
+
[
|
|
1391
|
+
["Signature", renderEventSignature(only)],
|
|
1392
|
+
["Description", only.description],
|
|
1393
|
+
["Payload schema", only.payload_schema]
|
|
1394
|
+
],
|
|
1395
|
+
flags
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1398
|
+
if (data.events.length === 0 && data.total > 0) {
|
|
1399
|
+
return [
|
|
1400
|
+
colors.green("Events"),
|
|
1401
|
+
` No events at offset ${data.offset ?? 0}; ${data.total} matching event${data.total === 1 ? "" : "s"} in total.`
|
|
1402
|
+
];
|
|
1403
|
+
}
|
|
1404
|
+
if (data.events.length === 0) {
|
|
1405
|
+
return [
|
|
1406
|
+
colors.green("Events"),
|
|
1407
|
+
data.name === void 0 ? " No events declared." : ` No events match ${JSON.stringify(data.name)}.`
|
|
1408
|
+
];
|
|
1409
|
+
}
|
|
1410
|
+
const lines = data.events.flatMap((event) => [
|
|
1411
|
+
` ${renderEventSignature(event)}`,
|
|
1412
|
+
` ${summarizeToolDescription(event.description)}`
|
|
1413
|
+
]);
|
|
1414
|
+
return [
|
|
1415
|
+
colors.green("Events"),
|
|
1416
|
+
...lines,
|
|
1417
|
+
...renderEventsTruncationLine(data),
|
|
1418
|
+
"",
|
|
1419
|
+
"Run `appduct events ls --name <name>` for an event's full payload schema."
|
|
1420
|
+
];
|
|
1421
|
+
};
|
|
1358
1422
|
var renderInvokeData = (colors, data, flags) => {
|
|
1359
1423
|
return [colors.green("Result"), formatScalar(data, flags)];
|
|
1360
1424
|
};
|
|
1361
1425
|
var renderLinkData = (colors, data, flags, qr) => {
|
|
1426
|
+
if ("attached" in data) {
|
|
1427
|
+
return [
|
|
1428
|
+
colors.green("Page Attached"),
|
|
1429
|
+
...renderFields(
|
|
1430
|
+
"Page",
|
|
1431
|
+
[
|
|
1432
|
+
["Session", data.sessionId],
|
|
1433
|
+
["Tab", data.targetId],
|
|
1434
|
+
["URL", data.url],
|
|
1435
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
1436
|
+
],
|
|
1437
|
+
flags
|
|
1438
|
+
)
|
|
1439
|
+
];
|
|
1440
|
+
}
|
|
1441
|
+
if ("script" in data) {
|
|
1442
|
+
return [
|
|
1443
|
+
colors.green("Link Created"),
|
|
1444
|
+
...renderFields(
|
|
1445
|
+
"Link",
|
|
1446
|
+
[
|
|
1447
|
+
["Session", data.sessionId],
|
|
1448
|
+
["URL", data.url],
|
|
1449
|
+
["Script", data.script],
|
|
1450
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
1451
|
+
],
|
|
1452
|
+
flags
|
|
1453
|
+
)
|
|
1454
|
+
];
|
|
1455
|
+
}
|
|
1362
1456
|
const lines = [
|
|
1363
1457
|
colors.green("Link Created"),
|
|
1364
1458
|
...renderFields(
|
|
@@ -1479,6 +1573,7 @@ var renderDaemonStatusData = (colors, data, flags) => {
|
|
|
1479
1573
|
["PID", data.daemon.pid],
|
|
1480
1574
|
["Started at", data.daemon.started_at],
|
|
1481
1575
|
["WSS port", data.daemon.wss_port],
|
|
1576
|
+
["Web port", data.daemon.web_port],
|
|
1482
1577
|
["Pinned keys", data.daemon.pinned_keys.length],
|
|
1483
1578
|
["Sessions", data.daemon.session_count]
|
|
1484
1579
|
],
|
|
@@ -1546,6 +1641,8 @@ var renderSuccessData = (colors, command, data, options) => {
|
|
|
1546
1641
|
return renderToolsListData(colors, data, flags, options.full);
|
|
1547
1642
|
case "tools describe":
|
|
1548
1643
|
return renderToolDetail(colors, data, flags);
|
|
1644
|
+
case "events ls":
|
|
1645
|
+
return renderEventsListData(colors, data, flags);
|
|
1549
1646
|
case "tools call":
|
|
1550
1647
|
return renderInvokeData(colors, data, flags);
|
|
1551
1648
|
case "sessions revoke":
|
|
@@ -87,6 +87,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
87
87
|
"daemonLogMaxBytes",
|
|
88
88
|
"eventsLogMaxBytes",
|
|
89
89
|
"policy",
|
|
90
|
+
"webOrigins",
|
|
90
91
|
"advertisedIp",
|
|
91
92
|
"scheme",
|
|
92
93
|
"restartDaemonOnVersionMismatch"
|
|
@@ -147,6 +148,7 @@ var defaultConfig = (paths) => {
|
|
|
147
148
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
148
149
|
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
149
150
|
restartDaemonOnVersionMismatch: false,
|
|
151
|
+
webOrigins: [],
|
|
150
152
|
policy: {
|
|
151
153
|
default: "allow",
|
|
152
154
|
destructive: "allow"
|
|
@@ -217,6 +219,12 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
217
219
|
"restartDaemonOnVersionMismatch"
|
|
218
220
|
);
|
|
219
221
|
}
|
|
222
|
+
if (parsed.webOrigins !== void 0) {
|
|
223
|
+
if (!Array.isArray(parsed.webOrigins)) {
|
|
224
|
+
throw configError("webOrigins", "must be an array of origin strings.");
|
|
225
|
+
}
|
|
226
|
+
config.webOrigins = parsed.webOrigins.map((origin) => requireNonEmptyString(origin, "webOrigins"));
|
|
227
|
+
}
|
|
220
228
|
if (parsed.policy !== void 0) {
|
|
221
229
|
if (typeof parsed.policy !== "object" || parsed.policy === null || Array.isArray(parsed.policy)) {
|
|
222
230
|
throw configError("policy", "must be an object.");
|
|
@@ -905,7 +913,7 @@ var EXIT_CODE_BY_ERROR_TYPE = {
|
|
|
905
913
|
// EX_NOINPUT (66): "an input file did not exist or was not readable" — `doctor` throws this for a
|
|
906
914
|
// missing external tool or an unreadable/corrupt artifact, deliberately distinct from every other
|
|
907
915
|
// code here so a release pipeline can't mistake "we couldn't tell" for either a clean pass or an
|
|
908
|
-
// assertion failure
|
|
916
|
+
// assertion failure.
|
|
909
917
|
inspection_error: 66,
|
|
910
918
|
connection_error: 70,
|
|
911
919
|
session_error: 71,
|
|
@@ -1048,6 +1056,7 @@ var formatJson = (value, flags) => {
|
|
|
1048
1056
|
import pc from "picocolors";
|
|
1049
1057
|
import {
|
|
1050
1058
|
formatAgentWebSocketUrl,
|
|
1059
|
+
renderEventSignature,
|
|
1051
1060
|
renderToolSignature,
|
|
1052
1061
|
summarizeToolDescription
|
|
1053
1062
|
} from "@appduct/shared";
|
|
@@ -1143,6 +1152,13 @@ var formatDevice = (device) => {
|
|
|
1143
1152
|
const label = parts.length > 0 ? parts.join(" ") : "unknown device";
|
|
1144
1153
|
return device.os ? `${label} (${device.os})` : label;
|
|
1145
1154
|
};
|
|
1155
|
+
var SUSPEND_REASON_LABELS = {
|
|
1156
|
+
app_backgrounded: "app in background",
|
|
1157
|
+
connection_lost: "connection lost"
|
|
1158
|
+
};
|
|
1159
|
+
var formatSessionState = (session) => {
|
|
1160
|
+
return session.suspendReason ? `${session.state} (${SUSPEND_REASON_LABELS[session.suspendReason]})` : session.state;
|
|
1161
|
+
};
|
|
1146
1162
|
var renderLsData = (colors, data, now) => {
|
|
1147
1163
|
if (data.length === 0) {
|
|
1148
1164
|
return [colors.dim("Sessions"), " No Appduct sessions are registered."];
|
|
@@ -1151,7 +1167,7 @@ var renderLsData = (colors, data, now) => {
|
|
|
1151
1167
|
const headers = ["Alias", "State", "Device", "Tools", "Age"];
|
|
1152
1168
|
const rows = data.map((session) => [
|
|
1153
1169
|
session.alias,
|
|
1154
|
-
session
|
|
1170
|
+
formatSessionState(session),
|
|
1155
1171
|
formatDevice(session.device),
|
|
1156
1172
|
String(session.toolCount),
|
|
1157
1173
|
formatAge(session.claimedAt ?? session.createdAt, nowIso)
|
|
@@ -1325,10 +1341,87 @@ var renderToolsListData = (colors, data, flags, full) => {
|
|
|
1325
1341
|
}
|
|
1326
1342
|
return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
|
|
1327
1343
|
};
|
|
1344
|
+
var renderEventsTruncationLine = (data) => {
|
|
1345
|
+
const offset = data.offset ?? 0;
|
|
1346
|
+
if (data.events.length >= data.total) {
|
|
1347
|
+
return [];
|
|
1348
|
+
}
|
|
1349
|
+
return [
|
|
1350
|
+
"",
|
|
1351
|
+
`Showing ${data.events.length} of ${data.total} events (offset ${offset}). Narrow with --name <glob> or page with --offset <n>.`
|
|
1352
|
+
];
|
|
1353
|
+
};
|
|
1354
|
+
var renderEventsListData = (colors, data, flags) => {
|
|
1355
|
+
const [only] = data.events;
|
|
1356
|
+
if (data.name !== void 0 && !data.name.includes("*") && only !== void 0) {
|
|
1357
|
+
return renderFields(
|
|
1358
|
+
colors.green(`Event: ${only.name}`),
|
|
1359
|
+
[
|
|
1360
|
+
["Signature", renderEventSignature(only)],
|
|
1361
|
+
["Description", only.description],
|
|
1362
|
+
["Payload schema", only.payload_schema]
|
|
1363
|
+
],
|
|
1364
|
+
flags
|
|
1365
|
+
);
|
|
1366
|
+
}
|
|
1367
|
+
if (data.events.length === 0 && data.total > 0) {
|
|
1368
|
+
return [
|
|
1369
|
+
colors.green("Events"),
|
|
1370
|
+
` No events at offset ${data.offset ?? 0}; ${data.total} matching event${data.total === 1 ? "" : "s"} in total.`
|
|
1371
|
+
];
|
|
1372
|
+
}
|
|
1373
|
+
if (data.events.length === 0) {
|
|
1374
|
+
return [
|
|
1375
|
+
colors.green("Events"),
|
|
1376
|
+
data.name === void 0 ? " No events declared." : ` No events match ${JSON.stringify(data.name)}.`
|
|
1377
|
+
];
|
|
1378
|
+
}
|
|
1379
|
+
const lines = data.events.flatMap((event) => [
|
|
1380
|
+
` ${renderEventSignature(event)}`,
|
|
1381
|
+
` ${summarizeToolDescription(event.description)}`
|
|
1382
|
+
]);
|
|
1383
|
+
return [
|
|
1384
|
+
colors.green("Events"),
|
|
1385
|
+
...lines,
|
|
1386
|
+
...renderEventsTruncationLine(data),
|
|
1387
|
+
"",
|
|
1388
|
+
"Run `appduct events ls --name <name>` for an event's full payload schema."
|
|
1389
|
+
];
|
|
1390
|
+
};
|
|
1328
1391
|
var renderInvokeData = (colors, data, flags) => {
|
|
1329
1392
|
return [colors.green("Result"), formatScalar(data, flags)];
|
|
1330
1393
|
};
|
|
1331
1394
|
var renderLinkData = (colors, data, flags, qr) => {
|
|
1395
|
+
if ("attached" in data) {
|
|
1396
|
+
return [
|
|
1397
|
+
colors.green("Page Attached"),
|
|
1398
|
+
...renderFields(
|
|
1399
|
+
"Page",
|
|
1400
|
+
[
|
|
1401
|
+
["Session", data.sessionId],
|
|
1402
|
+
["Tab", data.targetId],
|
|
1403
|
+
["URL", data.url],
|
|
1404
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
1405
|
+
],
|
|
1406
|
+
flags
|
|
1407
|
+
)
|
|
1408
|
+
];
|
|
1409
|
+
}
|
|
1410
|
+
if ("script" in data) {
|
|
1411
|
+
return [
|
|
1412
|
+
colors.green("Link Created"),
|
|
1413
|
+
...renderFields(
|
|
1414
|
+
"Link",
|
|
1415
|
+
[
|
|
1416
|
+
["Session", data.sessionId],
|
|
1417
|
+
["URL", data.url],
|
|
1418
|
+
["Script", data.script],
|
|
1419
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
1420
|
+
],
|
|
1421
|
+
flags
|
|
1422
|
+
)
|
|
1423
|
+
];
|
|
1424
|
+
}
|
|
1332
1425
|
const lines = [
|
|
1333
1426
|
colors.green("Link Created"),
|
|
1334
1427
|
...renderFields(
|
|
@@ -1449,6 +1542,7 @@ var renderDaemonStatusData = (colors, data, flags) => {
|
|
|
1449
1542
|
["PID", data.daemon.pid],
|
|
1450
1543
|
["Started at", data.daemon.started_at],
|
|
1451
1544
|
["WSS port", data.daemon.wss_port],
|
|
1545
|
+
["Web port", data.daemon.web_port],
|
|
1452
1546
|
["Pinned keys", data.daemon.pinned_keys.length],
|
|
1453
1547
|
["Sessions", data.daemon.session_count]
|
|
1454
1548
|
],
|
|
@@ -1516,6 +1610,8 @@ var renderSuccessData = (colors, command, data, options) => {
|
|
|
1516
1610
|
return renderToolsListData(colors, data, flags, options.full);
|
|
1517
1611
|
case "tools describe":
|
|
1518
1612
|
return renderToolDetail(colors, data, flags);
|
|
1613
|
+
case "events ls":
|
|
1614
|
+
return renderEventsListData(colors, data, flags);
|
|
1519
1615
|
case "tools call":
|
|
1520
1616
|
return renderInvokeData(colors, data, flags);
|
|
1521
1617
|
case "sessions revoke":
|
|
@@ -98,7 +98,7 @@ var EXIT_CODE_BY_ERROR_TYPE = {
|
|
|
98
98
|
// EX_NOINPUT (66): "an input file did not exist or was not readable" — `doctor` throws this for a
|
|
99
99
|
// missing external tool or an unreadable/corrupt artifact, deliberately distinct from every other
|
|
100
100
|
// code here so a release pipeline can't mistake "we couldn't tell" for either a clean pass or an
|
|
101
|
-
// assertion failure
|
|
101
|
+
// assertion failure.
|
|
102
102
|
inspection_error: 66,
|
|
103
103
|
connection_error: 70,
|
|
104
104
|
session_error: 71,
|
|
@@ -230,6 +230,7 @@ var ANDROID_DEX_PACKAGE_MARKERS = [
|
|
|
230
230
|
"com.callstackincubator.appduct"
|
|
231
231
|
];
|
|
232
232
|
var ANDROID_MANIFEST_KEY_MARKERS = ["com.callstack.appduct.", "com.callstackincubator.appduct."];
|
|
233
|
+
var FLUTTER_DART_CORE_MARKER = "appduct-dart-core/";
|
|
233
234
|
var bufferIncludesAscii = (haystack, needle) => {
|
|
234
235
|
return haystack.includes(Buffer.from(needle, "utf8"));
|
|
235
236
|
};
|
|
@@ -363,6 +364,9 @@ var detectIosSignals = (bytes) => {
|
|
|
363
364
|
if (IOS_INFO_PLIST_KEY_MARKERS.some((marker) => bufferIncludesAscii(bytes, marker))) {
|
|
364
365
|
signals.push("ios-info-plist-keys");
|
|
365
366
|
}
|
|
367
|
+
if (bufferIncludesAscii(bytes, FLUTTER_DART_CORE_MARKER)) {
|
|
368
|
+
signals.push("flutter-dart-core-marker");
|
|
369
|
+
}
|
|
366
370
|
return signals;
|
|
367
371
|
};
|
|
368
372
|
var detectAndroidSignals = (bytes) => {
|
|
@@ -378,6 +382,9 @@ var detectAndroidSignals = (bytes) => {
|
|
|
378
382
|
)) {
|
|
379
383
|
signals.push("android-manifest-meta-data-keys");
|
|
380
384
|
}
|
|
385
|
+
if (bufferIncludesAscii(bytes, FLUTTER_DART_CORE_MARKER)) {
|
|
386
|
+
signals.push("flutter-dart-core-marker");
|
|
387
|
+
}
|
|
381
388
|
return signals;
|
|
382
389
|
};
|
|
383
390
|
var inspectArtifact = async (artifactPath, options = {}) => {
|
|
@@ -403,7 +410,7 @@ var inspectArtifact = async (artifactPath, options = {}) => {
|
|
|
403
410
|
bytes = await readZipEntries(exec, artifactPath, format, context);
|
|
404
411
|
}
|
|
405
412
|
const signals = platform === "ios" ? detectIosSignals(bytes) : detectAndroidSignals(bytes);
|
|
406
|
-
const present = platform === "android" ? signals.includes("android-keep-rule-marker") : signals.includes("ios-core-marker-symbol") || signals.includes("ios-objc-class-symbol");
|
|
413
|
+
const present = signals.includes("flutter-dart-core-marker") || (platform === "android" ? signals.includes("android-keep-rule-marker") : signals.includes("ios-core-marker-symbol") || signals.includes("ios-objc-class-symbol"));
|
|
407
414
|
return {
|
|
408
415
|
platform,
|
|
409
416
|
format,
|
|
@@ -458,6 +465,7 @@ var formatJson = (value, flags) => {
|
|
|
458
465
|
import pc from "picocolors";
|
|
459
466
|
import {
|
|
460
467
|
formatAgentWebSocketUrl,
|
|
468
|
+
renderEventSignature,
|
|
461
469
|
renderToolSignature,
|
|
462
470
|
summarizeToolDescription
|
|
463
471
|
} from "@appduct/shared";
|
|
@@ -553,6 +561,13 @@ var formatDevice = (device) => {
|
|
|
553
561
|
const label = parts.length > 0 ? parts.join(" ") : "unknown device";
|
|
554
562
|
return device.os ? `${label} (${device.os})` : label;
|
|
555
563
|
};
|
|
564
|
+
var SUSPEND_REASON_LABELS = {
|
|
565
|
+
app_backgrounded: "app in background",
|
|
566
|
+
connection_lost: "connection lost"
|
|
567
|
+
};
|
|
568
|
+
var formatSessionState = (session) => {
|
|
569
|
+
return session.suspendReason ? `${session.state} (${SUSPEND_REASON_LABELS[session.suspendReason]})` : session.state;
|
|
570
|
+
};
|
|
556
571
|
var renderLsData = (colors, data, now) => {
|
|
557
572
|
if (data.length === 0) {
|
|
558
573
|
return [colors.dim("Sessions"), " No Appduct sessions are registered."];
|
|
@@ -561,7 +576,7 @@ var renderLsData = (colors, data, now) => {
|
|
|
561
576
|
const headers = ["Alias", "State", "Device", "Tools", "Age"];
|
|
562
577
|
const rows = data.map((session) => [
|
|
563
578
|
session.alias,
|
|
564
|
-
session
|
|
579
|
+
formatSessionState(session),
|
|
565
580
|
formatDevice(session.device),
|
|
566
581
|
String(session.toolCount),
|
|
567
582
|
formatAge(session.claimedAt ?? session.createdAt, nowIso)
|
|
@@ -735,10 +750,87 @@ var renderToolsListData = (colors, data, flags, full) => {
|
|
|
735
750
|
}
|
|
736
751
|
return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
|
|
737
752
|
};
|
|
753
|
+
var renderEventsTruncationLine = (data) => {
|
|
754
|
+
const offset = data.offset ?? 0;
|
|
755
|
+
if (data.events.length >= data.total) {
|
|
756
|
+
return [];
|
|
757
|
+
}
|
|
758
|
+
return [
|
|
759
|
+
"",
|
|
760
|
+
`Showing ${data.events.length} of ${data.total} events (offset ${offset}). Narrow with --name <glob> or page with --offset <n>.`
|
|
761
|
+
];
|
|
762
|
+
};
|
|
763
|
+
var renderEventsListData = (colors, data, flags) => {
|
|
764
|
+
const [only] = data.events;
|
|
765
|
+
if (data.name !== void 0 && !data.name.includes("*") && only !== void 0) {
|
|
766
|
+
return renderFields(
|
|
767
|
+
colors.green(`Event: ${only.name}`),
|
|
768
|
+
[
|
|
769
|
+
["Signature", renderEventSignature(only)],
|
|
770
|
+
["Description", only.description],
|
|
771
|
+
["Payload schema", only.payload_schema]
|
|
772
|
+
],
|
|
773
|
+
flags
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
if (data.events.length === 0 && data.total > 0) {
|
|
777
|
+
return [
|
|
778
|
+
colors.green("Events"),
|
|
779
|
+
` No events at offset ${data.offset ?? 0}; ${data.total} matching event${data.total === 1 ? "" : "s"} in total.`
|
|
780
|
+
];
|
|
781
|
+
}
|
|
782
|
+
if (data.events.length === 0) {
|
|
783
|
+
return [
|
|
784
|
+
colors.green("Events"),
|
|
785
|
+
data.name === void 0 ? " No events declared." : ` No events match ${JSON.stringify(data.name)}.`
|
|
786
|
+
];
|
|
787
|
+
}
|
|
788
|
+
const lines = data.events.flatMap((event) => [
|
|
789
|
+
` ${renderEventSignature(event)}`,
|
|
790
|
+
` ${summarizeToolDescription(event.description)}`
|
|
791
|
+
]);
|
|
792
|
+
return [
|
|
793
|
+
colors.green("Events"),
|
|
794
|
+
...lines,
|
|
795
|
+
...renderEventsTruncationLine(data),
|
|
796
|
+
"",
|
|
797
|
+
"Run `appduct events ls --name <name>` for an event's full payload schema."
|
|
798
|
+
];
|
|
799
|
+
};
|
|
738
800
|
var renderInvokeData = (colors, data, flags) => {
|
|
739
801
|
return [colors.green("Result"), formatScalar(data, flags)];
|
|
740
802
|
};
|
|
741
803
|
var renderLinkData = (colors, data, flags, qr) => {
|
|
804
|
+
if ("attached" in data) {
|
|
805
|
+
return [
|
|
806
|
+
colors.green("Page Attached"),
|
|
807
|
+
...renderFields(
|
|
808
|
+
"Page",
|
|
809
|
+
[
|
|
810
|
+
["Session", data.sessionId],
|
|
811
|
+
["Tab", data.targetId],
|
|
812
|
+
["URL", data.url],
|
|
813
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
814
|
+
],
|
|
815
|
+
flags
|
|
816
|
+
)
|
|
817
|
+
];
|
|
818
|
+
}
|
|
819
|
+
if ("script" in data) {
|
|
820
|
+
return [
|
|
821
|
+
colors.green("Link Created"),
|
|
822
|
+
...renderFields(
|
|
823
|
+
"Link",
|
|
824
|
+
[
|
|
825
|
+
["Session", data.sessionId],
|
|
826
|
+
["URL", data.url],
|
|
827
|
+
["Script", data.script],
|
|
828
|
+
["Expires", new Date(data.expiresAt * 1e3).toISOString()]
|
|
829
|
+
],
|
|
830
|
+
flags
|
|
831
|
+
)
|
|
832
|
+
];
|
|
833
|
+
}
|
|
742
834
|
const lines = [
|
|
743
835
|
colors.green("Link Created"),
|
|
744
836
|
...renderFields(
|
|
@@ -859,6 +951,7 @@ var renderDaemonStatusData = (colors, data, flags) => {
|
|
|
859
951
|
["PID", data.daemon.pid],
|
|
860
952
|
["Started at", data.daemon.started_at],
|
|
861
953
|
["WSS port", data.daemon.wss_port],
|
|
954
|
+
["Web port", data.daemon.web_port],
|
|
862
955
|
["Pinned keys", data.daemon.pinned_keys.length],
|
|
863
956
|
["Sessions", data.daemon.session_count]
|
|
864
957
|
],
|
|
@@ -926,6 +1019,8 @@ var renderSuccessData = (colors, command, data, options) => {
|
|
|
926
1019
|
return renderToolsListData(colors, data, flags, options.full);
|
|
927
1020
|
case "tools describe":
|
|
928
1021
|
return renderToolDetail(colors, data, flags);
|
|
1022
|
+
case "events ls":
|
|
1023
|
+
return renderEventsListData(colors, data, flags);
|
|
929
1024
|
case "tools call":
|
|
930
1025
|
return renderInvokeData(colors, data, flags);
|
|
931
1026
|
case "sessions revoke":
|