@prismshadow/penguin-server 0.2.7 → 0.2.9
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 +4 -4
- package/dist/api/types.d.ts +528 -39
- package/dist/auth-token.d.ts +29 -0
- package/dist/auth-token.js +51 -0
- package/dist/auth-token.js.map +1 -0
- package/dist/chunk-K4ZSUT72.js +34 -0
- package/dist/chunk-K4ZSUT72.js.map +1 -0
- package/dist/chunk-OTYHSDV7.js +374 -0
- package/dist/chunk-OTYHSDV7.js.map +1 -0
- package/dist/{chunk-WKJ3ANJP.js → chunk-WL5FUO3A.js} +92 -381
- package/dist/chunk-WL5FUO3A.js.map +1 -0
- package/dist/extension/index.d.ts +212 -0
- package/dist/extension/index.js +1 -0
- package/dist/extension/index.js.map +1 -0
- package/dist/index.js +7337 -1774
- package/dist/index.js.map +1 -1
- package/dist/initial-password.d.ts +9 -12
- package/dist/initial-password.js +3 -7
- package/dist/install.ps1 +729 -0
- package/dist/install.sh +785 -0
- package/dist/reset-admin-password.d.ts +4 -7
- package/dist/reset-admin-password.js +11 -9
- package/dist/reset-admin-password.js.map +1 -1
- package/dist/secret-file.d.ts +3 -0
- package/dist/secret-file.js +17 -0
- package/dist/secret-file.js.map +1 -0
- package/package.json +19 -3
- package/web-dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/web-dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/web-dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/web-dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/web-dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/web-dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/web-dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/web-dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/web-dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/web-dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/web-dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/web-dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/web-dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/web-dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/web-dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/web-dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/web-dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/web-dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/web-dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/web-dist/assets/{addon-fit-BXTX0Xqu.js → addon-fit-BjXzaLkS.js} +1 -1
- package/web-dist/assets/{addon-web-links-KebkunbU.js → addon-web-links-D4HvCIde.js} +1 -1
- package/web-dist/assets/{highlighter-B3HctNDB.js → highlighter-Di8euoN5.js} +1 -1
- package/web-dist/assets/index-C6i84Esu.js +451 -0
- package/web-dist/assets/index-DW00p4Ny.css +1 -0
- package/web-dist/assets/{xterm-fEUfDV0F.js → xterm-XhYBaOEK.js} +1 -1
- package/web-dist/index.html +2 -2
- package/dist/chunk-UUJCF46V.js +0 -50
- package/dist/chunk-UUJCF46V.js.map +0 -1
- package/dist/chunk-WKJ3ANJP.js.map +0 -1
- package/web-dist/assets/index-BbLm3DrY.css +0 -1
- package/web-dist/assets/index-DwgTjTHO.js +0 -189
package/dist/api/types.d.ts
CHANGED
|
@@ -47,6 +47,19 @@ interface AuthLoginRequest {
|
|
|
47
47
|
interface AuthResponse {
|
|
48
48
|
user: UserInfo;
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* GET /api/install — the identity of the data root this server is serving (install-id.ts),
|
|
52
|
+
* read by the web app before it mounts so state persisted against a DIFFERENT root can be
|
|
53
|
+
* swept. Public, like the login route it sits next to.
|
|
54
|
+
*/
|
|
55
|
+
interface InstallResponse {
|
|
56
|
+
/**
|
|
57
|
+
* Opaque per-data-root id, or null when the server could not establish one (an
|
|
58
|
+
* unreadable or unwritable root). Null means "unknown", and a client must change
|
|
59
|
+
* nothing on it — never treat it as a new install.
|
|
60
|
+
*/
|
|
61
|
+
installId: string | null;
|
|
62
|
+
}
|
|
50
63
|
interface MeResponse {
|
|
51
64
|
user: UserInfo;
|
|
52
65
|
/**
|
|
@@ -62,18 +75,19 @@ interface MeResponse {
|
|
|
62
75
|
/**
|
|
63
76
|
* Whether this server runs in desktop mode (spawned by the desktop shell with
|
|
64
77
|
* PENGUIN_DESKTOP_TOKEN). The web app then hides the logout entry, the
|
|
65
|
-
* initial-password banner and the self-update entry
|
|
66
|
-
* field when changing the password.
|
|
78
|
+
* initial-password banner and the self-update entry.
|
|
67
79
|
*/
|
|
68
80
|
desktopMode: boolean;
|
|
69
81
|
/**
|
|
70
|
-
* How THIS session was established
|
|
71
|
-
* desktop-mode server holds a "password" session
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
82
|
+
* How THIS session was established — distinct from desktopMode, which describes the
|
|
83
|
+
* server: a browser signed into a desktop-mode server holds a "password" session.
|
|
84
|
+
* "desktop" is the shell's own window (one-shot token); "setup" was claimed through the
|
|
85
|
+
* first-login link on a server whose admin password has never been set. Both may set a
|
|
86
|
+
* password without the old one (it is random and was never shown); only "desktop" opens
|
|
87
|
+
* desktop-only routes. "token" marks a request authenticated by the local API token's
|
|
88
|
+
* Bearer header (the CLI and agent-driven calls) — no stored session at all.
|
|
75
89
|
*/
|
|
76
|
-
sessionVia: "password" | "desktop" | "token";
|
|
90
|
+
sessionVia: "password" | "desktop" | "setup" | "token";
|
|
77
91
|
/**
|
|
78
92
|
* The upload limits currently in force, so the composer can refuse an oversize pick before
|
|
79
93
|
* reading it and can name the real number in the message. They are admin-settable and ride
|
|
@@ -108,7 +122,7 @@ interface UploadLimits {
|
|
|
108
122
|
attachmentLimitMaxMb: number;
|
|
109
123
|
}
|
|
110
124
|
interface PasswordChangeRequest {
|
|
111
|
-
/** Omitted only by desktop
|
|
125
|
+
/** Omitted only by a "desktop" or "setup" session (see {@link MeResponse.sessionVia}); required otherwise. */
|
|
112
126
|
oldPassword?: string;
|
|
113
127
|
/** At least 8 characters. */
|
|
114
128
|
newPassword: string;
|
|
@@ -220,6 +234,14 @@ interface UiPrefs {
|
|
|
220
234
|
credentialGuideSeen?: boolean;
|
|
221
235
|
/** The initial-password notice banner (app layout) was permanently dismissed by the user. */
|
|
222
236
|
initialPasswordBannerDismissed?: boolean;
|
|
237
|
+
/**
|
|
238
|
+
* "I have dealt with this" markers for the dismissible to-do badges, per Project id and then
|
|
239
|
+
* per trail (`skills` / `models` / `errors`). Each value is the SIGNATURE of what was waved
|
|
240
|
+
* away rather than a hidden flag, so anything new raises the dot again (web's
|
|
241
|
+
* `lib/todo-badges.ts`). Replaced whole on every write, like `draftShortcuts`: the merge is
|
|
242
|
+
* shallow, so this whole map is one field.
|
|
243
|
+
*/
|
|
244
|
+
todoDismissed?: Record<string, Record<string, string>>;
|
|
223
245
|
/**
|
|
224
246
|
* The draft screen's user-defined shortcuts, in display order. Replaced whole on every write
|
|
225
247
|
* (the merge is shallow, so the array is one field like any other) and bounded on write by
|
|
@@ -593,6 +615,13 @@ interface ModelOAuthStatusResponse {
|
|
|
593
615
|
status: "pending" | "done" | "error";
|
|
594
616
|
/** The provider group the flow mints a key for. */
|
|
595
617
|
provider: string;
|
|
618
|
+
/**
|
|
619
|
+
* How many models the minted key was written to — set on the `done` answer, the way
|
|
620
|
+
* {@link ModelOAuthCodeResponse} sets it on a redemption. The dialog reports this number, so
|
|
621
|
+
* it has to be the server's own: the caller's model table can outlive a rejected save and
|
|
622
|
+
* would otherwise name a count the server never wrote.
|
|
623
|
+
*/
|
|
624
|
+
applied?: number;
|
|
596
625
|
error?: ModelOAuthErrorCode;
|
|
597
626
|
}
|
|
598
627
|
/**
|
|
@@ -679,6 +708,13 @@ interface VaultEntryUpdate {
|
|
|
679
708
|
interface VaultUpdateRequest {
|
|
680
709
|
entries: VaultEntryUpdate[];
|
|
681
710
|
}
|
|
711
|
+
/** One installed Skill the library carries a higher version of (see {@link AgentSummary.skillUpdates}). */
|
|
712
|
+
interface SkillUpdateRef {
|
|
713
|
+
/** Skill directory name — the identity install / uninstall address it by. */
|
|
714
|
+
name: string;
|
|
715
|
+
/** The LIBRARY's version, i.e. what installing again would bring, not what is on disk. */
|
|
716
|
+
version: number;
|
|
717
|
+
}
|
|
682
718
|
interface AgentSummary {
|
|
683
719
|
agentId: string;
|
|
684
720
|
name?: string;
|
|
@@ -704,6 +740,14 @@ interface AgentSummary {
|
|
|
704
740
|
scheduleCount: number;
|
|
705
741
|
/** Installed Skill count (number of agent_state/skills/<name>/ directories with a SKILL.md). */
|
|
706
742
|
skillCount: number;
|
|
743
|
+
/**
|
|
744
|
+
* Installed Skills the built-in library has moved past, each with the library version on
|
|
745
|
+
* offer — the Skill-library update gate, riding along on the Agent list so a badge over
|
|
746
|
+
* that page costs no request of its own. Empty when nothing is behind. Skills that are not
|
|
747
|
+
* in the library (installed from a zip or a picked directory) are never listed: there is no
|
|
748
|
+
* library version for them to be behind.
|
|
749
|
+
*/
|
|
750
|
+
skillUpdates: SkillUpdateRef[];
|
|
707
751
|
/** Memory count (topic files summed over the scope directories under agent_state/memory/, independent of the memory switch). */
|
|
708
752
|
memoryCount: number;
|
|
709
753
|
}
|
|
@@ -1446,20 +1490,117 @@ interface SessionProcessesResponse {
|
|
|
1446
1490
|
processes: SessionProcessInfo[];
|
|
1447
1491
|
}
|
|
1448
1492
|
/** Messaging channels a Session can bind to. */
|
|
1449
|
-
type MessagingChannel = "feishu" | "telegram";
|
|
1493
|
+
type MessagingChannel = "feishu" | "telegram" | "qq" | "wechat";
|
|
1450
1494
|
/** Event-connection runtime state of one binding (kept in memory, not persisted). */
|
|
1451
1495
|
type MessagingRuntimeState = "disconnected" | "connecting" | "connected" | "error";
|
|
1496
|
+
/**
|
|
1497
|
+
* A failure that happened AFTER an inbound message was accepted — as opposed to a
|
|
1498
|
+
* connection failure, which `MessagingRuntimeStatus.lastError` reports.
|
|
1499
|
+
*
|
|
1500
|
+
* The two stages fail in completely different places and lead to different actions, and
|
|
1501
|
+
* from the chat they are indistinguishable (both produce silence), which is why the stage
|
|
1502
|
+
* is stated rather than folded into one message.
|
|
1503
|
+
*/
|
|
1504
|
+
interface MessagingDeliveryError {
|
|
1505
|
+
/** ISO 8601 timestamp of the failure. */
|
|
1506
|
+
at: string;
|
|
1507
|
+
/** `inbound` — the message arrived and its Task never started; `send` — a reply never reached the chat. */
|
|
1508
|
+
stage: "inbound" | "send";
|
|
1509
|
+
/** The failure's own message, as the channel or the Session reported it. */
|
|
1510
|
+
detail: string;
|
|
1511
|
+
}
|
|
1452
1512
|
interface MessagingRuntimeStatus {
|
|
1453
1513
|
state: MessagingRuntimeState;
|
|
1454
1514
|
/** Failure detail; present only in the `error` state. */
|
|
1455
1515
|
lastError?: string;
|
|
1456
1516
|
/** When the state last changed (ISO 8601); absent for a binding that never connected. */
|
|
1457
1517
|
changedAt?: string;
|
|
1518
|
+
/**
|
|
1519
|
+
* When this binding last accepted an inbound message (ISO 8601).
|
|
1520
|
+
*
|
|
1521
|
+
* "Connected, and nothing has arrived" is the answer to the one question a chat cannot
|
|
1522
|
+
* answer for itself — whether the platform is delivering anything at all. A channel that
|
|
1523
|
+
* withholds messages (Telegram's group privacy, a bot that is not a member) produces
|
|
1524
|
+
* exactly that, with no error anywhere.
|
|
1525
|
+
*
|
|
1526
|
+
* In-process AND scoped to one connection: it starts empty on every (re)connect, and a
|
|
1527
|
+
* re-enable or a credential save opens a new one. So an absent field means "nothing since
|
|
1528
|
+
* this connection opened", never "nothing ever" — anything reporting it has to say which,
|
|
1529
|
+
* or it sends a reader off to fix a channel that is working.
|
|
1530
|
+
*/
|
|
1531
|
+
lastInboundAt?: string;
|
|
1532
|
+
/**
|
|
1533
|
+
* The most recent post-acceptance failure; absent when none has happened since this
|
|
1534
|
+
* connection opened, and never cleared by a later success — an intermittent failure would
|
|
1535
|
+
* otherwise be erased by the next ordinary message. `at` is what says how stale it is.
|
|
1536
|
+
*/
|
|
1537
|
+
lastDeliveryError?: MessagingDeliveryError;
|
|
1538
|
+
/**
|
|
1539
|
+
* The most recent CONNECTION failure, kept after the connection recovers — unlike
|
|
1540
|
+
* `lastError`, which belongs to the `error` state and is gone the moment the state leaves it.
|
|
1541
|
+
*
|
|
1542
|
+
* A connection that fails and recovers repeatedly (a second program polling the same bot
|
|
1543
|
+
* token takes turns with this one) reads as `connected` in any snapshot taken between
|
|
1544
|
+
* flaps, with nothing at all to show for the failures in between. This is what is left
|
|
1545
|
+
* behind — for the life of the connection, like the two above it.
|
|
1546
|
+
*/
|
|
1547
|
+
lastConnectionError?: {
|
|
1548
|
+
at: string;
|
|
1549
|
+
detail: string;
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1552
|
+
/**
|
|
1553
|
+
* What a messaging binding carries whatever channel it is: the connection intent, the three
|
|
1554
|
+
* delivery preferences, whether a chat is known, and the row's identity and timestamps.
|
|
1555
|
+
*
|
|
1556
|
+
* Split out because this is the half that grows. Three delivery preferences arrived in one
|
|
1557
|
+
* release, and each would otherwise have been written into three interfaces — the credential
|
|
1558
|
+
* slice is the only thing a channel genuinely differs in, and it is what stays per-channel.
|
|
1559
|
+
*
|
|
1560
|
+
* `channel` is NOT here: a discriminated union discriminates on a literal the member itself
|
|
1561
|
+
* declares, so each interface keeps its own.
|
|
1562
|
+
*
|
|
1563
|
+
* A channel may RE-DECLARE a field below when it has more to say about it — QQ does, for all
|
|
1564
|
+
* three preferences, because the platform's passive-reply budget and its expiring window
|
|
1565
|
+
* change what setting one costs there. The re-declared type must be identical, which the
|
|
1566
|
+
* compiler enforces, so the redeclaration can only add documentation and never a contract.
|
|
1567
|
+
*/
|
|
1568
|
+
interface MessagingBindingCommon {
|
|
1569
|
+
sessionId: string;
|
|
1570
|
+
/** Connection INTENT (the state toggle's value); new bindings start disabled, and at most one of a Session's channels is enabled. */
|
|
1571
|
+
enabled: boolean;
|
|
1572
|
+
/**
|
|
1573
|
+
* Send each non-blank line of a relayed assistant reply as its own message instead of one
|
|
1574
|
+
* message per reply. Off by default; off is the original one-message-per-reply behaviour.
|
|
1575
|
+
*/
|
|
1576
|
+
linePerMessage: boolean;
|
|
1577
|
+
/**
|
|
1578
|
+
* Relay only the LAST completed assistant message of a run, delivered when the run ends,
|
|
1579
|
+
* instead of mirroring each completed message as it completes. Off by default; off is the
|
|
1580
|
+
* original every-message behaviour. Independent of `linePerMessage`, which then applies to
|
|
1581
|
+
* that one final message. The approval notice is not a reply and is unaffected.
|
|
1582
|
+
*/
|
|
1583
|
+
finalReplyOnly: boolean;
|
|
1584
|
+
/**
|
|
1585
|
+
* Render a relayed reply's Markdown in this channel's own markup instead of sending its
|
|
1586
|
+
* characters as written. ON by default. Each channel shows what it can — Telegram has no
|
|
1587
|
+
* headings, lists or tables, QQ has no code or tables, Feishu has all of them, and WeChat
|
|
1588
|
+
* reads Markdown itself so the render is a subtraction rather than a translation — and a
|
|
1589
|
+
* rendering the channel refuses falls back to the plain source, so this can cost
|
|
1590
|
+
* formatting and never a message.
|
|
1591
|
+
*/
|
|
1592
|
+
renderMarkdown: boolean;
|
|
1593
|
+
/**
|
|
1594
|
+
* Whether an inbound chat is known (the bot has been messaged at least once). Replies and
|
|
1595
|
+
* test messages target that chat; until it exists nothing can be sent.
|
|
1596
|
+
*/
|
|
1597
|
+
lastChatKnown: boolean;
|
|
1598
|
+
createdAt: string;
|
|
1599
|
+
updatedAt: string;
|
|
1458
1600
|
}
|
|
1459
1601
|
/** The stored Feishu config, secret masked (plaintext never leaves the server). */
|
|
1460
|
-
interface FeishuBindingInfo {
|
|
1602
|
+
interface FeishuBindingInfo extends MessagingBindingCommon {
|
|
1461
1603
|
channel: "feishu";
|
|
1462
|
-
sessionId: string;
|
|
1463
1604
|
appId: string;
|
|
1464
1605
|
/**
|
|
1465
1606
|
* Masked app secret (site-wide mask rule: `***`, or `first4…last4` for long values);
|
|
@@ -1468,20 +1609,10 @@ interface FeishuBindingInfo {
|
|
|
1468
1609
|
*/
|
|
1469
1610
|
appSecretMasked?: string;
|
|
1470
1611
|
baseDomain: string;
|
|
1471
|
-
/** Connection INTENT (the state toggle's value); new bindings start disabled, and at most one of a Session's channels is enabled. */
|
|
1472
|
-
enabled: boolean;
|
|
1473
|
-
/**
|
|
1474
|
-
* Whether an inbound Feishu chat is known (the bot has been messaged at least once).
|
|
1475
|
-
* Replies and test messages target that chat; until it exists nothing can be sent.
|
|
1476
|
-
*/
|
|
1477
|
-
lastChatKnown: boolean;
|
|
1478
|
-
createdAt: string;
|
|
1479
|
-
updatedAt: string;
|
|
1480
1612
|
}
|
|
1481
1613
|
/** The stored Telegram config, token masked (plaintext never leaves the server). */
|
|
1482
|
-
interface TelegramBindingInfo {
|
|
1614
|
+
interface TelegramBindingInfo extends MessagingBindingCommon {
|
|
1483
1615
|
channel: "telegram";
|
|
1484
|
-
sessionId: string;
|
|
1485
1616
|
/** The numeric bot id (the token's half before the colon) — the channel-scoped account identity, never secret. */
|
|
1486
1617
|
botId: string;
|
|
1487
1618
|
/**
|
|
@@ -1490,18 +1621,78 @@ interface TelegramBindingInfo {
|
|
|
1490
1621
|
* is saved.
|
|
1491
1622
|
*/
|
|
1492
1623
|
botTokenMasked?: string;
|
|
1493
|
-
|
|
1494
|
-
|
|
1624
|
+
}
|
|
1625
|
+
/**
|
|
1626
|
+
* The stored QQ config, secret masked (plaintext never leaves the server).
|
|
1627
|
+
*
|
|
1628
|
+
* The three preference fields are re-declared unchanged: every one of them costs something
|
|
1629
|
+
* different here, and the platform's reply budget is what a reader setting one needs to know.
|
|
1630
|
+
*/
|
|
1631
|
+
interface QQBindingInfo extends MessagingBindingCommon {
|
|
1632
|
+
channel: "qq";
|
|
1633
|
+
/** The bot's App ID — the channel-scoped account identity, never secret. */
|
|
1634
|
+
appId: string;
|
|
1635
|
+
/**
|
|
1636
|
+
* Masked App Secret (site-wide mask rule: `***`, or `first4…last4` for long values);
|
|
1637
|
+
* absent when no secret is stored (never entered, or cleared) — the binding cannot be
|
|
1638
|
+
* enabled until one is saved.
|
|
1639
|
+
*/
|
|
1640
|
+
appSecretMasked?: string;
|
|
1495
1641
|
/**
|
|
1496
|
-
*
|
|
1497
|
-
*
|
|
1642
|
+
* Send each non-blank line of a relayed assistant reply as its own message instead of one
|
|
1643
|
+
* message per reply. Off by default. On QQ the split is additionally capped at the
|
|
1644
|
+
* platform's passive-reply budget rather than the channel-neutral ceiling, so it yields
|
|
1645
|
+
* far fewer messages here than on the other channels.
|
|
1646
|
+
*/
|
|
1647
|
+
linePerMessage: boolean;
|
|
1648
|
+
/**
|
|
1649
|
+
* Relay only the LAST completed assistant message of a run, delivered when the run ends.
|
|
1650
|
+
* Off by default.
|
|
1651
|
+
*
|
|
1652
|
+
* On QQ it cuts both ways, which is worth knowing before setting it here. It spends the
|
|
1653
|
+
* least of the platform's passive-reply budget a run can spend — one message, where an
|
|
1654
|
+
* every-message relay spends one per completed message. But a passive reply is accepted
|
|
1655
|
+
* only for a few minutes after the inbound message that funds it, and holding the reply
|
|
1656
|
+
* to the run's end spends that window on the run: a run that outlives it delivers nothing
|
|
1657
|
+
* at all, where the every-message relay would have sent whatever completed inside it.
|
|
1658
|
+
*/
|
|
1659
|
+
finalReplyOnly: boolean;
|
|
1660
|
+
/**
|
|
1661
|
+
* Render a relayed reply's Markdown in this channel's own markup. ON by default. QQ's own
|
|
1662
|
+
* subset is the widest for prose and the narrowest for code: headings, lists, blockquotes
|
|
1663
|
+
* and rules render, while inline code, fenced code and tables have no syntax at all here —
|
|
1664
|
+
* a code block arrives as plain escaped lines. A rendering the platform refuses falls back
|
|
1665
|
+
* to the plain source, at the cost of one more slot from the passive-reply budget.
|
|
1666
|
+
*/
|
|
1667
|
+
renderMarkdown: boolean;
|
|
1668
|
+
/**
|
|
1669
|
+
* Whether an inbound QQ chat is known (the bot has been messaged at least once). Weaker
|
|
1670
|
+
* than it looks on this channel: QQ accepts only replies to a recent message, so a known
|
|
1671
|
+
* chat is necessary but not sufficient for anything to be deliverable right now.
|
|
1498
1672
|
*/
|
|
1499
1673
|
lastChatKnown: boolean;
|
|
1500
|
-
|
|
1501
|
-
|
|
1674
|
+
}
|
|
1675
|
+
/**
|
|
1676
|
+
* The stored WeChat config, token masked (plaintext never leaves the server).
|
|
1677
|
+
*
|
|
1678
|
+
* No preference field is re-declared. The three delivery preferences cost exactly what they
|
|
1679
|
+
* cost on Feishu and Telegram here — this channel has no reply budget and no expiring reply
|
|
1680
|
+
* window — and re-declaring a field to say nothing new about it would only invite the next
|
|
1681
|
+
* reader to look for the difference.
|
|
1682
|
+
*/
|
|
1683
|
+
interface WeChatBindingInfo extends MessagingBindingCommon {
|
|
1684
|
+
channel: "wechat";
|
|
1685
|
+
/** The bot id a scan issued — the channel-scoped account identity, never secret. */
|
|
1686
|
+
botId: string;
|
|
1687
|
+
/**
|
|
1688
|
+
* Masked bot token (site-wide mask rule: `***`, or `first4…last4` for long values);
|
|
1689
|
+
* absent when none is stored (cleared, or a scan that never completed) — the binding
|
|
1690
|
+
* cannot be enabled until a scan saves one.
|
|
1691
|
+
*/
|
|
1692
|
+
botTokenMasked?: string;
|
|
1502
1693
|
}
|
|
1503
1694
|
/** A Session's saved config for one messaging channel (`channel` is the discriminant). */
|
|
1504
|
-
type MessagingBindingInfo = FeishuBindingInfo | TelegramBindingInfo;
|
|
1695
|
+
type MessagingBindingInfo = FeishuBindingInfo | TelegramBindingInfo | QQBindingInfo | WeChatBindingInfo;
|
|
1505
1696
|
/** One saved channel config with its event-connection runtime status. */
|
|
1506
1697
|
interface MessagingChannelState {
|
|
1507
1698
|
binding: MessagingBindingInfo;
|
|
@@ -1526,12 +1717,37 @@ interface TelegramBindingResponse {
|
|
|
1526
1717
|
binding: TelegramBindingInfo | null;
|
|
1527
1718
|
status: MessagingRuntimeStatus;
|
|
1528
1719
|
}
|
|
1720
|
+
/** GET / PUT …/messaging/qq response (the QQ narrowing of the same envelope). */
|
|
1721
|
+
interface QQBindingResponse {
|
|
1722
|
+
binding: QQBindingInfo | null;
|
|
1723
|
+
status: MessagingRuntimeStatus;
|
|
1724
|
+
}
|
|
1725
|
+
/** GET / PUT …/messaging/wechat response (the WeChat narrowing of the same envelope). */
|
|
1726
|
+
interface WeChatBindingResponse {
|
|
1727
|
+
binding: WeChatBindingInfo | null;
|
|
1728
|
+
status: MessagingRuntimeStatus;
|
|
1729
|
+
}
|
|
1529
1730
|
/**
|
|
1530
1731
|
* PUT …/messaging/feishu — saves credentials/config ONLY, never flipping the connection
|
|
1531
1732
|
* (exception: an enabled binding's connector restarts with the new credentials so stored
|
|
1532
1733
|
* config and live connection never diverge). The connection toggle is POST …/state.
|
|
1533
1734
|
*/
|
|
1534
|
-
|
|
1735
|
+
/**
|
|
1736
|
+
* The delivery preferences any channel's PUT may set. Each is optional and each behaves the
|
|
1737
|
+
* same way on every channel: an omitted field keeps the stored value, so a client that knows
|
|
1738
|
+
* about one preference can save it without having to send the others back. Their meanings are
|
|
1739
|
+
* on {@link MessagingBindingCommon}, and where a channel charges differently for one, on that
|
|
1740
|
+
* channel's own `*BindingInfo`.
|
|
1741
|
+
*
|
|
1742
|
+
* The defaults a binding created without them starts from: `linePerMessage` off,
|
|
1743
|
+
* `finalReplyOnly` off, `renderMarkdown` ON.
|
|
1744
|
+
*/
|
|
1745
|
+
interface MessagingDeliveryPatch {
|
|
1746
|
+
linePerMessage?: boolean;
|
|
1747
|
+
finalReplyOnly?: boolean;
|
|
1748
|
+
renderMarkdown?: boolean;
|
|
1749
|
+
}
|
|
1750
|
+
interface FeishuBindingPutRequest extends MessagingDeliveryPatch {
|
|
1535
1751
|
appId: string;
|
|
1536
1752
|
/** Omitted or blank keeps the stored secret (the masked value never round-trips). */
|
|
1537
1753
|
appSecret?: string;
|
|
@@ -1546,9 +1762,10 @@ interface FeishuBindingPutRequest {
|
|
|
1546
1762
|
/**
|
|
1547
1763
|
* PUT …/messaging/telegram — saves the credential ONLY, same contract as the Feishu PUT
|
|
1548
1764
|
* (an enabled binding's connector restarts with the new token; the connection toggle is
|
|
1549
|
-
* POST …/state).
|
|
1765
|
+
* POST …/state). Saving never conflicts across Sessions: the same bot may sit saved on
|
|
1766
|
+
* several, and only enabling it is exclusive.
|
|
1550
1767
|
*/
|
|
1551
|
-
interface TelegramBindingPutRequest {
|
|
1768
|
+
interface TelegramBindingPutRequest extends MessagingDeliveryPatch {
|
|
1552
1769
|
/** Omitted or blank keeps the stored token (the masked value never round-trips). */
|
|
1553
1770
|
botToken?: string;
|
|
1554
1771
|
/**
|
|
@@ -1558,11 +1775,46 @@ interface TelegramBindingPutRequest {
|
|
|
1558
1775
|
*/
|
|
1559
1776
|
clearBotToken?: boolean;
|
|
1560
1777
|
}
|
|
1778
|
+
/**
|
|
1779
|
+
* PUT …/messaging/qq — saves the credential pair ONLY, same contract as the Feishu PUT
|
|
1780
|
+
* (an enabled binding's connector restarts with the new credentials; the connection toggle
|
|
1781
|
+
* is POST …/state). The App ID is the account identity, so changing it rebinds the row to
|
|
1782
|
+
* a different bot and drops the remembered chat.
|
|
1783
|
+
*/
|
|
1784
|
+
interface QQBindingPutRequest extends MessagingDeliveryPatch {
|
|
1785
|
+
appId: string;
|
|
1786
|
+
/** Omitted or blank keeps the stored secret (the masked value never round-trips). */
|
|
1787
|
+
appSecret?: string;
|
|
1788
|
+
/**
|
|
1789
|
+
* Drops the STORED secret (the models-page clear idiom; a typed `appSecret` wins over
|
|
1790
|
+
* it). Refused with 409 `messaging_disable_before_clear` while the binding is enabled.
|
|
1791
|
+
*/
|
|
1792
|
+
clearAppSecret?: boolean;
|
|
1793
|
+
}
|
|
1794
|
+
/**
|
|
1795
|
+
* PUT …/messaging/wechat — the delivery preferences ONLY.
|
|
1796
|
+
*
|
|
1797
|
+
* The one PUT on this router that carries no credential, because there is none to carry: a
|
|
1798
|
+
* WeChat bot token exists only where a scan put it, and there is no console to copy one out
|
|
1799
|
+
* of. Saving therefore presupposes a binding — a PUT before any scan answers 400
|
|
1800
|
+
* `wechat_token_required` rather than creating an empty row — and the connection toggle
|
|
1801
|
+
* stays POST …/state, as on every channel.
|
|
1802
|
+
*/
|
|
1803
|
+
interface WeChatBindingPutRequest extends MessagingDeliveryPatch {
|
|
1804
|
+
/**
|
|
1805
|
+
* Drops the STORED token (the models-page clear idiom). Refused with 409
|
|
1806
|
+
* `messaging_disable_before_clear` while the binding is enabled. The row and its bot
|
|
1807
|
+
* identity stay; only a fresh scan can make it connectable again.
|
|
1808
|
+
*/
|
|
1809
|
+
clearBotToken?: boolean;
|
|
1810
|
+
}
|
|
1561
1811
|
/**
|
|
1562
1812
|
* POST …/messaging/<channel>/state — enable connects with the STORED credentials,
|
|
1563
|
-
* disable terminates. Enabling is
|
|
1564
|
-
*
|
|
1565
|
-
*
|
|
1813
|
+
* disable terminates. Enabling is what binds the bot account to this Session, and it is
|
|
1814
|
+
* mutually exclusive twice over: while another channel of the same Session is enabled it
|
|
1815
|
+
* answers 409 `another_channel_enabled`, and while another SESSION has the same account
|
|
1816
|
+
* enabled it answers 409 `account_enabled_elsewhere` (both say: turn that one off first).
|
|
1817
|
+
* A config whose secret is missing answers its channel's 400 `*_required`.
|
|
1566
1818
|
*/
|
|
1567
1819
|
interface MessagingBindingStateRequest {
|
|
1568
1820
|
enabled: boolean;
|
|
@@ -1589,11 +1841,145 @@ interface TelegramTestResponse {
|
|
|
1589
1841
|
latencyMs?: number;
|
|
1590
1842
|
/** The bot's `@username`, when the API reports one. */
|
|
1591
1843
|
botUsername?: string;
|
|
1844
|
+
/**
|
|
1845
|
+
* True when @BotFather's **Group Privacy** is ON for this bot, which is the default. In
|
|
1846
|
+
* every group where the bot is not an administrator it then receives only a command
|
|
1847
|
+
* addressed to it or a reply to one of its own messages — an ordinary sentence is never
|
|
1848
|
+
* delivered, so a binding that answers fine in a direct chat stays silent there. The
|
|
1849
|
+
* setting is account-wide and Telegram overrides it for a group the bot administers, so
|
|
1850
|
+
* this reports the setting and never the outcome in any particular group. Absent when the
|
|
1851
|
+
* API did not report the setting; never inferred.
|
|
1852
|
+
*/
|
|
1853
|
+
groupPrivacy?: boolean;
|
|
1592
1854
|
error?: string;
|
|
1593
1855
|
}
|
|
1856
|
+
/** POST …/messaging/qq/test — draft values; each omitted field falls back to the stored binding. */
|
|
1857
|
+
interface QQTestRequest {
|
|
1858
|
+
appId?: string;
|
|
1859
|
+
appSecret?: string;
|
|
1860
|
+
}
|
|
1861
|
+
/**
|
|
1862
|
+
* QQ credential-test outcome. There is no account label: the platform's only credential
|
|
1863
|
+
* call is the access-token exchange, which identifies nothing beyond the App ID that was
|
|
1864
|
+
* sent to it.
|
|
1865
|
+
*/
|
|
1866
|
+
interface QQTestResponse {
|
|
1867
|
+
ok: boolean;
|
|
1868
|
+
latencyMs?: number;
|
|
1869
|
+
error?: string;
|
|
1870
|
+
}
|
|
1871
|
+
/**
|
|
1872
|
+
* POST …/messaging/qq/scan — starts a scan-to-connect flow: the server registers a bind
|
|
1873
|
+
* task under a fresh AES key it keeps to itself, and answers with what the browser may
|
|
1874
|
+
* know. The key is absent from this type on purpose — it decrypts the App Secret, so it
|
|
1875
|
+
* never leaves the server (the same rule that keeps a stored secret from round-tripping).
|
|
1876
|
+
*/
|
|
1877
|
+
interface QQScanStartResponse {
|
|
1878
|
+
/** Opaque bind-task handle, passed back to the poll endpoint. */
|
|
1879
|
+
taskId: string;
|
|
1880
|
+
/** The URL to ENCODE into a QR code. It is opened by the QQ app, never fetched by the browser. */
|
|
1881
|
+
qrUrl: string;
|
|
1882
|
+
/** How often to poll, in milliseconds (the interval the protocol is designed around). */
|
|
1883
|
+
pollMs: number;
|
|
1884
|
+
}
|
|
1885
|
+
/**
|
|
1886
|
+
* POST …/messaging/qq/scan/poll — one step of the scan. `pending` means keep polling,
|
|
1887
|
+
* `expired` means start a new task and show a new QR, and `completed` means the server has
|
|
1888
|
+
* already decrypted the App Secret and SAVED the binding: `appId` names the bot that landed.
|
|
1889
|
+
* Saving is all it does — enabling the connection stays the separate, exclusive act it is on
|
|
1890
|
+
* every channel. A task id that is unknown, belongs to another Session, was already
|
|
1891
|
+
* resolved, or is being resolved by a poll still in flight answers 404
|
|
1892
|
+
* `qq_scan_task_unknown`: the task is claimed by one poll, so a client whose interval fires
|
|
1893
|
+
* before the previous request came back binds once rather than once per overlapping poll.
|
|
1894
|
+
*/
|
|
1895
|
+
interface QQScanPollResponse {
|
|
1896
|
+
status: "none" | "pending" | "completed" | "expired";
|
|
1897
|
+
/** The bound bot's App ID; present only on `completed`. Never the secret. */
|
|
1898
|
+
appId?: string;
|
|
1899
|
+
/** The saved binding, present on `completed` so the editor refreshes without a second GET. */
|
|
1900
|
+
binding?: QQBindingInfo;
|
|
1901
|
+
}
|
|
1902
|
+
/**
|
|
1903
|
+
* WeChat credential-test outcome. There is no request body and no draft to probe: this
|
|
1904
|
+
* channel's credential exists only where a scan put it, so the test always probes the STORED
|
|
1905
|
+
* binding. It answers 400 `wechat_token_required` when there is none.
|
|
1906
|
+
*
|
|
1907
|
+
* No account label, for the same reason QQ has none: the probe (`getconfig`) reports the
|
|
1908
|
+
* bot's settings and names neither the bot nor the person.
|
|
1909
|
+
*/
|
|
1910
|
+
interface WeChatTestResponse {
|
|
1911
|
+
ok: boolean;
|
|
1912
|
+
latencyMs?: number;
|
|
1913
|
+
error?: string;
|
|
1914
|
+
}
|
|
1915
|
+
/**
|
|
1916
|
+
* POST …/messaging/wechat/scan — starts a scan-to-connect flow, which on this channel is the
|
|
1917
|
+
* ONLY way to bind: the bot token has no console to be copied out of.
|
|
1918
|
+
*
|
|
1919
|
+
* The server registers a code and answers with what the browser may know. The platform's own
|
|
1920
|
+
* poll handle is absent from this type on purpose — it is what collects the bot token, so it
|
|
1921
|
+
* never leaves the server, and `taskId` is a handle this server mints in its place.
|
|
1922
|
+
*/
|
|
1923
|
+
interface WeChatScanStartResponse {
|
|
1924
|
+
/** Opaque scan handle, passed back to the poll, verify and cancel endpoints. */
|
|
1925
|
+
taskId: string;
|
|
1926
|
+
/** The URL to ENCODE into a QR code. It is opened by WeChat, never fetched by the browser. */
|
|
1927
|
+
qrUrl: string;
|
|
1928
|
+
/** How often to poll, in milliseconds. */
|
|
1929
|
+
pollMs: number;
|
|
1930
|
+
}
|
|
1931
|
+
/**
|
|
1932
|
+
* Where a WeChat scan stands. Richer than QQ's four states because the flow is: WeChat
|
|
1933
|
+
* separates scanning from confirming, and may interpose a pairing code shown on the phone.
|
|
1934
|
+
*
|
|
1935
|
+
* - `pending` — the code is up and nothing has happened; keep polling.
|
|
1936
|
+
* - `scanned` — scanned; the phone is showing the confirmation prompt.
|
|
1937
|
+
* - `need_verify_code` — the phone is showing digits that must be sent to the verify
|
|
1938
|
+
* endpoint before the bind proceeds.
|
|
1939
|
+
* - `blocked` — too many wrong pairing codes; the code is spent and a new scan is needed.
|
|
1940
|
+
* - `expired` — the code lapsed before it was used; show a new one.
|
|
1941
|
+
* - `already_bound` — this bot is already bound to this server, so no new credentials were
|
|
1942
|
+
* issued and nothing was saved. Not a failure: the existing binding still works.
|
|
1943
|
+
* - `completed` — the server has already SAVED the binding; `botId` names the bot.
|
|
1944
|
+
*/
|
|
1945
|
+
type WeChatScanStatus = "pending" | "scanned" | "need_verify_code" | "blocked" | "expired" | "already_bound" | "completed";
|
|
1946
|
+
/**
|
|
1947
|
+
* POST …/messaging/wechat/scan/poll — one step of the scan.
|
|
1948
|
+
*
|
|
1949
|
+
* `completed` means the server has decrypted nothing and stored everything: the credentials
|
|
1950
|
+
* went from the platform into storage without passing through the browser. Saving is all it
|
|
1951
|
+
* does — enabling the connection stays the separate, exclusive act it is on every channel. A
|
|
1952
|
+
* task id that is unknown, belongs to another Session, or was already resolved answers 404
|
|
1953
|
+
* `wechat_scan_task_unknown`.
|
|
1954
|
+
*
|
|
1955
|
+
* Unlike QQ's poll, an overlapping request answers `pending` rather than 404: the upstream
|
|
1956
|
+
* call is a LONG poll, so one of them spans several of the client's intervals, and that
|
|
1957
|
+
* overlap is the normal rhythm rather than a replay.
|
|
1958
|
+
*/
|
|
1959
|
+
interface WeChatScanPollResponse {
|
|
1960
|
+
status: WeChatScanStatus;
|
|
1961
|
+
/** The bound bot's id; present only on `completed`. Never the token. */
|
|
1962
|
+
botId?: string;
|
|
1963
|
+
/** The saved binding, present on `completed` so the editor refreshes without a second GET. */
|
|
1964
|
+
binding?: WeChatBindingInfo;
|
|
1965
|
+
}
|
|
1966
|
+
/**
|
|
1967
|
+
* POST …/messaging/wechat/scan/verify — the digits WeChat showed on the phone.
|
|
1968
|
+
*
|
|
1969
|
+
* They ride the NEXT poll rather than a request of their own, because the platform takes the
|
|
1970
|
+
* pairing code as a parameter of the status call: this endpoint records them and answers
|
|
1971
|
+
* 204. A wrong code is not reported here — the next poll asks for one again, which is how
|
|
1972
|
+
* the platform reports it.
|
|
1973
|
+
*/
|
|
1974
|
+
interface WeChatScanVerifyRequest {
|
|
1975
|
+
taskId: string;
|
|
1976
|
+
verifyCode: string;
|
|
1977
|
+
}
|
|
1594
1978
|
/**
|
|
1595
1979
|
* POST …/messaging/<channel>/test-message — sent to the last known chat (409
|
|
1596
|
-
* `feishu_no_chat` / `telegram_no_chat` before one exists).
|
|
1980
|
+
* `feishu_no_chat` / `telegram_no_chat` / `qq_no_chat` before one exists). On QQ this can
|
|
1981
|
+
* still fail with 502 afterwards: the platform accepts only replies to a message sent from
|
|
1982
|
+
* QQ minutes earlier, so a known chat does not mean a deliverable one.
|
|
1597
1983
|
*/
|
|
1598
1984
|
interface MessagingTestMessageResponse {
|
|
1599
1985
|
ok: true;
|
|
@@ -2144,6 +2530,29 @@ interface UsageModelSeries extends UsageEntitySeriesCounts {
|
|
|
2144
2530
|
provider: string;
|
|
2145
2531
|
modelId: string;
|
|
2146
2532
|
}
|
|
2533
|
+
/**
|
|
2534
|
+
* Lifetime Token total for one Model, keyed by the (provider, modelId) pair. Deliberately
|
|
2535
|
+
* unfiltered — no date range, no Agent: it answers "how much has this model been used", a
|
|
2536
|
+
* question with no window attached, and the models page that shows it carries no filters of its
|
|
2537
|
+
* own to honour. Models never used are absent rather than zero.
|
|
2538
|
+
*/
|
|
2539
|
+
interface UsageModelTotal {
|
|
2540
|
+
provider: string;
|
|
2541
|
+
modelId: string;
|
|
2542
|
+
/** The three buckets summed (cache read + cache write + output), matching the cost center's Token figure. */
|
|
2543
|
+
tokens: number;
|
|
2544
|
+
requests: number;
|
|
2545
|
+
}
|
|
2546
|
+
/** Response of `GET /usage/model-totals`. */
|
|
2547
|
+
interface UsageModelTotals {
|
|
2548
|
+
totals: UsageModelTotal[];
|
|
2549
|
+
}
|
|
2550
|
+
/**
|
|
2551
|
+
* The two categories an error record is filed under: `unexpected` is a 500 or an unforeseen
|
|
2552
|
+
* runtime exception, `expected` an HttpError / business 4xx. The panel separates them by
|
|
2553
|
+
* colour, and `GET /usage/errors` takes one of them as its `kind` filter.
|
|
2554
|
+
*/
|
|
2555
|
+
type UsageErrorKind = "unexpected" | "expected";
|
|
2147
2556
|
/** Occurrence count of an error for a given source · code (the "most common" metric in the stats center's error panel). */
|
|
2148
2557
|
interface UsageErrorCount {
|
|
2149
2558
|
source: string;
|
|
@@ -2169,6 +2578,15 @@ interface UsageErrorItem {
|
|
|
2169
2578
|
*/
|
|
2170
2579
|
interface UsageErrors {
|
|
2171
2580
|
total: number;
|
|
2581
|
+
/**
|
|
2582
|
+
* How many of {@link total} a clear would actually take (see {@link UsageErrorsClearResponse}).
|
|
2583
|
+
*
|
|
2584
|
+
* The same as `total` for an ordinary member, and smaller for an admin, whose reads include
|
|
2585
|
+
* unattributed rows that no Project-scoped clear removes. The confirmation is the only place
|
|
2586
|
+
* this matters, and it is the place it matters most: an irreversible delete has to name the
|
|
2587
|
+
* number that will really go, not the number on screen.
|
|
2588
|
+
*/
|
|
2589
|
+
clearable: number;
|
|
2172
2590
|
/** Count of unexpected ones (500 / runtime exceptions) among them — the part the frontend highlights. */
|
|
2173
2591
|
unexpected: number;
|
|
2174
2592
|
/** The most frequent source · code (null when there are no errors). */
|
|
@@ -2180,13 +2598,28 @@ interface UsageErrors {
|
|
|
2180
2598
|
* GET /api/projects/:projectId/usage/errors — one page of the error detail table, newest
|
|
2181
2599
|
* first. The dashboard response above already carries the first page; this exists so
|
|
2182
2600
|
* "show me earlier ones" does not have to refetch the whole aggregate. It takes the same
|
|
2183
|
-
* date/agent filter as the dashboard, so a page never widens what the summary counted
|
|
2601
|
+
* date/agent filter as the dashboard, so a page never widens what the summary counted, plus
|
|
2602
|
+
* an optional `kind` ({@link UsageErrorKind}) narrowing to one of the two categories — which
|
|
2603
|
+
* is how the cost-center badge asks "are there unexpected errors, and how new is the newest"
|
|
2604
|
+
* with `limit=1` instead of pulling the whole dashboard aggregate.
|
|
2184
2605
|
*/
|
|
2185
2606
|
interface UsageErrorsPage {
|
|
2186
2607
|
items: UsageErrorItem[];
|
|
2187
2608
|
/** Filtered row count, so the caller knows when it has reached the end. */
|
|
2188
2609
|
total: number;
|
|
2189
2610
|
}
|
|
2611
|
+
/**
|
|
2612
|
+
* DELETE /api/projects/:projectId/usage/errors — empties the error table for the filter the
|
|
2613
|
+
* panel is showing (its date range and Agent), Project owner only.
|
|
2614
|
+
*
|
|
2615
|
+
* Scoped to the filter rather than the Project's whole history, so a clear takes exactly the
|
|
2616
|
+
* rows on screen. Errors with no Project attribution are never included, whoever asks: they
|
|
2617
|
+
* belong to no Project and are surfaced in every Project's admin view.
|
|
2618
|
+
*/
|
|
2619
|
+
interface UsageErrorsClearResponse {
|
|
2620
|
+
/** How many rows were deleted, so the caller can say what went instead of guessing. */
|
|
2621
|
+
deleted: number;
|
|
2622
|
+
}
|
|
2190
2623
|
interface UsageResponse {
|
|
2191
2624
|
summary: {
|
|
2192
2625
|
today: UsageBucket;
|
|
@@ -2491,5 +2924,61 @@ interface UpdateRunResponse {
|
|
|
2491
2924
|
/** True when the install changed (or was already current): restart the service to run the new version. */
|
|
2492
2925
|
needsRestart: boolean;
|
|
2493
2926
|
}
|
|
2927
|
+
/** One `Host` entry of the server's `~/.ssh/config`, as the Machines page lists it. */
|
|
2928
|
+
interface MachineInfo {
|
|
2929
|
+
/** `ssh:<alias>` — the id the install route is asked for. */
|
|
2930
|
+
id: string;
|
|
2931
|
+
/**
|
|
2932
|
+
* The alias exactly as written in the config. The list is the config text and nothing
|
|
2933
|
+
* else — no `ssh -G`, no processes, no network — so a config declaring hundreds of hosts
|
|
2934
|
+
* costs one file read; an alias is resolved only when it is actually installed to.
|
|
2935
|
+
*/
|
|
2936
|
+
alias: string;
|
|
2937
|
+
/**
|
|
2938
|
+
* The last install THIS server carried out there, remembered on disk so it survives a
|
|
2939
|
+
* restart, a hot push, and installing on some other machine. Null when this server has
|
|
2940
|
+
* never installed there.
|
|
2941
|
+
*
|
|
2942
|
+
* A record of what was done, not a survey of the far side: a machine wiped by hand still
|
|
2943
|
+
* reads as installed until the next install probes it and corrects the record. Asking the
|
|
2944
|
+
* remote instead would cost an ssh round trip per host at page load, which is the price
|
|
2945
|
+
* the config-text list exists to avoid.
|
|
2946
|
+
*/
|
|
2947
|
+
installed: {
|
|
2948
|
+
version: string;
|
|
2949
|
+
at: string;
|
|
2950
|
+
} | null;
|
|
2951
|
+
}
|
|
2952
|
+
/**
|
|
2953
|
+
* The running or last install, polled by GET /api/machines while one runs. `log` carries the
|
|
2954
|
+
* far side's own words where there are any: ssh's diagnostics and the remote installer's
|
|
2955
|
+
* output say more about a refused key or an unusable Node than a paraphrase would.
|
|
2956
|
+
*/
|
|
2957
|
+
interface MachineInstallJob {
|
|
2958
|
+
machineId: string;
|
|
2959
|
+
alias: string;
|
|
2960
|
+
running: boolean;
|
|
2961
|
+
log: string[];
|
|
2962
|
+
result: null | {
|
|
2963
|
+
ok: true;
|
|
2964
|
+
kind: "installed" | "already-installed";
|
|
2965
|
+
version: string | null;
|
|
2966
|
+
} | {
|
|
2967
|
+
ok: false;
|
|
2968
|
+
step: string;
|
|
2969
|
+
message: string;
|
|
2970
|
+
};
|
|
2971
|
+
}
|
|
2972
|
+
/** GET /api/machines, and the 202 body of POST /api/machines/:machineId/install. */
|
|
2973
|
+
interface MachinesResponse {
|
|
2974
|
+
machines: MachineInfo[];
|
|
2975
|
+
/**
|
|
2976
|
+
* The version an install would leave on the remote — the base release, plus a `+hmr.<sha>`
|
|
2977
|
+
* suffix when this server carries a pushed version to replicate. Null for a development
|
|
2978
|
+
* checkout, which stands on no release the remote could download.
|
|
2979
|
+
*/
|
|
2980
|
+
imageVersion: string | null;
|
|
2981
|
+
job: MachineInstallJob | null;
|
|
2982
|
+
}
|
|
2494
2983
|
|
|
2495
|
-
export type { AdminPasswordResetRequest, AdminUserCreateRequest, AdminUserCreateResponse, AdminUsersResponse, AgentCompactionConfigDto, AgentConfigDto, AgentConfigResponse, AgentConfigUpdateRequest, AgentCreateRequest, AgentCreateResponse, AgentImportRequest, AgentImportResponse, AgentKernelUpdateResponse, AgentMemoryConfigDto, AgentModelConfigDto, AgentSchedulesConfigDto, AgentSkillsConfigDto, AgentSkillsResponse, AgentSummary, AgentTraceDateGroup, AgentTraceFileRef, AgentTraceSessionEntry, AgentTraceSessionFile, AgentTraceSessionGroup, AgentTracesResponse, AgentVaultConfigDto, AgentsResponse, ApprovalDecisionRequest, ApprovalMode, AuthLoginRequest, AuthResponse, BenchmarkCaseScore, BenchmarkCaseSummary, BenchmarkCasesResponse, BenchmarkEvaluation, BenchmarkRunScore, BenchmarkSummary, BenchmarksResponse, CaseMaterial, ChatDefaultsDto, CommandPolicyDto, CommandPolicyRuleDto, ContextToolShare, CredentialInfo, DefaultModelResponse, DefaultModelUpdateRequest, DesktopUpdateStatus, DesktopUpdateStatusResponse, DesktopUpdaterCommandMessage, DesktopUpdaterStatusMessage, DirEntryInfo, DirListResponse, DirectorySkillItem, DirectorySkillsResponse, DraftShortcut, EndpointModelListRequest, EndpointModelListResponse, ErrorBody, FeishuBindingInfo, FeishuBindingPutRequest, FeishuBindingResponse, FeishuTestRequest, FeishuTestResponse, FilesStatRequest, FilesStatResponse, GoalResponse, GoalServerEvent, GoalStateView, HistoryMessage, McpServerTestResponse, MeResponse, MemberAddRequest, MemberAddResponse, MemberInfo, MembersResponse, MemoryFileInfo, MemoryFileResponse, MemoryFilesResponse, MemoryImportMode, MemoryImportRequest, MemoryImportResponse, MemoryOverviewResponse, MemoryScopeExport, MemoryScopeInfo, MemoryTransferFile, MessagesLiveTail, MessagesPageInfo, MessagesResponse, MessagingBindingInfo, MessagingBindingStateRequest, MessagingBindingsResponse, MessagingChannel, MessagingChannelState, MessagingRuntimeState, MessagingRuntimeStatus, MessagingTestMessageResponse, ModelInfo, ModelOAuthCodeRequest, ModelOAuthCodeResponse, ModelOAuthErrorCode, ModelOAuthMode, ModelOAuthStartRequest, ModelOAuthStartResponse, ModelOAuthStatusResponse, ModelPricingDto, ModelProtocolDetectRequest, ModelProtocolDetectResponse, ModelProtocolProbeDto, ModelRefDto, ModelTestRequest, ModelTestResponse, ModelUpdateEntry, ModelVisionDetectRequest, ModelVisionDetectResponse, ModelVisionOutcome, ModelsResponse, ModelsUpdateRequest, PasswordChangeRequest, PendingFollowUpInfo, PendingSteeringInfo, PrefsResponse, ProjectCreateRequest, ProjectCreateResponse, ProjectRole, ProjectSummary, ProjectUpdateRequest, ProjectUpdateResponse, ProjectsResponse, ProtocolProbeOutcome, RecalledMessageResponse, RequestSpan, RetryNowResponse, ScheduleItem, ScheduleServerEvent, ScheduleStatus, ScheduleUpsertRequest, SchedulesResponse, ServerEvent, ServerSettings, ServerSettingsResponse, ServerSettingsUpdateRequest, SessionCategory, SessionCategoryCounts, SessionContextParts, SessionContextResponse, SessionCreateRequest, SessionCreateResponse, SessionForkRequest, SessionForkResponse, SessionInfo, SessionPatchRequest, SessionProcessInfo, SessionProcessesResponse, SessionResponse, SessionSource, SessionStatus, SessionTracesResponse, SessionsResponse, SkillArchiveInstallRequest, SkillGroupItem, SkillInstallRequest, SkillLibraryResponse, SkillMetadataItem, SteerRequest, SubagentMessageResponse, SubagentRuntimeInfo, TaskCreateRequest, TaskCreateResponse, TaskInputPart, TelegramBindingInfo, TelegramBindingPutRequest, TelegramBindingResponse, TelegramTestRequest, TelegramTestResponse, ToolCallSpan, TraceAnalysisResponse, TraceEventsResponse, TraceFileInfo, TraceImportRequest, TraceImportResponse, TraceModelSegment, TraceOtherSpan, TracePosition, TraceTaskStats, TraceToolSpan, UiPrefs, UpdateCheckResponse, UpdateRunResponse, UploadLimits, UsageAgentSeries, UsageBucket, UsageEntitySeriesCounts, UsageErrorCount, UsageErrorItem, UsageErrors, UsageErrorsPage, UsageGranularity, UsageGroupBy, UsageGroupRow, UsageModelSeries, UsageResponse, UsageSeriesPoint, UsageTrendPointInTrace, UserInfo, VaultEntryInfo, VaultEntryUpdate, VaultResponse, VaultUpdateRequest, VersionResponse, WorkspaceFileEntry, WorkspaceFilesResponse };
|
|
2984
|
+
export type { AdminPasswordResetRequest, AdminUserCreateRequest, AdminUserCreateResponse, AdminUsersResponse, AgentCompactionConfigDto, AgentConfigDto, AgentConfigResponse, AgentConfigUpdateRequest, AgentCreateRequest, AgentCreateResponse, AgentImportRequest, AgentImportResponse, AgentKernelUpdateResponse, AgentMemoryConfigDto, AgentModelConfigDto, AgentSchedulesConfigDto, AgentSkillsConfigDto, AgentSkillsResponse, AgentSummary, AgentTraceDateGroup, AgentTraceFileRef, AgentTraceSessionEntry, AgentTraceSessionFile, AgentTraceSessionGroup, AgentTracesResponse, AgentVaultConfigDto, AgentsResponse, ApprovalDecisionRequest, ApprovalMode, AuthLoginRequest, AuthResponse, BenchmarkCaseScore, BenchmarkCaseSummary, BenchmarkCasesResponse, BenchmarkEvaluation, BenchmarkRunScore, BenchmarkSummary, BenchmarksResponse, CaseMaterial, ChatDefaultsDto, CommandPolicyDto, CommandPolicyRuleDto, ContextToolShare, CredentialInfo, DefaultModelResponse, DefaultModelUpdateRequest, DesktopUpdateStatus, DesktopUpdateStatusResponse, DesktopUpdaterCommandMessage, DesktopUpdaterStatusMessage, DirEntryInfo, DirListResponse, DirectorySkillItem, DirectorySkillsResponse, DraftShortcut, EndpointModelListRequest, EndpointModelListResponse, ErrorBody, FeishuBindingInfo, FeishuBindingPutRequest, FeishuBindingResponse, FeishuTestRequest, FeishuTestResponse, FilesStatRequest, FilesStatResponse, GoalResponse, GoalServerEvent, GoalStateView, HistoryMessage, InstallResponse, MachineInfo, MachineInstallJob, MachinesResponse, McpServerTestResponse, MeResponse, MemberAddRequest, MemberAddResponse, MemberInfo, MembersResponse, MemoryFileInfo, MemoryFileResponse, MemoryFilesResponse, MemoryImportMode, MemoryImportRequest, MemoryImportResponse, MemoryOverviewResponse, MemoryScopeExport, MemoryScopeInfo, MemoryTransferFile, MessagesLiveTail, MessagesPageInfo, MessagesResponse, MessagingBindingCommon, MessagingBindingInfo, MessagingBindingStateRequest, MessagingBindingsResponse, MessagingChannel, MessagingChannelState, MessagingDeliveryError, MessagingDeliveryPatch, MessagingRuntimeState, MessagingRuntimeStatus, MessagingTestMessageResponse, ModelInfo, ModelOAuthCodeRequest, ModelOAuthCodeResponse, ModelOAuthErrorCode, ModelOAuthMode, ModelOAuthStartRequest, ModelOAuthStartResponse, ModelOAuthStatusResponse, ModelPricingDto, ModelProtocolDetectRequest, ModelProtocolDetectResponse, ModelProtocolProbeDto, ModelRefDto, ModelTestRequest, ModelTestResponse, ModelUpdateEntry, ModelVisionDetectRequest, ModelVisionDetectResponse, ModelVisionOutcome, ModelsResponse, ModelsUpdateRequest, PasswordChangeRequest, PendingFollowUpInfo, PendingSteeringInfo, PrefsResponse, ProjectCreateRequest, ProjectCreateResponse, ProjectRole, ProjectSummary, ProjectUpdateRequest, ProjectUpdateResponse, ProjectsResponse, ProtocolProbeOutcome, QQBindingInfo, QQBindingPutRequest, QQBindingResponse, QQScanPollResponse, QQScanStartResponse, QQTestRequest, QQTestResponse, RecalledMessageResponse, RequestSpan, RetryNowResponse, ScheduleItem, ScheduleServerEvent, ScheduleStatus, ScheduleUpsertRequest, SchedulesResponse, ServerEvent, ServerSettings, ServerSettingsResponse, ServerSettingsUpdateRequest, SessionCategory, SessionCategoryCounts, SessionContextParts, SessionContextResponse, SessionCreateRequest, SessionCreateResponse, SessionForkRequest, SessionForkResponse, SessionInfo, SessionPatchRequest, SessionProcessInfo, SessionProcessesResponse, SessionResponse, SessionSource, SessionStatus, SessionTracesResponse, SessionsResponse, SkillArchiveInstallRequest, SkillGroupItem, SkillInstallRequest, SkillLibraryResponse, SkillMetadataItem, SkillUpdateRef, SteerRequest, SubagentMessageResponse, SubagentRuntimeInfo, TaskCreateRequest, TaskCreateResponse, TaskInputPart, TelegramBindingInfo, TelegramBindingPutRequest, TelegramBindingResponse, TelegramTestRequest, TelegramTestResponse, ToolCallSpan, TraceAnalysisResponse, TraceEventsResponse, TraceFileInfo, TraceImportRequest, TraceImportResponse, TraceModelSegment, TraceOtherSpan, TracePosition, TraceTaskStats, TraceToolSpan, UiPrefs, UpdateCheckResponse, UpdateRunResponse, UploadLimits, UsageAgentSeries, UsageBucket, UsageEntitySeriesCounts, UsageErrorCount, UsageErrorItem, UsageErrorKind, UsageErrors, UsageErrorsClearResponse, UsageErrorsPage, UsageGranularity, UsageGroupBy, UsageGroupRow, UsageModelSeries, UsageModelTotal, UsageModelTotals, UsageResponse, UsageSeriesPoint, UsageTrendPointInTrace, UserInfo, VaultEntryInfo, VaultEntryUpdate, VaultResponse, VaultUpdateRequest, VersionResponse, WeChatBindingInfo, WeChatBindingPutRequest, WeChatBindingResponse, WeChatScanPollResponse, WeChatScanStartResponse, WeChatScanStatus, WeChatScanVerifyRequest, WeChatTestResponse, WorkspaceFileEntry, WorkspaceFilesResponse };
|