@bohuyeshan/openagent-labforge-core 3.13.0 → 3.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -20518,13 +20518,16 @@ function isAgentRegistered(name) {
20518
20518
  }
20519
20519
  var sessionAgentMap = new Map;
20520
20520
  var ultraworkAutonomousSessionMap = new Map;
20521
+ function normalizeSessionAgentName(agent) {
20522
+ return getAgentConfigKey(agent);
20523
+ }
20521
20524
  function setSessionAgent(sessionID, agent) {
20522
20525
  if (!sessionAgentMap.has(sessionID)) {
20523
- sessionAgentMap.set(sessionID, agent);
20526
+ sessionAgentMap.set(sessionID, normalizeSessionAgentName(agent));
20524
20527
  }
20525
20528
  }
20526
20529
  function updateSessionAgent(sessionID, agent) {
20527
- sessionAgentMap.set(sessionID, agent);
20530
+ sessionAgentMap.set(sessionID, normalizeSessionAgentName(agent));
20528
20531
  }
20529
20532
  function getSessionAgent(sessionID) {
20530
20533
  return sessionAgentMap.get(sessionID);
@@ -61834,6 +61837,9 @@ function isAbortError(error48) {
61834
61837
  return false;
61835
61838
  }
61836
61839
 
61840
+ // src/hooks/atlas/idle-event.ts
61841
+ init_logger();
61842
+
61837
61843
  // src/hooks/atlas/boulder-continuation-injector.ts
61838
61844
  init_logger();
61839
61845
 
@@ -62140,10 +62146,196 @@ async function getLastAgentFromSession(sessionID, client) {
62140
62146
  return getLastAgentFromMessageDir(messageDir);
62141
62147
  }
62142
62148
 
62143
- // src/hooks/atlas/event-handler.ts
62149
+ // src/hooks/atlas/resolve-active-boulder-session.ts
62150
+ async function resolveActiveBoulderSession(input) {
62151
+ const boulderState = readBoulderState(input.directory);
62152
+ if (!boulderState) {
62153
+ return null;
62154
+ }
62155
+ const progress = getPlanProgress(boulderState.active_plan);
62156
+ if (progress.isComplete) {
62157
+ return { boulderState, progress, appendedSession: false };
62158
+ }
62159
+ if (boulderState.session_ids.includes(input.sessionID)) {
62160
+ return { boulderState, progress, appendedSession: false };
62161
+ }
62162
+ if (!subagentSessions.has(input.sessionID)) {
62163
+ return null;
62164
+ }
62165
+ const updatedBoulderState = appendSessionId(input.directory, input.sessionID);
62166
+ if (!updatedBoulderState?.session_ids.includes(input.sessionID)) {
62167
+ return null;
62168
+ }
62169
+ return {
62170
+ boulderState: updatedBoulderState,
62171
+ progress,
62172
+ appendedSession: true
62173
+ };
62174
+ }
62175
+
62176
+ // src/hooks/atlas/idle-event.ts
62144
62177
  var CONTINUATION_COOLDOWN_MS2 = 5000;
62145
62178
  var FAILURE_BACKOFF_MS = 5 * 60 * 1000;
62146
62179
  var RETRY_DELAY_MS = CONTINUATION_COOLDOWN_MS2 + 1000;
62180
+ function hasRunningBackgroundTasks(sessionID, options) {
62181
+ const backgroundManager = options?.backgroundManager;
62182
+ return backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((task) => task.status === "running") : false;
62183
+ }
62184
+ async function injectContinuation2(input) {
62185
+ const remaining = input.progress.total - input.progress.completed;
62186
+ input.sessionState.lastContinuationInjectedAt = Date.now();
62187
+ try {
62188
+ await injectBoulderContinuation({
62189
+ ctx: input.ctx,
62190
+ sessionID: input.sessionID,
62191
+ planName: input.planName,
62192
+ remaining,
62193
+ total: input.progress.total,
62194
+ agent: input.agent,
62195
+ worktreePath: input.worktreePath,
62196
+ backgroundManager: input.options?.backgroundManager,
62197
+ sessionState: input.sessionState
62198
+ });
62199
+ } catch (error48) {
62200
+ log(`[${HOOK_NAME7}] Failed to inject boulder continuation`, { sessionID: input.sessionID, error: error48 });
62201
+ input.sessionState.promptFailureCount += 1;
62202
+ }
62203
+ }
62204
+ function scheduleRetry(input) {
62205
+ const { ctx, sessionID, sessionState, options } = input;
62206
+ if (sessionState.pendingRetryTimer) {
62207
+ return;
62208
+ }
62209
+ sessionState.pendingRetryTimer = setTimeout(async () => {
62210
+ sessionState.pendingRetryTimer = undefined;
62211
+ if (sessionState.promptFailureCount >= 2)
62212
+ return;
62213
+ const currentBoulder = await resolveActiveBoulderSession({
62214
+ client: ctx.client,
62215
+ directory: ctx.directory,
62216
+ sessionID
62217
+ });
62218
+ if (!currentBoulder)
62219
+ return;
62220
+ if (currentBoulder.progress.isComplete)
62221
+ return;
62222
+ if (options?.isContinuationStopped?.(sessionID))
62223
+ return;
62224
+ if (hasRunningBackgroundTasks(sessionID, options))
62225
+ return;
62226
+ await injectContinuation2({
62227
+ ctx,
62228
+ sessionID,
62229
+ sessionState,
62230
+ options,
62231
+ planName: currentBoulder.boulderState.plan_name,
62232
+ progress: currentBoulder.progress,
62233
+ agent: currentBoulder.boulderState.agent,
62234
+ worktreePath: currentBoulder.boulderState.worktree_path
62235
+ });
62236
+ }, RETRY_DELAY_MS);
62237
+ }
62238
+ async function handleAtlasSessionIdle(input) {
62239
+ const { ctx, options, getState, sessionID } = input;
62240
+ log(`[${HOOK_NAME7}] session.idle`, { sessionID });
62241
+ const activeBoulderSession = await resolveActiveBoulderSession({
62242
+ client: ctx.client,
62243
+ directory: ctx.directory,
62244
+ sessionID
62245
+ });
62246
+ if (!activeBoulderSession) {
62247
+ log(`[${HOOK_NAME7}] Skipped: not boulder or background task session`, { sessionID });
62248
+ return;
62249
+ }
62250
+ const { boulderState, progress } = activeBoulderSession;
62251
+ if (progress.isComplete) {
62252
+ log(`[${HOOK_NAME7}] Boulder complete`, { sessionID, plan: boulderState.plan_name });
62253
+ return;
62254
+ }
62255
+ const sessionState = getState(sessionID);
62256
+ const now = Date.now();
62257
+ if (sessionState.lastEventWasAbortError) {
62258
+ sessionState.lastEventWasAbortError = false;
62259
+ log(`[${HOOK_NAME7}] Skipped: abort error immediately before idle`, { sessionID });
62260
+ return;
62261
+ }
62262
+ if (sessionState.promptFailureCount >= 2) {
62263
+ const timeSinceLastFailure = sessionState.lastFailureAt !== undefined ? now - sessionState.lastFailureAt : Number.POSITIVE_INFINITY;
62264
+ if (timeSinceLastFailure < FAILURE_BACKOFF_MS) {
62265
+ log(`[${HOOK_NAME7}] Skipped: continuation in backoff after repeated failures`, {
62266
+ sessionID,
62267
+ promptFailureCount: sessionState.promptFailureCount,
62268
+ backoffRemaining: FAILURE_BACKOFF_MS - timeSinceLastFailure
62269
+ });
62270
+ return;
62271
+ }
62272
+ sessionState.promptFailureCount = 0;
62273
+ sessionState.lastFailureAt = undefined;
62274
+ }
62275
+ if (hasRunningBackgroundTasks(sessionID, options)) {
62276
+ log(`[${HOOK_NAME7}] Skipped: background tasks running`, { sessionID });
62277
+ return;
62278
+ }
62279
+ if (options?.isContinuationStopped?.(sessionID)) {
62280
+ log(`[${HOOK_NAME7}] Skipped: continuation stopped for session`, { sessionID });
62281
+ return;
62282
+ }
62283
+ const sessionAgent = getSessionAgent(sessionID);
62284
+ const lastAgent = await getLastAgentFromSession(sessionID, ctx.client);
62285
+ const effectiveAgent = sessionAgent ?? lastAgent;
62286
+ const lastAgentKey = getAgentConfigKey(effectiveAgent ?? "");
62287
+ const configuredBoulderAgent = boulderState.agent;
62288
+ const requiredAgentName = configuredBoulderAgent ?? (isAgentRegistered("atlas") ? "atlas" : undefined);
62289
+ if (!requiredAgentName) {
62290
+ log(`[${HOOK_NAME7}] Skipped: boulder agent is unavailable for continuation`, {
62291
+ sessionID,
62292
+ requiredAgent: requiredAgentName ?? "unknown"
62293
+ });
62294
+ return;
62295
+ }
62296
+ if (!configuredBoulderAgent && !isAgentRegistered(requiredAgentName)) {
62297
+ log(`[${HOOK_NAME7}] Skipped: implicit boulder agent is unavailable for continuation`, {
62298
+ sessionID,
62299
+ requiredAgent: requiredAgentName
62300
+ });
62301
+ return;
62302
+ }
62303
+ const requiredAgent = getAgentConfigKey(requiredAgentName);
62304
+ const lastAgentMatchesRequired = lastAgentKey === requiredAgent;
62305
+ const boulderAgentDefaultsToAtlas = requiredAgent === "atlas";
62306
+ const lastAgentIsSisyphus = lastAgentKey === "sisyphus";
62307
+ const allowSisyphusForAtlasBoulder = boulderAgentDefaultsToAtlas && lastAgentIsSisyphus;
62308
+ const agentMatches = lastAgentMatchesRequired || allowSisyphusForAtlasBoulder;
62309
+ if (!agentMatches) {
62310
+ log(`[${HOOK_NAME7}] Skipped: last agent does not match boulder agent`, {
62311
+ sessionID,
62312
+ lastAgent: effectiveAgent ?? "unknown",
62313
+ requiredAgent
62314
+ });
62315
+ return;
62316
+ }
62317
+ if (sessionState.lastContinuationInjectedAt && now - sessionState.lastContinuationInjectedAt < CONTINUATION_COOLDOWN_MS2) {
62318
+ scheduleRetry({ ctx, sessionID, sessionState, options });
62319
+ log(`[${HOOK_NAME7}] Skipped: continuation cooldown active`, {
62320
+ sessionID,
62321
+ cooldownRemaining: CONTINUATION_COOLDOWN_MS2 - (now - sessionState.lastContinuationInjectedAt),
62322
+ pendingRetry: !!sessionState.pendingRetryTimer
62323
+ });
62324
+ return;
62325
+ }
62326
+ await injectContinuation2({
62327
+ ctx,
62328
+ sessionID,
62329
+ sessionState,
62330
+ options,
62331
+ planName: boulderState.plan_name,
62332
+ progress,
62333
+ agent: boulderState.agent,
62334
+ worktreePath: boulderState.worktree_path
62335
+ });
62336
+ }
62337
+
62338
+ // src/hooks/atlas/event-handler.ts
62147
62339
  function createAtlasEventHandler(input) {
62148
62340
  const { ctx, options, sessions, getState } = input;
62149
62341
  return async ({ event }) => {
@@ -62162,143 +62354,7 @@ function createAtlasEventHandler(input) {
62162
62354
  const sessionID = props?.sessionID;
62163
62355
  if (!sessionID)
62164
62356
  return;
62165
- log(`[${HOOK_NAME7}] session.idle`, { sessionID });
62166
- const boulderState = readBoulderState(ctx.directory);
62167
- const isBoulderSession = boulderState?.session_ids?.includes(sessionID) ?? false;
62168
- const isBackgroundTaskSession = subagentSessions.has(sessionID);
62169
- if (!isBackgroundTaskSession && !isBoulderSession) {
62170
- log(`[${HOOK_NAME7}] Skipped: not boulder or background task session`, { sessionID });
62171
- return;
62172
- }
62173
- const state3 = getState(sessionID);
62174
- const now = Date.now();
62175
- if (state3.lastEventWasAbortError) {
62176
- state3.lastEventWasAbortError = false;
62177
- log(`[${HOOK_NAME7}] Skipped: abort error immediately before idle`, { sessionID });
62178
- return;
62179
- }
62180
- if (state3.promptFailureCount >= 2) {
62181
- const timeSinceLastFailure = state3.lastFailureAt !== undefined ? now - state3.lastFailureAt : Number.POSITIVE_INFINITY;
62182
- if (timeSinceLastFailure < FAILURE_BACKOFF_MS) {
62183
- log(`[${HOOK_NAME7}] Skipped: continuation in backoff after repeated failures`, {
62184
- sessionID,
62185
- promptFailureCount: state3.promptFailureCount,
62186
- backoffRemaining: FAILURE_BACKOFF_MS - timeSinceLastFailure
62187
- });
62188
- return;
62189
- }
62190
- state3.promptFailureCount = 0;
62191
- state3.lastFailureAt = undefined;
62192
- }
62193
- const backgroundManager = options?.backgroundManager;
62194
- const hasRunningBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((t) => t.status === "running") : false;
62195
- if (hasRunningBgTasks) {
62196
- log(`[${HOOK_NAME7}] Skipped: background tasks running`, { sessionID });
62197
- return;
62198
- }
62199
- if (!boulderState) {
62200
- log(`[${HOOK_NAME7}] No active boulder`, { sessionID });
62201
- return;
62202
- }
62203
- if (options?.isContinuationStopped?.(sessionID)) {
62204
- log(`[${HOOK_NAME7}] Skipped: continuation stopped for session`, { sessionID });
62205
- return;
62206
- }
62207
- const sessionAgent = getSessionAgent(sessionID);
62208
- const lastAgent = await getLastAgentFromSession(sessionID, ctx.client);
62209
- const effectiveAgent = sessionAgent ?? lastAgent;
62210
- const lastAgentKey = getAgentConfigKey(effectiveAgent ?? "");
62211
- const requiredAgentName = boulderState.agent ?? (isAgentRegistered("atlas") ? "atlas" : undefined);
62212
- if (!requiredAgentName || !isAgentRegistered(requiredAgentName)) {
62213
- log(`[${HOOK_NAME7}] Skipped: boulder agent is unavailable for continuation`, {
62214
- sessionID,
62215
- requiredAgent: requiredAgentName ?? "unknown"
62216
- });
62217
- return;
62218
- }
62219
- const requiredAgent = getAgentConfigKey(requiredAgentName);
62220
- const lastAgentMatchesRequired = lastAgentKey === requiredAgent;
62221
- const boulderAgentDefaultsToAtlas = requiredAgent === "atlas";
62222
- const lastAgentIsSisyphus = lastAgentKey === "sisyphus";
62223
- const allowSisyphusForAtlasBoulder = boulderAgentDefaultsToAtlas && lastAgentIsSisyphus;
62224
- const agentMatches = lastAgentMatchesRequired || allowSisyphusForAtlasBoulder;
62225
- if (!agentMatches) {
62226
- log(`[${HOOK_NAME7}] Skipped: last agent does not match boulder agent`, {
62227
- sessionID,
62228
- lastAgent: effectiveAgent ?? "unknown",
62229
- requiredAgent
62230
- });
62231
- return;
62232
- }
62233
- const progress = getPlanProgress(boulderState.active_plan);
62234
- if (progress.isComplete) {
62235
- log(`[${HOOK_NAME7}] Boulder complete`, { sessionID, plan: boulderState.plan_name });
62236
- return;
62237
- }
62238
- if (state3.lastContinuationInjectedAt && now - state3.lastContinuationInjectedAt < CONTINUATION_COOLDOWN_MS2) {
62239
- if (!state3.pendingRetryTimer) {
62240
- state3.pendingRetryTimer = setTimeout(async () => {
62241
- state3.pendingRetryTimer = undefined;
62242
- if (state3.promptFailureCount >= 2)
62243
- return;
62244
- const currentBoulder = readBoulderState(ctx.directory);
62245
- if (!currentBoulder)
62246
- return;
62247
- if (!currentBoulder.session_ids?.includes(sessionID))
62248
- return;
62249
- const currentProgress = getPlanProgress(currentBoulder.active_plan);
62250
- if (currentProgress.isComplete)
62251
- return;
62252
- if (options?.isContinuationStopped?.(sessionID))
62253
- return;
62254
- const hasBgTasks = backgroundManager ? backgroundManager.getTasksByParentSession(sessionID).some((t) => t.status === "running") : false;
62255
- if (hasBgTasks)
62256
- return;
62257
- state3.lastContinuationInjectedAt = Date.now();
62258
- const currentRemaining = currentProgress.total - currentProgress.completed;
62259
- try {
62260
- await injectBoulderContinuation({
62261
- ctx,
62262
- sessionID,
62263
- planName: currentBoulder.plan_name,
62264
- remaining: currentRemaining,
62265
- total: currentProgress.total,
62266
- agent: currentBoulder.agent,
62267
- worktreePath: currentBoulder.worktree_path,
62268
- backgroundManager,
62269
- sessionState: state3
62270
- });
62271
- } catch (err) {
62272
- log(`[${HOOK_NAME7}] Delayed retry failed`, { sessionID, error: err });
62273
- state3.promptFailureCount++;
62274
- }
62275
- }, RETRY_DELAY_MS);
62276
- }
62277
- log(`[${HOOK_NAME7}] Skipped: continuation cooldown active`, {
62278
- sessionID,
62279
- cooldownRemaining: CONTINUATION_COOLDOWN_MS2 - (now - state3.lastContinuationInjectedAt),
62280
- pendingRetry: !!state3.pendingRetryTimer
62281
- });
62282
- return;
62283
- }
62284
- state3.lastContinuationInjectedAt = now;
62285
- const remaining = progress.total - progress.completed;
62286
- try {
62287
- await injectBoulderContinuation({
62288
- ctx,
62289
- sessionID,
62290
- planName: boulderState.plan_name,
62291
- remaining,
62292
- total: progress.total,
62293
- agent: boulderState.agent,
62294
- worktreePath: boulderState.worktree_path,
62295
- backgroundManager,
62296
- sessionState: state3
62297
- });
62298
- } catch (err) {
62299
- log(`[${HOOK_NAME7}] Failed to inject boulder continuation`, { sessionID, error: err });
62300
- state3.promptFailureCount++;
62301
- }
62357
+ await handleAtlasSessionIdle({ ctx, options, getState, sessionID });
62302
62358
  return;
62303
62359
  }
62304
62360
  if (event.type === "message.updated") {
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@bohuyeshan/openagent-labforge-core",
3
- "version": "3.13.0",
3
+ "version": "3.13.2",
4
4
  "description": "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
5
- "main": "./dist/index.js",
6
- "types": "./dist/index.d.ts",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
7
  "type": "module",
8
- "bin": {
9
- "openagent-labforge": "bin/openagent-labforge.js"
10
- },
11
- "oc-plugin": [
12
- "server",
13
- "tui"
14
- ],
8
+ "bin": {
9
+ "openagent-labforge": "bin/openagent-labforge.js"
10
+ },
11
+ "oc-plugin": [
12
+ "server",
13
+ "tui"
14
+ ],
15
15
  "files": [
16
16
  "dist",
17
17
  "bin",
@@ -50,14 +50,14 @@
50
50
  ],
51
51
  "author": "YeonGyu-Kim",
52
52
  "license": "SUL-1.0",
53
- "repository": {
54
- "type": "git",
55
- "url": "git+https://github.com/BOHUYESHAN-APB/openagent-labforge.git"
56
- },
57
- "bugs": {
58
- "url": "https://github.com/BOHUYESHAN-APB/openagent-labforge/issues"
59
- },
60
- "homepage": "https://github.com/BOHUYESHAN-APB/openagent-labforge#readme",
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "git+https://github.com/BOHUYESHAN-APB/openagent-labforge.git"
56
+ },
57
+ "bugs": {
58
+ "url": "https://github.com/BOHUYESHAN-APB/openagent-labforge/issues"
59
+ },
60
+ "homepage": "https://github.com/BOHUYESHAN-APB/openagent-labforge#readme",
61
61
  "dependencies": {
62
62
  "@ast-grep/cli": "^0.40.0",
63
63
  "@ast-grep/napi": "^0.40.0",
@@ -83,18 +83,18 @@
83
83
  "typescript": "^5.7.3"
84
84
  },
85
85
  "optionalDependencies": {
86
- "openagent-labforge-darwin-arm64": "3.11.2",
87
- "openagent-labforge-darwin-x64": "3.11.2",
88
- "openagent-labforge-darwin-x64-baseline": "3.11.2",
89
- "openagent-labforge-linux-arm64": "3.11.2",
90
- "openagent-labforge-linux-arm64-musl": "3.11.2",
91
- "openagent-labforge-linux-x64": "3.11.2",
92
- "openagent-labforge-linux-x64-baseline": "3.11.2",
93
- "openagent-labforge-linux-x64-musl": "3.11.2",
94
- "openagent-labforge-linux-x64-musl-baseline": "3.11.2",
95
- "openagent-labforge-windows-x64": "3.13.0",
96
- "openagent-labforge-windows-x64-baseline": "3.11.2"
97
- },
86
+ "openagent-labforge-darwin-arm64": "3.11.2",
87
+ "openagent-labforge-darwin-x64": "3.11.2",
88
+ "openagent-labforge-darwin-x64-baseline": "3.11.2",
89
+ "openagent-labforge-linux-arm64": "3.11.2",
90
+ "openagent-labforge-linux-arm64-musl": "3.11.2",
91
+ "openagent-labforge-linux-x64": "3.11.2",
92
+ "openagent-labforge-linux-x64-baseline": "3.11.2",
93
+ "openagent-labforge-linux-x64-musl": "3.11.2",
94
+ "openagent-labforge-linux-x64-musl-baseline": "3.11.2",
95
+ "openagent-labforge-windows-x64": "3.13.2",
96
+ "openagent-labforge-windows-x64-baseline": "3.11.2"
97
+ },
98
98
  "overrides": {
99
99
  "@opencode-ai/sdk": "^1.2.17"
100
100
  },