@integrity-labs/agt-cli 0.28.612 → 0.28.614
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/bin/agt.js +5 -5
- package/dist/{chunk-DJP4JZGE.js → chunk-6SJJM4FT.js} +2 -2
- package/dist/{chunk-F2WTBHMD.js → chunk-IDWOHBI3.js} +4 -4
- package/dist/{chunk-RQAAW5LL.js → chunk-TYVQNCBU.js} +59 -9
- package/dist/chunk-TYVQNCBU.js.map +1 -0
- package/dist/{claude-pair-runtime-4MKFMNYN.js → claude-pair-runtime-QCL2TB6N.js} +2 -2
- package/dist/lib/manager-worker.js +18 -13
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/direct-chat-channel.js +58 -8
- package/dist/mcp/origami.js +29 -2
- package/dist/mcp/slack-channel.js +248 -20
- package/dist/mcp/telegram-channel.js +58 -8
- package/dist/{persistent-session-KO24RZN7.js → persistent-session-GM3EH2ZU.js} +3 -3
- package/dist/{responsiveness-probe-V4O7DXYV.js → responsiveness-probe-VSSJC3MN.js} +3 -3
- package/dist/{session-auth-dead-S7WK33WO.js → session-auth-dead-KOKVXPPQ.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-RQAAW5LL.js.map +0 -1
- /package/dist/{chunk-DJP4JZGE.js.map → chunk-6SJJM4FT.js.map} +0 -0
- /package/dist/{chunk-F2WTBHMD.js.map → chunk-IDWOHBI3.js.map} +0 -0
- /package/dist/{claude-pair-runtime-4MKFMNYN.js.map → claude-pair-runtime-QCL2TB6N.js.map} +0 -0
- /package/dist/{persistent-session-KO24RZN7.js.map → persistent-session-GM3EH2ZU.js.map} +0 -0
- /package/dist/{responsiveness-probe-V4O7DXYV.js.map → responsiveness-probe-VSSJC3MN.js.map} +0 -0
- /package/dist/{session-auth-dead-S7WK33WO.js.map → session-auth-dead-KOKVXPPQ.js.map} +0 -0
|
@@ -33932,7 +33932,14 @@ var AGENT_DIRECTED_NOTICE_KINDS = [
|
|
|
33932
33932
|
// written for the machine. The user learns the same fact from the connect card
|
|
33933
33933
|
// in that conversation flipping to its connected state, so showing this row as
|
|
33934
33934
|
// well would say it twice, the second time in prose aimed at an agent.
|
|
33935
|
-
"integration_connected"
|
|
33935
|
+
"integration_connected",
|
|
33936
|
+
// ENG-8745. The offer RESULT receipt (not the offer card — that one is
|
|
33937
|
+
// written for the human and is how they decided). Its content opens "Your
|
|
33938
|
+
// offer was ACCEPTED", carries an `[offer_result]` machine tag, and closes by
|
|
33939
|
+
// instructing the agent what not to do ("do not re-raise it yourself"). The
|
|
33940
|
+
// human needs none of it: they are the person who tapped the button, and the
|
|
33941
|
+
// card swapped under their finger to say so.
|
|
33942
|
+
"offer_result"
|
|
33936
33943
|
];
|
|
33937
33944
|
var AGENT_DIRECTED_KIND_SET = new Set(AGENT_DIRECTED_NOTICE_KINDS);
|
|
33938
33945
|
|
|
@@ -34082,6 +34089,17 @@ var CONDITIONAL_DELIVERY_BODY = [
|
|
|
34082
34089
|
var FRESH_HEARTBEAT_THRESHOLD_MS = 2 * 60 * 1e3;
|
|
34083
34090
|
|
|
34084
34091
|
// ../core/dist/claude-code-usage/banner-parser.js
|
|
34092
|
+
var SESSION_QUALIFIER = /^(?:session|\d{1,2}\s*-?\s*hours?|\d{1,2}h)$/i;
|
|
34093
|
+
function classifyLimitScope(qualifier) {
|
|
34094
|
+
const q = (qualifier ?? "").trim();
|
|
34095
|
+
if (!q)
|
|
34096
|
+
return "weekly";
|
|
34097
|
+
if (SESSION_QUALIFIER.test(q))
|
|
34098
|
+
return "session";
|
|
34099
|
+
if (/^weekly$/i.test(q))
|
|
34100
|
+
return "weekly";
|
|
34101
|
+
return "unknown";
|
|
34102
|
+
}
|
|
34085
34103
|
var SEP = /[\s·\-–—]+/.source;
|
|
34086
34104
|
var SUBJECT = /(?:You(?:['’]ve|\s+have)?\s+)?/.source;
|
|
34087
34105
|
var TIME_OF_DAY = /\d{1,2}(?::\d{2})?\s*(?:am|pm)(?:\s*\(?UTC\)?)?/.source;
|
|
@@ -34095,7 +34113,27 @@ var BANNER_PATTERNS = [
|
|
|
34095
34113
|
// Wrapped to keep the per-pattern shape consistent with the percentage form:
|
|
34096
34114
|
// the parser checks group 1 for a digit string and treats a missing one as
|
|
34097
34115
|
// pct=100.
|
|
34098
|
-
|
|
34116
|
+
// ENG-9007: the qualifier is CAPTURED now, by name. It used to be
|
|
34117
|
+
// `(?:[a-z0-9-]+\s+)?` - permissive and non-capturing - so the parser
|
|
34118
|
+
// recognised "session" and "5-hour", matched on them, and threw the word away.
|
|
34119
|
+
// Named groups keep the numbered capture indices stable for the percentage
|
|
34120
|
+
// form above, which still reads groups 1 and 2 positionally.
|
|
34121
|
+
new RegExp(
|
|
34122
|
+
// CodeRabbit on #4621: the qualifier was ONE token, so `classifyLimitScope`
|
|
34123
|
+
// accepted "5 hours" while this pattern could never deliver it — the whole
|
|
34124
|
+
// banner failed to match, no observation was recorded, and the agent went
|
|
34125
|
+
// dark rather than merely being misclassified. Multi-token qualifiers now
|
|
34126
|
+
// match the duration shapes SESSION_QUALIFIER already accepts.
|
|
34127
|
+
//
|
|
34128
|
+
// Deliberately NOT the naive `[a-z0-9]+(?:\s*-?\s*[a-z0-9]+)*`: the
|
|
34129
|
+
// separator there can match empty, which reduces to `(a+)+` and backtracks
|
|
34130
|
+
// catastrophically on a long alphanumeric run that is never followed by
|
|
34131
|
+
// "limit". This parser runs over agent-produced pane.log tails, so that is
|
|
34132
|
+
// reachable input. Requiring at least one separator per extra token, and
|
|
34133
|
+
// bounding the count, keeps it linear.
|
|
34134
|
+
`${SUBJECT}hit\\s+your\\s+(?<qualifier>[a-z0-9]+(?:[\\s-]+[a-z0-9]+){0,3}\\s+)?limit${SEP}resets\\s+(?<reset>${RESET_DATE})`,
|
|
34135
|
+
"i"
|
|
34136
|
+
)
|
|
34099
34137
|
];
|
|
34100
34138
|
function parseUsageBanner(text, now = /* @__PURE__ */ new Date()) {
|
|
34101
34139
|
let bestIndex = -1;
|
|
@@ -34108,24 +34146,33 @@ function parseUsageBanner(text, now = /* @__PURE__ */ new Date()) {
|
|
|
34108
34146
|
pattern.lastIndex++;
|
|
34109
34147
|
let pct;
|
|
34110
34148
|
let resetStr;
|
|
34149
|
+
let qualifier;
|
|
34111
34150
|
if (i === 0) {
|
|
34112
34151
|
pct = Number.parseInt(match[1], 10);
|
|
34113
34152
|
resetStr = match[2];
|
|
34153
|
+
qualifier = "weekly";
|
|
34114
34154
|
} else {
|
|
34115
34155
|
pct = 100;
|
|
34116
|
-
resetStr = match[
|
|
34156
|
+
resetStr = match.groups?.["reset"] ?? "";
|
|
34157
|
+
qualifier = match.groups?.["qualifier"]?.trim() || null;
|
|
34117
34158
|
}
|
|
34118
34159
|
if (!Number.isFinite(pct) || pct < 0 || pct > 100)
|
|
34119
34160
|
continue;
|
|
34120
34161
|
const nextChar = text[match.index + match[0].length];
|
|
34121
34162
|
if (nextChar !== void 0 && /[A-Za-z0-9]/.test(nextChar))
|
|
34122
34163
|
continue;
|
|
34123
|
-
const
|
|
34124
|
-
if (!
|
|
34164
|
+
const reset = parseResetDateTime(resetStr, now);
|
|
34165
|
+
if (!reset)
|
|
34125
34166
|
continue;
|
|
34126
34167
|
if (match.index >= bestIndex) {
|
|
34127
34168
|
bestIndex = match.index;
|
|
34128
|
-
best = {
|
|
34169
|
+
best = {
|
|
34170
|
+
pct,
|
|
34171
|
+
weekResetsAt: reset.at,
|
|
34172
|
+
resetPrecision: reset.precision,
|
|
34173
|
+
limitScope: classifyLimitScope(qualifier),
|
|
34174
|
+
limitQualifier: qualifier
|
|
34175
|
+
};
|
|
34129
34176
|
}
|
|
34130
34177
|
}
|
|
34131
34178
|
}
|
|
@@ -34169,7 +34216,10 @@ function parseResetDateTime(humanDate, now) {
|
|
|
34169
34216
|
if (!hm)
|
|
34170
34217
|
return null;
|
|
34171
34218
|
const todayAt = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), hm.hour, hm.minute);
|
|
34172
|
-
return
|
|
34219
|
+
return {
|
|
34220
|
+
at: new Date(todayAt <= now.getTime() ? todayAt + MS_PER_DAY : todayAt),
|
|
34221
|
+
precision: "hour_only"
|
|
34222
|
+
};
|
|
34173
34223
|
}
|
|
34174
34224
|
const timeMatch = trimmed.match(TIME_TAIL);
|
|
34175
34225
|
const dateOnly = timeMatch ? trimmed.slice(0, timeMatch.index).trim() : trimmed;
|
|
@@ -34202,7 +34252,7 @@ function parseResetDateTime(humanDate, now) {
|
|
|
34202
34252
|
resolved = candidate;
|
|
34203
34253
|
}
|
|
34204
34254
|
}
|
|
34205
|
-
return resolved;
|
|
34255
|
+
return resolved ? { at: resolved, precision: "dated" } : null;
|
|
34206
34256
|
}
|
|
34207
34257
|
|
|
34208
34258
|
// ../core/dist/claude-code-usage/run-marker.js
|
package/dist/mcp/origami.js
CHANGED
|
@@ -40266,7 +40266,14 @@ var AGENT_DIRECTED_NOTICE_KINDS = [
|
|
|
40266
40266
|
// written for the machine. The user learns the same fact from the connect card
|
|
40267
40267
|
// in that conversation flipping to its connected state, so showing this row as
|
|
40268
40268
|
// well would say it twice, the second time in prose aimed at an agent.
|
|
40269
|
-
"integration_connected"
|
|
40269
|
+
"integration_connected",
|
|
40270
|
+
// ENG-8745. The offer RESULT receipt (not the offer card — that one is
|
|
40271
|
+
// written for the human and is how they decided). Its content opens "Your
|
|
40272
|
+
// offer was ACCEPTED", carries an `[offer_result]` machine tag, and closes by
|
|
40273
|
+
// instructing the agent what not to do ("do not re-raise it yourself"). The
|
|
40274
|
+
// human needs none of it: they are the person who tapped the button, and the
|
|
40275
|
+
// card swapped under their finger to say so.
|
|
40276
|
+
"offer_result"
|
|
40270
40277
|
];
|
|
40271
40278
|
var AGENT_DIRECTED_KIND_SET = new Set(AGENT_DIRECTED_NOTICE_KINDS);
|
|
40272
40279
|
|
|
@@ -40373,7 +40380,27 @@ var BANNER_PATTERNS = [
|
|
|
40373
40380
|
// Wrapped to keep the per-pattern shape consistent with the percentage form:
|
|
40374
40381
|
// the parser checks group 1 for a digit string and treats a missing one as
|
|
40375
40382
|
// pct=100.
|
|
40376
|
-
|
|
40383
|
+
// ENG-9007: the qualifier is CAPTURED now, by name. It used to be
|
|
40384
|
+
// `(?:[a-z0-9-]+\s+)?` - permissive and non-capturing - so the parser
|
|
40385
|
+
// recognised "session" and "5-hour", matched on them, and threw the word away.
|
|
40386
|
+
// Named groups keep the numbered capture indices stable for the percentage
|
|
40387
|
+
// form above, which still reads groups 1 and 2 positionally.
|
|
40388
|
+
new RegExp(
|
|
40389
|
+
// CodeRabbit on #4621: the qualifier was ONE token, so `classifyLimitScope`
|
|
40390
|
+
// accepted "5 hours" while this pattern could never deliver it — the whole
|
|
40391
|
+
// banner failed to match, no observation was recorded, and the agent went
|
|
40392
|
+
// dark rather than merely being misclassified. Multi-token qualifiers now
|
|
40393
|
+
// match the duration shapes SESSION_QUALIFIER already accepts.
|
|
40394
|
+
//
|
|
40395
|
+
// Deliberately NOT the naive `[a-z0-9]+(?:\s*-?\s*[a-z0-9]+)*`: the
|
|
40396
|
+
// separator there can match empty, which reduces to `(a+)+` and backtracks
|
|
40397
|
+
// catastrophically on a long alphanumeric run that is never followed by
|
|
40398
|
+
// "limit". This parser runs over agent-produced pane.log tails, so that is
|
|
40399
|
+
// reachable input. Requiring at least one separator per extra token, and
|
|
40400
|
+
// bounding the count, keeps it linear.
|
|
40401
|
+
`${SUBJECT}hit\\s+your\\s+(?<qualifier>[a-z0-9]+(?:[\\s-]+[a-z0-9]+){0,3}\\s+)?limit${SEP}resets\\s+(?<reset>${RESET_DATE})`,
|
|
40402
|
+
"i"
|
|
40403
|
+
)
|
|
40377
40404
|
];
|
|
40378
40405
|
var MS_PER_DAY = 24 * 60 * 60 * 1e3;
|
|
40379
40406
|
|
|
@@ -34317,7 +34317,14 @@ var AGENT_DIRECTED_NOTICE_KINDS = [
|
|
|
34317
34317
|
// written for the machine. The user learns the same fact from the connect card
|
|
34318
34318
|
// in that conversation flipping to its connected state, so showing this row as
|
|
34319
34319
|
// well would say it twice, the second time in prose aimed at an agent.
|
|
34320
|
-
"integration_connected"
|
|
34320
|
+
"integration_connected",
|
|
34321
|
+
// ENG-8745. The offer RESULT receipt (not the offer card — that one is
|
|
34322
|
+
// written for the human and is how they decided). Its content opens "Your
|
|
34323
|
+
// offer was ACCEPTED", carries an `[offer_result]` machine tag, and closes by
|
|
34324
|
+
// instructing the agent what not to do ("do not re-raise it yourself"). The
|
|
34325
|
+
// human needs none of it: they are the person who tapped the button, and the
|
|
34326
|
+
// card swapped under their finger to say so.
|
|
34327
|
+
"offer_result"
|
|
34321
34328
|
];
|
|
34322
34329
|
var AGENT_DIRECTED_KIND_SET = new Set(AGENT_DIRECTED_NOTICE_KINDS);
|
|
34323
34330
|
|
|
@@ -34411,6 +34418,17 @@ var CONDITIONAL_DELIVERY_BODY = [
|
|
|
34411
34418
|
var FRESH_HEARTBEAT_THRESHOLD_MS = 2 * 60 * 1e3;
|
|
34412
34419
|
|
|
34413
34420
|
// ../core/dist/claude-code-usage/banner-parser.js
|
|
34421
|
+
var SESSION_QUALIFIER = /^(?:session|\d{1,2}\s*-?\s*hours?|\d{1,2}h)$/i;
|
|
34422
|
+
function classifyLimitScope(qualifier) {
|
|
34423
|
+
const q = (qualifier ?? "").trim();
|
|
34424
|
+
if (!q)
|
|
34425
|
+
return "weekly";
|
|
34426
|
+
if (SESSION_QUALIFIER.test(q))
|
|
34427
|
+
return "session";
|
|
34428
|
+
if (/^weekly$/i.test(q))
|
|
34429
|
+
return "weekly";
|
|
34430
|
+
return "unknown";
|
|
34431
|
+
}
|
|
34414
34432
|
var SEP = /[\s·\-–—]+/.source;
|
|
34415
34433
|
var SUBJECT = /(?:You(?:['’]ve|\s+have)?\s+)?/.source;
|
|
34416
34434
|
var TIME_OF_DAY = /\d{1,2}(?::\d{2})?\s*(?:am|pm)(?:\s*\(?UTC\)?)?/.source;
|
|
@@ -34424,7 +34442,27 @@ var BANNER_PATTERNS = [
|
|
|
34424
34442
|
// Wrapped to keep the per-pattern shape consistent with the percentage form:
|
|
34425
34443
|
// the parser checks group 1 for a digit string and treats a missing one as
|
|
34426
34444
|
// pct=100.
|
|
34427
|
-
|
|
34445
|
+
// ENG-9007: the qualifier is CAPTURED now, by name. It used to be
|
|
34446
|
+
// `(?:[a-z0-9-]+\s+)?` - permissive and non-capturing - so the parser
|
|
34447
|
+
// recognised "session" and "5-hour", matched on them, and threw the word away.
|
|
34448
|
+
// Named groups keep the numbered capture indices stable for the percentage
|
|
34449
|
+
// form above, which still reads groups 1 and 2 positionally.
|
|
34450
|
+
new RegExp(
|
|
34451
|
+
// CodeRabbit on #4621: the qualifier was ONE token, so `classifyLimitScope`
|
|
34452
|
+
// accepted "5 hours" while this pattern could never deliver it — the whole
|
|
34453
|
+
// banner failed to match, no observation was recorded, and the agent went
|
|
34454
|
+
// dark rather than merely being misclassified. Multi-token qualifiers now
|
|
34455
|
+
// match the duration shapes SESSION_QUALIFIER already accepts.
|
|
34456
|
+
//
|
|
34457
|
+
// Deliberately NOT the naive `[a-z0-9]+(?:\s*-?\s*[a-z0-9]+)*`: the
|
|
34458
|
+
// separator there can match empty, which reduces to `(a+)+` and backtracks
|
|
34459
|
+
// catastrophically on a long alphanumeric run that is never followed by
|
|
34460
|
+
// "limit". This parser runs over agent-produced pane.log tails, so that is
|
|
34461
|
+
// reachable input. Requiring at least one separator per extra token, and
|
|
34462
|
+
// bounding the count, keeps it linear.
|
|
34463
|
+
`${SUBJECT}hit\\s+your\\s+(?<qualifier>[a-z0-9]+(?:[\\s-]+[a-z0-9]+){0,3}\\s+)?limit${SEP}resets\\s+(?<reset>${RESET_DATE})`,
|
|
34464
|
+
"i"
|
|
34465
|
+
)
|
|
34428
34466
|
];
|
|
34429
34467
|
function parseUsageBanner(text, now = /* @__PURE__ */ new Date()) {
|
|
34430
34468
|
let bestIndex = -1;
|
|
@@ -34437,24 +34475,33 @@ function parseUsageBanner(text, now = /* @__PURE__ */ new Date()) {
|
|
|
34437
34475
|
pattern.lastIndex++;
|
|
34438
34476
|
let pct;
|
|
34439
34477
|
let resetStr;
|
|
34478
|
+
let qualifier;
|
|
34440
34479
|
if (i === 0) {
|
|
34441
34480
|
pct = Number.parseInt(match[1], 10);
|
|
34442
34481
|
resetStr = match[2];
|
|
34482
|
+
qualifier = "weekly";
|
|
34443
34483
|
} else {
|
|
34444
34484
|
pct = 100;
|
|
34445
|
-
resetStr = match[
|
|
34485
|
+
resetStr = match.groups?.["reset"] ?? "";
|
|
34486
|
+
qualifier = match.groups?.["qualifier"]?.trim() || null;
|
|
34446
34487
|
}
|
|
34447
34488
|
if (!Number.isFinite(pct) || pct < 0 || pct > 100)
|
|
34448
34489
|
continue;
|
|
34449
34490
|
const nextChar = text[match.index + match[0].length];
|
|
34450
34491
|
if (nextChar !== void 0 && /[A-Za-z0-9]/.test(nextChar))
|
|
34451
34492
|
continue;
|
|
34452
|
-
const
|
|
34453
|
-
if (!
|
|
34493
|
+
const reset = parseResetDateTime(resetStr, now);
|
|
34494
|
+
if (!reset)
|
|
34454
34495
|
continue;
|
|
34455
34496
|
if (match.index >= bestIndex) {
|
|
34456
34497
|
bestIndex = match.index;
|
|
34457
|
-
best = {
|
|
34498
|
+
best = {
|
|
34499
|
+
pct,
|
|
34500
|
+
weekResetsAt: reset.at,
|
|
34501
|
+
resetPrecision: reset.precision,
|
|
34502
|
+
limitScope: classifyLimitScope(qualifier),
|
|
34503
|
+
limitQualifier: qualifier
|
|
34504
|
+
};
|
|
34458
34505
|
}
|
|
34459
34506
|
}
|
|
34460
34507
|
}
|
|
@@ -34498,7 +34545,10 @@ function parseResetDateTime(humanDate, now) {
|
|
|
34498
34545
|
if (!hm)
|
|
34499
34546
|
return null;
|
|
34500
34547
|
const todayAt = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), hm.hour, hm.minute);
|
|
34501
|
-
return
|
|
34548
|
+
return {
|
|
34549
|
+
at: new Date(todayAt <= now.getTime() ? todayAt + MS_PER_DAY : todayAt),
|
|
34550
|
+
precision: "hour_only"
|
|
34551
|
+
};
|
|
34502
34552
|
}
|
|
34503
34553
|
const timeMatch = trimmed.match(TIME_TAIL);
|
|
34504
34554
|
const dateOnly = timeMatch ? trimmed.slice(0, timeMatch.index).trim() : trimmed;
|
|
@@ -34531,7 +34581,7 @@ function parseResetDateTime(humanDate, now) {
|
|
|
34531
34581
|
resolved = candidate;
|
|
34532
34582
|
}
|
|
34533
34583
|
}
|
|
34534
|
-
return resolved;
|
|
34584
|
+
return resolved ? { at: resolved, precision: "dated" } : null;
|
|
34535
34585
|
}
|
|
34536
34586
|
|
|
34537
34587
|
// ../core/dist/claude-code-usage/run-marker.js
|
|
@@ -39394,6 +39444,91 @@ async function runOrRetry(fn, opts) {
|
|
|
39394
39444
|
}
|
|
39395
39445
|
}
|
|
39396
39446
|
|
|
39447
|
+
// src/slack-socket-reconnect.ts
|
|
39448
|
+
var RECONNECT_BASE_DELAY_MS = 1e3;
|
|
39449
|
+
var RECONNECT_MAX_DELAY_MS = 3e4;
|
|
39450
|
+
var SOCKET_OPEN_TIMEOUT_MS = 3e4;
|
|
39451
|
+
var CONNECT_FETCH_TIMEOUT_MS = 15e3;
|
|
39452
|
+
var SOCKET_DOWN_ALERT_AFTER_MS = 3 * 6e4;
|
|
39453
|
+
function reconnectDelayMs(attempt, opts = {}) {
|
|
39454
|
+
const base = opts.baseMs ?? RECONNECT_BASE_DELAY_MS;
|
|
39455
|
+
const max = opts.maxMs ?? RECONNECT_MAX_DELAY_MS;
|
|
39456
|
+
const random = opts.random ?? Math.random;
|
|
39457
|
+
const safeAttempt = Math.max(1, Math.min(Math.floor(attempt), 30));
|
|
39458
|
+
const ceiling = Math.min(max, base * 2 ** (safeAttempt - 1));
|
|
39459
|
+
const floor = Math.min(base, ceiling);
|
|
39460
|
+
return Math.round(floor + random() * (ceiling - floor));
|
|
39461
|
+
}
|
|
39462
|
+
function redactSocketUrl(text) {
|
|
39463
|
+
return text.replace(
|
|
39464
|
+
/([?&])(ticket|token|app_id_key)=[^&\s"']*/gi,
|
|
39465
|
+
(_m, sep2, key2) => `${sep2}${key2}=<redacted>`
|
|
39466
|
+
);
|
|
39467
|
+
}
|
|
39468
|
+
function describeWebSocketError(err) {
|
|
39469
|
+
const parts = [];
|
|
39470
|
+
const e = err ?? {};
|
|
39471
|
+
if (typeof e.message === "string" && e.message) parts.push(e.message);
|
|
39472
|
+
const cause = e.error;
|
|
39473
|
+
if (cause && typeof cause === "object") {
|
|
39474
|
+
if (typeof cause.message === "string" && cause.message && !parts.includes(cause.message)) {
|
|
39475
|
+
parts.push(cause.message);
|
|
39476
|
+
}
|
|
39477
|
+
if (typeof cause.code === "string" && cause.code) parts.push(`errno=${cause.code}`);
|
|
39478
|
+
}
|
|
39479
|
+
if (typeof e.code === "number") parts.push(`code=${e.code}`);
|
|
39480
|
+
if (typeof e.reason === "string" && e.reason) parts.push(`reason=${e.reason}`);
|
|
39481
|
+
if (typeof e.wasClean === "boolean") parts.push(`wasClean=${e.wasClean}`);
|
|
39482
|
+
if (parts.length === 0) {
|
|
39483
|
+
const type = typeof e.type === "string" && e.type ? e.type : typeof err;
|
|
39484
|
+
const ctor = err && typeof err === "object" ? err.constructor?.name ?? "Object" : typeof err;
|
|
39485
|
+
return redactSocketUrl(`no detail available (${ctor}, type=${type})`);
|
|
39486
|
+
}
|
|
39487
|
+
return redactSocketUrl(parts.join(" "));
|
|
39488
|
+
}
|
|
39489
|
+
function isWebSocketOpen(ws) {
|
|
39490
|
+
return ws?.readyState === 1;
|
|
39491
|
+
}
|
|
39492
|
+
function createReconnectScheduler(deps) {
|
|
39493
|
+
const now = deps.now ?? Date.now;
|
|
39494
|
+
const setTimer = deps.setTimer ?? ((fn, ms) => setTimeout(fn, ms));
|
|
39495
|
+
let pending = false;
|
|
39496
|
+
let attempt = 0;
|
|
39497
|
+
let downSince = now();
|
|
39498
|
+
return {
|
|
39499
|
+
schedule(reason) {
|
|
39500
|
+
if (deps.shouldStop() || pending) return;
|
|
39501
|
+
pending = true;
|
|
39502
|
+
if (downSince === null) downSince = now();
|
|
39503
|
+
attempt += 1;
|
|
39504
|
+
const opts = {};
|
|
39505
|
+
if (deps.baseMs !== void 0) opts.baseMs = deps.baseMs;
|
|
39506
|
+
if (deps.maxMs !== void 0) opts.maxMs = deps.maxMs;
|
|
39507
|
+
if (deps.random !== void 0) opts.random = deps.random;
|
|
39508
|
+
const delay = reconnectDelayMs(attempt, opts);
|
|
39509
|
+
deps.log(
|
|
39510
|
+
`slack-channel: Socket Mode reconnecting in ${delay}ms (attempt ${attempt}, ${reason})`
|
|
39511
|
+
);
|
|
39512
|
+
const timer = setTimer(() => {
|
|
39513
|
+
pending = false;
|
|
39514
|
+
if (deps.shouldStop()) return;
|
|
39515
|
+
deps.connect();
|
|
39516
|
+
}, delay);
|
|
39517
|
+
timer.unref?.();
|
|
39518
|
+
},
|
|
39519
|
+
noteOpen() {
|
|
39520
|
+
attempt = 0;
|
|
39521
|
+
downSince = null;
|
|
39522
|
+
},
|
|
39523
|
+
downForMs(connected) {
|
|
39524
|
+
if (connected) return null;
|
|
39525
|
+
return downSince === null ? null : now() - downSince;
|
|
39526
|
+
},
|
|
39527
|
+
attempts: () => attempt,
|
|
39528
|
+
isPending: () => pending
|
|
39529
|
+
};
|
|
39530
|
+
}
|
|
39531
|
+
|
|
39397
39532
|
// src/turn-initiator-marker.ts
|
|
39398
39533
|
import { writeFileSync as writeFileSync7, readFileSync as readFileSync9, mkdirSync as mkdirSync5, renameSync as renameSync2 } from "fs";
|
|
39399
39534
|
import { dirname as dirname4, join as join12 } from "path";
|
|
@@ -43163,10 +43298,12 @@ function formatLastActivity() {
|
|
|
43163
43298
|
return `${kindLabel} ${ago}`;
|
|
43164
43299
|
}
|
|
43165
43300
|
function buildAgentStatusReply(codeName) {
|
|
43166
|
-
const connected =
|
|
43301
|
+
const connected = isSocketConnected();
|
|
43167
43302
|
const dot = connected ? "\u{1F7E2}" : "\u{1F534}";
|
|
43168
43303
|
const state = connected ? "online" : "offline";
|
|
43169
|
-
const
|
|
43304
|
+
const downMs = socketDownForMs();
|
|
43305
|
+
const downSuffix = !connected && downMs !== null ? ` for ${Math.floor(downMs / 6e4)}m \u2014 inbound is dead` : "";
|
|
43306
|
+
const connectivityLine = `${dot} *${state}* \u2014 Socket Mode ${connected ? "connected" : `disconnected${downSuffix}`}. Last activity: ${formatLastActivity()}.`;
|
|
43170
43307
|
const sessionState = readAgentSessionState(SLACK_AGENT_DIR);
|
|
43171
43308
|
return buildAgentConfigReport({ codeName, connectivityLine, state: sessionState });
|
|
43172
43309
|
}
|
|
@@ -43177,9 +43314,16 @@ function statusRuntimeConfig() {
|
|
|
43177
43314
|
}
|
|
43178
43315
|
async function computeSlackOwnChannelLiveStatus() {
|
|
43179
43316
|
const checked_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
43180
|
-
const connected =
|
|
43317
|
+
const connected = isSocketConnected();
|
|
43181
43318
|
if (!connected) {
|
|
43182
|
-
|
|
43319
|
+
const downMs = socketDownForMs();
|
|
43320
|
+
const forSuffix = downMs === null ? "" : ` for ${Math.floor(downMs / 1e3)}s`;
|
|
43321
|
+
const sustained = downMs !== null && downMs >= SOCKET_DOWN_ALERT_AFTER_MS;
|
|
43322
|
+
return {
|
|
43323
|
+
level: "down",
|
|
43324
|
+
checked_at,
|
|
43325
|
+
reason: `Socket Mode disconnected${forSuffix}${sustained ? " - inbound Slack is DEAD (outbound still works, so this is invisible from outside)" : ""}`
|
|
43326
|
+
};
|
|
43183
43327
|
}
|
|
43184
43328
|
const { id, authFailed } = await getBotUserId();
|
|
43185
43329
|
if (id) {
|
|
@@ -43706,7 +43850,7 @@ async function handleSlashCommandEnvelope(payload) {
|
|
|
43706
43850
|
);
|
|
43707
43851
|
return;
|
|
43708
43852
|
}
|
|
43709
|
-
const connected =
|
|
43853
|
+
const connected = isSocketConnected();
|
|
43710
43854
|
const dot = connected ? "\u{1F7E2}" : "\u{1F534}";
|
|
43711
43855
|
const state = connected ? "online" : "offline";
|
|
43712
43856
|
const pong = `${dot} pong - \`${codeName}\` is ${state} (manager \u2022 ${(/* @__PURE__ */ new Date()).toISOString()}). Last activity: ${formatLastActivity()}.`;
|
|
@@ -45778,6 +45922,47 @@ async function resolveUserEmail(userId) {
|
|
|
45778
45922
|
}
|
|
45779
45923
|
var currentWs = null;
|
|
45780
45924
|
var isShuttingDown = false;
|
|
45925
|
+
var clearOpenWatchdog = null;
|
|
45926
|
+
function clearOpenWatchdogFor(ws) {
|
|
45927
|
+
if (currentWs !== ws) return;
|
|
45928
|
+
clearOpenWatchdog?.();
|
|
45929
|
+
clearOpenWatchdog = null;
|
|
45930
|
+
}
|
|
45931
|
+
var reconnectScheduler = createReconnectScheduler({
|
|
45932
|
+
connect: () => connectSocketModeSafely(),
|
|
45933
|
+
log: (line) => process.stderr.write(`${line}
|
|
45934
|
+
`),
|
|
45935
|
+
shouldStop: () => isShuttingDown
|
|
45936
|
+
});
|
|
45937
|
+
function isSocketConnected() {
|
|
45938
|
+
return !isShuttingDown && isWebSocketOpen(currentWs);
|
|
45939
|
+
}
|
|
45940
|
+
function scheduleReconnect(reason) {
|
|
45941
|
+
reconnectScheduler.schedule(reason);
|
|
45942
|
+
}
|
|
45943
|
+
function armOpenWatchdog(ws) {
|
|
45944
|
+
clearOpenWatchdog?.();
|
|
45945
|
+
const timer = setTimeout(() => {
|
|
45946
|
+
if (currentWs !== ws) return;
|
|
45947
|
+
if (isShuttingDown || isWebSocketOpen(ws)) return;
|
|
45948
|
+
process.stderr.write(
|
|
45949
|
+
`slack-channel: Socket Mode did not open within ${SOCKET_OPEN_TIMEOUT_MS}ms - abandoning it
|
|
45950
|
+
`
|
|
45951
|
+
);
|
|
45952
|
+
currentWs = null;
|
|
45953
|
+
clearOpenWatchdog = null;
|
|
45954
|
+
try {
|
|
45955
|
+
ws.close();
|
|
45956
|
+
} catch {
|
|
45957
|
+
}
|
|
45958
|
+
scheduleReconnect("open timeout");
|
|
45959
|
+
}, SOCKET_OPEN_TIMEOUT_MS);
|
|
45960
|
+
timer.unref?.();
|
|
45961
|
+
clearOpenWatchdog = () => clearTimeout(timer);
|
|
45962
|
+
}
|
|
45963
|
+
function socketDownForMs() {
|
|
45964
|
+
return reconnectScheduler.downForMs(isSocketConnected());
|
|
45965
|
+
}
|
|
45781
45966
|
var acquiredLockPath = null;
|
|
45782
45967
|
var stopLockHeartbeat = null;
|
|
45783
45968
|
async function seedMutedChannelsFromApi() {
|
|
@@ -45828,14 +46013,27 @@ async function connectSocketMode() {
|
|
|
45828
46013
|
if (isShuttingDown) return;
|
|
45829
46014
|
const res = await fetch("https://slack.com/api/apps.connections.open", {
|
|
45830
46015
|
method: "POST",
|
|
45831
|
-
headers: { Authorization: `Bearer ${APP_TOKEN}` }
|
|
46016
|
+
headers: { Authorization: `Bearer ${APP_TOKEN}` },
|
|
46017
|
+
// CodeRabbit, #4655. Without a deadline a hanging fetch is the one failure
|
|
46018
|
+
// this whole change does not cover: it never rejects, so the retry chain is
|
|
46019
|
+
// never entered, and no socket exists yet so the open watchdog does not
|
|
46020
|
+
// apply either. The process ends up with nothing pending and no attempt in
|
|
46021
|
+
// flight — the incident's shape, reached a different way. A timeout turns
|
|
46022
|
+
// the hang into a rejection, which the retry chain already handles.
|
|
46023
|
+
signal: AbortSignal.timeout(CONNECT_FETCH_TIMEOUT_MS)
|
|
46024
|
+
// CodeRabbit, #4655. Without a deadline a hanging fetch is the one failure
|
|
46025
|
+
// this whole change does not cover: it never rejects, so the retry chain is
|
|
46026
|
+
// never entered, and no socket exists yet so the open watchdog does not
|
|
46027
|
+
// apply either. The process ends up with nothing pending and no attempt in
|
|
46028
|
+
// flight — the incident's shape, reached a different way. A timeout turns
|
|
46029
|
+
// the hang into a rejection, which the retry chain already handles.
|
|
45832
46030
|
});
|
|
45833
46031
|
const data = await res.json();
|
|
45834
46032
|
if (isShuttingDown) return;
|
|
45835
46033
|
if (!data.ok || !data.url) {
|
|
45836
46034
|
process.stderr.write(`slack-channel: Socket Mode connection failed: ${data.error}
|
|
45837
46035
|
`);
|
|
45838
|
-
|
|
46036
|
+
scheduleReconnect(`apps.connections.open ${data.error ?? "failed"}`);
|
|
45839
46037
|
return;
|
|
45840
46038
|
}
|
|
45841
46039
|
const ws = new WebSocket(data.url);
|
|
@@ -45847,7 +46045,17 @@ async function connectSocketMode() {
|
|
|
45847
46045
|
return;
|
|
45848
46046
|
}
|
|
45849
46047
|
currentWs = ws;
|
|
46048
|
+
armOpenWatchdog(ws);
|
|
45850
46049
|
ws.onopen = () => {
|
|
46050
|
+
if (currentWs !== ws) {
|
|
46051
|
+
try {
|
|
46052
|
+
ws.close();
|
|
46053
|
+
} catch {
|
|
46054
|
+
}
|
|
46055
|
+
return;
|
|
46056
|
+
}
|
|
46057
|
+
clearOpenWatchdogFor(ws);
|
|
46058
|
+
reconnectScheduler.noteOpen();
|
|
45851
46059
|
process.stderr.write("slack-channel: Socket Mode connected\n");
|
|
45852
46060
|
recordActivity("connect");
|
|
45853
46061
|
void setBotStatus(":large_green_circle:", "Active");
|
|
@@ -46493,15 +46701,35 @@ async function connectSocketMode() {
|
|
|
46493
46701
|
`);
|
|
46494
46702
|
}
|
|
46495
46703
|
};
|
|
46496
|
-
ws.onclose = () => {
|
|
46497
|
-
if (currentWs
|
|
46704
|
+
ws.onclose = (evt) => {
|
|
46705
|
+
if (currentWs !== ws) return;
|
|
46706
|
+
clearOpenWatchdogFor(ws);
|
|
46707
|
+
currentWs = null;
|
|
46498
46708
|
if (isShuttingDown) return;
|
|
46499
|
-
process.stderr.write(
|
|
46500
|
-
|
|
46709
|
+
process.stderr.write(
|
|
46710
|
+
`slack-channel: Socket Mode disconnected (${describeWebSocketError(evt)})
|
|
46711
|
+
`
|
|
46712
|
+
);
|
|
46713
|
+
scheduleReconnect("close");
|
|
46501
46714
|
};
|
|
46502
46715
|
ws.onerror = (err) => {
|
|
46503
|
-
process.stderr.write(`slack-channel: WebSocket error: ${err}
|
|
46716
|
+
process.stderr.write(`slack-channel: WebSocket error: ${describeWebSocketError(err)}
|
|
46504
46717
|
`);
|
|
46718
|
+
if (currentWs !== ws) {
|
|
46719
|
+
try {
|
|
46720
|
+
ws.close();
|
|
46721
|
+
} catch {
|
|
46722
|
+
}
|
|
46723
|
+
return;
|
|
46724
|
+
}
|
|
46725
|
+
clearOpenWatchdogFor(ws);
|
|
46726
|
+
currentWs = null;
|
|
46727
|
+
try {
|
|
46728
|
+
ws.close();
|
|
46729
|
+
} catch {
|
|
46730
|
+
}
|
|
46731
|
+
if (isShuttingDown) return;
|
|
46732
|
+
scheduleReconnect("error");
|
|
46505
46733
|
};
|
|
46506
46734
|
}
|
|
46507
46735
|
function shutdown(reason, exitCode = 0) {
|
|
@@ -34476,7 +34476,14 @@ var AGENT_DIRECTED_NOTICE_KINDS = [
|
|
|
34476
34476
|
// written for the machine. The user learns the same fact from the connect card
|
|
34477
34477
|
// in that conversation flipping to its connected state, so showing this row as
|
|
34478
34478
|
// well would say it twice, the second time in prose aimed at an agent.
|
|
34479
|
-
"integration_connected"
|
|
34479
|
+
"integration_connected",
|
|
34480
|
+
// ENG-8745. The offer RESULT receipt (not the offer card — that one is
|
|
34481
|
+
// written for the human and is how they decided). Its content opens "Your
|
|
34482
|
+
// offer was ACCEPTED", carries an `[offer_result]` machine tag, and closes by
|
|
34483
|
+
// instructing the agent what not to do ("do not re-raise it yourself"). The
|
|
34484
|
+
// human needs none of it: they are the person who tapped the button, and the
|
|
34485
|
+
// card swapped under their finger to say so.
|
|
34486
|
+
"offer_result"
|
|
34480
34487
|
];
|
|
34481
34488
|
var AGENT_DIRECTED_KIND_SET = new Set(AGENT_DIRECTED_NOTICE_KINDS);
|
|
34482
34489
|
|
|
@@ -34570,6 +34577,17 @@ var CONDITIONAL_DELIVERY_BODY = [
|
|
|
34570
34577
|
var FRESH_HEARTBEAT_THRESHOLD_MS = 2 * 60 * 1e3;
|
|
34571
34578
|
|
|
34572
34579
|
// ../core/dist/claude-code-usage/banner-parser.js
|
|
34580
|
+
var SESSION_QUALIFIER = /^(?:session|\d{1,2}\s*-?\s*hours?|\d{1,2}h)$/i;
|
|
34581
|
+
function classifyLimitScope(qualifier) {
|
|
34582
|
+
const q = (qualifier ?? "").trim();
|
|
34583
|
+
if (!q)
|
|
34584
|
+
return "weekly";
|
|
34585
|
+
if (SESSION_QUALIFIER.test(q))
|
|
34586
|
+
return "session";
|
|
34587
|
+
if (/^weekly$/i.test(q))
|
|
34588
|
+
return "weekly";
|
|
34589
|
+
return "unknown";
|
|
34590
|
+
}
|
|
34573
34591
|
var SEP = /[\s·\-–—]+/.source;
|
|
34574
34592
|
var SUBJECT = /(?:You(?:['’]ve|\s+have)?\s+)?/.source;
|
|
34575
34593
|
var TIME_OF_DAY = /\d{1,2}(?::\d{2})?\s*(?:am|pm)(?:\s*\(?UTC\)?)?/.source;
|
|
@@ -34583,7 +34601,27 @@ var BANNER_PATTERNS = [
|
|
|
34583
34601
|
// Wrapped to keep the per-pattern shape consistent with the percentage form:
|
|
34584
34602
|
// the parser checks group 1 for a digit string and treats a missing one as
|
|
34585
34603
|
// pct=100.
|
|
34586
|
-
|
|
34604
|
+
// ENG-9007: the qualifier is CAPTURED now, by name. It used to be
|
|
34605
|
+
// `(?:[a-z0-9-]+\s+)?` - permissive and non-capturing - so the parser
|
|
34606
|
+
// recognised "session" and "5-hour", matched on them, and threw the word away.
|
|
34607
|
+
// Named groups keep the numbered capture indices stable for the percentage
|
|
34608
|
+
// form above, which still reads groups 1 and 2 positionally.
|
|
34609
|
+
new RegExp(
|
|
34610
|
+
// CodeRabbit on #4621: the qualifier was ONE token, so `classifyLimitScope`
|
|
34611
|
+
// accepted "5 hours" while this pattern could never deliver it — the whole
|
|
34612
|
+
// banner failed to match, no observation was recorded, and the agent went
|
|
34613
|
+
// dark rather than merely being misclassified. Multi-token qualifiers now
|
|
34614
|
+
// match the duration shapes SESSION_QUALIFIER already accepts.
|
|
34615
|
+
//
|
|
34616
|
+
// Deliberately NOT the naive `[a-z0-9]+(?:\s*-?\s*[a-z0-9]+)*`: the
|
|
34617
|
+
// separator there can match empty, which reduces to `(a+)+` and backtracks
|
|
34618
|
+
// catastrophically on a long alphanumeric run that is never followed by
|
|
34619
|
+
// "limit". This parser runs over agent-produced pane.log tails, so that is
|
|
34620
|
+
// reachable input. Requiring at least one separator per extra token, and
|
|
34621
|
+
// bounding the count, keeps it linear.
|
|
34622
|
+
`${SUBJECT}hit\\s+your\\s+(?<qualifier>[a-z0-9]+(?:[\\s-]+[a-z0-9]+){0,3}\\s+)?limit${SEP}resets\\s+(?<reset>${RESET_DATE})`,
|
|
34623
|
+
"i"
|
|
34624
|
+
)
|
|
34587
34625
|
];
|
|
34588
34626
|
function parseUsageBanner(text, now = /* @__PURE__ */ new Date()) {
|
|
34589
34627
|
let bestIndex = -1;
|
|
@@ -34596,24 +34634,33 @@ function parseUsageBanner(text, now = /* @__PURE__ */ new Date()) {
|
|
|
34596
34634
|
pattern.lastIndex++;
|
|
34597
34635
|
let pct;
|
|
34598
34636
|
let resetStr;
|
|
34637
|
+
let qualifier;
|
|
34599
34638
|
if (i === 0) {
|
|
34600
34639
|
pct = Number.parseInt(match[1], 10);
|
|
34601
34640
|
resetStr = match[2];
|
|
34641
|
+
qualifier = "weekly";
|
|
34602
34642
|
} else {
|
|
34603
34643
|
pct = 100;
|
|
34604
|
-
resetStr = match[
|
|
34644
|
+
resetStr = match.groups?.["reset"] ?? "";
|
|
34645
|
+
qualifier = match.groups?.["qualifier"]?.trim() || null;
|
|
34605
34646
|
}
|
|
34606
34647
|
if (!Number.isFinite(pct) || pct < 0 || pct > 100)
|
|
34607
34648
|
continue;
|
|
34608
34649
|
const nextChar = text[match.index + match[0].length];
|
|
34609
34650
|
if (nextChar !== void 0 && /[A-Za-z0-9]/.test(nextChar))
|
|
34610
34651
|
continue;
|
|
34611
|
-
const
|
|
34612
|
-
if (!
|
|
34652
|
+
const reset = parseResetDateTime(resetStr, now);
|
|
34653
|
+
if (!reset)
|
|
34613
34654
|
continue;
|
|
34614
34655
|
if (match.index >= bestIndex) {
|
|
34615
34656
|
bestIndex = match.index;
|
|
34616
|
-
best = {
|
|
34657
|
+
best = {
|
|
34658
|
+
pct,
|
|
34659
|
+
weekResetsAt: reset.at,
|
|
34660
|
+
resetPrecision: reset.precision,
|
|
34661
|
+
limitScope: classifyLimitScope(qualifier),
|
|
34662
|
+
limitQualifier: qualifier
|
|
34663
|
+
};
|
|
34617
34664
|
}
|
|
34618
34665
|
}
|
|
34619
34666
|
}
|
|
@@ -34657,7 +34704,10 @@ function parseResetDateTime(humanDate, now) {
|
|
|
34657
34704
|
if (!hm)
|
|
34658
34705
|
return null;
|
|
34659
34706
|
const todayAt = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), hm.hour, hm.minute);
|
|
34660
|
-
return
|
|
34707
|
+
return {
|
|
34708
|
+
at: new Date(todayAt <= now.getTime() ? todayAt + MS_PER_DAY : todayAt),
|
|
34709
|
+
precision: "hour_only"
|
|
34710
|
+
};
|
|
34661
34711
|
}
|
|
34662
34712
|
const timeMatch = trimmed.match(TIME_TAIL);
|
|
34663
34713
|
const dateOnly = timeMatch ? trimmed.slice(0, timeMatch.index).trim() : trimmed;
|
|
@@ -34690,7 +34740,7 @@ function parseResetDateTime(humanDate, now) {
|
|
|
34690
34740
|
resolved = candidate;
|
|
34691
34741
|
}
|
|
34692
34742
|
}
|
|
34693
|
-
return resolved;
|
|
34743
|
+
return resolved ? { at: resolved, precision: "dated" } : null;
|
|
34694
34744
|
}
|
|
34695
34745
|
|
|
34696
34746
|
// ../core/dist/claude-code-usage/run-marker.js
|