loadtoagent 1.3.5 → 1.3.7

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.
@@ -156,7 +156,7 @@ function outputStatus(value, explicitError = false) {
156
156
  if (firstLine.startsWith('script running')) return 'running';
157
157
  const code = exitCode(text);
158
158
  if (explicitError || (code != null && code !== 0) || /(?:script|command|process)\s+failed|isError["':\s]+true|fatal error/i.test(text)) return 'failed';
159
- if (/(?:script|command|process)\s+(?:is\s+)?(?:still\s+)?running|running\s+in\s+(?:the\s+)?background|background\s+(?:task|command)|yielded/i.test(text)) return 'running';
159
+ if (/^(?:command|process)\s+(?:is\s+)?(?:still\s+)?running\b|\brunning\s+in\s+(?:the\s+)?background\b|^background\s+(?:task|command)\b.*\brunning\b|\byielded\b/i.test(firstLine)) return 'running';
160
160
  return 'completed';
161
161
  }
162
162
 
@@ -270,6 +270,30 @@ function createExecutionTracker(options = {}) {
270
270
  return { activities, recordCall, recordOutput, finalize };
271
271
  }
272
272
 
273
+ function reconcileExecutionActivities(activities = [], options = {}) {
274
+ const now = Number.isFinite(Number(options.now)) ? Number(options.now) : Date.now();
275
+ const staleAfterMs = Math.max(0, Number(options.staleAfterMs || 0));
276
+ const turnSettled = Boolean(options.turnFinished || options.waitingForUser);
277
+ return activities.map((activity) => {
278
+ if (!activity || activity.status !== 'running') return activity;
279
+ const observedAt = Date.parse(activity.updatedAt || activity.startedAt || 0);
280
+ const observationAge = Number.isFinite(observedAt) ? Math.max(0, now - observedAt) : Number.POSITIVE_INFINITY;
281
+ const foregroundEnded = activity.mode !== 'background' && turnSettled;
282
+ const backgroundUnobserved = activity.mode === 'background'
283
+ && staleAfterMs > 0
284
+ && observationAge >= staleAfterMs;
285
+ if (!foregroundEnded && !backgroundUnobserved) return activity;
286
+ return {
287
+ ...activity,
288
+ status: 'unverified',
289
+ statusDetail: foregroundEnded
290
+ ? '턴 종료 후 실행 상태 미확인'
291
+ : '최근 실행 신호 없음',
292
+ completedAt: null,
293
+ };
294
+ });
295
+ }
296
+
273
297
  module.exports = {
274
298
  CONTINUATION_TOOLS,
275
299
  SHELL_TOOLS,
@@ -277,6 +301,7 @@ module.exports = {
277
301
  executionInput,
278
302
  outputStatus,
279
303
  outputText,
304
+ reconcileExecutionActivities,
280
305
  runtimeHandle,
281
306
  toolName,
282
307
  };
@@ -45,8 +45,8 @@ function createHierarchyAttacher(dependencies) {
45
45
  }
46
46
 
47
47
  function createHistoryChild(parent, record) {
48
- const externalId = String(record.childId || `${parent.externalId}:spawn:${record.callId}`).replace(/^codex:/, '');
49
- const child = baseSession('codex', externalId, '', {
48
+ const externalId = String(record.childId || `${parent.externalId}:spawn:${record.callId}`).replace(/^(?:codex|claude):/, '');
49
+ const child = baseSession(parent.provider, externalId, '', {
50
50
  mtimeMs: Date.parse(record.completedAt || record.startedAt || parent.updatedAt) || Date.now(),
51
51
  });
52
52
  child.id = record.childId || child.id;
@@ -69,7 +69,7 @@ function createHierarchyAttacher(dependencies) {
69
69
  child.completionObserved = child.status === 'completed';
70
70
  child.result = record.result || '';
71
71
  child.source = 'collaboration-history';
72
- child.sourceLabel = 'Codex 협업 이벤트';
72
+ child.sourceLabel = parent.provider === 'claude' ? 'Claude 협업 이벤트' : 'Codex 협업 이벤트';
73
73
  child.clientKind = parent.clientKind;
74
74
  child.model = parent.model;
75
75
  child.cwd = parent.cwd;
@@ -131,6 +131,7 @@ function createHierarchyAttacher(dependencies) {
131
131
  assignmentObserved: record.assignmentObserved,
132
132
  assignmentProtected: record.assignmentProtected,
133
133
  assignmentSource: record.assignmentSource,
134
+ assignmentContext: record.assignmentContext || '',
134
135
  sharedGoal: record.sharedGoal || child.sharedGoal || parent.title,
135
136
  result: record.result,
136
137
  startedAt: record.startedAt,
@@ -151,6 +152,7 @@ function createHierarchyAttacher(dependencies) {
151
152
  assignmentObserved: false,
152
153
  assignmentProtected: false,
153
154
  assignmentSource: 'unavailable',
155
+ assignmentContext: '',
154
156
  sharedGoal: child.sharedGoal || parent.title,
155
157
  status: child.status === 'completed' ? 'completed' : (child.status === 'running' ? 'running' : 'idle'),
156
158
  startedAt: child.startedAt,
@@ -169,6 +171,7 @@ function createHierarchyAttacher(dependencies) {
169
171
  assignmentObserved: false,
170
172
  assignmentProtected: true,
171
173
  assignmentSource: 'unavailable',
174
+ assignmentContext: '',
172
175
  sharedGoal: child.sharedGoal || parent.title,
173
176
  result: child.result || '',
174
177
  startedAt: child.startedAt,
@@ -492,10 +492,17 @@ class AgentMonitor extends EventEmitter {
492
492
 
493
493
  parseFile(info, parser, variant = '') {
494
494
  const key = `${info.file}|${info.mtimeMs}|${info.size}|${variant}`;
495
- const cached = this.parseCache.get(key);
496
- if (cached) return cached;
495
+ const cachedEntry = this.parseCache.get(key);
496
+ const cached = cachedEntry && cachedEntry.value || cachedEntry;
497
+ const parsedAt = Number(cachedEntry && cachedEntry.parsedAt || 0);
498
+ const timeSensitive = Boolean(cached && (
499
+ cached.status === 'running'
500
+ || cached.status === 'starting'
501
+ || (cached.executions || []).some(execution => execution.status === 'running')
502
+ ));
503
+ if (cached && (!timeSensitive || Date.now() - parsedAt < ACTIVE_THRESHOLD_MS)) return cached;
497
504
  const value = parser(info);
498
- if (value) this.parseCache.set(key, value);
505
+ if (value) this.parseCache.set(key, { value, parsedAt: Date.now() });
499
506
  if (this.parseCache.size > 500) {
500
507
  const keep = [...this.parseCache.entries()].slice(-300);
501
508
  this.parseCache = new Map(keep);
package/src/contracts.js CHANGED
@@ -42,7 +42,7 @@
42
42
  * @property {TokenUsage} usage
43
43
  * @property {Array<Object>} messages
44
44
  * @property {Array<Object>} lifecycle
45
- * @property {Array<{id:string,kind:'shell'|'background',mode:'foreground'|'background',tool:string,runtime:string,label:string,command:string,cwd:string,status:'running'|'completed'|'failed',statusDetail:string,output:string,backgroundId:string,exitCode:number|null,startedAt:string|null,updatedAt:string|null,completedAt:string|null}>} executions Logged regular and background command runs owned by this AI session.
45
+ * @property {Array<{id:string,kind:'shell'|'background',mode:'foreground'|'background',tool:string,runtime:string,label:string,command:string,cwd:string,status:'running'|'completed'|'failed'|'unverified',statusDetail:string,output:string,backgroundId:string,exitCode:number|null,startedAt:string|null,updatedAt:string|null,completedAt:string|null}>} executions Logged regular and background command runs owned by this AI session. `unverified` means the last running observation is no longer fresh enough to claim current liveness.
46
46
  * @property {CollaborationSummary|null} collaboration
47
47
  * @property {{kind:string,iteration:number,phase?:string}|boolean|null} loop Safe execution-loop metadata; internal goal text is never included.
48
48
  * @property {{required:boolean,kind:string,summary:string,requestedAt:string|null,source:string,confidence:string}} attention Actionable reason why the session needs the user.
@@ -107,6 +107,7 @@ function cardCollaboration(value) {
107
107
  assignmentObserved: Boolean(record.assignmentObserved),
108
108
  assignmentProtected: Boolean(record.assignmentProtected),
109
109
  assignmentSource: clip(record.assignmentSource, 80),
110
+ assignmentContext: clip(record.assignmentContext, 1200),
110
111
  sharedGoal: clip(record.sharedGoal, 1200),
111
112
  status: record.status,
112
113
  startedAt: record.startedAt,
@@ -194,6 +195,7 @@ function cardSession(session) {
194
195
  assignmentObserved: Boolean(session.delegation.assignmentObserved),
195
196
  assignmentProtected: Boolean(session.delegation.assignmentProtected),
196
197
  assignmentSource: clip(session.delegation.assignmentSource, 80),
198
+ assignmentContext: clip(session.delegation.assignmentContext, 1200),
197
199
  sharedGoal: clip(session.delegation.sharedGoal, 1200),
198
200
  result: clip(session.delegation.result, 1200),
199
201
  startedAt: session.delegation.startedAt,