@kyan-du/agent-wechat-cli 0.13.3 → 0.14.1
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 +1191 -123
- 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,19 +7805,20 @@ 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, signal) {
|
|
7817
|
+
const res = await fetch(`${this.base}${path6}`, {
|
|
7739
7818
|
method: "POST",
|
|
7740
7819
|
headers: this.headers,
|
|
7741
|
-
body: body != null ? JSON.stringify(body) : void 0
|
|
7820
|
+
body: body != null ? JSON.stringify(body) : void 0,
|
|
7821
|
+
signal
|
|
7742
7822
|
});
|
|
7743
7823
|
if (!res.ok)
|
|
7744
7824
|
await throwHttpError(res);
|
|
@@ -7783,8 +7863,14 @@ var WeChatClient = class {
|
|
|
7783
7863
|
async markChatRead(chatId) {
|
|
7784
7864
|
return this.post(`/api/chats/${encodeURIComponent(chatId)}/mark-read`);
|
|
7785
7865
|
}
|
|
7786
|
-
async openChat(chatId, clearUnreads) {
|
|
7787
|
-
return this.post(`/api/chats/${encodeURIComponent(chatId)}/open${qs({ clearUnreads })}
|
|
7866
|
+
async openChat(chatId, clearUnreads, signal, executionTimeoutMs) {
|
|
7867
|
+
return this.post(`/api/chats/${encodeURIComponent(chatId)}/open${qs({ clearUnreads, executionTimeoutMs })}`, void 0, signal);
|
|
7868
|
+
}
|
|
7869
|
+
async listGroupMembersPage(groupId, limit, cursor) {
|
|
7870
|
+
const page = groupMembersPageSchema.parse(await this.get(`/api/groups/${encodeURIComponent(groupId)}/members${qs({ limit, cursor })}`));
|
|
7871
|
+
if (page.errorCode)
|
|
7872
|
+
throw new WeChatHttpError(400, "Bad Request", page.errorCode, page.errorCode);
|
|
7873
|
+
return { ...page, nextCursor: page.nextCursor ?? void 0 };
|
|
7788
7874
|
}
|
|
7789
7875
|
// ---- Contacts ----
|
|
7790
7876
|
async listContactsPage(limit, cursor) {
|
|
@@ -7809,6 +7895,17 @@ var WeChatClient = class {
|
|
|
7809
7895
|
async listMessages(chatId, limit) {
|
|
7810
7896
|
return (await this.listMessagesPage(chatId, limit)).items;
|
|
7811
7897
|
}
|
|
7898
|
+
async syncChat(chatId, options = {}) {
|
|
7899
|
+
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 })}`);
|
|
7900
|
+
if (raw && typeof raw === "object" && typeof raw.errorCode === "string") {
|
|
7901
|
+
const errorCode = raw.errorCode;
|
|
7902
|
+
throw new WeChatHttpError(400, "Bad Request", errorCode, errorCode);
|
|
7903
|
+
}
|
|
7904
|
+
const page = chatSyncPageSchema.parse(raw);
|
|
7905
|
+
if (page.errorCode)
|
|
7906
|
+
throw new WeChatHttpError(400, "Bad Request", page.errorCode, page.errorCode);
|
|
7907
|
+
return { ...page, nextCursor: page.nextCursor ?? void 0 };
|
|
7908
|
+
}
|
|
7812
7909
|
async getMedia(chatId, localId) {
|
|
7813
7910
|
return this.get(`/api/messages/${encodeURIComponent(chatId)}/media/${localId}`);
|
|
7814
7911
|
}
|
|
@@ -8178,9 +8275,8 @@ function buildDockerRunArgs(identity, opts) {
|
|
|
8178
8275
|
"-e",
|
|
8179
8276
|
`AGENT_WECHAT_MAC=${identity.mac}`
|
|
8180
8277
|
];
|
|
8181
|
-
if (opts.proxy) {
|
|
8182
|
-
|
|
8183
|
-
}
|
|
8278
|
+
if (opts.proxy) args.push("-e", `PROXY=${opts.proxy}`);
|
|
8279
|
+
for (const [key, value] of Object.entries(opts.outbound ?? {})) args.push("-e", `${key}=${value}`);
|
|
8184
8280
|
args.push(opts.image);
|
|
8185
8281
|
return args;
|
|
8186
8282
|
}
|
|
@@ -8210,17 +8306,18 @@ function buildCliSendParams(options) {
|
|
|
8210
8306
|
var FORK_IMAGE = "ghcr.io/kyan-du/agent-wechat";
|
|
8211
8307
|
var VERSION_TAG = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?$/;
|
|
8212
8308
|
var DIGEST = /^sha256:[0-9a-f]{64}$/;
|
|
8309
|
+
var COMMIT_TAG = /^[a-f0-9]{7}$/;
|
|
8213
8310
|
function validatePublishedImageReference(reference) {
|
|
8214
8311
|
const tagPrefix = `${FORK_IMAGE}:`;
|
|
8215
8312
|
const digestPrefix = `${FORK_IMAGE}@`;
|
|
8216
|
-
if (reference.startsWith(tagPrefix) && VERSION_TAG.test(reference.slice(tagPrefix.length))) {
|
|
8313
|
+
if (reference.startsWith(tagPrefix) && (VERSION_TAG.test(reference.slice(tagPrefix.length)) || COMMIT_TAG.test(reference.slice(tagPrefix.length)))) {
|
|
8217
8314
|
return reference;
|
|
8218
8315
|
}
|
|
8219
8316
|
if (reference.startsWith(digestPrefix) && DIGEST.test(reference.slice(digestPrefix.length))) {
|
|
8220
8317
|
return reference;
|
|
8221
8318
|
}
|
|
8222
8319
|
throw new Error(
|
|
8223
|
-
`Invalid image reference. Use ${FORK_IMAGE}:<semver
|
|
8320
|
+
`Invalid image reference. Use ${FORK_IMAGE}:<semver>, ${FORK_IMAGE}:<7-character commit SHA>, or ${FORK_IMAGE}@sha256:<64 lowercase hex characters>.`
|
|
8224
8321
|
);
|
|
8225
8322
|
}
|
|
8226
8323
|
function localBuildImage(platform = process.platform, arch = process.arch) {
|
|
@@ -8326,8 +8423,8 @@ function assertSafePurgePath(target, root) {
|
|
|
8326
8423
|
|
|
8327
8424
|
// src/lifecycle.ts
|
|
8328
8425
|
import { execFileSync } from "node:child_process";
|
|
8329
|
-
import
|
|
8330
|
-
import
|
|
8426
|
+
import fs4 from "node:fs";
|
|
8427
|
+
import path4 from "node:path";
|
|
8331
8428
|
|
|
8332
8429
|
// src/exit-contract.ts
|
|
8333
8430
|
var EXIT = {
|
|
@@ -8369,47 +8466,910 @@ function failure(error) {
|
|
|
8369
8466
|
};
|
|
8370
8467
|
}
|
|
8371
8468
|
|
|
8372
|
-
// src/
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8469
|
+
// src/outbound-config.ts
|
|
8470
|
+
import fs3 from "node:fs";
|
|
8471
|
+
import path3 from "node:path";
|
|
8472
|
+
|
|
8473
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/error.js
|
|
8474
|
+
function getLineColFromPtr(string, ptr) {
|
|
8475
|
+
let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
|
|
8476
|
+
return [lines.length, lines.pop().length + 1];
|
|
8477
|
+
}
|
|
8478
|
+
function makeCodeBlock(string, line, column) {
|
|
8479
|
+
let lines = string.split(/\r\n|\n|\r/g);
|
|
8480
|
+
let codeblock = "";
|
|
8481
|
+
let numberLen = (Math.log10(line + 1) | 0) + 1;
|
|
8482
|
+
for (let i = line - 1; i <= line + 1; i++) {
|
|
8483
|
+
let l = lines[i - 1];
|
|
8484
|
+
if (!l)
|
|
8485
|
+
continue;
|
|
8486
|
+
codeblock += i.toString().padEnd(numberLen, " ");
|
|
8487
|
+
codeblock += ": ";
|
|
8488
|
+
codeblock += l;
|
|
8489
|
+
codeblock += "\n";
|
|
8490
|
+
if (i === line) {
|
|
8491
|
+
codeblock += " ".repeat(numberLen + column + 2);
|
|
8492
|
+
codeblock += "^\n";
|
|
8493
|
+
}
|
|
8494
|
+
}
|
|
8495
|
+
return codeblock;
|
|
8496
|
+
}
|
|
8497
|
+
var TomlError = class extends Error {
|
|
8498
|
+
line;
|
|
8499
|
+
column;
|
|
8500
|
+
codeblock;
|
|
8501
|
+
constructor(message, options) {
|
|
8502
|
+
const [line, column] = getLineColFromPtr(options.toml, options.ptr);
|
|
8503
|
+
const codeblock = makeCodeBlock(options.toml, line, column);
|
|
8504
|
+
super(`Invalid TOML document: ${message}
|
|
8505
|
+
|
|
8506
|
+
${codeblock}`, options);
|
|
8507
|
+
this.line = line;
|
|
8508
|
+
this.column = column;
|
|
8509
|
+
this.codeblock = codeblock;
|
|
8510
|
+
}
|
|
8511
|
+
};
|
|
8512
|
+
|
|
8513
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/util.js
|
|
8514
|
+
function isEscaped(str, ptr) {
|
|
8515
|
+
let i = 0;
|
|
8516
|
+
while (str[ptr - ++i] === "\\")
|
|
8517
|
+
;
|
|
8518
|
+
return --i && i % 2;
|
|
8519
|
+
}
|
|
8520
|
+
function indexOfNewline(str, start = 0, end = str.length) {
|
|
8521
|
+
let idx = str.indexOf("\n", start);
|
|
8522
|
+
if (str[idx - 1] === "\r")
|
|
8523
|
+
idx--;
|
|
8524
|
+
return idx <= end ? idx : -1;
|
|
8525
|
+
}
|
|
8526
|
+
function skipComment(str, ptr) {
|
|
8527
|
+
for (let i = ptr; i < str.length; i++) {
|
|
8528
|
+
let c = str[i];
|
|
8529
|
+
if (c === "\n")
|
|
8530
|
+
return i;
|
|
8531
|
+
if (c === "\r" && str[i + 1] === "\n")
|
|
8532
|
+
return i + 1;
|
|
8533
|
+
if (c < " " && c !== " " || c === "\x7F") {
|
|
8534
|
+
throw new TomlError("control characters are not allowed in comments", {
|
|
8535
|
+
toml: str,
|
|
8536
|
+
ptr
|
|
8537
|
+
});
|
|
8538
|
+
}
|
|
8539
|
+
}
|
|
8540
|
+
return str.length;
|
|
8541
|
+
}
|
|
8542
|
+
function skipVoid(str, ptr, banNewLines, banComments) {
|
|
8543
|
+
let c;
|
|
8544
|
+
while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n"))
|
|
8545
|
+
ptr++;
|
|
8546
|
+
return banComments || c !== "#" ? ptr : skipVoid(str, skipComment(str, ptr), banNewLines);
|
|
8547
|
+
}
|
|
8548
|
+
function skipUntil(str, ptr, sep, end, banNewLines = false) {
|
|
8549
|
+
if (!end) {
|
|
8550
|
+
ptr = indexOfNewline(str, ptr);
|
|
8551
|
+
return ptr < 0 ? str.length : ptr;
|
|
8552
|
+
}
|
|
8553
|
+
for (let i = ptr; i < str.length; i++) {
|
|
8554
|
+
let c = str[i];
|
|
8555
|
+
if (c === "#") {
|
|
8556
|
+
i = indexOfNewline(str, i);
|
|
8557
|
+
} else if (c === sep) {
|
|
8558
|
+
return i + 1;
|
|
8559
|
+
} else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
|
|
8560
|
+
return i;
|
|
8561
|
+
}
|
|
8562
|
+
}
|
|
8563
|
+
throw new TomlError("cannot find end of structure", {
|
|
8564
|
+
toml: str,
|
|
8565
|
+
ptr
|
|
8566
|
+
});
|
|
8567
|
+
}
|
|
8568
|
+
function getStringEnd(str, seek) {
|
|
8569
|
+
let first = str[seek];
|
|
8570
|
+
let target = first === str[seek + 1] && str[seek + 1] === str[seek + 2] ? str.slice(seek, seek + 3) : first;
|
|
8571
|
+
seek += target.length - 1;
|
|
8572
|
+
do
|
|
8573
|
+
seek = str.indexOf(target, ++seek);
|
|
8574
|
+
while (seek > -1 && first !== "'" && isEscaped(str, seek));
|
|
8575
|
+
if (seek > -1) {
|
|
8576
|
+
seek += target.length;
|
|
8577
|
+
if (target.length > 1) {
|
|
8578
|
+
if (str[seek] === first)
|
|
8579
|
+
seek++;
|
|
8580
|
+
if (str[seek] === first)
|
|
8581
|
+
seek++;
|
|
8582
|
+
}
|
|
8583
|
+
}
|
|
8584
|
+
return seek;
|
|
8585
|
+
}
|
|
8586
|
+
|
|
8587
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/date.js
|
|
8588
|
+
var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
|
|
8589
|
+
var TomlDate = class _TomlDate extends Date {
|
|
8590
|
+
#hasDate = false;
|
|
8591
|
+
#hasTime = false;
|
|
8592
|
+
#offset = null;
|
|
8593
|
+
constructor(date) {
|
|
8594
|
+
let hasDate = true;
|
|
8595
|
+
let hasTime = true;
|
|
8596
|
+
let offset = "Z";
|
|
8597
|
+
if (typeof date === "string") {
|
|
8598
|
+
let match = date.match(DATE_TIME_RE);
|
|
8599
|
+
if (match) {
|
|
8600
|
+
if (!match[1]) {
|
|
8601
|
+
hasDate = false;
|
|
8602
|
+
date = `0000-01-01T${date}`;
|
|
8603
|
+
}
|
|
8604
|
+
hasTime = !!match[2];
|
|
8605
|
+
hasTime && date[10] === " " && (date = date.replace(" ", "T"));
|
|
8606
|
+
if (match[2] && +match[2] > 23) {
|
|
8607
|
+
date = "";
|
|
8608
|
+
} else {
|
|
8609
|
+
offset = match[3] || null;
|
|
8610
|
+
date = date.toUpperCase();
|
|
8611
|
+
if (!offset && hasTime)
|
|
8612
|
+
date += "Z";
|
|
8613
|
+
}
|
|
8614
|
+
} else {
|
|
8615
|
+
date = "";
|
|
8616
|
+
}
|
|
8617
|
+
}
|
|
8618
|
+
super(date);
|
|
8619
|
+
if (!isNaN(this.getTime())) {
|
|
8620
|
+
this.#hasDate = hasDate;
|
|
8621
|
+
this.#hasTime = hasTime;
|
|
8622
|
+
this.#offset = offset;
|
|
8623
|
+
}
|
|
8624
|
+
}
|
|
8625
|
+
isDateTime() {
|
|
8626
|
+
return this.#hasDate && this.#hasTime;
|
|
8627
|
+
}
|
|
8628
|
+
isLocal() {
|
|
8629
|
+
return !this.#hasDate || !this.#hasTime || !this.#offset;
|
|
8630
|
+
}
|
|
8631
|
+
isDate() {
|
|
8632
|
+
return this.#hasDate && !this.#hasTime;
|
|
8633
|
+
}
|
|
8634
|
+
isTime() {
|
|
8635
|
+
return this.#hasTime && !this.#hasDate;
|
|
8636
|
+
}
|
|
8637
|
+
isValid() {
|
|
8638
|
+
return this.#hasDate || this.#hasTime;
|
|
8639
|
+
}
|
|
8640
|
+
toISOString() {
|
|
8641
|
+
let iso = super.toISOString();
|
|
8642
|
+
if (this.isDate())
|
|
8643
|
+
return iso.slice(0, 10);
|
|
8644
|
+
if (this.isTime())
|
|
8645
|
+
return iso.slice(11, 23);
|
|
8646
|
+
if (this.#offset === null)
|
|
8647
|
+
return iso.slice(0, -1);
|
|
8648
|
+
if (this.#offset === "Z")
|
|
8649
|
+
return iso;
|
|
8650
|
+
let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
|
|
8651
|
+
offset = this.#offset[0] === "-" ? offset : -offset;
|
|
8652
|
+
let offsetDate = new Date(this.getTime() - offset * 6e4);
|
|
8653
|
+
return offsetDate.toISOString().slice(0, -1) + this.#offset;
|
|
8654
|
+
}
|
|
8655
|
+
static wrapAsOffsetDateTime(jsDate, offset = "Z") {
|
|
8656
|
+
let date = new _TomlDate(jsDate);
|
|
8657
|
+
date.#offset = offset;
|
|
8658
|
+
return date;
|
|
8659
|
+
}
|
|
8660
|
+
static wrapAsLocalDateTime(jsDate) {
|
|
8661
|
+
let date = new _TomlDate(jsDate);
|
|
8662
|
+
date.#offset = null;
|
|
8663
|
+
return date;
|
|
8664
|
+
}
|
|
8665
|
+
static wrapAsLocalDate(jsDate) {
|
|
8666
|
+
let date = new _TomlDate(jsDate);
|
|
8667
|
+
date.#hasTime = false;
|
|
8668
|
+
date.#offset = null;
|
|
8669
|
+
return date;
|
|
8670
|
+
}
|
|
8671
|
+
static wrapAsLocalTime(jsDate) {
|
|
8672
|
+
let date = new _TomlDate(jsDate);
|
|
8673
|
+
date.#hasDate = false;
|
|
8674
|
+
date.#offset = null;
|
|
8675
|
+
return date;
|
|
8676
|
+
}
|
|
8677
|
+
};
|
|
8678
|
+
|
|
8679
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/primitive.js
|
|
8680
|
+
var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
|
|
8681
|
+
var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
|
|
8682
|
+
var LEADING_ZERO = /^[+-]?0[0-9_]/;
|
|
8683
|
+
var ESCAPE_REGEX = /^[0-9a-f]{2,8}$/i;
|
|
8684
|
+
var ESC_MAP = {
|
|
8685
|
+
b: "\b",
|
|
8686
|
+
t: " ",
|
|
8687
|
+
n: "\n",
|
|
8688
|
+
f: "\f",
|
|
8689
|
+
r: "\r",
|
|
8690
|
+
e: "\x1B",
|
|
8691
|
+
'"': '"',
|
|
8692
|
+
"\\": "\\"
|
|
8693
|
+
};
|
|
8694
|
+
function parseString(str, ptr = 0, endPtr = str.length) {
|
|
8695
|
+
let isLiteral = str[ptr] === "'";
|
|
8696
|
+
let isMultiline = str[ptr++] === str[ptr] && str[ptr] === str[ptr + 1];
|
|
8697
|
+
if (isMultiline) {
|
|
8698
|
+
endPtr -= 2;
|
|
8699
|
+
if (str[ptr += 2] === "\r")
|
|
8700
|
+
ptr++;
|
|
8701
|
+
if (str[ptr] === "\n")
|
|
8702
|
+
ptr++;
|
|
8703
|
+
}
|
|
8704
|
+
let tmp = 0;
|
|
8705
|
+
let isEscape;
|
|
8706
|
+
let parsed = "";
|
|
8707
|
+
let sliceStart = ptr;
|
|
8708
|
+
while (ptr < endPtr - 1) {
|
|
8709
|
+
let c = str[ptr++];
|
|
8710
|
+
if (c === "\n" || c === "\r" && str[ptr] === "\n") {
|
|
8711
|
+
if (!isMultiline) {
|
|
8712
|
+
throw new TomlError("newlines are not allowed in strings", {
|
|
8713
|
+
toml: str,
|
|
8714
|
+
ptr: ptr - 1
|
|
8715
|
+
});
|
|
8716
|
+
}
|
|
8717
|
+
} else if (c < " " && c !== " " || c === "\x7F") {
|
|
8718
|
+
throw new TomlError("control characters are not allowed in strings", {
|
|
8719
|
+
toml: str,
|
|
8720
|
+
ptr: ptr - 1
|
|
8721
|
+
});
|
|
8722
|
+
}
|
|
8723
|
+
if (isEscape) {
|
|
8724
|
+
isEscape = false;
|
|
8725
|
+
if (c === "x" || c === "u" || c === "U") {
|
|
8726
|
+
let code = str.slice(ptr, ptr += c === "x" ? 2 : c === "u" ? 4 : 8);
|
|
8727
|
+
if (!ESCAPE_REGEX.test(code)) {
|
|
8728
|
+
throw new TomlError("invalid unicode escape", {
|
|
8729
|
+
toml: str,
|
|
8730
|
+
ptr: tmp
|
|
8731
|
+
});
|
|
8732
|
+
}
|
|
8733
|
+
try {
|
|
8734
|
+
parsed += String.fromCodePoint(parseInt(code, 16));
|
|
8735
|
+
} catch {
|
|
8736
|
+
throw new TomlError("invalid unicode escape", {
|
|
8737
|
+
toml: str,
|
|
8738
|
+
ptr: tmp
|
|
8739
|
+
});
|
|
8740
|
+
}
|
|
8741
|
+
} else if (isMultiline && (c === "\n" || c === " " || c === " " || c === "\r")) {
|
|
8742
|
+
ptr = skipVoid(str, ptr - 1, true);
|
|
8743
|
+
if (str[ptr] !== "\n" && str[ptr] !== "\r") {
|
|
8744
|
+
throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
|
|
8745
|
+
toml: str,
|
|
8746
|
+
ptr: tmp
|
|
8747
|
+
});
|
|
8748
|
+
}
|
|
8749
|
+
ptr = skipVoid(str, ptr);
|
|
8750
|
+
} else if (c in ESC_MAP) {
|
|
8751
|
+
parsed += ESC_MAP[c];
|
|
8752
|
+
} else {
|
|
8753
|
+
throw new TomlError("unrecognized escape sequence", {
|
|
8754
|
+
toml: str,
|
|
8755
|
+
ptr: tmp
|
|
8756
|
+
});
|
|
8757
|
+
}
|
|
8758
|
+
sliceStart = ptr;
|
|
8759
|
+
} else if (!isLiteral && c === "\\") {
|
|
8760
|
+
tmp = ptr - 1;
|
|
8761
|
+
isEscape = true;
|
|
8762
|
+
parsed += str.slice(sliceStart, tmp);
|
|
8763
|
+
}
|
|
8764
|
+
}
|
|
8765
|
+
return parsed + str.slice(sliceStart, endPtr - 1);
|
|
8766
|
+
}
|
|
8767
|
+
function parseValue(value, toml, ptr, integersAsBigInt) {
|
|
8768
|
+
if (value === "true")
|
|
8769
|
+
return true;
|
|
8770
|
+
if (value === "false")
|
|
8771
|
+
return false;
|
|
8772
|
+
if (value === "-inf")
|
|
8773
|
+
return -Infinity;
|
|
8774
|
+
if (value === "inf" || value === "+inf")
|
|
8775
|
+
return Infinity;
|
|
8776
|
+
if (value === "nan" || value === "+nan" || value === "-nan")
|
|
8777
|
+
return NaN;
|
|
8778
|
+
if (value === "-0")
|
|
8779
|
+
return integersAsBigInt ? 0n : 0;
|
|
8780
|
+
let isInt = INT_REGEX.test(value);
|
|
8781
|
+
if (isInt || FLOAT_REGEX.test(value)) {
|
|
8782
|
+
if (LEADING_ZERO.test(value)) {
|
|
8783
|
+
throw new TomlError("leading zeroes are not allowed", {
|
|
8784
|
+
toml,
|
|
8785
|
+
ptr
|
|
8786
|
+
});
|
|
8787
|
+
}
|
|
8788
|
+
value = value.replace(/_/g, "");
|
|
8789
|
+
let numeric = +value;
|
|
8790
|
+
if (isNaN(numeric)) {
|
|
8791
|
+
throw new TomlError("invalid number", {
|
|
8792
|
+
toml,
|
|
8793
|
+
ptr
|
|
8794
|
+
});
|
|
8795
|
+
}
|
|
8796
|
+
if (isInt) {
|
|
8797
|
+
if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
|
|
8798
|
+
throw new TomlError("integer value cannot be represented losslessly", {
|
|
8799
|
+
toml,
|
|
8800
|
+
ptr
|
|
8801
|
+
});
|
|
8802
|
+
}
|
|
8803
|
+
if (isInt || integersAsBigInt === true)
|
|
8804
|
+
numeric = BigInt(value);
|
|
8805
|
+
}
|
|
8806
|
+
return numeric;
|
|
8807
|
+
}
|
|
8808
|
+
const date = new TomlDate(value);
|
|
8809
|
+
if (!date.isValid()) {
|
|
8810
|
+
throw new TomlError("invalid value", {
|
|
8811
|
+
toml,
|
|
8812
|
+
ptr
|
|
8813
|
+
});
|
|
8814
|
+
}
|
|
8815
|
+
return date;
|
|
8816
|
+
}
|
|
8817
|
+
|
|
8818
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/extract.js
|
|
8819
|
+
function sliceAndTrimEndOf(str, startPtr, endPtr) {
|
|
8820
|
+
let value = str.slice(startPtr, endPtr);
|
|
8821
|
+
let commentIdx = value.indexOf("#");
|
|
8822
|
+
if (commentIdx > -1) {
|
|
8823
|
+
skipComment(str, commentIdx);
|
|
8824
|
+
value = value.slice(0, commentIdx);
|
|
8825
|
+
}
|
|
8826
|
+
return [value.trimEnd(), commentIdx];
|
|
8827
|
+
}
|
|
8828
|
+
function extractValue(str, ptr, end, depth, integersAsBigInt) {
|
|
8829
|
+
if (depth === 0) {
|
|
8830
|
+
throw new TomlError("document contains excessively nested structures. aborting.", {
|
|
8831
|
+
toml: str,
|
|
8832
|
+
ptr
|
|
8833
|
+
});
|
|
8834
|
+
}
|
|
8835
|
+
let c = str[ptr];
|
|
8836
|
+
if (c === "[" || c === "{") {
|
|
8837
|
+
let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
|
|
8838
|
+
if (end) {
|
|
8839
|
+
endPtr2 = skipVoid(str, endPtr2);
|
|
8840
|
+
if (str[endPtr2] === ",")
|
|
8841
|
+
endPtr2++;
|
|
8842
|
+
else if (str[endPtr2] !== end) {
|
|
8843
|
+
throw new TomlError("expected comma or end of structure", {
|
|
8844
|
+
toml: str,
|
|
8845
|
+
ptr: endPtr2
|
|
8846
|
+
});
|
|
8847
|
+
}
|
|
8848
|
+
}
|
|
8849
|
+
return [value, endPtr2];
|
|
8850
|
+
}
|
|
8851
|
+
let endPtr;
|
|
8852
|
+
if (c === '"' || c === "'") {
|
|
8853
|
+
endPtr = getStringEnd(str, ptr);
|
|
8854
|
+
let parsed = parseString(str, ptr, endPtr);
|
|
8855
|
+
if (end) {
|
|
8856
|
+
endPtr = skipVoid(str, endPtr);
|
|
8857
|
+
if (str[endPtr] && str[endPtr] !== "," && str[endPtr] !== end && str[endPtr] !== "\n" && str[endPtr] !== "\r") {
|
|
8858
|
+
throw new TomlError("unexpected character encountered", {
|
|
8859
|
+
toml: str,
|
|
8860
|
+
ptr: endPtr
|
|
8861
|
+
});
|
|
8862
|
+
}
|
|
8863
|
+
endPtr += +(str[endPtr] === ",");
|
|
8864
|
+
}
|
|
8865
|
+
return [parsed, endPtr];
|
|
8866
|
+
}
|
|
8867
|
+
endPtr = skipUntil(str, ptr, ",", end);
|
|
8868
|
+
let slice = sliceAndTrimEndOf(str, ptr, endPtr - +(str[endPtr - 1] === ","));
|
|
8869
|
+
if (!slice[0]) {
|
|
8870
|
+
throw new TomlError("incomplete key-value declaration: no value specified", {
|
|
8871
|
+
toml: str,
|
|
8872
|
+
ptr
|
|
8873
|
+
});
|
|
8874
|
+
}
|
|
8875
|
+
if (end && slice[1] > -1) {
|
|
8876
|
+
endPtr = skipVoid(str, ptr + slice[1]);
|
|
8877
|
+
endPtr += +(str[endPtr] === ",");
|
|
8878
|
+
}
|
|
8879
|
+
return [
|
|
8880
|
+
parseValue(slice[0], str, ptr, integersAsBigInt),
|
|
8881
|
+
endPtr
|
|
8882
|
+
];
|
|
8883
|
+
}
|
|
8884
|
+
|
|
8885
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/struct.js
|
|
8886
|
+
var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
|
|
8887
|
+
function parseKey(str, ptr, end = "=") {
|
|
8888
|
+
let dot = ptr - 1;
|
|
8889
|
+
let parsed = [];
|
|
8890
|
+
let endPtr = str.indexOf(end, ptr);
|
|
8891
|
+
if (endPtr < 0) {
|
|
8892
|
+
throw new TomlError("incomplete key-value: cannot find end of key", {
|
|
8893
|
+
toml: str,
|
|
8894
|
+
ptr
|
|
8895
|
+
});
|
|
8896
|
+
}
|
|
8897
|
+
do {
|
|
8898
|
+
let c = str[ptr = ++dot];
|
|
8899
|
+
if (c !== " " && c !== " ") {
|
|
8900
|
+
if (c === '"' || c === "'") {
|
|
8901
|
+
if (c === str[ptr + 1] && c === str[ptr + 2]) {
|
|
8902
|
+
throw new TomlError("multiline strings are not allowed in keys", {
|
|
8903
|
+
toml: str,
|
|
8904
|
+
ptr
|
|
8905
|
+
});
|
|
8906
|
+
}
|
|
8907
|
+
let eos = getStringEnd(str, ptr);
|
|
8908
|
+
if (eos < 0) {
|
|
8909
|
+
throw new TomlError("unfinished string encountered", {
|
|
8910
|
+
toml: str,
|
|
8911
|
+
ptr
|
|
8912
|
+
});
|
|
8913
|
+
}
|
|
8914
|
+
dot = str.indexOf(".", eos);
|
|
8915
|
+
let strEnd = str.slice(eos, dot < 0 || dot > endPtr ? endPtr : dot);
|
|
8916
|
+
let newLine = indexOfNewline(strEnd);
|
|
8917
|
+
if (newLine > -1) {
|
|
8918
|
+
throw new TomlError("newlines are not allowed in keys", {
|
|
8919
|
+
toml: str,
|
|
8920
|
+
ptr: ptr + dot + newLine
|
|
8921
|
+
});
|
|
8922
|
+
}
|
|
8923
|
+
if (strEnd.trimStart()) {
|
|
8924
|
+
throw new TomlError("found extra tokens after the string part", {
|
|
8925
|
+
toml: str,
|
|
8926
|
+
ptr: eos
|
|
8927
|
+
});
|
|
8928
|
+
}
|
|
8929
|
+
if (endPtr < eos) {
|
|
8930
|
+
endPtr = str.indexOf(end, eos);
|
|
8931
|
+
if (endPtr < 0) {
|
|
8932
|
+
throw new TomlError("incomplete key-value: cannot find end of key", {
|
|
8933
|
+
toml: str,
|
|
8934
|
+
ptr
|
|
8935
|
+
});
|
|
8936
|
+
}
|
|
8937
|
+
}
|
|
8938
|
+
parsed.push(parseString(str, ptr, eos));
|
|
8939
|
+
} else {
|
|
8940
|
+
dot = str.indexOf(".", ptr);
|
|
8941
|
+
let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot);
|
|
8942
|
+
if (!KEY_PART_RE.test(part)) {
|
|
8943
|
+
throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", {
|
|
8944
|
+
toml: str,
|
|
8945
|
+
ptr
|
|
8946
|
+
});
|
|
8947
|
+
}
|
|
8948
|
+
parsed.push(part.trimEnd());
|
|
8949
|
+
}
|
|
8950
|
+
}
|
|
8951
|
+
} while (dot + 1 && dot < endPtr);
|
|
8952
|
+
return [parsed, skipVoid(str, endPtr + 1, true, true)];
|
|
8953
|
+
}
|
|
8954
|
+
function parseInlineTable(str, ptr, depth, integersAsBigInt) {
|
|
8955
|
+
let res = {};
|
|
8956
|
+
let seen = /* @__PURE__ */ new Set();
|
|
8957
|
+
let c;
|
|
8958
|
+
ptr++;
|
|
8959
|
+
while ((c = str[ptr++]) !== "}" && c) {
|
|
8960
|
+
if (c === ",") {
|
|
8961
|
+
throw new TomlError("expected value, found comma", {
|
|
8962
|
+
toml: str,
|
|
8963
|
+
ptr: ptr - 1
|
|
8964
|
+
});
|
|
8965
|
+
} else if (c === "#")
|
|
8966
|
+
ptr = skipComment(str, ptr);
|
|
8967
|
+
else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
|
|
8968
|
+
let k;
|
|
8969
|
+
let t = res;
|
|
8970
|
+
let hasOwn = false;
|
|
8971
|
+
let [key, keyEndPtr] = parseKey(str, ptr - 1);
|
|
8972
|
+
for (let i = 0; i < key.length; i++) {
|
|
8973
|
+
if (i)
|
|
8974
|
+
t = hasOwn ? t[k] : t[k] = {};
|
|
8975
|
+
k = key[i];
|
|
8976
|
+
if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
|
|
8977
|
+
throw new TomlError("trying to redefine an already defined value", {
|
|
8978
|
+
toml: str,
|
|
8979
|
+
ptr
|
|
8980
|
+
});
|
|
8981
|
+
}
|
|
8982
|
+
if (!hasOwn && k === "__proto__") {
|
|
8983
|
+
Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
|
|
8984
|
+
}
|
|
8985
|
+
}
|
|
8986
|
+
if (hasOwn) {
|
|
8987
|
+
throw new TomlError("trying to redefine an already defined value", {
|
|
8988
|
+
toml: str,
|
|
8989
|
+
ptr
|
|
8990
|
+
});
|
|
8991
|
+
}
|
|
8992
|
+
let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt);
|
|
8993
|
+
seen.add(value);
|
|
8994
|
+
t[k] = value;
|
|
8995
|
+
ptr = valueEndPtr;
|
|
8996
|
+
}
|
|
8997
|
+
}
|
|
8998
|
+
if (!c) {
|
|
8999
|
+
throw new TomlError("unfinished table encountered", {
|
|
9000
|
+
toml: str,
|
|
9001
|
+
ptr
|
|
9002
|
+
});
|
|
9003
|
+
}
|
|
9004
|
+
return [res, ptr];
|
|
8379
9005
|
}
|
|
8380
|
-
function
|
|
8381
|
-
|
|
8382
|
-
|
|
9006
|
+
function parseArray(str, ptr, depth, integersAsBigInt) {
|
|
9007
|
+
let res = [];
|
|
9008
|
+
let c;
|
|
9009
|
+
ptr++;
|
|
9010
|
+
while ((c = str[ptr++]) !== "]" && c) {
|
|
9011
|
+
if (c === ",") {
|
|
9012
|
+
throw new TomlError("expected value, found comma", {
|
|
9013
|
+
toml: str,
|
|
9014
|
+
ptr: ptr - 1
|
|
9015
|
+
});
|
|
9016
|
+
} else if (c === "#")
|
|
9017
|
+
ptr = skipComment(str, ptr);
|
|
9018
|
+
else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
|
|
9019
|
+
let e = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt);
|
|
9020
|
+
res.push(e[0]);
|
|
9021
|
+
ptr = e[1];
|
|
9022
|
+
}
|
|
9023
|
+
}
|
|
9024
|
+
if (!c) {
|
|
9025
|
+
throw new TomlError("unfinished array encountered", {
|
|
9026
|
+
toml: str,
|
|
9027
|
+
ptr
|
|
9028
|
+
});
|
|
8383
9029
|
}
|
|
8384
|
-
|
|
8385
|
-
|
|
9030
|
+
return [res, ptr];
|
|
9031
|
+
}
|
|
9032
|
+
|
|
9033
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/parse.js
|
|
9034
|
+
function peekTable(key, table, meta, type) {
|
|
9035
|
+
let t = table;
|
|
9036
|
+
let m = meta;
|
|
9037
|
+
let k;
|
|
9038
|
+
let hasOwn = false;
|
|
9039
|
+
let state;
|
|
9040
|
+
for (let i = 0; i < key.length; i++) {
|
|
9041
|
+
if (i) {
|
|
9042
|
+
t = hasOwn ? t[k] : t[k] = {};
|
|
9043
|
+
m = (state = m[k]).c;
|
|
9044
|
+
if (type === 0 && (state.t === 1 || state.t === 2)) {
|
|
9045
|
+
return null;
|
|
9046
|
+
}
|
|
9047
|
+
if (state.t === 2) {
|
|
9048
|
+
let l = t.length - 1;
|
|
9049
|
+
t = t[l];
|
|
9050
|
+
m = m[l].c;
|
|
9051
|
+
}
|
|
9052
|
+
}
|
|
9053
|
+
k = key[i];
|
|
9054
|
+
if ((hasOwn = Object.hasOwn(t, k)) && m[k]?.t === 0 && m[k]?.d) {
|
|
9055
|
+
return null;
|
|
9056
|
+
}
|
|
9057
|
+
if (!hasOwn) {
|
|
9058
|
+
if (k === "__proto__") {
|
|
9059
|
+
Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
|
|
9060
|
+
Object.defineProperty(m, k, { enumerable: true, configurable: true, writable: true });
|
|
9061
|
+
}
|
|
9062
|
+
m[k] = {
|
|
9063
|
+
t: i < key.length - 1 && type === 2 ? 3 : type,
|
|
9064
|
+
d: false,
|
|
9065
|
+
i: 0,
|
|
9066
|
+
c: {}
|
|
9067
|
+
};
|
|
9068
|
+
}
|
|
8386
9069
|
}
|
|
8387
|
-
|
|
8388
|
-
if (
|
|
8389
|
-
return
|
|
9070
|
+
state = m[k];
|
|
9071
|
+
if (state.t !== type && !(type === 1 && state.t === 3)) {
|
|
9072
|
+
return null;
|
|
8390
9073
|
}
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
9074
|
+
if (type === 2) {
|
|
9075
|
+
if (!state.d) {
|
|
9076
|
+
state.d = true;
|
|
9077
|
+
t[k] = [];
|
|
9078
|
+
}
|
|
9079
|
+
t[k].push(t = {});
|
|
9080
|
+
state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} };
|
|
8394
9081
|
}
|
|
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" };
|
|
9082
|
+
if (state.d) {
|
|
9083
|
+
return null;
|
|
8401
9084
|
}
|
|
8402
|
-
|
|
8403
|
-
if (
|
|
8404
|
-
|
|
9085
|
+
state.d = true;
|
|
9086
|
+
if (type === 1) {
|
|
9087
|
+
t = hasOwn ? t[k] : t[k] = {};
|
|
9088
|
+
} else if (type === 0 && hasOwn) {
|
|
9089
|
+
return null;
|
|
8405
9090
|
}
|
|
8406
|
-
return
|
|
9091
|
+
return [k, t, state.c];
|
|
8407
9092
|
}
|
|
8408
|
-
function
|
|
8409
|
-
|
|
8410
|
-
|
|
9093
|
+
function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|
9094
|
+
let res = {};
|
|
9095
|
+
let meta = {};
|
|
9096
|
+
let tbl = res;
|
|
9097
|
+
let m = meta;
|
|
9098
|
+
for (let ptr = skipVoid(toml, 0); ptr < toml.length; ) {
|
|
9099
|
+
if (toml[ptr] === "[") {
|
|
9100
|
+
let isTableArray = toml[++ptr] === "[";
|
|
9101
|
+
let k = parseKey(toml, ptr += +isTableArray, "]");
|
|
9102
|
+
if (isTableArray) {
|
|
9103
|
+
if (toml[k[1] - 1] !== "]") {
|
|
9104
|
+
throw new TomlError("expected end of table declaration", {
|
|
9105
|
+
toml,
|
|
9106
|
+
ptr: k[1] - 1
|
|
9107
|
+
});
|
|
9108
|
+
}
|
|
9109
|
+
k[1]++;
|
|
9110
|
+
}
|
|
9111
|
+
let p = peekTable(
|
|
9112
|
+
k[0],
|
|
9113
|
+
res,
|
|
9114
|
+
meta,
|
|
9115
|
+
isTableArray ? 2 : 1
|
|
9116
|
+
/* Type.EXPLICIT */
|
|
9117
|
+
);
|
|
9118
|
+
if (!p) {
|
|
9119
|
+
throw new TomlError("trying to redefine an already defined table or value", {
|
|
9120
|
+
toml,
|
|
9121
|
+
ptr
|
|
9122
|
+
});
|
|
9123
|
+
}
|
|
9124
|
+
m = p[2];
|
|
9125
|
+
tbl = p[1];
|
|
9126
|
+
ptr = k[1];
|
|
9127
|
+
} else {
|
|
9128
|
+
let k = parseKey(toml, ptr);
|
|
9129
|
+
let p = peekTable(
|
|
9130
|
+
k[0],
|
|
9131
|
+
tbl,
|
|
9132
|
+
m,
|
|
9133
|
+
0
|
|
9134
|
+
/* Type.DOTTED */
|
|
9135
|
+
);
|
|
9136
|
+
if (!p) {
|
|
9137
|
+
throw new TomlError("trying to redefine an already defined table or value", {
|
|
9138
|
+
toml,
|
|
9139
|
+
ptr
|
|
9140
|
+
});
|
|
9141
|
+
}
|
|
9142
|
+
let v = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt);
|
|
9143
|
+
p[1][p[0]] = v[0];
|
|
9144
|
+
ptr = v[1];
|
|
9145
|
+
}
|
|
9146
|
+
ptr = skipVoid(toml, ptr, true);
|
|
9147
|
+
if (toml[ptr] && toml[ptr] !== "\n" && toml[ptr] !== "\r") {
|
|
9148
|
+
throw new TomlError("each key-value declaration must be followed by an end-of-line", {
|
|
9149
|
+
toml,
|
|
9150
|
+
ptr
|
|
9151
|
+
});
|
|
9152
|
+
}
|
|
9153
|
+
ptr = skipVoid(toml, ptr);
|
|
8411
9154
|
}
|
|
8412
|
-
return
|
|
9155
|
+
return res;
|
|
9156
|
+
}
|
|
9157
|
+
|
|
9158
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/stringify.js
|
|
9159
|
+
var BARE_KEY = /^[a-z0-9-_]+$/i;
|
|
9160
|
+
function extendedTypeOf(obj) {
|
|
9161
|
+
let type = typeof obj;
|
|
9162
|
+
if (type === "object") {
|
|
9163
|
+
if (Array.isArray(obj))
|
|
9164
|
+
return "array";
|
|
9165
|
+
if (obj instanceof Date)
|
|
9166
|
+
return "date";
|
|
9167
|
+
}
|
|
9168
|
+
return type;
|
|
9169
|
+
}
|
|
9170
|
+
function isArrayOfTables(obj) {
|
|
9171
|
+
for (let i = 0; i < obj.length; i++) {
|
|
9172
|
+
if (extendedTypeOf(obj[i]) !== "object")
|
|
9173
|
+
return false;
|
|
9174
|
+
}
|
|
9175
|
+
return obj.length != 0;
|
|
9176
|
+
}
|
|
9177
|
+
function formatString(s) {
|
|
9178
|
+
return JSON.stringify(s).replace(/\x7f/g, "\\u007f");
|
|
9179
|
+
}
|
|
9180
|
+
function stringifyValue(val, type, depth, numberAsFloat) {
|
|
9181
|
+
if (depth === 0) {
|
|
9182
|
+
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
9183
|
+
}
|
|
9184
|
+
if (type === "number") {
|
|
9185
|
+
if (isNaN(val))
|
|
9186
|
+
return "nan";
|
|
9187
|
+
if (val === Infinity)
|
|
9188
|
+
return "inf";
|
|
9189
|
+
if (val === -Infinity)
|
|
9190
|
+
return "-inf";
|
|
9191
|
+
if (numberAsFloat && Number.isInteger(val))
|
|
9192
|
+
return val.toFixed(1);
|
|
9193
|
+
return val.toString();
|
|
9194
|
+
}
|
|
9195
|
+
if (type === "bigint" || type === "boolean") {
|
|
9196
|
+
return val.toString();
|
|
9197
|
+
}
|
|
9198
|
+
if (type === "string") {
|
|
9199
|
+
return formatString(val);
|
|
9200
|
+
}
|
|
9201
|
+
if (type === "date") {
|
|
9202
|
+
if (isNaN(val.getTime())) {
|
|
9203
|
+
throw new TypeError("cannot serialize invalid date");
|
|
9204
|
+
}
|
|
9205
|
+
return val.toISOString();
|
|
9206
|
+
}
|
|
9207
|
+
if (type === "object") {
|
|
9208
|
+
return stringifyInlineTable(val, depth, numberAsFloat);
|
|
9209
|
+
}
|
|
9210
|
+
if (type === "array") {
|
|
9211
|
+
return stringifyArray(val, depth, numberAsFloat);
|
|
9212
|
+
}
|
|
9213
|
+
}
|
|
9214
|
+
function stringifyInlineTable(obj, depth, numberAsFloat) {
|
|
9215
|
+
let keys = Object.keys(obj);
|
|
9216
|
+
if (keys.length === 0)
|
|
9217
|
+
return "{}";
|
|
9218
|
+
let res = "{ ";
|
|
9219
|
+
for (let i = 0; i < keys.length; i++) {
|
|
9220
|
+
let k = keys[i];
|
|
9221
|
+
if (i)
|
|
9222
|
+
res += ", ";
|
|
9223
|
+
res += BARE_KEY.test(k) ? k : formatString(k);
|
|
9224
|
+
res += " = ";
|
|
9225
|
+
res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat);
|
|
9226
|
+
}
|
|
9227
|
+
return res + " }";
|
|
9228
|
+
}
|
|
9229
|
+
function stringifyArray(array, depth, numberAsFloat) {
|
|
9230
|
+
if (array.length === 0)
|
|
9231
|
+
return "[]";
|
|
9232
|
+
let res = "[ ";
|
|
9233
|
+
for (let i = 0; i < array.length; i++) {
|
|
9234
|
+
if (i)
|
|
9235
|
+
res += ", ";
|
|
9236
|
+
if (array[i] === null || array[i] === void 0) {
|
|
9237
|
+
throw new TypeError("arrays cannot contain null or undefined values");
|
|
9238
|
+
}
|
|
9239
|
+
res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat);
|
|
9240
|
+
}
|
|
9241
|
+
return res + " ]";
|
|
9242
|
+
}
|
|
9243
|
+
function stringifyArrayTable(array, key, depth, numberAsFloat) {
|
|
9244
|
+
if (depth === 0) {
|
|
9245
|
+
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
9246
|
+
}
|
|
9247
|
+
let res = "";
|
|
9248
|
+
for (let i = 0; i < array.length; i++) {
|
|
9249
|
+
res += `${res && "\n"}[[${key}]]
|
|
9250
|
+
`;
|
|
9251
|
+
res += stringifyTable(0, array[i], key, depth, numberAsFloat);
|
|
9252
|
+
}
|
|
9253
|
+
return res;
|
|
9254
|
+
}
|
|
9255
|
+
function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat) {
|
|
9256
|
+
if (depth === 0) {
|
|
9257
|
+
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
9258
|
+
}
|
|
9259
|
+
let preamble = "";
|
|
9260
|
+
let tables = "";
|
|
9261
|
+
let keys = Object.keys(obj);
|
|
9262
|
+
for (let i = 0; i < keys.length; i++) {
|
|
9263
|
+
let k = keys[i];
|
|
9264
|
+
if (obj[k] !== null && obj[k] !== void 0) {
|
|
9265
|
+
let type = extendedTypeOf(obj[k]);
|
|
9266
|
+
if (type === "symbol" || type === "function") {
|
|
9267
|
+
throw new TypeError(`cannot serialize values of type '${type}'`);
|
|
9268
|
+
}
|
|
9269
|
+
let key = BARE_KEY.test(k) ? k : formatString(k);
|
|
9270
|
+
if (type === "array" && isArrayOfTables(obj[k])) {
|
|
9271
|
+
tables += (tables && "\n") + stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat);
|
|
9272
|
+
} else if (type === "object") {
|
|
9273
|
+
let tblKey = prefix ? `${prefix}.${key}` : key;
|
|
9274
|
+
tables += (tables && "\n") + stringifyTable(tblKey, obj[k], tblKey, depth - 1, numberAsFloat);
|
|
9275
|
+
} else {
|
|
9276
|
+
preamble += key;
|
|
9277
|
+
preamble += " = ";
|
|
9278
|
+
preamble += stringifyValue(obj[k], type, depth, numberAsFloat);
|
|
9279
|
+
preamble += "\n";
|
|
9280
|
+
}
|
|
9281
|
+
}
|
|
9282
|
+
}
|
|
9283
|
+
if (tableKey && (preamble || !tables))
|
|
9284
|
+
preamble = preamble ? `[${tableKey}]
|
|
9285
|
+
${preamble}` : `[${tableKey}]`;
|
|
9286
|
+
return preamble && tables ? `${preamble}
|
|
9287
|
+
${tables}` : preamble || tables;
|
|
9288
|
+
}
|
|
9289
|
+
function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
9290
|
+
if (extendedTypeOf(obj) !== "object") {
|
|
9291
|
+
throw new TypeError("stringify can only be called with an object");
|
|
9292
|
+
}
|
|
9293
|
+
let str = stringifyTable(0, obj, "", maxDepth, numbersAsFloat);
|
|
9294
|
+
if (str[str.length - 1] !== "\n")
|
|
9295
|
+
return str + "\n";
|
|
9296
|
+
return str;
|
|
9297
|
+
}
|
|
9298
|
+
|
|
9299
|
+
// ../../node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/index.js
|
|
9300
|
+
var dist_default = { parse, stringify, TomlDate, TomlError };
|
|
9301
|
+
|
|
9302
|
+
// src/outbound-config.ts
|
|
9303
|
+
var OUTBOUND_ENV_KEYS = [
|
|
9304
|
+
"AGENT_WECHAT_OUTBOUND_QUEUE_CAPACITY",
|
|
9305
|
+
"AGENT_WECHAT_OUTBOUND_MIN_SPACING_MS",
|
|
9306
|
+
"AGENT_WECHAT_OUTBOUND_JITTER_MS",
|
|
9307
|
+
"AGENT_WECHAT_CHAT_COOLDOWN_MS",
|
|
9308
|
+
"AGENT_WECHAT_HOURLY_BUDGET",
|
|
9309
|
+
"AGENT_WECHAT_DAILY_BUDGET",
|
|
9310
|
+
"AGENT_WECHAT_QUIET_START_MIN",
|
|
9311
|
+
"AGENT_WECHAT_QUIET_END_MIN",
|
|
9312
|
+
"AGENT_WECHAT_OUTBOUND_LONG_TAIL_JITTER_MS",
|
|
9313
|
+
"AGENT_WECHAT_OUTBOUND_LONG_TAIL_CHANCE_PERCENT",
|
|
9314
|
+
"AGENT_WECHAT_OUTBOUND_TASK_TTL_MS",
|
|
9315
|
+
"AGENT_WECHAT_OUTBOUND_IDEMPOTENCY_TTL_MS",
|
|
9316
|
+
"AGENT_WECHAT_OUTBOUND_IDEMPOTENCY_MAX_ROWS",
|
|
9317
|
+
"AGENT_WECHAT_OUTBOUND_DISABLED"
|
|
9318
|
+
];
|
|
9319
|
+
var aliases = {
|
|
9320
|
+
queueCapacity: "AGENT_WECHAT_OUTBOUND_QUEUE_CAPACITY",
|
|
9321
|
+
minSpacingMs: "AGENT_WECHAT_OUTBOUND_MIN_SPACING_MS",
|
|
9322
|
+
jitterMs: "AGENT_WECHAT_OUTBOUND_JITTER_MS",
|
|
9323
|
+
chatCooldownMs: "AGENT_WECHAT_CHAT_COOLDOWN_MS",
|
|
9324
|
+
hourlyBudget: "AGENT_WECHAT_HOURLY_BUDGET",
|
|
9325
|
+
dailyBudget: "AGENT_WECHAT_DAILY_BUDGET",
|
|
9326
|
+
quietStartMin: "AGENT_WECHAT_QUIET_START_MIN",
|
|
9327
|
+
quietEndMin: "AGENT_WECHAT_QUIET_END_MIN",
|
|
9328
|
+
longTailJitterMs: "AGENT_WECHAT_OUTBOUND_LONG_TAIL_JITTER_MS",
|
|
9329
|
+
longTailChancePercent: "AGENT_WECHAT_OUTBOUND_LONG_TAIL_CHANCE_PERCENT",
|
|
9330
|
+
taskTtlMs: "AGENT_WECHAT_OUTBOUND_TASK_TTL_MS",
|
|
9331
|
+
idempotencyTtlMs: "AGENT_WECHAT_OUTBOUND_IDEMPOTENCY_TTL_MS",
|
|
9332
|
+
idempotencyMaxRows: "AGENT_WECHAT_OUTBOUND_IDEMPOTENCY_MAX_ROWS",
|
|
9333
|
+
disabled: "AGENT_WECHAT_OUTBOUND_DISABLED"
|
|
9334
|
+
};
|
|
9335
|
+
function readOutboundConfig(file) {
|
|
9336
|
+
if (!file) return {};
|
|
9337
|
+
const parsed = dist_default.parse(fs3.readFileSync(path3.resolve(file), "utf8"));
|
|
9338
|
+
const result = {};
|
|
9339
|
+
for (const [key, env] of Object.entries(aliases)) if (parsed[key] !== void 0) result[env] = String(parsed[key]);
|
|
9340
|
+
for (const key of OUTBOUND_ENV_KEYS) if (parsed[key] !== void 0) result[key] = String(parsed[key]);
|
|
9341
|
+
return result;
|
|
9342
|
+
}
|
|
9343
|
+
function outboundFromEnvEntries(entries) {
|
|
9344
|
+
const result = {};
|
|
9345
|
+
const allowed = new Set(OUTBOUND_ENV_KEYS);
|
|
9346
|
+
for (const entry of entries) {
|
|
9347
|
+
const index = entry.indexOf("=");
|
|
9348
|
+
if (index > 0 && allowed.has(entry.slice(0, index))) result[entry.slice(0, index)] = entry.slice(index + 1);
|
|
9349
|
+
}
|
|
9350
|
+
return result;
|
|
9351
|
+
}
|
|
9352
|
+
function resolveOutboundConfig(file, cli = {}) {
|
|
9353
|
+
const config = file ? readOutboundConfig(file) : {};
|
|
9354
|
+
const env = {};
|
|
9355
|
+
for (const key of OUTBOUND_ENV_KEYS) if (process.env[key] !== void 0) env[key] = process.env[key];
|
|
9356
|
+
return { ...config, ...env, ...cli };
|
|
9357
|
+
}
|
|
9358
|
+
|
|
9359
|
+
// src/lifecycle-policy.ts
|
|
9360
|
+
var INSTANCE_LABEL = "dev.visionclaw.agent-wechat.instance";
|
|
9361
|
+
var IMAGE_LABEL = "dev.visionclaw.agent-wechat.image";
|
|
9362
|
+
var VOLUME_ROLE_LABEL = "dev.visionclaw.agent-wechat.volume-role";
|
|
9363
|
+
function hasOwnedContainer(info) {
|
|
9364
|
+
return info.Config?.Labels?.[INSTANCE_LABEL] === "default";
|
|
9365
|
+
}
|
|
9366
|
+
function isReconcileableContainer(info, inventory) {
|
|
9367
|
+
if (hasOwnedContainer(info)) return true;
|
|
9368
|
+
const id = inventory?.containerId;
|
|
9369
|
+
return Boolean(id && (info.Id === id || info.Id.startsWith(id) || id.startsWith(info.Id)));
|
|
9370
|
+
}
|
|
9371
|
+
function hasOwnedVolume(existing, name, role) {
|
|
9372
|
+
return existing.Name === name && existing.Driver === "local" && existing.Labels?.[INSTANCE_LABEL] === "default" && existing.Labels?.[VOLUME_ROLE_LABEL] === role;
|
|
8413
9373
|
}
|
|
8414
9374
|
|
|
8415
9375
|
// src/lifecycle.ts
|
|
@@ -8490,8 +9450,12 @@ function ensureOwnedVolumes(inventory) {
|
|
|
8490
9450
|
docker(["volume", "create", "--driver", "local", "--label", `${INSTANCE_LABEL}=default`, "--label", `${VOLUME_ROLE_LABEL}=${roles[index]}`, name]);
|
|
8491
9451
|
continue;
|
|
8492
9452
|
}
|
|
8493
|
-
|
|
8494
|
-
|
|
9453
|
+
assertVolumeOwnership(existing, name, roles[index]);
|
|
9454
|
+
}
|
|
9455
|
+
}
|
|
9456
|
+
function assertVolumeOwnership(existing, name, role) {
|
|
9457
|
+
if (!hasOwnedVolume(existing, name, role)) {
|
|
9458
|
+
throw new CliError("VOLUME_OWNERSHIP_MISMATCH", `refusing to use volume ${name} without trusted ownership`, EXIT.ENVIRONMENT);
|
|
8495
9459
|
}
|
|
8496
9460
|
}
|
|
8497
9461
|
function assertOwnedVolumes(inventory) {
|
|
@@ -8499,10 +9463,12 @@ function assertOwnedVolumes(inventory) {
|
|
|
8499
9463
|
for (const [index, name] of inventory.volumes.entries()) {
|
|
8500
9464
|
const existing = inspectVolume(name);
|
|
8501
9465
|
if (!existing) continue;
|
|
8502
|
-
|
|
8503
|
-
if (violation) throw new CliError(violation.code, violation.message, EXIT.CLEANUP);
|
|
9466
|
+
assertVolumeOwnership(existing, name, roles[index]);
|
|
8504
9467
|
}
|
|
8505
9468
|
}
|
|
9469
|
+
function assertOwnedContainer(info, inventory) {
|
|
9470
|
+
if (!isReconcileableContainer(info, inventory)) throw new CliError("CONTAINER_OWNERSHIP_MISMATCH", "refusing to operate on an unowned container with the fixed name", EXIT.ENVIRONMENT);
|
|
9471
|
+
}
|
|
8506
9472
|
function clearContainerIdentity(inventory) {
|
|
8507
9473
|
const info = inspectContainer();
|
|
8508
9474
|
if (!info) throw new CliError("INSTANCE_NOT_RUNNING", "trusted container is required to clear container identity", EXIT.CLEANUP);
|
|
@@ -8519,8 +9485,7 @@ function removeOwnedVolume(inventory, index, role) {
|
|
|
8519
9485
|
const name = inventory.volumes[index];
|
|
8520
9486
|
const existing = inspectVolume(name);
|
|
8521
9487
|
if (!existing) return false;
|
|
8522
|
-
|
|
8523
|
-
if (violation) throw new CliError(violation.code, violation.message, EXIT.CLEANUP);
|
|
9488
|
+
assertVolumeOwnership(existing, name, role);
|
|
8524
9489
|
docker(["volume", "rm", name]);
|
|
8525
9490
|
return true;
|
|
8526
9491
|
}
|
|
@@ -8542,10 +9507,6 @@ function resolveImage(options) {
|
|
|
8542
9507
|
if (published && !digest) throw new CliError("IMAGE_DIGEST_UNRESOLVED", "published image did not resolve to a fork repo digest", EXIT.ENVIRONMENT);
|
|
8543
9508
|
return { runReference: digest || requested, requestedReference: requested, digest };
|
|
8544
9509
|
}
|
|
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
9510
|
async function waitCompatible(token, timeoutMs = 3e4) {
|
|
8550
9511
|
await waitHealthy(timeoutMs);
|
|
8551
9512
|
try {
|
|
@@ -8572,21 +9533,19 @@ async function waitHealthy(timeoutMs = 3e4) {
|
|
|
8572
9533
|
}
|
|
8573
9534
|
async function startInstance(options) {
|
|
8574
9535
|
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
9536
|
const existing = inspectContainer();
|
|
8577
9537
|
const current = loadInventory();
|
|
8578
9538
|
if (existing) {
|
|
8579
|
-
if (!current) throw new CliError("INSTANCE_INVENTORY_MISSING", "existing container has no trusted inventory", EXIT.ENVIRONMENT);
|
|
8580
9539
|
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);
|
|
9540
|
+
if (options.outbound && Object.keys(options.outbound).length > 0) {
|
|
9541
|
+
throw new CliError("OUTBOUND_RESTART_REQUIRED", "outbound policy changed; run wx restart to recreate the container", EXIT.ARGUMENT);
|
|
8585
9542
|
}
|
|
8586
|
-
if (!
|
|
9543
|
+
if (!current) throw new CliError("INSTANCE_INVENTORY_MISSING", "existing container has no trusted inventory", EXIT.ENVIRONMENT);
|
|
9544
|
+
if (!existing.State?.Running) docker(["start", CONTAINER_NAME], { inherit: true });
|
|
8587
9545
|
await waitCompatible(options.token);
|
|
8588
9546
|
return current;
|
|
8589
9547
|
}
|
|
9548
|
+
const selected = resolveImage({ explicit: options.image, pull: options.pull, noPull: options.noPull, localDefault: options.localDefault });
|
|
8590
9549
|
const provisional = createInventory(selected.requestedReference, options.identity, selected.digest);
|
|
8591
9550
|
saveInventory(provisional);
|
|
8592
9551
|
ensureOwnedVolumes(provisional);
|
|
@@ -8595,7 +9554,8 @@ async function startInstance(options) {
|
|
|
8595
9554
|
containerName: CONTAINER_NAME,
|
|
8596
9555
|
tokenPath: TOKEN_PATH,
|
|
8597
9556
|
port: DEFAULT_PORT,
|
|
8598
|
-
proxy: options.proxy
|
|
9557
|
+
proxy: options.proxy,
|
|
9558
|
+
outbound: options.outbound
|
|
8599
9559
|
});
|
|
8600
9560
|
args.splice(args.length - 1, 0, "--label", `${INSTANCE_LABEL}=default`, "--label", `${IMAGE_LABEL}=${selected.digest || selected.runReference}`);
|
|
8601
9561
|
docker(args, { inherit: true });
|
|
@@ -8612,13 +9572,28 @@ async function startInstance(options) {
|
|
|
8612
9572
|
}
|
|
8613
9573
|
return inventory;
|
|
8614
9574
|
}
|
|
9575
|
+
function outboundFromContainer(info) {
|
|
9576
|
+
return outboundFromEnvEntries(info.Config?.Env ?? []);
|
|
9577
|
+
}
|
|
9578
|
+
function stopContainer(idOrName) {
|
|
9579
|
+
docker(["stop", idOrName], { inherit: true });
|
|
9580
|
+
}
|
|
9581
|
+
function renameContainer(id, name) {
|
|
9582
|
+
docker(["rename", id, name], { inherit: true });
|
|
9583
|
+
}
|
|
9584
|
+
function removeContainer(id) {
|
|
9585
|
+
docker(["rm", "-f", id], { inherit: true });
|
|
9586
|
+
}
|
|
9587
|
+
function startContainer(idOrName) {
|
|
9588
|
+
docker(["start", idOrName], { inherit: true });
|
|
9589
|
+
}
|
|
8615
9590
|
function stopInstance() {
|
|
8616
9591
|
if (!dockerAvailable()) throw new CliError("DOCKER_UNAVAILABLE", "Docker daemon is unavailable", EXIT.ENVIRONMENT);
|
|
8617
9592
|
const info = inspectContainer();
|
|
8618
9593
|
if (!info) return { stopped: false };
|
|
8619
9594
|
const inventory = loadInventory();
|
|
8620
|
-
if (!inventory) throw new CliError("INSTANCE_INVENTORY_MISSING", "refusing to remove an unowned container", EXIT.ENVIRONMENT);
|
|
8621
9595
|
assertOwnedContainer(info, inventory);
|
|
9596
|
+
if (!inventory) throw new CliError("INSTANCE_INVENTORY_MISSING", "refusing to remove an unowned container", EXIT.ENVIRONMENT);
|
|
8622
9597
|
docker(["rm", "-f", info.Id], { inherit: true });
|
|
8623
9598
|
return { stopped: true };
|
|
8624
9599
|
}
|
|
@@ -8637,18 +9612,18 @@ function purgeInstance() {
|
|
|
8637
9612
|
remaining.push(`volume:${volume}`);
|
|
8638
9613
|
}
|
|
8639
9614
|
}
|
|
8640
|
-
for (const file of [TOKEN_PATH,
|
|
9615
|
+
for (const file of [TOKEN_PATH, path4.join(CONFIG_DIR, "device-identity.env"), path4.join(CONFIG_DIR, "device-identity.json")]) {
|
|
8641
9616
|
try {
|
|
8642
9617
|
assertSafePurgePath(file, CONFIG_DIR);
|
|
8643
9618
|
} catch {
|
|
8644
|
-
remaining.push(
|
|
9619
|
+
remaining.push(path4.basename(file));
|
|
8645
9620
|
continue;
|
|
8646
9621
|
}
|
|
8647
9622
|
try {
|
|
8648
|
-
|
|
8649
|
-
removed.push(
|
|
9623
|
+
fs4.unlinkSync(file);
|
|
9624
|
+
removed.push(path4.basename(file));
|
|
8650
9625
|
} catch (error) {
|
|
8651
|
-
if (error.code !== "ENOENT") remaining.push(
|
|
9626
|
+
if (error.code !== "ENOENT") remaining.push(path4.basename(file));
|
|
8652
9627
|
}
|
|
8653
9628
|
}
|
|
8654
9629
|
if (remaining.length === 0) removeInventory();
|
|
@@ -8660,8 +9635,9 @@ async function replaceImage(options) {
|
|
|
8660
9635
|
if (!previous) throw new CliError("INSTANCE_INVENTORY_MISSING", "start the instance before image upgrade", EXIT.ENVIRONMENT);
|
|
8661
9636
|
const info = inspectContainer();
|
|
8662
9637
|
if (info) assertOwnedContainer(info, previous);
|
|
9638
|
+
const reconciled = previous;
|
|
8663
9639
|
const selected = resolveImage({ explicit: options.image, pull: true, localDefault: previous.imageRef });
|
|
8664
|
-
if (selected.digest ===
|
|
9640
|
+
if (selected.digest === reconciled.imageDigest) return reconciled;
|
|
8665
9641
|
if (info) {
|
|
8666
9642
|
if (info.State?.Running) docker(["stop", info.Id], { inherit: true });
|
|
8667
9643
|
docker(["rename", info.Id, `${CONTAINER_NAME}-rollback`]);
|
|
@@ -8675,7 +9651,7 @@ async function replaceImage(options) {
|
|
|
8675
9651
|
const failed = inspectContainer();
|
|
8676
9652
|
if (failed) docker(["rm", "-f", failed.Id]);
|
|
8677
9653
|
if (info) docker(["rename", info.Id, CONTAINER_NAME]);
|
|
8678
|
-
saveInventory(
|
|
9654
|
+
saveInventory(reconciled);
|
|
8679
9655
|
if (info?.State?.Running) docker(["start", CONTAINER_NAME]);
|
|
8680
9656
|
} catch {
|
|
8681
9657
|
throw new CliError("ROLLBACK_FAILED", "image upgrade failed and rollback was incomplete", EXIT.ROLLBACK);
|
|
@@ -8761,12 +9737,12 @@ function checkCliUpgrade(currentVersion, readLatest = () => execFileSync2("npm",
|
|
|
8761
9737
|
}
|
|
8762
9738
|
|
|
8763
9739
|
// src/cli.ts
|
|
8764
|
-
var VERSION = false ? "0.0.0-test" : "0.
|
|
9740
|
+
var VERSION = false ? "0.0.0-test" : "0.14.1";
|
|
8765
9741
|
var MAX_UPLOAD_BYTES = 50 * 1024 * 1024;
|
|
8766
9742
|
function readToken() {
|
|
8767
9743
|
try {
|
|
8768
9744
|
secureRegularFile(TOKEN_PATH);
|
|
8769
|
-
const value =
|
|
9745
|
+
const value = fs5.readFileSync(TOKEN_PATH, "utf8").trim();
|
|
8770
9746
|
if (!/^[a-f0-9]{64}$/.test(value)) throw new Error("INVALID_AUTH_TOKEN");
|
|
8771
9747
|
return value;
|
|
8772
9748
|
} catch (error) {
|
|
@@ -8778,9 +9754,9 @@ function readToken() {
|
|
|
8778
9754
|
function ensureToken() {
|
|
8779
9755
|
const current = readToken();
|
|
8780
9756
|
if (current) return current;
|
|
8781
|
-
|
|
9757
|
+
fs5.mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
8782
9758
|
const token = randomBytes2(32).toString("hex");
|
|
8783
|
-
|
|
9759
|
+
fs5.writeFileSync(TOKEN_PATH, `${token}
|
|
8784
9760
|
`, { mode: 384, flag: "wx" });
|
|
8785
9761
|
return token;
|
|
8786
9762
|
}
|
|
@@ -8880,13 +9856,13 @@ async function login(timeoutMs, newAccount) {
|
|
|
8880
9856
|
function regularUpload(target) {
|
|
8881
9857
|
let stat;
|
|
8882
9858
|
try {
|
|
8883
|
-
stat =
|
|
9859
|
+
stat = fs5.lstatSync(target);
|
|
8884
9860
|
} catch {
|
|
8885
9861
|
throw new CliError("FILE_NOT_FOUND", `file not found: ${target}`, EXIT.ARGUMENT);
|
|
8886
9862
|
}
|
|
8887
9863
|
if (!stat.isFile() || stat.isSymbolicLink()) throw new CliError("INVALID_UPLOAD_FILE", "upload must be a regular non-symlink file", EXIT.ARGUMENT);
|
|
8888
9864
|
if (stat.size > MAX_UPLOAD_BYTES) throw new CliError("UPLOAD_TOO_LARGE", `upload exceeds ${MAX_UPLOAD_BYTES} bytes`, EXIT.ARGUMENT);
|
|
8889
|
-
return
|
|
9865
|
+
return fs5.readFileSync(target);
|
|
8890
9866
|
}
|
|
8891
9867
|
function renderMessages(page) {
|
|
8892
9868
|
for (const item of [...page.items].reverse()) console.log(`${item.localId} ${item.timestamp} ${item.senderName || item.sender || ""} ${item.content}`);
|
|
@@ -8903,15 +9879,15 @@ async function resetAuth(yes) {
|
|
|
8903
9879
|
try {
|
|
8904
9880
|
removeOwnedVolume(inventory, 1, "wechat-home");
|
|
8905
9881
|
} catch (error) {
|
|
8906
|
-
if (error instanceof CliError && error.code === "
|
|
9882
|
+
if (error instanceof CliError && error.code === "VOLUME_DRIVER_UNSUPPORTED") throw error;
|
|
8907
9883
|
throw new CliError("AUTH_RESET_CLEANUP_INCOMPLETE", `remaining resource: volume:${inventory.volumes[1]}`, EXIT.CLEANUP);
|
|
8908
9884
|
}
|
|
8909
9885
|
const remaining = [];
|
|
8910
9886
|
for (const file of ["device-identity.env", "device-identity.json"]) {
|
|
8911
|
-
const target =
|
|
9887
|
+
const target = path5.join(CONFIG_DIR, file);
|
|
8912
9888
|
try {
|
|
8913
9889
|
assertSafePurgePath(target, CONFIG_DIR);
|
|
8914
|
-
|
|
9890
|
+
fs5.unlinkSync(target);
|
|
8915
9891
|
} catch (error) {
|
|
8916
9892
|
if (error.code !== "ENOENT") remaining.push(file);
|
|
8917
9893
|
}
|
|
@@ -8926,7 +9902,6 @@ function programStatus() {
|
|
|
8926
9902
|
const container = inspectContainer();
|
|
8927
9903
|
if (container) {
|
|
8928
9904
|
if (!inventory) throw new CliError("INSTANCE_INVENTORY_MISSING", "existing container has no trusted inventory", EXIT.ENVIRONMENT);
|
|
8929
|
-
assertOwnedContainer(container, inventory);
|
|
8930
9905
|
}
|
|
8931
9906
|
return {
|
|
8932
9907
|
cliVersion: VERSION,
|
|
@@ -8959,9 +9934,9 @@ program2.name("wx").description("Single-instance agent-wechat CLI").version(VERS
|
|
|
8959
9934
|
program2.showSuggestionAfterError();
|
|
8960
9935
|
program2.configureOutput({ outputError: (text) => process.stderr.write(text) });
|
|
8961
9936
|
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 () => {
|
|
9937
|
+
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
9938
|
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 });
|
|
9939
|
+
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
9940
|
output({ container: inventory.containerName, imageDigest: inventory.imageDigest, port: inventory.port }, () => console.log(`Started ${inventory.containerName} on port ${inventory.port}`));
|
|
8966
9941
|
}));
|
|
8967
9942
|
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 +9951,59 @@ program2.command("stop").description("Stop and remove the container; preserve da
|
|
|
8976
9951
|
output(result, () => console.log(result.stopped ? "Container stopped and removed" : "Container is absent"));
|
|
8977
9952
|
}
|
|
8978
9953
|
}));
|
|
8979
|
-
program2.command("restart").description("Restart while preserving data").action(() => action(async () => {
|
|
9954
|
+
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
9955
|
const inventory = loadInventory();
|
|
8981
9956
|
if (!inventory) throw new CliError("INSTANCE_INVENTORY_MISSING", "start the instance first", EXIT.SERVICE);
|
|
8982
|
-
|
|
8983
|
-
const
|
|
8984
|
-
|
|
9957
|
+
const oldContainer = inspectContainer();
|
|
9958
|
+
const cliOverrides = Object.fromEntries([
|
|
9959
|
+
["AGENT_WECHAT_OUTBOUND_QUEUE_CAPACITY", options.outboundQueueCapacity],
|
|
9960
|
+
["AGENT_WECHAT_OUTBOUND_DISABLED", options.outboundDisabled ? "true" : void 0],
|
|
9961
|
+
["AGENT_WECHAT_QUIET_START_MIN", options.outboundQuietStart],
|
|
9962
|
+
["AGENT_WECHAT_QUIET_END_MIN", options.outboundQuietEnd],
|
|
9963
|
+
["AGENT_WECHAT_HOURLY_BUDGET", options.outboundHourlyBudget],
|
|
9964
|
+
["AGENT_WECHAT_DAILY_BUDGET", options.outboundDailyBudget],
|
|
9965
|
+
["AGENT_WECHAT_CHAT_COOLDOWN_MS", options.outboundChatCooldownMs],
|
|
9966
|
+
["AGENT_WECHAT_OUTBOUND_MIN_SPACING_MS", options.outboundMinSpacingMs],
|
|
9967
|
+
["AGENT_WECHAT_OUTBOUND_JITTER_MS", options.outboundJitterMs],
|
|
9968
|
+
["AGENT_WECHAT_OUTBOUND_LONG_TAIL_JITTER_MS", options.outboundLongTailJitterMs],
|
|
9969
|
+
["AGENT_WECHAT_OUTBOUND_LONG_TAIL_CHANCE_PERCENT", options.outboundLongTailChancePercent],
|
|
9970
|
+
["AGENT_WECHAT_OUTBOUND_TASK_TTL_MS", options.outboundTaskTtlMs],
|
|
9971
|
+
["AGENT_WECHAT_OUTBOUND_IDEMPOTENCY_TTL_MS", options.outboundIdempotencyTtlMs],
|
|
9972
|
+
["AGENT_WECHAT_OUTBOUND_IDEMPOTENCY_MAX_ROWS", options.outboundIdempotencyMaxRows]
|
|
9973
|
+
].filter(([, v]) => v !== void 0));
|
|
9974
|
+
const outbound = resolveOutboundConfig(options.outboundConfig, cliOverrides);
|
|
9975
|
+
const oldOutbound = oldContainer ? outboundFromContainer(oldContainer) : {};
|
|
9976
|
+
const effectiveOutbound = { ...oldOutbound, ...outbound };
|
|
9977
|
+
const previousInventory = inventory;
|
|
9978
|
+
const rollbackName = `${CONTAINER_NAME}-rollback`;
|
|
9979
|
+
let oldStopped = false;
|
|
9980
|
+
let oldRenamed = false;
|
|
9981
|
+
try {
|
|
9982
|
+
if (oldContainer) {
|
|
9983
|
+
if (oldContainer.State?.Running) {
|
|
9984
|
+
stopContainer(oldContainer.Id);
|
|
9985
|
+
oldStopped = true;
|
|
9986
|
+
}
|
|
9987
|
+
renameContainer(oldContainer.Id, rollbackName);
|
|
9988
|
+
oldRenamed = true;
|
|
9989
|
+
}
|
|
9990
|
+
const result = await startInstance({ identity: ensureDeviceIdentity(CONFIG_DIR), token: ensureToken(), image: inventory.imageDigest || inventory.imageRef, noPull: true, localDefault: localBuildImage(), outbound: effectiveOutbound });
|
|
9991
|
+
if (oldRenamed) removeContainer(rollbackName);
|
|
9992
|
+
output({ restarted: true, imageDigest: result.imageDigest }, () => console.log("Instance restarted"));
|
|
9993
|
+
} catch (error) {
|
|
9994
|
+
try {
|
|
9995
|
+
const failed = inspectContainer();
|
|
9996
|
+
if (failed && failed.Id !== oldContainer?.Id) removeContainer(failed.Id);
|
|
9997
|
+
if (oldContainer) {
|
|
9998
|
+
if (oldRenamed) renameContainer(rollbackName, CONTAINER_NAME);
|
|
9999
|
+
if (oldStopped && oldContainer.State?.Running) startContainer(CONTAINER_NAME);
|
|
10000
|
+
}
|
|
10001
|
+
saveInventory(previousInventory);
|
|
10002
|
+
} catch {
|
|
10003
|
+
throw new CliError("ROLLBACK_FAILED", "restart failed and rollback was incomplete", EXIT.ROLLBACK);
|
|
10004
|
+
}
|
|
10005
|
+
throw error;
|
|
10006
|
+
}
|
|
8985
10007
|
}));
|
|
8986
10008
|
program2.command("status").description("Show read-only lifecycle and authentication status").action(() => action(async () => {
|
|
8987
10009
|
const status = programStatus();
|
|
@@ -9008,7 +10030,7 @@ program2.command("doctor").description("Run read-only environment and compatibil
|
|
|
9008
10030
|
const checks = programStatus();
|
|
9009
10031
|
checks.architecture = os2.arch();
|
|
9010
10032
|
checks.token = readToken() ? "present" : "absent";
|
|
9011
|
-
checks.configPermissions =
|
|
10033
|
+
checks.configPermissions = fs5.existsSync(CONFIG_DIR) ? (fs5.statSync(CONFIG_DIR).mode & 511).toString(8) : "absent";
|
|
9012
10034
|
if (checks.container === "running") {
|
|
9013
10035
|
try {
|
|
9014
10036
|
checks.health = (await fetch(`http://localhost:${DEFAULT_PORT}/health`)).ok ? "ok" : "failed";
|
|
@@ -9067,6 +10089,13 @@ chats.command("mark-read <chat-id>").action((chatId) => action(async () => {
|
|
|
9067
10089
|
if (!result.ok) throw new CliError(result.errorCode || "MARK_READ_FAILED", result.error || "mark-read was not verified", EXIT.SERVICE);
|
|
9068
10090
|
output(result, () => console.log(`${chatId}: ${result.beforeUnread} -> ${result.afterUnread}`));
|
|
9069
10091
|
}));
|
|
10092
|
+
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 () => {
|
|
10093
|
+
const page = await client().listGroupMembersPage(groupId, integer(options.limit, "limit", 1, 100), options.cursor);
|
|
10094
|
+
output(page, () => {
|
|
10095
|
+
for (const member of page.items) console.log(`${member.memberId} ${member.displayName} ${member.groupAlias ?? ""}`);
|
|
10096
|
+
if (page.nextCursor) console.error(`next cursor: ${page.nextCursor}`);
|
|
10097
|
+
});
|
|
10098
|
+
}));
|
|
9070
10099
|
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
10100
|
const page = await client().listContactsPage(integer(options.limit, "limit", 1, 200), options.cursor);
|
|
9072
10101
|
output(page, () => {
|
|
@@ -9083,8 +10112,8 @@ program2.command("messages <chat-id>").description("Read messages without openin
|
|
|
9083
10112
|
output(page, () => renderMessages(page));
|
|
9084
10113
|
}));
|
|
9085
10114
|
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:
|
|
10115
|
+
const image = options.image ? { data: regularUpload(options.image).toString("base64"), mimeType: path5.extname(options.image).toLowerCase() === ".jpg" ? "image/jpeg" : "image/png" } : void 0;
|
|
10116
|
+
const file = options.file ? { data: regularUpload(options.file).toString("base64"), filename: path5.basename(options.file) } : void 0;
|
|
9088
10117
|
let params;
|
|
9089
10118
|
try {
|
|
9090
10119
|
params = buildCliSendParams({ chatId, text: options.text, image, file, confirmSimilar: options.confirmSimilar, idempotencyKey: options.idempotencyKey });
|
|
@@ -9098,7 +10127,7 @@ program2.command("send <chat-id>").description("Send exactly one payload to a st
|
|
|
9098
10127
|
}
|
|
9099
10128
|
output(result, () => console.log("Message sent"));
|
|
9100
10129
|
}));
|
|
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
|
|
10130
|
+
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
10131
|
const selected = [options.check === true, options.cli === true, typeof options.image === "string"].filter(Boolean).length;
|
|
9103
10132
|
if (selected > 1) throw new CliError("ARGUMENT_CONFLICT", "--check, --cli, and --image are mutually exclusive", EXIT.ARGUMENT);
|
|
9104
10133
|
if (options.cli) {
|
|
@@ -9132,9 +10161,9 @@ for (const [oldName, replacement] of [["up", "start"], ["down", "stop"], ["updat
|
|
|
9132
10161
|
}
|
|
9133
10162
|
function sameEntrypoint(left, right) {
|
|
9134
10163
|
try {
|
|
9135
|
-
return
|
|
10164
|
+
return fs5.realpathSync(left) === fs5.realpathSync(right);
|
|
9136
10165
|
} catch {
|
|
9137
|
-
return
|
|
10166
|
+
return path5.resolve(left) === path5.resolve(right);
|
|
9138
10167
|
}
|
|
9139
10168
|
}
|
|
9140
10169
|
if (process.argv[1] && sameEntrypoint(process.argv[1], fileURLToPath(import.meta.url))) {
|
|
@@ -9148,3 +10177,42 @@ if (process.argv[1] && sameEntrypoint(process.argv[1], fileURLToPath(import.meta
|
|
|
9148
10177
|
process.exitCode = EXIT.SERVICE;
|
|
9149
10178
|
});
|
|
9150
10179
|
}
|
|
10180
|
+
/*! Bundled license information:
|
|
10181
|
+
|
|
10182
|
+
smol-toml/dist/error.js:
|
|
10183
|
+
smol-toml/dist/util.js:
|
|
10184
|
+
smol-toml/dist/date.js:
|
|
10185
|
+
smol-toml/dist/primitive.js:
|
|
10186
|
+
smol-toml/dist/extract.js:
|
|
10187
|
+
smol-toml/dist/struct.js:
|
|
10188
|
+
smol-toml/dist/parse.js:
|
|
10189
|
+
smol-toml/dist/stringify.js:
|
|
10190
|
+
smol-toml/dist/index.js:
|
|
10191
|
+
(*!
|
|
10192
|
+
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
10193
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
10194
|
+
*
|
|
10195
|
+
* Redistribution and use in source and binary forms, with or without
|
|
10196
|
+
* modification, are permitted provided that the following conditions are met:
|
|
10197
|
+
*
|
|
10198
|
+
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
10199
|
+
* list of conditions and the following disclaimer.
|
|
10200
|
+
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
10201
|
+
* this list of conditions and the following disclaimer in the
|
|
10202
|
+
* documentation and/or other materials provided with the distribution.
|
|
10203
|
+
* 3. Neither the name of the copyright holder nor the names of its contributors
|
|
10204
|
+
* may be used to endorse or promote products derived from this software without
|
|
10205
|
+
* specific prior written permission.
|
|
10206
|
+
*
|
|
10207
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
10208
|
+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
10209
|
+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
10210
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
10211
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
10212
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
10213
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
10214
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
10215
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
10216
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
10217
|
+
*)
|
|
10218
|
+
*/
|