appduct 0.12.0 → 0.14.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 +43 -37
- package/dist/bin.js +102 -37
- package/dist/cli/command-options.d.ts +7 -17
- package/dist/cli/result-types.d.ts +19 -9
- package/dist/cli/routes/daemon/index.js +70 -17
- package/dist/cli/routes/daemon/run.js +288 -50
- package/dist/cli/routes/daemon/start.js +70 -17
- package/dist/cli/routes/daemon/status.js +70 -17
- package/dist/cli/routes/daemon/stop.js +70 -17
- package/dist/cli/routes/doctor.js +70 -17
- package/dist/cli/routes/events/index.d.ts +6 -0
- package/dist/cli/routes/events/index.js +900 -0
- package/dist/cli/routes/events/ls.d.ts +5 -0
- package/dist/cli/routes/events/ls.js +1798 -0
- package/dist/cli/routes/events/shared-options.d.ts +12 -0
- package/dist/cli/routes/events/shared-options.js +102 -0
- package/dist/cli/routes/events/since.d.ts +6 -0
- package/dist/cli/routes/events/since.js +2034 -0
- package/dist/cli/routes/events/tail.d.ts +6 -0
- package/dist/cli/routes/{events.js → events/tail.js} +235 -163
- package/dist/cli/routes/init.js +72 -19
- package/dist/cli/routes/keygen.js +70 -17
- package/dist/cli/routes/mcp.js +289 -166
- package/dist/cli/routes/sessions/index.d.ts +7 -0
- package/dist/cli/routes/sessions/index.js +900 -0
- package/dist/cli/routes/sessions/link.d.ts +4 -0
- package/dist/cli/routes/{link.js → sessions/link.js} +71 -18
- package/dist/cli/routes/sessions/ls.d.ts +4 -0
- package/dist/cli/routes/{ls.js → sessions/ls.js} +71 -18
- package/dist/cli/routes/sessions/revoke.d.ts +4 -0
- package/dist/cli/routes/{revoke.js → sessions/revoke.js} +72 -19
- package/dist/cli/routes/tools/call.d.ts +4 -0
- package/dist/cli/routes/{invoke.js → tools/call.js} +73 -20
- package/dist/cli/routes/tools/describe.d.ts +6 -0
- package/dist/cli/routes/tools/describe.js +1894 -0
- package/dist/cli/routes/tools/index.d.ts +6 -0
- package/dist/cli/routes/tools/index.js +900 -0
- package/dist/cli/routes/tools/ls.d.ts +4 -0
- package/dist/cli/routes/{tools.js → tools/ls.js} +98 -74
- package/dist/cli/routes/tools/shared-options.d.ts +16 -0
- package/dist/cli/routes/tools/shared-options.js +122 -0
- package/dist/client/app-client.d.ts +96 -37
- package/dist/client/index.d.ts +3 -2
- package/dist/client/index.js +178 -138
- package/dist/commands/events-ls.d.ts +21 -0
- package/dist/commands/events.d.ts +31 -14
- package/dist/commands/invoke.d.ts +1 -1
- package/dist/commands/link.d.ts +1 -1
- package/dist/commands/ls.d.ts +1 -1
- package/dist/commands/revoke.d.ts +1 -1
- package/dist/commands/tools.d.ts +12 -13
- package/dist/daemon/calls.d.ts +3 -1
- package/dist/daemon/config.d.ts +1 -1
- package/dist/daemon/event-bus.d.ts +42 -0
- package/dist/daemon/registry.d.ts +20 -12
- package/dist/daemon/rpc-errors.d.ts +4 -1
- package/dist/daemon/sessions.d.ts +4 -2
- package/dist/errors.d.ts +1 -1
- package/dist/events/index.d.ts +60 -0
- package/dist/index.js +114 -40
- package/dist/link.d.ts +1 -1
- package/dist/mcp/app-tools.d.ts +22 -2
- package/dist/mcp/connect-tool.d.ts +1 -1
- package/dist/mcp/events-tool.d.ts +67 -27
- package/dist/native-scheme.d.ts +1 -1
- package/dist/output.d.ts +29 -6
- package/dist/rpc/client.d.ts +1 -1
- package/dist/scheme.d.ts +4 -4
- package/package.json +2 -2
- package/dist/cli/routes/events.d.ts +0 -3
- package/dist/cli/routes/invoke.d.ts +0 -3
- package/dist/cli/routes/link.d.ts +0 -3
- package/dist/cli/routes/ls.d.ts +0 -3
- package/dist/cli/routes/revoke.d.ts +0 -3
- package/dist/cli/routes/tools.d.ts +0 -3
|
@@ -484,6 +484,7 @@ var RpcApplicationError = class extends Error {
|
|
|
484
484
|
this.name = "RpcApplicationError";
|
|
485
485
|
}
|
|
486
486
|
};
|
|
487
|
+
var appBackgroundedMessage = (alias) => `Session "${alias}" is suspended because the app is in the background. Bring the app to the foreground to resume it.`;
|
|
487
488
|
|
|
488
489
|
// src/daemon/timers.ts
|
|
489
490
|
var systemTimers = {
|
|
@@ -586,7 +587,7 @@ var createCallsManager = (options) => {
|
|
|
586
587
|
const message = { type: "tool_cancel", session_id: sessionId, id: callId, reason };
|
|
587
588
|
return options.sendCancel(sessionId, message);
|
|
588
589
|
};
|
|
589
|
-
const rejectSession = (sessionId, errorType) => {
|
|
590
|
+
const rejectSession = (sessionId, errorType, options2 = {}) => {
|
|
590
591
|
const sessionMap = pendingBySession.get(sessionId);
|
|
591
592
|
if (!sessionMap) {
|
|
592
593
|
return;
|
|
@@ -594,13 +595,19 @@ var createCallsManager = (options) => {
|
|
|
594
595
|
pendingBySession.delete(sessionId);
|
|
595
596
|
for (const pending of sessionMap.values()) {
|
|
596
597
|
timers.clearTimeout(pending.timer);
|
|
597
|
-
pending.reject(
|
|
598
|
+
pending.reject(
|
|
599
|
+
new RpcApplicationError(
|
|
600
|
+
errorType,
|
|
601
|
+
options2.backgrounded ? appBackgroundedMessage(pending.alias) : "Session transitioned while the call was pending."
|
|
602
|
+
)
|
|
603
|
+
);
|
|
598
604
|
}
|
|
599
605
|
};
|
|
600
606
|
const unsubscribeFromEventBus = options.eventBus.subscribe((event) => {
|
|
601
607
|
const errorType = TERMINATING_KIND_ERROR_TYPES[event.kind];
|
|
602
608
|
if (errorType && event.sessionId) {
|
|
603
|
-
|
|
609
|
+
const backgrounded = event.kind === "session_suspended" && event.data.reason === "app_backgrounded";
|
|
610
|
+
rejectSession(event.sessionId, errorType, { backgrounded });
|
|
604
611
|
}
|
|
605
612
|
});
|
|
606
613
|
const disposeAll = () => {
|
|
@@ -614,6 +621,71 @@ var createCallsManager = (options) => {
|
|
|
614
621
|
|
|
615
622
|
// src/daemon/event-bus.ts
|
|
616
623
|
var TERMINAL_EVENT_KINDS = /* @__PURE__ */ new Set(["session_expired", "session_revoked"]);
|
|
624
|
+
var utf8ByteLength = (text) => Buffer.byteLength(text, "utf8");
|
|
625
|
+
var truncateToUtf8Bytes = (text, maxBytes) => {
|
|
626
|
+
const encoded = Buffer.from(text, "utf8");
|
|
627
|
+
if (encoded.length <= maxBytes) {
|
|
628
|
+
return text;
|
|
629
|
+
}
|
|
630
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
631
|
+
for (let end = maxBytes; end > 0; end--) {
|
|
632
|
+
try {
|
|
633
|
+
return decoder.decode(encoded.subarray(0, end));
|
|
634
|
+
} catch {
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return "";
|
|
638
|
+
};
|
|
639
|
+
var matchesNameGlob = (pattern, name) => {
|
|
640
|
+
const pieces = pattern.split("*");
|
|
641
|
+
const first = pieces[0] ?? "";
|
|
642
|
+
if (pieces.length === 1) {
|
|
643
|
+
return name === first;
|
|
644
|
+
}
|
|
645
|
+
const last = pieces[pieces.length - 1] ?? "";
|
|
646
|
+
if (first.length + last.length > name.length || !name.startsWith(first) || !name.endsWith(last)) {
|
|
647
|
+
return false;
|
|
648
|
+
}
|
|
649
|
+
const end = name.length - last.length;
|
|
650
|
+
let position = first.length;
|
|
651
|
+
for (const piece of pieces.slice(1, -1)) {
|
|
652
|
+
const found = name.indexOf(piece, position);
|
|
653
|
+
if (found === -1 || found + piece.length > end) {
|
|
654
|
+
return false;
|
|
655
|
+
}
|
|
656
|
+
position = found + piece.length;
|
|
657
|
+
}
|
|
658
|
+
return true;
|
|
659
|
+
};
|
|
660
|
+
var projectAppEvent = (event, options = {}) => {
|
|
661
|
+
if (event.kind !== "app_event") {
|
|
662
|
+
return event;
|
|
663
|
+
}
|
|
664
|
+
const data = event.data;
|
|
665
|
+
if (options.name !== void 0 && !(typeof data.name === "string" && matchesNameGlob(options.name, data.name))) {
|
|
666
|
+
return void 0;
|
|
667
|
+
}
|
|
668
|
+
if (options.payloadMaxBytes === void 0 || !("payload" in data)) {
|
|
669
|
+
return event;
|
|
670
|
+
}
|
|
671
|
+
const payloadJson = JSON.stringify(data.payload);
|
|
672
|
+
if (payloadJson === void 0) {
|
|
673
|
+
return event;
|
|
674
|
+
}
|
|
675
|
+
const payloadBytes = utf8ByteLength(payloadJson);
|
|
676
|
+
if (payloadBytes <= options.payloadMaxBytes) {
|
|
677
|
+
return event;
|
|
678
|
+
}
|
|
679
|
+
return {
|
|
680
|
+
...event,
|
|
681
|
+
data: {
|
|
682
|
+
name: data.name,
|
|
683
|
+
payloadPreview: truncateToUtf8Bytes(payloadJson, options.payloadMaxBytes),
|
|
684
|
+
truncated: true,
|
|
685
|
+
payloadBytes
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
};
|
|
617
689
|
var createEventBus = (options = {}) => {
|
|
618
690
|
const clock = options.clock ?? { now: () => /* @__PURE__ */ new Date() };
|
|
619
691
|
const bufferSize = options.bufferSize ?? 256;
|
|
@@ -631,8 +703,9 @@ var createEventBus = (options = {}) => {
|
|
|
631
703
|
return {
|
|
632
704
|
emit: (event) => {
|
|
633
705
|
const sessionId = event.sessionId;
|
|
634
|
-
|
|
635
|
-
if (sessionId !== void 0) {
|
|
706
|
+
let seq = 0;
|
|
707
|
+
if (sessionId !== void 0 && event.kind === "app_event") {
|
|
708
|
+
seq = (cursors.get(sessionId) ?? 0) + 1;
|
|
636
709
|
cursors.set(sessionId, seq);
|
|
637
710
|
}
|
|
638
711
|
const notification = {
|
|
@@ -664,15 +737,26 @@ var createEventBus = (options = {}) => {
|
|
|
664
737
|
since: (sessionId, query = {}) => {
|
|
665
738
|
const buffer = buffers.get(sessionId) ?? [];
|
|
666
739
|
const sessionCursor = cursors.get(sessionId) ?? 0;
|
|
667
|
-
|
|
740
|
+
const sinceValue = query.since ?? 0;
|
|
741
|
+
const oldestRetainedSeq = buffer.length > 0 ? buffer[0].seq : void 0;
|
|
742
|
+
const dropped = oldestRetainedSeq !== void 0 ? Math.max(0, oldestRetainedSeq - sinceValue - 1) : 0;
|
|
743
|
+
let matching = buffer.slice();
|
|
668
744
|
if (query.since !== void 0) {
|
|
669
|
-
|
|
745
|
+
matching = matching.filter((event) => event.seq > query.since);
|
|
746
|
+
}
|
|
747
|
+
if (query.name !== void 0) {
|
|
748
|
+
matching = matching.filter((event) => projectAppEvent(event, { name: query.name }) !== void 0);
|
|
670
749
|
}
|
|
750
|
+
let events = matching;
|
|
671
751
|
if (query.limit !== void 0 && events.length > query.limit) {
|
|
672
752
|
events = events.slice(0, query.limit);
|
|
673
753
|
}
|
|
754
|
+
const remaining = matching.length - events.length;
|
|
674
755
|
const cursor = events.length > 0 ? events[events.length - 1].seq : sessionCursor;
|
|
675
|
-
|
|
756
|
+
if (query.payloadMaxBytes !== void 0) {
|
|
757
|
+
events = events.map((event) => projectAppEvent(event, { payloadMaxBytes: query.payloadMaxBytes }));
|
|
758
|
+
}
|
|
759
|
+
return { events, cursor, dropped, remaining };
|
|
676
760
|
},
|
|
677
761
|
drop: (sessionId) => {
|
|
678
762
|
buffers.delete(sessionId);
|
|
@@ -714,6 +798,8 @@ import {
|
|
|
714
798
|
isEventMessage,
|
|
715
799
|
isToolCallProgressMessage,
|
|
716
800
|
isToolErrorMessage,
|
|
801
|
+
isEventRegistryDeltaMessage,
|
|
802
|
+
isEventRegistrySnapshotMessage,
|
|
717
803
|
isToolRegistryDeltaMessage,
|
|
718
804
|
isToolRegistrySnapshotMessage,
|
|
719
805
|
isToolResultMessage,
|
|
@@ -811,7 +897,7 @@ var createPendingLinkRegistry = (options) => {
|
|
|
811
897
|
};
|
|
812
898
|
|
|
813
899
|
// src/daemon/registry.ts
|
|
814
|
-
var
|
|
900
|
+
var createRegistry = (onChange) => {
|
|
815
901
|
let tools = /* @__PURE__ */ new Map();
|
|
816
902
|
const notify = () => {
|
|
817
903
|
onChange?.();
|
|
@@ -841,6 +927,8 @@ var RESUME_TOKEN_BYTES = 32;
|
|
|
841
927
|
var POST_CLAIM_MESSAGE_TYPES = /* @__PURE__ */ new Set([
|
|
842
928
|
"tool_registry_snapshot",
|
|
843
929
|
"tool_registry_delta",
|
|
930
|
+
"event_registry_snapshot",
|
|
931
|
+
"event_registry_delta",
|
|
844
932
|
"tool_result",
|
|
845
933
|
"tool_error",
|
|
846
934
|
"tool_call_progress",
|
|
@@ -911,6 +999,7 @@ var createSessionManager = (options) => {
|
|
|
911
999
|
createdAt: session.createdAt.toISOString(),
|
|
912
1000
|
claimedAt: session.claimedAt.toISOString(),
|
|
913
1001
|
...session.suspendedAt ? { suspendedAt: session.suspendedAt.toISOString() } : {},
|
|
1002
|
+
...session.suspendReason ? { suspendReason: session.suspendReason } : {},
|
|
914
1003
|
toolCount: session.registry.count()
|
|
915
1004
|
};
|
|
916
1005
|
};
|
|
@@ -947,7 +1036,8 @@ var createSessionManager = (options) => {
|
|
|
947
1036
|
alias: session.alias,
|
|
948
1037
|
resume_token: session.resumeToken.toString("base64url"),
|
|
949
1038
|
keepalive_interval_s: options.keepaliveIntervalSeconds,
|
|
950
|
-
grace_s: options.graceSeconds
|
|
1039
|
+
grace_s: options.graceSeconds,
|
|
1040
|
+
event_registry: true
|
|
951
1041
|
};
|
|
952
1042
|
socket.send(JSON.stringify(ack), (error) => {
|
|
953
1043
|
if (error) {
|
|
@@ -955,17 +1045,18 @@ var createSessionManager = (options) => {
|
|
|
955
1045
|
}
|
|
956
1046
|
});
|
|
957
1047
|
};
|
|
958
|
-
const suspend = (sessionId) => {
|
|
1048
|
+
const suspend = (sessionId, reason) => {
|
|
959
1049
|
const session = sessions.get(sessionId);
|
|
960
1050
|
if (!session || session.state !== "active") {
|
|
961
1051
|
return;
|
|
962
1052
|
}
|
|
963
1053
|
session.state = "suspended";
|
|
964
1054
|
session.suspendedAt = clock.now();
|
|
1055
|
+
session.suspendReason = reason;
|
|
965
1056
|
session.socket = void 0;
|
|
966
1057
|
session.missedPongs = 0;
|
|
967
1058
|
session.graceTimer = timers.setTimeout(() => expire(sessionId), options.graceSeconds * 1e3);
|
|
968
|
-
emit("session_suspended", session.sessionId, session.alias, {});
|
|
1059
|
+
emit("session_suspended", session.sessionId, session.alias, { reason });
|
|
969
1060
|
};
|
|
970
1061
|
const expire = (sessionId) => {
|
|
971
1062
|
const session = sessions.get(sessionId);
|
|
@@ -982,9 +1073,10 @@ var createSessionManager = (options) => {
|
|
|
982
1073
|
socket.on("pong", () => {
|
|
983
1074
|
session.missedPongs = 0;
|
|
984
1075
|
});
|
|
985
|
-
socket.on("close", () => {
|
|
1076
|
+
socket.on("close", (code, reason) => {
|
|
986
1077
|
if (session.socket === socket) {
|
|
987
|
-
|
|
1078
|
+
const backgrounded = code === 1001 && reason.toString("utf8") === "app_backgrounded";
|
|
1079
|
+
suspend(session.sessionId, backgrounded ? "app_backgrounded" : "connection_lost");
|
|
988
1080
|
}
|
|
989
1081
|
});
|
|
990
1082
|
};
|
|
@@ -996,7 +1088,7 @@ var createSessionManager = (options) => {
|
|
|
996
1088
|
if (session.missedPongs >= 2) {
|
|
997
1089
|
const staleSocket = session.socket;
|
|
998
1090
|
session.socket = void 0;
|
|
999
|
-
suspend(session.sessionId);
|
|
1091
|
+
suspend(session.sessionId, "connection_lost");
|
|
1000
1092
|
staleSocket.terminate();
|
|
1001
1093
|
continue;
|
|
1002
1094
|
}
|
|
@@ -1061,8 +1153,11 @@ var createSessionManager = (options) => {
|
|
|
1061
1153
|
resumeToken: randomBytes3(RESUME_TOKEN_BYTES),
|
|
1062
1154
|
socket,
|
|
1063
1155
|
missedPongs: 0,
|
|
1064
|
-
registry:
|
|
1156
|
+
registry: createRegistry(() => {
|
|
1065
1157
|
emit("tools_changed", sessionId, alias, { toolCount: session.registry.count() });
|
|
1158
|
+
}),
|
|
1159
|
+
eventRegistry: createRegistry(() => {
|
|
1160
|
+
emit("events_changed", sessionId, alias, { eventCount: session.eventRegistry.count() });
|
|
1066
1161
|
})
|
|
1067
1162
|
};
|
|
1068
1163
|
sessions.set(sessionId, session);
|
|
@@ -1094,6 +1189,7 @@ var createSessionManager = (options) => {
|
|
|
1094
1189
|
session.resumeToken = randomBytes3(RESUME_TOKEN_BYTES);
|
|
1095
1190
|
session.state = "active";
|
|
1096
1191
|
session.suspendedAt = void 0;
|
|
1192
|
+
session.suspendReason = void 0;
|
|
1097
1193
|
session.socket = socket;
|
|
1098
1194
|
session.missedPongs = 0;
|
|
1099
1195
|
attachSocketHandlers(session);
|
|
@@ -1128,6 +1224,26 @@ var createSessionManager = (options) => {
|
|
|
1128
1224
|
}
|
|
1129
1225
|
return;
|
|
1130
1226
|
}
|
|
1227
|
+
case "event_registry_snapshot": {
|
|
1228
|
+
if (!isEventRegistrySnapshotMessage(message)) {
|
|
1229
|
+
closeSocket(socket, 1008, "invalid_registry");
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
session.eventRegistry.snapshot(message.events);
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
case "event_registry_delta": {
|
|
1236
|
+
if (!isEventRegistryDeltaMessage(message)) {
|
|
1237
|
+
closeSocket(socket, 1008, "invalid_registry");
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
if (message.operation === "upsert") {
|
|
1241
|
+
session.eventRegistry.upsert(message.event);
|
|
1242
|
+
} else {
|
|
1243
|
+
session.eventRegistry.remove(message.name);
|
|
1244
|
+
}
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1131
1247
|
case "tool_result": {
|
|
1132
1248
|
if (!isToolResultMessage(message)) {
|
|
1133
1249
|
closeSocket(socket, 1008, "invalid_message");
|
|
@@ -1195,7 +1311,14 @@ var createSessionManager = (options) => {
|
|
|
1195
1311
|
};
|
|
1196
1312
|
const resolveForTools = (selector) => {
|
|
1197
1313
|
const session = resolveSession(selector);
|
|
1198
|
-
return {
|
|
1314
|
+
return {
|
|
1315
|
+
sessionId: session.sessionId,
|
|
1316
|
+
alias: session.alias,
|
|
1317
|
+
state: session.state,
|
|
1318
|
+
suspendReason: session.suspendReason,
|
|
1319
|
+
registry: session.registry,
|
|
1320
|
+
eventRegistry: session.eventRegistry
|
|
1321
|
+
};
|
|
1199
1322
|
};
|
|
1200
1323
|
const sendToApp = (sessionId, message) => {
|
|
1201
1324
|
const session = sessions.get(sessionId);
|
|
@@ -1963,6 +2086,26 @@ var asSelectorParams = (params) => {
|
|
|
1963
2086
|
}
|
|
1964
2087
|
return { selector };
|
|
1965
2088
|
};
|
|
2089
|
+
var asPageParams = (record) => {
|
|
2090
|
+
const limit = record.limit;
|
|
2091
|
+
if (limit !== void 0 && (typeof limit !== "number" || !Number.isInteger(limit) || limit <= 0)) {
|
|
2092
|
+
throw new RpcApplicationError("invalid_request", '"limit" must be a positive integer.');
|
|
2093
|
+
}
|
|
2094
|
+
const offset = record.offset;
|
|
2095
|
+
if (offset !== void 0 && (typeof offset !== "number" || !Number.isInteger(offset) || offset < 0)) {
|
|
2096
|
+
throw new RpcApplicationError("invalid_request", '"offset" must be a non-negative integer.');
|
|
2097
|
+
}
|
|
2098
|
+
return { limit, offset };
|
|
2099
|
+
};
|
|
2100
|
+
var asEventsListParams = (params) => {
|
|
2101
|
+
const { selector } = asSelectorParams(params);
|
|
2102
|
+
const record = asRecordParams(params);
|
|
2103
|
+
const name = record.name;
|
|
2104
|
+
if (name !== void 0 && typeof name !== "string") {
|
|
2105
|
+
throw new RpcApplicationError("invalid_request", '"name" must be a string.');
|
|
2106
|
+
}
|
|
2107
|
+
return { selector, name, ...asPageParams(record) };
|
|
2108
|
+
};
|
|
1966
2109
|
var asToolsListParams = (params) => {
|
|
1967
2110
|
const { selector } = asSelectorParams(params);
|
|
1968
2111
|
const record = asRecordParams(params);
|
|
@@ -1980,14 +2123,7 @@ var asToolsListParams = (params) => {
|
|
|
1980
2123
|
`"filter" must be a string of at most ${MAX_TOOLS_FILTER_LENGTH} characters.`
|
|
1981
2124
|
);
|
|
1982
2125
|
}
|
|
1983
|
-
const limit = record
|
|
1984
|
-
if (limit !== void 0 && (typeof limit !== "number" || !Number.isInteger(limit) || limit <= 0)) {
|
|
1985
|
-
throw new RpcApplicationError("invalid_request", '"limit" must be a positive integer.');
|
|
1986
|
-
}
|
|
1987
|
-
const offset = record.offset;
|
|
1988
|
-
if (offset !== void 0 && (typeof offset !== "number" || !Number.isInteger(offset) || offset < 0)) {
|
|
1989
|
-
throw new RpcApplicationError("invalid_request", '"offset" must be a non-negative integer.');
|
|
1990
|
-
}
|
|
2126
|
+
const { limit, offset } = asPageParams(record);
|
|
1991
2127
|
return {
|
|
1992
2128
|
selector,
|
|
1993
2129
|
group,
|
|
@@ -2072,7 +2208,26 @@ var asEventsSubscribeParams = (params) => {
|
|
|
2072
2208
|
}
|
|
2073
2209
|
kinds = kindsRaw;
|
|
2074
2210
|
}
|
|
2075
|
-
|
|
2211
|
+
const name = record.name;
|
|
2212
|
+
if (name !== void 0 && typeof name !== "string") {
|
|
2213
|
+
throw new RpcApplicationError("invalid_request", '"name" must be a string.');
|
|
2214
|
+
}
|
|
2215
|
+
const payloadMaxBytes = asPayloadMaxBytes(record.payloadMaxBytes);
|
|
2216
|
+
return {
|
|
2217
|
+
sessionSelector,
|
|
2218
|
+
kinds,
|
|
2219
|
+
name,
|
|
2220
|
+
payloadMaxBytes
|
|
2221
|
+
};
|
|
2222
|
+
};
|
|
2223
|
+
var asPayloadMaxBytes = (value) => {
|
|
2224
|
+
if (value === void 0) {
|
|
2225
|
+
return void 0;
|
|
2226
|
+
}
|
|
2227
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
2228
|
+
throw new RpcApplicationError("invalid_request", '"payloadMaxBytes" must be a positive integer.');
|
|
2229
|
+
}
|
|
2230
|
+
return value;
|
|
2076
2231
|
};
|
|
2077
2232
|
var asEventsSinceParams = (params) => {
|
|
2078
2233
|
const record = asRecordParams(params);
|
|
@@ -2088,10 +2243,17 @@ var asEventsSinceParams = (params) => {
|
|
|
2088
2243
|
if (limit !== void 0 && (typeof limit !== "number" || !Number.isInteger(limit) || limit <= 0)) {
|
|
2089
2244
|
throw new RpcApplicationError("invalid_request", '"limit" must be a positive integer.');
|
|
2090
2245
|
}
|
|
2246
|
+
const name = record.name;
|
|
2247
|
+
if (name !== void 0 && typeof name !== "string") {
|
|
2248
|
+
throw new RpcApplicationError("invalid_request", '"name" must be a string.');
|
|
2249
|
+
}
|
|
2250
|
+
const payloadMaxBytes = asPayloadMaxBytes(record.payloadMaxBytes);
|
|
2091
2251
|
return {
|
|
2092
2252
|
selector,
|
|
2093
2253
|
since,
|
|
2094
|
-
limit
|
|
2254
|
+
limit,
|
|
2255
|
+
name,
|
|
2256
|
+
payloadMaxBytes
|
|
2095
2257
|
};
|
|
2096
2258
|
};
|
|
2097
2259
|
var asLinkCreateParams = (params) => {
|
|
@@ -2238,10 +2400,17 @@ var startDaemon = async (options) => {
|
|
|
2238
2400
|
if (subscription.kinds && !subscription.kinds.has(event.kind)) {
|
|
2239
2401
|
continue;
|
|
2240
2402
|
}
|
|
2403
|
+
const projected = projectAppEvent(event, {
|
|
2404
|
+
name: subscription.name,
|
|
2405
|
+
payloadMaxBytes: subscription.payloadMaxBytes
|
|
2406
|
+
});
|
|
2407
|
+
if (projected === void 0) {
|
|
2408
|
+
continue;
|
|
2409
|
+
}
|
|
2241
2410
|
if (subscription.sessionSelector !== void 0 && event.sessionId !== subscription.sessionSelector && event.alias !== subscription.sessionSelector) {
|
|
2242
2411
|
continue;
|
|
2243
2412
|
}
|
|
2244
|
-
server?.notify(connection,
|
|
2413
|
+
server?.notify(connection, projected);
|
|
2245
2414
|
}
|
|
2246
2415
|
});
|
|
2247
2416
|
server = await startRpcServer({
|
|
@@ -2285,6 +2454,17 @@ var startDaemon = async (options) => {
|
|
|
2285
2454
|
activeSessionManager.revoke(selector);
|
|
2286
2455
|
return { ok: true };
|
|
2287
2456
|
},
|
|
2457
|
+
[RPC_METHODS.eventsList]: (params) => {
|
|
2458
|
+
const { selector, name, limit, offset } = asEventsListParams(params);
|
|
2459
|
+
const registered = activeSessionManager.resolveForTools(selector).eventRegistry.list();
|
|
2460
|
+
const sorted = registered.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
2461
|
+
const matching = name === void 0 ? sorted : sorted.filter((event) => matchesNameGlob(name, event.name));
|
|
2462
|
+
const start = offset ?? 0;
|
|
2463
|
+
return {
|
|
2464
|
+
events: limit === void 0 ? matching.slice(start) : matching.slice(start, start + limit),
|
|
2465
|
+
total: matching.length
|
|
2466
|
+
};
|
|
2467
|
+
},
|
|
2288
2468
|
[RPC_METHODS.toolsList]: (params) => {
|
|
2289
2469
|
const { selector, group, filter, limit, offset } = asToolsListParams(params);
|
|
2290
2470
|
const resolved = activeSessionManager.resolveForTools(selector);
|
|
@@ -2332,7 +2512,10 @@ var startDaemon = async (options) => {
|
|
|
2332
2512
|
if (resolved.state !== "active") {
|
|
2333
2513
|
const errorType = resolved.state === "suspended" ? "session_suspended" : "session_not_active";
|
|
2334
2514
|
writeAudit("error", errorType);
|
|
2335
|
-
throw new RpcApplicationError(
|
|
2515
|
+
throw new RpcApplicationError(
|
|
2516
|
+
errorType,
|
|
2517
|
+
resolved.suspendReason === "app_backgrounded" ? appBackgroundedMessage(resolved.alias) : `Session "${resolved.alias}" is not active.`
|
|
2518
|
+
);
|
|
2336
2519
|
}
|
|
2337
2520
|
const tool = resolved.registry.get(name);
|
|
2338
2521
|
if (!tool) {
|
|
@@ -2420,17 +2603,19 @@ var startDaemon = async (options) => {
|
|
|
2420
2603
|
return { cancelled };
|
|
2421
2604
|
},
|
|
2422
2605
|
[RPC_METHODS.eventsSubscribe]: (params, context) => {
|
|
2423
|
-
const { sessionSelector, kinds } = asEventsSubscribeParams(params);
|
|
2606
|
+
const { sessionSelector, kinds, name, payloadMaxBytes } = asEventsSubscribeParams(params);
|
|
2424
2607
|
context.connection.state.eventSubscription = {
|
|
2425
2608
|
sessionSelector,
|
|
2426
|
-
kinds: kinds ? new Set(kinds) : void 0
|
|
2609
|
+
kinds: kinds ? new Set(kinds) : void 0,
|
|
2610
|
+
name,
|
|
2611
|
+
payloadMaxBytes
|
|
2427
2612
|
};
|
|
2428
2613
|
return { ok: true };
|
|
2429
2614
|
},
|
|
2430
2615
|
[RPC_METHODS.eventsSince]: (params) => {
|
|
2431
|
-
const { selector, since, limit } = asEventsSinceParams(params);
|
|
2616
|
+
const { selector, since, limit, name, payloadMaxBytes } = asEventsSinceParams(params);
|
|
2432
2617
|
const resolved = activeSessionManager.describe(selector);
|
|
2433
|
-
return activeEventBus.since(resolved.sessionId, { since, limit });
|
|
2618
|
+
return activeEventBus.since(resolved.sessionId, { since, limit, name, payloadMaxBytes });
|
|
2434
2619
|
}
|
|
2435
2620
|
}
|
|
2436
2621
|
});
|
|
@@ -2674,6 +2859,7 @@ var formatJson = (value, flags) => {
|
|
|
2674
2859
|
import pc from "picocolors";
|
|
2675
2860
|
import {
|
|
2676
2861
|
formatAgentWebSocketUrl,
|
|
2862
|
+
renderEventSignature,
|
|
2677
2863
|
renderToolSignature,
|
|
2678
2864
|
summarizeToolDescription
|
|
2679
2865
|
} from "@appduct/shared";
|
|
@@ -2769,6 +2955,13 @@ var formatDevice = (device) => {
|
|
|
2769
2955
|
const label = parts.length > 0 ? parts.join(" ") : "unknown device";
|
|
2770
2956
|
return device.os ? `${label} (${device.os})` : label;
|
|
2771
2957
|
};
|
|
2958
|
+
var SUSPEND_REASON_LABELS = {
|
|
2959
|
+
app_backgrounded: "app in background",
|
|
2960
|
+
connection_lost: "connection lost"
|
|
2961
|
+
};
|
|
2962
|
+
var formatSessionState = (session) => {
|
|
2963
|
+
return session.suspendReason ? `${session.state} (${SUSPEND_REASON_LABELS[session.suspendReason]})` : session.state;
|
|
2964
|
+
};
|
|
2772
2965
|
var renderLsData = (colors, data, now) => {
|
|
2773
2966
|
if (data.length === 0) {
|
|
2774
2967
|
return [colors.dim("Sessions"), " No Appduct sessions are registered."];
|
|
@@ -2777,7 +2970,7 @@ var renderLsData = (colors, data, now) => {
|
|
|
2777
2970
|
const headers = ["Alias", "State", "Device", "Tools", "Age"];
|
|
2778
2971
|
const rows = data.map((session) => [
|
|
2779
2972
|
session.alias,
|
|
2780
|
-
session
|
|
2973
|
+
formatSessionState(session),
|
|
2781
2974
|
formatDevice(session.device),
|
|
2782
2975
|
String(session.toolCount),
|
|
2783
2976
|
formatAge(session.claimedAt ?? session.createdAt, nowIso)
|
|
@@ -2791,9 +2984,6 @@ var renderLsData = (colors, data, now) => {
|
|
|
2791
2984
|
...rows.map((row) => ` ${row.map((cell, index) => cell.padEnd(widths[index])).join(" ")}`)
|
|
2792
2985
|
];
|
|
2793
2986
|
};
|
|
2794
|
-
var isToolsListing = (data) => {
|
|
2795
|
-
return typeof data === "object" && data !== null && Array.isArray(data.tools);
|
|
2796
|
-
};
|
|
2797
2987
|
var isToolGroupsListing = (data) => {
|
|
2798
2988
|
return typeof data === "object" && data !== null && Array.isArray(data.groups) && !Array.isArray(data.tools);
|
|
2799
2989
|
};
|
|
@@ -2811,7 +3001,7 @@ var renderEmptyToolsLine = (data) => {
|
|
|
2811
3001
|
}
|
|
2812
3002
|
if (data.group !== void 0) {
|
|
2813
3003
|
const match = data.filter === void 0 ? "" : ` match ${JSON.stringify(data.filter)}`;
|
|
2814
|
-
return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools --groups\` to see the session's groups.`;
|
|
3004
|
+
return ` No tools in group ${JSON.stringify(data.group)}${match}. Run \`appduct tools ls --groups\` to see the session's groups.`;
|
|
2815
3005
|
}
|
|
2816
3006
|
return data.filter === void 0 ? " No tools registered." : ` No tools match ${JSON.stringify(data.filter)}.`;
|
|
2817
3007
|
};
|
|
@@ -2893,7 +3083,7 @@ var renderToolSummaryTable = (colors, data) => {
|
|
|
2893
3083
|
...grouped ? renderGroupedToolLines(colors, data.tools) : data.tools.flatMap((tool) => renderToolSummaryLines(tool, " ")),
|
|
2894
3084
|
...renderTruncationLine(data),
|
|
2895
3085
|
"",
|
|
2896
|
-
"Run `appduct tools <name>` for a tool's full schema."
|
|
3086
|
+
"Run `appduct tools describe <name>` for a tool's full schema."
|
|
2897
3087
|
];
|
|
2898
3088
|
};
|
|
2899
3089
|
var renderToolDetail = (colors, tool, flags) => {
|
|
@@ -2945,18 +3135,62 @@ var renderToolGroups = (colors, data) => {
|
|
|
2945
3135
|
colors.green("Groups"),
|
|
2946
3136
|
...data.groups.map((entry) => ` ${label(entry).padEnd(width)} ${String(entry.total).padStart(countWidth)}`),
|
|
2947
3137
|
"",
|
|
2948
|
-
`${data.total} tool${data.total === 1 ? "" : "s"} in total. ` + (hasAnyGroup(data.groups) ? "Run `appduct tools --group <name>` to list one group's tools." : "No tool declares a group.")
|
|
3138
|
+
`${data.total} tool${data.total === 1 ? "" : "s"} in total. ` + (hasAnyGroup(data.groups) ? "Run `appduct tools ls --group <name>` to list one group's tools." : "No tool declares a group.")
|
|
2949
3139
|
];
|
|
2950
3140
|
};
|
|
2951
|
-
var
|
|
3141
|
+
var renderToolsListData = (colors, data, flags, full) => {
|
|
2952
3142
|
if (isToolGroupsListing(data)) {
|
|
2953
3143
|
return renderToolGroups(colors, data);
|
|
2954
3144
|
}
|
|
2955
|
-
if (!isToolsListing(data)) {
|
|
2956
|
-
return renderToolDetail(colors, data, flags);
|
|
2957
|
-
}
|
|
2958
3145
|
return full ? renderToolsFullListing(colors, data, flags) : renderToolSummaryTable(colors, data);
|
|
2959
3146
|
};
|
|
3147
|
+
var renderEventsTruncationLine = (data) => {
|
|
3148
|
+
const offset = data.offset ?? 0;
|
|
3149
|
+
if (data.events.length >= data.total) {
|
|
3150
|
+
return [];
|
|
3151
|
+
}
|
|
3152
|
+
return [
|
|
3153
|
+
"",
|
|
3154
|
+
`Showing ${data.events.length} of ${data.total} events (offset ${offset}). Narrow with --name <glob> or page with --offset <n>.`
|
|
3155
|
+
];
|
|
3156
|
+
};
|
|
3157
|
+
var renderEventsListData = (colors, data, flags) => {
|
|
3158
|
+
const [only] = data.events;
|
|
3159
|
+
if (data.name !== void 0 && !data.name.includes("*") && only !== void 0) {
|
|
3160
|
+
return renderFields(
|
|
3161
|
+
colors.green(`Event: ${only.name}`),
|
|
3162
|
+
[
|
|
3163
|
+
["Signature", renderEventSignature(only)],
|
|
3164
|
+
["Description", only.description],
|
|
3165
|
+
["Payload schema", only.payload_schema]
|
|
3166
|
+
],
|
|
3167
|
+
flags
|
|
3168
|
+
);
|
|
3169
|
+
}
|
|
3170
|
+
if (data.events.length === 0 && data.total > 0) {
|
|
3171
|
+
return [
|
|
3172
|
+
colors.green("Events"),
|
|
3173
|
+
` No events at offset ${data.offset ?? 0}; ${data.total} matching event${data.total === 1 ? "" : "s"} in total.`
|
|
3174
|
+
];
|
|
3175
|
+
}
|
|
3176
|
+
if (data.events.length === 0) {
|
|
3177
|
+
return [
|
|
3178
|
+
colors.green("Events"),
|
|
3179
|
+
data.name === void 0 ? " No events declared." : ` No events match ${JSON.stringify(data.name)}.`
|
|
3180
|
+
];
|
|
3181
|
+
}
|
|
3182
|
+
const lines = data.events.flatMap((event) => [
|
|
3183
|
+
` ${renderEventSignature(event)}`,
|
|
3184
|
+
` ${summarizeToolDescription(event.description)}`
|
|
3185
|
+
]);
|
|
3186
|
+
return [
|
|
3187
|
+
colors.green("Events"),
|
|
3188
|
+
...lines,
|
|
3189
|
+
...renderEventsTruncationLine(data),
|
|
3190
|
+
"",
|
|
3191
|
+
"Run `appduct events ls --name <name>` for an event's full payload schema."
|
|
3192
|
+
];
|
|
3193
|
+
};
|
|
2960
3194
|
var renderInvokeData = (colors, data, flags) => {
|
|
2961
3195
|
return [colors.green("Result"), formatScalar(data, flags)];
|
|
2962
3196
|
};
|
|
@@ -3140,15 +3374,19 @@ var renderSuccessData = (colors, command, data, options) => {
|
|
|
3140
3374
|
return renderInitData(colors, data, flags);
|
|
3141
3375
|
case "keygen":
|
|
3142
3376
|
return renderKeygenData(colors, data, flags);
|
|
3143
|
-
case "link":
|
|
3377
|
+
case "sessions link":
|
|
3144
3378
|
return renderLinkData(colors, data, flags, options.qr);
|
|
3145
|
-
case "ls":
|
|
3379
|
+
case "sessions ls":
|
|
3146
3380
|
return renderLsData(colors, data, options.now ?? /* @__PURE__ */ new Date());
|
|
3147
|
-
case "tools":
|
|
3148
|
-
return
|
|
3149
|
-
case "
|
|
3381
|
+
case "tools ls":
|
|
3382
|
+
return renderToolsListData(colors, data, flags, options.full);
|
|
3383
|
+
case "tools describe":
|
|
3384
|
+
return renderToolDetail(colors, data, flags);
|
|
3385
|
+
case "events ls":
|
|
3386
|
+
return renderEventsListData(colors, data, flags);
|
|
3387
|
+
case "tools call":
|
|
3150
3388
|
return renderInvokeData(colors, data, flags);
|
|
3151
|
-
case "revoke":
|
|
3389
|
+
case "sessions revoke":
|
|
3152
3390
|
return renderRevokeData(colors, data);
|
|
3153
3391
|
case "daemon run":
|
|
3154
3392
|
return renderDaemonRunData(colors, data, flags);
|