@kyan-du/agent-wechat-cli 0.13.3 → 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 +6 -5
- package/dist/cli.js +1187 -120
- package/dist/image-compatibility.json +1 -1
- package/package.json +3 -2
package/dist/cli.js
CHANGED
|
@@ -1199,8 +1199,8 @@ var require_command = __commonJS({
|
|
|
1199
1199
|
"../../node_modules/.pnpm/commander@14.0.3/node_modules/commander/lib/command.js"(exports) {
|
|
1200
1200
|
var EventEmitter = __require("node:events").EventEmitter;
|
|
1201
1201
|
var childProcess = __require("node:child_process");
|
|
1202
|
-
var
|
|
1203
|
-
var
|
|
1202
|
+
var path6 = __require("node:path");
|
|
1203
|
+
var fs6 = __require("node:fs");
|
|
1204
1204
|
var process2 = __require("node:process");
|
|
1205
1205
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
1206
1206
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -2194,7 +2194,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2194
2194
|
* @param {string} subcommandName
|
|
2195
2195
|
*/
|
|
2196
2196
|
_checkForMissingExecutable(executableFile, executableDir, subcommandName) {
|
|
2197
|
-
if (
|
|
2197
|
+
if (fs6.existsSync(executableFile)) return;
|
|
2198
2198
|
const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
|
|
2199
2199
|
const executableMissing = `'${executableFile}' does not exist
|
|
2200
2200
|
- if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
|
|
@@ -2212,11 +2212,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2212
2212
|
let launchWithNode = false;
|
|
2213
2213
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
2214
2214
|
function findFile(baseDir, baseName) {
|
|
2215
|
-
const localBin =
|
|
2216
|
-
if (
|
|
2217
|
-
if (sourceExt.includes(
|
|
2215
|
+
const localBin = path6.resolve(baseDir, baseName);
|
|
2216
|
+
if (fs6.existsSync(localBin)) return localBin;
|
|
2217
|
+
if (sourceExt.includes(path6.extname(baseName))) return void 0;
|
|
2218
2218
|
const foundExt = sourceExt.find(
|
|
2219
|
-
(ext) =>
|
|
2219
|
+
(ext) => fs6.existsSync(`${localBin}${ext}`)
|
|
2220
2220
|
);
|
|
2221
2221
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
2222
2222
|
return void 0;
|
|
@@ -2228,21 +2228,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2228
2228
|
if (this._scriptPath) {
|
|
2229
2229
|
let resolvedScriptPath;
|
|
2230
2230
|
try {
|
|
2231
|
-
resolvedScriptPath =
|
|
2231
|
+
resolvedScriptPath = fs6.realpathSync(this._scriptPath);
|
|
2232
2232
|
} catch {
|
|
2233
2233
|
resolvedScriptPath = this._scriptPath;
|
|
2234
2234
|
}
|
|
2235
|
-
executableDir =
|
|
2236
|
-
|
|
2235
|
+
executableDir = path6.resolve(
|
|
2236
|
+
path6.dirname(resolvedScriptPath),
|
|
2237
2237
|
executableDir
|
|
2238
2238
|
);
|
|
2239
2239
|
}
|
|
2240
2240
|
if (executableDir) {
|
|
2241
2241
|
let localFile = findFile(executableDir, executableFile);
|
|
2242
2242
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
2243
|
-
const legacyName =
|
|
2243
|
+
const legacyName = path6.basename(
|
|
2244
2244
|
this._scriptPath,
|
|
2245
|
-
|
|
2245
|
+
path6.extname(this._scriptPath)
|
|
2246
2246
|
);
|
|
2247
2247
|
if (legacyName !== this._name) {
|
|
2248
2248
|
localFile = findFile(
|
|
@@ -2253,7 +2253,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2253
2253
|
}
|
|
2254
2254
|
executableFile = localFile || executableFile;
|
|
2255
2255
|
}
|
|
2256
|
-
launchWithNode = sourceExt.includes(
|
|
2256
|
+
launchWithNode = sourceExt.includes(path6.extname(executableFile));
|
|
2257
2257
|
let proc;
|
|
2258
2258
|
if (process2.platform !== "win32") {
|
|
2259
2259
|
if (launchWithNode) {
|
|
@@ -3055,9 +3055,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3055
3055
|
* @param {string[]} [aliases]
|
|
3056
3056
|
* @return {(string[]|Command)}
|
|
3057
3057
|
*/
|
|
3058
|
-
aliases(
|
|
3059
|
-
if (
|
|
3060
|
-
|
|
3058
|
+
aliases(aliases2) {
|
|
3059
|
+
if (aliases2 === void 0) return this._aliases;
|
|
3060
|
+
aliases2.forEach((alias) => this.alias(alias));
|
|
3061
3061
|
return this;
|
|
3062
3062
|
}
|
|
3063
3063
|
/**
|
|
@@ -3168,7 +3168,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3168
3168
|
* @return {Command}
|
|
3169
3169
|
*/
|
|
3170
3170
|
nameFromFilename(filename) {
|
|
3171
|
-
this._name =
|
|
3171
|
+
this._name = path6.basename(filename, path6.extname(filename));
|
|
3172
3172
|
return this;
|
|
3173
3173
|
}
|
|
3174
3174
|
/**
|
|
@@ -3182,9 +3182,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3182
3182
|
* @param {string} [path]
|
|
3183
3183
|
* @return {(string|null|Command)}
|
|
3184
3184
|
*/
|
|
3185
|
-
executableDir(
|
|
3186
|
-
if (
|
|
3187
|
-
this._executableDir =
|
|
3185
|
+
executableDir(path7) {
|
|
3186
|
+
if (path7 === void 0) return this._executableDir;
|
|
3187
|
+
this._executableDir = path7;
|
|
3188
3188
|
return this;
|
|
3189
3189
|
}
|
|
3190
3190
|
/**
|
|
@@ -3482,9 +3482,9 @@ var {
|
|
|
3482
3482
|
// src/cli.ts
|
|
3483
3483
|
import { execFileSync as execFileSync3, spawn } from "node:child_process";
|
|
3484
3484
|
import { createHash, randomBytes as randomBytes2 } from "node:crypto";
|
|
3485
|
-
import
|
|
3485
|
+
import fs5 from "node:fs";
|
|
3486
3486
|
import os2 from "node:os";
|
|
3487
|
-
import
|
|
3487
|
+
import path5 from "node:path";
|
|
3488
3488
|
import readline from "node:readline/promises";
|
|
3489
3489
|
import { fileURLToPath } from "node:url";
|
|
3490
3490
|
import qrTerminal from "qrcode-terminal";
|
|
@@ -3967,8 +3967,8 @@ function getErrorMap() {
|
|
|
3967
3967
|
|
|
3968
3968
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
3969
3969
|
var makeIssue = (params) => {
|
|
3970
|
-
const { data, path:
|
|
3971
|
-
const fullPath = [...
|
|
3970
|
+
const { data, path: path6, errorMaps, issueData } = params;
|
|
3971
|
+
const fullPath = [...path6, ...issueData.path || []];
|
|
3972
3972
|
const fullIssue = {
|
|
3973
3973
|
...issueData,
|
|
3974
3974
|
path: fullPath
|
|
@@ -4084,11 +4084,11 @@ var errorUtil;
|
|
|
4084
4084
|
|
|
4085
4085
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
4086
4086
|
var ParseInputLazyPath = class {
|
|
4087
|
-
constructor(parent, value,
|
|
4087
|
+
constructor(parent, value, path6, key) {
|
|
4088
4088
|
this._cachedPath = [];
|
|
4089
4089
|
this.parent = parent;
|
|
4090
4090
|
this.data = value;
|
|
4091
|
-
this._path =
|
|
4091
|
+
this._path = path6;
|
|
4092
4092
|
this._key = key;
|
|
4093
4093
|
}
|
|
4094
4094
|
get path() {
|
|
@@ -7585,6 +7585,23 @@ var chatSchema = external_exports.object({
|
|
|
7585
7585
|
unreadCount: external_exports.number().int().nonnegative(),
|
|
7586
7586
|
isGroup: external_exports.boolean()
|
|
7587
7587
|
});
|
|
7588
|
+
var groupMemberSchema = external_exports.object({
|
|
7589
|
+
memberId: external_exports.string().min(1),
|
|
7590
|
+
displayName: external_exports.string().min(1),
|
|
7591
|
+
groupAlias: external_exports.string().optional(),
|
|
7592
|
+
nickName: external_exports.string().optional()
|
|
7593
|
+
});
|
|
7594
|
+
var groupMembersPageSchema = external_exports.object({
|
|
7595
|
+
schemaVersion: external_exports.literal(1),
|
|
7596
|
+
items: external_exports.array(groupMemberSchema),
|
|
7597
|
+
nextCursor: external_exports.string().nullable().optional(),
|
|
7598
|
+
errorCode: external_exports.string().optional()
|
|
7599
|
+
});
|
|
7600
|
+
var listGroupMembersParamsSchema = external_exports.object({
|
|
7601
|
+
groupId: external_exports.string().endsWith("@chatroom"),
|
|
7602
|
+
limit: external_exports.number().int().positive().max(100).optional().default(50),
|
|
7603
|
+
cursor: external_exports.string().optional()
|
|
7604
|
+
});
|
|
7588
7605
|
var listChatsParamsSchema = external_exports.object({
|
|
7589
7606
|
limit: external_exports.number().int().positive().max(100).optional().default(50),
|
|
7590
7607
|
offset: external_exports.number().int().nonnegative().optional().default(0)
|
|
@@ -7611,6 +7628,22 @@ var openChatResultSchema = external_exports.object({
|
|
|
7611
7628
|
error: external_exports.string().optional()
|
|
7612
7629
|
});
|
|
7613
7630
|
var idempotencyKeySchema = external_exports.string().min(1).max(128).regex(/^[A-Za-z0-9._:-]+$/);
|
|
7631
|
+
var forwardedMessageNodeSchema = external_exports.lazy(() => external_exports.object({
|
|
7632
|
+
sender: external_exports.string().optional(),
|
|
7633
|
+
senderId: external_exports.string().optional(),
|
|
7634
|
+
timestamp: external_exports.string().optional(),
|
|
7635
|
+
text: external_exports.string().optional(),
|
|
7636
|
+
messageType: external_exports.number().int().optional(),
|
|
7637
|
+
media: external_exports.string().optional(),
|
|
7638
|
+
children: external_exports.array(forwardedMessageNodeSchema),
|
|
7639
|
+
truncated: external_exports.boolean()
|
|
7640
|
+
}));
|
|
7641
|
+
var forwardedMessageTreeSchema = external_exports.object({
|
|
7642
|
+
schemaVersion: external_exports.number().int(),
|
|
7643
|
+
title: external_exports.string().optional(),
|
|
7644
|
+
nodes: external_exports.array(forwardedMessageNodeSchema),
|
|
7645
|
+
truncated: external_exports.boolean()
|
|
7646
|
+
});
|
|
7614
7647
|
var messageSchema = external_exports.object({
|
|
7615
7648
|
localId: external_exports.number().int(),
|
|
7616
7649
|
serverId: external_exports.number(),
|
|
@@ -7619,7 +7652,26 @@ var messageSchema = external_exports.object({
|
|
|
7619
7652
|
senderName: external_exports.string().optional(),
|
|
7620
7653
|
type: external_exports.number().int(),
|
|
7621
7654
|
content: external_exports.string(),
|
|
7622
|
-
timestamp: external_exports.string()
|
|
7655
|
+
timestamp: external_exports.string(),
|
|
7656
|
+
forwarded: forwardedMessageTreeSchema.optional()
|
|
7657
|
+
});
|
|
7658
|
+
var mediaReferenceSchema = external_exports.object({
|
|
7659
|
+
localId: external_exports.number().int(),
|
|
7660
|
+
url: external_exports.string().min(1)
|
|
7661
|
+
});
|
|
7662
|
+
var syncReadStateSchema = external_exports.object({
|
|
7663
|
+
unreadCount: external_exports.number().int().nonnegative(),
|
|
7664
|
+
observedAt: external_exports.string().min(1)
|
|
7665
|
+
});
|
|
7666
|
+
var chatSyncPageSchema = external_exports.object({
|
|
7667
|
+
schemaVersion: external_exports.literal(1),
|
|
7668
|
+
chat: chatSchema.optional(),
|
|
7669
|
+
items: external_exports.array(messageSchema),
|
|
7670
|
+
nextCursor: external_exports.string().optional().nullable(),
|
|
7671
|
+
syncToken: external_exports.string(),
|
|
7672
|
+
readState: syncReadStateSchema,
|
|
7673
|
+
media: external_exports.array(mediaReferenceSchema),
|
|
7674
|
+
errorCode: external_exports.string().optional()
|
|
7623
7675
|
});
|
|
7624
7676
|
var listMessagesParamsSchema = external_exports.object({
|
|
7625
7677
|
chatId: external_exports.string().min(1),
|
|
@@ -7645,6 +7697,31 @@ var sendParamsSchema = external_exports.object({
|
|
|
7645
7697
|
source: external_exports.string().min(1).max(64).regex(/^[A-Za-z0-9._:-]+$/).optional(),
|
|
7646
7698
|
similarityConfirmed: external_exports.boolean().optional()
|
|
7647
7699
|
});
|
|
7700
|
+
var deliveryStateSchema = external_exports.enum(["queued", "composing", "submitted", "observed_in_chat", "confirmed", "uncertain", "failed"]);
|
|
7701
|
+
var deliveryCauseSchema = external_exports.enum(["send_accepted", "target_sender_and_payload_match", "observation_confirmed", "target_mismatch", "sender_unverified", "payload_mismatch", "pre_commit_failure", "post_commit_uncertain"]);
|
|
7702
|
+
var deliveryTransitionSchema = external_exports.object({ from: deliveryStateSchema, to: deliveryStateSchema, at: external_exports.string().datetime(), reason: deliveryCauseSchema });
|
|
7703
|
+
var deliveryObservationSchema = external_exports.object({
|
|
7704
|
+
chatId: external_exports.string().trim().min(1).max(512),
|
|
7705
|
+
localId: external_exports.number().int().nonnegative().safe(),
|
|
7706
|
+
serverId: external_exports.number().int().nonnegative().safe(),
|
|
7707
|
+
timestamp: external_exports.string().datetime(),
|
|
7708
|
+
type: external_exports.number().int().nonnegative().safe(),
|
|
7709
|
+
sender: external_exports.string().trim().min(1).max(512),
|
|
7710
|
+
content: external_exports.string().max(1e6)
|
|
7711
|
+
}).strict();
|
|
7712
|
+
var deliveryAttemptSchema = external_exports.object({
|
|
7713
|
+
schemaVersion: external_exports.literal(1),
|
|
7714
|
+
idempotencyKey: idempotencyKeySchema.optional(),
|
|
7715
|
+
senderId: external_exports.string().trim().min(1).max(512),
|
|
7716
|
+
targetChatId: external_exports.string().trim().min(1).max(512),
|
|
7717
|
+
payloadDigest: external_exports.string().regex(/^[a-f0-9]{64}$/),
|
|
7718
|
+
state: deliveryStateSchema,
|
|
7719
|
+
commitAttempted: external_exports.boolean(),
|
|
7720
|
+
createdAt: external_exports.string().datetime(),
|
|
7721
|
+
updatedAt: external_exports.string().datetime(),
|
|
7722
|
+
observedLocalId: external_exports.number().int().nonnegative().optional(),
|
|
7723
|
+
transitions: external_exports.array(deliveryTransitionSchema).max(32)
|
|
7724
|
+
});
|
|
7648
7725
|
var sendResultSchema = external_exports.object({
|
|
7649
7726
|
success: external_exports.boolean(),
|
|
7650
7727
|
messageId: external_exports.string().optional(),
|
|
@@ -7657,11 +7734,13 @@ var getMediaParamsSchema = external_exports.object({
|
|
|
7657
7734
|
localId: external_exports.number().int()
|
|
7658
7735
|
});
|
|
7659
7736
|
var mediaResultSchema = external_exports.object({
|
|
7660
|
-
type: external_exports.enum(["image", "emoji", "voice", "video", "unsupported"]),
|
|
7737
|
+
type: external_exports.enum(["image", "emoji", "file", "voice", "video", "pending", "unsupported"]),
|
|
7661
7738
|
data: external_exports.string().optional(),
|
|
7662
7739
|
url: external_exports.string().optional(),
|
|
7663
7740
|
format: external_exports.string(),
|
|
7664
|
-
filename: external_exports.string()
|
|
7741
|
+
filename: external_exports.string(),
|
|
7742
|
+
source: external_exports.enum(["original", "thumbnail"]).optional(),
|
|
7743
|
+
errorCode: external_exports.string().optional()
|
|
7665
7744
|
});
|
|
7666
7745
|
var agentConfigSchema = external_exports.object({
|
|
7667
7746
|
maxTurns: external_exports.number().int().positive().default(30),
|
|
@@ -7726,16 +7805,16 @@ var WeChatClient = class {
|
|
|
7726
7805
|
return this.base;
|
|
7727
7806
|
}
|
|
7728
7807
|
// ---- internal helpers ----
|
|
7729
|
-
async get(
|
|
7730
|
-
const res = await fetch(`${this.base}${
|
|
7808
|
+
async get(path6) {
|
|
7809
|
+
const res = await fetch(`${this.base}${path6}`, {
|
|
7731
7810
|
headers: this.headers
|
|
7732
7811
|
});
|
|
7733
7812
|
if (!res.ok)
|
|
7734
7813
|
await throwHttpError(res);
|
|
7735
7814
|
return res.json();
|
|
7736
7815
|
}
|
|
7737
|
-
async post(
|
|
7738
|
-
const res = await fetch(`${this.base}${
|
|
7816
|
+
async post(path6, body) {
|
|
7817
|
+
const res = await fetch(`${this.base}${path6}`, {
|
|
7739
7818
|
method: "POST",
|
|
7740
7819
|
headers: this.headers,
|
|
7741
7820
|
body: body != null ? JSON.stringify(body) : void 0
|
|
@@ -7786,6 +7865,12 @@ var WeChatClient = class {
|
|
|
7786
7865
|
async openChat(chatId, clearUnreads) {
|
|
7787
7866
|
return this.post(`/api/chats/${encodeURIComponent(chatId)}/open${qs({ clearUnreads })}`);
|
|
7788
7867
|
}
|
|
7868
|
+
async listGroupMembersPage(groupId, limit, cursor) {
|
|
7869
|
+
const page = groupMembersPageSchema.parse(await this.get(`/api/groups/${encodeURIComponent(groupId)}/members${qs({ limit, cursor })}`));
|
|
7870
|
+
if (page.errorCode)
|
|
7871
|
+
throw new WeChatHttpError(400, "Bad Request", page.errorCode, page.errorCode);
|
|
7872
|
+
return { ...page, nextCursor: page.nextCursor ?? void 0 };
|
|
7873
|
+
}
|
|
7789
7874
|
// ---- Contacts ----
|
|
7790
7875
|
async listContactsPage(limit, cursor) {
|
|
7791
7876
|
const page = await this.get(`/api/contacts${qs({ limit, cursor })}`);
|
|
@@ -7809,6 +7894,17 @@ var WeChatClient = class {
|
|
|
7809
7894
|
async listMessages(chatId, limit) {
|
|
7810
7895
|
return (await this.listMessagesPage(chatId, limit)).items;
|
|
7811
7896
|
}
|
|
7897
|
+
async syncChat(chatId, options = {}) {
|
|
7898
|
+
const raw = await this.get(`/api/sync/${encodeURIComponent(chatId)}${qs({ limit: options.limit, cursor: options.cursor, since: options.since, from: options.from, to: options.to })}`);
|
|
7899
|
+
if (raw && typeof raw === "object" && typeof raw.errorCode === "string") {
|
|
7900
|
+
const errorCode = raw.errorCode;
|
|
7901
|
+
throw new WeChatHttpError(400, "Bad Request", errorCode, errorCode);
|
|
7902
|
+
}
|
|
7903
|
+
const page = chatSyncPageSchema.parse(raw);
|
|
7904
|
+
if (page.errorCode)
|
|
7905
|
+
throw new WeChatHttpError(400, "Bad Request", page.errorCode, page.errorCode);
|
|
7906
|
+
return { ...page, nextCursor: page.nextCursor ?? void 0 };
|
|
7907
|
+
}
|
|
7812
7908
|
async getMedia(chatId, localId) {
|
|
7813
7909
|
return this.get(`/api/messages/${encodeURIComponent(chatId)}/media/${localId}`);
|
|
7814
7910
|
}
|
|
@@ -8178,9 +8274,8 @@ function buildDockerRunArgs(identity, opts) {
|
|
|
8178
8274
|
"-e",
|
|
8179
8275
|
`AGENT_WECHAT_MAC=${identity.mac}`
|
|
8180
8276
|
];
|
|
8181
|
-
if (opts.proxy) {
|
|
8182
|
-
|
|
8183
|
-
}
|
|
8277
|
+
if (opts.proxy) args.push("-e", `PROXY=${opts.proxy}`);
|
|
8278
|
+
for (const [key, value] of Object.entries(opts.outbound ?? {})) args.push("-e", `${key}=${value}`);
|
|
8184
8279
|
args.push(opts.image);
|
|
8185
8280
|
return args;
|
|
8186
8281
|
}
|
|
@@ -8210,17 +8305,18 @@ function buildCliSendParams(options) {
|
|
|
8210
8305
|
var FORK_IMAGE = "ghcr.io/kyan-du/agent-wechat";
|
|
8211
8306
|
var VERSION_TAG = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?$/;
|
|
8212
8307
|
var DIGEST = /^sha256:[0-9a-f]{64}$/;
|
|
8308
|
+
var COMMIT_TAG = /^[a-f0-9]{7}$/;
|
|
8213
8309
|
function validatePublishedImageReference(reference) {
|
|
8214
8310
|
const tagPrefix = `${FORK_IMAGE}:`;
|
|
8215
8311
|
const digestPrefix = `${FORK_IMAGE}@`;
|
|
8216
|
-
if (reference.startsWith(tagPrefix) && VERSION_TAG.test(reference.slice(tagPrefix.length))) {
|
|
8312
|
+
if (reference.startsWith(tagPrefix) && (VERSION_TAG.test(reference.slice(tagPrefix.length)) || COMMIT_TAG.test(reference.slice(tagPrefix.length)))) {
|
|
8217
8313
|
return reference;
|
|
8218
8314
|
}
|
|
8219
8315
|
if (reference.startsWith(digestPrefix) && DIGEST.test(reference.slice(digestPrefix.length))) {
|
|
8220
8316
|
return reference;
|
|
8221
8317
|
}
|
|
8222
8318
|
throw new Error(
|
|
8223
|
-
`Invalid image reference. Use ${FORK_IMAGE}:<semver
|
|
8319
|
+
`Invalid image reference. Use ${FORK_IMAGE}:<semver>, ${FORK_IMAGE}:<7-character commit SHA>, or ${FORK_IMAGE}@sha256:<64 lowercase hex characters>.`
|
|
8224
8320
|
);
|
|
8225
8321
|
}
|
|
8226
8322
|
function localBuildImage(platform = process.platform, arch = process.arch) {
|
|
@@ -8326,8 +8422,8 @@ function assertSafePurgePath(target, root) {
|
|
|
8326
8422
|
|
|
8327
8423
|
// src/lifecycle.ts
|
|
8328
8424
|
import { execFileSync } from "node:child_process";
|
|
8329
|
-
import
|
|
8330
|
-
import
|
|
8425
|
+
import fs4 from "node:fs";
|
|
8426
|
+
import path4 from "node:path";
|
|
8331
8427
|
|
|
8332
8428
|
// src/exit-contract.ts
|
|
8333
8429
|
var EXIT = {
|
|
@@ -8369,47 +8465,910 @@ function failure(error) {
|
|
|
8369
8465
|
};
|
|
8370
8466
|
}
|
|
8371
8467
|
|
|
8372
|
-
// src/
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8468
|
+
// src/outbound-config.ts
|
|
8469
|
+
import fs3 from "node:fs";
|
|
8470
|
+
import path3 from "node:path";
|
|
8471
|
+
|
|
8472
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/error.js
|
|
8473
|
+
function getLineColFromPtr(string, ptr) {
|
|
8474
|
+
let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
|
|
8475
|
+
return [lines.length, lines.pop().length + 1];
|
|
8476
|
+
}
|
|
8477
|
+
function makeCodeBlock(string, line, column) {
|
|
8478
|
+
let lines = string.split(/\r\n|\n|\r/g);
|
|
8479
|
+
let codeblock = "";
|
|
8480
|
+
let numberLen = (Math.log10(line + 1) | 0) + 1;
|
|
8481
|
+
for (let i = line - 1; i <= line + 1; i++) {
|
|
8482
|
+
let l = lines[i - 1];
|
|
8483
|
+
if (!l)
|
|
8484
|
+
continue;
|
|
8485
|
+
codeblock += i.toString().padEnd(numberLen, " ");
|
|
8486
|
+
codeblock += ": ";
|
|
8487
|
+
codeblock += l;
|
|
8488
|
+
codeblock += "\n";
|
|
8489
|
+
if (i === line) {
|
|
8490
|
+
codeblock += " ".repeat(numberLen + column + 2);
|
|
8491
|
+
codeblock += "^\n";
|
|
8492
|
+
}
|
|
8493
|
+
}
|
|
8494
|
+
return codeblock;
|
|
8495
|
+
}
|
|
8496
|
+
var TomlError = class extends Error {
|
|
8497
|
+
line;
|
|
8498
|
+
column;
|
|
8499
|
+
codeblock;
|
|
8500
|
+
constructor(message, options) {
|
|
8501
|
+
const [line, column] = getLineColFromPtr(options.toml, options.ptr);
|
|
8502
|
+
const codeblock = makeCodeBlock(options.toml, line, column);
|
|
8503
|
+
super(`Invalid TOML document: ${message}
|
|
8504
|
+
|
|
8505
|
+
${codeblock}`, options);
|
|
8506
|
+
this.line = line;
|
|
8507
|
+
this.column = column;
|
|
8508
|
+
this.codeblock = codeblock;
|
|
8509
|
+
}
|
|
8510
|
+
};
|
|
8511
|
+
|
|
8512
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/util.js
|
|
8513
|
+
function isEscaped(str, ptr) {
|
|
8514
|
+
let i = 0;
|
|
8515
|
+
while (str[ptr - ++i] === "\\")
|
|
8516
|
+
;
|
|
8517
|
+
return --i && i % 2;
|
|
8518
|
+
}
|
|
8519
|
+
function indexOfNewline(str, start = 0, end = str.length) {
|
|
8520
|
+
let idx = str.indexOf("\n", start);
|
|
8521
|
+
if (str[idx - 1] === "\r")
|
|
8522
|
+
idx--;
|
|
8523
|
+
return idx <= end ? idx : -1;
|
|
8524
|
+
}
|
|
8525
|
+
function skipComment(str, ptr) {
|
|
8526
|
+
for (let i = ptr; i < str.length; i++) {
|
|
8527
|
+
let c = str[i];
|
|
8528
|
+
if (c === "\n")
|
|
8529
|
+
return i;
|
|
8530
|
+
if (c === "\r" && str[i + 1] === "\n")
|
|
8531
|
+
return i + 1;
|
|
8532
|
+
if (c < " " && c !== " " || c === "\x7F") {
|
|
8533
|
+
throw new TomlError("control characters are not allowed in comments", {
|
|
8534
|
+
toml: str,
|
|
8535
|
+
ptr
|
|
8536
|
+
});
|
|
8537
|
+
}
|
|
8538
|
+
}
|
|
8539
|
+
return str.length;
|
|
8540
|
+
}
|
|
8541
|
+
function skipVoid(str, ptr, banNewLines, banComments) {
|
|
8542
|
+
let c;
|
|
8543
|
+
while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n"))
|
|
8544
|
+
ptr++;
|
|
8545
|
+
return banComments || c !== "#" ? ptr : skipVoid(str, skipComment(str, ptr), banNewLines);
|
|
8546
|
+
}
|
|
8547
|
+
function skipUntil(str, ptr, sep, end, banNewLines = false) {
|
|
8548
|
+
if (!end) {
|
|
8549
|
+
ptr = indexOfNewline(str, ptr);
|
|
8550
|
+
return ptr < 0 ? str.length : ptr;
|
|
8551
|
+
}
|
|
8552
|
+
for (let i = ptr; i < str.length; i++) {
|
|
8553
|
+
let c = str[i];
|
|
8554
|
+
if (c === "#") {
|
|
8555
|
+
i = indexOfNewline(str, i);
|
|
8556
|
+
} else if (c === sep) {
|
|
8557
|
+
return i + 1;
|
|
8558
|
+
} else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
|
|
8559
|
+
return i;
|
|
8560
|
+
}
|
|
8561
|
+
}
|
|
8562
|
+
throw new TomlError("cannot find end of structure", {
|
|
8563
|
+
toml: str,
|
|
8564
|
+
ptr
|
|
8565
|
+
});
|
|
8566
|
+
}
|
|
8567
|
+
function getStringEnd(str, seek) {
|
|
8568
|
+
let first = str[seek];
|
|
8569
|
+
let target = first === str[seek + 1] && str[seek + 1] === str[seek + 2] ? str.slice(seek, seek + 3) : first;
|
|
8570
|
+
seek += target.length - 1;
|
|
8571
|
+
do
|
|
8572
|
+
seek = str.indexOf(target, ++seek);
|
|
8573
|
+
while (seek > -1 && first !== "'" && isEscaped(str, seek));
|
|
8574
|
+
if (seek > -1) {
|
|
8575
|
+
seek += target.length;
|
|
8576
|
+
if (target.length > 1) {
|
|
8577
|
+
if (str[seek] === first)
|
|
8578
|
+
seek++;
|
|
8579
|
+
if (str[seek] === first)
|
|
8580
|
+
seek++;
|
|
8581
|
+
}
|
|
8582
|
+
}
|
|
8583
|
+
return seek;
|
|
8584
|
+
}
|
|
8585
|
+
|
|
8586
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/date.js
|
|
8587
|
+
var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
|
|
8588
|
+
var TomlDate = class _TomlDate extends Date {
|
|
8589
|
+
#hasDate = false;
|
|
8590
|
+
#hasTime = false;
|
|
8591
|
+
#offset = null;
|
|
8592
|
+
constructor(date) {
|
|
8593
|
+
let hasDate = true;
|
|
8594
|
+
let hasTime = true;
|
|
8595
|
+
let offset = "Z";
|
|
8596
|
+
if (typeof date === "string") {
|
|
8597
|
+
let match = date.match(DATE_TIME_RE);
|
|
8598
|
+
if (match) {
|
|
8599
|
+
if (!match[1]) {
|
|
8600
|
+
hasDate = false;
|
|
8601
|
+
date = `0000-01-01T${date}`;
|
|
8602
|
+
}
|
|
8603
|
+
hasTime = !!match[2];
|
|
8604
|
+
hasTime && date[10] === " " && (date = date.replace(" ", "T"));
|
|
8605
|
+
if (match[2] && +match[2] > 23) {
|
|
8606
|
+
date = "";
|
|
8607
|
+
} else {
|
|
8608
|
+
offset = match[3] || null;
|
|
8609
|
+
date = date.toUpperCase();
|
|
8610
|
+
if (!offset && hasTime)
|
|
8611
|
+
date += "Z";
|
|
8612
|
+
}
|
|
8613
|
+
} else {
|
|
8614
|
+
date = "";
|
|
8615
|
+
}
|
|
8616
|
+
}
|
|
8617
|
+
super(date);
|
|
8618
|
+
if (!isNaN(this.getTime())) {
|
|
8619
|
+
this.#hasDate = hasDate;
|
|
8620
|
+
this.#hasTime = hasTime;
|
|
8621
|
+
this.#offset = offset;
|
|
8622
|
+
}
|
|
8623
|
+
}
|
|
8624
|
+
isDateTime() {
|
|
8625
|
+
return this.#hasDate && this.#hasTime;
|
|
8626
|
+
}
|
|
8627
|
+
isLocal() {
|
|
8628
|
+
return !this.#hasDate || !this.#hasTime || !this.#offset;
|
|
8629
|
+
}
|
|
8630
|
+
isDate() {
|
|
8631
|
+
return this.#hasDate && !this.#hasTime;
|
|
8632
|
+
}
|
|
8633
|
+
isTime() {
|
|
8634
|
+
return this.#hasTime && !this.#hasDate;
|
|
8635
|
+
}
|
|
8636
|
+
isValid() {
|
|
8637
|
+
return this.#hasDate || this.#hasTime;
|
|
8638
|
+
}
|
|
8639
|
+
toISOString() {
|
|
8640
|
+
let iso = super.toISOString();
|
|
8641
|
+
if (this.isDate())
|
|
8642
|
+
return iso.slice(0, 10);
|
|
8643
|
+
if (this.isTime())
|
|
8644
|
+
return iso.slice(11, 23);
|
|
8645
|
+
if (this.#offset === null)
|
|
8646
|
+
return iso.slice(0, -1);
|
|
8647
|
+
if (this.#offset === "Z")
|
|
8648
|
+
return iso;
|
|
8649
|
+
let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
|
|
8650
|
+
offset = this.#offset[0] === "-" ? offset : -offset;
|
|
8651
|
+
let offsetDate = new Date(this.getTime() - offset * 6e4);
|
|
8652
|
+
return offsetDate.toISOString().slice(0, -1) + this.#offset;
|
|
8653
|
+
}
|
|
8654
|
+
static wrapAsOffsetDateTime(jsDate, offset = "Z") {
|
|
8655
|
+
let date = new _TomlDate(jsDate);
|
|
8656
|
+
date.#offset = offset;
|
|
8657
|
+
return date;
|
|
8658
|
+
}
|
|
8659
|
+
static wrapAsLocalDateTime(jsDate) {
|
|
8660
|
+
let date = new _TomlDate(jsDate);
|
|
8661
|
+
date.#offset = null;
|
|
8662
|
+
return date;
|
|
8663
|
+
}
|
|
8664
|
+
static wrapAsLocalDate(jsDate) {
|
|
8665
|
+
let date = new _TomlDate(jsDate);
|
|
8666
|
+
date.#hasTime = false;
|
|
8667
|
+
date.#offset = null;
|
|
8668
|
+
return date;
|
|
8669
|
+
}
|
|
8670
|
+
static wrapAsLocalTime(jsDate) {
|
|
8671
|
+
let date = new _TomlDate(jsDate);
|
|
8672
|
+
date.#hasDate = false;
|
|
8673
|
+
date.#offset = null;
|
|
8674
|
+
return date;
|
|
8675
|
+
}
|
|
8676
|
+
};
|
|
8677
|
+
|
|
8678
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/primitive.js
|
|
8679
|
+
var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
|
|
8680
|
+
var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
|
|
8681
|
+
var LEADING_ZERO = /^[+-]?0[0-9_]/;
|
|
8682
|
+
var ESCAPE_REGEX = /^[0-9a-f]{2,8}$/i;
|
|
8683
|
+
var ESC_MAP = {
|
|
8684
|
+
b: "\b",
|
|
8685
|
+
t: " ",
|
|
8686
|
+
n: "\n",
|
|
8687
|
+
f: "\f",
|
|
8688
|
+
r: "\r",
|
|
8689
|
+
e: "\x1B",
|
|
8690
|
+
'"': '"',
|
|
8691
|
+
"\\": "\\"
|
|
8692
|
+
};
|
|
8693
|
+
function parseString(str, ptr = 0, endPtr = str.length) {
|
|
8694
|
+
let isLiteral = str[ptr] === "'";
|
|
8695
|
+
let isMultiline = str[ptr++] === str[ptr] && str[ptr] === str[ptr + 1];
|
|
8696
|
+
if (isMultiline) {
|
|
8697
|
+
endPtr -= 2;
|
|
8698
|
+
if (str[ptr += 2] === "\r")
|
|
8699
|
+
ptr++;
|
|
8700
|
+
if (str[ptr] === "\n")
|
|
8701
|
+
ptr++;
|
|
8702
|
+
}
|
|
8703
|
+
let tmp = 0;
|
|
8704
|
+
let isEscape;
|
|
8705
|
+
let parsed = "";
|
|
8706
|
+
let sliceStart = ptr;
|
|
8707
|
+
while (ptr < endPtr - 1) {
|
|
8708
|
+
let c = str[ptr++];
|
|
8709
|
+
if (c === "\n" || c === "\r" && str[ptr] === "\n") {
|
|
8710
|
+
if (!isMultiline) {
|
|
8711
|
+
throw new TomlError("newlines are not allowed in strings", {
|
|
8712
|
+
toml: str,
|
|
8713
|
+
ptr: ptr - 1
|
|
8714
|
+
});
|
|
8715
|
+
}
|
|
8716
|
+
} else if (c < " " && c !== " " || c === "\x7F") {
|
|
8717
|
+
throw new TomlError("control characters are not allowed in strings", {
|
|
8718
|
+
toml: str,
|
|
8719
|
+
ptr: ptr - 1
|
|
8720
|
+
});
|
|
8721
|
+
}
|
|
8722
|
+
if (isEscape) {
|
|
8723
|
+
isEscape = false;
|
|
8724
|
+
if (c === "x" || c === "u" || c === "U") {
|
|
8725
|
+
let code = str.slice(ptr, ptr += c === "x" ? 2 : c === "u" ? 4 : 8);
|
|
8726
|
+
if (!ESCAPE_REGEX.test(code)) {
|
|
8727
|
+
throw new TomlError("invalid unicode escape", {
|
|
8728
|
+
toml: str,
|
|
8729
|
+
ptr: tmp
|
|
8730
|
+
});
|
|
8731
|
+
}
|
|
8732
|
+
try {
|
|
8733
|
+
parsed += String.fromCodePoint(parseInt(code, 16));
|
|
8734
|
+
} catch {
|
|
8735
|
+
throw new TomlError("invalid unicode escape", {
|
|
8736
|
+
toml: str,
|
|
8737
|
+
ptr: tmp
|
|
8738
|
+
});
|
|
8739
|
+
}
|
|
8740
|
+
} else if (isMultiline && (c === "\n" || c === " " || c === " " || c === "\r")) {
|
|
8741
|
+
ptr = skipVoid(str, ptr - 1, true);
|
|
8742
|
+
if (str[ptr] !== "\n" && str[ptr] !== "\r") {
|
|
8743
|
+
throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
|
|
8744
|
+
toml: str,
|
|
8745
|
+
ptr: tmp
|
|
8746
|
+
});
|
|
8747
|
+
}
|
|
8748
|
+
ptr = skipVoid(str, ptr);
|
|
8749
|
+
} else if (c in ESC_MAP) {
|
|
8750
|
+
parsed += ESC_MAP[c];
|
|
8751
|
+
} else {
|
|
8752
|
+
throw new TomlError("unrecognized escape sequence", {
|
|
8753
|
+
toml: str,
|
|
8754
|
+
ptr: tmp
|
|
8755
|
+
});
|
|
8756
|
+
}
|
|
8757
|
+
sliceStart = ptr;
|
|
8758
|
+
} else if (!isLiteral && c === "\\") {
|
|
8759
|
+
tmp = ptr - 1;
|
|
8760
|
+
isEscape = true;
|
|
8761
|
+
parsed += str.slice(sliceStart, tmp);
|
|
8762
|
+
}
|
|
8763
|
+
}
|
|
8764
|
+
return parsed + str.slice(sliceStart, endPtr - 1);
|
|
8765
|
+
}
|
|
8766
|
+
function parseValue(value, toml, ptr, integersAsBigInt) {
|
|
8767
|
+
if (value === "true")
|
|
8768
|
+
return true;
|
|
8769
|
+
if (value === "false")
|
|
8770
|
+
return false;
|
|
8771
|
+
if (value === "-inf")
|
|
8772
|
+
return -Infinity;
|
|
8773
|
+
if (value === "inf" || value === "+inf")
|
|
8774
|
+
return Infinity;
|
|
8775
|
+
if (value === "nan" || value === "+nan" || value === "-nan")
|
|
8776
|
+
return NaN;
|
|
8777
|
+
if (value === "-0")
|
|
8778
|
+
return integersAsBigInt ? 0n : 0;
|
|
8779
|
+
let isInt = INT_REGEX.test(value);
|
|
8780
|
+
if (isInt || FLOAT_REGEX.test(value)) {
|
|
8781
|
+
if (LEADING_ZERO.test(value)) {
|
|
8782
|
+
throw new TomlError("leading zeroes are not allowed", {
|
|
8783
|
+
toml,
|
|
8784
|
+
ptr
|
|
8785
|
+
});
|
|
8786
|
+
}
|
|
8787
|
+
value = value.replace(/_/g, "");
|
|
8788
|
+
let numeric = +value;
|
|
8789
|
+
if (isNaN(numeric)) {
|
|
8790
|
+
throw new TomlError("invalid number", {
|
|
8791
|
+
toml,
|
|
8792
|
+
ptr
|
|
8793
|
+
});
|
|
8794
|
+
}
|
|
8795
|
+
if (isInt) {
|
|
8796
|
+
if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
|
|
8797
|
+
throw new TomlError("integer value cannot be represented losslessly", {
|
|
8798
|
+
toml,
|
|
8799
|
+
ptr
|
|
8800
|
+
});
|
|
8801
|
+
}
|
|
8802
|
+
if (isInt || integersAsBigInt === true)
|
|
8803
|
+
numeric = BigInt(value);
|
|
8804
|
+
}
|
|
8805
|
+
return numeric;
|
|
8806
|
+
}
|
|
8807
|
+
const date = new TomlDate(value);
|
|
8808
|
+
if (!date.isValid()) {
|
|
8809
|
+
throw new TomlError("invalid value", {
|
|
8810
|
+
toml,
|
|
8811
|
+
ptr
|
|
8812
|
+
});
|
|
8813
|
+
}
|
|
8814
|
+
return date;
|
|
8815
|
+
}
|
|
8816
|
+
|
|
8817
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/extract.js
|
|
8818
|
+
function sliceAndTrimEndOf(str, startPtr, endPtr) {
|
|
8819
|
+
let value = str.slice(startPtr, endPtr);
|
|
8820
|
+
let commentIdx = value.indexOf("#");
|
|
8821
|
+
if (commentIdx > -1) {
|
|
8822
|
+
skipComment(str, commentIdx);
|
|
8823
|
+
value = value.slice(0, commentIdx);
|
|
8824
|
+
}
|
|
8825
|
+
return [value.trimEnd(), commentIdx];
|
|
8826
|
+
}
|
|
8827
|
+
function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
|
8828
|
+
if (depth === 0) {
|
|
8829
|
+
throw new TomlError("document contains excessively nested structures. aborting.", {
|
|
8830
|
+
toml: str,
|
|
8831
|
+
ptr
|
|
8832
|
+
});
|
|
8833
|
+
}
|
|
8834
|
+
let c = str[ptr];
|
|
8835
|
+
if (c === "[" || c === "{") {
|
|
8836
|
+
let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
|
|
8837
|
+
if (end) {
|
|
8838
|
+
endPtr2 = skipVoid(str, endPtr2);
|
|
8839
|
+
if (str[endPtr2] === ",")
|
|
8840
|
+
endPtr2++;
|
|
8841
|
+
else if (str[endPtr2] !== end) {
|
|
8842
|
+
throw new TomlError("expected comma or end of structure", {
|
|
8843
|
+
toml: str,
|
|
8844
|
+
ptr: endPtr2
|
|
8845
|
+
});
|
|
8846
|
+
}
|
|
8847
|
+
}
|
|
8848
|
+
return [value, endPtr2];
|
|
8849
|
+
}
|
|
8850
|
+
let endPtr;
|
|
8851
|
+
if (c === '"' || c === "'") {
|
|
8852
|
+
endPtr = getStringEnd(str, ptr);
|
|
8853
|
+
let parsed = parseString(str, ptr, endPtr);
|
|
8854
|
+
if (end) {
|
|
8855
|
+
endPtr = skipVoid(str, endPtr);
|
|
8856
|
+
if (str[endPtr] && str[endPtr] !== "," && str[endPtr] !== end && str[endPtr] !== "\n" && str[endPtr] !== "\r") {
|
|
8857
|
+
throw new TomlError("unexpected character encountered", {
|
|
8858
|
+
toml: str,
|
|
8859
|
+
ptr: endPtr
|
|
8860
|
+
});
|
|
8861
|
+
}
|
|
8862
|
+
endPtr += +(str[endPtr] === ",");
|
|
8863
|
+
}
|
|
8864
|
+
return [parsed, endPtr];
|
|
8865
|
+
}
|
|
8866
|
+
endPtr = skipUntil(str, ptr, ",", end);
|
|
8867
|
+
let slice = sliceAndTrimEndOf(str, ptr, endPtr - +(str[endPtr - 1] === ","));
|
|
8868
|
+
if (!slice[0]) {
|
|
8869
|
+
throw new TomlError("incomplete key-value declaration: no value specified", {
|
|
8870
|
+
toml: str,
|
|
8871
|
+
ptr
|
|
8872
|
+
});
|
|
8873
|
+
}
|
|
8874
|
+
if (end && slice[1] > -1) {
|
|
8875
|
+
endPtr = skipVoid(str, ptr + slice[1]);
|
|
8876
|
+
endPtr += +(str[endPtr] === ",");
|
|
8877
|
+
}
|
|
8878
|
+
return [
|
|
8879
|
+
parseValue(slice[0], str, ptr, integersAsBigInt),
|
|
8880
|
+
endPtr
|
|
8881
|
+
];
|
|
8882
|
+
}
|
|
8883
|
+
|
|
8884
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/struct.js
|
|
8885
|
+
var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
|
|
8886
|
+
function parseKey(str, ptr, end = "=") {
|
|
8887
|
+
let dot = ptr - 1;
|
|
8888
|
+
let parsed = [];
|
|
8889
|
+
let endPtr = str.indexOf(end, ptr);
|
|
8890
|
+
if (endPtr < 0) {
|
|
8891
|
+
throw new TomlError("incomplete key-value: cannot find end of key", {
|
|
8892
|
+
toml: str,
|
|
8893
|
+
ptr
|
|
8894
|
+
});
|
|
8895
|
+
}
|
|
8896
|
+
do {
|
|
8897
|
+
let c = str[ptr = ++dot];
|
|
8898
|
+
if (c !== " " && c !== " ") {
|
|
8899
|
+
if (c === '"' || c === "'") {
|
|
8900
|
+
if (c === str[ptr + 1] && c === str[ptr + 2]) {
|
|
8901
|
+
throw new TomlError("multiline strings are not allowed in keys", {
|
|
8902
|
+
toml: str,
|
|
8903
|
+
ptr
|
|
8904
|
+
});
|
|
8905
|
+
}
|
|
8906
|
+
let eos = getStringEnd(str, ptr);
|
|
8907
|
+
if (eos < 0) {
|
|
8908
|
+
throw new TomlError("unfinished string encountered", {
|
|
8909
|
+
toml: str,
|
|
8910
|
+
ptr
|
|
8911
|
+
});
|
|
8912
|
+
}
|
|
8913
|
+
dot = str.indexOf(".", eos);
|
|
8914
|
+
let strEnd = str.slice(eos, dot < 0 || dot > endPtr ? endPtr : dot);
|
|
8915
|
+
let newLine = indexOfNewline(strEnd);
|
|
8916
|
+
if (newLine > -1) {
|
|
8917
|
+
throw new TomlError("newlines are not allowed in keys", {
|
|
8918
|
+
toml: str,
|
|
8919
|
+
ptr: ptr + dot + newLine
|
|
8920
|
+
});
|
|
8921
|
+
}
|
|
8922
|
+
if (strEnd.trimStart()) {
|
|
8923
|
+
throw new TomlError("found extra tokens after the string part", {
|
|
8924
|
+
toml: str,
|
|
8925
|
+
ptr: eos
|
|
8926
|
+
});
|
|
8927
|
+
}
|
|
8928
|
+
if (endPtr < eos) {
|
|
8929
|
+
endPtr = str.indexOf(end, eos);
|
|
8930
|
+
if (endPtr < 0) {
|
|
8931
|
+
throw new TomlError("incomplete key-value: cannot find end of key", {
|
|
8932
|
+
toml: str,
|
|
8933
|
+
ptr
|
|
8934
|
+
});
|
|
8935
|
+
}
|
|
8936
|
+
}
|
|
8937
|
+
parsed.push(parseString(str, ptr, eos));
|
|
8938
|
+
} else {
|
|
8939
|
+
dot = str.indexOf(".", ptr);
|
|
8940
|
+
let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot);
|
|
8941
|
+
if (!KEY_PART_RE.test(part)) {
|
|
8942
|
+
throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", {
|
|
8943
|
+
toml: str,
|
|
8944
|
+
ptr
|
|
8945
|
+
});
|
|
8946
|
+
}
|
|
8947
|
+
parsed.push(part.trimEnd());
|
|
8948
|
+
}
|
|
8949
|
+
}
|
|
8950
|
+
} while (dot + 1 && dot < endPtr);
|
|
8951
|
+
return [parsed, skipVoid(str, endPtr + 1, true, true)];
|
|
8952
|
+
}
|
|
8953
|
+
function parseInlineTable(str, ptr, depth, integersAsBigInt) {
|
|
8954
|
+
let res = {};
|
|
8955
|
+
let seen = /* @__PURE__ */ new Set();
|
|
8956
|
+
let c;
|
|
8957
|
+
ptr++;
|
|
8958
|
+
while ((c = str[ptr++]) !== "}" && c) {
|
|
8959
|
+
if (c === ",") {
|
|
8960
|
+
throw new TomlError("expected value, found comma", {
|
|
8961
|
+
toml: str,
|
|
8962
|
+
ptr: ptr - 1
|
|
8963
|
+
});
|
|
8964
|
+
} else if (c === "#")
|
|
8965
|
+
ptr = skipComment(str, ptr);
|
|
8966
|
+
else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
|
|
8967
|
+
let k;
|
|
8968
|
+
let t = res;
|
|
8969
|
+
let hasOwn = false;
|
|
8970
|
+
let [key, keyEndPtr] = parseKey(str, ptr - 1);
|
|
8971
|
+
for (let i = 0; i < key.length; i++) {
|
|
8972
|
+
if (i)
|
|
8973
|
+
t = hasOwn ? t[k] : t[k] = {};
|
|
8974
|
+
k = key[i];
|
|
8975
|
+
if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
|
|
8976
|
+
throw new TomlError("trying to redefine an already defined value", {
|
|
8977
|
+
toml: str,
|
|
8978
|
+
ptr
|
|
8979
|
+
});
|
|
8980
|
+
}
|
|
8981
|
+
if (!hasOwn && k === "__proto__") {
|
|
8982
|
+
Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
|
|
8983
|
+
}
|
|
8984
|
+
}
|
|
8985
|
+
if (hasOwn) {
|
|
8986
|
+
throw new TomlError("trying to redefine an already defined value", {
|
|
8987
|
+
toml: str,
|
|
8988
|
+
ptr
|
|
8989
|
+
});
|
|
8990
|
+
}
|
|
8991
|
+
let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt);
|
|
8992
|
+
seen.add(value);
|
|
8993
|
+
t[k] = value;
|
|
8994
|
+
ptr = valueEndPtr;
|
|
8995
|
+
}
|
|
8996
|
+
}
|
|
8997
|
+
if (!c) {
|
|
8998
|
+
throw new TomlError("unfinished table encountered", {
|
|
8999
|
+
toml: str,
|
|
9000
|
+
ptr
|
|
9001
|
+
});
|
|
9002
|
+
}
|
|
9003
|
+
return [res, ptr];
|
|
8379
9004
|
}
|
|
8380
|
-
function
|
|
8381
|
-
|
|
8382
|
-
|
|
9005
|
+
function parseArray(str, ptr, depth, integersAsBigInt) {
|
|
9006
|
+
let res = [];
|
|
9007
|
+
let c;
|
|
9008
|
+
ptr++;
|
|
9009
|
+
while ((c = str[ptr++]) !== "]" && c) {
|
|
9010
|
+
if (c === ",") {
|
|
9011
|
+
throw new TomlError("expected value, found comma", {
|
|
9012
|
+
toml: str,
|
|
9013
|
+
ptr: ptr - 1
|
|
9014
|
+
});
|
|
9015
|
+
} else if (c === "#")
|
|
9016
|
+
ptr = skipComment(str, ptr);
|
|
9017
|
+
else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
|
|
9018
|
+
let e = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt);
|
|
9019
|
+
res.push(e[0]);
|
|
9020
|
+
ptr = e[1];
|
|
9021
|
+
}
|
|
9022
|
+
}
|
|
9023
|
+
if (!c) {
|
|
9024
|
+
throw new TomlError("unfinished array encountered", {
|
|
9025
|
+
toml: str,
|
|
9026
|
+
ptr
|
|
9027
|
+
});
|
|
8383
9028
|
}
|
|
8384
|
-
|
|
8385
|
-
|
|
9029
|
+
return [res, ptr];
|
|
9030
|
+
}
|
|
9031
|
+
|
|
9032
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/parse.js
|
|
9033
|
+
function peekTable(key, table, meta, type) {
|
|
9034
|
+
let t = table;
|
|
9035
|
+
let m = meta;
|
|
9036
|
+
let k;
|
|
9037
|
+
let hasOwn = false;
|
|
9038
|
+
let state;
|
|
9039
|
+
for (let i = 0; i < key.length; i++) {
|
|
9040
|
+
if (i) {
|
|
9041
|
+
t = hasOwn ? t[k] : t[k] = {};
|
|
9042
|
+
m = (state = m[k]).c;
|
|
9043
|
+
if (type === 0 && (state.t === 1 || state.t === 2)) {
|
|
9044
|
+
return null;
|
|
9045
|
+
}
|
|
9046
|
+
if (state.t === 2) {
|
|
9047
|
+
let l = t.length - 1;
|
|
9048
|
+
t = t[l];
|
|
9049
|
+
m = m[l].c;
|
|
9050
|
+
}
|
|
9051
|
+
}
|
|
9052
|
+
k = key[i];
|
|
9053
|
+
if ((hasOwn = Object.hasOwn(t, k)) && m[k]?.t === 0 && m[k]?.d) {
|
|
9054
|
+
return null;
|
|
9055
|
+
}
|
|
9056
|
+
if (!hasOwn) {
|
|
9057
|
+
if (k === "__proto__") {
|
|
9058
|
+
Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
|
|
9059
|
+
Object.defineProperty(m, k, { enumerable: true, configurable: true, writable: true });
|
|
9060
|
+
}
|
|
9061
|
+
m[k] = {
|
|
9062
|
+
t: i < key.length - 1 && type === 2 ? 3 : type,
|
|
9063
|
+
d: false,
|
|
9064
|
+
i: 0,
|
|
9065
|
+
c: {}
|
|
9066
|
+
};
|
|
9067
|
+
}
|
|
8386
9068
|
}
|
|
8387
|
-
|
|
8388
|
-
if (
|
|
8389
|
-
return
|
|
9069
|
+
state = m[k];
|
|
9070
|
+
if (state.t !== type && !(type === 1 && state.t === 3)) {
|
|
9071
|
+
return null;
|
|
8390
9072
|
}
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
9073
|
+
if (type === 2) {
|
|
9074
|
+
if (!state.d) {
|
|
9075
|
+
state.d = true;
|
|
9076
|
+
t[k] = [];
|
|
9077
|
+
}
|
|
9078
|
+
t[k].push(t = {});
|
|
9079
|
+
state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} };
|
|
8394
9080
|
}
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
const home = mounts.get("/home/wechat");
|
|
8398
|
-
const token = mounts.get("/data/auth-token");
|
|
8399
|
-
if (data?.Type !== "volume" || data.Name !== inventory.volumes[0] || home?.Type !== "volume" || home.Name !== inventory.volumes[1] || token?.Type !== "bind" || token.Source !== inventory.tokenPath) {
|
|
8400
|
-
return { code: "CONTAINER_RESOURCE_MISMATCH", message: "container mounts do not match inventory" };
|
|
9081
|
+
if (state.d) {
|
|
9082
|
+
return null;
|
|
8401
9083
|
}
|
|
8402
|
-
|
|
8403
|
-
if (
|
|
8404
|
-
|
|
9084
|
+
state.d = true;
|
|
9085
|
+
if (type === 1) {
|
|
9086
|
+
t = hasOwn ? t[k] : t[k] = {};
|
|
9087
|
+
} else if (type === 0 && hasOwn) {
|
|
9088
|
+
return null;
|
|
8405
9089
|
}
|
|
8406
|
-
return
|
|
9090
|
+
return [k, t, state.c];
|
|
8407
9091
|
}
|
|
8408
|
-
function
|
|
8409
|
-
|
|
8410
|
-
|
|
9092
|
+
function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
9093
|
+
let res = {};
|
|
9094
|
+
let meta = {};
|
|
9095
|
+
let tbl = res;
|
|
9096
|
+
let m = meta;
|
|
9097
|
+
for (let ptr = skipVoid(toml, 0); ptr < toml.length; ) {
|
|
9098
|
+
if (toml[ptr] === "[") {
|
|
9099
|
+
let isTableArray = toml[++ptr] === "[";
|
|
9100
|
+
let k = parseKey(toml, ptr += +isTableArray, "]");
|
|
9101
|
+
if (isTableArray) {
|
|
9102
|
+
if (toml[k[1] - 1] !== "]") {
|
|
9103
|
+
throw new TomlError("expected end of table declaration", {
|
|
9104
|
+
toml,
|
|
9105
|
+
ptr: k[1] - 1
|
|
9106
|
+
});
|
|
9107
|
+
}
|
|
9108
|
+
k[1]++;
|
|
9109
|
+
}
|
|
9110
|
+
let p = peekTable(
|
|
9111
|
+
k[0],
|
|
9112
|
+
res,
|
|
9113
|
+
meta,
|
|
9114
|
+
isTableArray ? 2 : 1
|
|
9115
|
+
/* Type.EXPLICIT */
|
|
9116
|
+
);
|
|
9117
|
+
if (!p) {
|
|
9118
|
+
throw new TomlError("trying to redefine an already defined table or value", {
|
|
9119
|
+
toml,
|
|
9120
|
+
ptr
|
|
9121
|
+
});
|
|
9122
|
+
}
|
|
9123
|
+
m = p[2];
|
|
9124
|
+
tbl = p[1];
|
|
9125
|
+
ptr = k[1];
|
|
9126
|
+
} else {
|
|
9127
|
+
let k = parseKey(toml, ptr);
|
|
9128
|
+
let p = peekTable(
|
|
9129
|
+
k[0],
|
|
9130
|
+
tbl,
|
|
9131
|
+
m,
|
|
9132
|
+
0
|
|
9133
|
+
/* Type.DOTTED */
|
|
9134
|
+
);
|
|
9135
|
+
if (!p) {
|
|
9136
|
+
throw new TomlError("trying to redefine an already defined table or value", {
|
|
9137
|
+
toml,
|
|
9138
|
+
ptr
|
|
9139
|
+
});
|
|
9140
|
+
}
|
|
9141
|
+
let v = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt);
|
|
9142
|
+
p[1][p[0]] = v[0];
|
|
9143
|
+
ptr = v[1];
|
|
9144
|
+
}
|
|
9145
|
+
ptr = skipVoid(toml, ptr, true);
|
|
9146
|
+
if (toml[ptr] && toml[ptr] !== "\n" && toml[ptr] !== "\r") {
|
|
9147
|
+
throw new TomlError("each key-value declaration must be followed by an end-of-line", {
|
|
9148
|
+
toml,
|
|
9149
|
+
ptr
|
|
9150
|
+
});
|
|
9151
|
+
}
|
|
9152
|
+
ptr = skipVoid(toml, ptr);
|
|
8411
9153
|
}
|
|
8412
|
-
return
|
|
9154
|
+
return res;
|
|
9155
|
+
}
|
|
9156
|
+
|
|
9157
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/stringify.js
|
|
9158
|
+
var BARE_KEY = /^[a-z0-9-_]+$/i;
|
|
9159
|
+
function extendedTypeOf(obj) {
|
|
9160
|
+
let type = typeof obj;
|
|
9161
|
+
if (type === "object") {
|
|
9162
|
+
if (Array.isArray(obj))
|
|
9163
|
+
return "array";
|
|
9164
|
+
if (obj instanceof Date)
|
|
9165
|
+
return "date";
|
|
9166
|
+
}
|
|
9167
|
+
return type;
|
|
9168
|
+
}
|
|
9169
|
+
function isArrayOfTables(obj) {
|
|
9170
|
+
for (let i = 0; i < obj.length; i++) {
|
|
9171
|
+
if (extendedTypeOf(obj[i]) !== "object")
|
|
9172
|
+
return false;
|
|
9173
|
+
}
|
|
9174
|
+
return obj.length != 0;
|
|
9175
|
+
}
|
|
9176
|
+
function formatString(s) {
|
|
9177
|
+
return JSON.stringify(s).replace(/\x7f/g, "\\u007f");
|
|
9178
|
+
}
|
|
9179
|
+
function stringifyValue(val, type, depth, numberAsFloat) {
|
|
9180
|
+
if (depth === 0) {
|
|
9181
|
+
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
9182
|
+
}
|
|
9183
|
+
if (type === "number") {
|
|
9184
|
+
if (isNaN(val))
|
|
9185
|
+
return "nan";
|
|
9186
|
+
if (val === Infinity)
|
|
9187
|
+
return "inf";
|
|
9188
|
+
if (val === -Infinity)
|
|
9189
|
+
return "-inf";
|
|
9190
|
+
if (numberAsFloat && Number.isInteger(val))
|
|
9191
|
+
return val.toFixed(1);
|
|
9192
|
+
return val.toString();
|
|
9193
|
+
}
|
|
9194
|
+
if (type === "bigint" || type === "boolean") {
|
|
9195
|
+
return val.toString();
|
|
9196
|
+
}
|
|
9197
|
+
if (type === "string") {
|
|
9198
|
+
return formatString(val);
|
|
9199
|
+
}
|
|
9200
|
+
if (type === "date") {
|
|
9201
|
+
if (isNaN(val.getTime())) {
|
|
9202
|
+
throw new TypeError("cannot serialize invalid date");
|
|
9203
|
+
}
|
|
9204
|
+
return val.toISOString();
|
|
9205
|
+
}
|
|
9206
|
+
if (type === "object") {
|
|
9207
|
+
return stringifyInlineTable(val, depth, numberAsFloat);
|
|
9208
|
+
}
|
|
9209
|
+
if (type === "array") {
|
|
9210
|
+
return stringifyArray(val, depth, numberAsFloat);
|
|
9211
|
+
}
|
|
9212
|
+
}
|
|
9213
|
+
function stringifyInlineTable(obj, depth, numberAsFloat) {
|
|
9214
|
+
let keys = Object.keys(obj);
|
|
9215
|
+
if (keys.length === 0)
|
|
9216
|
+
return "{}";
|
|
9217
|
+
let res = "{ ";
|
|
9218
|
+
for (let i = 0; i < keys.length; i++) {
|
|
9219
|
+
let k = keys[i];
|
|
9220
|
+
if (i)
|
|
9221
|
+
res += ", ";
|
|
9222
|
+
res += BARE_KEY.test(k) ? k : formatString(k);
|
|
9223
|
+
res += " = ";
|
|
9224
|
+
res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat);
|
|
9225
|
+
}
|
|
9226
|
+
return res + " }";
|
|
9227
|
+
}
|
|
9228
|
+
function stringifyArray(array, depth, numberAsFloat) {
|
|
9229
|
+
if (array.length === 0)
|
|
9230
|
+
return "[]";
|
|
9231
|
+
let res = "[ ";
|
|
9232
|
+
for (let i = 0; i < array.length; i++) {
|
|
9233
|
+
if (i)
|
|
9234
|
+
res += ", ";
|
|
9235
|
+
if (array[i] === null || array[i] === void 0) {
|
|
9236
|
+
throw new TypeError("arrays cannot contain null or undefined values");
|
|
9237
|
+
}
|
|
9238
|
+
res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat);
|
|
9239
|
+
}
|
|
9240
|
+
return res + " ]";
|
|
9241
|
+
}
|
|
9242
|
+
function stringifyArrayTable(array, key, depth, numberAsFloat) {
|
|
9243
|
+
if (depth === 0) {
|
|
9244
|
+
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
9245
|
+
}
|
|
9246
|
+
let res = "";
|
|
9247
|
+
for (let i = 0; i < array.length; i++) {
|
|
9248
|
+
res += `${res && "\n"}[[${key}]]
|
|
9249
|
+
`;
|
|
9250
|
+
res += stringifyTable(0, array[i], key, depth, numberAsFloat);
|
|
9251
|
+
}
|
|
9252
|
+
return res;
|
|
9253
|
+
}
|
|
9254
|
+
function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat) {
|
|
9255
|
+
if (depth === 0) {
|
|
9256
|
+
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
9257
|
+
}
|
|
9258
|
+
let preamble = "";
|
|
9259
|
+
let tables = "";
|
|
9260
|
+
let keys = Object.keys(obj);
|
|
9261
|
+
for (let i = 0; i < keys.length; i++) {
|
|
9262
|
+
let k = keys[i];
|
|
9263
|
+
if (obj[k] !== null && obj[k] !== void 0) {
|
|
9264
|
+
let type = extendedTypeOf(obj[k]);
|
|
9265
|
+
if (type === "symbol" || type === "function") {
|
|
9266
|
+
throw new TypeError(`cannot serialize values of type '${type}'`);
|
|
9267
|
+
}
|
|
9268
|
+
let key = BARE_KEY.test(k) ? k : formatString(k);
|
|
9269
|
+
if (type === "array" && isArrayOfTables(obj[k])) {
|
|
9270
|
+
tables += (tables && "\n") + stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat);
|
|
9271
|
+
} else if (type === "object") {
|
|
9272
|
+
let tblKey = prefix ? `${prefix}.${key}` : key;
|
|
9273
|
+
tables += (tables && "\n") + stringifyTable(tblKey, obj[k], tblKey, depth - 1, numberAsFloat);
|
|
9274
|
+
} else {
|
|
9275
|
+
preamble += key;
|
|
9276
|
+
preamble += " = ";
|
|
9277
|
+
preamble += stringifyValue(obj[k], type, depth, numberAsFloat);
|
|
9278
|
+
preamble += "\n";
|
|
9279
|
+
}
|
|
9280
|
+
}
|
|
9281
|
+
}
|
|
9282
|
+
if (tableKey && (preamble || !tables))
|
|
9283
|
+
preamble = preamble ? `[${tableKey}]
|
|
9284
|
+
${preamble}` : `[${tableKey}]`;
|
|
9285
|
+
return preamble && tables ? `${preamble}
|
|
9286
|
+
${tables}` : preamble || tables;
|
|
9287
|
+
}
|
|
9288
|
+
function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
9289
|
+
if (extendedTypeOf(obj) !== "object") {
|
|
9290
|
+
throw new TypeError("stringify can only be called with an object");
|
|
9291
|
+
}
|
|
9292
|
+
let str = stringifyTable(0, obj, "", maxDepth, numbersAsFloat);
|
|
9293
|
+
if (str[str.length - 1] !== "\n")
|
|
9294
|
+
return str + "\n";
|
|
9295
|
+
return str;
|
|
9296
|
+
}
|
|
9297
|
+
|
|
9298
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/index.js
|
|
9299
|
+
var dist_default = { parse, stringify, TomlDate, TomlError };
|
|
9300
|
+
|
|
9301
|
+
// src/outbound-config.ts
|
|
9302
|
+
var OUTBOUND_ENV_KEYS = [
|
|
9303
|
+
"AGENT_WECHAT_OUTBOUND_QUEUE_CAPACITY",
|
|
9304
|
+
"AGENT_WECHAT_OUTBOUND_MIN_SPACING_MS",
|
|
9305
|
+
"AGENT_WECHAT_OUTBOUND_JITTER_MS",
|
|
9306
|
+
"AGENT_WECHAT_CHAT_COOLDOWN_MS",
|
|
9307
|
+
"AGENT_WECHAT_HOURLY_BUDGET",
|
|
9308
|
+
"AGENT_WECHAT_DAILY_BUDGET",
|
|
9309
|
+
"AGENT_WECHAT_QUIET_START_MIN",
|
|
9310
|
+
"AGENT_WECHAT_QUIET_END_MIN",
|
|
9311
|
+
"AGENT_WECHAT_OUTBOUND_LONG_TAIL_JITTER_MS",
|
|
9312
|
+
"AGENT_WECHAT_OUTBOUND_LONG_TAIL_CHANCE_PERCENT",
|
|
9313
|
+
"AGENT_WECHAT_OUTBOUND_TASK_TTL_MS",
|
|
9314
|
+
"AGENT_WECHAT_OUTBOUND_IDEMPOTENCY_TTL_MS",
|
|
9315
|
+
"AGENT_WECHAT_OUTBOUND_IDEMPOTENCY_MAX_ROWS",
|
|
9316
|
+
"AGENT_WECHAT_OUTBOUND_DISABLED"
|
|
9317
|
+
];
|
|
9318
|
+
var aliases = {
|
|
9319
|
+
queueCapacity: "AGENT_WECHAT_OUTBOUND_QUEUE_CAPACITY",
|
|
9320
|
+
minSpacingMs: "AGENT_WECHAT_OUTBOUND_MIN_SPACING_MS",
|
|
9321
|
+
jitterMs: "AGENT_WECHAT_OUTBOUND_JITTER_MS",
|
|
9322
|
+
chatCooldownMs: "AGENT_WECHAT_CHAT_COOLDOWN_MS",
|
|
9323
|
+
hourlyBudget: "AGENT_WECHAT_HOURLY_BUDGET",
|
|
9324
|
+
dailyBudget: "AGENT_WECHAT_DAILY_BUDGET",
|
|
9325
|
+
quietStartMin: "AGENT_WECHAT_QUIET_START_MIN",
|
|
9326
|
+
quietEndMin: "AGENT_WECHAT_QUIET_END_MIN",
|
|
9327
|
+
longTailJitterMs: "AGENT_WECHAT_OUTBOUND_LONG_TAIL_JITTER_MS",
|
|
9328
|
+
longTailChancePercent: "AGENT_WECHAT_OUTBOUND_LONG_TAIL_CHANCE_PERCENT",
|
|
9329
|
+
taskTtlMs: "AGENT_WECHAT_OUTBOUND_TASK_TTL_MS",
|
|
9330
|
+
idempotencyTtlMs: "AGENT_WECHAT_OUTBOUND_IDEMPOTENCY_TTL_MS",
|
|
9331
|
+
idempotencyMaxRows: "AGENT_WECHAT_OUTBOUND_IDEMPOTENCY_MAX_ROWS",
|
|
9332
|
+
disabled: "AGENT_WECHAT_OUTBOUND_DISABLED"
|
|
9333
|
+
};
|
|
9334
|
+
function readOutboundConfig(file) {
|
|
9335
|
+
if (!file) return {};
|
|
9336
|
+
const parsed = dist_default.parse(fs3.readFileSync(path3.resolve(file), "utf8"));
|
|
9337
|
+
const result = {};
|
|
9338
|
+
for (const [key, env] of Object.entries(aliases)) if (parsed[key] !== void 0) result[env] = String(parsed[key]);
|
|
9339
|
+
for (const key of OUTBOUND_ENV_KEYS) if (parsed[key] !== void 0) result[key] = String(parsed[key]);
|
|
9340
|
+
return result;
|
|
9341
|
+
}
|
|
9342
|
+
function outboundFromEnvEntries(entries) {
|
|
9343
|
+
const result = {};
|
|
9344
|
+
const allowed = new Set(OUTBOUND_ENV_KEYS);
|
|
9345
|
+
for (const entry of entries) {
|
|
9346
|
+
const index = entry.indexOf("=");
|
|
9347
|
+
if (index > 0 && allowed.has(entry.slice(0, index))) result[entry.slice(0, index)] = entry.slice(index + 1);
|
|
9348
|
+
}
|
|
9349
|
+
return result;
|
|
9350
|
+
}
|
|
9351
|
+
function resolveOutboundConfig(file, cli = {}) {
|
|
9352
|
+
const config = file ? readOutboundConfig(file) : {};
|
|
9353
|
+
const env = {};
|
|
9354
|
+
for (const key of OUTBOUND_ENV_KEYS) if (process.env[key] !== void 0) env[key] = process.env[key];
|
|
9355
|
+
return { ...config, ...env, ...cli };
|
|
9356
|
+
}
|
|
9357
|
+
|
|
9358
|
+
// src/lifecycle-policy.ts
|
|
9359
|
+
var INSTANCE_LABEL = "dev.visionclaw.agent-wechat.instance";
|
|
9360
|
+
var IMAGE_LABEL = "dev.visionclaw.agent-wechat.image";
|
|
9361
|
+
var VOLUME_ROLE_LABEL = "dev.visionclaw.agent-wechat.volume-role";
|
|
9362
|
+
function hasOwnedContainer(info) {
|
|
9363
|
+
return info.Config?.Labels?.[INSTANCE_LABEL] === "default";
|
|
9364
|
+
}
|
|
9365
|
+
function isReconcileableContainer(info, inventory) {
|
|
9366
|
+
if (hasOwnedContainer(info)) return true;
|
|
9367
|
+
const id = inventory?.containerId;
|
|
9368
|
+
return Boolean(id && (info.Id === id || info.Id.startsWith(id) || id.startsWith(info.Id)));
|
|
9369
|
+
}
|
|
9370
|
+
function hasOwnedVolume(existing, name, role) {
|
|
9371
|
+
return existing.Name === name && existing.Driver === "local" && existing.Labels?.[INSTANCE_LABEL] === "default" && existing.Labels?.[VOLUME_ROLE_LABEL] === role;
|
|
8413
9372
|
}
|
|
8414
9373
|
|
|
8415
9374
|
// src/lifecycle.ts
|
|
@@ -8490,8 +9449,12 @@ function ensureOwnedVolumes(inventory) {
|
|
|
8490
9449
|
docker(["volume", "create", "--driver", "local", "--label", `${INSTANCE_LABEL}=default`, "--label", `${VOLUME_ROLE_LABEL}=${roles[index]}`, name]);
|
|
8491
9450
|
continue;
|
|
8492
9451
|
}
|
|
8493
|
-
|
|
8494
|
-
|
|
9452
|
+
assertVolumeOwnership(existing, name, roles[index]);
|
|
9453
|
+
}
|
|
9454
|
+
}
|
|
9455
|
+
function assertVolumeOwnership(existing, name, role) {
|
|
9456
|
+
if (!hasOwnedVolume(existing, name, role)) {
|
|
9457
|
+
throw new CliError("VOLUME_OWNERSHIP_MISMATCH", `refusing to use volume ${name} without trusted ownership`, EXIT.ENVIRONMENT);
|
|
8495
9458
|
}
|
|
8496
9459
|
}
|
|
8497
9460
|
function assertOwnedVolumes(inventory) {
|
|
@@ -8499,10 +9462,12 @@ function assertOwnedVolumes(inventory) {
|
|
|
8499
9462
|
for (const [index, name] of inventory.volumes.entries()) {
|
|
8500
9463
|
const existing = inspectVolume(name);
|
|
8501
9464
|
if (!existing) continue;
|
|
8502
|
-
|
|
8503
|
-
if (violation) throw new CliError(violation.code, violation.message, EXIT.CLEANUP);
|
|
9465
|
+
assertVolumeOwnership(existing, name, roles[index]);
|
|
8504
9466
|
}
|
|
8505
9467
|
}
|
|
9468
|
+
function assertOwnedContainer(info, inventory) {
|
|
9469
|
+
if (!isReconcileableContainer(info, inventory)) throw new CliError("CONTAINER_OWNERSHIP_MISMATCH", "refusing to operate on an unowned container with the fixed name", EXIT.ENVIRONMENT);
|
|
9470
|
+
}
|
|
8506
9471
|
function clearContainerIdentity(inventory) {
|
|
8507
9472
|
const info = inspectContainer();
|
|
8508
9473
|
if (!info) throw new CliError("INSTANCE_NOT_RUNNING", "trusted container is required to clear container identity", EXIT.CLEANUP);
|
|
@@ -8519,8 +9484,7 @@ function removeOwnedVolume(inventory, index, role) {
|
|
|
8519
9484
|
const name = inventory.volumes[index];
|
|
8520
9485
|
const existing = inspectVolume(name);
|
|
8521
9486
|
if (!existing) return false;
|
|
8522
|
-
|
|
8523
|
-
if (violation) throw new CliError(violation.code, violation.message, EXIT.CLEANUP);
|
|
9487
|
+
assertVolumeOwnership(existing, name, role);
|
|
8524
9488
|
docker(["volume", "rm", name]);
|
|
8525
9489
|
return true;
|
|
8526
9490
|
}
|
|
@@ -8542,10 +9506,6 @@ function resolveImage(options) {
|
|
|
8542
9506
|
if (published && !digest) throw new CliError("IMAGE_DIGEST_UNRESOLVED", "published image did not resolve to a fork repo digest", EXIT.ENVIRONMENT);
|
|
8543
9507
|
return { runReference: digest || requested, requestedReference: requested, digest };
|
|
8544
9508
|
}
|
|
8545
|
-
function assertOwnedContainer(info, inventory) {
|
|
8546
|
-
const violation = containerOwnershipError(info, inventory);
|
|
8547
|
-
if (violation) throw new CliError(violation.code, violation.message, EXIT.ENVIRONMENT);
|
|
8548
|
-
}
|
|
8549
9509
|
async function waitCompatible(token, timeoutMs = 3e4) {
|
|
8550
9510
|
await waitHealthy(timeoutMs);
|
|
8551
9511
|
try {
|
|
@@ -8572,21 +9532,19 @@ async function waitHealthy(timeoutMs = 3e4) {
|
|
|
8572
9532
|
}
|
|
8573
9533
|
async function startInstance(options) {
|
|
8574
9534
|
if (!dockerAvailable()) throw new CliError("DOCKER_UNAVAILABLE", "Docker daemon is unavailable", EXIT.ENVIRONMENT);
|
|
8575
|
-
const selected = resolveImage({ explicit: options.image, pull: options.pull, noPull: options.noPull, localDefault: options.localDefault });
|
|
8576
9535
|
const existing = inspectContainer();
|
|
8577
9536
|
const current = loadInventory();
|
|
8578
9537
|
if (existing) {
|
|
8579
|
-
if (!current) throw new CliError("INSTANCE_INVENTORY_MISSING", "existing container has no trusted inventory", EXIT.ENVIRONMENT);
|
|
8580
9538
|
assertOwnedContainer(existing, current);
|
|
8581
|
-
|
|
8582
|
-
|
|
8583
|
-
if (existing.Config?.Image !== expected || recorded !== expected) {
|
|
8584
|
-
throw new CliError("IMAGE_COMPATIBILITY_MISMATCH", "existing container image does not match requested compatible image", EXIT.ENVIRONMENT);
|
|
9539
|
+
if (options.outbound && Object.keys(options.outbound).length > 0) {
|
|
9540
|
+
throw new CliError("OUTBOUND_RESTART_REQUIRED", "outbound policy changed; run wx restart to recreate the container", EXIT.ARGUMENT);
|
|
8585
9541
|
}
|
|
8586
|
-
if (!
|
|
9542
|
+
if (!current) throw new CliError("INSTANCE_INVENTORY_MISSING", "existing container has no trusted inventory", EXIT.ENVIRONMENT);
|
|
9543
|
+
if (!existing.State?.Running) docker(["start", CONTAINER_NAME], { inherit: true });
|
|
8587
9544
|
await waitCompatible(options.token);
|
|
8588
9545
|
return current;
|
|
8589
9546
|
}
|
|
9547
|
+
const selected = resolveImage({ explicit: options.image, pull: options.pull, noPull: options.noPull, localDefault: options.localDefault });
|
|
8590
9548
|
const provisional = createInventory(selected.requestedReference, options.identity, selected.digest);
|
|
8591
9549
|
saveInventory(provisional);
|
|
8592
9550
|
ensureOwnedVolumes(provisional);
|
|
@@ -8595,7 +9553,8 @@ async function startInstance(options) {
|
|
|
8595
9553
|
containerName: CONTAINER_NAME,
|
|
8596
9554
|
tokenPath: TOKEN_PATH,
|
|
8597
9555
|
port: DEFAULT_PORT,
|
|
8598
|
-
proxy: options.proxy
|
|
9556
|
+
proxy: options.proxy,
|
|
9557
|
+
outbound: options.outbound
|
|
8599
9558
|
});
|
|
8600
9559
|
args.splice(args.length - 1, 0, "--label", `${INSTANCE_LABEL}=default`, "--label", `${IMAGE_LABEL}=${selected.digest || selected.runReference}`);
|
|
8601
9560
|
docker(args, { inherit: true });
|
|
@@ -8612,13 +9571,28 @@ async function startInstance(options) {
|
|
|
8612
9571
|
}
|
|
8613
9572
|
return inventory;
|
|
8614
9573
|
}
|
|
9574
|
+
function outboundFromContainer(info) {
|
|
9575
|
+
return outboundFromEnvEntries(info.Config?.Env ?? []);
|
|
9576
|
+
}
|
|
9577
|
+
function stopContainer(idOrName) {
|
|
9578
|
+
docker(["stop", idOrName], { inherit: true });
|
|
9579
|
+
}
|
|
9580
|
+
function renameContainer(id, name) {
|
|
9581
|
+
docker(["rename", id, name], { inherit: true });
|
|
9582
|
+
}
|
|
9583
|
+
function removeContainer(id) {
|
|
9584
|
+
docker(["rm", "-f", id], { inherit: true });
|
|
9585
|
+
}
|
|
9586
|
+
function startContainer(idOrName) {
|
|
9587
|
+
docker(["start", idOrName], { inherit: true });
|
|
9588
|
+
}
|
|
8615
9589
|
function stopInstance() {
|
|
8616
9590
|
if (!dockerAvailable()) throw new CliError("DOCKER_UNAVAILABLE", "Docker daemon is unavailable", EXIT.ENVIRONMENT);
|
|
8617
9591
|
const info = inspectContainer();
|
|
8618
9592
|
if (!info) return { stopped: false };
|
|
8619
9593
|
const inventory = loadInventory();
|
|
8620
|
-
if (!inventory) throw new CliError("INSTANCE_INVENTORY_MISSING", "refusing to remove an unowned container", EXIT.ENVIRONMENT);
|
|
8621
9594
|
assertOwnedContainer(info, inventory);
|
|
9595
|
+
if (!inventory) throw new CliError("INSTANCE_INVENTORY_MISSING", "refusing to remove an unowned container", EXIT.ENVIRONMENT);
|
|
8622
9596
|
docker(["rm", "-f", info.Id], { inherit: true });
|
|
8623
9597
|
return { stopped: true };
|
|
8624
9598
|
}
|
|
@@ -8637,18 +9611,18 @@ function purgeInstance() {
|
|
|
8637
9611
|
remaining.push(`volume:${volume}`);
|
|
8638
9612
|
}
|
|
8639
9613
|
}
|
|
8640
|
-
for (const file of [TOKEN_PATH,
|
|
9614
|
+
for (const file of [TOKEN_PATH, path4.join(CONFIG_DIR, "device-identity.env"), path4.join(CONFIG_DIR, "device-identity.json")]) {
|
|
8641
9615
|
try {
|
|
8642
9616
|
assertSafePurgePath(file, CONFIG_DIR);
|
|
8643
9617
|
} catch {
|
|
8644
|
-
remaining.push(
|
|
9618
|
+
remaining.push(path4.basename(file));
|
|
8645
9619
|
continue;
|
|
8646
9620
|
}
|
|
8647
9621
|
try {
|
|
8648
|
-
|
|
8649
|
-
removed.push(
|
|
9622
|
+
fs4.unlinkSync(file);
|
|
9623
|
+
removed.push(path4.basename(file));
|
|
8650
9624
|
} catch (error) {
|
|
8651
|
-
if (error.code !== "ENOENT") remaining.push(
|
|
9625
|
+
if (error.code !== "ENOENT") remaining.push(path4.basename(file));
|
|
8652
9626
|
}
|
|
8653
9627
|
}
|
|
8654
9628
|
if (remaining.length === 0) removeInventory();
|
|
@@ -8660,8 +9634,9 @@ async function replaceImage(options) {
|
|
|
8660
9634
|
if (!previous) throw new CliError("INSTANCE_INVENTORY_MISSING", "start the instance before image upgrade", EXIT.ENVIRONMENT);
|
|
8661
9635
|
const info = inspectContainer();
|
|
8662
9636
|
if (info) assertOwnedContainer(info, previous);
|
|
9637
|
+
const reconciled = previous;
|
|
8663
9638
|
const selected = resolveImage({ explicit: options.image, pull: true, localDefault: previous.imageRef });
|
|
8664
|
-
if (selected.digest ===
|
|
9639
|
+
if (selected.digest === reconciled.imageDigest) return reconciled;
|
|
8665
9640
|
if (info) {
|
|
8666
9641
|
if (info.State?.Running) docker(["stop", info.Id], { inherit: true });
|
|
8667
9642
|
docker(["rename", info.Id, `${CONTAINER_NAME}-rollback`]);
|
|
@@ -8675,7 +9650,7 @@ async function replaceImage(options) {
|
|
|
8675
9650
|
const failed = inspectContainer();
|
|
8676
9651
|
if (failed) docker(["rm", "-f", failed.Id]);
|
|
8677
9652
|
if (info) docker(["rename", info.Id, CONTAINER_NAME]);
|
|
8678
|
-
saveInventory(
|
|
9653
|
+
saveInventory(reconciled);
|
|
8679
9654
|
if (info?.State?.Running) docker(["start", CONTAINER_NAME]);
|
|
8680
9655
|
} catch {
|
|
8681
9656
|
throw new CliError("ROLLBACK_FAILED", "image upgrade failed and rollback was incomplete", EXIT.ROLLBACK);
|
|
@@ -8761,12 +9736,12 @@ function checkCliUpgrade(currentVersion, readLatest = () => execFileSync2("npm",
|
|
|
8761
9736
|
}
|
|
8762
9737
|
|
|
8763
9738
|
// src/cli.ts
|
|
8764
|
-
var VERSION = false ? "0.0.0-test" : "0.
|
|
9739
|
+
var VERSION = false ? "0.0.0-test" : "0.14.0";
|
|
8765
9740
|
var MAX_UPLOAD_BYTES = 50 * 1024 * 1024;
|
|
8766
9741
|
function readToken() {
|
|
8767
9742
|
try {
|
|
8768
9743
|
secureRegularFile(TOKEN_PATH);
|
|
8769
|
-
const value =
|
|
9744
|
+
const value = fs5.readFileSync(TOKEN_PATH, "utf8").trim();
|
|
8770
9745
|
if (!/^[a-f0-9]{64}$/.test(value)) throw new Error("INVALID_AUTH_TOKEN");
|
|
8771
9746
|
return value;
|
|
8772
9747
|
} catch (error) {
|
|
@@ -8778,9 +9753,9 @@ function readToken() {
|
|
|
8778
9753
|
function ensureToken() {
|
|
8779
9754
|
const current = readToken();
|
|
8780
9755
|
if (current) return current;
|
|
8781
|
-
|
|
9756
|
+
fs5.mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
8782
9757
|
const token = randomBytes2(32).toString("hex");
|
|
8783
|
-
|
|
9758
|
+
fs5.writeFileSync(TOKEN_PATH, `${token}
|
|
8784
9759
|
`, { mode: 384, flag: "wx" });
|
|
8785
9760
|
return token;
|
|
8786
9761
|
}
|
|
@@ -8880,13 +9855,13 @@ async function login(timeoutMs, newAccount) {
|
|
|
8880
9855
|
function regularUpload(target) {
|
|
8881
9856
|
let stat;
|
|
8882
9857
|
try {
|
|
8883
|
-
stat =
|
|
9858
|
+
stat = fs5.lstatSync(target);
|
|
8884
9859
|
} catch {
|
|
8885
9860
|
throw new CliError("FILE_NOT_FOUND", `file not found: ${target}`, EXIT.ARGUMENT);
|
|
8886
9861
|
}
|
|
8887
9862
|
if (!stat.isFile() || stat.isSymbolicLink()) throw new CliError("INVALID_UPLOAD_FILE", "upload must be a regular non-symlink file", EXIT.ARGUMENT);
|
|
8888
9863
|
if (stat.size > MAX_UPLOAD_BYTES) throw new CliError("UPLOAD_TOO_LARGE", `upload exceeds ${MAX_UPLOAD_BYTES} bytes`, EXIT.ARGUMENT);
|
|
8889
|
-
return
|
|
9864
|
+
return fs5.readFileSync(target);
|
|
8890
9865
|
}
|
|
8891
9866
|
function renderMessages(page) {
|
|
8892
9867
|
for (const item of [...page.items].reverse()) console.log(`${item.localId} ${item.timestamp} ${item.senderName || item.sender || ""} ${item.content}`);
|
|
@@ -8903,15 +9878,15 @@ async function resetAuth(yes) {
|
|
|
8903
9878
|
try {
|
|
8904
9879
|
removeOwnedVolume(inventory, 1, "wechat-home");
|
|
8905
9880
|
} catch (error) {
|
|
8906
|
-
if (error instanceof CliError && error.code === "
|
|
9881
|
+
if (error instanceof CliError && error.code === "VOLUME_DRIVER_UNSUPPORTED") throw error;
|
|
8907
9882
|
throw new CliError("AUTH_RESET_CLEANUP_INCOMPLETE", `remaining resource: volume:${inventory.volumes[1]}`, EXIT.CLEANUP);
|
|
8908
9883
|
}
|
|
8909
9884
|
const remaining = [];
|
|
8910
9885
|
for (const file of ["device-identity.env", "device-identity.json"]) {
|
|
8911
|
-
const target =
|
|
9886
|
+
const target = path5.join(CONFIG_DIR, file);
|
|
8912
9887
|
try {
|
|
8913
9888
|
assertSafePurgePath(target, CONFIG_DIR);
|
|
8914
|
-
|
|
9889
|
+
fs5.unlinkSync(target);
|
|
8915
9890
|
} catch (error) {
|
|
8916
9891
|
if (error.code !== "ENOENT") remaining.push(file);
|
|
8917
9892
|
}
|
|
@@ -8926,7 +9901,6 @@ function programStatus() {
|
|
|
8926
9901
|
const container = inspectContainer();
|
|
8927
9902
|
if (container) {
|
|
8928
9903
|
if (!inventory) throw new CliError("INSTANCE_INVENTORY_MISSING", "existing container has no trusted inventory", EXIT.ENVIRONMENT);
|
|
8929
|
-
assertOwnedContainer(container, inventory);
|
|
8930
9904
|
}
|
|
8931
9905
|
return {
|
|
8932
9906
|
cliVersion: VERSION,
|
|
@@ -8959,9 +9933,9 @@ program2.name("wx").description("Single-instance agent-wechat CLI").version(VERS
|
|
|
8959
9933
|
program2.showSuggestionAfterError();
|
|
8960
9934
|
program2.configureOutput({ outputError: (text) => process.stderr.write(text) });
|
|
8961
9935
|
program2.exitOverride();
|
|
8962
|
-
program2.command("start").description("Start the compatible single-instance container").option("--image <reference>", `exact ${GHCR_IMAGE} semver tag or digest`).option("--pull", "pull and resolve the selected image").option("--offline", "offline mode; never pull").option("--proxy <url>", "transparent proxy URL").action((options) => action(async () => {
|
|
9936
|
+
program2.command("start").description("Start the compatible single-instance container").option("--image <reference>", `exact ${GHCR_IMAGE} semver/commit tag or digest`).option("--pull", "pull and resolve the selected image").option("--offline", "offline mode; never pull").option("--proxy <url>", "transparent proxy URL").option("--outbound-config <file>", "TOML outbound policy file (never logged)").option("--outbound-queue-capacity <count>", "outbound queue capacity").option("--outbound-disabled", "disable outbound sending").option("--outbound-quiet-start <minutes>", "quiet-hours start minute").option("--outbound-quiet-end <minutes>", "quiet-hours end minute").option("--outbound-hourly-budget <count>", "hourly outbound budget").option("--outbound-daily-budget <count>", "daily outbound budget").option("--outbound-chat-cooldown-ms <ms>", "per-chat cooldown").option("--outbound-min-spacing-ms <ms>", "minimum spacing").option("--outbound-jitter-ms <ms>", "spacing jitter").option("--outbound-long-tail-jitter-ms <ms>", "long-tail jitter").option("--outbound-long-tail-chance-percent <percent>", "long-tail chance").option("--outbound-task-ttl-ms <ms>", "task TTL").option("--outbound-idempotency-ttl-ms <ms>", "idempotency TTL").option("--outbound-idempotency-max-rows <rows>", "idempotency max rows").action((options) => action(async () => {
|
|
8963
9937
|
if (options.pull && options.offline) throw new CliError("ARGUMENT_CONFLICT", "--pull and --offline are mutually exclusive", EXIT.ARGUMENT);
|
|
8964
|
-
const inventory = await startInstance({ identity: ensureDeviceIdentity(CONFIG_DIR), token: ensureToken(), localDefault: localBuildImage(), noPull: options.offline === true, ...options });
|
|
9938
|
+
const inventory = await startInstance({ identity: ensureDeviceIdentity(CONFIG_DIR), token: ensureToken(), localDefault: localBuildImage(), noPull: options.offline === true, outbound: resolveOutboundConfig(options.outboundConfig, Object.fromEntries([["AGENT_WECHAT_OUTBOUND_QUEUE_CAPACITY", options.outboundQueueCapacity], ["AGENT_WECHAT_OUTBOUND_DISABLED", options.outboundDisabled ? "true" : void 0], ["AGENT_WECHAT_QUIET_START_MIN", options.outboundQuietStart], ["AGENT_WECHAT_QUIET_END_MIN", options.outboundQuietEnd], ["AGENT_WECHAT_HOURLY_BUDGET", options.outboundHourlyBudget], ["AGENT_WECHAT_DAILY_BUDGET", options.outboundDailyBudget], ["AGENT_WECHAT_CHAT_COOLDOWN_MS", options.outboundChatCooldownMs], ["AGENT_WECHAT_OUTBOUND_MIN_SPACING_MS", options.outboundMinSpacingMs], ["AGENT_WECHAT_OUTBOUND_JITTER_MS", options.outboundJitterMs], ["AGENT_WECHAT_OUTBOUND_LONG_TAIL_JITTER_MS", options.outboundLongTailJitterMs], ["AGENT_WECHAT_OUTBOUND_LONG_TAIL_CHANCE_PERCENT", options.outboundLongTailChancePercent], ["AGENT_WECHAT_OUTBOUND_TASK_TTL_MS", options.outboundTaskTtlMs], ["AGENT_WECHAT_OUTBOUND_IDEMPOTENCY_TTL_MS", options.outboundIdempotencyTtlMs], ["AGENT_WECHAT_OUTBOUND_IDEMPOTENCY_MAX_ROWS", options.outboundIdempotencyMaxRows]].filter(([, v]) => v !== void 0))), ...options });
|
|
8965
9939
|
output({ container: inventory.containerName, imageDigest: inventory.imageDigest, port: inventory.port }, () => console.log(`Started ${inventory.containerName} on port ${inventory.port}`));
|
|
8966
9940
|
}));
|
|
8967
9941
|
program2.command("stop").description("Stop and remove the container; preserve data unless --purge").option("--purge", "delete every resource in the trusted default-instance inventory").option("--yes", "skip only the interactive confirmation").action((options) => action(async () => {
|
|
@@ -8976,12 +9950,59 @@ program2.command("stop").description("Stop and remove the container; preserve da
|
|
|
8976
9950
|
output(result, () => console.log(result.stopped ? "Container stopped and removed" : "Container is absent"));
|
|
8977
9951
|
}
|
|
8978
9952
|
}));
|
|
8979
|
-
program2.command("restart").description("Restart while preserving data").action(() => action(async () => {
|
|
9953
|
+
program2.command("restart").description("Restart while preserving data").option("--outbound-config <file>", "TOML outbound policy file (never logged)").option("--outbound-queue-capacity <count>", "outbound queue capacity").option("--outbound-disabled", "disable outbound sending").option("--outbound-quiet-start <minutes>").option("--outbound-quiet-end <minutes>").option("--outbound-hourly-budget <count>").option("--outbound-daily-budget <count>").option("--outbound-chat-cooldown-ms <ms>").option("--outbound-min-spacing-ms <ms>").option("--outbound-jitter-ms <ms>").option("--outbound-long-tail-jitter-ms <ms>").option("--outbound-long-tail-chance-percent <percent>").option("--outbound-task-ttl-ms <ms>").option("--outbound-idempotency-ttl-ms <ms>").option("--outbound-idempotency-max-rows <rows>").action((options) => action(async () => {
|
|
8980
9954
|
const inventory = loadInventory();
|
|
8981
9955
|
if (!inventory) throw new CliError("INSTANCE_INVENTORY_MISSING", "start the instance first", EXIT.SERVICE);
|
|
8982
|
-
|
|
8983
|
-
const
|
|
8984
|
-
|
|
9956
|
+
const oldContainer = inspectContainer();
|
|
9957
|
+
const cliOverrides = Object.fromEntries([
|
|
9958
|
+
["AGENT_WECHAT_OUTBOUND_QUEUE_CAPACITY", options.outboundQueueCapacity],
|
|
9959
|
+
["AGENT_WECHAT_OUTBOUND_DISABLED", options.outboundDisabled ? "true" : void 0],
|
|
9960
|
+
["AGENT_WECHAT_QUIET_START_MIN", options.outboundQuietStart],
|
|
9961
|
+
["AGENT_WECHAT_QUIET_END_MIN", options.outboundQuietEnd],
|
|
9962
|
+
["AGENT_WECHAT_HOURLY_BUDGET", options.outboundHourlyBudget],
|
|
9963
|
+
["AGENT_WECHAT_DAILY_BUDGET", options.outboundDailyBudget],
|
|
9964
|
+
["AGENT_WECHAT_CHAT_COOLDOWN_MS", options.outboundChatCooldownMs],
|
|
9965
|
+
["AGENT_WECHAT_OUTBOUND_MIN_SPACING_MS", options.outboundMinSpacingMs],
|
|
9966
|
+
["AGENT_WECHAT_OUTBOUND_JITTER_MS", options.outboundJitterMs],
|
|
9967
|
+
["AGENT_WECHAT_OUTBOUND_LONG_TAIL_JITTER_MS", options.outboundLongTailJitterMs],
|
|
9968
|
+
["AGENT_WECHAT_OUTBOUND_LONG_TAIL_CHANCE_PERCENT", options.outboundLongTailChancePercent],
|
|
9969
|
+
["AGENT_WECHAT_OUTBOUND_TASK_TTL_MS", options.outboundTaskTtlMs],
|
|
9970
|
+
["AGENT_WECHAT_OUTBOUND_IDEMPOTENCY_TTL_MS", options.outboundIdempotencyTtlMs],
|
|
9971
|
+
["AGENT_WECHAT_OUTBOUND_IDEMPOTENCY_MAX_ROWS", options.outboundIdempotencyMaxRows]
|
|
9972
|
+
].filter(([, v]) => v !== void 0));
|
|
9973
|
+
const outbound = resolveOutboundConfig(options.outboundConfig, cliOverrides);
|
|
9974
|
+
const oldOutbound = oldContainer ? outboundFromContainer(oldContainer) : {};
|
|
9975
|
+
const effectiveOutbound = { ...oldOutbound, ...outbound };
|
|
9976
|
+
const previousInventory = inventory;
|
|
9977
|
+
const rollbackName = `${CONTAINER_NAME}-rollback`;
|
|
9978
|
+
let oldStopped = false;
|
|
9979
|
+
let oldRenamed = false;
|
|
9980
|
+
try {
|
|
9981
|
+
if (oldContainer) {
|
|
9982
|
+
if (oldContainer.State?.Running) {
|
|
9983
|
+
stopContainer(oldContainer.Id);
|
|
9984
|
+
oldStopped = true;
|
|
9985
|
+
}
|
|
9986
|
+
renameContainer(oldContainer.Id, rollbackName);
|
|
9987
|
+
oldRenamed = true;
|
|
9988
|
+
}
|
|
9989
|
+
const result = await startInstance({ identity: ensureDeviceIdentity(CONFIG_DIR), token: ensureToken(), image: inventory.imageDigest || inventory.imageRef, noPull: true, localDefault: localBuildImage(), outbound: effectiveOutbound });
|
|
9990
|
+
if (oldRenamed) removeContainer(rollbackName);
|
|
9991
|
+
output({ restarted: true, imageDigest: result.imageDigest }, () => console.log("Instance restarted"));
|
|
9992
|
+
} catch (error) {
|
|
9993
|
+
try {
|
|
9994
|
+
const failed = inspectContainer();
|
|
9995
|
+
if (failed && failed.Id !== oldContainer?.Id) removeContainer(failed.Id);
|
|
9996
|
+
if (oldContainer) {
|
|
9997
|
+
if (oldRenamed) renameContainer(rollbackName, CONTAINER_NAME);
|
|
9998
|
+
if (oldStopped && oldContainer.State?.Running) startContainer(CONTAINER_NAME);
|
|
9999
|
+
}
|
|
10000
|
+
saveInventory(previousInventory);
|
|
10001
|
+
} catch {
|
|
10002
|
+
throw new CliError("ROLLBACK_FAILED", "restart failed and rollback was incomplete", EXIT.ROLLBACK);
|
|
10003
|
+
}
|
|
10004
|
+
throw error;
|
|
10005
|
+
}
|
|
8985
10006
|
}));
|
|
8986
10007
|
program2.command("status").description("Show read-only lifecycle and authentication status").action(() => action(async () => {
|
|
8987
10008
|
const status = programStatus();
|
|
@@ -9008,7 +10029,7 @@ program2.command("doctor").description("Run read-only environment and compatibil
|
|
|
9008
10029
|
const checks = programStatus();
|
|
9009
10030
|
checks.architecture = os2.arch();
|
|
9010
10031
|
checks.token = readToken() ? "present" : "absent";
|
|
9011
|
-
checks.configPermissions =
|
|
10032
|
+
checks.configPermissions = fs5.existsSync(CONFIG_DIR) ? (fs5.statSync(CONFIG_DIR).mode & 511).toString(8) : "absent";
|
|
9012
10033
|
if (checks.container === "running") {
|
|
9013
10034
|
try {
|
|
9014
10035
|
checks.health = (await fetch(`http://localhost:${DEFAULT_PORT}/health`)).ok ? "ok" : "failed";
|
|
@@ -9067,6 +10088,13 @@ chats.command("mark-read <chat-id>").action((chatId) => action(async () => {
|
|
|
9067
10088
|
if (!result.ok) throw new CliError(result.errorCode || "MARK_READ_FAILED", result.error || "mark-read was not verified", EXIT.SERVICE);
|
|
9068
10089
|
output(result, () => console.log(`${chatId}: ${result.beforeUnread} -> ${result.afterUnread}`));
|
|
9069
10090
|
}));
|
|
10091
|
+
chats.command("members <group-id>").description("List a bounded page of group members read-only").option("--limit <number>", "page size", "50").option("--cursor <cursor>", "opaque next-page cursor").action((groupId, options) => action(async () => {
|
|
10092
|
+
const page = await client().listGroupMembersPage(groupId, integer(options.limit, "limit", 1, 100), options.cursor);
|
|
10093
|
+
output(page, () => {
|
|
10094
|
+
for (const member of page.items) console.log(`${member.memberId} ${member.displayName} ${member.groupAlias ?? ""}`);
|
|
10095
|
+
if (page.nextCursor) console.error(`next cursor: ${page.nextCursor}`);
|
|
10096
|
+
});
|
|
10097
|
+
}));
|
|
9070
10098
|
var contacts = program2.command("contacts").description("List contacts read-only").option("--limit <number>", "page size", "200").option("--cursor <cursor>", "opaque next-page cursor").action((options) => action(async () => {
|
|
9071
10099
|
const page = await client().listContactsPage(integer(options.limit, "limit", 1, 200), options.cursor);
|
|
9072
10100
|
output(page, () => {
|
|
@@ -9083,8 +10111,8 @@ program2.command("messages <chat-id>").description("Read messages without openin
|
|
|
9083
10111
|
output(page, () => renderMessages(page));
|
|
9084
10112
|
}));
|
|
9085
10113
|
program2.command("send <chat-id>").description("Send exactly one payload to a stable chat ID").option("--text <message>").option("--image <path>").option("--file <path>").option("--idempotency-key <key>", "stable key for retry/reconciliation").option("--confirm-similar", "confirm operator-reviewed similar text").action((chatId, options) => action(async () => {
|
|
9086
|
-
const image = options.image ? { data: regularUpload(options.image).toString("base64"), mimeType:
|
|
9087
|
-
const file = options.file ? { data: regularUpload(options.file).toString("base64"), filename:
|
|
10114
|
+
const image = options.image ? { data: regularUpload(options.image).toString("base64"), mimeType: path5.extname(options.image).toLowerCase() === ".jpg" ? "image/jpeg" : "image/png" } : void 0;
|
|
10115
|
+
const file = options.file ? { data: regularUpload(options.file).toString("base64"), filename: path5.basename(options.file) } : void 0;
|
|
9088
10116
|
let params;
|
|
9089
10117
|
try {
|
|
9090
10118
|
params = buildCliSendParams({ chatId, text: options.text, image, file, confirmSimilar: options.confirmSimilar, idempotencyKey: options.idempotencyKey });
|
|
@@ -9098,7 +10126,7 @@ program2.command("send <chat-id>").description("Send exactly one payload to a st
|
|
|
9098
10126
|
}
|
|
9099
10127
|
output(result, () => console.log("Message sent"));
|
|
9100
10128
|
}));
|
|
9101
|
-
program2.command("upgrade").description("Check CLI/image upgrades without claiming atomic self-upgrade").addOption(new Option("--check", "read-only upgrade check")).addOption(new Option("--cli", "print an exact npm CLI upgrade command")).addOption(new Option("--image <reference>", "transactionally rebuild with an exact
|
|
10129
|
+
program2.command("upgrade").description("Check CLI/image upgrades without claiming atomic self-upgrade").addOption(new Option("--check", "read-only upgrade check")).addOption(new Option("--cli", "print an exact npm CLI upgrade command")).addOption(new Option("--image <reference>", "transactionally rebuild with an exact semver/commit tag or digest")).action((options) => action(async () => {
|
|
9102
10130
|
const selected = [options.check === true, options.cli === true, typeof options.image === "string"].filter(Boolean).length;
|
|
9103
10131
|
if (selected > 1) throw new CliError("ARGUMENT_CONFLICT", "--check, --cli, and --image are mutually exclusive", EXIT.ARGUMENT);
|
|
9104
10132
|
if (options.cli) {
|
|
@@ -9132,9 +10160,9 @@ for (const [oldName, replacement] of [["up", "start"], ["down", "stop"], ["updat
|
|
|
9132
10160
|
}
|
|
9133
10161
|
function sameEntrypoint(left, right) {
|
|
9134
10162
|
try {
|
|
9135
|
-
return
|
|
10163
|
+
return fs5.realpathSync(left) === fs5.realpathSync(right);
|
|
9136
10164
|
} catch {
|
|
9137
|
-
return
|
|
10165
|
+
return path5.resolve(left) === path5.resolve(right);
|
|
9138
10166
|
}
|
|
9139
10167
|
}
|
|
9140
10168
|
if (process.argv[1] && sameEntrypoint(process.argv[1], fileURLToPath(import.meta.url))) {
|
|
@@ -9148,3 +10176,42 @@ if (process.argv[1] && sameEntrypoint(process.argv[1], fileURLToPath(import.meta
|
|
|
9148
10176
|
process.exitCode = EXIT.SERVICE;
|
|
9149
10177
|
});
|
|
9150
10178
|
}
|
|
10179
|
+
/*! Bundled license information:
|
|
10180
|
+
|
|
10181
|
+
smol-toml/dist/error.js:
|
|
10182
|
+
smol-toml/dist/util.js:
|
|
10183
|
+
smol-toml/dist/date.js:
|
|
10184
|
+
smol-toml/dist/primitive.js:
|
|
10185
|
+
smol-toml/dist/extract.js:
|
|
10186
|
+
smol-toml/dist/struct.js:
|
|
10187
|
+
smol-toml/dist/parse.js:
|
|
10188
|
+
smol-toml/dist/stringify.js:
|
|
10189
|
+
smol-toml/dist/index.js:
|
|
10190
|
+
(*!
|
|
10191
|
+
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
10192
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
10193
|
+
*
|
|
10194
|
+
* Redistribution and use in source and binary forms, with or without
|
|
10195
|
+
* modification, are permitted provided that the following conditions are met:
|
|
10196
|
+
*
|
|
10197
|
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
10198
|
+
* list of conditions and the following disclaimer.
|
|
10199
|
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
10200
|
+
* this list of conditions and the following disclaimer in the
|
|
10201
|
+
* documentation and/or other materials provided with the distribution.
|
|
10202
|
+
* 3. Neither the name of the copyright holder nor the names of its contributors
|
|
10203
|
+
* may be used to endorse or promote products derived from this software without
|
|
10204
|
+
* specific prior written permission.
|
|
10205
|
+
*
|
|
10206
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
10207
|
+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
10208
|
+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
10209
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
10210
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
10211
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
10212
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
10213
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
10214
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
10215
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
10216
|
+
*)
|
|
10217
|
+
*/
|