oh-my-opencode 3.17.12 → 3.17.14
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.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.ru.md +1 -1
- package/README.zh-cn.md +1 -1
- package/dist/cli/index.js +20504 -20595
- package/dist/cli/run/continuation-state.d.ts +1 -0
- package/dist/features/background-agent/manager.d.ts +14 -9
- package/dist/features/background-agent/process-cleanup.d.ts +4 -0
- package/dist/features/background-agent/types.d.ts +12 -12
- package/dist/features/background-agent/wait-for-task-session.d.ts +1 -1
- package/dist/features/run-continuation-state/types.d.ts +1 -1
- package/dist/features/skill-mcp-manager/types.d.ts +1 -0
- package/dist/features/team-mode/resolve-caller-team-lead.d.ts +8 -0
- package/dist/hooks/ralph-loop/loop-session-recovery.d.ts +7 -0
- package/dist/hooks/session-notification-scheduler.d.ts +2 -4
- package/dist/hooks/session-notification-utils.d.ts +1 -0
- package/dist/index.js +620 -334
- package/dist/shared/posthog-activity-state.d.ts +0 -5
- package/dist/shared/posthog.d.ts +0 -5
- package/package.json +13 -13
package/dist/index.js
CHANGED
|
@@ -3003,6 +3003,7 @@ function truncateDescription(description, maxLength = 120) {
|
|
|
3003
3003
|
var require_constants = __commonJS((exports, module) => {
|
|
3004
3004
|
var WIN_SLASH = "\\\\/";
|
|
3005
3005
|
var WIN_NO_SLASH = `[^${WIN_SLASH}]`;
|
|
3006
|
+
var DEFAULT_MAX_EXTGLOB_RECURSION = 0;
|
|
3006
3007
|
var DOT_LITERAL = "\\.";
|
|
3007
3008
|
var PLUS_LITERAL = "\\+";
|
|
3008
3009
|
var QMARK_LITERAL = "\\?";
|
|
@@ -3053,6 +3054,7 @@ var require_constants = __commonJS((exports, module) => {
|
|
|
3053
3054
|
SEP: "\\"
|
|
3054
3055
|
};
|
|
3055
3056
|
var POSIX_REGEX_SOURCE = {
|
|
3057
|
+
__proto__: null,
|
|
3056
3058
|
alnum: "a-zA-Z0-9",
|
|
3057
3059
|
alpha: "a-zA-Z",
|
|
3058
3060
|
ascii: "\\x00-\\x7F",
|
|
@@ -3069,6 +3071,7 @@ var require_constants = __commonJS((exports, module) => {
|
|
|
3069
3071
|
xdigit: "A-Fa-f0-9"
|
|
3070
3072
|
};
|
|
3071
3073
|
module.exports = {
|
|
3074
|
+
DEFAULT_MAX_EXTGLOB_RECURSION,
|
|
3072
3075
|
MAX_LENGTH: 1024 * 64,
|
|
3073
3076
|
POSIX_REGEX_SOURCE,
|
|
3074
3077
|
REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g,
|
|
@@ -3546,6 +3549,213 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
3546
3549
|
var syntaxError = (type2, char) => {
|
|
3547
3550
|
return `Missing ${type2}: "${char}" - use "\\\\${char}" to match literal characters`;
|
|
3548
3551
|
};
|
|
3552
|
+
var splitTopLevel = (input) => {
|
|
3553
|
+
const parts = [];
|
|
3554
|
+
let bracket = 0;
|
|
3555
|
+
let paren = 0;
|
|
3556
|
+
let quote = 0;
|
|
3557
|
+
let value = "";
|
|
3558
|
+
let escaped = false;
|
|
3559
|
+
for (const ch of input) {
|
|
3560
|
+
if (escaped === true) {
|
|
3561
|
+
value += ch;
|
|
3562
|
+
escaped = false;
|
|
3563
|
+
continue;
|
|
3564
|
+
}
|
|
3565
|
+
if (ch === "\\") {
|
|
3566
|
+
value += ch;
|
|
3567
|
+
escaped = true;
|
|
3568
|
+
continue;
|
|
3569
|
+
}
|
|
3570
|
+
if (ch === '"') {
|
|
3571
|
+
quote = quote === 1 ? 0 : 1;
|
|
3572
|
+
value += ch;
|
|
3573
|
+
continue;
|
|
3574
|
+
}
|
|
3575
|
+
if (quote === 0) {
|
|
3576
|
+
if (ch === "[") {
|
|
3577
|
+
bracket++;
|
|
3578
|
+
} else if (ch === "]" && bracket > 0) {
|
|
3579
|
+
bracket--;
|
|
3580
|
+
} else if (bracket === 0) {
|
|
3581
|
+
if (ch === "(") {
|
|
3582
|
+
paren++;
|
|
3583
|
+
} else if (ch === ")" && paren > 0) {
|
|
3584
|
+
paren--;
|
|
3585
|
+
} else if (ch === "|" && paren === 0) {
|
|
3586
|
+
parts.push(value);
|
|
3587
|
+
value = "";
|
|
3588
|
+
continue;
|
|
3589
|
+
}
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
value += ch;
|
|
3593
|
+
}
|
|
3594
|
+
parts.push(value);
|
|
3595
|
+
return parts;
|
|
3596
|
+
};
|
|
3597
|
+
var isPlainBranch = (branch) => {
|
|
3598
|
+
let escaped = false;
|
|
3599
|
+
for (const ch of branch) {
|
|
3600
|
+
if (escaped === true) {
|
|
3601
|
+
escaped = false;
|
|
3602
|
+
continue;
|
|
3603
|
+
}
|
|
3604
|
+
if (ch === "\\") {
|
|
3605
|
+
escaped = true;
|
|
3606
|
+
continue;
|
|
3607
|
+
}
|
|
3608
|
+
if (/[?*+@!()[\]{}]/.test(ch)) {
|
|
3609
|
+
return false;
|
|
3610
|
+
}
|
|
3611
|
+
}
|
|
3612
|
+
return true;
|
|
3613
|
+
};
|
|
3614
|
+
var normalizeSimpleBranch = (branch) => {
|
|
3615
|
+
let value = branch.trim();
|
|
3616
|
+
let changed = true;
|
|
3617
|
+
while (changed === true) {
|
|
3618
|
+
changed = false;
|
|
3619
|
+
if (/^@\([^\\()[\]{}|]+\)$/.test(value)) {
|
|
3620
|
+
value = value.slice(2, -1);
|
|
3621
|
+
changed = true;
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
if (!isPlainBranch(value)) {
|
|
3625
|
+
return;
|
|
3626
|
+
}
|
|
3627
|
+
return value.replace(/\\(.)/g, "$1");
|
|
3628
|
+
};
|
|
3629
|
+
var hasRepeatedCharPrefixOverlap = (branches) => {
|
|
3630
|
+
const values = branches.map(normalizeSimpleBranch).filter(Boolean);
|
|
3631
|
+
for (let i2 = 0;i2 < values.length; i2++) {
|
|
3632
|
+
for (let j = i2 + 1;j < values.length; j++) {
|
|
3633
|
+
const a = values[i2];
|
|
3634
|
+
const b = values[j];
|
|
3635
|
+
const char = a[0];
|
|
3636
|
+
if (!char || a !== char.repeat(a.length) || b !== char.repeat(b.length)) {
|
|
3637
|
+
continue;
|
|
3638
|
+
}
|
|
3639
|
+
if (a === b || a.startsWith(b) || b.startsWith(a)) {
|
|
3640
|
+
return true;
|
|
3641
|
+
}
|
|
3642
|
+
}
|
|
3643
|
+
}
|
|
3644
|
+
return false;
|
|
3645
|
+
};
|
|
3646
|
+
var parseRepeatedExtglob = (pattern, requireEnd = true) => {
|
|
3647
|
+
if (pattern[0] !== "+" && pattern[0] !== "*" || pattern[1] !== "(") {
|
|
3648
|
+
return;
|
|
3649
|
+
}
|
|
3650
|
+
let bracket = 0;
|
|
3651
|
+
let paren = 0;
|
|
3652
|
+
let quote = 0;
|
|
3653
|
+
let escaped = false;
|
|
3654
|
+
for (let i2 = 1;i2 < pattern.length; i2++) {
|
|
3655
|
+
const ch = pattern[i2];
|
|
3656
|
+
if (escaped === true) {
|
|
3657
|
+
escaped = false;
|
|
3658
|
+
continue;
|
|
3659
|
+
}
|
|
3660
|
+
if (ch === "\\") {
|
|
3661
|
+
escaped = true;
|
|
3662
|
+
continue;
|
|
3663
|
+
}
|
|
3664
|
+
if (ch === '"') {
|
|
3665
|
+
quote = quote === 1 ? 0 : 1;
|
|
3666
|
+
continue;
|
|
3667
|
+
}
|
|
3668
|
+
if (quote === 1) {
|
|
3669
|
+
continue;
|
|
3670
|
+
}
|
|
3671
|
+
if (ch === "[") {
|
|
3672
|
+
bracket++;
|
|
3673
|
+
continue;
|
|
3674
|
+
}
|
|
3675
|
+
if (ch === "]" && bracket > 0) {
|
|
3676
|
+
bracket--;
|
|
3677
|
+
continue;
|
|
3678
|
+
}
|
|
3679
|
+
if (bracket > 0) {
|
|
3680
|
+
continue;
|
|
3681
|
+
}
|
|
3682
|
+
if (ch === "(") {
|
|
3683
|
+
paren++;
|
|
3684
|
+
continue;
|
|
3685
|
+
}
|
|
3686
|
+
if (ch === ")") {
|
|
3687
|
+
paren--;
|
|
3688
|
+
if (paren === 0) {
|
|
3689
|
+
if (requireEnd === true && i2 !== pattern.length - 1) {
|
|
3690
|
+
return;
|
|
3691
|
+
}
|
|
3692
|
+
return {
|
|
3693
|
+
type: pattern[0],
|
|
3694
|
+
body: pattern.slice(2, i2),
|
|
3695
|
+
end: i2
|
|
3696
|
+
};
|
|
3697
|
+
}
|
|
3698
|
+
}
|
|
3699
|
+
}
|
|
3700
|
+
};
|
|
3701
|
+
var getStarExtglobSequenceOutput = (pattern) => {
|
|
3702
|
+
let index = 0;
|
|
3703
|
+
const chars = [];
|
|
3704
|
+
while (index < pattern.length) {
|
|
3705
|
+
const match = parseRepeatedExtglob(pattern.slice(index), false);
|
|
3706
|
+
if (!match || match.type !== "*") {
|
|
3707
|
+
return;
|
|
3708
|
+
}
|
|
3709
|
+
const branches = splitTopLevel(match.body).map((branch2) => branch2.trim());
|
|
3710
|
+
if (branches.length !== 1) {
|
|
3711
|
+
return;
|
|
3712
|
+
}
|
|
3713
|
+
const branch = normalizeSimpleBranch(branches[0]);
|
|
3714
|
+
if (!branch || branch.length !== 1) {
|
|
3715
|
+
return;
|
|
3716
|
+
}
|
|
3717
|
+
chars.push(branch);
|
|
3718
|
+
index += match.end + 1;
|
|
3719
|
+
}
|
|
3720
|
+
if (chars.length < 1) {
|
|
3721
|
+
return;
|
|
3722
|
+
}
|
|
3723
|
+
const source = chars.length === 1 ? utils.escapeRegex(chars[0]) : `[${chars.map((ch) => utils.escapeRegex(ch)).join("")}]`;
|
|
3724
|
+
return `${source}*`;
|
|
3725
|
+
};
|
|
3726
|
+
var repeatedExtglobRecursion = (pattern) => {
|
|
3727
|
+
let depth = 0;
|
|
3728
|
+
let value = pattern.trim();
|
|
3729
|
+
let match = parseRepeatedExtglob(value);
|
|
3730
|
+
while (match) {
|
|
3731
|
+
depth++;
|
|
3732
|
+
value = match.body.trim();
|
|
3733
|
+
match = parseRepeatedExtglob(value);
|
|
3734
|
+
}
|
|
3735
|
+
return depth;
|
|
3736
|
+
};
|
|
3737
|
+
var analyzeRepeatedExtglob = (body, options) => {
|
|
3738
|
+
if (options.maxExtglobRecursion === false) {
|
|
3739
|
+
return { risky: false };
|
|
3740
|
+
}
|
|
3741
|
+
const max = typeof options.maxExtglobRecursion === "number" ? options.maxExtglobRecursion : constants5.DEFAULT_MAX_EXTGLOB_RECURSION;
|
|
3742
|
+
const branches = splitTopLevel(body).map((branch) => branch.trim());
|
|
3743
|
+
if (branches.length > 1) {
|
|
3744
|
+
if (branches.some((branch) => branch === "") || branches.some((branch) => /^[*?]+$/.test(branch)) || hasRepeatedCharPrefixOverlap(branches)) {
|
|
3745
|
+
return { risky: true };
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
for (const branch of branches) {
|
|
3749
|
+
const safeOutput = getStarExtglobSequenceOutput(branch);
|
|
3750
|
+
if (safeOutput) {
|
|
3751
|
+
return { risky: true, safeOutput };
|
|
3752
|
+
}
|
|
3753
|
+
if (repeatedExtglobRecursion(branch) > max) {
|
|
3754
|
+
return { risky: true };
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
return { risky: false };
|
|
3758
|
+
};
|
|
3549
3759
|
var parse3 = (input, options) => {
|
|
3550
3760
|
if (typeof input !== "string") {
|
|
3551
3761
|
throw new TypeError("Expected a string");
|
|
@@ -3677,6 +3887,8 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
3677
3887
|
token.prev = prev;
|
|
3678
3888
|
token.parens = state3.parens;
|
|
3679
3889
|
token.output = state3.output;
|
|
3890
|
+
token.startIndex = state3.index;
|
|
3891
|
+
token.tokensIndex = tokens.length;
|
|
3680
3892
|
const output = (opts.capture ? "(" : "") + token.open;
|
|
3681
3893
|
increment("parens");
|
|
3682
3894
|
push({ type: type2, value: value2, output: state3.output ? "" : ONE_CHAR });
|
|
@@ -3684,6 +3896,26 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
3684
3896
|
extglobs.push(token);
|
|
3685
3897
|
};
|
|
3686
3898
|
const extglobClose = (token) => {
|
|
3899
|
+
const literal = input.slice(token.startIndex, state3.index + 1);
|
|
3900
|
+
const body = input.slice(token.startIndex + 2, state3.index);
|
|
3901
|
+
const analysis = analyzeRepeatedExtglob(body, opts);
|
|
3902
|
+
if ((token.type === "plus" || token.type === "star") && analysis.risky) {
|
|
3903
|
+
const safeOutput = analysis.safeOutput ? (token.output ? "" : ONE_CHAR) + (opts.capture ? `(${analysis.safeOutput})` : analysis.safeOutput) : undefined;
|
|
3904
|
+
const open = tokens[token.tokensIndex];
|
|
3905
|
+
open.type = "text";
|
|
3906
|
+
open.value = literal;
|
|
3907
|
+
open.output = safeOutput || utils.escapeRegex(literal);
|
|
3908
|
+
for (let i2 = token.tokensIndex + 1;i2 < tokens.length; i2++) {
|
|
3909
|
+
tokens[i2].value = "";
|
|
3910
|
+
tokens[i2].output = "";
|
|
3911
|
+
delete tokens[i2].suffix;
|
|
3912
|
+
}
|
|
3913
|
+
state3.output = token.output + open.output;
|
|
3914
|
+
state3.backtrack = true;
|
|
3915
|
+
push({ type: "paren", extglob: true, value, output: "" });
|
|
3916
|
+
decrement("parens");
|
|
3917
|
+
return;
|
|
3918
|
+
}
|
|
3687
3919
|
let output = token.close + (opts.capture ? ")" : "");
|
|
3688
3920
|
let rest;
|
|
3689
3921
|
if (token.type === "negate") {
|
|
@@ -19339,13 +19571,11 @@ var AGENT_RESTRICTIONS = {
|
|
|
19339
19571
|
},
|
|
19340
19572
|
metis: {
|
|
19341
19573
|
write: false,
|
|
19342
|
-
edit: false
|
|
19343
|
-
task: false
|
|
19574
|
+
edit: false
|
|
19344
19575
|
},
|
|
19345
19576
|
momus: {
|
|
19346
19577
|
write: false,
|
|
19347
|
-
edit: false
|
|
19348
|
-
task: false
|
|
19578
|
+
edit: false
|
|
19349
19579
|
},
|
|
19350
19580
|
"multimodal-looker": {
|
|
19351
19581
|
read: true
|
|
@@ -19382,6 +19612,7 @@ function toLogLabel(cacheLabel) {
|
|
|
19382
19612
|
}
|
|
19383
19613
|
function createJsonFileCacheStore(options) {
|
|
19384
19614
|
let memoryValue;
|
|
19615
|
+
let writtenInCurrentProcess = false;
|
|
19385
19616
|
function getCacheFilePath() {
|
|
19386
19617
|
return join10(options.getCacheDir(), options.filename);
|
|
19387
19618
|
}
|
|
@@ -19416,6 +19647,12 @@ function createJsonFileCacheStore(options) {
|
|
|
19416
19647
|
}
|
|
19417
19648
|
}
|
|
19418
19649
|
function has() {
|
|
19650
|
+
if (memoryValue !== undefined && memoryValue !== null) {
|
|
19651
|
+
return true;
|
|
19652
|
+
}
|
|
19653
|
+
if (writtenInCurrentProcess) {
|
|
19654
|
+
return true;
|
|
19655
|
+
}
|
|
19419
19656
|
return existsSync10(getCacheFilePath());
|
|
19420
19657
|
}
|
|
19421
19658
|
function write(value) {
|
|
@@ -19424,6 +19661,7 @@ function createJsonFileCacheStore(options) {
|
|
|
19424
19661
|
try {
|
|
19425
19662
|
writeFileSync2(cacheFile, options.serialize?.(value) ?? JSON.stringify(value, null, 2));
|
|
19426
19663
|
memoryValue = value;
|
|
19664
|
+
writtenInCurrentProcess = true;
|
|
19427
19665
|
log(`[${options.logPrefix}] ${options.cacheLabel} written`, options.describe(value));
|
|
19428
19666
|
} catch (error) {
|
|
19429
19667
|
log(`[${options.logPrefix}] Error writing ${toLogLabel(options.cacheLabel)}`, {
|
|
@@ -19433,6 +19671,7 @@ function createJsonFileCacheStore(options) {
|
|
|
19433
19671
|
}
|
|
19434
19672
|
function resetMemory() {
|
|
19435
19673
|
memoryValue = undefined;
|
|
19674
|
+
writtenInCurrentProcess = false;
|
|
19436
19675
|
}
|
|
19437
19676
|
return {
|
|
19438
19677
|
read,
|
|
@@ -19443,6 +19682,7 @@ function createJsonFileCacheStore(options) {
|
|
|
19443
19682
|
}
|
|
19444
19683
|
|
|
19445
19684
|
// src/shared/connected-providers-cache.ts
|
|
19685
|
+
var providerModelsCacheWrittenInCurrentProcess = false;
|
|
19446
19686
|
var CONNECTED_PROVIDERS_CACHE_FILE = "connected-providers.json";
|
|
19447
19687
|
var PROVIDER_MODELS_CACHE_FILE = "provider-models.json";
|
|
19448
19688
|
function isRecord(value) {
|
|
@@ -19482,6 +19722,9 @@ function createConnectedProvidersCacheStore(getCacheDir2 = getOmoOpenCodeCacheDi
|
|
|
19482
19722
|
return providerModelsCacheStore.read();
|
|
19483
19723
|
}
|
|
19484
19724
|
function hasProviderModelsCache() {
|
|
19725
|
+
if (providerModelsCacheWrittenInCurrentProcess) {
|
|
19726
|
+
return true;
|
|
19727
|
+
}
|
|
19485
19728
|
return providerModelsCacheStore.has();
|
|
19486
19729
|
}
|
|
19487
19730
|
function writeProviderModelsCache(data) {
|
|
@@ -19489,6 +19732,7 @@ function createConnectedProvidersCacheStore(getCacheDir2 = getOmoOpenCodeCacheDi
|
|
|
19489
19732
|
...data,
|
|
19490
19733
|
updatedAt: new Date().toISOString()
|
|
19491
19734
|
});
|
|
19735
|
+
providerModelsCacheWrittenInCurrentProcess = true;
|
|
19492
19736
|
}
|
|
19493
19737
|
async function updateConnectedProvidersCache(client) {
|
|
19494
19738
|
if (!client?.provider?.list) {
|
|
@@ -19537,6 +19781,7 @@ function createConnectedProvidersCacheStore(getCacheDir2 = getOmoOpenCodeCacheDi
|
|
|
19537
19781
|
function _resetMemCacheForTesting() {
|
|
19538
19782
|
connectedProvidersCacheStore.resetMemory();
|
|
19539
19783
|
providerModelsCacheStore.resetMemory();
|
|
19784
|
+
providerModelsCacheWrittenInCurrentProcess = false;
|
|
19540
19785
|
}
|
|
19541
19786
|
return {
|
|
19542
19787
|
readConnectedProvidersCache,
|
|
@@ -66429,7 +66674,7 @@ async function injectContinuation(args) {
|
|
|
66429
66674
|
log(`[${HOOK_NAME}] Skipped injection: continuation stopped for session`, { sessionID });
|
|
66430
66675
|
return;
|
|
66431
66676
|
}
|
|
66432
|
-
const hasRunningBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((task) => task.status === "running") : false;
|
|
66677
|
+
const hasRunningBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((task) => task.status === "running" || task.status === "pending") : false;
|
|
66433
66678
|
if (hasRunningBgTasks) {
|
|
66434
66679
|
log(`[${HOOK_NAME}] Skipped injection: background tasks running`, { sessionID });
|
|
66435
66680
|
return;
|
|
@@ -66635,7 +66880,7 @@ async function handleSessionIdle(args) {
|
|
|
66635
66880
|
}
|
|
66636
66881
|
state2.abortDetectedAt = undefined;
|
|
66637
66882
|
}
|
|
66638
|
-
const hasRunningBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((task) => task.status === "running") : false;
|
|
66883
|
+
const hasRunningBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((task) => task.status === "running" || task.status === "pending") : false;
|
|
66639
66884
|
if (hasRunningBgTasks) {
|
|
66640
66885
|
log(`[${HOOK_NAME}] Skipped: background tasks running`, { sessionID });
|
|
66641
66886
|
return;
|
|
@@ -67193,8 +67438,9 @@ function createContextWindowMonitorHook(_ctx, modelCacheState) {
|
|
|
67193
67438
|
if (actualUsagePercentage < CONTEXT_WARNING_THRESHOLD)
|
|
67194
67439
|
return;
|
|
67195
67440
|
remindedSessions.add(sessionID);
|
|
67196
|
-
const
|
|
67197
|
-
const
|
|
67441
|
+
const clampedPercentage = Math.min(Math.max(actualUsagePercentage, 0), 1);
|
|
67442
|
+
const usedPct = (clampedPercentage * 100).toFixed(1);
|
|
67443
|
+
const remainingPct = ((1 - clampedPercentage) * 100).toFixed(1);
|
|
67198
67444
|
const usedTokens = totalInputTokens.toLocaleString();
|
|
67199
67445
|
const limitTokens = actualLimit.toLocaleString();
|
|
67200
67446
|
output.output += `
|
|
@@ -67349,8 +67595,12 @@ var getAfplayPath = createCommandFinder("afplay");
|
|
|
67349
67595
|
var getPaplayPath = createCommandFinder("paplay");
|
|
67350
67596
|
var getAplayPath = createCommandFinder("aplay");
|
|
67351
67597
|
var getTerminalNotifierPath = createCommandFinder("terminal-notifier");
|
|
67598
|
+
var getCmuxPath = createCommandFinder("cmux");
|
|
67352
67599
|
function startBackgroundCheck2(platform) {
|
|
67353
67600
|
if (platform === "darwin") {
|
|
67601
|
+
getCmuxPath().catch((error) => {
|
|
67602
|
+
logBackgroundCheckError("cmux", error);
|
|
67603
|
+
});
|
|
67354
67604
|
getOsascriptPath().catch((error) => {
|
|
67355
67605
|
logBackgroundCheckError("osascript", error);
|
|
67356
67606
|
});
|
|
@@ -67423,6 +67673,13 @@ function getDefaultSoundPath(platform2) {
|
|
|
67423
67673
|
async function sendSessionNotification(ctx, platform2, title, message) {
|
|
67424
67674
|
switch (platform2) {
|
|
67425
67675
|
case "darwin": {
|
|
67676
|
+
const cmuxPath = await getCmuxPath();
|
|
67677
|
+
if (cmuxPath) {
|
|
67678
|
+
try {
|
|
67679
|
+
await ctx.$`${cmuxPath} notify --title ${title} --body ${message}`.quiet();
|
|
67680
|
+
break;
|
|
67681
|
+
} catch {}
|
|
67682
|
+
}
|
|
67426
67683
|
const terminalNotifierPath = await getTerminalNotifierPath();
|
|
67427
67684
|
if (terminalNotifierPath) {
|
|
67428
67685
|
const bundleId = process.env.__CFBundleIdentifier;
|
|
@@ -67654,9 +67911,9 @@ function createIdleNotificationScheduler(options) {
|
|
|
67654
67911
|
return;
|
|
67655
67912
|
}
|
|
67656
67913
|
notifiedSessions.add(sessionID);
|
|
67657
|
-
await options.send(options.ctx,
|
|
67914
|
+
await options.send(options.ctx, sessionID);
|
|
67658
67915
|
if (options.config.playSound && options.config.soundPath) {
|
|
67659
|
-
await options.playSound(options.ctx, options.
|
|
67916
|
+
await options.playSound(options.ctx, options.config.soundPath);
|
|
67660
67917
|
}
|
|
67661
67918
|
} finally {
|
|
67662
67919
|
executingNotifications.delete(sessionID);
|
|
@@ -67746,10 +68003,10 @@ function createSessionNotification(ctx, config = {}) {
|
|
|
67746
68003
|
let defaultSoundPath = mergedConfig.soundPath;
|
|
67747
68004
|
const scheduler = createIdleNotificationScheduler({
|
|
67748
68005
|
ctx,
|
|
67749
|
-
platform: "unsupported",
|
|
67750
68006
|
config: mergedConfig,
|
|
67751
68007
|
hasIncompleteTodos,
|
|
67752
|
-
send: async (hookCtx,
|
|
68008
|
+
send: async (hookCtx, sessionID) => {
|
|
68009
|
+
const platform2 = ensureNotificationPlatform();
|
|
67753
68010
|
if (typeof hookCtx.client.session.get !== "function" && typeof hookCtx.client.session.messages !== "function") {
|
|
67754
68011
|
await sendSessionNotification(hookCtx, platform2, mergedConfig.title, mergedConfig.message);
|
|
67755
68012
|
return;
|
|
@@ -67761,7 +68018,10 @@ function createSessionNotification(ctx, config = {}) {
|
|
|
67761
68018
|
});
|
|
67762
68019
|
await sendSessionNotification(hookCtx, platform2, content.title, content.message);
|
|
67763
68020
|
},
|
|
67764
|
-
playSound:
|
|
68021
|
+
playSound: async (hookCtx, soundPath) => {
|
|
68022
|
+
const platform2 = ensureNotificationPlatform();
|
|
68023
|
+
await playSessionNotificationSound(hookCtx, platform2, soundPath);
|
|
68024
|
+
}
|
|
67765
68025
|
});
|
|
67766
68026
|
const QUESTION_TOOLS = new Set(["question", "ask_user_question", "askuserquestion"]);
|
|
67767
68027
|
const PERMISSION_EVENTS = new Set(["permission.ask", "permission.asked", "permission.updated", "permission.requested"]);
|
|
@@ -74560,6 +74820,7 @@ async function runBunInstallWithDetails(options) {
|
|
|
74560
74820
|
try {
|
|
74561
74821
|
const proc = spawnWithWindowsHide(["bun", "install"], {
|
|
74562
74822
|
cwd: cacheDir,
|
|
74823
|
+
env: process.env,
|
|
74563
74824
|
stdout: outputMode,
|
|
74564
74825
|
stderr: outputMode
|
|
74565
74826
|
});
|
|
@@ -76173,7 +76434,7 @@ IF COMPLEX - DO NOT STRUGGLE ALONE. Consult specialists:
|
|
|
76173
76434
|
|
|
76174
76435
|
SYNTHESIZE findings before proceeding.
|
|
76175
76436
|
---
|
|
76176
|
-
MANDATORY delegate_task params: ALWAYS include load_skills
|
|
76437
|
+
MANDATORY delegate_task params: ALWAYS include load_skills and run_in_background when calling delegate_task. Evaluate available skills before dispatch - pass task-appropriate skills when relevant, pass [] ONLY when no skill matches the task domain.
|
|
76177
76438
|
Example: delegate_task(subagent_type="explore", prompt="...", run_in_background=true, load_skills=[])`
|
|
76178
76439
|
}
|
|
76179
76440
|
];
|
|
@@ -85832,6 +86093,7 @@ async function resolveRecentPromptContextForSession(ctx, sessionID) {
|
|
|
85832
86093
|
}
|
|
85833
86094
|
|
|
85834
86095
|
// src/hooks/atlas/boulder-continuation-injector.ts
|
|
86096
|
+
var ACTIVE_BACKGROUND_TASK_STATUSES = new Set(["pending", "running"]);
|
|
85835
86097
|
async function injectBoulderContinuation(input) {
|
|
85836
86098
|
const {
|
|
85837
86099
|
ctx,
|
|
@@ -85846,7 +86108,7 @@ async function injectBoulderContinuation(input) {
|
|
|
85846
86108
|
backgroundManager,
|
|
85847
86109
|
sessionState
|
|
85848
86110
|
} = input;
|
|
85849
|
-
const hasRunningBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((t) => t.status
|
|
86111
|
+
const hasRunningBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((t) => ACTIVE_BACKGROUND_TASK_STATUSES.has(t.status)) : false;
|
|
85850
86112
|
if (hasRunningBgTasks) {
|
|
85851
86113
|
log(`[${HOOK_NAME7}] Skipped injection: background tasks running`, { sessionID });
|
|
85852
86114
|
return "skipped_background_tasks";
|
|
@@ -87795,7 +88057,7 @@ Task ID: ${task.id}
|
|
|
87795
88057
|
Description: ${task.description}
|
|
87796
88058
|
Agent: ${task.agent}
|
|
87797
88059
|
Status: ${task.status}
|
|
87798
|
-
Session ID: ${task.
|
|
88060
|
+
Session ID: ${task.sessionId ?? "N/A"}
|
|
87799
88061
|
|
|
87800
88062
|
Thinking summary (first ${THINKING_SUMMARY_MAX_CHARS} chars):
|
|
87801
88063
|
${summaryText}
|
|
@@ -87944,7 +88206,7 @@ function createUnstableAgentBabysitterHook(ctx, options) {
|
|
|
87944
88206
|
const lastReminderAt = reminderCooldowns.get(task.id);
|
|
87945
88207
|
if (lastReminderAt && now - lastReminderAt < COOLDOWN_MS)
|
|
87946
88208
|
continue;
|
|
87947
|
-
const summary = task.
|
|
88209
|
+
const summary = task.sessionId ? await getThinkingSummary(ctx, task.sessionId) : null;
|
|
87948
88210
|
const reminder = buildReminder(task, summary, idleMs);
|
|
87949
88211
|
const { agent, model, tools } = await resolveMainSessionTarget(ctx, mainSessionID);
|
|
87950
88212
|
try {
|
|
@@ -96102,7 +96364,8 @@ function createSkillMcpTool(options) {
|
|
|
96102
96364
|
serverName: args.mcp_name,
|
|
96103
96365
|
skillName: found.skill.name,
|
|
96104
96366
|
sessionID,
|
|
96105
|
-
scope: found.skill.scope
|
|
96367
|
+
scope: found.skill.scope,
|
|
96368
|
+
directory: toolContext.directory
|
|
96106
96369
|
};
|
|
96107
96370
|
const context = {
|
|
96108
96371
|
config: found.config,
|
|
@@ -96264,7 +96527,7 @@ ${truncated}
|
|
|
96264
96527
|
| Agent | ${task.agent} |
|
|
96265
96528
|
| Status | **${task.status}** |
|
|
96266
96529
|
| ${durationLabel} | ${duration} |
|
|
96267
|
-
| Session ID | \`${task.
|
|
96530
|
+
| Session ID | \`${task.sessionId}\` |${progressSection}
|
|
96268
96531
|
${statusNote}
|
|
96269
96532
|
## Original Prompt
|
|
96270
96533
|
|
|
@@ -96296,11 +96559,11 @@ function extractToolResultText(part) {
|
|
|
96296
96559
|
return [];
|
|
96297
96560
|
}
|
|
96298
96561
|
async function formatFullSession(task, client2, options) {
|
|
96299
|
-
if (!task.
|
|
96562
|
+
if (!task.sessionId) {
|
|
96300
96563
|
return formatTaskStatus(task);
|
|
96301
96564
|
}
|
|
96302
96565
|
const messagesResult = await client2.session.messages({
|
|
96303
|
-
path: { id: task.
|
|
96566
|
+
path: { id: task.sessionId }
|
|
96304
96567
|
});
|
|
96305
96568
|
const errorMessage = getErrorMessage4(messagesResult);
|
|
96306
96569
|
if (errorMessage) {
|
|
@@ -96351,7 +96614,7 @@ async function formatFullSession(task, client2, options) {
|
|
|
96351
96614
|
lines.push(`Task ID: ${task.id}`);
|
|
96352
96615
|
lines.push(`Description: ${task.description}`);
|
|
96353
96616
|
lines.push(`Status: ${task.status}`);
|
|
96354
|
-
lines.push(`Session ID: ${task.
|
|
96617
|
+
lines.push(`Session ID: ${task.sessionId}`);
|
|
96355
96618
|
lines.push(`Total messages: ${normalizedMessages.length}`);
|
|
96356
96619
|
lines.push(`Returned: ${visibleMessages.length}`);
|
|
96357
96620
|
lines.push(`Has more: ${hasMore ? "true" : "false"}`);
|
|
@@ -96471,11 +96734,11 @@ function getTimeString(value) {
|
|
|
96471
96734
|
return typeof value === "string" ? value : "";
|
|
96472
96735
|
}
|
|
96473
96736
|
async function formatTaskResult(task, client2) {
|
|
96474
|
-
if (!task.
|
|
96737
|
+
if (!task.sessionId) {
|
|
96475
96738
|
return `Error: Task has no sessionID`;
|
|
96476
96739
|
}
|
|
96477
96740
|
const messagesResult = await client2.session.messages({
|
|
96478
|
-
path: { id: task.
|
|
96741
|
+
path: { id: task.sessionId }
|
|
96479
96742
|
});
|
|
96480
96743
|
const errorMessage = getErrorMessage4(messagesResult);
|
|
96481
96744
|
if (errorMessage) {
|
|
@@ -96488,7 +96751,7 @@ async function formatTaskResult(task, client2) {
|
|
|
96488
96751
|
Task ID: ${task.id}
|
|
96489
96752
|
Description: ${task.description}
|
|
96490
96753
|
Duration: ${formatDuration(task.startedAt ?? new Date, task.completedAt)}
|
|
96491
|
-
Session ID: ${task.
|
|
96754
|
+
Session ID: ${task.sessionId}
|
|
96492
96755
|
|
|
96493
96756
|
---
|
|
96494
96757
|
|
|
@@ -96501,7 +96764,7 @@ Session ID: ${task.sessionID}
|
|
|
96501
96764
|
Task ID: ${task.id}
|
|
96502
96765
|
Description: ${task.description}
|
|
96503
96766
|
Duration: ${formatDuration(task.startedAt ?? new Date, task.completedAt)}
|
|
96504
|
-
Session ID: ${task.
|
|
96767
|
+
Session ID: ${task.sessionId}
|
|
96505
96768
|
|
|
96506
96769
|
---
|
|
96507
96770
|
|
|
@@ -96519,13 +96782,13 @@ Session ID: ${task.sessionID}
|
|
|
96519
96782
|
Task ID: ${task.id}
|
|
96520
96783
|
Description: ${task.description}
|
|
96521
96784
|
Duration: ${formatDuration(task.startedAt ?? new Date, task.completedAt)}
|
|
96522
|
-
Session ID: ${task.
|
|
96785
|
+
Session ID: ${task.sessionId}
|
|
96523
96786
|
|
|
96524
96787
|
---
|
|
96525
96788
|
|
|
96526
96789
|
Session error: ${sessionError}`;
|
|
96527
96790
|
}
|
|
96528
|
-
const newMessages = consumeNewMessages(task.
|
|
96791
|
+
const newMessages = consumeNewMessages(task.sessionId, sortedMessages);
|
|
96529
96792
|
if (newMessages.length === 0) {
|
|
96530
96793
|
const duration2 = formatDuration(task.startedAt ?? new Date, task.completedAt);
|
|
96531
96794
|
return `Task Result
|
|
@@ -96533,7 +96796,7 @@ Session error: ${sessionError}`;
|
|
|
96533
96796
|
Task ID: ${task.id}
|
|
96534
96797
|
Description: ${task.description}
|
|
96535
96798
|
Duration: ${duration2}
|
|
96536
|
-
Session ID: ${task.
|
|
96799
|
+
Session ID: ${task.sessionId}
|
|
96537
96800
|
|
|
96538
96801
|
---
|
|
96539
96802
|
|
|
@@ -96571,7 +96834,7 @@ Session ID: ${task.sessionID}
|
|
|
96571
96834
|
Task ID: ${task.id}
|
|
96572
96835
|
Description: ${task.description}
|
|
96573
96836
|
Duration: ${duration}
|
|
96574
|
-
Session ID: ${task.
|
|
96837
|
+
Session ID: ${task.sessionId}
|
|
96575
96838
|
|
|
96576
96839
|
---
|
|
96577
96840
|
|
|
@@ -96673,7 +96936,7 @@ function createBackgroundOutput(manager, client2) {
|
|
|
96673
96936
|
agent: task.agent,
|
|
96674
96937
|
category: task.category,
|
|
96675
96938
|
description: task.description,
|
|
96676
|
-
...task.
|
|
96939
|
+
...task.sessionId ? { sessionId: task.sessionId, taskId: task.sessionId } : {}
|
|
96677
96940
|
}
|
|
96678
96941
|
};
|
|
96679
96942
|
await publishToolMetadata(ctx, meta);
|
|
@@ -96719,7 +96982,7 @@ function createBackgroundOutput(manager, client2) {
|
|
|
96719
96982
|
return didTimeoutWhileActive ? appendTimeoutNote(output, timeoutMs) : output;
|
|
96720
96983
|
}
|
|
96721
96984
|
if (resolvedTask.status === "completed") {
|
|
96722
|
-
recordBackgroundOutputConsumption(ctx.sessionID, ctx.messageID, resolvedTask.
|
|
96985
|
+
recordBackgroundOutputConsumption(ctx.sessionID, ctx.messageID, resolvedTask.sessionId);
|
|
96723
96986
|
return await formatTaskResult(resolvedTask, client2);
|
|
96724
96987
|
}
|
|
96725
96988
|
if (resolvedTask.status === "error" || resolvedTask.status === "cancelled" || resolvedTask.status === "interrupt") {
|
|
@@ -96767,7 +97030,7 @@ function createBackgroundCancel(manager, _client) {
|
|
|
96767
97030
|
id: task2.id,
|
|
96768
97031
|
description: task2.description,
|
|
96769
97032
|
status: originalStatus === "pending" ? "pending" : "running",
|
|
96770
|
-
sessionID: task2.
|
|
97033
|
+
sessionID: task2.sessionId
|
|
96771
97034
|
});
|
|
96772
97035
|
}
|
|
96773
97036
|
const tableRows = cancelledInfo.map((t) => `| \`${t.id}\` | ${t.description} | ${t.status} | ${t.sessionID ? `\`${t.sessionID}\`` : "(not started)"} |`).join(`
|
|
@@ -96818,7 +97081,7 @@ Status: ${task.status}`;
|
|
|
96818
97081
|
|
|
96819
97082
|
Task ID: ${task.id}
|
|
96820
97083
|
Description: ${task.description}
|
|
96821
|
-
Session ID: ${task.
|
|
97084
|
+
Session ID: ${task.sessionId}
|
|
96822
97085
|
Status: ${task.status}`;
|
|
96823
97086
|
} catch (error) {
|
|
96824
97087
|
return `[ERROR] Error cancelling task: ${error instanceof Error ? error.message : String(error)}`;
|
|
@@ -96955,8 +97218,8 @@ async function executeBackground(args, toolContext, manager, client2, fallbackCh
|
|
|
96955
97218
|
description: args.description,
|
|
96956
97219
|
prompt: args.prompt,
|
|
96957
97220
|
agent: args.subagent_type,
|
|
96958
|
-
|
|
96959
|
-
|
|
97221
|
+
parentSessionId: toolContext.sessionID,
|
|
97222
|
+
parentMessageId: toolContext.messageID,
|
|
96960
97223
|
parentAgent,
|
|
96961
97224
|
parentTools: getSessionTools(toolContext.sessionID),
|
|
96962
97225
|
model,
|
|
@@ -96965,7 +97228,7 @@ async function executeBackground(args, toolContext, manager, client2, fallbackCh
|
|
|
96965
97228
|
const WAIT_FOR_SESSION_INTERVAL_MS = 50;
|
|
96966
97229
|
const WAIT_FOR_SESSION_TIMEOUT_MS = 30000;
|
|
96967
97230
|
const waitStart = Date.now();
|
|
96968
|
-
let sessionId = task.
|
|
97231
|
+
let sessionId = task.sessionId;
|
|
96969
97232
|
while (!sessionId && Date.now() - waitStart < WAIT_FOR_SESSION_TIMEOUT_MS) {
|
|
96970
97233
|
const updated = manager.getTask(task.id);
|
|
96971
97234
|
if (updated?.status === "error" || updated?.status === "cancelled" || updated?.status === "interrupt") {
|
|
@@ -96973,7 +97236,7 @@ async function executeBackground(args, toolContext, manager, client2, fallbackCh
|
|
|
96973
97236
|
|
|
96974
97237
|
Task ID: ${task.id}`;
|
|
96975
97238
|
}
|
|
96976
|
-
sessionId = updated?.
|
|
97239
|
+
sessionId = updated?.sessionId;
|
|
96977
97240
|
if (sessionId) {
|
|
96978
97241
|
break;
|
|
96979
97242
|
}
|
|
@@ -98332,13 +98595,13 @@ ${args.prompt}` : args.prompt;
|
|
|
98332
98595
|
const task = await manager.resume({
|
|
98333
98596
|
sessionId: taskID,
|
|
98334
98597
|
prompt: effectivePrompt,
|
|
98335
|
-
|
|
98336
|
-
|
|
98598
|
+
parentSessionId: parentContext.sessionID,
|
|
98599
|
+
parentMessageId: parentContext.messageID,
|
|
98337
98600
|
parentModel: parentContext.model,
|
|
98338
98601
|
parentAgent: parentContext.agent,
|
|
98339
98602
|
parentTools: getSessionTools(parentContext.sessionID)
|
|
98340
98603
|
});
|
|
98341
|
-
const sessionId = task.
|
|
98604
|
+
const sessionId = task.sessionId;
|
|
98342
98605
|
const backgroundTaskId = task.id;
|
|
98343
98606
|
const resolvedModel = resolveMetadataModel(task.model, parentContext.model);
|
|
98344
98607
|
const bgContMeta = {
|
|
@@ -98829,8 +99092,8 @@ async function executeUnstableAgentTask(args, ctx, executorCtx, parentContext, a
|
|
|
98829
99092
|
description: args.description,
|
|
98830
99093
|
prompt: effectivePrompt,
|
|
98831
99094
|
agent: agentToUse,
|
|
98832
|
-
|
|
98833
|
-
|
|
99095
|
+
parentSessionId: parentContext.sessionID,
|
|
99096
|
+
parentMessageId: parentContext.messageID,
|
|
98834
99097
|
parentModel: parentContext.model,
|
|
98835
99098
|
parentAgent: parentContext.agent,
|
|
98836
99099
|
parentTools: getSessionTools(parentContext.sessionID),
|
|
@@ -98843,7 +99106,7 @@ async function executeUnstableAgentTask(args, ctx, executorCtx, parentContext, a
|
|
|
98843
99106
|
launchedTaskID = task.id;
|
|
98844
99107
|
const timing = getTimingConfig();
|
|
98845
99108
|
const waitStart = Date.now();
|
|
98846
|
-
let sessionID = task.
|
|
99109
|
+
let sessionID = task.sessionId;
|
|
98847
99110
|
while (!sessionID && Date.now() - waitStart < timing.WAIT_FOR_SESSION_TIMEOUT_MS) {
|
|
98848
99111
|
if (ctx.abort?.aborted) {
|
|
98849
99112
|
cleanupReason = "Parent aborted while waiting for unstable task session start";
|
|
@@ -98853,7 +99116,7 @@ Task ID: ${task.id}`;
|
|
|
98853
99116
|
}
|
|
98854
99117
|
await new Promise((resolve21) => setTimeout(resolve21, timing.WAIT_FOR_SESSION_INTERVAL_MS));
|
|
98855
99118
|
const updated = manager.getTask(task.id);
|
|
98856
|
-
sessionID = updated?.
|
|
99119
|
+
sessionID = updated?.sessionId;
|
|
98857
99120
|
}
|
|
98858
99121
|
if (!sessionID) {
|
|
98859
99122
|
cleanupReason = "Unstable task session start timed out before session became available";
|
|
@@ -99048,7 +99311,7 @@ function continueSessionSetup(args) {
|
|
|
99048
99311
|
if (updated.status === "error" || updated.status === "cancelled" || updated.status === "interrupt") {
|
|
99049
99312
|
return;
|
|
99050
99313
|
}
|
|
99051
|
-
const sessionId = updated.
|
|
99314
|
+
const sessionId = updated.sessionId;
|
|
99052
99315
|
if (!sessionId) {
|
|
99053
99316
|
continue;
|
|
99054
99317
|
}
|
|
@@ -99070,7 +99333,7 @@ async function waitForBackgroundSessionStart(args) {
|
|
|
99070
99333
|
if (updated?.status === "error" || updated?.status === "cancelled" || updated?.status === "interrupt") {
|
|
99071
99334
|
return;
|
|
99072
99335
|
}
|
|
99073
|
-
sessionId = updated?.
|
|
99336
|
+
sessionId = updated?.sessionId;
|
|
99074
99337
|
if (sessionId) {
|
|
99075
99338
|
return sessionId;
|
|
99076
99339
|
}
|
|
@@ -99092,8 +99355,8 @@ async function executeBackgroundTask(args, ctx, executorCtx, parentContext, agen
|
|
|
99092
99355
|
description: args.description,
|
|
99093
99356
|
prompt: effectivePrompt,
|
|
99094
99357
|
agent: normalizedAgent,
|
|
99095
|
-
|
|
99096
|
-
|
|
99358
|
+
parentSessionId: parentContext.sessionID,
|
|
99359
|
+
parentMessageId: parentContext.messageID,
|
|
99097
99360
|
parentModel: parentContext.model,
|
|
99098
99361
|
parentAgent: parentContext.agent,
|
|
99099
99362
|
parentTools: getSessionTools(parentContext.sessionID),
|
|
@@ -99107,7 +99370,7 @@ async function executeBackgroundTask(args, ctx, executorCtx, parentContext, agen
|
|
|
99107
99370
|
const timing = getTimingConfig();
|
|
99108
99371
|
let sessionId = await waitForBackgroundSessionStart({
|
|
99109
99372
|
taskId: task.id,
|
|
99110
|
-
initialSessionId: task.
|
|
99373
|
+
initialSessionId: task.sessionId,
|
|
99111
99374
|
manager,
|
|
99112
99375
|
timing,
|
|
99113
99376
|
abortSignal: ctx.abort,
|
|
@@ -103742,14 +104005,14 @@ function formatDuration3(start, end) {
|
|
|
103742
104005
|
|
|
103743
104006
|
// src/features/background-agent/background-task-notification-template.ts
|
|
103744
104007
|
function formatAttemptModel(attempt) {
|
|
103745
|
-
if (attempt.
|
|
103746
|
-
return `${attempt.
|
|
104008
|
+
if (attempt.providerId && attempt.modelId) {
|
|
104009
|
+
return `${attempt.providerId}/${attempt.modelId}`;
|
|
103747
104010
|
}
|
|
103748
|
-
if (attempt.
|
|
103749
|
-
return attempt.
|
|
104011
|
+
if (attempt.modelId) {
|
|
104012
|
+
return attempt.modelId;
|
|
103750
104013
|
}
|
|
103751
|
-
if (attempt.
|
|
103752
|
-
return attempt.
|
|
104014
|
+
if (attempt.providerId) {
|
|
104015
|
+
return attempt.providerId;
|
|
103753
104016
|
}
|
|
103754
104017
|
return "unknown-model";
|
|
103755
104018
|
}
|
|
@@ -103759,7 +104022,7 @@ function formatAttemptTimeline(task) {
|
|
|
103759
104022
|
}
|
|
103760
104023
|
const lines = task.attempts.map((attempt) => {
|
|
103761
104024
|
const attemptLines = [
|
|
103762
|
-
` - Attempt ${attempt.attemptNumber} \u2014 ${attempt.status.toUpperCase()} \u2014 ${formatAttemptModel(attempt)} \u2014 ${attempt.
|
|
104025
|
+
` - Attempt ${attempt.attemptNumber} \u2014 ${attempt.status.toUpperCase()} \u2014 ${formatAttemptModel(attempt)} \u2014 ${attempt.sessionId ?? "unknown"}`
|
|
103763
104026
|
];
|
|
103764
104027
|
if (attempt.status !== "completed" && attempt.error) {
|
|
103765
104028
|
attemptLines.push(` Error: ${attempt.error}`);
|
|
@@ -103862,23 +104125,23 @@ async function abortWithTimeout(client2, sessionID, timeoutMs = 1e4) {
|
|
|
103862
104125
|
// src/features/background-agent/attempt-lifecycle.ts
|
|
103863
104126
|
function toAttemptModel(model) {
|
|
103864
104127
|
return {
|
|
103865
|
-
|
|
103866
|
-
|
|
104128
|
+
providerId: model?.providerID,
|
|
104129
|
+
modelId: model?.modelID,
|
|
103867
104130
|
variant: model?.variant
|
|
103868
104131
|
};
|
|
103869
104132
|
}
|
|
103870
104133
|
function toTaskModel(attempt) {
|
|
103871
|
-
if (!attempt.
|
|
104134
|
+
if (!attempt.providerId || !attempt.modelId) {
|
|
103872
104135
|
return;
|
|
103873
104136
|
}
|
|
103874
104137
|
return {
|
|
103875
|
-
providerID: attempt.
|
|
103876
|
-
modelID: attempt.
|
|
104138
|
+
providerID: attempt.providerId,
|
|
104139
|
+
modelID: attempt.modelId,
|
|
103877
104140
|
...attempt.variant ? { variant: attempt.variant } : {}
|
|
103878
104141
|
};
|
|
103879
104142
|
}
|
|
103880
104143
|
function getAttemptIndex(task, attemptID) {
|
|
103881
|
-
return task.attempts?.findIndex((attempt) => attempt.
|
|
104144
|
+
return task.attempts?.findIndex((attempt) => attempt.attemptId === attemptID) ?? -1;
|
|
103882
104145
|
}
|
|
103883
104146
|
function getAttempt(task, attemptID) {
|
|
103884
104147
|
const index = getAttemptIndex(task, attemptID);
|
|
@@ -103899,9 +104162,9 @@ function ensureCurrentAttempt(task, model = task.model) {
|
|
|
103899
104162
|
return existingAttempt;
|
|
103900
104163
|
}
|
|
103901
104164
|
const attempt = {
|
|
103902
|
-
|
|
104165
|
+
attemptId: `att_${crypto.randomUUID().slice(0, 8)}`,
|
|
103903
104166
|
attemptNumber: (task.attempts?.length ?? 0) + 1,
|
|
103904
|
-
|
|
104167
|
+
sessionId: task.sessionId,
|
|
103905
104168
|
...toAttemptModel(model),
|
|
103906
104169
|
status: task.status,
|
|
103907
104170
|
error: task.error,
|
|
@@ -103909,7 +104172,7 @@ function ensureCurrentAttempt(task, model = task.model) {
|
|
|
103909
104172
|
completedAt: task.completedAt
|
|
103910
104173
|
};
|
|
103911
104174
|
task.attempts = [...task.attempts ?? [], attempt];
|
|
103912
|
-
task.currentAttemptID = attempt.
|
|
104175
|
+
task.currentAttemptID = attempt.attemptId;
|
|
103913
104176
|
return attempt;
|
|
103914
104177
|
}
|
|
103915
104178
|
function projectTaskFromCurrentAttempt(task) {
|
|
@@ -103918,7 +104181,7 @@ function projectTaskFromCurrentAttempt(task) {
|
|
|
103918
104181
|
return task;
|
|
103919
104182
|
}
|
|
103920
104183
|
task.status = currentAttempt.status;
|
|
103921
|
-
task.
|
|
104184
|
+
task.sessionId = currentAttempt.sessionId;
|
|
103922
104185
|
task.startedAt = currentAttempt.startedAt;
|
|
103923
104186
|
task.completedAt = currentAttempt.completedAt;
|
|
103924
104187
|
task.error = currentAttempt.error;
|
|
@@ -103927,15 +104190,15 @@ function projectTaskFromCurrentAttempt(task) {
|
|
|
103927
104190
|
}
|
|
103928
104191
|
function startAttempt(task, model) {
|
|
103929
104192
|
const attempt = {
|
|
103930
|
-
|
|
104193
|
+
attemptId: `att_${crypto.randomUUID().slice(0, 8)}`,
|
|
103931
104194
|
attemptNumber: (task.attempts?.length ?? 0) + 1,
|
|
103932
104195
|
...toAttemptModel(model),
|
|
103933
104196
|
status: "pending"
|
|
103934
104197
|
};
|
|
103935
104198
|
task.attempts = [...task.attempts ?? [], attempt];
|
|
103936
|
-
task.currentAttemptID = attempt.
|
|
104199
|
+
task.currentAttemptID = attempt.attemptId;
|
|
103937
104200
|
task.status = "pending";
|
|
103938
|
-
task.
|
|
104201
|
+
task.sessionId = undefined;
|
|
103939
104202
|
task.startedAt = undefined;
|
|
103940
104203
|
task.completedAt = undefined;
|
|
103941
104204
|
task.error = undefined;
|
|
@@ -103951,13 +104214,13 @@ function bindAttemptSession(task, attemptID, sessionID, model) {
|
|
|
103951
104214
|
if (!attempt || isTerminalStatus(attempt.status)) {
|
|
103952
104215
|
return;
|
|
103953
104216
|
}
|
|
103954
|
-
attempt.
|
|
104217
|
+
attempt.sessionId = sessionID;
|
|
103955
104218
|
attempt.status = "running";
|
|
103956
104219
|
attempt.startedAt = new Date;
|
|
103957
104220
|
attempt.completedAt = undefined;
|
|
103958
104221
|
attempt.error = undefined;
|
|
103959
|
-
attempt.
|
|
103960
|
-
attempt.
|
|
104222
|
+
attempt.providerId = model?.providerID ?? attempt.providerId;
|
|
104223
|
+
attempt.modelId = model?.modelID ?? attempt.modelId;
|
|
103961
104224
|
attempt.variant = model?.variant ?? attempt.variant;
|
|
103962
104225
|
return getCurrentAttempt(projectTaskFromCurrentAttempt(task));
|
|
103963
104226
|
}
|
|
@@ -103982,7 +104245,7 @@ function scheduleRetryAttempt(task, failedAttemptID, nextModel, error) {
|
|
|
103982
104245
|
return startAttempt(task, nextModel);
|
|
103983
104246
|
}
|
|
103984
104247
|
function findAttemptBySession(task, sessionID) {
|
|
103985
|
-
return task.attempts?.find((attempt) => attempt.
|
|
104248
|
+
return task.attempts?.find((attempt) => attempt.sessionId === sessionID);
|
|
103986
104249
|
}
|
|
103987
104250
|
|
|
103988
104251
|
// src/features/background-agent/fallback-retry-handler.ts
|
|
@@ -104061,7 +104324,7 @@ async function tryFallbackRetry(args) {
|
|
|
104061
104324
|
clearTimeout(idleTimer);
|
|
104062
104325
|
idleDeferralTimers.delete(task.id);
|
|
104063
104326
|
}
|
|
104064
|
-
const previousSessionID = task.
|
|
104327
|
+
const previousSessionID = task.sessionId;
|
|
104065
104328
|
const previousModel = task.model;
|
|
104066
104329
|
const transformedModelId = transformModelForProvider(providerID, nextFallback.model);
|
|
104067
104330
|
const nextModel = {
|
|
@@ -104070,7 +104333,7 @@ async function tryFallbackRetry(args) {
|
|
|
104070
104333
|
variant: nextFallback.variant
|
|
104071
104334
|
};
|
|
104072
104335
|
task.attemptCount = selectedAttemptCount;
|
|
104073
|
-
const failedAttemptID = ensureCurrentAttempt(task, previousModel).
|
|
104336
|
+
const failedAttemptID = ensureCurrentAttempt(task, previousModel).attemptId;
|
|
104074
104337
|
const nextAttempt = failedAttemptID ? scheduleRetryAttempt(task, failedAttemptID, nextModel, errorInfo.message) : undefined;
|
|
104075
104338
|
if (!nextAttempt) {
|
|
104076
104339
|
return false;
|
|
@@ -104096,8 +104359,8 @@ async function tryFallbackRetry(args) {
|
|
|
104096
104359
|
description: task.description,
|
|
104097
104360
|
prompt: task.prompt,
|
|
104098
104361
|
agent: task.agent,
|
|
104099
|
-
|
|
104100
|
-
|
|
104362
|
+
parentSessionId: task.parentSessionId,
|
|
104363
|
+
parentMessageId: task.parentMessageId,
|
|
104101
104364
|
parentModel: task.parentModel,
|
|
104102
104365
|
parentAgent: task.parentAgent,
|
|
104103
104366
|
parentTools: task.parentTools,
|
|
@@ -104109,18 +104372,24 @@ async function tryFallbackRetry(args) {
|
|
|
104109
104372
|
if (previousSessionID) {
|
|
104110
104373
|
await abortWithTimeout(client2, previousSessionID).catch(() => {});
|
|
104111
104374
|
}
|
|
104112
|
-
queue.push({ task, input: retryInput, attemptID: nextAttempt.
|
|
104375
|
+
queue.push({ task, input: retryInput, attemptID: nextAttempt.attemptId });
|
|
104113
104376
|
queuesByKey.set(key, queue);
|
|
104114
104377
|
processKey(key);
|
|
104115
104378
|
return true;
|
|
104116
104379
|
}
|
|
104117
104380
|
|
|
104118
104381
|
// src/features/background-agent/process-cleanup.ts
|
|
104119
|
-
|
|
104382
|
+
var _scheduleForcedExitEnabled = true;
|
|
104383
|
+
function scheduleForcedExit(cleanupResult, exitCode, exitAfterCleanup = false) {
|
|
104384
|
+
if (!_scheduleForcedExitEnabled)
|
|
104385
|
+
return;
|
|
104120
104386
|
process.exitCode = exitCode;
|
|
104121
104387
|
const exitTimeout = setTimeout(() => process.exit(), 6000);
|
|
104122
104388
|
Promise.resolve(cleanupResult).finally(() => {
|
|
104123
104389
|
clearTimeout(exitTimeout);
|
|
104390
|
+
if (exitAfterCleanup) {
|
|
104391
|
+
process.exit(exitCode);
|
|
104392
|
+
}
|
|
104124
104393
|
});
|
|
104125
104394
|
}
|
|
104126
104395
|
function registerProcessSignal(signal, handler, exitAfter) {
|
|
@@ -104135,8 +104404,9 @@ function registerProcessSignal(signal, handler, exitAfter) {
|
|
|
104135
104404
|
}
|
|
104136
104405
|
function registerErrorEvent(signal, handler) {
|
|
104137
104406
|
const listener = (error) => {
|
|
104407
|
+
process.off(signal, listener);
|
|
104138
104408
|
log(`[background-agent] ${signal} received during shutdown cleanup:`, error);
|
|
104139
|
-
scheduleForcedExit(handler(error), 1);
|
|
104409
|
+
scheduleForcedExit(handler(error), 1, true);
|
|
104140
104410
|
};
|
|
104141
104411
|
process.on(signal, listener);
|
|
104142
104412
|
return listener;
|
|
@@ -104521,7 +104791,7 @@ async function checkAndInterruptStaleTasks(args) {
|
|
|
104521
104791
|
if (task.status !== "running")
|
|
104522
104792
|
continue;
|
|
104523
104793
|
const startedAt = task.startedAt;
|
|
104524
|
-
const sessionID = task.
|
|
104794
|
+
const sessionID = task.sessionId;
|
|
104525
104795
|
if (!startedAt || !sessionID)
|
|
104526
104796
|
continue;
|
|
104527
104797
|
const sessionStatus = sessionStatuses?.[sessionID]?.type;
|
|
@@ -104728,16 +104998,16 @@ function resolveMessagePartInfo(properties) {
|
|
|
104728
104998
|
return properties;
|
|
104729
104999
|
}
|
|
104730
105000
|
function formatAttemptModelSummary(attempt) {
|
|
104731
|
-
if (!attempt?.
|
|
105001
|
+
if (!attempt?.providerId || !attempt.modelId) {
|
|
104732
105002
|
return;
|
|
104733
105003
|
}
|
|
104734
|
-
return `${attempt.
|
|
105004
|
+
return `${attempt.providerId}/${attempt.modelId}`;
|
|
104735
105005
|
}
|
|
104736
105006
|
function getPreviousAttempt(task, attemptID) {
|
|
104737
105007
|
if (!attemptID || !task.attempts || task.attempts.length === 0) {
|
|
104738
105008
|
return;
|
|
104739
105009
|
}
|
|
104740
|
-
const attemptIndex = task.attempts.findIndex((attempt) => attempt.
|
|
105010
|
+
const attemptIndex = task.attempts.findIndex((attempt) => attempt.attemptId === attemptID);
|
|
104741
105011
|
if (attemptIndex <= 0) {
|
|
104742
105012
|
return;
|
|
104743
105013
|
}
|
|
@@ -104783,18 +105053,20 @@ class BackgroundManager {
|
|
|
104783
105053
|
preStartDescendantReservations;
|
|
104784
105054
|
enableParentSessionNotifications;
|
|
104785
105055
|
modelFallbackControllerAccessor;
|
|
105056
|
+
loggedSessionStatusUnavailable = false;
|
|
104786
105057
|
taskHistory = new TaskHistory;
|
|
104787
105058
|
cachedCircuitBreakerSettings;
|
|
104788
|
-
constructor(
|
|
105059
|
+
constructor(config2) {
|
|
105060
|
+
const { pluginContext, ...options } = config2;
|
|
104789
105061
|
this.tasks = new Map;
|
|
104790
105062
|
this.tasksByParentSession = new Map;
|
|
104791
105063
|
this.notifications = new Map;
|
|
104792
105064
|
this.pendingNotifications = new Map;
|
|
104793
105065
|
this.pendingByParent = new Map;
|
|
104794
|
-
this.client =
|
|
104795
|
-
this.directory =
|
|
104796
|
-
this.concurrencyManager = new ConcurrencyManager(
|
|
104797
|
-
this.config =
|
|
105066
|
+
this.client = pluginContext.client;
|
|
105067
|
+
this.directory = pluginContext.directory;
|
|
105068
|
+
this.concurrencyManager = new ConcurrencyManager(options.config);
|
|
105069
|
+
this.config = options.config;
|
|
104798
105070
|
this.tmuxEnabled = options?.tmuxConfig?.enabled ?? false;
|
|
104799
105071
|
this.onSubagentSessionCreated = options?.onSubagentSessionCreated;
|
|
104800
105072
|
this.onShutdown = options?.onShutdown;
|
|
@@ -104869,30 +105141,30 @@ class BackgroundManager {
|
|
|
104869
105141
|
if (!this.preStartDescendantReservations.delete(task.id)) {
|
|
104870
105142
|
return;
|
|
104871
105143
|
}
|
|
104872
|
-
if (!task.
|
|
105144
|
+
if (!task.rootSessionId) {
|
|
104873
105145
|
return;
|
|
104874
105146
|
}
|
|
104875
|
-
this.unregisterRootDescendant(task.
|
|
105147
|
+
this.unregisterRootDescendant(task.rootSessionId);
|
|
104876
105148
|
}
|
|
104877
105149
|
addTask(task) {
|
|
104878
105150
|
this.tasks.set(task.id, task);
|
|
104879
|
-
if (!task.
|
|
105151
|
+
if (!task.parentSessionId) {
|
|
104880
105152
|
return;
|
|
104881
105153
|
}
|
|
104882
|
-
const taskIDs = this.tasksByParentSession.get(task.
|
|
105154
|
+
const taskIDs = this.tasksByParentSession.get(task.parentSessionId) ?? new Set;
|
|
104883
105155
|
taskIDs.add(task.id);
|
|
104884
|
-
this.tasksByParentSession.set(task.
|
|
105156
|
+
this.tasksByParentSession.set(task.parentSessionId, taskIDs);
|
|
104885
105157
|
}
|
|
104886
105158
|
removeTask(task) {
|
|
104887
105159
|
this.tasks.delete(task.id);
|
|
104888
|
-
this.removeTaskFromParentIndex(task.id, task.
|
|
105160
|
+
this.removeTaskFromParentIndex(task.id, task.parentSessionId);
|
|
104889
105161
|
}
|
|
104890
105162
|
updateTaskParent(task, parentSessionID) {
|
|
104891
|
-
if (task.
|
|
105163
|
+
if (task.parentSessionId === parentSessionID) {
|
|
104892
105164
|
return;
|
|
104893
105165
|
}
|
|
104894
|
-
this.removeTaskFromParentIndex(task.id, task.
|
|
104895
|
-
task.
|
|
105166
|
+
this.removeTaskFromParentIndex(task.id, task.parentSessionId);
|
|
105167
|
+
task.parentSessionId = parentSessionID;
|
|
104896
105168
|
const taskIDs = this.tasksByParentSession.get(parentSessionID) ?? new Set;
|
|
104897
105169
|
taskIDs.add(task.id);
|
|
104898
105170
|
this.tasksByParentSession.set(parentSessionID, taskIDs);
|
|
@@ -104915,15 +105187,15 @@ class BackgroundManager {
|
|
|
104915
105187
|
agent: input.agent,
|
|
104916
105188
|
model: input.model,
|
|
104917
105189
|
description: input.description,
|
|
104918
|
-
parentSessionID: input.
|
|
105190
|
+
parentSessionID: input.parentSessionId
|
|
104919
105191
|
});
|
|
104920
105192
|
if (!input.agent || input.agent.trim() === "") {
|
|
104921
105193
|
throw new Error("Agent parameter is required");
|
|
104922
105194
|
}
|
|
104923
|
-
const spawnReservation = await this.reserveSubagentSpawn(input.
|
|
105195
|
+
const spawnReservation = await this.reserveSubagentSpawn(input.parentSessionId);
|
|
104924
105196
|
try {
|
|
104925
105197
|
log("[background-agent] spawn guard passed", {
|
|
104926
|
-
parentSessionID: input.
|
|
105198
|
+
parentSessionID: input.parentSessionId,
|
|
104927
105199
|
rootSessionID: spawnReservation.spawnContext.rootSessionID,
|
|
104928
105200
|
childDepth: spawnReservation.spawnContext.childDepth,
|
|
104929
105201
|
descendantCount: spawnReservation.descendantCount
|
|
@@ -104932,13 +105204,13 @@ class BackgroundManager {
|
|
|
104932
105204
|
id: `bg_${crypto.randomUUID().slice(0, 8)}`,
|
|
104933
105205
|
status: "pending",
|
|
104934
105206
|
queuedAt: new Date,
|
|
104935
|
-
|
|
105207
|
+
rootSessionId: spawnReservation.spawnContext.rootSessionID,
|
|
104936
105208
|
description: input.description,
|
|
104937
105209
|
prompt: input.prompt,
|
|
104938
105210
|
agent: input.agent,
|
|
104939
105211
|
spawnDepth: spawnReservation.spawnContext.childDepth,
|
|
104940
|
-
|
|
104941
|
-
|
|
105212
|
+
parentSessionId: input.parentSessionId,
|
|
105213
|
+
parentMessageId: input.parentMessageId,
|
|
104942
105214
|
parentModel: input.parentModel,
|
|
104943
105215
|
parentAgent: input.parentAgent,
|
|
104944
105216
|
parentTools: input.parentTools,
|
|
@@ -104949,15 +105221,15 @@ class BackgroundManager {
|
|
|
104949
105221
|
};
|
|
104950
105222
|
const firstAttempt = startAttempt(task, input.model);
|
|
104951
105223
|
this.addTask(task);
|
|
104952
|
-
this.taskHistory.record(input.
|
|
104953
|
-
if (input.
|
|
104954
|
-
const pending = this.pendingByParent.get(input.
|
|
105224
|
+
this.taskHistory.record(input.parentSessionId, { id: task.id, agent: input.agent, description: input.description, status: "pending", category: input.category });
|
|
105225
|
+
if (input.parentSessionId) {
|
|
105226
|
+
const pending = this.pendingByParent.get(input.parentSessionId) ?? new Set;
|
|
104955
105227
|
pending.add(task.id);
|
|
104956
|
-
this.pendingByParent.set(input.
|
|
105228
|
+
this.pendingByParent.set(input.parentSessionId, pending);
|
|
104957
105229
|
}
|
|
104958
105230
|
const key = this.getConcurrencyKeyFromInput(input);
|
|
104959
105231
|
const queue = this.queuesByKey.get(key) ?? [];
|
|
104960
|
-
queue.push({ task, input, attemptID: firstAttempt.
|
|
105232
|
+
queue.push({ task, input, attemptID: firstAttempt.attemptId });
|
|
104961
105233
|
this.queuesByKey.set(key, queue);
|
|
104962
105234
|
log("[background-agent] Task queued:", { taskId: task.id, key, queueLength: queue.length });
|
|
104963
105235
|
const toastManager = getTaskToastManager();
|
|
@@ -104973,6 +105245,7 @@ class BackgroundManager {
|
|
|
104973
105245
|
}
|
|
104974
105246
|
spawnReservation.commit();
|
|
104975
105247
|
this.markPreStartDescendantReservation(task);
|
|
105248
|
+
this.updateBackgroundTaskMarker(input.parentSessionId);
|
|
104976
105249
|
this.processKey(key);
|
|
104977
105250
|
return { ...task };
|
|
104978
105251
|
} catch (error) {
|
|
@@ -105017,11 +105290,12 @@ class BackgroundManager {
|
|
|
105017
105290
|
this.concurrencyManager.release(key);
|
|
105018
105291
|
}
|
|
105019
105292
|
removeTaskToastTracking(item.task.id);
|
|
105020
|
-
if (item.task.
|
|
105021
|
-
await this.abortSessionWithLogging(item.task.
|
|
105293
|
+
if (item.task.sessionId) {
|
|
105294
|
+
await this.abortSessionWithLogging(item.task.sessionId, "startTask error cleanup");
|
|
105022
105295
|
}
|
|
105296
|
+
this.updateBackgroundTaskMarker(item.task.parentSessionId);
|
|
105023
105297
|
this.markForNotification(item.task);
|
|
105024
|
-
this.enqueueNotificationForParent(item.task.
|
|
105298
|
+
this.enqueueNotificationForParent(item.task.parentSessionId, () => this.notifyParentSession(item.task)).catch((err) => {
|
|
105025
105299
|
log("[background-agent] Failed to notify on startTask error:", err);
|
|
105026
105300
|
});
|
|
105027
105301
|
}
|
|
@@ -105032,7 +105306,7 @@ class BackgroundManager {
|
|
|
105032
105306
|
}
|
|
105033
105307
|
async startTask(item) {
|
|
105034
105308
|
const { task, input } = item;
|
|
105035
|
-
const attemptID = item.attemptID ?? ensureCurrentAttempt(task, input.model).
|
|
105309
|
+
const attemptID = item.attemptID ?? ensureCurrentAttempt(task, input.model).attemptId;
|
|
105036
105310
|
log("[background-agent] Starting task:", {
|
|
105037
105311
|
taskId: task.id,
|
|
105038
105312
|
agent: input.agent,
|
|
@@ -105040,7 +105314,7 @@ class BackgroundManager {
|
|
|
105040
105314
|
});
|
|
105041
105315
|
const concurrencyKey = this.getConcurrencyKeyFromInput(input);
|
|
105042
105316
|
const parentSession = await this.client.session.get({
|
|
105043
|
-
path: { id: input.
|
|
105317
|
+
path: { id: input.parentSessionId },
|
|
105044
105318
|
query: { directory: this.directory }
|
|
105045
105319
|
}).catch((err) => {
|
|
105046
105320
|
log(`[background-agent] Failed to get parent session: ${err}`);
|
|
@@ -105050,7 +105324,7 @@ class BackgroundManager {
|
|
|
105050
105324
|
log(`[background-agent] Parent dir: ${parentSession?.data?.directory}, using: ${parentDirectory}`);
|
|
105051
105325
|
const createResult = await this.client.session.create({
|
|
105052
105326
|
body: {
|
|
105053
|
-
parentID: input.
|
|
105327
|
+
parentID: input.parentSessionId,
|
|
105054
105328
|
title: `${input.description} (@${input.agent} subagent)`,
|
|
105055
105329
|
...input.sessionPermission ? { permission: input.sessionPermission } : {}
|
|
105056
105330
|
},
|
|
@@ -105077,13 +105351,13 @@ class BackgroundManager {
|
|
|
105077
105351
|
tmuxEnabled: this.tmuxEnabled,
|
|
105078
105352
|
isInsideTmux: isInsideTmux(),
|
|
105079
105353
|
sessionID,
|
|
105080
|
-
parentID: input.
|
|
105354
|
+
parentID: input.parentSessionId
|
|
105081
105355
|
});
|
|
105082
105356
|
if (this.onSubagentSessionCreated && this.tmuxEnabled && isInsideTmux()) {
|
|
105083
105357
|
log("[background-agent] Invoking tmux callback NOW", { sessionID });
|
|
105084
105358
|
await this.onSubagentSessionCreated({
|
|
105085
105359
|
sessionID,
|
|
105086
|
-
parentID: input.
|
|
105360
|
+
parentID: input.parentSessionId,
|
|
105087
105361
|
title: input.description
|
|
105088
105362
|
}).catch((err) => {
|
|
105089
105363
|
log("[background-agent] Failed to spawn tmux pane:", err);
|
|
@@ -105096,8 +105370,8 @@ class BackgroundManager {
|
|
|
105096
105370
|
if (this.tasks.get(task.id)?.status === "cancelled") {
|
|
105097
105371
|
await this.abortSessionWithLogging(sessionID, "cancelled during tmux setup");
|
|
105098
105372
|
subagentSessions.delete(sessionID);
|
|
105099
|
-
if (task.
|
|
105100
|
-
this.unregisterRootDescendant(task.
|
|
105373
|
+
if (task.rootSessionId) {
|
|
105374
|
+
this.unregisterRootDescendant(task.rootSessionId);
|
|
105101
105375
|
}
|
|
105102
105376
|
this.concurrencyManager.release(concurrencyKey);
|
|
105103
105377
|
return;
|
|
@@ -105106,8 +105380,8 @@ class BackgroundManager {
|
|
|
105106
105380
|
if (!boundAttempt) {
|
|
105107
105381
|
await this.abortSessionWithLogging(sessionID, "stale attempt binding cleanup");
|
|
105108
105382
|
subagentSessions.delete(sessionID);
|
|
105109
|
-
if (task.
|
|
105110
|
-
this.unregisterRootDescendant(task.
|
|
105383
|
+
if (task.rootSessionId) {
|
|
105384
|
+
this.unregisterRootDescendant(task.rootSessionId);
|
|
105111
105385
|
}
|
|
105112
105386
|
this.concurrencyManager.release(concurrencyKey);
|
|
105113
105387
|
return;
|
|
@@ -105121,8 +105395,8 @@ class BackgroundManager {
|
|
|
105121
105395
|
if (task.retryNotification) {
|
|
105122
105396
|
const attemptNumber = boundAttempt.attemptNumber;
|
|
105123
105397
|
const retrySessionUrl = buildLocalSessionUrl(parentDirectory, sessionID);
|
|
105124
|
-
const previousAttempt = getPreviousAttempt(task, boundAttempt.
|
|
105125
|
-
const failedSessionID = previousAttempt?.
|
|
105398
|
+
const previousAttempt = getPreviousAttempt(task, boundAttempt.attemptId);
|
|
105399
|
+
const failedSessionID = previousAttempt?.sessionId ?? task.retryNotification.previousSessionID;
|
|
105126
105400
|
const failedSessionLine = failedSessionID ? `
|
|
105127
105401
|
- Failed session: \`${failedSessionID}\`` : "";
|
|
105128
105402
|
const failedModel = formatAttemptModelSummary(previousAttempt) ?? task.retryNotification.failedModel;
|
|
@@ -105132,7 +105406,7 @@ class BackgroundManager {
|
|
|
105132
105406
|
const failedErrorLine = failedError ? `
|
|
105133
105407
|
- Error: ${failedError}` : "";
|
|
105134
105408
|
const retryModel = formatAttemptModelSummary(boundAttempt) ?? task.retryNotification.nextModel;
|
|
105135
|
-
this.queuePendingNotification(task.
|
|
105409
|
+
this.queuePendingNotification(task.parentSessionId, `<system-reminder>
|
|
105136
105410
|
[BACKGROUND TASK RETRY SESSION READY]
|
|
105137
105411
|
**ID:** \`${task.id}\`
|
|
105138
105412
|
**Description:** ${task.description}
|
|
@@ -105145,7 +105419,7 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105145
105419
|
</system-reminder>`);
|
|
105146
105420
|
task.retryNotification = undefined;
|
|
105147
105421
|
}
|
|
105148
|
-
this.taskHistory.record(input.
|
|
105422
|
+
this.taskHistory.record(input.parentSessionId, { id: task.id, sessionID, agent: input.agent, description: input.description, status: "running", category: input.category, startedAt: task.startedAt });
|
|
105149
105423
|
this.startPolling();
|
|
105150
105424
|
log("[background-agent] Launching task:", { taskId: task.id, sessionID, agent: input.agent });
|
|
105151
105425
|
const toastManager = getTaskToastManager();
|
|
@@ -105235,8 +105509,8 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105235
105509
|
existingTask.error = terminalError;
|
|
105236
105510
|
existingTask.completedAt = new Date;
|
|
105237
105511
|
}
|
|
105238
|
-
if (existingTask.
|
|
105239
|
-
this.unregisterRootDescendant(existingTask.
|
|
105512
|
+
if (existingTask.rootSessionId) {
|
|
105513
|
+
this.unregisterRootDescendant(existingTask.rootSessionId);
|
|
105240
105514
|
}
|
|
105241
105515
|
if (existingTask.concurrencyKey) {
|
|
105242
105516
|
this.concurrencyManager.release(existingTask.concurrencyKey);
|
|
@@ -105245,7 +105519,7 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105245
105519
|
removeTaskToastTracking(existingTask.id);
|
|
105246
105520
|
await this.abortSessionWithLogging(sessionID, "launch error cleanup");
|
|
105247
105521
|
this.markForNotification(existingTask);
|
|
105248
|
-
this.enqueueNotificationForParent(existingTask.
|
|
105522
|
+
this.enqueueNotificationForParent(existingTask.parentSessionId, () => this.notifyParentSession(existingTask)).catch((err) => {
|
|
105249
105523
|
log("[background-agent] Failed to notify on error:", err);
|
|
105250
105524
|
});
|
|
105251
105525
|
}
|
|
@@ -105259,7 +105533,7 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105259
105533
|
if (!taskIDs) {
|
|
105260
105534
|
const result = [];
|
|
105261
105535
|
for (const task of this.tasks.values()) {
|
|
105262
|
-
if (task.
|
|
105536
|
+
if (task.parentSessionId === sessionID) {
|
|
105263
105537
|
result.push(task);
|
|
105264
105538
|
}
|
|
105265
105539
|
}
|
|
@@ -105274,13 +105548,22 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105274
105548
|
}
|
|
105275
105549
|
return tasks;
|
|
105276
105550
|
}
|
|
105551
|
+
updateBackgroundTaskMarker(parentSessionID) {
|
|
105552
|
+
const tasks = this.getTasksByParentSession(parentSessionID);
|
|
105553
|
+
const activeTasks = tasks.filter((t) => t.status === "running" || t.status === "pending");
|
|
105554
|
+
if (activeTasks.length > 0) {
|
|
105555
|
+
setContinuationMarkerSource(this.directory, parentSessionID, "background-task", "active", `${activeTasks.length} background task(s) active`);
|
|
105556
|
+
} else {
|
|
105557
|
+
setContinuationMarkerSource(this.directory, parentSessionID, "background-task", "idle");
|
|
105558
|
+
}
|
|
105559
|
+
}
|
|
105277
105560
|
getAllDescendantTasks(sessionID) {
|
|
105278
105561
|
const result = [];
|
|
105279
105562
|
const directChildren = this.getTasksByParentSession(sessionID);
|
|
105280
105563
|
for (const child of directChildren) {
|
|
105281
105564
|
result.push(child);
|
|
105282
|
-
if (child.
|
|
105283
|
-
const descendants = this.getAllDescendantTasks(child.
|
|
105565
|
+
if (child.sessionId) {
|
|
105566
|
+
const descendants = this.getAllDescendantTasks(child.sessionId);
|
|
105284
105567
|
result.push(...descendants);
|
|
105285
105568
|
}
|
|
105286
105569
|
}
|
|
@@ -105288,7 +105571,7 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105288
105571
|
}
|
|
105289
105572
|
findBySession(sessionID) {
|
|
105290
105573
|
for (const task of this.tasks.values()) {
|
|
105291
|
-
if (task.
|
|
105574
|
+
if (task.sessionId === sessionID) {
|
|
105292
105575
|
return task;
|
|
105293
105576
|
}
|
|
105294
105577
|
if (findAttemptBySession(task, sessionID)) {
|
|
@@ -105307,13 +105590,13 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105307
105590
|
return {
|
|
105308
105591
|
task,
|
|
105309
105592
|
attemptID: undefined,
|
|
105310
|
-
isCurrent: task.
|
|
105593
|
+
isCurrent: task.sessionId === sessionID
|
|
105311
105594
|
};
|
|
105312
105595
|
}
|
|
105313
105596
|
return {
|
|
105314
105597
|
task,
|
|
105315
|
-
attemptID: attempt.
|
|
105316
|
-
isCurrent: task.currentAttemptID === attempt.
|
|
105598
|
+
attemptID: attempt.attemptId,
|
|
105599
|
+
isCurrent: task.currentAttemptID === attempt.attemptId
|
|
105317
105600
|
};
|
|
105318
105601
|
}
|
|
105319
105602
|
getConcurrencyKeyFromInput(input) {
|
|
@@ -105325,10 +105608,10 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105325
105608
|
async trackTask(input) {
|
|
105326
105609
|
const existingTask = this.tasks.get(input.taskId);
|
|
105327
105610
|
if (existingTask) {
|
|
105328
|
-
const parentChanged = input.
|
|
105611
|
+
const parentChanged = input.parentSessionId !== existingTask.parentSessionId;
|
|
105329
105612
|
if (parentChanged) {
|
|
105330
105613
|
this.cleanupPendingByParent(existingTask);
|
|
105331
|
-
this.updateTaskParent(existingTask, input.
|
|
105614
|
+
this.updateTaskParent(existingTask, input.parentSessionId);
|
|
105332
105615
|
}
|
|
105333
105616
|
if (input.parentAgent !== undefined) {
|
|
105334
105617
|
existingTask.parentAgent = input.parentAgent;
|
|
@@ -105336,18 +105619,18 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105336
105619
|
if (!existingTask.concurrencyGroup) {
|
|
105337
105620
|
existingTask.concurrencyGroup = input.concurrencyKey ?? existingTask.agent;
|
|
105338
105621
|
}
|
|
105339
|
-
if (existingTask.
|
|
105340
|
-
subagentSessions.add(existingTask.
|
|
105622
|
+
if (existingTask.sessionId) {
|
|
105623
|
+
subagentSessions.add(existingTask.sessionId);
|
|
105341
105624
|
}
|
|
105342
105625
|
this.startPolling();
|
|
105343
105626
|
if (existingTask.status === "pending" || existingTask.status === "running") {
|
|
105344
|
-
const pending = this.pendingByParent.get(input.
|
|
105627
|
+
const pending = this.pendingByParent.get(input.parentSessionId) ?? new Set;
|
|
105345
105628
|
pending.add(existingTask.id);
|
|
105346
|
-
this.pendingByParent.set(input.
|
|
105629
|
+
this.pendingByParent.set(input.parentSessionId, pending);
|
|
105347
105630
|
} else if (!parentChanged) {
|
|
105348
105631
|
this.cleanupPendingByParent(existingTask);
|
|
105349
105632
|
}
|
|
105350
|
-
log("[background-agent] External task already registered:", { taskId: existingTask.id, sessionID: existingTask.
|
|
105633
|
+
log("[background-agent] External task already registered:", { taskId: existingTask.id, sessionID: existingTask.sessionId, status: existingTask.status });
|
|
105351
105634
|
return existingTask;
|
|
105352
105635
|
}
|
|
105353
105636
|
const concurrencyGroup = input.concurrencyKey ?? input.agent ?? "task";
|
|
@@ -105356,9 +105639,9 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105356
105639
|
}
|
|
105357
105640
|
const task = {
|
|
105358
105641
|
id: input.taskId,
|
|
105359
|
-
|
|
105360
|
-
|
|
105361
|
-
|
|
105642
|
+
sessionId: input.sessionId,
|
|
105643
|
+
parentSessionId: input.parentSessionId,
|
|
105644
|
+
parentMessageId: "",
|
|
105362
105645
|
description: input.description,
|
|
105363
105646
|
prompt: "",
|
|
105364
105647
|
agent: input.agent || "task",
|
|
@@ -105373,15 +105656,15 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105373
105656
|
concurrencyGroup
|
|
105374
105657
|
};
|
|
105375
105658
|
this.addTask(task);
|
|
105376
|
-
subagentSessions.add(input.
|
|
105659
|
+
subagentSessions.add(input.sessionId);
|
|
105377
105660
|
this.startPolling();
|
|
105378
|
-
this.taskHistory.record(input.
|
|
105379
|
-
if (input.
|
|
105380
|
-
const pending = this.pendingByParent.get(input.
|
|
105661
|
+
this.taskHistory.record(input.parentSessionId, { id: task.id, sessionID: input.sessionId, agent: input.agent || "task", description: input.description, status: "running", startedAt: task.startedAt });
|
|
105662
|
+
if (input.parentSessionId) {
|
|
105663
|
+
const pending = this.pendingByParent.get(input.parentSessionId) ?? new Set;
|
|
105381
105664
|
pending.add(task.id);
|
|
105382
|
-
this.pendingByParent.set(input.
|
|
105665
|
+
this.pendingByParent.set(input.parentSessionId, pending);
|
|
105383
105666
|
}
|
|
105384
|
-
log("[background-agent] Registered external task:", { taskId: task.id, sessionID: input.
|
|
105667
|
+
log("[background-agent] Registered external task:", { taskId: task.id, sessionID: input.sessionId });
|
|
105385
105668
|
return task;
|
|
105386
105669
|
}
|
|
105387
105670
|
async resume(input) {
|
|
@@ -105389,13 +105672,13 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105389
105672
|
if (!existingTask) {
|
|
105390
105673
|
throw new Error(`Task not found for session: ${input.sessionId}`);
|
|
105391
105674
|
}
|
|
105392
|
-
if (!existingTask.
|
|
105675
|
+
if (!existingTask.sessionId) {
|
|
105393
105676
|
throw new Error(`Task has no sessionID: ${existingTask.id}`);
|
|
105394
105677
|
}
|
|
105395
105678
|
if (existingTask.status === "running") {
|
|
105396
105679
|
log("[background-agent] Resume skipped - task already running:", {
|
|
105397
105680
|
taskId: existingTask.id,
|
|
105398
|
-
sessionID: existingTask.
|
|
105681
|
+
sessionID: existingTask.sessionId
|
|
105399
105682
|
});
|
|
105400
105683
|
return existingTask;
|
|
105401
105684
|
}
|
|
@@ -105411,8 +105694,8 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105411
105694
|
existingTask.status = "running";
|
|
105412
105695
|
existingTask.completedAt = undefined;
|
|
105413
105696
|
existingTask.error = undefined;
|
|
105414
|
-
this.updateTaskParent(existingTask, input.
|
|
105415
|
-
existingTask.
|
|
105697
|
+
this.updateTaskParent(existingTask, input.parentSessionId);
|
|
105698
|
+
existingTask.parentMessageId = input.parentMessageId;
|
|
105416
105699
|
existingTask.parentModel = input.parentModel;
|
|
105417
105700
|
existingTask.parentAgent = input.parentAgent;
|
|
105418
105701
|
if (input.parentTools) {
|
|
@@ -105426,13 +105709,13 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105426
105709
|
lastUpdate: new Date
|
|
105427
105710
|
};
|
|
105428
105711
|
this.startPolling();
|
|
105429
|
-
if (existingTask.
|
|
105430
|
-
subagentSessions.add(existingTask.
|
|
105712
|
+
if (existingTask.sessionId) {
|
|
105713
|
+
subagentSessions.add(existingTask.sessionId);
|
|
105431
105714
|
}
|
|
105432
|
-
if (input.
|
|
105433
|
-
const pending = this.pendingByParent.get(input.
|
|
105715
|
+
if (input.parentSessionId) {
|
|
105716
|
+
const pending = this.pendingByParent.get(input.parentSessionId) ?? new Set;
|
|
105434
105717
|
pending.add(existingTask.id);
|
|
105435
|
-
this.pendingByParent.set(input.
|
|
105718
|
+
this.pendingByParent.set(input.parentSessionId, pending);
|
|
105436
105719
|
}
|
|
105437
105720
|
const toastManager = getTaskToastManager();
|
|
105438
105721
|
if (toastManager) {
|
|
@@ -105443,9 +105726,9 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105443
105726
|
isBackground: true
|
|
105444
105727
|
});
|
|
105445
105728
|
}
|
|
105446
|
-
log("[background-agent] Resuming task:", { taskId: existingTask.id, sessionID: existingTask.
|
|
105729
|
+
log("[background-agent] Resuming task:", { taskId: existingTask.id, sessionID: existingTask.sessionId });
|
|
105447
105730
|
log("[background-agent] Resuming task - calling prompt (fire-and-forget) with:", {
|
|
105448
|
-
sessionID: existingTask.
|
|
105731
|
+
sessionID: existingTask.sessionId,
|
|
105449
105732
|
agent: existingTask.agent,
|
|
105450
105733
|
model: existingTask.model,
|
|
105451
105734
|
promptLength: input.prompt.length
|
|
@@ -105456,10 +105739,10 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105456
105739
|
} : undefined;
|
|
105457
105740
|
const resumeVariant = existingTask.model?.variant;
|
|
105458
105741
|
if (existingTask.model) {
|
|
105459
|
-
applySessionPromptParams(existingTask.
|
|
105742
|
+
applySessionPromptParams(existingTask.sessionId, existingTask.model);
|
|
105460
105743
|
}
|
|
105461
105744
|
this.client.session.promptAsync({
|
|
105462
|
-
path: { id: existingTask.
|
|
105745
|
+
path: { id: existingTask.sessionId },
|
|
105463
105746
|
body: {
|
|
105464
105747
|
agent: existingTask.agent,
|
|
105465
105748
|
...resumeModel ? { model: resumeModel } : {},
|
|
@@ -105471,7 +105754,7 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105471
105754
|
question: false,
|
|
105472
105755
|
...getAgentToolRestrictions(existingTask.agent)
|
|
105473
105756
|
};
|
|
105474
|
-
setSessionTools(existingTask.
|
|
105757
|
+
setSessionTools(existingTask.sessionId, tools);
|
|
105475
105758
|
return tools;
|
|
105476
105759
|
})(),
|
|
105477
105760
|
parts: [createInternalAgentTextPart(input.prompt)]
|
|
@@ -105489,19 +105772,19 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105489
105772
|
const errorMessage = errorInfo.message ?? (error instanceof Error ? error.message : String(error));
|
|
105490
105773
|
existingTask.error = errorMessage;
|
|
105491
105774
|
existingTask.completedAt = new Date;
|
|
105492
|
-
if (existingTask.
|
|
105493
|
-
this.unregisterRootDescendant(existingTask.
|
|
105775
|
+
if (existingTask.rootSessionId) {
|
|
105776
|
+
this.unregisterRootDescendant(existingTask.rootSessionId);
|
|
105494
105777
|
}
|
|
105495
105778
|
if (existingTask.concurrencyKey) {
|
|
105496
105779
|
this.concurrencyManager.release(existingTask.concurrencyKey);
|
|
105497
105780
|
existingTask.concurrencyKey = undefined;
|
|
105498
105781
|
}
|
|
105499
105782
|
removeTaskToastTracking(existingTask.id);
|
|
105500
|
-
if (existingTask.
|
|
105501
|
-
await this.abortSessionWithLogging(existingTask.
|
|
105783
|
+
if (existingTask.sessionId) {
|
|
105784
|
+
await this.abortSessionWithLogging(existingTask.sessionId, "resume error cleanup");
|
|
105502
105785
|
}
|
|
105503
105786
|
this.markForNotification(existingTask);
|
|
105504
|
-
this.enqueueNotificationForParent(existingTask.
|
|
105787
|
+
this.enqueueNotificationForParent(existingTask.parentSessionId, () => this.notifyParentSession(existingTask)).catch((err) => {
|
|
105505
105788
|
log("[background-agent] Failed to notify on resume error:", err);
|
|
105506
105789
|
});
|
|
105507
105790
|
});
|
|
@@ -105743,23 +106026,23 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105743
106026
|
const parentSessionsToClear = new Set;
|
|
105744
106027
|
const deletedSessionIDs = new Set([sessionID]);
|
|
105745
106028
|
for (const task of tasksToCancel.values()) {
|
|
105746
|
-
if (task.
|
|
105747
|
-
deletedSessionIDs.add(task.
|
|
106029
|
+
if (task.sessionId) {
|
|
106030
|
+
deletedSessionIDs.add(task.sessionId);
|
|
105748
106031
|
}
|
|
105749
106032
|
}
|
|
105750
106033
|
for (const task of tasksToCancel.values()) {
|
|
105751
|
-
parentSessionsToClear.add(task.
|
|
106034
|
+
parentSessionsToClear.add(task.parentSessionId);
|
|
105752
106035
|
if (task.status === "running" || task.status === "pending") {
|
|
105753
106036
|
this.cancelTask(task.id, {
|
|
105754
106037
|
source: "session.deleted",
|
|
105755
106038
|
reason: "Session deleted"
|
|
105756
106039
|
}).then(() => {
|
|
105757
|
-
if (deletedSessionIDs.has(task.
|
|
105758
|
-
this.pendingNotifications.delete(task.
|
|
106040
|
+
if (deletedSessionIDs.has(task.parentSessionId)) {
|
|
106041
|
+
this.pendingNotifications.delete(task.parentSessionId);
|
|
105759
106042
|
}
|
|
105760
106043
|
}).catch((err) => {
|
|
105761
|
-
if (deletedSessionIDs.has(task.
|
|
105762
|
-
this.pendingNotifications.delete(task.
|
|
106044
|
+
if (deletedSessionIDs.has(task.parentSessionId)) {
|
|
106045
|
+
this.pendingNotifications.delete(task.parentSessionId);
|
|
105763
106046
|
}
|
|
105764
106047
|
log("[background-agent] Failed to cancel task on session.deleted:", { taskId: task.id, error: err });
|
|
105765
106048
|
});
|
|
@@ -105794,8 +106077,8 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105794
106077
|
}
|
|
105795
106078
|
async handleSessionErrorEvent(args) {
|
|
105796
106079
|
const { task, errorInfo, errorMessage, errorName } = args;
|
|
105797
|
-
if (!task.fallbackChain && task.
|
|
105798
|
-
const sessionFallbackChain = this.modelFallbackControllerAccessor?.getSessionFallbackChain(task.
|
|
106080
|
+
if (!task.fallbackChain && task.sessionId) {
|
|
106081
|
+
const sessionFallbackChain = this.modelFallbackControllerAccessor?.getSessionFallbackChain(task.sessionId);
|
|
105799
106082
|
if (sessionFallbackChain?.length) {
|
|
105800
106083
|
task.fallbackChain = sessionFallbackChain;
|
|
105801
106084
|
}
|
|
@@ -105826,10 +106109,10 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105826
106109
|
task.error = errorMsg;
|
|
105827
106110
|
task.completedAt = new Date;
|
|
105828
106111
|
}
|
|
105829
|
-
if (task.
|
|
105830
|
-
this.unregisterRootDescendant(task.
|
|
106112
|
+
if (task.rootSessionId) {
|
|
106113
|
+
this.unregisterRootDescendant(task.rootSessionId);
|
|
105831
106114
|
}
|
|
105832
|
-
this.taskHistory.record(task.
|
|
106115
|
+
this.taskHistory.record(task.parentSessionId, { id: task.id, sessionID: task.sessionId, agent: task.agent, description: task.description, status: "error", category: task.category, startedAt: task.startedAt, completedAt: task.completedAt });
|
|
105833
106116
|
if (task.concurrencyKey) {
|
|
105834
106117
|
this.concurrencyManager.release(task.concurrencyKey);
|
|
105835
106118
|
task.concurrencyKey = undefined;
|
|
@@ -105851,16 +106134,19 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105851
106134
|
toastManager.removeTask(task.id);
|
|
105852
106135
|
}
|
|
105853
106136
|
this.scheduleTaskRemoval(task.id);
|
|
105854
|
-
if (task.
|
|
105855
|
-
SessionCategoryRegistry.remove(task.
|
|
106137
|
+
if (task.sessionId) {
|
|
106138
|
+
SessionCategoryRegistry.remove(task.sessionId);
|
|
106139
|
+
}
|
|
106140
|
+
if (task.parentSessionId) {
|
|
106141
|
+
this.updateBackgroundTaskMarker(task.parentSessionId);
|
|
105856
106142
|
}
|
|
105857
106143
|
this.markForNotification(task);
|
|
105858
|
-
this.enqueueNotificationForParent(task.
|
|
106144
|
+
this.enqueueNotificationForParent(task.parentSessionId, () => this.notifyParentSession(task)).catch((err) => {
|
|
105859
106145
|
log("[background-agent] Error in notifyParentSession for errored task:", { taskId: task.id, error: err });
|
|
105860
106146
|
});
|
|
105861
106147
|
}
|
|
105862
106148
|
tryFallbackRetry(task, errorInfo, source) {
|
|
105863
|
-
const previousSessionID = task.
|
|
106149
|
+
const previousSessionID = task.sessionId;
|
|
105864
106150
|
const result = tryFallbackRetry({
|
|
105865
106151
|
task,
|
|
105866
106152
|
errorInfo,
|
|
@@ -105872,17 +106158,17 @@ The fallback retry session is now created and can be inspected directly.
|
|
|
105872
106158
|
processKey: (key) => this.processKey(key),
|
|
105873
106159
|
onRetrying: ({ task: task2, source: source2 }) => {
|
|
105874
106160
|
const currentAttempt = getCurrentAttempt(task2);
|
|
105875
|
-
const previousAttempt = getPreviousAttempt(task2, currentAttempt?.
|
|
106161
|
+
const previousAttempt = getPreviousAttempt(task2, currentAttempt?.attemptId);
|
|
105876
106162
|
const sourceText = source2 ? ` via ${source2}` : "";
|
|
105877
|
-
const failedSessionLine = previousAttempt?.
|
|
105878
|
-
- Failed session: \`${previousAttempt.
|
|
106163
|
+
const failedSessionLine = previousAttempt?.sessionId ? `
|
|
106164
|
+
- Failed session: \`${previousAttempt.sessionId}\`` : "";
|
|
105879
106165
|
const failedModel = formatAttemptModelSummary(previousAttempt);
|
|
105880
106166
|
const failedModelLine = failedModel ? `
|
|
105881
106167
|
- Failed model: \`${failedModel}\`` : "";
|
|
105882
106168
|
const failedErrorLine = previousAttempt?.error ? `
|
|
105883
106169
|
- Error: ${previousAttempt.error}` : "";
|
|
105884
106170
|
const nextModel = formatAttemptModelSummary(currentAttempt);
|
|
105885
|
-
this.queuePendingNotification(task2.
|
|
106171
|
+
this.queuePendingNotification(task2.parentSessionId, `<system-reminder>
|
|
105886
106172
|
[BACKGROUND TASK RETRYING]
|
|
105887
106173
|
**ID:** \`${task2.id}\`
|
|
105888
106174
|
**Description:** ${task2.description}${sourceText}${failedSessionLine}${failedModelLine}${failedErrorLine}${nextModel ? `
|
|
@@ -105902,9 +106188,9 @@ The task was re-queued on a fallback model after a retryable failure.
|
|
|
105902
106188
|
});
|
|
105903
106189
|
}
|
|
105904
106190
|
markForNotification(task) {
|
|
105905
|
-
const queue = this.notifications.get(task.
|
|
106191
|
+
const queue = this.notifications.get(task.parentSessionId) ?? [];
|
|
105906
106192
|
queue.push(task);
|
|
105907
|
-
this.notifications.set(task.
|
|
106193
|
+
this.notifications.set(task.parentSessionId, queue);
|
|
105908
106194
|
}
|
|
105909
106195
|
getPendingNotifications(sessionID) {
|
|
105910
106196
|
return this.notifications.get(sessionID) ?? [];
|
|
@@ -105982,13 +106268,13 @@ ${originalText}`;
|
|
|
105982
106268
|
}
|
|
105983
106269
|
}
|
|
105984
106270
|
cleanupPendingByParent(task) {
|
|
105985
|
-
if (!task.
|
|
106271
|
+
if (!task.parentSessionId)
|
|
105986
106272
|
return;
|
|
105987
|
-
const pending = this.pendingByParent.get(task.
|
|
106273
|
+
const pending = this.pendingByParent.get(task.parentSessionId);
|
|
105988
106274
|
if (pending) {
|
|
105989
106275
|
pending.delete(task.id);
|
|
105990
106276
|
if (pending.size === 0) {
|
|
105991
|
-
this.pendingByParent.delete(task.
|
|
106277
|
+
this.pendingByParent.delete(task.parentSessionId);
|
|
105992
106278
|
}
|
|
105993
106279
|
}
|
|
105994
106280
|
}
|
|
@@ -106011,8 +106297,8 @@ ${originalText}`;
|
|
|
106011
106297
|
const task = this.tasks.get(taskId);
|
|
106012
106298
|
if (!task)
|
|
106013
106299
|
return;
|
|
106014
|
-
if (task.
|
|
106015
|
-
const siblings = this.getTasksByParentSession(task.
|
|
106300
|
+
if (task.parentSessionId) {
|
|
106301
|
+
const siblings = this.getTasksByParentSession(task.parentSessionId);
|
|
106016
106302
|
const runningOrPendingSiblings = siblings.filter((sibling) => sibling.id !== taskId && (sibling.status === "running" || sibling.status === "pending"));
|
|
106017
106303
|
const completedAtTimestamp = task.completedAt?.getTime();
|
|
106018
106304
|
const reachedTaskTtl = completedAtTimestamp !== undefined && Date.now() - completedAtTimestamp >= TASK_TTL_MS;
|
|
@@ -106023,10 +106309,10 @@ ${originalText}`;
|
|
|
106023
106309
|
}
|
|
106024
106310
|
this.clearNotificationsForTask(taskId);
|
|
106025
106311
|
this.removeTask(task);
|
|
106026
|
-
this.clearTaskHistoryWhenParentTasksGone(task.
|
|
106027
|
-
if (task.
|
|
106028
|
-
subagentSessions.delete(task.
|
|
106029
|
-
SessionCategoryRegistry.remove(task.
|
|
106312
|
+
this.clearTaskHistoryWhenParentTasksGone(task.parentSessionId);
|
|
106313
|
+
if (task.sessionId) {
|
|
106314
|
+
subagentSessions.delete(task.sessionId);
|
|
106315
|
+
SessionCategoryRegistry.remove(task.sessionId);
|
|
106030
106316
|
}
|
|
106031
106317
|
log("[background-agent] Removed completed task from memory:", taskId);
|
|
106032
106318
|
}, TASK_CLEANUP_DELAY_MS);
|
|
@@ -106065,10 +106351,10 @@ ${originalText}`;
|
|
|
106065
106351
|
task.error = reason;
|
|
106066
106352
|
}
|
|
106067
106353
|
}
|
|
106068
|
-
if (wasRunning && task.
|
|
106069
|
-
this.unregisterRootDescendant(task.
|
|
106354
|
+
if (wasRunning && task.rootSessionId) {
|
|
106355
|
+
this.unregisterRootDescendant(task.rootSessionId);
|
|
106070
106356
|
}
|
|
106071
|
-
this.taskHistory.record(task.
|
|
106357
|
+
this.taskHistory.record(task.parentSessionId, { id: task.id, sessionID: task.sessionId, agent: task.agent, description: task.description, status: "cancelled", category: task.category, startedAt: task.startedAt, completedAt: task.completedAt });
|
|
106072
106358
|
if (task.concurrencyKey) {
|
|
106073
106359
|
this.concurrencyManager.release(task.concurrencyKey);
|
|
106074
106360
|
task.concurrencyKey = undefined;
|
|
@@ -106083,11 +106369,14 @@ ${originalText}`;
|
|
|
106083
106369
|
clearTimeout(idleTimer);
|
|
106084
106370
|
this.idleDeferralTimers.delete(task.id);
|
|
106085
106371
|
}
|
|
106086
|
-
if (abortSession && task.
|
|
106087
|
-
await this.abortSessionWithLogging(task.
|
|
106088
|
-
SessionCategoryRegistry.remove(task.
|
|
106372
|
+
if (abortSession && task.sessionId) {
|
|
106373
|
+
await this.abortSessionWithLogging(task.sessionId, `task cancellation (${source})`);
|
|
106374
|
+
SessionCategoryRegistry.remove(task.sessionId);
|
|
106089
106375
|
}
|
|
106090
106376
|
removeTaskToastTracking(task.id);
|
|
106377
|
+
if (task.parentSessionId) {
|
|
106378
|
+
this.updateBackgroundTaskMarker(task.parentSessionId);
|
|
106379
|
+
}
|
|
106091
106380
|
if (options?.skipNotification) {
|
|
106092
106381
|
this.cleanupPendingByParent(task);
|
|
106093
106382
|
this.scheduleTaskRemoval(task.id);
|
|
@@ -106096,7 +106385,7 @@ ${originalText}`;
|
|
|
106096
106385
|
}
|
|
106097
106386
|
this.markForNotification(task);
|
|
106098
106387
|
try {
|
|
106099
|
-
await this.enqueueNotificationForParent(task.
|
|
106388
|
+
await this.enqueueNotificationForParent(task.parentSessionId, () => this.notifyParentSession(task));
|
|
106100
106389
|
log(`[background-agent] Task cancelled via ${source}:`, task.id);
|
|
106101
106390
|
} catch (err) {
|
|
106102
106391
|
log("[background-agent] Error in notifyParentSession for cancelled task:", { taskId: task.id, error: err });
|
|
@@ -106148,9 +106437,9 @@ ${originalText}`;
|
|
|
106148
106437
|
task.status = "completed";
|
|
106149
106438
|
task.completedAt = new Date;
|
|
106150
106439
|
}
|
|
106151
|
-
this.taskHistory.record(task.
|
|
106152
|
-
if (task.
|
|
106153
|
-
this.unregisterRootDescendant(task.
|
|
106440
|
+
this.taskHistory.record(task.parentSessionId, { id: task.id, sessionID: task.sessionId, agent: task.agent, description: task.description, status: "completed", category: task.category, startedAt: task.startedAt, completedAt: task.completedAt });
|
|
106441
|
+
if (task.rootSessionId) {
|
|
106442
|
+
this.unregisterRootDescendant(task.rootSessionId);
|
|
106154
106443
|
}
|
|
106155
106444
|
removeTaskToastTracking(task.id);
|
|
106156
106445
|
if (task.concurrencyKey) {
|
|
@@ -106163,12 +106452,15 @@ ${originalText}`;
|
|
|
106163
106452
|
clearTimeout(idleTimer);
|
|
106164
106453
|
this.idleDeferralTimers.delete(task.id);
|
|
106165
106454
|
}
|
|
106166
|
-
if (task.
|
|
106167
|
-
await this.abortSessionWithLogging(task.
|
|
106168
|
-
SessionCategoryRegistry.remove(task.
|
|
106455
|
+
if (task.sessionId) {
|
|
106456
|
+
await this.abortSessionWithLogging(task.sessionId, `task completion (${source})`);
|
|
106457
|
+
SessionCategoryRegistry.remove(task.sessionId);
|
|
106458
|
+
}
|
|
106459
|
+
if (task.parentSessionId) {
|
|
106460
|
+
this.updateBackgroundTaskMarker(task.parentSessionId);
|
|
106169
106461
|
}
|
|
106170
106462
|
try {
|
|
106171
|
-
await this.enqueueNotificationForParent(task.
|
|
106463
|
+
await this.enqueueNotificationForParent(task.parentSessionId, () => this.notifyParentSession(task));
|
|
106172
106464
|
log(`[background-agent] Task completed via ${source}:`, task.id);
|
|
106173
106465
|
} catch (err) {
|
|
106174
106466
|
log("[background-agent] Error in notifyParentSession:", { taskId: task.id, error: err });
|
|
@@ -106186,17 +106478,17 @@ ${originalText}`;
|
|
|
106186
106478
|
duration
|
|
106187
106479
|
});
|
|
106188
106480
|
}
|
|
106189
|
-
if (!this.completedTaskSummaries.has(task.
|
|
106190
|
-
this.completedTaskSummaries.set(task.
|
|
106481
|
+
if (!this.completedTaskSummaries.has(task.parentSessionId)) {
|
|
106482
|
+
this.completedTaskSummaries.set(task.parentSessionId, []);
|
|
106191
106483
|
}
|
|
106192
|
-
this.completedTaskSummaries.get(task.
|
|
106484
|
+
this.completedTaskSummaries.get(task.parentSessionId).push({
|
|
106193
106485
|
id: task.id,
|
|
106194
106486
|
description: task.description,
|
|
106195
106487
|
status: task.status,
|
|
106196
106488
|
error: task.error,
|
|
106197
106489
|
attempts: cloneAttempts(task)
|
|
106198
106490
|
});
|
|
106199
|
-
const pendingSet = this.pendingByParent.get(task.
|
|
106491
|
+
const pendingSet = this.pendingByParent.get(task.parentSessionId);
|
|
106200
106492
|
let allComplete = false;
|
|
106201
106493
|
let remainingCount = 0;
|
|
106202
106494
|
if (pendingSet) {
|
|
@@ -106204,15 +106496,15 @@ ${originalText}`;
|
|
|
106204
106496
|
remainingCount = pendingSet.size;
|
|
106205
106497
|
allComplete = remainingCount === 0;
|
|
106206
106498
|
if (allComplete) {
|
|
106207
|
-
this.pendingByParent.delete(task.
|
|
106499
|
+
this.pendingByParent.delete(task.parentSessionId);
|
|
106208
106500
|
}
|
|
106209
106501
|
} else {
|
|
106210
|
-
remainingCount = Array.from(this.tasks.values()).filter((t) => t.
|
|
106502
|
+
remainingCount = Array.from(this.tasks.values()).filter((t) => t.parentSessionId === task.parentSessionId && t.id !== task.id && (t.status === "running" || t.status === "pending")).length;
|
|
106211
106503
|
allComplete = remainingCount === 0;
|
|
106212
106504
|
}
|
|
106213
|
-
const completedTasks = allComplete ? this.completedTaskSummaries.get(task.
|
|
106505
|
+
const completedTasks = allComplete ? this.completedTaskSummaries.get(task.parentSessionId) ?? [{ id: task.id, description: task.description, status: task.status, error: task.error, attempts: cloneAttempts(task) }] : [];
|
|
106214
106506
|
if (allComplete) {
|
|
106215
|
-
this.completedTaskSummaries.delete(task.
|
|
106507
|
+
this.completedTaskSummaries.delete(task.parentSessionId);
|
|
106216
106508
|
}
|
|
106217
106509
|
const statusText = task.status === "completed" ? "COMPLETED" : task.status === "interrupt" ? "INTERRUPTED" : task.status === "error" ? "ERROR" : "CANCELLED";
|
|
106218
106510
|
const notification2 = buildBackgroundTaskNotificationText({
|
|
@@ -106229,9 +106521,9 @@ ${originalText}`;
|
|
|
106229
106521
|
let promptContext = null;
|
|
106230
106522
|
if (this.enableParentSessionNotifications) {
|
|
106231
106523
|
try {
|
|
106232
|
-
const messagesResp = await this.client.session.messages({ path: { id: task.
|
|
106524
|
+
const messagesResp = await this.client.session.messages({ path: { id: task.parentSessionId } });
|
|
106233
106525
|
const messages = normalizeSDKResponse(messagesResp, []);
|
|
106234
|
-
promptContext = resolvePromptContextFromSessionMessages(messages, task.
|
|
106526
|
+
promptContext = resolvePromptContextFromSessionMessages(messages, task.parentSessionId);
|
|
106235
106527
|
const normalizedTools = isRecord15(promptContext?.tools) ? normalizePromptTools(promptContext.tools) : undefined;
|
|
106236
106528
|
if (promptContext?.agent || promptContext?.model || normalizedTools) {
|
|
106237
106529
|
agent = promptContext?.agent ?? task.parentAgent;
|
|
@@ -106242,16 +106534,16 @@ ${originalText}`;
|
|
|
106242
106534
|
if (isAbortedSessionError(error)) {
|
|
106243
106535
|
log("[background-agent] Parent session aborted while loading messages; using messageDir fallback:", {
|
|
106244
106536
|
taskId: task.id,
|
|
106245
|
-
parentSessionID: task.
|
|
106537
|
+
parentSessionID: task.parentSessionId
|
|
106246
106538
|
});
|
|
106247
106539
|
}
|
|
106248
|
-
const messageDir = join95(MESSAGE_STORAGE, task.
|
|
106249
|
-
const currentMessage = messageDir ? findNearestMessageExcludingCompaction(messageDir, task.
|
|
106540
|
+
const messageDir = join95(MESSAGE_STORAGE, task.parentSessionId);
|
|
106541
|
+
const currentMessage = messageDir ? findNearestMessageExcludingCompaction(messageDir, task.parentSessionId) : null;
|
|
106250
106542
|
agent = currentMessage?.agent ?? task.parentAgent;
|
|
106251
106543
|
model = currentMessage?.model?.providerID && currentMessage?.model?.modelID ? { providerID: currentMessage.model.providerID, modelID: currentMessage.model.modelID } : undefined;
|
|
106252
106544
|
tools = normalizePromptTools(currentMessage?.tools) ?? tools;
|
|
106253
106545
|
}
|
|
106254
|
-
const resolvedTools = resolveInheritedPromptTools(task.
|
|
106546
|
+
const resolvedTools = resolveInheritedPromptTools(task.parentSessionId, tools);
|
|
106255
106547
|
log("[background-agent] notifyParentSession context:", {
|
|
106256
106548
|
taskId: task.id,
|
|
106257
106549
|
resolvedAgent: agent,
|
|
@@ -106262,7 +106554,7 @@ ${originalText}`;
|
|
|
106262
106554
|
const variant = promptContext?.model?.variant;
|
|
106263
106555
|
try {
|
|
106264
106556
|
await this.client.session.promptAsync({
|
|
106265
|
-
path: { id: task.
|
|
106557
|
+
path: { id: task.parentSessionId },
|
|
106266
106558
|
body: {
|
|
106267
106559
|
noReply: !shouldReply,
|
|
106268
106560
|
...agent !== undefined ? { agent } : {},
|
|
@@ -106282,9 +106574,9 @@ ${originalText}`;
|
|
|
106282
106574
|
if (isAbortedSessionError(error)) {
|
|
106283
106575
|
log("[background-agent] Parent session aborted while sending notification; continuing cleanup:", {
|
|
106284
106576
|
taskId: task.id,
|
|
106285
|
-
parentSessionID: task.
|
|
106577
|
+
parentSessionID: task.parentSessionId
|
|
106286
106578
|
});
|
|
106287
|
-
this.queuePendingNotification(task.
|
|
106579
|
+
this.queuePendingNotification(task.parentSessionId, notification2);
|
|
106288
106580
|
} else {
|
|
106289
106581
|
log("[background-agent] Failed to send notification:", error);
|
|
106290
106582
|
}
|
|
@@ -106292,7 +106584,7 @@ ${originalText}`;
|
|
|
106292
106584
|
} else {
|
|
106293
106585
|
log("[background-agent] Parent session notifications disabled, skipping prompt injection:", {
|
|
106294
106586
|
taskId: task.id,
|
|
106295
|
-
parentSessionID: task.
|
|
106587
|
+
parentSessionID: task.parentSessionId
|
|
106296
106588
|
});
|
|
106297
106589
|
}
|
|
106298
106590
|
if (task.status !== "running" && task.status !== "pending") {
|
|
@@ -106317,10 +106609,10 @@ ${originalText}`;
|
|
|
106317
106609
|
task.status = "error";
|
|
106318
106610
|
task.error = errorMessage;
|
|
106319
106611
|
task.completedAt = new Date;
|
|
106320
|
-
if (!wasPending && task.
|
|
106321
|
-
this.unregisterRootDescendant(task.
|
|
106612
|
+
if (!wasPending && task.rootSessionId) {
|
|
106613
|
+
this.unregisterRootDescendant(task.rootSessionId);
|
|
106322
106614
|
}
|
|
106323
|
-
this.taskHistory.record(task.
|
|
106615
|
+
this.taskHistory.record(task.parentSessionId, { id: task.id, sessionID: task.sessionId, agent: task.agent, description: task.description, status: "error", category: task.category, startedAt: task.startedAt, completedAt: task.completedAt });
|
|
106324
106616
|
if (task.concurrencyKey) {
|
|
106325
106617
|
this.concurrencyManager.release(task.concurrencyKey);
|
|
106326
106618
|
task.concurrencyKey = undefined;
|
|
@@ -106350,21 +106642,24 @@ ${originalText}`;
|
|
|
106350
106642
|
}
|
|
106351
106643
|
}
|
|
106352
106644
|
this.cleanupPendingByParent(task);
|
|
106645
|
+
if (task.parentSessionId) {
|
|
106646
|
+
this.updateBackgroundTaskMarker(task.parentSessionId);
|
|
106647
|
+
}
|
|
106353
106648
|
this.markForNotification(task);
|
|
106354
|
-
this.enqueueNotificationForParent(task.
|
|
106649
|
+
this.enqueueNotificationForParent(task.parentSessionId, () => this.notifyParentSession(task)).catch((err) => {
|
|
106355
106650
|
log("[background-agent] Error in notifyParentSession for stale-pruned task:", { taskId: task.id, error: err });
|
|
106356
106651
|
});
|
|
106357
106652
|
}
|
|
106358
106653
|
});
|
|
106359
106654
|
}
|
|
106360
|
-
async checkAndInterruptStaleTasks(allStatuses
|
|
106655
|
+
async checkAndInterruptStaleTasks(allStatuses) {
|
|
106361
106656
|
await checkAndInterruptStaleTasks({
|
|
106362
106657
|
tasks: this.tasks.values(),
|
|
106363
106658
|
client: this.client,
|
|
106364
106659
|
directory: this.directory,
|
|
106365
106660
|
config: this.config,
|
|
106366
106661
|
concurrencyManager: this.concurrencyManager,
|
|
106367
|
-
notifyParentSession: (task) => this.enqueueNotificationForParent(task.
|
|
106662
|
+
notifyParentSession: (task) => this.enqueueNotificationForParent(task.parentSessionId, () => this.notifyParentSession(task)),
|
|
106368
106663
|
sessionStatuses: allStatuses
|
|
106369
106664
|
});
|
|
106370
106665
|
}
|
|
@@ -106379,10 +106674,10 @@ ${originalText}`;
|
|
|
106379
106674
|
task.error = errorMessage;
|
|
106380
106675
|
task.completedAt = new Date;
|
|
106381
106676
|
}
|
|
106382
|
-
if (task.
|
|
106383
|
-
this.unregisterRootDescendant(task.
|
|
106677
|
+
if (task.rootSessionId) {
|
|
106678
|
+
this.unregisterRootDescendant(task.rootSessionId);
|
|
106384
106679
|
}
|
|
106385
|
-
this.taskHistory.record(task.
|
|
106680
|
+
this.taskHistory.record(task.parentSessionId, { id: task.id, sessionID: task.sessionId, agent: task.agent, description: task.description, status: "error", category: task.category, startedAt: task.startedAt, completedAt: task.completedAt });
|
|
106386
106681
|
if (task.concurrencyKey) {
|
|
106387
106682
|
this.concurrencyManager.release(task.concurrencyKey);
|
|
106388
106683
|
task.concurrencyKey = undefined;
|
|
@@ -106401,11 +106696,14 @@ ${originalText}`;
|
|
|
106401
106696
|
this.clearNotificationsForTask(task.id);
|
|
106402
106697
|
removeTaskToastTracking(task.id);
|
|
106403
106698
|
this.scheduleTaskRemoval(task.id);
|
|
106404
|
-
if (task.
|
|
106405
|
-
SessionCategoryRegistry.remove(task.
|
|
106699
|
+
if (task.sessionId) {
|
|
106700
|
+
SessionCategoryRegistry.remove(task.sessionId);
|
|
106701
|
+
}
|
|
106702
|
+
if (task.parentSessionId) {
|
|
106703
|
+
this.updateBackgroundTaskMarker(task.parentSessionId);
|
|
106406
106704
|
}
|
|
106407
106705
|
this.markForNotification(task);
|
|
106408
|
-
this.enqueueNotificationForParent(task.
|
|
106706
|
+
this.enqueueNotificationForParent(task.parentSessionId, () => this.notifyParentSession(task)).catch((err) => {
|
|
106409
106707
|
log("[background-agent] Error in notifyParentSession for crashed task:", { taskId: task.id, error: err });
|
|
106410
106708
|
});
|
|
106411
106709
|
}
|
|
@@ -106415,17 +106713,35 @@ ${originalText}`;
|
|
|
106415
106713
|
this.pollingInFlight = true;
|
|
106416
106714
|
try {
|
|
106417
106715
|
this.pruneStaleTasksAndNotifications();
|
|
106418
|
-
|
|
106419
|
-
const
|
|
106716
|
+
let allStatuses;
|
|
106717
|
+
const sessionStatusMethod = this.client?.session?.status;
|
|
106718
|
+
if (typeof sessionStatusMethod !== "function") {
|
|
106719
|
+
if (!this.loggedSessionStatusUnavailable) {
|
|
106720
|
+
log("[background-agent] Unable to poll session statuses:", {
|
|
106721
|
+
reason: "session.status unavailable"
|
|
106722
|
+
});
|
|
106723
|
+
this.loggedSessionStatusUnavailable = true;
|
|
106724
|
+
}
|
|
106725
|
+
} else {
|
|
106726
|
+
try {
|
|
106727
|
+
const statusResult = await this.client.session.status();
|
|
106728
|
+
allStatuses = normalizeSDKResponse(statusResult, {});
|
|
106729
|
+
} catch (error) {
|
|
106730
|
+
if (!this.loggedSessionStatusUnavailable) {
|
|
106731
|
+
log("[background-agent] Error polling session statuses:", { error });
|
|
106732
|
+
this.loggedSessionStatusUnavailable = true;
|
|
106733
|
+
}
|
|
106734
|
+
}
|
|
106735
|
+
}
|
|
106420
106736
|
await this.checkAndInterruptStaleTasks(allStatuses);
|
|
106421
106737
|
for (const task of this.tasks.values()) {
|
|
106422
106738
|
if (task.status !== "running")
|
|
106423
106739
|
continue;
|
|
106424
|
-
const sessionID = task.
|
|
106740
|
+
const sessionID = task.sessionId;
|
|
106425
106741
|
if (!sessionID)
|
|
106426
106742
|
continue;
|
|
106427
106743
|
try {
|
|
106428
|
-
const sessionStatus = allStatuses[sessionID];
|
|
106744
|
+
const sessionStatus = allStatuses?.[sessionID];
|
|
106429
106745
|
if (sessionStatus?.type === "retry") {
|
|
106430
106746
|
const retryMessage = typeof sessionStatus.message === "string" ? sessionStatus.message : undefined;
|
|
106431
106747
|
const errorInfo = { name: "SessionRetry", message: retryMessage };
|
|
@@ -106453,7 +106769,10 @@ ${originalText}`;
|
|
|
106453
106769
|
sessionStatus: sessionStatus.type
|
|
106454
106770
|
});
|
|
106455
106771
|
}
|
|
106456
|
-
|
|
106772
|
+
if (allStatuses === undefined) {
|
|
106773
|
+
continue;
|
|
106774
|
+
}
|
|
106775
|
+
const sessionGoneFromStatus = allStatuses !== undefined && !sessionStatus;
|
|
106457
106776
|
const sessionGoneThresholdReached = sessionGoneFromStatus && (task.consecutiveMissedPolls ?? 0) >= MIN_SESSION_GONE_POLLS;
|
|
106458
106777
|
const completionSource = sessionStatus?.type === "idle" ? "polling (idle status)" : "polling (session gone from status)";
|
|
106459
106778
|
const hasValidOutput = await this.validateSessionHasOutput(sessionID);
|
|
@@ -106498,13 +106817,13 @@ ${originalText}`;
|
|
|
106498
106817
|
const trackedSessionIDs = new Set;
|
|
106499
106818
|
const abortRequests = [];
|
|
106500
106819
|
for (const task of this.tasks.values()) {
|
|
106501
|
-
if (task.
|
|
106502
|
-
trackedSessionIDs.add(task.
|
|
106820
|
+
if (task.sessionId) {
|
|
106821
|
+
trackedSessionIDs.add(task.sessionId);
|
|
106503
106822
|
}
|
|
106504
|
-
if (task.status === "running" && task.
|
|
106823
|
+
if (task.status === "running" && task.sessionId) {
|
|
106505
106824
|
abortRequests.push({
|
|
106506
|
-
sessionID: task.
|
|
106507
|
-
promise: abortWithTimeout(this.client, task.
|
|
106825
|
+
sessionID: task.sessionId,
|
|
106826
|
+
promise: abortWithTimeout(this.client, task.sessionId)
|
|
106508
106827
|
});
|
|
106509
106828
|
}
|
|
106510
106829
|
}
|
|
@@ -111508,7 +111827,8 @@ async function createStdioClient(params) {
|
|
|
111508
111827
|
command,
|
|
111509
111828
|
args,
|
|
111510
111829
|
env: mergedEnv,
|
|
111511
|
-
stderr: "ignore"
|
|
111830
|
+
stderr: "ignore",
|
|
111831
|
+
...info.directory ? { cwd: info.directory } : {}
|
|
111512
111832
|
});
|
|
111513
111833
|
const client2 = stdioClientDependencies.createClient({ name: `skill-mcp-${info.skillName}-${info.serverName}`, version: "1.0.0" }, { capabilities: {} });
|
|
111514
111834
|
try {
|
|
@@ -118830,8 +119150,7 @@ call_omo_agent(subagent_type="librarian", prompt="I'm looking for proven impleme
|
|
|
118830
119150
|
var metisRestrictions = createAgentToolRestrictions([
|
|
118831
119151
|
"write",
|
|
118832
119152
|
"edit",
|
|
118833
|
-
"apply_patch"
|
|
118834
|
-
"task"
|
|
119153
|
+
"apply_patch"
|
|
118835
119154
|
]);
|
|
118836
119155
|
function createMetisAgent(model) {
|
|
118837
119156
|
return {
|
|
@@ -120348,8 +120667,7 @@ function createMomusAgent(model) {
|
|
|
120348
120667
|
const restrictions = createAgentToolRestrictions([
|
|
120349
120668
|
"write",
|
|
120350
120669
|
"edit",
|
|
120351
|
-
"apply_patch"
|
|
120352
|
-
"task"
|
|
120670
|
+
"apply_patch"
|
|
120353
120671
|
]);
|
|
120354
120672
|
const base = {
|
|
120355
120673
|
description: "Expert reviewer for evaluating work plans against rigorous clarity, verifiability, and completeness standards. (Momus - OhMyOpenCode)",
|
|
@@ -121840,7 +122158,7 @@ function resolvePromptAppend(promptAppend, configDir) {
|
|
|
121840
122158
|
filePath,
|
|
121841
122159
|
projectRoot
|
|
121842
122160
|
});
|
|
121843
|
-
return `[WARNING: Path rejected: ${promptAppend}]`;
|
|
122161
|
+
return `[WARNING: Path rejected: ${promptAppend} (resolved outside project root ${projectRoot}; file:// prompts must reside within the project boundary)]`;
|
|
121844
122162
|
}
|
|
121845
122163
|
if (!existsSync91(filePath)) {
|
|
121846
122164
|
return `[WARNING: Could not resolve file URI: ${promptAppend}]`;
|
|
@@ -126715,7 +127033,9 @@ function createManagers(args) {
|
|
|
126715
127033
|
});
|
|
126716
127034
|
}
|
|
126717
127035
|
});
|
|
126718
|
-
const backgroundManager = new deps.BackgroundManagerClass(
|
|
127036
|
+
const backgroundManager = new deps.BackgroundManagerClass({
|
|
127037
|
+
pluginContext: ctx,
|
|
127038
|
+
config: pluginConfig.background_task,
|
|
126719
127039
|
tmuxConfig,
|
|
126720
127040
|
onSubagentSessionCreated: async (event) => {
|
|
126721
127041
|
log("[create-managers] onSubagentSessionCreated callback received", {
|
|
@@ -127339,7 +127659,6 @@ init_agent_display_names();
|
|
|
127339
127659
|
init_agent_display_names();
|
|
127340
127660
|
|
|
127341
127661
|
// src/plugin/ultrawork-db-model-override.ts
|
|
127342
|
-
import { Database } from "bun:sqlite";
|
|
127343
127662
|
import { join as join102 } from "path";
|
|
127344
127663
|
import { existsSync as existsSync92 } from "fs";
|
|
127345
127664
|
function getDbPath() {
|
|
@@ -127418,7 +127737,13 @@ function retryViaMicrotask(db, messageId, targetModel, variant, attempt) {
|
|
|
127418
127737
|
});
|
|
127419
127738
|
}
|
|
127420
127739
|
function scheduleDeferredModelOverride(messageId, targetModel, variant) {
|
|
127421
|
-
queueMicrotask(() => {
|
|
127740
|
+
queueMicrotask(async () => {
|
|
127741
|
+
const sqliteModule = await import("bun:sqlite").catch(() => null);
|
|
127742
|
+
const Database = sqliteModule?.Database;
|
|
127743
|
+
if (typeof Database !== "function") {
|
|
127744
|
+
log("[ultrawork-db-override] bun:sqlite unavailable, skipping deferred override", { messageId });
|
|
127745
|
+
return;
|
|
127746
|
+
}
|
|
127422
127747
|
const dbPath = getDbPath();
|
|
127423
127748
|
if (!existsSync92(dbPath)) {
|
|
127424
127749
|
log("[ultrawork-db-override] DB not found, skipping deferred override");
|
|
@@ -127829,11 +128154,24 @@ function createChatMessageHandler3(args) {
|
|
|
127829
128154
|
}
|
|
127830
128155
|
|
|
127831
128156
|
// src/plugin/messages-transform.ts
|
|
128157
|
+
init_logger();
|
|
128158
|
+
async function runMessagesTransformHookSafely(hookName, handler, input, output) {
|
|
128159
|
+
if (!handler)
|
|
128160
|
+
return;
|
|
128161
|
+
try {
|
|
128162
|
+
await Promise.resolve(handler(input, output));
|
|
128163
|
+
} catch (error) {
|
|
128164
|
+
log("[messages-transform] hook execution failed", {
|
|
128165
|
+
hook: hookName,
|
|
128166
|
+
error
|
|
128167
|
+
});
|
|
128168
|
+
}
|
|
128169
|
+
}
|
|
127832
128170
|
function createMessagesTransformHandler(args) {
|
|
127833
128171
|
return async (input, output) => {
|
|
127834
|
-
await args.hooks.contextInjectorMessagesTransform?.["experimental.chat.messages.transform"]
|
|
127835
|
-
await args.hooks.thinkingBlockValidator?.["experimental.chat.messages.transform"]
|
|
127836
|
-
await args.hooks.toolPairValidator?.["experimental.chat.messages.transform"]
|
|
128172
|
+
await runMessagesTransformHookSafely("contextInjectorMessagesTransform", args.hooks.contextInjectorMessagesTransform?.["experimental.chat.messages.transform"], input, output);
|
|
128173
|
+
await runMessagesTransformHookSafely("thinkingBlockValidator", args.hooks.thinkingBlockValidator?.["experimental.chat.messages.transform"], input, output);
|
|
128174
|
+
await runMessagesTransformHookSafely("toolPairValidator", args.hooks.toolPairValidator?.["experimental.chat.messages.transform"], input, output);
|
|
127837
128175
|
};
|
|
127838
128176
|
}
|
|
127839
128177
|
|
|
@@ -133505,7 +133843,7 @@ class PostHog extends PostHogBackendClient {
|
|
|
133505
133843
|
// package.json
|
|
133506
133844
|
var package_default = {
|
|
133507
133845
|
name: "oh-my-opencode",
|
|
133508
|
-
version: "3.17.
|
|
133846
|
+
version: "3.17.14",
|
|
133509
133847
|
description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
|
|
133510
133848
|
main: "./dist/index.js",
|
|
133511
133849
|
types: "dist/index.d.ts",
|
|
@@ -133573,7 +133911,7 @@ var package_default = {
|
|
|
133573
133911
|
"js-yaml": "^4.1.1",
|
|
133574
133912
|
"jsonc-parser": "^3.3.1",
|
|
133575
133913
|
picocolors: "^1.1.1",
|
|
133576
|
-
picomatch: "^4.0.
|
|
133914
|
+
picomatch: "^4.0.4",
|
|
133577
133915
|
"posthog-node": "^5.29.2",
|
|
133578
133916
|
"vscode-jsonrpc": "^8.2.0"
|
|
133579
133917
|
},
|
|
@@ -133585,17 +133923,17 @@ var package_default = {
|
|
|
133585
133923
|
zod: "^4.3.0"
|
|
133586
133924
|
},
|
|
133587
133925
|
optionalDependencies: {
|
|
133588
|
-
"oh-my-opencode-darwin-arm64": "3.17.
|
|
133589
|
-
"oh-my-opencode-darwin-x64": "3.17.
|
|
133590
|
-
"oh-my-opencode-darwin-x64-baseline": "3.17.
|
|
133591
|
-
"oh-my-opencode-linux-arm64": "3.17.
|
|
133592
|
-
"oh-my-opencode-linux-arm64-musl": "3.17.
|
|
133593
|
-
"oh-my-opencode-linux-x64": "3.17.
|
|
133594
|
-
"oh-my-opencode-linux-x64-baseline": "3.17.
|
|
133595
|
-
"oh-my-opencode-linux-x64-musl": "3.17.
|
|
133596
|
-
"oh-my-opencode-linux-x64-musl-baseline": "3.17.
|
|
133597
|
-
"oh-my-opencode-windows-x64": "3.17.
|
|
133598
|
-
"oh-my-opencode-windows-x64-baseline": "3.17.
|
|
133926
|
+
"oh-my-opencode-darwin-arm64": "3.17.14",
|
|
133927
|
+
"oh-my-opencode-darwin-x64": "3.17.14",
|
|
133928
|
+
"oh-my-opencode-darwin-x64-baseline": "3.17.14",
|
|
133929
|
+
"oh-my-opencode-linux-arm64": "3.17.14",
|
|
133930
|
+
"oh-my-opencode-linux-arm64-musl": "3.17.14",
|
|
133931
|
+
"oh-my-opencode-linux-x64": "3.17.14",
|
|
133932
|
+
"oh-my-opencode-linux-x64-baseline": "3.17.14",
|
|
133933
|
+
"oh-my-opencode-linux-x64-musl": "3.17.14",
|
|
133934
|
+
"oh-my-opencode-linux-x64-musl-baseline": "3.17.14",
|
|
133935
|
+
"oh-my-opencode-windows-x64": "3.17.14",
|
|
133936
|
+
"oh-my-opencode-windows-x64-baseline": "3.17.14"
|
|
133599
133937
|
},
|
|
133600
133938
|
overrides: {},
|
|
133601
133939
|
trustedDependencies: [
|
|
@@ -133674,21 +134012,6 @@ function getPostHogActivityCaptureState(now = new Date) {
|
|
|
133674
134012
|
captureDaily
|
|
133675
134013
|
};
|
|
133676
134014
|
}
|
|
133677
|
-
function getPluginLoadedCaptureState(now = new Date) {
|
|
133678
|
-
const state3 = readPostHogActivityState();
|
|
133679
|
-
const dayUTC = getUtcDayString(now);
|
|
133680
|
-
const capturePluginLoaded = state3.lastPluginLoadedDayUTC !== dayUTC;
|
|
133681
|
-
if (capturePluginLoaded) {
|
|
133682
|
-
writePostHogActivityState({
|
|
133683
|
-
...state3,
|
|
133684
|
-
lastPluginLoadedDayUTC: dayUTC
|
|
133685
|
-
});
|
|
133686
|
-
}
|
|
133687
|
-
return {
|
|
133688
|
-
dayUTC,
|
|
133689
|
-
capturePluginLoaded
|
|
133690
|
-
};
|
|
133691
|
-
}
|
|
133692
134015
|
|
|
133693
134016
|
// src/shared/posthog.ts
|
|
133694
134017
|
var activityStateProviderOverride = null;
|
|
@@ -133698,12 +134021,6 @@ function resolveActivityState() {
|
|
|
133698
134021
|
var DEFAULT_POSTHOG_HOST = "https://us.i.posthog.com";
|
|
133699
134022
|
var DEFAULT_POSTHOG_API_KEY = "phc_CFJhj5HyvA62QPhvyaUCtaq23aUfznnijg5VaaGkNk74";
|
|
133700
134023
|
var NO_OP_POSTHOG = {
|
|
133701
|
-
capture: () => {
|
|
133702
|
-
return;
|
|
133703
|
-
},
|
|
133704
|
-
captureException: () => {
|
|
133705
|
-
return;
|
|
133706
|
-
},
|
|
133707
134024
|
trackActive: () => {
|
|
133708
134025
|
return;
|
|
133709
134026
|
},
|
|
@@ -133777,21 +134094,6 @@ function createPostHogClient(source, options) {
|
|
|
133777
134094
|
}
|
|
133778
134095
|
const sharedProperties = getSharedProperties(source);
|
|
133779
134096
|
return {
|
|
133780
|
-
capture: (message) => {
|
|
133781
|
-
configuredClient.capture({
|
|
133782
|
-
...message,
|
|
133783
|
-
properties: {
|
|
133784
|
-
...sharedProperties,
|
|
133785
|
-
...message.properties
|
|
133786
|
-
}
|
|
133787
|
-
});
|
|
133788
|
-
},
|
|
133789
|
-
captureException: (error, distinctId, additionalProperties) => {
|
|
133790
|
-
configuredClient.captureException(error, distinctId, {
|
|
133791
|
-
...sharedProperties,
|
|
133792
|
-
...additionalProperties
|
|
133793
|
-
});
|
|
133794
|
-
},
|
|
133795
134097
|
trackActive: (distinctId, reason) => {
|
|
133796
134098
|
const activityState = resolveActivityState();
|
|
133797
134099
|
if (activityState.captureDaily) {
|
|
@@ -133800,6 +134102,7 @@ function createPostHogClient(source, options) {
|
|
|
133800
134102
|
event: "omo_daily_active",
|
|
133801
134103
|
properties: {
|
|
133802
134104
|
...sharedProperties,
|
|
134105
|
+
$process_person_profile: false,
|
|
133803
134106
|
day_utc: activityState.dayUTC,
|
|
133804
134107
|
reason
|
|
133805
134108
|
}
|
|
@@ -133839,23 +134142,6 @@ var serverPlugin = async (input, _options) => {
|
|
|
133839
134142
|
try {
|
|
133840
134143
|
posthog.trackActive(distinctId, "plugin_loaded");
|
|
133841
134144
|
} catch {}
|
|
133842
|
-
let pluginLoadedCaptureState = null;
|
|
133843
|
-
try {
|
|
133844
|
-
pluginLoadedCaptureState = getPluginLoadedCaptureState();
|
|
133845
|
-
} catch {}
|
|
133846
|
-
if (pluginLoadedCaptureState?.capturePluginLoaded) {
|
|
133847
|
-
try {
|
|
133848
|
-
posthog.capture({
|
|
133849
|
-
distinctId,
|
|
133850
|
-
event: "plugin_loaded",
|
|
133851
|
-
properties: {
|
|
133852
|
-
entry_point: "plugin",
|
|
133853
|
-
has_openclaw: !!pluginConfig.openclaw,
|
|
133854
|
-
tmux_enabled: isTmuxIntegrationEnabled(pluginConfig)
|
|
133855
|
-
}
|
|
133856
|
-
});
|
|
133857
|
-
} catch {}
|
|
133858
|
-
}
|
|
133859
134145
|
if (pluginConfig.openclaw) {
|
|
133860
134146
|
await initializeOpenClaw(pluginConfig.openclaw);
|
|
133861
134147
|
}
|