@agentcomms/whatsapp 0.24.0 → 0.26.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/dist/cli.mjs +2 -2
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{server-Btcjiqz2.mjs → server-ubl3VinK.mjs} +1 -1
- package/dist/{stdio-entry-pwRwRiwa.mjs → stdio-entry-DQ1RgYGk.mjs} +1 -1
- package/dist/{sync-DYq2CGVj.mjs → sync-BwJSBi-M.mjs} +83 -29
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as gatedChangeAtTerminal, A as requireAccount, B as PATH_OPTIONS, Ct as CALLER, F as expandSource, G as approveChangeAtTerminal, H as absoluteSearchPath, J as cliHandoffs, K as canPrompt, L as CHANNEL_SERVERS, M as storeIdentity, N as checkStorePath, O as PLATFORM, P as defaultStorePath, Q as exemptFromUpdateNotice, R as CommsError, S as chatRefOf, St as writeResult, Tt as VERSION, U as agentMarker, W as approveAndWaitSentence, X as commandPathOf, Y as colorEnabled, Z as escapeForDisplay, _ as WhatsAppContext, _t as truncateDisplay, a as CHAT_KINDS, at as nameAvailable, b as requireSupportedNode, bt as windowsSystemProgram, c as searchMessages, ct as paint, dt as renderPrune, et as handoffSentence, f as draftMessage, ft as resolvePaths, ht as serverPruneChange, i as probeStore, it as lookupName, j as requireNamedConfig, k as newWhatsAppAccount, l as Presenter, lt as pathOverridesFromCliOptions, m as listKey, mt as serverInstallChange, nt as installExitStatus, o as listChats, ot as nameShapeProblem, p as Visibility, pt as runCommand, q as childEnvironment, r as whatsappStatus, rt as isCommsError, s as readChat, st as openCore, t as syncAccount, tt as handoffText, u as innerText, ut as renderInstall, v as WhatsAppIndex, vt as updateNoticeAtTerminal, xt as withFileLock, z as EXIT_CODES } from "./sync-
|
|
2
|
+
import { $ as gatedChangeAtTerminal, A as requireAccount, B as PATH_OPTIONS, Ct as CALLER, F as expandSource, G as approveChangeAtTerminal, H as absoluteSearchPath, J as cliHandoffs, K as canPrompt, L as CHANNEL_SERVERS, M as storeIdentity, N as checkStorePath, O as PLATFORM, P as defaultStorePath, Q as exemptFromUpdateNotice, R as CommsError, S as chatRefOf, St as writeResult, Tt as VERSION, U as agentMarker, W as approveAndWaitSentence, X as commandPathOf, Y as colorEnabled, Z as escapeForDisplay, _ as WhatsAppContext, _t as truncateDisplay, a as CHAT_KINDS, at as nameAvailable, b as requireSupportedNode, bt as windowsSystemProgram, c as searchMessages, ct as paint, dt as renderPrune, et as handoffSentence, f as draftMessage, ft as resolvePaths, ht as serverPruneChange, i as probeStore, it as lookupName, j as requireNamedConfig, k as newWhatsAppAccount, l as Presenter, lt as pathOverridesFromCliOptions, m as listKey, mt as serverInstallChange, nt as installExitStatus, o as listChats, ot as nameShapeProblem, p as Visibility, pt as runCommand, q as childEnvironment, r as whatsappStatus, rt as isCommsError, s as readChat, st as openCore, t as syncAccount, tt as handoffText, u as innerText, ut as renderInstall, v as WhatsAppIndex, vt as updateNoticeAtTerminal, xt as withFileLock, z as EXIT_CODES } from "./sync-BwJSBi-M.mjs";
|
|
3
3
|
import { rm } from "node:fs/promises";
|
|
4
4
|
import path, { delimiter, join } from "node:path";
|
|
5
5
|
import { stripVTControlCharacters } from "node:util";
|
|
@@ -3569,7 +3569,7 @@ a macOS dialog may be waiting) · 77 permission needed (macOS privacy) · 78 con
|
|
|
3569
3569
|
ran = true;
|
|
3570
3570
|
exitCode = await runCommand(output(), async () => {
|
|
3571
3571
|
requireSupportedNode();
|
|
3572
|
-
await (deps.startMcp ?? (await import("./stdio-entry-
|
|
3572
|
+
await (deps.startMcp ?? (await import("./stdio-entry-DQ1RgYGk.mjs")).startWhatsAppStdioServer)({
|
|
3573
3573
|
env,
|
|
3574
3574
|
platform,
|
|
3575
3575
|
...deps,
|
package/dist/index.d.mts
CHANGED
|
@@ -4277,7 +4277,7 @@ declare namespace external_d_exports {
|
|
|
4277
4277
|
export { $brand, $input, $output, BRAND, CompileOptions, GlobalMeta, INVALID, Infer$1 as Infer, IssueData, JSONType, NEVER, $RefinementCtx as RefinementCtx, SafeExtendShape, Schema, TimePrecision, TypeOf, ZodAny, ZodArray, ZodBase64, ZodBase64URL, ZodBigInt, ZodBigIntFormat, ZodBoolean, ZodCIDRv4, ZodCIDRv6, ZodCUID, ZodCUID2, ZodCatch, ZodCodec, ZodCoercedBigInt, ZodCoercedBoolean, ZodCoercedDate, ZodCoercedNumber, ZodCoercedString, ZodCompileAsyncError, ZodCompileUnsupportedError, ZodCreditCard, ZodCustom, ZodCustomStringFormat, ZodDate, ZodDefault, ZodDiscriminatedUnion, ZodE164, ZodEmail, ZodEmoji, ZodEnum, ZodError, ZodErrorMap, ZodExactOptional, ZodFile, ZodFirstPartySchemaTypes, ZodFirstPartyTypeKind, ZodFlattenedError, ZodFloat32, ZodFloat64, ZodFormattedError, ZodFunction, ZodGUID, ZodIBAN, ZodIPv4, ZodIPv6, ZodISODate, ZodISODateTime, ZodISODuration, ZodISOTime, ZodInstanceOf, ZodInt, ZodInt32, ZodInt64, ZodIntersection, ZodIssue, ZodIssueCode, ZodJSONSchema, ZodJSONSchemaInternals, ZodJWT, ZodKSUID, ZodLazy, ZodLiteral, ZodMAC, ZodMap, ZodNaN, ZodNanoID, ZodNever, ZodNonOptional, ZodNull, ZodNullable, ZodNumber, ZodNumberFormat, ZodObject, ZodOptional, ZodPipe, ZodPrefault, ZodPreprocess, ZodPromise, ZodRawShape$1 as ZodRawShape, ZodReadonly, ZodRealError, ZodRecord, ZodSafeParseError, ZodSafeParseResult, ZodSafeParseSuccess, ZodSchema, ZodSet, ZodStandardSchemaWithJSON, ZodString, ZodStringFormat, ZodSuccess, ZodSymbol, ZodTemplateLiteral, ZodTransform, ZodTuple, ZodType, ZodTypeAny, ZodUInt32, ZodUInt64, ZodULID, ZodURL, ZodUUID, ZodUndefined, ZodUnion, ZodUnknown, ZodVoid, ZodXID, ZodXor, _ZodBigInt, _ZodBoolean, _ZodDate, _ZodNumber, _ZodString, _ZodType, _default, _function, any, array, base64, base64url, bigint$1 as bigint, boolean$1 as boolean, _catch as catch, check, cidrv4, cidrv6, clone, codec, coerce_d_exports as coerce, compile, config, index_d_exports$1 as core, creditCard, cuid, cuid2, currencyCode, custom, date$2 as date, decode, decodeAsync, deepPartial, describe, discriminatedUnion, e164, email, emoji, encode, encodeAsync, _endsWith as endsWith, _enum as enum, exactOptional, file, flattenError, float32, float64, formatError, fromJSONSchema, _function as function, getDiscriminatedOption, getErrorMap, globalRegistry, _gt as gt, _gte as gte, guid, hash, hex, hostname, httpUrl, iban, _includes as includes, output$1 as infer, inferFlattenedErrors, inferFormattedError, input, _instanceof as instanceof, int, int32, int64, intersection, invertCodec, ipv4, ipv6, iso_d_exports as iso, json, jwt, keyof, ksuid, lazy, _length as length, literal, index_d_exports$2 as locales, looseObject, looseRecord, _lowercase as lowercase, _lt as lt, _lte as lte, mac, map, _maxLength as maxLength, _maxSize as maxSize, memoizer, meta, _mime as mime, _minLength as minLength, _minSize as minSize, _multipleOf as multipleOf, nan, nanoid, nativeEnum, _negative as negative, never, _nonnegative as nonnegative, nonoptional, _nonpositive as nonpositive, _normalize as normalize, _null as null, nullable, nullish, number$1 as number, object, optional, output, _overwrite as overwrite, parse, parseAsync, partialRecord, pipe, _positive as positive, prefault, preprocess, prettifyError, promise, _properties as properties, _property as property, readonly, record, refine, _regex as regex, regexes_d_exports as regexes, registry, safeDecode, safeDecodeAsync, safeEncode, safeEncodeAsync, safeParse, safeParseAsync, set, setErrorMap, _size as size, _slugify as slugify, _startsWith as startsWith, strictObject, string$1 as string, stringFormat, stringbool, success, superRefine, symbol, templateLiteral, toJSONSchema, _toLowerCase as toLowerCase, _toUpperCase as toUpperCase, toZod, transform, treeifyError, _trim as trim, tuple, uint32, uint64, ulid, _undefined as undefined, union, unknown, _uppercase as uppercase, url, util_d_exports as util, uuid, uuidv4, uuidv6, uuidv7, validate, validateAsync, _void as void, withParser, xid, xor };
|
|
4278
4278
|
}
|
|
4279
4279
|
//#endregion
|
|
4280
|
-
//#region ../core/dist/launcher-
|
|
4280
|
+
//#region ../core/dist/launcher-PMDWJUz9.d.mts
|
|
4281
4281
|
interface RegisteredServer {
|
|
4282
4282
|
client: string;
|
|
4283
4283
|
path: string;
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as chatKindOf, D as text, E as numeric, R as CommsError, T as kindOf, Tt as VERSION, _ as WhatsAppContext, d as composeDraft, g as visibilityUnitKey, h as statusAuthor, m as listKey, n as withCheckedCopy, p as Visibility, w as coreDataToIso, wt as PACKAGE_NAME, x as inspectSchema, y as rebuildIndex } from "./sync-
|
|
2
|
-
import { t as createWhatsAppMcpServer } from "./server-
|
|
1
|
+
import { C as chatKindOf, D as text, E as numeric, R as CommsError, T as kindOf, Tt as VERSION, _ as WhatsAppContext, d as composeDraft, g as visibilityUnitKey, h as statusAuthor, m as listKey, n as withCheckedCopy, p as Visibility, w as coreDataToIso, wt as PACKAGE_NAME, x as inspectSchema, y as rebuildIndex } from "./sync-BwJSBi-M.mjs";
|
|
2
|
+
import { t as createWhatsAppMcpServer } from "./server-ubl3VinK.mjs";
|
|
3
3
|
//#region src/source/event-reader.ts
|
|
4
4
|
function rawFromMe(value) {
|
|
5
5
|
const number = numeric(value);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as strictToolArguments, Tt as VERSION, V as UNTRUSTED_NOTICE, _ as WhatsAppContext, a as CHAT_KINDS, c as searchMessages, f as draftMessage, gt as toCommsError, o as listChats, r as whatsappStatus, s as readChat, t as syncAccount, yt as updateToolNotice } from "./sync-
|
|
1
|
+
import { I as strictToolArguments, Tt as VERSION, V as UNTRUSTED_NOTICE, _ as WhatsAppContext, a as CHAT_KINDS, c as searchMessages, f as draftMessage, gt as toCommsError, o as listChats, r as whatsappStatus, s as readChat, t as syncAccount, yt as updateToolNotice } from "./sync-BwJSBi-M.mjs";
|
|
2
2
|
import { c as boolean, h as number, x as string } from "./iso-USuVU_sk.mjs";
|
|
3
3
|
import { t as McpServer } from "./mcp-DIH4cS6P-CIWWZQbz.mjs";
|
|
4
4
|
//#region src/mcp/server.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as createWhatsAppMcpServer } from "./server-
|
|
1
|
+
import { t as createWhatsAppMcpServer } from "./server-ubl3VinK.mjs";
|
|
2
2
|
//#region src/mcp/stdio-entry.ts
|
|
3
3
|
/**
|
|
4
4
|
* Starting the stdio server. On stdio, stdout is the protocol, so the console is redirected to stderr first — the
|
|
@@ -11,7 +11,7 @@ import { execFile, spawn } from "node:child_process";
|
|
|
11
11
|
//#endregion
|
|
12
12
|
//#region src/version.ts
|
|
13
13
|
/** The package version, read from package.json at build time. */
|
|
14
|
-
const VERSION$2 = "0.
|
|
14
|
+
const VERSION$2 = "0.26.0";
|
|
15
15
|
//#endregion
|
|
16
16
|
//#region src/caller.ts
|
|
17
17
|
/** This package's name, as its manifest has it. */
|
|
@@ -28,7 +28,7 @@ const CALLER = Object.freeze({
|
|
|
28
28
|
packageName: PACKAGE_NAME
|
|
29
29
|
});
|
|
30
30
|
//#endregion
|
|
31
|
-
//#region ../core/dist/update-check-
|
|
31
|
+
//#region ../core/dist/update-check-C3j1VxDg.mjs
|
|
32
32
|
/**
|
|
33
33
|
* Every failure a user or an agent can act on carries a specific, stable code from this registry, a message, an
|
|
34
34
|
* optional one-line hint and structured `details`. The code decides the process exit status; agents and skills branch
|
|
@@ -7157,6 +7157,24 @@ function parseConfig(text, source = "config.json") {
|
|
|
7157
7157
|
if (!parsed.success) throw new CommsError("CONFIG", `${source} is invalid: ${describeIssues(parsed.error, naming === 1 ? 1 : 2)}`);
|
|
7158
7158
|
return parsed.data;
|
|
7159
7159
|
}
|
|
7160
|
+
/**
|
|
7161
|
+
* How a config write waits for the config lock: five seconds for each holder, thirty seconds in all.
|
|
7162
|
+
*
|
|
7163
|
+
* The lock is a queue. Every send prepare, claim and approval on every channel runs `ensureSendEpochConfig` first, and
|
|
7164
|
+
* while a legacy drain is open that is a config write or two per call, so an agent's parallel calls across several MCP
|
|
7165
|
+
* servers arrive at this lock together, each holding it for one read, check and fsynced rename (and the drain's, for a
|
|
7166
|
+
* list of the approvals too). Counted from when each waiter began, the lock's five seconds were a budget for the whole
|
|
7167
|
+
* line ahead: on the Windows runner a line of twelve writes gave up at the ninth, "another agent-communications process
|
|
7168
|
+
* is holding", while the lock was being handed on exactly as it should be. A holder there took about half a second, and
|
|
7169
|
+
* on Windows a rename alone may retry for one. Counted per holder, as Resend's throttle and Gmail's history caches count
|
|
7170
|
+
* theirs, a write gives up only on a holder that keeps the lock for the whole five seconds: the stuck lock the timeout is
|
|
7171
|
+
* for. The lock is polled rather than queued, so thirty seconds in all bounds the rest, and leaves room inside the minute
|
|
7172
|
+
* an MCP client waits for a tool call.
|
|
7173
|
+
*/
|
|
7174
|
+
const CONFIG_WRITE_LOCK = {
|
|
7175
|
+
timeoutPerHolder: true,
|
|
7176
|
+
maxWaitMs: 3e4
|
|
7177
|
+
};
|
|
7160
7178
|
var ConfigStore = class {
|
|
7161
7179
|
path;
|
|
7162
7180
|
#lockPath;
|
|
@@ -7177,6 +7195,10 @@ var ConfigStore = class {
|
|
|
7177
7195
|
#namesMigrateAgain(why) {
|
|
7178
7196
|
return handoffSentence(requiredHandoffs(this.#handoffs).core(["names", "migrate"]), (command) => `Run ${command} again ${why}.`, { instead: `Call comms_names_migrate again ${why}.` });
|
|
7179
7197
|
}
|
|
7198
|
+
/** Runs `fn` holding the config lock, waited for as a write waits for it (`CONFIG_WRITE_LOCK`). */
|
|
7199
|
+
#withWriteLock(fn) {
|
|
7200
|
+
return withFileLock(this.#lockPath, fn, CONFIG_WRITE_LOCK);
|
|
7201
|
+
}
|
|
7180
7202
|
/** The current config; an empty one when the file does not exist yet. */
|
|
7181
7203
|
async load() {
|
|
7182
7204
|
let key;
|
|
@@ -7203,7 +7225,7 @@ var ConfigStore = class {
|
|
|
7203
7225
|
let committed;
|
|
7204
7226
|
let result;
|
|
7205
7227
|
try {
|
|
7206
|
-
result = await
|
|
7228
|
+
result = await this.#withWriteLock(async () => {
|
|
7207
7229
|
options.signal?.throwIfAborted();
|
|
7208
7230
|
this.#cache = null;
|
|
7209
7231
|
const current = structuredClone(await this.load());
|
|
@@ -12004,7 +12026,7 @@ function folding(platform) {
|
|
|
12004
12026
|
return platform === "win32" ? (text) => text.toLowerCase() : (text) => text;
|
|
12005
12027
|
}
|
|
12006
12028
|
/** The package version, read from package.json at build time. */
|
|
12007
|
-
const VERSION = "0.
|
|
12029
|
+
const VERSION = "0.26.0";
|
|
12008
12030
|
/**
|
|
12009
12031
|
* The command a person is told to run for one of this suite's own CLIs (design 2026-10-04, D1 and D5; CUE-403).
|
|
12010
12032
|
*
|
|
@@ -13298,7 +13320,7 @@ const PER_WORKSPACE = {
|
|
|
13298
13320
|
"agentLabel.slackStyles": "app",
|
|
13299
13321
|
"agentLabel.slackIcons": "your Slack photo"
|
|
13300
13322
|
};
|
|
13301
|
-
function recordOf$
|
|
13323
|
+
function recordOf$2(value) {
|
|
13302
13324
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
13303
13325
|
}
|
|
13304
13326
|
/**
|
|
@@ -13308,7 +13330,7 @@ function recordOf$1(value) {
|
|
|
13308
13330
|
*/
|
|
13309
13331
|
function perWorkspace(field, before, after) {
|
|
13310
13332
|
const none = PER_WORKSPACE[field];
|
|
13311
|
-
const [was, now] = [recordOf$
|
|
13333
|
+
const [was, now] = [recordOf$2(before ?? {}), recordOf$2(after ?? {})];
|
|
13312
13334
|
if (none === void 0 || was === void 0 || now === void 0) return void 0;
|
|
13313
13335
|
const value = (record, name) => Object.hasOwn(record, name) ? String(record[name]) : none;
|
|
13314
13336
|
const moved = [.../* @__PURE__ */ new Set([...Object.keys(was), ...Object.keys(now)])].filter((name) => value(was, name) !== value(now, name)).sort();
|
|
@@ -13321,7 +13343,7 @@ function perWorkspace(field, before, after) {
|
|
|
13321
13343
|
* commas. A level one side does not list allows everything there. Undefined for a value of another shape.
|
|
13322
13344
|
*/
|
|
13323
13345
|
function perLevel(field, before, after) {
|
|
13324
|
-
const [was, now] = [recordOf$
|
|
13346
|
+
const [was, now] = [recordOf$2(before ?? {}), recordOf$2(after ?? {})];
|
|
13325
13347
|
if (field !== "behaviour.rules" || was === void 0 || now === void 0) return void 0;
|
|
13326
13348
|
const value = (record, level) => Object.hasOwn(record, level) ? String(record[level]) : "everything";
|
|
13327
13349
|
const levels = [.../* @__PURE__ */ new Set([...Object.keys(was), ...Object.keys(now)])].sort();
|
|
@@ -13896,7 +13918,7 @@ const OUTCOMES = [
|
|
|
13896
13918
|
"unknown"
|
|
13897
13919
|
];
|
|
13898
13920
|
const isString = (value) => typeof value === "string";
|
|
13899
|
-
const isTime$
|
|
13921
|
+
const isTime$3 = (value) => isString(value) && ISO.test(value) && !Number.isNaN(Date.parse(value));
|
|
13900
13922
|
/** One line as an entry, or null when it is not one this release wrote. */
|
|
13901
13923
|
function entryOf$2(line) {
|
|
13902
13924
|
let raw;
|
|
@@ -13907,7 +13929,7 @@ function entryOf$2(line) {
|
|
|
13907
13929
|
}
|
|
13908
13930
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return null;
|
|
13909
13931
|
const entry = raw;
|
|
13910
|
-
if (!isTime$
|
|
13932
|
+
if (!isTime$3(entry.at)) return null;
|
|
13911
13933
|
if (entry.kind === "use") {
|
|
13912
13934
|
if (![
|
|
13913
13935
|
"standingId",
|
|
@@ -13939,7 +13961,7 @@ function entryOf$2(line) {
|
|
|
13939
13961
|
if (entry.kind === "outcome") {
|
|
13940
13962
|
if (!isString(entry.childId) || !isString(entry.outcome) || !OUTCOMES.includes(entry.outcome)) return null;
|
|
13941
13963
|
if (!isString(entry.notice) || entry.link !== void 0 && !isString(entry.link)) return null;
|
|
13942
|
-
if (entry.actAt !== void 0 && !isTime$
|
|
13964
|
+
if (entry.actAt !== void 0 && !isTime$3(entry.actAt)) return null;
|
|
13943
13965
|
return {
|
|
13944
13966
|
kind: "outcome",
|
|
13945
13967
|
at: entry.at,
|
|
@@ -14384,7 +14406,7 @@ function updateJobSupported(platform) {
|
|
|
14384
14406
|
function updateJobMarkerPath(stateDir) {
|
|
14385
14407
|
return join(stateDir, "update-job.json");
|
|
14386
14408
|
}
|
|
14387
|
-
const isTime$
|
|
14409
|
+
const isTime$2 = (value) => typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
14388
14410
|
/** The record, or null when there is none — or none this release can read, which is treated as none. */
|
|
14389
14411
|
async function readUpdateJobMarker(stateDir) {
|
|
14390
14412
|
let parsed;
|
|
@@ -14399,11 +14421,11 @@ async function readUpdateJobMarker(stateDir) {
|
|
|
14399
14421
|
platform: record.platform,
|
|
14400
14422
|
installedAt: record.installedAt,
|
|
14401
14423
|
label: record.label,
|
|
14402
|
-
...isTime$
|
|
14424
|
+
...isTime$2(record.lastRun) ? { lastRun: record.lastRun } : {}
|
|
14403
14425
|
};
|
|
14404
14426
|
}
|
|
14405
14427
|
function within$1(at, now, intervalMs) {
|
|
14406
|
-
if (at === void 0 || !isTime$
|
|
14428
|
+
if (at === void 0 || !isTime$2(at)) return false;
|
|
14407
14429
|
const since = now.getTime() - Date.parse(at);
|
|
14408
14430
|
return since >= -3e5 && since < intervalMs;
|
|
14409
14431
|
}
|
|
@@ -14484,7 +14506,7 @@ const NOTICE_OUTCOMES = [
|
|
|
14484
14506
|
function readBackgroundNotice(value) {
|
|
14485
14507
|
if (typeof value !== "object" || value === null) return null;
|
|
14486
14508
|
const { at, outcome, version, text } = value;
|
|
14487
|
-
if (!isTime(at) || !NOTICE_OUTCOMES.includes(outcome) || typeof text !== "string") return null;
|
|
14509
|
+
if (!isTime$1(at) || !NOTICE_OUTCOMES.includes(outcome) || typeof text !== "string") return null;
|
|
14488
14510
|
return {
|
|
14489
14511
|
at,
|
|
14490
14512
|
outcome,
|
|
@@ -14513,7 +14535,7 @@ const EMPTY_UPDATE_CHECK = Object.freeze({
|
|
|
14513
14535
|
function updateCheckPath(stateDir) {
|
|
14514
14536
|
return join(stateDir, UPDATE_CHECK_FILE);
|
|
14515
14537
|
}
|
|
14516
|
-
const isTime = (value) => typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
14538
|
+
const isTime$1 = (value) => typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
14517
14539
|
const isWords = (value) => Array.isArray(value) && value.every((word) => typeof word === "string");
|
|
14518
14540
|
function readRelease(value) {
|
|
14519
14541
|
if (typeof value !== "object" || value === null) return null;
|
|
@@ -14546,17 +14568,17 @@ async function readUpdateCheck(stateDir) {
|
|
|
14546
14568
|
}
|
|
14547
14569
|
const held = typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
14548
14570
|
return {
|
|
14549
|
-
lastChecked: isTime(held.lastChecked) ? held.lastChecked : null,
|
|
14571
|
+
lastChecked: isTime$1(held.lastChecked) ? held.lastChecked : null,
|
|
14550
14572
|
latest: isPlainVersion(held.latest) ? held.latest : null,
|
|
14551
14573
|
behind: typeof held.behind === "boolean" ? held.behind : null,
|
|
14552
14574
|
current: readCurrent(held.current),
|
|
14553
14575
|
lastError: typeof held.lastError === "string" ? held.lastError.slice(0, 300) : null,
|
|
14554
|
-
snoozedUntil: isTime(held.snoozedUntil) ? held.snoozedUntil : null,
|
|
14555
|
-
checking: isTime(held.checking) ? held.checking : null,
|
|
14556
|
-
commandNoticeAt: isTime(held.commandNoticeAt) ? held.commandNoticeAt : null,
|
|
14557
|
-
noticeAt: isTime(held.noticeAt) ? held.noticeAt : null,
|
|
14558
|
-
pausedAt: isTime(held.pausedAt) ? held.pausedAt : null,
|
|
14559
|
-
pausedUntil: isTime(held.pausedUntil) ? held.pausedUntil : null,
|
|
14576
|
+
snoozedUntil: isTime$1(held.snoozedUntil) ? held.snoozedUntil : null,
|
|
14577
|
+
checking: isTime$1(held.checking) ? held.checking : null,
|
|
14578
|
+
commandNoticeAt: isTime$1(held.commandNoticeAt) ? held.commandNoticeAt : null,
|
|
14579
|
+
noticeAt: isTime$1(held.noticeAt) ? held.noticeAt : null,
|
|
14580
|
+
pausedAt: isTime$1(held.pausedAt) ? held.pausedAt : null,
|
|
14581
|
+
pausedUntil: isTime$1(held.pausedUntil) ? held.pausedUntil : null,
|
|
14560
14582
|
release: readRelease(held.release),
|
|
14561
14583
|
securityAsked: isPlainVersion(held.securityAsked) ? held.securityAsked : null,
|
|
14562
14584
|
securityShown: readSecurityShown(held.securityShown),
|
|
@@ -14565,11 +14587,41 @@ async function readUpdateCheck(stateDir) {
|
|
|
14565
14587
|
};
|
|
14566
14588
|
}
|
|
14567
14589
|
/**
|
|
14590
|
+
* How every writer of the record takes the lock beside it: 2 s for each holder, and 15 s in all (design 2026-10-22, R2).
|
|
14591
|
+
*
|
|
14592
|
+
* Every server's tool call takes this lock for its refresh, so on a busy machine a writer often waits behind several
|
|
14593
|
+
* holders in turn, each holding it for a moment. Counted from the start of the wait, 2 s was a budget for that whole
|
|
14594
|
+
* queue, and a writer at the back of it gave up while the lock was being handed on exactly as it should be: a
|
|
14595
|
+
* person's update was installed and its record dropped. Counted per holder, a writer gives up only on one holder that
|
|
14596
|
+
* kept the lock for 2 s, which is a stuck lock; 15 s bounds a queue that never empties, as config writes are bounded.
|
|
14597
|
+
*/
|
|
14598
|
+
const UPDATE_CHECK_LOCK = Object.freeze({
|
|
14599
|
+
timeoutPerHolder: true,
|
|
14600
|
+
timeoutMs: 2e3,
|
|
14601
|
+
maxWaitMs: 15e3
|
|
14602
|
+
});
|
|
14603
|
+
/**
|
|
14604
|
+
* How a notice takes the lock: 2 s in all, counted from the start of the wait, however often it changes hands meanwhile.
|
|
14605
|
+
*
|
|
14606
|
+
* A notice is best effort. Deciding a tool call's or a command's line, the security line in a preview, and recording
|
|
14607
|
+
* the person's answer to that line take the lock only for what is said, and each runs while a person or an agent
|
|
14608
|
+
* waits. Waited out holder by holder, as `UPDATE_CHECK_LOCK` waits, a busy machine's queue of refreshes held them for
|
|
14609
|
+
* up to 15 s. Busy past 2 s, a notice decides nothing this time, and a later call says it.
|
|
14610
|
+
*
|
|
14611
|
+
* Claiming the day's check is best effort too: busy past 2 s, nothing is claimed, and a later process claims it (0.26.0
|
|
14612
|
+
* review B). The claim's function is not named here: this comment ships in WhatsApp's bundle, which carries none of the
|
|
14613
|
+
* checker, not even its name (`packages/whatsapp/test/update-gate.test.ts`).
|
|
14614
|
+
*/
|
|
14615
|
+
const UPDATE_NOTICE_LOCK = Object.freeze({ timeoutMs: 2e3 });
|
|
14616
|
+
/**
|
|
14568
14617
|
* Reads the record, changes it and writes it back, under a lock beside it, atomically — so a server recording a check
|
|
14569
14618
|
* and a person's "not now" arriving at the same moment each keep what the other wrote. Returns what `change` returned
|
|
14570
14619
|
* alongside the record written; `change` returning `null` writes nothing.
|
|
14620
|
+
*
|
|
14621
|
+
* `lock` is how long to wait for the lock: `UPDATE_CHECK_LOCK`, for a record that matters, unless a notice or the
|
|
14622
|
+
* day's claim passes `UPDATE_NOTICE_LOCK`. Busy past it, this throws LOCK_TIMEOUT, and nothing is written.
|
|
14571
14623
|
*/
|
|
14572
|
-
async function changeUpdateCheck(stateDir, change) {
|
|
14624
|
+
async function changeUpdateCheck(stateDir, change, lock = UPDATE_CHECK_LOCK) {
|
|
14573
14625
|
return withFileLock(join(stateDir, ".update-check.lock"), async () => {
|
|
14574
14626
|
const current = await readUpdateCheck(stateDir);
|
|
14575
14627
|
const next = change(current);
|
|
@@ -14584,7 +14636,7 @@ async function changeUpdateCheck(stateDir, change) {
|
|
|
14584
14636
|
result: next.result,
|
|
14585
14637
|
written: true
|
|
14586
14638
|
};
|
|
14587
|
-
},
|
|
14639
|
+
}, lock);
|
|
14588
14640
|
}
|
|
14589
14641
|
/**
|
|
14590
14642
|
* Whether the check is due: never asked, asked a day or more ago, or — a clock that went back — asked more than a few
|
|
@@ -14823,7 +14875,7 @@ async function securityAnswered(stateDir, approvalId) {
|
|
|
14823
14875
|
securityAsked: record.securityShown.version,
|
|
14824
14876
|
securityShown: null
|
|
14825
14877
|
} };
|
|
14826
|
-
});
|
|
14878
|
+
}, UPDATE_NOTICE_LOCK);
|
|
14827
14879
|
} catch {}
|
|
14828
14880
|
}
|
|
14829
14881
|
/** A local time as a person reads it in a preview: `2026-09-29 00:00`. */
|
|
@@ -15488,6 +15540,7 @@ function serverInstallChange(core, env, request, own, deps = {}) {
|
|
|
15488
15540
|
});
|
|
15489
15541
|
const unverifiedOwn = fetches && deps.verifyRelease === void 0 && running !== void 0 && running.packageName === product.packageName && running.version === version;
|
|
15490
15542
|
const verified = fetches && !unverifiedOwn || checksDisk ? (await verifyReleaseSet(from, /* @__PURE__ */ new Map([[product.packageName, version]]), "install", from.registry === null || from.verify === null ? verifyInCore() : void 0)).get(product.packageName) : void 0;
|
|
15543
|
+
if (request.print !== true && launcher === "npx" && target.writes && deps.verifyRelease !== void 0) await verifyReleaseSet(from, /* @__PURE__ */ new Map([[facts.npxPackage, version]]), "install");
|
|
15491
15544
|
planned = {
|
|
15492
15545
|
product,
|
|
15493
15546
|
install: plannedInstall(preflight),
|
|
@@ -15667,7 +15720,7 @@ function serverPruneChange(core, env, request, own) {
|
|
|
15667
15720
|
};
|
|
15668
15721
|
const { packageName, version } = ownProduct(request.channel, own) ?? {
|
|
15669
15722
|
packageName: serverFacts(request.channel).packageName,
|
|
15670
|
-
version: "0.
|
|
15723
|
+
version: "0.26.0"
|
|
15671
15724
|
};
|
|
15672
15725
|
const product = {
|
|
15673
15726
|
packageName,
|
|
@@ -15949,7 +16002,7 @@ async function decideNotice(options, where) {
|
|
|
15949
16002
|
};
|
|
15950
16003
|
};
|
|
15951
16004
|
if (due(await readUpdateCheck(options.core.paths.stateDir), now()) === null) return null;
|
|
15952
|
-
|
|
16005
|
+
const decide = (record) => {
|
|
15953
16006
|
const at = now();
|
|
15954
16007
|
const decision = due(record, at);
|
|
15955
16008
|
if (decision === null) return null;
|
|
@@ -15973,7 +16026,8 @@ async function decideNotice(options, where) {
|
|
|
15973
16026
|
}
|
|
15974
16027
|
}
|
|
15975
16028
|
};
|
|
15976
|
-
}
|
|
16029
|
+
};
|
|
16030
|
+
return (await changeUpdateCheck(options.core.paths.stateDir, decide, UPDATE_NOTICE_LOCK)).result ?? null;
|
|
15977
16031
|
}
|
|
15978
16032
|
/**
|
|
15979
16033
|
* What a background run left, when it is this process's to say: an install only to a process running a release before
|
|
@@ -16206,7 +16260,7 @@ function commandDecisionLine(core, decision, channel, platform) {
|
|
|
16206
16260
|
}
|
|
16207
16261
|
channelServer("core").packageName;
|
|
16208
16262
|
//#endregion
|
|
16209
|
-
//#region ../core/dist/tool-arguments-
|
|
16263
|
+
//#region ../core/dist/tool-arguments-C8Oy4uOx.mjs
|
|
16210
16264
|
const APPLIED = Symbol.for("agentcomms.strictToolArguments");
|
|
16211
16265
|
const TARGET = "draft-2020-12";
|
|
16212
16266
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentcomms/whatsapp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "WhatsApp for coding agents, read-only: list, read and search the chats WhatsApp for Mac keeps on this Mac, and draft replies as links the person sends. No network client; it never sends.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@agentcomms/core": "0.
|
|
37
|
+
"@agentcomms/core": "0.26.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@modelcontextprotocol/client": "2.3.1",
|
|
@@ -98,5 +98,5 @@
|
|
|
98
98
|
"typecheck": "tsc -p tsconfig.json",
|
|
99
99
|
"test": "node --experimental-strip-types --disable-warning=ExperimentalWarning --test --test-timeout=600000 \"test/**/*.test.ts\""
|
|
100
100
|
},
|
|
101
|
-
"gitHead": "
|
|
101
|
+
"gitHead": "4a096cb13ea1444f1301137f9f91d07b8401aaa2"
|
|
102
102
|
}
|